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


Ignore:
Timestamp:
2011-02-21T22:25:58Z (14 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
233e68d
Parents:
fb78ae72 (diff), dbe25f1 (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 merge

File:
1 edited

Legend:

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

    rfb78ae72 rdeece2f  
    3434 */
    3535#include <sys/types.h>
    36 #include <usb_iface.h>
    37 #include <usb/usbdrv.h>
    3836#include <usb/pipes.h>
    3937#include <usb/recognise.h>
     38#include <usb/ddfiface.h>
    4039#include <usb/request.h>
    4140#include <usb/classes/classes.h>
     
    4645static FIBRIL_MUTEX_INITIALIZE(device_name_index_mutex);
    4746
    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 
    7847device_ops_t child_ops = {
    79         .interfaces[USB_DEV_IFACE] = &usb_iface
     48        .interfaces[USB_DEV_IFACE] = &usb_iface_hub_child_impl
    8049};
    8150
     
    142111}
    143112
     113#define ADD_MATCHID_OR_RETURN(match_ids, score, format, ...) \
     114        do { \
     115                int __rc = usb_add_match_id((match_ids), (score), \
     116                    format, ##__VA_ARGS__); \
     117                if (__rc != EOK) { \
     118                        return __rc; \
     119                } \
     120        } while (0)
     121
     122/** Create device match ids based on its interface.
     123 *
     124 * @param[in] descriptor Interface descriptor.
     125 * @param[out] matches Initialized list of match ids.
     126 * @return Error code (the two mentioned are not the only ones).
     127 * @retval EINVAL Invalid input parameters (expects non NULL pointers).
     128 * @retval ENOENT Interface does not specify class.
     129 */
     130int usb_device_create_match_ids_from_interface(
     131    const usb_standard_device_descriptor_t *desc_device,
     132    const usb_standard_interface_descriptor_t *desc_interface,
     133    match_id_list_t *matches)
     134{
     135        if (desc_interface == NULL) {
     136                return EINVAL;
     137        }
     138        if (matches == NULL) {
     139                return EINVAL;
     140        }
     141
     142        if (desc_interface->interface_class == USB_CLASS_USE_INTERFACE) {
     143                return ENOENT;
     144        }
     145
     146        const char *classname = usb_str_class(desc_interface->interface_class);
     147        assert(classname != NULL);
     148
     149#define IFACE_PROTOCOL_FMT "interface&class=%s&subclass=0x%02x&protocol=0x%02x"
     150#define IFACE_PROTOCOL_ARGS classname, desc_interface->interface_subclass, \
     151    desc_interface->interface_protocol
     152
     153#define IFACE_SUBCLASS_FMT "interface&class=%s&subclass=0x%02x"
     154#define IFACE_SUBCLASS_ARGS classname, desc_interface->interface_subclass
     155
     156#define IFACE_CLASS_FMT "interface&class=%s"
     157#define IFACE_CLASS_ARGS classname
     158
     159#define VENDOR_RELEASE_FMT "vendor=0x%04x&product=0x%04x&release=" BCD_FMT
     160#define VENDOR_RELEASE_ARGS desc_device->vendor_id, desc_device->product_id, \
     161    BCD_ARGS(desc_device->device_version)
     162
     163#define VENDOR_PRODUCT_FMT "vendor=0x%04x&product=0x%04x"
     164#define VENDOR_PRODUCT_ARGS desc_device->vendor_id, desc_device->product_id
     165
     166#define VENDOR_ONLY_FMT "vendor=0x%04x"
     167#define VENDOR_ONLY_ARGS desc_device->vendor_id
     168
     169        /*
     170         * If the vendor is specified, create match ids with vendor with
     171         * higher score.
     172         * Then the same ones without the vendor part.
     173         */
     174        if ((desc_device != NULL) && (desc_device->vendor_id != 0)) {
     175                /* First, interface matches with device release number. */
     176                ADD_MATCHID_OR_RETURN(matches, 250,
     177                    "usb&" VENDOR_RELEASE_FMT "&" IFACE_PROTOCOL_FMT,
     178                    VENDOR_RELEASE_ARGS, IFACE_PROTOCOL_ARGS);
     179                ADD_MATCHID_OR_RETURN(matches, 240,
     180                    "usb&" VENDOR_RELEASE_FMT "&" IFACE_SUBCLASS_FMT,
     181                    VENDOR_RELEASE_ARGS, IFACE_SUBCLASS_ARGS);
     182                ADD_MATCHID_OR_RETURN(matches, 230,
     183                    "usb&" VENDOR_RELEASE_FMT "&" IFACE_CLASS_FMT,
     184                    VENDOR_RELEASE_ARGS, IFACE_CLASS_ARGS);
     185
     186                /* Next, interface matches without release number. */
     187                ADD_MATCHID_OR_RETURN(matches, 220,
     188                    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_PROTOCOL_FMT,
     189                    VENDOR_PRODUCT_ARGS, IFACE_PROTOCOL_ARGS);
     190                ADD_MATCHID_OR_RETURN(matches, 210,
     191                    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_SUBCLASS_FMT,
     192                    VENDOR_PRODUCT_ARGS, IFACE_SUBCLASS_ARGS);
     193                ADD_MATCHID_OR_RETURN(matches, 200,
     194                    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_CLASS_FMT,
     195                    VENDOR_PRODUCT_ARGS, IFACE_CLASS_ARGS);
     196
     197                /* Finally, interface matches with only vendor. */
     198                ADD_MATCHID_OR_RETURN(matches, 190,
     199                    "usb&" VENDOR_ONLY_FMT "&" IFACE_PROTOCOL_FMT,
     200                    VENDOR_ONLY_ARGS, IFACE_PROTOCOL_ARGS);
     201                ADD_MATCHID_OR_RETURN(matches, 180,
     202                    "usb&" VENDOR_ONLY_FMT "&" IFACE_SUBCLASS_FMT,
     203                    VENDOR_ONLY_ARGS, IFACE_SUBCLASS_ARGS);
     204                ADD_MATCHID_OR_RETURN(matches, 170,
     205                    "usb&" VENDOR_ONLY_FMT "&" IFACE_CLASS_FMT,
     206                    VENDOR_ONLY_ARGS, IFACE_CLASS_ARGS);
     207        }
     208
     209        /* Now, the same but without any vendor specification. */
     210        ADD_MATCHID_OR_RETURN(matches, 160,
     211            "usb&" IFACE_PROTOCOL_FMT,
     212            IFACE_PROTOCOL_ARGS);
     213        ADD_MATCHID_OR_RETURN(matches, 150,
     214            "usb&" IFACE_SUBCLASS_FMT,
     215            IFACE_SUBCLASS_ARGS);
     216        ADD_MATCHID_OR_RETURN(matches, 140,
     217            "usb&" IFACE_CLASS_FMT,
     218            IFACE_CLASS_ARGS);
     219
     220#undef IFACE_PROTOCOL_FMT
     221#undef IFACE_PROTOCOL_ARGS
     222#undef IFACE_SUBCLASS_FMT
     223#undef IFACE_SUBCLASS_ARGS
     224#undef IFACE_CLASS_FMT
     225#undef IFACE_CLASS_ARGS
     226#undef VENDOR_RELEASE_FMT
     227#undef VENDOR_RELEASE_ARGS
     228#undef VENDOR_PRODUCT_FMT
     229#undef VENDOR_PRODUCT_ARGS
     230#undef VENDOR_ONLY_FMT
     231#undef VENDOR_ONLY_ARGS
     232
     233        return EOK;
     234}
     235
    144236/** Create DDF match ids from USB device descriptor.
    145237 *
     
    148240 * @return Error code.
    149241 */
    150 int usb_drv_create_match_ids_from_device_descriptor(
    151     match_id_list_t *matches,
    152     const usb_standard_device_descriptor_t *device_descriptor)
     242int usb_device_create_match_ids_from_device_descriptor(
     243    const usb_standard_device_descriptor_t *device_descriptor,
     244    match_id_list_t *matches)
    153245{
    154         int rc;
    155        
    156246        /*
    157247         * Unless the vendor id is 0, the pair idVendor-idProduct
     
    160250        if (device_descriptor->vendor_id != 0) {
    161251                /* First, with release number. */
    162                 rc = usb_add_match_id(matches, 100,
     252                ADD_MATCHID_OR_RETURN(matches, 100,
    163253                    "usb&vendor=0x%04x&product=0x%04x&release=" BCD_FMT,
    164254                    (int) device_descriptor->vendor_id,
    165255                    (int) device_descriptor->product_id,
    166256                    BCD_ARGS(device_descriptor->device_version));
    167                 if (rc != EOK) {
    168                         return rc;
    169                 }
    170257               
    171258                /* Next, without release number. */
    172                 rc = usb_add_match_id(matches, 90,
     259                ADD_MATCHID_OR_RETURN(matches, 90,
    173260                    "usb&vendor=0x%04x&product=0x%04x",
    174261                    (int) device_descriptor->vendor_id,
    175262                    (int) device_descriptor->product_id);
    176                 if (rc != EOK) {
    177                         return rc;
    178                 }
    179263        }       
    180264
    181265        /*
    182266         * If the device class points to interface we skip adding
    183          * class directly.
     267         * class directly but we add a multi interface device.
    184268         */
    185269        if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) {
    186                 rc = usb_add_match_id(matches, 50, "usb&class=%s",
     270                ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s",
    187271                    usb_str_class(device_descriptor->device_class));
    188                 if (rc != EOK) {
    189                         return rc;
    190                 }
     272        } else {
     273                ADD_MATCHID_OR_RETURN(matches, 50, "usb&mid");
    191274        }
    192275       
     
    194277}
    195278
    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 }
    300279
    301280/** Create match ids describing attached device.
     
    323302        }
    324303
    325         rc = usb_drv_create_match_ids_from_device_descriptor(matches,
    326             &device_descriptor);
     304        rc = usb_device_create_match_ids_from_device_descriptor(
     305            &device_descriptor, matches);
    327306        if (rc != EOK) {
    328307                return rc;
     
    330309
    331310        /*
    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         /*
    342311         * As a fallback, provide the simplest match id possible.
    343312         */
    344         rc = usb_add_match_id(matches, 1, "usb&fallback");
    345         if (rc != EOK) {
    346                 return rc;
    347         }
     313        ADD_MATCHID_OR_RETURN(matches, 1, "usb&fallback");
    348314
    349315        return EOK;
Note: See TracChangeset for help on using the changeset viewer.