Ignore:
File:
1 edited

Legend:

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

    re0a5d4c rb7fd2a0  
    22 * Copyright (c) 2010 Matus Dekanek
    33 * Copyright (c) 2011 Jan Vesely
    4  * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    54 * All rights reserved.
    65 *
     
    5251#include <usb/classes/hub.h>
    5352#include <usb/dev/poll.h>
    54 #include <usbhc_iface.h>
     53#include <usb_iface.h>
    5554
    5655#include "usbhub.h"
     
    5958#define HUB_FNC_NAME "hub"
    6059
    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  */
    84 static 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 
    88 const usb_endpoint_description_t *usb_hub_endpoints [] = {
    89         &status_change_single_tt_only,
    90         &status_change_mtt_available,
     60/** Hub status-change endpoint description.
     61 *
     62 * For more information see section 11.15.1 of USB 1.1 specification.
     63 */
     64const 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
    9172};
    9273
     
    10081};
    10182
    102 static errno_t usb_set_first_configuration(usb_device_t *);
    103 static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *);
    104 static void usb_hub_over_current(const usb_hub_dev_t *, usb_hub_status_t);
    105 static errno_t usb_hub_polling_init(usb_hub_dev_t *, usb_endpoint_mapping_t *);
    106 static void usb_hub_global_interrupt(const usb_hub_dev_t *);
    107 
    108 static 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 }
     83static errno_t usb_set_first_configuration(usb_device_t *usb_device);
     84static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev);
     85static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
     86    usb_hub_status_t status);
     87static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev);
     88static void usb_hub_polling_terminated_callback(usb_device_t *device,
     89    bool was_error, void *data);
    11990
    12091/**
     
    12899errno_t usb_hub_device_add(usb_device_t *usb_dev)
    129100{
    130         errno_t err;
    131101        assert(usb_dev);
    132 
    133102        /* Create driver soft-state structure */
    134103        usb_hub_dev_t *hub_dev =
    135104            usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
    136105        if (hub_dev == NULL) {
    137                 usb_log_error("Failed to create hub driver structure.");
     106                usb_log_error("Failed to create hub driver structure.\n");
    138107                return ENOMEM;
    139108        }
    140109        hub_dev->usb_device = usb_dev;
    141         hub_dev->speed = usb_device_get_speed(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);
    142114
    143115        /* Set hub's first configuration. (There should be only one) */
    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;
     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;
    147121        }
    148122
    149123        /* Get port count and create attached_devices. */
    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;
     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;
    164129        }
    165130
    166131        /* Create hub control function. */
    167         usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.");
     132        usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
    168133        hub_dev->hub_fun = usb_device_ddf_fun_create(hub_dev->usb_device,
    169134            fun_exposed, HUB_FNC_NAME);
    170135        if (hub_dev->hub_fun == NULL) {
    171                 usb_log_error("Failed to create hub function.");
     136                usb_log_error("Failed to create hub function.\n");
    172137                return ENOMEM;
    173138        }
    174139
    175140        /* Bind hub control function. */
    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;
     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;
    179147        }
    180148
    181149        /* Start hub operation. */
    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),
     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",
    189164            usb_device_get_name(hub_dev->usb_device), hub_dev,
    190165            hub_dev->port_count);
    191166
    192167        return EOK;
    193 
    194 err_bound:
    195         ddf_fun_unbind(hub_dev->hub_fun);
    196 err_ddf_fun:
    197         ddf_fun_destroy(hub_dev->hub_fun);
    198         return err;
    199 }
    200 
    201 static errno_t usb_hub_cleanup(usb_hub_dev_t *hub)
    202 {
    203         free(hub->polling.buffer);
    204         usb_polling_fini(&hub->polling);
     168}
     169
     170/**
     171 * Turn off power to all ports.
     172 *
     173 * @param usb_dev generic usb device information
     174 * @return error code
     175 */
     176errno_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 */
     186errno_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);
    205202
    206203        for (size_t port = 0; port < hub->port_count; ++port) {
    207                 usb_port_fini(&hub->ports[port].base);
     204                const errno_t ret = usb_hub_port_fini(&hub->ports[port], hub);
     205                if (ret != EOK)
     206                        return ret;
    208207        }
    209208        free(hub->ports);
     
    218217
    219218        usb_log_info("(%p) USB hub driver stopped and cleaned.", hub);
    220 
    221         /* Device data (usb_hub_dev_t) will be freed by usbdev. */
    222219        return EOK;
    223220}
    224221
    225 /**
    226  * Turn off power to all ports.
    227  *
    228  * @param usb_dev generic usb device information
    229  * @return error code
    230  */
    231 errno_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  */
    252 errno_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  */
    273 static 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.
     222/** Callback for polling hub for changes.
    302223 *
    303224 * @param dev Device where the change occured.
     
    324245        }
    325246
    326         /* Nth bit indicates change on port N */
     247        /* N + 1 bit indicates change on port N */
    327248        for (size_t port = 0; port < hub->port_count; ++port) {
    328249                const size_t bit = port + 1;
    329250                const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1;
    330251                if (change) {
    331                         usb_hub_port_process_interrupt(&hub->ports[port]);
     252                        usb_hub_port_process_interrupt(&hub->ports[port], hub);
    332253                }
    333254        }
    334255        return true;
    335 }
    336 
    337 static 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         }
    360256}
    361257
     
    374270        assert(hub_dev);
    375271
     272        /* Get hub descriptor. */
    376273        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 
    382         /* Get hub descriptor. */
     274        usb_pipe_t *control_pipe =
     275            usb_device_get_default_pipe(hub_dev->usb_device);
     276
    383277        usb_hub_descriptor_header_t descriptor;
    384278        size_t received_size;
    385279        errno_t opResult = usb_request_get_descriptor(control_pipe,
    386280            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    387             desc_type, 0, 0, &descriptor,
     281            USB_DESCTYPE_HUB, 0, 0, &descriptor,
    388282            sizeof(usb_hub_descriptor_header_t), &received_size);
    389283        if (opResult != EOK) {
    390                 usb_log_error("(%p): Failed to receive hub descriptor: %s.",
     284                usb_log_error("(%p): Failed to receive hub descriptor: %s.\n",
    391285                    hub_dev, str_error(opResult));
    392286                return opResult;
    393287        }
    394288
    395         usb_log_debug("(%p): Setting port count to %d.", hub_dev,
     289        usb_log_debug("(%p): Setting port count to %d.\n", hub_dev,
    396290            descriptor.port_count);
    397291        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         }
    407292
    408293        hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t));
     
    412297
    413298        for (size_t port = 0; port < hub_dev->port_count; ++port) {
    414                 usb_hub_port_init(&hub_dev->ports[port], hub_dev, port + 1);
     299                usb_hub_port_init(
     300                    &hub_dev->ports[port], port + 1, control_pipe);
    415301        }
    416302
     
    420306            descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG;
    421307
    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 
     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        }
    428334        return EOK;
    429335}
     
    443349        const size_t configuration_count =
    444350            usb_device_descriptors(usb_device)->device.configuration_count;
    445         usb_log_debug("Hub has %zu configurations.", configuration_count);
     351        usb_log_debug("Hub has %zu configurations.\n", configuration_count);
    446352
    447353        if (configuration_count < 1) {
    448                 usb_log_error("There are no configurations available");
     354                usb_log_error("There are no configurations available\n");
    449355                return EINVAL;
    450356        }
     
    463369        /* Set configuration. Use the configuration that was in
    464370         * usb_device->descriptors.configuration i.e. The first one. */
    465         errno_t opResult = usb_request_set_configuration(
     371        const errno_t opResult = usb_request_set_configuration(
    466372            usb_device_get_default_pipe(usb_device),
    467373            config_descriptor->configuration_number);
    468374        if (opResult != EOK) {
    469                 usb_log_error("Failed to set hub configuration: %s.",
     375                usb_log_error("Failed to set hub configuration: %s.\n",
    470376                    str_error(opResult));
    471377        } else {
    472                 usb_log_debug("\tUsed configuration %d",
     378                usb_log_debug("\tUsed configuration %d\n",
    473379                    config_descriptor->configuration_number);
    474380        }
    475 
    476381        return opResult;
    477382}
     
    501406        /* Over-current condition is gone, it is safe to turn the ports on. */
    502407        for (size_t port = 0; port < hub_dev->port_count; ++port) {
    503                 const errno_t ret = usb_hub_set_port_feature(hub_dev, port,
    504                     USB_HUB_FEATURE_PORT_POWER);
     408                const errno_t ret = usb_hub_port_set_feature(
     409                    &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
    505410                if (ret != EOK) {
    506411                        usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot"
     
    512417                }
    513418        }
    514 }
    515 
    516 /**
    517  * Set feature on the real hub port.
    518  *
    519  * @param port Port structure.
    520  * @param feature Feature selector.
    521  */
    522 errno_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  */
    547 errno_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  */
    568 errno_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  */
    590 errno_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;
     419
    620420}
    621421
     
    692492
    693493/**
    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  */
    699 static FIBRIL_CONDVAR_INITIALIZE(global_hub_default_address_cv);
    700 static 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  */
    708 errno_t usb_hub_reserve_default_address(usb_hub_dev_t *hub, async_exch_t *exch,
    709     usb_port_t *port)
    710 {
     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 */
     501static void usb_hub_polling_terminated_callback(usb_device_t *device,
     502    bool was_error, void *data)
     503{
     504        usb_hub_dev_t *hub = data;
    711505        assert(hub);
    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
     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.
    720516         */
    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  */
    755 errno_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 
     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}
    768530/**
    769531 * @}
Note: See TracChangeset for help on using the changeset viewer.