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


Ignore:
Timestamp:
2011-10-13T13:20:26Z (13 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
3a5506a
Parents:
cff3fb6 (diff), 22a2b763 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge initial USB unplug support.

Support device_remove and device_gone in libusbdev.
usbhub and uhcirh try to unbind and destroy functions of attached devices.
add unplug support for usbhub driver (only works on empty hubs as there is no support in other drivers).

Drivers to go:

usbmid
usbflbk
usbhid
usbmast
usbmouse

Tested on:

qemu UHCI and emulated hub,
ICH8 hw and Alcor Micro Corp. USB Hub

File:
1 edited

Legend:

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

    rcff3fb6 rd083126  
    6868
    6969static int usb_set_first_configuration(usb_device_t *usb_device);
    70 static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev);
    71 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info);
    72 static void usb_hub_over_current(const usb_hub_info_t *hub_info,
     70static usb_hub_dev_t * usb_hub_dev_create(usb_device_t *usb_dev);
     71static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev);
     72static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
    7373    usb_hub_status_t status);
    74 static void usb_hub_global_interrupt(const usb_hub_info_t *hub_info);
     74static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev);
    7575static void usb_hub_polling_terminated_callback(usb_device_t *device,
    7676    bool was_error, void *data);
    77 
    7877/**
    7978 * Initialize hub device driver fibril
     
    8483 * @return error code
    8584 */
    86 int usb_hub_add_device(usb_device_t *usb_dev)
     85int usb_hub_device_gone(usb_device_t *usb_dev)
     86{
     87        assert(usb_dev);
     88        usb_hub_dev_t *hub = usb_dev->driver_data;
     89        assert(hub);
     90        unsigned tries = 10;
     91        while (hub->running) {
     92                async_usleep(100000);
     93                if (!tries--) {
     94                        usb_log_error("Can't remove hub, still running.\n");
     95                        return EINPROGRESS;
     96                }
     97        }
     98
     99        assert(!hub->running);
     100
     101        for (size_t port = 0; port < hub->port_count; ++port) {
     102                if (hub->ports[port].attached_device.fun) {
     103                        const int ret =
     104                            usb_hub_port_fini(&hub->ports[port], hub);
     105                        if (ret != EOK)
     106                                return ret;
     107                }
     108        }
     109        free(hub->ports);
     110
     111        const int ret = ddf_fun_unbind(hub->hub_fun);
     112        if (ret != EOK) {
     113                usb_log_error("Failed to unbind '%s' function: %s.\n",
     114                   HUB_FNC_NAME, str_error(ret));
     115                return ret;
     116        }
     117        ddf_fun_destroy(hub->hub_fun);
     118
     119        free(hub);
     120        usb_dev->driver_data = NULL;
     121        usb_log_info("USB hub driver, stopped and cleaned.\n");
     122        return EOK;
     123}
     124/*----------------------------------------------------------------------------*/
     125/**
     126 * Initialize hub device driver fibril
     127 *
     128 * Creates hub representation and fibril that periodically checks hub's status.
     129 * Hub representation is passed to the fibril.
     130 * @param usb_dev generic usb device information
     131 * @return error code
     132 */
     133int usb_hub_device_add(usb_device_t *usb_dev)
    87134{
    88135        assert(usb_dev);
    89136        /* Create driver soft-state structure */
    90         usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev);
    91         if (hub_info == NULL) {
     137        usb_hub_dev_t *hub_dev = usb_hub_dev_create(usb_dev);
     138        if (hub_dev == NULL) {
    92139                usb_log_error("Failed to create hun driver structure.\n");
    93140                return ENOMEM;
     
    97144        usb_log_debug("Initializing USB wire abstraction.\n");
    98145        int opResult = usb_hc_connection_initialize_from_device(
    99             &hub_info->connection, hub_info->usb_device->ddf_dev);
     146            &hub_dev->connection, hub_dev->usb_device->ddf_dev);
    100147        if (opResult != EOK) {
    101148                usb_log_error("Could not initialize connection to device: %s\n",
    102149                    str_error(opResult));
    103                 free(hub_info);
     150                free(hub_dev);
    104151                return opResult;
    105152        }
     
    110157                usb_log_error("Could not set hub configuration: %s\n",
    111158                    str_error(opResult));
    112                 free(hub_info);
     159                free(hub_dev);
    113160                return opResult;
    114161        }
    115162
    116         //get port count and create attached_devs
    117         opResult = usb_hub_process_hub_specific_info(hub_info);
     163        /* Get port count and create attached_devices. */
     164        opResult = usb_hub_process_hub_specific_info(hub_dev);
    118165        if (opResult != EOK) {
    119166                usb_log_error("Could process hub specific info, %s\n",
    120167                    str_error(opResult));
    121                 free(hub_info);
     168                free(hub_dev);
    122169                return opResult;
    123170        }
    124171
    125172        usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
    126         ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
     173        hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev,
    127174            fun_exposed, HUB_FNC_NAME);
    128         if (hub_fun == NULL) {
     175        if (hub_dev->hub_fun == NULL) {
    129176                usb_log_error("Failed to create hub function.\n");
    130                 free(hub_info);
     177                free(hub_dev);
    131178                return ENOMEM;
    132179        }
    133180
    134         opResult = ddf_fun_bind(hub_fun);
     181        opResult = ddf_fun_bind(hub_dev->hub_fun);
    135182        if (opResult != EOK) {
    136183                usb_log_error("Failed to bind hub function: %s.\n",
    137184                   str_error(opResult));
    138                 free(hub_info);
    139                 ddf_fun_destroy(hub_fun);
     185                free(hub_dev);
     186                ddf_fun_destroy(hub_dev->hub_fun);
    140187                return opResult;
    141188        }
    142189
    143         opResult = usb_device_auto_poll(hub_info->usb_device, 0,
    144             hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1,
    145             usb_hub_polling_terminated_callback, hub_info);
    146         if (opResult != EOK) {
    147                 ddf_fun_destroy(hub_fun);
    148                 free(hub_info);
     190        opResult = usb_device_auto_poll(hub_dev->usb_device, 0,
     191            hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8),
     192            usb_hub_polling_terminated_callback, hub_dev);
     193        if (opResult != EOK) {
     194                /* Function is already bound */
     195                ddf_fun_unbind(hub_dev->hub_fun);
     196                ddf_fun_destroy(hub_dev->hub_fun);
     197                free(hub_dev);
    149198                usb_log_error("Failed to create polling fibril: %s.\n",
    150199                    str_error(opResult));
    151200                return opResult;
    152201        }
     202        hub_dev->running = true;
    153203        usb_log_info("Controlling hub '%s' (%zu ports).\n",
    154             hub_info->usb_device->ddf_dev->name, hub_info->port_count);
     204            hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);
    155205
    156206        return EOK;
     
    162212 * @param change_bitmap Bitmap of changed ports.
    163213 * @param change_bitmap_size Size of the bitmap in bytes.
    164  * @param arg Custom argument, points to @c usb_hub_info_t.
     214 * @param arg Custom argument, points to @c usb_hub_dev_t.
    165215 * @return Whether to continue polling.
    166216 */
     
    169219{
    170220        usb_log_debug("hub_port_changes_callback\n");
    171         usb_hub_info_t *hub = arg;
     221        usb_hub_dev_t *hub = arg;
    172222        assert(hub);
    173223
     
    184234
    185235        /* N + 1 bit indicates change on port N */
    186         size_t port = 1;
    187         for (; port < hub->port_count + 1; port++) {
    188                 const bool change = (change_bitmap[port / 8] >> (port % 8)) & 1;
     236        for (size_t port = 0; port < hub->port_count + 1; port++) {
     237                const size_t bit = port + 1;
     238                const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1;
    189239                if (change) {
    190240                        usb_hub_port_process_interrupt(&hub->ports[port], hub);
     
    195245/*----------------------------------------------------------------------------*/
    196246/**
    197  * create usb_hub_info_t structure
     247 * create usb_hub_dev_t structure
    198248 *
    199249 * Does only basic copying of known information into new structure.
    200250 * @param usb_dev usb device structure
    201  * @return basic usb_hub_info_t structure
    202  */
    203 static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev)
     251 * @return basic usb_hub_dev_t structure
     252 */
     253static usb_hub_dev_t * usb_hub_dev_create(usb_device_t *usb_dev)
    204254{
    205255        assert(usb_dev);
    206         usb_hub_info_t *info = malloc(sizeof(usb_hub_info_t));
    207         if (!info)
     256        usb_hub_dev_t *hub_dev = malloc(sizeof(usb_hub_dev_t));
     257        if (!hub_dev)
    208258            return NULL;
    209259
    210         info->usb_device = usb_dev;
    211 
    212         info->ports = NULL;
    213         info->port_count = -1;
    214         fibril_mutex_initialize(&info->pending_ops_mutex);
    215         fibril_condvar_initialize(&info->pending_ops_cv);
    216         info->pending_ops_count = 0;
    217 
    218         return info;
    219 }
    220 /*----------------------------------------------------------------------------*/
    221 /**
    222  * Load hub-specific information into hub_info structure and process if needed
     260        hub_dev->usb_device = usb_dev;
     261
     262        hub_dev->ports = NULL;
     263        hub_dev->port_count = 0;
     264        hub_dev->pending_ops_count = 0;
     265        hub_dev->running = false;
     266        fibril_mutex_initialize(&hub_dev->pending_ops_mutex);
     267        fibril_condvar_initialize(&hub_dev->pending_ops_cv);
     268        usb_dev->driver_data = hub_dev;
     269
     270        return hub_dev;
     271}
     272/*----------------------------------------------------------------------------*/
     273/**
     274 * Load hub-specific information into hub_dev structure and process if needed
    223275 *
    224276 * Read port count and initialize structures holding per port information.
     
    226278 * This function is hub-specific and should be run only after the hub is
    227279 * configured using usb_set_first_configuration function.
    228  * @param hub_info hub representation
     280 * @param hub_dev hub representation
    229281 * @return error code
    230282 */
    231 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info)
    232 {
    233         assert(hub_info);
     283static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev)
     284{
     285        assert(hub_dev);
    234286
    235287        /* Get hub descriptor. */
    236288        usb_log_debug("Retrieving descriptor\n");
    237         usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe;
     289        usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
    238290
    239291        usb_hub_descriptor_header_t descriptor;
     
    250302
    251303        usb_log_debug("Setting port count to %d.\n", descriptor.port_count);
    252         hub_info->port_count = descriptor.port_count;
    253 
    254         // TODO: +1 hack is no longer necessary
    255         hub_info->ports =
    256             malloc(sizeof(usb_hub_port_t) * (hub_info->port_count + 1));
    257         if (!hub_info->ports) {
     304        hub_dev->port_count = descriptor.port_count;
     305
     306        hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t));
     307        if (!hub_dev->ports) {
    258308                return ENOMEM;
    259309        }
    260310
    261         size_t port;
    262         for (port = 0; port < hub_info->port_count + 1; ++port) {
    263                 usb_hub_port_init(&hub_info->ports[port], port, control_pipe);
     311        for (size_t port = 0; port < hub_dev->port_count; ++port) {
     312                usb_hub_port_init(
     313                    &hub_dev->ports[port], port + 1, control_pipe);
    264314        }
    265315
     
    271321                    & HUB_CHAR_POWER_PER_PORT_FLAG;
    272322
    273                 for (port = 1; port <= hub_info->port_count; ++port) {
     323                for (size_t port = 0; port < hub_dev->port_count; ++port) {
    274324                        usb_log_debug("Powering port %zu.\n", port);
    275325                        opResult = usb_hub_port_set_feature(
    276                             &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER);
     326                            &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
    277327                        if (opResult != EOK) {
    278328                                usb_log_error("Cannot power on port %zu: %s.\n",
     
    314364        }
    315365
    316         // TODO: Make sure that there is enough data and the cast is correct
     366        if (usb_device->descriptors.configuration_size
     367            < sizeof(usb_standard_configuration_descriptor_t)) {
     368            usb_log_error("Configuration descriptor is not big enough"
     369                " to fit standard configuration descriptor.\n");
     370            return EOVERFLOW;
     371        }
     372
     373        // TODO: Make sure that the cast is correct
    317374        usb_standard_configuration_descriptor_t *config_descriptor
    318375            = (usb_standard_configuration_descriptor_t *)
     
    337394 *
    338395 * This means either to power off the hub or power it on.
    339  * @param hub_info hub instance
     396 * @param hub_dev hub instance
    340397 * @param status hub status bitmask
    341398 * @return error code
    342399 */
    343 static void usb_hub_over_current(const usb_hub_info_t *hub_info,
     400static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
    344401    usb_hub_status_t status)
    345402{
     
    351408                /* Over-current condition is gone, it is safe to turn the
    352409                 * ports on. */
    353                 size_t port;
    354                 for (port = 1; port <= hub_info->port_count; ++port) {
     410                for (size_t port = 0; port < hub_dev->port_count; ++port) {
    355411                        const int opResult = usb_hub_port_set_feature(
    356                             &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER);
     412                            &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     413                        // TODO: consider power policy here
    357414                        if (opResult != EOK) {
    358415                                usb_log_warning(
     
    364421        }
    365422        const int opResult = usb_request_clear_feature(
    366             &hub_info->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
     423            &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
    367424            USB_REQUEST_RECIPIENT_DEVICE,
    368425            USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0);
     
    378435 *
    379436 * The change can be either in the over-current condition or local-power change.
    380  * @param hub_info hub instance
    381  */
    382 static void usb_hub_global_interrupt(const usb_hub_info_t *hub_info)
    383 {
    384         assert(hub_info);
    385         assert(hub_info->usb_device);
     437 * @param hub_dev hub instance
     438 */
     439static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev)
     440{
     441        assert(hub_dev);
     442        assert(hub_dev->usb_device);
    386443        usb_log_debug("Global interrupt on a hub\n");
    387         usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe;
     444        usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
    388445
    389446        usb_hub_status_t status;
     
    406463        /* Handle status changes */
    407464        if (status & USB_HUB_STATUS_C_OVER_CURRENT) {
    408                 usb_hub_over_current(hub_info, status);
     465                usb_hub_over_current(hub_dev, status);
    409466        }
    410467
     
    438495 * callback called from hub polling fibril when the fibril terminates
    439496 *
    440  * Should perform a cleanup - deletes hub_info.
     497 * Does not perform cleanup, just marks the hub as not running.
    441498 * @param device usb device afected
    442499 * @param was_error indicates that the fibril is stoped due to an error
    443  * @param data pointer to usb_hub_info_t structure
     500 * @param data pointer to usb_hub_dev_t structure
    444501 */
    445502static void usb_hub_polling_terminated_callback(usb_device_t *device,
    446503    bool was_error, void *data)
    447504{
    448         usb_hub_info_t *hub = data;
     505        usb_hub_dev_t *hub = data;
    449506        assert(hub);
    450507
     
    460517         */
    461518        if (hub->pending_ops_count > 0) {
    462                 size_t port;
    463                 for (port = 0; port < hub->port_count; port++) {
     519                for (size_t port = 0; port < hub->port_count; ++port) {
    464520                        usb_hub_port_reset_fail(&hub->ports[port]);
    465521                }
     
    471527        }
    472528        fibril_mutex_unlock(&hub->pending_ops_mutex);
    473 
    474         usb_device_destroy(hub->usb_device);
    475 
    476         free(hub->ports);
    477         free(hub);
     529        hub->running = false;
    478530}
    479531/**
Note: See TracChangeset for help on using the changeset viewer.