Ignore:
File:
1 edited

Legend:

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

    rb7fd2a0 raa148b3  
    5151#include <usb/classes/hub.h>
    5252#include <usb/dev/poll.h>
    53 #include <usb_iface.h>
     53#include <usbhc_iface.h>
    5454
    5555#include "usbhub.h"
     
    5858#define HUB_FNC_NAME "hub"
    5959
    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
     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 */
     83static 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
     87const usb_endpoint_description_t *usb_hub_endpoints [] = {
     88        &status_change_single_tt_only,
     89        &status_change_mtt_available,
    7290};
    7391
     
    8199};
    82100
    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);
     101static errno_t usb_set_first_configuration(usb_device_t *);
     102static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *);
     103static void usb_hub_over_current(const usb_hub_dev_t *, usb_hub_status_t);
     104static errno_t usb_hub_polling_init(usb_hub_dev_t *, usb_endpoint_mapping_t *);
     105static void usb_hub_global_interrupt(const usb_hub_dev_t *);
     106
     107static 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}
    90118
    91119/**
     
    99127errno_t usb_hub_device_add(usb_device_t *usb_dev)
    100128{
     129        errno_t err;
    101130        assert(usb_dev);
     131
    102132        /* Create driver soft-state structure */
    103133        usb_hub_dev_t *hub_dev =
    104134            usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
    105135        if (hub_dev == NULL) {
    106                 usb_log_error("Failed to create hub driver structure.\n");
     136                usb_log_error("Failed to create hub driver structure.");
    107137                return ENOMEM;
    108138        }
    109139        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);
     140        hub_dev->speed = usb_device_get_speed(usb_dev);
    114141
    115142        /* 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;
     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;
    121146        }
    122147
    123148        /* 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;
     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;
    129163        }
    130164
    131165        /* Create hub control function. */
    132         usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
     166        usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.");
    133167        hub_dev->hub_fun = usb_device_ddf_fun_create(hub_dev->usb_device,
    134168            fun_exposed, HUB_FNC_NAME);
    135169        if (hub_dev->hub_fun == NULL) {
    136                 usb_log_error("Failed to create hub function.\n");
     170                usb_log_error("Failed to create hub function.");
    137171                return ENOMEM;
    138172        }
    139173
    140174        /* 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;
     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;
    147178        }
    148179
    149180        /* 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",
     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),
    164188            usb_device_get_name(hub_dev->usb_device), hub_dev,
    165189            hub_dev->port_count);
    166190
    167191        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);
     192
     193err_bound:
     194        ddf_fun_unbind(hub_dev->hub_fun);
     195err_ddf_fun:
     196        ddf_fun_destroy(hub_dev->hub_fun);
     197        return err;
     198}
     199
     200static errno_t usb_hub_cleanup(usb_hub_dev_t *hub)
     201{
     202        free(hub->polling.buffer);
     203        usb_polling_fini(&hub->polling);
    202204
    203205        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;
     206                usb_port_fini(&hub->ports[port].base);
    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. */
    219221        return EOK;
    220222}
    221223
    222 /** Callback for polling hub for changes.
     224/**
     225 * Turn off power to all ports.
     226 *
     227 * @param usb_dev generic usb device information
     228 * @return error code
     229 */
     230errno_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 */
     251errno_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 */
     272static 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.
    223301 *
    224302 * @param dev Device where the change occured.
     
    245323        }
    246324
    247         /* N + 1 bit indicates change on port N */
     325        /* Nth bit indicates change on port N */
    248326        for (size_t port = 0; port < hub->port_count; ++port) {
    249327                const size_t bit = port + 1;
    250328                const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1;
    251329                if (change) {
    252                         usb_hub_port_process_interrupt(&hub->ports[port], hub);
     330                        usb_hub_port_process_interrupt(&hub->ports[port]);
    253331                }
    254332        }
    255333        return true;
     334}
     335
     336static 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        }
    256359}
    257360
     
    270373        assert(hub_dev);
    271374
     375        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
    272381        /* 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 
    277382        usb_hub_descriptor_header_t descriptor;
    278383        size_t received_size;
    279384        errno_t opResult = usb_request_get_descriptor(control_pipe,
    280385            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    281             USB_DESCTYPE_HUB, 0, 0, &descriptor,
     386            desc_type, 0, 0, &descriptor,
    282387            sizeof(usb_hub_descriptor_header_t), &received_size);
    283388        if (opResult != EOK) {
    284                 usb_log_error("(%p): Failed to receive hub descriptor: %s.\n",
     389                usb_log_error("(%p): Failed to receive hub descriptor: %s.",
    285390                    hub_dev, str_error(opResult));
    286391                return opResult;
    287392        }
    288393
    289         usb_log_debug("(%p): Setting port count to %d.\n", hub_dev,
     394        usb_log_debug("(%p): Setting port count to %d.", hub_dev,
    290395            descriptor.port_count);
    291396        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        }
    292406
    293407        hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t));
     
    297411
    298412        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);
     413                usb_hub_port_init(&hub_dev->ports[port], hub_dev, port + 1);
    301414        }
    302415
     
    306419            descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG;
    307420
    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         }
     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
    334427        return EOK;
    335428}
     
    349442        const size_t configuration_count =
    350443            usb_device_descriptors(usb_device)->device.configuration_count;
    351         usb_log_debug("Hub has %zu configurations.\n", configuration_count);
     444        usb_log_debug("Hub has %zu configurations.", configuration_count);
    352445
    353446        if (configuration_count < 1) {
    354                 usb_log_error("There are no configurations available\n");
     447                usb_log_error("There are no configurations available");
    355448                return EINVAL;
    356449        }
     
    369462        /* Set configuration. Use the configuration that was in
    370463         * usb_device->descriptors.configuration i.e. The first one. */
    371         const errno_t opResult = usb_request_set_configuration(
     464        errno_t opResult = usb_request_set_configuration(
    372465            usb_device_get_default_pipe(usb_device),
    373466            config_descriptor->configuration_number);
    374467        if (opResult != EOK) {
    375                 usb_log_error("Failed to set hub configuration: %s.\n",
     468                usb_log_error("Failed to set hub configuration: %s.",
    376469                    str_error(opResult));
    377470        } else {
    378                 usb_log_debug("\tUsed configuration %d\n",
     471                usb_log_debug("\tUsed configuration %d",
    379472                    config_descriptor->configuration_number);
    380473        }
     474
    381475        return opResult;
    382476}
     
    406500        /* Over-current condition is gone, it is safe to turn the ports on. */
    407501        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);
     502                const errno_t ret = usb_hub_set_port_feature(hub_dev, port,
     503                    USB_HUB_FEATURE_PORT_POWER);
    410504                if (ret != EOK) {
    411505                        usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot"
     
    417511                }
    418512        }
    419 
     513}
     514
     515/**
     516 * Set feature on the real hub port.
     517 *
     518 * @param port Port structure.
     519 * @param feature Feature selector.
     520 */
     521errno_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 */
     546errno_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 */
     567errno_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 */
     589errno_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;
    420619}
    421620
     
    492691
    493692/**
    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;
     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 */
     698static FIBRIL_CONDVAR_INITIALIZE(global_hub_default_address_cv);
     699static 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 */
     707errno_t usb_hub_reserve_default_address(usb_hub_dev_t *hub, async_exch_t *exch,
     708    usb_port_t *port)
     709{
    505710        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.
     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
    516719         */
    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 }
     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 */
     754errno_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
    530767/**
    531768 * @}
Note: See TracChangeset for help on using the changeset viewer.