Changeset 0cec844 in mainline for uspace/lib/usb/src/devdrv.c


Ignore:
Timestamp:
2011-04-03T17:39:48Z (14 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
3094804b, baa9d5d, c593b21
Parents:
b8f7a0d2 (diff), 0b4e7ca (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:

Add base support for alternate interfaces

File:
1 edited

Legend:

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

    rb8f7a0d2 r0cec844  
    3636#include <usb/request.h>
    3737#include <usb/debug.h>
     38#include <usb/dp.h>
    3839#include <errno.h>
    3940#include <str_error.h>
     
    8687 * @return Number of pipes (excluding default control pipe).
    8788 */
    88 static size_t count_other_pipes(usb_driver_t *drv)
     89static size_t count_other_pipes(usb_endpoint_description_t **endpoints)
    8990{
    9091        size_t count = 0;
    91         if (drv->endpoints == NULL) {
     92        if (endpoints == NULL) {
    9293                return 0;
    9394        }
    9495
    95         while (drv->endpoints[count] != NULL) {
     96        while (endpoints[count] != NULL) {
    9697                count++;
    9798        }
     
    106107 * @return Error code.
    107108 */
    108 static int initialize_other_pipes(usb_driver_t *drv, usb_device_t *dev)
     109static int initialize_other_pipes(usb_endpoint_description_t **endpoints,
     110    usb_device_t *dev)
    109111{
    110112        int rc;
    111         dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
    112 
    113         size_t pipe_count = count_other_pipes(drv);
     113
     114        size_t pipe_count = count_other_pipes(endpoints);
     115        if (pipe_count == 0) {
     116                return EOK;
     117        }
     118
    114119        dev->pipes = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
    115120        if (dev->pipes == NULL) {
     
    133138                }
    134139
    135                 dev->pipes[i].description = drv->endpoints[i];
     140                dev->pipes[i].description = endpoints[i];
    136141                dev->pipes[i].interface_no = dev->interface_no;
     142                dev->pipes[i].interface_setting = 0;
    137143        }
    138144
     
    178184        usb_hc_connection_close(&hc_conn);
    179185
     186        dev->pipes_count = pipe_count;
     187
    180188        return EOK;
    181189
     
    227235        }
    228236
     237        /* Get our interface. */
     238        dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
     239
    229240        /*
    230241         * For further actions, we need open session on default control pipe.
     
    257268
    258269        if (driver->endpoints != NULL) {
    259                 rc = initialize_other_pipes(driver, dev);
     270                rc = initialize_other_pipes(driver->endpoints, dev);
    260271        }
    261272
     
    271282
    272283        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 */
     293static 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 */
     330static 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;
    273408}
    274409
     
    301436        dev->descriptors.configuration = NULL;
    302437
     438        dev->pipes_count = 0;
     439        dev->pipes = NULL;
     440
    303441        rc = initialize_pipes(dev);
    304442        if (rc != EOK) {
     
    307445        }
    308446
     447        (void) initialize_alternate_interfaces(dev);
     448
    309449        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 */
     457static 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 */
     512int 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;
    310540}
    311541
Note: See TracChangeset for help on using the changeset viewer.