Changeset 32fb6bce in mainline for uspace/lib/usbhost/src


Ignore:
Timestamp:
2017-12-18T22:50:21Z (8 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.

Location:
uspace/lib/usbhost/src
Files:
5 edited

Legend:

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

    r1ea0bbf r32fb6bce  
    4646 * Initializes the bus structure.
    4747 */
    48 void bus_init(bus_t *bus, hcd_t *hcd, size_t device_size)
    49 {
    50         assert(bus);
    51         assert(hcd);
     48void bus_init(bus_t *bus, size_t device_size)
     49{
     50        assert(bus);
    5251        assert(device_size >= sizeof(device_t));
    5352        memset(bus, 0, sizeof(bus_t));
    5453
    5554        fibril_mutex_initialize(&bus->guard);
    56         bus->hcd = hcd;
    5755        bus->device_size = device_size;
    5856}
     
    6159{
    6260        assert(bus);
    63         assert(bus->hcd);
    6461
    6562        memset(dev, 0, sizeof(*dev));
     
    258255}
    259256
     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 */
     267int 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
     292typedef 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
     301static 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
     314ssize_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
    260341/**
    261342 * @}
  • 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 * @}
  • uspace/lib/usbhost/src/endpoint.c

    r1ea0bbf r32fb6bce  
    3939#include <mem.h>
    4040#include <stdlib.h>
     41#include <str_error.h>
     42#include <usb/debug.h>
     43#include <usb/host/hcd.h>
    4144
    4245#include "usb_transfer_batch.h"
     
    187190}
    188191
     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 */
     202int 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
    189253/**
    190254 * @}
  • uspace/lib/usbhost/src/hcd.c

    r1ea0bbf r32fb6bce  
    3636#include <assert.h>
    3737#include <async.h>
     38#include <ddf/interrupt.h>
    3839#include <errno.h>
    3940#include <macros.h>
     
    4546
    4647#include "bus.h"
     48#include "ddf_helpers.h"
    4749#include "endpoint.h"
    4850#include "usb_transfer_batch.h"
     
    5052#include "hcd.h"
    5153
    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) {
     54int hc_dev_add(ddf_dev_t *);
     55int hc_dev_remove(ddf_dev_t *);
     56int hc_dev_gone(ddf_dev_t *);
     57int hc_fun_online(ddf_fun_t *);
     58int hc_fun_offline(ddf_fun_t *);
     59
     60static 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
     68static const hc_driver_t *hc_driver;
     69
     70int 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 */
     89static 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 */
     103static int interrupt_polling(void *arg)
     104{
     105        hc_device_t *hcd = arg;
    62106        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
     126static 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 */
     149static 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 */
     196int 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
     285err_polling:
     286        // TODO: Stop the polling fibril (refactor the interrupt_polling func)
     287        //
     288err_started:
     289        if (hc_driver->stop)
     290                hc_driver->stop(hcd);
     291err_irq:
     292        unregister_interrupt_handler(device, hcd->irq_cap);
     293        if (hc_driver->hc_remove)
     294                hc_driver->hc_remove(hcd);
     295err_hw_res:
     296        hw_res_list_parsed_clean(&hw_res);
     297err_hcd:
     298        hcd_ddf_clean_hc(hcd);
     299        return ret;
     300}
     301
     302int 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
     324int 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
     337int 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
     348int 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);
    65357}
    66358
     
    72364 * @return Max packet size for EP 0
    73365 */
    74 int hcd_get_ep0_max_packet_size(uint16_t *mps, hcd_t *hcd, device_t *dev)
     366int hcd_get_ep0_max_packet_size(uint16_t *mps, bus_t *bus, device_t *dev)
    75367{
    76368        assert(mps);
     
    97389
    98390        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,
    100392            (char *) &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8,
    101393            "read first 8 bytes of dev descriptor");
     
    156448 *
    157449 */
    158 static toggle_reset_mode_t hcd_get_request_toggle_reset_mode(
     450toggle_reset_mode_t hcd_get_request_toggle_reset_mode(
    159451    const usb_device_request_setup_packet_t *request)
    160452{
     
    186478}
    187479
    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 hand
    218         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_mode
    249                         = 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_size
    307                 : (ssize_t) sd.error;
    308 }
    309 
    310480
    311481/**
  • uspace/lib/usbhost/src/usb2_bus.c

    r1ea0bbf r32fb6bce  
    205205
    206206        usb2_bus_t *bus = (usb2_bus_t *) dev->bus;
    207         hcd_t *hcd = (hcd_t *) bus->base.hcd;
    208207
    209208        /* The default address is currently reserved for this device */
     
    231230
    232231        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)))
    234233                goto err_address;
    235234
     
    238237
    239238        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,
    241240            NULL, 0, *(uint64_t *)&set_address, "set address");
    242241        if (err != 0) {
     
    315314
    316315        /* Read the device descriptor, derive the match ids */
    317         if ((err = hcd_ddf_device_explore(dev))) {
     316        if ((err = hcd_device_explore(dev))) {
    318317                usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
    319318                release_address(bus, dev->address);
     
    463462 * @return Error code.
    464463 */
    465 int usb2_bus_init(usb2_bus_t *bus, hcd_t *hcd, size_t available_bandwidth)
     464int usb2_bus_init(usb2_bus_t *bus, size_t available_bandwidth)
    466465{
    467466        assert(bus);
    468467
    469         bus_init(&bus->base, hcd, sizeof(device_t));
     468        bus_init(&bus->base, sizeof(device_t));
    470469        bus->base.ops = &usb2_bus_ops;
    471470
Note: See TracChangeset for help on using the changeset viewer.