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