Changeset 26d46d2 in mainline for uspace/lib/usb/src/devdrv.c


Ignore:
Timestamp:
2011-04-10T22:33:27Z (13 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1a46610, fd153d3
Parents:
c6fe469 (diff), c7bdfa7 (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:

Development branch changes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usb/src/devdrv.c

    rc6fe469 r26d46d2  
    100100    usb_device_t *dev, int alternate_setting)
    101101{
     102        if (endpoints == NULL) {
     103                dev->pipes = NULL;
     104                dev->pipes_count = 0;
     105                return EOK;
     106        }
     107
    102108        usb_endpoint_mapping_t *pipes;
    103109        size_t pipes_count;
     
    109115
    110116        if (rc != EOK) {
    111                 usb_log_error(
    112                     "Failed to create endpoint pipes for `%s': %s.\n",
    113                     dev->ddf_dev->name, str_error(rc));
    114117                return rc;
    115118        }
     
    117120        dev->pipes = pipes;
    118121        dev->pipes_count = pipes_count;
    119 
    120         return EOK;
    121 }
    122 
    123 /** Initialize all endpoint pipes.
    124  *
    125  * @param drv The driver.
    126  * @param dev The device to be initialized.
    127  * @return Error code.
    128  */
    129 static int initialize_pipes(usb_device_t *dev)
    130 {
    131         int rc;
    132 
    133         rc = usb_device_connection_initialize_from_device(&dev->wire,
    134             dev->ddf_dev);
    135         if (rc != EOK) {
    136                 usb_log_error(
    137                     "Failed initializing connection on device `%s'. %s.\n",
    138                     dev->ddf_dev->name, str_error(rc));
    139                 return rc;
    140         }
    141 
    142         rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe,
    143             &dev->wire);
    144         if (rc != EOK) {
    145                 usb_log_error("Failed to initialize default control pipe " \
    146                     "on device `%s': %s.\n",
    147                     dev->ddf_dev->name, str_error(rc));
    148                 return rc;
    149         }
    150 
    151         rc = usb_pipe_probe_default_control(&dev->ctrl_pipe);
    152         if (rc != EOK) {
    153                 usb_log_error(
    154                     "Probing default control pipe on device `%s' failed: %s.\n",
    155                     dev->ddf_dev->name, str_error(rc));
    156                 return rc;
    157         }
    158 
    159         /* Get our interface. */
    160         dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
    161 
    162         /*
    163          * We will do some querying of the device, it is worth to prepare
    164          * the long transfer.
    165          */
    166         rc = usb_pipe_start_long_transfer(&dev->ctrl_pipe);
    167         if (rc != EOK) {
    168                 usb_log_error("Failed to start transfer: %s.\n",
    169                     str_error(rc));
    170                 return rc;
    171         }
    172 
    173         /* Retrieve the descriptors. */
    174         rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,
    175             &dev->descriptors);
    176         if (rc != EOK) {
    177                 usb_log_error("Failed to retrieve standard device " \
    178                     "descriptors of %s: %s.\n",
    179                     dev->ddf_dev->name, str_error(rc));
    180                 return rc;
    181         }
    182 
    183 
    184         if (driver->endpoints != NULL) {
    185                 rc = initialize_other_pipes(driver->endpoints, dev, 0);
    186         }
    187 
    188         usb_pipe_end_long_transfer(&dev->ctrl_pipe);
    189 
    190         /* Rollback actions. */
    191         if (rc != EOK) {
    192                 if (dev->descriptors.configuration != NULL) {
    193                         free(dev->descriptors.configuration);
    194                 }
    195         }
    196 
    197         return rc;
    198 }
    199 
    200 /** Count number of alternate settings of a interface.
    201  *
    202  * @param config_descr Full configuration descriptor.
    203  * @param config_descr_size Size of @p config_descr in bytes.
    204  * @param interface_no Interface number.
    205  * @return Number of alternate interfaces for @p interface_no interface.
    206  */
    207 size_t usb_interface_count_alternates(uint8_t *config_descr,
    208     size_t config_descr_size, uint8_t interface_no)
    209 {
    210         assert(config_descr != NULL);
    211         assert(config_descr_size > 0);
    212 
    213         usb_dp_parser_t dp_parser = {
    214                 .nesting = usb_dp_standard_descriptor_nesting
    215         };
    216         usb_dp_parser_data_t dp_data = {
    217                 .data = config_descr,
    218                 .size = config_descr_size,
    219                 .arg = NULL
    220         };
    221 
    222         size_t alternate_count = 0;
    223 
    224         uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
    225             &dp_data, config_descr);
    226         while (iface_ptr != NULL) {
    227                 usb_standard_interface_descriptor_t *iface
    228                     = (usb_standard_interface_descriptor_t *) iface_ptr;
    229                 if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) {
    230                         if (iface->interface_number == interface_no) {
    231                                 alternate_count++;
    232                         }
    233                 }
    234                 iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
    235                     config_descr, iface_ptr);
    236         }
    237 
    238         return alternate_count;
    239 }
    240 
    241 /** Initialize structures related to alternate interfaces.
    242  *
    243  * @param dev Device where alternate settings shall be initialized.
    244  * @return Error code.
    245  */
    246 static int initialize_alternate_interfaces(usb_device_t *dev)
    247 {
    248         if (dev->interface_no < 0) {
    249                 dev->alternate_interfaces = NULL;
    250                 return EOK;
    251         }
    252 
    253         usb_alternate_interfaces_t *alternates
    254             = malloc(sizeof(usb_alternate_interfaces_t));
    255 
    256         if (alternates == NULL) {
    257                 return ENOMEM;
    258         }
    259 
    260         alternates->alternative_count
    261             = usb_interface_count_alternates(dev->descriptors.configuration,
    262             dev->descriptors.configuration_size, dev->interface_no);
    263 
    264         if (alternates->alternative_count == 0) {
    265                 free(alternates);
    266                 return ENOENT;
    267         }
    268 
    269         alternates->alternatives = malloc(alternates->alternative_count
    270             * sizeof(usb_alternate_interface_descriptors_t));
    271         if (alternates->alternatives == NULL) {
    272                 free(alternates);
    273                 return ENOMEM;
    274         }
    275 
    276         alternates->current = 0;
    277 
    278         usb_dp_parser_t dp_parser = {
    279                 .nesting = usb_dp_standard_descriptor_nesting
    280         };
    281         usb_dp_parser_data_t dp_data = {
    282                 .data = dev->descriptors.configuration,
    283                 .size = dev->descriptors.configuration_size,
    284                 .arg = NULL
    285         };
    286 
    287         usb_alternate_interface_descriptors_t *cur_alt_iface
    288             = &alternates->alternatives[0];
    289 
    290         uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
    291             &dp_data, dp_data.data);
    292         while (iface_ptr != NULL) {
    293                 usb_standard_interface_descriptor_t *iface
    294                     = (usb_standard_interface_descriptor_t *) iface_ptr;
    295                 if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
    296                     || (iface->interface_number != dev->interface_no)) {
    297                         iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
    298                             &dp_data,
    299                             dp_data.data, iface_ptr);
    300                         continue;
    301                 }
    302 
    303                 cur_alt_iface->interface = iface;
    304                 cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface);
    305 
    306                 /* Find next interface to count size of nested descriptors. */
    307                 iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
    308                     dp_data.data, iface_ptr);
    309                 if (iface_ptr == NULL) {
    310                         uint8_t *next = dp_data.data + dp_data.size;
    311                         cur_alt_iface->nested_descriptors_size
    312                             = next - cur_alt_iface->nested_descriptors;
    313                 } else {
    314                         cur_alt_iface->nested_descriptors_size
    315                             = iface_ptr - cur_alt_iface->nested_descriptors;
    316                 }
    317 
    318                 cur_alt_iface++;
    319         }
    320 
    321         dev->alternate_interfaces = alternates;
    322122
    323123        return EOK;
     
    339139        int rc;
    340140
    341         usb_device_t *dev = malloc(sizeof(usb_device_t));
    342         if (dev == NULL) {
    343                 usb_log_error("Out of memory when adding device `%s'.\n",
    344                     gen_dev->name);
    345                 return ENOMEM;
    346         }
    347 
    348 
    349         dev->ddf_dev = gen_dev;
    350         dev->ddf_dev->driver_data = dev;
    351         dev->driver_data = NULL;
    352         dev->descriptors.configuration = NULL;
    353 
    354         dev->pipes_count = 0;
    355         dev->pipes = NULL;
    356 
    357         rc = initialize_pipes(dev);
    358         if (rc != EOK) {
    359                 free(dev);
    360                 return rc;
    361         }
    362 
    363         (void) initialize_alternate_interfaces(dev);
     141        usb_device_t *dev = NULL;
     142        const char *err_msg = NULL;
     143        rc = usb_device_create(gen_dev, driver->endpoints, &dev, &err_msg);
     144        if (rc != EOK) {
     145                usb_log_error("USB device `%s' creation failed (%s): %s.\n",
     146                    gen_dev->name, err_msg, str_error(rc));
     147                return rc;
     148        }
    364149
    365150        return driver->ops->add_device(dev);
     
    395180 * with usb_pipe_initialize_from_configuration().
    396181 *
     182 * @warning This is a wrapper function that does several operations that
     183 * can fail and that cannot be rollbacked easily. That means that a failure
     184 * during the SET_INTERFACE request would result in having a device with
     185 * no pipes at all (except the default control one). That is because the old
     186 * pipes needs to be unregistered at HC first and the new ones could not
     187 * be created.
     188 *
    397189 * @param dev USB device.
    398190 * @param alternate_setting Alternate setting to choose.
     
    409201        int rc;
    410202
    411         /* TODO: more transactional behavior. */
    412 
    413203        /* Destroy existing pipes. */
    414204        rc = destroy_current_pipes(dev);
     
    432222/** Retrieve basic descriptors from the device.
    433223 *
    434  * @param[in] ctrl_pipe Control pipe with opened session.
     224 * @param[in] ctrl_pipe Control endpoint pipe.
    435225 * @param[out] descriptors Where to store the descriptors.
    436226 * @return Error code.
     
    440230{
    441231        assert(descriptors != NULL);
    442         assert(usb_pipe_is_session_started(ctrl_pipe));
    443232
    444233        descriptors->configuration = NULL;
    445234
    446235        int rc;
     236
     237        /* It is worth to start a long transfer. */
     238        rc = usb_pipe_start_long_transfer(ctrl_pipe);
     239        if (rc != EOK) {
     240                return rc;
     241        }
    447242
    448243        /* Get the device descriptor. */
    449244        rc = usb_request_get_device_descriptor(ctrl_pipe, &descriptors->device);
    450245        if (rc != EOK) {
    451                 return rc;
     246                goto leave;
    452247        }
    453248
     
    456251            ctrl_pipe, 0, (void **) &descriptors->configuration,
    457252            &descriptors->configuration_size);
    458         if (rc != EOK) {
    459                 return rc;
    460         }
    461 
    462         return EOK;
     253
     254leave:
     255        usb_pipe_end_long_transfer(ctrl_pipe);
     256
     257        return rc;
    463258}
    464259
     
    641436}
    642437
     438/** Initialize control pipe in a device.
     439 *
     440 * @param dev USB device in question.
     441 * @param errmsg Where to store error context.
     442 * @return
     443 */
     444static int init_wire_and_ctrl_pipe(usb_device_t *dev, const char **errmsg)
     445{
     446        int rc;
     447
     448        rc = usb_device_connection_initialize_from_device(&dev->wire,
     449            dev->ddf_dev);
     450        if (rc != EOK) {
     451                *errmsg = "device connection initialization";
     452                return rc;
     453        }
     454
     455        rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe,
     456            &dev->wire);
     457        if (rc != EOK) {
     458                *errmsg = "default control pipe initialization";
     459                return rc;
     460        }
     461
     462        return EOK;
     463}
     464
     465
     466/** Create new instance of USB device.
     467 *
     468 * @param[in] ddf_dev Generic DDF device backing the USB one.
     469 * @param[in] endpoints NULL terminated array of endpoints (NULL for none).
     470 * @param[out] dev_ptr Where to store pointer to the new device.
     471 * @param[out] errstr_ptr Where to store description of context
     472 *      (in case error occurs).
     473 * @return Error code.
     474 */
     475int usb_device_create(ddf_dev_t *ddf_dev,
     476    usb_endpoint_description_t **endpoints,
     477    usb_device_t **dev_ptr, const char **errstr_ptr)
     478{
     479        assert(dev_ptr != NULL);
     480        assert(ddf_dev != NULL);
     481
     482        int rc;
     483
     484        usb_device_t *dev = malloc(sizeof(usb_device_t));
     485        if (dev == NULL) {
     486                *errstr_ptr = "structure allocation";
     487                return ENOMEM;
     488        }
     489
     490        // FIXME: proper deallocation in case of errors
     491
     492        dev->ddf_dev = ddf_dev;
     493        dev->driver_data = NULL;
     494        dev->descriptors.configuration = NULL;
     495        dev->alternate_interfaces = NULL;
     496
     497        dev->pipes_count = 0;
     498        dev->pipes = NULL;
     499
     500        /* Initialize backing wire and control pipe. */
     501        rc = init_wire_and_ctrl_pipe(dev, errstr_ptr);
     502        if (rc != EOK) {
     503                return rc;
     504        }
     505
     506        /* Get our interface. */
     507        dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
     508
     509        /* Retrieve standard descriptors. */
     510        rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,
     511            &dev->descriptors);
     512        if (rc != EOK) {
     513                *errstr_ptr = "descriptor retrieval";
     514                return rc;
     515        }
     516
     517        /* Create alternate interfaces. */
     518        rc = usb_alternate_interfaces_create(dev->descriptors.configuration,
     519            dev->descriptors.configuration_size, dev->interface_no,
     520            &dev->alternate_interfaces);
     521        if (rc != EOK) {
     522                /* We will try to silently ignore this. */
     523                dev->alternate_interfaces = NULL;
     524        }
     525
     526        rc = initialize_other_pipes(endpoints, dev, 0);
     527        if (rc != EOK) {
     528                *errstr_ptr = "pipes initialization";
     529                return rc;
     530        }
     531
     532        *errstr_ptr = NULL;
     533        *dev_ptr = dev;
     534
     535        return EOK;
     536}
     537
    643538/**
    644539 * @}
Note: See TracChangeset for help on using the changeset viewer.