Ignore:
File:
1 edited

Legend:

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

    rb207803 r3f0ef89d  
    2727 */
    2828
    29 /** @addtogroup libusb usb
     29/** @addtogroup libusb
    3030 * @{
    3131 */
     
    3333 * @brief Functions for recognising kind of attached devices.
    3434 */
    35 #include <usb_iface.h>
    36 #include <usb/usbdrv.h>
     35#include <sys/types.h>
     36#include <fibril_synch.h>
     37#include <usb/pipes.h>
     38#include <usb/recognise.h>
     39#include <usb/ddfiface.h>
     40#include <usb/request.h>
    3741#include <usb/classes/classes.h>
    3842#include <stdio.h>
    3943#include <errno.h>
    40 
    41 static int usb_iface_get_hc_handle(device_t *dev, devman_handle_t *handle)
    42 {
    43         assert(dev);
    44         assert(dev->parent != NULL);
    45 
    46         device_t *parent = dev->parent;
    47 
    48         if (parent->ops && parent->ops->interfaces[USB_DEV_IFACE]) {
    49                 usb_iface_t *usb_iface
    50                     = (usb_iface_t *) parent->ops->interfaces[USB_DEV_IFACE];
    51                 assert(usb_iface != NULL);
    52                 if (usb_iface->get_hc_handle) {
    53                         int rc = usb_iface->get_hc_handle(parent, handle);
    54                         return rc;
    55                 }
    56         }
    57 
    58         return ENOTSUP;
    59 }
    60 
    61 static usb_iface_t usb_iface = {
    62         .get_hc_handle = usb_iface_get_hc_handle
    63 };
    64 
    65 static device_ops_t child_ops = {
    66         .interfaces[USB_DEV_IFACE] = &usb_iface
     44#include <assert.h>
     45
     46static size_t device_name_index = 0;
     47static FIBRIL_MUTEX_INITIALIZE(device_name_index_mutex);
     48
     49ddf_dev_ops_t child_ops = {
     50        .interfaces[USB_DEV_IFACE] = &usb_iface_hub_child_impl
    6751};
    6852
     
    129113}
    130114
     115#define ADD_MATCHID_OR_RETURN(match_ids, score, format, ...) \
     116        do { \
     117                int __rc = usb_add_match_id((match_ids), (score), \
     118                    format, ##__VA_ARGS__); \
     119                if (__rc != EOK) { \
     120                        return __rc; \
     121                } \
     122        } while (0)
     123
     124/** Create device match ids based on its interface.
     125 *
     126 * @param[in] descriptor Interface descriptor.
     127 * @param[out] matches Initialized list of match ids.
     128 * @return Error code (the two mentioned are not the only ones).
     129 * @retval EINVAL Invalid input parameters (expects non NULL pointers).
     130 * @retval ENOENT Interface does not specify class.
     131 */
     132int usb_device_create_match_ids_from_interface(
     133    const usb_standard_device_descriptor_t *desc_device,
     134    const usb_standard_interface_descriptor_t *desc_interface,
     135    match_id_list_t *matches)
     136{
     137        if (desc_interface == NULL) {
     138                return EINVAL;
     139        }
     140        if (matches == NULL) {
     141                return EINVAL;
     142        }
     143
     144        if (desc_interface->interface_class == USB_CLASS_USE_INTERFACE) {
     145                return ENOENT;
     146        }
     147
     148        const char *classname = usb_str_class(desc_interface->interface_class);
     149        assert(classname != NULL);
     150
     151#define IFACE_PROTOCOL_FMT "interface&class=%s&subclass=0x%02x&protocol=0x%02x"
     152#define IFACE_PROTOCOL_ARGS classname, desc_interface->interface_subclass, \
     153    desc_interface->interface_protocol
     154
     155#define IFACE_SUBCLASS_FMT "interface&class=%s&subclass=0x%02x"
     156#define IFACE_SUBCLASS_ARGS classname, desc_interface->interface_subclass
     157
     158#define IFACE_CLASS_FMT "interface&class=%s"
     159#define IFACE_CLASS_ARGS classname
     160
     161#define VENDOR_RELEASE_FMT "vendor=0x%04x&product=0x%04x&release=" BCD_FMT
     162#define VENDOR_RELEASE_ARGS desc_device->vendor_id, desc_device->product_id, \
     163    BCD_ARGS(desc_device->device_version)
     164
     165#define VENDOR_PRODUCT_FMT "vendor=0x%04x&product=0x%04x"
     166#define VENDOR_PRODUCT_ARGS desc_device->vendor_id, desc_device->product_id
     167
     168#define VENDOR_ONLY_FMT "vendor=0x%04x"
     169#define VENDOR_ONLY_ARGS desc_device->vendor_id
     170
     171        /*
     172         * If the vendor is specified, create match ids with vendor with
     173         * higher score.
     174         * Then the same ones without the vendor part.
     175         */
     176        if ((desc_device != NULL) && (desc_device->vendor_id != 0)) {
     177                /* First, interface matches with device release number. */
     178                ADD_MATCHID_OR_RETURN(matches, 250,
     179                    "usb&" VENDOR_RELEASE_FMT "&" IFACE_PROTOCOL_FMT,
     180                    VENDOR_RELEASE_ARGS, IFACE_PROTOCOL_ARGS);
     181                ADD_MATCHID_OR_RETURN(matches, 240,
     182                    "usb&" VENDOR_RELEASE_FMT "&" IFACE_SUBCLASS_FMT,
     183                    VENDOR_RELEASE_ARGS, IFACE_SUBCLASS_ARGS);
     184                ADD_MATCHID_OR_RETURN(matches, 230,
     185                    "usb&" VENDOR_RELEASE_FMT "&" IFACE_CLASS_FMT,
     186                    VENDOR_RELEASE_ARGS, IFACE_CLASS_ARGS);
     187
     188                /* Next, interface matches without release number. */
     189                ADD_MATCHID_OR_RETURN(matches, 220,
     190                    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_PROTOCOL_FMT,
     191                    VENDOR_PRODUCT_ARGS, IFACE_PROTOCOL_ARGS);
     192                ADD_MATCHID_OR_RETURN(matches, 210,
     193                    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_SUBCLASS_FMT,
     194                    VENDOR_PRODUCT_ARGS, IFACE_SUBCLASS_ARGS);
     195                ADD_MATCHID_OR_RETURN(matches, 200,
     196                    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_CLASS_FMT,
     197                    VENDOR_PRODUCT_ARGS, IFACE_CLASS_ARGS);
     198
     199                /* Finally, interface matches with only vendor. */
     200                ADD_MATCHID_OR_RETURN(matches, 190,
     201                    "usb&" VENDOR_ONLY_FMT "&" IFACE_PROTOCOL_FMT,
     202                    VENDOR_ONLY_ARGS, IFACE_PROTOCOL_ARGS);
     203                ADD_MATCHID_OR_RETURN(matches, 180,
     204                    "usb&" VENDOR_ONLY_FMT "&" IFACE_SUBCLASS_FMT,
     205                    VENDOR_ONLY_ARGS, IFACE_SUBCLASS_ARGS);
     206                ADD_MATCHID_OR_RETURN(matches, 170,
     207                    "usb&" VENDOR_ONLY_FMT "&" IFACE_CLASS_FMT,
     208                    VENDOR_ONLY_ARGS, IFACE_CLASS_ARGS);
     209        }
     210
     211        /* Now, the same but without any vendor specification. */
     212        ADD_MATCHID_OR_RETURN(matches, 160,
     213            "usb&" IFACE_PROTOCOL_FMT,
     214            IFACE_PROTOCOL_ARGS);
     215        ADD_MATCHID_OR_RETURN(matches, 150,
     216            "usb&" IFACE_SUBCLASS_FMT,
     217            IFACE_SUBCLASS_ARGS);
     218        ADD_MATCHID_OR_RETURN(matches, 140,
     219            "usb&" IFACE_CLASS_FMT,
     220            IFACE_CLASS_ARGS);
     221
     222#undef IFACE_PROTOCOL_FMT
     223#undef IFACE_PROTOCOL_ARGS
     224#undef IFACE_SUBCLASS_FMT
     225#undef IFACE_SUBCLASS_ARGS
     226#undef IFACE_CLASS_FMT
     227#undef IFACE_CLASS_ARGS
     228#undef VENDOR_RELEASE_FMT
     229#undef VENDOR_RELEASE_ARGS
     230#undef VENDOR_PRODUCT_FMT
     231#undef VENDOR_PRODUCT_ARGS
     232#undef VENDOR_ONLY_FMT
     233#undef VENDOR_ONLY_ARGS
     234
     235        return EOK;
     236}
     237
    131238/** Create DDF match ids from USB device descriptor.
    132239 *
     
    135242 * @return Error code.
    136243 */
    137 int usb_drv_create_match_ids_from_device_descriptor(
    138     match_id_list_t *matches,
    139     const usb_standard_device_descriptor_t *device_descriptor)
     244int usb_device_create_match_ids_from_device_descriptor(
     245    const usb_standard_device_descriptor_t *device_descriptor,
     246    match_id_list_t *matches)
    140247{
    141         int rc;
    142        
    143248        /*
    144249         * Unless the vendor id is 0, the pair idVendor-idProduct
     
    147252        if (device_descriptor->vendor_id != 0) {
    148253                /* First, with release number. */
    149                 rc = usb_add_match_id(matches, 100,
    150                     "usb&vendor=%d&product=%d&release=" BCD_FMT,
     254                ADD_MATCHID_OR_RETURN(matches, 100,
     255                    "usb&vendor=0x%04x&product=0x%04x&release=" BCD_FMT,
    151256                    (int) device_descriptor->vendor_id,
    152257                    (int) device_descriptor->product_id,
    153258                    BCD_ARGS(device_descriptor->device_version));
    154                 if (rc != EOK) {
    155                         return rc;
    156                 }
    157259               
    158260                /* Next, without release number. */
    159                 rc = usb_add_match_id(matches, 90, "usb&vendor=%d&product=%d",
     261                ADD_MATCHID_OR_RETURN(matches, 90,
     262                    "usb&vendor=0x%04x&product=0x%04x",
    160263                    (int) device_descriptor->vendor_id,
    161264                    (int) device_descriptor->product_id);
    162                 if (rc != EOK) {
    163                         return rc;
    164                 }
    165265        }       
    166266
    167267        /*
    168268         * If the device class points to interface we skip adding
    169          * class directly.
     269         * class directly but we add a multi interface device.
    170270         */
    171271        if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) {
    172                 rc = usb_add_match_id(matches, 50, "usb&class=%s",
     272                ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s",
    173273                    usb_str_class(device_descriptor->device_class));
    174                 if (rc != EOK) {
    175                         return rc;
    176                 }
     274        } else {
     275                ADD_MATCHID_OR_RETURN(matches, 50, "usb&mid");
    177276        }
    178277       
     
    180279}
    181280
    182 /** Create DDF match ids from USB configuration descriptor.
    183  * The configuration descriptor is expected to be in the complete form,
    184  * i.e. including interface, endpoint etc. descriptors.
    185  *
    186  * @param matches List of match ids to extend.
    187  * @param config_descriptor Configuration descriptor returned by given device.
    188  * @param total_size Size of the @p config_descriptor.
     281
     282/** Create match ids describing attached device.
     283 *
     284 * @warning The list of match ids @p matches may change even when
     285 * function exits with error.
     286 *
     287 * @param ctrl_pipe Control pipe to given device (session must be already
     288 *      started).
     289 * @param matches Initialized list of match ids.
    189290 * @return Error code.
    190291 */
    191 int usb_drv_create_match_ids_from_configuration_descriptor(
    192     match_id_list_t *matches,
    193     const void *config_descriptor, size_t total_size)
     292int usb_device_create_match_ids(usb_endpoint_pipe_t *ctrl_pipe,
     293    match_id_list_t *matches)
    194294{
    195         /*
    196          * Iterate through config descriptor to find the interface
    197          * descriptors.
    198          */
    199         size_t position = sizeof(usb_standard_configuration_descriptor_t);
    200         while (position + 1 < total_size) {
    201                 uint8_t *current_descriptor
    202                     = ((uint8_t *) config_descriptor) + position;
    203                 uint8_t cur_descr_len = current_descriptor[0];
    204                 uint8_t cur_descr_type = current_descriptor[1];
    205                
    206                 position += cur_descr_len;
    207                
    208                 if (cur_descr_type != USB_DESCTYPE_INTERFACE) {
    209                         continue;
    210                 }
    211                
    212                 /*
    213                  * Finally, we found an interface descriptor.
    214                  */
    215                 usb_standard_interface_descriptor_t *interface
    216                     = (usb_standard_interface_descriptor_t *)
    217                     current_descriptor;
    218                
    219                 int rc = usb_add_match_id(matches, 50,
    220                     "usb&interface&class=%s",
    221                     usb_str_class(interface->interface_class));
    222                 if (rc != EOK) {
    223                         return rc;
    224                 }
    225         }
    226        
     295        int rc;
     296        /*
     297         * Retrieve device descriptor and add matches from it.
     298         */
     299        usb_standard_device_descriptor_t device_descriptor;
     300
     301        rc = usb_request_get_device_descriptor(ctrl_pipe, &device_descriptor);
     302        if (rc != EOK) {
     303                return rc;
     304        }
     305
     306        rc = usb_device_create_match_ids_from_device_descriptor(
     307            &device_descriptor, matches);
     308        if (rc != EOK) {
     309                return rc;
     310        }
     311
    227312        return EOK;
    228313}
    229314
    230 /** Add match ids based on configuration descriptor.
    231  *
    232  * @param hc Open phone to host controller.
    233  * @param matches Match ids list to add matches to.
    234  * @param address USB address of the attached device.
     315/** Probe for device kind and register it in devman.
     316 *
     317 * @param[in] address Address of the (unknown) attached device.
     318 * @param[in] hc_handle Handle of the host controller.
     319 * @param[in] parent Parent device.
     320 * @param[out] child_handle Handle of the child device.
    235321 * @return Error code.
    236322 */
    237 static int usb_add_config_descriptor_match_ids(int hc,
    238     match_id_list_t *matches, usb_address_t address,
    239     int config_count)
     323int usb_device_register_child_in_devman(usb_address_t address,
     324    devman_handle_t hc_handle,
     325    ddf_dev_t *parent, devman_handle_t *child_handle,
     326    ddf_dev_ops_t *dev_ops, void *dev_data, ddf_fun_t **child_fun)
    240327{
    241         int final_rc = EOK;
    242        
    243         int config_index;
    244         for (config_index = 0; config_index < config_count; config_index++) {
    245                 int rc;
    246                 usb_standard_configuration_descriptor_t config_descriptor;
    247                 rc = usb_drv_req_get_bare_configuration_descriptor(hc,
    248                     address,  config_index, &config_descriptor);
    249                 if (rc != EOK) {
    250                         final_rc = rc;
    251                         continue;
    252                 }
    253 
    254                 size_t full_config_descriptor_size;
    255                 void *full_config_descriptor
    256                     = malloc(config_descriptor.total_length);
    257                 rc = usb_drv_req_get_full_configuration_descriptor(hc,
    258                     address, config_index,
    259                     full_config_descriptor, config_descriptor.total_length,
    260                     &full_config_descriptor_size);
    261                 if (rc != EOK) {
    262                         final_rc = rc;
    263                         continue;
    264                 }
    265                 if (full_config_descriptor_size
    266                     != config_descriptor.total_length) {
    267                         final_rc = ERANGE;
    268                         continue;
    269                 }
    270                
    271                 rc = usb_drv_create_match_ids_from_configuration_descriptor(
    272                     matches,
    273                     full_config_descriptor, full_config_descriptor_size);
    274                 if (rc != EOK) {
    275                         final_rc = rc;
    276                         continue;
    277                 }
    278                
    279         }
    280        
    281         return final_rc;
    282 }
    283 
    284 /** Create match ids describing attached device.
    285  *
    286  * @warning The list of match ids @p matches may change even when
    287  * function exits with error.
    288  *
    289  * @param hc Open phone to host controller.
    290  * @param matches Initialized list of match ids.
    291  * @param address USB address of the attached device.
    292  * @return Error code.
    293  */
    294 int usb_drv_create_device_match_ids(int hc, match_id_list_t *matches,
    295     usb_address_t address)
    296 {
    297         int rc;
    298        
    299         /*
    300          * Retrieve device descriptor and add matches from it.
    301          */
    302         usb_standard_device_descriptor_t device_descriptor;
    303 
    304         rc = usb_drv_req_get_device_descriptor(hc, address,
    305             &device_descriptor);
    306         if (rc != EOK) {
    307                 return rc;
    308         }
    309        
    310         rc = usb_drv_create_match_ids_from_device_descriptor(matches,
    311             &device_descriptor);
    312         if (rc != EOK) {
    313                 return rc;
    314         }
    315        
    316         /*
    317          * Go through all configurations and add matches
    318          * based on interface class.
    319          */
    320         rc = usb_add_config_descriptor_match_ids(hc, matches,
    321             address, device_descriptor.configuration_count);
    322         if (rc != EOK) {
    323                 return rc;
    324         }
    325 
    326         /*
    327          * As a fallback, provide the simplest match id possible.
    328          */
    329         rc = usb_add_match_id(matches, 1, "usb&fallback");
    330         if (rc != EOK) {
    331                 return rc;
    332         }
    333 
    334         return EOK;
    335 }
    336 
    337 
    338 /** Probe for device kind and register it in devman.
    339  *
    340  * @param hc Open phone to the host controller.
    341  * @param parent Parent device.
    342  * @param address Address of the (unknown) attached device.
    343  * @return Error code.
    344  */
    345 int usb_drv_register_child_in_devman(int hc, device_t *parent,
    346     usb_address_t address, devman_handle_t *child_handle)
    347 {
    348         static size_t device_name_index = 0;
    349 
    350         device_t *child = NULL;
     328        size_t this_device_name_index;
     329
     330        fibril_mutex_lock(&device_name_index_mutex);
     331        this_device_name_index = device_name_index;
     332        device_name_index++;
     333        fibril_mutex_unlock(&device_name_index_mutex);
     334
     335        ddf_fun_t *child = NULL;
    351336        char *child_name = NULL;
    352337        int rc;
    353 
    354         child = create_device();
     338        usb_device_connection_t dev_connection;
     339        usb_endpoint_pipe_t ctrl_pipe;
     340
     341        rc = usb_device_connection_initialize(&dev_connection, hc_handle, address);
     342        if (rc != EOK) {
     343                goto failure;
     344        }
     345
     346        rc = usb_endpoint_pipe_initialize_default_control(&ctrl_pipe,
     347            &dev_connection);
     348        if (rc != EOK) {
     349                goto failure;
     350        }
     351
     352        /*
     353         * TODO: Once the device driver framework support persistent
     354         * naming etc., something more descriptive could be created.
     355         */
     356        rc = asprintf(&child_name, "usbdev%02zu", this_device_name_index);
     357        if (rc < 0) {
     358                goto failure;
     359        }
     360
     361        child = ddf_fun_create(parent, fun_inner, child_name);
    355362        if (child == NULL) {
    356363                rc = ENOMEM;
     
    358365        }
    359366
    360         /*
    361          * TODO: Once the device driver framework support persistent
    362          * naming etc., something more descriptive could be created.
    363          */
    364         rc = asprintf(&child_name, "usbdev%02zu", device_name_index);
    365         if (rc < 0) {
    366                 goto failure;
    367         }
    368         child->parent = parent;
    369         child->name = child_name;
    370         child->ops = &child_ops;
    371        
    372         rc = usb_drv_create_device_match_ids(hc, &child->match_ids, address);
    373         if (rc != EOK) {
    374                 goto failure;
    375         }
    376 
    377         rc = child_device_register(child, parent);
     367        if (dev_ops != NULL) {
     368                child->ops = dev_ops;
     369        } else {
     370                child->ops = &child_ops;
     371        }
     372
     373        child->driver_data = dev_data;
     374
     375        rc = usb_endpoint_pipe_start_session(&ctrl_pipe);
     376        if (rc != EOK) {
     377                goto failure;
     378        }
     379
     380        rc = usb_device_create_match_ids(&ctrl_pipe, &child->match_ids);
     381        if (rc != EOK) {
     382                goto failure;
     383        }
     384
     385        rc = usb_endpoint_pipe_end_session(&ctrl_pipe);
     386        if (rc != EOK) {
     387                goto failure;
     388        }
     389
     390        rc = ddf_fun_bind(child);
    378391        if (rc != EOK) {
    379392                goto failure;
     
    383396                *child_handle = child->handle;
    384397        }
    385        
    386         device_name_index++;
     398
     399        if (child_fun != NULL) {
     400                *child_fun = child;
     401        }
    387402
    388403        return EOK;
     
    392407                child->name = NULL;
    393408                /* This takes care of match_id deallocation as well. */
    394                 delete_device(child);
     409                ddf_fun_destroy(child);
    395410        }
    396411        if (child_name != NULL) {
     
    399414
    400415        return rc;
    401 
    402416}
    403417
Note: See TracChangeset for help on using the changeset viewer.