Ignore:
File:
1 edited

Legend:

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

    r065064e6 r32cd37f  
    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         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  */
    131 int usb_hub_device_add(usb_device_t *usb_dev)
     86int usb_hub_add_device(usb_device_t *usb_dev)
    13287{
    13388        assert(usb_dev);
    13489        /* Create driver soft-state structure */
    135         usb_hub_dev_t *hub_dev = usb_hub_dev_create(usb_dev);
    136         if (hub_dev == NULL) {
     90        usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev);
     91        if (hub_info == NULL) {
    13792                usb_log_error("Failed to create hun driver structure.\n");
    13893                return ENOMEM;
     
    14297        usb_log_debug("Initializing USB wire abstraction.\n");
    14398        int opResult = usb_hc_connection_initialize_from_device(
    144             &hub_dev->connection, hub_dev->usb_device->ddf_dev);
     99            &hub_info->connection, hub_info->usb_device->ddf_dev);
    145100        if (opResult != EOK) {
    146101                usb_log_error("Could not initialize connection to device: %s\n",
    147102                    str_error(opResult));
    148                 free(hub_dev);
     103                free(hub_info);
    149104                return opResult;
    150105        }
     
    155110                usb_log_error("Could not set hub configuration: %s\n",
    156111                    str_error(opResult));
    157                 free(hub_dev);
    158                 return opResult;
    159         }
    160 
    161         /* Get port count and create attached_devices. */
    162         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);
    163118        if (opResult != EOK) {
    164119                usb_log_error("Could process hub specific info, %s\n",
    165120                    str_error(opResult));
    166                 free(hub_dev);
     121                free(hub_info);
    167122                return opResult;
    168123        }
    169124
    170125        usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
    171         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,
    172127            fun_exposed, HUB_FNC_NAME);
    173         if (hub_dev->hub_fun == NULL) {
     128        if (hub_fun == NULL) {
    174129                usb_log_error("Failed to create hub function.\n");
    175                 free(hub_dev);
     130                free(hub_info);
    176131                return ENOMEM;
    177132        }
    178133
    179         opResult = ddf_fun_bind(hub_dev->hub_fun);
     134        opResult = ddf_fun_bind(hub_fun);
    180135        if (opResult != EOK) {
    181136                usb_log_error("Failed to bind hub function: %s.\n",
    182137                   str_error(opResult));
    183                 free(hub_dev);
    184                 ddf_fun_destroy(hub_dev->hub_fun);
    185                 return opResult;
    186         }
    187 
    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);
     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);
    196149                usb_log_error("Failed to create polling fibril: %s.\n",
    197150                    str_error(opResult));
    198151                return opResult;
    199152        }
    200         hub_dev->running = true;
    201153        usb_log_info("Controlling hub '%s' (%zu ports).\n",
    202             hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);
     154            hub_info->usb_device->ddf_dev->name, hub_info->port_count);
    203155
    204156        return EOK;
     
    210162 * @param change_bitmap Bitmap of changed ports.
    211163 * @param change_bitmap_size Size of the bitmap in bytes.
    212  * @param arg Custom argument, points to @c usb_hub_dev_t.
     164 * @param arg Custom argument, points to @c usb_hub_info_t.
    213165 * @return Whether to continue polling.
    214166 */
     
    217169{
    218170        usb_log_debug("hub_port_changes_callback\n");
    219         usb_hub_dev_t *hub = arg;
     171        usb_hub_info_t *hub = arg;
    220172        assert(hub);
    221173
     
    232184
    233185        /* N + 1 bit indicates change on port N */
    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;
     186        size_t port = 1;
     187        for (; port < hub->port_count + 1; port++) {
     188                const bool change = (change_bitmap[port / 8] >> (port % 8)) & 1;
    237189                if (change) {
    238190                        usb_hub_port_process_interrupt(&hub->ports[port], hub);
     
    243195/*----------------------------------------------------------------------------*/
    244196/**
    245  * create usb_hub_dev_t structure
     197 * create usb_hub_info_t structure
    246198 *
    247199 * Does only basic copying of known information into new structure.
    248200 * @param usb_dev usb device structure
    249  * @return basic usb_hub_dev_t structure
    250  */
    251 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)
    252204{
    253205        assert(usb_dev);
    254         usb_hub_dev_t *hub_dev =
    255             usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
    256         if (!hub_dev)
     206        usb_hub_info_t *info = malloc(sizeof(usb_hub_info_t));
     207        if (!info)
    257208            return NULL;
    258209
    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
     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
    272223 *
    273224 * Read port count and initialize structures holding per port information.
     
    275226 * This function is hub-specific and should be run only after the hub is
    276227 * configured using usb_set_first_configuration function.
    277  * @param hub_dev hub representation
     228 * @param hub_info hub representation
    278229 * @return error code
    279230 */
    280 static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev)
    281 {
    282         assert(hub_dev);
     231static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info)
     232{
     233        assert(hub_info);
    283234
    284235        /* Get hub descriptor. */
    285236        usb_log_debug("Retrieving descriptor\n");
    286         usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
     237        usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe;
    287238
    288239        usb_hub_descriptor_header_t descriptor;
     
    299250
    300251        usb_log_debug("Setting port count to %d.\n", descriptor.port_count);
    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) {
     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) {
    305258                return ENOMEM;
    306259        }
    307260
    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);
     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);
    311264        }
    312265
     
    318271                    & HUB_CHAR_POWER_PER_PORT_FLAG;
    319272
    320                 for (size_t port = 0; port < hub_dev->port_count; ++port) {
     273                for (port = 1; port <= hub_info->port_count; ++port) {
    321274                        usb_log_debug("Powering port %zu.\n", port);
    322275                        opResult = usb_hub_port_set_feature(
    323                             &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     276                            &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER);
    324277                        if (opResult != EOK) {
    325278                                usb_log_error("Cannot power on port %zu: %s.\n",
     
    361314        }
    362315
    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
     316        // TODO: Make sure that there is enough data and the cast is correct
    371317        usb_standard_configuration_descriptor_t *config_descriptor
    372318            = (usb_standard_configuration_descriptor_t *)
     
    391337 *
    392338 * This means either to power off the hub or power it on.
    393  * @param hub_dev hub instance
     339 * @param hub_info hub instance
    394340 * @param status hub status bitmask
    395341 * @return error code
    396342 */
    397 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,
    398344    usb_hub_status_t status)
    399345{
     
    405351                /* Over-current condition is gone, it is safe to turn the
    406352                 * ports on. */
    407                 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) {
    408355                        const int opResult = usb_hub_port_set_feature(
    409                             &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
    410                         // TODO: consider power policy here
     356                            &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER);
    411357                        if (opResult != EOK) {
    412358                                usb_log_warning(
     
    418364        }
    419365        const int opResult = usb_request_clear_feature(
    420             &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
     366            &hub_info->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
    421367            USB_REQUEST_RECIPIENT_DEVICE,
    422368            USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0);
     
    432378 *
    433379 * The change can be either in the over-current condition or local-power change.
    434  * @param hub_dev hub instance
    435  */
    436 static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev)
    437 {
    438         assert(hub_dev);
    439         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);
    440386        usb_log_debug("Global interrupt on a hub\n");
    441         usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
     387        usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe;
    442388
    443389        usb_hub_status_t status;
     
    460406        /* Handle status changes */
    461407        if (status & USB_HUB_STATUS_C_OVER_CURRENT) {
    462                 usb_hub_over_current(hub_dev, status);
     408                usb_hub_over_current(hub_info, status);
    463409        }
    464410
     
    492438 * callback called from hub polling fibril when the fibril terminates
    493439 *
    494  * Does not perform cleanup, just marks the hub as not running.
     440 * Should perform a cleanup - deletes hub_info.
    495441 * @param device usb device afected
    496442 * @param was_error indicates that the fibril is stoped due to an error
    497  * @param data pointer to usb_hub_dev_t structure
     443 * @param data pointer to usb_hub_info_t structure
    498444 */
    499445static void usb_hub_polling_terminated_callback(usb_device_t *device,
    500446    bool was_error, void *data)
    501447{
    502         usb_hub_dev_t *hub = data;
     448        usb_hub_info_t *hub = data;
    503449        assert(hub);
    504450
     
    514460         */
    515461        if (hub->pending_ops_count > 0) {
    516                 for (size_t port = 0; port < hub->port_count; ++port) {
     462                size_t port;
     463                for (port = 0; port < hub->port_count; port++) {
    517464                        usb_hub_port_reset_fail(&hub->ports[port]);
    518465                }
     
    524471        }
    525472        fibril_mutex_unlock(&hub->pending_ops_mutex);
    526         hub->running = false;
     473
     474        usb_device_destroy(hub->usb_device);
     475
     476        free(hub->ports);
     477        free(hub);
    527478}
    528479/**
Note: See TracChangeset for help on using the changeset viewer.