diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2008-12-15 10:40:06 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-07 13:00:12 -0500 |
commit | c838ea4626d6e982489ff519f9ecf5e1649ca90b (patch) | |
tree | 74d9f7e85b99c836ee14afb204416ee6e41450e9 /drivers/usb/storage | |
parent | 25ff1c316f6a763f1eefe7f8984b2d8c03888432 (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.c | 169 |
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; | |||
111 | module_param(delay_use, uint, S_IRUGO | S_IWUSR); | 111 | module_param(delay_use, uint, S_IRUGO | S_IWUSR); |
112 | MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); | 112 | MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); |
113 | 113 | ||
114 | static char *quirks; | 114 | static char quirks[128]; |
115 | module_param(quirks, charp, S_IRUGO); | 115 | module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR); |
116 | MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); | 116 | MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); |
117 | 117 | ||
118 | struct quirks_entry { | ||
119 | u16 vid, pid; | ||
120 | u32 fflags; | ||
121 | }; | ||
122 | static 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 */ |
485 | static void adjust_quirks(struct us_data *us) | 482 | static 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 | |||
1098 | static 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 | |||
1171 | static int __init usb_stor_init(void) | 1141 | static 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); |