Changeset 32fb6bce in mainline for uspace/lib/usbhost/src
- Timestamp:
- 2017-12-18T22:50:21Z (8 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)
- Location:
- uspace/lib/usbhost/src
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/src/bus.c
r1ea0bbf r32fb6bce 46 46 * Initializes the bus structure. 47 47 */ 48 void bus_init(bus_t *bus, hcd_t *hcd, size_t device_size) 49 { 50 assert(bus); 51 assert(hcd); 48 void bus_init(bus_t *bus, size_t device_size) 49 { 50 assert(bus); 52 51 assert(device_size >= sizeof(device_t)); 53 52 memset(bus, 0, sizeof(bus_t)); 54 53 55 54 fibril_mutex_initialize(&bus->guard); 56 bus->hcd = hcd;57 55 bus->device_size = device_size; 58 56 } … … 61 59 { 62 60 assert(bus); 63 assert(bus->hcd);64 61 65 62 memset(dev, 0, sizeof(*dev)); … … 258 255 } 259 256 257 /** Prepare generic usb_transfer_batch and schedule it. 258 * @param device Device for which to send the batch 259 * @param target address and endpoint number. 260 * @param setup_data Data to use in setup stage (Control communication type) 261 * @param in Callback for device to host communication. 262 * @param out Callback for host to device communication. 263 * @param arg Callback parameter. 264 * @param name Communication identifier (for nicer output). 265 * @return Error code. 266 */ 267 int bus_device_send_batch(device_t *device, usb_target_t target, 268 usb_direction_t direction, char *data, size_t size, uint64_t setup_data, 269 usbhc_iface_transfer_callback_t on_complete, void *arg, const char *name) 270 { 271 assert(device->address == target.address); 272 273 /* Temporary reference */ 274 endpoint_t *ep = bus_find_endpoint(device, target, direction); 275 if (ep == NULL) { 276 usb_log_error("Endpoint(%d:%d) not registered for %s.\n", 277 device->address, target.endpoint, name); 278 return ENOENT; 279 } 280 281 assert(ep->device == device); 282 283 const int err = endpoint_send_batch(ep, target, direction, data, size, setup_data, 284 on_complete, arg, name); 285 286 /* Temporary reference */ 287 endpoint_del_ref(ep); 288 289 return err; 290 } 291 292 typedef struct { 293 fibril_mutex_t done_mtx; 294 fibril_condvar_t done_cv; 295 unsigned done; 296 297 size_t transfered_size; 298 int error; 299 } sync_data_t; 300 301 static int sync_transfer_complete(void *arg, int error, size_t transfered_size) 302 { 303 sync_data_t *d = arg; 304 assert(d); 305 d->transfered_size = transfered_size; 306 d->error = error; 307 fibril_mutex_lock(&d->done_mtx); 308 d->done = 1; 309 fibril_condvar_broadcast(&d->done_cv); 310 fibril_mutex_unlock(&d->done_mtx); 311 return EOK; 312 } 313 314 ssize_t bus_device_send_batch_sync(device_t *device, usb_target_t target, 315 usb_direction_t direction, char *data, size_t size, uint64_t setup_data, 316 const char *name) 317 { 318 sync_data_t sd = { .done = 0 }; 319 fibril_mutex_initialize(&sd.done_mtx); 320 fibril_condvar_initialize(&sd.done_cv); 321 322 const int ret = bus_device_send_batch(device, target, direction, 323 data, size, setup_data, 324 sync_transfer_complete, &sd, name); 325 if (ret != EOK) 326 return ret; 327 328 fibril_mutex_lock(&sd.done_mtx); 329 while (!sd.done) { 330 fibril_condvar_wait_timeout(&sd.done_cv, &sd.done_mtx, 3000000); 331 if (!sd.done) 332 usb_log_debug2("Still waiting..."); 333 } 334 fibril_mutex_unlock(&sd.done_mtx); 335 336 return (sd.error == EOK) 337 ? (ssize_t) sd.transfered_size 338 : (ssize_t) sd.error; 339 } 340 260 341 /** 261 342 * @} -
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 * @} -
uspace/lib/usbhost/src/endpoint.c
r1ea0bbf r32fb6bce 39 39 #include <mem.h> 40 40 #include <stdlib.h> 41 #include <str_error.h> 42 #include <usb/debug.h> 43 #include <usb/host/hcd.h> 41 44 42 45 #include "usb_transfer_batch.h" … … 187 190 } 188 191 192 /** Prepare generic usb_transfer_batch and schedule it. 193 * @param ep Endpoint for which the batch shall be created. 194 * @param target address and endpoint number. 195 * @param setup_data Data to use in setup stage (Control communication type) 196 * @param in Callback for device to host communication. 197 * @param out Callback for host to device communication. 198 * @param arg Callback parameter. 199 * @param name Communication identifier (for nicer output). 200 * @return Error code. 201 */ 202 int endpoint_send_batch(endpoint_t *ep, usb_target_t target, 203 usb_direction_t direction, char *data, size_t size, uint64_t setup_data, 204 usbhc_iface_transfer_callback_t on_complete, void *arg, const char *name) 205 { 206 usb_log_debug2("%s %d:%d %zu(%zu).\n", 207 name, target.address, target.endpoint, size, ep->max_packet_size); 208 209 bus_t *bus = endpoint_get_bus(ep); 210 const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, batch_schedule); 211 if (!ops) { 212 usb_log_error("HCD does not implement scheduler.\n"); 213 return ENOTSUP; 214 } 215 216 const size_t bw = endpoint_count_bw(ep, size); 217 /* Check if we have enough bandwidth reserved */ 218 if (ep->bandwidth < bw) { 219 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 220 "but only %zu is reserved.\n", 221 ep->device->address, ep->endpoint, name, bw, ep->bandwidth); 222 return ENOSPC; 223 } 224 225 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep); 226 if (!batch) { 227 usb_log_error("Failed to create transfer batch.\n"); 228 return ENOMEM; 229 } 230 231 batch->target = target; 232 batch->buffer = data; 233 batch->buffer_size = size; 234 batch->setup.packed = setup_data; 235 batch->dir = direction; 236 batch->on_complete = on_complete; 237 batch->on_complete_data = arg; 238 239 /* Check for commands that reset toggle bit */ 240 if (ep->transfer_type == USB_TRANSFER_CONTROL) 241 batch->toggle_reset_mode 242 = hcd_get_request_toggle_reset_mode(&batch->setup.packet); 243 244 const int ret = ops->batch_schedule(batch); 245 if (ret != EOK) { 246 usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret)); 247 usb_transfer_batch_destroy(batch); 248 } 249 250 return ret; 251 } 252 189 253 /** 190 254 * @} -
uspace/lib/usbhost/src/hcd.c
r1ea0bbf r32fb6bce 36 36 #include <assert.h> 37 37 #include <async.h> 38 #include <ddf/interrupt.h> 38 39 #include <errno.h> 39 40 #include <macros.h> … … 45 46 46 47 #include "bus.h" 48 #include "ddf_helpers.h" 47 49 #include "endpoint.h" 48 50 #include "usb_transfer_batch.h" … … 50 52 #include "hcd.h" 51 53 52 53 /** Initialize hcd_t structure. 54 * Initializes device and endpoint managers. Sets data and hook pointer to NULL. 55 * 56 * @param hcd hcd_t structure to initialize, non-null. 57 * @param max_speed Maximum supported USB speed (full, high). 58 * @param bandwidth Available bandwidth, passed to endpoint manager. 59 * @param bw_count Bandwidth compute function, passed to endpoint manager. 60 */ 61 void hcd_init(hcd_t *hcd) { 54 int hc_dev_add(ddf_dev_t *); 55 int hc_dev_remove(ddf_dev_t *); 56 int hc_dev_gone(ddf_dev_t *); 57 int hc_fun_online(ddf_fun_t *); 58 int hc_fun_offline(ddf_fun_t *); 59 60 static driver_ops_t hc_driver_ops = { 61 .dev_add = hc_dev_add, 62 .dev_remove = hc_dev_remove, 63 .dev_gone = hc_dev_gone, 64 .fun_online = hc_fun_offline, 65 .fun_offline = hc_fun_offline, 66 }; 67 68 static const hc_driver_t *hc_driver; 69 70 int hc_driver_main(const hc_driver_t *driver) 71 { 72 driver_t ddf_driver = { 73 .name = driver->name, 74 .driver_ops = &hc_driver_ops, 75 }; 76 77 /* Remember ops to call. */ 78 hc_driver = driver; 79 80 return ddf_driver_main(&ddf_driver); 81 } 82 83 /** IRQ handling callback, forward status from call to diver structure. 84 * 85 * @param[in] dev DDF instance of the device to use. 86 * @param[in] iid (Unused). 87 * @param[in] call Pointer to the call from kernel. 88 */ 89 static void irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev) 90 { 91 assert(dev); 92 hc_device_t *hcd = dev_to_hcd(dev); 93 94 const bus_ops_t *ops = BUS_OPS_LOOKUP(hcd->bus->ops, interrupt); 95 assert(ops); 96 97 const uint32_t status = IPC_GET_ARG1(*call); 98 ops->interrupt(hcd->bus, status); 99 } 100 101 /** Worker for the HW interrupt replacement fibril. 102 */ 103 static int interrupt_polling(void *arg) 104 { 105 hc_device_t *hcd = arg; 62 106 assert(hcd); 63 64 hcd_set_implementation(hcd, NULL, NULL, NULL); 107 bus_t *bus = hcd->bus; 108 109 const bus_ops_t *interrupt_ops = BUS_OPS_LOOKUP(bus->ops, interrupt); 110 const bus_ops_t *status_ops = BUS_OPS_LOOKUP(bus->ops, status); 111 if (!interrupt_ops || !status_ops) 112 return ENOTSUP; 113 114 uint32_t status = 0; 115 while (status_ops->status(bus, &status) == EOK) { 116 interrupt_ops->interrupt(bus, status); 117 status = 0; 118 /* We should wait 1 frame - 1ms here, but this polling is a 119 * lame crutch anyway so don't hog the system. 10ms is still 120 * good enough for emergency mode */ 121 async_usleep(10000); 122 } 123 return EOK; 124 } 125 126 static inline void irq_code_clean(irq_code_t *code) 127 { 128 if (code) { 129 free(code->ranges); 130 free(code->cmds); 131 code->ranges = NULL; 132 code->cmds = NULL; 133 code->rangecount = 0; 134 code->cmdcount = 0; 135 } 136 } 137 138 /** Register interrupt handler 139 * 140 * @param[in] device Host controller DDF device 141 * @param[in] regs Register range 142 * @param[in] irq Interrupt number 143 * @paran[in] handler Interrupt handler 144 * @param[in] gen_irq_code IRQ code generator. 145 * 146 * @return IRQ capability handle on success. 147 * @return Negative error code. 148 */ 149 static int hcd_ddf_setup_interrupts(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res) 150 { 151 assert(hcd); 152 irq_code_t irq_code = {0}; 153 154 if (!hc_driver->irq_code_gen) 155 return ENOTSUP; 156 157 const int irq = hc_driver->irq_code_gen(&irq_code, hcd, hw_res); 158 if (irq < 0) { 159 usb_log_error("Failed to generate IRQ code: %s.\n", 160 str_error(irq)); 161 return irq; 162 } 163 164 /* Register handler to avoid interrupt lockup */ 165 const int irq_cap = register_interrupt_handler(hcd->ddf_dev, irq, irq_handler, &irq_code); 166 irq_code_clean(&irq_code); 167 if (irq_cap < 0) { 168 usb_log_error("Failed to register interrupt handler: %s.\n", 169 str_error(irq_cap)); 170 return irq_cap; 171 } 172 173 /* Enable interrupts */ 174 int ret = hcd_ddf_enable_interrupt(hcd, irq); 175 if (ret != EOK) { 176 usb_log_error("Failed to enable interrupts: %s.\n", 177 str_error(ret)); 178 unregister_interrupt_handler(hcd->ddf_dev, irq_cap); 179 return ret; 180 } 181 return irq_cap; 182 } 183 184 /** Initialize HC in memory of the driver. 185 * 186 * @param device DDF instance of the device to use 187 * @return Error code 188 * 189 * This function does all the preparatory work for hc and rh drivers: 190 * - gets device's hw resources 191 * - attempts to enable interrupts 192 * - registers interrupt handler 193 * - calls driver specific initialization 194 * - registers root hub 195 */ 196 int hc_dev_add(ddf_dev_t *device) 197 { 198 int ret = EOK; 199 assert(device); 200 201 if (!hc_driver->hc_add) { 202 usb_log_error("Driver '%s' does not support adding devices.", hc_driver->name); 203 return ENOTSUP; 204 } 205 206 ret = hcd_ddf_setup_hc(device, hc_driver->hc_device_size); 207 if (ret != EOK) { 208 usb_log_error("Failed to setup HC device.\n"); 209 return ret; 210 } 211 212 hc_device_t *hcd = dev_to_hcd(device); 213 214 hw_res_list_parsed_t hw_res; 215 ret = hcd_ddf_get_registers(hcd, &hw_res); 216 if (ret != EOK) { 217 usb_log_error("Failed to get register memory addresses " 218 "for `%s': %s.\n", ddf_dev_get_name(device), 219 str_error(ret)); 220 goto err_hcd; 221 } 222 223 ret = hc_driver->hc_add(hcd, &hw_res); 224 if (ret != EOK) { 225 usb_log_error("Failed to init HCD.\n"); 226 goto err_hw_res; 227 } 228 229 assert(hcd->bus); 230 231 /* Setup interrupts */ 232 hcd->irq_cap = hcd_ddf_setup_interrupts(hcd, &hw_res); 233 if (hcd->irq_cap >= 0) { 234 usb_log_debug("Hw interrupts enabled.\n"); 235 } 236 237 /* Claim the device from BIOS */ 238 if (hc_driver->claim) 239 ret = hc_driver->claim(hcd); 240 if (ret != EOK) { 241 usb_log_error("Failed to claim `%s' for `%s': %s", 242 ddf_dev_get_name(device), hc_driver->name, str_error(ret)); 243 goto err_irq; 244 } 245 246 /* Start hw */ 247 if (hc_driver->start) 248 ret = hc_driver->start(hcd); 249 if (ret != EOK) { 250 usb_log_error("Failed to start HCD: %s.\n", str_error(ret)); 251 goto err_irq; 252 } 253 254 const bus_ops_t *ops = BUS_OPS_LOOKUP(hcd->bus->ops, status); 255 256 /* Need working irq replacement to setup root hub */ 257 if (hcd->irq_cap < 0 && ops) { 258 hcd->polling_fibril = fibril_create(interrupt_polling, hcd->bus); 259 if (!hcd->polling_fibril) { 260 usb_log_error("Failed to create polling fibril\n"); 261 ret = ENOMEM; 262 goto err_started; 263 } 264 fibril_add_ready(hcd->polling_fibril); 265 usb_log_warning("Failed to enable interrupts: %s." 266 " Falling back to polling.\n", str_error(hcd->irq_cap)); 267 } 268 269 /* 270 * Creating root hub registers a new USB device so HC 271 * needs to be ready at this time. 272 */ 273 if (hc_driver->setup_root_hub) 274 ret = hc_driver->setup_root_hub(hcd); 275 if (ret != EOK) { 276 usb_log_error("Failed to setup HC root hub: %s.\n", 277 str_error(ret)); 278 goto err_polling; 279 } 280 281 usb_log_info("Controlling new `%s' device `%s'.\n", 282 hc_driver->name, ddf_dev_get_name(device)); 283 return EOK; 284 285 err_polling: 286 // TODO: Stop the polling fibril (refactor the interrupt_polling func) 287 // 288 err_started: 289 if (hc_driver->stop) 290 hc_driver->stop(hcd); 291 err_irq: 292 unregister_interrupt_handler(device, hcd->irq_cap); 293 if (hc_driver->hc_remove) 294 hc_driver->hc_remove(hcd); 295 err_hw_res: 296 hw_res_list_parsed_clean(&hw_res); 297 err_hcd: 298 hcd_ddf_clean_hc(hcd); 299 return ret; 300 } 301 302 int hc_dev_remove(ddf_dev_t *dev) 303 { 304 int err; 305 hc_device_t *hcd = dev_to_hcd(dev); 306 307 if (hc_driver->stop) 308 if ((err = hc_driver->stop(hcd))) 309 return err; 310 311 unregister_interrupt_handler(dev, hcd->irq_cap); 312 313 if (hc_driver->hc_remove) 314 if ((err = hc_driver->hc_remove(hcd))) 315 return err; 316 317 hcd_ddf_clean_hc(hcd); 318 319 // TODO probably not complete 320 321 return EOK; 322 } 323 324 int hc_dev_gone(ddf_dev_t *dev) 325 { 326 int err = ENOTSUP; 327 hc_device_t *hcd = dev_to_hcd(dev); 328 329 if (hc_driver->hc_gone) 330 err = hc_driver->hc_gone(hcd); 331 332 hcd_ddf_clean_hc(hcd); 333 334 return err; 335 } 336 337 int hc_fun_online(ddf_fun_t *fun) 338 { 339 assert(fun); 340 341 device_t *dev = ddf_fun_data_get(fun); 342 assert(dev); 343 344 usb_log_info("Device(%d): Requested to be brought online.", dev->address); 345 return bus_device_online(dev); 346 } 347 348 int hc_fun_offline(ddf_fun_t *fun) 349 { 350 assert(fun); 351 352 device_t *dev = ddf_fun_data_get(fun); 353 assert(dev); 354 355 usb_log_info("Device(%d): Requested to be taken offline.", dev->address); 356 return bus_device_offline(dev); 65 357 } 66 358 … … 72 364 * @return Max packet size for EP 0 73 365 */ 74 int hcd_get_ep0_max_packet_size(uint16_t *mps, hcd_t *hcd, device_t *dev)366 int hcd_get_ep0_max_packet_size(uint16_t *mps, bus_t *bus, device_t *dev) 75 367 { 76 368 assert(mps); … … 97 389 98 390 usb_log_debug("Requesting first 8B of device descriptor to determine MPS."); 99 ssize_t got = hcd_send_batch_sync(hcd,dev, control_ep, USB_DIRECTION_IN,391 ssize_t got = bus_device_send_batch_sync(dev, control_ep, USB_DIRECTION_IN, 100 392 (char *) &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8, 101 393 "read first 8 bytes of dev descriptor"); … … 156 448 * 157 449 */ 158 statictoggle_reset_mode_t hcd_get_request_toggle_reset_mode(450 toggle_reset_mode_t hcd_get_request_toggle_reset_mode( 159 451 const usb_device_request_setup_packet_t *request) 160 452 { … … 186 478 } 187 479 188 /** Prepare generic usb_transfer_batch and schedule it.189 * @param hcd Host controller driver.190 * @param target address and endpoint number.191 * @param setup_data Data to use in setup stage (Control communication type)192 * @param in Callback for device to host communication.193 * @param out Callback for host to device communication.194 * @param arg Callback parameter.195 * @param name Communication identifier (for nicer output).196 * @return Error code.197 */198 int hcd_send_batch(hcd_t *hcd, device_t *device, usb_target_t target,199 usb_direction_t direction, char *data, size_t size, uint64_t setup_data,200 usbhc_iface_transfer_callback_t on_complete, void *arg, const char *name)201 {202 assert(hcd);203 assert(device->address == target.address);204 205 if (!hcd->ops.schedule) {206 usb_log_error("HCD does not implement scheduler.\n");207 return ENOTSUP;208 }209 210 endpoint_t *ep = bus_find_endpoint(device, target, direction);211 if (ep == NULL) {212 usb_log_error("Endpoint(%d:%d) not registered for %s.\n",213 device->address, target.endpoint, name);214 return ENOENT;215 }216 217 // TODO cut here aka provide helper to call with instance of endpoint_t in hand218 assert(ep->device == device);219 220 usb_log_debug2("%s %d:%d %zu(%zu).\n",221 name, target.address, target.endpoint, size, ep->max_packet_size);222 223 const size_t bw = endpoint_count_bw(ep, size);224 /* Check if we have enough bandwidth reserved */225 if (ep->bandwidth < bw) {226 usb_log_error("Endpoint(%d:%d) %s needs %zu bw "227 "but only %zu is reserved.\n",228 device->address, ep->endpoint, name, bw, ep->bandwidth);229 return ENOSPC;230 }231 232 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep);233 if (!batch) {234 usb_log_error("Failed to create transfer batch.\n");235 return ENOMEM;236 }237 238 batch->target = target;239 batch->buffer = data;240 batch->buffer_size = size;241 batch->setup.packed = setup_data;242 batch->dir = direction;243 batch->on_complete = on_complete;244 batch->on_complete_data = arg;245 246 /* Check for commands that reset toggle bit */247 if (ep->transfer_type == USB_TRANSFER_CONTROL)248 batch->toggle_reset_mode249 = hcd_get_request_toggle_reset_mode(&batch->setup.packet);250 251 const int ret = hcd->ops.schedule(hcd, batch);252 if (ret != EOK) {253 usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret));254 usb_transfer_batch_destroy(batch);255 }256 257 /* Drop our own reference to ep. */258 endpoint_del_ref(ep);259 260 return ret;261 }262 263 typedef struct {264 fibril_mutex_t done_mtx;265 fibril_condvar_t done_cv;266 unsigned done;267 268 size_t transfered_size;269 int error;270 } sync_data_t;271 272 static int sync_transfer_complete(void *arg, int error, size_t transfered_size)273 {274 sync_data_t *d = arg;275 assert(d);276 d->transfered_size = transfered_size;277 d->error = error;278 fibril_mutex_lock(&d->done_mtx);279 d->done = 1;280 fibril_condvar_broadcast(&d->done_cv);281 fibril_mutex_unlock(&d->done_mtx);282 return EOK;283 }284 285 ssize_t hcd_send_batch_sync(hcd_t *hcd, device_t *device, usb_target_t target,286 usb_direction_t direction, char *data, size_t size, uint64_t setup_data,287 const char *name)288 {289 assert(hcd);290 sync_data_t sd = { .done = 0 };291 fibril_mutex_initialize(&sd.done_mtx);292 fibril_condvar_initialize(&sd.done_cv);293 294 const int ret = hcd_send_batch(hcd, device, target, direction,295 data, size, setup_data,296 sync_transfer_complete, &sd, name);297 if (ret != EOK)298 return ret;299 300 fibril_mutex_lock(&sd.done_mtx);301 while (!sd.done)302 fibril_condvar_wait(&sd.done_cv, &sd.done_mtx);303 fibril_mutex_unlock(&sd.done_mtx);304 305 return (sd.error == EOK)306 ? (ssize_t) sd.transfered_size307 : (ssize_t) sd.error;308 }309 310 480 311 481 /** -
uspace/lib/usbhost/src/usb2_bus.c
r1ea0bbf r32fb6bce 205 205 206 206 usb2_bus_t *bus = (usb2_bus_t *) dev->bus; 207 hcd_t *hcd = (hcd_t *) bus->base.hcd;208 207 209 208 /* The default address is currently reserved for this device */ … … 231 230 232 231 uint16_t max_packet_size; 233 if ((err = hcd_get_ep0_max_packet_size(&max_packet_size, hcd, dev)))232 if ((err = hcd_get_ep0_max_packet_size(&max_packet_size, &bus->base, dev))) 234 233 goto err_address; 235 234 … … 238 237 239 238 usb_log_debug("Device(%d): Setting USB address.", address); 240 err = hcd_send_batch_sync(hcd,dev, usb2_default_target, USB_DIRECTION_OUT,239 err = bus_device_send_batch_sync(dev, usb2_default_target, USB_DIRECTION_OUT, 241 240 NULL, 0, *(uint64_t *)&set_address, "set address"); 242 241 if (err != 0) { … … 315 314 316 315 /* Read the device descriptor, derive the match ids */ 317 if ((err = hcd_d df_device_explore(dev))) {316 if ((err = hcd_device_explore(dev))) { 318 317 usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err)); 319 318 release_address(bus, dev->address); … … 463 462 * @return Error code. 464 463 */ 465 int usb2_bus_init(usb2_bus_t *bus, hcd_t *hcd,size_t available_bandwidth)464 int usb2_bus_init(usb2_bus_t *bus, size_t available_bandwidth) 466 465 { 467 466 assert(bus); 468 467 469 bus_init(&bus->base, hcd,sizeof(device_t));468 bus_init(&bus->base, sizeof(device_t)); 470 469 bus->base.ops = &usb2_bus_ops; 471 470
Note:
See TracChangeset
for help on using the changeset viewer.