Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 26 Oct 2008 13:28:33 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 151947 for review
Message-ID:  <200810261328.m9QDSXr9063836@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=151947

Change 151947 by hselasky@hselasky_laptop001 on 2008/10/26 13:28:23

	
	Add support for dynamic USB quirks - final step.

Affected files ...

.. //depot/projects/usb/src/lib/libusb20/libusb20.h#6 edit
.. //depot/projects/usb/src/lib/libusb20/libusb20_ugen20.c#6 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.c#37 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_dynamic.c#4 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_dynamic.h#4 edit
.. //depot/projects/usb/src/sys/dev/usb2/include/usb2_ioctl.h#21 edit
.. //depot/projects/usb/src/sys/dev/usb2/quirk/usb2_quirk.c#7 edit
.. //depot/projects/usb/src/usr.sbin/usbconfig/dump.c#6 edit
.. //depot/projects/usb/src/usr.sbin/usbconfig/usbconfig.c#3 edit

Differences ...

==== //depot/projects/usb/src/lib/libusb20/libusb20.h#6 (text+ko) ====

@@ -189,9 +189,11 @@
 struct libusb20_quirk {
 	uint16_t vid;			/* vendor ID */
 	uint16_t pid;			/* product ID */
+	uint16_t bcdDeviceLow;		/* low revision value, inclusive */
+	uint16_t bcdDeviceHigh;		/* high revision value, inclusive */
 	uint16_t reserved[2];		/* for the future */
-	char	quirkname[64 - 8];	/* quirk name including terminating
-					 * zero */
+	/* quirk name, UQ_XXX, including terminating zero */
+	char	quirkname[64 - 12];
 };
 
 /* USB transfer operations */

==== //depot/projects/usb/src/lib/libusb20/libusb20_ugen20.c#6 (text+ko) ====

@@ -936,28 +936,98 @@
 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
     uint16_t index, struct libusb20_quirk *pq)
 {
-	return (LIBUSB20_ERROR_NOT_SUPPORTED);
+	struct usb2_gen_quirk q;
+	int err;
+
+	memset(&q, 0, sizeof(q));
+
+	q.index = index;
+
+	err = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
+
+	if (err) {
+		if (errno == EINVAL) {
+			return (LIBUSB20_ERROR_NOT_FOUND);
+		}
+	} else {
+		pq->vid = q.vid;
+		pq->pid = q.pid;
+		pq->bcdDeviceLow = q.bcdDeviceLow;
+		pq->bcdDeviceHigh = q.bcdDeviceHigh;
+		strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
+	}
+	return (err);
 }
 
 static int
 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t index,
     struct libusb20_quirk *pq)
 {
-	return (LIBUSB20_ERROR_NOT_SUPPORTED);
+	struct usb2_gen_quirk q;
+	int err;
+
+	memset(&q, 0, sizeof(q));
+
+	q.index = index;
+
+	err = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
+
+	if (err) {
+		if (errno == EINVAL) {
+			return (LIBUSB20_ERROR_NOT_FOUND);
+		}
+	} else {
+		strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
+	}
+	return (err);
 }
 
 static int
 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
     struct libusb20_quirk *pq)
 {
-	return (LIBUSB20_ERROR_NOT_SUPPORTED);
+	struct usb2_gen_quirk q;
+	int err;
+
+	memset(&q, 0, sizeof(q));
+
+	q.vid = pq->vid;
+	q.pid = pq->pid;
+	q.bcdDeviceLow = pq->bcdDeviceLow;
+	q.bcdDeviceHigh = pq->bcdDeviceHigh;
+	strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
+
+	err = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
+	if (err) {
+		if (errno == ENOMEM) {
+			return (LIBUSB20_ERROR_NO_MEM);
+		}
+	}
+	return (err);
 }
 
 static int
 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
     struct libusb20_quirk *pq)
 {
-	return (LIBUSB20_ERROR_NOT_SUPPORTED);
+	struct usb2_gen_quirk q;
+	int err;
+
+	memset(&q, 0, sizeof(q));
+
+	q.vid = pq->vid;
+	q.pid = pq->pid;
+	q.bcdDeviceLow = pq->bcdDeviceLow;
+	q.bcdDeviceHigh = pq->bcdDeviceHigh;
+	strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
+
+	err = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
+	if (err) {
+		if (errno == EINVAL) {
+			return (LIBUSB20_ERROR_NOT_FOUND);
+		}
+	}
+	return (err);
 }
 
 static int

==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_dev.c#37 (text+ko) ====

@@ -1302,6 +1302,12 @@
 	case USB_GET_ROOT_PERM:
 		err = usb2_get_perm(u.udp, 0);
 		break;
+	case USB_DEV_QUIRK_GET:
+	case USB_QUIRK_NAME_GET:
+	case USB_DEV_QUIRK_ADD:
+	case USB_DEV_QUIRK_REMOVE:
+		err = usb2_quirk_ioctl_p(cmd, data, fflag, td);
+		break;
 	default:
 		err = ENOTTY;
 		break;

==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_dynamic.c#4 (text+ko) ====

@@ -39,12 +39,14 @@
 static usb2_temp_setup_by_index_t usb2_temp_setup_by_index_w;
 static usb2_temp_unsetup_t usb2_temp_unsetup_w;
 static usb2_test_quirk_t usb2_test_quirk_w;
+static usb2_quirk_ioctl_t usb2_quirk_ioctl_w;
 
 /* global variables */
 usb2_temp_get_desc_t *usb2_temp_get_desc_p = &usb2_temp_get_desc_w;
 usb2_temp_setup_by_index_t *usb2_temp_setup_by_index_p = &usb2_temp_setup_by_index_w;
 usb2_temp_unsetup_t *usb2_temp_unsetup_p = &usb2_temp_unsetup_w;
 usb2_test_quirk_t *usb2_test_quirk_p = &usb2_test_quirk_w;
+usb2_quirk_ioctl_t *usb2_quirk_ioctl_p = &usb2_quirk_ioctl_w;
 devclass_t usb2_devclass_ptr = NULL;
 
 static usb2_error_t
@@ -59,6 +61,12 @@
 	return (0);			/* no match */
 }
 
+static int
+usb2_quirk_ioctl_w(unsigned long cmd, caddr_t data, int fflag, struct thread *td)
+{
+	return (ENOIOCTL);
+}
+
 static void
 usb2_temp_get_desc_w(struct usb2_device *udev, struct usb2_device_request *req, const void **pPtr, uint16_t *pLength)
 {
@@ -86,6 +94,7 @@
 	/* reset function pointers */
 
 	usb2_test_quirk_p = &usb2_test_quirk_w;
+	usb2_quirk_ioctl_p = &usb2_quirk_ioctl_w;
 
 	/* wait for CPU to exit the loaded functions, if any */
 

==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_dynamic.h#4 (text+ko) ====

@@ -37,6 +37,7 @@
 
 typedef usb2_error_t (usb2_temp_setup_by_index_t)(struct usb2_device *udev, uint16_t index);
 typedef uint8_t (usb2_test_quirk_t)(const struct usb2_lookup_info *info, uint16_t quirk);
+typedef int (usb2_quirk_ioctl_t)(unsigned long cmd, caddr_t data, int fflag, struct thread *td);
 typedef void (usb2_temp_get_desc_t)(struct usb2_device *udev, struct usb2_device_request *req, const void **pPtr, uint16_t *pLength);
 typedef void (usb2_temp_unsetup_t)(struct usb2_device *udev);
 
@@ -46,6 +47,7 @@
 extern usb2_temp_setup_by_index_t *usb2_temp_setup_by_index_p;
 extern usb2_temp_unsetup_t *usb2_temp_unsetup_p;
 extern usb2_test_quirk_t *usb2_test_quirk_p;
+extern usb2_quirk_ioctl_t *usb2_quirk_ioctl_p;
 extern devclass_t usb2_devclass_ptr;
 
 /* function prototypes */

==== //depot/projects/usb/src/sys/dev/usb2/include/usb2_ioctl.h#21 (text+ko) ====

@@ -202,6 +202,20 @@
 	uint16_t iface_index;
 };
 
+struct usb2_gen_quirk {
+	uint16_t index;			/* Quirk Index */
+	uint16_t vid;			/* Vendor ID */
+	uint16_t pid;			/* Product ID */
+	uint16_t bcdDeviceLow;		/* Low Device Revision */
+	uint16_t bcdDeviceHigh;		/* High Device Revision */
+	uint16_t reserved[2];
+	/*
+	 * String version of quirk including terminating zero. See UQ_XXX in
+	 * "usb2_quirk.h".
+	 */
+	char	quirkname[64 - 14];
+};
+
 /* USB controller */
 #define	USB_REQUEST		_IOWR('U', 1, struct usb2_ctl_request)
 #define	USB_SETDEBUG		_IOW ('U', 2, int)
@@ -278,4 +292,10 @@
 #define	USB_FS_CLOSE		_IOW ('U', 198, struct usb2_fs_close)
 #define	USB_FS_CLEAR_STALL_SYNC _IOW ('U', 199, struct usb2_fs_clear_stall_sync)
 
+/* USB quirk system interface */
+#define	USB_DEV_QUIRK_GET	_IOWR('Q', 0, struct usb2_gen_quirk)
+#define	USB_QUIRK_NAME_GET	_IOWR('Q', 1, struct usb2_gen_quirk)
+#define	USB_DEV_QUIRK_ADD	_IOW ('Q', 2, struct usb2_gen_quirk)
+#define	USB_DEV_QUIRK_REMOVE	_IOW ('Q', 3, struct usb2_gen_quirk)
+
 #endif					/* _USB2_IOCTL_H_ */

==== //depot/projects/usb/src/sys/dev/usb2/quirk/usb2_quirk.c#7 (text+ko) ====

@@ -26,6 +26,8 @@
  * SUCH DAMAGE.
  */
 
+#include <dev/usb2/include/usb2_standard.h>
+#include <dev/usb2/include/usb2_ioctl.h>
 #include <dev/usb2/include/usb2_mfunc.h>
 #include <dev/usb2/include/usb2_devid.h>
 
@@ -42,68 +44,70 @@
 MODULE_VERSION(usb2_quirk, 1);
 
 /*
- * The following macro adds a quirk for any revision of a device:
+ * The following macro adds one or more quirks for a USB device:
  */
-#define	USB_VPA(v,p,r,...)					\
-    USB_VPI(v,p,((const uint16_t []){__VA_ARGS__}))
+#define	USB_QUIRK_ENTRY(v,p,l,h,...) \
+  .vid = (v), .pid = (p), .lo_rev = (l), .hi_rev = (h), .quirks = { __VA_ARGS__ }
+
+#define	USB_DEV_QUIRKS_MAX 128
+#define	USB_SUB_QUIRKS_MAX 8
+
+struct usb2_quirk_entry {
+	uint16_t vid;
+	uint16_t pid;
+	uint16_t lo_rev;
+	uint16_t hi_rev;
+	uint16_t quirks[USB_SUB_QUIRKS_MAX];
+};
 
-/*
- * The following macro adds a quirk for a specific revision of a
- * device:
- */
-#define	USB_VPR(v,p,r,...)				\
-    USB_VPI(v,p, ((const uint16_t []){__VA_ARGS__})),	\
-    USB_DEV_BCD_LTEQ(r),				\
-    USB_DEV_BCD_GTEQ(r)
+static struct mtx usb2_quirk_mtx;
 
-/* try to keep the quirks on one line, hence grepping becomes easier */
+static struct usb2_quirk_entry usb2_quirks[USB_DEV_QUIRKS_MAX] = {
+	{USB_QUIRK_ENTRY(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_LCM, 0x0000, 0xFFFF, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_INSIDEOUT, USB_PRODUCT_INSIDEOUT_EDGEPORT4, 0x094, 0x094, UQ_SWAP_UNICODE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_DALLAS, USB_PRODUCT_DALLAS_J6502, 0x0a2, 0x0a2, UQ_BAD_ADC, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_DALLAS, USB_PRODUCT_DALLAS_J6502, 0x0a2, 0x0a2, UQ_AU_NO_XU, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_ALTEC, USB_PRODUCT_ALTEC_ADA70, 0x103, 0x103, UQ_BAD_ADC, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_ALTEC, USB_PRODUCT_ALTEC_ASC495, 0x000, 0x000, UQ_BAD_AUDIO, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_QTRONIX, USB_PRODUCT_QTRONIX_980N, 0x110, 0x110, UQ_SPUR_BUT_UP, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_ALCOR2, USB_PRODUCT_ALCOR2_KBD_HUB, 0x001, 0x001, UQ_SPUR_BUT_UP, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_MCT, USB_PRODUCT_MCT_HUB0100, 0x102, 0x102, UQ_BUS_POWERED, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0x102, 0x102, UQ_BUS_POWERED, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_TI, USB_PRODUCT_TI_UTUSB41, 0x110, 0x110, UQ_POWER_CLAIM, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_TELEX, USB_PRODUCT_TELEX_MIC1, 0x009, 0x009, UQ_AU_NO_FRAC, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_SILICONPORTALS, USB_PRODUCT_SILICONPORTALS_YAPPHONE, 0x100, 0x100, UQ_AU_INP_ASYNC, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_LOGITECH, USB_PRODUCT_LOGITECH_UN53B, 0x0000, 0xFFFF, UQ_NO_STRINGS, UQ_NONE)},
 
-static const struct usb2_device_id usb2_quirks[] = {
-	{USB_VPA(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_LCM, 0x000, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_INSIDEOUT, USB_PRODUCT_INSIDEOUT_EDGEPORT4, 0x094, UQ_SWAP_UNICODE, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_DALLAS, USB_PRODUCT_DALLAS_J6502, 0x0a2, UQ_BAD_ADC, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_DALLAS, USB_PRODUCT_DALLAS_J6502, 0x0a2, UQ_AU_NO_XU, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_ALTEC, USB_PRODUCT_ALTEC_ADA70, 0x103, UQ_BAD_ADC, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_ALTEC, USB_PRODUCT_ALTEC_ASC495, 0x000, UQ_BAD_AUDIO, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_QTRONIX, USB_PRODUCT_QTRONIX_980N, 0x110, UQ_SPUR_BUT_UP, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_ALCOR2, USB_PRODUCT_ALCOR2_KBD_HUB, 0x001, UQ_SPUR_BUT_UP, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_MCT, USB_PRODUCT_MCT_HUB0100, 0x102, UQ_BUS_POWERED, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0x102, UQ_BUS_POWERED, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_TI, USB_PRODUCT_TI_UTUSB41, 0x110, UQ_POWER_CLAIM, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_TELEX, USB_PRODUCT_TELEX_MIC1, 0x009, UQ_AU_NO_FRAC, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_SILICONPORTALS, USB_PRODUCT_SILICONPORTALS_YAPPHONE, 0x100, UQ_AU_INP_ASYNC, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_LOGITECH, USB_PRODUCT_LOGITECH_UN53B, 0x000, UQ_NO_STRINGS, UQ_NONE)},
 	/*
-	 * XXX These should have a revision number, but I don't know what
-	 * they are.
+	 * XXX The following quirks should have a more specific revision
+	 * number:
 	 */
-	{USB_VPA(USB_VENDOR_HP, USB_PRODUCT_HP_895C, 0x000, UQ_BROKEN_BIDIR, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_HP, USB_PRODUCT_HP_880C, 0x000, UQ_BROKEN_BIDIR, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_HP, USB_PRODUCT_HP_815C, 0x000, UQ_BROKEN_BIDIR, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_HP, USB_PRODUCT_HP_810C, 0x000, UQ_BROKEN_BIDIR, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_HP, USB_PRODUCT_HP_830C, 0x000, UQ_BROKEN_BIDIR, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_HP, USB_PRODUCT_HP_1220C, 0x000, UQ_BROKEN_BIDIR, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_XEROX, USB_PRODUCT_XEROX_WCM15, 0x000, UQ_BROKEN_BIDIR, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_HP, USB_PRODUCT_HP_895C, 0x0000, 0xFFFF, UQ_BROKEN_BIDIR, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_HP, USB_PRODUCT_HP_880C, 0x0000, 0xFFFF, UQ_BROKEN_BIDIR, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_HP, USB_PRODUCT_HP_815C, 0x0000, 0xFFFF, UQ_BROKEN_BIDIR, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_HP, USB_PRODUCT_HP_810C, 0x0000, 0xFFFF, UQ_BROKEN_BIDIR, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_HP, USB_PRODUCT_HP_830C, 0x0000, 0xFFFF, UQ_BROKEN_BIDIR, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_HP, USB_PRODUCT_HP_1220C, 0x0000, 0xFFFF, UQ_BROKEN_BIDIR, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_XEROX, USB_PRODUCT_XEROX_WCM15, 0x0000, 0xFFFF, UQ_BROKEN_BIDIR, UQ_NONE)},
 	/* Devices which should be ignored by uhid */
-	{USB_VPA(USB_VENDOR_APC, USB_PRODUCT_APC_UPS, 0x000, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6C550AVR, 0x000, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_CYBERPOWER, USB_PRODUCT_CYBERPOWER_1500CAVRLCD, 0x000, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_DELORME, USB_PRODUCT_DELORME_EARTHMATE, 0x000, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_ITUNERNET, USB_PRODUCT_ITUNERNET_USBLCD2X20, 0x000, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_MGE, USB_PRODUCT_MGE_UPS1, 0x000, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_MGE, USB_PRODUCT_MGE_UPS2, 0x000, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE, 0x000, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3G, 0x000, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_APC, USB_PRODUCT_APC_UPS, 0x0000, 0xFFFF, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6C550AVR, 0x0000, 0xFFFF, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_CYBERPOWER, USB_PRODUCT_CYBERPOWER_1500CAVRLCD, 0x0000, 0xFFFF, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_DELORME, USB_PRODUCT_DELORME_EARTHMATE, 0x0000, 0xFFFF, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_ITUNERNET, USB_PRODUCT_ITUNERNET_USBLCD2X20, 0x0000, 0xFFFF, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_MGE, USB_PRODUCT_MGE_UPS1, 0x0000, 0xFFFF, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_MGE, USB_PRODUCT_MGE_UPS2, 0x0000, 0xFFFF, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE, 0x0000, 0xFFFF, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3G, 0x0000, 0xFFFF, UQ_HID_IGNORE, UQ_NONE)},
 	/* Devices which should be ignored by both ukbd and uhid */
-	{USB_VPA(USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_WISPY1A, 0x000, UQ_KBD_IGNORE, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_METAGEEK, USB_PRODUCT_METAGEEK_WISPY1B, 0x000, UQ_KBD_IGNORE, UQ_HID_IGNORE, UQ_NONE)},
-	{USB_VPR(USB_VENDOR_TENX, USB_PRODUCT_TENX_UAUDIO0, 0x0101, UQ_AUDIO_SWAP_LR, UQ_NONE)},
-
+	{USB_QUIRK_ENTRY(USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_WISPY1A, 0x0000, 0xFFFF, UQ_KBD_IGNORE, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_METAGEEK, USB_PRODUCT_METAGEEK_WISPY1B, 0x0000, 0xFFFF, UQ_KBD_IGNORE, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_TENX, USB_PRODUCT_TENX_UAUDIO0, 0x0101, 0x0101, UQ_AUDIO_SWAP_LR, UQ_NONE)},
 	/* MS keyboards do weird things */
-	{USB_VPA(USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLNOTEBOOK, 0x000, UQ_MS_BAD_CLASS, UQ_MS_LEADING_BYTE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLNOTEBOOK2, 0x000, UQ_MS_BAD_CLASS, UQ_MS_LEADING_BYTE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLINTELLIMOUSE, 0x000, UQ_MS_LEADING_BYTE, UQ_NONE)},
-	{USB_VPA(USB_VENDOR_METAGEEK, USB_PRODUCT_METAGEEK_WISPY24X, 0x000, UQ_KBD_IGNORE, UQ_HID_IGNORE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLNOTEBOOK, 0x0000, 0xFFFF, UQ_MS_BAD_CLASS, UQ_MS_LEADING_BYTE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLNOTEBOOK2, 0x0000, 0xFFFF, UQ_MS_BAD_CLASS, UQ_MS_LEADING_BYTE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLINTELLIMOUSE, 0x0000, 0xFFFF, UQ_MS_LEADING_BYTE, UQ_NONE)},
+	{USB_QUIRK_ENTRY(USB_VENDOR_METAGEEK, USB_PRODUCT_METAGEEK_WISPY24X, 0x0000, 0xFFFF, UQ_KBD_IGNORE, UQ_HID_IGNORE, UQ_NONE)},
 };
 
 USB_MAKE_DEBUG_TABLE(USB_QUIRK);
@@ -130,36 +134,239 @@
 static uint8_t
 usb2_test_quirk_by_info(const struct usb2_lookup_info *info, uint16_t quirk)
 {
-	const struct usb2_device_id *pe;
-	const uint16_t *px;
+	uint16_t x;
+	uint16_t y;
 
 	if (quirk == UQ_NONE) {
 		return (0);
 	}
-	pe = usb2_lookup_id_by_info(usb2_quirks, sizeof(usb2_quirks), info);
-	if (pe && pe->driver_info) {
-		px = pe->driver_info;
-		while (1) {
-			if (*px == quirk) {
+	mtx_lock(&usb2_quirk_mtx);
+
+	for (x = 0; x != USB_DEV_QUIRKS_MAX; x++) {
+		/* see if quirk information does not match */
+		if ((usb2_quirks[x].vid != info->idVendor) ||
+		    (usb2_quirks[x].pid != info->idProduct) ||
+		    (usb2_quirks[x].lo_rev > info->bcdDevice) ||
+		    (usb2_quirks[x].hi_rev < info->bcdDevice)) {
+			continue;
+		}
+		/* lookup quirk */
+		for (y = 0; y != USB_SUB_QUIRKS_MAX; y++) {
+			if (usb2_quirks[x].quirks[y] == quirk) {
+				mtx_unlock(&usb2_quirk_mtx);
 				DPRINTF("Found quirk '%s'.\n", usb2_quirkstr(quirk));
 				return (1);
 			}
-			if (*px == UQ_NONE) {
-				return (0);
+		}
+		/* no quirk found */
+		break;
+	}
+	mtx_unlock(&usb2_quirk_mtx);
+	return (0);
+}
+
+static struct usb2_quirk_entry *
+usb2_quirk_get_entry(uint16_t vid, uint16_t pid,
+    uint16_t lo_rev, uint16_t hi_rev, uint8_t do_alloc)
+{
+	uint16_t x;
+
+	mtx_assert(&usb2_quirk_mtx, MA_OWNED);
+
+	if ((vid | pid | lo_rev | hi_rev) == 0) {
+		/* all zero - special case */
+		return (usb2_quirks + USB_DEV_QUIRKS_MAX - 1);
+	}
+	/* search for an existing entry */
+	for (x = 0; x != USB_DEV_QUIRKS_MAX; x++) {
+		/* see if quirk information does not match */
+		if ((usb2_quirks[x].vid != vid) ||
+		    (usb2_quirks[x].pid != pid) ||
+		    (usb2_quirks[x].lo_rev != lo_rev) ||
+		    (usb2_quirks[x].hi_rev != hi_rev)) {
+			continue;
+		}
+		return (usb2_quirks + x);
+	}
+
+	if (do_alloc == 0) {
+		/* no match */
+		return (NULL);
+	}
+	/* search for a free entry */
+	for (x = 0; x != USB_DEV_QUIRKS_MAX; x++) {
+		/* see if quirk information does not match */
+		if ((usb2_quirks[x].vid |
+		    usb2_quirks[x].pid |
+		    usb2_quirks[x].lo_rev |
+		    usb2_quirks[x].hi_rev) != 0) {
+			continue;
+		}
+		usb2_quirks[x].vid = vid;
+		usb2_quirks[x].pid = pid;
+		usb2_quirks[x].lo_rev = lo_rev;
+		usb2_quirks[x].hi_rev = hi_rev;
+
+		return (usb2_quirks + x);
+	}
+
+	/* no entry found */
+	return (NULL);
+}
+
+/*------------------------------------------------------------------------*
+ *	usb2_quirk_ioctl - handle quirk IOCTLs
+ *
+ * Returns:
+ * 0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+static int
+usb2_quirk_ioctl(unsigned long cmd, caddr_t data,
+    int fflag, struct thread *td)
+{
+	struct usb2_gen_quirk *pgq;
+	struct usb2_quirk_entry *pqe;
+	uint32_t x;
+	uint32_t y;
+	int err;
+
+	switch (cmd) {
+	case USB_DEV_QUIRK_GET:
+		pgq = (void *)data;
+		x = pgq->index % USB_SUB_QUIRKS_MAX;
+		y = pgq->index / USB_SUB_QUIRKS_MAX;
+		if (y >= USB_DEV_QUIRKS_MAX) {
+			return (EINVAL);
+		}
+		mtx_lock(&usb2_quirk_mtx);
+		/* copy out data */
+		pgq->vid = usb2_quirks[y].vid;
+		pgq->pid = usb2_quirks[y].pid;
+		pgq->bcdDeviceLow = usb2_quirks[y].lo_rev;
+		pgq->bcdDeviceHigh = usb2_quirks[y].hi_rev;
+		strlcpy(pgq->quirkname,
+		    usb2_quirkstr(usb2_quirks[y].quirks[x]),
+		    sizeof(pgq->quirkname));
+		mtx_unlock(&usb2_quirk_mtx);
+		return (0);		/* success */
+
+	case USB_QUIRK_NAME_GET:
+		pgq = (void *)data;
+		x = pgq->index;
+		if (x >= USB_QUIRK_MAX) {
+			return (EINVAL);
+		}
+		strlcpy(pgq->quirkname,
+		    usb2_quirkstr(x), sizeof(pgq->quirkname));
+		return (0);		/* success */
+
+	case USB_DEV_QUIRK_ADD:
+		pgq = (void *)data;
+
+		/* check privileges */
+		err = priv_check(curthread, PRIV_DRIVER);
+		if (err) {
+			return (err);
+		}
+		/* convert quirk string into numerical */
+		for (y = 0; y != USB_DEV_QUIRKS_MAX; y++) {
+			if (strcmp(pgq->quirkname, usb2_quirkstr(y)) == 0) {
+				break;
+			}
+		}
+		if (y == USB_DEV_QUIRKS_MAX) {
+			return (EINVAL);
+		}
+		if (y == UQ_NONE) {
+			return (EINVAL);
+		}
+		mtx_lock(&usb2_quirk_mtx);
+		pqe = usb2_quirk_get_entry(pgq->vid, pgq->pid,
+		    pgq->bcdDeviceLow, pgq->bcdDeviceHigh, 1);
+		for (x = 0; x != USB_SUB_QUIRKS_MAX; x++) {
+			if (pqe->quirks[x] == UQ_NONE) {
+				pqe->quirks[x] = y;
+				break;
+			}
+		}
+		mtx_unlock(&usb2_quirk_mtx);
+		if (x == USB_SUB_QUIRKS_MAX) {
+			return (ENOMEM);
+		}
+		return (0);		/* success */
+
+	case USB_DEV_QUIRK_REMOVE:
+		pgq = (void *)data;
+		/* check privileges */
+		err = priv_check(curthread, PRIV_DRIVER);
+		if (err) {
+			return (err);
+		}
+		/* convert quirk string into numerical */
+		for (y = 0; y != USB_DEV_QUIRKS_MAX; y++) {
+			if (strcmp(pgq->quirkname, usb2_quirkstr(y)) == 0) {
+				break;
+			}
+		}
+		if (y == USB_DEV_QUIRKS_MAX) {
+			return (EINVAL);
+		}
+		if (y == UQ_NONE) {
+			return (EINVAL);
+		}
+		mtx_lock(&usb2_quirk_mtx);
+		pqe = usb2_quirk_get_entry(pgq->vid, pgq->pid,
+		    pgq->bcdDeviceLow, pgq->bcdDeviceHigh, 0);
+		for (x = 0; x != USB_SUB_QUIRKS_MAX; x++) {
+			if (pqe->quirks[x] == y) {
+				pqe->quirks[x] = UQ_NONE;
+				break;
+			}
+		}
+		if (x == USB_SUB_QUIRKS_MAX) {
+			mtx_unlock(&usb2_quirk_mtx);
+			return (ENOMEM);
+		}
+		for (x = 0; x != USB_SUB_QUIRKS_MAX; x++) {
+			if (pqe->quirks[x] != UQ_NONE) {
+				break;
 			}
-			px++;
+		}
+		if (x == USB_SUB_QUIRKS_MAX) {
+			/* all quirk entries are unused - release */
+			memset(pqe, 0, sizeof(pqe));
 		}
+		mtx_unlock(&usb2_quirk_mtx);
+		return (0);		/* success */
+
+	default:
+		break;
 	}
-	return (0);
+	return (ENOIOCTL);
 }
 
 static void
 usb2_quirk_init(void *arg)
 {
+	/* initialize mutex */
+	mtx_init(&usb2_quirk_mtx, "USB quirk", NULL, MTX_DEF);
+
 	/* register our function */
 	usb2_test_quirk_p = &usb2_test_quirk_by_info;
+	usb2_quirk_ioctl_p = &usb2_quirk_ioctl;
 	return;
 }
 
+static void
+usb2_quirk_uninit(void *arg)
+{
+	usb2_quirk_unload(arg);
+
+	/* destroy mutex */
+	mtx_destroy(&usb2_quirk_mtx);
+	return;
+}
+
 SYSINIT(usb2_quirk_init, SI_SUB_LOCK, SI_ORDER_FIRST, usb2_quirk_init, NULL);
-SYSUNINIT(usb2_quirk_unload, SI_SUB_LOCK, SI_ORDER_ANY, usb2_quirk_unload, NULL);
+SYSUNINIT(usb2_quirk_uninit, SI_SUB_LOCK, SI_ORDER_ANY, usb2_quirk_uninit, NULL);

==== //depot/projects/usb/src/usr.sbin/usbconfig/dump.c#6 (text+ko) ====

@@ -260,7 +260,8 @@
 			}
 			break;
 		}
-		printf("%s\n", q.quirkname);
+		if (strcmp(q.quirkname, "UQ_NONE"))
+			printf("%s\n", q.quirkname);
 	}
 	printf("\n");
 	return;
@@ -280,17 +281,19 @@
 	for (x = 0; x != 0xFFFF; x++) {
 
 		err = libusb20_be_get_dev_quirk(pbe, x, &q);
-		if (err == LIBUSB20_ERROR_NOT_FOUND) {
-			continue;
-		} else if (err) {
+		if (err) {
 			if (x == 0) {
 				printf("No device quirks - maybe the USB quirk "
 				    "module has not been loaded.\n");
 			}
 			break;
 		}
-		printf("VID=0x%04x PID=0x%04x QUIRK=%s\n",
-		    q.vid, q.pid, q.quirkname);
+		if (strcmp(q.quirkname, "UQ_NONE")) {
+			printf("VID=0x%04x PID=0x%04x REVLO=0x%04x "
+			    "REVHI=0x%04x QUIRK=%s\n",
+			    q.vid, q.pid, q.bcdDeviceLow,
+			    q.bcdDeviceHigh, q.quirkname);
+		}
 	}
 	printf("\n");
 	return;

==== //depot/projects/usb/src/usr.sbin/usbconfig/usbconfig.c#3 (text+ko) ====

@@ -49,6 +49,8 @@
 	uint16_t iface;
 	uint16_t vid;
 	uint16_t pid;
+	uint16_t lo_rev;		/* inclusive */
+	uint16_t hi_rev;		/* inclusive */
 	uint8_t	config_index;
 	uint8_t	alt_index;
 	uint8_t	got_list:1;
@@ -118,8 +120,8 @@
 	{"set_alt", T_SET_ALT, 1},
 	{"set_owner", T_SET_OWNER, 1},
 	{"set_perm", T_SET_PERM, 1},
-	{"add_dev_quirk", T_ADD_DEVICE_QUIRK, 3},
-	{"remove_dev_quirk", T_REMOVE_DEVICE_QUIRK, 3},
+	{"add_dev_quirk_vplh", T_ADD_DEVICE_QUIRK, 5},
+	{"remove_dev_quirk_vplh", T_REMOVE_DEVICE_QUIRK, 5},
 	{"dump_quirk_names", T_DUMP_QUIRK_NAMES, 0},
 	{"dump_device_quirks", T_DUMP_DEVICE_QUIRKS, 0},
 	{"dump_device_desc", T_DUMP_DEVICE_DESC, 0},
@@ -137,7 +139,9 @@
 };
 
 static void
-be_dev_remove_quirk(struct libusb20_backend *pbe, uint16_t vid, uint16_t pid, const char *str)
+be_dev_remove_quirk(struct libusb20_backend *pbe,
+    uint16_t vid, uint16_t pid, uint16_t lorev, uint16_t hirev,
+    const char *str)
 {
 	struct libusb20_quirk q;
 	int err;
@@ -146,6 +150,8 @@
 
 	q.vid = vid;
 	q.pid = pid;
+	q.bcdDeviceLow = lorev;
+	q.bcdDeviceHigh = hirev;
 	strlcpy(q.quirkname, str, sizeof(q.quirkname));
 
 	err = libusb20_be_remove_dev_quirk(pbe, &q);
@@ -156,7 +162,9 @@
 }
 
 static void
-be_dev_add_quirk(struct libusb20_backend *pbe, uint16_t vid, uint16_t pid, const char *str)
+be_dev_add_quirk(struct libusb20_backend *pbe,
+    uint16_t vid, uint16_t pid, uint16_t lorev, uint16_t hirev,
+    const char *str)
 {
 	struct libusb20_quirk q;
 	int err;
@@ -165,6 +173,8 @@
 
 	q.vid = vid;
 	q.pid = pid;
+	q.bcdDeviceLow = lorev;
+	q.bcdDeviceHigh = hirev;
 	strlcpy(q.quirkname, str, sizeof(q.quirkname));
 
 	err = libusb20_be_add_dev_quirk(pbe, &q);
@@ -260,8 +270,8 @@
 	    "  set_alt <altno>" "\n"
 	    "  set_owner <user:group>" "\n"
 	    "  set_perm <mode>" "\n"
-	    "  add_dev_quirk <vid> <pid> <quirk>" "\n"
-	    "  remove_dev_quirk <vid> <pid> <quirk>" "\n"
+	    "  add_dev_quirk_vplh <vid> <pid> <lo_rev> <hi_rev> <quirk>" "\n"
+	    "  remove_dev_quirk_vplh <vid> <pid> <lo_rev> <hi_rev> <quirk>" "\n"
 	    "  dump_quirk_names" "\n"
 	    "  dump_device_quirks" "\n"
 	    "  dump_device_desc" "\n"
@@ -322,11 +332,13 @@
 	}
 	if (opt->got_remove_device_quirk) {
 		opt->got_any--;
-		be_dev_remove_quirk(pbe, opt->vid, opt->pid, opt->quirkname);
+		be_dev_remove_quirk(pbe,
+		    opt->vid, opt->pid, opt->lo_rev, opt->hi_rev, opt->quirkname);
 	}
 	if (opt->got_add_device_quirk) {
 		opt->got_any--;
-		be_dev_add_quirk(pbe, opt->vid, opt->pid, opt->quirkname);
+		be_dev_add_quirk(pbe,
+		    opt->vid, opt->pid, opt->lo_rev, opt->hi_rev, opt->quirkname);
 	}
 	if (opt->got_any == 0) {
 		/*
@@ -519,8 +531,10 @@
 			}
 			opt->vid = num_id(argv[n + 1], "Vendor ID");
 			opt->pid = num_id(argv[n + 2], "Product ID");
-			opt->quirkname = argv[n + 3];
-			n += 3;
+			opt->lo_rev = num_id(argv[n + 3], "Low Revision");
+			opt->hi_rev = num_id(argv[n + 4], "High Revision");
+			opt->quirkname = argv[n + 5];
+			n += 5;
 
 			opt->got_add_device_quirk = 1;
 			opt->got_any++;
@@ -532,9 +546,10 @@
 			}
 			opt->vid = num_id(argv[n + 1], "Vendor ID");
 			opt->pid = num_id(argv[n + 2], "Product ID");
-			opt->quirkname = argv[n + 3];
-			n += 3;
-
+			opt->lo_rev = num_id(argv[n + 3], "Low Revision");
+			opt->hi_rev = num_id(argv[n + 4], "High Revision");
+			opt->quirkname = argv[n + 5];
+			n += 5;
 			opt->got_remove_device_quirk = 1;
 			opt->got_any++;
 			break;



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