[PATCH] USB: match on bInterfaceNumber

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxx>
---
So, how about something like this?

Barely tested:

bjorn@nemi:~$ modinfo sierra|grep 68A2
alias:          usb:v1199p68A2d*dc*dsc*dp*ic*isc*ip*in03*
alias:          usb:v1199p68A2d*dc*dsc*dp*ic*isc*ip*in02*
bjorn@nemi:~$ modinfo qmi_wwan|grep 68A2
alias:          usb:v1199p68A2d*dc*dsc*dp*ic*isc*ip*in08*

May 18 21:09:30 nemi kernel: [  273.244184] usb 8-4: new high-speed USB device number 3 using ehci_hcd
May 18 21:09:31 nemi kernel: [  273.379669] usb 8-4: config 1 has an invalid interface number: 8 but max is 3
May 18 21:09:31 nemi kernel: [  273.379679] usb 8-4: config 1 has no interface number 1
May 18 21:09:31 nemi kernel: [  273.383670] usb 8-4: New USB device found, idVendor=1199, idProduct=68a2
May 18 21:09:31 nemi kernel: [  273.383680] usb 8-4: New USB device strings: Mfr=3, Product=2, SerialNumber=4
May 18 21:09:31 nemi kernel: [  273.383686] usb 8-4: Product: MC7710
May 18 21:09:31 nemi kernel: [  273.383691] usb 8-4: Manufacturer: Sierra Wireless, Incorporated
May 18 21:09:31 nemi kernel: [  273.383697] usb 8-4: SerialNumber: 3581780400xxxxx
May 18 21:09:31 nemi kernel: [  273.408874] usbcore: registered new interface driver usbserial
May 18 21:09:31 nemi kernel: [  273.409161] usbcore: registered new interface driver usbserial_generic
May 18 21:09:31 nemi kernel: [  273.409455] USB Serial support registered for generic
May 18 21:09:31 nemi kernel: [  273.409585] usbserial: USB Serial Driver core
May 18 21:09:31 nemi kernel: [  273.410975] usbcore: registered new interface driver sierra
May 18 21:09:31 nemi kernel: [  273.411267] USB Serial support registered for Sierra USB modem
May 18 21:09:31 nemi kernel: [  273.411376] sierra 8-4:1.2: Sierra USB modem converter detected
May 18 21:09:36 nemi kernel: [  278.409188] usb 8-4: Sierra USB modem converter now attached to ttyUSB0
May 18 21:09:36 nemi kernel: [  278.409255] sierra 8-4:1.3: Sierra USB modem converter detected
May 18 21:09:36 nemi kernel: [  278.410157] usb 8-4: Sierra USB modem converter now attached to ttyUSB1
May 18 21:09:36 nemi kernel: [  278.416162] qmi_wwan 8-4:1.8: cdc-wdm0: USB WDM device
May 18 21:09:36 nemi kernel: [  278.416923] qmi_wwan 8-4:1.8: wwan0: register 'qmi_wwan' at usb-0000:00:1d.7-4, Sierra Wireless wwan/QMI device, e2:d9:a3:bb:da:ba
May 18 21:09:36 nemi kernel: [  278.417008] usbcore: registered new interface driver qmi_wwan


Looks like it might be working. This could lead to a
single device requiring a large number of entries if
there are many interfaces to match.  However, there is
nothing preventing a driver from ignoring this, and use
the same probing strategy as today so I don't that is a
real problem.

So?  Anything I missed here?  I tried grepping for the
alias string, but looking at the split matches I found
I guess I could have missed something...




Bjørn

 drivers/usb/core/driver.c       |    9 +++++++--
 drivers/usb/core/message.c      |    5 +++--
 drivers/usb/core/sysfs.c        |    5 +++--
 include/linux/mod_devicetable.h |    7 +++++++
 include/linux/usb.h             |   16 ++++++++++++++++
 scripts/mod/file2alias.c        |    5 ++++-
 6 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index f6f81c8..780910e 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -570,14 +570,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) &&
@@ -592,6 +593,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);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index ca717da..640366b 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1535,7 +1535,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),
@@ -1544,7 +1544,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;
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 566d9f9..87678c5 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,
 	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);
 
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 501da4c..826bd72 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -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)
 
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 1493345..3f12e06 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -721,6 +721,22 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
 	.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
  * @sc: bDeviceSubClass value
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 44ddaa5..f527f4f 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,
 }
 
 /* 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,
-- 
1.7.10

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux