Changeset 34d750c in mainline


Ignore:
Timestamp:
2018-01-22T21:44:56Z (6 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
3ac86a4
Parents:
9f685aa
Message:

usbhub: documentation, cleanup, refactoring

Location:
uspace/drv/bus/usb/usbhub
Files:
2 edited

Legend:

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

    r9f685aa r34d750c  
    6767}
    6868
    69 /** Hub status-change endpoint description.
    70  *
    71  * For more information see section 11.15.1 of USB 1.1 specification.
     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)
    7282 */
    7383static const usb_endpoint_description_t
     
    7989        &status_change_mtt_available,
    8090};
    81 
    8291
    8392/** Standard get hub global status request */
     
    9099};
    91100
    92 static int usb_set_first_configuration(usb_device_t *usb_device);
    93 static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev);
    94 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
    95     usb_hub_status_t status);
    96 static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev);
    97 
    98 static bool usb_hub_polling_error_callback(usb_device_t *dev, int err_code, void *arg)
     101static int usb_set_first_configuration(usb_device_t *);
     102static int 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 int 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        int err_code, void *arg)
    99109{
    100110        assert(dev);
    101111        assert(arg);
    102112
    103         usb_log_error("Device %s polling error: %s", usb_device_get_name(dev), str_error(err_code));
     113        usb_log_error("Device %s polling error: %s",
     114                usb_device_get_name(dev), str_error(err_code));
    104115
    105116        return true;
     
    116127int usb_hub_device_add(usb_device_t *usb_dev)
    117128{
     129        int err;
    118130        assert(usb_dev);
     131
    119132        /* Create driver soft-state structure */
    120133        usb_hub_dev_t *hub_dev =
     
    127140        hub_dev->speed = usb_device_get_speed(usb_dev);
    128141
    129         fibril_mutex_initialize(&hub_dev->default_address_guard);
    130         fibril_condvar_initialize(&hub_dev->default_address_cv);
    131 
    132142        /* Set hub's first configuration. (There should be only one) */
    133         int opResult = usb_set_first_configuration(usb_dev);
    134         if (opResult != EOK) {
    135                 usb_log_error("Could not set hub configuration: %s",
    136                     str_error(opResult));
    137                 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;
    138146        }
    139147
    140148        /* Get port count and create attached_devices. */
    141         opResult = usb_hub_process_hub_specific_info(hub_dev);
    142         if (opResult != EOK) {
    143                 usb_log_error("Could process hub specific info, %s",
    144                     str_error(opResult));
    145                 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;
    146152        }
    147153
     
    167173
    168174        /* Bind hub control function. */
    169         opResult = ddf_fun_bind(hub_dev->hub_fun);
    170         if (opResult != EOK) {
    171                 usb_log_error("Failed to bind hub function: %s.",
    172                    str_error(opResult));
    173                 ddf_fun_destroy(hub_dev->hub_fun);
    174                 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;
    175178        }
    176179
    177180        /* 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),
     188            usb_device_get_name(hub_dev->usb_device), hub_dev,
     189            hub_dev->port_count);
     190
     191        return EOK;
     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 int usb_hub_cleanup(usb_hub_dev_t *hub)
     201{
     202        free(hub->polling.buffer);
     203        usb_polling_fini(&hub->polling);
     204
     205        for (size_t port = 0; port < hub->port_count; ++port) {
     206                usb_port_fini(&hub->ports[port].base);
     207        }
     208        free(hub->ports);
     209
     210        const int ret = ddf_fun_unbind(hub->hub_fun);
     211        if (ret != EOK) {
     212                usb_log_error("(%p) Failed to unbind '%s' function: %s.",
     213                   hub, HUB_FNC_NAME, str_error(ret));
     214                return ret;
     215        }
     216        ddf_fun_destroy(hub->hub_fun);
     217
     218        usb_log_info("(%p) USB hub driver stopped and cleaned.", hub);
     219
     220        /* Device data (usb_hub_dev_t) will be freed by usbdev. */
     221        return EOK;
     222}
     223
     224/**
     225 * Turn off power to all ports.
     226 *
     227 * @param usb_dev generic usb device information
     228 * @return error code
     229 */
     230int 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 */
     251int 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 int usb_hub_polling_init(usb_hub_dev_t *hub_dev,
     273        usb_endpoint_mapping_t *mapping)
     274{
     275        int err;
    178276        usb_polling_t *polling = &hub_dev->polling;
    179         opResult = usb_polling_init(polling);
    180         if (opResult != EOK) {
    181                 /* Function is already bound */
    182                 ddf_fun_unbind(hub_dev->hub_fun);
    183                 ddf_fun_destroy(hub_dev->hub_fun);
    184                 usb_log_error("Failed to initialize polling fibril: %s.",
    185                     str_error(opResult));
    186                 return opResult;
    187         }
     277
     278        if ((err = usb_polling_init(polling)))
     279                return err;
    188280
    189281        polling->device = hub_dev->usb_device;
    190         polling->ep_mapping = status_change_mapping;
     282        polling->ep_mapping = mapping;
    191283        polling->request_size = ((hub_dev->port_count + 1 + 7) / 8);
    192284        polling->buffer = malloc(polling->request_size);
     
    195287        polling->arg = hub_dev;
    196288
    197         opResult = usb_polling_start(polling);
    198         if (opResult != EOK) {
     289        if ((err = usb_polling_start(polling))) {
    199290                /* Polling is already initialized. */
    200291                free(polling->buffer);
    201292                usb_polling_fini(polling);
    202                 ddf_fun_unbind(hub_dev->hub_fun);
    203                 ddf_fun_destroy(hub_dev->hub_fun);
    204                 usb_log_error("Failed to create polling fibril: %s.",
    205                     str_error(opResult));
    206                 return opResult;
    207         }
    208 
    209         usb_log_info("Controlling %s-speed hub '%s' (%p: %zu ports).",
    210             usb_str_speed(hub_dev->speed),
    211             usb_device_get_name(hub_dev->usb_device), hub_dev,
    212             hub_dev->port_count);
     293                return err;
     294        }
    213295
    214296        return EOK;
    215297}
    216298
    217 static int usb_hub_cleanup(usb_hub_dev_t *hub)
    218 {
    219         free(hub->polling.buffer);
    220         usb_polling_fini(&hub->polling);
    221 
    222         for (size_t port = 0; port < hub->port_count; ++port) {
    223                 usb_port_fini(&hub->ports[port].base);
    224         }
    225         free(hub->ports);
    226 
    227         const int ret = ddf_fun_unbind(hub->hub_fun);
    228         if (ret != EOK) {
    229                 usb_log_error("(%p) Failed to unbind '%s' function: %s.",
    230                    hub, HUB_FNC_NAME, str_error(ret));
    231                 return ret;
    232         }
    233         ddf_fun_destroy(hub->hub_fun);
    234 
    235         usb_log_info("(%p) USB hub driver stopped and cleaned.", hub);
    236 
    237         /* Device data (usb_hub_dev_t) will be freed by usbdev. */
    238         return EOK;
    239 }
    240 
    241 /**
    242  * Turn off power to all ports.
    243  *
    244  * @param usb_dev generic usb device information
    245  * @return error code
    246  */
    247 int usb_hub_device_remove(usb_device_t *usb_dev)
    248 {
    249         assert(usb_dev);
    250         usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
    251         assert(hub);
    252 
    253         usb_log_info("(%p) USB hub removed, joining polling fibril.", hub);
    254 
    255         /* Join polling fibril (ignoring error code). */
    256         usb_polling_join(&hub->polling);
    257         usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
    258 
    259         /* Destroy hub. */
    260         return usb_hub_cleanup(hub);
    261 }
    262 
    263 /**
    264  * Remove all attached devices
    265  * @param usb_dev generic usb device information
    266  * @return error code
    267  */
    268 int usb_hub_device_gone(usb_device_t *usb_dev)
    269 {
    270         assert(usb_dev);
    271         usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
    272         assert(hub);
    273 
    274         usb_log_info("(%p) USB hub gone, joining polling fibril.", hub);
    275 
    276         /* Join polling fibril (ignoring error code). */
    277         usb_polling_join(&hub->polling);
    278         usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
    279 
    280         /* Destroy hub. */
    281         return usb_hub_cleanup(hub);
    282 }
    283 
    284 /** Callback for polling hub for changes.
     299/**
     300 * Callback for polling hub for changes.
    285301 *
    286302 * @param dev Device where the change occured.
     
    307323        }
    308324
    309         /* N + 1 bit indicates change on port N */
     325        /* Nth bit indicates change on port N */
    310326        for (size_t port = 0; port < hub->port_count; ++port) {
    311327                const size_t bit = port + 1;
     
    331347        for (unsigned int port = 0; port < hub_dev->port_count; ++port) {
    332348                usb_log_debug("(%p): Powering port %u.", hub_dev, port + 1);
    333                 const int ret = usb_hub_set_port_feature(hub_dev, port + 1, USB_HUB_FEATURE_PORT_POWER);
     349                const int ret = usb_hub_set_port_feature(hub_dev, port + 1,
     350                    USB_HUB_FEATURE_PORT_POWER);
    334351
    335352                if (ret != EOK) {
     
    356373        assert(hub_dev);
    357374
    358         /* Get hub descriptor. */
    359375        usb_log_debug("(%p): Retrieving descriptor.", hub_dev);
    360376        usb_pipe_t *control_pipe = usb_device_get_default_pipe(hub_dev->usb_device);
     
    363379                ? USB_DESCTYPE_SSPEED_HUB : USB_DESCTYPE_HUB;
    364380
     381        /* Get hub descriptor. */
    365382        usb_hub_descriptor_header_t descriptor;
    366383        size_t received_size;
     
    483500        /* Over-current condition is gone, it is safe to turn the ports on. */
    484501        for (size_t port = 0; port < hub_dev->port_count; ++port) {
    485                 const int ret = usb_hub_set_port_feature(hub_dev, port, USB_HUB_FEATURE_PORT_POWER);
     502                const int ret = usb_hub_set_port_feature(hub_dev, port,
     503                    USB_HUB_FEATURE_PORT_POWER);
    486504                if (ret != EOK) {
    487505                        usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot"
     
    526544 * @param feature Feature selector.
    527545 */
    528 int usb_hub_set_port_feature(const usb_hub_dev_t *hub, size_t port_number, usb_hub_class_feature_t feature)
     546int usb_hub_set_port_feature(const usb_hub_dev_t *hub, size_t port_number,
     547    usb_hub_class_feature_t feature)
    529548{
    530549        assert(hub);
     
    546565 * @param feature Feature selector.
    547566 */
    548 int usb_hub_clear_port_feature(const usb_hub_dev_t *hub, size_t port_number, usb_hub_class_feature_t feature)
     567int usb_hub_clear_port_feature(const usb_hub_dev_t *hub, size_t port_number,
     568    usb_hub_class_feature_t feature)
    549569{
    550570        assert(hub);
     
    567587 * @return Error code.
    568588 */
    569 int usb_hub_get_port_status(const usb_hub_dev_t *hub, size_t port_number, usb_port_status_t *status)
     589int usb_hub_get_port_status(const usb_hub_dev_t *hub, size_t port_number,
     590    usb_port_status_t *status)
    570591{
    571592        assert(hub);
     
    669690}
    670691
     692/**
     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 */
    671698static FIBRIL_CONDVAR_INITIALIZE(global_hub_default_address_cv);
     699static FIBRIL_MUTEX_INITIALIZE(global_hub_default_address_guard);
    672700
    673701/**
     
    677705 * is connected with already attached devices.
    678706 */
    679 int usb_hub_reserve_default_address(usb_hub_dev_t *hub, async_exch_t *exch, usb_port_t *port)
     707int usb_hub_reserve_default_address(usb_hub_dev_t *hub, async_exch_t *exch,
     708    usb_port_t *port)
    680709{
    681710        assert(hub);
     
    684713        assert(fibril_mutex_is_locked(&port->guard));
    685714
    686         fibril_mutex_lock(&hub->default_address_guard);
    687         if (hub->default_address_requests++ == 0) {
    688                 /* We're the first to request the address, we can just do it */
    689                 fibril_mutex_unlock(&hub->default_address_guard);
    690                 int err;
    691                 while ((err = usbhc_reserve_default_address(exch)) == EAGAIN) {
    692                         // We ignore the return value here, as we cannot give up now.
    693                         usb_port_condvar_wait_timeout(port, &global_hub_default_address_cv, 500000);
    694                 }
    695                 return err;
    696         } else {
     715        int err = usbhc_reserve_default_address(exch);
     716        /*
     717         * EINVAL signalls that its our hub (hopefully different port) that has
     718         * this address reserved
     719         */
     720        while (err == EAGAIN || err == EINVAL) {
    697721                /* Drop the port guard, we're going to wait */
    698722                fibril_mutex_unlock(&port->guard);
    699723
    700                 /* Wait for a signal */
    701                 fibril_condvar_wait(&hub->default_address_cv, &hub->default_address_guard);
    702 
    703                 /* Remember ABBA, first drop the hub guard */
    704                 fibril_mutex_unlock(&hub->default_address_guard);
     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
    705730                fibril_mutex_lock(&port->guard);
    706                 return EOK;
    707         }
     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;
    708749}
    709750
     
    713754int usb_hub_release_default_address(usb_hub_dev_t *hub, async_exch_t *exch)
    714755{
    715         int ret = EOK;
    716 
    717         fibril_mutex_lock(&hub->default_address_guard);
    718         if (--hub->default_address_requests == 0) {
    719                 // We must do it in critical section to prevent other fibril
    720                 // from requesting the address before we release
    721                 ret = usbhc_release_default_address(exch);
    722                 // This is optimistic optimization - it may wake one hub from polling sleep
    723                 fibril_condvar_signal(&global_hub_default_address_cv);
    724         } else {
    725                 fibril_condvar_signal(&hub->default_address_cv);
    726         }
    727         fibril_mutex_unlock(&hub->default_address_guard);
     756        const int 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);
    728763
    729764        return ret;
  • uspace/drv/bus/usb/usbhub/usbhub.h

    r9f685aa r34d750c  
    7474        /** Whether MTT is available */
    7575        bool mtt_available;
    76 
    77         /** Default address management */
    78         unsigned default_address_requests;
    79         fibril_mutex_t default_address_guard;
    80         fibril_condvar_t default_address_cv;
    8176};
    8277
Note: See TracChangeset for help on using the changeset viewer.