Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
crystalhd_cmds.c
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (c) 2005-2009, Broadcom Corporation.
3  *
4  * Name: crystalhd_cmds . c
5  *
6  * Description:
7  * BCM70010 Linux driver user command interfaces.
8  *
9  * HISTORY:
10  *
11  **********************************************************************
12  * This file is part of the crystalhd device driver.
13  *
14  * This driver is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, version 2 of the License.
17  *
18  * This driver is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this driver. If not, see <http://www.gnu.org/licenses/>.
25  **********************************************************************/
26 
27 #include "crystalhd.h"
28 
29 static struct crystalhd_user *bc_cproc_get_uid(struct crystalhd_cmd *ctx)
30 {
31  struct crystalhd_user *user = NULL;
32  int i;
33 
34  for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
35  if (!ctx->user[i].in_use) {
36  user = &ctx->user[i];
37  break;
38  }
39  }
40 
41  return user;
42 }
43 
44 static int bc_cproc_get_user_count(struct crystalhd_cmd *ctx)
45 {
46  int i, count = 0;
47 
48  for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
49  if (ctx->user[i].in_use)
50  count++;
51  }
52 
53  return count;
54 }
55 
56 static void bc_cproc_mark_pwr_state(struct crystalhd_cmd *ctx)
57 {
58  int i;
59 
60  for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
61  if (!ctx->user[i].in_use)
62  continue;
63  if (ctx->user[i].mode == DTS_DIAG_MODE ||
64  ctx->user[i].mode == DTS_PLAYBACK_MODE) {
65  ctx->pwr_state_change = 1;
66  break;
67  }
68  }
69 }
70 
71 static enum BC_STATUS bc_cproc_notify_mode(struct crystalhd_cmd *ctx,
72  struct crystalhd_ioctl_data *idata)
73 {
74  int rc = 0, i = 0;
75 
76  if (!ctx || !idata) {
77  BCMLOG_ERR("Invalid Arg!!\n");
78  return BC_STS_INV_ARG;
79  }
80 
81  if (ctx->user[idata->u_id].mode != DTS_MODE_INV) {
82  BCMLOG_ERR("Close the handle first..\n");
83  return BC_STS_ERR_USAGE;
84  }
85  if (idata->udata.u.NotifyMode.Mode == DTS_MONITOR_MODE) {
86  ctx->user[idata->u_id].mode = idata->udata.u.NotifyMode.Mode;
87  return BC_STS_SUCCESS;
88  }
89  if (ctx->state != BC_LINK_INVALID) {
90  BCMLOG_ERR("Link invalid state %d\n", ctx->state);
91  return BC_STS_ERR_USAGE;
92  }
93  /* Check for duplicate playback sessions..*/
94  for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
95  if (ctx->user[i].mode == DTS_DIAG_MODE ||
96  ctx->user[i].mode == DTS_PLAYBACK_MODE) {
97  BCMLOG_ERR("multiple playback sessions are not "
98  "supported..\n");
99  return BC_STS_ERR_USAGE;
100  }
101  }
102  ctx->cin_wait_exit = 0;
103  ctx->user[idata->u_id].mode = idata->udata.u.NotifyMode.Mode;
104  /* Setup mmap pool for uaddr sgl mapping..*/
106  if (rc)
107  return BC_STS_ERROR;
108 
109  /* Setup Hardware DMA rings */
110  return crystalhd_hw_setup_dma_rings(&ctx->hw_ctx);
111 }
112 
113 static enum BC_STATUS bc_cproc_get_version(struct crystalhd_cmd *ctx,
114  struct crystalhd_ioctl_data *idata)
115 {
116 
117  if (!ctx || !idata) {
118  BCMLOG_ERR("Invalid Arg!!\n");
119  return BC_STS_INV_ARG;
120  }
121  idata->udata.u.VerInfo.DriverMajor = crystalhd_kmod_major;
122  idata->udata.u.VerInfo.DriverMinor = crystalhd_kmod_minor;
123  idata->udata.u.VerInfo.DriverRevision = crystalhd_kmod_rev;
124  return BC_STS_SUCCESS;
125 }
126 
127 
128 static enum BC_STATUS bc_cproc_get_hwtype(struct crystalhd_cmd *ctx,
129  struct crystalhd_ioctl_data *idata)
130 {
131  if (!ctx || !idata) {
132  BCMLOG_ERR("Invalid Arg!!\n");
133  return BC_STS_INV_ARG;
134  }
135 
136  crystalhd_pci_cfg_rd(ctx->adp, 0, 2,
137  (uint32_t *)&idata->udata.u.hwType.PciVenId);
138  crystalhd_pci_cfg_rd(ctx->adp, 2, 2,
139  (uint32_t *)&idata->udata.u.hwType.PciDevId);
140  crystalhd_pci_cfg_rd(ctx->adp, 8, 1,
141  (uint32_t *)&idata->udata.u.hwType.HwRev);
142 
143  return BC_STS_SUCCESS;
144 }
145 
146 static enum BC_STATUS bc_cproc_reg_rd(struct crystalhd_cmd *ctx,
147  struct crystalhd_ioctl_data *idata)
148 {
149  if (!ctx || !idata)
150  return BC_STS_INV_ARG;
151  idata->udata.u.regAcc.Value = bc_dec_reg_rd(ctx->adp,
152  idata->udata.u.regAcc.Offset);
153  return BC_STS_SUCCESS;
154 }
155 
156 static enum BC_STATUS bc_cproc_reg_wr(struct crystalhd_cmd *ctx,
157  struct crystalhd_ioctl_data *idata)
158 {
159  if (!ctx || !idata)
160  return BC_STS_INV_ARG;
161 
162  bc_dec_reg_wr(ctx->adp, idata->udata.u.regAcc.Offset,
163  idata->udata.u.regAcc.Value);
164 
165  return BC_STS_SUCCESS;
166 }
167 
168 static enum BC_STATUS bc_cproc_link_reg_rd(struct crystalhd_cmd *ctx,
169  struct crystalhd_ioctl_data *idata)
170 {
171  if (!ctx || !idata)
172  return BC_STS_INV_ARG;
173 
174  idata->udata.u.regAcc.Value = crystalhd_reg_rd(ctx->adp,
175  idata->udata.u.regAcc.Offset);
176  return BC_STS_SUCCESS;
177 }
178 
179 static enum BC_STATUS bc_cproc_link_reg_wr(struct crystalhd_cmd *ctx,
180  struct crystalhd_ioctl_data *idata)
181 {
182  if (!ctx || !idata)
183  return BC_STS_INV_ARG;
184 
185  crystalhd_reg_wr(ctx->adp, idata->udata.u.regAcc.Offset,
186  idata->udata.u.regAcc.Value);
187 
188  return BC_STS_SUCCESS;
189 }
190 
191 static enum BC_STATUS bc_cproc_mem_rd(struct crystalhd_cmd *ctx,
192  struct crystalhd_ioctl_data *idata)
193 {
195 
196  if (!ctx || !idata || !idata->add_cdata)
197  return BC_STS_INV_ARG;
198 
199  if (idata->udata.u.devMem.NumDwords > (idata->add_cdata_sz / 4)) {
200  BCMLOG_ERR("insufficient buffer\n");
201  return BC_STS_INV_ARG;
202  }
203  sts = crystalhd_mem_rd(ctx->adp, idata->udata.u.devMem.StartOff,
204  idata->udata.u.devMem.NumDwords,
205  (uint32_t *)idata->add_cdata);
206  return sts;
207 
208 }
209 
210 static enum BC_STATUS bc_cproc_mem_wr(struct crystalhd_cmd *ctx,
211  struct crystalhd_ioctl_data *idata)
212 {
213  enum BC_STATUS sts = BC_STS_SUCCESS;
214 
215  if (!ctx || !idata || !idata->add_cdata)
216  return BC_STS_INV_ARG;
217 
218  if (idata->udata.u.devMem.NumDwords > (idata->add_cdata_sz / 4)) {
219  BCMLOG_ERR("insufficient buffer\n");
220  return BC_STS_INV_ARG;
221  }
222 
223  sts = crystalhd_mem_wr(ctx->adp, idata->udata.u.devMem.StartOff,
224  idata->udata.u.devMem.NumDwords,
225  (uint32_t *)idata->add_cdata);
226  return sts;
227 }
228 
229 static enum BC_STATUS bc_cproc_cfg_rd(struct crystalhd_cmd *ctx,
230  struct crystalhd_ioctl_data *idata)
231 {
232  uint32_t ix, cnt, off, len;
233  enum BC_STATUS sts = BC_STS_SUCCESS;
234  uint32_t *temp;
235 
236  if (!ctx || !idata)
237  return BC_STS_INV_ARG;
238 
239  temp = (uint32_t *) idata->udata.u.pciCfg.pci_cfg_space;
240  off = idata->udata.u.pciCfg.Offset;
241  len = idata->udata.u.pciCfg.Size;
242 
243  if (len <= 4)
244  return crystalhd_pci_cfg_rd(ctx->adp, off, len, temp);
245 
246  /* Truncate to dword alignment..*/
247  len = 4;
248  cnt = idata->udata.u.pciCfg.Size / len;
249  for (ix = 0; ix < cnt; ix++) {
250  sts = crystalhd_pci_cfg_rd(ctx->adp, off, len, &temp[ix]);
251  if (sts != BC_STS_SUCCESS) {
252  BCMLOG_ERR("config read : %d\n", sts);
253  return sts;
254  }
255  off += len;
256  }
257 
258  return sts;
259 }
260 
261 static enum BC_STATUS bc_cproc_cfg_wr(struct crystalhd_cmd *ctx,
262  struct crystalhd_ioctl_data *idata)
263 {
264  uint32_t ix, cnt, off, len;
265  enum BC_STATUS sts = BC_STS_SUCCESS;
266  uint32_t *temp;
267 
268  if (!ctx || !idata)
269  return BC_STS_INV_ARG;
270 
271  temp = (uint32_t *) idata->udata.u.pciCfg.pci_cfg_space;
272  off = idata->udata.u.pciCfg.Offset;
273  len = idata->udata.u.pciCfg.Size;
274 
275  if (len <= 4)
276  return crystalhd_pci_cfg_wr(ctx->adp, off, len, temp[0]);
277 
278  /* Truncate to dword alignment..*/
279  len = 4;
280  cnt = idata->udata.u.pciCfg.Size / len;
281  for (ix = 0; ix < cnt; ix++) {
282  sts = crystalhd_pci_cfg_wr(ctx->adp, off, len, temp[ix]);
283  if (sts != BC_STS_SUCCESS) {
284  BCMLOG_ERR("config write : %d\n", sts);
285  return sts;
286  }
287  off += len;
288  }
289 
290  return sts;
291 }
292 
293 static enum BC_STATUS bc_cproc_download_fw(struct crystalhd_cmd *ctx,
294  struct crystalhd_ioctl_data *idata)
295 {
296  enum BC_STATUS sts = BC_STS_SUCCESS;
297 
298  if (!ctx || !idata || !idata->add_cdata || !idata->add_cdata_sz) {
299  BCMLOG_ERR("Invalid Arg!!\n");
300  return BC_STS_INV_ARG;
301  }
302 
303  if (ctx->state != BC_LINK_INVALID) {
304  BCMLOG_ERR("Link invalid state %d\n", ctx->state);
305  return BC_STS_ERR_USAGE;
306  }
307 
308  sts = crystalhd_download_fw(ctx->adp, (uint8_t *)idata->add_cdata,
309  idata->add_cdata_sz);
310 
311  if (sts != BC_STS_SUCCESS) {
312  BCMLOG_ERR("Firmware Download Failure!! - %d\n", sts);
313  } else
314  ctx->state |= BC_LINK_INIT;
315 
316  return sts;
317 }
318 
319 /*
320  * We use the FW_CMD interface to sync up playback state with application
321  * and firmware. This function will perform the required pre and post
322  * processing of the Firmware commands.
323  *
324  * Pause -
325  * Disable capture after decoder pause.
326  * Resume -
327  * First enable capture and issue decoder resume command.
328  * Flush -
329  * Abort pending input transfers and issue decoder flush command.
330  *
331  */
332 static enum BC_STATUS bc_cproc_do_fw_cmd(struct crystalhd_cmd *ctx,
333  struct crystalhd_ioctl_data *idata)
334 {
335  enum BC_STATUS sts;
336  uint32_t *cmd;
337 
338  if (!(ctx->state & BC_LINK_INIT)) {
339  BCMLOG_ERR("Link invalid state %d\n", ctx->state);
340  return BC_STS_ERR_USAGE;
341  }
342 
343  cmd = idata->udata.u.fwCmd.cmd;
344 
345  /* Pre-Process */
346  if (cmd[0] == eCMD_C011_DEC_CHAN_PAUSE) {
347  if (!cmd[3]) {
348  ctx->state &= ~BC_LINK_PAUSED;
350  }
351  } else if (cmd[0] == eCMD_C011_DEC_CHAN_FLUSH) {
352  BCMLOG(BCMLOG_INFO, "Flush issued\n");
353  if (cmd[3])
354  ctx->cin_wait_exit = 1;
355  }
356 
357  sts = crystalhd_do_fw_cmd(&ctx->hw_ctx, &idata->udata.u.fwCmd);
358 
359  if (sts != BC_STS_SUCCESS) {
360  BCMLOG(BCMLOG_INFO, "fw cmd %x failed\n", cmd[0]);
361  return sts;
362  }
363 
364  /* Post-Process */
365  if (cmd[0] == eCMD_C011_DEC_CHAN_PAUSE) {
366  if (cmd[3]) {
367  ctx->state |= BC_LINK_PAUSED;
368  crystalhd_hw_pause(&ctx->hw_ctx);
369  }
370  }
371 
372  return sts;
373 }
374 
375 static void bc_proc_in_completion(struct crystalhd_dio_req *dio_hnd,
376  wait_queue_head_t *event, enum BC_STATUS sts)
377 {
378  if (!dio_hnd || !event) {
379  BCMLOG_ERR("Invalid Arg!!\n");
380  return;
381  }
382  if (sts == BC_STS_IO_USER_ABORT)
383  return;
384 
385  dio_hnd->uinfo.comp_sts = sts;
386  dio_hnd->uinfo.ev_sts = 1;
387  crystalhd_set_event(event);
388 }
389 
390 static enum BC_STATUS bc_cproc_codein_sleep(struct crystalhd_cmd *ctx)
391 {
392  wait_queue_head_t sleep_ev;
393  int rc = 0;
394 
395  if (ctx->state & BC_LINK_SUSPEND)
396  return BC_STS_IO_USER_ABORT;
397 
398  if (ctx->cin_wait_exit) {
399  ctx->cin_wait_exit = 0;
400  return BC_STS_CMD_CANCELLED;
401  }
402  crystalhd_create_event(&sleep_ev);
403  crystalhd_wait_on_event(&sleep_ev, 0, 100, rc, 0);
404  if (rc == -EINTR)
405  return BC_STS_IO_USER_ABORT;
406 
407  return BC_STS_SUCCESS;
408 }
409 
410 static enum BC_STATUS bc_cproc_hw_txdma(struct crystalhd_cmd *ctx,
411  struct crystalhd_ioctl_data *idata,
412  struct crystalhd_dio_req *dio)
413 {
414  uint32_t tx_listid = 0;
415  enum BC_STATUS sts = BC_STS_SUCCESS;
417  int rc = 0;
418 
419  if (!ctx || !idata || !dio) {
420  BCMLOG_ERR("Invalid Arg!!\n");
421  return BC_STS_INV_ARG;
422  }
423 
424  crystalhd_create_event(&event);
425 
426  ctx->tx_list_id = 0;
427  /* msleep_interruptible(2000); */
428  sts = crystalhd_hw_post_tx(&ctx->hw_ctx, dio, bc_proc_in_completion,
429  &event, &tx_listid,
430  idata->udata.u.ProcInput.Encrypted);
431 
432  while (sts == BC_STS_BUSY) {
433  sts = bc_cproc_codein_sleep(ctx);
434  if (sts != BC_STS_SUCCESS)
435  break;
436  sts = crystalhd_hw_post_tx(&ctx->hw_ctx, dio,
437  bc_proc_in_completion,
438  &event, &tx_listid,
439  idata->udata.u.ProcInput.Encrypted);
440  }
441  if (sts != BC_STS_SUCCESS) {
442  BCMLOG(BCMLOG_DBG, "_hw_txdma returning sts:%d\n", sts);
443  return sts;
444  }
445  if (ctx->cin_wait_exit)
446  ctx->cin_wait_exit = 0;
447 
448  ctx->tx_list_id = tx_listid;
449 
450  /* _post() succeeded.. wait for the completion. */
451  crystalhd_wait_on_event(&event, (dio->uinfo.ev_sts), 3000, rc, 0);
452  ctx->tx_list_id = 0;
453  if (!rc) {
454  return dio->uinfo.comp_sts;
455  } else if (rc == -EBUSY) {
456  BCMLOG(BCMLOG_DBG, "_tx_post() T/O\n");
457  sts = BC_STS_TIMEOUT;
458  } else if (rc == -EINTR) {
459  BCMLOG(BCMLOG_DBG, "Tx Wait Signal int.\n");
460  sts = BC_STS_IO_USER_ABORT;
461  } else {
462  sts = BC_STS_IO_ERROR;
463  }
464 
465  /* We are cancelling the IO from the same context as the _post().
466  * so no need to wait on the event again.. the return itself
467  * ensures the release of our resources.
468  */
469  crystalhd_hw_cancel_tx(&ctx->hw_ctx, tx_listid);
470 
471  return sts;
472 }
473 
474 /* Helper function to check on user buffers */
475 static enum BC_STATUS bc_cproc_check_inbuffs(bool pin, void *ubuff, uint32_t ub_sz,
476  uint32_t uv_off, bool en_422)
477 {
478  if (!ubuff || !ub_sz) {
479  BCMLOG_ERR("%s->Invalid Arg %p %x\n",
480  ((pin) ? "TX" : "RX"), ubuff, ub_sz);
481  return BC_STS_INV_ARG;
482  }
483 
484  /* Check for alignment */
485  if (((uintptr_t)ubuff) & 0x03) {
486  BCMLOG_ERR("%s-->Un-aligned address not implemented yet.. %p\n",
487  ((pin) ? "TX" : "RX"), ubuff);
488  return BC_STS_NOT_IMPL;
489  }
490  if (pin)
491  return BC_STS_SUCCESS;
492 
493  if (!en_422 && !uv_off) {
494  BCMLOG_ERR("Need UV offset for 420 mode.\n");
495  return BC_STS_INV_ARG;
496  }
497 
498  if (en_422 && uv_off) {
499  BCMLOG_ERR("UV offset in 422 mode ??\n");
500  return BC_STS_INV_ARG;
501  }
502 
503  return BC_STS_SUCCESS;
504 }
505 
506 static enum BC_STATUS bc_cproc_proc_input(struct crystalhd_cmd *ctx,
507  struct crystalhd_ioctl_data *idata)
508 {
509  void *ubuff;
510  uint32_t ub_sz;
511  struct crystalhd_dio_req *dio_hnd = NULL;
512  enum BC_STATUS sts = BC_STS_SUCCESS;
513 
514  if (!ctx || !idata) {
515  BCMLOG_ERR("Invalid Arg!!\n");
516  return BC_STS_INV_ARG;
517  }
518 
519  ubuff = idata->udata.u.ProcInput.pDmaBuff;
520  ub_sz = idata->udata.u.ProcInput.BuffSz;
521 
522  sts = bc_cproc_check_inbuffs(1, ubuff, ub_sz, 0, 0);
523  if (sts != BC_STS_SUCCESS)
524  return sts;
525 
526  sts = crystalhd_map_dio(ctx->adp, ubuff, ub_sz, 0, 0, 1, &dio_hnd);
527  if (sts != BC_STS_SUCCESS) {
528  BCMLOG_ERR("dio map - %d\n", sts);
529  return sts;
530  }
531 
532  if (!dio_hnd)
533  return BC_STS_ERROR;
534 
535  sts = bc_cproc_hw_txdma(ctx, idata, dio_hnd);
536 
537  crystalhd_unmap_dio(ctx->adp, dio_hnd);
538 
539  return sts;
540 }
541 
542 static enum BC_STATUS bc_cproc_add_cap_buff(struct crystalhd_cmd *ctx,
543  struct crystalhd_ioctl_data *idata)
544 {
545  void *ubuff;
546  uint32_t ub_sz, uv_off;
547  bool en_422;
548  struct crystalhd_dio_req *dio_hnd = NULL;
549  enum BC_STATUS sts = BC_STS_SUCCESS;
550 
551  if (!ctx || !idata) {
552  BCMLOG_ERR("Invalid Arg!!\n");
553  return BC_STS_INV_ARG;
554  }
555 
556  ubuff = idata->udata.u.RxBuffs.YuvBuff;
557  ub_sz = idata->udata.u.RxBuffs.YuvBuffSz;
558  uv_off = idata->udata.u.RxBuffs.UVbuffOffset;
559  en_422 = idata->udata.u.RxBuffs.b422Mode;
560 
561  sts = bc_cproc_check_inbuffs(0, ubuff, ub_sz, uv_off, en_422);
562  if (sts != BC_STS_SUCCESS)
563  return sts;
564 
565  sts = crystalhd_map_dio(ctx->adp, ubuff, ub_sz, uv_off,
566  en_422, 0, &dio_hnd);
567  if (sts != BC_STS_SUCCESS) {
568  BCMLOG_ERR("dio map - %d\n", sts);
569  return sts;
570  }
571 
572  if (!dio_hnd)
573  return BC_STS_ERROR;
574 
575  sts = crystalhd_hw_add_cap_buffer(&ctx->hw_ctx, dio_hnd, (ctx->state == BC_LINK_READY));
576  if ((sts != BC_STS_SUCCESS) && (sts != BC_STS_BUSY)) {
577  crystalhd_unmap_dio(ctx->adp, dio_hnd);
578  return sts;
579  }
580 
581  return BC_STS_SUCCESS;
582 }
583 
584 static enum BC_STATUS bc_cproc_fmt_change(struct crystalhd_cmd *ctx,
585  struct crystalhd_dio_req *dio)
586 {
587  enum BC_STATUS sts = BC_STS_SUCCESS;
588 
589  sts = crystalhd_hw_add_cap_buffer(&ctx->hw_ctx, dio, 0);
590  if (sts != BC_STS_SUCCESS)
591  return sts;
592 
593  ctx->state |= BC_LINK_FMT_CHG;
594  if (ctx->state == BC_LINK_READY)
595  sts = crystalhd_hw_start_capture(&ctx->hw_ctx);
596 
597  return sts;
598 }
599 
600 static enum BC_STATUS bc_cproc_fetch_frame(struct crystalhd_cmd *ctx,
601  struct crystalhd_ioctl_data *idata)
602 {
603  struct crystalhd_dio_req *dio = NULL;
604  enum BC_STATUS sts = BC_STS_SUCCESS;
605  struct BC_DEC_OUT_BUFF *frame;
606 
607  if (!ctx || !idata) {
608  BCMLOG_ERR("Invalid Arg!!\n");
609  return BC_STS_INV_ARG;
610  }
611 
612  if (!(ctx->state & BC_LINK_CAP_EN)) {
613  BCMLOG(BCMLOG_DBG, "Capture not enabled..%x\n", ctx->state);
614  return BC_STS_ERR_USAGE;
615  }
616 
617  frame = &idata->udata.u.DecOutData;
618 
619  sts = crystalhd_hw_get_cap_buffer(&ctx->hw_ctx, &frame->PibInfo, &dio);
620  if (sts != BC_STS_SUCCESS)
621  return (ctx->state & BC_LINK_SUSPEND) ? BC_STS_IO_USER_ABORT : sts;
622 
623  frame->Flags = dio->uinfo.comp_flags;
624 
625  if (frame->Flags & COMP_FLAG_FMT_CHANGE)
626  return bc_cproc_fmt_change(ctx, dio);
627 
628  frame->OutPutBuffs.YuvBuff = dio->uinfo.xfr_buff;
629  frame->OutPutBuffs.YuvBuffSz = dio->uinfo.xfr_len;
630  frame->OutPutBuffs.UVbuffOffset = dio->uinfo.uv_offset;
631  frame->OutPutBuffs.b422Mode = dio->uinfo.b422mode;
632 
633  frame->OutPutBuffs.YBuffDoneSz = dio->uinfo.y_done_sz;
634  frame->OutPutBuffs.UVBuffDoneSz = dio->uinfo.uv_done_sz;
635 
636  crystalhd_unmap_dio(ctx->adp, dio);
637 
638  return BC_STS_SUCCESS;
639 }
640 
641 static enum BC_STATUS bc_cproc_start_capture(struct crystalhd_cmd *ctx,
642  struct crystalhd_ioctl_data *idata)
643 {
644  ctx->state |= BC_LINK_CAP_EN;
645  if (ctx->state == BC_LINK_READY)
646  return crystalhd_hw_start_capture(&ctx->hw_ctx);
647 
648  return BC_STS_SUCCESS;
649 }
650 
651 static enum BC_STATUS bc_cproc_flush_cap_buffs(struct crystalhd_cmd *ctx,
652  struct crystalhd_ioctl_data *idata)
653 {
654  struct crystalhd_dio_req *dio = NULL;
655  enum BC_STATUS sts = BC_STS_SUCCESS;
656  struct BC_DEC_OUT_BUFF *frame;
657  uint32_t count;
658 
659  if (!ctx || !idata) {
660  BCMLOG_ERR("Invalid Arg!!\n");
661  return BC_STS_INV_ARG;
662  }
663 
664  if (!(ctx->state & BC_LINK_CAP_EN))
665  return BC_STS_ERR_USAGE;
666 
667  /* We should ack flush even when we are in paused/suspend state */
668  if (!(ctx->state & BC_LINK_READY))
669  return crystalhd_hw_stop_capture(&ctx->hw_ctx);
670 
672 
673  frame = &idata->udata.u.DecOutData;
674  for (count = 0; count < BC_RX_LIST_CNT; count++) {
675 
676  sts = crystalhd_hw_get_cap_buffer(&ctx->hw_ctx, &frame->PibInfo, &dio);
677  if (sts != BC_STS_SUCCESS)
678  break;
679 
680  crystalhd_unmap_dio(ctx->adp, dio);
681  }
682 
683  return crystalhd_hw_stop_capture(&ctx->hw_ctx);
684 }
685 
686 static enum BC_STATUS bc_cproc_get_stats(struct crystalhd_cmd *ctx,
687  struct crystalhd_ioctl_data *idata)
688 {
689  struct BC_DTS_STATS *stats;
690  struct crystalhd_hw_stats hw_stats;
691 
692  if (!ctx || !idata) {
693  BCMLOG_ERR("Invalid Arg!!\n");
694  return BC_STS_INV_ARG;
695  }
696 
697  crystalhd_hw_stats(&ctx->hw_ctx, &hw_stats);
698 
699  stats = &idata->udata.u.drvStat;
700  stats->drvRLL = hw_stats.rdyq_count;
701  stats->drvFLL = hw_stats.freeq_count;
702  stats->DrvTotalFrmDropped = hw_stats.rx_errors;
703  stats->DrvTotalHWErrs = hw_stats.rx_errors + hw_stats.tx_errors;
704  stats->intCount = hw_stats.num_interrupts;
705  stats->DrvIgnIntrCnt = hw_stats.num_interrupts -
706  hw_stats.dev_interrupts;
707  stats->TxFifoBsyCnt = hw_stats.cin_busy;
708  stats->pauseCount = hw_stats.pause_cnt;
709 
710  if (ctx->pwr_state_change)
711  stats->pwr_state_change = 1;
712  if (ctx->state & BC_LINK_PAUSED)
713  stats->DrvPauseTime = 1;
714 
715  return BC_STS_SUCCESS;
716 }
717 
718 static enum BC_STATUS bc_cproc_reset_stats(struct crystalhd_cmd *ctx,
719  struct crystalhd_ioctl_data *idata)
720 {
722 
723  return BC_STS_SUCCESS;
724 }
725 
726 static enum BC_STATUS bc_cproc_chg_clk(struct crystalhd_cmd *ctx,
727  struct crystalhd_ioctl_data *idata)
728 {
729  struct BC_CLOCK *clock;
730  uint32_t oldClk;
731  enum BC_STATUS sts = BC_STS_SUCCESS;
732 
733  if (!ctx || !idata) {
734  BCMLOG_ERR("Invalid Arg!!\n");
735  return BC_STS_INV_ARG;
736  }
737 
738  clock = &idata->udata.u.clockValue;
739  oldClk = ctx->hw_ctx.core_clock_mhz;
740  ctx->hw_ctx.core_clock_mhz = clock->clk;
741 
742  if (ctx->state & BC_LINK_READY) {
743  sts = crystalhd_hw_set_core_clock(&ctx->hw_ctx);
744  if (sts == BC_STS_CLK_NOCHG)
745  ctx->hw_ctx.core_clock_mhz = oldClk;
746  }
747 
748  clock->clk = ctx->hw_ctx.core_clock_mhz;
749 
750  return sts;
751 }
752 
753 /*=============== Cmd Proc Table.. ======================================*/
754 static const struct crystalhd_cmd_tbl g_crystalhd_cproc_tbl[] = {
755  { BCM_IOC_GET_VERSION, bc_cproc_get_version, 0},
756  { BCM_IOC_GET_HWTYPE, bc_cproc_get_hwtype, 0},
757  { BCM_IOC_REG_RD, bc_cproc_reg_rd, 0},
758  { BCM_IOC_REG_WR, bc_cproc_reg_wr, 0},
759  { BCM_IOC_FPGA_RD, bc_cproc_link_reg_rd, 0},
760  { BCM_IOC_FPGA_WR, bc_cproc_link_reg_wr, 0},
761  { BCM_IOC_MEM_RD, bc_cproc_mem_rd, 0},
762  { BCM_IOC_MEM_WR, bc_cproc_mem_wr, 0},
763  { BCM_IOC_RD_PCI_CFG, bc_cproc_cfg_rd, 0},
764  { BCM_IOC_WR_PCI_CFG, bc_cproc_cfg_wr, 1},
765  { BCM_IOC_FW_DOWNLOAD, bc_cproc_download_fw, 1},
766  { BCM_IOC_FW_CMD, bc_cproc_do_fw_cmd, 1},
767  { BCM_IOC_PROC_INPUT, bc_cproc_proc_input, 1},
768  { BCM_IOC_ADD_RXBUFFS, bc_cproc_add_cap_buff, 1},
769  { BCM_IOC_FETCH_RXBUFF, bc_cproc_fetch_frame, 1},
770  { BCM_IOC_START_RX_CAP, bc_cproc_start_capture, 1},
771  { BCM_IOC_FLUSH_RX_CAP, bc_cproc_flush_cap_buffs, 1},
772  { BCM_IOC_GET_DRV_STAT, bc_cproc_get_stats, 0},
773  { BCM_IOC_RST_DRV_STAT, bc_cproc_reset_stats, 0},
774  { BCM_IOC_NOTIFY_MODE, bc_cproc_notify_mode, 0},
775  { BCM_IOC_CHG_CLK, bc_cproc_chg_clk, 0},
776  { BCM_IOC_END, NULL},
777 };
778 
779 /*=============== Cmd Proc Functions.. ===================================*/
780 
802  struct crystalhd_ioctl_data *idata)
803 {
804  enum BC_STATUS sts = BC_STS_SUCCESS;
805 
806  if (!ctx || !idata) {
807  BCMLOG_ERR("Invalid Parameters\n");
808  return BC_STS_ERROR;
809  }
810 
811  if (ctx->state & BC_LINK_SUSPEND)
812  return BC_STS_SUCCESS;
813 
814  if (ctx->state == BC_LINK_INVALID) {
815  BCMLOG(BCMLOG_DBG, "Nothing To Do Suspend Success\n");
816  return BC_STS_SUCCESS;
817  }
818 
819  ctx->state |= BC_LINK_SUSPEND;
820 
821  bc_cproc_mark_pwr_state(ctx);
822 
823  if (ctx->state & BC_LINK_CAP_EN) {
824  sts = bc_cproc_flush_cap_buffs(ctx, idata);
825  if (sts != BC_STS_SUCCESS)
826  return sts;
827  }
828 
829  if (ctx->tx_list_id) {
830  sts = crystalhd_hw_cancel_tx(&ctx->hw_ctx, ctx->tx_list_id);
831  if (sts != BC_STS_SUCCESS)
832  return sts;
833  }
834 
835  sts = crystalhd_hw_suspend(&ctx->hw_ctx);
836  if (sts != BC_STS_SUCCESS)
837  return sts;
838 
839  BCMLOG(BCMLOG_DBG, "BCM70012 suspend success\n");
840 
841  return BC_STS_SUCCESS;
842 }
843 
861 {
862  BCMLOG(BCMLOG_DBG, "crystalhd_resume Success %x\n", ctx->state);
863 
864  bc_cproc_mark_pwr_state(ctx);
865 
866  return BC_STS_SUCCESS;
867 }
868 
882  struct crystalhd_user **user_ctx)
883 {
884  struct crystalhd_user *uc;
885 
886  if (!ctx || !user_ctx) {
887  BCMLOG_ERR("Invalid arg..\n");
888  return BC_STS_INV_ARG;
889  }
890 
891  uc = bc_cproc_get_uid(ctx);
892  if (!uc) {
893  BCMLOG(BCMLOG_INFO, "No free user context...\n");
894  return BC_STS_BUSY;
895  }
896 
897  BCMLOG(BCMLOG_INFO, "Opening new user[%x] handle\n", uc->uid);
898 
899  crystalhd_hw_open(&ctx->hw_ctx, ctx->adp);
900 
901  uc->in_use = 1;
902 
903  *user_ctx = uc;
904 
905  return BC_STS_SUCCESS;
906 }
907 
920 {
921  uint32_t mode = uc->mode;
922 
923  ctx->user[uc->uid].mode = DTS_MODE_INV;
924  ctx->user[uc->uid].in_use = 0;
925  ctx->cin_wait_exit = 1;
926  ctx->pwr_state_change = 0;
927 
928  BCMLOG(BCMLOG_INFO, "Closing user[%x] handle\n", uc->uid);
929 
930  if ((mode == DTS_DIAG_MODE) || (mode == DTS_PLAYBACK_MODE)) {
933  } else if (bc_cproc_get_user_count(ctx)) {
934  return BC_STS_SUCCESS;
935  }
936 
937  crystalhd_hw_close(&ctx->hw_ctx);
938 
939  ctx->state = BC_LINK_INVALID;
940 
941  return BC_STS_SUCCESS;
942 }
943 
955  struct crystalhd_adp *adp)
956 {
957  int i = 0;
958 
959  if (!ctx || !adp) {
960  BCMLOG_ERR("Invalid arg!!\n");
961  return BC_STS_INV_ARG;
962  }
963 
964  if (ctx->adp)
965  BCMLOG(BCMLOG_DBG, "Resetting Cmd context delete missing..\n");
966 
967  ctx->adp = adp;
968  for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
969  ctx->user[i].uid = i;
970  ctx->user[i].in_use = 0;
971  ctx->user[i].mode = DTS_MODE_INV;
972  }
973 
974  /*Open and Close the Hardware to put it in to sleep state*/
975  crystalhd_hw_open(&ctx->hw_ctx, ctx->adp);
976  crystalhd_hw_close(&ctx->hw_ctx);
977  return BC_STS_SUCCESS;
978 }
979 
990 {
991  BCMLOG(BCMLOG_DBG, "Deleting Command context..\n");
992 
993  ctx->adp = NULL;
994 
995  return BC_STS_SUCCESS;
996 }
997 
1012  struct crystalhd_user *uc)
1013 {
1014  crystalhd_cmd_proc cproc = NULL;
1015  unsigned int i, tbl_sz;
1016 
1017  if (!ctx) {
1018  BCMLOG_ERR("Invalid arg.. Cmd[%d]\n", cmd);
1019  return NULL;
1020  }
1021 
1022  if ((cmd != BCM_IOC_GET_DRV_STAT) && (ctx->state & BC_LINK_SUSPEND)) {
1023  BCMLOG_ERR("Invalid State [suspend Set].. Cmd[%d]\n", cmd);
1024  return NULL;
1025  }
1026 
1027  tbl_sz = sizeof(g_crystalhd_cproc_tbl) / sizeof(struct crystalhd_cmd_tbl);
1028  for (i = 0; i < tbl_sz; i++) {
1029  if (g_crystalhd_cproc_tbl[i].cmd_id == cmd) {
1030  if ((uc->mode == DTS_MONITOR_MODE) &&
1031  (g_crystalhd_cproc_tbl[i].block_mon)) {
1032  BCMLOG(BCMLOG_INFO, "Blocking cmd %d\n", cmd);
1033  break;
1034  }
1035  cproc = g_crystalhd_cproc_tbl[i].cmd_proc;
1036  break;
1037  }
1038  }
1039 
1040  return cproc;
1041 }
1042 
1054 {
1055  if (!ctx) {
1056  BCMLOG_ERR("Invalid arg..\n");
1057  return 0;
1058  }
1059 
1060  return crystalhd_hw_interrupt(ctx->adp, &ctx->hw_ctx);
1061 }