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