]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[usb] Select preferred USB device configuration based on driver score
authorMichael Brown <mcb30@ipxe.org>
Mon, 14 Sep 2015 15:53:05 +0000 (16:53 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 14 Sep 2015 20:45:34 +0000 (21:45 +0100)
Generate a score for each possible USB device configuration based on
the available driver support, and select the configuration with the
highest score.  This will allow us to prefer ECM over RNDIS (for
devices which support both) and will allow us to meaningfully select a
configuration even when we have drivers available for all functions
(e.g. when exposing unused functions via EFI_USB_IO_PROTOCOL).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/bus/usb.c
src/drivers/net/dm96xx.c
src/drivers/net/ecm.c
src/drivers/net/ncm.c
src/drivers/net/smsc75xx.c
src/drivers/usb/usbhub.c
src/drivers/usb/usbio.c
src/drivers/usb/usbkbd.c
src/drivers/usb/usbnet.c
src/include/ipxe/usb.h

index cd80c320141d51f3e4d098865fee092e0b8dd38f..d8d7f6b37686f8a0ee1e17a1ea89cb403272c1a9 100644 (file)
@@ -900,76 +900,155 @@ int usb_get_string_descriptor ( struct usb_device *usb, unsigned int index,
  ******************************************************************************
  */
 
+/**
+ * Get USB configuration descriptor
+ *
+ * @v usb              USB device
+ * @v index            Configuration index
+ * @ret config         Configuration descriptor
+ * @ret rc             Return status code
+ *
+ * The configuration descriptor is dynamically allocated and must
+ * eventually be freed by the caller.
+ */
+static int
+usb_config_descriptor ( struct usb_device *usb, unsigned int index,
+                       struct usb_configuration_descriptor **config ) {
+       struct usb_configuration_descriptor partial;
+       size_t len;
+       int rc;
+
+       /* Read first part of configuration descriptor to get size */
+       if ( ( rc = usb_get_config_descriptor ( usb, index, &partial,
+                                               sizeof ( partial ) ) ) != 0 ) {
+               DBGC ( usb, "USB %s could not get configuration descriptor %d: "
+                      "%s\n", usb->name, index, strerror ( rc ) );
+               goto err_get_partial;
+       }
+       len = le16_to_cpu ( partial.len );
+       if ( len < sizeof ( partial ) ) {
+               DBGC ( usb, "USB %s underlength configuraton descriptor %d\n",
+                      usb->name, index );
+               rc = -EINVAL;
+               goto err_partial_len;
+       }
+
+       /* Allocate buffer for whole configuration descriptor */
+       *config = malloc ( len );
+       if ( ! *config ) {
+               rc = -ENOMEM;
+               goto err_alloc_config;
+       }
+
+       /* Read whole configuration descriptor */
+       if ( ( rc = usb_get_config_descriptor ( usb, index, *config,
+                                               len ) ) != 0 ) {
+               DBGC ( usb, "USB %s could not get configuration descriptor %d: "
+                      "%s\n", usb->name, index, strerror ( rc ) );
+               goto err_get_config_descriptor;
+       }
+       if ( (*config)->len != partial.len ) {
+               DBGC ( usb, "USB %s bad configuration descriptor %d length\n",
+                      usb->name, index );
+               rc = -EINVAL;
+               goto err_config_len;
+       }
+
+       return 0;
+
+ err_config_len:
+ err_get_config_descriptor:
+       free ( *config );
+ err_alloc_config:
+ err_partial_len:
+ err_get_partial:
+       return rc;
+}
+
 /**
  * Describe USB function
  *
- * @v func             USB function
+ * @v usb              USB device
  * @v config           Configuration descriptor
  * @v first            First interface number
+ * @v interfaces       Interface list to fill in
+ * @v desc             Function descriptor to fill in
  * @ret rc             Return status code
  */
-static int usb_function ( struct usb_function *func,
+static int usb_describe ( struct usb_device *usb,
                          struct usb_configuration_descriptor *config,
-                         unsigned int first ) {
-       struct usb_device *usb = func->usb;
+                         unsigned int first, uint8_t *interfaces,
+                         struct usb_function_descriptor *desc ) {
        struct usb_interface_association_descriptor *association;
        struct usb_interface_descriptor *interface;
        struct cdc_union_descriptor *cdc_union;
        unsigned int i;
 
+       /* Fill in vendor and product ID */
+       desc->vendor = le16_to_cpu ( usb->device.vendor );
+       desc->product = le16_to_cpu ( usb->device.product );
+
        /* First, look for an interface association descriptor */
        association = usb_interface_association_descriptor ( config, first );
        if ( association ) {
 
                /* Sanity check */
-               if ( association->count > config->interfaces ) {
+               assert ( association->first == first );
+               if ( ( first + association->count ) > config->interfaces ) {
                        DBGC ( usb, "USB %s has invalid association [%d-%d)\n",
-                              func->name, association->first,
-                              ( association->first + association->count ) );
+                              usb->name, first, ( first + association->count));
                        return -ERANGE;
                }
 
                /* Describe function */
-               memcpy ( &func->class, &association->class,
-                        sizeof ( func->class ) );
-               func->count = association->count;
+               memcpy ( &desc->class, &association->class,
+                        sizeof ( desc->class ) );
+               desc->count = association->count;
                for ( i = 0 ; i < association->count ; i++ )
-                       func->interface[i] = ( association->first + i );
+                       interfaces[i] = ( first + i );
                return 0;
        }
 
        /* Next, look for an interface descriptor */
        interface = usb_interface_descriptor ( config, first, 0 );
        if ( ! interface ) {
-               DBGC ( usb, "USB %s has no interface descriptor\n",
-                      func->name );
+               DBGC ( usb, "USB %s has no descriptor for interface %d\n",
+                      usb->name, first );
                return -ENOENT;
        }
 
        /* Describe function */
-       memcpy ( &func->class, &interface->class, sizeof ( func->class ) );
-       func->count = 1;
-       func->interface[0] = first;
+       memcpy ( &desc->class, &interface->class, sizeof ( desc->class ) );
+       desc->count = 1;
+       interfaces[0] = first;
 
        /* Look for a CDC union descriptor, if applicable */
-       if ( ( func->class.class == USB_CLASS_CDC ) &&
+       if ( ( desc->class.class == USB_CLASS_CDC ) &&
             ( cdc_union = cdc_union_descriptor ( config, interface ) ) ) {
 
                /* Determine interface count */
-               func->count = ( ( cdc_union->header.len -
+               desc->count = ( ( cdc_union->header.len -
                                  offsetof ( typeof ( *cdc_union ),
                                             interface[0] ) ) /
                                sizeof ( cdc_union->interface[0] ) );
-               if ( func->count > config->interfaces ) {
+               if ( desc->count > config->interfaces ) {
                        DBGC ( usb, "USB %s has invalid union functional "
                               "descriptor with %d interfaces\n",
-                              func->name, func->count );
+                              usb->name, desc->count );
                        return -ERANGE;
                }
 
                /* Describe function */
-               for ( i = 0 ; i < func->count ; i++ )
-                       func->interface[i] = cdc_union->interface[i];
+               for ( i = 0 ; i < desc->count ; i++ ) {
+                       if ( cdc_union->interface[i] >= config->interfaces ) {
+                               DBGC ( usb, "USB %s has invalid union "
+                                      "functional descriptor covering "
+                                      "interface %d\n", usb->name,
+                                      cdc_union->interface[i] );
+                               return -ERANGE;
+                       }
+                       interfaces[i] = cdc_union->interface[i];
+               }
 
                return 0;
        }
@@ -977,17 +1056,38 @@ static int usb_function ( struct usb_function *func,
        return 0;
 }
 
+/**
+ * Update list of used interface
+ *
+ * @v usb              USB device
+ * @v count            Number of interfaces
+ * @v interface                List of interfaces
+ * @v used             List of already-used interfaces
+ * @ret rc             Return status code
+ */
+static int usb_used ( struct usb_device *usb, unsigned int count,
+                     uint8_t *interface, uint8_t *used ) {
+       unsigned int i;
+
+       for ( i = 0 ; i < count ; i++ ) {
+               if ( used[interface[i]] ) {
+                       DBGC ( usb, "USB %s interface %d already in use\n",
+                              usb->name, interface[i] );
+                       return -EINVAL;
+               }
+               used[interface[i]] = 1;
+       }
+       return 0;
+}
+
 /**
  * Find USB device driver
  *
- * @v vendor           Vendor ID
- * @v product          Product ID
- * @v class            Class
+ * @v desc             Function descriptor
  * @ret id             USB device ID, or NULL
  * @ret driver         USB device driver, or NULL
  */
-struct usb_driver * usb_find_driver ( unsigned int vendor, unsigned int product,
-                                     struct usb_class *class,
+struct usb_driver * usb_find_driver ( struct usb_function_descriptor *desc,
                                      struct usb_device_id **id ) {
        struct usb_driver *driver;
        unsigned int i;
@@ -998,13 +1098,13 @@ struct usb_driver * usb_find_driver ( unsigned int vendor, unsigned int product,
 
                        /* Check for a matching ID */
                        *id = &driver->ids[i];
-                       if ( ( ( (*id)->vendor == vendor ) ||
+                       if ( ( ( (*id)->vendor == desc->vendor ) ||
                               ( (*id)->vendor == USB_ANY_ID ) ) &&
-                            ( ( (*id)->product == product ) ||
+                            ( ( (*id)->product == desc->product ) ||
                               ( (*id)->product == USB_ANY_ID ) ) &&
-                            ( (*id)->class.class == class->class ) &&
-                            ( (*id)->class.subclass == class->subclass ) &&
-                            ( (*id)->class.protocol == class->protocol ) )
+                            ( (*id)->class.class == desc->class.class ) &&
+                            ( (*id)->class.subclass == desc->class.subclass )&&
+                            ( (*id)->class.protocol == desc->class.protocol ) )
                                return driver;
                }
        }
@@ -1014,6 +1114,51 @@ struct usb_driver * usb_find_driver ( unsigned int vendor, unsigned int product,
        return NULL;
 }
 
+/**
+ * Get USB device configuration score
+ *
+ * @v usb              USB device
+ * @v config           Configuration descriptor
+ * @ret score          Device configuration score, or negative error
+ */
+static int usb_score ( struct usb_device *usb,
+                      struct usb_configuration_descriptor *config ) {
+       uint8_t used[config->interfaces];
+       uint8_t interface[config->interfaces];
+       struct usb_function_descriptor desc;
+       struct usb_driver *driver;
+       struct usb_device_id *id;
+       unsigned int first;
+       unsigned int score = 0;
+       int rc;
+
+       /* Identify each function in turn */
+       memset ( used, 0, sizeof ( used ) );
+       for ( first = 0 ; first < config->interfaces ; first++ ) {
+
+               /* Skip interfaces already used */
+               if ( used[first] )
+                       continue;
+
+               /* Describe function */
+               if ( ( rc = usb_describe ( usb, config, first, interface,
+                                          &desc ) ) != 0 )
+                       return rc;
+
+               /* Update used interfaces */
+               if ( ( rc = usb_used ( usb, desc.count, interface,
+                                      used ) ) != 0 )
+                       return rc;
+
+               /* Look for a driver for this function */
+               driver = usb_find_driver ( &desc, &id );
+               if ( driver )
+                       score += driver->score;
+       }
+
+       return score;
+}
+
 /**
  * Probe USB device driver
  *
@@ -1029,13 +1174,12 @@ static int usb_probe ( struct usb_function *func,
        int rc;
 
        /* Identify driver */
-       driver = usb_find_driver ( func->dev.desc.vendor, func->dev.desc.device,
-                                  &func->class, &id );
+       driver = usb_find_driver ( &func->desc, &id );
        if ( ! driver ) {
                DBGC ( usb, "USB %s %04x:%04x class %d:%d:%d has no driver\n",
-                      func->name, func->dev.desc.vendor, func->dev.desc.device,
-                      func->class.class, func->class.subclass,
-                      func->class.protocol );
+                      func->name, func->desc.vendor, func->desc.product,
+                      func->desc.class.class, func->desc.class.subclass,
+                      func->desc.class.protocol );
                return -ENOENT;
        }
 
@@ -1106,28 +1250,24 @@ usb_probe_all ( struct usb_device *usb,
                list_add_tail ( &func->list, &usb->functions );
 
                /* Identify function */
-               if ( ( rc = usb_function ( func, config, first ) ) != 0 )
-                       goto err_function;
-               assert ( func->count <= config->interfaces );
+               if ( ( rc = usb_describe ( usb, config, first, func->interface,
+                                          &func->desc ) ) != 0 )
+                       goto err_describe;
+               assert ( func->desc.count <= config->interfaces );
 
                /* Mark interfaces as used */
-               for ( i = 0 ; i < func->count ; i++ ) {
-                       if ( func->interface[i] >= config->interfaces ) {
-                               DBGC ( usb, "USB %s has invalid interface %d\n",
-                                      func->name, func->interface[i] );
-                               goto err_interface;
-                       }
-                       used[ func->interface[i] ] = 1;
-               }
+               if ( ( rc = usb_used ( usb, func->desc.count, func->interface,
+                                      used ) ) != 0 )
+                       goto err_used;
 
                /* Probe device driver */
                if ( ( rc = usb_probe ( func, config ) ) != 0 )
                        goto err_probe;
                DBGC ( usb, "USB %s %04x:%04x class %d:%d:%d interfaces ",
-                      func->name, func->dev.desc.vendor, func->dev.desc.device,
-                      func->class.class, func->class.subclass,
-                      func->class.protocol );
-               for ( i = 0 ; i < func->count ; i++ )
+                      func->name, func->desc.vendor, func->desc.product,
+                      func->desc.class.class, func->desc.class.subclass,
+                      func->desc.class.protocol );
+               for ( i = 0 ; i < func->desc.count ; i++ )
                        DBGC ( usb, "%s%d", ( i ? "," : "" ),
                               func->interface[i] );
                DBGC ( usb, " using driver %s\n", func->dev.driver_name );
@@ -1140,8 +1280,8 @@ usb_probe_all ( struct usb_device *usb,
                list_del ( &func->dev.siblings );
                usb_remove ( func );
        err_probe:
-       err_interface:
-       err_function:
+       err_used:
+       err_describe:
                list_del ( &func->list );
                free ( func );
        err_alloc:
@@ -1177,82 +1317,6 @@ static void usb_remove_all ( struct usb_device *usb ) {
        }
 }
 
-/**
- * Select USB device configuration
- *
- * @v usb              USB device
- * @v index            Configuration index
- * @ret rc             Return status code
- */
-static int usb_configure ( struct usb_device *usb, unsigned int index ) {
-       struct usb_configuration_descriptor partial;
-       struct usb_configuration_descriptor *config;
-       size_t len;
-       int rc;
-
-       /* Read first part of configuration descriptor to get size */
-       if ( ( rc = usb_get_config_descriptor ( usb, index, &partial,
-                                               sizeof ( partial ) ) ) != 0 ) {
-               DBGC ( usb, "USB %s could not get configuration descriptor %d: "
-                      "%s\n", usb->name, index, strerror ( rc ) );
-               goto err_get_partial;
-       }
-       len = le16_to_cpu ( partial.len );
-       if ( len < sizeof ( partial ) ) {
-               DBGC ( usb, "USB %s underlength configuraton descriptor %d\n",
-                      usb->name, index );
-               rc = -EINVAL;
-               goto err_partial_len;
-       }
-
-       /* Allocate buffer for whole configuration descriptor */
-       config = malloc ( len );
-       if ( ! config ) {
-               rc = -ENOMEM;
-               goto err_alloc_config;
-       }
-
-       /* Read whole configuration descriptor */
-       if ( ( rc = usb_get_config_descriptor ( usb, index, config,
-                                               len ) ) != 0 ) {
-               DBGC ( usb, "USB %s could not get configuration descriptor %d: "
-                      "%s\n", usb->name, index, strerror ( rc ) );
-               goto err_get_config_descriptor;
-       }
-       if ( config->len != partial.len ) {
-               DBGC ( usb, "USB %s bad configuration descriptor %d length\n",
-                      usb->name, index );
-               rc = -EINVAL;
-               goto err_config_len;
-       }
-
-       /* Set configuration */
-       if ( ( rc = usb_set_configuration ( usb, config->config ) ) != 0){
-               DBGC ( usb, "USB %s could not set configuration %d: %s\n",
-                      usb->name, config->config, strerror ( rc ) );
-               goto err_set_configuration;
-       }
-
-       /* Probe USB device drivers */
-       usb_probe_all ( usb, config );
-
-       /* Free configuration descriptor */
-       free ( config );
-
-       return 0;
-
-       usb_remove_all ( usb );
-       usb_set_configuration ( usb, 0 );
- err_set_configuration:
- err_config_len:
- err_get_config_descriptor:
-       free ( config );
- err_alloc_config:
- err_partial_len:
- err_get_partial:
-       return rc;
-}
-
 /**
  * Clear USB device configuration
  *
@@ -1275,32 +1339,76 @@ static void usb_deconfigure ( struct usb_device *usb ) {
 }
 
 /**
- * Find and select a supported USB device configuration
+ * Choose our preferred USB device configuration
  *
  * @v usb              USB device
  * @ret rc             Return status code
  */
-static int usb_configure_any ( struct usb_device *usb ) {
+static int usb_autoconfigure ( struct usb_device *usb ) {
+       struct usb_configuration_descriptor *config;
+       unsigned int preferred = 0;
        unsigned int index;
-       int rc = -ENOENT;
+       int score;
+       int best = 0;
+       int rc;
 
-       /* Attempt all configuration indexes */
+       /* Calculate driver score for each configuration index */
        for ( index = 0 ; index < usb->device.configurations ; index++ ) {
 
-               /* Attempt this configuration index */
-               if ( ( rc = usb_configure ( usb, index ) ) != 0 )
-                       continue;
+               /* Read configuration descriptor */
+               if ( ( rc = usb_config_descriptor ( usb, index,
+                                                   &config ) ) != 0 )
+                       goto err_config;
 
-               /* If we have no drivers, then try the next configuration */
-               if ( list_empty ( &usb->functions ) ) {
-                       rc = -ENOTSUP;
-                       usb_deconfigure ( usb );
-                       continue;
+               /* Get score for this configuration */
+               score = usb_score ( usb, config );
+               if ( score < 0 ) {
+                       rc = score;
+                       goto err_score;
                }
+               DBGC2 ( usb, "USB %s configuration %d score %d\n",
+                       usb->name, config->config, score );
 
-               return 0;
+               /* Record as preferred configuration, if applicable */
+               if ( score > best ) {
+                       best = score;
+                       preferred = index;
+               }
+
+               /* Free configuration descriptor */
+               free ( config );
+               config = NULL;
        }
 
+       /* Read preferred configuration descriptor */
+       if ( ( rc = usb_config_descriptor ( usb, preferred, &config ) ) != 0 )
+               goto err_preferred;
+
+       /* Set configuration */
+       if ( ( rc = usb_set_configuration ( usb, config->config ) ) != 0){
+               DBGC ( usb, "USB %s could not set configuration %d: %s\n",
+                      usb->name, config->config, strerror ( rc ) );
+               goto err_set_configuration;
+       }
+
+       /* Probe USB device drivers */
+       usb_probe_all ( usb, config );
+
+       /* Free configuration descriptor */
+       free ( config );
+
+       return 0;
+
+       usb_remove_all ( usb );
+       usb_set_configuration ( usb, 0 );
+ err_set_configuration:
+       free ( config );
+ err_preferred:
+       return rc;
+
+ err_score:
+       free ( config );
+ err_config:
        return rc;
 }
 
@@ -1444,13 +1552,13 @@ static int register_usb ( struct usb_device *usb ) {
               usb_speed_name ( port->speed ), usb->control.mtu );
 
        /* Configure device */
-       if ( ( rc = usb_configure_any ( usb ) ) != 0 )
-               goto err_configure_any;
+       if ( ( rc = usb_autoconfigure ( usb ) ) != 0 )
+               goto err_autoconfigure;
 
        return 0;
 
        usb_deconfigure ( usb );
- err_configure_any:
+ err_autoconfigure:
  err_get_device_descriptor:
  err_mtu:
  err_get_mtu:
index 58d8dd9649038a0bef7201484db0b95aa55683ad..b4eff50abfff23899605df8b7ea6e5400c44b0d0 100644 (file)
@@ -666,6 +666,7 @@ static struct usb_device_id dm96xx_ids[] = {
 struct usb_driver dm96xx_driver __usb_driver = {
        .ids = dm96xx_ids,
        .id_count = ( sizeof ( dm96xx_ids ) / sizeof ( dm96xx_ids[0] ) ),
+       .score = USB_SCORE_NORMAL,
        .probe = dm96xx_probe,
        .remove = dm96xx_remove,
 };
index 8c84ea9e910cdef0a5b663c51dca1826962131e1..f24a435a52da5e705baa8dcf7333d918e10cb0d5 100644 (file)
@@ -515,6 +515,7 @@ static struct usb_device_id ecm_ids[] = {
 struct usb_driver ecm_driver __usb_driver = {
        .ids = ecm_ids,
        .id_count = ( sizeof ( ecm_ids ) / sizeof ( ecm_ids[0] ) ),
+       .score = USB_SCORE_NORMAL,
        .probe = ecm_probe,
        .remove = ecm_remove,
 };
index 10728d2a1dd3f4957bd219cebe4e394adba45133..3c3ab90f1c857ca432568b15a0273489a9e702ff 100644 (file)
@@ -667,6 +667,7 @@ static struct usb_device_id ncm_ids[] = {
 struct usb_driver ncm_driver __usb_driver = {
        .ids = ncm_ids,
        .id_count = ( sizeof ( ncm_ids ) / sizeof ( ncm_ids[0] ) ),
+       .score = USB_SCORE_NORMAL,
        .probe = ncm_probe,
        .remove = ncm_remove,
 };
index 017e02a59b678095b3799e2b4cca48659ade49b0..854329c5ca3500fafbfa599ae8825f3b6de264af 100644 (file)
@@ -1052,6 +1052,7 @@ static struct usb_device_id smsc75xx_ids[] = {
 struct usb_driver smsc75xx_driver __usb_driver = {
        .ids = smsc75xx_ids,
        .id_count = ( sizeof ( smsc75xx_ids ) / sizeof ( smsc75xx_ids[0] ) ),
+       .score = USB_SCORE_NORMAL,
        .probe = smsc75xx_probe,
        .remove = smsc75xx_remove,
 };
index bf2a2000565a2bfd8dd4214f5aaa5fec5e91eb3f..97d21ef4eefd5c8cd8bd27b2408faa73b81acc96 100644 (file)
@@ -542,6 +542,7 @@ static struct usb_device_id hub_ids[] = {
 struct usb_driver usb_hub_driver __usb_driver = {
        .ids = hub_ids,
        .id_count = ( sizeof ( hub_ids ) / sizeof ( hub_ids[0] ) ),
+       .score = USB_SCORE_NORMAL,
        .probe = hub_probe,
        .remove = hub_remove,
 };
index 2c15200ce42f2d898402c7800b2d29e549c2b8f6..55c61ed4918af4eae60765b55b05cb5f9ced8c2d 100644 (file)
@@ -158,7 +158,7 @@ static int usbio_interface ( struct usbio_device *usbio,
                                        continue;
 
                                /* Iterate over all interfaces for a match */
-                               for ( i = 0 ; i < func->count ; i++ ) {
+                               for ( i = 0 ; i < func->desc.count ; i++ ) {
                                        if ( interface->interface ==
                                             func->interface[i] )
                                                return interface->interface;
@@ -1287,15 +1287,13 @@ static int usbio_supported ( EFI_HANDLE handle ) {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        EFI_USB_DEVICE_DESCRIPTOR device;
        EFI_USB_INTERFACE_DESCRIPTOR interface;
-       struct usb_class class;
+       struct usb_function_descriptor desc;
        struct usb_driver *driver;
        struct usb_device_id *id;
        union {
                void *interface;
                EFI_USB_IO_PROTOCOL *io;
        } usb;
-       unsigned int vendor;
-       unsigned int product;
        EFI_STATUS efirc;
        int rc;
 
@@ -1318,8 +1316,8 @@ static int usbio_supported ( EFI_HANDLE handle ) {
                       "%s\n", efi_handle_name ( handle ), strerror ( rc ) );
                goto err_get_device_descriptor;
        }
-       vendor = device.IdVendor;
-       product = device.IdProduct;
+       desc.vendor = device.IdVendor;
+       desc.product = device.IdProduct;
 
        /* Get interface descriptor */
        if ( ( efirc = usb.io->UsbGetInterfaceDescriptor ( usb.io,
@@ -1329,12 +1327,12 @@ static int usbio_supported ( EFI_HANDLE handle ) {
                       "%s\n", efi_handle_name ( handle ), strerror ( rc ) );
                goto err_get_interface_descriptor;
        }
-       class.class = interface.InterfaceClass;
-       class.subclass = interface.InterfaceSubClass;
-       class.protocol = interface.InterfaceProtocol;
+       desc.class.class = interface.InterfaceClass;
+       desc.class.subclass = interface.InterfaceSubClass;
+       desc.class.protocol = interface.InterfaceProtocol;
 
        /* Look for a driver for this interface */
-       driver = usb_find_driver ( vendor, product, &class, &id );
+       driver = usb_find_driver ( &desc, &id );
        if ( ! driver ) {
                rc = -ENOTSUP;
                goto err_unsupported;
index ea94f2e6335c80ad2f2e839e191908b501b53511..b134bc78a194bbd932e678ac21139557ef65ad70 100644 (file)
@@ -449,6 +449,7 @@ static struct usb_device_id usbkbd_ids[] = {
 struct usb_driver usbkbd_driver __usb_driver = {
        .ids = usbkbd_ids,
        .id_count = ( sizeof ( usbkbd_ids ) / sizeof ( usbkbd_ids[0] ) ),
+       .score = USB_SCORE_NORMAL,
        .probe = usbkbd_probe,
        .remove = usbkbd_remove,
 };
index b92336d052999a3c9b4098183411501038eee5df..d18d81772306e9f9f4f50043c8aed8b6c19504e2 100644 (file)
@@ -173,7 +173,7 @@ static int usbnet_comms_describe ( struct usbnet_device *usbnet,
        int rc;
 
        /* Iterate over all available interfaces */
-       for ( i = 0 ; i < usbnet->func->count ; i++ ) {
+       for ( i = 0 ; i < usbnet->func->desc.count ; i++ ) {
 
                /* Get interface number */
                comms = usbnet->func->interface[i];
@@ -217,7 +217,7 @@ static int usbnet_data_describe ( struct usbnet_device *usbnet,
        int rc;
 
        /* Iterate over all available interfaces */
-       for ( i = 0 ; i < usbnet->func->count ; i++ ) {
+       for ( i = 0 ; i < usbnet->func->desc.count ; i++ ) {
 
                /* Get interface number */
                data = usbnet->func->interface[i];
index 0640f9e3879032853442e2adb6e59df440caed9e..8fee00e5614bcaaa7388c2ba52858e59821cee32 100644 (file)
@@ -615,6 +615,23 @@ extern int usb_prefill ( struct usb_endpoint *ep );
 extern int usb_refill ( struct usb_endpoint *ep );
 extern void usb_flush ( struct usb_endpoint *ep );
 
+/**
+ * A USB function descriptor
+ *
+ * This is an internal descriptor used to represent an association of
+ * interfaces within a USB device.
+ */
+struct usb_function_descriptor {
+       /** Vendor ID */
+       uint16_t vendor;
+       /** Product ID */
+       uint16_t product;
+       /** Class */
+       struct usb_class class;
+       /** Number of interfaces */
+       unsigned int count;
+};
+
 /**
  * A USB function
  *
@@ -626,10 +643,8 @@ struct usb_function {
        const char *name;
        /** USB device */
        struct usb_device *usb;
-       /** Class */
-       struct usb_class class;
-       /** Number of interfaces */
-       unsigned int count;
+       /** Function descriptor */
+       struct usb_function_descriptor desc;
        /** Generic device */
        struct device dev;
        /** List of functions within this USB device */
@@ -1161,7 +1176,7 @@ usb_get_device_descriptor ( struct usb_device *usb,
  * @v data             Configuration descriptor to fill in
  * @ret rc             Return status code
  */
-static inline __attribute (( always_inline )) int
+static inline __attribute__ (( always_inline )) int
 usb_get_config_descriptor ( struct usb_device *usb, unsigned int index,
                            struct usb_configuration_descriptor *data,
                            size_t len ) {
@@ -1296,6 +1311,12 @@ struct usb_driver {
        struct usb_device_id *ids;
        /** Number of entries in ID table */
        unsigned int id_count;
+       /** Driver score
+        *
+        * This is used to determine the preferred configuration for a
+        * USB device.
+        */
+       unsigned int score;
        /**
         * Probe device
         *
@@ -1319,9 +1340,18 @@ struct usb_driver {
 /** Declare a USB driver */
 #define __usb_driver __table_entry ( USB_DRIVERS, 01 )
 
-extern struct usb_driver * usb_find_driver ( unsigned int vendor,
-                                            unsigned int product,
-                                            struct usb_class *class,
-                                            struct usb_device_id **id );
+/** USB driver scores */
+enum usb_driver_score {
+       /** Fallback driver (has no effect on overall score) */
+       USB_SCORE_FALLBACK = 0,
+       /** Deprecated driver */
+       USB_SCORE_DEPRECATED = 1,
+       /** Normal driver */
+       USB_SCORE_NORMAL = 2,
+};
+
+extern struct usb_driver *
+usb_find_driver ( struct usb_function_descriptor *desc,
+                 struct usb_device_id **id );
 
 #endif /* _IPXE_USB_H */