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 application 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);