1 /***************************************************************************
2 * Copyright (c) 2005-2009, Broadcom Corporation.
4 * Name: crystalhd_cmds . c
7 * BCM70010 Linux driver user command interfaces.
11 **********************************************************************
12 * This file is part of the crystalhd device driver.
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.
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.
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 **********************************************************************/
27 #include "crystalhd_cmds.h"
28 #include "crystalhd_hw.h"
30 static struct crystalhd_user *bc_cproc_get_uid(struct crystalhd_cmd *ctx)
32 struct crystalhd_user *user = NULL;
35 for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
36 if (!ctx->user[i].in_use) {
45 static int bc_cproc_get_user_count(struct crystalhd_cmd *ctx)
49 for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
50 if (ctx->user[i].in_use)
57 static void bc_cproc_mark_pwr_state(struct crystalhd_cmd *ctx)
61 for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
62 if (!ctx->user[i].in_use)
64 if (ctx->user[i].mode == DTS_DIAG_MODE ||
65 ctx->user[i].mode == DTS_PLAYBACK_MODE) {
66 ctx->pwr_state_change = 1;
72 static BC_STATUS bc_cproc_notify_mode(struct crystalhd_cmd *ctx,
73 crystalhd_ioctl_data *idata)
78 BCMLOG_ERR("Invalid Arg!!\n");
79 return BC_STS_INV_ARG;
82 if (ctx->user[idata->u_id].mode != DTS_MODE_INV) {
83 BCMLOG_ERR("Close the handle first..\n");
84 return BC_STS_ERR_USAGE;
86 if (idata->udata.u.NotifyMode.Mode == DTS_MONITOR_MODE) {
87 ctx->user[idata->u_id].mode = idata->udata.u.NotifyMode.Mode;
88 return BC_STS_SUCCESS;
90 if (ctx->state != BC_LINK_INVALID) {
91 BCMLOG_ERR("Link invalid state %d\n", ctx->state);
92 return BC_STS_ERR_USAGE;
94 /* Check for duplicate playback sessions..*/
95 for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
96 if (ctx->user[i].mode == DTS_DIAG_MODE ||
97 ctx->user[i].mode == DTS_PLAYBACK_MODE) {
98 BCMLOG_ERR("multiple playback sessions are not "
100 return BC_STS_ERR_USAGE;
103 ctx->cin_wait_exit = 0;
104 ctx->user[idata->u_id].mode = idata->udata.u.NotifyMode.Mode;
105 /* Setup mmap pool for uaddr sgl mapping..*/
106 rc = crystalhd_create_dio_pool(ctx->adp, BC_LINK_MAX_SGLS);
110 /* Setup Hardware DMA rings */
111 return crystalhd_hw_setup_dma_rings(&ctx->hw_ctx);
114 static BC_STATUS bc_cproc_get_version(struct crystalhd_cmd *ctx,
115 crystalhd_ioctl_data *idata)
118 if (!ctx || !idata) {
119 BCMLOG_ERR("Invalid Arg!!\n");
120 return BC_STS_INV_ARG;
122 idata->udata.u.VerInfo.DriverMajor = crystalhd_kmod_major;
123 idata->udata.u.VerInfo.DriverMinor = crystalhd_kmod_minor;
124 idata->udata.u.VerInfo.DriverRevision = crystalhd_kmod_rev;
125 return BC_STS_SUCCESS;
129 static BC_STATUS bc_cproc_get_hwtype(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata)
131 if (!ctx || !idata) {
132 BCMLOG_ERR("Invalid Arg!!\n");
133 return BC_STS_INV_ARG;
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);
143 return BC_STS_SUCCESS;
146 static BC_STATUS bc_cproc_reg_rd(struct crystalhd_cmd *ctx,
147 crystalhd_ioctl_data *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;
156 static BC_STATUS bc_cproc_reg_wr(struct crystalhd_cmd *ctx,
157 crystalhd_ioctl_data *idata)
160 return BC_STS_INV_ARG;
162 bc_dec_reg_wr(ctx->adp, idata->udata.u.regAcc.Offset,
163 idata->udata.u.regAcc.Value);
165 return BC_STS_SUCCESS;
168 static BC_STATUS bc_cproc_link_reg_rd(struct crystalhd_cmd *ctx,
169 crystalhd_ioctl_data *idata)
172 return BC_STS_INV_ARG;
174 idata->udata.u.regAcc.Value = crystalhd_reg_rd(ctx->adp,
175 idata->udata.u.regAcc.Offset);
176 return BC_STS_SUCCESS;
179 static BC_STATUS bc_cproc_link_reg_wr(struct crystalhd_cmd *ctx,
180 crystalhd_ioctl_data *idata)
183 return BC_STS_INV_ARG;
185 crystalhd_reg_wr(ctx->adp, idata->udata.u.regAcc.Offset,
186 idata->udata.u.regAcc.Value);
188 return BC_STS_SUCCESS;
191 static BC_STATUS bc_cproc_mem_rd(struct crystalhd_cmd *ctx,
192 crystalhd_ioctl_data *idata)
194 BC_STATUS sts = BC_STS_SUCCESS;
196 if (!ctx || !idata || !idata->add_cdata)
197 return BC_STS_INV_ARG;
199 if (idata->udata.u.devMem.NumDwords > (idata->add_cdata_sz / 4)) {
200 BCMLOG_ERR("insufficient buffer\n");
201 return BC_STS_INV_ARG;
203 sts = crystalhd_mem_rd(ctx->adp, idata->udata.u.devMem.StartOff,
204 idata->udata.u.devMem.NumDwords,
205 (uint32_t *)idata->add_cdata);
210 static BC_STATUS bc_cproc_mem_wr(struct crystalhd_cmd *ctx,
211 crystalhd_ioctl_data *idata)
213 BC_STATUS sts = BC_STS_SUCCESS;
215 if (!ctx || !idata || !idata->add_cdata)
216 return BC_STS_INV_ARG;
218 if (idata->udata.u.devMem.NumDwords > (idata->add_cdata_sz / 4)) {
219 BCMLOG_ERR("insufficient buffer\n");
220 return BC_STS_INV_ARG;
223 sts = crystalhd_mem_wr(ctx->adp, idata->udata.u.devMem.StartOff,
224 idata->udata.u.devMem.NumDwords,
225 (uint32_t *)idata->add_cdata);
229 static BC_STATUS bc_cproc_cfg_rd(struct crystalhd_cmd *ctx,
230 crystalhd_ioctl_data *idata)
232 uint32_t ix, cnt, off, len;
233 BC_STATUS sts = BC_STS_SUCCESS;
237 return BC_STS_INV_ARG;
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;
244 return crystalhd_pci_cfg_rd(ctx->adp, off, len, temp);
246 /* Truncate to dword alignment..*/
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);
261 static BC_STATUS bc_cproc_cfg_wr(struct crystalhd_cmd *ctx,
262 crystalhd_ioctl_data *idata)
264 uint32_t ix, cnt, off, len;
265 BC_STATUS sts = BC_STS_SUCCESS;
269 return BC_STS_INV_ARG;
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;
276 return crystalhd_pci_cfg_wr(ctx->adp, off, len, temp[0]);
278 /* Truncate to dword alignment..*/
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);
293 static BC_STATUS bc_cproc_download_fw(struct crystalhd_cmd *ctx,
294 crystalhd_ioctl_data *idata)
296 BC_STATUS sts = BC_STS_SUCCESS;
298 if (!ctx || !idata || !idata->add_cdata || !idata->add_cdata_sz) {
299 BCMLOG_ERR("Invalid Arg!!\n");
300 return BC_STS_INV_ARG;
303 if (ctx->state != BC_LINK_INVALID) {
304 BCMLOG_ERR("Link invalid state %d\n", ctx->state);
305 return BC_STS_ERR_USAGE;
308 sts = crystalhd_download_fw(ctx->adp, (uint8_t *)idata->add_cdata,
309 idata->add_cdata_sz);
311 if (sts != BC_STS_SUCCESS) {
312 BCMLOG_ERR("Firmware Download Failure!! - %d\n", sts)
314 ctx->state |= BC_LINK_INIT;
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.
325 * Disable capture after decoder pause.
327 * First enable capture and issue decoder resume command.
329 * Abort pending input transfers and issue decoder flush command.
332 static BC_STATUS bc_cproc_do_fw_cmd(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata)
337 if (!(ctx->state & BC_LINK_INIT)) {
338 BCMLOG_ERR("Link invalid state %d\n", ctx->state);
339 return BC_STS_ERR_USAGE;
342 cmd = idata->udata.u.fwCmd.cmd;
345 if (cmd[0] == eCMD_C011_DEC_CHAN_PAUSE) {
347 ctx->state &= ~BC_LINK_PAUSED;
348 crystalhd_hw_unpause(&ctx->hw_ctx);
350 } else if (cmd[0] == eCMD_C011_DEC_CHAN_FLUSH) {
351 BCMLOG(BCMLOG_INFO, "Flush issued\n");
353 ctx->cin_wait_exit = 1;
356 sts = crystalhd_do_fw_cmd(&ctx->hw_ctx, &idata->udata.u.fwCmd);
358 if (sts != BC_STS_SUCCESS) {
359 BCMLOG(BCMLOG_INFO, "fw cmd %x failed\n", cmd[0]);
364 if (cmd[0] == eCMD_C011_DEC_CHAN_PAUSE) {
366 ctx->state |= BC_LINK_PAUSED;
367 crystalhd_hw_pause(&ctx->hw_ctx);
374 static void bc_proc_in_completion(crystalhd_dio_req *dio_hnd,
375 wait_queue_head_t *event, BC_STATUS sts)
377 if (!dio_hnd || !event) {
378 BCMLOG_ERR("Invalid Arg!!\n");
381 if (sts == BC_STS_IO_USER_ABORT)
384 dio_hnd->uinfo.comp_sts = sts;
385 dio_hnd->uinfo.ev_sts = 1;
386 crystalhd_set_event(event);
389 static BC_STATUS bc_cproc_codein_sleep(struct crystalhd_cmd *ctx)
391 wait_queue_head_t sleep_ev;
394 if (ctx->state & BC_LINK_SUSPEND)
395 return BC_STS_IO_USER_ABORT;
397 if (ctx->cin_wait_exit) {
398 ctx->cin_wait_exit = 0;
399 return BC_STS_CMD_CANCELLED;
401 crystalhd_create_event(&sleep_ev);
402 crystalhd_wait_on_event(&sleep_ev, 0, 100, rc, 0);
404 return BC_STS_IO_USER_ABORT;
406 return BC_STS_SUCCESS;
409 static BC_STATUS bc_cproc_hw_txdma(struct crystalhd_cmd *ctx,
410 crystalhd_ioctl_data *idata,
411 crystalhd_dio_req *dio)
413 uint32_t tx_listid = 0;
414 BC_STATUS sts = BC_STS_SUCCESS;
415 wait_queue_head_t event;
418 if (!ctx || !idata || !dio) {
419 BCMLOG_ERR("Invalid Arg!!\n");
420 return BC_STS_INV_ARG;
423 crystalhd_create_event(&event);
426 /* msleep_interruptible(2000); */
427 sts = crystalhd_hw_post_tx(&ctx->hw_ctx, dio, bc_proc_in_completion,
429 idata->udata.u.ProcInput.Encrypted);
431 while (sts == BC_STS_BUSY) {
432 sts = bc_cproc_codein_sleep(ctx);
433 if (sts != BC_STS_SUCCESS)
435 sts = crystalhd_hw_post_tx(&ctx->hw_ctx, dio,
436 bc_proc_in_completion,
438 idata->udata.u.ProcInput.Encrypted);
440 if (sts != BC_STS_SUCCESS) {
441 BCMLOG(BCMLOG_DBG, "_hw_txdma returning sts:%d\n", sts);
444 if (ctx->cin_wait_exit)
445 ctx->cin_wait_exit = 0;
447 ctx->tx_list_id = tx_listid;
449 /* _post() succeeded.. wait for the completion. */
450 crystalhd_wait_on_event(&event, (dio->uinfo.ev_sts), 3000, rc, 0);
453 return dio->uinfo.comp_sts;
454 } else if (rc == -EBUSY) {
455 BCMLOG(BCMLOG_DBG, "_tx_post() T/O\n");
456 sts = BC_STS_TIMEOUT;
457 } else if (rc == -EINTR) {
458 BCMLOG(BCMLOG_DBG, "Tx Wait Signal int.\n");
459 sts = BC_STS_IO_USER_ABORT;
461 sts = BC_STS_IO_ERROR;
464 /* We are cancelling the IO from the same context as the _post().
465 * so no need to wait on the event again.. the return itself
466 * ensures the release of our resources.
468 crystalhd_hw_cancel_tx(&ctx->hw_ctx, tx_listid);
473 /* Helper function to check on user buffers */
474 static BC_STATUS bc_cproc_check_inbuffs(bool pin, void *ubuff, uint32_t ub_sz,
475 uint32_t uv_off, bool en_422)
477 if (!ubuff || !ub_sz) {
478 BCMLOG_ERR("%s->Invalid Arg %p %x\n",
479 ((pin) ? "TX" : "RX"), ubuff, ub_sz);
480 return BC_STS_INV_ARG;
483 /* Check for alignment */
484 if (((uintptr_t)ubuff) & 0x03) {
485 BCMLOG_ERR("%s-->Un-aligned address not implemented yet.. %p\n",
486 ((pin) ? "TX" : "RX"), ubuff);
487 return BC_STS_NOT_IMPL;
490 return BC_STS_SUCCESS;
492 if (!en_422 && !uv_off) {
493 BCMLOG_ERR("Need UV offset for 420 mode.\n");
494 return BC_STS_INV_ARG;
497 if (en_422 && uv_off) {
498 BCMLOG_ERR("UV offset in 422 mode ??\n");
499 return BC_STS_INV_ARG;
502 return BC_STS_SUCCESS;
505 static BC_STATUS bc_cproc_proc_input(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata)
509 crystalhd_dio_req *dio_hnd = NULL;
510 BC_STATUS sts = BC_STS_SUCCESS;
512 if (!ctx || !idata) {
513 BCMLOG_ERR("Invalid Arg!!\n");
514 return BC_STS_INV_ARG;
517 ubuff = idata->udata.u.ProcInput.pDmaBuff;
518 ub_sz = idata->udata.u.ProcInput.BuffSz;
520 sts = bc_cproc_check_inbuffs(1, ubuff, ub_sz, 0, 0);
521 if (sts != BC_STS_SUCCESS)
524 sts = crystalhd_map_dio(ctx->adp, ubuff, ub_sz, 0, 0, 1, &dio_hnd);
525 if (sts != BC_STS_SUCCESS) {
526 BCMLOG_ERR("dio map - %d\n", sts);
533 sts = bc_cproc_hw_txdma(ctx, idata, dio_hnd);
535 crystalhd_unmap_dio(ctx->adp, dio_hnd);
540 static BC_STATUS bc_cproc_add_cap_buff(struct crystalhd_cmd *ctx,
541 crystalhd_ioctl_data *idata)
544 uint32_t ub_sz, uv_off;
546 crystalhd_dio_req *dio_hnd = NULL;
547 BC_STATUS sts = BC_STS_SUCCESS;
549 if (!ctx || !idata) {
550 BCMLOG_ERR("Invalid Arg!!\n");
551 return BC_STS_INV_ARG;
554 ubuff = idata->udata.u.RxBuffs.YuvBuff;
555 ub_sz = idata->udata.u.RxBuffs.YuvBuffSz;
556 uv_off = idata->udata.u.RxBuffs.UVbuffOffset;
557 en_422 = idata->udata.u.RxBuffs.b422Mode;
559 sts = bc_cproc_check_inbuffs(0, ubuff, ub_sz, uv_off, en_422);
560 if (sts != BC_STS_SUCCESS)
563 sts = crystalhd_map_dio(ctx->adp, ubuff, ub_sz, uv_off,
564 en_422, 0, &dio_hnd);
565 if (sts != BC_STS_SUCCESS) {
566 BCMLOG_ERR("dio map - %d\n", sts);
573 sts = crystalhd_hw_add_cap_buffer(&ctx->hw_ctx, dio_hnd, (ctx->state == BC_LINK_READY));
574 if ((sts != BC_STS_SUCCESS) && (sts != BC_STS_BUSY)) {
575 crystalhd_unmap_dio(ctx->adp, dio_hnd);
579 return BC_STS_SUCCESS;
582 static BC_STATUS bc_cproc_fmt_change(struct crystalhd_cmd *ctx,
583 crystalhd_dio_req *dio)
585 BC_STATUS sts = BC_STS_SUCCESS;
587 sts = crystalhd_hw_add_cap_buffer(&ctx->hw_ctx, dio, 0);
588 if (sts != BC_STS_SUCCESS)
591 ctx->state |= BC_LINK_FMT_CHG;
592 if (ctx->state == BC_LINK_READY)
593 sts = crystalhd_hw_start_capture(&ctx->hw_ctx);
598 static BC_STATUS bc_cproc_fetch_frame(struct crystalhd_cmd *ctx,
599 crystalhd_ioctl_data *idata)
601 crystalhd_dio_req *dio = NULL;
602 BC_STATUS sts = BC_STS_SUCCESS;
603 BC_DEC_OUT_BUFF *frame;
605 if (!ctx || !idata) {
606 BCMLOG_ERR("Invalid Arg!!\n");
607 return BC_STS_INV_ARG;
610 if (!(ctx->state & BC_LINK_CAP_EN)) {
611 BCMLOG(BCMLOG_DBG, "Capture not enabled..%x\n", ctx->state);
612 return BC_STS_ERR_USAGE;
615 frame = &idata->udata.u.DecOutData;
617 sts = crystalhd_hw_get_cap_buffer(&ctx->hw_ctx, &frame->PibInfo, &dio);
618 if (sts != BC_STS_SUCCESS)
619 return (ctx->state & BC_LINK_SUSPEND) ? BC_STS_IO_USER_ABORT : sts;
621 frame->Flags = dio->uinfo.comp_flags;
623 if (frame->Flags & COMP_FLAG_FMT_CHANGE)
624 return bc_cproc_fmt_change(ctx, dio);
626 frame->OutPutBuffs.YuvBuff = dio->uinfo.xfr_buff;
627 frame->OutPutBuffs.YuvBuffSz = dio->uinfo.xfr_len;
628 frame->OutPutBuffs.UVbuffOffset = dio->uinfo.uv_offset;
629 frame->OutPutBuffs.b422Mode = dio->uinfo.b422mode;
631 frame->OutPutBuffs.YBuffDoneSz = dio->uinfo.y_done_sz;
632 frame->OutPutBuffs.UVBuffDoneSz = dio->uinfo.uv_done_sz;
634 crystalhd_unmap_dio(ctx->adp, dio);
636 return BC_STS_SUCCESS;
639 static BC_STATUS bc_cproc_start_capture(struct crystalhd_cmd *ctx,
640 crystalhd_ioctl_data *idata)
642 ctx->state |= BC_LINK_CAP_EN;
643 if (ctx->state == BC_LINK_READY)
644 return crystalhd_hw_start_capture(&ctx->hw_ctx);
646 return BC_STS_SUCCESS;
649 static BC_STATUS bc_cproc_flush_cap_buffs(struct crystalhd_cmd *ctx,
650 crystalhd_ioctl_data *idata)
652 crystalhd_dio_req *dio = NULL;
653 BC_STATUS sts = BC_STS_SUCCESS;
654 BC_DEC_OUT_BUFF *frame;
657 if (!ctx || !idata) {
658 BCMLOG_ERR("Invalid Arg!!\n");
659 return BC_STS_INV_ARG;
662 if (!(ctx->state & BC_LINK_CAP_EN))
663 return BC_STS_ERR_USAGE;
665 /* We should ack flush even when we are in paused/suspend state */
666 if (!(ctx->state & BC_LINK_READY))
667 return crystalhd_hw_stop_capture(&ctx->hw_ctx);
669 ctx->state &= ~(BC_LINK_CAP_EN|BC_LINK_FMT_CHG);
671 frame = &idata->udata.u.DecOutData;
672 for (count = 0; count < BC_RX_LIST_CNT; count++) {
674 sts = crystalhd_hw_get_cap_buffer(&ctx->hw_ctx, &frame->PibInfo, &dio);
675 if (sts != BC_STS_SUCCESS)
678 crystalhd_unmap_dio(ctx->adp, dio);
681 return crystalhd_hw_stop_capture(&ctx->hw_ctx);
684 static BC_STATUS bc_cproc_get_stats(struct crystalhd_cmd *ctx,
685 crystalhd_ioctl_data *idata)
688 struct crystalhd_hw_stats hw_stats;
690 if (!ctx || !idata) {
691 BCMLOG_ERR("Invalid Arg!!\n");
692 return BC_STS_INV_ARG;
695 crystalhd_hw_stats(&ctx->hw_ctx, &hw_stats);
697 stats = &idata->udata.u.drvStat;
698 stats->drvRLL = hw_stats.rdyq_count;
699 stats->drvFLL = hw_stats.freeq_count;
700 stats->DrvTotalFrmDropped = hw_stats.rx_errors;
701 stats->DrvTotalHWErrs = hw_stats.rx_errors + hw_stats.tx_errors;
702 stats->intCount = hw_stats.num_interrupts;
703 stats->DrvIgnIntrCnt = hw_stats.num_interrupts -
704 hw_stats.dev_interrupts;
705 stats->TxFifoBsyCnt = hw_stats.cin_busy;
706 stats->pauseCount = hw_stats.pause_cnt;
708 if (ctx->pwr_state_change)
709 stats->pwr_state_change = 1;
710 if (ctx->state & BC_LINK_PAUSED)
711 stats->DrvPauseTime = 1;
713 return BC_STS_SUCCESS;
716 static BC_STATUS bc_cproc_reset_stats(struct crystalhd_cmd *ctx,
717 crystalhd_ioctl_data *idata)
719 crystalhd_hw_stats(&ctx->hw_ctx, NULL);
721 return BC_STS_SUCCESS;
724 static BC_STATUS bc_cproc_chg_clk(struct crystalhd_cmd *ctx,
725 crystalhd_ioctl_data *idata)
729 BC_STATUS sts = BC_STS_SUCCESS;
731 if (!ctx || !idata) {
732 BCMLOG_ERR("Invalid Arg!!\n");
733 return BC_STS_INV_ARG;
736 clock = &idata->udata.u.clockValue;
737 oldClk = ctx->hw_ctx.core_clock_mhz;
738 ctx->hw_ctx.core_clock_mhz = clock->clk;
740 if (ctx->state & BC_LINK_READY) {
741 sts = crystalhd_hw_set_core_clock(&ctx->hw_ctx);
742 if (sts == BC_STS_CLK_NOCHG)
743 ctx->hw_ctx.core_clock_mhz = oldClk;
746 clock->clk = ctx->hw_ctx.core_clock_mhz;
751 /*=============== Cmd Proc Table.. ======================================*/
752 static const crystalhd_cmd_tbl_t g_crystalhd_cproc_tbl[] = {
753 { BCM_IOC_GET_VERSION, bc_cproc_get_version, 0},
754 { BCM_IOC_GET_HWTYPE, bc_cproc_get_hwtype, 0},
755 { BCM_IOC_REG_RD, bc_cproc_reg_rd, 0},
756 { BCM_IOC_REG_WR, bc_cproc_reg_wr, 0},
757 { BCM_IOC_FPGA_RD, bc_cproc_link_reg_rd, 0},
758 { BCM_IOC_FPGA_WR, bc_cproc_link_reg_wr, 0},
759 { BCM_IOC_MEM_RD, bc_cproc_mem_rd, 0},
760 { BCM_IOC_MEM_WR, bc_cproc_mem_wr, 0},
761 { BCM_IOC_RD_PCI_CFG, bc_cproc_cfg_rd, 0},
762 { BCM_IOC_WR_PCI_CFG, bc_cproc_cfg_wr, 1},
763 { BCM_IOC_FW_DOWNLOAD, bc_cproc_download_fw, 1},
764 { BCM_IOC_FW_CMD, bc_cproc_do_fw_cmd, 1},
765 { BCM_IOC_PROC_INPUT, bc_cproc_proc_input, 1},
766 { BCM_IOC_ADD_RXBUFFS, bc_cproc_add_cap_buff, 1},
767 { BCM_IOC_FETCH_RXBUFF, bc_cproc_fetch_frame, 1},
768 { BCM_IOC_START_RX_CAP, bc_cproc_start_capture, 1},
769 { BCM_IOC_FLUSH_RX_CAP, bc_cproc_flush_cap_buffs, 1},
770 { BCM_IOC_GET_DRV_STAT, bc_cproc_get_stats, 0},
771 { BCM_IOC_RST_DRV_STAT, bc_cproc_reset_stats, 0},
772 { BCM_IOC_NOTIFY_MODE, bc_cproc_notify_mode, 0},
773 { BCM_IOC_CHG_CLK, bc_cproc_chg_clk, 0},
774 { BCM_IOC_END, NULL},
777 /*=============== Cmd Proc Functions.. ===================================*/
780 * crystalhd_suspend - Power management suspend request.
781 * @ctx: Command layer context.
782 * @idata: Iodata - required for internal use.
787 * 1. Set the state to Suspend.
788 * 2. Flush the Rx Buffers it will unmap all the buffers and
789 * stop the RxDMA engine.
790 * 3. Cancel The TX Io and Stop Dma Engine.
791 * 4. Put the DDR in to deep sleep.
792 * 5. Stop the hardware putting it in to Reset State.
794 * Current gstreamer frame work does not provide any power management
795 * related notification to user mode decoder plug-in. As a work-around
796 * we pass on the power mangement notification to our plug-in by completing
797 * all outstanding requests with BC_STS_IO_USER_ABORT return code.
799 BC_STATUS crystalhd_suspend(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata)
801 BC_STATUS sts = BC_STS_SUCCESS;
803 if (!ctx || !idata) {
804 BCMLOG_ERR("Invalid Parameters\n");
808 if (ctx->state & BC_LINK_SUSPEND)
809 return BC_STS_SUCCESS;
811 if (ctx->state == BC_LINK_INVALID) {
812 BCMLOG(BCMLOG_DBG, "Nothing To Do Suspend Success\n");
813 return BC_STS_SUCCESS;
816 ctx->state |= BC_LINK_SUSPEND;
818 bc_cproc_mark_pwr_state(ctx);
820 if (ctx->state & BC_LINK_CAP_EN) {
821 sts = bc_cproc_flush_cap_buffs(ctx, idata);
822 if (sts != BC_STS_SUCCESS)
826 if (ctx->tx_list_id) {
827 sts = crystalhd_hw_cancel_tx(&ctx->hw_ctx, ctx->tx_list_id);
828 if (sts != BC_STS_SUCCESS)
832 sts = crystalhd_hw_suspend(&ctx->hw_ctx);
833 if (sts != BC_STS_SUCCESS)
836 BCMLOG(BCMLOG_DBG, "BCM70012 suspend success\n");
838 return BC_STS_SUCCESS;
842 * crystalhd_resume - Resume frame capture.
843 * @ctx: Command layer contextx.
849 * Resume frame capture.
851 * PM_Resume can't resume the playback state back to pre-suspend state
852 * because we don't keep video clip related information within driver.
853 * To get back to the pre-suspend state App will re-open the device and
854 * start a new playback session from the pre-suspend clip position.
857 BC_STATUS crystalhd_resume(struct crystalhd_cmd *ctx)
859 BCMLOG(BCMLOG_DBG, "crystalhd_resume Success %x\n", ctx->state);
861 bc_cproc_mark_pwr_state(ctx);
863 return BC_STS_SUCCESS;
867 * crystalhd_user_open - Create application handle.
868 * @ctx: Command layer contextx.
869 * @user_ctx: User ID context.
874 * Creates an application specific UID and allocates
875 * application specific resources. HW layer initialization
876 * is done for the first open request.
878 BC_STATUS crystalhd_user_open(struct crystalhd_cmd *ctx,
879 struct crystalhd_user **user_ctx)
881 struct crystalhd_user *uc;
883 if (!ctx || !user_ctx) {
884 BCMLOG_ERR("Invalid arg..\n");
885 return BC_STS_INV_ARG;
888 uc = bc_cproc_get_uid(ctx);
890 BCMLOG(BCMLOG_INFO, "No free user context...\n");
894 BCMLOG(BCMLOG_INFO, "Opening new user[%x] handle\n", uc->uid);
896 crystalhd_hw_open(&ctx->hw_ctx, ctx->adp);
902 return BC_STS_SUCCESS;
906 * crystalhd_user_close - Close application handle.
907 * @ctx: Command layer contextx.
908 * @uc: User ID context.
913 * Closer aplication handle and release app specific
916 BC_STATUS crystalhd_user_close(struct crystalhd_cmd *ctx, struct crystalhd_user *uc)
918 uint32_t mode = uc->mode;
920 ctx->user[uc->uid].mode = DTS_MODE_INV;
921 ctx->user[uc->uid].in_use = 0;
922 ctx->cin_wait_exit = 1;
923 ctx->pwr_state_change = 0;
925 BCMLOG(BCMLOG_INFO, "Closing user[%x] handle\n", uc->uid);
927 if ((mode == DTS_DIAG_MODE) || (mode == DTS_PLAYBACK_MODE)) {
928 crystalhd_hw_free_dma_rings(&ctx->hw_ctx);
929 crystalhd_destroy_dio_pool(ctx->adp);
930 } else if (bc_cproc_get_user_count(ctx)) {
931 return BC_STS_SUCCESS;
934 crystalhd_hw_close(&ctx->hw_ctx);
936 ctx->state = BC_LINK_INVALID;
938 return BC_STS_SUCCESS;
942 * crystalhd_setup_cmd_context - Setup Command layer resources.
943 * @ctx: Command layer contextx.
944 * @adp: Adapter context
949 * Called at the time of driver load.
951 BC_STATUS __devinit crystalhd_setup_cmd_context(struct crystalhd_cmd *ctx,
952 struct crystalhd_adp *adp)
957 BCMLOG_ERR("Invalid arg!!\n");
958 return BC_STS_INV_ARG;
962 BCMLOG(BCMLOG_DBG, "Resetting Cmd context delete missing..\n");
965 for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
966 ctx->user[i].uid = i;
967 ctx->user[i].in_use = 0;
968 ctx->user[i].mode = DTS_MODE_INV;
971 /*Open and Close the Hardware to put it in to sleep state*/
972 crystalhd_hw_open(&ctx->hw_ctx, ctx->adp);
973 crystalhd_hw_close(&ctx->hw_ctx);
974 return BC_STS_SUCCESS;
978 * crystalhd_delete_cmd_context - Release Command layer resources.
979 * @ctx: Command layer contextx.
984 * Called at the time of driver un-load.
986 BC_STATUS __devexit crystalhd_delete_cmd_context(struct crystalhd_cmd *ctx)
988 BCMLOG(BCMLOG_DBG, "Deleting Command context..\n");
992 return BC_STS_SUCCESS;
996 * crystalhd_get_cmd_proc - Cproc table lookup.
997 * @ctx: Command layer contextx.
998 * @cmd: IOCTL command code.
999 * @uc: User ID context.
1002 * command proc function pointer
1004 * This function checks the process context, application's
1005 * mode of operation and returns the function pointer
1006 * from the cproc table.
1008 crystalhd_cmd_proc crystalhd_get_cmd_proc(struct crystalhd_cmd *ctx, uint32_t cmd,
1009 struct crystalhd_user *uc)
1011 crystalhd_cmd_proc cproc = NULL;
1012 unsigned int i, tbl_sz;
1015 BCMLOG_ERR("Invalid arg.. Cmd[%d]\n", cmd);
1019 if ((cmd != BCM_IOC_GET_DRV_STAT) && (ctx->state & BC_LINK_SUSPEND)) {
1020 BCMLOG_ERR("Invalid State [suspend Set].. Cmd[%d]\n", cmd);
1024 tbl_sz = sizeof(g_crystalhd_cproc_tbl) / sizeof(crystalhd_cmd_tbl_t);
1025 for (i = 0; i < tbl_sz; i++) {
1026 if (g_crystalhd_cproc_tbl[i].cmd_id == cmd) {
1027 if ((uc->mode == DTS_MONITOR_MODE) &&
1028 (g_crystalhd_cproc_tbl[i].block_mon)) {
1029 BCMLOG(BCMLOG_INFO, "Blocking cmd %d\n", cmd);
1032 cproc = g_crystalhd_cproc_tbl[i].cmd_proc;
1041 * crystalhd_cmd_interrupt - ISR entry point
1042 * @ctx: Command layer contextx.
1045 * TRUE: If interrupt from bcm70012 device.
1048 * ISR entry point from OS layer.
1050 bool crystalhd_cmd_interrupt(struct crystalhd_cmd *ctx)
1053 BCMLOG_ERR("Invalid arg..\n");
1057 return crystalhd_hw_interrupt(ctx->adp, &ctx->hw_ctx);