[PATCH 15/19] USB: add a blacklist for devices that can't handle some things we throw at them.

Greg Kroah-Hartman <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
From: Oliver Neukum <[email protected]>

This adds a blacklist to the USB core to handle some autosuspend and
string issues that devices have.

Originally written by Oliver, but hacked up a lot by Greg.

Signed-off-by: Oliver Neukum <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
 drivers/usb/core/Makefile  |    2 +-
 drivers/usb/core/hub.c     |    3 ++
 drivers/usb/core/message.c |    6 +++-
 drivers/usb/core/quirks.c  |   75 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/core/sysfs.c   |   11 ++++++
 drivers/usb/core/usb.h     |    1 +
 include/linux/usb.h        |    1 +
 include/linux/usb/quirks.h |   11 ++++++
 8 files changed, 108 insertions(+), 2 deletions(-)
 create mode 100644 drivers/usb/core/quirks.c
 create mode 100644 include/linux/usb/quirks.h

diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 34e9bac..b607870 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -4,7 +4,7 @@
 
 usbcore-objs	:= usb.o hub.o hcd.o urb.o message.o driver.o \
 			config.o file.o buffer.o sysfs.o endpoint.o \
-			devio.o notify.o generic.o
+			devio.o notify.o generic.o quirks.o
 
 ifeq ($(CONFIG_PCI),y)
 	usbcore-objs	+= hcd-pci.o
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 50c0db1..4140074 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1287,6 +1287,9 @@ int usb_new_device(struct usb_device *udev)
 	if (!try_module_get(THIS_MODULE))
 		return -EINVAL;
 
+	/* Determine quirks */
+	usb_detect_quirks(udev);
+
 	err = usb_get_configuration(udev);
 	if (err < 0) {
 		dev_err(&udev->dev, "can't read configurations, error %d\n",
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 74edaea..2f17468 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -11,6 +11,7 @@
 #include <linux/timer.h>
 #include <linux/ctype.h>
 #include <linux/device.h>
+#include <linux/usb/quirks.h>
 #include <asm/byteorder.h>
 #include <asm/scatterlist.h>
 
@@ -685,7 +686,10 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
 
 	/* Try to read the string descriptor by asking for the maximum
 	 * possible number of bytes */
-	rc = usb_get_string(dev, langid, index, buf, 255);
+	if (dev->quirks & USB_QUIRK_STRING_FETCH_255)
+		rc = -EIO;
+	else
+		rc = usb_get_string(dev, langid, index, buf, 255);
 
 	/* If that failed try to read the descriptor length, then
 	 * ask for just that many bytes */
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
new file mode 100644
index 0000000..ea0e48e
--- /dev/null
+++ b/drivers/usb/core/quirks.c
@@ -0,0 +1,75 @@
+/*
+ * USB device quirk handling logic and table
+ *
+ * Copyright (c) 2007 Oliver Neukum
+ * Copyright (c) 2007 Greg Kroah-Hartman <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/quirks.h>
+#include "usb.h"
+
+/* List of quirky USB devices.  Please keep this list ordered by:
+ * 	1) Vendor ID
+ * 	2) Product ID
+ * 	3) Class ID
+ *
+ * as we want specific devices to be overridden first, and only after that, any
+ * class specific quirks.
+ *
+ * Right now the logic aborts if it finds a valid device in the table, we might
+ * want to change that in the future if it turns out that a whole class of
+ * devices is broken...
+ */
+static const struct usb_device_id usb_quirk_list[] = {
+	/* HP 5300/5370C scanner */
+	{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
+
+	/* Elsa MicroLink 56k (V.250) */
+	{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+	{ }  /* terminating entry must be last */
+};
+
+static void usb_autosuspend_quirk(struct usb_device *udev)
+{
+	/* unbalanced resume to prevent autosuspends */
+	usb_autoresume_device(udev);
+}
+
+static const struct usb_device_id *find_id(struct usb_device *udev)
+{
+	const struct usb_device_id *id = usb_quirk_list;
+
+	for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
+			id->driver_info; id++) {
+		if (usb_match_device(udev, id))
+			return id;
+	}
+	return NULL;
+}
+
+/*
+ * Detect any quirks the device has, and do any housekeeping for it if needed.
+ */
+void usb_detect_quirks(struct usb_device *udev)
+{
+	const struct usb_device_id *id = usb_quirk_list;
+
+	id = find_id(udev);
+	if (id)
+		udev->quirks = (u32)(id->driver_info);
+	if (udev->quirks)
+		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
+				udev->quirks);
+
+	/* do any special quirk handling here if needed */
+	if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
+		usb_autosuspend_quirk(udev);
+}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 0edfbaf..8f5a764 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -148,6 +148,16 @@ show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
 
+static ssize_t
+show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev;
+
+	udev = to_usb_device(dev);
+	return sprintf(buf, "0x%x\n", udev->quirks);
+}
+static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
+
 /* Descriptor fields */
 #define usb_descriptor_attr_le16(field, format_string)			\
 static ssize_t								\
@@ -204,6 +214,7 @@ static struct attribute *dev_attrs[] = {
 	&dev_attr_devnum.attr,
 	&dev_attr_version.attr,
 	&dev_attr_maxchild.attr,
+	&dev_attr_quirks.attr,
 	NULL,
 };
 static struct attribute_group dev_attr_grp = {
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 86692a2..045cbd1 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -13,6 +13,7 @@ extern void usb_disable_interface (struct usb_device *dev,
 		struct usb_interface *intf);
 extern void usb_release_interface_cache(struct kref *ref);
 extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern void usb_detect_quirks(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
 		unsigned int size);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index a8e8d1e..37e522e 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -388,6 +388,7 @@ struct usb_device {
 	struct usb_device *children[USB_MAXCHILDREN];
 
 	int pm_usage_cnt;		/* usage counter for autosuspend */
+	u32 quirks;			/* quirks of the whole device */
 #ifdef CONFIG_PM
 	struct delayed_work autosuspend; /* for delayed autosuspends */
 	struct mutex pm_mutex;		/* protects PM operations */
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
new file mode 100644
index 0000000..6bac8fa
--- /dev/null
+++ b/include/linux/usb/quirks.h
@@ -0,0 +1,11 @@
+/*
+ * This file holds the definitions of quirks found in USB devices.
+ * Only quirks that affect the whole device, not an interface,
+ * belong here.
+ */
+
+/* device must not be autosuspended */
+#define USB_QUIRK_NO_AUTOSUSPEND	0x00000001
+
+/* string descriptors must not be fetched using a 255-byte read */
+#define USB_QUIRK_STRING_FETCH_255	0x00000002
-- 
1.5.0.1


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.