Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4f373e5 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 74c71ebd
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ parameter is applicable:
	SUSPEND	System suspend states are enabled.
	FTRACE	Function tracing enabled.
	TS	Appropriate touchscreen support is enabled.
	UMS	USB Mass Storage support is enabled.
	USB	USB support is enabled.
	USBHID	USB Human Interface Device 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] 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
			kernel's map of available physical RAM.

+113 −0
Original line number Diff line number Diff line
@@ -113,6 +113,16 @@ static unsigned int delay_use = 5;
module_param(delay_use, uint, S_IRUGO | S_IWUSR);
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,
@@ -473,6 +483,30 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf)
	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) */
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 :
			unusual_dev->useTransport;
	us->fflags = USB_US_ORIG_FLAGS(id->driver_info);
	adjust_quirks(us);

	if (us->fflags & US_FL_IGNORE_DEVICE) {
		printk(KERN_INFO USB_STORAGE "device ignored\n");
@@ -1061,10 +1096,88 @@ static struct usb_driver usb_storage_driver = {
	.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)
{
	int retval;

	printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
	parse_quirks();

	/* register the driver, return usb_register return code if error */
	retval = usb_register(&usb_storage_driver);