Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Apr 2008 18:00:06 GMT
From:      Hans Petter Selasky <hselasky@c2i.net>
To:        freebsd-usb@FreeBSD.org
Subject:   Re: usb/122819: Patch to provide dynamic additions to the usb quirks table
Message-ID:  <200804161800.m3GI06vk097202@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR usb/122819; it has been noted by GNATS.

From: Hans Petter Selasky <hselasky@c2i.net>
To: freebsd-usb@freebsd.org,
 Maurice Castro <maurice@castro.aus.net>
Cc: FreeBSD-gnats-submit@freebsd.org
Subject: Re: usb/122819: Patch to provide dynamic additions to the usb quirks table
Date: Wed, 16 Apr 2008 18:54:02 +0200

 Hi,
 
 Maybe you can prefix the string version of the quirks by the USB module name ?
 
 For example:
 
 MS_REVZ -> UMS_REVZ
 AU_NO_FRAC -> UAUDIO_NO_FRAC
 
 Then it is easier to know where the quirk belongs.
 
 Add a short description of what the quirk does in the "usb" manpage.
 
 There might be a race condition reading and writing the quirks. Probably a 
 mutex is appropriate.
 
 You can improve the quirk string to numerical conversion code by using binary 
 search.
 
 Else your patch looks fine to me.
 
 --HPS
 
 On Wednesday 16 April 2008, Maurice Castro wrote:
 > >Number:         122819
 > >Category:       usb
 > >Synopsis:       Patch to provide dynamic additions to the usb quirks table
 > >Confidential:   no
 > >Severity:       non-critical
 > >Priority:       medium
 > >Responsible:    freebsd-usb
 > >State:          open
 > >Quarter:
 > >Keywords:
 > >Date-Required:
 > >Class:          change-request
 > >Submitter-Id:   current-users
 > >Arrival-Date:   Wed Apr 16 15:40:01 UTC 2008
 > >Closed-Date:
 > >Last-Modified:
 > >Originator:     Maurice Castro
 > >Release:        FreeBSD 7.0-RELEASE i386
 > >Organization:
 > >Environment:
 >
 > System: FreeBSD atum.castro.aus.net 7.0-RELEASE FreeBSD 7.0-RELEASE #9: Wed
 > Apr 16 17:42:53 EST 2008
 > root@atum.castro.aus.net:/scratch/src/sys/i386/compile/USBTEST i386
 >
 >
 >
 > 	FreeBSD all versions
 >
 > >Description:
 >
 > 	The current USB implementation uses a quirks table that is compiled
 > 	into the kernel. Under most circumstances this approach works.
 > 	However, some manufacturers of USB devices have reused keys used
 > 	in the table and hence changing the compiled in table will result
 > 	in an inappropriate entries being present. A localised method of
 > 	changing the quirks values without recompiling their kernel would
 > 	assist developers and users facing this problem. USB developers in
 > 	particular can benefit from the ability to prevent a device
 > 	inappropriately identifying itself as a hid device without having
 > 	to recompile their kernel.
 >
 > 	The supplied patch uses entries in the kernel environment to create
 > 	a dynamic quirks table. The data is available at boot time so
 > 	devices that are connected across a reboot are correctly handled.
 > 	This table can also be updated after boot time by calling an IOCTL.
 >
 > >How-To-Repeat:
 > >Fix:
 >
 > diff -ur /usr/src/share/man/man4/usb.4 /scratch/src/share/man/man4/usb.4
 > --- /usr/src/share/man/man4/usb.4	2008-04-11 22:43:31.000000000 +1000
 > +++ /scratch/src/share/man/man4/usb.4	2008-04-17 00:23:48.000000000 +1000
 > @@ -288,6 +288,66 @@
 >  .Em DANGEROUS
 >  and should be used with great care since it
 >  can destroy the bus integrity.
 > +.It Dv USB_SETDYNQUIRKS
 > +This command will cause the dynamic quirks table to be rebuilt from the
 > +contents of the kernel environment. Environment strings of the form
 > +.Pp
 > +.Ic usb.quirk.N="VENDOR PRODUCT REVISION FLAGS"
 > +.Pp
 > +where
 > +.Ic N
 > +is a number between 0 and 9 and quirks must be numbered contiguously;
 > +.Ic VENDOR PRODUCT
 > +and
 > +.Ic REVISION
 > +are constants that identify the device (the value 0xffff for
 > +.Ic REVISION
 > +denotes all revisions); and
 > +.Ic FLAGS
 > +is any combination of
 > +.Bl -bullet -offset indent -compact
 > +.It
 > +SWAP_UNICODE
 > +.It
 > +MS_REVZ
 > +.It
 > +NO_STRINGS
 > +.It
 > +BAD_ADC
 > +.It
 > +BUS_POWERED
 > +.It
 > +BAD_AUDIO
 > +.It
 > +SPUR_BUT_UP
 > +.It
 > +AU_NO_XU
 > +.It
 > +POWER_CLAIM
 > +.It
 > +AU_NO_FRAC
 > +.It
 > +AU_INP_ASYNC
 > +.It
 > +BROKEN_BIDIR
 > +.It
 > +OPEN_CLEARSTALL
 > +.It
 > +HID_IGNORE
 > +.It
 > +KBD_IGNORE
 > +.It
 > +MS_BAD_CLASS
 > +.It
 > +MS_LEADING_BYTE
 > +.El
 > +separated by "|" characters. These lines set the quirks for each device
 > +identified.
 > +.Pp
 > +The dynamic quirks table is designed to supplement the quirks table built
 > +in to the kernel. It is of particular use to developers working with
 > devices +that inappropriately share vendor, product and revision
 > information and hence +cannot be correctly added in to the kernel's quirks
 > table.
 >  .El
 >  .Pp
 >  The include file
 > diff -ur /usr/src/sys/dev/usb/usb.c /scratch/src/sys/dev/usb/usb.c
 > --- /usr/src/sys/dev/usb/usb.c	2008-04-11 22:43:56.000000000 +1000
 > +++ /scratch/src/sys/dev/usb/usb.c	2008-04-16 23:23:55.000000000 +1000
 > @@ -668,6 +668,10 @@
 >  		*(struct usb_device_stats *)data = sc->sc_bus->stats;
 >  		break;
 >
 > +	case USB_SETDYNQUIRKS:
 > +    		usbd_populate_dynamic_quirks();
 > +		break;
 > +
 >  	default:
 >  		return (EINVAL);
 >  	}
 > diff -ur /usr/src/sys/dev/usb/usb.h /scratch/src/sys/dev/usb/usb.h
 > --- /usr/src/sys/dev/usb/usb.h	2008-04-11 22:43:56.000000000 +1000
 > +++ /scratch/src/sys/dev/usb/usb.h	2008-04-16 23:22:34.000000000 +1000
 > @@ -673,6 +673,7 @@
 >  #define USB_DISCOVER		_IO  ('U', 3)
 >  #define USB_DEVICEINFO		_IOWR('U', 4, struct usb_device_info)
 >  #define USB_DEVICESTATS		_IOR ('U', 5, struct usb_device_stats)
 > +#define USB_SETDYNQUIRKS	_IO  ('U', 6)
 >
 >  /* Generic HID device */
 >  #define USB_GET_REPORT_DESC	_IOR ('U', 21, struct usb_ctl_report_desc)
 > diff -ur /usr/src/sys/dev/usb/usb_quirks.c
 > /scratch/src/sys/dev/usb/usb_quirks.c ---
 > /usr/src/sys/dev/usb/usb_quirks.c	2008-04-11 22:43:56.000000000 +1000 +++
 > /scratch/src/sys/dev/usb/usb_quirks.c	2008-04-16 17:42:12.000000000 +1000
 > @@ -42,8 +42,11 @@
 >
 >  #include <sys/param.h>
 >  #include <sys/systm.h>
 > +#include <sys/kernel.h>
 > +#include <sys/ctype.h>
 >
 >  #include <dev/usb/usb.h>
 > +#include <sys/kenv.h>
 >
 >  #include "usbdevs.h"
 >  #include <dev/usb/usb_quirks.h>
 > @@ -54,12 +57,14 @@
 >
 >  #define ANY 0xffff
 >
 > -static const struct usbd_quirk_entry {
 > +struct usbd_quirk_entry {
 >  	u_int16_t idVendor;
 >  	u_int16_t idProduct;
 >  	u_int16_t bcdDevice;
 >  	struct usbd_quirks quirks;
 > -} usb_quirks[] = {
 > +};
 > +
 > +static struct usbd_quirk_entry usb_quirks[] = {
 >   { USB_VENDOR_INSIDEOUT, USB_PRODUCT_INSIDEOUT_EDGEPORT4,
 >     						    0x094, { UQ_SWAP_UNICODE}},
 >   { USB_VENDOR_DALLAS, USB_PRODUCT_DALLAS_J6502,	    0x0a2, { UQ_BAD_ADC
 > }}, @@ -117,15 +122,24 @@
 >
 >  const struct usbd_quirks usbd_no_quirk = { 0 };
 >
 > -const struct usbd_quirks *
 > -usbd_find_quirk(usb_device_descriptor_t *d)
 > +#define MAX_DYNAMIC_USB_QUIRKS 10
 > +#define ENVNAMEROOT "usb.quirk."
 > +#define SEPCHAR "|"
 > +
 > +static struct usbd_quirk_entry dynamic_usb_quirks[MAX_DYNAMIC_USB_QUIRKS];
 > +
 > +static struct usbd_quirks *
 > +usbd_search_quirk(struct usbd_quirk_entry *quirks, usb_device_descriptor_t
 > *d); +
 > +static struct usbd_quirks *
 > +usbd_search_quirk(struct usbd_quirk_entry *quirks, usb_device_descriptor_t
 > *d) {
 > -	const struct usbd_quirk_entry *t;
 > +	struct usbd_quirk_entry *t;
 >  	u_int16_t vendor = UGETW(d->idVendor);
 >  	u_int16_t product = UGETW(d->idProduct);
 >  	u_int16_t revision = UGETW(d->bcdDevice);
 >
 > -	for (t = usb_quirks; t->idVendor != 0; t++) {
 > +	for (t = quirks; t->idVendor != 0; t++) {
 >  		if (t->idVendor  == vendor &&
 >  		    t->idProduct == product &&
 >  		    (t->bcdDevice == ANY || t->bcdDevice == revision))
 > @@ -139,3 +153,134 @@
 >  #endif
 >  	return (&t->quirks);
 >  }
 > +
 > +const struct usbd_quirks *
 > +usbd_find_quirk(usb_device_descriptor_t *d)
 > +{
 > +	struct usbd_quirks *quirks;
 > +	/* check the dynamic quirks list first for local entries */
 > +	quirks = usbd_search_quirk((struct usbd_quirk_entry *)
 > dynamic_usb_quirks, d); +	if (quirks->uq_flags != 0)
 > +		return quirks;
 > +	/* check the compiled in quirks list if dynamic entry not set */
 > +	return(usbd_search_quirk((struct usbd_quirk_entry *) usb_quirks, d));
 > +}
 > +
 > +void usbd_populate_dynamic_quirks()
 > +{
 > +	/* the size of envkey must exceed the length of ENVNAMEROOT */
 > +	/* and the maximum number of digits in MAX_DYNAMIC_USB_QUIRKS plus 1 */
 > +	/* as the environment size is limitted to 512 entries and a maximum */
 > +	/* of 128 usb devices are supported 3 digits is appropriate for
 > +	all valid values of MAX_DYNAMIC_USB_QUIRKS */
 > +	const int envkeysz = strlen(ENVNAMEROOT)+3+1;
 > +	char envkey[envkeysz];
 > +	int i;
 > +	char *env;
 > +	char *pt;
 > +	char *e;
 > +	int n;
 > +	for (i=0; i<MAX_DYNAMIC_USB_QUIRKS; i++)
 > +	{
 > +		dynamic_usb_quirks[i].quirks.uq_flags = 0;
 > +		dynamic_usb_quirks[i].idVendor = 0;
 > +		dynamic_usb_quirks[i].idProduct = 0;
 > +		dynamic_usb_quirks[i].bcdDevice = 0;
 > +		snprintf(envkey,envkeysz,"%s%d",ENVNAMEROOT,i);
 > +		if (testenv(envkey))
 > +		{
 > +#ifdef USB_DEBUG
 > +			printf("usbd config %s\n", envkey);
 > +#endif
 > +			env = getenv(envkey);
 > +			dynamic_usb_quirks[i].idVendor = strtoul(env, &pt, 0);
 > +			dynamic_usb_quirks[i].idProduct = strtoul(pt, &pt, 0);
 > +			dynamic_usb_quirks[i].bcdDevice = strtoul(pt, &pt, 0);
 > +			/* skip anything which isn't a flag */
 > +			while (*pt && !isalpha(*pt)) pt++;
 > +			/* read in flags */
 > +			while (*pt)
 > +			{
 > +				e = strstr(pt,SEPCHAR);
 > +				if (!e)
 > +				{
 > +					n = strlen(pt);
 > +				}
 > +				else
 > +				{
 > +					n = e - pt;
 > +				}
 > +				if (!strncmp("SWAP_UNICODE", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_SWAP_UNICODE;
 > +				if (!strncmp("MS_REVZ", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_MS_REVZ;
 > +				if (!strncmp("NO_STRINGS", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_NO_STRINGS;
 > +				if (!strncmp("BAD_ADC", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_BAD_ADC;
 > +				if (!strncmp("BUS_POWERED", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_BUS_POWERED;
 > +				if (!strncmp("BAD_AUDIO", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_BAD_AUDIO;
 > +				if (!strncmp("SPUR_BUT_UP", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_SPUR_BUT_UP;
 > +				if (!strncmp("AU_NO_XU", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_AU_NO_XU;
 > +				if (!strncmp("POWER_CLAIM", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_POWER_CLAIM;
 > +				if (!strncmp("AU_NO_FRAC", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_AU_NO_FRAC;
 > +				if (!strncmp("AU_INP_ASYNC", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_AU_INP_ASYNC;
 > +				if (!strncmp("BROKEN_BIDIR", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_BROKEN_BIDIR;
 > +				if (!strncmp("OPEN_CLEARSTALL", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_OPEN_CLEARSTALL;
 > +				if (!strncmp("HID_IGNORE", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_HID_IGNORE;
 > +				if (!strncmp("KBD_IGNORE", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_KBD_IGNORE;
 > +				if (!strncmp("MS_BAD_CLASS", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_MS_BAD_CLASS;
 > +				if (!strncmp("MS_LEADING_BYTE", pt, n))
 > +					dynamic_usb_quirks[i].quirks.uq_flags |= UQ_MS_LEADING_BYTE;
 > +				pt += n;
 > +				pt += strspn(pt, SEPCHAR);
 > +			}
 > +#ifdef USB_DEBUG
 > +			printf("usbd quirk %d %x %x %x %x\n",
 > +				dynamic_usb_quirks[i].quirks.uq_flags,
 > +				dynamic_usb_quirks[i].idVendor,
 > +				dynamic_usb_quirks[i].idProduct,
 > +				dynamic_usb_quirks[i].bcdDevice,
 > +				dynamic_usb_quirks[i].quirks.uq_flags
 > +				);
 > +#endif
 > +			freeenv(env);
 > +		}
 > +		else
 > +		{
 > +			break;
 > +		}
 > +	}
 > +	for (; i<MAX_DYNAMIC_USB_QUIRKS; i++)
 > +	{
 > +#ifdef USB_DEBUG
 > +		printf("usbd clear dynamic quirk %d\n", i);
 > +#endif
 > +		dynamic_usb_quirks[i].quirks.uq_flags = 0;
 > +		dynamic_usb_quirks[i].idVendor = 0;
 > +		dynamic_usb_quirks[i].idProduct = 0;
 > +		dynamic_usb_quirks[i].bcdDevice = 0;
 > +		snprintf(envkey,envkeysz,"%s%d",ENVNAMEROOT,i);
 > +		if (testenv(envkey))
 > +		{
 > +#ifdef USB_DEBUG
 > +			printf("usbd key %s invalid as earlier entry missing\n", envkey);
 > +#endif
 > +		}
 > +	}
 > +}
 > +
 > +SYSINIT(usbd_populate_dynamic_quirks, SI_SUB_KLD, SI_ORDER_MIDDLE,
 > +    usbd_populate_dynamic_quirks, NULL);
 > diff -ur /usr/src/sys/dev/usb/usb_quirks.h
 > /scratch/src/sys/dev/usb/usb_quirks.h ---
 > /usr/src/sys/dev/usb/usb_quirks.h	2008-04-11 22:43:56.000000000 +1000 +++
 > /scratch/src/sys/dev/usb/usb_quirks.h	2008-04-16 11:09:35.000000000 +1000
 > @@ -62,3 +62,5 @@
 >  extern const struct usbd_quirks usbd_no_quirk;
 >
 >  const struct usbd_quirks *usbd_find_quirk(usb_device_descriptor_t *);
 > +
 > +void usbd_populate_dynamic_quirks(void);
 >
 > >Release-Note:
 > >Audit-Trail:
 > >Unformatted:
 >
 > _______________________________________________
 > freebsd-usb@freebsd.org mailing list
 > http://lists.freebsd.org/mailman/listinfo/freebsd-usb
 > To unsubscribe, send any mail to "freebsd-usb-unsubscribe@freebsd.org"
 
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200804161800.m3GI06vk097202>