Changeset 7526e3d in mainline


Ignore:
Timestamp:
2011-04-03T16:34:31Z (14 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
159b91f4
Parents:
bb18a59
Message:

Add base support for alternate interfaces

Currently, alternate interfaces are queried and are part of the
usb_device_t structure. Changing interface is not possible easily.

Location:
uspace/lib/usb
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usb/include/usb/devdrv.h

    rbb18a59 r7526e3d  
    4747} usb_device_descriptors_t;
    4848
     49/** Wrapper for data related to alternate interface setting.
     50 * The pointers will typically point inside configuration descriptor and
     51 * thus you shall not deallocate them.
     52 */
     53typedef struct {
     54        /** Interface descriptor. */
     55        usb_standard_interface_descriptor_t *interface;
     56        /** Pointer to start of descriptor tree bound with this interface. */
     57        uint8_t *nested_descriptors;
     58        /** Size of data pointed by nested_descriptors in bytes. */
     59        size_t nested_descriptors_size;
     60} usb_alternate_interface_descriptors_t;
     61
     62/** Alternate interface settings. */
     63typedef struct {
     64        /** Array of alternate interfaces descriptions. */
     65        usb_alternate_interface_descriptors_t *alternatives;
     66        /** Size of @c alternatives array. */
     67        size_t alternative_count;
     68        /** Index of currently selected one. */
     69        size_t current;
     70} usb_alternate_interfaces_t;
     71
    4972/** USB device structure. */
    5073typedef struct {
     
    6184         */
    6285        int interface_no;
     86
     87        /** Alternative interfaces.
     88         * Set to NULL when the driver controls whole device
     89         * (i.e. more (or any) interfaces).
     90         */
     91        usb_alternate_interfaces_t *alternate_interfaces;
    6392
    6493        /** Some useful descriptors. */
     
    132161typedef void (*usb_polling_terminted_callback_t)(usb_device_t *, bool, void *);
    133162
    134 
    135163int usb_device_auto_poll(usb_device_t *, size_t,
    136164    usb_polling_callback_t, size_t, usb_polling_terminted_callback_t, void *);
  • uspace/lib/usb/src/devdrv.c

    rbb18a59 r7526e3d  
    3636#include <usb/request.h>
    3737#include <usb/debug.h>
     38#include <usb/dp.h>
    3839#include <errno.h>
    3940#include <str_error.h>
     
    275276}
    276277
     278/** Count number of alternate settings of a interface.
     279 *
     280 * @param config_descr Full configuration descriptor.
     281 * @param config_descr_size Size of @p config_descr in bytes.
     282 * @param interface_no Interface number.
     283 * @return Number of alternate interfaces for @p interface_no interface.
     284 */
     285static size_t count_alternate_interfaces(uint8_t *config_descr,
     286    size_t config_descr_size, int interface_no)
     287{
     288        assert(config_descr != NULL);
     289        usb_dp_parser_t dp_parser = {
     290                .nesting = usb_dp_standard_descriptor_nesting
     291        };
     292        usb_dp_parser_data_t dp_data = {
     293                .data = config_descr,
     294                .size = config_descr_size,
     295                .arg = NULL
     296        };
     297
     298        size_t alternate_count = 0;
     299
     300        uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
     301            &dp_data, config_descr);
     302        while (iface_ptr != NULL) {
     303                usb_standard_interface_descriptor_t *iface
     304                    = (usb_standard_interface_descriptor_t *) iface_ptr;
     305                if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) {
     306                        if (iface->interface_number == interface_no) {
     307                                alternate_count++;
     308                        }
     309                }
     310                iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
     311                    config_descr, iface_ptr);
     312        }
     313
     314        return alternate_count;
     315}
     316
     317/** Initialize structures related to alternate interfaces.
     318 *
     319 * @param dev Device where alternate settings shall be initialized.
     320 * @return Error code.
     321 */
     322static int initialize_alternate_interfaces(usb_device_t *dev)
     323{
     324        if (dev->interface_no < 0) {
     325                dev->alternate_interfaces = NULL;
     326                return EOK;
     327        }
     328
     329        usb_alternate_interfaces_t *alternates
     330            = malloc(sizeof(usb_alternate_interfaces_t));
     331
     332        if (alternates == NULL) {
     333                return ENOMEM;
     334        }
     335
     336        alternates->alternative_count
     337            = count_alternate_interfaces(dev->descriptors.configuration,
     338            dev->descriptors.configuration_size, dev->interface_no);
     339
     340        if (alternates->alternative_count == 0) {
     341                free(alternates);
     342                return ENOENT;
     343        }
     344
     345        alternates->alternatives = malloc(alternates->alternative_count
     346            * sizeof(usb_alternate_interface_descriptors_t));
     347        if (alternates->alternatives == NULL) {
     348                free(alternates);
     349                return ENOMEM;
     350        }
     351
     352        alternates->current = 0;
     353
     354        usb_dp_parser_t dp_parser = {
     355                .nesting = usb_dp_standard_descriptor_nesting
     356        };
     357        usb_dp_parser_data_t dp_data = {
     358                .data = dev->descriptors.configuration,
     359                .size = dev->descriptors.configuration_size,
     360                .arg = NULL
     361        };
     362
     363        usb_alternate_interface_descriptors_t *cur_alt_iface
     364            = &alternates->alternatives[0];
     365
     366        uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
     367            &dp_data, dp_data.data);
     368        while (iface_ptr != NULL) {
     369                usb_standard_interface_descriptor_t *iface
     370                    = (usb_standard_interface_descriptor_t *) iface_ptr;
     371                if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
     372                    || (iface->interface_number != dev->interface_no)) {
     373                        iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
     374                            &dp_data,
     375                            dp_data.data, iface_ptr);
     376                        continue;
     377                }
     378
     379                cur_alt_iface->interface = iface;
     380                cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface);
     381
     382                /* Find next interface to count size of nested descriptors. */
     383                iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
     384                    dp_data.data, iface_ptr);
     385                if (iface_ptr == NULL) {
     386                        uint8_t *next = dp_data.data + dp_data.size;
     387                        cur_alt_iface->nested_descriptors_size
     388                            = next - cur_alt_iface->nested_descriptors;
     389                } else {
     390                        cur_alt_iface->nested_descriptors_size
     391                            = iface_ptr - cur_alt_iface->nested_descriptors;
     392                }
     393
     394                cur_alt_iface++;
     395        }
     396
     397        dev->alternate_interfaces = alternates;
     398
     399        return EOK;
     400}
     401
    277402/** Callback when new device is supposed to be controlled by this driver.
    278403 *
     
    309434        }
    310435
     436        (void) initialize_alternate_interfaces(dev);
     437
    311438        return driver->ops->add_device(dev);
    312439}
Note: See TracChangeset for help on using the changeset viewer.