Home | History | Annotate | Line # | Download | only in usb
usb_quirks.c revision 1.99
      1 /*	$NetBSD: usb_quirks.c,v 1.99 2021/10/01 21:09:50 macallan Exp $	*/
      2 /*	$FreeBSD: src/sys/dev/usb/usb_quirks.c,v 1.30 2003/01/02 04:15:55 imp Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
      6  * All rights reserved.
      7  *
      8  * This code is derived from software contributed to The NetBSD Foundation
      9  * by Lennart Augustsson (lennart (at) augustsson.net) at
     10  * Carlstedt Research & Technology.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: usb_quirks.c,v 1.99 2021/10/01 21:09:50 macallan Exp $");
     36 
     37 #ifdef _KERNEL_OPT
     38 #include "opt_usb.h"
     39 #endif
     40 
     41 #include <sys/param.h>
     42 #include <sys/systm.h>
     43 
     44 #include <dev/usb/usb.h>
     45 #include <dev/usb/usbdevs.h>
     46 #include <dev/usb/usbdi.h>
     47 #include <dev/usb/usbdivar.h>
     48 #include <dev/usb/usbhist.h>
     49 #include <dev/usb/usb_quirks.h>
     50 
     51 #ifdef USB_DEBUG
     52 extern int usbdebug;
     53 #endif
     54 
     55 #define DPRINTF(FMT,A,B,C,D)    USBHIST_LOG(usbdebug,FMT,A,B,C,D)
     56 
     57 #define ANY 0xffff
     58 #define _USETW(w) { (w) & 0x00ff, ((w) & 0xff00) >> 8 }
     59 
     60 /*
     61  * NXP PN533 NFC chip descriptors
     62  */
     63 static const usb_endpoint_descriptor_t desc_ep_pn533_in = {
     64 	/* bLength */		sizeof(desc_ep_pn533_in),
     65 	/* bDescriptorType */	UDESC_ENDPOINT,
     66 	/* bEndpointAddress */	UE_DIR_IN | 0x04,
     67 	/* bmAttributes */	UE_BULK,
     68 	/* wMaxPacketSize */	_USETW(0x0040),
     69 	/* bInterval */		0x04, /* 255ms */
     70 };
     71 
     72 static const usb_endpoint_descriptor_t desc_ep_pn533_out = {
     73 	/* bLength */		sizeof(desc_ep_pn533_in),
     74 	/* bDescriptorType */	UDESC_ENDPOINT,
     75 	/* bEndpointAddress */	UE_DIR_OUT | 0x04,
     76 	/* bmAttributes */	UE_BULK,
     77 	/* wMaxPacketSize */	_USETW(0x0040),
     78 	/* bInterval */		0x04, /* 255ms */
     79 };
     80 
     81 static const usb_interface_descriptor_t desc_iface_pn533 = {
     82 	/* bLength */		sizeof(desc_iface_pn533),
     83 	/* bDescriptorType */	 UDESC_INTERFACE,
     84 	/* bInterfaceNumber */	 0,
     85 	/* bAlternateSetting */	 0,
     86 	/* bNumEndpoints */	 2,
     87 	/* bInterfaceClass */	 0xff,
     88 	/* bInterfaceSubClass */ 0xff,
     89 	/* bInterfaceProtocol */ 0xff,
     90 	/* iInterface */	 0,
     91 };
     92 
     93 static const usb_config_descriptor_t desc_conf_pn533 = {
     94 	/* bLength */		 sizeof(desc_conf_pn533),
     95 	/* bDescriptorType */	 UDESC_CONFIG,
     96 	/* wTotalLength	 */	 _USETW(sizeof(desc_conf_pn533) +
     97 					sizeof(desc_iface_pn533) +
     98 					sizeof(desc_ep_pn533_in) +
     99 					sizeof(desc_ep_pn533_out)
    100 				 ),
    101 	/* bNumInterface */	 1,
    102 	/* bConfigurationValue */1,
    103 	/* iConfiguration */	 0,
    104 	/* bmAttributes	*/	 UC_ATTR_MBO,
    105 	/* bMaxPower */		 0x32, /* 100mA */
    106 };
    107 
    108 static const usb_descriptor_t *desc_pn533[] = {
    109 	(const usb_descriptor_t *)&desc_conf_pn533,
    110 	(const usb_descriptor_t *)&desc_iface_pn533,
    111 	(const usb_descriptor_t *)&desc_ep_pn533_out,
    112 	(const usb_descriptor_t *)&desc_ep_pn533_in,
    113 	NULL
    114 };
    115 
    116 
    117 usbd_status
    118 usbd_get_desc_fake(struct usbd_device *dev, int type, int index,
    119 		   int len, void *desc)
    120 {
    121 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
    122 #ifdef USB_DEBUG
    123 	const usb_device_descriptor_t *dd = usbd_get_device_descriptor(dev);
    124 #endif
    125 	const usb_descriptor_t *ub;
    126 	int i = 0;
    127 	int j = 0;
    128 	usbd_status err = USBD_INVAL;
    129 
    130 	if (dev->ud_quirks == NULL || dev->ud_quirks->desc == NULL) {
    131 		DPRINTF("%04jx/%04j: no fake descriptors",
    132 		        UGETW(dd->idVendor), UGETW(dd->idProduct), 0, 0);
    133 		goto out;
    134 	}
    135 
    136 	for (j = 0; dev->ud_quirks->desc[j]; j++) {
    137 		ub = dev->ud_quirks->desc[j];
    138 		if (ub->bDescriptorType == type && i++ == index)
    139 			break;
    140 	}
    141 
    142 	if (dev->ud_quirks->desc[j] == NULL) {
    143 		DPRINTF("%04jx/%04jx: no fake descriptor type = %jd, len = %jd",
    144 		       UGETW(dd->idVendor), UGETW(dd->idProduct), type, len);
    145 		goto out;
    146 	}
    147 
    148 	do {
    149 		ub = dev->ud_quirks->desc[j];
    150 
    151 		if (ub->bLength > len) {
    152 			DPRINTF("%04jx/%04jx: short buf len = %jd, bLength = %jd",
    153 			        UGETW(dd->idVendor), UGETW(dd->idProduct),
    154 			        type, ub->bLength);
    155 			goto out;
    156 		}
    157 
    158 		memcpy(desc, ub, ub->bLength);
    159 		DPRINTF("%04jx/%04jx: Use fake descriptor type %jd",
    160 			UGETW(dd->idVendor), UGETW(dd->idProduct),
    161 			type, 0);
    162 
    163 		desc = (char *)desc + ub->bLength;
    164 		len -= ub->bLength;
    165 		j++;
    166 	} while (len && dev->ud_quirks->desc[j] &&
    167 		 dev->ud_quirks->desc[j]->bDescriptorType != type);
    168 
    169 	err = USBD_NORMAL_COMPLETION;
    170 
    171 	DPRINTF("%04jx/%04jx: Using fake USB descriptors\n",
    172 	        UGETW(dd->idVendor), UGETW(dd->idProduct), 0, 0);
    173 out:
    174 	DPRINTF("return err = %jd", err, 0, 0, 0);
    175 	return err;
    176 }
    177 
    178 Static const struct usbd_quirk_entry {
    179 	uint16_t idVendor;
    180 	uint16_t idProduct;
    181 	uint16_t bcdDevice;
    182 	struct usbd_quirks quirks;
    183 } usb_quirks[] = {
    184  /* Devices which should be ignored by uhid */
    185  { USB_VENDOR_APC,		USB_PRODUCT_APC_UPS,			ANY,
    186 	{ UQ_HID_IGNORE, NULL }},
    187  { USB_VENDOR_CYBERPOWER,	USB_PRODUCT_CYBERPOWER_UPS,		ANY,
    188 	{ UQ_HID_IGNORE, NULL }},
    189  { USB_VENDOR_GRETAGMACBETH,	ANY,					ANY,
    190 	{ UQ_HID_IGNORE, NULL }},
    191  { USB_VENDOR_MGE,		USB_PRODUCT_MGE_UPS1,			ANY,
    192 	{ UQ_HID_IGNORE, NULL }},
    193  { USB_VENDOR_MGE,		USB_PRODUCT_MGE_UPS2,			ANY,
    194 	{ UQ_HID_IGNORE, NULL }},
    195  { USB_VENDOR_MICROCHIP,	USB_PRODUCT_MICROCHIP_PICKIT1,		ANY,
    196 	{ UQ_HID_IGNORE, NULL }},
    197  { USB_VENDOR_TRIPPLITE2,	ANY,					ANY,
    198 	{ UQ_HID_IGNORE, NULL }},
    199  { USB_VENDOR_MISC,		USB_PRODUCT_MISC_WISPY_24X,		ANY,
    200 	{ UQ_HID_IGNORE, NULL }},
    201  { USB_VENDOR_WELTREND,	USB_PRODUCT_WELTREND_HID,		ANY,
    202 	{ UQ_HID_IGNORE, NULL }},
    203  { USB_VENDOR_SILABS,		USB_PRODUCT_SILABS_EC3,			ANY,
    204 	{ UQ_HID_IGNORE, NULL }},
    205  { USB_VENDOR_TI,		USB_PRODUCT_TI_MSP430,			ANY,
    206 	{ UQ_HID_IGNORE, NULL }},
    207  { USB_VENDOR_XRITE,		ANY,					ANY,
    208 	{ UQ_HID_IGNORE, NULL }},
    209  { USB_VENDOR_WAYTECH,		USB_PRODUCT_WAYTECH_USB2SERIAL,		ANY,
    210 	{ UQ_HID_IGNORE, NULL }},
    211  { USB_VENDOR_KYE,		USB_PRODUCT_KYE_NICHE,			0x100,
    212 	{ UQ_NO_SET_PROTO, NULL }},
    213  { USB_VENDOR_INSIDEOUT,	USB_PRODUCT_INSIDEOUT_EDGEPORT4,	0x094,
    214 	{ UQ_SWAP_UNICODE, NULL }},
    215  { USB_VENDOR_DALLAS,		USB_PRODUCT_DALLAS_J6502,		0x0a2,
    216 	{ UQ_BAD_ADC, NULL }},
    217  { USB_VENDOR_DALLAS,		USB_PRODUCT_DALLAS_J6502,		0x0a2,
    218 	{ UQ_AU_NO_XU, NULL }},
    219  { USB_VENDOR_ALTEC,		USB_PRODUCT_ALTEC_ADA70,		0x103,
    220 	{ UQ_BAD_ADC, NULL }},
    221  { USB_VENDOR_ALTEC,		USB_PRODUCT_ALTEC_ASC495,		0x000,
    222 	{ UQ_BAD_AUDIO, NULL }},
    223  { USB_VENDOR_SONY,		USB_PRODUCT_SONY_PS2EYETOY4,		0x000,
    224 	{ UQ_BAD_AUDIO, NULL }},
    225  { USB_VENDOR_SONY,		USB_PRODUCT_SONY_PS2EYETOY5,		0x000,
    226 	{ UQ_BAD_AUDIO, NULL }},
    227  { USB_VENDOR_PHILIPS,		USB_PRODUCT_PHILIPS_PCVC740K,		ANY,
    228 	{ UQ_BAD_AUDIO, NULL }},
    229  { USB_VENDOR_LOGITECH,		USB_PRODUCT_LOGITECH_QUICKCAMPRONB,	0x000,
    230 	{ UQ_BAD_AUDIO, NULL }},
    231  { USB_VENDOR_LOGITECH,		USB_PRODUCT_LOGITECH_QUICKCAMPRO4K,	0x000,
    232 	{ UQ_BAD_AUDIO, NULL }},
    233  { USB_VENDOR_LOGITECH,		USB_PRODUCT_LOGITECH_QUICKCAMMESS,	0x100,
    234 	{ UQ_BAD_ADC, NULL }},
    235  { USB_VENDOR_QTRONIX,		USB_PRODUCT_QTRONIX_980N,		0x110,
    236 	{ UQ_SPUR_BUT_UP, NULL }},
    237  { USB_VENDOR_ALCOR2,		USB_PRODUCT_ALCOR2_KBD_HUB,		0x001,
    238 	{ UQ_SPUR_BUT_UP, NULL }},
    239  { USB_VENDOR_METRICOM,		USB_PRODUCT_METRICOM_RICOCHET_GS,	0x100,
    240 	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
    241  { USB_VENDOR_SANYO,		USB_PRODUCT_SANYO_SCP4900,		0x000,
    242 	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
    243  { USB_VENDOR_MOTOROLA2,	USB_PRODUCT_MOTOROLA2_T720C,		0x001,
    244 	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
    245  { USB_VENDOR_EICON,		USB_PRODUCT_EICON_DIVA852,		0x100,
    246 	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
    247  { USB_VENDOR_SIEMENS2,		USB_PRODUCT_SIEMENS2_MC75,		0x000,
    248 	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
    249  { USB_VENDOR_TELEX,		USB_PRODUCT_TELEX_MIC1,			0x009,
    250 	{ UQ_AU_NO_FRAC, NULL }},
    251  { USB_VENDOR_SILICONPORTALS,	USB_PRODUCT_SILICONPORTALS_YAPPHONE,	0x100,
    252 	{ UQ_AU_INP_ASYNC, NULL }},
    253  { USB_VENDOR_AVANCELOGIC,	USB_PRODUCT_AVANCELOGIC_USBAUDIO,	0x101,
    254 	{ UQ_AU_INP_ASYNC, NULL }},
    255  { USB_VENDOR_PLANTRONICS,	USB_PRODUCT_PLANTRONICS_HEADSET,	0x004,
    256 	{ UQ_AU_INP_ASYNC, NULL }},
    257  { USB_VENDOR_CMEDIA,		USB_PRODUCT_CMEDIA_USBAUDIO,		ANY,
    258 	{ UQ_AU_INP_ASYNC, NULL }},
    259 
    260  /* XXX These should have a revision number, but I don't know what they are. */
    261  { USB_VENDOR_HP,		USB_PRODUCT_HP_895C,			ANY,
    262 	{ UQ_BROKEN_BIDIR, NULL }},
    263  { USB_VENDOR_HP,		USB_PRODUCT_HP_880C,			ANY,
    264 	{ UQ_BROKEN_BIDIR, NULL }},
    265  { USB_VENDOR_HP,		USB_PRODUCT_HP_815C,			ANY,
    266 	{ UQ_BROKEN_BIDIR, NULL }},
    267  { USB_VENDOR_HP,		USB_PRODUCT_HP_810C,			ANY,
    268 	{ UQ_BROKEN_BIDIR, NULL }},
    269  { USB_VENDOR_HP,		USB_PRODUCT_HP_830C,			ANY,
    270 	{ UQ_BROKEN_BIDIR, NULL }},
    271  { USB_VENDOR_HP,		USB_PRODUCT_HP_885C,			ANY,
    272 	{ UQ_BROKEN_BIDIR, NULL }},
    273  { USB_VENDOR_HP,		USB_PRODUCT_HP_840C,			ANY,
    274 	{ UQ_BROKEN_BIDIR, NULL }},
    275  { USB_VENDOR_HP,		USB_PRODUCT_HP_816C,			ANY,
    276 	{ UQ_BROKEN_BIDIR, NULL }},
    277  { USB_VENDOR_HP,		USB_PRODUCT_HP_959C,			ANY,
    278 	{ UQ_BROKEN_BIDIR, NULL }},
    279  { USB_VENDOR_MTK,		USB_PRODUCT_MTK_GPS_RECEIVER,		ANY,
    280 	{ UQ_NO_UNION_NRM, NULL }},
    281  { USB_VENDOR_NEC,		USB_PRODUCT_NEC_PICTY900,		ANY,
    282 	{ UQ_BROKEN_BIDIR, NULL }},
    283  { USB_VENDOR_NEC,		USB_PRODUCT_NEC_PICTY760,		ANY,
    284 	{ UQ_BROKEN_BIDIR, NULL }},
    285  { USB_VENDOR_NEC,		USB_PRODUCT_NEC_PICTY920,		ANY,
    286 	{ UQ_BROKEN_BIDIR, NULL }},
    287  { USB_VENDOR_NEC,		USB_PRODUCT_NEC_PICTY800,		ANY,
    288 	{ UQ_BROKEN_BIDIR, NULL }},
    289  { USB_VENDOR_HP,		USB_PRODUCT_HP_1220C,			ANY,
    290 	{ UQ_BROKEN_BIDIR, NULL }},
    291 
    292  /* Apple internal notebook ISO keyboards have swapped keys */
    293  { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_FOUNTAIN_ISO,		ANY,
    294 	{ UQ_APPLE_ISO, NULL }},
    295  { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_GEYSER_ISO,		ANY,
    296 	{ UQ_APPLE_ISO, NULL }},
    297 
    298  /* HID and audio are both invalid on iPhone/iPod Touch */
    299  { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_IPHONE,		ANY,
    300 	{ UQ_HID_IGNORE | UQ_BAD_AUDIO, NULL }},
    301  { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_IPOD_TOUCH,		ANY,
    302 	{ UQ_HID_IGNORE | UQ_BAD_AUDIO, NULL }},
    303  { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_IPOD_TOUCH_4G,	ANY,
    304 	{ UQ_HID_IGNORE | UQ_BAD_AUDIO, NULL }},
    305  { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_IPHONE_3G,		ANY,
    306 	{ UQ_HID_IGNORE | UQ_BAD_AUDIO, NULL }},
    307  { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_IPHONE_3GS,		ANY,
    308 	{ UQ_HID_IGNORE | UQ_BAD_AUDIO, NULL }},
    309 
    310  /*
    311   * Various devices using serial boot loader protocol, as supported
    312   * by pkgsrc/sysutils/imx_usb_loader
    313   */
    314  { 0x066f,			0x3780,		/* mx23 */		ANY,
    315 	{ UQ_HID_IGNORE, NULL }},
    316  { 0x15a2,			0x004f,		/* mx28 */		ANY,
    317 	{ UQ_HID_IGNORE, NULL }},
    318  { 0x15a2,			0x0052,		/* mx50 */		ANY,
    319 	{ UQ_HID_IGNORE, NULL }},
    320  { 0x15a2,			0x0054,		/* mx6 */		ANY,
    321 	{ UQ_HID_IGNORE, NULL }},
    322  { 0x15a2,			0x0061,		/* mx6 */		ANY,
    323 	{ UQ_HID_IGNORE, NULL }},
    324  { 0x15a2,			0x0063,		/* mx6 */		ANY,
    325 	{ UQ_HID_IGNORE, NULL }},
    326  { 0x15a2,			0x0071,		/* mx6 */		ANY,
    327 	{ UQ_HID_IGNORE, NULL }},
    328  { 0x15a2,			0x007d,		/* mx6 */		ANY,
    329 	{ UQ_HID_IGNORE, NULL }},
    330  { 0x15a2,			0x0080,		/* mx6ull */		ANY,
    331 	{ UQ_HID_IGNORE, NULL }},
    332  { 0x1fc9,			0x0128,		/* mx6 */		ANY,
    333 	{ UQ_HID_IGNORE, NULL }},
    334  { 0x15a2,			0x0076,		/* mx7 */		ANY,
    335 	{ UQ_HID_IGNORE, NULL }},
    336  { 0x1fc9,			0x0126,		/* mx7ulp */		ANY,
    337 	{ UQ_HID_IGNORE, NULL }},
    338  { 0x15a2,			0x0041,		/* mx51 */		ANY,
    339 	{ UQ_HID_IGNORE, NULL }},
    340  { 0x15a2,			0x004e,		/* mx53 */		ANY,
    341 	{ UQ_HID_IGNORE, NULL }},
    342  { 0x15a2,			0x006a,		/* vybrid */		ANY,
    343 	{ UQ_HID_IGNORE, NULL }},
    344  { 0x066f,			0x37ff,		/* linux_gadget */	ANY,
    345 	{ UQ_HID_IGNORE, NULL }},
    346  { 0x1b67,			0x4fff,		/* mx6 */		ANY,
    347 	{ UQ_HID_IGNORE, NULL }},
    348  { 0x0525,			0xb4a4,		/* mx6 */		ANY,
    349 	{ UQ_HID_IGNORE, NULL }},
    350  { 0x1fc9,			0x012b,		/* mx8mq */		ANY,
    351 	{ UQ_HID_IGNORE, NULL }},
    352  { 0x1fc9,			0x0134,		/* mx8mm */		ANY,
    353 	{ UQ_HID_IGNORE, NULL }},
    354  { 0x1fc9,			0x013e,		/* mx8mn */		ANY,
    355 	{ UQ_HID_IGNORE, NULL }},
    356  { 0x3016,			0x1001, 	/* mx8mn */		ANY,
    357 	{ UQ_HID_IGNORE, NULL }},
    358 
    359  { USB_VENDOR_LG,		USB_PRODUCT_LG_CDMA_MSM,		ANY,
    360 	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
    361  { USB_VENDOR_QUALCOMM2,	USB_PRODUCT_QUALCOMM2_CDMA_MSM,		ANY,
    362 	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
    363  { USB_VENDOR_HYUNDAI,		USB_PRODUCT_HYUNDAI_UM175,		ANY,
    364 	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
    365  { USB_VENDOR_ZOOM,		USB_PRODUCT_ZOOM_3095,			ANY,
    366 	{ UQ_LOST_CS_DESC, NULL }},
    367 
    368  /*
    369   * NXP PN533 bugs
    370   *
    371   * 1. It corrupts its USB descriptors. The quirk is to provide hardcoded
    372   *    descriptors instead of getting them from the device.
    373   * 2. It mishandles the USB toggle bit. This causes some replies to be
    374   *    filered out by the USB host controller and be reported as timed out.
    375   *    NFC tool's libnfc workaround this bug by sending a dummy frame to
    376   *    resync the toggle bit, but in order to succeed, that operation must
    377   *    not be reported as failed. The quirk is therefore to pretend to
    378   *    userland that output timeouts are successes.
    379   */
    380  { USB_VENDOR_PHILIPSSEMI,	USB_PRODUCT_PHILIPSSEMI_PN533,		ANY,
    381 	{ UQ_DESC_CORRUPT | UQ_MISS_OUT_ACK, desc_pn533 }},
    382  { USB_VENDOR_SHUTTLE,		USB_PRODUCT_SHUTTLE_SCL3711,		ANY,
    383 	{ UQ_DESC_CORRUPT | UQ_MISS_OUT_ACK, desc_pn533 }},
    384  { USB_VENDOR_SHUTTLE,		USB_PRODUCT_SHUTTLE_SCL3712,		ANY,
    385 	{ UQ_DESC_CORRUPT | UQ_MISS_OUT_ACK, desc_pn533 }},
    386 
    387 /*
    388  * These cheap mice will disconnect after 60 seconds,
    389  * reconnect, and then disconnect again (ad nauseum)
    390  * unless it's kept open.
    391  */
    392  { USB_VENDOR_CHICONY,		USB_PRODUCT_CHICONY_OPTMOUSE0939,	ANY,
    393 	{ UQ_ALWAYS_ON, NULL }},
    394  { USB_VENDOR_PIXART,		USB_PRODUCT_PIXART_RPIMOUSE,		ANY,
    395 	{ UQ_ALWAYS_ON, NULL }},
    396 /*
    397  * The HAILUCK USB Keyboard has a built-in touchpad, which
    398  * needs to be active for the keyboard to function properly.
    399  */
    400  { USB_VENDOR_HAILUCK,		USB_PRODUCT_HAILUCK_KEYBOARD,		ANY,
    401 	{ UQ_ALWAYS_ON, NULL }},
    402 
    403  { 0, 0, 0, { 0, NULL } }
    404 };
    405 
    406 const struct usbd_quirks usbd_no_quirk = { 0 };
    407 
    408 const struct usbd_quirks *
    409 usbd_find_quirk(usb_device_descriptor_t *d)
    410 {
    411 	const struct usbd_quirk_entry *t;
    412 	uint16_t vendor = UGETW(d->idVendor);
    413 	uint16_t product = UGETW(d->idProduct);
    414 	uint16_t revision = UGETW(d->bcdDevice);
    415 
    416 	for (t = usb_quirks; t->idVendor != 0; t++) {
    417 		if (t->idVendor == vendor &&
    418 		    (t->idProduct == ANY || t->idProduct == product) &&
    419 		    (t->bcdDevice == ANY || t->bcdDevice == revision))
    420 			break;
    421 	}
    422 #ifdef USB_DEBUG
    423 	if (usbdebug && t->quirks.uq_flags)
    424 		printf("usbd_find_quirk 0x%04x/0x%04x/%x: %d\n",
    425 			  UGETW(d->idVendor), UGETW(d->idProduct),
    426 			  UGETW(d->bcdDevice), t->quirks.uq_flags);
    427 #endif
    428 	return &t->quirks;
    429 }
    430