Ignore:
File:
1 edited

Legend:

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

    ra825eeb0 re231d26  
    6868
    6969static int usb_set_first_configuration(usb_device_t *usb_device);
    70 static usb_hub_dev_t * usb_hub_dev_create(usb_device_t *usb_dev);
    71 static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev);
    72 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
     70static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev);
     71static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info);
     72static void usb_hub_over_current(const usb_hub_info_t *hub_info,
    7373    usb_hub_status_t status);
    74 static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev);
     74static void usb_hub_global_interrupt(const usb_hub_info_t *hub_info);
    7575static void usb_hub_polling_terminated_callback(usb_device_t *device,
    7676    bool was_error, void *data);
     77
    7778/**
    7879 * Initialize hub device driver fibril
     
    8384 * @return error code
    8485 */
    85 int 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  */
    133 int usb_hub_device_add(usb_device_t *usb_dev)
     86int usb_hub_add_device(usb_device_t *usb_dev)
    13487{
    13588        assert(usb_dev);
    13689        /* Create driver soft-state structure */
    137         usb_hub_dev_t *hub_dev = usb_hub_dev_create(usb_dev);
    138         if (hub_dev == NULL) {
     90        usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev);
     91        if (hub_info == NULL) {
    13992                usb_log_error("Failed to create hun driver structure.\n");
    14093                return ENOMEM;
     
    14497        usb_log_debug("Initializing USB wire abstraction.\n");
    14598        int opResult = usb_hc_connection_initialize_from_device(
    146             &hub_dev->connection, hub_dev->usb_device->ddf_dev);
     99            &hub_info->connection, hub_info->usb_device->ddf_dev);
    147100        if (opResult != EOK) {
    148101                usb_log_error("Could not initialize connection to device: %s\n",
    149102                    str_error(opResult));
    150                 free(hub_dev);
     103                free(hub_info);
    151104                return opResult;
    152105        }
     
    157110                usb_log_error("Could not set hub configuration: %s\n",
    158111                    str_error(opResult));
    159                 free(hub_dev);
    160                 return opResult;
    161         }
    162 
    163         /* Get port count and create attached_devices. */
    164         opResult = usb_hub_process_hub_specific_info(hub_dev);
     112                free(hub_info);
     113                return opResult;
     114        }
     115
     116        //get port count and create attached_devs
     117        opResult = usb_hub_process_hub_specific_info(hub_info);
    165118        if (opResult != EOK) {
    166119                usb_log_error("Could process hub specific info, %s\n",
    167120                    str_error(opResult));
    168                 free(hub_dev);
     121                free(hub_info);
    169122                return opResult;
    170123        }
    171124
    172125        usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
    173         hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev,
     126        ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
    174127            fun_exposed, HUB_FNC_NAME);
    175         if (hub_dev->hub_fun == NULL) {
     128        if (hub_fun == NULL) {
    176129                usb_log_error("Failed to create hub function.\n");
    177                 free(hub_dev);
     130                free(hub_info);
    178131                return ENOMEM;
    179132        }
    180133
    181         opResult = ddf_fun_bind(hub_dev->hub_fun);
     134        opResult = ddf_fun_bind(hub_fun);
    182135        if (opResult != EOK) {
    183136                usb_log_error("Failed to bind hub function: %s.\n",
    184137                   str_error(opResult));
    185                 free(hub_dev);
    186                 ddf_fun_destroy(hub_dev->hub_fun);
    187                 return opResult;
    188         }
    189 
    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);
     138                free(hub_info);
     139                ddf_fun_destroy(hub_fun);
     140                return opResult;
     141        }
     142
     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);
    198149                usb_log_error("Failed to create polling fibril: %s.\n",
    199150                    str_error(opResult));
    200151                return opResult;
    201152        }
    202         hub_dev->running = true;
    203153        usb_log_info("Controlling hub '%s' (%zu ports).\n",
    204             hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);
     154            hub_info->usb_device->ddf_dev->name, hub_info->port_count);
    205155
    206156        return EOK;
     
    212162 * @param change_bitmap Bitmap of changed ports.
    213163 * @param change_bitmap_size Size of the bitmap in bytes.
    214  * @param arg Custom argument, points to @c usb_hub_dev_t.
     164 * @param arg Custom argument, points to @c usb_hub_info_t.
    215165 * @return Whether to continue polling.
    216166 */
     
    219169{
    220170        usb_log_debug("hub_port_changes_callback\n");
    221         usb_hub_dev_t *hub = arg;
     171        usb_hub_info_t *hub = arg;
    222172        assert(hub);
    223173
     
    234184
    235185        /* N + 1 bit indicates change on port N */
    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;
     186        size_t port = 1;
     187        for (; port < hub->port_count + 1; port++) {
     188                const bool change = (change_bitmap[port / 8] >> (port % 8)) & 1;
    239189                if (change) {
    240190                        usb_hub_port_process_interrupt(&hub->ports[port], hub);
     
    245195/*----------------------------------------------------------------------------*/
    246196/**
    247  * create usb_hub_dev_t structure
     197 * create usb_hub_info_t structure
    248198 *
    249199 * Does only basic copying of known information into new structure.
    250200 * @param usb_dev usb device structure
    251  * @return basic usb_hub_dev_t structure
    252  */
    253 static usb_hub_dev_t * usb_hub_dev_create(usb_device_t *usb_dev)
     201 * @return basic usb_hub_info_t structure
     202 */
     203static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev)
    254204{
    255205        assert(usb_dev);
    256         usb_hub_dev_t *hub_dev = malloc(sizeof(usb_hub_dev_t));
    257         if (!hub_dev)
     206        usb_hub_info_t *info = malloc(sizeof(usb_hub_info_t));
     207        if (!info)
    258208            return NULL;
    259209
    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
     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
    275223 *
    276224 * Read port count and initialize structures holding per port information.
     
    278226 * This function is hub-specific and should be run only after the hub is
    279227 * configured using usb_set_first_configuration function.
    280  * @param hub_dev hub representation
     228 * @param hub_info hub representation
    281229 * @return error code
    282230 */
    283 static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev)
    284 {
    285         assert(hub_dev);
     231static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info)
     232{
     233        assert(hub_info);
    286234
    287235        /* Get hub descriptor. */
    288236        usb_log_debug("Retrieving descriptor\n");
    289         usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
     237        usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe;
    290238
    291239        usb_hub_descriptor_header_t descriptor;
     
    294242            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    295243            USB_DESCTYPE_HUB, 0, 0, &descriptor,
    296             sizeof(usb_hub_descriptor_header_t), &received_size);
     244            sizeof(usb_hub_descriptor_t), &received_size);
    297245        if (opResult != EOK) {
    298246                usb_log_error("Failed to receive hub descriptor: %s.\n",
     
    302250
    303251        usb_log_debug("Setting port count to %d.\n", descriptor.port_count);
    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) {
     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) {
    308258                return ENOMEM;
    309259        }
    310260
    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);
     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);
    314264        }
    315265
     
    321271                    & HUB_CHAR_POWER_PER_PORT_FLAG;
    322272
    323                 for (size_t port = 0; port < hub_dev->port_count; ++port) {
     273                for (port = 1; port <= hub_info->port_count; ++port) {
    324274                        usb_log_debug("Powering port %zu.\n", port);
    325275                        opResult = usb_hub_port_set_feature(
    326                             &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     276                            &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER);
    327277                        if (opResult != EOK) {
    328278                                usb_log_error("Cannot power on port %zu: %s.\n",
     
    364314        }
    365315
    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
     316        // TODO: Make sure that there is enough data and the cast is correct
    374317        usb_standard_configuration_descriptor_t *config_descriptor
    375318            = (usb_standard_configuration_descriptor_t *)
     
    394337 *
    395338 * This means either to power off the hub or power it on.
    396  * @param hub_dev hub instance
     339 * @param hub_info hub instance
    397340 * @param status hub status bitmask
    398341 * @return error code
    399342 */
    400 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
     343static void usb_hub_over_current(const usb_hub_info_t *hub_info,
    401344    usb_hub_status_t status)
    402345{
     
    408351                /* Over-current condition is gone, it is safe to turn the
    409352                 * ports on. */
    410                 for (size_t port = 0; port < hub_dev->port_count; ++port) {
     353                size_t port;
     354                for (port = 1; port <= hub_info->port_count; ++port) {
    411355                        const int opResult = usb_hub_port_set_feature(
    412                             &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
    413                         // TODO: consider power policy here
     356                            &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER);
    414357                        if (opResult != EOK) {
    415358                                usb_log_warning(
     
    421364        }
    422365        const int opResult = usb_request_clear_feature(
    423             &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
     366            &hub_info->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
    424367            USB_REQUEST_RECIPIENT_DEVICE,
    425368            USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0);
     
    435378 *
    436379 * The change can be either in the over-current condition or local-power change.
    437  * @param hub_dev hub instance
    438  */
    439 static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev)
    440 {
    441         assert(hub_dev);
    442         assert(hub_dev->usb_device);
     380 * @param hub_info hub instance
     381 */
     382static void usb_hub_global_interrupt(const usb_hub_info_t *hub_info)
     383{
     384        assert(hub_info);
     385        assert(hub_info->usb_device);
    443386        usb_log_debug("Global interrupt on a hub\n");
    444         usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
     387        usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe;
    445388
    446389        usb_hub_status_t status;
     
    463406        /* Handle status changes */
    464407        if (status & USB_HUB_STATUS_C_OVER_CURRENT) {
    465                 usb_hub_over_current(hub_dev, status);
     408                usb_hub_over_current(hub_info, status);
    466409        }
    467410
     
    495438 * callback called from hub polling fibril when the fibril terminates
    496439 *
    497  * Does not perform cleanup, just marks the hub as not running.
     440 * Should perform a cleanup - deletes hub_info.
    498441 * @param device usb device afected
    499442 * @param was_error indicates that the fibril is stoped due to an error
    500  * @param data pointer to usb_hub_dev_t structure
     443 * @param data pointer to usb_hub_info_t structure
    501444 */
    502445static void usb_hub_polling_terminated_callback(usb_device_t *device,
    503446    bool was_error, void *data)
    504447{
    505         usb_hub_dev_t *hub = data;
     448        usb_hub_info_t *hub = data;
    506449        assert(hub);
    507450
     
    517460         */
    518461        if (hub->pending_ops_count > 0) {
    519                 for (size_t port = 0; port < hub->port_count; ++port) {
     462                size_t port;
     463                for (port = 0; port < hub->port_count; port++) {
    520464                        usb_hub_port_reset_fail(&hub->ports[port]);
    521465                }
     
    527471        }
    528472        fibril_mutex_unlock(&hub->pending_ops_mutex);
    529         hub->running = false;
     473
     474        usb_device_destroy(hub->usb_device);
     475
     476        free(hub->ports);
     477        free(hub);
    530478}
    531479/**
Note: See TracChangeset for help on using the changeset viewer.