]> git.karo-electronics.de Git - linux-beck.git/commitdiff
USB: allow match on bInterfaceNumber
authorBjørn Mork <bjorn@mork.no>
Fri, 18 May 2012 19:27:43 +0000 (21:27 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Jun 2012 22:40:09 +0000 (15:40 -0700)
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>
drivers/usb/core/driver.c
drivers/usb/core/message.c
drivers/usb/core/sysfs.c
include/linux/mod_devicetable.h
include/linux/usb.h
scripts/mod/file2alias.c

index f536aebc958e71d459f71ee5b9ae19f717a851c6..23d7bbd199a5a5c8ba670cbbfdde5a95a4560a87 100644 (file)
@@ -622,14 +622,15 @@ int usb_match_one_id(struct usb_interface *interface,
        if (!usb_match_device(dev, id))
                return 0;
 
-       /* The interface class, subclass, and protocol should never be
+       /* The interface class, subclass, protocol and number should never be
         * checked for a match if the device class is Vendor Specific,
         * unless the match record specifies the Vendor ID. */
        if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
                        !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
                        (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
                                USB_DEVICE_ID_MATCH_INT_SUBCLASS |
-                               USB_DEVICE_ID_MATCH_INT_PROTOCOL)))
+                               USB_DEVICE_ID_MATCH_INT_PROTOCOL |
+                               USB_DEVICE_ID_MATCH_INT_NUMBER)))
                return 0;
 
        if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
@@ -644,6 +645,10 @@ int usb_match_one_id(struct usb_interface *interface,
            (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
                return 0;
 
+       if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
+           (id->bInterfaceNumber != intf->desc.bInterfaceNumber))
+               return 0;
+
        return 1;
 }
 EXPORT_SYMBOL_GPL(usb_match_one_id);
index b548cf1dbc625c66181c1a6928c160fc597bc2e6..ca7fc392fd9e5e5a6930408ab8c0fd89c18eead7 100644 (file)
@@ -1559,7 +1559,7 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 
        if (add_uevent_var(env,
                   "MODALIAS=usb:"
-                  "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+                  "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02Xin%02X",
                   le16_to_cpu(usb_dev->descriptor.idVendor),
                   le16_to_cpu(usb_dev->descriptor.idProduct),
                   le16_to_cpu(usb_dev->descriptor.bcdDevice),
@@ -1568,7 +1568,8 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
                   usb_dev->descriptor.bDeviceProtocol,
                   alt->desc.bInterfaceClass,
                   alt->desc.bInterfaceSubClass,
-                  alt->desc.bInterfaceProtocol))
+                  alt->desc.bInterfaceProtocol,
+                  alt->desc.bInterfaceNumber))
                return -ENOMEM;
 
        return 0;
index 9a56e3adf476f07073500f7a9364b2e4290b8adc..777f03c3772506526e69c4d1e14eab2f61dfd274 100644 (file)
@@ -840,7 +840,7 @@ static ssize_t show_modalias(struct device *dev,
        alt = intf->cur_altsetting;
 
        return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
-                       "ic%02Xisc%02Xip%02X\n",
+                       "ic%02Xisc%02Xip%02Xin%02X\n",
                        le16_to_cpu(udev->descriptor.idVendor),
                        le16_to_cpu(udev->descriptor.idProduct),
                        le16_to_cpu(udev->descriptor.bcdDevice),
@@ -849,7 +849,8 @@ static ssize_t show_modalias(struct device *dev,
                        udev->descriptor.bDeviceProtocol,
                        alt->desc.bInterfaceClass,
                        alt->desc.bInterfaceSubClass,
-                       alt->desc.bInterfaceProtocol);
+                       alt->desc.bInterfaceProtocol,
+                       alt->desc.bInterfaceNumber);
 }
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
index 5db93821f9c7d473d1d4fe87f9e3fc5d988044bb..7771d453e5f3fb89463091f0b585e8c0be505637 100644 (file)
@@ -78,6 +78,9 @@ struct ieee1394_device_id {
  *     of a given interface; other interfaces may support other classes.
  * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
  * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
+ * @bInterfaceNumber: Number of interface; composite devices may use
+ *     fixed interface numbers to differentiate between vendor-specific
+ *     interfaces.
  * @driver_info: Holds information used by the driver.  Usually it holds
  *     a pointer to a descriptor understood by the driver, or perhaps
  *     device flags.
@@ -115,6 +118,9 @@ struct usb_device_id {
        __u8            bInterfaceSubClass;
        __u8            bInterfaceProtocol;
 
+       /* Used for vendor-specific interface matches */
+       __u8            bInterfaceNumber;
+
        /* not matched against */
        kernel_ulong_t  driver_info;
 };
@@ -130,6 +136,7 @@ struct usb_device_id {
 #define USB_DEVICE_ID_MATCH_INT_CLASS          0x0080
 #define USB_DEVICE_ID_MATCH_INT_SUBCLASS       0x0100
 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL       0x0200
+#define USB_DEVICE_ID_MATCH_INT_NUMBER         0x0400
 
 #define HID_ANY_ID                             (~0)
 #define HID_BUS_ANY                            0xffff
index dea39dc551d44c3602f1b7c33800dfba57a0a5b3..f717fbdaee8e1726ef6e1ce08ce9175b4765b205 100644 (file)
@@ -776,6 +776,22 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
        .idProduct = (prod), \
        .bInterfaceProtocol = (pr)
 
+/**
+ * USB_DEVICE_INTERFACE_NUMBER - describe a usb device with a specific interface number
+ * @vend: the 16 bit USB Vendor ID
+ * @prod: the 16 bit USB Product ID
+ * @num: bInterfaceNumber value
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific interface number of devices.
+ */
+#define USB_DEVICE_INTERFACE_NUMBER(vend, prod, num) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+                      USB_DEVICE_ID_MATCH_INT_NUMBER, \
+       .idVendor = (vend), \
+       .idProduct = (prod), \
+       .bInterfaceNumber = (num)
+
 /**
  * USB_DEVICE_INFO - macro used to describe a class of usb devices
  * @cl: bDeviceClass value
index 5759751a1f61212ec02e16de995a8a0482b37c11..7ed6864ef65b7372a0e671280fe80a35794606ae 100644 (file)
@@ -156,7 +156,7 @@ static void device_id_check(const char *modname, const char *device_id,
 }
 
 /* USB is special because the bcdDevice can be matched against a numeric range */
-/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */
+/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */
 static void do_usb_entry(struct usb_device_id *id,
                         unsigned int bcdDevice_initial, int bcdDevice_initial_digits,
                         unsigned char range_lo, unsigned char range_hi,
@@ -210,6 +210,9 @@ static void do_usb_entry(struct usb_device_id *id,
        ADD(alias, "ip",
            id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
            id->bInterfaceProtocol);
+       ADD(alias, "in",
+           id->match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER,
+           id->bInterfaceNumber);
 
        add_wildcard(alias);
        buf_printf(&mod->dev_table_buf,