aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt7
-rw-r--r--drivers/usb/storage/usb.c169
2 files changed, 76 insertions, 100 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 8eb6e35405c..a58fc8b7339 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2396,14 +2396,21 @@ and is between 256 and 4096 characters. It is defined in the file
2396 and Product ID values (4-digit hex numbers) and 2396 and Product ID values (4-digit hex numbers) and
2397 Flags is a set of characters, each corresponding 2397 Flags is a set of characters, each corresponding
2398 to a common usb-storage quirk flag as follows: 2398 to a common usb-storage quirk flag as follows:
2399 a = SANE_SENSE (collect more than 18 bytes
2400 of sense data);
2399 c = FIX_CAPACITY (decrease the reported 2401 c = FIX_CAPACITY (decrease the reported
2400 device capacity by one sector); 2402 device capacity by one sector);
2403 h = CAPACITY_HEURISTICS (decrease the
2404 reported device capacity by one
2405 sector if the number is odd);
2401 i = IGNORE_DEVICE (don't bind to this 2406 i = IGNORE_DEVICE (don't bind to this
2402 device); 2407 device);
2403 l = NOT_LOCKABLE (don't try to lock and 2408 l = NOT_LOCKABLE (don't try to lock and
2404 unlock ejectable media); 2409 unlock ejectable media);
2405 m = MAX_SECTORS_64 (don't transfer more 2410 m = MAX_SECTORS_64 (don't transfer more
2406 than 64 sectors = 32 KB at a time); 2411 than 64 sectors = 32 KB at a time);
2412 o = CAPACITY_OK (accept the capacity
2413 reported by the device);
2407 r = IGNORE_RESIDUE (the device reports 2414 r = IGNORE_RESIDUE (the device reports
2408 bogus residue values); 2415 bogus residue values);
2409 s = SINGLE_LUN (the device has only one 2416 s = SINGLE_LUN (the device has only one
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 80e234bf4e5..4becf495ca2 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -111,16 +111,10 @@ static unsigned int delay_use = 5;
111module_param(delay_use, uint, S_IRUGO | S_IWUSR); 111module_param(delay_use, uint, S_IRUGO | S_IWUSR);
112MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); 112MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
113 113
114static char *quirks; 114static char quirks[128];
115module_param(quirks, charp, S_IRUGO); 115module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR);
116MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); 116MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
117 117
118struct quirks_entry {
119 u16 vid, pid;
120 u32 fflags;
121};
122static struct quirks_entry *quirks_list, *quirks_end;
123
124 118
125/* 119/*
126 * The entries in this table correspond, line for line, 120 * The entries in this table correspond, line for line,
@@ -481,28 +475,80 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf)
481 return 0; 475 return 0;
482} 476}
483 477
478/* Works only for digits and letters, but small and fast */
479#define TOLOWER(x) ((x) | 0x20)
480
484/* Adjust device flags based on the "quirks=" module parameter */ 481/* Adjust device flags based on the "quirks=" module parameter */
485static void adjust_quirks(struct us_data *us) 482static void adjust_quirks(struct us_data *us)
486{ 483{
487 u16 vid, pid; 484 char *p;
488 struct quirks_entry *q; 485 u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor);
489 unsigned int mask = (US_FL_FIX_CAPACITY | US_FL_IGNORE_DEVICE | 486 u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
487 unsigned f = 0;
488 unsigned int mask = (US_FL_SANE_SENSE | US_FL_FIX_CAPACITY |
489 US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE |
490 US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 | 490 US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
491 US_FL_IGNORE_RESIDUE | US_FL_SINGLE_LUN | 491 US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE |
492 US_FL_NO_WP_DETECT); 492 US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT);
493 493
494 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor); 494 p = quirks;
495 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct); 495 while (*p) {
496 496 /* Each entry consists of VID:PID:flags */
497 for (q = quirks_list; q != quirks_end; ++q) { 497 if (vid == simple_strtoul(p, &p, 16) &&
498 if (q->vid == vid && q->pid == pid) { 498 *p == ':' &&
499 us->fflags = (us->fflags & ~mask) | q->fflags; 499 pid == simple_strtoul(p+1, &p, 16) &&
500 dev_info(&us->pusb_intf->dev, "Quirks match for " 500 *p == ':')
501 "vid %04x pid %04x: %x\n",
502 vid, pid, q->fflags);
503 break; 501 break;
502
503 /* Move forward to the next entry */
504 while (*p) {
505 if (*p++ == ',')
506 break;
504 } 507 }
505 } 508 }
509 if (!*p) /* No match */
510 return;
511
512 /* Collect the flags */
513 while (*++p && *p != ',') {
514 switch (TOLOWER(*p)) {
515 case 'a':
516 f |= US_FL_SANE_SENSE;
517 break;
518 case 'c':
519 f |= US_FL_FIX_CAPACITY;
520 break;
521 case 'h':
522 f |= US_FL_CAPACITY_HEURISTICS;
523 break;
524 case 'i':
525 f |= US_FL_IGNORE_DEVICE;
526 break;
527 case 'l':
528 f |= US_FL_NOT_LOCKABLE;
529 break;
530 case 'm':
531 f |= US_FL_MAX_SECTORS_64;
532 break;
533 case 'o':
534 f |= US_FL_CAPACITY_OK;
535 break;
536 case 'r':
537 f |= US_FL_IGNORE_RESIDUE;
538 break;
539 case 's':
540 f |= US_FL_SINGLE_LUN;
541 break;
542 case 'w':
543 f |= US_FL_NO_WP_DETECT;
544 break;
545 /* Ignore unrecognized flag characters */
546 }
547 }
548 us->fflags = (us->fflags & ~mask) | f;
549 dev_info(&us->pusb_intf->dev, "Quirks match for "
550 "vid %04x pid %04x: %x\n",
551 vid, pid, f);
506} 552}
507 553
508/* Find an unusual_dev descriptor (always succeeds in the current code) */ 554/* Find an unusual_dev descriptor (always succeeds in the current code) */
@@ -1092,88 +1138,11 @@ static struct usb_driver usb_storage_driver = {
1092 .soft_unbind = 1, 1138 .soft_unbind = 1,
1093}; 1139};
1094 1140
1095/* Works only for digits and letters, but small and fast */
1096#define TOLOWER(x) ((x) | 0x20)
1097
1098static void __init parse_quirks(void)
1099{
1100 int n, i;
1101 char *p;
1102
1103 if (!quirks)
1104 return;
1105
1106 /* Count the ':' characters to get 2 * the number of entries */
1107 n = 0;
1108 for (p = quirks; *p; ++p) {
1109 if (*p == ':')
1110 ++n;
1111 }
1112 n /= 2;
1113 if (n == 0)
1114 return; /* Don't allocate 0 bytes */
1115
1116 quirks_list = kmalloc(n * sizeof(*quirks_list), GFP_KERNEL);
1117 if (!quirks_list)
1118 return;
1119
1120 p = quirks;
1121 quirks_end = quirks_list;
1122 for (i = 0; i < n && *p; ++i) {
1123 unsigned f = 0;
1124
1125 /* Each entry consists of VID:PID:flags */
1126 quirks_end->vid = simple_strtoul(p, &p, 16);
1127 if (*p != ':')
1128 goto skip_to_next;
1129 quirks_end->pid = simple_strtoul(p+1, &p, 16);
1130 if (*p != ':')
1131 goto skip_to_next;
1132
1133 while (*++p && *p != ',') {
1134 switch (TOLOWER(*p)) {
1135 case 'c':
1136 f |= US_FL_FIX_CAPACITY;
1137 break;
1138 case 'i':
1139 f |= US_FL_IGNORE_DEVICE;
1140 break;
1141 case 'l':
1142 f |= US_FL_NOT_LOCKABLE;
1143 break;
1144 case 'm':
1145 f |= US_FL_MAX_SECTORS_64;
1146 break;
1147 case 'r':
1148 f |= US_FL_IGNORE_RESIDUE;
1149 break;
1150 case 's':
1151 f |= US_FL_SINGLE_LUN;
1152 break;
1153 case 'w':
1154 f |= US_FL_NO_WP_DETECT;
1155 break;
1156 /* Ignore unrecognized flag characters */
1157 }
1158 }
1159 quirks_end->fflags = f;
1160 ++quirks_end;
1161
1162 skip_to_next:
1163 /* Entries are separated by commas */
1164 while (*p) {
1165 if (*p++ == ',')
1166 break;
1167 }
1168 } /* for (i = 0; ...) */
1169}
1170
1171static int __init usb_stor_init(void) 1141static int __init usb_stor_init(void)
1172{ 1142{
1173 int retval; 1143 int retval;
1174 1144
1175 printk(KERN_INFO "Initializing USB Mass Storage driver...\n"); 1145 printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
1176 parse_quirks();
1177 1146
1178 /* register the driver, return usb_register return code if error */ 1147 /* register the driver, return usb_register return code if error */
1179 retval = usb_register(&usb_storage_driver); 1148 retval = usb_register(&usb_storage_driver);