crystalhd_cmds.c revision 641b63f9981a082eeefab3b395203a54dcd6e93b
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_cmds.h" 28#include "crystalhd_hw.h" 29 30static struct crystalhd_user *bc_cproc_get_uid(struct crystalhd_cmd *ctx) 31{ 32 struct crystalhd_user *user = NULL; 33 int i; 34 35 for (i = 0; i < BC_LINK_MAX_OPENS; i++) { 36 if (!ctx->user[i].in_use) { 37 user = &ctx->user[i]; 38 break; 39 } 40 } 41 42 return user; 43} 44 45static int bc_cproc_get_user_count(struct crystalhd_cmd *ctx) 46{ 47 int i, count = 0; 48 49 for (i = 0; i < BC_LINK_MAX_OPENS; i++) { 50 if (ctx->user[i].in_use) 51 count++; 52 } 53 54 return count; 55} 56 57static void bc_cproc_mark_pwr_state(struct crystalhd_cmd *ctx) 58{ 59 int i; 60 61 for (i = 0; i < BC_LINK_MAX_OPENS; i++) { 62 if (!ctx->user[i].in_use) 63 continue; 64 if (ctx->user[i].mode == DTS_DIAG_MODE || 65 ctx->user[i].mode == DTS_PLAYBACK_MODE) { 66 ctx->pwr_state_change = 1; 67 break; 68 } 69 } 70} 71 72static BC_STATUS bc_cproc_notify_mode(struct crystalhd_cmd *ctx, 73 crystalhd_ioctl_data *idata) 74{ 75 int rc = 0, i = 0; 76 77 if (!ctx || !idata) { 78 BCMLOG_ERR("Invalid Arg!!\n"); 79 return BC_STS_INV_ARG; 80 } 81 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; 85 } 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; 89 } 90 if (ctx->state != BC_LINK_INVALID) { 91 BCMLOG_ERR("Link invalid state %d\n", ctx->state); 92 return BC_STS_ERR_USAGE; 93 } 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 " 99 "supported..\n"); 100 return BC_STS_ERR_USAGE; 101 } 102 } 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); 107 if (rc) 108 return BC_STS_ERROR; 109 110 /* Setup Hardware DMA rings */ 111 return crystalhd_hw_setup_dma_rings(&ctx->hw_ctx); 112} 113 114static BC_STATUS bc_cproc_get_version(struct crystalhd_cmd *ctx, 115 crystalhd_ioctl_data *idata) 116{ 117 118 if (!ctx || !idata) { 119 BCMLOG_ERR("Invalid Arg!!\n"); 120 return BC_STS_INV_ARG; 121 } 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; 126} 127 128 129static BC_STATUS bc_cproc_get_hwtype(struct crystalhd_cmd *ctx, 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 BC_STATUS bc_cproc_reg_rd(struct crystalhd_cmd *ctx, 147 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 BC_STATUS bc_cproc_reg_wr(struct crystalhd_cmd *ctx, 157 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 BC_STATUS bc_cproc_link_reg_rd(struct crystalhd_cmd *ctx, 169 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 BC_STATUS bc_cproc_link_reg_wr(struct crystalhd_cmd *ctx, 180 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 BC_STATUS bc_cproc_mem_rd(struct crystalhd_cmd *ctx, 192 crystalhd_ioctl_data *idata) 193{ 194 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 BC_STATUS bc_cproc_mem_wr(struct crystalhd_cmd *ctx, 211 crystalhd_ioctl_data *idata) 212{ 213 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 BC_STATUS bc_cproc_cfg_rd(struct crystalhd_cmd *ctx, 230 crystalhd_ioctl_data *idata) 231{ 232 uint32_t ix, cnt, off, len; 233 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 BC_STATUS bc_cproc_cfg_wr(struct crystalhd_cmd *ctx, 262 crystalhd_ioctl_data *idata) 263{ 264 uint32_t ix, cnt, off, len; 265 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 BC_STATUS bc_cproc_download_fw(struct crystalhd_cmd *ctx, 294 crystalhd_ioctl_data *idata) 295{ 296 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 BC_STATUS bc_cproc_do_fw_cmd(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata) 333{ 334 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 374static void bc_proc_in_completion(crystalhd_dio_req *dio_hnd, 375 wait_queue_head_t *event, 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 389static 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 409static BC_STATUS bc_cproc_hw_txdma(struct crystalhd_cmd *ctx, 410 crystalhd_ioctl_data *idata, 411 crystalhd_dio_req *dio) 412{ 413 uint32_t tx_listid = 0; 414 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 */ 474static BC_STATUS bc_cproc_check_inbuffs(bool pin, void *ubuff, uint32_t ub_sz, 475 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("%s-->Un-aligned address not implemented yet.. %p\n", 486 ((pin) ? "TX" : "RX"), ubuff); 487 return BC_STS_NOT_IMPL; 488 } 489 if (pin) 490 return BC_STS_SUCCESS; 491 492 if (!en_422 && !uv_off) { 493 BCMLOG_ERR("Need UV offset for 420 mode.\n"); 494 return BC_STS_INV_ARG; 495 } 496 497 if (en_422 && uv_off) { 498 BCMLOG_ERR("UV offset in 422 mode ??\n"); 499 return BC_STS_INV_ARG; 500 } 501 502 return BC_STS_SUCCESS; 503} 504 505static BC_STATUS bc_cproc_proc_input(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata) 506{ 507 void *ubuff; 508 uint32_t ub_sz; 509 crystalhd_dio_req *dio_hnd = NULL; 510 BC_STATUS sts = BC_STS_SUCCESS; 511 512 if (!ctx || !idata) { 513 BCMLOG_ERR("Invalid Arg!!\n"); 514 return BC_STS_INV_ARG; 515 } 516 517 ubuff = idata->udata.u.ProcInput.pDmaBuff; 518 ub_sz = idata->udata.u.ProcInput.BuffSz; 519 520 sts = bc_cproc_check_inbuffs(1, ubuff, ub_sz, 0, 0); 521 if (sts != BC_STS_SUCCESS) 522 return sts; 523 524 sts = crystalhd_map_dio(ctx->adp, ubuff, ub_sz, 0, 0, 1, &dio_hnd); 525 if (sts != BC_STS_SUCCESS) { 526 BCMLOG_ERR("dio map - %d\n", sts); 527 return sts; 528 } 529 530 if (!dio_hnd) 531 return BC_STS_ERROR; 532 533 sts = bc_cproc_hw_txdma(ctx, idata, dio_hnd); 534 535 crystalhd_unmap_dio(ctx->adp, dio_hnd); 536 537 return sts; 538} 539 540static BC_STATUS bc_cproc_add_cap_buff(struct crystalhd_cmd *ctx, 541 crystalhd_ioctl_data *idata) 542{ 543 void *ubuff; 544 uint32_t ub_sz, uv_off; 545 bool en_422; 546 crystalhd_dio_req *dio_hnd = NULL; 547 BC_STATUS sts = BC_STS_SUCCESS; 548 549 if (!ctx || !idata) { 550 BCMLOG_ERR("Invalid Arg!!\n"); 551 return BC_STS_INV_ARG; 552 } 553 554 ubuff = idata->udata.u.RxBuffs.YuvBuff; 555 ub_sz = idata->udata.u.RxBuffs.YuvBuffSz; 556 uv_off = idata->udata.u.RxBuffs.UVbuffOffset; 557 en_422 = idata->udata.u.RxBuffs.b422Mode; 558 559 sts = bc_cproc_check_inbuffs(0, ubuff, ub_sz, uv_off, en_422); 560 if (sts != BC_STS_SUCCESS) 561 return sts; 562 563 sts = crystalhd_map_dio(ctx->adp, ubuff, ub_sz, uv_off, 564 en_422, 0, &dio_hnd); 565 if (sts != BC_STS_SUCCESS) { 566 BCMLOG_ERR("dio map - %d\n", sts); 567 return sts; 568 } 569 570 if (!dio_hnd) 571 return BC_STS_ERROR; 572 573 sts = crystalhd_hw_add_cap_buffer(&ctx->hw_ctx, dio_hnd, (ctx->state == BC_LINK_READY)); 574 if ((sts != BC_STS_SUCCESS) && (sts != BC_STS_BUSY)) { 575 crystalhd_unmap_dio(ctx->adp, dio_hnd); 576 return sts; 577 } 578 579 return BC_STS_SUCCESS; 580} 581 582static BC_STATUS bc_cproc_fmt_change(struct crystalhd_cmd *ctx, 583 crystalhd_dio_req *dio) 584{ 585 BC_STATUS sts = BC_STS_SUCCESS; 586 587 sts = crystalhd_hw_add_cap_buffer(&ctx->hw_ctx, dio, 0); 588 if (sts != BC_STS_SUCCESS) 589 return sts; 590 591 ctx->state |= BC_LINK_FMT_CHG; 592 if (ctx->state == BC_LINK_READY) 593 sts = crystalhd_hw_start_capture(&ctx->hw_ctx); 594 595 return sts; 596} 597 598static BC_STATUS bc_cproc_fetch_frame(struct crystalhd_cmd *ctx, 599 crystalhd_ioctl_data *idata) 600{ 601 crystalhd_dio_req *dio = NULL; 602 BC_STATUS sts = BC_STS_SUCCESS; 603 BC_DEC_OUT_BUFF *frame; 604 605 if (!ctx || !idata) { 606 BCMLOG_ERR("Invalid Arg!!\n"); 607 return BC_STS_INV_ARG; 608 } 609 610 if (!(ctx->state & BC_LINK_CAP_EN)) { 611 BCMLOG(BCMLOG_DBG, "Capture not enabled..%x\n", ctx->state); 612 return BC_STS_ERR_USAGE; 613 } 614 615 frame = &idata->udata.u.DecOutData; 616 617 sts = crystalhd_hw_get_cap_buffer(&ctx->hw_ctx, &frame->PibInfo, &dio); 618 if (sts != BC_STS_SUCCESS) 619 return (ctx->state & BC_LINK_SUSPEND) ? BC_STS_IO_USER_ABORT : sts; 620 621 frame->Flags = dio->uinfo.comp_flags; 622 623 if (frame->Flags & COMP_FLAG_FMT_CHANGE) 624 return bc_cproc_fmt_change(ctx, dio); 625 626 frame->OutPutBuffs.YuvBuff = dio->uinfo.xfr_buff; 627 frame->OutPutBuffs.YuvBuffSz = dio->uinfo.xfr_len; 628 frame->OutPutBuffs.UVbuffOffset = dio->uinfo.uv_offset; 629 frame->OutPutBuffs.b422Mode = dio->uinfo.b422mode; 630 631 frame->OutPutBuffs.YBuffDoneSz = dio->uinfo.y_done_sz; 632 frame->OutPutBuffs.UVBuffDoneSz = dio->uinfo.uv_done_sz; 633 634 crystalhd_unmap_dio(ctx->adp, dio); 635 636 return BC_STS_SUCCESS; 637} 638 639static BC_STATUS bc_cproc_start_capture(struct crystalhd_cmd *ctx, 640 crystalhd_ioctl_data *idata) 641{ 642 ctx->state |= BC_LINK_CAP_EN; 643 if (ctx->state == BC_LINK_READY) 644 return crystalhd_hw_start_capture(&ctx->hw_ctx); 645 646 return BC_STS_SUCCESS; 647} 648 649static BC_STATUS bc_cproc_flush_cap_buffs(struct crystalhd_cmd *ctx, 650 crystalhd_ioctl_data *idata) 651{ 652 crystalhd_dio_req *dio = NULL; 653 BC_STATUS sts = BC_STS_SUCCESS; 654 BC_DEC_OUT_BUFF *frame; 655 uint32_t count; 656 657 if (!ctx || !idata) { 658 BCMLOG_ERR("Invalid Arg!!\n"); 659 return BC_STS_INV_ARG; 660 } 661 662 if (!(ctx->state & BC_LINK_CAP_EN)) 663 return BC_STS_ERR_USAGE; 664 665 /* We should ack flush even when we are in paused/suspend state */ 666 if (!(ctx->state & BC_LINK_READY)) 667 return crystalhd_hw_stop_capture(&ctx->hw_ctx); 668 669 ctx->state &= ~(BC_LINK_CAP_EN|BC_LINK_FMT_CHG); 670 671 frame = &idata->udata.u.DecOutData; 672 for (count = 0; count < BC_RX_LIST_CNT; count++) { 673 674 sts = crystalhd_hw_get_cap_buffer(&ctx->hw_ctx, &frame->PibInfo, &dio); 675 if (sts != BC_STS_SUCCESS) 676 break; 677 678 crystalhd_unmap_dio(ctx->adp, dio); 679 } 680 681 return crystalhd_hw_stop_capture(&ctx->hw_ctx); 682} 683 684static BC_STATUS bc_cproc_get_stats(struct crystalhd_cmd *ctx, 685 crystalhd_ioctl_data *idata) 686{ 687 BC_DTS_STATS *stats; 688 struct crystalhd_hw_stats hw_stats; 689 690 if (!ctx || !idata) { 691 BCMLOG_ERR("Invalid Arg!!\n"); 692 return BC_STS_INV_ARG; 693 } 694 695 crystalhd_hw_stats(&ctx->hw_ctx, &hw_stats); 696 697 stats = &idata->udata.u.drvStat; 698 stats->drvRLL = hw_stats.rdyq_count; 699 stats->drvFLL = hw_stats.freeq_count; 700 stats->DrvTotalFrmDropped = hw_stats.rx_errors; 701 stats->DrvTotalHWErrs = hw_stats.rx_errors + hw_stats.tx_errors; 702 stats->intCount = hw_stats.num_interrupts; 703 stats->DrvIgnIntrCnt = hw_stats.num_interrupts - 704 hw_stats.dev_interrupts; 705 stats->TxFifoBsyCnt = hw_stats.cin_busy; 706 stats->pauseCount = hw_stats.pause_cnt; 707 708 if (ctx->pwr_state_change) 709 stats->pwr_state_change = 1; 710 if (ctx->state & BC_LINK_PAUSED) 711 stats->DrvPauseTime = 1; 712 713 return BC_STS_SUCCESS; 714} 715 716static BC_STATUS bc_cproc_reset_stats(struct crystalhd_cmd *ctx, 717 crystalhd_ioctl_data *idata) 718{ 719 crystalhd_hw_stats(&ctx->hw_ctx, NULL); 720 721 return BC_STS_SUCCESS; 722} 723 724static BC_STATUS bc_cproc_chg_clk(struct crystalhd_cmd *ctx, 725 crystalhd_ioctl_data *idata) 726{ 727 BC_CLOCK *clock; 728 uint32_t oldClk; 729 BC_STATUS sts = BC_STS_SUCCESS; 730 731 if (!ctx || !idata) { 732 BCMLOG_ERR("Invalid Arg!!\n"); 733 return BC_STS_INV_ARG; 734 } 735 736 clock = &idata->udata.u.clockValue; 737 oldClk = ctx->hw_ctx.core_clock_mhz; 738 ctx->hw_ctx.core_clock_mhz = clock->clk; 739 740 if (ctx->state & BC_LINK_READY) { 741 sts = crystalhd_hw_set_core_clock(&ctx->hw_ctx); 742 if (sts == BC_STS_CLK_NOCHG) 743 ctx->hw_ctx.core_clock_mhz = oldClk; 744 } 745 746 clock->clk = ctx->hw_ctx.core_clock_mhz; 747 748 return sts; 749} 750 751/*=============== Cmd Proc Table.. ======================================*/ 752static const crystalhd_cmd_tbl_t g_crystalhd_cproc_tbl[] = { 753 { BCM_IOC_GET_VERSION, bc_cproc_get_version, 0}, 754 { BCM_IOC_GET_HWTYPE, bc_cproc_get_hwtype, 0}, 755 { BCM_IOC_REG_RD, bc_cproc_reg_rd, 0}, 756 { BCM_IOC_REG_WR, bc_cproc_reg_wr, 0}, 757 { BCM_IOC_FPGA_RD, bc_cproc_link_reg_rd, 0}, 758 { BCM_IOC_FPGA_WR, bc_cproc_link_reg_wr, 0}, 759 { BCM_IOC_MEM_RD, bc_cproc_mem_rd, 0}, 760 { BCM_IOC_MEM_WR, bc_cproc_mem_wr, 0}, 761 { BCM_IOC_RD_PCI_CFG, bc_cproc_cfg_rd, 0}, 762 { BCM_IOC_WR_PCI_CFG, bc_cproc_cfg_wr, 1}, 763 { BCM_IOC_FW_DOWNLOAD, bc_cproc_download_fw, 1}, 764 { BCM_IOC_FW_CMD, bc_cproc_do_fw_cmd, 1}, 765 { BCM_IOC_PROC_INPUT, bc_cproc_proc_input, 1}, 766 { BCM_IOC_ADD_RXBUFFS, bc_cproc_add_cap_buff, 1}, 767 { BCM_IOC_FETCH_RXBUFF, bc_cproc_fetch_frame, 1}, 768 { BCM_IOC_START_RX_CAP, bc_cproc_start_capture, 1}, 769 { BCM_IOC_FLUSH_RX_CAP, bc_cproc_flush_cap_buffs, 1}, 770 { BCM_IOC_GET_DRV_STAT, bc_cproc_get_stats, 0}, 771 { BCM_IOC_RST_DRV_STAT, bc_cproc_reset_stats, 0}, 772 { BCM_IOC_NOTIFY_MODE, bc_cproc_notify_mode, 0}, 773 { BCM_IOC_CHG_CLK, bc_cproc_chg_clk, 0}, 774 { BCM_IOC_END, NULL}, 775}; 776 777/*=============== Cmd Proc Functions.. ===================================*/ 778 779/** 780 * crystalhd_suspend - Power management suspend request. 781 * @ctx: Command layer context. 782 * @idata: Iodata - required for internal use. 783 * 784 * Return: 785 * status 786 * 787 * 1. Set the state to Suspend. 788 * 2. Flush the Rx Buffers it will unmap all the buffers and 789 * stop the RxDMA engine. 790 * 3. Cancel The TX Io and Stop Dma Engine. 791 * 4. Put the DDR in to deep sleep. 792 * 5. Stop the hardware putting it in to Reset State. 793 * 794 * Current gstreamer frame work does not provide any power management 795 * related notification to user mode decoder plug-in. As a work-around 796 * we pass on the power mangement notification to our plug-in by completing 797 * all outstanding requests with BC_STS_IO_USER_ABORT return code. 798 */ 799BC_STATUS crystalhd_suspend(struct crystalhd_cmd *ctx, crystalhd_ioctl_data *idata) 800{ 801 BC_STATUS sts = BC_STS_SUCCESS; 802 803 if (!ctx || !idata) { 804 BCMLOG_ERR("Invalid Parameters\n"); 805 return BC_STS_ERROR; 806 } 807 808 if (ctx->state & BC_LINK_SUSPEND) 809 return BC_STS_SUCCESS; 810 811 if (ctx->state == BC_LINK_INVALID) { 812 BCMLOG(BCMLOG_DBG, "Nothing To Do Suspend Success\n"); 813 return BC_STS_SUCCESS; 814 } 815 816 ctx->state |= BC_LINK_SUSPEND; 817 818 bc_cproc_mark_pwr_state(ctx); 819 820 if (ctx->state & BC_LINK_CAP_EN) { 821 sts = bc_cproc_flush_cap_buffs(ctx, idata); 822 if (sts != BC_STS_SUCCESS) 823 return sts; 824 } 825 826 if (ctx->tx_list_id) { 827 sts = crystalhd_hw_cancel_tx(&ctx->hw_ctx, ctx->tx_list_id); 828 if (sts != BC_STS_SUCCESS) 829 return sts; 830 } 831 832 sts = crystalhd_hw_suspend(&ctx->hw_ctx); 833 if (sts != BC_STS_SUCCESS) 834 return sts; 835 836 BCMLOG(BCMLOG_DBG, "BCM70012 suspend success\n"); 837 838 return BC_STS_SUCCESS; 839} 840 841/** 842 * crystalhd_resume - Resume frame capture. 843 * @ctx: Command layer contextx. 844 * 845 * Return: 846 * status 847 * 848 * 849 * Resume frame capture. 850 * 851 * PM_Resume can't resume the playback state back to pre-suspend state 852 * because we don't keep video clip related information within driver. 853 * To get back to the pre-suspend state App will re-open the device and 854 * start a new playback session from the pre-suspend clip position. 855 * 856 */ 857BC_STATUS crystalhd_resume(struct crystalhd_cmd *ctx) 858{ 859 BCMLOG(BCMLOG_DBG, "crystalhd_resume Success %x\n", ctx->state); 860 861 bc_cproc_mark_pwr_state(ctx); 862 863 return BC_STS_SUCCESS; 864} 865 866/** 867 * crystalhd_user_open - Create application handle. 868 * @ctx: Command layer contextx. 869 * @user_ctx: User ID context. 870 * 871 * Return: 872 * status 873 * 874 * Creates an application specific UID and allocates 875 * application specific resources. HW layer initialization 876 * is done for the first open request. 877 */ 878BC_STATUS crystalhd_user_open(struct crystalhd_cmd *ctx, 879 struct crystalhd_user **user_ctx) 880{ 881 struct crystalhd_user *uc; 882 883 if (!ctx || !user_ctx) { 884 BCMLOG_ERR("Invalid arg..\n"); 885 return BC_STS_INV_ARG; 886 } 887 888 uc = bc_cproc_get_uid(ctx); 889 if (!uc) { 890 BCMLOG(BCMLOG_INFO, "No free user context...\n"); 891 return BC_STS_BUSY; 892 } 893 894 BCMLOG(BCMLOG_INFO, "Opening new user[%x] handle\n", uc->uid); 895 896 crystalhd_hw_open(&ctx->hw_ctx, ctx->adp); 897 898 uc->in_use = 1; 899 900 *user_ctx = uc; 901 902 return BC_STS_SUCCESS; 903} 904 905/** 906 * crystalhd_user_close - Close application handle. 907 * @ctx: Command layer contextx. 908 * @uc: User ID context. 909 * 910 * Return: 911 * status 912 * 913 * Closer aplication handle and release app specific 914 * resources. 915 */ 916BC_STATUS crystalhd_user_close(struct crystalhd_cmd *ctx, struct crystalhd_user *uc) 917{ 918 uint32_t mode = uc->mode; 919 920 ctx->user[uc->uid].mode = DTS_MODE_INV; 921 ctx->user[uc->uid].in_use = 0; 922 ctx->cin_wait_exit = 1; 923 ctx->pwr_state_change = 0; 924 925 BCMLOG(BCMLOG_INFO, "Closing user[%x] handle\n", uc->uid); 926 927 if ((mode == DTS_DIAG_MODE) || (mode == DTS_PLAYBACK_MODE)) { 928 crystalhd_hw_free_dma_rings(&ctx->hw_ctx); 929 crystalhd_destroy_dio_pool(ctx->adp); 930 } else if (bc_cproc_get_user_count(ctx)) { 931 return BC_STS_SUCCESS; 932 } 933 934 crystalhd_hw_close(&ctx->hw_ctx); 935 936 ctx->state = BC_LINK_INVALID; 937 938 return BC_STS_SUCCESS; 939} 940 941/** 942 * crystalhd_setup_cmd_context - Setup Command layer resources. 943 * @ctx: Command layer contextx. 944 * @adp: Adapter context 945 * 946 * Return: 947 * status 948 * 949 * Called at the time of driver load. 950 */ 951BC_STATUS __devinit crystalhd_setup_cmd_context(struct crystalhd_cmd *ctx, 952 struct crystalhd_adp *adp) 953{ 954 int i = 0; 955 956 if (!ctx || !adp) { 957 BCMLOG_ERR("Invalid arg!!\n"); 958 return BC_STS_INV_ARG; 959 } 960 961 if (ctx->adp) 962 BCMLOG(BCMLOG_DBG, "Resetting Cmd context delete missing..\n"); 963 964 ctx->adp = adp; 965 for (i = 0; i < BC_LINK_MAX_OPENS; i++) { 966 ctx->user[i].uid = i; 967 ctx->user[i].in_use = 0; 968 ctx->user[i].mode = DTS_MODE_INV; 969 } 970 971 /*Open and Close the Hardware to put it in to sleep state*/ 972 crystalhd_hw_open(&ctx->hw_ctx, ctx->adp); 973 crystalhd_hw_close(&ctx->hw_ctx); 974 return BC_STS_SUCCESS; 975} 976 977/** 978 * crystalhd_delete_cmd_context - Release Command layer resources. 979 * @ctx: Command layer contextx. 980 * 981 * Return: 982 * status 983 * 984 * Called at the time of driver un-load. 985 */ 986BC_STATUS __devexit crystalhd_delete_cmd_context(struct crystalhd_cmd *ctx) 987{ 988 BCMLOG(BCMLOG_DBG, "Deleting Command context..\n"); 989 990 ctx->adp = NULL; 991 992 return BC_STS_SUCCESS; 993} 994 995/** 996 * crystalhd_get_cmd_proc - Cproc table lookup. 997 * @ctx: Command layer contextx. 998 * @cmd: IOCTL command code. 999 * @uc: User ID context. 1000 * 1001 * Return: 1002 * command proc function pointer 1003 * 1004 * This function checks the process context, application's 1005 * mode of operation and returns the function pointer 1006 * from the cproc table. 1007 */ 1008crystalhd_cmd_proc crystalhd_get_cmd_proc(struct crystalhd_cmd *ctx, uint32_t cmd, 1009 struct crystalhd_user *uc) 1010{ 1011 crystalhd_cmd_proc cproc = NULL; 1012 unsigned int i, tbl_sz; 1013 1014 if (!ctx) { 1015 BCMLOG_ERR("Invalid arg.. Cmd[%d]\n", cmd); 1016 return NULL; 1017 } 1018 1019 if ((cmd != BCM_IOC_GET_DRV_STAT) && (ctx->state & BC_LINK_SUSPEND)) { 1020 BCMLOG_ERR("Invalid State [suspend Set].. Cmd[%d]\n", cmd); 1021 return NULL; 1022 } 1023 1024 tbl_sz = sizeof(g_crystalhd_cproc_tbl) / sizeof(crystalhd_cmd_tbl_t); 1025 for (i = 0; i < tbl_sz; i++) { 1026 if (g_crystalhd_cproc_tbl[i].cmd_id == cmd) { 1027 if ((uc->mode == DTS_MONITOR_MODE) && 1028 (g_crystalhd_cproc_tbl[i].block_mon)) { 1029 BCMLOG(BCMLOG_INFO, "Blocking cmd %d\n", cmd); 1030 break; 1031 } 1032 cproc = g_crystalhd_cproc_tbl[i].cmd_proc; 1033 break; 1034 } 1035 } 1036 1037 return cproc; 1038} 1039 1040/** 1041 * crystalhd_cmd_interrupt - ISR entry point 1042 * @ctx: Command layer contextx. 1043 * 1044 * Return: 1045 * TRUE: If interrupt from bcm70012 device. 1046 * 1047 * 1048 * ISR entry point from OS layer. 1049 */ 1050bool crystalhd_cmd_interrupt(struct crystalhd_cmd *ctx) 1051{ 1052 if (!ctx) { 1053 BCMLOG_ERR("Invalid arg..\n"); 1054 return 0; 1055 } 1056 1057 return crystalhd_hw_interrupt(ctx->adp, &ctx->hw_ctx); 1058} 1059