Ignore:
File:
1 edited

Legend:

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

    re231d26 ra825eeb0  
    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;
     
    242294            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    243295            USB_DESCTYPE_HUB, 0, 0, &descriptor,
    244             sizeof(usb_hub_descriptor_t), &received_size);
     296            sizeof(usb_hub_descriptor_header_t), &received_size);
    245297        if (opResult != EOK) {
    246298                usb_log_error("Failed to receive hub descriptor: %s.\n",
     
    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.