diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2008-11-10 14:07:45 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-07 12:59:53 -0500 |
commit | d4f373e57d3916814110968c5ea1155a8d972b5a (patch) | |
tree | eb9e79187ab45942044e48c22c1b62c7c0c29ce1 | |
parent | 74c71ebd8d7c7a513022851a02bb52b9fa7e0dcb (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.txt | 29 | ||||
-rw-r--r-- | drivers/usb/storage/usb.c | 113 |
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; | |||
113 | module_param(delay_use, uint, S_IRUGO | S_IWUSR); | 113 | module_param(delay_use, uint, S_IRUGO | S_IWUSR); |
114 | MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); | 114 | MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); |
115 | 115 | ||
116 | static char *quirks; | ||
117 | module_param(quirks, charp, S_IRUGO); | ||
118 | MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); | ||
119 | |||
120 | struct quirks_entry { | ||
121 | u16 vid, pid; | ||
122 | u32 fflags; | ||
123 | }; | ||
124 | static 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 */ | ||
487 | static 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) */ |
477 | static struct us_unusual_dev *find_unusual(const struct usb_device_id *id) | 511 | static 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 | |||
1102 | static 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 | |||
1064 | static int __init usb_stor_init(void) | 1175 | static 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); |