blob: 69d1c397783f067d9f7137613ec480b5db963f06 [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
Julius Wernerd13e2c42013-09-17 22:16:04 -0700152int
153get_descriptor (usbdev_t *dev, int rtype, int descType, int descIdx,
154 void *data, size_t len)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000155{
Patrick Georgid21f68b2008-09-02 16:06:22 +0000156 dev_req_t dr;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000157
Julius Wernerd13e2c42013-09-17 22:16:04 -0700158 dr.bmRequestType = rtype;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000159 dr.bRequest = GET_DESCRIPTOR;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700160 dr.wValue = descType << 8 | descIdx;
161 dr.wIndex = 0;
162 dr.wLength = len;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000163
Julius Wernerd13e2c42013-09-17 22:16:04 -0700164 return dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000165}
166
Julius Wernerd13e2c42013-09-17 22:16:04 -0700167int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000168set_configuration (usbdev_t *dev)
169{
170 dev_req_t dr;
171
172 dr.bmRequestType = 0;
173 dr.bRequest = SET_CONFIGURATION;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700174 dr.wValue = dev->configuration->bConfigurationValue;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000175 dr.wIndex = 0;
176 dr.wLength = 0;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700177
178 return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000179}
180
Nico Huber79e1f2f2012-06-01 09:50:11 +0200181int
Nico Huber5f595cb2012-05-21 16:19:05 +0200182clear_feature (usbdev_t *dev, int endp, int feature, int rtype)
183{
184 dev_req_t dr;
185
186 dr.bmRequestType = rtype;
187 dr.data_dir = host_to_device;
188 dr.bRequest = CLEAR_FEATURE;
189 dr.wValue = feature;
190 dr.wIndex = endp;
191 dr.wLength = 0;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700192
Julius Wernere9738db2013-02-21 13:41:40 -0800193 return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0;
Nico Huber5f595cb2012-05-21 16:19:05 +0200194}
195
Patrick Georgid21f68b2008-09-02 16:06:22 +0000196int
197clear_stall (endpoint_t *ep)
198{
Julius Wernerd13e2c42013-09-17 22:16:04 -0700199 int ret = clear_feature (ep->dev, ep->endpoint, ENDPOINT_HALT,
200 gen_bmRequestType (host_to_device, standard_type, endp_recp));
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000201 ep->toggle = 0;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200202 return ret;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000203}
204
205/* returns free address or -1 */
206static int
207get_free_address (hci_t *controller)
208{
Julius Werner6af43802014-04-28 16:04:24 -0700209 int i = controller->latest_address + 1;
210 for (; i != controller->latest_address; i++) {
211 if (i >= ARRAY_SIZE(controller->devices) || i < 1) {
212 usb_debug("WARNING: Device addresses for controller %#x"
213 " wrapped around!\n", controller->reg_base);
214 i = 0;
215 continue;
216 }
217 if (controller->devices[i] == 0) {
218 controller->latest_address = i;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000219 return i;
Julius Werner6af43802014-04-28 16:04:24 -0700220 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000221 }
Gabe Black93ded592012-11-01 15:44:10 -0700222 usb_debug ("no free address found\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000223 return -1; // no free address
224}
225
Patrick Georgi482af6d2013-05-24 15:48:56 +0200226int
Julius Wernere00ba212013-09-24 20:03:54 -0700227usb_decode_mps0(usb_speed speed, u8 bMaxPacketSize0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000228{
Julius Wernere00ba212013-09-24 20:03:54 -0700229 switch (speed) {
230 case LOW_SPEED:
231 if (bMaxPacketSize0 != 8) {
232 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
233 bMaxPacketSize0 = 8;
234 }
235 return bMaxPacketSize0;
236 case FULL_SPEED:
237 switch (bMaxPacketSize0) {
238 case 8: case 16: case 32: case 64:
239 return bMaxPacketSize0;
240 default:
241 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
242 return 8;
243 }
244 case HIGH_SPEED:
245 if (bMaxPacketSize0 != 64) {
246 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
247 bMaxPacketSize0 = 64;
248 }
249 return bMaxPacketSize0;
250 case SUPER_SPEED:
251 if (bMaxPacketSize0 != 9) {
252 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
253 bMaxPacketSize0 = 9;
254 }
Chunfeng Yun08e30132015-05-07 15:28:19 +0800255 return 1 << bMaxPacketSize0;
Julius Wernere00ba212013-09-24 20:03:54 -0700256 default: /* GCC is stupid and cannot deal with enums correctly */
257 return 8;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000258 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200259}
260
Nico Huberaee44fa2013-06-06 10:20:35 +0200261/* Normalize bInterval to log2 of microframes */
262static int
Julius Wernere00ba212013-09-24 20:03:54 -0700263usb_decode_interval(usb_speed speed, const endpoint_type type, const unsigned char bInterval)
Nico Huberaee44fa2013-06-06 10:20:35 +0200264{
265#define LOG2(a) ((sizeof(unsigned) << 3) - __builtin_clz(a) - 1)
266 switch (speed) {
267 case LOW_SPEED:
268 switch (type) {
269 case ISOCHRONOUS: case INTERRUPT:
270 return LOG2(bInterval) + 3;
271 default:
272 return 0;
273 }
274 case FULL_SPEED:
275 switch (type) {
276 case ISOCHRONOUS:
277 return (bInterval - 1) + 3;
278 case INTERRUPT:
279 return LOG2(bInterval) + 3;
280 default:
281 return 0;
282 }
283 case HIGH_SPEED:
284 switch (type) {
285 case ISOCHRONOUS: case INTERRUPT:
286 return bInterval - 1;
287 default:
288 return LOG2(bInterval);
289 }
290 case SUPER_SPEED:
291 switch (type) {
292 case ISOCHRONOUS: case INTERRUPT:
293 return bInterval - 1;
294 default:
295 return 0;
296 }
297 default:
298 return 0;
299 }
300#undef LOG2
301}
302
Julius Wernerd13e2c42013-09-17 22:16:04 -0700303usbdev_t *
Julius Wernere00ba212013-09-24 20:03:54 -0700304generic_set_address (hci_t *controller, usb_speed speed,
305 int hubport, int hubaddr)
306{
307 int adr = get_free_address (controller); // address to set
308 dev_req_t dr;
309
310 memset (&dr, 0, sizeof (dr));
311 dr.data_dir = host_to_device;
312 dr.req_type = standard_type;
313 dr.req_recp = dev_recp;
314 dr.bRequest = SET_ADDRESS;
315 dr.wValue = adr;
316 dr.wIndex = 0;
317 dr.wLength = 0;
318
Julius Wernerd13e2c42013-09-17 22:16:04 -0700319 usbdev_t *dev = init_device_entry(controller, adr);
320 if (!dev)
321 return NULL;
322
Julius Wernere00ba212013-09-24 20:03:54 -0700323 // dummy values for registering the address
324 dev->address = 0;
325 dev->hub = hubaddr;
326 dev->port = hubport;
327 dev->speed = speed;
328 dev->endpoints[0].dev = dev;
329 dev->endpoints[0].endpoint = 0;
330 dev->endpoints[0].maxpacketsize = 8;
331 dev->endpoints[0].toggle = 0;
332 dev->endpoints[0].direction = SETUP;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700333 dev->endpoints[0].type = CONTROL;
Julius Wernere00ba212013-09-24 20:03:54 -0700334 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0) {
335 usb_debug ("set_address failed\n");
Julius Wernerd13e2c42013-09-17 22:16:04 -0700336 usb_detach_device (controller, adr);
337 return NULL;
Julius Wernere00ba212013-09-24 20:03:54 -0700338 }
339 mdelay (SET_ADDRESS_MDELAY);
340
Julius Wernerd13e2c42013-09-17 22:16:04 -0700341 u8 buf[8];
342 dev->address = adr;
343 if (get_descriptor (dev, DR_DESC, DT_DEV, 0, buf, sizeof(buf))
344 != sizeof(buf)) {
345 usb_debug("first get_descriptor(DT_DEV) failed\n");
346 usb_detach_device (controller, adr);
347 return NULL;
348 }
349 dev->endpoints[0].maxpacketsize = usb_decode_mps0(speed, buf[7]);
350
351 return dev;
Julius Wernere00ba212013-09-24 20:03:54 -0700352}
353
Patrick Georgi482af6d2013-05-24 15:48:56 +0200354static int
Julius Wernere00ba212013-09-24 20:03:54 -0700355set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
Patrick Georgi482af6d2013-05-24 15:48:56 +0200356{
Julius Wernerd13e2c42013-09-17 22:16:04 -0700357 usbdev_t *dev = controller->set_address(controller, speed,
358 hubport, hubaddr);
359 if (!dev) {
Patrick Georgi482af6d2013-05-24 15:48:56 +0200360 usb_debug ("set_address failed\n");
361 return -1;
362 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200363
Julius Wernerd13e2c42013-09-17 22:16:04 -0700364 dev->descriptor = malloc(sizeof(*dev->descriptor));
365 if (!dev->descriptor || get_descriptor (dev, DR_DESC, DT_DEV, 0,
366 dev->descriptor, sizeof(*dev->descriptor))
367 != sizeof(*dev->descriptor)) {
368 usb_debug ("get_descriptor(DT_DEV) failed\n");
369 usb_detach_device (controller, dev->address);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000370 return -1;
371 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000372
Julius Wernerd13e2c42013-09-17 22:16:04 -0700373 usb_debug ("* found device (0x%04x:0x%04x, USB %x.%x, MPS0: %d)\n",
374 dev->descriptor->idVendor, dev->descriptor->idProduct,
375 dev->descriptor->bcdUSB >> 8, dev->descriptor->bcdUSB & 0xff,
376 dev->endpoints[0].maxpacketsize);
377 dev->quirks = usb_quirk_check(dev->descriptor->idVendor,
378 dev->descriptor->idProduct);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000379
Julius Wernerd13e2c42013-09-17 22:16:04 -0700380 usb_debug ("device has %d configurations\n",
381 dev->descriptor->bNumConfigurations);
382 if (dev->descriptor->bNumConfigurations == 0) {
383 /* device isn't usable */
384 usb_debug ("... no usable configuration!\n");
385 usb_detach_device (controller, dev->address);
386 return -1;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000387 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000388
Julius Wernerd13e2c42013-09-17 22:16:04 -0700389 u16 buf[2];
390 if (get_descriptor (dev, DR_DESC, DT_CFG, 0, buf, sizeof(buf))
391 != sizeof(buf)) {
392 usb_debug ("first get_descriptor(DT_CFG) failed\n");
393 usb_detach_device (controller, dev->address);
394 return -1;
395 }
Patrick Georgif72d328d2014-11-10 16:50:21 +0100396 /* workaround for some USB devices: wait until they're ready, or
397 * they send a NAK when they're not allowed to do. 1ms is enough */
398 mdelay(1);
Julius Wernerd13e2c42013-09-17 22:16:04 -0700399 dev->configuration = malloc(buf[1]);
400 if (!dev->configuration) {
401 usb_debug ("could not allocate %d bytes for DT_CFG\n", buf[1]);
402 usb_detach_device (controller, dev->address);
403 return -1;
404 }
405 if (get_descriptor (dev, DR_DESC, DT_CFG, 0, dev->configuration,
406 buf[1]) != buf[1]) {
407 usb_debug ("get_descriptor(DT_CFG) failed\n");
408 usb_detach_device (controller, dev->address);
409 return -1;
410 }
411 configuration_descriptor_t *cd = dev->configuration;
412 if (cd->wTotalLength != buf[1]) {
413 usb_debug ("configuration descriptor size changed, aborting\n");
414 usb_detach_device (controller, dev->address);
415 return -1;
416 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200417
Julius Wernerd13e2c42013-09-17 22:16:04 -0700418 /*
419 * If the device is not well known (ifnum == -1), we use the first
420 * interface we encounter, as there was no need to implement something
421 * else for the time being. If you need it, see the SetInterface and
422 * GetInterface functions in the USB specification and set it yourself.
423 */
424 usb_debug ("device has %x interfaces\n", cd->bNumInterfaces);
425 int ifnum = usb_interface_check(dev->descriptor->idVendor,
426 dev->descriptor->idProduct);
427 if (cd->bNumInterfaces > 1 && ifnum < 0)
428 usb_debug ("NOTICE: Your device has multiple interfaces and\n"
429 "this driver will only use the first one. That may\n"
430 "be the wrong choice and cause the device to not\n"
431 "work correctly. Please report this case\n"
432 "(including the above debugging output) to\n"
433 "coreboot@coreboot.org to have the device added to\n"
434 "the list of well-known quirks.\n");
Patrick Georgi482af6d2013-05-24 15:48:56 +0200435
Julius Wernerd13e2c42013-09-17 22:16:04 -0700436 u8 *end = (void *)dev->configuration + cd->wTotalLength;
437 interface_descriptor_t *intf;
438 u8 *ptr;
439
440 /* Find our interface (or the first good one if we don't know) */
441 for (ptr = (void *)dev->configuration + sizeof(*cd); ; ptr += ptr[0]) {
442 if (ptr + 2 > end || !ptr[0] || ptr + ptr[0] > end) {
443 usb_debug ("Couldn't find usable DT_INTF\n");
444 usb_detach_device (controller, dev->address);
445 return -1;
446 }
447 if (ptr[1] != DT_INTF)
448 continue;
449 intf = (void *)ptr;
450 if (intf->bLength != sizeof(*intf)) {
451 usb_debug ("Skipping broken DT_INTF\n");
452 continue;
453 }
454 if (ifnum >= 0 && intf->bInterfaceNumber != ifnum)
455 continue;
456 usb_debug ("Interface %d: class 0x%x, sub 0x%x. proto 0x%x\n",
457 intf->bInterfaceNumber, intf->bInterfaceClass,
458 intf->bInterfaceSubClass, intf->bInterfaceProtocol);
459 ptr += sizeof(*intf);
460 break;
461 }
462
463 /* Gather up all endpoints belonging to this inteface */
464 dev->num_endp = 1;
465 for (; ptr + 2 <= end && ptr[0] && ptr + ptr[0] <= end; ptr += ptr[0]) {
466 if (ptr[1] == DT_INTF || ptr[1] == DT_CFG ||
467 dev->num_endp >= ARRAY_SIZE(dev->endpoints))
468 break;
469 if (ptr[1] != DT_ENDP)
470 continue;
471
472 endpoint_descriptor_t *desc = (void *)ptr;
473 static const char *transfertypes[4] = {
474 "control", "isochronous", "bulk", "interrupt"
475 };
476 usb_debug (" #Endpoint %d (%s), max packet size %x, type %s\n",
477 desc->bEndpointAddress & 0x7f,
478 (desc->bEndpointAddress & 0x80) ? "in" : "out",
479 desc->wMaxPacketSize,
480 transfertypes[desc->bmAttributes & 0x3]);
481
482 endpoint_t *ep = &dev->endpoints[dev->num_endp++];
483 ep->dev = dev;
484 ep->endpoint = desc->bEndpointAddress;
485 ep->toggle = 0;
486 ep->maxpacketsize = desc->wMaxPacketSize;
487 ep->direction = (desc->bEndpointAddress & 0x80) ? IN : OUT;
488 ep->type = desc->bmAttributes & 0x3;
489 ep->interval = usb_decode_interval (dev->speed, ep->type,
490 desc->bInterval);
491 }
492
493 if ((controller->finish_device_config &&
494 controller->finish_device_config(dev)) ||
495 set_configuration(dev) < 0) {
496 usb_debug ("Could not finalize device configuration\n");
497 usb_detach_device (controller, dev->address);
498 return -1;
499 }
500
501 int class = dev->descriptor->bDeviceClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000502 if (class == 0)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700503 class = intf->bInterfaceClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000504
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000505 enum {
506 audio_device = 0x01,
507 comm_device = 0x02,
508 hid_device = 0x03,
509 physical_device = 0x05,
510 imaging_device = 0x06,
511 printer_device = 0x07,
512 msc_device = 0x08,
513 hub_device = 0x09,
514 cdc_device = 0x0a,
515 ccid_device = 0x0b,
516 security_device = 0x0d,
517 video_device = 0x0e,
518 healthcare_device = 0x0f,
519 diagnostic_device = 0xdc,
520 wireless_device = 0xe0,
521 misc_device = 0xef,
522 };
Julius Wernerd13e2c42013-09-17 22:16:04 -0700523 usb_debug("Class: ");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000524 switch (class) {
525 case audio_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700526 usb_debug("audio\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000527 break;
528 case comm_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700529 usb_debug("communication\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000530 break;
531 case hid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700532 usb_debug ("HID\n");
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700533#if IS_ENABLED(CONFIG_LP_USB_HID)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700534 dev->init = usb_hid_init;
535 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000536#else
Gabe Black93ded592012-11-01 15:44:10 -0700537 usb_debug ("NOTICE: USB HID support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000538#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000539 break;
540 case physical_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700541 usb_debug("physical\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000542 break;
543 case imaging_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700544 usb_debug("camera\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000545 break;
546 case printer_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700547 usb_debug("printer\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000548 break;
549 case msc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700550 usb_debug ("MSC\n");
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700551#if IS_ENABLED(CONFIG_LP_USB_MSC)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700552 dev->init = usb_msc_init;
553 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000554#else
Gabe Black93ded592012-11-01 15:44:10 -0700555 usb_debug ("NOTICE: USB MSC support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000556#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000557 break;
558 case hub_device:
Julius Werner752fba72015-07-09 16:29:10 -0700559 usb_debug ("hub\n");
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700560#if IS_ENABLED(CONFIG_LP_USB_HUB)
Julius Werner752fba72015-07-09 16:29:10 -0700561 dev->init = usb_hub_init;
562 return dev->address;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000563#else
Julius Werner752fba72015-07-09 16:29:10 -0700564 usb_debug ("NOTICE: USB hub support not compiled in\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000565#endif
566 break;
567 case cdc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700568 usb_debug("CDC\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000569 break;
570 case ccid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700571 usb_debug("smartcard / CCID\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000572 break;
573 case security_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700574 usb_debug("content security\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000575 break;
576 case video_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700577 usb_debug("video\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000578 break;
579 case healthcare_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700580 usb_debug("healthcare\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000581 break;
582 case diagnostic_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700583 usb_debug("diagnostic\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000584 break;
585 case wireless_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700586 usb_debug("wireless\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000587 break;
588 default:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700589 usb_debug("unsupported class %x\n", class);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000590 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000591 }
Julius Wernerd13e2c42013-09-17 22:16:04 -0700592 dev->init = usb_generic_init;
593 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000594}
Patrick Georgi4727c072008-10-16 19:20:51 +0000595
Nico Huber79e1f2f2012-06-01 09:50:11 +0200596/*
597 * Should be called by the hub drivers whenever a physical detach occurs
598 * and can be called by usb class drivers if they are unsatisfied with a
599 * malfunctioning device.
600 */
Patrick Georgi4727c072008-10-16 19:20:51 +0000601void
602usb_detach_device(hci_t *controller, int devno)
603{
Nico Huber79e1f2f2012-06-01 09:50:11 +0200604 /* check if device exists, as we may have
605 been called yet by the usb class driver */
606 if (controller->devices[devno]) {
607 controller->devices[devno]->destroy (controller->devices[devno]);
Julius Wernerd609e892013-09-25 12:30:07 -0700608 free(controller->devices[devno]);
609 controller->devices[devno] = NULL;
Julius Wernere00ba212013-09-24 20:03:54 -0700610 if (controller->destroy_device)
611 controller->destroy_device(controller, devno);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200612 }
Patrick Georgi4727c072008-10-16 19:20:51 +0000613}
614
615int
Julius Wernere00ba212013-09-24 20:03:54 -0700616usb_attach_device(hci_t *controller, int hubaddress, int port, usb_speed speed)
Patrick Georgi4727c072008-10-16 19:20:51 +0000617{
Julius Wernere00ba212013-09-24 20:03:54 -0700618 static const char* speeds[] = { "full", "low", "high", "super" };
619 usb_debug ("%sspeed device\n", (speed < sizeof(speeds) / sizeof(char*))
620 ? speeds[speed] : "invalid value - no");
Nico Huber1ab60752012-05-23 09:21:54 +0200621 int newdev = set_address (controller, speed, port, hubaddress);
Patrick Georgi4727c072008-10-16 19:20:51 +0000622 if (newdev == -1)
623 return -1;
624 usbdev_t *newdev_t = controller->devices[newdev];
Patrick Georgi4727c072008-10-16 19:20:51 +0000625 // determine responsible driver - current done in set_address
626 newdev_t->init (newdev_t);
Nico Huberd8a66802012-06-21 11:21:23 +0200627 /* init() may have called usb_detach_device() yet, so check */
628 return controller->devices[newdev] ? newdev : -1;
Patrick Georgi4727c072008-10-16 19:20:51 +0000629}
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000630
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800631static void
632usb_generic_destroy (usbdev_t *dev)
633{
634 if (usb_generic_remove)
635 usb_generic_remove(dev);
636}
637
638void
639usb_generic_init (usbdev_t *dev)
640{
641 dev->data = NULL;
642 dev->destroy = usb_generic_destroy;
643
644 if (usb_generic_create)
645 usb_generic_create(dev);
Shawn Nematbakhsh7faff542014-04-15 21:34:30 -0700646
647 if (dev->data == NULL) {
648 usb_debug("Detaching device not used by payload\n");
649 usb_detach_device(dev->controller, dev->address);
650 }
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800651}
Yunzhi Liebd3da72015-07-02 15:28:11 +0800652
653/*
654 * returns the address of the closest USB2.0 hub, which is responsible for
655 * split transactions, along with the number of the used downstream port
656 */
657int closest_usb2_hub(const usbdev_t *dev, int *const addr, int *const port)
658{
659 const usbdev_t *usb1dev;
660
661 do {
662 usb1dev = dev;
663 if ((dev->hub >= 0) && (dev->hub < 128))
664 dev = dev->controller->devices[dev->hub];
665 else
666 dev = NULL;
667 } while (dev && (dev->speed < 2));
668
669 if (dev) {
670 *addr = usb1dev->hub;
671 *port = usb1dev->port;
672 return 0;
673 }
674
675 usb_debug("Couldn't find closest USB2.0 hub.\n");
676 return 1;
677}