aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-11-10 14:07:45 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-07 12:59:53 -0500
commitd4f373e57d3916814110968c5ea1155a8d972b5a (patch)
treeeb9e79187ab45942044e48c22c1b62c7c0c29ce1
parent74c71ebd8d7c7a513022851a02bb52b9fa7e0dcb (diff)
USB: usb-storage: add "quirks=" module parameter
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@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--Documentation/kernel-parameters.txt29
-rw-r--r--drivers/usb/storage/usb.c113
2 files changed, 142 insertions, 0 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 0b3f6711d2f1..8eb6e35405cd 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -91,6 +91,7 @@ parameter is applicable:
91 SUSPEND System suspend states are enabled. 91 SUSPEND System suspend states are enabled.
92 FTRACE Function tracing enabled. 92 FTRACE Function tracing enabled.
93 TS Appropriate touchscreen support is enabled. 93 TS Appropriate touchscreen support is enabled.
94 UMS USB Mass Storage support is enabled.
94 USB USB support is enabled. 95 USB USB support is enabled.
95 USBHID USB Human Interface Device support is enabled. 96 USBHID USB Human Interface Device support is enabled.
96 V4L Video For Linux support is enabled. 97 V4L Video For Linux support is enabled.
@@ -2383,6 +2384,34 @@ and is between 256 and 4096 characters. It is defined in the file
2383 usbhid.mousepoll= 2384 usbhid.mousepoll=
2384 [USBHID] The interval which mice are to be polled at. 2385 [USBHID] The interval which mice are to be polled at.
2385 2386
2387 usb-storage.delay_use=
2388 [UMS] The delay in seconds before a new device is
2389 scanned for Logical Units (default 5).
2390
2391 usb-storage.quirks=
2392 [UMS] A list of quirks entries to supplement or
2393 override the built-in unusual_devs list. List
2394 entries are separated by commas. Each entry has
2395 the form VID:PID:Flags where VID and PID are Vendor
2396 and Product ID values (4-digit hex numbers) and
2397 Flags is a set of characters, each corresponding
2398 to a common usb-storage quirk flag as follows:
2399 c = FIX_CAPACITY (decrease the reported
2400 device capacity by one sector);
2401 i = IGNORE_DEVICE (don't bind to this
2402 device);
2403 l = NOT_LOCKABLE (don't try to lock and
2404 unlock ejectable media);
2405 m = MAX_SECTORS_64 (don't transfer more
2406 than 64 sectors = 32 KB at a time);
2407 r = IGNORE_RESIDUE (the device reports
2408 bogus residue values);
2409 s = SINGLE_LUN (the device has only one
2410 Logical Unit);
2411 w = NO_WP_DETECT (don't test whether the
2412 medium is write-protected).
2413 Example: quirks=0419:aaf5:rl,0421:0433:rc
2414
2386 add_efi_memmap [EFI; x86-32,X86-64] Include EFI memory map in 2415 add_efi_memmap [EFI; x86-32,X86-64] Include EFI memory map in
2387 kernel's map of available physical RAM. 2416 kernel's map of available physical RAM.
2388 2417
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 27016fd2cad1..eb1a53a3e5ca 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -113,6 +113,16 @@ static unsigned int delay_use = 5;
113module_param(delay_use, uint, S_IRUGO | S_IWUSR); 113module_param(delay_use, uint, S_IRUGO | S_IWUSR);
114MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); 114MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
115 115
116static char *quirks;
117module_param(quirks, charp, S_IRUGO);
118MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
119
120struct quirks_entry {
121 u16 vid, pid;
122 u32 fflags;
123};
124static struct quirks_entry *quirks_list, *quirks_end;
125
116 126
117/* 127/*
118 * The entries in this table correspond, line for line, 128 * The entries in this table correspond, line for line,
@@ -473,6 +483,30 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf)
473 return 0; 483 return 0;
474} 484}
475 485
486/* Adjust device flags based on the "quirks=" module parameter */
487static void adjust_quirks(struct us_data *us)
488{
489 u16 vid, pid;
490 struct quirks_entry *q;
491 unsigned int mask = (US_FL_FIX_CAPACITY | US_FL_IGNORE_DEVICE |
492 US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
493 US_FL_IGNORE_RESIDUE | US_FL_SINGLE_LUN |
494 US_FL_NO_WP_DETECT);
495
496 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor);
497 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
498
499 for (q = quirks_list; q != quirks_end; ++q) {
500 if (q->vid == vid && q->pid == pid) {
501 us->fflags = (us->fflags & ~mask) | q->fflags;
502 dev_info(&us->pusb_intf->dev, "Quirks match for "
503 "vid %04x pid %04x: %x\n",
504 vid, pid, q->fflags);
505 break;
506 }
507 }
508}
509
476/* Find an unusual_dev descriptor (always succeeds in the current code) */ 510/* Find an unusual_dev descriptor (always succeeds in the current code) */
477static struct us_unusual_dev *find_unusual(const struct usb_device_id *id) 511static struct us_unusual_dev *find_unusual(const struct usb_device_id *id)
478{ 512{
@@ -497,6 +531,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id)
497 idesc->bInterfaceProtocol : 531 idesc->bInterfaceProtocol :
498 unusual_dev->useTransport; 532 unusual_dev->useTransport;
499 us->fflags = USB_US_ORIG_FLAGS(id->driver_info); 533 us->fflags = USB_US_ORIG_FLAGS(id->driver_info);
534 adjust_quirks(us);
500 535
501 if (us->fflags & US_FL_IGNORE_DEVICE) { 536 if (us->fflags & US_FL_IGNORE_DEVICE) {
502 printk(KERN_INFO USB_STORAGE "device ignored\n"); 537 printk(KERN_INFO USB_STORAGE "device ignored\n");
@@ -1061,10 +1096,88 @@ static struct usb_driver usb_storage_driver = {
1061 .soft_unbind = 1, 1096 .soft_unbind = 1,
1062}; 1097};
1063 1098
1099/* Works only for digits and letters, but small and fast */
1100#define TOLOWER(x) ((x) | 0x20)
1101
1102static void __init parse_quirks(void)
1103{
1104 int n, i;
1105 char *p;
1106
1107 if (!quirks)
1108 return;
1109
1110 /* Count the ':' characters to get 2 * the number of entries */
1111 n = 0;
1112 for (p = quirks; *p; ++p) {
1113 if (*p == ':')
1114 ++n;
1115 }
1116 n /= 2;
1117 if (n == 0)
1118 return; /* Don't allocate 0 bytes */
1119
1120 quirks_list = kmalloc(n * sizeof(*quirks_list), GFP_KERNEL);
1121 if (!quirks_list)
1122 return;
1123
1124 p = quirks;
1125 quirks_end = quirks_list;
1126 for (i = 0; i < n && *p; ++i) {
1127 unsigned f = 0;
1128
1129 /* Each entry consists of VID:PID:flags */
1130 quirks_end->vid = simple_strtoul(p, &p, 16);
1131 if (*p != ':')
1132 goto skip_to_next;
1133 quirks_end->pid = simple_strtoul(p+1, &p, 16);
1134 if (*p != ':')
1135 goto skip_to_next;
1136
1137 while (*++p && *p != ',') {
1138 switch (TOLOWER(*p)) {
1139 case 'c':
1140 f |= US_FL_FIX_CAPACITY;
1141 break;
1142 case 'i':
1143 f |= US_FL_IGNORE_DEVICE;
1144 break;
1145 case 'l':
1146 f |= US_FL_NOT_LOCKABLE;
1147 break;
1148 case 'm':
1149 f |= US_FL_MAX_SECTORS_64;
1150 break;
1151 case 'r':
1152 f |= US_FL_IGNORE_RESIDUE;
1153 break;
1154 case 's':
1155 f |= US_FL_SINGLE_LUN;
1156 break;
1157 case 'w':
1158 f |= US_FL_NO_WP_DETECT;
1159 break;
1160 /* Ignore unrecognized flag characters */
1161 }
1162 }
1163 quirks_end->fflags = f;
1164 ++quirks_end;
1165
1166 skip_to_next:
1167 /* Entries are separated by commas */
1168 while (*p) {
1169 if (*p++ == ',')
1170 break;
1171 }
1172 } /* for (i = 0; ...) */
1173}
1174
1064static int __init usb_stor_init(void) 1175static int __init usb_stor_init(void)
1065{ 1176{
1066 int retval; 1177 int retval;
1178
1067 printk(KERN_INFO "Initializing USB Mass Storage driver...\n"); 1179 printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
1180 parse_quirks();
1068 1181
1069 /* register the driver, return usb_register return code if error */ 1182 /* register the driver, return usb_register return code if error */
1070 retval = usb_register(&usb_storage_driver); 1183 retval = usb_register(&usb_storage_driver);