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


Ignore:
Timestamp:
2011-10-15T20:05:00Z (13 years ago)
Author:
Frantisek Princ <frantisek.princ@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
22ceff3a
Parents:
1ccc32f (diff), 721d4b6e (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 with mainline

File:
1 edited

Legend:

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

    r1ccc32f r25696fea  
    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        usb_log_info("USB hub driver, stopped and cleaned.\n");
     120        return EOK;
     121}
     122/*----------------------------------------------------------------------------*/
     123/**
     124 * Initialize hub device driver fibril
     125 *
     126 * Creates hub representation and fibril that periodically checks hub's status.
     127 * Hub representation is passed to the fibril.
     128 * @param usb_dev generic usb device information
     129 * @return error code
     130 */
     131int usb_hub_device_add(usb_device_t *usb_dev)
    87132{
    88133        assert(usb_dev);
    89134        /* Create driver soft-state structure */
    90         usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev);
    91         if (hub_info == NULL) {
     135        usb_hub_dev_t *hub_dev = usb_hub_dev_create(usb_dev);
     136        if (hub_dev == NULL) {
    92137                usb_log_error("Failed to create hun driver structure.\n");
    93138                return ENOMEM;
     
    97142        usb_log_debug("Initializing USB wire abstraction.\n");
    98143        int opResult = usb_hc_connection_initialize_from_device(
    99             &hub_info->connection, hub_info->usb_device->ddf_dev);
     144            &hub_dev->connection, hub_dev->usb_device->ddf_dev);
    100145        if (opResult != EOK) {
    101146                usb_log_error("Could not initialize connection to device: %s\n",
    102147                    str_error(opResult));
    103                 free(hub_info);
     148                free(hub_dev);
    104149                return opResult;
    105150        }
     
    110155                usb_log_error("Could not set hub configuration: %s\n",
    111156                    str_error(opResult));
    112                 free(hub_info);
     157                free(hub_dev);
    113158                return opResult;
    114159        }
    115160
    116         //get port count and create attached_devs
    117         opResult = usb_hub_process_hub_specific_info(hub_info);
     161        /* Get port count and create attached_devices. */
     162        opResult = usb_hub_process_hub_specific_info(hub_dev);
    118163        if (opResult != EOK) {
    119164                usb_log_error("Could process hub specific info, %s\n",
    120165                    str_error(opResult));
    121                 free(hub_info);
     166                free(hub_dev);
    122167                return opResult;
    123168        }
    124169
    125170        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,
     171        hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev,
    127172            fun_exposed, HUB_FNC_NAME);
    128         if (hub_fun == NULL) {
     173        if (hub_dev->hub_fun == NULL) {
    129174                usb_log_error("Failed to create hub function.\n");
    130                 free(hub_info);
     175                free(hub_dev);
    131176                return ENOMEM;
    132177        }
    133178
    134         opResult = ddf_fun_bind(hub_fun);
     179        opResult = ddf_fun_bind(hub_dev->hub_fun);
    135180        if (opResult != EOK) {
    136181                usb_log_error("Failed to bind hub function: %s.\n",
    137182                   str_error(opResult));
    138                 free(hub_info);
    139                 ddf_fun_destroy(hub_fun);
     183                free(hub_dev);
     184                ddf_fun_destroy(hub_dev->hub_fun);
    140185                return opResult;
    141186        }
    142187
    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);
     188        opResult = usb_device_auto_poll(hub_dev->usb_device, 0,
     189            hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8),
     190            usb_hub_polling_terminated_callback, hub_dev);
     191        if (opResult != EOK) {
     192                /* Function is already bound */
     193                ddf_fun_unbind(hub_dev->hub_fun);
     194                ddf_fun_destroy(hub_dev->hub_fun);
     195                free(hub_dev);
    149196                usb_log_error("Failed to create polling fibril: %s.\n",
    150197                    str_error(opResult));
    151198                return opResult;
    152199        }
     200        hub_dev->running = true;
    153201        usb_log_info("Controlling hub '%s' (%zu ports).\n",
    154             hub_info->usb_device->ddf_dev->name, hub_info->port_count);
     202            hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);
    155203
    156204        return EOK;
     
    162210 * @param change_bitmap Bitmap of changed ports.
    163211 * @param change_bitmap_size Size of the bitmap in bytes.
    164  * @param arg Custom argument, points to @c usb_hub_info_t.
     212 * @param arg Custom argument, points to @c usb_hub_dev_t.
    165213 * @return Whether to continue polling.
    166214 */
     
    169217{
    170218        usb_log_debug("hub_port_changes_callback\n");
    171         usb_hub_info_t *hub = arg;
     219        usb_hub_dev_t *hub = arg;
    172220        assert(hub);
    173221
     
    184232
    185233        /* 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;
     234        for (size_t port = 0; port < hub->port_count + 1; port++) {
     235                const size_t bit = port + 1;
     236                const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1;
    189237                if (change) {
    190238                        usb_hub_port_process_interrupt(&hub->ports[port], hub);
     
    195243/*----------------------------------------------------------------------------*/
    196244/**
    197  * create usb_hub_info_t structure
     245 * create usb_hub_dev_t structure
    198246 *
    199247 * Does only basic copying of known information into new structure.
    200248 * @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)
     249 * @return basic usb_hub_dev_t structure
     250 */
     251static usb_hub_dev_t * usb_hub_dev_create(usb_device_t *usb_dev)
    204252{
    205253        assert(usb_dev);
    206         usb_hub_info_t *info = malloc(sizeof(usb_hub_info_t));
    207         if (!info)
     254        usb_hub_dev_t *hub_dev =
     255            usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
     256        if (!hub_dev)
    208257            return NULL;
    209258
    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
     259        hub_dev->usb_device = usb_dev;
     260        hub_dev->ports = NULL;
     261        hub_dev->port_count = 0;
     262        hub_dev->pending_ops_count = 0;
     263        hub_dev->running = false;
     264        fibril_mutex_initialize(&hub_dev->pending_ops_mutex);
     265        fibril_condvar_initialize(&hub_dev->pending_ops_cv);
     266
     267        return hub_dev;
     268}
     269/*----------------------------------------------------------------------------*/
     270/**
     271 * Load hub-specific information into hub_dev structure and process if needed
    223272 *
    224273 * Read port count and initialize structures holding per port information.
     
    226275 * This function is hub-specific and should be run only after the hub is
    227276 * configured using usb_set_first_configuration function.
    228  * @param hub_info hub representation
     277 * @param hub_dev hub representation
    229278 * @return error code
    230279 */
    231 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info)
    232 {
    233         assert(hub_info);
     280static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev)
     281{
     282        assert(hub_dev);
    234283
    235284        /* Get hub descriptor. */
    236285        usb_log_debug("Retrieving descriptor\n");
    237         usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe;
     286        usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
    238287
    239288        usb_hub_descriptor_header_t descriptor;
     
    250299
    251300        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) {
     301        hub_dev->port_count = descriptor.port_count;
     302
     303        hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t));
     304        if (!hub_dev->ports) {
    258305                return ENOMEM;
    259306        }
    260307
    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);
     308        for (size_t port = 0; port < hub_dev->port_count; ++port) {
     309                usb_hub_port_init(
     310                    &hub_dev->ports[port], port + 1, control_pipe);
    264311        }
    265312
     
    271318                    & HUB_CHAR_POWER_PER_PORT_FLAG;
    272319
    273                 for (port = 1; port <= hub_info->port_count; ++port) {
     320                for (size_t port = 0; port < hub_dev->port_count; ++port) {
    274321                        usb_log_debug("Powering port %zu.\n", port);
    275322                        opResult = usb_hub_port_set_feature(
    276                             &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER);
     323                            &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
    277324                        if (opResult != EOK) {
    278325                                usb_log_error("Cannot power on port %zu: %s.\n",
     
    314361        }
    315362
    316         // TODO: Make sure that there is enough data and the cast is correct
     363        if (usb_device->descriptors.configuration_size
     364            < sizeof(usb_standard_configuration_descriptor_t)) {
     365            usb_log_error("Configuration descriptor is not big enough"
     366                " to fit standard configuration descriptor.\n");
     367            return EOVERFLOW;
     368        }
     369
     370        // TODO: Make sure that the cast is correct
    317371        usb_standard_configuration_descriptor_t *config_descriptor
    318372            = (usb_standard_configuration_descriptor_t *)
     
    337391 *
    338392 * This means either to power off the hub or power it on.
    339  * @param hub_info hub instance
     393 * @param hub_dev hub instance
    340394 * @param status hub status bitmask
    341395 * @return error code
    342396 */
    343 static void usb_hub_over_current(const usb_hub_info_t *hub_info,
     397static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
    344398    usb_hub_status_t status)
    345399{
     
    351405                /* Over-current condition is gone, it is safe to turn the
    352406                 * ports on. */
    353                 size_t port;
    354                 for (port = 1; port <= hub_info->port_count; ++port) {
     407                for (size_t port = 0; port < hub_dev->port_count; ++port) {
    355408                        const int opResult = usb_hub_port_set_feature(
    356                             &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER);
     409                            &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     410                        // TODO: consider power policy here
    357411                        if (opResult != EOK) {
    358412                                usb_log_warning(
     
    364418        }
    365419        const int opResult = usb_request_clear_feature(
    366             &hub_info->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
     420            &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
    367421            USB_REQUEST_RECIPIENT_DEVICE,
    368422            USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0);
     
    378432 *
    379433 * 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);
     434 * @param hub_dev hub instance
     435 */
     436static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev)
     437{
     438        assert(hub_dev);
     439        assert(hub_dev->usb_device);
    386440        usb_log_debug("Global interrupt on a hub\n");
    387         usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe;
     441        usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
    388442
    389443        usb_hub_status_t status;
     
    406460        /* Handle status changes */
    407461        if (status & USB_HUB_STATUS_C_OVER_CURRENT) {
    408                 usb_hub_over_current(hub_info, status);
     462                usb_hub_over_current(hub_dev, status);
    409463        }
    410464
     
    438492 * callback called from hub polling fibril when the fibril terminates
    439493 *
    440  * Should perform a cleanup - deletes hub_info.
     494 * Does not perform cleanup, just marks the hub as not running.
    441495 * @param device usb device afected
    442496 * @param was_error indicates that the fibril is stoped due to an error
    443  * @param data pointer to usb_hub_info_t structure
     497 * @param data pointer to usb_hub_dev_t structure
    444498 */
    445499static void usb_hub_polling_terminated_callback(usb_device_t *device,
    446500    bool was_error, void *data)
    447501{
    448         usb_hub_info_t *hub = data;
     502        usb_hub_dev_t *hub = data;
    449503        assert(hub);
    450504
     
    460514         */
    461515        if (hub->pending_ops_count > 0) {
    462                 size_t port;
    463                 for (port = 0; port < hub->port_count; port++) {
     516                for (size_t port = 0; port < hub->port_count; ++port) {
    464517                        usb_hub_port_reset_fail(&hub->ports[port]);
    465518                }
     
    471524        }
    472525        fibril_mutex_unlock(&hub->pending_ops_mutex);
    473 
    474         usb_device_destroy(hub->usb_device);
    475 
    476         free(hub->ports);
    477         free(hub);
     526        hub->running = false;
    478527}
    479528/**
Note: See TracChangeset for help on using the changeset viewer.