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