Ignore:
File:
1 edited

Legend:

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

    raa148b3 rb7fd2a0  
    5151#include <usb/classes/hub.h>
    5252#include <usb/dev/poll.h>
    53 #include <usbhc_iface.h>
     53#include <usb_iface.h>
    5454
    5555#include "usbhub.h"
     
    5858#define HUB_FNC_NAME "hub"
    5959
    60 #define HUB_STATUS_CHANGE_EP(protocol) { \
    61         .transfer_type = USB_TRANSFER_INTERRUPT, \
    62         .direction = USB_DIRECTION_IN, \
    63         .interface_class = USB_CLASS_HUB, \
    64         .interface_subclass = 0, \
    65         .interface_protocol = (protocol), \
    66         .flags = 0 \
    67 }
    68 
    69 /**
    70  * Hub status-change endpoint description.
    71  *
    72  * According to USB 2.0 specification, there are two possible arrangements of
    73  * endpoints, depending on whether the hub has a MTT or not.
    74  *
    75  * Under any circumstances, there shall be exactly one endpoint descriptor.
    76  * Though to be sure, let's map the protocol precisely. The possible
    77  * combinations are:
    78  *                            | bDeviceProtocol | bInterfaceProtocol
    79  *      Only single TT        |       0         |         0
    80  *      MTT in Single-TT mode |       2         |         1
    81  *      MTT in MTT mode       |       2         |         2     (iface alt. 1)
    82  */
    83 static const usb_endpoint_description_t
    84         status_change_single_tt_only = HUB_STATUS_CHANGE_EP(0),
    85         status_change_mtt_available = HUB_STATUS_CHANGE_EP(1);
    86 
    87 const usb_endpoint_description_t *usb_hub_endpoints [] = {
    88         &status_change_single_tt_only,
    89         &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
    9072};
    9173
     
    9981};
    10082
    101 static errno_t usb_set_first_configuration(usb_device_t *);
    102 static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *);
    103 static void usb_hub_over_current(const usb_hub_dev_t *, usb_hub_status_t);
    104 static errno_t usb_hub_polling_init(usb_hub_dev_t *, usb_endpoint_mapping_t *);
    105 static void usb_hub_global_interrupt(const usb_hub_dev_t *);
    106 
    107 static bool usb_hub_polling_error_callback(usb_device_t *dev,
    108         errno_t err_code, void *arg)
    109 {
    110         assert(dev);
    111         assert(arg);
    112 
    113         usb_log_error("Device %s polling error: %s",
    114                 usb_device_get_name(dev), str_error(err_code));
    115 
    116         return true;
    117 }
     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);
    11890
    11991/**
     
    12799errno_t usb_hub_device_add(usb_device_t *usb_dev)
    128100{
    129         errno_t err;
    130101        assert(usb_dev);
    131 
    132102        /* Create driver soft-state structure */
    133103        usb_hub_dev_t *hub_dev =
    134104            usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
    135105        if (hub_dev == NULL) {
    136                 usb_log_error("Failed to create hub driver structure.");
     106                usb_log_error("Failed to create hub driver structure.\n");
    137107                return ENOMEM;
    138108        }
    139109        hub_dev->usb_device = usb_dev;
    140         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);
    141114
    142115        /* Set hub's first configuration. (There should be only one) */
    143         if ((err = usb_set_first_configuration(usb_dev))) {
    144                 usb_log_error("Could not set hub configuration: %s", str_error(err));
    145                 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;
    146121        }
    147122
    148123        /* Get port count and create attached_devices. */
    149         if ((err = usb_hub_process_hub_specific_info(hub_dev))) {
    150                 usb_log_error("Could process hub specific info, %s", str_error(err));
    151                 return err;
    152         }
    153 
    154         const usb_endpoint_description_t *status_change = hub_dev->mtt_available
    155             ? &status_change_mtt_available
    156             : &status_change_single_tt_only;
    157 
    158         usb_endpoint_mapping_t *status_change_mapping
    159                 = usb_device_get_mapped_ep_desc(hub_dev->usb_device, status_change);
    160         if (!status_change_mapping) {
    161                 usb_log_error("Failed to map the Status Change Endpoint of a hub.");
    162                 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;
    163129        }
    164130
    165131        /* Create hub control function. */
    166         usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.");
     132        usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
    167133        hub_dev->hub_fun = usb_device_ddf_fun_create(hub_dev->usb_device,
    168134            fun_exposed, HUB_FNC_NAME);
    169135        if (hub_dev->hub_fun == NULL) {
    170                 usb_log_error("Failed to create hub function.");
     136                usb_log_error("Failed to create hub function.\n");
    171137                return ENOMEM;
    172138        }
    173139
    174140        /* Bind hub control function. */
    175         if ((err = ddf_fun_bind(hub_dev->hub_fun))) {
    176                 usb_log_error("Failed to bind hub function: %s.", str_error(err));
    177                 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;
    178147        }
    179148
    180149        /* Start hub operation. */
    181         if ((err = usb_hub_polling_init(hub_dev, status_change_mapping))) {
    182                 usb_log_error("Failed to start polling: %s.", str_error(err));
    183                 goto err_bound;
    184         }
    185 
    186         usb_log_info("Controlling %s-speed hub '%s' (%p: %zu ports).",
    187             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",
    188164            usb_device_get_name(hub_dev->usb_device), hub_dev,
    189165            hub_dev->port_count);
    190166
    191167        return EOK;
    192 
    193 err_bound:
    194         ddf_fun_unbind(hub_dev->hub_fun);
    195 err_ddf_fun:
    196         ddf_fun_destroy(hub_dev->hub_fun);
    197         return err;
    198 }
    199 
    200 static errno_t usb_hub_cleanup(usb_hub_dev_t *hub)
    201 {
    202         free(hub->polling.buffer);
    203         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);
    204202
    205203        for (size_t port = 0; port < hub->port_count; ++port) {
    206                 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;
    207207        }
    208208        free(hub->ports);
     
    217217
    218218        usb_log_info("(%p) USB hub driver stopped and cleaned.", hub);
    219 
    220         /* Device data (usb_hub_dev_t) will be freed by usbdev. */
    221219        return EOK;
    222220}
    223221
    224 /**
    225  * Turn off power to all ports.
    226  *
    227  * @param usb_dev generic usb device information
    228  * @return error code
    229  */
    230 errno_t usb_hub_device_remove(usb_device_t *usb_dev)
    231 {
    232         assert(usb_dev);
    233         usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
    234         assert(hub);
    235 
    236         usb_log_info("(%p) USB hub removed, joining polling fibril.", hub);
    237 
    238         /* Join polling fibril (ignoring error code). */
    239         usb_polling_join(&hub->polling);
    240         usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
    241 
    242         /* Destroy hub. */
    243         return usb_hub_cleanup(hub);
    244 }
    245 
    246 /**
    247  * Remove all attached devices
    248  * @param usb_dev generic usb device information
    249  * @return error code
    250  */
    251 errno_t usb_hub_device_gone(usb_device_t *usb_dev)
    252 {
    253         assert(usb_dev);
    254         usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
    255         assert(hub);
    256 
    257         usb_log_info("(%p) USB hub gone, joining polling fibril.", hub);
    258 
    259         /* Join polling fibril (ignoring error code). */
    260         usb_polling_join(&hub->polling);
    261         usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
    262 
    263         /* Destroy hub. */
    264         return usb_hub_cleanup(hub);
    265 }
    266 
    267 /**
    268  * Initialize and start the polling of the Status Change Endpoint.
    269  *
    270  * @param mapping The mapping of Status Change Endpoint
    271  */
    272 static errno_t usb_hub_polling_init(usb_hub_dev_t *hub_dev,
    273         usb_endpoint_mapping_t *mapping)
    274 {
    275         errno_t err;
    276         usb_polling_t *polling = &hub_dev->polling;
    277 
    278         if ((err = usb_polling_init(polling)))
    279                 return err;
    280 
    281         polling->device = hub_dev->usb_device;
    282         polling->ep_mapping = mapping;
    283         polling->request_size = ((hub_dev->port_count + 1 + 7) / 8);
    284         polling->buffer = malloc(polling->request_size);
    285         polling->on_data = hub_port_changes_callback;
    286         polling->on_error = usb_hub_polling_error_callback;
    287         polling->arg = hub_dev;
    288 
    289         if ((err = usb_polling_start(polling))) {
    290                 /* Polling is already initialized. */
    291                 free(polling->buffer);
    292                 usb_polling_fini(polling);
    293                 return err;
    294         }
    295 
    296         return EOK;
    297 }
    298 
    299 /**
    300  * Callback for polling hub for changes.
     222/** Callback for polling hub for changes.
    301223 *
    302224 * @param dev Device where the change occured.
     
    323245        }
    324246
    325         /* Nth bit indicates change on port N */
     247        /* N + 1 bit indicates change on port N */
    326248        for (size_t port = 0; port < hub->port_count; ++port) {
    327249                const size_t bit = port + 1;
    328250                const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1;
    329251                if (change) {
    330                         usb_hub_port_process_interrupt(&hub->ports[port]);
     252                        usb_hub_port_process_interrupt(&hub->ports[port], hub);
    331253                }
    332254        }
    333255        return true;
    334 }
    335 
    336 static void usb_hub_power_ports(usb_hub_dev_t *hub_dev)
    337 {
    338         if (!hub_dev->power_switched) {
    339                 usb_log_info("(%p): Power switching not supported, "
    340                     "ports always powered.", hub_dev);
    341                 return;
    342         }
    343 
    344         usb_log_info("(%p): Hub port power switching enabled (%s).", hub_dev,
    345             hub_dev->per_port_power ? "per port" : "ganged");
    346 
    347         for (unsigned int port = 0; port < hub_dev->port_count; ++port) {
    348                 usb_log_debug("(%p): Powering port %u.", hub_dev, port + 1);
    349                 const errno_t ret = usb_hub_set_port_feature(hub_dev, port + 1,
    350                     USB_HUB_FEATURE_PORT_POWER);
    351 
    352                 if (ret != EOK) {
    353                         usb_log_error("(%p-%u): Cannot power on port: %s.",
    354                             hub_dev, hub_dev->ports[port].port_number,
    355                             str_error(ret));
    356                         /* Continue to try at least other ports */
    357                 }
    358         }
    359256}
    360257
     
    373270        assert(hub_dev);
    374271
     272        /* Get hub descriptor. */
    375273        usb_log_debug("(%p): Retrieving descriptor.", hub_dev);
    376         usb_pipe_t *control_pipe = usb_device_get_default_pipe(hub_dev->usb_device);
    377 
    378         usb_descriptor_type_t desc_type = hub_dev->speed >= USB_SPEED_SUPER
    379                 ? USB_DESCTYPE_SSPEED_HUB : USB_DESCTYPE_HUB;
    380 
    381         /* Get hub descriptor. */
     274        usb_pipe_t *control_pipe =
     275            usb_device_get_default_pipe(hub_dev->usb_device);
     276
    382277        usb_hub_descriptor_header_t descriptor;
    383278        size_t received_size;
    384279        errno_t opResult = usb_request_get_descriptor(control_pipe,
    385280            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    386             desc_type, 0, 0, &descriptor,
     281            USB_DESCTYPE_HUB, 0, 0, &descriptor,
    387282            sizeof(usb_hub_descriptor_header_t), &received_size);
    388283        if (opResult != EOK) {
    389                 usb_log_error("(%p): Failed to receive hub descriptor: %s.",
     284                usb_log_error("(%p): Failed to receive hub descriptor: %s.\n",
    390285                    hub_dev, str_error(opResult));
    391286                return opResult;
    392287        }
    393288
    394         usb_log_debug("(%p): Setting port count to %d.", hub_dev,
     289        usb_log_debug("(%p): Setting port count to %d.\n", hub_dev,
    395290            descriptor.port_count);
    396291        hub_dev->port_count = descriptor.port_count;
    397         hub_dev->control_pipe = control_pipe;
    398 
    399         usb_log_debug("(%p): Setting hub depth to %u.", hub_dev,
    400             usb_device_get_depth(hub_dev->usb_device));
    401         if ((opResult = usb_hub_set_depth(hub_dev))) {
    402                 usb_log_error("(%p): Failed to set hub depth: %s.",
    403                     hub_dev, str_error(opResult));
    404                 return opResult;
    405         }
    406292
    407293        hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t));
     
    411297
    412298        for (size_t port = 0; port < hub_dev->port_count; ++port) {
    413                 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);
    414301        }
    415302
     
    419306            descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG;
    420307
    421         const uint8_t protocol = usb_device_descriptors(hub_dev->usb_device)
    422                 ->device.device_protocol;
    423         hub_dev->mtt_available = (protocol == 2);
    424 
    425         usb_hub_power_ports(hub_dev);
    426 
     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        }
    427334        return EOK;
    428335}
     
    442349        const size_t configuration_count =
    443350            usb_device_descriptors(usb_device)->device.configuration_count;
    444         usb_log_debug("Hub has %zu configurations.", configuration_count);
     351        usb_log_debug("Hub has %zu configurations.\n", configuration_count);
    445352
    446353        if (configuration_count < 1) {
    447                 usb_log_error("There are no configurations available");
     354                usb_log_error("There are no configurations available\n");
    448355                return EINVAL;
    449356        }
     
    462369        /* Set configuration. Use the configuration that was in
    463370         * usb_device->descriptors.configuration i.e. The first one. */
    464         errno_t opResult = usb_request_set_configuration(
     371        const errno_t opResult = usb_request_set_configuration(
    465372            usb_device_get_default_pipe(usb_device),
    466373            config_descriptor->configuration_number);
    467374        if (opResult != EOK) {
    468                 usb_log_error("Failed to set hub configuration: %s.",
     375                usb_log_error("Failed to set hub configuration: %s.\n",
    469376                    str_error(opResult));
    470377        } else {
    471                 usb_log_debug("\tUsed configuration %d",
     378                usb_log_debug("\tUsed configuration %d\n",
    472379                    config_descriptor->configuration_number);
    473380        }
    474 
    475381        return opResult;
    476382}
     
    500406        /* Over-current condition is gone, it is safe to turn the ports on. */
    501407        for (size_t port = 0; port < hub_dev->port_count; ++port) {
    502                 const errno_t ret = usb_hub_set_port_feature(hub_dev, port,
    503                     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);
    504410                if (ret != EOK) {
    505411                        usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot"
     
    511417                }
    512418        }
    513 }
    514 
    515 /**
    516  * Set feature on the real hub port.
    517  *
    518  * @param port Port structure.
    519  * @param feature Feature selector.
    520  */
    521 errno_t usb_hub_set_depth(const usb_hub_dev_t *hub)
    522 {
    523         assert(hub);
    524 
    525         /* Slower hubs do not care about depth */
    526         if (hub->speed < USB_SPEED_SUPER)
    527                 return EOK;
    528 
    529         const usb_device_request_setup_packet_t set_request = {
    530                 .request_type = USB_HUB_REQ_TYPE_SET_HUB_DEPTH,
    531                 .request = USB_HUB_REQUEST_SET_HUB_DEPTH,
    532                 .value = uint16_host2usb(usb_device_get_depth(hub->usb_device) - 1),
    533                 .index = 0,
    534                 .length = 0,
    535         };
    536         return usb_pipe_control_write(hub->control_pipe, &set_request,
    537             sizeof(set_request), NULL, 0);
    538 }
    539 
    540 /**
    541  * Set feature on the real hub port.
    542  *
    543  * @param port Port structure.
    544  * @param feature Feature selector.
    545  */
    546 errno_t usb_hub_set_port_feature(const usb_hub_dev_t *hub, size_t port_number,
    547     usb_hub_class_feature_t feature)
    548 {
    549         assert(hub);
    550         const usb_device_request_setup_packet_t clear_request = {
    551                 .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE,
    552                 .request = USB_DEVREQ_SET_FEATURE,
    553                 .index = uint16_host2usb(port_number),
    554                 .value = feature,
    555                 .length = 0,
    556         };
    557         return usb_pipe_control_write(hub->control_pipe, &clear_request,
    558             sizeof(clear_request), NULL, 0);
    559 }
    560 
    561 /**
    562  * Clear feature on the real hub port.
    563  *
    564  * @param port Port structure.
    565  * @param feature Feature selector.
    566  */
    567 errno_t usb_hub_clear_port_feature(const usb_hub_dev_t *hub, size_t port_number,
    568     usb_hub_class_feature_t feature)
    569 {
    570         assert(hub);
    571         const usb_device_request_setup_packet_t clear_request = {
    572                 .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE,
    573                 .request = USB_DEVREQ_CLEAR_FEATURE,
    574                 .value = feature,
    575                 .index = uint16_host2usb(port_number),
    576                 .length = 0,
    577         };
    578         return usb_pipe_control_write(hub->control_pipe,
    579             &clear_request, sizeof(clear_request), NULL, 0);
    580 }
    581 
    582 /**
    583  * Retrieve port status.
    584  *
    585  * @param[in] port Port structure
    586  * @param[out] status Where to store the port status.
    587  * @return Error code.
    588  */
    589 errno_t usb_hub_get_port_status(const usb_hub_dev_t *hub, size_t port_number,
    590     usb_port_status_t *status)
    591 {
    592         assert(hub);
    593         assert(status);
    594 
    595         /* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6
    596          * Generic GET_STATUS request cannot be used because of the difference
    597          * in status data size (2B vs. 4B)*/
    598         const usb_device_request_setup_packet_t request = {
    599                 .request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS,
    600                 .request = USB_HUB_REQUEST_GET_STATUS,
    601                 .value = 0,
    602                 .index = uint16_host2usb(port_number),
    603                 .length = sizeof(usb_port_status_t),
    604         };
    605         size_t recv_size;
    606 
    607         uint32_t buffer;
    608         const errno_t rc = usb_pipe_control_read(hub->control_pipe,
    609             &request, sizeof(usb_device_request_setup_packet_t),
    610             &buffer, sizeof(buffer), &recv_size);
    611         if (rc != EOK)
    612                 return rc;
    613 
    614         if (recv_size != sizeof(*status))
    615                 return ELIMIT;
    616 
    617         *status = uint32_usb2host(buffer);
    618         return EOK;
     419
    619420}
    620421
     
    691492
    692493/**
    693  * Instead of just sleeping, we may as well sleep on a condition variable.
    694  * This has the advantage that we may instantly wait other hub from the polling
    695  * sleep, mitigating the delay of polling while still being synchronized with
    696  * other devices in need of the default address (there shall not be any).
    697  */
    698 static FIBRIL_CONDVAR_INITIALIZE(global_hub_default_address_cv);
    699 static FIBRIL_MUTEX_INITIALIZE(global_hub_default_address_guard);
    700 
    701 /**
    702  * Reserve a default address for a port across all other devices connected to
    703  * the bus. We aggregate requests for ports to minimize delays between
    704  * connecting multiple devices from one hub - which happens e.g. when the hub
    705  * is connected with already attached devices.
    706  */
    707 errno_t usb_hub_reserve_default_address(usb_hub_dev_t *hub, async_exch_t *exch,
    708     usb_port_t *port)
    709 {
     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;
    710505        assert(hub);
    711         assert(exch);
    712         assert(port);
    713         assert(fibril_mutex_is_locked(&port->guard));
    714 
    715         errno_t err = usbhc_reserve_default_address(exch);
    716         /*
    717          * EINVAL signalls that its our hub (hopefully different port) that has
    718          * 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.
    719516         */
    720         while (err == EAGAIN || err == EINVAL) {
    721                 /* Drop the port guard, we're going to wait */
    722                 fibril_mutex_unlock(&port->guard);
    723 
    724                 /* This sleeping might be disturbed by other hub */
    725                 fibril_mutex_lock(&global_hub_default_address_guard);
    726                 fibril_condvar_wait_timeout(&global_hub_default_address_cv,
    727                     &global_hub_default_address_guard, 2000000);
    728                 fibril_mutex_unlock(&global_hub_default_address_guard);
    729 
    730                 fibril_mutex_lock(&port->guard);
    731                 err = usbhc_reserve_default_address(exch);
    732         }
    733 
    734         if (err)
    735                 return err;
    736 
    737         /*
    738          * As we dropped the port guard, we need to check whether the device is
    739          * still connected. If the release fails, we still hold the default
    740          * address -- but then there is probably a bigger problem with the HC
    741          * anyway.
    742          */
    743         if (port->state != PORT_CONNECTING) {
    744                 err = usb_hub_release_default_address(hub, exch);
    745                 return err ? err : EINTR;
    746         }
    747 
    748         return EOK;
    749 }
    750 
    751 /**
    752  * Release the default address from a port.
    753  */
    754 errno_t usb_hub_release_default_address(usb_hub_dev_t *hub, async_exch_t *exch)
    755 {
    756         const errno_t ret = usbhc_release_default_address(exch);
    757 
    758         /*
    759          * This is an optimistic optimization - it may wake
    760          * one hub from polling sleep instantly.
    761          */
    762         fibril_condvar_signal(&global_hub_default_address_cv);
    763 
    764         return ret;
    765 }
    766 
     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}
    767530/**
    768531 * @}
Note: See TracChangeset for help on using the changeset viewer.