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 enum BC_STATUS
bc_cproc_notify_mode(struct crystalhd_cmd
*ctx
,
73 struct 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 enum BC_STATUS
bc_cproc_get_version(struct crystalhd_cmd
*ctx
,
115 struct 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 enum BC_STATUS
bc_cproc_get_hwtype(struct crystalhd_cmd
*ctx
,
130 struct crystalhd_ioctl_data
*idata
)
132 if (!ctx
|| !idata
) {
133 BCMLOG_ERR("Invalid Arg!!\n");
134 return BC_STS_INV_ARG
;
137 crystalhd_pci_cfg_rd(ctx
->adp
, 0, 2,
138 (uint32_t *)&idata
->udata
.u
.hwType
.PciVenId
);
139 crystalhd_pci_cfg_rd(ctx
->adp
, 2, 2,
140 (uint32_t *)&idata
->udata
.u
.hwType
.PciDevId
);
141 crystalhd_pci_cfg_rd(ctx
->adp
, 8, 1,
142 (uint32_t *)&idata
->udata
.u
.hwType
.HwRev
);
144 return BC_STS_SUCCESS
;
147 static enum BC_STATUS
bc_cproc_reg_rd(struct crystalhd_cmd
*ctx
,
148 struct crystalhd_ioctl_data
*idata
)
151 return BC_STS_INV_ARG
;
152 idata
->udata
.u
.regAcc
.Value
= bc_dec_reg_rd(ctx
->adp
,
153 idata
->udata
.u
.regAcc
.Offset
);
154 return BC_STS_SUCCESS
;
157 static enum BC_STATUS
bc_cproc_reg_wr(struct crystalhd_cmd
*ctx
,
158 struct crystalhd_ioctl_data
*idata
)
161 return BC_STS_INV_ARG
;
163 bc_dec_reg_wr(ctx
->adp
, idata
->udata
.u
.regAcc
.Offset
,
164 idata
->udata
.u
.regAcc
.Value
);
166 return BC_STS_SUCCESS
;
169 static enum BC_STATUS
bc_cproc_link_reg_rd(struct crystalhd_cmd
*ctx
,
170 struct crystalhd_ioctl_data
*idata
)
173 return BC_STS_INV_ARG
;
175 idata
->udata
.u
.regAcc
.Value
= crystalhd_reg_rd(ctx
->adp
,
176 idata
->udata
.u
.regAcc
.Offset
);
177 return BC_STS_SUCCESS
;
180 static enum BC_STATUS
bc_cproc_link_reg_wr(struct crystalhd_cmd
*ctx
,
181 struct crystalhd_ioctl_data
*idata
)
184 return BC_STS_INV_ARG
;
186 crystalhd_reg_wr(ctx
->adp
, idata
->udata
.u
.regAcc
.Offset
,
187 idata
->udata
.u
.regAcc
.Value
);
189 return BC_STS_SUCCESS
;
192 static enum BC_STATUS
bc_cproc_mem_rd(struct crystalhd_cmd
*ctx
,
193 struct crystalhd_ioctl_data
*idata
)
195 enum BC_STATUS sts
= BC_STS_SUCCESS
;
197 if (!ctx
|| !idata
|| !idata
->add_cdata
)
198 return BC_STS_INV_ARG
;
200 if (idata
->udata
.u
.devMem
.NumDwords
> (idata
->add_cdata_sz
/ 4)) {
201 BCMLOG_ERR("insufficient buffer\n");
202 return BC_STS_INV_ARG
;
204 sts
= crystalhd_mem_rd(ctx
->adp
, idata
->udata
.u
.devMem
.StartOff
,
205 idata
->udata
.u
.devMem
.NumDwords
,
206 (uint32_t *)idata
->add_cdata
);
211 static enum BC_STATUS
bc_cproc_mem_wr(struct crystalhd_cmd
*ctx
,
212 struct crystalhd_ioctl_data
*idata
)
214 enum BC_STATUS sts
= BC_STS_SUCCESS
;
216 if (!ctx
|| !idata
|| !idata
->add_cdata
)
217 return BC_STS_INV_ARG
;
219 if (idata
->udata
.u
.devMem
.NumDwords
> (idata
->add_cdata_sz
/ 4)) {
220 BCMLOG_ERR("insufficient buffer\n");
221 return BC_STS_INV_ARG
;
224 sts
= crystalhd_mem_wr(ctx
->adp
, idata
->udata
.u
.devMem
.StartOff
,
225 idata
->udata
.u
.devMem
.NumDwords
,
226 (uint32_t *)idata
->add_cdata
);
230 static enum BC_STATUS
bc_cproc_cfg_rd(struct crystalhd_cmd
*ctx
,
231 struct crystalhd_ioctl_data
*idata
)
233 uint32_t ix
, cnt
, off
, len
;
234 enum BC_STATUS sts
= BC_STS_SUCCESS
;
238 return BC_STS_INV_ARG
;
240 temp
= (uint32_t *) idata
->udata
.u
.pciCfg
.pci_cfg_space
;
241 off
= idata
->udata
.u
.pciCfg
.Offset
;
242 len
= idata
->udata
.u
.pciCfg
.Size
;
245 return crystalhd_pci_cfg_rd(ctx
->adp
, off
, len
, temp
);
247 /* Truncate to dword alignment..*/
249 cnt
= idata
->udata
.u
.pciCfg
.Size
/ len
;
250 for (ix
= 0; ix
< cnt
; ix
++) {
251 sts
= crystalhd_pci_cfg_rd(ctx
->adp
, off
, len
, &temp
[ix
]);
252 if (sts
!= BC_STS_SUCCESS
) {
253 BCMLOG_ERR("config read : %d\n", sts
);
262 static enum BC_STATUS
bc_cproc_cfg_wr(struct crystalhd_cmd
*ctx
,
263 struct crystalhd_ioctl_data
*idata
)
265 uint32_t ix
, cnt
, off
, len
;
266 enum BC_STATUS sts
= BC_STS_SUCCESS
;
270 return BC_STS_INV_ARG
;
272 temp
= (uint32_t *) idata
->udata
.u
.pciCfg
.pci_cfg_space
;
273 off
= idata
->udata
.u
.pciCfg
.Offset
;
274 len
= idata
->udata
.u
.pciCfg
.Size
;
277 return crystalhd_pci_cfg_wr(ctx
->adp
, off
, len
, temp
[0]);
279 /* Truncate to dword alignment..*/
281 cnt
= idata
->udata
.u
.pciCfg
.Size
/ len
;
282 for (ix
= 0; ix
< cnt
; ix
++) {
283 sts
= crystalhd_pci_cfg_wr(ctx
->adp
, off
, len
, temp
[ix
]);
284 if (sts
!= BC_STS_SUCCESS
) {
285 BCMLOG_ERR("config write : %d\n", sts
);
294 static enum BC_STATUS
bc_cproc_download_fw(struct crystalhd_cmd
*ctx
,
295 struct crystalhd_ioctl_data
*idata
)
297 enum BC_STATUS sts
= BC_STS_SUCCESS
;
299 if (!ctx
|| !idata
|| !idata
->add_cdata
|| !idata
->add_cdata_sz
) {
300 BCMLOG_ERR("Invalid Arg!!\n");
301 return BC_STS_INV_ARG
;
304 if (ctx
->state
!= BC_LINK_INVALID
) {
305 BCMLOG_ERR("Link invalid state %d\n", ctx
->state
);
306 return BC_STS_ERR_USAGE
;
309 sts
= crystalhd_download_fw(ctx
->adp
, (uint8_t *)idata
->add_cdata
,
310 idata
->add_cdata_sz
);
312 if (sts
!= BC_STS_SUCCESS
) {
313 BCMLOG_ERR("Firmware Download Failure!! - %d\n", sts
);
315 ctx
->state
|= BC_LINK_INIT
;
321 * We use the FW_CMD interface to sync up playback state with application
322 * and firmware. This function will perform the required pre and post
323 * processing of the Firmware commands.
326 * Disable capture after decoder pause.
328 * First enable capture and issue decoder resume command.
330 * Abort pending input transfers and issue decoder flush command.
333 static enum BC_STATUS
bc_cproc_do_fw_cmd(struct crystalhd_cmd
*ctx
,
334 struct crystalhd_ioctl_data
*idata
)
339 if (!(ctx
->state
& BC_LINK_INIT
)) {
340 BCMLOG_ERR("Link invalid state %d\n", ctx
->state
);
341 return BC_STS_ERR_USAGE
;
344 cmd
= idata
->udata
.u
.fwCmd
.cmd
;
347 if (cmd
[0] == eCMD_C011_DEC_CHAN_PAUSE
) {
349 ctx
->state
&= ~BC_LINK_PAUSED
;
350 crystalhd_hw_unpause(&ctx
->hw_ctx
);
352 } else if (cmd
[0] == eCMD_C011_DEC_CHAN_FLUSH
) {
353 BCMLOG(BCMLOG_INFO
, "Flush issued\n");
355 ctx
->cin_wait_exit
= 1;
358 sts
= crystalhd_do_fw_cmd(&ctx
->hw_ctx
, &idata
->udata
.u
.fwCmd
);
360 if (sts
!= BC_STS_SUCCESS
) {
361 BCMLOG(BCMLOG_INFO
, "fw cmd %x failed\n", cmd
[0]);
366 if (cmd
[0] == eCMD_C011_DEC_CHAN_PAUSE
) {
368 ctx
->state
|= BC_LINK_PAUSED
;
369 crystalhd_hw_pause(&ctx
->hw_ctx
);
376 static void bc_proc_in_completion(struct crystalhd_dio_req
*dio_hnd
,
377 wait_queue_head_t
*event
, enum BC_STATUS sts
)
379 if (!dio_hnd
|| !event
) {
380 BCMLOG_ERR("Invalid Arg!!\n");
383 if (sts
== BC_STS_IO_USER_ABORT
)
386 dio_hnd
->uinfo
.comp_sts
= sts
;
387 dio_hnd
->uinfo
.ev_sts
= 1;
388 crystalhd_set_event(event
);
391 static enum BC_STATUS
bc_cproc_codein_sleep(struct crystalhd_cmd
*ctx
)
393 wait_queue_head_t sleep_ev
;
396 if (ctx
->state
& BC_LINK_SUSPEND
)
397 return BC_STS_IO_USER_ABORT
;
399 if (ctx
->cin_wait_exit
) {
400 ctx
->cin_wait_exit
= 0;
401 return BC_STS_CMD_CANCELLED
;
403 crystalhd_create_event(&sleep_ev
);
404 crystalhd_wait_on_event(&sleep_ev
, 0, 100, rc
, 0);
406 return BC_STS_IO_USER_ABORT
;
408 return BC_STS_SUCCESS
;
411 static enum BC_STATUS
bc_cproc_hw_txdma(struct crystalhd_cmd
*ctx
,
412 struct crystalhd_ioctl_data
*idata
,
413 struct crystalhd_dio_req
*dio
)
415 uint32_t tx_listid
= 0;
416 enum BC_STATUS sts
= BC_STS_SUCCESS
;
417 wait_queue_head_t event
;
420 if (!ctx
|| !idata
|| !dio
) {
421 BCMLOG_ERR("Invalid Arg!!\n");
422 return BC_STS_INV_ARG
;
425 crystalhd_create_event(&event
);
428 /* msleep_interruptible(2000); */
429 sts
= crystalhd_hw_post_tx(&ctx
->hw_ctx
, dio
, bc_proc_in_completion
,
431 idata
->udata
.u
.ProcInput
.Encrypted
);
433 while (sts
== BC_STS_BUSY
) {
434 sts
= bc_cproc_codein_sleep(ctx
);
435 if (sts
!= BC_STS_SUCCESS
)
437 sts
= crystalhd_hw_post_tx(&ctx
->hw_ctx
, dio
,
438 bc_proc_in_completion
,
440 idata
->udata
.u
.ProcInput
.Encrypted
);
442 if (sts
!= BC_STS_SUCCESS
) {
443 BCMLOG(BCMLOG_DBG
, "_hw_txdma returning sts:%d\n", sts
);
446 if (ctx
->cin_wait_exit
)
447 ctx
->cin_wait_exit
= 0;
449 ctx
->tx_list_id
= tx_listid
;
451 /* _post() succeeded.. wait for the completion. */
452 crystalhd_wait_on_event(&event
, (dio
->uinfo
.ev_sts
), 3000, rc
, 0);
455 return dio
->uinfo
.comp_sts
;
456 } else if (rc
== -EBUSY
) {
457 BCMLOG(BCMLOG_DBG
, "_tx_post() T/O\n");
458 sts
= BC_STS_TIMEOUT
;
459 } else if (rc
== -EINTR
) {
460 BCMLOG(BCMLOG_DBG
, "Tx Wait Signal int.\n");
461 sts
= BC_STS_IO_USER_ABORT
;
463 sts
= BC_STS_IO_ERROR
;
466 /* We are cancelling the IO from the same context as the _post().
467 * so no need to wait on the event again.. the return itself
468 * ensures the release of our resources.
470 crystalhd_hw_cancel_tx(&ctx
->hw_ctx
, tx_listid
);
475 /* Helper function to check on user buffers */
476 static enum BC_STATUS
bc_cproc_check_inbuffs(bool pin
, void *ubuff
, uint32_t ub_sz
,
477 uint32_t uv_off
, bool en_422
)
479 if (!ubuff
|| !ub_sz
) {
480 BCMLOG_ERR("%s->Invalid Arg %p %x\n",
481 ((pin
) ? "TX" : "RX"), ubuff
, ub_sz
);
482 return BC_STS_INV_ARG
;
485 /* Check for alignment */
486 if (((uintptr_t)ubuff
) & 0x03) {
487 BCMLOG_ERR("%s-->Un-aligned address not implemented yet.. %p\n",
488 ((pin
) ? "TX" : "RX"), ubuff
);
489 return BC_STS_NOT_IMPL
;
492 return BC_STS_SUCCESS
;
494 if (!en_422
&& !uv_off
) {
495 BCMLOG_ERR("Need UV offset for 420 mode.\n");
496 return BC_STS_INV_ARG
;
499 if (en_422
&& uv_off
) {
500 BCMLOG_ERR("UV offset in 422 mode ??\n");
501 return BC_STS_INV_ARG
;
504 return BC_STS_SUCCESS
;
507 static enum BC_STATUS
bc_cproc_proc_input(struct crystalhd_cmd
*ctx
,
508 struct crystalhd_ioctl_data
*idata
)
512 struct crystalhd_dio_req
*dio_hnd
= NULL
;
513 enum BC_STATUS sts
= BC_STS_SUCCESS
;
515 if (!ctx
|| !idata
) {
516 BCMLOG_ERR("Invalid Arg!!\n");
517 return BC_STS_INV_ARG
;
520 ubuff
= idata
->udata
.u
.ProcInput
.pDmaBuff
;
521 ub_sz
= idata
->udata
.u
.ProcInput
.BuffSz
;
523 sts
= bc_cproc_check_inbuffs(1, ubuff
, ub_sz
, 0, 0);
524 if (sts
!= BC_STS_SUCCESS
)
527 sts
= crystalhd_map_dio(ctx
->adp
, ubuff
, ub_sz
, 0, 0, 1, &dio_hnd
);
528 if (sts
!= BC_STS_SUCCESS
) {
529 BCMLOG_ERR("dio map - %d\n", sts
);
536 sts
= bc_cproc_hw_txdma(ctx
, idata
, dio_hnd
);
538 crystalhd_unmap_dio(ctx
->adp
, dio_hnd
);
543 static enum BC_STATUS
bc_cproc_add_cap_buff(struct crystalhd_cmd
*ctx
,
544 struct crystalhd_ioctl_data
*idata
)
547 uint32_t ub_sz
, uv_off
;
549 struct crystalhd_dio_req
*dio_hnd
= NULL
;
550 enum BC_STATUS sts
= BC_STS_SUCCESS
;
552 if (!ctx
|| !idata
) {
553 BCMLOG_ERR("Invalid Arg!!\n");
554 return BC_STS_INV_ARG
;
557 ubuff
= idata
->udata
.u
.RxBuffs
.YuvBuff
;
558 ub_sz
= idata
->udata
.u
.RxBuffs
.YuvBuffSz
;
559 uv_off
= idata
->udata
.u
.RxBuffs
.UVbuffOffset
;
560 en_422
= idata
->udata
.u
.RxBuffs
.b422Mode
;
562 sts
= bc_cproc_check_inbuffs(0, ubuff
, ub_sz
, uv_off
, en_422
);
563 if (sts
!= BC_STS_SUCCESS
)
566 sts
= crystalhd_map_dio(ctx
->adp
, ubuff
, ub_sz
, uv_off
,
567 en_422
, 0, &dio_hnd
);
568 if (sts
!= BC_STS_SUCCESS
) {
569 BCMLOG_ERR("dio map - %d\n", sts
);
576 sts
= crystalhd_hw_add_cap_buffer(&ctx
->hw_ctx
, dio_hnd
, (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
) ? BC_STS_IO_USER_ABORT
: sts
;
624 frame
->Flags
= dio
->uinfo
.comp_flags
;
626 if (frame
->Flags
& COMP_FLAG_FMT_CHANGE
)
627 return bc_cproc_fmt_change(ctx
, dio
);
629 frame
->OutPutBuffs
.YuvBuff
= dio
->uinfo
.xfr_buff
;
630 frame
->OutPutBuffs
.YuvBuffSz
= dio
->uinfo
.xfr_len
;
631 frame
->OutPutBuffs
.UVbuffOffset
= dio
->uinfo
.uv_offset
;
632 frame
->OutPutBuffs
.b422Mode
= dio
->uinfo
.b422mode
;
634 frame
->OutPutBuffs
.YBuffDoneSz
= dio
->uinfo
.y_done_sz
;
635 frame
->OutPutBuffs
.UVBuffDoneSz
= dio
->uinfo
.uv_done_sz
;
637 crystalhd_unmap_dio(ctx
->adp
, dio
);
639 return BC_STS_SUCCESS
;
642 static enum BC_STATUS
bc_cproc_start_capture(struct crystalhd_cmd
*ctx
,
643 struct crystalhd_ioctl_data
*idata
)
645 ctx
->state
|= BC_LINK_CAP_EN
;
646 if (ctx
->state
== BC_LINK_READY
)
647 return crystalhd_hw_start_capture(&ctx
->hw_ctx
);
649 return BC_STS_SUCCESS
;
652 static enum BC_STATUS
bc_cproc_flush_cap_buffs(struct crystalhd_cmd
*ctx
,
653 struct crystalhd_ioctl_data
*idata
)
655 struct crystalhd_dio_req
*dio
= NULL
;
656 enum BC_STATUS sts
= BC_STS_SUCCESS
;
657 struct BC_DEC_OUT_BUFF
*frame
;
660 if (!ctx
|| !idata
) {
661 BCMLOG_ERR("Invalid Arg!!\n");
662 return BC_STS_INV_ARG
;
665 if (!(ctx
->state
& BC_LINK_CAP_EN
))
666 return BC_STS_ERR_USAGE
;
668 /* We should ack flush even when we are in paused/suspend state */
669 if (!(ctx
->state
& BC_LINK_READY
))
670 return crystalhd_hw_stop_capture(&ctx
->hw_ctx
);
672 ctx
->state
&= ~(BC_LINK_CAP_EN
|BC_LINK_FMT_CHG
);
674 frame
= &idata
->udata
.u
.DecOutData
;
675 for (count
= 0; count
< BC_RX_LIST_CNT
; count
++) {
677 sts
= crystalhd_hw_get_cap_buffer(&ctx
->hw_ctx
, &frame
->PibInfo
, &dio
);
678 if (sts
!= BC_STS_SUCCESS
)
681 crystalhd_unmap_dio(ctx
->adp
, dio
);
684 return crystalhd_hw_stop_capture(&ctx
->hw_ctx
);
687 static enum BC_STATUS
bc_cproc_get_stats(struct crystalhd_cmd
*ctx
,
688 struct crystalhd_ioctl_data
*idata
)
690 struct BC_DTS_STATS
*stats
;
691 struct crystalhd_hw_stats hw_stats
;
693 if (!ctx
|| !idata
) {
694 BCMLOG_ERR("Invalid Arg!!\n");
695 return BC_STS_INV_ARG
;
698 crystalhd_hw_stats(&ctx
->hw_ctx
, &hw_stats
);
700 stats
= &idata
->udata
.u
.drvStat
;
701 stats
->drvRLL
= hw_stats
.rdyq_count
;
702 stats
->drvFLL
= hw_stats
.freeq_count
;
703 stats
->DrvTotalFrmDropped
= hw_stats
.rx_errors
;
704 stats
->DrvTotalHWErrs
= hw_stats
.rx_errors
+ hw_stats
.tx_errors
;
705 stats
->intCount
= hw_stats
.num_interrupts
;
706 stats
->DrvIgnIntrCnt
= hw_stats
.num_interrupts
-
707 hw_stats
.dev_interrupts
;
708 stats
->TxFifoBsyCnt
= hw_stats
.cin_busy
;
709 stats
->pauseCount
= hw_stats
.pause_cnt
;
711 if (ctx
->pwr_state_change
)
712 stats
->pwr_state_change
= 1;
713 if (ctx
->state
& BC_LINK_PAUSED
)
714 stats
->DrvPauseTime
= 1;
716 return BC_STS_SUCCESS
;
719 static enum BC_STATUS
bc_cproc_reset_stats(struct crystalhd_cmd
*ctx
,
720 struct crystalhd_ioctl_data
*idata
)
722 crystalhd_hw_stats(&ctx
->hw_ctx
, NULL
);
724 return BC_STS_SUCCESS
;
727 static enum BC_STATUS
bc_cproc_chg_clk(struct crystalhd_cmd
*ctx
,
728 struct crystalhd_ioctl_data
*idata
)
730 struct BC_CLOCK
*clock
;
732 enum BC_STATUS sts
= BC_STS_SUCCESS
;
734 if (!ctx
|| !idata
) {
735 BCMLOG_ERR("Invalid Arg!!\n");
736 return BC_STS_INV_ARG
;
739 clock
= &idata
->udata
.u
.clockValue
;
740 oldClk
= ctx
->hw_ctx
.core_clock_mhz
;
741 ctx
->hw_ctx
.core_clock_mhz
= clock
->clk
;
743 if (ctx
->state
& BC_LINK_READY
) {
744 sts
= crystalhd_hw_set_core_clock(&ctx
->hw_ctx
);
745 if (sts
== BC_STS_CLK_NOCHG
)
746 ctx
->hw_ctx
.core_clock_mhz
= oldClk
;
749 clock
->clk
= ctx
->hw_ctx
.core_clock_mhz
;
754 /*=============== Cmd Proc Table.. ======================================*/
755 static const struct crystalhd_cmd_tbl g_crystalhd_cproc_tbl
[] = {
756 { BCM_IOC_GET_VERSION
, bc_cproc_get_version
, 0},
757 { BCM_IOC_GET_HWTYPE
, bc_cproc_get_hwtype
, 0},
758 { BCM_IOC_REG_RD
, bc_cproc_reg_rd
, 0},
759 { BCM_IOC_REG_WR
, bc_cproc_reg_wr
, 0},
760 { BCM_IOC_FPGA_RD
, bc_cproc_link_reg_rd
, 0},
761 { BCM_IOC_FPGA_WR
, bc_cproc_link_reg_wr
, 0},
762 { BCM_IOC_MEM_RD
, bc_cproc_mem_rd
, 0},
763 { BCM_IOC_MEM_WR
, bc_cproc_mem_wr
, 0},
764 { BCM_IOC_RD_PCI_CFG
, bc_cproc_cfg_rd
, 0},
765 { BCM_IOC_WR_PCI_CFG
, bc_cproc_cfg_wr
, 1},
766 { BCM_IOC_FW_DOWNLOAD
, bc_cproc_download_fw
, 1},
767 { BCM_IOC_FW_CMD
, bc_cproc_do_fw_cmd
, 1},
768 { BCM_IOC_PROC_INPUT
, bc_cproc_proc_input
, 1},
769 { BCM_IOC_ADD_RXBUFFS
, bc_cproc_add_cap_buff
, 1},
770 { BCM_IOC_FETCH_RXBUFF
, bc_cproc_fetch_frame
, 1},
771 { BCM_IOC_START_RX_CAP
, bc_cproc_start_capture
, 1},
772 { BCM_IOC_FLUSH_RX_CAP
, bc_cproc_flush_cap_buffs
, 1},
773 { BCM_IOC_GET_DRV_STAT
, bc_cproc_get_stats
, 0},
774 { BCM_IOC_RST_DRV_STAT
, bc_cproc_reset_stats
, 0},
775 { BCM_IOC_NOTIFY_MODE
, bc_cproc_notify_mode
, 0},
776 { BCM_IOC_CHG_CLK
, bc_cproc_chg_clk
, 0},
777 { BCM_IOC_END
, NULL
},
780 /*=============== Cmd Proc Functions.. ===================================*/
783 * crystalhd_suspend - Power management suspend request.
784 * @ctx: Command layer context.
785 * @idata: Iodata - required for internal use.
790 * 1. Set the state to Suspend.
791 * 2. Flush the Rx Buffers it will unmap all the buffers and
792 * stop the RxDMA engine.
793 * 3. Cancel The TX Io and Stop Dma Engine.
794 * 4. Put the DDR in to deep sleep.
795 * 5. Stop the hardware putting it in to Reset State.
797 * Current gstreamer frame work does not provide any power management
798 * related notification to user mode decoder plug-in. As a work-around
799 * we pass on the power mangement notification to our plug-in by completing
800 * all outstanding requests with BC_STS_IO_USER_ABORT return code.
802 enum BC_STATUS
crystalhd_suspend(struct crystalhd_cmd
*ctx
,
803 struct crystalhd_ioctl_data
*idata
)
805 enum BC_STATUS sts
= BC_STS_SUCCESS
;
807 if (!ctx
|| !idata
) {
808 BCMLOG_ERR("Invalid Parameters\n");
812 if (ctx
->state
& BC_LINK_SUSPEND
)
813 return BC_STS_SUCCESS
;
815 if (ctx
->state
== BC_LINK_INVALID
) {
816 BCMLOG(BCMLOG_DBG
, "Nothing To Do Suspend Success\n");
817 return BC_STS_SUCCESS
;
820 ctx
->state
|= BC_LINK_SUSPEND
;
822 bc_cproc_mark_pwr_state(ctx
);
824 if (ctx
->state
& BC_LINK_CAP_EN
) {
825 sts
= bc_cproc_flush_cap_buffs(ctx
, idata
);
826 if (sts
!= BC_STS_SUCCESS
)
830 if (ctx
->tx_list_id
) {
831 sts
= crystalhd_hw_cancel_tx(&ctx
->hw_ctx
, ctx
->tx_list_id
);
832 if (sts
!= BC_STS_SUCCESS
)
836 sts
= crystalhd_hw_suspend(&ctx
->hw_ctx
);
837 if (sts
!= BC_STS_SUCCESS
)
840 BCMLOG(BCMLOG_DBG
, "BCM70012 suspend success\n");
842 return BC_STS_SUCCESS
;
846 * crystalhd_resume - Resume frame capture.
847 * @ctx: Command layer contextx.
853 * Resume frame capture.
855 * PM_Resume can't resume the playback state back to pre-suspend state
856 * because we don't keep video clip related information within driver.
857 * To get back to the pre-suspend state App will re-open the device and
858 * start a new playback session from the pre-suspend clip position.
861 enum BC_STATUS
crystalhd_resume(struct crystalhd_cmd
*ctx
)
863 BCMLOG(BCMLOG_DBG
, "crystalhd_resume Success %x\n", ctx
->state
);
865 bc_cproc_mark_pwr_state(ctx
);
867 return BC_STS_SUCCESS
;
871 * crystalhd_user_open - Create application handle.
872 * @ctx: Command layer contextx.
873 * @user_ctx: User ID context.
878 * Creates an application specific UID and allocates
879 * application specific resources. HW layer initialization
880 * is done for the first open request.
882 enum BC_STATUS
crystalhd_user_open(struct crystalhd_cmd
*ctx
,
883 struct crystalhd_user
**user_ctx
)
885 struct crystalhd_user
*uc
;
887 if (!ctx
|| !user_ctx
) {
888 BCMLOG_ERR("Invalid arg..\n");
889 return BC_STS_INV_ARG
;
892 uc
= bc_cproc_get_uid(ctx
);
894 BCMLOG(BCMLOG_INFO
, "No free user context...\n");
898 BCMLOG(BCMLOG_INFO
, "Opening new user[%x] handle\n", uc
->uid
);
900 crystalhd_hw_open(&ctx
->hw_ctx
, ctx
->adp
);
906 return BC_STS_SUCCESS
;
910 * crystalhd_user_close - Close application handle.
911 * @ctx: Command layer contextx.
912 * @uc: User ID context.
917 * Closer aplication handle and release app specific
920 enum BC_STATUS
crystalhd_user_close(struct crystalhd_cmd
*ctx
, struct crystalhd_user
*uc
)
922 uint32_t mode
= uc
->mode
;
924 ctx
->user
[uc
->uid
].mode
= DTS_MODE_INV
;
925 ctx
->user
[uc
->uid
].in_use
= 0;
926 ctx
->cin_wait_exit
= 1;
927 ctx
->pwr_state_change
= 0;
929 BCMLOG(BCMLOG_INFO
, "Closing user[%x] handle\n", uc
->uid
);
931 if ((mode
== DTS_DIAG_MODE
) || (mode
== DTS_PLAYBACK_MODE
)) {
932 crystalhd_hw_free_dma_rings(&ctx
->hw_ctx
);
933 crystalhd_destroy_dio_pool(ctx
->adp
);
934 } else if (bc_cproc_get_user_count(ctx
)) {
935 return BC_STS_SUCCESS
;
938 crystalhd_hw_close(&ctx
->hw_ctx
);
940 ctx
->state
= BC_LINK_INVALID
;
942 return BC_STS_SUCCESS
;
946 * crystalhd_setup_cmd_context - Setup Command layer resources.
947 * @ctx: Command layer contextx.
948 * @adp: Adapter context
953 * Called at the time of driver load.
955 enum BC_STATUS __devinit
crystalhd_setup_cmd_context(struct crystalhd_cmd
*ctx
,
956 struct crystalhd_adp
*adp
)
961 BCMLOG_ERR("Invalid arg!!\n");
962 return BC_STS_INV_ARG
;
966 BCMLOG(BCMLOG_DBG
, "Resetting Cmd context delete missing..\n");
969 for (i
= 0; i
< BC_LINK_MAX_OPENS
; i
++) {
970 ctx
->user
[i
].uid
= i
;
971 ctx
->user
[i
].in_use
= 0;
972 ctx
->user
[i
].mode
= DTS_MODE_INV
;
975 /*Open and Close the Hardware to put it in to sleep state*/
976 crystalhd_hw_open(&ctx
->hw_ctx
, ctx
->adp
);
977 crystalhd_hw_close(&ctx
->hw_ctx
);
978 return BC_STS_SUCCESS
;
982 * crystalhd_delete_cmd_context - Release Command layer resources.
983 * @ctx: Command layer contextx.
988 * Called at the time of driver un-load.
990 enum BC_STATUS __devexit
crystalhd_delete_cmd_context(struct crystalhd_cmd
*ctx
)
992 BCMLOG(BCMLOG_DBG
, "Deleting Command context..\n");
996 return BC_STS_SUCCESS
;
1000 * crystalhd_get_cmd_proc - Cproc table lookup.
1001 * @ctx: Command layer contextx.
1002 * @cmd: IOCTL command code.
1003 * @uc: User ID context.
1006 * command proc function pointer
1008 * This function checks the process context, application's
1009 * mode of operation and returns the function pointer
1010 * from the cproc table.
1012 crystalhd_cmd_proc
crystalhd_get_cmd_proc(struct crystalhd_cmd
*ctx
, uint32_t cmd
,
1013 struct crystalhd_user
*uc
)
1015 crystalhd_cmd_proc cproc
= NULL
;
1016 unsigned int i
, tbl_sz
;
1019 BCMLOG_ERR("Invalid arg.. Cmd[%d]\n", cmd
);
1023 if ((cmd
!= BCM_IOC_GET_DRV_STAT
) && (ctx
->state
& BC_LINK_SUSPEND
)) {
1024 BCMLOG_ERR("Invalid State [suspend Set].. Cmd[%d]\n", cmd
);
1028 tbl_sz
= sizeof(g_crystalhd_cproc_tbl
) / sizeof(struct crystalhd_cmd_tbl
);
1029 for (i
= 0; i
< tbl_sz
; i
++) {
1030 if (g_crystalhd_cproc_tbl
[i
].cmd_id
== cmd
) {
1031 if ((uc
->mode
== DTS_MONITOR_MODE
) &&
1032 (g_crystalhd_cproc_tbl
[i
].block_mon
)) {
1033 BCMLOG(BCMLOG_INFO
, "Blocking cmd %d\n", cmd
);
1036 cproc
= g_crystalhd_cproc_tbl
[i
].cmd_proc
;
1045 * crystalhd_cmd_interrupt - ISR entry point
1046 * @ctx: Command layer contextx.
1049 * TRUE: If interrupt from bcm70012 device.
1052 * ISR entry point from OS layer.
1054 bool crystalhd_cmd_interrupt(struct crystalhd_cmd
*ctx
)
1057 BCMLOG_ERR("Invalid arg..\n");
1061 return crystalhd_hw_interrupt(ctx
->adp
, &ctx
->hw_ctx
);