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.h"
29 static struct crystalhd_user
*bc_cproc_get_uid(struct crystalhd_cmd
*ctx
)
31 struct crystalhd_user
*user
= NULL
;
34 for (i
= 0; i
< BC_LINK_MAX_OPENS
; i
++) {
35 if (!ctx
->user
[i
].in_use
) {
44 static int bc_cproc_get_user_count(struct crystalhd_cmd
*ctx
)
48 for (i
= 0; i
< BC_LINK_MAX_OPENS
; i
++) {
49 if (ctx
->user
[i
].in_use
)
56 static void bc_cproc_mark_pwr_state(struct crystalhd_cmd
*ctx
)
60 for (i
= 0; i
< BC_LINK_MAX_OPENS
; i
++) {
61 if (!ctx
->user
[i
].in_use
)
63 if (ctx
->user
[i
].mode
== DTS_DIAG_MODE
||
64 ctx
->user
[i
].mode
== DTS_PLAYBACK_MODE
) {
65 ctx
->pwr_state_change
= 1;
71 static enum BC_STATUS
bc_cproc_notify_mode(struct crystalhd_cmd
*ctx
,
72 struct crystalhd_ioctl_data
*idata
)
77 BCMLOG_ERR("Invalid Arg!!\n");
78 return BC_STS_INV_ARG
;
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
;
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
;
89 if (ctx
->state
!= BC_LINK_INVALID
) {
90 BCMLOG_ERR("Link invalid state %d\n", ctx
->state
);
91 return BC_STS_ERR_USAGE
;
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 supported..\n");
98 return BC_STS_ERR_USAGE
;
101 ctx
->cin_wait_exit
= 0;
102 ctx
->user
[idata
->u_id
].mode
= idata
->udata
.u
.NotifyMode
.Mode
;
103 /* Setup mmap pool for uaddr sgl mapping..*/
104 rc
= crystalhd_create_dio_pool(ctx
->adp
, BC_LINK_MAX_SGLS
);
108 /* Setup Hardware DMA rings */
109 return crystalhd_hw_setup_dma_rings(&ctx
->hw_ctx
);
112 static enum BC_STATUS
bc_cproc_get_version(struct crystalhd_cmd
*ctx
,
113 struct crystalhd_ioctl_data
*idata
)
116 if (!ctx
|| !idata
) {
117 BCMLOG_ERR("Invalid Arg!!\n");
118 return BC_STS_INV_ARG
;
120 idata
->udata
.u
.VerInfo
.DriverMajor
= crystalhd_kmod_major
;
121 idata
->udata
.u
.VerInfo
.DriverMinor
= crystalhd_kmod_minor
;
122 idata
->udata
.u
.VerInfo
.DriverRevision
= crystalhd_kmod_rev
;
123 return BC_STS_SUCCESS
;
127 static enum BC_STATUS
bc_cproc_get_hwtype(struct crystalhd_cmd
*ctx
,
128 struct crystalhd_ioctl_data
*idata
)
130 if (!ctx
|| !idata
) {
131 BCMLOG_ERR("Invalid Arg!!\n");
132 return BC_STS_INV_ARG
;
135 crystalhd_pci_cfg_rd(ctx
->adp
, 0, 2,
136 (uint32_t *)&idata
->udata
.u
.hwType
.PciVenId
);
137 crystalhd_pci_cfg_rd(ctx
->adp
, 2, 2,
138 (uint32_t *)&idata
->udata
.u
.hwType
.PciDevId
);
139 crystalhd_pci_cfg_rd(ctx
->adp
, 8, 1,
140 (uint32_t *)&idata
->udata
.u
.hwType
.HwRev
);
142 return BC_STS_SUCCESS
;
145 static enum BC_STATUS
bc_cproc_reg_rd(struct crystalhd_cmd
*ctx
,
146 struct crystalhd_ioctl_data
*idata
)
149 return BC_STS_INV_ARG
;
150 idata
->udata
.u
.regAcc
.Value
= bc_dec_reg_rd(ctx
->adp
,
151 idata
->udata
.u
.regAcc
.Offset
);
152 return BC_STS_SUCCESS
;
155 static enum BC_STATUS
bc_cproc_reg_wr(struct crystalhd_cmd
*ctx
,
156 struct crystalhd_ioctl_data
*idata
)
159 return BC_STS_INV_ARG
;
161 bc_dec_reg_wr(ctx
->adp
, idata
->udata
.u
.regAcc
.Offset
,
162 idata
->udata
.u
.regAcc
.Value
);
164 return BC_STS_SUCCESS
;
167 static enum BC_STATUS
bc_cproc_link_reg_rd(struct crystalhd_cmd
*ctx
,
168 struct crystalhd_ioctl_data
*idata
)
171 return BC_STS_INV_ARG
;
173 idata
->udata
.u
.regAcc
.Value
= crystalhd_reg_rd(ctx
->adp
,
174 idata
->udata
.u
.regAcc
.Offset
);
175 return BC_STS_SUCCESS
;
178 static enum BC_STATUS
bc_cproc_link_reg_wr(struct crystalhd_cmd
*ctx
,
179 struct crystalhd_ioctl_data
*idata
)
182 return BC_STS_INV_ARG
;
184 crystalhd_reg_wr(ctx
->adp
, idata
->udata
.u
.regAcc
.Offset
,
185 idata
->udata
.u
.regAcc
.Value
);
187 return BC_STS_SUCCESS
;
190 static enum BC_STATUS
bc_cproc_mem_rd(struct crystalhd_cmd
*ctx
,
191 struct crystalhd_ioctl_data
*idata
)
193 enum BC_STATUS sts
= BC_STS_SUCCESS
;
195 if (!ctx
|| !idata
|| !idata
->add_cdata
)
196 return BC_STS_INV_ARG
;
198 if (idata
->udata
.u
.devMem
.NumDwords
> (idata
->add_cdata_sz
/ 4)) {
199 BCMLOG_ERR("insufficient buffer\n");
200 return BC_STS_INV_ARG
;
202 sts
= crystalhd_mem_rd(ctx
->adp
, idata
->udata
.u
.devMem
.StartOff
,
203 idata
->udata
.u
.devMem
.NumDwords
,
204 (uint32_t *)idata
->add_cdata
);
209 static enum BC_STATUS
bc_cproc_mem_wr(struct crystalhd_cmd
*ctx
,
210 struct crystalhd_ioctl_data
*idata
)
212 enum BC_STATUS sts
= BC_STS_SUCCESS
;
214 if (!ctx
|| !idata
|| !idata
->add_cdata
)
215 return BC_STS_INV_ARG
;
217 if (idata
->udata
.u
.devMem
.NumDwords
> (idata
->add_cdata_sz
/ 4)) {
218 BCMLOG_ERR("insufficient buffer\n");
219 return BC_STS_INV_ARG
;
222 sts
= crystalhd_mem_wr(ctx
->adp
, idata
->udata
.u
.devMem
.StartOff
,
223 idata
->udata
.u
.devMem
.NumDwords
,
224 (uint32_t *)idata
->add_cdata
);
228 static enum BC_STATUS
bc_cproc_cfg_rd(struct crystalhd_cmd
*ctx
,
229 struct crystalhd_ioctl_data
*idata
)
231 uint32_t ix
, cnt
, off
, len
;
232 enum BC_STATUS sts
= BC_STS_SUCCESS
;
236 return BC_STS_INV_ARG
;
238 temp
= (uint32_t *) idata
->udata
.u
.pciCfg
.pci_cfg_space
;
239 off
= idata
->udata
.u
.pciCfg
.Offset
;
240 len
= idata
->udata
.u
.pciCfg
.Size
;
243 return crystalhd_pci_cfg_rd(ctx
->adp
, off
, len
, temp
);
245 /* Truncate to dword alignment..*/
247 cnt
= idata
->udata
.u
.pciCfg
.Size
/ len
;
248 for (ix
= 0; ix
< cnt
; ix
++) {
249 sts
= crystalhd_pci_cfg_rd(ctx
->adp
, off
, len
, &temp
[ix
]);
250 if (sts
!= BC_STS_SUCCESS
) {
251 BCMLOG_ERR("config read : %d\n", sts
);
260 static enum BC_STATUS
bc_cproc_cfg_wr(struct crystalhd_cmd
*ctx
,
261 struct crystalhd_ioctl_data
*idata
)
263 uint32_t ix
, cnt
, off
, len
;
264 enum BC_STATUS sts
= BC_STS_SUCCESS
;
268 return BC_STS_INV_ARG
;
270 temp
= (uint32_t *) idata
->udata
.u
.pciCfg
.pci_cfg_space
;
271 off
= idata
->udata
.u
.pciCfg
.Offset
;
272 len
= idata
->udata
.u
.pciCfg
.Size
;
275 return crystalhd_pci_cfg_wr(ctx
->adp
, off
, len
, temp
[0]);
277 /* Truncate to dword alignment..*/
279 cnt
= idata
->udata
.u
.pciCfg
.Size
/ len
;
280 for (ix
= 0; ix
< cnt
; ix
++) {
281 sts
= crystalhd_pci_cfg_wr(ctx
->adp
, off
, len
, temp
[ix
]);
282 if (sts
!= BC_STS_SUCCESS
) {
283 BCMLOG_ERR("config write : %d\n", sts
);
292 static enum BC_STATUS
bc_cproc_download_fw(struct crystalhd_cmd
*ctx
,
293 struct crystalhd_ioctl_data
*idata
)
295 enum BC_STATUS sts
= BC_STS_SUCCESS
;
297 if (!ctx
|| !idata
|| !idata
->add_cdata
|| !idata
->add_cdata_sz
) {
298 BCMLOG_ERR("Invalid Arg!!\n");
299 return BC_STS_INV_ARG
;
302 if (ctx
->state
!= BC_LINK_INVALID
) {
303 BCMLOG_ERR("Link invalid state %d\n", ctx
->state
);
304 return BC_STS_ERR_USAGE
;
307 sts
= crystalhd_download_fw(ctx
->adp
, (uint8_t *)idata
->add_cdata
,
308 idata
->add_cdata_sz
);
310 if (sts
!= BC_STS_SUCCESS
)
311 BCMLOG_ERR("Firmware Download Failure!! - %d\n", sts
);
313 ctx
->state
|= BC_LINK_INIT
;
319 * We use the FW_CMD interface to sync up playback state with application
320 * and firmware. This function will perform the required pre and post
321 * processing of the Firmware commands.
324 * Disable capture after decoder pause.
326 * First enable capture and issue decoder resume command.
328 * Abort pending input transfers and issue decoder flush command.
331 static enum BC_STATUS
bc_cproc_do_fw_cmd(struct crystalhd_cmd
*ctx
,
332 struct 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(struct crystalhd_dio_req
*dio_hnd
,
375 wait_queue_head_t
*event
, enum 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 enum 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 enum BC_STATUS
bc_cproc_hw_txdma(struct crystalhd_cmd
*ctx
,
410 struct crystalhd_ioctl_data
*idata
,
411 struct crystalhd_dio_req
*dio
)
413 uint32_t tx_listid
= 0;
414 enum 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 enum BC_STATUS
bc_cproc_check_inbuffs(bool pin
, void *ubuff
,
475 uint32_t ub_sz
, 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) {
486 "%s-->Un-aligned address not implemented yet.. %p\n",
487 ((pin
) ? "TX" : "RX"), ubuff
);
488 return BC_STS_NOT_IMPL
;
491 return BC_STS_SUCCESS
;
493 if (!en_422
&& !uv_off
) {
494 BCMLOG_ERR("Need UV offset for 420 mode.\n");
495 return BC_STS_INV_ARG
;
498 if (en_422
&& uv_off
) {
499 BCMLOG_ERR("UV offset in 422 mode ??\n");
500 return BC_STS_INV_ARG
;
503 return BC_STS_SUCCESS
;
506 static enum BC_STATUS
bc_cproc_proc_input(struct crystalhd_cmd
*ctx
,
507 struct crystalhd_ioctl_data
*idata
)
511 struct crystalhd_dio_req
*dio_hnd
= NULL
;
512 enum BC_STATUS sts
= BC_STS_SUCCESS
;
514 if (!ctx
|| !idata
) {
515 BCMLOG_ERR("Invalid Arg!!\n");
516 return BC_STS_INV_ARG
;
519 ubuff
= idata
->udata
.u
.ProcInput
.pDmaBuff
;
520 ub_sz
= idata
->udata
.u
.ProcInput
.BuffSz
;
522 sts
= bc_cproc_check_inbuffs(1, ubuff
, ub_sz
, 0, 0);
523 if (sts
!= BC_STS_SUCCESS
)
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
);
535 sts
= bc_cproc_hw_txdma(ctx
, idata
, dio_hnd
);
537 crystalhd_unmap_dio(ctx
->adp
, dio_hnd
);
542 static enum BC_STATUS
bc_cproc_add_cap_buff(struct crystalhd_cmd
*ctx
,
543 struct crystalhd_ioctl_data
*idata
)
546 uint32_t ub_sz
, uv_off
;
548 struct crystalhd_dio_req
*dio_hnd
= NULL
;
549 enum BC_STATUS sts
= BC_STS_SUCCESS
;
551 if (!ctx
|| !idata
) {
552 BCMLOG_ERR("Invalid Arg!!\n");
553 return BC_STS_INV_ARG
;
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
;
561 sts
= bc_cproc_check_inbuffs(0, ubuff
, ub_sz
, uv_off
, en_422
);
562 if (sts
!= BC_STS_SUCCESS
)
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
);
575 sts
= crystalhd_hw_add_cap_buffer(&ctx
->hw_ctx
, dio_hnd
,
576 (ctx
->state
== BC_LINK_READY
));
577 if ((sts
!= BC_STS_SUCCESS
) && (sts
!= BC_STS_BUSY
)) {
578 crystalhd_unmap_dio(ctx
->adp
, dio_hnd
);
582 return BC_STS_SUCCESS
;
585 static enum BC_STATUS
bc_cproc_fmt_change(struct crystalhd_cmd
*ctx
,
586 struct crystalhd_dio_req
*dio
)
588 enum BC_STATUS sts
= BC_STS_SUCCESS
;
590 sts
= crystalhd_hw_add_cap_buffer(&ctx
->hw_ctx
, dio
, 0);
591 if (sts
!= BC_STS_SUCCESS
)
594 ctx
->state
|= BC_LINK_FMT_CHG
;
595 if (ctx
->state
== BC_LINK_READY
)
596 sts
= crystalhd_hw_start_capture(&ctx
->hw_ctx
);
601 static enum BC_STATUS
bc_cproc_fetch_frame(struct crystalhd_cmd
*ctx
,
602 struct crystalhd_ioctl_data
*idata
)
604 struct crystalhd_dio_req
*dio
= NULL
;
605 enum BC_STATUS sts
= BC_STS_SUCCESS
;
606 struct BC_DEC_OUT_BUFF
*frame
;
608 if (!ctx
|| !idata
) {
609 BCMLOG_ERR("Invalid Arg!!\n");
610 return BC_STS_INV_ARG
;
613 if (!(ctx
->state
& BC_LINK_CAP_EN
)) {
614 BCMLOG(BCMLOG_DBG
, "Capture not enabled..%x\n", ctx
->state
);
615 return BC_STS_ERR_USAGE
;
618 frame
= &idata
->udata
.u
.DecOutData
;
620 sts
= crystalhd_hw_get_cap_buffer(&ctx
->hw_ctx
, &frame
->PibInfo
, &dio
);
621 if (sts
!= BC_STS_SUCCESS
)
622 return (ctx
->state
& BC_LINK_SUSPEND
) ?
623 BC_STS_IO_USER_ABORT
: sts
;
625 frame
->Flags
= dio
->uinfo
.comp_flags
;
627 if (frame
->Flags
& COMP_FLAG_FMT_CHANGE
)
628 return bc_cproc_fmt_change(ctx
, dio
);
630 frame
->OutPutBuffs
.YuvBuff
= dio
->uinfo
.xfr_buff
;
631 frame
->OutPutBuffs
.YuvBuffSz
= dio
->uinfo
.xfr_len
;
632 frame
->OutPutBuffs
.UVbuffOffset
= dio
->uinfo
.uv_offset
;
633 frame
->OutPutBuffs
.b422Mode
= dio
->uinfo
.b422mode
;
635 frame
->OutPutBuffs
.YBuffDoneSz
= dio
->uinfo
.y_done_sz
;
636 frame
->OutPutBuffs
.UVBuffDoneSz
= dio
->uinfo
.uv_done_sz
;
638 crystalhd_unmap_dio(ctx
->adp
, dio
);
640 return BC_STS_SUCCESS
;
643 static enum BC_STATUS
bc_cproc_start_capture(struct crystalhd_cmd
*ctx
,
644 struct crystalhd_ioctl_data
*idata
)
646 ctx
->state
|= BC_LINK_CAP_EN
;
647 if (ctx
->state
== BC_LINK_READY
)
648 return crystalhd_hw_start_capture(&ctx
->hw_ctx
);
650 return BC_STS_SUCCESS
;
653 static enum BC_STATUS
bc_cproc_flush_cap_buffs(struct crystalhd_cmd
*ctx
,
654 struct crystalhd_ioctl_data
*idata
)
656 struct crystalhd_dio_req
*dio
= NULL
;
657 enum BC_STATUS sts
= BC_STS_SUCCESS
;
658 struct BC_DEC_OUT_BUFF
*frame
;
661 if (!ctx
|| !idata
) {
662 BCMLOG_ERR("Invalid Arg!!\n");
663 return BC_STS_INV_ARG
;
666 if (!(ctx
->state
& BC_LINK_CAP_EN
))
667 return BC_STS_ERR_USAGE
;
669 /* We should ack flush even when we are in paused/suspend state */
670 if (!(ctx
->state
& BC_LINK_READY
))
671 return crystalhd_hw_stop_capture(&ctx
->hw_ctx
);
673 ctx
->state
&= ~(BC_LINK_CAP_EN
|BC_LINK_FMT_CHG
);
675 frame
= &idata
->udata
.u
.DecOutData
;
676 for (count
= 0; count
< BC_RX_LIST_CNT
; count
++) {
678 sts
= crystalhd_hw_get_cap_buffer(&ctx
->hw_ctx
,
679 &frame
->PibInfo
, &dio
);
680 if (sts
!= BC_STS_SUCCESS
)
683 crystalhd_unmap_dio(ctx
->adp
, dio
);
686 return crystalhd_hw_stop_capture(&ctx
->hw_ctx
);
689 static enum BC_STATUS
bc_cproc_get_stats(struct crystalhd_cmd
*ctx
,
690 struct crystalhd_ioctl_data
*idata
)
692 struct BC_DTS_STATS
*stats
;
693 struct crystalhd_hw_stats hw_stats
;
695 if (!ctx
|| !idata
) {
696 BCMLOG_ERR("Invalid Arg!!\n");
697 return BC_STS_INV_ARG
;
700 crystalhd_hw_stats(&ctx
->hw_ctx
, &hw_stats
);
702 stats
= &idata
->udata
.u
.drvStat
;
703 stats
->drvRLL
= hw_stats
.rdyq_count
;
704 stats
->drvFLL
= hw_stats
.freeq_count
;
705 stats
->DrvTotalFrmDropped
= hw_stats
.rx_errors
;
706 stats
->DrvTotalHWErrs
= hw_stats
.rx_errors
+ hw_stats
.tx_errors
;
707 stats
->intCount
= hw_stats
.num_interrupts
;
708 stats
->DrvIgnIntrCnt
= hw_stats
.num_interrupts
-
709 hw_stats
.dev_interrupts
;
710 stats
->TxFifoBsyCnt
= hw_stats
.cin_busy
;
711 stats
->pauseCount
= hw_stats
.pause_cnt
;
713 if (ctx
->pwr_state_change
)
714 stats
->pwr_state_change
= 1;
715 if (ctx
->state
& BC_LINK_PAUSED
)
716 stats
->DrvPauseTime
= 1;
718 return BC_STS_SUCCESS
;
721 static enum BC_STATUS
bc_cproc_reset_stats(struct crystalhd_cmd
*ctx
,
722 struct crystalhd_ioctl_data
*idata
)
724 crystalhd_hw_stats(&ctx
->hw_ctx
, NULL
);
726 return BC_STS_SUCCESS
;
729 static enum BC_STATUS
bc_cproc_chg_clk(struct crystalhd_cmd
*ctx
,
730 struct crystalhd_ioctl_data
*idata
)
732 struct BC_CLOCK
*clock
;
734 enum BC_STATUS sts
= BC_STS_SUCCESS
;
736 if (!ctx
|| !idata
) {
737 BCMLOG_ERR("Invalid Arg!!\n");
738 return BC_STS_INV_ARG
;
741 clock
= &idata
->udata
.u
.clockValue
;
742 oldClk
= ctx
->hw_ctx
.core_clock_mhz
;
743 ctx
->hw_ctx
.core_clock_mhz
= clock
->clk
;
745 if (ctx
->state
& BC_LINK_READY
) {
746 sts
= crystalhd_hw_set_core_clock(&ctx
->hw_ctx
);
747 if (sts
== BC_STS_CLK_NOCHG
)
748 ctx
->hw_ctx
.core_clock_mhz
= oldClk
;
751 clock
->clk
= ctx
->hw_ctx
.core_clock_mhz
;
756 /*=============== Cmd Proc Table.. ======================================*/
757 static const struct crystalhd_cmd_tbl g_crystalhd_cproc_tbl
[] = {
758 { BCM_IOC_GET_VERSION
, bc_cproc_get_version
, 0},
759 { BCM_IOC_GET_HWTYPE
, bc_cproc_get_hwtype
, 0},
760 { BCM_IOC_REG_RD
, bc_cproc_reg_rd
, 0},
761 { BCM_IOC_REG_WR
, bc_cproc_reg_wr
, 0},
762 { BCM_IOC_FPGA_RD
, bc_cproc_link_reg_rd
, 0},
763 { BCM_IOC_FPGA_WR
, bc_cproc_link_reg_wr
, 0},
764 { BCM_IOC_MEM_RD
, bc_cproc_mem_rd
, 0},
765 { BCM_IOC_MEM_WR
, bc_cproc_mem_wr
, 0},
766 { BCM_IOC_RD_PCI_CFG
, bc_cproc_cfg_rd
, 0},
767 { BCM_IOC_WR_PCI_CFG
, bc_cproc_cfg_wr
, 1},
768 { BCM_IOC_FW_DOWNLOAD
, bc_cproc_download_fw
, 1},
769 { BCM_IOC_FW_CMD
, bc_cproc_do_fw_cmd
, 1},
770 { BCM_IOC_PROC_INPUT
, bc_cproc_proc_input
, 1},
771 { BCM_IOC_ADD_RXBUFFS
, bc_cproc_add_cap_buff
, 1},
772 { BCM_IOC_FETCH_RXBUFF
, bc_cproc_fetch_frame
, 1},
773 { BCM_IOC_START_RX_CAP
, bc_cproc_start_capture
, 1},
774 { BCM_IOC_FLUSH_RX_CAP
, bc_cproc_flush_cap_buffs
, 1},
775 { BCM_IOC_GET_DRV_STAT
, bc_cproc_get_stats
, 0},
776 { BCM_IOC_RST_DRV_STAT
, bc_cproc_reset_stats
, 0},
777 { BCM_IOC_NOTIFY_MODE
, bc_cproc_notify_mode
, 0},
778 { BCM_IOC_CHG_CLK
, bc_cproc_chg_clk
, 0},
779 { BCM_IOC_END
, NULL
},
782 /*=============== Cmd Proc Functions.. ===================================*/
785 * crystalhd_suspend - Power management suspend request.
786 * @ctx: Command layer context.
787 * @idata: Iodata - required for internal use.
792 * 1. Set the state to Suspend.
793 * 2. Flush the Rx Buffers it will unmap all the buffers and
794 * stop the RxDMA engine.
795 * 3. Cancel The TX Io and Stop Dma Engine.
796 * 4. Put the DDR in to deep sleep.
797 * 5. Stop the hardware putting it in to Reset State.
799 * Current gstreamer frame work does not provide any power management
800 * related notification to user mode decoder plug-in. As a work-around
801 * we pass on the power mangement notification to our plug-in by completing
802 * all outstanding requests with BC_STS_IO_USER_ABORT return code.
804 enum BC_STATUS
crystalhd_suspend(struct crystalhd_cmd
*ctx
,
805 struct crystalhd_ioctl_data
*idata
)
807 enum BC_STATUS sts
= BC_STS_SUCCESS
;
809 if (!ctx
|| !idata
) {
810 BCMLOG_ERR("Invalid Parameters\n");
814 if (ctx
->state
& BC_LINK_SUSPEND
)
815 return BC_STS_SUCCESS
;
817 if (ctx
->state
== BC_LINK_INVALID
) {
818 BCMLOG(BCMLOG_DBG
, "Nothing To Do Suspend Success\n");
819 return BC_STS_SUCCESS
;
822 ctx
->state
|= BC_LINK_SUSPEND
;
824 bc_cproc_mark_pwr_state(ctx
);
826 if (ctx
->state
& BC_LINK_CAP_EN
) {
827 sts
= bc_cproc_flush_cap_buffs(ctx
, idata
);
828 if (sts
!= BC_STS_SUCCESS
)
832 if (ctx
->tx_list_id
) {
833 sts
= crystalhd_hw_cancel_tx(&ctx
->hw_ctx
, ctx
->tx_list_id
);
834 if (sts
!= BC_STS_SUCCESS
)
838 sts
= crystalhd_hw_suspend(&ctx
->hw_ctx
);
839 if (sts
!= BC_STS_SUCCESS
)
842 BCMLOG(BCMLOG_DBG
, "BCM70012 suspend success\n");
844 return BC_STS_SUCCESS
;
848 * crystalhd_resume - Resume frame capture.
849 * @ctx: Command layer contextx.
855 * Resume frame capture.
857 * PM_Resume can't resume the playback state back to pre-suspend state
858 * because we don't keep video clip related information within driver.
859 * To get back to the pre-suspend state App will re-open the device and
860 * start a new playback session from the pre-suspend clip position.
863 enum BC_STATUS
crystalhd_resume(struct crystalhd_cmd
*ctx
)
865 BCMLOG(BCMLOG_DBG
, "crystalhd_resume Success %x\n", ctx
->state
);
867 bc_cproc_mark_pwr_state(ctx
);
869 return BC_STS_SUCCESS
;
873 * crystalhd_user_open - Create application handle.
874 * @ctx: Command layer contextx.
875 * @user_ctx: User ID context.
880 * Creates an application specific UID and allocates
881 * application specific resources. HW layer initialization
882 * is done for the first open request.
884 enum BC_STATUS
crystalhd_user_open(struct crystalhd_cmd
*ctx
,
885 struct crystalhd_user
**user_ctx
)
887 struct crystalhd_user
*uc
;
889 if (!ctx
|| !user_ctx
) {
890 BCMLOG_ERR("Invalid arg..\n");
891 return BC_STS_INV_ARG
;
894 uc
= bc_cproc_get_uid(ctx
);
896 BCMLOG(BCMLOG_INFO
, "No free user context...\n");
900 BCMLOG(BCMLOG_INFO
, "Opening new user[%x] handle\n", uc
->uid
);
902 crystalhd_hw_open(&ctx
->hw_ctx
, ctx
->adp
);
908 return BC_STS_SUCCESS
;
912 * crystalhd_user_close - Close application handle.
913 * @ctx: Command layer contextx.
914 * @uc: User ID context.
919 * Closer application handle and release app specific
922 enum BC_STATUS
crystalhd_user_close(struct crystalhd_cmd
*ctx
,
923 struct crystalhd_user
*uc
)
925 uint32_t mode
= uc
->mode
;
927 ctx
->user
[uc
->uid
].mode
= DTS_MODE_INV
;
928 ctx
->user
[uc
->uid
].in_use
= 0;
929 ctx
->cin_wait_exit
= 1;
930 ctx
->pwr_state_change
= 0;
932 BCMLOG(BCMLOG_INFO
, "Closing user[%x] handle\n", uc
->uid
);
934 if ((mode
== DTS_DIAG_MODE
) || (mode
== DTS_PLAYBACK_MODE
)) {
935 crystalhd_hw_free_dma_rings(&ctx
->hw_ctx
);
936 crystalhd_destroy_dio_pool(ctx
->adp
);
937 } else if (bc_cproc_get_user_count(ctx
)) {
938 return BC_STS_SUCCESS
;
941 crystalhd_hw_close(&ctx
->hw_ctx
);
943 ctx
->state
= BC_LINK_INVALID
;
945 return BC_STS_SUCCESS
;
949 * crystalhd_setup_cmd_context - Setup Command layer resources.
950 * @ctx: Command layer contextx.
951 * @adp: Adapter context
956 * Called at the time of driver load.
958 enum BC_STATUS
crystalhd_setup_cmd_context(struct crystalhd_cmd
*ctx
,
959 struct crystalhd_adp
*adp
)
964 BCMLOG_ERR("Invalid arg!!\n");
965 return BC_STS_INV_ARG
;
969 BCMLOG(BCMLOG_DBG
, "Resetting Cmd context delete missing..\n");
972 for (i
= 0; i
< BC_LINK_MAX_OPENS
; i
++) {
973 ctx
->user
[i
].uid
= i
;
974 ctx
->user
[i
].in_use
= 0;
975 ctx
->user
[i
].mode
= DTS_MODE_INV
;
978 /*Open and Close the Hardware to put it in to sleep state*/
979 crystalhd_hw_open(&ctx
->hw_ctx
, ctx
->adp
);
980 crystalhd_hw_close(&ctx
->hw_ctx
);
981 return BC_STS_SUCCESS
;
985 * crystalhd_delete_cmd_context - Release Command layer resources.
986 * @ctx: Command layer contextx.
991 * Called at the time of driver un-load.
993 enum BC_STATUS
crystalhd_delete_cmd_context(struct crystalhd_cmd
*ctx
)
995 BCMLOG(BCMLOG_DBG
, "Deleting Command context..\n");
999 return BC_STS_SUCCESS
;
1003 * crystalhd_get_cmd_proc - Cproc table lookup.
1004 * @ctx: Command layer contextx.
1005 * @cmd: IOCTL command code.
1006 * @uc: User ID context.
1009 * command proc function pointer
1011 * This function checks the process context, application's
1012 * mode of operation and returns the function pointer
1013 * from the cproc table.
1015 crystalhd_cmd_proc
crystalhd_get_cmd_proc(struct crystalhd_cmd
*ctx
,
1016 uint32_t cmd
, struct crystalhd_user
*uc
)
1018 crystalhd_cmd_proc cproc
= NULL
;
1019 unsigned int i
, tbl_sz
;
1022 BCMLOG_ERR("Invalid arg.. Cmd[%d]\n", cmd
);
1026 if ((cmd
!= BCM_IOC_GET_DRV_STAT
) && (ctx
->state
& BC_LINK_SUSPEND
)) {
1027 BCMLOG_ERR("Invalid State [suspend Set].. Cmd[%d]\n", cmd
);
1031 tbl_sz
= sizeof(g_crystalhd_cproc_tbl
) /
1032 sizeof(struct crystalhd_cmd_tbl
);
1033 for (i
= 0; i
< tbl_sz
; i
++) {
1034 if (g_crystalhd_cproc_tbl
[i
].cmd_id
== cmd
) {
1035 if ((uc
->mode
== DTS_MONITOR_MODE
) &&
1036 (g_crystalhd_cproc_tbl
[i
].block_mon
)) {
1037 BCMLOG(BCMLOG_INFO
, "Blocking cmd %d\n", cmd
);
1040 cproc
= g_crystalhd_cproc_tbl
[i
].cmd_proc
;
1049 * crystalhd_cmd_interrupt - ISR entry point
1050 * @ctx: Command layer contextx.
1053 * TRUE: If interrupt from bcm70012 device.
1056 * ISR entry point from OS layer.
1058 bool crystalhd_cmd_interrupt(struct crystalhd_cmd
*ctx
)
1061 BCMLOG_ERR("Invalid arg..\n");
1065 return crystalhd_hw_interrupt(ctx
->adp
, &ctx
->hw_ctx
);