aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2012-05-18 15:27:43 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-13 18:40:09 -0400
commit81df2d594340dcb6d1a02191976be88a1ca8120c (patch)
treef5a20ebf416c03b41611518d54706019d0c0ffa2
parent7e97243c2080ecae7129e83635227fdebd4feef6 (diff)
USB: allow match on bInterfaceNumber
Some composite USB devices provide multiple interfaces with different functions, all using "vendor-specific" for class/subclass/protocol. Another OS use interface numbers to match the driver and interface. It seems these devices are designed with that in mind - using static interface numbers for the different functions. This adds support for matching against the bInterfaceNumber, allowing such devices to be supported without having to resort to testing against interface number whitelists and/or blacklists in the probe. Signed-off-by: Bjørn Mork <bjorn@mork.no> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/core/driver.c9
-rw-r--r--drivers/usb/core/message.c5
-rw-r--r--drivers/usb/core/sysfs.c5
-rw-r--r--include/linux/mod_devicetable.h7
-rw-r--r--include/linux/usb.h16
-rw-r--r--scripts/mod/file2alias.c5
6 files changed, 40 insertions, 7 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index f536aebc958e..23d7bbd199a5 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -622,14 +622,15 @@ int usb_match_one_id(struct usb_interface *interface,
622 if (!usb_match_device(dev, id)) 622 if (!usb_match_device(dev, id))
623 return 0; 623 return 0;
624 624
625 /* The interface class, subclass, and protocol should never be 625 /* The interface class, subclass, protocol and number should never be
626 * checked for a match if the device class is Vendor Specific, 626 * checked for a match if the device class is Vendor Specific,
627 * unless the match record specifies the Vendor ID. */ 627 * unless the match record specifies the Vendor ID. */
628 if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC && 628 if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
629 !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && 629 !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
630 (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS | 630 (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
631 USB_DEVICE_ID_MATCH_INT_SUBCLASS | 631 USB_DEVICE_ID_MATCH_INT_SUBCLASS |
632 USB_DEVICE_ID_MATCH_INT_PROTOCOL))) 632 USB_DEVICE_ID_MATCH_INT_PROTOCOL |
633 USB_DEVICE_ID_MATCH_INT_NUMBER)))
633 return 0; 634 return 0;
634 635
635 if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && 636 if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
@@ -644,6 +645,10 @@ int usb_match_one_id(struct usb_interface *interface,
644 (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol)) 645 (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
645 return 0; 646 return 0;
646 647
648 if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
649 (id->bInterfaceNumber != intf->desc.bInterfaceNumber))
650 return 0;
651
647 return 1; 652 return 1;
648} 653}
649EXPORT_SYMBOL_GPL(usb_match_one_id); 654EXPORT_SYMBOL_GPL(usb_match_one_id);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index b548cf1dbc62..ca7fc392fd9e 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1559,7 +1559,7 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
1559 1559
1560 if (add_uevent_var(env, 1560 if (add_uevent_var(env,
1561 "MODALIAS=usb:" 1561 "MODALIAS=usb:"
1562 "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", 1562 "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02Xin%02X",
1563 le16_to_cpu(usb_dev->descriptor.idVendor), 1563 le16_to_cpu(usb_dev->descriptor.idVendor),
1564 le16_to_cpu(usb_dev->descriptor.idProduct), 1564 le16_to_cpu(usb_dev->descriptor.idProduct),
1565 le16_to_cpu(usb_dev->descriptor.bcdDevice), 1565 le16_to_cpu(usb_dev->descriptor.bcdDevice),
@@ -1568,7 +1568,8 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
1568 usb_dev->descriptor.bDeviceProtocol, 1568 usb_dev->descriptor.bDeviceProtocol,
1569 alt->desc.bInterfaceClass, 1569 alt->desc.bInterfaceClass,
1570 alt->desc.bInterfaceSubClass, 1570 alt->desc.bInterfaceSubClass,
1571 alt->desc.bInterfaceProtocol)) 1571 alt->desc.bInterfaceProtocol,
1572 alt->desc.bInterfaceNumber))
1572 return -ENOMEM; 1573 return -ENOMEM;
1573 1574
1574 return 0; 1575 return 0;
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 9a56e3adf476..777f03c37725 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -840,7 +840,7 @@ static ssize_t show_modalias(struct device *dev,
840 alt = intf->cur_altsetting; 840 alt = intf->cur_altsetting;
841 841
842 return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" 842 return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
843 "ic%02Xisc%02Xip%02X\n", 843 "ic%02Xisc%02Xip%02Xin%02X\n",
844 le16_to_cpu(udev->descriptor.idVendor), 844 le16_to_cpu(udev->descriptor.idVendor),
845 le16_to_cpu(udev->descriptor.idProduct), 845 le16_to_cpu(udev->descriptor.idProduct),
846 le16_to_cpu(udev->descriptor.bcdDevice), 846 le16_to_cpu(udev->descriptor.bcdDevice),
@@ -849,7 +849,8 @@ static ssize_t show_modalias(struct device *dev,
849 udev->descriptor.bDeviceProtocol, 849 udev->descriptor.bDeviceProtocol,
850 alt->desc.bInterfaceClass, 850 alt->desc.bInterfaceClass,
851 alt->desc.bInterfaceSubClass, 851 alt->desc.bInterfaceSubClass,
852 alt->desc.bInterfaceProtocol); 852 alt->desc.bInterfaceProtocol,
853 alt->desc.bInterfaceNumber);
853} 854}
854static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); 855static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
855 856
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 5db93821f9c7..7771d453e5f3 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -78,6 +78,9 @@ struct ieee1394_device_id {
78 * of a given interface; other interfaces may support other classes. 78 * of a given interface; other interfaces may support other classes.
79 * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass. 79 * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
80 * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass. 80 * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
81 * @bInterfaceNumber: Number of interface; composite devices may use
82 * fixed interface numbers to differentiate between vendor-specific
83 * interfaces.
81 * @driver_info: Holds information used by the driver. Usually it holds 84 * @driver_info: Holds information used by the driver. Usually it holds
82 * a pointer to a descriptor understood by the driver, or perhaps 85 * a pointer to a descriptor understood by the driver, or perhaps
83 * device flags. 86 * device flags.
@@ -115,6 +118,9 @@ struct usb_device_id {
115 __u8 bInterfaceSubClass; 118 __u8 bInterfaceSubClass;
116 __u8 bInterfaceProtocol; 119 __u8 bInterfaceProtocol;
117 120
121 /* Used for vendor-specific interface matches */
122 __u8 bInterfaceNumber;
123
118 /* not matched against */ 124 /* not matched against */
119 kernel_ulong_t driver_info; 125 kernel_ulong_t driver_info;
120}; 126};
@@ -130,6 +136,7 @@ struct usb_device_id {
130#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 136#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
131#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 137#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
132#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 138#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
139#define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400
133 140
134#define HID_ANY_ID (~0) 141#define HID_ANY_ID (~0)
135#define HID_BUS_ANY 0xffff 142#define HID_BUS_ANY 0xffff
diff --git a/include/linux/usb.h b/include/linux/usb.h
index dea39dc551d4..f717fbdaee8e 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -777,6 +777,22 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
777 .bInterfaceProtocol = (pr) 777 .bInterfaceProtocol = (pr)
778 778
779/** 779/**
780 * USB_DEVICE_INTERFACE_NUMBER - describe a usb device with a specific interface number
781 * @vend: the 16 bit USB Vendor ID
782 * @prod: the 16 bit USB Product ID
783 * @num: bInterfaceNumber value
784 *
785 * This macro is used to create a struct usb_device_id that matches a
786 * specific interface number of devices.
787 */
788#define USB_DEVICE_INTERFACE_NUMBER(vend, prod, num) \
789 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
790 USB_DEVICE_ID_MATCH_INT_NUMBER, \
791 .idVendor = (vend), \
792 .idProduct = (prod), \
793 .bInterfaceNumber = (num)
794
795/**
780 * USB_DEVICE_INFO - macro used to describe a class of usb devices 796 * USB_DEVICE_INFO - macro used to describe a class of usb devices
781 * @cl: bDeviceClass value 797 * @cl: bDeviceClass value
782 * @sc: bDeviceSubClass value 798 * @sc: bDeviceSubClass value
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 5759751a1f61..7ed6864ef65b 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -156,7 +156,7 @@ static void device_id_check(const char *modname, const char *device_id,
156} 156}
157 157
158/* USB is special because the bcdDevice can be matched against a numeric range */ 158/* USB is special because the bcdDevice can be matched against a numeric range */
159/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */ 159/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */
160static void do_usb_entry(struct usb_device_id *id, 160static void do_usb_entry(struct usb_device_id *id,
161 unsigned int bcdDevice_initial, int bcdDevice_initial_digits, 161 unsigned int bcdDevice_initial, int bcdDevice_initial_digits,
162 unsigned char range_lo, unsigned char range_hi, 162 unsigned char range_lo, unsigned char range_hi,
@@ -210,6 +210,9 @@ static void do_usb_entry(struct usb_device_id *id,
210 ADD(alias, "ip", 210 ADD(alias, "ip",
211 id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, 211 id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
212 id->bInterfaceProtocol); 212 id->bInterfaceProtocol);
213 ADD(alias, "in",
214 id->match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER,
215 id->bInterfaceNumber);
213 216
214 add_wildcard(alias); 217 add_wildcard(alias);
215 buf_printf(&mod->dev_table_buf, 218 buf_printf(&mod->dev_table_buf,