Changeset 32fb6bce in mainline for uspace/lib/usbhost/src/ddf_helpers.c
- Timestamp:
- 2017-12-18T22:50:21Z (6 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 7f70d1c
- Parents:
- 1ea0bbf
- git-author:
- Ondřej Hlavatý <aearsis@…> (2017-12-18 22:04:50)
- git-committer:
- Ondřej Hlavatý <aearsis@…> (2017-12-18 22:50:21)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/src/ddf_helpers.c
r1ea0bbf r32fb6bce 53 53 #include "ddf_helpers.h" 54 54 55 typedef struct hc_dev { 56 ddf_fun_t *ctl_fun; 57 hcd_t hcd; 58 } hc_dev_t; 59 60 static hc_dev_t *dev_to_hc_dev(ddf_dev_t *dev) 61 { 62 return ddf_dev_data_get(dev); 63 } 64 65 hcd_t *dev_to_hcd(ddf_dev_t *dev) 66 { 67 hc_dev_t *hc_dev = dev_to_hc_dev(dev); 68 if (!hc_dev) { 69 usb_log_error("Invalid HCD device.\n"); 70 return NULL; 71 } 72 return &hc_dev->hcd; 73 } 74 75 76 static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, device_t *hub_dev, unsigned port); 55 56 static int hcd_ddf_new_device(hc_device_t *hcd, ddf_dev_t *hc, device_t *hub_dev, unsigned port); 77 57 static int hcd_ddf_remove_device(ddf_dev_t *device, device_t *hub, unsigned port); 78 58 … … 89 69 { 90 70 assert(fun); 91 hc d_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));71 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 92 72 device_t *dev = ddf_fun_data_get(fun); 93 73 assert(hcd); … … 113 93 { 114 94 assert(fun); 115 hc d_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));95 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 116 96 device_t *dev = ddf_fun_data_get(fun); 117 97 assert(hcd); … … 138 118 { 139 119 assert(fun); 140 hc d_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));120 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 141 121 device_t *dev = ddf_fun_data_get(fun); 142 122 assert(hcd); … … 152 132 { 153 133 assert(fun); 154 hc d_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));134 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 155 135 device_t *dev = ddf_fun_data_get(fun); 156 136 assert(hcd); … … 167 147 ddf_dev_t *hc = ddf_fun_get_dev(fun); 168 148 assert(hc); 169 hc d_t *hcd = dev_to_hcd(hc);149 hc_device_t *hcd = dev_to_hcd(hc); 170 150 assert(hcd); 171 151 device_t *hub = ddf_fun_data_get(fun); … … 218 198 { 219 199 assert(fun); 220 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));221 200 device_t *dev = ddf_fun_data_get(fun); 222 201 assert(dev); … … 224 203 target.address = dev->address; 225 204 226 return hcd_send_batch(hcd,dev, target, USB_DIRECTION_IN,205 return bus_device_send_batch(dev, target, USB_DIRECTION_IN, 227 206 data, size, setup_data, 228 207 callback, arg, "READ"); … … 244 223 { 245 224 assert(fun); 246 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));247 225 device_t *dev = ddf_fun_data_get(fun); 248 226 assert(dev); … … 250 228 target.address = dev->address; 251 229 252 return hcd_send_batch(hcd,dev, target, USB_DIRECTION_OUT,230 return bus_device_send_batch(dev, target, USB_DIRECTION_OUT, 253 231 (char *) data, size, setup_data, 254 232 callback, arg, "WRITE"); … … 337 315 assert(device); 338 316 339 hc d_t *hcd = dev_to_hcd(device);317 hc_device_t *hcd = dev_to_hcd(device); 340 318 assert(hcd); 341 319 assert(hcd->bus); 342 343 hc_dev_t *hc_dev = dev_to_hc_dev(device);344 assert(hc_dev);345 320 346 321 fibril_mutex_lock(&hub->guard); … … 374 349 } 375 350 376 device_t *hcd_ddf_ device_create(ddf_dev_t *hc, bus_t *bus)351 device_t *hcd_ddf_fun_create(hc_device_t *hc) 377 352 { 378 353 /* Create DDF function for the new device */ 379 ddf_fun_t *fun = ddf_fun_create(hc , fun_inner, NULL);354 ddf_fun_t *fun = ddf_fun_create(hc->ddf_dev, fun_inner, NULL); 380 355 if (!fun) 381 356 return NULL; … … 384 359 385 360 /* Create USB device node for the new device */ 386 device_t *dev = ddf_fun_data_alloc(fun, bus->device_size);361 device_t *dev = ddf_fun_data_alloc(fun, hc->bus->device_size); 387 362 if (!dev) { 388 363 ddf_fun_destroy(fun); … … 390 365 } 391 366 392 bus_device_init(dev, bus);367 bus_device_init(dev, hc->bus); 393 368 dev->fun = fun; 394 369 return dev; 395 370 } 396 371 397 void hcd_ddf_ device_destroy(device_t *dev)372 void hcd_ddf_fun_destroy(device_t *dev) 398 373 { 399 374 assert(dev); … … 402 377 } 403 378 404 int hcd_d df_device_explore(device_t *device)379 int hcd_device_explore(device_t *device) 405 380 { 406 381 int err; … … 421 396 usb_log_debug("Device(%d): Requesting full device descriptor.", 422 397 device->address); 423 ssize_t got = hcd_send_batch_sync(device->bus->hcd,device, control_ep, USB_DIRECTION_IN,398 ssize_t got = bus_device_send_batch_sync(device, control_ep, USB_DIRECTION_IN, 424 399 (char *) &desc, sizeof(desc), *(uint64_t *)&get_device_desc, 425 400 "read device descriptor"); … … 447 422 } 448 423 449 int hcd_ddf_device_online(ddf_fun_t *fun) 450 { 451 assert(fun); 452 453 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 454 device_t *dev = ddf_fun_data_get(fun); 455 assert(dev); 456 assert(hcd->bus); 457 458 usb_log_info("Device(%d): Requested to be brought online.", dev->address); 459 460 return bus_device_online(dev); 461 } 462 463 int hcd_ddf_device_offline(ddf_fun_t *fun) 464 { 465 assert(fun); 466 467 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 468 device_t *dev = ddf_fun_data_get(fun); 469 assert(dev); 470 assert(hcd->bus); 471 472 usb_log_info("Device(%d): Requested to be taken offline.", dev->address); 473 474 return bus_device_offline(dev); 475 } 476 477 static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, device_t *hub, unsigned port) 424 static int hcd_ddf_new_device(hc_device_t *hcd, ddf_dev_t *hc, device_t *hub, unsigned port) 478 425 { 479 426 int err; … … 483 430 assert(hc); 484 431 485 device_t *dev = hcd_ddf_ device_create(hc, hcd->bus);432 device_t *dev = hcd_ddf_fun_create(hcd); 486 433 if (!dev) { 487 434 usb_log_error("Failed to create USB device function."); … … 516 463 517 464 err_usb_dev: 518 hcd_ddf_ device_destroy(dev);465 hcd_ddf_fun_destroy(dev); 519 466 return err; 520 467 } … … 525 472 * @return Error code 526 473 */ 527 int hcd_setup_virtual_root_hub(hc d_t *hcd, ddf_dev_t *hc)474 int hcd_setup_virtual_root_hub(hc_device_t *hcd) 528 475 { 529 476 int err; 530 477 531 assert(hc); 532 assert(hcd); 533 assert(hcd->bus); 478 assert(hcd); 534 479 535 480 if ((err = bus_reserve_default_address(hcd->bus, USB_SPEED_MAX))) { … … 538 483 } 539 484 540 device_t *dev = hcd_ddf_ device_create(hc, hcd->bus);485 device_t *dev = hcd_ddf_fun_create(hcd); 541 486 if (!dev) { 542 487 usb_log_error("Failed to create function for the root hub."); … … 561 506 562 507 err_usb_dev: 563 hcd_ddf_ device_destroy(dev);508 hcd_ddf_fun_destroy(dev); 564 509 err_default_address: 565 510 bus_release_default_address(hcd->bus); … … 577 522 * This function does all the ddf work for hc driver. 578 523 */ 579 int hcd_ddf_setup_hc(ddf_dev_t *device )524 int hcd_ddf_setup_hc(ddf_dev_t *device, size_t size) 580 525 { 581 526 assert(device); 582 527 583 hc_dev _t *instance = ddf_dev_data_alloc(device, sizeof(hc_dev_t));528 hc_device_t *instance = ddf_dev_data_alloc(device, size); 584 529 if (instance == NULL) { 585 530 usb_log_error("Failed to allocate HCD ddf structure.\n"); 586 531 return ENOMEM; 587 532 } 588 hcd_init(&instance->hcd);533 instance->ddf_dev = device; 589 534 590 535 int ret = ENOMEM; … … 618 563 } 619 564 620 void hcd_ddf_clean_hc(ddf_dev_t *device) 621 { 622 assert(device); 623 hc_dev_t *hc = dev_to_hc_dev(device); 624 assert(hc); 625 const int ret = ddf_fun_unbind(hc->ctl_fun); 626 if (ret == EOK) 627 ddf_fun_destroy(hc->ctl_fun); 628 } 629 630 //TODO: Cache parent session in HCD 565 void hcd_ddf_clean_hc(hc_device_t *hcd) 566 { 567 if (ddf_fun_unbind(hcd->ctl_fun) == EOK) 568 ddf_fun_destroy(hcd->ctl_fun); 569 } 570 631 571 /** Call the parent driver with a request to enable interrupt 632 572 * … … 635 575 * @return Error code. 636 576 */ 637 int hcd_ddf_enable_interrupt( ddf_dev_t *device, int inum)638 { 639 async_sess_t *parent_sess = ddf_dev_parent_sess_get( device);577 int hcd_ddf_enable_interrupt(hc_device_t *hcd, int inum) 578 { 579 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 640 580 if (parent_sess == NULL) 641 581 return EIO; … … 644 584 } 645 585 646 //TODO: Cache parent session in HCD 647 int hcd_ddf_get_registers(ddf_dev_t *device, hw_res_list_parsed_t *hw_res) 648 { 649 async_sess_t *parent_sess = ddf_dev_parent_sess_get(device); 586 int hcd_ddf_get_registers(hc_device_t *hcd, hw_res_list_parsed_t *hw_res) 587 { 588 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 650 589 if (parent_sess == NULL) 651 590 return EIO; … … 658 597 } 659 598 660 // TODO: move this someplace else661 static inline void irq_code_clean(irq_code_t *code)662 {663 if (code) {664 free(code->ranges);665 free(code->cmds);666 code->ranges = NULL;667 code->cmds = NULL;668 code->rangecount = 0;669 code->cmdcount = 0;670 }671 }672 673 /** Register interrupt handler674 *675 * @param[in] device Host controller DDF device676 * @param[in] regs Register range677 * @param[in] irq Interrupt number678 * @paran[in] handler Interrupt handler679 * @param[in] gen_irq_code IRQ code generator.680 *681 * @return IRQ capability handle on success.682 * @return Negative error code.683 */684 int hcd_ddf_setup_interrupts(ddf_dev_t *device,685 const hw_res_list_parsed_t *hw_res,686 interrupt_handler_t handler,687 irq_code_gen_t gen_irq_code)688 {689 assert(device);690 691 hcd_t *hcd = dev_to_hcd(device);692 693 if (!handler || !gen_irq_code)694 return ENOTSUP;695 696 irq_code_t irq_code = {0};697 698 const int irq = gen_irq_code(&irq_code, hcd, hw_res);699 if (irq < 0) {700 usb_log_error("Failed to generate IRQ code: %s.\n",701 str_error(irq));702 return irq;703 }704 705 /* Register handler to avoid interrupt lockup */706 const int irq_cap = register_interrupt_handler(device, irq, handler,707 &irq_code);708 irq_code_clean(&irq_code);709 if (irq_cap < 0) {710 usb_log_error("Failed to register interrupt handler: %s.\n",711 str_error(irq_cap));712 return irq_cap;713 }714 715 /* Enable interrupts */716 int ret = hcd_ddf_enable_interrupt(device, irq);717 if (ret != EOK) {718 usb_log_error("Failed to enable interrupts: %s.\n",719 str_error(ret));720 unregister_interrupt_handler(device, irq_cap);721 return ret;722 }723 return irq_cap;724 }725 726 /** IRQ handling callback, forward status from call to diver structure.727 *728 * @param[in] dev DDF instance of the device to use.729 * @param[in] iid (Unused).730 * @param[in] call Pointer to the call from kernel.731 */732 void ddf_hcd_gen_irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev)733 {734 assert(dev);735 hcd_t *hcd = dev_to_hcd(dev);736 if (!hcd || !hcd->ops.irq_hook) {737 usb_log_error("Interrupt on not yet initialized device.\n");738 return;739 }740 const uint32_t status = IPC_GET_ARG1(*call);741 hcd->ops.irq_hook(hcd, status);742 }743 744 static int interrupt_polling(void *arg)745 {746 hcd_t *hcd = arg;747 assert(hcd);748 if (!hcd->ops.status_hook || !hcd->ops.irq_hook)749 return ENOTSUP;750 uint32_t status = 0;751 while (hcd->ops.status_hook(hcd, &status) == EOK) {752 hcd->ops.irq_hook(hcd, status);753 status = 0;754 /* We should wait 1 frame - 1ms here, but this polling is a755 * lame crutch anyway so don't hog the system. 10ms is still756 * good enough for emergency mode */757 async_usleep(10000);758 }759 return EOK;760 }761 762 /** Initialize hc and rh DDF structures and their respective drivers.763 *764 * @param device DDF instance of the device to use765 * @param speed Maximum supported speed766 * @param bw Available bandwidth (arbitrary units)767 * @param bw_count Bandwidth computing function768 * @param irq_handler IRQ handling function769 * @param gen_irq_code Function to generate IRQ pseudocode770 * (it needs to return used irq number)771 * @param driver_init Function to initialize HC driver772 * @param driver_fini Function to cleanup HC driver773 * @return Error code774 *775 * This function does all the preparatory work for hc and rh drivers:776 * - gets device's hw resources777 * - attempts to enable interrupts778 * - registers interrupt handler779 * - calls driver specific initialization780 * - registers root hub781 */782 int hcd_ddf_add_hc(ddf_dev_t *device, const ddf_hc_driver_t *driver)783 {784 assert(driver);785 786 int ret = EOK;787 788 hw_res_list_parsed_t hw_res;789 ret = hcd_ddf_get_registers(device, &hw_res);790 if (ret != EOK) {791 usb_log_error("Failed to get register memory addresses "792 "for `%s': %s.\n", ddf_dev_get_name(device),793 str_error(ret));794 return ret;795 }796 797 ret = hcd_ddf_setup_hc(device);798 if (ret != EOK) {799 usb_log_error("Failed to setup generic HCD.\n");800 goto err_hw_res;801 }802 803 hcd_t *hcd = dev_to_hcd(device);804 805 if (driver->init)806 ret = driver->init(hcd, &hw_res, device);807 if (ret != EOK) {808 usb_log_error("Failed to init HCD.\n");809 goto err_hcd;810 }811 812 /* Setup interrupts */813 interrupt_handler_t *irq_handler =814 driver->irq_handler ? driver->irq_handler : ddf_hcd_gen_irq_handler;815 const int irq_cap = hcd_ddf_setup_interrupts(device, &hw_res,816 irq_handler, driver->irq_code_gen);817 bool irqs_enabled = !(irq_cap < 0);818 if (irqs_enabled) {819 usb_log_debug("Hw interrupts enabled.\n");820 }821 822 /* Claim the device from BIOS */823 if (driver->claim)824 ret = driver->claim(hcd, device);825 if (ret != EOK) {826 usb_log_error("Failed to claim `%s' for driver `%s': %s",827 ddf_dev_get_name(device), driver->name, str_error(ret));828 goto err_irq;829 }830 831 /* Start hw driver */832 if (driver->start)833 ret = driver->start(hcd, irqs_enabled);834 if (ret != EOK) {835 usb_log_error("Failed to start HCD: %s.\n", str_error(ret));836 goto err_irq;837 }838 839 /* Need working irq replacement to setup root hub */840 if (!irqs_enabled && hcd->ops.status_hook) {841 hcd->polling_fibril = fibril_create(interrupt_polling, hcd);842 if (hcd->polling_fibril == 0) {843 usb_log_error("Failed to create polling fibril\n");844 ret = ENOMEM;845 goto err_started;846 }847 fibril_add_ready(hcd->polling_fibril);848 usb_log_warning("Failed to enable interrupts: %s."849 " Falling back to polling.\n", str_error(irq_cap));850 }851 852 /*853 * Creating root hub registers a new USB device so HC854 * needs to be ready at this time.855 */856 if (driver->setup_root_hub)857 ret = driver->setup_root_hub(hcd, device);858 if (ret != EOK) {859 usb_log_error("Failed to setup HC root hub: %s.\n",860 str_error(ret));861 goto err_polling;862 }863 864 usb_log_info("Controlling new `%s' device `%s'.\n",865 driver->name, ddf_dev_get_name(device));866 return EOK;867 868 err_polling:869 // TODO: Stop the polling fibril (refactor the interrupt_polling func)870 //871 err_started:872 if (driver->stop)873 driver->stop(hcd);874 err_irq:875 unregister_interrupt_handler(device, irq_cap);876 if (driver->fini)877 driver->fini(hcd);878 err_hcd:879 hcd_ddf_clean_hc(device);880 err_hw_res:881 hw_res_list_parsed_clean(&hw_res);882 return ret;883 }884 885 599 /** 886 600 * @}
Note:
See TracChangeset
for help on using the changeset viewer.