Ignore:
File:
1 edited

Legend:

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

    r7f56fb7 r345ea18  
    3434 */
    3535#include <sys/types.h>
     36#include <usb_iface.h>
    3637#include <usb/usbdrv.h>
    3738#include <usb/pipes.h>
    3839#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 */
     54static 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
     74static usb_iface_t usb_iface = {
     75        .get_hc_handle = usb_iface_get_hc_handle
     76};
     77
    4878device_ops_t child_ops = {
    49         .interfaces[USB_DEV_IFACE] = &usb_iface_hub_child_impl
     79        .interfaces[USB_DEV_IFACE] = &usb_iface
    5080};
    5181
     
    112142}
    113143
    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  */
    131 int 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 
    237144/** Create DDF match ids from USB device descriptor.
    238145 *
     
    245152    const usb_standard_device_descriptor_t *device_descriptor)
    246153{
     154        int rc;
     155       
    247156        /*
    248157         * Unless the vendor id is 0, the pair idVendor-idProduct
     
    251160        if (device_descriptor->vendor_id != 0) {
    252161                /* First, with release number. */
    253                 ADD_MATCHID_OR_RETURN(matches, 100,
     162                rc = usb_add_match_id(matches, 100,
    254163                    "usb&vendor=0x%04x&product=0x%04x&release=" BCD_FMT,
    255164                    (int) device_descriptor->vendor_id,
    256165                    (int) device_descriptor->product_id,
    257166                    BCD_ARGS(device_descriptor->device_version));
     167                if (rc != EOK) {
     168                        return rc;
     169                }
    258170               
    259171                /* Next, without release number. */
    260                 ADD_MATCHID_OR_RETURN(matches, 90,
     172                rc = usb_add_match_id(matches, 90,
    261173                    "usb&vendor=0x%04x&product=0x%04x",
    262174                    (int) device_descriptor->vendor_id,
    263175                    (int) device_descriptor->product_id);
     176                if (rc != EOK) {
     177                        return rc;
     178                }
    264179        }       
    265180
    266181        /*
    267182         * If the device class points to interface we skip adding
    268          * class directly but we add a multi interface device.
     183         * class directly.
    269184         */
    270185        if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) {
    271                 ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s",
     186                rc = usb_add_match_id(matches, 50, "usb&class=%s",
    272187                    usb_str_class(device_descriptor->device_class));
    273         } else {
    274                 ADD_MATCHID_OR_RETURN(matches, 50, "usb&mid");
     188                if (rc != EOK) {
     189                        return rc;
     190                }
    275191        }
    276192       
     
    278194}
    279195
     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 */
     205int 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 */
     255static 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}
    280300
    281301/** Create match ids describing attached device.
     
    310330
    311331        /*
     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        /*
    312342         * As a fallback, provide the simplest match id possible.
    313343         */
    314         ADD_MATCHID_OR_RETURN(matches, 1, "usb&fallback");
     344        rc = usb_add_match_id(matches, 1, "usb&fallback");
     345        if (rc != EOK) {
     346                return rc;
     347        }
    315348
    316349        return EOK;
Note: See TracChangeset for help on using the changeset viewer.