mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
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>
This commit is contained in:
parent
74c71ebd8d
commit
d4f373e57d
2 changed files with 142 additions and 0 deletions
|
@ -91,6 +91,7 @@ parameter is applicable:
|
||||||
SUSPEND System suspend states are enabled.
|
SUSPEND System suspend states are enabled.
|
||||||
FTRACE Function tracing enabled.
|
FTRACE Function tracing enabled.
|
||||||
TS Appropriate touchscreen support is enabled.
|
TS Appropriate touchscreen support is enabled.
|
||||||
|
UMS USB Mass Storage support is enabled.
|
||||||
USB USB support is enabled.
|
USB USB support is enabled.
|
||||||
USBHID USB Human Interface Device support is enabled.
|
USBHID USB Human Interface Device support is enabled.
|
||||||
V4L Video For Linux support is enabled.
|
V4L Video For Linux support is enabled.
|
||||||
|
@ -2383,6 +2384,34 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||||
usbhid.mousepoll=
|
usbhid.mousepoll=
|
||||||
[USBHID] The interval which mice are to be polled at.
|
[USBHID] The interval which mice are to be polled at.
|
||||||
|
|
||||||
|
usb-storage.delay_use=
|
||||||
|
[UMS] The delay in seconds before a new device is
|
||||||
|
scanned for Logical Units (default 5).
|
||||||
|
|
||||||
|
usb-storage.quirks=
|
||||||
|
[UMS] A list of quirks entries to supplement or
|
||||||
|
override the built-in unusual_devs list. List
|
||||||
|
entries are separated by commas. Each entry has
|
||||||
|
the form VID:PID:Flags where VID and PID are Vendor
|
||||||
|
and Product ID values (4-digit hex numbers) and
|
||||||
|
Flags is a set of characters, each corresponding
|
||||||
|
to a common usb-storage quirk flag as follows:
|
||||||
|
c = FIX_CAPACITY (decrease the reported
|
||||||
|
device capacity by one sector);
|
||||||
|
i = IGNORE_DEVICE (don't bind to this
|
||||||
|
device);
|
||||||
|
l = NOT_LOCKABLE (don't try to lock and
|
||||||
|
unlock ejectable media);
|
||||||
|
m = MAX_SECTORS_64 (don't transfer more
|
||||||
|
than 64 sectors = 32 KB at a time);
|
||||||
|
r = IGNORE_RESIDUE (the device reports
|
||||||
|
bogus residue values);
|
||||||
|
s = SINGLE_LUN (the device has only one
|
||||||
|
Logical Unit);
|
||||||
|
w = NO_WP_DETECT (don't test whether the
|
||||||
|
medium is write-protected).
|
||||||
|
Example: quirks=0419:aaf5:rl,0421:0433:rc
|
||||||
|
|
||||||
add_efi_memmap [EFI; x86-32,X86-64] Include EFI memory map in
|
add_efi_memmap [EFI; x86-32,X86-64] Include EFI memory map in
|
||||||
kernel's map of available physical RAM.
|
kernel's map of available physical RAM.
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,16 @@ static unsigned int delay_use = 5;
|
||||||
module_param(delay_use, uint, S_IRUGO | S_IWUSR);
|
module_param(delay_use, uint, S_IRUGO | S_IWUSR);
|
||||||
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
|
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
|
||||||
|
|
||||||
|
static char *quirks;
|
||||||
|
module_param(quirks, charp, S_IRUGO);
|
||||||
|
MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
|
||||||
|
|
||||||
|
struct quirks_entry {
|
||||||
|
u16 vid, pid;
|
||||||
|
u32 fflags;
|
||||||
|
};
|
||||||
|
static struct quirks_entry *quirks_list, *quirks_end;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The entries in this table correspond, line for line,
|
* 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)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Adjust device flags based on the "quirks=" module parameter */
|
||||||
|
static void adjust_quirks(struct us_data *us)
|
||||||
|
{
|
||||||
|
u16 vid, pid;
|
||||||
|
struct quirks_entry *q;
|
||||||
|
unsigned int mask = (US_FL_FIX_CAPACITY | US_FL_IGNORE_DEVICE |
|
||||||
|
US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
|
||||||
|
US_FL_IGNORE_RESIDUE | US_FL_SINGLE_LUN |
|
||||||
|
US_FL_NO_WP_DETECT);
|
||||||
|
|
||||||
|
vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor);
|
||||||
|
pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
|
||||||
|
|
||||||
|
for (q = quirks_list; q != quirks_end; ++q) {
|
||||||
|
if (q->vid == vid && q->pid == pid) {
|
||||||
|
us->fflags = (us->fflags & ~mask) | q->fflags;
|
||||||
|
dev_info(&us->pusb_intf->dev, "Quirks match for "
|
||||||
|
"vid %04x pid %04x: %x\n",
|
||||||
|
vid, pid, q->fflags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Find an unusual_dev descriptor (always succeeds in the current code) */
|
/* Find an unusual_dev descriptor (always succeeds in the current code) */
|
||||||
static struct us_unusual_dev *find_unusual(const struct usb_device_id *id)
|
static struct us_unusual_dev *find_unusual(const struct usb_device_id *id)
|
||||||
{
|
{
|
||||||
|
@ -497,6 +531,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id)
|
||||||
idesc->bInterfaceProtocol :
|
idesc->bInterfaceProtocol :
|
||||||
unusual_dev->useTransport;
|
unusual_dev->useTransport;
|
||||||
us->fflags = USB_US_ORIG_FLAGS(id->driver_info);
|
us->fflags = USB_US_ORIG_FLAGS(id->driver_info);
|
||||||
|
adjust_quirks(us);
|
||||||
|
|
||||||
if (us->fflags & US_FL_IGNORE_DEVICE) {
|
if (us->fflags & US_FL_IGNORE_DEVICE) {
|
||||||
printk(KERN_INFO USB_STORAGE "device ignored\n");
|
printk(KERN_INFO USB_STORAGE "device ignored\n");
|
||||||
|
@ -1061,10 +1096,88 @@ static struct usb_driver usb_storage_driver = {
|
||||||
.soft_unbind = 1,
|
.soft_unbind = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Works only for digits and letters, but small and fast */
|
||||||
|
#define TOLOWER(x) ((x) | 0x20)
|
||||||
|
|
||||||
|
static void __init parse_quirks(void)
|
||||||
|
{
|
||||||
|
int n, i;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (!quirks)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Count the ':' characters to get 2 * the number of entries */
|
||||||
|
n = 0;
|
||||||
|
for (p = quirks; *p; ++p) {
|
||||||
|
if (*p == ':')
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
n /= 2;
|
||||||
|
if (n == 0)
|
||||||
|
return; /* Don't allocate 0 bytes */
|
||||||
|
|
||||||
|
quirks_list = kmalloc(n * sizeof(*quirks_list), GFP_KERNEL);
|
||||||
|
if (!quirks_list)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p = quirks;
|
||||||
|
quirks_end = quirks_list;
|
||||||
|
for (i = 0; i < n && *p; ++i) {
|
||||||
|
unsigned f = 0;
|
||||||
|
|
||||||
|
/* Each entry consists of VID:PID:flags */
|
||||||
|
quirks_end->vid = simple_strtoul(p, &p, 16);
|
||||||
|
if (*p != ':')
|
||||||
|
goto skip_to_next;
|
||||||
|
quirks_end->pid = simple_strtoul(p+1, &p, 16);
|
||||||
|
if (*p != ':')
|
||||||
|
goto skip_to_next;
|
||||||
|
|
||||||
|
while (*++p && *p != ',') {
|
||||||
|
switch (TOLOWER(*p)) {
|
||||||
|
case 'c':
|
||||||
|
f |= US_FL_FIX_CAPACITY;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
f |= US_FL_IGNORE_DEVICE;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
f |= US_FL_NOT_LOCKABLE;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
f |= US_FL_MAX_SECTORS_64;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
f |= US_FL_IGNORE_RESIDUE;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
f |= US_FL_SINGLE_LUN;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
f |= US_FL_NO_WP_DETECT;
|
||||||
|
break;
|
||||||
|
/* Ignore unrecognized flag characters */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
quirks_end->fflags = f;
|
||||||
|
++quirks_end;
|
||||||
|
|
||||||
|
skip_to_next:
|
||||||
|
/* Entries are separated by commas */
|
||||||
|
while (*p) {
|
||||||
|
if (*p++ == ',')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} /* for (i = 0; ...) */
|
||||||
|
}
|
||||||
|
|
||||||
static int __init usb_stor_init(void)
|
static int __init usb_stor_init(void)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
|
printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
|
||||||
|
parse_quirks();
|
||||||
|
|
||||||
/* register the driver, return usb_register return code if error */
|
/* register the driver, return usb_register return code if error */
|
||||||
retval = usb_register(&usb_storage_driver);
|
retval = usb_register(&usb_storage_driver);
|
||||||
|
|
Loading…
Reference in a new issue