Changeset df6ded8 in mainline for uspace/drv/bus/usb/usbhub/usbhub.c


Ignore:
Timestamp:
2018-02-28T16:37:50Z (7 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1b20da0
Parents:
f5e5f73 (diff), b2dca8de (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Jakub Jermar <jakub@…> (2018-02-28 16:06:42)
git-committer:
Jakub Jermar <jakub@…> (2018-02-28 16:37:50)
Message:

Merge github.com:helenos-xhci-team/helenos

This commit merges support for USB 3 and generally refactors, fixes,
extends and cleans up the existing USB framework.

Notable additions and features:

  • new host controller driver has been implemented to control various xHC models (among others, NEC Renesas uPD720200)
  • isochronous data transfer mode
  • support for explicit USB device removal
  • USB tablet driver
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/usbhub/usbhub.c

    rf5e5f73 rdf6ded8  
    22 * Copyright (c) 2010 Matus Dekanek
    33 * Copyright (c) 2011 Jan Vesely
     4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    45 * All rights reserved.
    56 *
     
    5152#include <usb/classes/hub.h>
    5253#include <usb/dev/poll.h>
    53 #include <usb_iface.h>
     54#include <usbhc_iface.h>
    5455
    5556#include "usbhub.h"
     
    5859#define HUB_FNC_NAME "hub"
    5960
    60 /** Hub status-change endpoint description.
    61  *
    62  * For more information see section 11.15.1 of USB 1.1 specification.
    63  */
    64 const usb_endpoint_description_t hub_status_change_endpoint_description =
    65 {
    66         .transfer_type = USB_TRANSFER_INTERRUPT,
    67         .direction = USB_DIRECTION_IN,
    68         .interface_class = USB_CLASS_HUB,
    69         .interface_subclass = 0,
    70         .interface_protocol = 0,
    71         .flags = 0
     61#define HUB_STATUS_CHANGE_EP(protocol) { \
     62        .transfer_type = USB_TRANSFER_INTERRUPT, \
     63        .direction = USB_DIRECTION_IN, \
     64        .interface_class = USB_CLASS_HUB, \
     65        .interface_subclass = 0, \
     66        .interface_protocol = (protocol), \
     67        .flags = 0 \
     68}
     69
     70/**
     71 * Hub status-change endpoint description.
     72 *
     73 * According to USB 2.0 specification, there are two possible arrangements of
     74 * endpoints, depending on whether the hub has a MTT or not.
     75 *
     76 * Under any circumstances, there shall be exactly one endpoint descriptor.
     77 * Though to be sure, let's map the protocol precisely. The possible
     78 * combinations are:
     79 *                            | bDeviceProtocol | bInterfaceProtocol
     80 *      Only single TT        |       0         |         0
     81 *      MTT in Single-TT mode |       2         |         1
     82 *      MTT in MTT mode       |       2         |         2     (iface alt. 1)
     83 */
     84static const usb_endpoint_description_t
     85        status_change_single_tt_only = HUB_STATUS_CHANGE_EP(0),
     86        status_change_mtt_available = HUB_STATUS_CHANGE_EP(1);
     87
     88const usb_endpoint_description_t *usb_hub_endpoints [] = {
     89        &status_change_single_tt_only,
     90        &status_change_mtt_available,
    7291};
    7392
     
    81100};
    82101
    83 static errno_t usb_set_first_configuration(usb_device_t *usb_device);
    84 static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev);
    85 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
    86     usb_hub_status_t status);
    87 static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev);
    88 static void usb_hub_polling_terminated_callback(usb_device_t *device,
    89     bool was_error, void *data);
     102static errno_t usb_set_first_configuration(usb_device_t *);
     103static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *);
     104static void usb_hub_over_current(const usb_hub_dev_t *, usb_hub_status_t);
     105static errno_t usb_hub_polling_init(usb_hub_dev_t *, usb_endpoint_mapping_t *);
     106static void usb_hub_global_interrupt(const usb_hub_dev_t *);
     107
     108static bool usb_hub_polling_error_callback(usb_device_t *dev,
     109        errno_t err_code, void *arg)
     110{
     111        assert(dev);
     112        assert(arg);
     113
     114        usb_log_error("Device %s polling error: %s",
     115                usb_device_get_name(dev), str_error(err_code));
     116
     117        return true;
     118}
    90119
    91120/**
     
    99128errno_t usb_hub_device_add(usb_device_t *usb_dev)
    100129{
     130        errno_t err;
    101131        assert(usb_dev);
     132
    102133        /* Create driver soft-state structure */
    103134        usb_hub_dev_t *hub_dev =
    104135            usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
    105136        if (hub_dev == NULL) {
    106                 usb_log_error("Failed to create hub driver structure.\n");
     137                usb_log_error("Failed to create hub driver structure.");
    107138                return ENOMEM;
    108139        }
    109140        hub_dev->usb_device = usb_dev;
    110         hub_dev->pending_ops_count = 0;
    111         hub_dev->running = false;
    112         fibril_mutex_initialize(&hub_dev->pending_ops_mutex);
    113         fibril_condvar_initialize(&hub_dev->pending_ops_cv);
     141        hub_dev->speed = usb_device_get_speed(usb_dev);
    114142
    115143        /* Set hub's first configuration. (There should be only one) */
    116         errno_t opResult = usb_set_first_configuration(usb_dev);
    117         if (opResult != EOK) {
    118                 usb_log_error("Could not set hub configuration: %s\n",
    119                     str_error(opResult));
    120                 return opResult;
     144        if ((err = usb_set_first_configuration(usb_dev))) {
     145                usb_log_error("Could not set hub configuration: %s", str_error(err));
     146                return err;
    121147        }
    122148
    123149        /* Get port count and create attached_devices. */
    124         opResult = usb_hub_process_hub_specific_info(hub_dev);
    125         if (opResult != EOK) {
    126                 usb_log_error("Could process hub specific info, %s\n",
    127                     str_error(opResult));
    128                 return opResult;
     150        if ((err = usb_hub_process_hub_specific_info(hub_dev))) {
     151                usb_log_error("Could process hub specific info, %s", str_error(err));
     152                return err;
     153        }
     154
     155        const usb_endpoint_description_t *status_change = hub_dev->mtt_available
     156            ? &status_change_mtt_available
     157            : &status_change_single_tt_only;
     158
     159        usb_endpoint_mapping_t *status_change_mapping
     160                = usb_device_get_mapped_ep_desc(hub_dev->usb_device, status_change);
     161        if (!status_change_mapping) {
     162                usb_log_error("Failed to map the Status Change Endpoint of a hub.");
     163                return EIO;
    129164        }
    130165
    131166        /* Create hub control function. */
    132         usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
     167        usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.");
    133168        hub_dev->hub_fun = usb_device_ddf_fun_create(hub_dev->usb_device,
    134169            fun_exposed, HUB_FNC_NAME);
    135170        if (hub_dev->hub_fun == NULL) {
    136                 usb_log_error("Failed to create hub function.\n");
     171                usb_log_error("Failed to create hub function.");
    137172                return ENOMEM;
    138173        }
    139174
    140175        /* Bind hub control function. */
    141         opResult = ddf_fun_bind(hub_dev->hub_fun);
    142         if (opResult != EOK) {
    143                 usb_log_error("Failed to bind hub function: %s.\n",
    144                    str_error(opResult));
    145                 ddf_fun_destroy(hub_dev->hub_fun);
    146                 return opResult;
     176        if ((err = ddf_fun_bind(hub_dev->hub_fun))) {
     177                usb_log_error("Failed to bind hub function: %s.", str_error(err));
     178                goto err_ddf_fun;
    147179        }
    148180
    149181        /* Start hub operation. */
    150         opResult = usb_device_auto_poll_desc(hub_dev->usb_device,
    151             &hub_status_change_endpoint_description,
    152             hub_port_changes_callback, ((hub_dev->port_count + 1 + 7) / 8),
    153             -1, usb_hub_polling_terminated_callback, hub_dev);
    154         if (opResult != EOK) {
    155                 /* Function is already bound */
    156                 ddf_fun_unbind(hub_dev->hub_fun);
    157                 ddf_fun_destroy(hub_dev->hub_fun);
    158                 usb_log_error("Failed to create polling fibril: %s.\n",
    159                     str_error(opResult));
    160                 return opResult;
    161         }
    162         hub_dev->running = true;
    163         usb_log_info("Controlling hub '%s' (%p: %zu ports).\n",
     182        if ((err = usb_hub_polling_init(hub_dev, status_change_mapping))) {
     183                usb_log_error("Failed to start polling: %s.", str_error(err));
     184                goto err_bound;
     185        }
     186
     187        usb_log_info("Controlling %s-speed hub '%s' (%p: %zu ports).",
     188            usb_str_speed(hub_dev->speed),
    164189            usb_device_get_name(hub_dev->usb_device), hub_dev,
    165190            hub_dev->port_count);
    166191
    167192        return EOK;
    168 }
    169 
    170 /**
    171  * Turn off power to all ports.
    172  *
    173  * @param usb_dev generic usb device information
    174  * @return error code
    175  */
    176 errno_t usb_hub_device_remove(usb_device_t *usb_dev)
    177 {
    178         return ENOTSUP;
    179 }
    180 
    181 /**
    182  * Remove all attached devices
    183  * @param usb_dev generic usb device information
    184  * @return error code
    185  */
    186 errno_t usb_hub_device_gone(usb_device_t *usb_dev)
    187 {
    188         assert(usb_dev);
    189         usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
    190         assert(hub);
    191         unsigned tries = 10;
    192         while (hub->running) {
    193                 async_usleep(100000);
    194                 if (!tries--) {
    195                         usb_log_error("(%p): Can't remove hub, still running.",
    196                             hub);
    197                         return EBUSY;
    198                 }
    199         }
    200 
    201         assert(!hub->running);
     193
     194err_bound:
     195        ddf_fun_unbind(hub_dev->hub_fun);
     196err_ddf_fun:
     197        ddf_fun_destroy(hub_dev->hub_fun);
     198        return err;
     199}
     200
     201static errno_t usb_hub_cleanup(usb_hub_dev_t *hub)
     202{
     203        free(hub->polling.buffer);
     204        usb_polling_fini(&hub->polling);
    202205
    203206        for (size_t port = 0; port < hub->port_count; ++port) {
    204                 const errno_t ret = usb_hub_port_fini(&hub->ports[port], hub);
    205                 if (ret != EOK)
    206                         return ret;
     207                usb_port_fini(&hub->ports[port].base);
    207208        }
    208209        free(hub->ports);
     
    217218
    218219        usb_log_info("(%p) USB hub driver stopped and cleaned.", hub);
     220
     221        /* Device data (usb_hub_dev_t) will be freed by usbdev. */
    219222        return EOK;
    220223}
    221224
    222 /** Callback for polling hub for changes.
     225/**
     226 * Turn off power to all ports.
     227 *
     228 * @param usb_dev generic usb device information
     229 * @return error code
     230 */
     231errno_t usb_hub_device_remove(usb_device_t *usb_dev)
     232{
     233        assert(usb_dev);
     234        usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
     235        assert(hub);
     236
     237        usb_log_info("(%p) USB hub removed, joining polling fibril.", hub);
     238
     239        /* Join polling fibril (ignoring error code). */
     240        usb_polling_join(&hub->polling);
     241        usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
     242
     243        /* Destroy hub. */
     244        return usb_hub_cleanup(hub);
     245}
     246
     247/**
     248 * Remove all attached devices
     249 * @param usb_dev generic usb device information
     250 * @return error code
     251 */
     252errno_t usb_hub_device_gone(usb_device_t *usb_dev)
     253{
     254        assert(usb_dev);
     255        usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
     256        assert(hub);
     257
     258        usb_log_info("(%p) USB hub gone, joining polling fibril.", hub);
     259
     260        /* Join polling fibril (ignoring error code). */
     261        usb_polling_join(&hub->polling);
     262        usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
     263
     264        /* Destroy hub. */
     265        return usb_hub_cleanup(hub);
     266}
     267
     268/**
     269 * Initialize and start the polling of the Status Change Endpoint.
     270 *
     271 * @param mapping The mapping of Status Change Endpoint
     272 */
     273static errno_t usb_hub_polling_init(usb_hub_dev_t *hub_dev,
     274        usb_endpoint_mapping_t *mapping)
     275{
     276        errno_t err;
     277        usb_polling_t *polling = &hub_dev->polling;
     278
     279        if ((err = usb_polling_init(polling)))
     280                return err;
     281
     282        polling->device = hub_dev->usb_device;
     283        polling->ep_mapping = mapping;
     284        polling->request_size = ((hub_dev->port_count + 1 + 7) / 8);
     285        polling->buffer = malloc(polling->request_size);
     286        polling->on_data = hub_port_changes_callback;
     287        polling->on_error = usb_hub_polling_error_callback;
     288        polling->arg = hub_dev;
     289
     290        if ((err = usb_polling_start(polling))) {
     291                /* Polling is already initialized. */
     292                free(polling->buffer);
     293                usb_polling_fini(polling);
     294                return err;
     295        }
     296
     297        return EOK;
     298}
     299
     300/**
     301 * Callback for polling hub for changes.
    223302 *
    224303 * @param dev Device where the change occured.
     
    245324        }
    246325
    247         /* N + 1 bit indicates change on port N */
     326        /* Nth bit indicates change on port N */
    248327        for (size_t port = 0; port < hub->port_count; ++port) {
    249328                const size_t bit = port + 1;
    250329                const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1;
    251330                if (change) {
    252                         usb_hub_port_process_interrupt(&hub->ports[port], hub);
     331                        usb_hub_port_process_interrupt(&hub->ports[port]);
    253332                }
    254333        }
    255334        return true;
     335}
     336
     337static void usb_hub_power_ports(usb_hub_dev_t *hub_dev)
     338{
     339        if (!hub_dev->power_switched) {
     340                usb_log_info("(%p): Power switching not supported, "
     341                    "ports always powered.", hub_dev);
     342                return;
     343        }
     344
     345        usb_log_info("(%p): Hub port power switching enabled (%s).", hub_dev,
     346            hub_dev->per_port_power ? "per port" : "ganged");
     347
     348        for (unsigned int port = 0; port < hub_dev->port_count; ++port) {
     349                usb_log_debug("(%p): Powering port %u.", hub_dev, port + 1);
     350                const errno_t ret = usb_hub_set_port_feature(hub_dev, port + 1,
     351                    USB_HUB_FEATURE_PORT_POWER);
     352
     353                if (ret != EOK) {
     354                        usb_log_error("(%p-%u): Cannot power on port: %s.",
     355                            hub_dev, hub_dev->ports[port].port_number,
     356                            str_error(ret));
     357                        /* Continue to try at least other ports */
     358                }
     359        }
    256360}
    257361
     
    270374        assert(hub_dev);
    271375
     376        usb_log_debug("(%p): Retrieving descriptor.", hub_dev);
     377        usb_pipe_t *control_pipe = usb_device_get_default_pipe(hub_dev->usb_device);
     378
     379        usb_descriptor_type_t desc_type = hub_dev->speed >= USB_SPEED_SUPER
     380                ? USB_DESCTYPE_SSPEED_HUB : USB_DESCTYPE_HUB;
     381
    272382        /* Get hub descriptor. */
    273         usb_log_debug("(%p): Retrieving descriptor.", hub_dev);
    274         usb_pipe_t *control_pipe =
    275             usb_device_get_default_pipe(hub_dev->usb_device);
    276 
    277383        usb_hub_descriptor_header_t descriptor;
    278384        size_t received_size;
    279385        errno_t opResult = usb_request_get_descriptor(control_pipe,
    280386            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    281             USB_DESCTYPE_HUB, 0, 0, &descriptor,
     387            desc_type, 0, 0, &descriptor,
    282388            sizeof(usb_hub_descriptor_header_t), &received_size);
    283389        if (opResult != EOK) {
    284                 usb_log_error("(%p): Failed to receive hub descriptor: %s.\n",
     390                usb_log_error("(%p): Failed to receive hub descriptor: %s.",
    285391                    hub_dev, str_error(opResult));
    286392                return opResult;
    287393        }
    288394
    289         usb_log_debug("(%p): Setting port count to %d.\n", hub_dev,
     395        usb_log_debug("(%p): Setting port count to %d.", hub_dev,
    290396            descriptor.port_count);
    291397        hub_dev->port_count = descriptor.port_count;
     398        hub_dev->control_pipe = control_pipe;
     399
     400        usb_log_debug("(%p): Setting hub depth to %u.", hub_dev,
     401            usb_device_get_depth(hub_dev->usb_device));
     402        if ((opResult = usb_hub_set_depth(hub_dev))) {
     403                usb_log_error("(%p): Failed to set hub depth: %s.",
     404                    hub_dev, str_error(opResult));
     405                return opResult;
     406        }
    292407
    293408        hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t));
     
    297412
    298413        for (size_t port = 0; port < hub_dev->port_count; ++port) {
    299                 usb_hub_port_init(
    300                     &hub_dev->ports[port], port + 1, control_pipe);
     414                usb_hub_port_init(&hub_dev->ports[port], hub_dev, port + 1);
    301415        }
    302416
     
    306420            descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG;
    307421
    308         if (!hub_dev->power_switched) {
    309                 usb_log_info("(%p): Power switching not supported, "
    310                     "ports always powered.", hub_dev);
    311                 return EOK;
    312         }
    313 
    314         usb_log_info("(%p): Hub port power switching enabled (%s).\n", hub_dev,
    315             hub_dev->per_port_power ? "per port" : "ganged");
    316 
    317         for (unsigned int port = 0; port < hub_dev->port_count; ++port) {
    318                 usb_log_debug("(%p): Powering port %u.", hub_dev, port);
    319                 const errno_t ret = usb_hub_port_set_feature(
    320                     &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
    321 
    322                 if (ret != EOK) {
    323                         usb_log_error("(%p-%u): Cannot power on port: %s.\n",
    324                             hub_dev, hub_dev->ports[port].port_number,
    325                             str_error(ret));
    326                 } else {
    327                         if (!hub_dev->per_port_power) {
    328                                 usb_log_debug("(%p) Ganged power switching, "
    329                                     "one port is enough.", hub_dev);
    330                                 break;
    331                         }
    332                 }
    333         }
     422        const uint8_t protocol = usb_device_descriptors(hub_dev->usb_device)
     423                ->device.device_protocol;
     424        hub_dev->mtt_available = (protocol == 2);
     425
     426        usb_hub_power_ports(hub_dev);
     427
    334428        return EOK;
    335429}
     
    349443        const size_t configuration_count =
    350444            usb_device_descriptors(usb_device)->device.configuration_count;
    351         usb_log_debug("Hub has %zu configurations.\n", configuration_count);
     445        usb_log_debug("Hub has %zu configurations.", configuration_count);
    352446
    353447        if (configuration_count < 1) {
    354                 usb_log_error("There are no configurations available\n");
     448                usb_log_error("There are no configurations available");
    355449                return EINVAL;
    356450        }
     
    369463        /* Set configuration. Use the configuration that was in
    370464         * usb_device->descriptors.configuration i.e. The first one. */
    371         const errno_t opResult = usb_request_set_configuration(
     465        errno_t opResult = usb_request_set_configuration(
    372466            usb_device_get_default_pipe(usb_device),
    373467            config_descriptor->configuration_number);
    374468        if (opResult != EOK) {
    375                 usb_log_error("Failed to set hub configuration: %s.\n",
     469                usb_log_error("Failed to set hub configuration: %s.",
    376470                    str_error(opResult));
    377471        } else {
    378                 usb_log_debug("\tUsed configuration %d\n",
     472                usb_log_debug("\tUsed configuration %d",
    379473                    config_descriptor->configuration_number);
    380474        }
     475
    381476        return opResult;
    382477}
     
    406501        /* Over-current condition is gone, it is safe to turn the ports on. */
    407502        for (size_t port = 0; port < hub_dev->port_count; ++port) {
    408                 const errno_t ret = usb_hub_port_set_feature(
    409                     &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     503                const errno_t ret = usb_hub_set_port_feature(hub_dev, port,
     504                    USB_HUB_FEATURE_PORT_POWER);
    410505                if (ret != EOK) {
    411506                        usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot"
     
    417512                }
    418513        }
    419 
     514}
     515
     516/**
     517 * Set feature on the real hub port.
     518 *
     519 * @param port Port structure.
     520 * @param feature Feature selector.
     521 */
     522errno_t usb_hub_set_depth(const usb_hub_dev_t *hub)
     523{
     524        assert(hub);
     525
     526        /* Slower hubs do not care about depth */
     527        if (hub->speed < USB_SPEED_SUPER)
     528                return EOK;
     529
     530        const usb_device_request_setup_packet_t set_request = {
     531                .request_type = USB_HUB_REQ_TYPE_SET_HUB_DEPTH,
     532                .request = USB_HUB_REQUEST_SET_HUB_DEPTH,
     533                .value = uint16_host2usb(usb_device_get_depth(hub->usb_device) - 1),
     534                .index = 0,
     535                .length = 0,
     536        };
     537        return usb_pipe_control_write(hub->control_pipe, &set_request,
     538            sizeof(set_request), NULL, 0);
     539}
     540
     541/**
     542 * Set feature on the real hub port.
     543 *
     544 * @param port Port structure.
     545 * @param feature Feature selector.
     546 */
     547errno_t usb_hub_set_port_feature(const usb_hub_dev_t *hub, size_t port_number,
     548    usb_hub_class_feature_t feature)
     549{
     550        assert(hub);
     551        const usb_device_request_setup_packet_t clear_request = {
     552                .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE,
     553                .request = USB_DEVREQ_SET_FEATURE,
     554                .index = uint16_host2usb(port_number),
     555                .value = feature,
     556                .length = 0,
     557        };
     558        return usb_pipe_control_write(hub->control_pipe, &clear_request,
     559            sizeof(clear_request), NULL, 0);
     560}
     561
     562/**
     563 * Clear feature on the real hub port.
     564 *
     565 * @param port Port structure.
     566 * @param feature Feature selector.
     567 */
     568errno_t usb_hub_clear_port_feature(const usb_hub_dev_t *hub, size_t port_number,
     569    usb_hub_class_feature_t feature)
     570{
     571        assert(hub);
     572        const usb_device_request_setup_packet_t clear_request = {
     573                .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE,
     574                .request = USB_DEVREQ_CLEAR_FEATURE,
     575                .value = feature,
     576                .index = uint16_host2usb(port_number),
     577                .length = 0,
     578        };
     579        return usb_pipe_control_write(hub->control_pipe,
     580            &clear_request, sizeof(clear_request), NULL, 0);
     581}
     582
     583/**
     584 * Retrieve port status.
     585 *
     586 * @param[in] port Port structure
     587 * @param[out] status Where to store the port status.
     588 * @return Error code.
     589 */
     590errno_t usb_hub_get_port_status(const usb_hub_dev_t *hub, size_t port_number,
     591    usb_port_status_t *status)
     592{
     593        assert(hub);
     594        assert(status);
     595
     596        /* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6
     597         * Generic GET_STATUS request cannot be used because of the difference
     598         * in status data size (2B vs. 4B)*/
     599        const usb_device_request_setup_packet_t request = {
     600                .request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS,
     601                .request = USB_HUB_REQUEST_GET_STATUS,
     602                .value = 0,
     603                .index = uint16_host2usb(port_number),
     604                .length = sizeof(usb_port_status_t),
     605        };
     606        size_t recv_size;
     607
     608        uint32_t buffer;
     609        const errno_t rc = usb_pipe_control_read(hub->control_pipe,
     610            &request, sizeof(usb_device_request_setup_packet_t),
     611            &buffer, sizeof(buffer), &recv_size);
     612        if (rc != EOK)
     613                return rc;
     614
     615        if (recv_size != sizeof(*status))
     616                return ELIMIT;
     617
     618        *status = uint32_usb2host(buffer);
     619        return EOK;
    420620}
    421621
     
    492692
    493693/**
    494  * callback called from hub polling fibril when the fibril terminates
    495  *
    496  * Does not perform cleanup, just marks the hub as not running.
    497  * @param device usb device afected
    498  * @param was_error indicates that the fibril is stoped due to an error
    499  * @param data pointer to usb_hub_dev_t structure
    500  */
    501 static void usb_hub_polling_terminated_callback(usb_device_t *device,
    502     bool was_error, void *data)
    503 {
    504         usb_hub_dev_t *hub = data;
     694 * Instead of just sleeping, we may as well sleep on a condition variable.
     695 * This has the advantage that we may instantly wait other hub from the polling
     696 * sleep, mitigating the delay of polling while still being synchronized with
     697 * other devices in need of the default address (there shall not be any).
     698 */
     699static FIBRIL_CONDVAR_INITIALIZE(global_hub_default_address_cv);
     700static FIBRIL_MUTEX_INITIALIZE(global_hub_default_address_guard);
     701
     702/**
     703 * Reserve a default address for a port across all other devices connected to
     704 * the bus. We aggregate requests for ports to minimize delays between
     705 * connecting multiple devices from one hub - which happens e.g. when the hub
     706 * is connected with already attached devices.
     707 */
     708errno_t usb_hub_reserve_default_address(usb_hub_dev_t *hub, async_exch_t *exch,
     709    usb_port_t *port)
     710{
    505711        assert(hub);
    506 
    507         fibril_mutex_lock(&hub->pending_ops_mutex);
    508 
    509         /* The device is dead. However there might be some pending operations
    510          * that we need to wait for.
    511          * One of them is device adding in progress.
    512          * The respective fibril is probably waiting for status change
    513          * in port reset (port enable) callback.
    514          * Such change would never come (otherwise we would not be here).
    515          * Thus, we would flush all pending port resets.
     712        assert(exch);
     713        assert(port);
     714        assert(fibril_mutex_is_locked(&port->guard));
     715
     716        errno_t err = usbhc_reserve_default_address(exch);
     717        /*
     718         * EINVAL signalls that its our hub (hopefully different port) that has
     719         * this address reserved
    516720         */
    517         if (hub->pending_ops_count > 0) {
    518                 for (size_t port = 0; port < hub->port_count; ++port) {
    519                         usb_hub_port_reset_fail(&hub->ports[port]);
    520                 }
    521         }
    522         /* And now wait for them. */
    523         while (hub->pending_ops_count > 0) {
    524                 fibril_condvar_wait(&hub->pending_ops_cv,
    525                     &hub->pending_ops_mutex);
    526         }
    527         fibril_mutex_unlock(&hub->pending_ops_mutex);
    528         hub->running = false;
    529 }
     721        while (err == EAGAIN || err == EINVAL) {
     722                /* Drop the port guard, we're going to wait */
     723                fibril_mutex_unlock(&port->guard);
     724
     725                /* This sleeping might be disturbed by other hub */
     726                fibril_mutex_lock(&global_hub_default_address_guard);
     727                fibril_condvar_wait_timeout(&global_hub_default_address_cv,
     728                    &global_hub_default_address_guard, 2000000);
     729                fibril_mutex_unlock(&global_hub_default_address_guard);
     730
     731                fibril_mutex_lock(&port->guard);
     732                err = usbhc_reserve_default_address(exch);
     733        }
     734
     735        if (err)
     736                return err;
     737
     738        /*
     739         * As we dropped the port guard, we need to check whether the device is
     740         * still connected. If the release fails, we still hold the default
     741         * address -- but then there is probably a bigger problem with the HC
     742         * anyway.
     743         */
     744        if (port->state != PORT_CONNECTING) {
     745                err = usb_hub_release_default_address(hub, exch);
     746                return err ? err : EINTR;
     747        }
     748
     749        return EOK;
     750}
     751
     752/**
     753 * Release the default address from a port.
     754 */
     755errno_t usb_hub_release_default_address(usb_hub_dev_t *hub, async_exch_t *exch)
     756{
     757        const errno_t ret = usbhc_release_default_address(exch);
     758
     759        /*
     760         * This is an optimistic optimization - it may wake
     761         * one hub from polling sleep instantly.
     762         */
     763        fibril_condvar_signal(&global_hub_default_address_cv);
     764
     765        return ret;
     766}
     767
    530768/**
    531769 * @}
Note: See TracChangeset for help on using the changeset viewer.