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