Root/drivers/staging/crystalhd/crystalhd_cmds.c

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

Archive Download this file



interactive