Changeset 41e645c in mainline for uspace/lib/usb/src/recognise.c


Ignore:
Timestamp:
2011-02-20T21:43:50Z (14 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
070f11e, ace12560
Parents:
423e8c81 (diff), 063ead6f (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 simple USB multi interface device driver

The MID driver serves as a mini bus driver for devices with several
interfaces or for devices with classes defined at interface level.

The keyboard driver is working with this driver with the same problems
as before introduction of USB MID driver.

The merge also includes addition of bulk transfers.

File:
1 edited

Legend:

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

    r423e8c81 r41e645c  
    3434 */
    3535#include <sys/types.h>
    36 #include <usb_iface.h>
    3736#include <usb/usbdrv.h>
    3837#include <usb/pipes.h>
    3938#include <usb/recognise.h>
     39#include <usb/ddfiface.h>
    4040#include <usb/request.h>
    4141#include <usb/classes/classes.h>
     
    4646static FIBRIL_MUTEX_INITIALIZE(device_name_index_mutex);
    4747
    48 /** Callback for getting host controller handle.
    49  *
    50  * @param dev Device in question.
    51  * @param[out] handle Devman handle of the host controller.
    52  * @return Error code.
    53  */
    54 static int usb_iface_get_hc_handle(device_t *dev, devman_handle_t *handle)
    55 {
    56         assert(dev);
    57         assert(dev->parent != NULL);
    58 
    59         device_t *parent = dev->parent;
    60 
    61         if (parent->ops && parent->ops->interfaces[USB_DEV_IFACE]) {
    62                 usb_iface_t *usb_iface
    63                     = (usb_iface_t *) parent->ops->interfaces[USB_DEV_IFACE];
    64                 assert(usb_iface != NULL);
    65                 if (usb_iface->get_hc_handle) {
    66                         int rc = usb_iface->get_hc_handle(parent, handle);
    67                         return rc;
    68                 }
    69         }
    70 
    71         return ENOTSUP;
    72 }
    73 
    74 static usb_iface_t usb_iface = {
    75         .get_hc_handle = usb_iface_get_hc_handle
    76 };
    77 
    7848device_ops_t child_ops = {
    79         .interfaces[USB_DEV_IFACE] = &usb_iface
     49        .interfaces[USB_DEV_IFACE] = &usb_iface_hub_child_impl
    8050};
    8151
     
    142112}
    143113
     114#define ADD_MATCHID_OR_RETURN(match_ids, score, format, ...) \
     115        do { \
     116                int __rc = usb_add_match_id((match_ids), (score), \
     117                    format, ##__VA_ARGS__); \
     118                if (__rc != EOK) { \
     119                        return __rc; \
     120                } \
     121        } while (0)
     122
     123/** Create device match ids based on its interface.
     124 *
     125 * @param[in] descriptor Interface descriptor.
     126 * @param[out] matches Initialized list of match ids.
     127 * @return Error code (the two mentioned are not the only ones).
     128 * @retval EINVAL Invalid input parameters (expects non NULL pointers).
     129 * @retval ENOENT Interface does not specify class.
     130 */
     131int usb_device_create_match_ids_from_interface(
     132    const usb_standard_device_descriptor_t *desc_device,
     133    const usb_standard_interface_descriptor_t *desc_interface,
     134    match_id_list_t *matches)
     135{
     136        if (desc_interface == NULL) {
     137                return EINVAL;
     138        }
     139        if (matches == NULL) {
     140                return EINVAL;
     141        }
     142
     143        if (desc_interface->interface_class == USB_CLASS_USE_INTERFACE) {
     144                return ENOENT;
     145        }
     146
     147        const char *classname = usb_str_class(desc_interface->interface_class);
     148        assert(classname != NULL);
     149
     150#define IFACE_PROTOCOL_FMT "interface&class=%s&subclass=0x%02x&protocol=0x%02x"
     151#define IFACE_PROTOCOL_ARGS classname, desc_interface->interface_subclass, \
     152    desc_interface->interface_protocol
     153
     154#define IFACE_SUBCLASS_FMT "interface&class=%s&subclass=0x%02x"
     155#define IFACE_SUBCLASS_ARGS classname, desc_interface->interface_subclass
     156
     157#define IFACE_CLASS_FMT "interface&class=%s"
     158#define IFACE_CLASS_ARGS classname
     159
     160#define VENDOR_RELEASE_FMT "vendor=0x%04x&product=0x%04x&release=" BCD_FMT
     161#define VENDOR_RELEASE_ARGS desc_device->vendor_id, desc_device->product_id, \
     162    BCD_ARGS(desc_device->device_version)
     163
     164#define VENDOR_PRODUCT_FMT "vendor=0x%04x&product=0x%04x"
     165#define VENDOR_PRODUCT_ARGS desc_device->vendor_id, desc_device->product_id
     166
     167#define VENDOR_ONLY_FMT "vendor=0x%04x"
     168#define VENDOR_ONLY_ARGS desc_device->vendor_id
     169
     170        /*
     171         * If the vendor is specified, create match ids with vendor with
     172         * higher score.
     173         * Then the same ones without the vendor part.
     174         */
     175        if ((desc_device != NULL) && (desc_device->vendor_id != 0)) {
     176                /* First, interface matches with device release number. */
     177                ADD_MATCHID_OR_RETURN(matches, 250,
     178                    "usb&" VENDOR_RELEASE_FMT "&" IFACE_PROTOCOL_FMT,
     179                    VENDOR_RELEASE_ARGS, IFACE_PROTOCOL_ARGS);
     180                ADD_MATCHID_OR_RETURN(matches, 240,
     181                    "usb&" VENDOR_RELEASE_FMT "&" IFACE_SUBCLASS_FMT,
     182                    VENDOR_RELEASE_ARGS, IFACE_SUBCLASS_ARGS);
     183                ADD_MATCHID_OR_RETURN(matches, 230,
     184                    "usb&" VENDOR_RELEASE_FMT "&" IFACE_CLASS_FMT,
     185                    VENDOR_RELEASE_ARGS, IFACE_CLASS_ARGS);
     186
     187                /* Next, interface matches without release number. */
     188                ADD_MATCHID_OR_RETURN(matches, 220,
     189                    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_PROTOCOL_FMT,
     190                    VENDOR_PRODUCT_ARGS, IFACE_PROTOCOL_ARGS);
     191                ADD_MATCHID_OR_RETURN(matches, 210,
     192                    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_SUBCLASS_FMT,
     193                    VENDOR_PRODUCT_ARGS, IFACE_SUBCLASS_ARGS);
     194                ADD_MATCHID_OR_RETURN(matches, 200,
     195                    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_CLASS_FMT,
     196                    VENDOR_PRODUCT_ARGS, IFACE_CLASS_ARGS);
     197
     198                /* Finally, interface matches with only vendor. */
     199                ADD_MATCHID_OR_RETURN(matches, 190,
     200                    "usb&" VENDOR_ONLY_FMT "&" IFACE_PROTOCOL_FMT,
     201                    VENDOR_ONLY_ARGS, IFACE_PROTOCOL_ARGS);
     202                ADD_MATCHID_OR_RETURN(matches, 180,
     203                    "usb&" VENDOR_ONLY_FMT "&" IFACE_SUBCLASS_FMT,
     204                    VENDOR_ONLY_ARGS, IFACE_SUBCLASS_ARGS);
     205                ADD_MATCHID_OR_RETURN(matches, 170,
     206                    "usb&" VENDOR_ONLY_FMT "&" IFACE_CLASS_FMT,
     207                    VENDOR_ONLY_ARGS, IFACE_CLASS_ARGS);
     208        }
     209
     210        /* Now, the same but without any vendor specification. */
     211        ADD_MATCHID_OR_RETURN(matches, 160,
     212            "usb&" IFACE_PROTOCOL_FMT,
     213            IFACE_PROTOCOL_ARGS);
     214        ADD_MATCHID_OR_RETURN(matches, 150,
     215            "usb&" IFACE_SUBCLASS_FMT,
     216            IFACE_SUBCLASS_ARGS);
     217        ADD_MATCHID_OR_RETURN(matches, 140,
     218            "usb&" IFACE_CLASS_FMT,
     219            IFACE_CLASS_ARGS);
     220
     221#undef IFACE_PROTOCOL_FMT
     222#undef IFACE_PROTOCOL_ARGS
     223#undef IFACE_SUBCLASS_FMT
     224#undef IFACE_SUBCLASS_ARGS
     225#undef IFACE_CLASS_FMT
     226#undef IFACE_CLASS_ARGS
     227#undef VENDOR_RELEASE_FMT
     228#undef VENDOR_RELEASE_ARGS
     229#undef VENDOR_PRODUCT_FMT
     230#undef VENDOR_PRODUCT_ARGS
     231#undef VENDOR_ONLY_FMT
     232#undef VENDOR_ONLY_ARGS
     233
     234        return EOK;
     235}
     236
    144237/** Create DDF match ids from USB device descriptor.
    145238 *
     
    152245    const usb_standard_device_descriptor_t *device_descriptor)
    153246{
    154         int rc;
    155        
    156247        /*
    157248         * Unless the vendor id is 0, the pair idVendor-idProduct
     
    160251        if (device_descriptor->vendor_id != 0) {
    161252                /* First, with release number. */
    162                 rc = usb_add_match_id(matches, 100,
     253                ADD_MATCHID_OR_RETURN(matches, 100,
    163254                    "usb&vendor=0x%04x&product=0x%04x&release=" BCD_FMT,
    164255                    (int) device_descriptor->vendor_id,
    165256                    (int) device_descriptor->product_id,
    166257                    BCD_ARGS(device_descriptor->device_version));
    167                 if (rc != EOK) {
    168                         return rc;
    169                 }
    170258               
    171259                /* Next, without release number. */
    172                 rc = usb_add_match_id(matches, 90,
     260                ADD_MATCHID_OR_RETURN(matches, 90,
    173261                    "usb&vendor=0x%04x&product=0x%04x",
    174262                    (int) device_descriptor->vendor_id,
    175263                    (int) device_descriptor->product_id);
    176                 if (rc != EOK) {
    177                         return rc;
    178                 }
    179264        }       
    180265
    181266        /*
    182267         * If the device class points to interface we skip adding
    183          * class directly.
     268         * class directly but we add a multi interface device.
    184269         */
    185270        if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) {
    186                 rc = usb_add_match_id(matches, 50, "usb&class=%s",
     271                ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s",
    187272                    usb_str_class(device_descriptor->device_class));
    188                 if (rc != EOK) {
    189                         return rc;
    190                 }
     273        } else {
     274                ADD_MATCHID_OR_RETURN(matches, 50, "usb&mid");
    191275        }
    192276       
     
    194278}
    195279
    196 /** Create DDF match ids from USB configuration descriptor.
    197  * The configuration descriptor is expected to be in the complete form,
    198  * i.e. including interface, endpoint etc. descriptors.
    199  *
    200  * @param matches List of match ids to extend.
    201  * @param config_descriptor Configuration descriptor returned by given device.
    202  * @param total_size Size of the @p config_descriptor.
    203  * @return Error code.
    204  */
    205 int usb_drv_create_match_ids_from_configuration_descriptor(
    206     match_id_list_t *matches,
    207     const void *config_descriptor, size_t total_size)
    208 {
    209         /*
    210          * Iterate through config descriptor to find the interface
    211          * descriptors.
    212          */
    213         size_t position = sizeof(usb_standard_configuration_descriptor_t);
    214         while (position + 1 < total_size) {
    215                 uint8_t *current_descriptor
    216                     = ((uint8_t *) config_descriptor) + position;
    217                 uint8_t cur_descr_len = current_descriptor[0];
    218                 uint8_t cur_descr_type = current_descriptor[1];
    219 
    220                 if (cur_descr_len == 0) {
    221                         return ENOENT;
    222                 }
    223                
    224                 position += cur_descr_len;
    225                
    226                 if (cur_descr_type != USB_DESCTYPE_INTERFACE) {
    227                         continue;
    228                 }
    229                
    230                 /*
    231                  * Finally, we found an interface descriptor.
    232                  */
    233                 usb_standard_interface_descriptor_t *interface
    234                     = (usb_standard_interface_descriptor_t *)
    235                     current_descriptor;
    236                
    237                 int rc = usb_add_match_id(matches, 50,
    238                     "usb&interface&class=%s",
    239                     usb_str_class(interface->interface_class));
    240                 if (rc != EOK) {
    241                         return rc;
    242                 }
    243         }
    244        
    245         return EOK;
    246 }
    247 
    248 /** Add match ids based on configuration descriptor.
    249  *
    250  * @param pipe Control pipe to the device.
    251  * @param matches Match ids list to add matches to.
    252  * @param config_count Number of configurations the device has.
    253  * @return Error code.
    254  */
    255 static int usb_add_config_descriptor_match_ids(usb_endpoint_pipe_t *pipe,
    256     match_id_list_t *matches, int config_count)
    257 {
    258         int final_rc = EOK;
    259        
    260         int config_index;
    261         for (config_index = 0; config_index < config_count; config_index++) {
    262                 int rc;
    263                 usb_standard_configuration_descriptor_t config_descriptor;
    264                 rc = usb_request_get_bare_configuration_descriptor(pipe,
    265                     config_index, &config_descriptor);
    266                 if (rc != EOK) {
    267                         final_rc = rc;
    268                         continue;
    269                 }
    270 
    271                 size_t full_config_descriptor_size;
    272                 void *full_config_descriptor
    273                     = malloc(config_descriptor.total_length);
    274                 rc = usb_request_get_full_configuration_descriptor(pipe,
    275                     config_index,
    276                     full_config_descriptor, config_descriptor.total_length,
    277                     &full_config_descriptor_size);
    278                 if (rc != EOK) {
    279                         final_rc = rc;
    280                         continue;
    281                 }
    282                 if (full_config_descriptor_size
    283                     != config_descriptor.total_length) {
    284                         final_rc = ERANGE;
    285                         continue;
    286                 }
    287                
    288                 rc = usb_drv_create_match_ids_from_configuration_descriptor(
    289                     matches,
    290                     full_config_descriptor, full_config_descriptor_size);
    291                 if (rc != EOK) {
    292                         final_rc = rc;
    293                         continue;
    294                 }
    295                
    296         }
    297        
    298         return final_rc;
    299 }
    300280
    301281/** Create match ids describing attached device.
     
    330310
    331311        /*
    332          * Go through all configurations and add matches
    333          * based on interface class.
    334          */
    335         rc = usb_add_config_descriptor_match_ids(ctrl_pipe, matches,
    336             device_descriptor.configuration_count);
    337         if (rc != EOK) {
    338                 return rc;
    339         }
    340 
    341         /*
    342312         * As a fallback, provide the simplest match id possible.
    343313         */
    344         rc = usb_add_match_id(matches, 1, "usb&fallback");
    345         if (rc != EOK) {
    346                 return rc;
    347         }
     314        ADD_MATCHID_OR_RETURN(matches, 1, "usb&fallback");
    348315
    349316        return EOK;
Note: See TracChangeset for help on using the changeset viewer.