blob: 25bd954ded16d60da1d90e471c98e8ba68bb4a71 [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{
209 int i;
210 for (i = 1; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +0000211 if (controller->devices[i] == 0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000212 return i;
213 }
Gabe Black93ded592012-11-01 15:44:10 -0700214 usb_debug ("no free address found\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000215 return -1; // no free address
216}
217
Patrick Georgi482af6d2013-05-24 15:48:56 +0200218int
Julius Wernere00ba212013-09-24 20:03:54 -0700219usb_decode_mps0(usb_speed speed, u8 bMaxPacketSize0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000220{
Julius Wernere00ba212013-09-24 20:03:54 -0700221 switch (speed) {
222 case LOW_SPEED:
223 if (bMaxPacketSize0 != 8) {
224 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
225 bMaxPacketSize0 = 8;
226 }
227 return bMaxPacketSize0;
228 case FULL_SPEED:
229 switch (bMaxPacketSize0) {
230 case 8: case 16: case 32: case 64:
231 return bMaxPacketSize0;
232 default:
233 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
234 return 8;
235 }
236 case HIGH_SPEED:
237 if (bMaxPacketSize0 != 64) {
238 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
239 bMaxPacketSize0 = 64;
240 }
241 return bMaxPacketSize0;
242 case SUPER_SPEED:
243 if (bMaxPacketSize0 != 9) {
244 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
245 bMaxPacketSize0 = 9;
246 }
247 return 2 << bMaxPacketSize0;
248 default: /* GCC is stupid and cannot deal with enums correctly */
249 return 8;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000250 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200251}
252
Nico Huberaee44fa2013-06-06 10:20:35 +0200253/* Normalize bInterval to log2 of microframes */
254static int
Julius Wernere00ba212013-09-24 20:03:54 -0700255usb_decode_interval(usb_speed speed, const endpoint_type type, const unsigned char bInterval)
Nico Huberaee44fa2013-06-06 10:20:35 +0200256{
257#define LOG2(a) ((sizeof(unsigned) << 3) - __builtin_clz(a) - 1)
258 switch (speed) {
259 case LOW_SPEED:
260 switch (type) {
261 case ISOCHRONOUS: case INTERRUPT:
262 return LOG2(bInterval) + 3;
263 default:
264 return 0;
265 }
266 case FULL_SPEED:
267 switch (type) {
268 case ISOCHRONOUS:
269 return (bInterval - 1) + 3;
270 case INTERRUPT:
271 return LOG2(bInterval) + 3;
272 default:
273 return 0;
274 }
275 case HIGH_SPEED:
276 switch (type) {
277 case ISOCHRONOUS: case INTERRUPT:
278 return bInterval - 1;
279 default:
280 return LOG2(bInterval);
281 }
282 case SUPER_SPEED:
283 switch (type) {
284 case ISOCHRONOUS: case INTERRUPT:
285 return bInterval - 1;
286 default:
287 return 0;
288 }
289 default:
290 return 0;
291 }
292#undef LOG2
293}
294
Julius Wernerd13e2c42013-09-17 22:16:04 -0700295usbdev_t *
Julius Wernere00ba212013-09-24 20:03:54 -0700296generic_set_address (hci_t *controller, usb_speed speed,
297 int hubport, int hubaddr)
298{
299 int adr = get_free_address (controller); // address to set
300 dev_req_t dr;
301
302 memset (&dr, 0, sizeof (dr));
303 dr.data_dir = host_to_device;
304 dr.req_type = standard_type;
305 dr.req_recp = dev_recp;
306 dr.bRequest = SET_ADDRESS;
307 dr.wValue = adr;
308 dr.wIndex = 0;
309 dr.wLength = 0;
310
Julius Wernerd13e2c42013-09-17 22:16:04 -0700311 usbdev_t *dev = init_device_entry(controller, adr);
312 if (!dev)
313 return NULL;
314
Julius Wernere00ba212013-09-24 20:03:54 -0700315 // dummy values for registering the address
316 dev->address = 0;
317 dev->hub = hubaddr;
318 dev->port = hubport;
319 dev->speed = speed;
320 dev->endpoints[0].dev = dev;
321 dev->endpoints[0].endpoint = 0;
322 dev->endpoints[0].maxpacketsize = 8;
323 dev->endpoints[0].toggle = 0;
324 dev->endpoints[0].direction = SETUP;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700325 dev->endpoints[0].type = CONTROL;
Julius Wernere00ba212013-09-24 20:03:54 -0700326 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0) {
327 usb_debug ("set_address failed\n");
Julius Wernerd13e2c42013-09-17 22:16:04 -0700328 usb_detach_device (controller, adr);
329 return NULL;
Julius Wernere00ba212013-09-24 20:03:54 -0700330 }
331 mdelay (SET_ADDRESS_MDELAY);
332
Julius Wernerd13e2c42013-09-17 22:16:04 -0700333 u8 buf[8];
334 dev->address = adr;
335 if (get_descriptor (dev, DR_DESC, DT_DEV, 0, buf, sizeof(buf))
336 != sizeof(buf)) {
337 usb_debug("first get_descriptor(DT_DEV) failed\n");
338 usb_detach_device (controller, adr);
339 return NULL;
340 }
341 dev->endpoints[0].maxpacketsize = usb_decode_mps0(speed, buf[7]);
342
343 return dev;
Julius Wernere00ba212013-09-24 20:03:54 -0700344}
345
Patrick Georgi482af6d2013-05-24 15:48:56 +0200346static int
Julius Wernere00ba212013-09-24 20:03:54 -0700347set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
Patrick Georgi482af6d2013-05-24 15:48:56 +0200348{
Julius Wernerd13e2c42013-09-17 22:16:04 -0700349 usbdev_t *dev = controller->set_address(controller, speed,
350 hubport, hubaddr);
351 if (!dev) {
Patrick Georgi482af6d2013-05-24 15:48:56 +0200352 usb_debug ("set_address failed\n");
353 return -1;
354 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200355
Julius Wernerd13e2c42013-09-17 22:16:04 -0700356 dev->descriptor = malloc(sizeof(*dev->descriptor));
357 if (!dev->descriptor || get_descriptor (dev, DR_DESC, DT_DEV, 0,
358 dev->descriptor, sizeof(*dev->descriptor))
359 != sizeof(*dev->descriptor)) {
360 usb_debug ("get_descriptor(DT_DEV) failed\n");
361 usb_detach_device (controller, dev->address);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000362 return -1;
363 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000364
Julius Wernerd13e2c42013-09-17 22:16:04 -0700365 usb_debug ("* found device (0x%04x:0x%04x, USB %x.%x, MPS0: %d)\n",
366 dev->descriptor->idVendor, dev->descriptor->idProduct,
367 dev->descriptor->bcdUSB >> 8, dev->descriptor->bcdUSB & 0xff,
368 dev->endpoints[0].maxpacketsize);
369 dev->quirks = usb_quirk_check(dev->descriptor->idVendor,
370 dev->descriptor->idProduct);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000371
Julius Wernerd13e2c42013-09-17 22:16:04 -0700372 usb_debug ("device has %d configurations\n",
373 dev->descriptor->bNumConfigurations);
374 if (dev->descriptor->bNumConfigurations == 0) {
375 /* device isn't usable */
376 usb_debug ("... no usable configuration!\n");
377 usb_detach_device (controller, dev->address);
378 return -1;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000379 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000380
Julius Wernerd13e2c42013-09-17 22:16:04 -0700381 u16 buf[2];
382 if (get_descriptor (dev, DR_DESC, DT_CFG, 0, buf, sizeof(buf))
383 != sizeof(buf)) {
384 usb_debug ("first get_descriptor(DT_CFG) failed\n");
385 usb_detach_device (controller, dev->address);
386 return -1;
387 }
388 dev->configuration = malloc(buf[1]);
389 if (!dev->configuration) {
390 usb_debug ("could not allocate %d bytes for DT_CFG\n", buf[1]);
391 usb_detach_device (controller, dev->address);
392 return -1;
393 }
394 if (get_descriptor (dev, DR_DESC, DT_CFG, 0, dev->configuration,
395 buf[1]) != buf[1]) {
396 usb_debug ("get_descriptor(DT_CFG) failed\n");
397 usb_detach_device (controller, dev->address);
398 return -1;
399 }
400 configuration_descriptor_t *cd = dev->configuration;
401 if (cd->wTotalLength != buf[1]) {
402 usb_debug ("configuration descriptor size changed, aborting\n");
403 usb_detach_device (controller, dev->address);
404 return -1;
405 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200406
Julius Wernerd13e2c42013-09-17 22:16:04 -0700407 /*
408 * If the device is not well known (ifnum == -1), we use the first
409 * interface we encounter, as there was no need to implement something
410 * else for the time being. If you need it, see the SetInterface and
411 * GetInterface functions in the USB specification and set it yourself.
412 */
413 usb_debug ("device has %x interfaces\n", cd->bNumInterfaces);
414 int ifnum = usb_interface_check(dev->descriptor->idVendor,
415 dev->descriptor->idProduct);
416 if (cd->bNumInterfaces > 1 && ifnum < 0)
417 usb_debug ("NOTICE: Your device has multiple interfaces and\n"
418 "this driver will only use the first one. That may\n"
419 "be the wrong choice and cause the device to not\n"
420 "work correctly. Please report this case\n"
421 "(including the above debugging output) to\n"
422 "coreboot@coreboot.org to have the device added to\n"
423 "the list of well-known quirks.\n");
Patrick Georgi482af6d2013-05-24 15:48:56 +0200424
Julius Wernerd13e2c42013-09-17 22:16:04 -0700425 u8 *end = (void *)dev->configuration + cd->wTotalLength;
426 interface_descriptor_t *intf;
427 u8 *ptr;
428
429 /* Find our interface (or the first good one if we don't know) */
430 for (ptr = (void *)dev->configuration + sizeof(*cd); ; ptr += ptr[0]) {
431 if (ptr + 2 > end || !ptr[0] || ptr + ptr[0] > end) {
432 usb_debug ("Couldn't find usable DT_INTF\n");
433 usb_detach_device (controller, dev->address);
434 return -1;
435 }
436 if (ptr[1] != DT_INTF)
437 continue;
438 intf = (void *)ptr;
439 if (intf->bLength != sizeof(*intf)) {
440 usb_debug ("Skipping broken DT_INTF\n");
441 continue;
442 }
443 if (ifnum >= 0 && intf->bInterfaceNumber != ifnum)
444 continue;
445 usb_debug ("Interface %d: class 0x%x, sub 0x%x. proto 0x%x\n",
446 intf->bInterfaceNumber, intf->bInterfaceClass,
447 intf->bInterfaceSubClass, intf->bInterfaceProtocol);
448 ptr += sizeof(*intf);
449 break;
450 }
451
452 /* Gather up all endpoints belonging to this inteface */
453 dev->num_endp = 1;
454 for (; ptr + 2 <= end && ptr[0] && ptr + ptr[0] <= end; ptr += ptr[0]) {
455 if (ptr[1] == DT_INTF || ptr[1] == DT_CFG ||
456 dev->num_endp >= ARRAY_SIZE(dev->endpoints))
457 break;
458 if (ptr[1] != DT_ENDP)
459 continue;
460
461 endpoint_descriptor_t *desc = (void *)ptr;
462 static const char *transfertypes[4] = {
463 "control", "isochronous", "bulk", "interrupt"
464 };
465 usb_debug (" #Endpoint %d (%s), max packet size %x, type %s\n",
466 desc->bEndpointAddress & 0x7f,
467 (desc->bEndpointAddress & 0x80) ? "in" : "out",
468 desc->wMaxPacketSize,
469 transfertypes[desc->bmAttributes & 0x3]);
470
471 endpoint_t *ep = &dev->endpoints[dev->num_endp++];
472 ep->dev = dev;
473 ep->endpoint = desc->bEndpointAddress;
474 ep->toggle = 0;
475 ep->maxpacketsize = desc->wMaxPacketSize;
476 ep->direction = (desc->bEndpointAddress & 0x80) ? IN : OUT;
477 ep->type = desc->bmAttributes & 0x3;
478 ep->interval = usb_decode_interval (dev->speed, ep->type,
479 desc->bInterval);
480 }
481
482 if ((controller->finish_device_config &&
483 controller->finish_device_config(dev)) ||
484 set_configuration(dev) < 0) {
485 usb_debug ("Could not finalize device configuration\n");
486 usb_detach_device (controller, dev->address);
487 return -1;
488 }
489
490 int class = dev->descriptor->bDeviceClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000491 if (class == 0)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700492 class = intf->bInterfaceClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000493
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000494 enum {
495 audio_device = 0x01,
496 comm_device = 0x02,
497 hid_device = 0x03,
498 physical_device = 0x05,
499 imaging_device = 0x06,
500 printer_device = 0x07,
501 msc_device = 0x08,
502 hub_device = 0x09,
503 cdc_device = 0x0a,
504 ccid_device = 0x0b,
505 security_device = 0x0d,
506 video_device = 0x0e,
507 healthcare_device = 0x0f,
508 diagnostic_device = 0xdc,
509 wireless_device = 0xe0,
510 misc_device = 0xef,
511 };
Julius Wernerd13e2c42013-09-17 22:16:04 -0700512 usb_debug("Class: ");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000513 switch (class) {
514 case audio_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700515 usb_debug("audio\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000516 break;
517 case comm_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700518 usb_debug("communication\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000519 break;
520 case hid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700521 usb_debug ("HID\n");
Gabe Black1ee2c6d2013-08-09 04:27:35 -0700522#ifdef CONFIG_LP_USB_HID
Julius Wernerd13e2c42013-09-17 22:16:04 -0700523 dev->init = usb_hid_init;
524 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000525#else
Gabe Black93ded592012-11-01 15:44:10 -0700526 usb_debug ("NOTICE: USB HID support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000527#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000528 break;
529 case physical_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700530 usb_debug("physical\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000531 break;
532 case imaging_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700533 usb_debug("camera\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000534 break;
535 case printer_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700536 usb_debug("printer\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000537 break;
538 case msc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700539 usb_debug ("MSC\n");
Gabe Black1ee2c6d2013-08-09 04:27:35 -0700540#ifdef CONFIG_LP_USB_MSC
Julius Wernerd13e2c42013-09-17 22:16:04 -0700541 dev->init = usb_msc_init;
542 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000543#else
Gabe Black93ded592012-11-01 15:44:10 -0700544 usb_debug ("NOTICE: USB MSC support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000545#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000546 break;
547 case hub_device:
Julius Wernerd13e2c42013-09-17 22:16:04 -0700548 if (speed < SUPER_SPEED) {
549 usb_debug ("hub (2.0)\n");
Gabe Black1ee2c6d2013-08-09 04:27:35 -0700550#ifdef CONFIG_LP_USB_HUB
Julius Wernerd13e2c42013-09-17 22:16:04 -0700551 dev->init = usb_hub_init;
552 return dev->address;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000553#else
Julius Wernerd13e2c42013-09-17 22:16:04 -0700554 usb_debug ("NOTICE: USB hub support not compiled in\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000555#endif
Julius Wernerd13e2c42013-09-17 22:16:04 -0700556 } else {
557 usb_debug ("hub (3.0) - not yet supported!\n");
558 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000559 break;
560 case cdc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700561 usb_debug("CDC\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000562 break;
563 case ccid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700564 usb_debug("smartcard / CCID\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000565 break;
566 case security_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700567 usb_debug("content security\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000568 break;
569 case video_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700570 usb_debug("video\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000571 break;
572 case healthcare_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700573 usb_debug("healthcare\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000574 break;
575 case diagnostic_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700576 usb_debug("diagnostic\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000577 break;
578 case wireless_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700579 usb_debug("wireless\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000580 break;
581 default:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700582 usb_debug("unsupported class %x\n", class);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000583 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000584 }
Julius Wernerd13e2c42013-09-17 22:16:04 -0700585 dev->init = usb_generic_init;
586 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000587}
Patrick Georgi4727c072008-10-16 19:20:51 +0000588
Nico Huber79e1f2f2012-06-01 09:50:11 +0200589/*
590 * Should be called by the hub drivers whenever a physical detach occurs
591 * and can be called by usb class drivers if they are unsatisfied with a
592 * malfunctioning device.
593 */
Patrick Georgi4727c072008-10-16 19:20:51 +0000594void
595usb_detach_device(hci_t *controller, int devno)
596{
Nico Huber79e1f2f2012-06-01 09:50:11 +0200597 /* check if device exists, as we may have
598 been called yet by the usb class driver */
599 if (controller->devices[devno]) {
600 controller->devices[devno]->destroy (controller->devices[devno]);
Julius Wernerd609e892013-09-25 12:30:07 -0700601 free(controller->devices[devno]);
602 controller->devices[devno] = NULL;
Julius Wernere00ba212013-09-24 20:03:54 -0700603 if (controller->destroy_device)
604 controller->destroy_device(controller, devno);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200605 }
Patrick Georgi4727c072008-10-16 19:20:51 +0000606}
607
608int
Julius Wernere00ba212013-09-24 20:03:54 -0700609usb_attach_device(hci_t *controller, int hubaddress, int port, usb_speed speed)
Patrick Georgi4727c072008-10-16 19:20:51 +0000610{
Julius Wernere00ba212013-09-24 20:03:54 -0700611 static const char* speeds[] = { "full", "low", "high", "super" };
612 usb_debug ("%sspeed device\n", (speed < sizeof(speeds) / sizeof(char*))
613 ? speeds[speed] : "invalid value - no");
Nico Huber1ab60752012-05-23 09:21:54 +0200614 int newdev = set_address (controller, speed, port, hubaddress);
Patrick Georgi4727c072008-10-16 19:20:51 +0000615 if (newdev == -1)
616 return -1;
617 usbdev_t *newdev_t = controller->devices[newdev];
Patrick Georgi4727c072008-10-16 19:20:51 +0000618 // determine responsible driver - current done in set_address
619 newdev_t->init (newdev_t);
Nico Huberd8a66802012-06-21 11:21:23 +0200620 /* init() may have called usb_detach_device() yet, so check */
621 return controller->devices[newdev] ? newdev : -1;
Patrick Georgi4727c072008-10-16 19:20:51 +0000622}
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000623
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800624static void
625usb_generic_destroy (usbdev_t *dev)
626{
627 if (usb_generic_remove)
628 usb_generic_remove(dev);
629}
630
631void
632usb_generic_init (usbdev_t *dev)
633{
634 dev->data = NULL;
635 dev->destroy = usb_generic_destroy;
636
637 if (usb_generic_create)
638 usb_generic_create(dev);
Shawn Nematbakhsh7faff542014-04-15 21:34:30 -0700639
640 if (dev->data == NULL) {
641 usb_debug("Detaching device not used by payload\n");
642 usb_detach_device(dev->controller, dev->address);
643 }
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800644}