[usb] Allow for wildcard USB class IDs
Make the class ID a property of the USB driver (rather than a property of the USB device ID), and allow USB drivers to specify a wildcard ID for any of the three component IDs (class, subclass, or protocol). Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
549a0caabb
commit
668dc73d52
|
@ -985,6 +985,7 @@ static int usb_describe ( struct usb_device *usb,
|
|||
unsigned int i;
|
||||
|
||||
/* Fill in vendor and product ID */
|
||||
memset ( desc, 0, sizeof ( *desc ) );
|
||||
desc->vendor = le16_to_cpu ( usb->device.vendor );
|
||||
desc->product = le16_to_cpu ( usb->device.product );
|
||||
|
||||
|
@ -1023,7 +1024,7 @@ static int usb_describe ( struct usb_device *usb,
|
|||
interfaces[0] = first;
|
||||
|
||||
/* Look for a CDC union descriptor, if applicable */
|
||||
if ( ( desc->class.class == USB_CLASS_CDC ) &&
|
||||
if ( ( desc->class.class.class == USB_CLASS_CDC ) &&
|
||||
( cdc_union = cdc_union_descriptor ( config, interface ) ) ) {
|
||||
|
||||
/* Determine interface count */
|
||||
|
@ -1096,15 +1097,17 @@ struct usb_driver * usb_find_driver ( struct usb_function_descriptor *desc,
|
|||
for_each_table_entry ( driver, USB_DRIVERS ) {
|
||||
for ( i = 0 ; i < driver->id_count ; i++ ) {
|
||||
|
||||
/* Check for a matching ID */
|
||||
/* Ignore non-matching driver class */
|
||||
if ( ( driver->class.class.scalar ^ desc->class.scalar )
|
||||
& driver->class.mask.scalar )
|
||||
continue;
|
||||
|
||||
/* Look for a matching ID */
|
||||
*id = &driver->ids[i];
|
||||
if ( ( ( (*id)->vendor == desc->vendor ) ||
|
||||
( (*id)->vendor == USB_ANY_ID ) ) &&
|
||||
( ( (*id)->product == desc->product ) ||
|
||||
( (*id)->product == USB_ANY_ID ) ) &&
|
||||
( (*id)->class.class == desc->class.class ) &&
|
||||
( (*id)->class.subclass == desc->class.subclass )&&
|
||||
( (*id)->class.protocol == desc->class.protocol ) )
|
||||
( (*id)->product == USB_ANY_ID ) ) )
|
||||
return driver;
|
||||
}
|
||||
}
|
||||
|
@ -1178,8 +1181,9 @@ static int usb_probe ( struct usb_function *func,
|
|||
if ( ! driver ) {
|
||||
DBGC ( usb, "USB %s %04x:%04x class %d:%d:%d has no driver\n",
|
||||
func->name, func->desc.vendor, func->desc.product,
|
||||
func->desc.class.class, func->desc.class.subclass,
|
||||
func->desc.class.protocol );
|
||||
func->desc.class.class.class,
|
||||
func->desc.class.class.subclass,
|
||||
func->desc.class.class.protocol );
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
@ -1265,8 +1269,9 @@ usb_probe_all ( struct usb_device *usb,
|
|||
goto err_probe;
|
||||
DBGC ( usb, "USB %s %04x:%04x class %d:%d:%d interfaces ",
|
||||
func->name, func->desc.vendor, func->desc.product,
|
||||
func->desc.class.class, func->desc.class.subclass,
|
||||
func->desc.class.protocol );
|
||||
func->desc.class.class.class,
|
||||
func->desc.class.class.subclass,
|
||||
func->desc.class.class.protocol );
|
||||
for ( i = 0 ; i < func->desc.count ; i++ )
|
||||
DBGC ( usb, "%s%d", ( i ? "," : "" ),
|
||||
func->interface[i] );
|
||||
|
|
|
@ -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] ) ),
|
||||
.class = USB_CLASS_ID ( USB_ANY_ID, USB_ANY_ID, USB_ANY_ID ),
|
||||
.score = USB_SCORE_NORMAL,
|
||||
.probe = dm96xx_probe,
|
||||
.remove = dm96xx_remove,
|
||||
|
|
|
@ -503,11 +503,6 @@ static struct usb_device_id ecm_ids[] = {
|
|||
.name = "cdc-ecm",
|
||||
.vendor = USB_ANY_ID,
|
||||
.product = USB_ANY_ID,
|
||||
.class = {
|
||||
.class = USB_CLASS_CDC,
|
||||
.subclass = USB_SUBCLASS_CDC_ECM,
|
||||
.protocol = 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -515,6 +510,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] ) ),
|
||||
.class = USB_CLASS_ID ( USB_CLASS_CDC, USB_SUBCLASS_CDC_ECM, 0 ),
|
||||
.score = USB_SCORE_NORMAL,
|
||||
.probe = ecm_probe,
|
||||
.remove = ecm_remove,
|
||||
|
|
|
@ -655,11 +655,6 @@ static struct usb_device_id ncm_ids[] = {
|
|||
.name = "cdc-ncm",
|
||||
.vendor = USB_ANY_ID,
|
||||
.product = USB_ANY_ID,
|
||||
.class = {
|
||||
.class = USB_CLASS_CDC,
|
||||
.subclass = USB_SUBCLASS_CDC_NCM,
|
||||
.protocol = 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -667,6 +662,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] ) ),
|
||||
.class = USB_CLASS_ID ( USB_CLASS_CDC, USB_SUBCLASS_CDC_NCM, 0 ),
|
||||
.score = USB_SCORE_NORMAL,
|
||||
.probe = ncm_probe,
|
||||
.remove = ncm_remove,
|
||||
|
|
|
@ -1038,13 +1038,11 @@ static struct usb_device_id smsc75xx_ids[] = {
|
|||
.name = "smsc7500",
|
||||
.vendor = 0x0424,
|
||||
.product = 0x7500,
|
||||
.class = { 0xff, 0x00, 0xff },
|
||||
},
|
||||
{
|
||||
.name = "smsc7505",
|
||||
.vendor = 0x0424,
|
||||
.product = 0x7505,
|
||||
.class = { 0xff, 0x00, 0xff },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1052,6 +1050,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] ) ),
|
||||
.class = USB_CLASS_ID ( 0xff, 0x00, 0xff ),
|
||||
.score = USB_SCORE_NORMAL,
|
||||
.probe = smsc75xx_probe,
|
||||
.remove = smsc75xx_remove,
|
||||
|
|
|
@ -517,24 +517,9 @@ static void hub_remove ( struct usb_function *func ) {
|
|||
/** USB hub device IDs */
|
||||
static struct usb_device_id hub_ids[] = {
|
||||
{
|
||||
.name = "hub-1",
|
||||
.name = "hub",
|
||||
.vendor = USB_ANY_ID,
|
||||
.product = USB_ANY_ID,
|
||||
.class = {
|
||||
.class = USB_CLASS_HUB,
|
||||
.subclass = 0,
|
||||
.protocol = 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "hub-2",
|
||||
.vendor = USB_ANY_ID,
|
||||
.product = USB_ANY_ID,
|
||||
.class = {
|
||||
.class = USB_CLASS_HUB,
|
||||
.subclass = 0,
|
||||
.protocol = 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -542,6 +527,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] ) ),
|
||||
.class = USB_CLASS_ID ( USB_CLASS_HUB, 0, USB_ANY_ID ),
|
||||
.score = USB_SCORE_NORMAL,
|
||||
.probe = hub_probe,
|
||||
.remove = hub_remove,
|
||||
|
|
|
@ -1316,6 +1316,7 @@ static int usbio_supported ( EFI_HANDLE handle ) {
|
|||
"%s\n", efi_handle_name ( handle ), strerror ( rc ) );
|
||||
goto err_get_device_descriptor;
|
||||
}
|
||||
memset ( &desc, 0, sizeof ( desc ) );
|
||||
desc.vendor = device.IdVendor;
|
||||
desc.product = device.IdProduct;
|
||||
|
||||
|
@ -1327,9 +1328,9 @@ static int usbio_supported ( EFI_HANDLE handle ) {
|
|||
"%s\n", efi_handle_name ( handle ), strerror ( rc ) );
|
||||
goto err_get_interface_descriptor;
|
||||
}
|
||||
desc.class.class = interface.InterfaceClass;
|
||||
desc.class.subclass = interface.InterfaceSubClass;
|
||||
desc.class.protocol = interface.InterfaceProtocol;
|
||||
desc.class.class.class = interface.InterfaceClass;
|
||||
desc.class.class.subclass = interface.InterfaceSubClass;
|
||||
desc.class.class.protocol = interface.InterfaceProtocol;
|
||||
|
||||
/* Look for a driver for this interface */
|
||||
driver = usb_find_driver ( &desc, &id );
|
||||
|
|
|
@ -437,11 +437,6 @@ static struct usb_device_id usbkbd_ids[] = {
|
|||
.name = "kbd",
|
||||
.vendor = USB_ANY_ID,
|
||||
.product = USB_ANY_ID,
|
||||
.class = {
|
||||
.class = USB_CLASS_HID,
|
||||
.subclass = USB_SUBCLASS_HID_BOOT,
|
||||
.protocol = USBKBD_PROTOCOL,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -449,6 +444,8 @@ 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] ) ),
|
||||
.class = USB_CLASS_ID ( USB_CLASS_HID, USB_SUBCLASS_HID_BOOT,
|
||||
USBKBD_PROTOCOL ),
|
||||
.score = USB_SCORE_NORMAL,
|
||||
.probe = usbkbd_probe,
|
||||
.remove = usbkbd_remove,
|
||||
|
|
|
@ -615,6 +615,14 @@ 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 class descriptor */
|
||||
union usb_class_descriptor {
|
||||
/** Class */
|
||||
struct usb_class class;
|
||||
/** Scalar value */
|
||||
uint32_t scalar;
|
||||
};
|
||||
|
||||
/**
|
||||
* A USB function descriptor
|
||||
*
|
||||
|
@ -627,7 +635,7 @@ struct usb_function_descriptor {
|
|||
/** Product ID */
|
||||
uint16_t product;
|
||||
/** Class */
|
||||
struct usb_class class;
|
||||
union usb_class_descriptor class;
|
||||
/** Number of interfaces */
|
||||
unsigned int count;
|
||||
};
|
||||
|
@ -1298,19 +1306,50 @@ struct usb_device_id {
|
|||
uint16_t vendor;
|
||||
/** Product ID */
|
||||
uint16_t product;
|
||||
/** Class */
|
||||
struct usb_class class;
|
||||
};
|
||||
|
||||
/** Match-anything ID */
|
||||
#define USB_ANY_ID 0xffff
|
||||
|
||||
/** A USB class ID */
|
||||
struct usb_class_id {
|
||||
/** Class */
|
||||
union usb_class_descriptor class;
|
||||
/** Class mask */
|
||||
union usb_class_descriptor mask;
|
||||
};
|
||||
|
||||
/** Construct USB class ID
|
||||
*
|
||||
* @v base Base class code (or USB_ANY_ID)
|
||||
* @v subclass Subclass code (or USB_ANY_ID)
|
||||
* @v protocol Protocol code (or USB_ANY_ID)
|
||||
*/
|
||||
#define USB_CLASS_ID( base, subclass, protocol ) { \
|
||||
.class = { \
|
||||
.class = { \
|
||||
( (base) & 0xff ), \
|
||||
( (subclass) & 0xff ), \
|
||||
( (protocol) & 0xff ), \
|
||||
}, \
|
||||
}, \
|
||||
.mask = { \
|
||||
.class = { \
|
||||
( ( (base) == USB_ANY_ID ) ? 0x00 : 0xff ), \
|
||||
( ( (subclass) == USB_ANY_ID ) ? 0x00 : 0xff ), \
|
||||
( ( (protocol) == USB_ANY_ID ) ? 0x00 : 0xff ), \
|
||||
}, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/** A USB driver */
|
||||
struct usb_driver {
|
||||
/** USB ID table */
|
||||
struct usb_device_id *ids;
|
||||
/** Number of entries in ID table */
|
||||
unsigned int id_count;
|
||||
/** Class ID */
|
||||
struct usb_class_id class;
|
||||
/** Driver score
|
||||
*
|
||||
* This is used to determine the preferred configuration for a
|
||||
|
|
Reference in New Issue