brcmfmac: remove unnecessary EXPORT_SYMBOL() usage
[deliverable/linux.git] / 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
29 static 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
44 static 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
56 static 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
71 static 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 supported..\n");
98 return BC_STS_ERR_USAGE;
99 }
100 }
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);
105 if (rc)
106 return BC_STS_ERROR;
107
108 /* Setup Hardware DMA rings */
109 return crystalhd_hw_setup_dma_rings(&ctx->hw_ctx);
110 }
111
112 static enum BC_STATUS bc_cproc_get_version(struct crystalhd_cmd *ctx,
113 struct crystalhd_ioctl_data *idata)
114 {
115
116 if (!ctx || !idata) {
117 BCMLOG_ERR("Invalid Arg!!\n");
118 return BC_STS_INV_ARG;
119 }
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;
124 }
125
126
127 static enum BC_STATUS bc_cproc_get_hwtype(struct crystalhd_cmd *ctx,
128 struct crystalhd_ioctl_data *idata)
129 {
130 if (!ctx || !idata) {
131 BCMLOG_ERR("Invalid Arg!!\n");
132 return BC_STS_INV_ARG;
133 }
134
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);
141
142 return BC_STS_SUCCESS;
143 }
144
145 static enum BC_STATUS bc_cproc_reg_rd(struct crystalhd_cmd *ctx,
146 struct crystalhd_ioctl_data *idata)
147 {
148 if (!ctx || !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;
153 }
154
155 static enum BC_STATUS bc_cproc_reg_wr(struct crystalhd_cmd *ctx,
156 struct crystalhd_ioctl_data *idata)
157 {
158 if (!ctx || !idata)
159 return BC_STS_INV_ARG;
160
161 bc_dec_reg_wr(ctx->adp, idata->udata.u.regAcc.Offset,
162 idata->udata.u.regAcc.Value);
163
164 return BC_STS_SUCCESS;
165 }
166
167 static enum BC_STATUS bc_cproc_link_reg_rd(struct crystalhd_cmd *ctx,
168 struct crystalhd_ioctl_data *idata)
169 {
170 if (!ctx || !idata)
171 return BC_STS_INV_ARG;
172
173 idata->udata.u.regAcc.Value = crystalhd_reg_rd(ctx->adp,
174 idata->udata.u.regAcc.Offset);
175 return BC_STS_SUCCESS;
176 }
177
178 static enum BC_STATUS bc_cproc_link_reg_wr(struct crystalhd_cmd *ctx,
179 struct crystalhd_ioctl_data *idata)
180 {
181 if (!ctx || !idata)
182 return BC_STS_INV_ARG;
183
184 crystalhd_reg_wr(ctx->adp, idata->udata.u.regAcc.Offset,
185 idata->udata.u.regAcc.Value);
186
187 return BC_STS_SUCCESS;
188 }
189
190 static enum BC_STATUS bc_cproc_mem_rd(struct crystalhd_cmd *ctx,
191 struct crystalhd_ioctl_data *idata)
192 {
193 enum BC_STATUS sts = BC_STS_SUCCESS;
194
195 if (!ctx || !idata || !idata->add_cdata)
196 return BC_STS_INV_ARG;
197
198 if (idata->udata.u.devMem.NumDwords > (idata->add_cdata_sz / 4)) {
199 BCMLOG_ERR("insufficient buffer\n");
200 return BC_STS_INV_ARG;
201 }
202 sts = crystalhd_mem_rd(ctx->adp, idata->udata.u.devMem.StartOff,
203 idata->udata.u.devMem.NumDwords,
204 (uint32_t *)idata->add_cdata);
205 return sts;
206
207 }
208
209 static enum BC_STATUS bc_cproc_mem_wr(struct crystalhd_cmd *ctx,
210 struct crystalhd_ioctl_data *idata)
211 {
212 enum BC_STATUS sts = BC_STS_SUCCESS;
213
214 if (!ctx || !idata || !idata->add_cdata)
215 return BC_STS_INV_ARG;
216
217 if (idata->udata.u.devMem.NumDwords > (idata->add_cdata_sz / 4)) {
218 BCMLOG_ERR("insufficient buffer\n");
219 return BC_STS_INV_ARG;
220 }
221
222 sts = crystalhd_mem_wr(ctx->adp, idata->udata.u.devMem.StartOff,
223 idata->udata.u.devMem.NumDwords,
224 (uint32_t *)idata->add_cdata);
225 return sts;
226 }
227
228 static enum BC_STATUS bc_cproc_cfg_rd(struct crystalhd_cmd *ctx,
229 struct crystalhd_ioctl_data *idata)
230 {
231 uint32_t ix, cnt, off, len;
232 enum BC_STATUS sts = BC_STS_SUCCESS;
233 uint32_t *temp;
234
235 if (!ctx || !idata)
236 return BC_STS_INV_ARG;
237
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;
241
242 if (len <= 4)
243 return crystalhd_pci_cfg_rd(ctx->adp, off, len, temp);
244
245 /* Truncate to dword alignment..*/
246 len = 4;
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);
252 return sts;
253 }
254 off += len;
255 }
256
257 return sts;
258 }
259
260 static enum BC_STATUS bc_cproc_cfg_wr(struct crystalhd_cmd *ctx,
261 struct crystalhd_ioctl_data *idata)
262 {
263 uint32_t ix, cnt, off, len;
264 enum BC_STATUS sts = BC_STS_SUCCESS;
265 uint32_t *temp;
266
267 if (!ctx || !idata)
268 return BC_STS_INV_ARG;
269
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;
273
274 if (len <= 4)
275 return crystalhd_pci_cfg_wr(ctx->adp, off, len, temp[0]);
276
277 /* Truncate to dword alignment..*/
278 len = 4;
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);
284 return sts;
285 }
286 off += len;
287 }
288
289 return sts;
290 }
291
292 static enum BC_STATUS bc_cproc_download_fw(struct crystalhd_cmd *ctx,
293 struct crystalhd_ioctl_data *idata)
294 {
295 enum BC_STATUS sts = BC_STS_SUCCESS;
296
297 if (!ctx || !idata || !idata->add_cdata || !idata->add_cdata_sz) {
298 BCMLOG_ERR("Invalid Arg!!\n");
299 return BC_STS_INV_ARG;
300 }
301
302 if (ctx->state != BC_LINK_INVALID) {
303 BCMLOG_ERR("Link invalid state %d\n", ctx->state);
304 return BC_STS_ERR_USAGE;
305 }
306
307 sts = crystalhd_download_fw(ctx->adp, (uint8_t *)idata->add_cdata,
308 idata->add_cdata_sz);
309
310 if (sts != BC_STS_SUCCESS)
311 BCMLOG_ERR("Firmware Download Failure!! - %d\n", sts);
312 else
313 ctx->state |= BC_LINK_INIT;
314
315 return sts;
316 }
317
318 /*
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.
322 *
323 * Pause -
324 * Disable capture after decoder pause.
325 * Resume -
326 * First enable capture and issue decoder resume command.
327 * Flush -
328 * Abort pending input transfers and issue decoder flush command.
329 *
330 */
331 static enum BC_STATUS bc_cproc_do_fw_cmd(struct crystalhd_cmd *ctx,
332 struct crystalhd_ioctl_data *idata)
333 {
334 enum BC_STATUS sts;
335 uint32_t *cmd;
336
337 if (!(ctx->state & BC_LINK_INIT)) {
338 BCMLOG_ERR("Link invalid state %d\n", ctx->state);
339 return BC_STS_ERR_USAGE;
340 }
341
342 cmd = idata->udata.u.fwCmd.cmd;
343
344 /* Pre-Process */
345 if (cmd[0] == eCMD_C011_DEC_CHAN_PAUSE) {
346 if (!cmd[3]) {
347 ctx->state &= ~BC_LINK_PAUSED;
348 crystalhd_hw_unpause(&ctx->hw_ctx);
349 }
350 } else if (cmd[0] == eCMD_C011_DEC_CHAN_FLUSH) {
351 BCMLOG(BCMLOG_INFO, "Flush issued\n");
352 if (cmd[3])
353 ctx->cin_wait_exit = 1;
354 }
355
356 sts = crystalhd_do_fw_cmd(&ctx->hw_ctx, &idata->udata.u.fwCmd);
357
358 if (sts != BC_STS_SUCCESS) {
359 BCMLOG(BCMLOG_INFO, "fw cmd %x failed\n", cmd[0]);
360 return sts;
361 }
362
363 /* Post-Process */
364 if (cmd[0] == eCMD_C011_DEC_CHAN_PAUSE) {
365 if (cmd[3]) {
366 ctx->state |= BC_LINK_PAUSED;
367 crystalhd_hw_pause(&ctx->hw_ctx);
368 }
369 }
370
371 return sts;
372 }
373
374 static void bc_proc_in_completion(struct crystalhd_dio_req *dio_hnd,
375 wait_queue_head_t *event, enum BC_STATUS sts)
376 {
377 if (!dio_hnd || !event) {
378 BCMLOG_ERR("Invalid Arg!!\n");
379 return;
380 }
381 if (sts == BC_STS_IO_USER_ABORT)
382 return;
383
384 dio_hnd->uinfo.comp_sts = sts;
385 dio_hnd->uinfo.ev_sts = 1;
386 crystalhd_set_event(event);
387 }
388
389 static enum BC_STATUS bc_cproc_codein_sleep(struct crystalhd_cmd *ctx)
390 {
391 wait_queue_head_t sleep_ev;
392 int rc = 0;
393
394 if (ctx->state & BC_LINK_SUSPEND)
395 return BC_STS_IO_USER_ABORT;
396
397 if (ctx->cin_wait_exit) {
398 ctx->cin_wait_exit = 0;
399 return BC_STS_CMD_CANCELLED;
400 }
401 crystalhd_create_event(&sleep_ev);
402 crystalhd_wait_on_event(&sleep_ev, 0, 100, rc, 0);
403 if (rc == -EINTR)
404 return BC_STS_IO_USER_ABORT;
405
406 return BC_STS_SUCCESS;
407 }
408
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)
412 {
413 uint32_t tx_listid = 0;
414 enum BC_STATUS sts = BC_STS_SUCCESS;
415 wait_queue_head_t event;
416 int rc = 0;
417
418 if (!ctx || !idata || !dio) {
419 BCMLOG_ERR("Invalid Arg!!\n");
420 return BC_STS_INV_ARG;
421 }
422
423 crystalhd_create_event(&event);
424
425 ctx->tx_list_id = 0;
426 /* msleep_interruptible(2000); */
427 sts = crystalhd_hw_post_tx(&ctx->hw_ctx, dio, bc_proc_in_completion,
428 &event, &tx_listid,
429 idata->udata.u.ProcInput.Encrypted);
430
431 while (sts == BC_STS_BUSY) {
432 sts = bc_cproc_codein_sleep(ctx);
433 if (sts != BC_STS_SUCCESS)
434 break;
435 sts = crystalhd_hw_post_tx(&ctx->hw_ctx, dio,
436 bc_proc_in_completion,
437 &event, &tx_listid,
438 idata->udata.u.ProcInput.Encrypted);
439 }
440 if (sts != BC_STS_SUCCESS) {
441 BCMLOG(BCMLOG_DBG, "_hw_txdma returning sts:%d\n", sts);
442 return sts;
443 }
444 if (ctx->cin_wait_exit)
445 ctx->cin_wait_exit = 0;
446
447 ctx->tx_list_id = tx_listid;
448
449 /* _post() succeeded.. wait for the completion. */
450 crystalhd_wait_on_event(&event, (dio->uinfo.ev_sts), 3000, rc, 0);
451 ctx->tx_list_id = 0;
452 if (!rc) {
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;
460 } else {
461 sts = BC_STS_IO_ERROR;
462 }
463
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.
467 */
468 crystalhd_hw_cancel_tx(&ctx->hw_ctx, tx_listid);
469
470 return sts;
471 }
472
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)
476 {
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;
481 }
482
483 /* Check for alignment */
484 if (((uintptr_t)ubuff) & 0x03) {
485 BCMLOG_ERR(
486 "%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
506 static 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
542 static 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,
576 (ctx->state == BC_LINK_READY));
577 if ((sts != BC_STS_SUCCESS) && (sts != BC_STS_BUSY)) {
578 crystalhd_unmap_dio(ctx->adp, dio_hnd);
579 return sts;
580 }
581
582 return BC_STS_SUCCESS;
583 }
584
585 static enum BC_STATUS bc_cproc_fmt_change(struct crystalhd_cmd *ctx,
586 struct crystalhd_dio_req *dio)
587 {
588 enum BC_STATUS sts = BC_STS_SUCCESS;
589
590 sts = crystalhd_hw_add_cap_buffer(&ctx->hw_ctx, dio, 0);
591 if (sts != BC_STS_SUCCESS)
592 return sts;
593
594 ctx->state |= BC_LINK_FMT_CHG;
595 if (ctx->state == BC_LINK_READY)
596 sts = crystalhd_hw_start_capture(&ctx->hw_ctx);
597
598 return sts;
599 }
600
601 static enum BC_STATUS bc_cproc_fetch_frame(struct crystalhd_cmd *ctx,
602 struct crystalhd_ioctl_data *idata)
603 {
604 struct crystalhd_dio_req *dio = NULL;
605 enum BC_STATUS sts = BC_STS_SUCCESS;
606 struct BC_DEC_OUT_BUFF *frame;
607
608 if (!ctx || !idata) {
609 BCMLOG_ERR("Invalid Arg!!\n");
610 return BC_STS_INV_ARG;
611 }
612
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;
616 }
617
618 frame = &idata->udata.u.DecOutData;
619
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;
624
625 frame->Flags = dio->uinfo.comp_flags;
626
627 if (frame->Flags & COMP_FLAG_FMT_CHANGE)
628 return bc_cproc_fmt_change(ctx, dio);
629
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;
634
635 frame->OutPutBuffs.YBuffDoneSz = dio->uinfo.y_done_sz;
636 frame->OutPutBuffs.UVBuffDoneSz = dio->uinfo.uv_done_sz;
637
638 crystalhd_unmap_dio(ctx->adp, dio);
639
640 return BC_STS_SUCCESS;
641 }
642
643 static enum BC_STATUS bc_cproc_start_capture(struct crystalhd_cmd *ctx,
644 struct crystalhd_ioctl_data *idata)
645 {
646 ctx->state |= BC_LINK_CAP_EN;
647 if (ctx->state == BC_LINK_READY)
648 return crystalhd_hw_start_capture(&ctx->hw_ctx);
649
650 return BC_STS_SUCCESS;
651 }
652
653 static enum BC_STATUS bc_cproc_flush_cap_buffs(struct crystalhd_cmd *ctx,
654 struct crystalhd_ioctl_data *idata)
655 {
656 struct crystalhd_dio_req *dio = NULL;
657 enum BC_STATUS sts = BC_STS_SUCCESS;
658 struct BC_DEC_OUT_BUFF *frame;
659 uint32_t count;
660
661 if (!ctx || !idata) {
662 BCMLOG_ERR("Invalid Arg!!\n");
663 return BC_STS_INV_ARG;
664 }
665
666 if (!(ctx->state & BC_LINK_CAP_EN))
667 return BC_STS_ERR_USAGE;
668
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);
672
673 ctx->state &= ~(BC_LINK_CAP_EN|BC_LINK_FMT_CHG);
674
675 frame = &idata->udata.u.DecOutData;
676 for (count = 0; count < BC_RX_LIST_CNT; count++) {
677
678 sts = crystalhd_hw_get_cap_buffer(&ctx->hw_ctx,
679 &frame->PibInfo, &dio);
680 if (sts != BC_STS_SUCCESS)
681 break;
682
683 crystalhd_unmap_dio(ctx->adp, dio);
684 }
685
686 return crystalhd_hw_stop_capture(&ctx->hw_ctx);
687 }
688
689 static enum BC_STATUS bc_cproc_get_stats(struct crystalhd_cmd *ctx,
690 struct crystalhd_ioctl_data *idata)
691 {
692 struct BC_DTS_STATS *stats;
693 struct crystalhd_hw_stats hw_stats;
694
695 if (!ctx || !idata) {
696 BCMLOG_ERR("Invalid Arg!!\n");
697 return BC_STS_INV_ARG;
698 }
699
700 crystalhd_hw_stats(&ctx->hw_ctx, &hw_stats);
701
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;
712
713 if (ctx->pwr_state_change)
714 stats->pwr_state_change = 1;
715 if (ctx->state & BC_LINK_PAUSED)
716 stats->DrvPauseTime = 1;
717
718 return BC_STS_SUCCESS;
719 }
720
721 static enum BC_STATUS bc_cproc_reset_stats(struct crystalhd_cmd *ctx,
722 struct crystalhd_ioctl_data *idata)
723 {
724 crystalhd_hw_stats(&ctx->hw_ctx, NULL);
725
726 return BC_STS_SUCCESS;
727 }
728
729 static enum BC_STATUS bc_cproc_chg_clk(struct crystalhd_cmd *ctx,
730 struct crystalhd_ioctl_data *idata)
731 {
732 struct BC_CLOCK *clock;
733 uint32_t oldClk;
734 enum BC_STATUS sts = BC_STS_SUCCESS;
735
736 if (!ctx || !idata) {
737 BCMLOG_ERR("Invalid Arg!!\n");
738 return BC_STS_INV_ARG;
739 }
740
741 clock = &idata->udata.u.clockValue;
742 oldClk = ctx->hw_ctx.core_clock_mhz;
743 ctx->hw_ctx.core_clock_mhz = clock->clk;
744
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;
749 }
750
751 clock->clk = ctx->hw_ctx.core_clock_mhz;
752
753 return sts;
754 }
755
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},
780 };
781
782 /*=============== Cmd Proc Functions.. ===================================*/
783
784 /**
785 * crystalhd_suspend - Power management suspend request.
786 * @ctx: Command layer context.
787 * @idata: Iodata - required for internal use.
788 *
789 * Return:
790 * status
791 *
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.
798 *
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.
803 */
804 enum BC_STATUS crystalhd_suspend(struct crystalhd_cmd *ctx,
805 struct crystalhd_ioctl_data *idata)
806 {
807 enum BC_STATUS sts = BC_STS_SUCCESS;
808
809 if (!ctx || !idata) {
810 BCMLOG_ERR("Invalid Parameters\n");
811 return BC_STS_ERROR;
812 }
813
814 if (ctx->state & BC_LINK_SUSPEND)
815 return BC_STS_SUCCESS;
816
817 if (ctx->state == BC_LINK_INVALID) {
818 BCMLOG(BCMLOG_DBG, "Nothing To Do Suspend Success\n");
819 return BC_STS_SUCCESS;
820 }
821
822 ctx->state |= BC_LINK_SUSPEND;
823
824 bc_cproc_mark_pwr_state(ctx);
825
826 if (ctx->state & BC_LINK_CAP_EN) {
827 sts = bc_cproc_flush_cap_buffs(ctx, idata);
828 if (sts != BC_STS_SUCCESS)
829 return sts;
830 }
831
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)
835 return sts;
836 }
837
838 sts = crystalhd_hw_suspend(&ctx->hw_ctx);
839 if (sts != BC_STS_SUCCESS)
840 return sts;
841
842 BCMLOG(BCMLOG_DBG, "BCM70012 suspend success\n");
843
844 return BC_STS_SUCCESS;
845 }
846
847 /**
848 * crystalhd_resume - Resume frame capture.
849 * @ctx: Command layer contextx.
850 *
851 * Return:
852 * status
853 *
854 *
855 * Resume frame capture.
856 *
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.
861 *
862 */
863 enum BC_STATUS crystalhd_resume(struct crystalhd_cmd *ctx)
864 {
865 BCMLOG(BCMLOG_DBG, "crystalhd_resume Success %x\n", ctx->state);
866
867 bc_cproc_mark_pwr_state(ctx);
868
869 return BC_STS_SUCCESS;
870 }
871
872 /**
873 * crystalhd_user_open - Create application handle.
874 * @ctx: Command layer contextx.
875 * @user_ctx: User ID context.
876 *
877 * Return:
878 * status
879 *
880 * Creates an application specific UID and allocates
881 * application specific resources. HW layer initialization
882 * is done for the first open request.
883 */
884 enum BC_STATUS crystalhd_user_open(struct crystalhd_cmd *ctx,
885 struct crystalhd_user **user_ctx)
886 {
887 struct crystalhd_user *uc;
888
889 if (!ctx || !user_ctx) {
890 BCMLOG_ERR("Invalid arg..\n");
891 return BC_STS_INV_ARG;
892 }
893
894 uc = bc_cproc_get_uid(ctx);
895 if (!uc) {
896 BCMLOG(BCMLOG_INFO, "No free user context...\n");
897 return BC_STS_BUSY;
898 }
899
900 BCMLOG(BCMLOG_INFO, "Opening new user[%x] handle\n", uc->uid);
901
902 crystalhd_hw_open(&ctx->hw_ctx, ctx->adp);
903
904 uc->in_use = 1;
905
906 *user_ctx = uc;
907
908 return BC_STS_SUCCESS;
909 }
910
911 /**
912 * crystalhd_user_close - Close application handle.
913 * @ctx: Command layer contextx.
914 * @uc: User ID context.
915 *
916 * Return:
917 * status
918 *
919 * Closer application handle and release app specific
920 * resources.
921 */
922 enum BC_STATUS crystalhd_user_close(struct crystalhd_cmd *ctx,
923 struct crystalhd_user *uc)
924 {
925 uint32_t mode = uc->mode;
926
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;
931
932 BCMLOG(BCMLOG_INFO, "Closing user[%x] handle\n", uc->uid);
933
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;
939 }
940
941 crystalhd_hw_close(&ctx->hw_ctx);
942
943 ctx->state = BC_LINK_INVALID;
944
945 return BC_STS_SUCCESS;
946 }
947
948 /**
949 * crystalhd_setup_cmd_context - Setup Command layer resources.
950 * @ctx: Command layer contextx.
951 * @adp: Adapter context
952 *
953 * Return:
954 * status
955 *
956 * Called at the time of driver load.
957 */
958 enum BC_STATUS crystalhd_setup_cmd_context(struct crystalhd_cmd *ctx,
959 struct crystalhd_adp *adp)
960 {
961 int i = 0;
962
963 if (!ctx || !adp) {
964 BCMLOG_ERR("Invalid arg!!\n");
965 return BC_STS_INV_ARG;
966 }
967
968 if (ctx->adp)
969 BCMLOG(BCMLOG_DBG, "Resetting Cmd context delete missing..\n");
970
971 ctx->adp = adp;
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;
976 }
977
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;
982 }
983
984 /**
985 * crystalhd_delete_cmd_context - Release Command layer resources.
986 * @ctx: Command layer contextx.
987 *
988 * Return:
989 * status
990 *
991 * Called at the time of driver un-load.
992 */
993 enum BC_STATUS crystalhd_delete_cmd_context(struct crystalhd_cmd *ctx)
994 {
995 BCMLOG(BCMLOG_DBG, "Deleting Command context..\n");
996
997 ctx->adp = NULL;
998
999 return BC_STS_SUCCESS;
1000 }
1001
1002 /**
1003 * crystalhd_get_cmd_proc - Cproc table lookup.
1004 * @ctx: Command layer contextx.
1005 * @cmd: IOCTL command code.
1006 * @uc: User ID context.
1007 *
1008 * Return:
1009 * command proc function pointer
1010 *
1011 * This function checks the process context, application's
1012 * mode of operation and returns the function pointer
1013 * from the cproc table.
1014 */
1015 crystalhd_cmd_proc crystalhd_get_cmd_proc(struct crystalhd_cmd *ctx,
1016 uint32_t cmd, struct crystalhd_user *uc)
1017 {
1018 crystalhd_cmd_proc cproc = NULL;
1019 unsigned int i, tbl_sz;
1020
1021 if (!ctx) {
1022 BCMLOG_ERR("Invalid arg.. Cmd[%d]\n", cmd);
1023 return NULL;
1024 }
1025
1026 if ((cmd != BCM_IOC_GET_DRV_STAT) && (ctx->state & BC_LINK_SUSPEND)) {
1027 BCMLOG_ERR("Invalid State [suspend Set].. Cmd[%d]\n", cmd);
1028 return NULL;
1029 }
1030
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);
1038 break;
1039 }
1040 cproc = g_crystalhd_cproc_tbl[i].cmd_proc;
1041 break;
1042 }
1043 }
1044
1045 return cproc;
1046 }
1047
1048 /**
1049 * crystalhd_cmd_interrupt - ISR entry point
1050 * @ctx: Command layer contextx.
1051 *
1052 * Return:
1053 * TRUE: If interrupt from bcm70012 device.
1054 *
1055 *
1056 * ISR entry point from OS layer.
1057 */
1058 bool crystalhd_cmd_interrupt(struct crystalhd_cmd *ctx)
1059 {
1060 if (!ctx) {
1061 BCMLOG_ERR("Invalid arg..\n");
1062 return 0;
1063 }
1064
1065 return crystalhd_hw_interrupt(ctx->adp, &ctx->hw_ctx);
1066 }
This page took 0.060501 seconds and 5 git commands to generate.