blob: e87e397061e8c0b839dc3d90d6dd8d355f6991e9 [file] [log] [blame]
Patrick Georgid21f68b2008-09-02 16:06:22 +00001/*
2 * This file is part of the libpayload project.
3 *
Stefan Reinauerb56f2d02010-03-25 22:17:36 +00004 * Copyright (C) 2008-2010 coresystems GmbH
Patrick Georgid21f68b2008-09-02 16:06:22 +00005 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000030//#define USB_DEBUG
31
Jordan Crousedb8c0ab2008-11-24 17:54:46 +000032#include <libpayload-config.h>
Jordan Crouse29061a52008-09-11 17:29:00 +000033#include <usb/usb.h>
Patrick Georgid21f68b2008-09-02 16:06:22 +000034
Julius Wernerd13e2c42013-09-17 22:16:04 -070035#define DR_DESC gen_bmRequestType(device_to_host, standard_type, dev_recp)
36
Patrick Georgid21f68b2008-09-02 16:06:22 +000037hci_t *usb_hcs = 0;
38
39hci_t *
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000040new_controller (void)
Patrick Georgid21f68b2008-09-02 16:06:22 +000041{
Julius Werner7234d602014-04-08 12:54:25 -070042 hci_t *controller = xzalloc(sizeof (hci_t));
43 controller->next = usb_hcs;
44 usb_hcs = controller;
Patrick Georgid21f68b2008-09-02 16:06:22 +000045 return controller;
46}
47
48void
49detach_controller (hci_t *controller)
50{
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000051 if (controller == NULL)
Patrick Georgid21f68b2008-09-02 16:06:22 +000052 return;
Julius Werner7234d602014-04-08 12:54:25 -070053
54 usb_detach_device(controller, 0); /* tear down root hub tree */
55
Patrick Georgid21f68b2008-09-02 16:06:22 +000056 if (usb_hcs == controller) {
57 usb_hcs = controller->next;
58 } else {
59 hci_t *it = usb_hcs;
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000060 while (it != NULL) {
Patrick Georgid21f68b2008-09-02 16:06:22 +000061 if (it->next == controller) {
62 it->next = controller->next;
63 return;
64 }
Anton Kochkov421303a2012-06-20 03:57:18 +040065 it = it->next;
Patrick Georgid21f68b2008-09-02 16:06:22 +000066 }
67 }
68}
69
70/**
Patrick Georgibbc52312011-11-04 12:06:06 +010071 * Shut down all controllers
72 */
73int
74usb_exit (void)
75{
Mathias Krause59c020a2013-03-24 19:40:02 +010076 while (usb_hcs != NULL) {
77 usb_hcs->shutdown(usb_hcs);
Patrick Georgibbc52312011-11-04 12:06:06 +010078 }
79 return 0;
80}
81
82/**
Patrick Georgid21f68b2008-09-02 16:06:22 +000083 * Polls all hubs on all USB controllers, to find out about device changes
84 */
85void
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000086usb_poll (void)
Patrick Georgid21f68b2008-09-02 16:06:22 +000087{
88 if (usb_hcs == 0)
89 return;
90 hci_t *controller = usb_hcs;
Patrick Georgidb89ec92011-11-18 11:56:38 +010091 while (controller != NULL) {
Patrick Georgid21f68b2008-09-02 16:06:22 +000092 int i;
93 for (i = 0; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +000094 if (controller->devices[i] != 0) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000095 controller->devices[i]->poll (controller->devices[i]);
Patrick Georgid21f68b2008-09-02 16:06:22 +000096 }
97 }
98 controller = controller->next;
99 }
100}
101
Julius Wernerd13e2c42013-09-17 22:16:04 -0700102usbdev_t *
Patrick Georgid21f68b2008-09-02 16:06:22 +0000103init_device_entry (hci_t *controller, int i)
104{
Julius Wernerd13e2c42013-09-17 22:16:04 -0700105 usbdev_t *dev = calloc(1, sizeof(usbdev_t));
106 if (!dev) {
107 usb_debug("no memory to allocate device structure\n");
108 return NULL;
109 }
Patrick Georgi4727c072008-10-16 19:20:51 +0000110 if (controller->devices[i] != 0)
Gabe Black93ded592012-11-01 15:44:10 -0700111 usb_debug("warning: device %d reassigned?\n", i);
Julius Wernerd13e2c42013-09-17 22:16:04 -0700112 controller->devices[i] = dev;
113 dev->controller = controller;
114 dev->address = -1;
115 dev->hub = -1;
116 dev->port = -1;
117 dev->init = usb_nop_init;
118 dev->init (controller->devices[i]);
119 return dev;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000120}
121
Julius Wernerd13e2c42013-09-17 22:16:04 -0700122int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000123set_feature (usbdev_t *dev, int endp, int feature, int rtype)
124{
125 dev_req_t dr;
126
127 dr.bmRequestType = rtype;
128 dr.data_dir = host_to_device;
129 dr.bRequest = SET_FEATURE;
130 dr.wValue = feature;
131 dr.wIndex = endp;
132 dr.wLength = 0;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700133
134 return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000135}
136
Julius Wernerd13e2c42013-09-17 22:16:04 -0700137int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000138get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
139{
140 dev_req_t dr;
141
142 dr.bmRequestType = rtype;
143 dr.data_dir = device_to_host;
144 dr.bRequest = GET_STATUS;
145 dr.wValue = 0;
146 dr.wIndex = intf;
147 dr.wLength = len;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700148
149 return dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000150}
151
Shawn Nematbakhshff5d0b22015-09-24 14:45:10 -0700152/*
153 * Certain Lexar / Micron USB 2.0 disks will fail the get_descriptor(DT_CFG)
154 * call due to timing issues. Work around this by making extra attempts on
155 * failure.
156 */
157#define GET_DESCRIPTOR_TRIES 3
158
Julius Wernerd13e2c42013-09-17 22:16:04 -0700159int
Shawn Nematbakhshff5d0b22015-09-24 14:45:10 -0700160get_descriptor(usbdev_t *dev, int rtype, int desc_type, int desc_idx,
Julius Wernerd13e2c42013-09-17 22:16:04 -0700161 void *data, size_t len)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000162{
Patrick Georgid21f68b2008-09-02 16:06:22 +0000163 dev_req_t dr;
Shawn Nematbakhshff5d0b22015-09-24 14:45:10 -0700164 int fail_tries = 0;
165 int ret = 0;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000166
Shawn Nematbakhshff5d0b22015-09-24 14:45:10 -0700167 while (fail_tries++ < GET_DESCRIPTOR_TRIES) {
168 dr.bmRequestType = rtype;
169 dr.bRequest = GET_DESCRIPTOR;
170 dr.wValue = desc_type << 8 | desc_idx;
171 dr.wIndex = 0;
172 dr.wLength = len;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000173
Shawn Nematbakhshff5d0b22015-09-24 14:45:10 -0700174 ret = dev->controller->control(dev, IN,
175 sizeof(dr), &dr, len, data);
176 if (ret)
177 udelay(10);
178 else
179 return 0;
180 }
181 return ret;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000182}
183
Julius Wernerd13e2c42013-09-17 22:16:04 -0700184int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000185set_configuration (usbdev_t *dev)
186{
187 dev_req_t dr;
188
189 dr.bmRequestType = 0;
190 dr.bRequest = SET_CONFIGURATION;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700191 dr.wValue = dev->configuration->bConfigurationValue;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000192 dr.wIndex = 0;
193 dr.wLength = 0;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700194
195 return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000196}
197
Nico Huber79e1f2f2012-06-01 09:50:11 +0200198int
Nico Huber5f595cb2012-05-21 16:19:05 +0200199clear_feature (usbdev_t *dev, int endp, int feature, int rtype)
200{
201 dev_req_t dr;
202
203 dr.bmRequestType = rtype;
204 dr.data_dir = host_to_device;
205 dr.bRequest = CLEAR_FEATURE;
206 dr.wValue = feature;
207 dr.wIndex = endp;
208 dr.wLength = 0;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700209
Julius Wernere9738db2013-02-21 13:41:40 -0800210 return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0;
Nico Huber5f595cb2012-05-21 16:19:05 +0200211}
212
Patrick Georgid21f68b2008-09-02 16:06:22 +0000213int
214clear_stall (endpoint_t *ep)
215{
Julius Wernerd13e2c42013-09-17 22:16:04 -0700216 int ret = clear_feature (ep->dev, ep->endpoint, ENDPOINT_HALT,
217 gen_bmRequestType (host_to_device, standard_type, endp_recp));
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000218 ep->toggle = 0;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200219 return ret;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000220}
221
222/* returns free address or -1 */
223static int
224get_free_address (hci_t *controller)
225{
Julius Werner6af43802014-04-28 16:04:24 -0700226 int i = controller->latest_address + 1;
227 for (; i != controller->latest_address; i++) {
228 if (i >= ARRAY_SIZE(controller->devices) || i < 1) {
229 usb_debug("WARNING: Device addresses for controller %#x"
230 " wrapped around!\n", controller->reg_base);
231 i = 0;
232 continue;
233 }
234 if (controller->devices[i] == 0) {
235 controller->latest_address = i;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000236 return i;
Julius Werner6af43802014-04-28 16:04:24 -0700237 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000238 }
Gabe Black93ded592012-11-01 15:44:10 -0700239 usb_debug ("no free address found\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000240 return -1; // no free address
241}
242
Patrick Georgi482af6d2013-05-24 15:48:56 +0200243int
Julius Wernere00ba212013-09-24 20:03:54 -0700244usb_decode_mps0(usb_speed speed, u8 bMaxPacketSize0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000245{
Julius Wernere00ba212013-09-24 20:03:54 -0700246 switch (speed) {
247 case LOW_SPEED:
248 if (bMaxPacketSize0 != 8) {
249 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
250 bMaxPacketSize0 = 8;
251 }
252 return bMaxPacketSize0;
253 case FULL_SPEED:
254 switch (bMaxPacketSize0) {
255 case 8: case 16: case 32: case 64:
256 return bMaxPacketSize0;
257 default:
258 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
259 return 8;
260 }
261 case HIGH_SPEED:
262 if (bMaxPacketSize0 != 64) {
263 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
264 bMaxPacketSize0 = 64;
265 }
266 return bMaxPacketSize0;
267 case SUPER_SPEED:
268 if (bMaxPacketSize0 != 9) {
269 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
270 bMaxPacketSize0 = 9;
271 }
Chunfeng Yun08e30132015-05-07 15:28:19 +0800272 return 1 << bMaxPacketSize0;
Julius Wernere00ba212013-09-24 20:03:54 -0700273 default: /* GCC is stupid and cannot deal with enums correctly */
274 return 8;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000275 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200276}
277
Nico Huberaee44fa2013-06-06 10:20:35 +0200278/* Normalize bInterval to log2 of microframes */
279static int
Julius Wernere00ba212013-09-24 20:03:54 -0700280usb_decode_interval(usb_speed speed, const endpoint_type type, const unsigned char bInterval)
Nico Huberaee44fa2013-06-06 10:20:35 +0200281{
282#define LOG2(a) ((sizeof(unsigned) << 3) - __builtin_clz(a) - 1)
283 switch (speed) {
284 case LOW_SPEED:
285 switch (type) {
286 case ISOCHRONOUS: case INTERRUPT:
287 return LOG2(bInterval) + 3;
288 default:
289 return 0;
290 }
291 case FULL_SPEED:
292 switch (type) {
293 case ISOCHRONOUS:
294 return (bInterval - 1) + 3;
295 case INTERRUPT:
296 return LOG2(bInterval) + 3;
297 default:
298 return 0;
299 }
300 case HIGH_SPEED:
301 switch (type) {
302 case ISOCHRONOUS: case INTERRUPT:
303 return bInterval - 1;
304 default:
305 return LOG2(bInterval);
306 }
307 case SUPER_SPEED:
308 switch (type) {
309 case ISOCHRONOUS: case INTERRUPT:
310 return bInterval - 1;
311 default:
312 return 0;
313 }
314 default:
315 return 0;
316 }
317#undef LOG2
318}
319
Julius Wernerd13e2c42013-09-17 22:16:04 -0700320usbdev_t *
Julius Wernere00ba212013-09-24 20:03:54 -0700321generic_set_address (hci_t *controller, usb_speed speed,
322 int hubport, int hubaddr)
323{
324 int adr = get_free_address (controller); // address to set
325 dev_req_t dr;
326
327 memset (&dr, 0, sizeof (dr));
328 dr.data_dir = host_to_device;
329 dr.req_type = standard_type;
330 dr.req_recp = dev_recp;
331 dr.bRequest = SET_ADDRESS;
332 dr.wValue = adr;
333 dr.wIndex = 0;
334 dr.wLength = 0;
335
Julius Wernerd13e2c42013-09-17 22:16:04 -0700336 usbdev_t *dev = init_device_entry(controller, adr);
337 if (!dev)
338 return NULL;
339
Julius Wernere00ba212013-09-24 20:03:54 -0700340 // dummy values for registering the address
341 dev->address = 0;
342 dev->hub = hubaddr;
343 dev->port = hubport;
344 dev->speed = speed;
345 dev->endpoints[0].dev = dev;
346 dev->endpoints[0].endpoint = 0;
347 dev->endpoints[0].maxpacketsize = 8;
348 dev->endpoints[0].toggle = 0;
349 dev->endpoints[0].direction = SETUP;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700350 dev->endpoints[0].type = CONTROL;
Julius Wernere00ba212013-09-24 20:03:54 -0700351 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0) {
352 usb_debug ("set_address failed\n");
Julius Wernerd13e2c42013-09-17 22:16:04 -0700353 usb_detach_device (controller, adr);
354 return NULL;
Julius Wernere00ba212013-09-24 20:03:54 -0700355 }
356 mdelay (SET_ADDRESS_MDELAY);
357
Julius Wernerd13e2c42013-09-17 22:16:04 -0700358 u8 buf[8];
359 dev->address = adr;
360 if (get_descriptor (dev, DR_DESC, DT_DEV, 0, buf, sizeof(buf))
361 != sizeof(buf)) {
362 usb_debug("first get_descriptor(DT_DEV) failed\n");
363 usb_detach_device (controller, adr);
364 return NULL;
365 }
366 dev->endpoints[0].maxpacketsize = usb_decode_mps0(speed, buf[7]);
367
368 return dev;
Julius Wernere00ba212013-09-24 20:03:54 -0700369}
370
Patrick Georgi482af6d2013-05-24 15:48:56 +0200371static int
Julius Wernere00ba212013-09-24 20:03:54 -0700372set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
Patrick Georgi482af6d2013-05-24 15:48:56 +0200373{
Julius Wernerd13e2c42013-09-17 22:16:04 -0700374 usbdev_t *dev = controller->set_address(controller, speed,
375 hubport, hubaddr);
376 if (!dev) {
Patrick Georgi482af6d2013-05-24 15:48:56 +0200377 usb_debug ("set_address failed\n");
378 return -1;
379 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200380
Julius Wernerd13e2c42013-09-17 22:16:04 -0700381 dev->descriptor = malloc(sizeof(*dev->descriptor));
382 if (!dev->descriptor || get_descriptor (dev, DR_DESC, DT_DEV, 0,
383 dev->descriptor, sizeof(*dev->descriptor))
384 != sizeof(*dev->descriptor)) {
385 usb_debug ("get_descriptor(DT_DEV) failed\n");
386 usb_detach_device (controller, dev->address);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000387 return -1;
388 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000389
Julius Wernerd13e2c42013-09-17 22:16:04 -0700390 usb_debug ("* found device (0x%04x:0x%04x, USB %x.%x, MPS0: %d)\n",
391 dev->descriptor->idVendor, dev->descriptor->idProduct,
392 dev->descriptor->bcdUSB >> 8, dev->descriptor->bcdUSB & 0xff,
393 dev->endpoints[0].maxpacketsize);
394 dev->quirks = usb_quirk_check(dev->descriptor->idVendor,
395 dev->descriptor->idProduct);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000396
Julius Wernerd13e2c42013-09-17 22:16:04 -0700397 usb_debug ("device has %d configurations\n",
398 dev->descriptor->bNumConfigurations);
399 if (dev->descriptor->bNumConfigurations == 0) {
400 /* device isn't usable */
401 usb_debug ("... no usable configuration!\n");
402 usb_detach_device (controller, dev->address);
403 return -1;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000404 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000405
Julius Wernerd13e2c42013-09-17 22:16:04 -0700406 u16 buf[2];
407 if (get_descriptor (dev, DR_DESC, DT_CFG, 0, buf, sizeof(buf))
408 != sizeof(buf)) {
409 usb_debug ("first get_descriptor(DT_CFG) failed\n");
410 usb_detach_device (controller, dev->address);
411 return -1;
412 }
Patrick Georgif72d328d2014-11-10 16:50:21 +0100413 /* workaround for some USB devices: wait until they're ready, or
414 * they send a NAK when they're not allowed to do. 1ms is enough */
415 mdelay(1);
Julius Wernerd13e2c42013-09-17 22:16:04 -0700416 dev->configuration = malloc(buf[1]);
417 if (!dev->configuration) {
418 usb_debug ("could not allocate %d bytes for DT_CFG\n", buf[1]);
419 usb_detach_device (controller, dev->address);
420 return -1;
421 }
422 if (get_descriptor (dev, DR_DESC, DT_CFG, 0, dev->configuration,
423 buf[1]) != buf[1]) {
424 usb_debug ("get_descriptor(DT_CFG) failed\n");
425 usb_detach_device (controller, dev->address);
426 return -1;
427 }
428 configuration_descriptor_t *cd = dev->configuration;
429 if (cd->wTotalLength != buf[1]) {
430 usb_debug ("configuration descriptor size changed, aborting\n");
431 usb_detach_device (controller, dev->address);
432 return -1;
433 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200434
Julius Wernerd13e2c42013-09-17 22:16:04 -0700435 /*
436 * If the device is not well known (ifnum == -1), we use the first
437 * interface we encounter, as there was no need to implement something
438 * else for the time being. If you need it, see the SetInterface and
439 * GetInterface functions in the USB specification and set it yourself.
440 */
441 usb_debug ("device has %x interfaces\n", cd->bNumInterfaces);
442 int ifnum = usb_interface_check(dev->descriptor->idVendor,
443 dev->descriptor->idProduct);
444 if (cd->bNumInterfaces > 1 && ifnum < 0)
445 usb_debug ("NOTICE: Your device has multiple interfaces and\n"
446 "this driver will only use the first one. That may\n"
447 "be the wrong choice and cause the device to not\n"
448 "work correctly. Please report this case\n"
449 "(including the above debugging output) to\n"
450 "coreboot@coreboot.org to have the device added to\n"
451 "the list of well-known quirks.\n");
Patrick Georgi482af6d2013-05-24 15:48:56 +0200452
Julius Wernerd13e2c42013-09-17 22:16:04 -0700453 u8 *end = (void *)dev->configuration + cd->wTotalLength;
454 interface_descriptor_t *intf;
455 u8 *ptr;
456
457 /* Find our interface (or the first good one if we don't know) */
458 for (ptr = (void *)dev->configuration + sizeof(*cd); ; ptr += ptr[0]) {
459 if (ptr + 2 > end || !ptr[0] || ptr + ptr[0] > end) {
460 usb_debug ("Couldn't find usable DT_INTF\n");
461 usb_detach_device (controller, dev->address);
462 return -1;
463 }
464 if (ptr[1] != DT_INTF)
465 continue;
466 intf = (void *)ptr;
467 if (intf->bLength != sizeof(*intf)) {
468 usb_debug ("Skipping broken DT_INTF\n");
469 continue;
470 }
471 if (ifnum >= 0 && intf->bInterfaceNumber != ifnum)
472 continue;
473 usb_debug ("Interface %d: class 0x%x, sub 0x%x. proto 0x%x\n",
474 intf->bInterfaceNumber, intf->bInterfaceClass,
475 intf->bInterfaceSubClass, intf->bInterfaceProtocol);
476 ptr += sizeof(*intf);
477 break;
478 }
479
480 /* Gather up all endpoints belonging to this inteface */
481 dev->num_endp = 1;
482 for (; ptr + 2 <= end && ptr[0] && ptr + ptr[0] <= end; ptr += ptr[0]) {
483 if (ptr[1] == DT_INTF || ptr[1] == DT_CFG ||
484 dev->num_endp >= ARRAY_SIZE(dev->endpoints))
485 break;
486 if (ptr[1] != DT_ENDP)
487 continue;
488
489 endpoint_descriptor_t *desc = (void *)ptr;
490 static const char *transfertypes[4] = {
491 "control", "isochronous", "bulk", "interrupt"
492 };
493 usb_debug (" #Endpoint %d (%s), max packet size %x, type %s\n",
494 desc->bEndpointAddress & 0x7f,
495 (desc->bEndpointAddress & 0x80) ? "in" : "out",
496 desc->wMaxPacketSize,
497 transfertypes[desc->bmAttributes & 0x3]);
498
499 endpoint_t *ep = &dev->endpoints[dev->num_endp++];
500 ep->dev = dev;
501 ep->endpoint = desc->bEndpointAddress;
502 ep->toggle = 0;
503 ep->maxpacketsize = desc->wMaxPacketSize;
504 ep->direction = (desc->bEndpointAddress & 0x80) ? IN : OUT;
505 ep->type = desc->bmAttributes & 0x3;
506 ep->interval = usb_decode_interval (dev->speed, ep->type,
507 desc->bInterval);
508 }
509
510 if ((controller->finish_device_config &&
511 controller->finish_device_config(dev)) ||
512 set_configuration(dev) < 0) {
513 usb_debug ("Could not finalize device configuration\n");
514 usb_detach_device (controller, dev->address);
515 return -1;
516 }
517
518 int class = dev->descriptor->bDeviceClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000519 if (class == 0)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700520 class = intf->bInterfaceClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000521
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000522 enum {
523 audio_device = 0x01,
524 comm_device = 0x02,
525 hid_device = 0x03,
526 physical_device = 0x05,
527 imaging_device = 0x06,
528 printer_device = 0x07,
529 msc_device = 0x08,
530 hub_device = 0x09,
531 cdc_device = 0x0a,
532 ccid_device = 0x0b,
533 security_device = 0x0d,
534 video_device = 0x0e,
535 healthcare_device = 0x0f,
536 diagnostic_device = 0xdc,
537 wireless_device = 0xe0,
538 misc_device = 0xef,
539 };
Julius Wernerd13e2c42013-09-17 22:16:04 -0700540 usb_debug("Class: ");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000541 switch (class) {
542 case audio_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700543 usb_debug("audio\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000544 break;
545 case comm_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700546 usb_debug("communication\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000547 break;
548 case hid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700549 usb_debug ("HID\n");
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700550#if IS_ENABLED(CONFIG_LP_USB_HID)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700551 dev->init = usb_hid_init;
552 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000553#else
Gabe Black93ded592012-11-01 15:44:10 -0700554 usb_debug ("NOTICE: USB HID support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000555#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000556 break;
557 case physical_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700558 usb_debug("physical\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000559 break;
560 case imaging_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700561 usb_debug("camera\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000562 break;
563 case printer_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700564 usb_debug("printer\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000565 break;
566 case msc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700567 usb_debug ("MSC\n");
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700568#if IS_ENABLED(CONFIG_LP_USB_MSC)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700569 dev->init = usb_msc_init;
570 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000571#else
Gabe Black93ded592012-11-01 15:44:10 -0700572 usb_debug ("NOTICE: USB MSC support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000573#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000574 break;
575 case hub_device:
Julius Werner752fba72015-07-09 16:29:10 -0700576 usb_debug ("hub\n");
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700577#if IS_ENABLED(CONFIG_LP_USB_HUB)
Julius Werner752fba72015-07-09 16:29:10 -0700578 dev->init = usb_hub_init;
579 return dev->address;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000580#else
Julius Werner752fba72015-07-09 16:29:10 -0700581 usb_debug ("NOTICE: USB hub support not compiled in\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000582#endif
583 break;
584 case cdc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700585 usb_debug("CDC\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000586 break;
587 case ccid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700588 usb_debug("smartcard / CCID\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000589 break;
590 case security_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700591 usb_debug("content security\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000592 break;
593 case video_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700594 usb_debug("video\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000595 break;
596 case healthcare_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700597 usb_debug("healthcare\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000598 break;
599 case diagnostic_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700600 usb_debug("diagnostic\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000601 break;
602 case wireless_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700603 usb_debug("wireless\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000604 break;
605 default:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700606 usb_debug("unsupported class %x\n", class);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000607 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000608 }
Julius Wernerd13e2c42013-09-17 22:16:04 -0700609 dev->init = usb_generic_init;
610 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000611}
Patrick Georgi4727c072008-10-16 19:20:51 +0000612
Nico Huber79e1f2f2012-06-01 09:50:11 +0200613/*
614 * Should be called by the hub drivers whenever a physical detach occurs
615 * and can be called by usb class drivers if they are unsatisfied with a
616 * malfunctioning device.
617 */
Patrick Georgi4727c072008-10-16 19:20:51 +0000618void
619usb_detach_device(hci_t *controller, int devno)
620{
Nico Huber79e1f2f2012-06-01 09:50:11 +0200621 /* check if device exists, as we may have
622 been called yet by the usb class driver */
623 if (controller->devices[devno]) {
624 controller->devices[devno]->destroy (controller->devices[devno]);
Julius Wernere00ba212013-09-24 20:03:54 -0700625 if (controller->destroy_device)
626 controller->destroy_device(controller, devno);
Aaron Durbine3260ec2015-07-31 17:08:00 -0500627 /* Tear down the device itself *after* destroy_device()
628 * has had a chance to interoogate it. */
629 free(controller->devices[devno]);
630 controller->devices[devno] = NULL;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200631 }
Patrick Georgi4727c072008-10-16 19:20:51 +0000632}
633
634int
Julius Wernere00ba212013-09-24 20:03:54 -0700635usb_attach_device(hci_t *controller, int hubaddress, int port, usb_speed speed)
Patrick Georgi4727c072008-10-16 19:20:51 +0000636{
Julius Wernere00ba212013-09-24 20:03:54 -0700637 static const char* speeds[] = { "full", "low", "high", "super" };
638 usb_debug ("%sspeed device\n", (speed < sizeof(speeds) / sizeof(char*))
639 ? speeds[speed] : "invalid value - no");
Nico Huber1ab60752012-05-23 09:21:54 +0200640 int newdev = set_address (controller, speed, port, hubaddress);
Patrick Georgi4727c072008-10-16 19:20:51 +0000641 if (newdev == -1)
642 return -1;
643 usbdev_t *newdev_t = controller->devices[newdev];
Patrick Georgi4727c072008-10-16 19:20:51 +0000644 // determine responsible driver - current done in set_address
645 newdev_t->init (newdev_t);
Nico Huberd8a66802012-06-21 11:21:23 +0200646 /* init() may have called usb_detach_device() yet, so check */
647 return controller->devices[newdev] ? newdev : -1;
Patrick Georgi4727c072008-10-16 19:20:51 +0000648}
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000649
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800650static void
651usb_generic_destroy (usbdev_t *dev)
652{
653 if (usb_generic_remove)
654 usb_generic_remove(dev);
655}
656
657void
658usb_generic_init (usbdev_t *dev)
659{
660 dev->data = NULL;
661 dev->destroy = usb_generic_destroy;
662
663 if (usb_generic_create)
664 usb_generic_create(dev);
Shawn Nematbakhsh7faff542014-04-15 21:34:30 -0700665
666 if (dev->data == NULL) {
667 usb_debug("Detaching device not used by payload\n");
668 usb_detach_device(dev->controller, dev->address);
669 }
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800670}
Yunzhi Liebd3da72015-07-02 15:28:11 +0800671
672/*
673 * returns the address of the closest USB2.0 hub, which is responsible for
674 * split transactions, along with the number of the used downstream port
675 */
676int closest_usb2_hub(const usbdev_t *dev, int *const addr, int *const port)
677{
678 const usbdev_t *usb1dev;
679
680 do {
681 usb1dev = dev;
682 if ((dev->hub >= 0) && (dev->hub < 128))
683 dev = dev->controller->devices[dev->hub];
684 else
685 dev = NULL;
686 } while (dev && (dev->speed < 2));
687
688 if (dev) {
689 *addr = usb1dev->hub;
690 *port = usb1dev->port;
691 return 0;
692 }
693
694 usb_debug("Couldn't find closest USB2.0 hub.\n");
695 return 1;
696}