1/*	$NetBSD: usb_quirks.c,v 1.108 2024/02/28 21:52:40 dholland 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@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.108 2024/02/28 21:52:40 dholland 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#define DPRINTF(FMT,A,B,C,D)    USBHIST_LOG(usbdebug,FMT,A,B,C,D)
52
53#define ANY 0xffff
54#define _USETW(w) { (w) & 0x00ff, ((w) & 0xff00) >> 8 }
55
56/*
57 * NXP PN533 NFC chip descriptors
58 */
59static const usb_endpoint_descriptor_t desc_ep_pn533_in = {
60	/* bLength */		sizeof(desc_ep_pn533_in),
61	/* bDescriptorType */	UDESC_ENDPOINT,
62	/* bEndpointAddress */	UE_DIR_IN | 0x04,
63	/* bmAttributes */	UE_BULK,
64	/* wMaxPacketSize */	_USETW(0x0040),
65	/* bInterval */		0x04, /* 255ms */
66};
67
68static const usb_endpoint_descriptor_t desc_ep_pn533_out = {
69	/* bLength */		sizeof(desc_ep_pn533_in),
70	/* bDescriptorType */	UDESC_ENDPOINT,
71	/* bEndpointAddress */	UE_DIR_OUT | 0x04,
72	/* bmAttributes */	UE_BULK,
73	/* wMaxPacketSize */	_USETW(0x0040),
74	/* bInterval */		0x04, /* 255ms */
75};
76
77static const usb_interface_descriptor_t desc_iface_pn533 = {
78	/* bLength */		sizeof(desc_iface_pn533),
79	/* bDescriptorType */	 UDESC_INTERFACE,
80	/* bInterfaceNumber */	 0,
81	/* bAlternateSetting */	 0,
82	/* bNumEndpoints */	 2,
83	/* bInterfaceClass */	 0xff,
84	/* bInterfaceSubClass */ 0xff,
85	/* bInterfaceProtocol */ 0xff,
86	/* iInterface */	 0,
87};
88
89static const usb_config_descriptor_t desc_conf_pn533 = {
90	/* bLength */		 sizeof(desc_conf_pn533),
91	/* bDescriptorType */	 UDESC_CONFIG,
92	/* wTotalLength	 */	 _USETW(sizeof(desc_conf_pn533) +
93					sizeof(desc_iface_pn533) +
94					sizeof(desc_ep_pn533_in) +
95					sizeof(desc_ep_pn533_out)
96				 ),
97	/* bNumInterface */	 1,
98	/* bConfigurationValue */1,
99	/* iConfiguration */	 0,
100	/* bmAttributes	*/	 UC_ATTR_MBO,
101	/* bMaxPower */		 0x32, /* 100mA */
102};
103
104static const usb_descriptor_t *desc_pn533[] = {
105	(const usb_descriptor_t *)&desc_conf_pn533,
106	(const usb_descriptor_t *)&desc_iface_pn533,
107	(const usb_descriptor_t *)&desc_ep_pn533_out,
108	(const usb_descriptor_t *)&desc_ep_pn533_in,
109	NULL
110};
111
112
113usbd_status
114usbd_get_desc_fake(struct usbd_device *dev, int type, int index,
115		   int len, void *desc)
116{
117	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
118#ifdef USB_DEBUG
119	const usb_device_descriptor_t *dd = usbd_get_device_descriptor(dev);
120#endif
121	const usb_descriptor_t *ub;
122	int i = 0;
123	int j = 0;
124	usbd_status err = USBD_INVAL;
125
126	if (dev->ud_quirks == NULL || dev->ud_quirks->desc == NULL) {
127		DPRINTF("%04jx/%04j: no fake descriptors",
128		        UGETW(dd->idVendor), UGETW(dd->idProduct), 0, 0);
129		goto out;
130	}
131
132	for (j = 0; dev->ud_quirks->desc[j]; j++) {
133		ub = dev->ud_quirks->desc[j];
134		if (ub->bDescriptorType == type && i++ == index)
135			break;
136	}
137
138	if (dev->ud_quirks->desc[j] == NULL) {
139		DPRINTF("%04jx/%04jx: no fake descriptor type = %jd, len = %jd",
140		       UGETW(dd->idVendor), UGETW(dd->idProduct), type, len);
141		goto out;
142	}
143
144	do {
145		ub = dev->ud_quirks->desc[j];
146
147		if (ub->bLength > len) {
148			DPRINTF("%04jx/%04jx: short buf len = %jd, bLength = %jd",
149			        UGETW(dd->idVendor), UGETW(dd->idProduct),
150			        type, ub->bLength);
151			goto out;
152		}
153
154		memcpy(desc, ub, ub->bLength);
155		DPRINTF("%04jx/%04jx: Use fake descriptor type %jd",
156			UGETW(dd->idVendor), UGETW(dd->idProduct),
157			type, 0);
158
159		desc = (char *)desc + ub->bLength;
160		len -= ub->bLength;
161		j++;
162	} while (len && dev->ud_quirks->desc[j] &&
163		 dev->ud_quirks->desc[j]->bDescriptorType != type);
164
165	err = USBD_NORMAL_COMPLETION;
166
167	DPRINTF("%04jx/%04jx: Using fake USB descriptors\n",
168	        UGETW(dd->idVendor), UGETW(dd->idProduct), 0, 0);
169out:
170	DPRINTF("return err = %jd", err, 0, 0, 0);
171	return err;
172}
173
174Static const struct usbd_quirk_entry {
175	uint16_t idVendor;
176	uint16_t idProduct;
177	uint16_t bcdDevice;
178	struct usbd_quirks quirks;
179} usb_quirks[] = {
180 /* Devices which should be ignored by uhid */
181 { USB_VENDOR_APC,		USB_PRODUCT_APC_UPS,			ANY,
182	{ UQ_HID_IGNORE, NULL }},
183 { USB_VENDOR_APC,		USB_PRODUCT_APC_UPS3,			ANY,
184	{ UQ_HID_IGNORE, NULL }},
185 { USB_VENDOR_CYBERPOWER,	USB_PRODUCT_CYBERPOWER_UPS0,		ANY,
186	{ UQ_HID_IGNORE, NULL }},
187 { USB_VENDOR_CYBERPOWER,	USB_PRODUCT_CYBERPOWER_UPS,		ANY,
188	{ UQ_HID_IGNORE, NULL }},
189 { USB_VENDOR_CYBERPOWER,	USB_PRODUCT_CYBERPOWER_UPS2,		ANY,
190	{ UQ_HID_IGNORE, NULL }},
191 { USB_VENDOR_GRETAGMACBETH,	ANY,					ANY,
192	{ UQ_HID_IGNORE, NULL }},
193 { USB_VENDOR_MGE,		USB_PRODUCT_MGE_UPS1,			ANY,
194	{ UQ_HID_IGNORE, NULL }},
195 { USB_VENDOR_MGE,		USB_PRODUCT_MGE_UPS2,			ANY,
196	{ UQ_HID_IGNORE, NULL }},
197 { USB_VENDOR_MICROCHIP,	USB_PRODUCT_MICROCHIP_PICKIT1,		ANY,
198	{ UQ_HID_IGNORE, NULL }},
199 { USB_VENDOR_MICROCHIP,	USB_PRODUCT_MICROCHIP_PICKIT2,		ANY,
200	{ UQ_HID_IGNORE, NULL }},
201 { USB_VENDOR_MICROCHIP,	USB_PRODUCT_MICROCHIP_PICKIT3,		ANY,
202	{ UQ_HID_IGNORE, NULL }},
203 { USB_VENDOR_TRIPPLITE2,	ANY,					ANY,
204	{ UQ_HID_IGNORE, NULL }},
205 { USB_VENDOR_MISC,		USB_PRODUCT_MISC_WISPY_24X,		ANY,
206	{ UQ_HID_IGNORE, NULL }},
207 { USB_VENDOR_WELTREND,	USB_PRODUCT_WELTREND_HID,		ANY,
208	{ UQ_HID_IGNORE, NULL }},
209 { USB_VENDOR_SILABS,		USB_PRODUCT_SILABS_EC3,			ANY,
210	{ UQ_HID_IGNORE, NULL }},
211 { USB_VENDOR_TI,		USB_PRODUCT_TI_MSP430,			ANY,
212	{ UQ_HID_IGNORE, NULL }},
213 { USB_VENDOR_XRITE,		ANY,					ANY,
214	{ UQ_HID_IGNORE, NULL }},
215 { USB_VENDOR_WAYTECH,		USB_PRODUCT_WAYTECH_USB2SERIAL,		ANY,
216	{ UQ_HID_IGNORE, NULL }},
217 { USB_VENDOR_KYE,		USB_PRODUCT_KYE_NICHE,			0x100,
218	{ UQ_NO_SET_PROTO, NULL }},
219 { USB_VENDOR_INSIDEOUT,	USB_PRODUCT_INSIDEOUT_EDGEPORT4,	0x094,
220	{ UQ_SWAP_UNICODE, NULL }},
221 { USB_VENDOR_DALLAS,		USB_PRODUCT_DALLAS_J6502,		0x0a2,
222	{ UQ_BAD_ADC, NULL }},
223 { USB_VENDOR_DALLAS,		USB_PRODUCT_DALLAS_J6502,		0x0a2,
224	{ UQ_AU_NO_XU, NULL }},
225 { USB_VENDOR_ALTEC,		USB_PRODUCT_ALTEC_ADA70,		0x103,
226	{ UQ_BAD_ADC, NULL }},
227 { USB_VENDOR_ALTEC,		USB_PRODUCT_ALTEC_ASC495,		0x000,
228	{ UQ_BAD_AUDIO, NULL }},
229 { USB_VENDOR_SONY,		USB_PRODUCT_SONY_PS2EYETOY4,		0x000,
230	{ UQ_BAD_AUDIO, NULL }},
231 { USB_VENDOR_SONY,		USB_PRODUCT_SONY_PS2EYETOY5,		0x000,
232	{ UQ_BAD_AUDIO, NULL }},
233 { USB_VENDOR_PHILIPS,		USB_PRODUCT_PHILIPS_PCVC740K,		ANY,
234	{ UQ_BAD_AUDIO, NULL }},
235 { USB_VENDOR_LOGITECH,		USB_PRODUCT_LOGITECH_QUICKCAMPRONB,	0x000,
236	{ UQ_BAD_AUDIO, NULL }},
237 { USB_VENDOR_LOGITECH,		USB_PRODUCT_LOGITECH_QUICKCAMPRO4K,	0x000,
238	{ UQ_BAD_AUDIO, NULL }},
239 { USB_VENDOR_LOGITECH,		USB_PRODUCT_LOGITECH_QUICKCAMMESS,	0x100,
240	{ UQ_BAD_ADC, NULL }},
241 { USB_VENDOR_QTRONIX,		USB_PRODUCT_QTRONIX_980N,		0x110,
242	{ UQ_SPUR_BUT_UP, NULL }},
243 { USB_VENDOR_ALCOR2,		USB_PRODUCT_ALCOR2_KBD_HUB,		0x001,
244	{ UQ_SPUR_BUT_UP, NULL }},
245 { USB_VENDOR_METRICOM,		USB_PRODUCT_METRICOM_RICOCHET_GS,	0x100,
246	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
247 { USB_VENDOR_SANYO,		USB_PRODUCT_SANYO_SCP4900,		0x000,
248	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
249 { USB_VENDOR_MOTOROLA2,	USB_PRODUCT_MOTOROLA2_T720C,		0x001,
250	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
251 { USB_VENDOR_EICON,		USB_PRODUCT_EICON_DIVA852,		0x100,
252	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
253 { USB_VENDOR_SIEMENS2,		USB_PRODUCT_SIEMENS2_MC75,		0x000,
254	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
255 { USB_VENDOR_TELEX,		USB_PRODUCT_TELEX_MIC1,			0x009,
256	{ UQ_AU_NO_FRAC, NULL }},
257 { USB_VENDOR_SILICONPORTALS,	USB_PRODUCT_SILICONPORTALS_YAPPHONE,	0x100,
258	{ UQ_AU_INP_ASYNC, NULL }},
259 { USB_VENDOR_AVANCELOGIC,	USB_PRODUCT_AVANCELOGIC_USBAUDIO,	0x101,
260	{ UQ_AU_INP_ASYNC, NULL }},
261 { USB_VENDOR_PLANTRONICS,	USB_PRODUCT_PLANTRONICS_HEADSET,	0x004,
262	{ UQ_AU_INP_ASYNC, NULL }},
263 { USB_VENDOR_CMEDIA,		USB_PRODUCT_CMEDIA_USBAUDIO,		ANY,
264	{ UQ_AU_INP_ASYNC, NULL }},
265
266 /* XXX These should have a revision number, but I don't know what they are. */
267 { USB_VENDOR_HP,		USB_PRODUCT_HP_895C,			ANY,
268	{ UQ_BROKEN_BIDIR, NULL }},
269 { USB_VENDOR_HP,		USB_PRODUCT_HP_880C,			ANY,
270	{ UQ_BROKEN_BIDIR, NULL }},
271 { USB_VENDOR_HP,		USB_PRODUCT_HP_815C,			ANY,
272	{ UQ_BROKEN_BIDIR, NULL }},
273 { USB_VENDOR_HP,		USB_PRODUCT_HP_810C,			ANY,
274	{ UQ_BROKEN_BIDIR, NULL }},
275 { USB_VENDOR_HP,		USB_PRODUCT_HP_830C,			ANY,
276	{ UQ_BROKEN_BIDIR, NULL }},
277 { USB_VENDOR_HP,		USB_PRODUCT_HP_885C,			ANY,
278	{ UQ_BROKEN_BIDIR, NULL }},
279 { USB_VENDOR_HP,		USB_PRODUCT_HP_840C,			ANY,
280	{ UQ_BROKEN_BIDIR, NULL }},
281 { USB_VENDOR_HP,		USB_PRODUCT_HP_816C,			ANY,
282	{ UQ_BROKEN_BIDIR, NULL }},
283 { USB_VENDOR_HP,		USB_PRODUCT_HP_959C,			ANY,
284	{ UQ_BROKEN_BIDIR, NULL }},
285 { USB_VENDOR_MTK,		USB_PRODUCT_MTK_GPS_RECEIVER,		ANY,
286	{ UQ_NO_UNION_NRM, NULL }},
287 { USB_VENDOR_NEC,		USB_PRODUCT_NEC_PICTY900,		ANY,
288	{ UQ_BROKEN_BIDIR, NULL }},
289 { USB_VENDOR_NEC,		USB_PRODUCT_NEC_PICTY760,		ANY,
290	{ UQ_BROKEN_BIDIR, NULL }},
291 { USB_VENDOR_NEC,		USB_PRODUCT_NEC_PICTY920,		ANY,
292	{ UQ_BROKEN_BIDIR, NULL }},
293 { USB_VENDOR_NEC,		USB_PRODUCT_NEC_PICTY800,		ANY,
294	{ UQ_BROKEN_BIDIR, NULL }},
295 { USB_VENDOR_HP,		USB_PRODUCT_HP_1220C,			ANY,
296	{ UQ_BROKEN_BIDIR, NULL }},
297
298 /* Apple internal notebook ISO keyboards have swapped keys */
299 { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_FOUNTAIN_ISO,		ANY,
300	{ UQ_APPLE_ISO, NULL }},
301 { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_GEYSER_ISO,		ANY,
302	{ UQ_APPLE_ISO, NULL }},
303
304 /* HID and audio are both invalid on iPhone/iPod Touch */
305 { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_IPHONE,		ANY,
306	{ UQ_HID_IGNORE | UQ_BAD_AUDIO, NULL }},
307 { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_IPOD_TOUCH,		ANY,
308	{ UQ_HID_IGNORE | UQ_BAD_AUDIO, NULL }},
309 { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_IPOD_TOUCH_4G,	ANY,
310	{ UQ_HID_IGNORE | UQ_BAD_AUDIO, NULL }},
311 { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_IPHONE_3G,		ANY,
312	{ UQ_HID_IGNORE | UQ_BAD_AUDIO, NULL }},
313 { USB_VENDOR_APPLE,		USB_PRODUCT_APPLE_IPHONE_3GS,		ANY,
314	{ UQ_HID_IGNORE | UQ_BAD_AUDIO, NULL }},
315
316 /*
317  * Various devices using serial boot loader protocol, as supported
318  * by pkgsrc/sysutils/imx_usb_loader
319  */
320 { 0x066f,			0x3780,		/* mx23 */		ANY,
321	{ UQ_HID_IGNORE, NULL }},
322 { 0x15a2,			0x004f,		/* mx28 */		ANY,
323	{ UQ_HID_IGNORE, NULL }},
324 { 0x15a2,			0x0052,		/* mx50 */		ANY,
325	{ UQ_HID_IGNORE, NULL }},
326 { 0x15a2,			0x0054,		/* mx6 */		ANY,
327	{ UQ_HID_IGNORE, NULL }},
328 { 0x15a2,			0x0061,		/* mx6 */		ANY,
329	{ UQ_HID_IGNORE, NULL }},
330 { 0x15a2,			0x0063,		/* mx6 */		ANY,
331	{ UQ_HID_IGNORE, NULL }},
332 { 0x15a2,			0x0071,		/* mx6 */		ANY,
333	{ UQ_HID_IGNORE, NULL }},
334 { 0x15a2,			0x007d,		/* mx6 */		ANY,
335	{ UQ_HID_IGNORE, NULL }},
336 { 0x15a2,			0x0080,		/* mx6ull */		ANY,
337	{ UQ_HID_IGNORE, NULL }},
338 { 0x1fc9,			0x0128,		/* mx6 */		ANY,
339	{ UQ_HID_IGNORE, NULL }},
340 { 0x15a2,			0x0076,		/* mx7 */		ANY,
341	{ UQ_HID_IGNORE, NULL }},
342 { 0x1fc9,			0x0126,		/* mx7ulp */		ANY,
343	{ UQ_HID_IGNORE, NULL }},
344 { 0x15a2,			0x0041,		/* mx51 */		ANY,
345	{ UQ_HID_IGNORE, NULL }},
346 { 0x15a2,			0x004e,		/* mx53 */		ANY,
347	{ UQ_HID_IGNORE, NULL }},
348 { 0x15a2,			0x006a,		/* vybrid */		ANY,
349	{ UQ_HID_IGNORE, NULL }},
350 { 0x066f,			0x37ff,		/* linux_gadget */	ANY,
351	{ UQ_HID_IGNORE, NULL }},
352 { 0x1b67,			0x4fff,		/* mx6 */		ANY,
353	{ UQ_HID_IGNORE, NULL }},
354 { 0x0525,			0xb4a4,		/* mx6 */		ANY,
355	{ UQ_HID_IGNORE, NULL }},
356 { 0x1fc9,			0x012b,		/* mx8mq */		ANY,
357	{ UQ_HID_IGNORE, NULL }},
358 { 0x1fc9,			0x0134,		/* mx8mm */		ANY,
359	{ UQ_HID_IGNORE, NULL }},
360 { 0x1fc9,			0x013e,		/* mx8mn */		ANY,
361	{ UQ_HID_IGNORE, NULL }},
362 { 0x3016,			0x1001, 	/* mx8mn */		ANY,
363	{ UQ_HID_IGNORE, NULL }},
364
365 { USB_VENDOR_LG,		USB_PRODUCT_LG_CDMA_MSM,		ANY,
366	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
367 { USB_VENDOR_QUALCOMM2,	USB_PRODUCT_QUALCOMM2_CDMA_MSM,		ANY,
368	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
369 { USB_VENDOR_HYUNDAI,		USB_PRODUCT_HYUNDAI_UM175,		ANY,
370	{ UQ_ASSUME_CM_OVER_DATA, NULL }},
371 { USB_VENDOR_ZOOM,		USB_PRODUCT_ZOOM_3095,			ANY,
372	{ UQ_LOST_CS_DESC, NULL }},
373
374 /*
375  * NXP PN533 bugs
376  *
377  * 1. It corrupts its USB descriptors. The quirk is to provide hardcoded
378  *    descriptors instead of getting them from the device.
379  * 2. It mishandles the USB toggle bit. This causes some replies to be
380  *    filtered out by the USB host controller and be reported as timed out.
381  *    NFC tool's libnfc workaround this bug by sending a dummy frame to
382  *    resync the toggle bit, but in order to succeed, that operation must
383  *    not be reported as failed. The quirk is therefore to pretend to
384  *    userland that output timeouts are successes.
385  */
386 { USB_VENDOR_PHILIPSSEMI,	USB_PRODUCT_PHILIPSSEMI_PN533,		ANY,
387	{ UQ_DESC_CORRUPT | UQ_MISS_OUT_ACK, desc_pn533 }},
388 { USB_VENDOR_SHUTTLE,		USB_PRODUCT_SHUTTLE_SCL3711,		ANY,
389	{ UQ_DESC_CORRUPT | UQ_MISS_OUT_ACK, desc_pn533 }},
390 { USB_VENDOR_SHUTTLE,		USB_PRODUCT_SHUTTLE_SCL3712,		ANY,
391	{ UQ_DESC_CORRUPT | UQ_MISS_OUT_ACK, desc_pn533 }},
392
393/*
394 * These cheap mice will disconnect after 60 seconds,
395 * reconnect, and then disconnect again (ad nauseum)
396 * unless it's kept open.
397 */
398 { USB_VENDOR_CHICONY,		USB_PRODUCT_CHICONY_OPTMOUSE0939,	ANY,
399	{ UQ_ALWAYS_ON, NULL }},
400 { USB_VENDOR_PIXART,		USB_PRODUCT_PIXART_RPIMOUSE,		ANY,
401	{ UQ_ALWAYS_ON, NULL }},
402 { USB_VENDOR_LOGITECH, 	USB_PRODUCT_LOGITECH_B100_1,		ANY,
403	{ UQ_ALWAYS_ON, NULL }},
404 { USB_VENDOR_LOGITECH, 	USB_PRODUCT_LOGITECH_B100_2,		ANY,
405	{ UQ_ALWAYS_ON, NULL }},
406 { USB_VENDOR_LENOVO,		USB_PRODUCT_LENOVO_OPTUSBMOUSE,		ANY,		{ UQ_ALWAYS_ON, NULL }},
407/*
408 * The HAILUCK USB Keyboard has a built-in touchpad, which
409 * needs to be active for the keyboard to function properly.
410 */
411 { USB_VENDOR_HAILUCK,		USB_PRODUCT_HAILUCK_KEYBOARD,		ANY,
412	{ UQ_ALWAYS_ON, NULL }},
413
414 { 0, 0, 0, { 0, NULL } }
415};
416
417const struct usbd_quirks usbd_no_quirk = { 0 };
418
419const struct usbd_quirks *
420usbd_find_quirk(usb_device_descriptor_t *d)
421{
422	const struct usbd_quirk_entry *t;
423	uint16_t vendor = UGETW(d->idVendor);
424	uint16_t product = UGETW(d->idProduct);
425	uint16_t revision = UGETW(d->bcdDevice);
426
427	for (t = usb_quirks; t->idVendor != 0; t++) {
428		if (t->idVendor == vendor &&
429		    (t->idProduct == ANY || t->idProduct == product) &&
430		    (t->bcdDevice == ANY || t->bcdDevice == revision))
431			break;
432	}
433#ifdef USB_DEBUG
434	if (usbdebug && t->quirks.uq_flags)
435		printf("usbd_find_quirk 0x%04x/0x%04x/%x: %d\n",
436			  UGETW(d->idVendor), UGETW(d->idProduct),
437			  UGETW(d->bcdDevice), t->quirks.uq_flags);
438#endif
439	return &t->quirks;
440}
441