aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-12-15 10:40:06 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-07 13:00:12 -0500
commitc838ea4626d6e982489ff519f9ecf5e1649ca90b (patch)
tree74d9f7e85b99c836ee14afb204416ee6e41450e9 /drivers/usb/storage
parent25ff1c316f6a763f1eefe7f8984b2d8c03888432 (diff)
USB: storage: make the "quirks=" module parameter writable
This patch (as1190) makes usb-storage's "quirks=" module parameter writable, so that users can add entries for their devices at runtime with no need to reboot or reload usb-storage. New codes are added for the SANE_SENSE, CAPACITY_HEURISTICS, and CAPACITY_OK flags. 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.c169
1 files changed, 69 insertions, 100 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 80e234bf4e50..4becf495ca2d 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);