Ignore:
File:
1 edited

Legend:

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

    r0b4e7ca re484f3b  
    3636#include <usb/request.h>
    3737#include <usb/debug.h>
    38 #include <usb/dp.h>
    3938#include <errno.h>
    4039#include <str_error.h>
     
    8786 * @return Number of pipes (excluding default control pipe).
    8887 */
    89 static size_t count_other_pipes(usb_endpoint_description_t **endpoints)
     88static size_t count_other_pipes(usb_driver_t *drv)
    9089{
    9190        size_t count = 0;
    92         if (endpoints == NULL) {
     91        if (drv->endpoints == NULL) {
    9392                return 0;
    9493        }
    9594
    96         while (endpoints[count] != NULL) {
     95        while (drv->endpoints[count] != NULL) {
    9796                count++;
    9897        }
     
    107106 * @return Error code.
    108107 */
    109 static int initialize_other_pipes(usb_endpoint_description_t **endpoints,
    110     usb_device_t *dev)
     108static int initialize_other_pipes(usb_driver_t *drv, usb_device_t *dev)
    111109{
    112110        int rc;
    113 
    114         size_t pipe_count = count_other_pipes(endpoints);
    115         if (pipe_count == 0) {
    116                 return EOK;
    117         }
    118 
     111        dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
     112
     113        size_t pipe_count = count_other_pipes(drv);
    119114        dev->pipes = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
    120115        if (dev->pipes == NULL) {
     
    138133                }
    139134
    140                 dev->pipes[i].description = endpoints[i];
     135                dev->pipes[i].description = drv->endpoints[i];
    141136                dev->pipes[i].interface_no = dev->interface_no;
    142                 dev->pipes[i].interface_setting = 0;
    143137        }
    144138
     
    184178        usb_hc_connection_close(&hc_conn);
    185179
    186         dev->pipes_count = pipe_count;
    187 
    188180        return EOK;
    189181
     
    235227        }
    236228
    237         /* Get our interface. */
    238         dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
    239 
    240229        /*
    241230         * For further actions, we need open session on default control pipe.
     
    268257
    269258        if (driver->endpoints != NULL) {
    270                 rc = initialize_other_pipes(driver->endpoints, dev);
     259                rc = initialize_other_pipes(driver, dev);
    271260        }
    272261
     
    282271
    283272        return rc;
    284 }
    285 
    286 /** Count number of alternate settings of a interface.
    287  *
    288  * @param config_descr Full configuration descriptor.
    289  * @param config_descr_size Size of @p config_descr in bytes.
    290  * @param interface_no Interface number.
    291  * @return Number of alternate interfaces for @p interface_no interface.
    292  */
    293 static size_t count_alternate_interfaces(uint8_t *config_descr,
    294     size_t config_descr_size, int interface_no)
    295 {
    296         assert(config_descr != NULL);
    297         usb_dp_parser_t dp_parser = {
    298                 .nesting = usb_dp_standard_descriptor_nesting
    299         };
    300         usb_dp_parser_data_t dp_data = {
    301                 .data = config_descr,
    302                 .size = config_descr_size,
    303                 .arg = NULL
    304         };
    305 
    306         size_t alternate_count = 0;
    307 
    308         uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
    309             &dp_data, config_descr);
    310         while (iface_ptr != NULL) {
    311                 usb_standard_interface_descriptor_t *iface
    312                     = (usb_standard_interface_descriptor_t *) iface_ptr;
    313                 if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) {
    314                         if (iface->interface_number == interface_no) {
    315                                 alternate_count++;
    316                         }
    317                 }
    318                 iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
    319                     config_descr, iface_ptr);
    320         }
    321 
    322         return alternate_count;
    323 }
    324 
    325 /** Initialize structures related to alternate interfaces.
    326  *
    327  * @param dev Device where alternate settings shall be initialized.
    328  * @return Error code.
    329  */
    330 static int initialize_alternate_interfaces(usb_device_t *dev)
    331 {
    332         if (dev->interface_no < 0) {
    333                 dev->alternate_interfaces = NULL;
    334                 return EOK;
    335         }
    336 
    337         usb_alternate_interfaces_t *alternates
    338             = malloc(sizeof(usb_alternate_interfaces_t));
    339 
    340         if (alternates == NULL) {
    341                 return ENOMEM;
    342         }
    343 
    344         alternates->alternative_count
    345             = count_alternate_interfaces(dev->descriptors.configuration,
    346             dev->descriptors.configuration_size, dev->interface_no);
    347 
    348         if (alternates->alternative_count == 0) {
    349                 free(alternates);
    350                 return ENOENT;
    351         }
    352 
    353         alternates->alternatives = malloc(alternates->alternative_count
    354             * sizeof(usb_alternate_interface_descriptors_t));
    355         if (alternates->alternatives == NULL) {
    356                 free(alternates);
    357                 return ENOMEM;
    358         }
    359 
    360         alternates->current = 0;
    361 
    362         usb_dp_parser_t dp_parser = {
    363                 .nesting = usb_dp_standard_descriptor_nesting
    364         };
    365         usb_dp_parser_data_t dp_data = {
    366                 .data = dev->descriptors.configuration,
    367                 .size = dev->descriptors.configuration_size,
    368                 .arg = NULL
    369         };
    370 
    371         usb_alternate_interface_descriptors_t *cur_alt_iface
    372             = &alternates->alternatives[0];
    373 
    374         uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
    375             &dp_data, dp_data.data);
    376         while (iface_ptr != NULL) {
    377                 usb_standard_interface_descriptor_t *iface
    378                     = (usb_standard_interface_descriptor_t *) iface_ptr;
    379                 if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
    380                     || (iface->interface_number != dev->interface_no)) {
    381                         iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
    382                             &dp_data,
    383                             dp_data.data, iface_ptr);
    384                         continue;
    385                 }
    386 
    387                 cur_alt_iface->interface = iface;
    388                 cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface);
    389 
    390                 /* Find next interface to count size of nested descriptors. */
    391                 iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
    392                     dp_data.data, iface_ptr);
    393                 if (iface_ptr == NULL) {
    394                         uint8_t *next = dp_data.data + dp_data.size;
    395                         cur_alt_iface->nested_descriptors_size
    396                             = next - cur_alt_iface->nested_descriptors;
    397                 } else {
    398                         cur_alt_iface->nested_descriptors_size
    399                             = iface_ptr - cur_alt_iface->nested_descriptors;
    400                 }
    401 
    402                 cur_alt_iface++;
    403         }
    404 
    405         dev->alternate_interfaces = alternates;
    406 
    407         return EOK;
    408273}
    409274
     
    436301        dev->descriptors.configuration = NULL;
    437302
    438         dev->pipes_count = 0;
    439         dev->pipes = NULL;
    440 
    441303        rc = initialize_pipes(dev);
    442304        if (rc != EOK) {
     
    445307        }
    446308
    447         (void) initialize_alternate_interfaces(dev);
    448 
    449309        return driver->ops->add_device(dev);
    450 }
    451 
    452 /** Destroy existing pipes of a USB device.
    453  *
    454  * @param dev Device where to destroy the pipes.
    455  * @return Error code.
    456  */
    457 static int destroy_current_pipes(usb_device_t *dev)
    458 {
    459         size_t i;
    460         int rc;
    461 
    462         /* TODO: this shall be done under some device mutex. */
    463 
    464         /* First check that no session is opened. */
    465         for (i = 0; i < dev->pipes_count; i++) {
    466                 if (usb_pipe_is_session_started(dev->pipes[i].pipe)) {
    467                         return EBUSY;
    468                 }
    469         }
    470 
    471         /* Prepare connection to HC. */
    472         usb_hc_connection_t hc_conn;
    473         rc = usb_hc_connection_initialize_from_device(&hc_conn, dev->ddf_dev);
    474         if (rc != EOK) {
    475                 return rc;
    476         }
    477         rc = usb_hc_connection_open(&hc_conn);
    478         if (rc != EOK) {
    479                 return rc;
    480         }
    481 
    482         /* Destroy the pipes. */
    483         for (i = 0; i < dev->pipes_count; i++) {
    484                 usb_pipe_unregister(dev->pipes[i].pipe, &hc_conn);
    485                 free(dev->pipes[i].pipe);
    486         }
    487 
    488         usb_hc_connection_close(&hc_conn);
    489 
    490         free(dev->pipes);
    491         dev->pipes = NULL;
    492         dev->pipes_count = 0;
    493 
    494         return EOK;
    495 }
    496 
    497 /** Change interface setting of a device.
    498  * This function selects new alternate setting of an interface by issuing
    499  * proper USB command to the device and also creates new USB pipes
    500  * under @c dev->pipes.
    501  *
    502  * @warning This function is intended for drivers working at interface level.
    503  * For drivers controlling the whole device, you need to change interface
    504  * manually using usb_request_set_interface() and creating new pipes
    505  * with usb_pipe_initialize_from_configuration().
    506  *
    507  * @param dev USB device.
    508  * @param alternate_setting Alternate setting to choose.
    509  * @param endpoints New endpoint descriptions.
    510  * @return Error code.
    511  */
    512 int usb_device_select_interface(usb_device_t *dev, uint8_t alternate_setting,
    513     usb_endpoint_description_t **endpoints)
    514 {
    515         if (dev->interface_no < 0) {
    516                 return EINVAL;
    517         }
    518 
    519         int rc;
    520 
    521         /* TODO: more transactional behavior. */
    522 
    523         /* Destroy existing pipes. */
    524         rc = destroy_current_pipes(dev);
    525         if (rc != EOK) {
    526                 return rc;
    527         }
    528 
    529         /* Change the interface itself. */
    530         rc = usb_request_set_interface(&dev->ctrl_pipe, dev->interface_no,
    531             alternate_setting);
    532         if (rc != EOK) {
    533                 return rc;
    534         }
    535 
    536         /* Create new pipes. */
    537         rc = initialize_other_pipes(endpoints, dev);
    538 
    539         return rc;
    540310}
    541311
Note: See TracChangeset for help on using the changeset viewer.