11
11
#include <linux/usb/hcd.h>
12
12
#include "usb.h"
13
13
14
+ struct quirk_entry {
15
+ u16 vid ;
16
+ u16 pid ;
17
+ u32 flags ;
18
+ };
19
+
20
+ static DEFINE_MUTEX (quirk_mutex );
21
+
22
+ static struct quirk_entry * quirk_list ;
23
+ static unsigned int quirk_count ;
24
+
25
+ static char quirks_param [128 ];
26
+
27
+ static int quirks_param_set (const char * val , const struct kernel_param * kp )
28
+ {
29
+ char * p , * field ;
30
+ u16 vid , pid ;
31
+ u32 flags ;
32
+ size_t i ;
33
+
34
+ mutex_lock (& quirk_mutex );
35
+
36
+ if (!val || !* val ) {
37
+ quirk_count = 0 ;
38
+ kfree (quirk_list );
39
+ quirk_list = NULL ;
40
+ goto unlock ;
41
+ }
42
+
43
+ for (quirk_count = 1 , i = 0 ; val [i ]; i ++ )
44
+ if (val [i ] == ',' )
45
+ quirk_count ++ ;
46
+
47
+ if (quirk_list ) {
48
+ kfree (quirk_list );
49
+ quirk_list = NULL ;
50
+ }
51
+
52
+ quirk_list = kcalloc (quirk_count , sizeof (struct quirk_entry ),
53
+ GFP_KERNEL );
54
+ if (!quirk_list ) {
55
+ mutex_unlock (& quirk_mutex );
56
+ return - ENOMEM ;
57
+ }
58
+
59
+ for (i = 0 , p = (char * )val ; p && * p ;) {
60
+ /* Each entry consists of VID:PID:flags */
61
+ field = strsep (& p , ":" );
62
+ if (!field )
63
+ break ;
64
+
65
+ if (kstrtou16 (field , 16 , & vid ))
66
+ break ;
67
+
68
+ field = strsep (& p , ":" );
69
+ if (!field )
70
+ break ;
71
+
72
+ if (kstrtou16 (field , 16 , & pid ))
73
+ break ;
74
+
75
+ field = strsep (& p , "," );
76
+ if (!field || !* field )
77
+ break ;
78
+
79
+ /* Collect the flags */
80
+ for (flags = 0 ; * field ; field ++ ) {
81
+ switch (* field ) {
82
+ case 'a' :
83
+ flags |= USB_QUIRK_STRING_FETCH_255 ;
84
+ break ;
85
+ case 'b' :
86
+ flags |= USB_QUIRK_RESET_RESUME ;
87
+ break ;
88
+ case 'c' :
89
+ flags |= USB_QUIRK_NO_SET_INTF ;
90
+ break ;
91
+ case 'd' :
92
+ flags |= USB_QUIRK_CONFIG_INTF_STRINGS ;
93
+ break ;
94
+ case 'e' :
95
+ flags |= USB_QUIRK_RESET ;
96
+ break ;
97
+ case 'f' :
98
+ flags |= USB_QUIRK_HONOR_BNUMINTERFACES ;
99
+ break ;
100
+ case 'g' :
101
+ flags |= USB_QUIRK_DELAY_INIT ;
102
+ break ;
103
+ case 'h' :
104
+ flags |= USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL ;
105
+ break ;
106
+ case 'i' :
107
+ flags |= USB_QUIRK_DEVICE_QUALIFIER ;
108
+ break ;
109
+ case 'j' :
110
+ flags |= USB_QUIRK_IGNORE_REMOTE_WAKEUP ;
111
+ break ;
112
+ case 'k' :
113
+ flags |= USB_QUIRK_NO_LPM ;
114
+ break ;
115
+ case 'l' :
116
+ flags |= USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL ;
117
+ break ;
118
+ case 'm' :
119
+ flags |= USB_QUIRK_DISCONNECT_SUSPEND ;
120
+ break ;
121
+ /* Ignore unrecognized flag characters */
122
+ }
123
+ }
124
+
125
+ quirk_list [i ++ ] = (struct quirk_entry )
126
+ { .vid = vid , .pid = pid , .flags = flags };
127
+ }
128
+
129
+ if (i < quirk_count )
130
+ quirk_count = i ;
131
+
132
+ unlock :
133
+ mutex_unlock (& quirk_mutex );
134
+
135
+ return param_set_copystring (val , kp );
136
+ }
137
+
138
+ static const struct kernel_param_ops quirks_param_ops = {
139
+ .set = quirks_param_set ,
140
+ .get = param_get_string ,
141
+ };
142
+
143
+ static struct kparam_string quirks_param_string = {
144
+ .maxlen = sizeof (quirks_param ),
145
+ .string = quirks_param ,
146
+ };
147
+
148
+ module_param_cb (quirks , & quirks_param_ops , & quirks_param_string , 0644 );
149
+ MODULE_PARM_DESC (quirks , "Add/modify USB quirks by specifying quirks=vendorID:productID:quirks" );
150
+
14
151
/* Lists of quirky USB devices, split in device quirks and interface quirks.
15
152
* Device quirks are applied at the very beginning of the enumeration process,
16
153
* right after reading the device descriptor. They can thus only match on device
@@ -320,8 +457,8 @@ static int usb_amd_resume_quirk(struct usb_device *udev)
320
457
return 0 ;
321
458
}
322
459
323
- static u32 __usb_detect_quirks (struct usb_device * udev ,
324
- const struct usb_device_id * id )
460
+ static u32 usb_detect_static_quirks (struct usb_device * udev ,
461
+ const struct usb_device_id * id )
325
462
{
326
463
u32 quirks = 0 ;
327
464
@@ -339,21 +476,43 @@ static u32 __usb_detect_quirks(struct usb_device *udev,
339
476
return quirks ;
340
477
}
341
478
479
+ static u32 usb_detect_dynamic_quirks (struct usb_device * udev )
480
+ {
481
+ u16 vid = le16_to_cpu (udev -> descriptor .idVendor );
482
+ u16 pid = le16_to_cpu (udev -> descriptor .idProduct );
483
+ int i , flags = 0 ;
484
+
485
+ mutex_lock (& quirk_mutex );
486
+
487
+ for (i = 0 ; i < quirk_count ; i ++ ) {
488
+ if (vid == quirk_list [i ].vid && pid == quirk_list [i ].pid ) {
489
+ flags = quirk_list [i ].flags ;
490
+ break ;
491
+ }
492
+ }
493
+
494
+ mutex_unlock (& quirk_mutex );
495
+
496
+ return flags ;
497
+ }
498
+
342
499
/*
343
500
* Detect any quirks the device has, and do any housekeeping for it if needed.
344
501
*/
345
502
void usb_detect_quirks (struct usb_device * udev )
346
503
{
347
- udev -> quirks = __usb_detect_quirks (udev , usb_quirk_list );
504
+ udev -> quirks = usb_detect_static_quirks (udev , usb_quirk_list );
348
505
349
506
/*
350
507
* Pixart-based mice would trigger remote wakeup issue on AMD
351
508
* Yangtze chipset, so set them as RESET_RESUME flag.
352
509
*/
353
510
if (usb_amd_resume_quirk (udev ))
354
- udev -> quirks |= __usb_detect_quirks (udev ,
511
+ udev -> quirks |= usb_detect_static_quirks (udev ,
355
512
usb_amd_resume_quirk_list );
356
513
514
+ udev -> quirks ^= usb_detect_dynamic_quirks (udev );
515
+
357
516
if (udev -> quirks )
358
517
dev_dbg (& udev -> dev , "USB quirks for this device: %x\n" ,
359
518
udev -> quirks );
@@ -372,11 +531,19 @@ void usb_detect_interface_quirks(struct usb_device *udev)
372
531
{
373
532
u32 quirks ;
374
533
375
- quirks = __usb_detect_quirks (udev , usb_interface_quirk_list );
534
+ quirks = usb_detect_static_quirks (udev , usb_interface_quirk_list );
376
535
if (quirks == 0 )
377
536
return ;
378
537
379
538
dev_dbg (& udev -> dev , "USB interface quirks for this device: %x\n" ,
380
539
quirks );
381
540
udev -> quirks |= quirks ;
382
541
}
542
+
543
+ void usb_release_quirk_list (void )
544
+ {
545
+ mutex_lock (& quirk_mutex );
546
+ kfree (quirk_list );
547
+ quirk_list = NULL ;
548
+ mutex_unlock (& quirk_mutex );
549
+ }
0 commit comments