blob: bfb697d619caafc26fa19fffd15bbf7162bd96f4 [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
Varadarajan Narayanan8e0ffe22016-03-17 14:43:35 +0530278int speed_to_default_mps(usb_speed speed)
279{
280 switch (speed) {
281 case LOW_SPEED:
282 return 8;
283 case FULL_SPEED:
284 case HIGH_SPEED:
285 return 64;
286 case SUPER_SPEED:
287 default:
288 return 512;
289 }
290}
291
Nico Huberaee44fa2013-06-06 10:20:35 +0200292/* Normalize bInterval to log2 of microframes */
293static int
Julius Wernere00ba212013-09-24 20:03:54 -0700294usb_decode_interval(usb_speed speed, const endpoint_type type, const unsigned char bInterval)
Nico Huberaee44fa2013-06-06 10:20:35 +0200295{
296#define LOG2(a) ((sizeof(unsigned) << 3) - __builtin_clz(a) - 1)
297 switch (speed) {
298 case LOW_SPEED:
299 switch (type) {
300 case ISOCHRONOUS: case INTERRUPT:
301 return LOG2(bInterval) + 3;
302 default:
303 return 0;
304 }
305 case FULL_SPEED:
306 switch (type) {
307 case ISOCHRONOUS:
308 return (bInterval - 1) + 3;
309 case INTERRUPT:
310 return LOG2(bInterval) + 3;
311 default:
312 return 0;
313 }
314 case HIGH_SPEED:
315 switch (type) {
316 case ISOCHRONOUS: case INTERRUPT:
317 return bInterval - 1;
318 default:
319 return LOG2(bInterval);
320 }
321 case SUPER_SPEED:
322 switch (type) {
323 case ISOCHRONOUS: case INTERRUPT:
324 return bInterval - 1;
325 default:
326 return 0;
327 }
328 default:
329 return 0;
330 }
331#undef LOG2
332}
333
Julius Wernerd13e2c42013-09-17 22:16:04 -0700334usbdev_t *
Julius Wernere00ba212013-09-24 20:03:54 -0700335generic_set_address (hci_t *controller, usb_speed speed,
336 int hubport, int hubaddr)
337{
338 int adr = get_free_address (controller); // address to set
339 dev_req_t dr;
340
341 memset (&dr, 0, sizeof (dr));
342 dr.data_dir = host_to_device;
343 dr.req_type = standard_type;
344 dr.req_recp = dev_recp;
345 dr.bRequest = SET_ADDRESS;
346 dr.wValue = adr;
347 dr.wIndex = 0;
348 dr.wLength = 0;
349
Julius Wernerd13e2c42013-09-17 22:16:04 -0700350 usbdev_t *dev = init_device_entry(controller, adr);
351 if (!dev)
352 return NULL;
353
Julius Wernere00ba212013-09-24 20:03:54 -0700354 // dummy values for registering the address
355 dev->address = 0;
356 dev->hub = hubaddr;
357 dev->port = hubport;
358 dev->speed = speed;
359 dev->endpoints[0].dev = dev;
360 dev->endpoints[0].endpoint = 0;
361 dev->endpoints[0].maxpacketsize = 8;
362 dev->endpoints[0].toggle = 0;
363 dev->endpoints[0].direction = SETUP;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700364 dev->endpoints[0].type = CONTROL;
Julius Wernere00ba212013-09-24 20:03:54 -0700365 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0) {
366 usb_debug ("set_address failed\n");
Julius Wernerd13e2c42013-09-17 22:16:04 -0700367 usb_detach_device (controller, adr);
368 return NULL;
Julius Wernere00ba212013-09-24 20:03:54 -0700369 }
370 mdelay (SET_ADDRESS_MDELAY);
371
Julius Wernerd13e2c42013-09-17 22:16:04 -0700372 u8 buf[8];
373 dev->address = adr;
374 if (get_descriptor (dev, DR_DESC, DT_DEV, 0, buf, sizeof(buf))
375 != sizeof(buf)) {
376 usb_debug("first get_descriptor(DT_DEV) failed\n");
377 usb_detach_device (controller, adr);
378 return NULL;
379 }
380 dev->endpoints[0].maxpacketsize = usb_decode_mps0(speed, buf[7]);
381
382 return dev;
Julius Wernere00ba212013-09-24 20:03:54 -0700383}
384
Patrick Georgi482af6d2013-05-24 15:48:56 +0200385static int
Julius Wernere00ba212013-09-24 20:03:54 -0700386set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
Patrick Georgi482af6d2013-05-24 15:48:56 +0200387{
Julius Wernerd13e2c42013-09-17 22:16:04 -0700388 usbdev_t *dev = controller->set_address(controller, speed,
389 hubport, hubaddr);
390 if (!dev) {
Patrick Georgi482af6d2013-05-24 15:48:56 +0200391 usb_debug ("set_address failed\n");
392 return -1;
393 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200394
Julius Wernerd13e2c42013-09-17 22:16:04 -0700395 dev->descriptor = malloc(sizeof(*dev->descriptor));
396 if (!dev->descriptor || get_descriptor (dev, DR_DESC, DT_DEV, 0,
397 dev->descriptor, sizeof(*dev->descriptor))
398 != sizeof(*dev->descriptor)) {
399 usb_debug ("get_descriptor(DT_DEV) failed\n");
400 usb_detach_device (controller, dev->address);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000401 return -1;
402 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000403
Julius Wernerd13e2c42013-09-17 22:16:04 -0700404 usb_debug ("* found device (0x%04x:0x%04x, USB %x.%x, MPS0: %d)\n",
405 dev->descriptor->idVendor, dev->descriptor->idProduct,
406 dev->descriptor->bcdUSB >> 8, dev->descriptor->bcdUSB & 0xff,
407 dev->endpoints[0].maxpacketsize);
408 dev->quirks = usb_quirk_check(dev->descriptor->idVendor,
409 dev->descriptor->idProduct);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000410
Julius Wernerd13e2c42013-09-17 22:16:04 -0700411 usb_debug ("device has %d configurations\n",
412 dev->descriptor->bNumConfigurations);
413 if (dev->descriptor->bNumConfigurations == 0) {
414 /* device isn't usable */
415 usb_debug ("... no usable configuration!\n");
416 usb_detach_device (controller, dev->address);
417 return -1;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000418 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000419
Julius Wernerd13e2c42013-09-17 22:16:04 -0700420 u16 buf[2];
421 if (get_descriptor (dev, DR_DESC, DT_CFG, 0, buf, sizeof(buf))
422 != sizeof(buf)) {
423 usb_debug ("first get_descriptor(DT_CFG) failed\n");
424 usb_detach_device (controller, dev->address);
425 return -1;
426 }
Patrick Georgif72d328d2014-11-10 16:50:21 +0100427 /* workaround for some USB devices: wait until they're ready, or
428 * they send a NAK when they're not allowed to do. 1ms is enough */
429 mdelay(1);
Julius Wernerd13e2c42013-09-17 22:16:04 -0700430 dev->configuration = malloc(buf[1]);
431 if (!dev->configuration) {
432 usb_debug ("could not allocate %d bytes for DT_CFG\n", buf[1]);
433 usb_detach_device (controller, dev->address);
434 return -1;
435 }
436 if (get_descriptor (dev, DR_DESC, DT_CFG, 0, dev->configuration,
437 buf[1]) != buf[1]) {
438 usb_debug ("get_descriptor(DT_CFG) failed\n");
439 usb_detach_device (controller, dev->address);
440 return -1;
441 }
442 configuration_descriptor_t *cd = dev->configuration;
443 if (cd->wTotalLength != buf[1]) {
444 usb_debug ("configuration descriptor size changed, aborting\n");
445 usb_detach_device (controller, dev->address);
446 return -1;
447 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200448
Julius Wernerd13e2c42013-09-17 22:16:04 -0700449 /*
450 * If the device is not well known (ifnum == -1), we use the first
451 * interface we encounter, as there was no need to implement something
452 * else for the time being. If you need it, see the SetInterface and
453 * GetInterface functions in the USB specification and set it yourself.
454 */
455 usb_debug ("device has %x interfaces\n", cd->bNumInterfaces);
456 int ifnum = usb_interface_check(dev->descriptor->idVendor,
457 dev->descriptor->idProduct);
458 if (cd->bNumInterfaces > 1 && ifnum < 0)
459 usb_debug ("NOTICE: Your device has multiple interfaces and\n"
460 "this driver will only use the first one. That may\n"
461 "be the wrong choice and cause the device to not\n"
462 "work correctly. Please report this case\n"
463 "(including the above debugging output) to\n"
464 "coreboot@coreboot.org to have the device added to\n"
465 "the list of well-known quirks.\n");
Patrick Georgi482af6d2013-05-24 15:48:56 +0200466
Julius Wernerd13e2c42013-09-17 22:16:04 -0700467 u8 *end = (void *)dev->configuration + cd->wTotalLength;
468 interface_descriptor_t *intf;
469 u8 *ptr;
470
471 /* Find our interface (or the first good one if we don't know) */
472 for (ptr = (void *)dev->configuration + sizeof(*cd); ; ptr += ptr[0]) {
473 if (ptr + 2 > end || !ptr[0] || ptr + ptr[0] > end) {
474 usb_debug ("Couldn't find usable DT_INTF\n");
475 usb_detach_device (controller, dev->address);
476 return -1;
477 }
478 if (ptr[1] != DT_INTF)
479 continue;
480 intf = (void *)ptr;
481 if (intf->bLength != sizeof(*intf)) {
482 usb_debug ("Skipping broken DT_INTF\n");
483 continue;
484 }
485 if (ifnum >= 0 && intf->bInterfaceNumber != ifnum)
486 continue;
487 usb_debug ("Interface %d: class 0x%x, sub 0x%x. proto 0x%x\n",
488 intf->bInterfaceNumber, intf->bInterfaceClass,
489 intf->bInterfaceSubClass, intf->bInterfaceProtocol);
490 ptr += sizeof(*intf);
491 break;
492 }
493
494 /* Gather up all endpoints belonging to this inteface */
495 dev->num_endp = 1;
496 for (; ptr + 2 <= end && ptr[0] && ptr + ptr[0] <= end; ptr += ptr[0]) {
497 if (ptr[1] == DT_INTF || ptr[1] == DT_CFG ||
498 dev->num_endp >= ARRAY_SIZE(dev->endpoints))
499 break;
500 if (ptr[1] != DT_ENDP)
501 continue;
502
503 endpoint_descriptor_t *desc = (void *)ptr;
504 static const char *transfertypes[4] = {
505 "control", "isochronous", "bulk", "interrupt"
506 };
507 usb_debug (" #Endpoint %d (%s), max packet size %x, type %s\n",
508 desc->bEndpointAddress & 0x7f,
509 (desc->bEndpointAddress & 0x80) ? "in" : "out",
510 desc->wMaxPacketSize,
511 transfertypes[desc->bmAttributes & 0x3]);
512
513 endpoint_t *ep = &dev->endpoints[dev->num_endp++];
514 ep->dev = dev;
515 ep->endpoint = desc->bEndpointAddress;
516 ep->toggle = 0;
517 ep->maxpacketsize = desc->wMaxPacketSize;
518 ep->direction = (desc->bEndpointAddress & 0x80) ? IN : OUT;
519 ep->type = desc->bmAttributes & 0x3;
520 ep->interval = usb_decode_interval (dev->speed, ep->type,
521 desc->bInterval);
522 }
523
524 if ((controller->finish_device_config &&
525 controller->finish_device_config(dev)) ||
526 set_configuration(dev) < 0) {
527 usb_debug ("Could not finalize device configuration\n");
528 usb_detach_device (controller, dev->address);
529 return -1;
530 }
531
532 int class = dev->descriptor->bDeviceClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000533 if (class == 0)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700534 class = intf->bInterfaceClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000535
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000536 enum {
537 audio_device = 0x01,
538 comm_device = 0x02,
539 hid_device = 0x03,
540 physical_device = 0x05,
541 imaging_device = 0x06,
542 printer_device = 0x07,
543 msc_device = 0x08,
544 hub_device = 0x09,
545 cdc_device = 0x0a,
546 ccid_device = 0x0b,
547 security_device = 0x0d,
548 video_device = 0x0e,
549 healthcare_device = 0x0f,
550 diagnostic_device = 0xdc,
551 wireless_device = 0xe0,
552 misc_device = 0xef,
553 };
Julius Wernerd13e2c42013-09-17 22:16:04 -0700554 usb_debug("Class: ");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000555 switch (class) {
556 case audio_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700557 usb_debug("audio\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000558 break;
559 case comm_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700560 usb_debug("communication\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000561 break;
562 case hid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700563 usb_debug ("HID\n");
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700564#if IS_ENABLED(CONFIG_LP_USB_HID)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700565 dev->init = usb_hid_init;
566 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000567#else
Gabe Black93ded592012-11-01 15:44:10 -0700568 usb_debug ("NOTICE: USB HID support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000569#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000570 break;
571 case physical_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700572 usb_debug("physical\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000573 break;
574 case imaging_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700575 usb_debug("camera\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000576 break;
577 case printer_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700578 usb_debug("printer\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000579 break;
580 case msc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700581 usb_debug ("MSC\n");
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700582#if IS_ENABLED(CONFIG_LP_USB_MSC)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700583 dev->init = usb_msc_init;
584 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000585#else
Gabe Black93ded592012-11-01 15:44:10 -0700586 usb_debug ("NOTICE: USB MSC support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000587#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000588 break;
589 case hub_device:
Julius Werner752fba72015-07-09 16:29:10 -0700590 usb_debug ("hub\n");
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700591#if IS_ENABLED(CONFIG_LP_USB_HUB)
Julius Werner752fba72015-07-09 16:29:10 -0700592 dev->init = usb_hub_init;
593 return dev->address;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000594#else
Julius Werner752fba72015-07-09 16:29:10 -0700595 usb_debug ("NOTICE: USB hub support not compiled in\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000596#endif
597 break;
598 case cdc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700599 usb_debug("CDC\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000600 break;
601 case ccid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700602 usb_debug("smartcard / CCID\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000603 break;
604 case security_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700605 usb_debug("content security\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000606 break;
607 case video_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700608 usb_debug("video\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000609 break;
610 case healthcare_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700611 usb_debug("healthcare\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000612 break;
613 case diagnostic_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700614 usb_debug("diagnostic\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000615 break;
616 case wireless_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700617 usb_debug("wireless\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000618 break;
619 default:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700620 usb_debug("unsupported class %x\n", class);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000621 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000622 }
Julius Wernerd13e2c42013-09-17 22:16:04 -0700623 dev->init = usb_generic_init;
624 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000625}
Patrick Georgi4727c072008-10-16 19:20:51 +0000626
Nico Huber79e1f2f2012-06-01 09:50:11 +0200627/*
628 * Should be called by the hub drivers whenever a physical detach occurs
629 * and can be called by usb class drivers if they are unsatisfied with a
630 * malfunctioning device.
631 */
Patrick Georgi4727c072008-10-16 19:20:51 +0000632void
633usb_detach_device(hci_t *controller, int devno)
634{
Nico Huber79e1f2f2012-06-01 09:50:11 +0200635 /* check if device exists, as we may have
636 been called yet by the usb class driver */
637 if (controller->devices[devno]) {
638 controller->devices[devno]->destroy (controller->devices[devno]);
Julius Wernere00ba212013-09-24 20:03:54 -0700639 if (controller->destroy_device)
640 controller->destroy_device(controller, devno);
Aaron Durbine3260ec2015-07-31 17:08:00 -0500641 /* Tear down the device itself *after* destroy_device()
642 * has had a chance to interoogate it. */
643 free(controller->devices[devno]);
644 controller->devices[devno] = NULL;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200645 }
Patrick Georgi4727c072008-10-16 19:20:51 +0000646}
647
648int
Julius Wernere00ba212013-09-24 20:03:54 -0700649usb_attach_device(hci_t *controller, int hubaddress, int port, usb_speed speed)
Patrick Georgi4727c072008-10-16 19:20:51 +0000650{
Julius Wernere00ba212013-09-24 20:03:54 -0700651 static const char* speeds[] = { "full", "low", "high", "super" };
652 usb_debug ("%sspeed device\n", (speed < sizeof(speeds) / sizeof(char*))
653 ? speeds[speed] : "invalid value - no");
Nico Huber1ab60752012-05-23 09:21:54 +0200654 int newdev = set_address (controller, speed, port, hubaddress);
Patrick Georgi4727c072008-10-16 19:20:51 +0000655 if (newdev == -1)
656 return -1;
657 usbdev_t *newdev_t = controller->devices[newdev];
Patrick Georgi4727c072008-10-16 19:20:51 +0000658 // determine responsible driver - current done in set_address
659 newdev_t->init (newdev_t);
Nico Huberd8a66802012-06-21 11:21:23 +0200660 /* init() may have called usb_detach_device() yet, so check */
661 return controller->devices[newdev] ? newdev : -1;
Patrick Georgi4727c072008-10-16 19:20:51 +0000662}
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000663
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800664static void
665usb_generic_destroy (usbdev_t *dev)
666{
667 if (usb_generic_remove)
668 usb_generic_remove(dev);
669}
670
671void
672usb_generic_init (usbdev_t *dev)
673{
674 dev->data = NULL;
675 dev->destroy = usb_generic_destroy;
676
677 if (usb_generic_create)
678 usb_generic_create(dev);
Shawn Nematbakhsh7faff542014-04-15 21:34:30 -0700679
680 if (dev->data == NULL) {
681 usb_debug("Detaching device not used by payload\n");
682 usb_detach_device(dev->controller, dev->address);
683 }
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800684}
Yunzhi Liebd3da72015-07-02 15:28:11 +0800685
686/*
687 * returns the address of the closest USB2.0 hub, which is responsible for
688 * split transactions, along with the number of the used downstream port
689 */
690int closest_usb2_hub(const usbdev_t *dev, int *const addr, int *const port)
691{
692 const usbdev_t *usb1dev;
693
694 do {
695 usb1dev = dev;
696 if ((dev->hub >= 0) && (dev->hub < 128))
697 dev = dev->controller->devices[dev->hub];
698 else
699 dev = NULL;
700 } while (dev && (dev->speed < 2));
701
702 if (dev) {
703 *addr = usb1dev->hub;
704 *port = usb1dev->port;
705 return 0;
706 }
707
708 usb_debug("Couldn't find closest USB2.0 hub.\n");
709 return 1;
710}