Ignore:
Timestamp:
2017-12-18T22:50:21Z (6 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
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)
Message:

usbhost: refactoring

This commit moves interrupt, status and schedule to bus
operations. Then the purpose of hcd_t is better defined, and split into
hc_driver_t and hc_device_t. hc_driver_t is used to wrap driver
implementation by the library (similar to how usb_driver_t is used to
wrap usb device drivers). hc_device_t is used as a parent for hc_t
inside drivers, and is allocated inside the DDF device node.

To support these changes, some local identifiers were renamed, some
functions were moved and/or renamed and their arguments changed. The
most notable one being hcd_send_batch → bus_device_send_batch.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usbhost/src/ddf_helpers.c

    r1ea0bbf r32fb6bce  
    5353#include "ddf_helpers.h"
    5454
    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
     56static int hcd_ddf_new_device(hc_device_t *hcd, ddf_dev_t *hc, device_t *hub_dev, unsigned port);
    7757static int hcd_ddf_remove_device(ddf_dev_t *device, device_t *hub, unsigned port);
    7858
     
    8969{
    9070        assert(fun);
    91         hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
     71        hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    9272        device_t *dev = ddf_fun_data_get(fun);
    9373        assert(hcd);
     
    11393{
    11494        assert(fun);
    115         hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
     95        hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    11696        device_t *dev = ddf_fun_data_get(fun);
    11797        assert(hcd);
     
    138118{
    139119        assert(fun);
    140         hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
     120        hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    141121        device_t *dev = ddf_fun_data_get(fun);
    142122        assert(hcd);
     
    152132{
    153133        assert(fun);
    154         hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
     134        hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    155135        device_t *dev = ddf_fun_data_get(fun);
    156136        assert(hcd);
     
    167147        ddf_dev_t *hc = ddf_fun_get_dev(fun);
    168148        assert(hc);
    169         hcd_t *hcd = dev_to_hcd(hc);
     149        hc_device_t *hcd = dev_to_hcd(hc);
    170150        assert(hcd);
    171151        device_t *hub = ddf_fun_data_get(fun);
     
    218198{
    219199        assert(fun);
    220         hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    221200        device_t *dev = ddf_fun_data_get(fun);
    222201        assert(dev);
     
    224203        target.address = dev->address;
    225204
    226         return hcd_send_batch(hcd, dev, target, USB_DIRECTION_IN,
     205        return bus_device_send_batch(dev, target, USB_DIRECTION_IN,
    227206            data, size, setup_data,
    228207            callback, arg, "READ");
     
    244223{
    245224        assert(fun);
    246         hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
    247225        device_t *dev = ddf_fun_data_get(fun);
    248226        assert(dev);
     
    250228        target.address = dev->address;
    251229
    252         return hcd_send_batch(hcd, dev, target, USB_DIRECTION_OUT,
     230        return bus_device_send_batch(dev, target, USB_DIRECTION_OUT,
    253231            (char *) data, size, setup_data,
    254232            callback, arg, "WRITE");
     
    337315        assert(device);
    338316
    339         hcd_t *hcd = dev_to_hcd(device);
     317        hc_device_t *hcd = dev_to_hcd(device);
    340318        assert(hcd);
    341319        assert(hcd->bus);
    342 
    343         hc_dev_t *hc_dev = dev_to_hc_dev(device);
    344         assert(hc_dev);
    345320
    346321        fibril_mutex_lock(&hub->guard);
     
    374349}
    375350
    376 device_t *hcd_ddf_device_create(ddf_dev_t *hc, bus_t *bus)
     351device_t *hcd_ddf_fun_create(hc_device_t *hc)
    377352{
    378353        /* 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);
    380355        if (!fun)
    381356                return NULL;
     
    384359
    385360        /* 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);
    387362        if (!dev) {
    388363                ddf_fun_destroy(fun);
     
    390365        }
    391366
    392         bus_device_init(dev, bus);
     367        bus_device_init(dev, hc->bus);
    393368        dev->fun = fun;
    394369        return dev;
    395370}
    396371
    397 void hcd_ddf_device_destroy(device_t *dev)
     372void hcd_ddf_fun_destroy(device_t *dev)
    398373{
    399374        assert(dev);
     
    402377}
    403378
    404 int hcd_ddf_device_explore(device_t *device)
     379int hcd_device_explore(device_t *device)
    405380{
    406381        int err;
     
    421396        usb_log_debug("Device(%d): Requesting full device descriptor.",
    422397            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,
    424399            (char *) &desc, sizeof(desc), *(uint64_t *)&get_device_desc,
    425400            "read device descriptor");
     
    447422}
    448423
    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)
     424static int hcd_ddf_new_device(hc_device_t *hcd, ddf_dev_t *hc, device_t *hub, unsigned port)
    478425{
    479426        int err;
     
    483430        assert(hc);
    484431
    485         device_t *dev = hcd_ddf_device_create(hc, hcd->bus);
     432        device_t *dev = hcd_ddf_fun_create(hcd);
    486433        if (!dev) {
    487434                usb_log_error("Failed to create USB device function.");
     
    516463
    517464err_usb_dev:
    518         hcd_ddf_device_destroy(dev);
     465        hcd_ddf_fun_destroy(dev);
    519466        return err;
    520467}
     
    525472 * @return Error code
    526473 */
    527 int hcd_setup_virtual_root_hub(hcd_t *hcd, ddf_dev_t *hc)
     474int hcd_setup_virtual_root_hub(hc_device_t *hcd)
    528475{
    529476        int err;
    530477
    531         assert(hc);
    532         assert(hcd);
    533         assert(hcd->bus);
     478        assert(hcd);
    534479
    535480        if ((err = bus_reserve_default_address(hcd->bus, USB_SPEED_MAX))) {
     
    538483        }
    539484
    540         device_t *dev = hcd_ddf_device_create(hc, hcd->bus);
     485        device_t *dev = hcd_ddf_fun_create(hcd);
    541486        if (!dev) {
    542487                usb_log_error("Failed to create function for the root hub.");
     
    561506
    562507err_usb_dev:
    563         hcd_ddf_device_destroy(dev);
     508        hcd_ddf_fun_destroy(dev);
    564509err_default_address:
    565510        bus_release_default_address(hcd->bus);
     
    577522 * This function does all the ddf work for hc driver.
    578523 */
    579 int hcd_ddf_setup_hc(ddf_dev_t *device)
     524int hcd_ddf_setup_hc(ddf_dev_t *device, size_t size)
    580525{
    581526        assert(device);
    582527
    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);
    584529        if (instance == NULL) {
    585530                usb_log_error("Failed to allocate HCD ddf structure.\n");
    586531                return ENOMEM;
    587532        }
    588         hcd_init(&instance->hcd);
     533        instance->ddf_dev = device;
    589534
    590535        int ret = ENOMEM;
     
    618563}
    619564
    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
     565void 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
    631571/** Call the parent driver with a request to enable interrupt
    632572 *
     
    635575 * @return Error code.
    636576 */
    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);
     577int 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);
    640580        if (parent_sess == NULL)
    641581                return EIO;
     
    644584}
    645585
    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);
     586int 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);
    650589        if (parent_sess == NULL)
    651590                return EIO;
     
    658597}
    659598
    660 // TODO: move this someplace else
    661 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 handler
    674  *
    675  * @param[in] device Host controller DDF device
    676  * @param[in] regs Register range
    677  * @param[in] irq Interrupt number
    678  * @paran[in] handler Interrupt handler
    679  * @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 a
    755                  * lame crutch anyway so don't hog the system. 10ms is still
    756                  * 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 use
    765  * @param speed Maximum supported speed
    766  * @param bw Available bandwidth (arbitrary units)
    767  * @param bw_count Bandwidth computing function
    768  * @param irq_handler IRQ handling function
    769  * @param gen_irq_code Function to generate IRQ pseudocode
    770  *                     (it needs to return used irq number)
    771  * @param driver_init Function to initialize HC driver
    772  * @param driver_fini Function to cleanup HC driver
    773  * @return Error code
    774  *
    775  * This function does all the preparatory work for hc and rh drivers:
    776  *  - gets device's hw resources
    777  *  - attempts to enable interrupts
    778  *  - registers interrupt handler
    779  *  - calls driver specific initialization
    780  *  - registers root hub
    781  */
    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 HC
    854          * 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 
    885599/**
    886600 * @}
Note: See TracChangeset for help on using the changeset viewer.