aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage
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 /drivers/usb/storage
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>
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/usb.c113
1 files changed, 113 insertions, 0 deletions
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);