xref: /openbmc/linux/drivers/usb/core/quirks.c (revision 6e4f6b5eac461867471b3f368699097b31843d23)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
27ceec1f1SOliver Neukum /*
37ceec1f1SOliver Neukum  * USB device quirk handling logic and table
47ceec1f1SOliver Neukum  *
57ceec1f1SOliver Neukum  * Copyright (c) 2007 Oliver Neukum
67ceec1f1SOliver Neukum  * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
77ceec1f1SOliver Neukum  */
87ceec1f1SOliver Neukum 
9027bd6caSKai-Heng Feng #include <linux/moduleparam.h>
107ceec1f1SOliver Neukum #include <linux/usb.h>
117ceec1f1SOliver Neukum #include <linux/usb/quirks.h>
127868943dSHuang Rui #include <linux/usb/hcd.h>
137ceec1f1SOliver Neukum #include "usb.h"
147ceec1f1SOliver Neukum 
15027bd6caSKai-Heng Feng struct quirk_entry {
16027bd6caSKai-Heng Feng 	u16 vid;
17027bd6caSKai-Heng Feng 	u16 pid;
18027bd6caSKai-Heng Feng 	u32 flags;
19027bd6caSKai-Heng Feng };
20027bd6caSKai-Heng Feng 
21027bd6caSKai-Heng Feng static DEFINE_MUTEX(quirk_mutex);
22027bd6caSKai-Heng Feng 
23027bd6caSKai-Heng Feng static struct quirk_entry *quirk_list;
24027bd6caSKai-Heng Feng static unsigned int quirk_count;
25027bd6caSKai-Heng Feng 
26027bd6caSKai-Heng Feng static char quirks_param[128];
27027bd6caSKai-Heng Feng 
quirks_param_set(const char * value,const struct kernel_param * kp)28b1b6bed3SKars Mulder static int quirks_param_set(const char *value, const struct kernel_param *kp)
29027bd6caSKai-Heng Feng {
30b1b6bed3SKars Mulder 	char *val, *p, *field;
31027bd6caSKai-Heng Feng 	u16 vid, pid;
32027bd6caSKai-Heng Feng 	u32 flags;
33027bd6caSKai-Heng Feng 	size_t i;
34a0305014SKai-Heng Feng 	int err;
35a0305014SKai-Heng Feng 
36b1b6bed3SKars Mulder 	val = kstrdup(value, GFP_KERNEL);
37b1b6bed3SKars Mulder 	if (!val)
38b1b6bed3SKars Mulder 		return -ENOMEM;
39b1b6bed3SKars Mulder 
40a0305014SKai-Heng Feng 	err = param_set_copystring(val, kp);
41b1b6bed3SKars Mulder 	if (err) {
42b1b6bed3SKars Mulder 		kfree(val);
43a0305014SKai-Heng Feng 		return err;
44b1b6bed3SKars Mulder 	}
45027bd6caSKai-Heng Feng 
46027bd6caSKai-Heng Feng 	mutex_lock(&quirk_mutex);
47027bd6caSKai-Heng Feng 
48a0305014SKai-Heng Feng 	if (!*val) {
49027bd6caSKai-Heng Feng 		quirk_count = 0;
50027bd6caSKai-Heng Feng 		kfree(quirk_list);
51027bd6caSKai-Heng Feng 		quirk_list = NULL;
52027bd6caSKai-Heng Feng 		goto unlock;
53027bd6caSKai-Heng Feng 	}
54027bd6caSKai-Heng Feng 
55027bd6caSKai-Heng Feng 	for (quirk_count = 1, i = 0; val[i]; i++)
56027bd6caSKai-Heng Feng 		if (val[i] == ',')
57027bd6caSKai-Heng Feng 			quirk_count++;
58027bd6caSKai-Heng Feng 
59027bd6caSKai-Heng Feng 	if (quirk_list) {
60027bd6caSKai-Heng Feng 		kfree(quirk_list);
61027bd6caSKai-Heng Feng 		quirk_list = NULL;
62027bd6caSKai-Heng Feng 	}
63027bd6caSKai-Heng Feng 
64027bd6caSKai-Heng Feng 	quirk_list = kcalloc(quirk_count, sizeof(struct quirk_entry),
65027bd6caSKai-Heng Feng 			     GFP_KERNEL);
66027bd6caSKai-Heng Feng 	if (!quirk_list) {
6716c4cb19SHarry Pan 		quirk_count = 0;
68027bd6caSKai-Heng Feng 		mutex_unlock(&quirk_mutex);
69b1b6bed3SKars Mulder 		kfree(val);
70027bd6caSKai-Heng Feng 		return -ENOMEM;
71027bd6caSKai-Heng Feng 	}
72027bd6caSKai-Heng Feng 
73b1b6bed3SKars Mulder 	for (i = 0, p = val; p && *p;) {
74027bd6caSKai-Heng Feng 		/* Each entry consists of VID:PID:flags */
75027bd6caSKai-Heng Feng 		field = strsep(&p, ":");
76027bd6caSKai-Heng Feng 		if (!field)
77027bd6caSKai-Heng Feng 			break;
78027bd6caSKai-Heng Feng 
79027bd6caSKai-Heng Feng 		if (kstrtou16(field, 16, &vid))
80027bd6caSKai-Heng Feng 			break;
81027bd6caSKai-Heng Feng 
82027bd6caSKai-Heng Feng 		field = strsep(&p, ":");
83027bd6caSKai-Heng Feng 		if (!field)
84027bd6caSKai-Heng Feng 			break;
85027bd6caSKai-Heng Feng 
86027bd6caSKai-Heng Feng 		if (kstrtou16(field, 16, &pid))
87027bd6caSKai-Heng Feng 			break;
88027bd6caSKai-Heng Feng 
89027bd6caSKai-Heng Feng 		field = strsep(&p, ",");
90027bd6caSKai-Heng Feng 		if (!field || !*field)
91027bd6caSKai-Heng Feng 			break;
92027bd6caSKai-Heng Feng 
93027bd6caSKai-Heng Feng 		/* Collect the flags */
94027bd6caSKai-Heng Feng 		for (flags = 0; *field; field++) {
95027bd6caSKai-Heng Feng 			switch (*field) {
96027bd6caSKai-Heng Feng 			case 'a':
97027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_STRING_FETCH_255;
98027bd6caSKai-Heng Feng 				break;
99027bd6caSKai-Heng Feng 			case 'b':
100027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_RESET_RESUME;
101027bd6caSKai-Heng Feng 				break;
102027bd6caSKai-Heng Feng 			case 'c':
103027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_NO_SET_INTF;
104027bd6caSKai-Heng Feng 				break;
105027bd6caSKai-Heng Feng 			case 'd':
106027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_CONFIG_INTF_STRINGS;
107027bd6caSKai-Heng Feng 				break;
108027bd6caSKai-Heng Feng 			case 'e':
109027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_RESET;
110027bd6caSKai-Heng Feng 				break;
111027bd6caSKai-Heng Feng 			case 'f':
112027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_HONOR_BNUMINTERFACES;
113027bd6caSKai-Heng Feng 				break;
114027bd6caSKai-Heng Feng 			case 'g':
115027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_DELAY_INIT;
116027bd6caSKai-Heng Feng 				break;
117027bd6caSKai-Heng Feng 			case 'h':
118027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL;
119027bd6caSKai-Heng Feng 				break;
120027bd6caSKai-Heng Feng 			case 'i':
121027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_DEVICE_QUALIFIER;
122027bd6caSKai-Heng Feng 				break;
123027bd6caSKai-Heng Feng 			case 'j':
124027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_IGNORE_REMOTE_WAKEUP;
125027bd6caSKai-Heng Feng 				break;
126027bd6caSKai-Heng Feng 			case 'k':
127027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_NO_LPM;
128027bd6caSKai-Heng Feng 				break;
129027bd6caSKai-Heng Feng 			case 'l':
130027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL;
131027bd6caSKai-Heng Feng 				break;
132027bd6caSKai-Heng Feng 			case 'm':
133027bd6caSKai-Heng Feng 				flags |= USB_QUIRK_DISCONNECT_SUSPEND;
134027bd6caSKai-Heng Feng 				break;
1354d8d5a39SKai-Heng Feng 			case 'n':
1364d8d5a39SKai-Heng Feng 				flags |= USB_QUIRK_DELAY_CTRL_MSG;
1374d8d5a39SKai-Heng Feng 				break;
138781f0766SKai-Heng Feng 			case 'o':
139781f0766SKai-Heng Feng 				flags |= USB_QUIRK_HUB_SLOW_RESET;
140781f0766SKai-Heng Feng 				break;
1413adcbec4SHardik Gajjar 			case 'p':
1423adcbec4SHardik Gajjar 				flags |= USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT;
1433adcbec4SHardik Gajjar 				break;
144027bd6caSKai-Heng Feng 			/* Ignore unrecognized flag characters */
145027bd6caSKai-Heng Feng 			}
146027bd6caSKai-Heng Feng 		}
147027bd6caSKai-Heng Feng 
148027bd6caSKai-Heng Feng 		quirk_list[i++] = (struct quirk_entry)
149027bd6caSKai-Heng Feng 			{ .vid = vid, .pid = pid, .flags = flags };
150027bd6caSKai-Heng Feng 	}
151027bd6caSKai-Heng Feng 
152027bd6caSKai-Heng Feng 	if (i < quirk_count)
153027bd6caSKai-Heng Feng 		quirk_count = i;
154027bd6caSKai-Heng Feng 
155027bd6caSKai-Heng Feng unlock:
156027bd6caSKai-Heng Feng 	mutex_unlock(&quirk_mutex);
157b1b6bed3SKars Mulder 	kfree(val);
158027bd6caSKai-Heng Feng 
159a0305014SKai-Heng Feng 	return 0;
160027bd6caSKai-Heng Feng }
161027bd6caSKai-Heng Feng 
162027bd6caSKai-Heng Feng static const struct kernel_param_ops quirks_param_ops = {
163027bd6caSKai-Heng Feng 	.set = quirks_param_set,
164027bd6caSKai-Heng Feng 	.get = param_get_string,
165027bd6caSKai-Heng Feng };
166027bd6caSKai-Heng Feng 
167027bd6caSKai-Heng Feng static struct kparam_string quirks_param_string = {
168027bd6caSKai-Heng Feng 	.maxlen = sizeof(quirks_param),
169027bd6caSKai-Heng Feng 	.string = quirks_param,
170027bd6caSKai-Heng Feng };
171027bd6caSKai-Heng Feng 
17216c4cb19SHarry Pan device_param_cb(quirks, &quirks_param_ops, &quirks_param_string, 0644);
173027bd6caSKai-Heng Feng MODULE_PARM_DESC(quirks, "Add/modify USB quirks by specifying quirks=vendorID:productID:quirks");
174027bd6caSKai-Heng Feng 
17580da2e0dSLaurent Pinchart /* Lists of quirky USB devices, split in device quirks and interface quirks.
17680da2e0dSLaurent Pinchart  * Device quirks are applied at the very beginning of the enumeration process,
17780da2e0dSLaurent Pinchart  * right after reading the device descriptor. They can thus only match on device
17880da2e0dSLaurent Pinchart  * information.
17980da2e0dSLaurent Pinchart  *
18080da2e0dSLaurent Pinchart  * Interface quirks are applied after reading all the configuration descriptors.
18180da2e0dSLaurent Pinchart  * They can match on both device and interface information.
18280da2e0dSLaurent Pinchart  *
18380da2e0dSLaurent Pinchart  * Note that the DELAY_INIT and HONOR_BNUMINTERFACES quirks do not make sense as
18480da2e0dSLaurent Pinchart  * interface quirks, as they only influence the enumeration process which is run
18580da2e0dSLaurent Pinchart  * before processing the interface quirks.
18680da2e0dSLaurent Pinchart  *
18780da2e0dSLaurent Pinchart  * Please keep the lists ordered by:
1887ceec1f1SOliver Neukum  * 	1) Vendor ID
1897ceec1f1SOliver Neukum  * 	2) Product ID
1907ceec1f1SOliver Neukum  * 	3) Class ID
1917ceec1f1SOliver Neukum  */
1927ceec1f1SOliver Neukum static const struct usb_device_id usb_quirk_list[] = {
193ce05916fSOliver Neukum 	/* CBM - Flash disk */
194ce05916fSOliver Neukum 	{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
19514f3546fSAlan Stern 
1969b83a1c3SMaxence Duprès 	/* WORLDE Controller KS49 or Prodipe MIDI 49C USB controller */
1979b83a1c3SMaxence Duprès 	{ USB_DEVICE(0x0218, 0x0201), .driver_info =
1989b83a1c3SMaxence Duprès 			USB_QUIRK_CONFIG_INTF_STRINGS },
1999b83a1c3SMaxence Duprès 
200d9b2997eSLukáš Lalinský 	/* WORLDE easy key (easykey.25) MIDI controller  */
201d9b2997eSLukáš Lalinský 	{ USB_DEVICE(0x0218, 0x0401), .driver_info =
202d9b2997eSLukáš Lalinský 			USB_QUIRK_CONFIG_INTF_STRINGS },
203d9b2997eSLukáš Lalinský 
2047ceec1f1SOliver Neukum 	/* HP 5300/5370C scanner */
20514f3546fSAlan Stern 	{ USB_DEVICE(0x03f0, 0x0701), .driver_info =
20614f3546fSAlan Stern 			USB_QUIRK_STRING_FETCH_255 },
207e6a20ff9SOliver Neukum 
2083180dabeSKamil Lulko 	/* HP v222w 16GB Mini USB Drive */
2093180dabeSKamil Lulko 	{ USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT },
2103180dabeSKamil Lulko 
211b68a42b1SOliver Neukum 	/* Creative SB Audigy 2 NX */
212b68a42b1SOliver Neukum 	{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
213b68a42b1SOliver Neukum 
21481099f97SHans de Goede 	/* USB3503 */
21581099f97SHans de Goede 	{ USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME },
21681099f97SHans de Goede 
217263e80b4SHans de Goede 	/* Microsoft Wireless Laser Mouse 6000 Receiver */
218263e80b4SHans de Goede 	{ USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME },
219263e80b4SHans de Goede 
220bc009ecaSAndreas Fleig 	/* Microsoft LifeCam-VX700 v2.0 */
221bc009ecaSAndreas Fleig 	{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
222bc009ecaSAndreas Fleig 
223ea261113SMaximilian Luz 	/* Microsoft Surface Dock Ethernet (RTL8153 GigE) */
224ea261113SMaximilian Luz 	{ USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM },
225ea261113SMaximilian Luz 
226effd14f6SMichael Niewöhner 	/* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */
227effd14f6SMichael Niewöhner 	{ USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME },
228effd14f6SMichael Niewöhner 
229bd21f022SMarco Zatta 	/* Logitech HD Webcam C270 */
230bd21f022SMarco Zatta 	{ USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME },
231bd21f022SMarco Zatta 
2325d802192STomasz Meresiński 	/* Logitech HD Pro Webcams C920, C920-C, C922, C925e and C930e */
233e0429362SJulius Werner 	{ USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT },
234a1279ef7SDmitry Fleytman 	{ USB_DEVICE(0x046d, 0x0841), .driver_info = USB_QUIRK_DELAY_INIT },
235e0429362SJulius Werner 	{ USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT },
2367f038d25SDmitry Fleytman Dmitry Fleytman 	{ USB_DEVICE(0x046d, 0x085b), .driver_info = USB_QUIRK_DELAY_INIT },
2375d802192STomasz Meresiński 	{ USB_DEVICE(0x046d, 0x085c), .driver_info = USB_QUIRK_DELAY_INIT },
238e0429362SJulius Werner 
23972194739SVincent Palatin 	/* Logitech ConferenceCam CC3000e */
24072194739SVincent Palatin 	{ USB_DEVICE(0x046d, 0x0847), .driver_info = USB_QUIRK_DELAY_INIT },
24172194739SVincent Palatin 	{ USB_DEVICE(0x046d, 0x0848), .driver_info = USB_QUIRK_DELAY_INIT },
24272194739SVincent Palatin 
24372194739SVincent Palatin 	/* Logitech PTZ Pro Camera */
24472194739SVincent Palatin 	{ USB_DEVICE(0x046d, 0x0853), .driver_info = USB_QUIRK_DELAY_INIT },
24572194739SVincent Palatin 
246b96ed52dSDan Lazewatsky 	/* Logitech Screen Share */
247b96ed52dSDan Lazewatsky 	{ USB_DEVICE(0x046d, 0x086c), .driver_info = USB_QUIRK_NO_LPM },
248b96ed52dSDan Lazewatsky 
249e387ef5cSLaurent Pinchart 	/* Logitech Quickcam Fusion */
250e387ef5cSLaurent Pinchart 	{ USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
2512394d67eSOliver Neukum 
252e387ef5cSLaurent Pinchart 	/* Logitech Quickcam Orbit MP */
253e387ef5cSLaurent Pinchart 	{ USB_DEVICE(0x046d, 0x08c2), .driver_info = USB_QUIRK_RESET_RESUME },
2542394d67eSOliver Neukum 
255e387ef5cSLaurent Pinchart 	/* Logitech Quickcam Pro for Notebook */
256e387ef5cSLaurent Pinchart 	{ USB_DEVICE(0x046d, 0x08c3), .driver_info = USB_QUIRK_RESET_RESUME },
2575b253d88SJon Levell 
258e387ef5cSLaurent Pinchart 	/* Logitech Quickcam Pro 5000 */
259e387ef5cSLaurent Pinchart 	{ USB_DEVICE(0x046d, 0x08c5), .driver_info = USB_QUIRK_RESET_RESUME },
2602394d67eSOliver Neukum 
261e387ef5cSLaurent Pinchart 	/* Logitech Quickcam OEM Dell Notebook */
262e387ef5cSLaurent Pinchart 	{ USB_DEVICE(0x046d, 0x08c6), .driver_info = USB_QUIRK_RESET_RESUME },
26360c71ca9SJosh Boyer 
264e387ef5cSLaurent Pinchart 	/* Logitech Quickcam OEM Cisco VT Camera II */
265e387ef5cSLaurent Pinchart 	{ USB_DEVICE(0x046d, 0x08c7), .driver_info = USB_QUIRK_RESET_RESUME },
2660d145d7dSsordna 
26793362a87SPhil Dibowitz 	/* Logitech Harmony 700-series */
26893362a87SPhil Dibowitz 	{ USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT },
26993362a87SPhil Dibowitz 
27014f3546fSAlan Stern 	/* Philips PSC805 audio device */
27114f3546fSAlan Stern 	{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
27214f3546fSAlan Stern 
2738484bf29SYao-Wen Mao 	/* Plantronic Audio 655 DSP */
2748484bf29SYao-Wen Mao 	{ USB_DEVICE(0x047f, 0xc008), .driver_info = USB_QUIRK_RESET_RESUME },
2758484bf29SYao-Wen Mao 
2768484bf29SYao-Wen Mao 	/* Plantronic Audio 648 USB */
2778484bf29SYao-Wen Mao 	{ USB_DEVICE(0x047f, 0xc013), .driver_info = USB_QUIRK_RESET_RESUME },
2788484bf29SYao-Wen Mao 
27947f19c0eSPaul Mortier 	/* Artisman Watchdog Dongle */
28047f19c0eSPaul Mortier 	{ USB_DEVICE(0x04b4, 0x0526), .driver_info =
28147f19c0eSPaul Mortier 			USB_QUIRK_CONFIG_INTF_STRINGS },
28247f19c0eSPaul Mortier 
28392fc7a8bSAlan Stern 	/* Microchip Joss Optical infrared touchboard device */
28492fc7a8bSAlan Stern 	{ USB_DEVICE(0x04d8, 0x000c), .driver_info =
28592fc7a8bSAlan Stern 			USB_QUIRK_CONFIG_INTF_STRINGS },
28692fc7a8bSAlan Stern 
287304ab4abSOliver Neukum 	/* CarrolTouch 4000U */
288304ab4abSOliver Neukum 	{ USB_DEVICE(0x04e7, 0x0009), .driver_info = USB_QUIRK_RESET_RESUME },
289304ab4abSOliver Neukum 
290304ab4abSOliver Neukum 	/* CarrolTouch 4500U */
291304ab4abSOliver Neukum 	{ USB_DEVICE(0x04e7, 0x0030), .driver_info = USB_QUIRK_RESET_RESUME },
292304ab4abSOliver Neukum 
29372a012ceSMaciej Szmigiero 	/* Samsung Android phone modem - ID conflict with SPH-I500 */
29472a012ceSMaciej Szmigiero 	{ USB_DEVICE(0x04e8, 0x6601), .driver_info =
29572a012ceSMaciej Szmigiero 			USB_QUIRK_CONFIG_INTF_STRINGS },
29672a012ceSMaciej Szmigiero 
297c68929f7SJohan Hovold 	/* Elan Touchscreen */
298c68929f7SJohan Hovold 	{ USB_DEVICE(0x04f3, 0x0089), .driver_info =
299c68929f7SJohan Hovold 			USB_QUIRK_DEVICE_QUALIFIER },
300c68929f7SJohan Hovold 
301876af5d4SAdel Gadllah 	{ USB_DEVICE(0x04f3, 0x009b), .driver_info =
302876af5d4SAdel Gadllah 			USB_QUIRK_DEVICE_QUALIFIER },
303876af5d4SAdel Gadllah 
304a32c99e7SOliver Neukum 	{ USB_DEVICE(0x04f3, 0x010c), .driver_info =
305a32c99e7SOliver Neukum 			USB_QUIRK_DEVICE_QUALIFIER },
306a32c99e7SOliver Neukum 
307dc703ec2SLogan Gunthorpe 	{ USB_DEVICE(0x04f3, 0x0125), .driver_info =
308dc703ec2SLogan Gunthorpe 			USB_QUIRK_DEVICE_QUALIFIER },
309dc703ec2SLogan Gunthorpe 
310d7499475SAdel Gadllah 	{ USB_DEVICE(0x04f3, 0x016f), .driver_info =
311d7499475SAdel Gadllah 			USB_QUIRK_DEVICE_QUALIFIER },
312d7499475SAdel Gadllah 
31325b1f9acSJoseph Salisbury 	{ USB_DEVICE(0x04f3, 0x0381), .driver_info =
31425b1f9acSJoseph Salisbury 			USB_QUIRK_NO_LPM },
31525b1f9acSJoseph Salisbury 
316df36c5beSAdrien Vergé 	{ USB_DEVICE(0x04f3, 0x21b8), .driver_info =
317df36c5beSAdrien Vergé 			USB_QUIRK_DEVICE_QUALIFIER },
318df36c5beSAdrien Vergé 
319b68a42b1SOliver Neukum 	/* Roland SC-8820 */
320b68a42b1SOliver Neukum 	{ USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME },
321b68a42b1SOliver Neukum 
322b68a42b1SOliver Neukum 	/* Edirol SD-20 */
323b68a42b1SOliver Neukum 	{ USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME },
324b68a42b1SOliver Neukum 
325bac6b032SOliver Neukum 	/* Alcor Micro Corp. Hub */
326bac6b032SOliver Neukum 	{ USB_DEVICE(0x058f, 0x9254), .driver_info = USB_QUIRK_RESET_RESUME },
327bac6b032SOliver Neukum 
32890d95ef6SOliver Neukum 	/* appletouch */
32990d95ef6SOliver Neukum 	{ USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
33090d95ef6SOliver Neukum 
331e43a12f1SKai-Heng Feng 	/* Genesys Logic hub, internally used by KY-688 USB 3.1 Type-C Hub */
332e43a12f1SKai-Heng Feng 	{ USB_DEVICE(0x05e3, 0x0612), .driver_info = USB_QUIRK_NO_LPM },
333e43a12f1SKai-Heng Feng 
334b9096d9fSOliver Neukum 	/* ELSA MicroLink 56K */
335b9096d9fSOliver Neukum 	{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_RESET_RESUME },
336b9096d9fSOliver Neukum 
3377496cfe5SKai-Heng Feng 	/* Genesys Logic hub, internally used by Moshi USB to Ethernet Adapter */
3387496cfe5SKai-Heng Feng 	{ USB_DEVICE(0x05e3, 0x0616), .driver_info = USB_QUIRK_NO_LPM },
3397496cfe5SKai-Heng Feng 
340598eff6dSRené Rebe 	/* Avision AV600U */
341598eff6dSRené Rebe 	{ USB_DEVICE(0x0638, 0x0a13), .driver_info =
342598eff6dSRené Rebe 	  USB_QUIRK_STRING_FETCH_255 },
343598eff6dSRené Rebe 
3441662e3a7SAlan Stern 	/* Saitek Cyborg Gold Joystick */
3451662e3a7SAlan Stern 	{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
3461662e3a7SAlan Stern 			USB_QUIRK_CONFIG_INTF_STRINGS },
3471662e3a7SAlan Stern 
34808a02f95SOliver Neukum 	/* Agfa SNAPSCAN 1212U */
34908a02f95SOliver Neukum 	{ USB_DEVICE(0x06bd, 0x0001), .driver_info = USB_QUIRK_RESET_RESUME },
35008a02f95SOliver Neukum 
35135284b3dSOliver Neukum 	/* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */
3522394d67eSOliver Neukum 	{ USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
3532394d67eSOliver Neukum 
35435284b3dSOliver Neukum 	/* Guillemot Webcam Hercules Dualpix Exchange*/
35535284b3dSOliver Neukum 	{ USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
35635284b3dSOliver Neukum 
357184eead0SAlan Stern 	/* Guillemot Hercules DJ Console audio card (BZ 208357) */
358184eead0SAlan Stern 	{ USB_DEVICE(0x06f8, 0xb000), .driver_info =
359184eead0SAlan Stern 			USB_QUIRK_ENDPOINT_IGNORE },
360184eead0SAlan Stern 
361166cb70eSSteffen Müller 	/* Midiman M-Audio Keystation 88es */
362166cb70eSSteffen Müller 	{ USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME },
363166cb70eSSteffen Müller 
3642f2dde6bSHarry Pan 	/* SanDisk Ultra Fit and Ultra Flair */
3652f2dde6bSHarry Pan 	{ USB_DEVICE(0x0781, 0x5583), .driver_info = USB_QUIRK_NO_LPM },
3662f2dde6bSHarry Pan 	{ USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM },
3672f2dde6bSHarry Pan 
368181135bbSNicolas Dumazet 	/* Realforce 87U Keyboard */
369181135bbSNicolas Dumazet 	{ USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM },
370181135bbSNicolas Dumazet 
37186833691SLamarque Vieira Souza 	/* M-Systems Flash Disk Pioneers */
37286833691SLamarque Vieira Souza 	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
37386833691SLamarque Vieira Souza 
3743243367bSSamuel Thibault 	/* Baum Vario Ultra */
3753243367bSSamuel Thibault 	{ USB_DEVICE(0x0904, 0x6101), .driver_info =
3763243367bSSamuel Thibault 			USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
3773243367bSSamuel Thibault 	{ USB_DEVICE(0x0904, 0x6102), .driver_info =
3783243367bSSamuel Thibault 			USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
3793243367bSSamuel Thibault 	{ USB_DEVICE(0x0904, 0x6103), .driver_info =
3803243367bSSamuel Thibault 			USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
3813243367bSSamuel Thibault 
382bdd1b147SJohan Hovold 	/* Sound Devices USBPre2 */
383bdd1b147SJohan Hovold 	{ USB_DEVICE(0x0926, 0x0202), .driver_info =
38491c7eaa6SGreg Kroah-Hartman 			USB_QUIRK_ENDPOINT_IGNORE },
385bdd1b147SJohan Hovold 
386068834a2SAlan Stern 	/* Sound Devices MixPre-D */
387068834a2SAlan Stern 	{ USB_DEVICE(0x0926, 0x0208), .driver_info =
388068834a2SAlan Stern 			USB_QUIRK_ENDPOINT_IGNORE },
389068834a2SAlan Stern 
3903c18e30fSAlan Stern 	/* Keytouch QWERTY Panel keyboard */
3913c18e30fSAlan Stern 	{ USB_DEVICE(0x0926, 0x3333), .driver_info =
3923c18e30fSAlan Stern 			USB_QUIRK_CONFIG_INTF_STRINGS },
3933c18e30fSAlan Stern 
394afaa2e74SAlan Stern 	/* Kingston DataTraveler 3.0 */
395afaa2e74SAlan Stern 	{ USB_DEVICE(0x0951, 0x1666), .driver_info = USB_QUIRK_NO_LPM },
396afaa2e74SAlan Stern 
397fc4ade55SHannu Hartikainen 	/* NVIDIA Jetson devices in Force Recovery mode */
398fc4ade55SHannu Hartikainen 	{ USB_DEVICE(0x0955, 0x7018), .driver_info = USB_QUIRK_RESET_RESUME },
399fc4ade55SHannu Hartikainen 	{ USB_DEVICE(0x0955, 0x7019), .driver_info = USB_QUIRK_RESET_RESUME },
400fc4ade55SHannu Hartikainen 	{ USB_DEVICE(0x0955, 0x7418), .driver_info = USB_QUIRK_RESET_RESUME },
401fc4ade55SHannu Hartikainen 	{ USB_DEVICE(0x0955, 0x7721), .driver_info = USB_QUIRK_RESET_RESUME },
402fc4ade55SHannu Hartikainen 	{ USB_DEVICE(0x0955, 0x7c18), .driver_info = USB_QUIRK_RESET_RESUME },
403fc4ade55SHannu Hartikainen 	{ USB_DEVICE(0x0955, 0x7e19), .driver_info = USB_QUIRK_RESET_RESUME },
404fc4ade55SHannu Hartikainen 	{ USB_DEVICE(0x0955, 0x7f21), .driver_info = USB_QUIRK_RESET_RESUME },
405fc4ade55SHannu Hartikainen 
406392e1d98SAlan Stern 	/* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */
407392e1d98SAlan Stern 	{ USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF },
408392e1d98SAlan Stern 
4091ebe718bSStefan Ursella 	/* ELMO L-12F document camera */
4101ebe718bSStefan Ursella 	{ USB_DEVICE(0x09a1, 0x0028), .driver_info = USB_QUIRK_DELAY_CTRL_MSG },
4111ebe718bSStefan Ursella 
41263ab71deSOliver Neukum 	/* Broadcom BCM92035DGROM BT dongle */
41363ab71deSOliver Neukum 	{ USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME },
41463ab71deSOliver Neukum 
4154294bca7SOliver Neukum 	/* MAYA44USB sound device */
4164294bca7SOliver Neukum 	{ USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME },
4174294bca7SOliver Neukum 
41881099f97SHans de Goede 	/* ASUS Base Station(T100) */
41981099f97SHans de Goede 	{ USB_DEVICE(0x0b05, 0x17e0), .driver_info =
42081099f97SHans de Goede 			USB_QUIRK_IGNORE_REMOTE_WAKEUP },
42181099f97SHans de Goede 
4222a7ccf6bSOliver Neukum 	/* Realtek Semiconductor Corp. Mass Storage Device (Multicard Reader)*/
4232a7ccf6bSOliver Neukum 	{ USB_DEVICE(0x0bda, 0x0151), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },
4242a7ccf6bSOliver Neukum 
425b63e48fbSKai-Heng Feng 	/* Realtek hub in Dell WD19 (Type-C) */
426b63e48fbSKai-Heng Feng 	{ USB_DEVICE(0x0bda, 0x0487), .driver_info = USB_QUIRK_NO_LPM },
427b63e48fbSKai-Heng Feng 
42875d7676eSHans de Goede 	/* Generic RTL8153 based ethernet adapters */
42975d7676eSHans de Goede 	{ USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM },
43075d7676eSHans de Goede 
431bcea6dafSPenghao 	/* SONiX USB DEVICE Touchpad */
432bcea6dafSPenghao 	{ USB_DEVICE(0x0c45, 0x7056), .driver_info =
433bcea6dafSPenghao 			USB_QUIRK_IGNORE_REMOTE_WAKEUP },
434bcea6dafSPenghao 
43514f3546fSAlan Stern 	/* Action Semiconductor flash disk */
43614f3546fSAlan Stern 	{ USB_DEVICE(0x10d6, 0x2200), .driver_info =
43714f3546fSAlan Stern 			USB_QUIRK_STRING_FETCH_255 },
4386bc6cff5SAlan Stern 
43943861d29SJohan Hovold 	/* novation SoundControl XL */
44043861d29SJohan Hovold 	{ USB_DEVICE(0x1235, 0x0061), .driver_info = USB_QUIRK_RESET_RESUME },
44143861d29SJohan Hovold 
4429dc162e2SŁukasz Bartosik 	/* Focusrite Scarlett Solo USB */
4439dc162e2SŁukasz Bartosik 	{ USB_DEVICE(0x1235, 0x8211), .driver_info =
4449dc162e2SŁukasz Bartosik 			USB_QUIRK_DISCONNECT_SUSPEND },
4459dc162e2SŁukasz Bartosik 
4468dd8d2c9SDaniel Drake 	/* Huawei 4G LTE module */
4478dd8d2c9SDaniel Drake 	{ USB_DEVICE(0x12d1, 0x15bb), .driver_info =
4488dd8d2c9SDaniel Drake 			USB_QUIRK_DISCONNECT_SUSPEND },
4498dd8d2c9SDaniel Drake 	{ USB_DEVICE(0x12d1, 0x15c3), .driver_info =
4508dd8d2c9SDaniel Drake 			USB_QUIRK_DISCONNECT_SUSPEND },
4518dd8d2c9SDaniel Drake 
45286833691SLamarque Vieira Souza 	/* SKYMEDI USB_DRIVE */
45386833691SLamarque Vieira Souza 	{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
45486833691SLamarque Vieira Souza 
455cd83ce9eSJames P Michels III 	/* Razer - Razer Blade Keyboard */
456cd83ce9eSJames P Michels III 	{ USB_DEVICE(0x1532, 0x0116), .driver_info =
457cd83ce9eSJames P Michels III 			USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
458cd83ce9eSJames P Michels III 
45937d49519SJean-Francois Le Fillatre 	/* Lenovo ThinkPad OneLink+ Dock twin hub controllers (VIA Labs VL812) */
46037d49519SJean-Francois Le Fillatre 	{ USB_DEVICE(0x17ef, 0x1018), .driver_info = USB_QUIRK_RESET_RESUME },
46137d49519SJean-Francois Le Fillatre 	{ USB_DEVICE(0x17ef, 0x1019), .driver_info = USB_QUIRK_RESET_RESUME },
46237d49519SJean-Francois Le Fillatre 
4630ad3bd56SJimmy Wang 	/* Lenovo USB-C to Ethernet Adapter RTL8153-04 */
4640ad3bd56SJimmy Wang 	{ USB_DEVICE(0x17ef, 0x720c), .driver_info = USB_QUIRK_NO_LPM },
4650ad3bd56SJimmy Wang 
46649989adcSOle Ernst 	/* Lenovo Powered USB-C Travel Hub (4X90S92381, RTL8153 GigE) */
46749989adcSOle Ernst 	{ USB_DEVICE(0x17ef, 0x721e), .driver_info = USB_QUIRK_NO_LPM },
46849989adcSOle Ernst 
4699ca57518Spenghao 	/* Lenovo ThinkCenter A630Z TI024Gen3 usb-audio */
4709ca57518Spenghao 	{ USB_DEVICE(0x17ef, 0xa012), .driver_info =
4719ca57518Spenghao 			USB_QUIRK_DISCONNECT_SUSPEND },
4729ca57518Spenghao 
4738f23fe35SKai-Heng Feng 	/* Lenovo ThinkPad USB-C Dock Gen2 Ethernet (RTL8153 GigE) */
4748f23fe35SKai-Heng Feng 	{ USB_DEVICE(0x17ef, 0xa387), .driver_info = USB_QUIRK_NO_LPM },
4758f23fe35SKai-Heng Feng 
476317149c6SHans de Goede 	/* BUILDWIN Photo Frame */
477317149c6SHans de Goede 	{ USB_DEVICE(0x1908, 0x1315), .driver_info =
478317149c6SHans de Goede 			USB_QUIRK_HONOR_BNUMINTERFACES },
479317149c6SHans de Goede 
480e5dff0e8SMacpaul Lin 	/* Protocol and OTG Electrical Test Device */
481e5dff0e8SMacpaul Lin 	{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =
482e5dff0e8SMacpaul Lin 			USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
483e5dff0e8SMacpaul Lin 
484781f0766SKai-Heng Feng 	/* Terminus Technology Inc. Hub */
485781f0766SKai-Heng Feng 	{ USB_DEVICE(0x1a40, 0x0101), .driver_info = USB_QUIRK_HUB_SLOW_RESET },
486781f0766SKai-Heng Feng 
4877a1646d9SJack Stocker 	/* Corsair K70 RGB */
4883483254bSJack Stocker 	{ USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT |
4893483254bSJack Stocker 	  USB_QUIRK_DELAY_CTRL_MSG },
4907a1646d9SJack Stocker 
491bba57eddSNico Sneck 	/* Corsair Strafe */
492bba57eddSNico Sneck 	{ USB_DEVICE(0x1b1c, 0x1b15), .driver_info = USB_QUIRK_DELAY_INIT |
493bba57eddSNico Sneck 	  USB_QUIRK_DELAY_CTRL_MSG },
494bba57eddSNico Sneck 
495de3af5bfSKai-Heng Feng 	/* Corsair Strafe RGB */
496cb88a058SDanilo Krummrich 	{ USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT |
497cb88a058SDanilo Krummrich 	  USB_QUIRK_DELAY_CTRL_MSG },
498de3af5bfSKai-Heng Feng 
499a7711257SEmmanuel Pescosta 	/* Corsair K70 LUX RGB */
500a7711257SEmmanuel Pescosta 	{ USB_DEVICE(0x1b1c, 0x1b33), .driver_info = USB_QUIRK_DELAY_INIT },
501a7711257SEmmanuel Pescosta 
502a0fea602SBernhard Rosenkraenzer 	/* Corsair K70 LUX */
503a0fea602SBernhard Rosenkraenzer 	{ USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT },
504a0fea602SBernhard Rosenkraenzer 
505be34a585SJonathan Cox 	/* Corsair K70 RGB RAPDIFIRE */
506be34a585SJonathan Cox 	{ USB_DEVICE(0x1b1c, 0x1b38), .driver_info = USB_QUIRK_DELAY_INIT |
507be34a585SJonathan Cox 	  USB_QUIRK_DELAY_CTRL_MSG },
508be34a585SJonathan Cox 
509*20836c95SWangYuli 	/* START BP-850k Printer */
510*20836c95SWangYuli 	{ USB_DEVICE(0x1bc3, 0x0003), .driver_info = USB_QUIRK_NO_SET_INTF },
511*20836c95SWangYuli 
5122811501eSFelipe Balbi 	/* MIDI keyboard WORLDE MINI */
5132811501eSFelipe Balbi 	{ USB_DEVICE(0x1c75, 0x0204), .driver_info =
5142811501eSFelipe Balbi 			USB_QUIRK_CONFIG_INTF_STRINGS },
5152811501eSFelipe Balbi 
51632cb0b37SHans de Goede 	/* Acer C120 LED Projector */
51732cb0b37SHans de Goede 	{ USB_DEVICE(0x1de1, 0xc102), .driver_info = USB_QUIRK_NO_LPM },
51832cb0b37SHans de Goede 
519ad87e032SAlan Stern 	/* Blackmagic Design Intensity Shuttle */
520ad87e032SAlan Stern 	{ USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM },
521ad87e032SAlan Stern 
522ad87e032SAlan Stern 	/* Blackmagic Design UltraStudio SDI */
523ad87e032SAlan Stern 	{ USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM },
524ad87e032SAlan Stern 
5256836796dSDevin Heitmueller 	/* Hauppauge HVR-950q */
5266836796dSDevin Heitmueller 	{ USB_DEVICE(0x2040, 0x7200), .driver_info =
5276836796dSDevin Heitmueller 			USB_QUIRK_CONFIG_INTF_STRINGS },
5286836796dSDevin Heitmueller 
529deefd242SKai-Heng Feng 	/* Raydium Touchscreen */
530deefd242SKai-Heng Feng 	{ USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM },
531deefd242SKai-Heng Feng 
532deefd242SKai-Heng Feng 	{ USB_DEVICE(0x2386, 0x3119), .driver_info = USB_QUIRK_NO_LPM },
533deefd242SKai-Heng Feng 
5345967116eSKai-Heng Feng 	{ USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
5355967116eSKai-Heng Feng 
5363adcbec4SHardik Gajjar 	/* APTIV AUTOMOTIVE HUB */
5373adcbec4SHardik Gajjar 	{ USB_DEVICE(0x2c48, 0x0132), .driver_info =
5383adcbec4SHardik Gajjar 			USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT },
5393adcbec4SHardik Gajjar 
540f45681f9STim Anderson 	/* DJI CineSSD */
541f45681f9STim Anderson 	{ USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
542f45681f9STim Anderson 
543303e724dSMark Pearson 	/* Alcor Link AK9563 SC Reader used in 2022 Lenovo ThinkPads */
544303e724dSMark Pearson 	{ USB_DEVICE(0x2ce3, 0x9563), .driver_info = USB_QUIRK_NO_LPM },
545303e724dSMark Pearson 
54697fa5887SMonish Kumar R 	/* DELL USB GEN2 */
54797fa5887SMonish Kumar R 	{ USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME },
54897fa5887SMonish Kumar R 
549ec547af8SOliver Neukum 	/* VCOM device */
550ec547af8SOliver Neukum 	{ USB_DEVICE(0x4296, 0x7570), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },
551ec547af8SOliver Neukum 
55281099f97SHans de Goede 	/* INTEL VALUE SSD */
55381099f97SHans de Goede 	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
55481099f97SHans de Goede 
5557ceec1f1SOliver Neukum 	{ }  /* terminating entry must be last */
5567ceec1f1SOliver Neukum };
5577ceec1f1SOliver Neukum 
55880da2e0dSLaurent Pinchart static const struct usb_device_id usb_interface_quirk_list[] = {
559e387ef5cSLaurent Pinchart 	/* Logitech UVC Cameras */
560e387ef5cSLaurent Pinchart 	{ USB_VENDOR_AND_INTERFACE_INFO(0x046d, USB_CLASS_VIDEO, 1, 0),
561e387ef5cSLaurent Pinchart 	  .driver_info = USB_QUIRK_RESET_RESUME },
562e387ef5cSLaurent Pinchart 
56380da2e0dSLaurent Pinchart 	{ }  /* terminating entry must be last */
56480da2e0dSLaurent Pinchart };
5657ceec1f1SOliver Neukum 
5667868943dSHuang Rui static const struct usb_device_id usb_amd_resume_quirk_list[] = {
5677868943dSHuang Rui 	/* Lenovo Mouse with Pixart controller */
5687868943dSHuang Rui 	{ USB_DEVICE(0x17ef, 0x602e), .driver_info = USB_QUIRK_RESET_RESUME },
5697868943dSHuang Rui 
5707868943dSHuang Rui 	/* Pixart Mouse */
5717868943dSHuang Rui 	{ USB_DEVICE(0x093a, 0x2500), .driver_info = USB_QUIRK_RESET_RESUME },
5727868943dSHuang Rui 	{ USB_DEVICE(0x093a, 0x2510), .driver_info = USB_QUIRK_RESET_RESUME },
5737868943dSHuang Rui 	{ USB_DEVICE(0x093a, 0x2521), .driver_info = USB_QUIRK_RESET_RESUME },
574e788787eSSandeep Singh 	{ USB_DEVICE(0x03f0, 0x2b4a), .driver_info = USB_QUIRK_RESET_RESUME },
5757868943dSHuang Rui 
5767868943dSHuang Rui 	/* Logitech Optical Mouse M90/M100 */
5777868943dSHuang Rui 	{ USB_DEVICE(0x046d, 0xc05a), .driver_info = USB_QUIRK_RESET_RESUME },
5787868943dSHuang Rui 
5797868943dSHuang Rui 	{ }  /* terminating entry must be last */
5807868943dSHuang Rui };
5817868943dSHuang Rui 
58273f8bda9SJohan Hovold /*
58391c7eaa6SGreg Kroah-Hartman  * Entries for endpoints that should be ignored when parsing configuration
58491c7eaa6SGreg Kroah-Hartman  * descriptors.
58573f8bda9SJohan Hovold  *
58691c7eaa6SGreg Kroah-Hartman  * Matched for devices with USB_QUIRK_ENDPOINT_IGNORE.
58773f8bda9SJohan Hovold  */
58891c7eaa6SGreg Kroah-Hartman static const struct usb_device_id usb_endpoint_ignore[] = {
589184eead0SAlan Stern 	{ USB_DEVICE_INTERFACE_NUMBER(0x06f8, 0xb000, 5), .driver_info = 0x01 },
590184eead0SAlan Stern 	{ USB_DEVICE_INTERFACE_NUMBER(0x06f8, 0xb000, 5), .driver_info = 0x81 },
591bdd1b147SJohan Hovold 	{ USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 },
592068834a2SAlan Stern 	{ USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0208, 1), .driver_info = 0x85 },
59373f8bda9SJohan Hovold 	{ }
59473f8bda9SJohan Hovold };
59573f8bda9SJohan Hovold 
usb_endpoint_is_ignored(struct usb_device * udev,struct usb_host_interface * intf,struct usb_endpoint_descriptor * epd)59691c7eaa6SGreg Kroah-Hartman bool usb_endpoint_is_ignored(struct usb_device *udev,
59773f8bda9SJohan Hovold 			     struct usb_host_interface *intf,
59873f8bda9SJohan Hovold 			     struct usb_endpoint_descriptor *epd)
59973f8bda9SJohan Hovold {
60073f8bda9SJohan Hovold 	const struct usb_device_id *id;
60173f8bda9SJohan Hovold 	unsigned int address;
60273f8bda9SJohan Hovold 
60391c7eaa6SGreg Kroah-Hartman 	for (id = usb_endpoint_ignore; id->match_flags; ++id) {
60473f8bda9SJohan Hovold 		if (!usb_match_device(udev, id))
60573f8bda9SJohan Hovold 			continue;
60673f8bda9SJohan Hovold 
60773f8bda9SJohan Hovold 		if (!usb_match_one_id_intf(udev, intf, id))
60873f8bda9SJohan Hovold 			continue;
60973f8bda9SJohan Hovold 
61073f8bda9SJohan Hovold 		address = id->driver_info;
61173f8bda9SJohan Hovold 		if (address == epd->bEndpointAddress)
61273f8bda9SJohan Hovold 			return true;
61373f8bda9SJohan Hovold 	}
61473f8bda9SJohan Hovold 
61573f8bda9SJohan Hovold 	return false;
61673f8bda9SJohan Hovold }
61773f8bda9SJohan Hovold 
usb_match_any_interface(struct usb_device * udev,const struct usb_device_id * id)61880da2e0dSLaurent Pinchart static bool usb_match_any_interface(struct usb_device *udev,
61980da2e0dSLaurent Pinchart 				    const struct usb_device_id *id)
62080da2e0dSLaurent Pinchart {
62180da2e0dSLaurent Pinchart 	unsigned int i;
62280da2e0dSLaurent Pinchart 
62380da2e0dSLaurent Pinchart 	for (i = 0; i < udev->descriptor.bNumConfigurations; ++i) {
62480da2e0dSLaurent Pinchart 		struct usb_host_config *cfg = &udev->config[i];
62580da2e0dSLaurent Pinchart 		unsigned int j;
62680da2e0dSLaurent Pinchart 
62780da2e0dSLaurent Pinchart 		for (j = 0; j < cfg->desc.bNumInterfaces; ++j) {
62880da2e0dSLaurent Pinchart 			struct usb_interface_cache *cache;
62980da2e0dSLaurent Pinchart 			struct usb_host_interface *intf;
63080da2e0dSLaurent Pinchart 
63180da2e0dSLaurent Pinchart 			cache = cfg->intf_cache[j];
63280da2e0dSLaurent Pinchart 			if (cache->num_altsetting == 0)
63380da2e0dSLaurent Pinchart 				continue;
63480da2e0dSLaurent Pinchart 
63580da2e0dSLaurent Pinchart 			intf = &cache->altsetting[0];
63680da2e0dSLaurent Pinchart 			if (usb_match_one_id_intf(udev, intf, id))
63780da2e0dSLaurent Pinchart 				return true;
6387ceec1f1SOliver Neukum 		}
63980da2e0dSLaurent Pinchart 	}
64080da2e0dSLaurent Pinchart 
64180da2e0dSLaurent Pinchart 	return false;
64280da2e0dSLaurent Pinchart }
64380da2e0dSLaurent Pinchart 
usb_amd_resume_quirk(struct usb_device * udev)64400d5f289SFengguang Wu static int usb_amd_resume_quirk(struct usb_device *udev)
6457868943dSHuang Rui {
6467868943dSHuang Rui 	struct usb_hcd *hcd;
6477868943dSHuang Rui 
6487868943dSHuang Rui 	hcd = bus_to_hcd(udev->bus);
6497868943dSHuang Rui 	/* The device should be attached directly to root hub */
6507868943dSHuang Rui 	if (udev->level == 1 && hcd->amd_resume_bug == 1)
6517868943dSHuang Rui 		return 1;
6527868943dSHuang Rui 
6537868943dSHuang Rui 	return 0;
6547868943dSHuang Rui }
6557868943dSHuang Rui 
usb_detect_static_quirks(struct usb_device * udev,const struct usb_device_id * id)656027bd6caSKai-Heng Feng static u32 usb_detect_static_quirks(struct usb_device *udev,
65780da2e0dSLaurent Pinchart 				    const struct usb_device_id *id)
65880da2e0dSLaurent Pinchart {
65980da2e0dSLaurent Pinchart 	u32 quirks = 0;
66080da2e0dSLaurent Pinchart 
66180da2e0dSLaurent Pinchart 	for (; id->match_flags; id++) {
66280da2e0dSLaurent Pinchart 		if (!usb_match_device(udev, id))
66380da2e0dSLaurent Pinchart 			continue;
66480da2e0dSLaurent Pinchart 
66580da2e0dSLaurent Pinchart 		if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_INFO) &&
66680da2e0dSLaurent Pinchart 		    !usb_match_any_interface(udev, id))
66780da2e0dSLaurent Pinchart 			continue;
66880da2e0dSLaurent Pinchart 
66980da2e0dSLaurent Pinchart 		quirks |= (u32)(id->driver_info);
67080da2e0dSLaurent Pinchart 	}
67180da2e0dSLaurent Pinchart 
67280da2e0dSLaurent Pinchart 	return quirks;
6737ceec1f1SOliver Neukum }
6747ceec1f1SOliver Neukum 
usb_detect_dynamic_quirks(struct usb_device * udev)675027bd6caSKai-Heng Feng static u32 usb_detect_dynamic_quirks(struct usb_device *udev)
676027bd6caSKai-Heng Feng {
677027bd6caSKai-Heng Feng 	u16 vid = le16_to_cpu(udev->descriptor.idVendor);
678027bd6caSKai-Heng Feng 	u16 pid = le16_to_cpu(udev->descriptor.idProduct);
679027bd6caSKai-Heng Feng 	int i, flags = 0;
680027bd6caSKai-Heng Feng 
681027bd6caSKai-Heng Feng 	mutex_lock(&quirk_mutex);
682027bd6caSKai-Heng Feng 
683027bd6caSKai-Heng Feng 	for (i = 0; i < quirk_count; i++) {
684027bd6caSKai-Heng Feng 		if (vid == quirk_list[i].vid && pid == quirk_list[i].pid) {
685027bd6caSKai-Heng Feng 			flags = quirk_list[i].flags;
686027bd6caSKai-Heng Feng 			break;
687027bd6caSKai-Heng Feng 		}
688027bd6caSKai-Heng Feng 	}
689027bd6caSKai-Heng Feng 
690027bd6caSKai-Heng Feng 	mutex_unlock(&quirk_mutex);
691027bd6caSKai-Heng Feng 
692027bd6caSKai-Heng Feng 	return flags;
693027bd6caSKai-Heng Feng }
694027bd6caSKai-Heng Feng 
6957ceec1f1SOliver Neukum /*
6967ceec1f1SOliver Neukum  * Detect any quirks the device has, and do any housekeeping for it if needed.
6977ceec1f1SOliver Neukum  */
usb_detect_quirks(struct usb_device * udev)6987ceec1f1SOliver Neukum void usb_detect_quirks(struct usb_device *udev)
6997ceec1f1SOliver Neukum {
700027bd6caSKai-Heng Feng 	udev->quirks = usb_detect_static_quirks(udev, usb_quirk_list);
7017868943dSHuang Rui 
7027868943dSHuang Rui 	/*
7037868943dSHuang Rui 	 * Pixart-based mice would trigger remote wakeup issue on AMD
7047868943dSHuang Rui 	 * Yangtze chipset, so set them as RESET_RESUME flag.
7057868943dSHuang Rui 	 */
7067868943dSHuang Rui 	if (usb_amd_resume_quirk(udev))
707027bd6caSKai-Heng Feng 		udev->quirks |= usb_detect_static_quirks(udev,
7087868943dSHuang Rui 				usb_amd_resume_quirk_list);
7097868943dSHuang Rui 
710027bd6caSKai-Heng Feng 	udev->quirks ^= usb_detect_dynamic_quirks(udev);
711027bd6caSKai-Heng Feng 
7127ceec1f1SOliver Neukum 	if (udev->quirks)
7137ceec1f1SOliver Neukum 		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
7147ceec1f1SOliver Neukum 			udev->quirks);
7157ceec1f1SOliver Neukum 
7164f482038SJulius Werner #ifdef CONFIG_USB_DEFAULT_PERSIST
7174f482038SJulius Werner 	if (!(udev->quirks & USB_QUIRK_RESET))
7184f482038SJulius Werner 		udev->persist_enabled = 1;
7194f482038SJulius Werner #else
720feccc30dSAlan Stern 	/* Hubs are automatically enabled for USB-PERSIST */
721feccc30dSAlan Stern 	if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
722feccc30dSAlan Stern 		udev->persist_enabled = 1;
7234f482038SJulius Werner #endif	/* CONFIG_USB_DEFAULT_PERSIST */
7247ceec1f1SOliver Neukum }
72580da2e0dSLaurent Pinchart 
usb_detect_interface_quirks(struct usb_device * udev)72680da2e0dSLaurent Pinchart void usb_detect_interface_quirks(struct usb_device *udev)
72780da2e0dSLaurent Pinchart {
72880da2e0dSLaurent Pinchart 	u32 quirks;
72980da2e0dSLaurent Pinchart 
730027bd6caSKai-Heng Feng 	quirks = usb_detect_static_quirks(udev, usb_interface_quirk_list);
73180da2e0dSLaurent Pinchart 	if (quirks == 0)
73280da2e0dSLaurent Pinchart 		return;
73380da2e0dSLaurent Pinchart 
73480da2e0dSLaurent Pinchart 	dev_dbg(&udev->dev, "USB interface quirks for this device: %x\n",
73580da2e0dSLaurent Pinchart 		quirks);
73680da2e0dSLaurent Pinchart 	udev->quirks |= quirks;
73780da2e0dSLaurent Pinchart }
738027bd6caSKai-Heng Feng 
usb_release_quirk_list(void)739027bd6caSKai-Heng Feng void usb_release_quirk_list(void)
740027bd6caSKai-Heng Feng {
741027bd6caSKai-Heng Feng 	mutex_lock(&quirk_mutex);
742027bd6caSKai-Heng Feng 	kfree(quirk_list);
743027bd6caSKai-Heng Feng 	quirk_list = NULL;
744027bd6caSKai-Heng Feng 	mutex_unlock(&quirk_mutex);
745027bd6caSKai-Heng Feng }
746