1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/usb.h>
21#include <linux/usb/hcd.h>
22#include "usb.h"
23
24static inline const char *plural(int n)
25{
26 return (n == 1 ? "" : "s");
27}
28
29static int is_rndis(struct usb_interface_descriptor *desc)
30{
31 return desc->bInterfaceClass == USB_CLASS_COMM
32 && desc->bInterfaceSubClass == 2
33 && desc->bInterfaceProtocol == 0xff;
34}
35
36static int is_activesync(struct usb_interface_descriptor *desc)
37{
38 return desc->bInterfaceClass == USB_CLASS_MISC
39 && desc->bInterfaceSubClass == 1
40 && desc->bInterfaceProtocol == 1;
41}
42
43int usb_choose_configuration(struct usb_device *udev)
44{
45 int i;
46 int num_configs;
47 int insufficient_power = 0;
48 struct usb_host_config *c, *best;
49
50 best = NULL;
51 c = udev->config;
52 num_configs = udev->descriptor.bNumConfigurations;
53 for (i = 0; i < num_configs; (i++, c++)) {
54 struct usb_interface_descriptor *desc = NULL;
55
56
57 if (c->desc.bNumInterfaces > 0)
58 desc = &c->intf_cache[0]->altsetting->desc;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80#if 0
81
82 if (bus_powered && (c->desc.bmAttributes &
83 USB_CONFIG_ATT_SELFPOWER))
84 continue;
85#endif
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 if (c->desc.bMaxPower * 2 > udev->bus_mA) {
101 insufficient_power++;
102 continue;
103 }
104
105
106
107
108
109
110 if (i == 0 && num_configs > 1 && desc &&
111 (is_rndis(desc) || is_activesync(desc))) {
112#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
113 continue;
114#else
115 best = c;
116#endif
117 }
118
119
120
121
122
123 else if (udev->descriptor.bDeviceClass !=
124 USB_CLASS_VENDOR_SPEC &&
125 (desc && desc->bInterfaceClass !=
126 USB_CLASS_VENDOR_SPEC)) {
127 best = c;
128 break;
129 }
130
131
132
133 else if (!best)
134 best = c;
135 }
136
137 if (insufficient_power > 0)
138 dev_info(&udev->dev, "rejected %d configuration%s "
139 "due to insufficient available bus power\n",
140 insufficient_power, plural(insufficient_power));
141
142 if (best) {
143 i = best->desc.bConfigurationValue;
144 dev_dbg(&udev->dev,
145 "configuration #%d chosen from %d choice%s\n",
146 i, num_configs, plural(num_configs));
147 } else {
148 i = -1;
149 dev_warn(&udev->dev,
150 "no configuration chosen from %d choice%s\n",
151 num_configs, plural(num_configs));
152 }
153 return i;
154}
155
156static int generic_probe(struct usb_device *udev)
157{
158 int err, c;
159
160
161
162
163 if (usb_device_is_owned(udev))
164 ;
165 else if (udev->authorized == 0)
166 dev_err(&udev->dev, "Device is not authorized for usage\n");
167 else {
168 c = usb_choose_configuration(udev);
169 if (c >= 0) {
170 err = usb_set_configuration(udev, c);
171 if (err) {
172 dev_err(&udev->dev, "can't set config #%d, error %d\n",
173 c, err);
174
175
176 }
177 }
178 }
179
180 usb_notify_add_device(udev);
181
182 return 0;
183}
184
185static void generic_disconnect(struct usb_device *udev)
186{
187 usb_notify_remove_device(udev);
188
189
190
191 if (udev->actconfig)
192 usb_set_configuration(udev, -1);
193}
194
195#ifdef CONFIG_PM
196
197static int generic_suspend(struct usb_device *udev, pm_message_t msg)
198{
199 int rc;
200
201
202
203
204
205
206 if (!udev->parent)
207 rc = hcd_bus_suspend(udev, msg);
208
209
210 else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
211 rc = 0;
212 else
213 rc = usb_port_suspend(udev, msg);
214
215 return rc;
216}
217
218static int generic_resume(struct usb_device *udev, pm_message_t msg)
219{
220 int rc;
221
222
223
224
225
226
227 if (!udev->parent)
228 rc = hcd_bus_resume(udev, msg);
229 else
230 rc = usb_port_resume(udev, msg);
231 return rc;
232}
233
234#endif
235
236struct usb_device_driver usb_generic_driver = {
237 .name = "usb",
238 .probe = generic_probe,
239 .disconnect = generic_disconnect,
240#ifdef CONFIG_PM
241 .suspend = generic_suspend,
242 .resume = generic_resume,
243#endif
244 .supports_autosuspend = 1,
245};
246