Ignore:
File:
1 edited

Legend:

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

    re231d26 rcae002c  
    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 int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev);
     71static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
    7372    usb_hub_status_t status);
    74 static void usb_hub_global_interrupt(const usb_hub_info_t *hub_info);
     73static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev);
    7574static void usb_hub_polling_terminated_callback(usb_device_t *device,
    7675    bool was_error, void *data);
    7776
    7877/**
    79  * Initialize hub device driver fibril
     78 * Initialize hub device driver structure.
    8079 *
    8180 * Creates hub representation and fibril that periodically checks hub's status.
     
    8483 * @return error code
    8584 */
    86 int usb_hub_add_device(usb_device_t *usb_dev)
     85int usb_hub_device_add(usb_device_t *usb_dev)
    8786{
    8887        assert(usb_dev);
    8988        /* Create driver soft-state structure */
    90         usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev);
    91         if (hub_info == NULL) {
    92                 usb_log_error("Failed to create hun driver structure.\n");
     89        usb_hub_dev_t *hub_dev =
     90            usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
     91        if (hub_dev == NULL) {
     92                usb_log_error("Failed to create hub driver structure.\n");
    9393                return ENOMEM;
    9494        }
     95        hub_dev->usb_device = usb_dev;
     96        hub_dev->pending_ops_count = 0;
     97        hub_dev->running = false;
     98        fibril_mutex_initialize(&hub_dev->pending_ops_mutex);
     99        fibril_condvar_initialize(&hub_dev->pending_ops_cv);
    95100
    96101        /* Create hc connection */
    97102        usb_log_debug("Initializing USB wire abstraction.\n");
    98103        int opResult = usb_hc_connection_initialize_from_device(
    99             &hub_info->connection, hub_info->usb_device->ddf_dev);
     104            &hub_dev->connection, hub_dev->usb_device->ddf_dev);
    100105        if (opResult != EOK) {
    101106                usb_log_error("Could not initialize connection to device: %s\n",
    102107                    str_error(opResult));
    103                 free(hub_info);
    104108                return opResult;
    105109        }
     
    110114                usb_log_error("Could not set hub configuration: %s\n",
    111115                    str_error(opResult));
    112                 free(hub_info);
    113116                return opResult;
    114117        }
    115118
    116         //get port count and create attached_devs
    117         opResult = usb_hub_process_hub_specific_info(hub_info);
     119        /* Get port count and create attached_devices. */
     120        opResult = usb_hub_process_hub_specific_info(hub_dev);
    118121        if (opResult != EOK) {
    119122                usb_log_error("Could process hub specific info, %s\n",
    120123                    str_error(opResult));
    121                 free(hub_info);
    122124                return opResult;
    123125        }
    124126
     127        /* Create hub control function. */
    125128        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,
     129        hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev,
    127130            fun_exposed, HUB_FNC_NAME);
    128         if (hub_fun == NULL) {
     131        if (hub_dev->hub_fun == NULL) {
    129132                usb_log_error("Failed to create hub function.\n");
    130                 free(hub_info);
    131133                return ENOMEM;
    132134        }
    133135
    134         opResult = ddf_fun_bind(hub_fun);
     136        /* Bind hub control function. */
     137        opResult = ddf_fun_bind(hub_dev->hub_fun);
    135138        if (opResult != EOK) {
    136139                usb_log_error("Failed to bind hub function: %s.\n",
    137140                   str_error(opResult));
    138                 free(hub_info);
    139                 ddf_fun_destroy(hub_fun);
     141                ddf_fun_destroy(hub_dev->hub_fun);
    140142                return opResult;
    141143        }
    142144
    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);
     145        /* Start hub operation. */
     146        opResult = usb_device_auto_poll(hub_dev->usb_device, 0,
     147            hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8),
     148            usb_hub_polling_terminated_callback, hub_dev);
     149        if (opResult != EOK) {
     150                /* Function is already bound */
     151                ddf_fun_unbind(hub_dev->hub_fun);
     152                ddf_fun_destroy(hub_dev->hub_fun);
    149153                usb_log_error("Failed to create polling fibril: %s.\n",
    150154                    str_error(opResult));
    151155                return opResult;
    152156        }
     157        hub_dev->running = true;
    153158        usb_log_info("Controlling hub '%s' (%zu ports).\n",
    154             hub_info->usb_device->ddf_dev->name, hub_info->port_count);
    155 
     159            hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);
     160
     161        return EOK;
     162}
     163/*----------------------------------------------------------------------------*/
     164/**
     165 * Turn off power to all ports.
     166 *
     167 * @param usb_dev generic usb device information
     168 * @return error code
     169 */
     170int usb_hub_device_remove(usb_device_t *usb_dev)
     171{
     172        return ENOTSUP;
     173}
     174/*----------------------------------------------------------------------------*/
     175/**
     176 * Remove all attached devices
     177 * @param usb_dev generic usb device information
     178 * @return error code
     179 */
     180int usb_hub_device_gone(usb_device_t *usb_dev)
     181{
     182        assert(usb_dev);
     183        usb_hub_dev_t *hub = usb_dev->driver_data;
     184        assert(hub);
     185        unsigned tries = 10;
     186        while (hub->running) {
     187                async_usleep(100000);
     188                if (!tries--) {
     189                        usb_log_error("Can't remove hub, still running.\n");
     190                        return EINPROGRESS;
     191                }
     192        }
     193
     194        assert(!hub->running);
     195
     196        for (size_t port = 0; port < hub->port_count; ++port) {
     197                if (hub->ports[port].attached_device.fun) {
     198                        const int ret =
     199                            usb_hub_port_fini(&hub->ports[port], hub);
     200                        if (ret != EOK)
     201                                return ret;
     202                }
     203        }
     204        free(hub->ports);
     205
     206        const int ret = ddf_fun_unbind(hub->hub_fun);
     207        if (ret != EOK) {
     208                usb_log_error("Failed to unbind '%s' function: %s.\n",
     209                   HUB_FNC_NAME, str_error(ret));
     210                return ret;
     211        }
     212        ddf_fun_destroy(hub->hub_fun);
     213
     214        usb_log_info("USB hub driver, stopped and cleaned.\n");
    156215        return EOK;
    157216}
     
    162221 * @param change_bitmap Bitmap of changed ports.
    163222 * @param change_bitmap_size Size of the bitmap in bytes.
    164  * @param arg Custom argument, points to @c usb_hub_info_t.
     223 * @param arg Custom argument, points to @c usb_hub_dev_t.
    165224 * @return Whether to continue polling.
    166225 */
     
    169228{
    170229        usb_log_debug("hub_port_changes_callback\n");
    171         usb_hub_info_t *hub = arg;
     230        usb_hub_dev_t *hub = arg;
    172231        assert(hub);
    173232
     
    184243
    185244        /* 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;
     245        for (size_t port = 0; port < hub->port_count + 1; port++) {
     246                const size_t bit = port + 1;
     247                const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1;
    189248                if (change) {
    190249                        usb_hub_port_process_interrupt(&hub->ports[port], hub);
     
    195254/*----------------------------------------------------------------------------*/
    196255/**
    197  * create usb_hub_info_t structure
    198  *
    199  * Does only basic copying of known information into new structure.
    200  * @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)
    204 {
    205         assert(usb_dev);
    206         usb_hub_info_t *info = malloc(sizeof(usb_hub_info_t));
    207         if (!info)
    208             return NULL;
    209 
    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
     256 * Load hub-specific information into hub_dev structure and process if needed
    223257 *
    224258 * Read port count and initialize structures holding per port information.
     
    226260 * This function is hub-specific and should be run only after the hub is
    227261 * configured using usb_set_first_configuration function.
    228  * @param hub_info hub representation
     262 * @param hub_dev hub representation
    229263 * @return error code
    230264 */
    231 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info)
    232 {
    233         assert(hub_info);
     265static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev)
     266{
     267        assert(hub_dev);
    234268
    235269        /* Get hub descriptor. */
    236270        usb_log_debug("Retrieving descriptor\n");
    237         usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe;
     271        usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
    238272
    239273        usb_hub_descriptor_header_t descriptor;
     
    242276            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    243277            USB_DESCTYPE_HUB, 0, 0, &descriptor,
    244             sizeof(usb_hub_descriptor_t), &received_size);
     278            sizeof(usb_hub_descriptor_header_t), &received_size);
    245279        if (opResult != EOK) {
    246280                usb_log_error("Failed to receive hub descriptor: %s.\n",
     
    250284
    251285        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) {
     286        hub_dev->port_count = descriptor.port_count;
     287
     288        hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t));
     289        if (!hub_dev->ports) {
    258290                return ENOMEM;
    259291        }
    260292
    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);
    264         }
    265 
    266         const bool is_power_switched =
     293        for (size_t port = 0; port < hub_dev->port_count; ++port) {
     294                usb_hub_port_init(
     295                    &hub_dev->ports[port], port + 1, control_pipe);
     296        }
     297
     298        hub_dev->power_switched =
    267299            !(descriptor.characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG);
    268         if (is_power_switched) {
    269                 usb_log_debug("Hub power switched\n");
    270                 const bool per_port_power = descriptor.characteristics
    271                     & HUB_CHAR_POWER_PER_PORT_FLAG;
    272 
    273                 for (port = 1; port <= hub_info->port_count; ++port) {
    274                         usb_log_debug("Powering port %zu.\n", port);
    275                         opResult = usb_hub_port_set_feature(
    276                             &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER);
    277                         if (opResult != EOK) {
    278                                 usb_log_error("Cannot power on port %zu: %s.\n",
    279                                     port, str_error(opResult));
    280                         } else {
    281                                 if (!per_port_power) {
    282                                         usb_log_debug(
    283                                             "Ganged power switching mode, "
    284                                             "one port is enough.\n");
    285                                         break;
    286                                 }
     300        hub_dev->per_port_power =
     301            descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG;
     302
     303        if (!hub_dev->power_switched) {
     304                usb_log_info(
     305                   "Power switching not supported, ports always powered.\n");
     306                return EOK;
     307        }
     308
     309        usb_log_info("Hub port power switching enabled.\n");
     310
     311        for (size_t port = 0; port < hub_dev->port_count; ++port) {
     312                usb_log_debug("Powering port %zu.\n", port);
     313                const int ret = usb_hub_port_set_feature(
     314                    &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     315
     316                if (ret != EOK) {
     317                        usb_log_error("Cannot power on port %zu: %s.\n",
     318                            hub_dev->ports[port].port_number, str_error(ret));
     319                } else {
     320                        if (!hub_dev->per_port_power) {
     321                                usb_log_debug("Ganged power switching, "
     322                                    "one port is enough.\n");
     323                                break;
    287324                        }
    288325                }
    289         } else {
    290                 usb_log_debug("Power not switched, ports always powered\n");
    291326        }
    292327        return EOK;
     
    314349        }
    315350
    316         // TODO: Make sure that there is enough data and the cast is correct
     351        if (usb_device->descriptors.configuration_size
     352            < sizeof(usb_standard_configuration_descriptor_t)) {
     353            usb_log_error("Configuration descriptor is not big enough"
     354                " to fit standard configuration descriptor.\n");
     355            return EOVERFLOW;
     356        }
     357
     358        // TODO: Make sure that the cast is correct
    317359        usb_standard_configuration_descriptor_t *config_descriptor
    318360            = (usb_standard_configuration_descriptor_t *)
     
    337379 *
    338380 * This means either to power off the hub or power it on.
    339  * @param hub_info hub instance
     381 * @param hub_dev hub instance
    340382 * @param status hub status bitmask
    341383 * @return error code
    342384 */
    343 static void usb_hub_over_current(const usb_hub_info_t *hub_info,
     385static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
    344386    usb_hub_status_t status)
    345387{
     
    348390                usb_log_warning("Detected hub over-current condition, "
    349391                    "all ports should be powered off.");
    350         } else {
    351                 /* Over-current condition is gone, it is safe to turn the
    352                  * ports on. */
    353                 size_t port;
    354                 for (port = 1; port <= hub_info->port_count; ++port) {
    355                         const int opResult = usb_hub_port_set_feature(
    356                             &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER);
    357                         if (opResult != EOK) {
    358                                 usb_log_warning(
    359                                     "HUB OVER-CURRENT GONE: Cannot power on "
    360                                     "port %zu;  %s\n",
    361                                     port, str_error(opResult));
    362                         }
    363                 }
    364         }
    365         const int opResult = usb_request_clear_feature(
    366             &hub_info->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
    367             USB_REQUEST_RECIPIENT_DEVICE,
    368             USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0);
    369         if (opResult != EOK) {
    370                 usb_log_error(
    371                     "Failed to clear hub over-current change flag: %s.\n",
    372                     str_error(opResult));
    373         }
     392                return;
     393        }
     394
     395        /* Ports are always powered. */
     396        if (!hub_dev->power_switched)
     397                return;
     398
     399        /* Over-current condition is gone, it is safe to turn the ports on. */
     400        for (size_t port = 0; port < hub_dev->port_count; ++port) {
     401                const int ret = usb_hub_port_set_feature(
     402                    &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     403                if (ret != EOK) {
     404                        usb_log_warning("HUB OVER-CURRENT GONE: Cannot power on"
     405                            " port %zu: %s\n", hub_dev->ports[port].port_number,
     406                            str_error(ret));
     407                } else {
     408                        if (!hub_dev->per_port_power)
     409                                return;
     410                }
     411        }
     412
    374413}
    375414/*----------------------------------------------------------------------------*/
     
    378417 *
    379418 * 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);
     419 * @param hub_dev hub instance
     420 */
     421static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev)
     422{
     423        assert(hub_dev);
     424        assert(hub_dev->usb_device);
    386425        usb_log_debug("Global interrupt on a hub\n");
    387         usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe;
     426        usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
    388427
    389428        usb_hub_status_t status;
     
    406445        /* Handle status changes */
    407446        if (status & USB_HUB_STATUS_C_OVER_CURRENT) {
    408                 usb_hub_over_current(hub_info, status);
     447                usb_hub_over_current(hub_dev, status);
     448                /* Ack change in hub OC flag */
     449                const int ret = usb_request_clear_feature(
     450                    &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
     451                    USB_REQUEST_RECIPIENT_DEVICE,
     452                    USB_HUB_FEATURE_C_HUB_OVER_CURRENT, 0);
     453                if (ret != EOK) {
     454                        usb_log_error("Failed to clear hub over-current "
     455                            "change flag: %s.\n", str_error(opResult));
     456                }
    409457        }
    410458
     
    423471                 * Just ACK the change.
    424472                 */
    425                 const int opResult = usb_request_clear_feature(
     473                const int ret = usb_request_clear_feature(
    426474                    control_pipe, USB_REQUEST_TYPE_CLASS,
    427475                    USB_REQUEST_RECIPIENT_DEVICE,
    428476                    USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0);
    429477                if (opResult != EOK) {
    430                         usb_log_error(
    431                             "Failed to clear hub power change flag: %s.\n",
    432                             str_error(opResult));
     478                        usb_log_error("Failed to clear hub power change "
     479                            "flag: %s.\n", str_error(ret));
    433480                }
    434481        }
     
    438485 * callback called from hub polling fibril when the fibril terminates
    439486 *
    440  * Should perform a cleanup - deletes hub_info.
     487 * Does not perform cleanup, just marks the hub as not running.
    441488 * @param device usb device afected
    442489 * @param was_error indicates that the fibril is stoped due to an error
    443  * @param data pointer to usb_hub_info_t structure
     490 * @param data pointer to usb_hub_dev_t structure
    444491 */
    445492static void usb_hub_polling_terminated_callback(usb_device_t *device,
    446493    bool was_error, void *data)
    447494{
    448         usb_hub_info_t *hub = data;
     495        usb_hub_dev_t *hub = data;
    449496        assert(hub);
    450497
     
    460507         */
    461508        if (hub->pending_ops_count > 0) {
    462                 size_t port;
    463                 for (port = 0; port < hub->port_count; port++) {
     509                for (size_t port = 0; port < hub->port_count; ++port) {
    464510                        usb_hub_port_reset_fail(&hub->ports[port]);
    465511                }
     
    471517        }
    472518        fibril_mutex_unlock(&hub->pending_ops_mutex);
    473 
    474         usb_device_destroy(hub->usb_device);
    475 
    476         free(hub->ports);
    477         free(hub);
     519        hub->running = false;
    478520}
    479521/**
Note: See TracChangeset for help on using the changeset viewer.