Discussion:
[PATCH ver 2] usb-storage: add "quirks=" module parameter
Alan Stern
2008-11-10 19:07:45 UTC
Permalink
This patch (as1163b) adds a "quirks=" module parameter to usb-storage.
This will allow people to make short-term changes to their
unusual_devs list without rebuilding the entire driver. Testing will
become much easier, and less-sophisticated users will be able to
access their buggy devices after a simple config-file change instead
of having to wait for a new kernel release.

The patch also adds a documentation entry for usb-storage's
"delay_use" parameter, which has been around for years but but was
never listed among the kernel parameters.

Signed-off-by: Alan Stern <stern-nwvwT67g6+6dFdvTe/***@public.gmane.org>

---

Small correction to the previous version: Don't try to allocate 0
bytes.


Index: usb-2.6/Documentation/kernel-parameters.txt
===================================================================
--- usb-2.6.orig/Documentation/kernel-parameters.txt
+++ usb-2.6/Documentation/kernel-parameters.txt
@@ -90,6 +90,7 @@ parameter is applicable:
SWSUSP Software suspend (hibernation) is enabled.
SUSPEND System suspend states are enabled.
TS Appropriate touchscreen support is enabled.
+ UMS USB Mass Storage support is enabled.
USB USB support is enabled.
USBHID USB Human Interface Device support is enabled.
V4L Video For Linux support is enabled.
@@ -2323,6 +2324,34 @@ and is between 256 and 4096 characters.
usbhid.mousepoll=
[USBHID] The interval which mice are to be polled at.

+ usb-storage.delay_use=
+ [UMS] The delay in seconds before a new device is
+ scanned for Logical Units (default 5).
+
+ usb-storage.quirks=
+ [UMS] A list of quirks entries to supplement or
+ override the built-in unusual_devs list. List
+ entries are separated by commas. Each entry has
+ the form VID:PID:Flags where VID and PID are Vendor
+ and Product ID values (4-digit hex numbers) and
+ Flags is a set of characters, each corresponding
+ to a common usb-storage quirk flag as follows:
+ c = FIX_CAPACITY (decrease the reported
+ device capacity by one sector);
+ i = IGNORE_DEVICE (don't bind to this
+ device);
+ l = NOT_LOCKABLE (don't try to lock and
+ unlock ejectable media);
+ m = MAX_SECTORS_64 (don't transfer more
+ than 64 sectors = 32 KB at a time);
+ r = IGNORE_RESIDUE (the device reports
+ bogus residue values);
+ s = SINGLE_LUN (the device has only one
+ Logical Unit);
+ w = NO_WP_DETECT (don't test whether the
+ medium is write-protected).
+ Example: quirks=0419:aaf5:rl,0421:0433:rc
+
add_efi_memmap [EFI; x86-32,X86-64] Include EFI memory map in
kernel's map of available physical RAM.

Index: usb-2.6/drivers/usb/storage/usb.c
===================================================================
--- usb-2.6.orig/drivers/usb/storage/usb.c
+++ usb-2.6/drivers/usb/storage/usb.c
@@ -113,6 +113,16 @@ static unsigned int delay_use = 5;
module_param(delay_use, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");

+static char *quirks;
+module_param(quirks, charp, S_IRUGO);
+MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
+
+struct quirks_entry {
+ u16 vid, pid;
+ u32 fflags;
+};
+static struct quirks_entry *quirks_list, *quirks_end;
+

/*
* The entries in this table correspond, line for line,
@@ -473,6 +483,30 @@ static int associate_dev(struct us_data
return 0;
}

+/* Adjust device flags based on the "quirks=" module parameter */
+static void adjust_quirks(struct us_data *us)
+{
+ u16 vid, pid;
+ struct quirks_entry *q;
+ unsigned int mask = (US_FL_FIX_CAPACITY | US_FL_IGNORE_DEVICE |
+ US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
+ US_FL_IGNORE_RESIDUE | US_FL_SINGLE_LUN |
+ US_FL_NO_WP_DETECT);
+
+ vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor);
+ pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
+
+ for (q = quirks_list; q != quirks_end; ++q) {
+ if (q->vid == vid && q->pid == pid) {
+ us->fflags = (us->fflags & ~mask) | q->fflags;
+ dev_info(&us->pusb_intf->dev, "Quirks match for "
+ "vid %04x pid %04x: %x\n",
+ vid, pid, q->fflags);
+ break;
+ }
+ }
+}
+
/* Find an unusual_dev descriptor (always succeeds in the current code) */
static struct us_unusual_dev *find_unusual(const struct usb_device_id *id)
{
@@ -497,6 +531,7 @@ static int get_device_info(struct us_dat
idesc->bInterfaceProtocol :
unusual_dev->useTransport;
us->fflags = USB_US_ORIG_FLAGS(id->driver_info);
+ adjust_quirks(us);

if (us->fflags & US_FL_IGNORE_DEVICE) {
printk(KERN_INFO USB_STORAGE "device ignored\n");
@@ -1061,10 +1096,88 @@ static struct usb_driver usb_storage_dri
.soft_unbind = 1,
};

+/* Works only for digits and letters, but small and fast */
+#define TOLOWER(x) ((x) | 0x20)
+
+static void __init parse_quirks(void)
+{
+ int n, i;
+ char *p;
+
+ if (!quirks)
+ return;
+
+ /* Count the ':' characters to get 2 * the number of entries */
+ n = 0;
+ for (p = quirks; *p; ++p) {
+ if (*p == ':')
+ ++n;
+ }
+ n /= 2;
+ if (n == 0)
+ return; /* Don't allocate 0 bytes */
+
+ quirks_list = kmalloc(n * sizeof(*quirks_list), GFP_KERNEL);
+ if (!quirks_list)
+ return;
+
+ p = quirks;
+ quirks_end = quirks_list;
+ for (i = 0; i < n && *p; ++i) {
+ unsigned f = 0;
+
+ /* Each entry consists of VID:PID:flags */
+ quirks_end->vid = simple_strtoul(p, &p, 16);
+ if (*p != ':')
+ goto skip_to_next;
+ quirks_end->pid = simple_strtoul(p+1, &p, 16);
+ if (*p != ':')
+ goto skip_to_next;
+
+ while (*++p && *p != ',') {
+ switch (TOLOWER(*p)) {
+ case 'c':
+ f |= US_FL_FIX_CAPACITY;
+ break;
+ case 'i':
+ f |= US_FL_IGNORE_DEVICE;
+ break;
+ case 'l':
+ f |= US_FL_NOT_LOCKABLE;
+ break;
+ case 'm':
+ f |= US_FL_MAX_SECTORS_64;
+ break;
+ case 'r':
+ f |= US_FL_IGNORE_RESIDUE;
+ break;
+ case 's':
+ f |= US_FL_SINGLE_LUN;
+ break;
+ case 'w':
+ f |= US_FL_NO_WP_DETECT;
+ break;
+ /* Ignore unrecognized flag characters */
+ }
+ }
+ quirks_end->fflags = f;
+ ++quirks_end;
+
+ skip_to_next:
+ /* Entries are separated by commas */
+ while (*p) {
+ if (*p++ == ',')
+ break;
+ }
+ } /* for (i = 0; ...) */
+}
+
static int __init usb_stor_init(void)
{
int retval;
+
printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
+ parse_quirks();

/* register the driver, return usb_register return code if error */
retval = usb_register(&usb_storage_driver);

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Greg KH
2008-11-12 19:50:30 UTC
Permalink
Post by Alan Stern
This patch (as1163b) adds a "quirks=" module parameter to usb-storage.
This will allow people to make short-term changes to their
unusual_devs list without rebuilding the entire driver. Testing will
become much easier, and less-sophisticated users will be able to
access their buggy devices after a simple config-file change instead
of having to wait for a new kernel release.
The patch also adds a documentation entry for usb-storage's
"delay_use" parameter, which has been around for years but but was
never listed among the kernel parameters.
Very cool, I don't know why no one thought of this before :)

Thanks for doing this.

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Loading...