blob: 4f21e0cf3b4f71adf695ac46782a6a0c152b0c30 [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{
42 hci_t *controller = malloc (sizeof (hci_t));
43
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000044 if (controller) {
45 /* atomic */
46 controller->next = usb_hcs;
47 usb_hcs = controller;
48 /* atomic end */
49 }
Patrick Georgid21f68b2008-09-02 16:06:22 +000050
51 return controller;
52}
53
54void
55detach_controller (hci_t *controller)
56{
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000057 if (controller == NULL)
Patrick Georgid21f68b2008-09-02 16:06:22 +000058 return;
59 if (usb_hcs == controller) {
60 usb_hcs = controller->next;
61 } else {
62 hci_t *it = usb_hcs;
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000063 while (it != NULL) {
Patrick Georgid21f68b2008-09-02 16:06:22 +000064 if (it->next == controller) {
65 it->next = controller->next;
66 return;
67 }
Anton Kochkov421303a2012-06-20 03:57:18 +040068 it = it->next;
Patrick Georgid21f68b2008-09-02 16:06:22 +000069 }
70 }
71}
72
73/**
Patrick Georgibbc52312011-11-04 12:06:06 +010074 * Shut down all controllers
75 */
76int
77usb_exit (void)
78{
Mathias Krause59c020a2013-03-24 19:40:02 +010079 while (usb_hcs != NULL) {
80 usb_hcs->shutdown(usb_hcs);
Patrick Georgibbc52312011-11-04 12:06:06 +010081 }
82 return 0;
83}
84
85/**
Patrick Georgid21f68b2008-09-02 16:06:22 +000086 * Polls all hubs on all USB controllers, to find out about device changes
87 */
88void
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000089usb_poll (void)
Patrick Georgid21f68b2008-09-02 16:06:22 +000090{
91 if (usb_hcs == 0)
92 return;
93 hci_t *controller = usb_hcs;
Patrick Georgidb89ec92011-11-18 11:56:38 +010094 while (controller != NULL) {
Patrick Georgid21f68b2008-09-02 16:06:22 +000095 int i;
96 for (i = 0; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +000097 if (controller->devices[i] != 0) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000098 controller->devices[i]->poll (controller->devices[i]);
Patrick Georgid21f68b2008-09-02 16:06:22 +000099 }
100 }
101 controller = controller->next;
102 }
103}
104
Julius Wernerd13e2c42013-09-17 22:16:04 -0700105usbdev_t *
Patrick Georgid21f68b2008-09-02 16:06:22 +0000106init_device_entry (hci_t *controller, int i)
107{
Julius Wernerd13e2c42013-09-17 22:16:04 -0700108 usbdev_t *dev = calloc(1, sizeof(usbdev_t));
109 if (!dev) {
110 usb_debug("no memory to allocate device structure\n");
111 return NULL;
112 }
Patrick Georgi4727c072008-10-16 19:20:51 +0000113 if (controller->devices[i] != 0)
Gabe Black93ded592012-11-01 15:44:10 -0700114 usb_debug("warning: device %d reassigned?\n", i);
Julius Wernerd13e2c42013-09-17 22:16:04 -0700115 controller->devices[i] = dev;
116 dev->controller = controller;
117 dev->address = -1;
118 dev->hub = -1;
119 dev->port = -1;
120 dev->init = usb_nop_init;
121 dev->init (controller->devices[i]);
122 return dev;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000123}
124
Julius Wernerd13e2c42013-09-17 22:16:04 -0700125int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000126set_feature (usbdev_t *dev, int endp, int feature, int rtype)
127{
128 dev_req_t dr;
129
130 dr.bmRequestType = rtype;
131 dr.data_dir = host_to_device;
132 dr.bRequest = SET_FEATURE;
133 dr.wValue = feature;
134 dr.wIndex = endp;
135 dr.wLength = 0;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700136
137 return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000138}
139
Julius Wernerd13e2c42013-09-17 22:16:04 -0700140int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000141get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
142{
143 dev_req_t dr;
144
145 dr.bmRequestType = rtype;
146 dr.data_dir = device_to_host;
147 dr.bRequest = GET_STATUS;
148 dr.wValue = 0;
149 dr.wIndex = intf;
150 dr.wLength = len;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700151
152 return dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000153}
154
Julius Wernerd13e2c42013-09-17 22:16:04 -0700155int
156get_descriptor (usbdev_t *dev, int rtype, int descType, int descIdx,
157 void *data, size_t len)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000158{
Patrick Georgid21f68b2008-09-02 16:06:22 +0000159 dev_req_t dr;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000160
Julius Wernerd13e2c42013-09-17 22:16:04 -0700161 dr.bmRequestType = rtype;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000162 dr.bRequest = GET_DESCRIPTOR;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700163 dr.wValue = descType << 8 | descIdx;
164 dr.wIndex = 0;
165 dr.wLength = len;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000166
Julius Wernerd13e2c42013-09-17 22:16:04 -0700167 return dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000168}
169
Julius Wernerd13e2c42013-09-17 22:16:04 -0700170int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000171set_configuration (usbdev_t *dev)
172{
173 dev_req_t dr;
174
175 dr.bmRequestType = 0;
176 dr.bRequest = SET_CONFIGURATION;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700177 dr.wValue = dev->configuration->bConfigurationValue;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000178 dr.wIndex = 0;
179 dr.wLength = 0;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700180
181 return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000182}
183
Nico Huber79e1f2f2012-06-01 09:50:11 +0200184int
Nico Huber5f595cb2012-05-21 16:19:05 +0200185clear_feature (usbdev_t *dev, int endp, int feature, int rtype)
186{
187 dev_req_t dr;
188
189 dr.bmRequestType = rtype;
190 dr.data_dir = host_to_device;
191 dr.bRequest = CLEAR_FEATURE;
192 dr.wValue = feature;
193 dr.wIndex = endp;
194 dr.wLength = 0;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700195
Julius Wernere9738db2013-02-21 13:41:40 -0800196 return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0;
Nico Huber5f595cb2012-05-21 16:19:05 +0200197}
198
Patrick Georgid21f68b2008-09-02 16:06:22 +0000199int
200clear_stall (endpoint_t *ep)
201{
Julius Wernerd13e2c42013-09-17 22:16:04 -0700202 int ret = clear_feature (ep->dev, ep->endpoint, ENDPOINT_HALT,
203 gen_bmRequestType (host_to_device, standard_type, endp_recp));
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000204 ep->toggle = 0;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200205 return ret;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000206}
207
208/* returns free address or -1 */
209static int
210get_free_address (hci_t *controller)
211{
212 int i;
213 for (i = 1; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +0000214 if (controller->devices[i] == 0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000215 return i;
216 }
Gabe Black93ded592012-11-01 15:44:10 -0700217 usb_debug ("no free address found\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000218 return -1; // no free address
219}
220
Patrick Georgi482af6d2013-05-24 15:48:56 +0200221int
Julius Wernere00ba212013-09-24 20:03:54 -0700222usb_decode_mps0(usb_speed speed, u8 bMaxPacketSize0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000223{
Julius Wernere00ba212013-09-24 20:03:54 -0700224 switch (speed) {
225 case LOW_SPEED:
226 if (bMaxPacketSize0 != 8) {
227 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
228 bMaxPacketSize0 = 8;
229 }
230 return bMaxPacketSize0;
231 case FULL_SPEED:
232 switch (bMaxPacketSize0) {
233 case 8: case 16: case 32: case 64:
234 return bMaxPacketSize0;
235 default:
236 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
237 return 8;
238 }
239 case HIGH_SPEED:
240 if (bMaxPacketSize0 != 64) {
241 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
242 bMaxPacketSize0 = 64;
243 }
244 return bMaxPacketSize0;
245 case SUPER_SPEED:
246 if (bMaxPacketSize0 != 9) {
247 usb_debug("Invalid MPS0: 0x%02x\n", bMaxPacketSize0);
248 bMaxPacketSize0 = 9;
249 }
250 return 2 << bMaxPacketSize0;
251 default: /* GCC is stupid and cannot deal with enums correctly */
252 return 8;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000253 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200254}
255
Nico Huberaee44fa2013-06-06 10:20:35 +0200256/* Normalize bInterval to log2 of microframes */
257static int
Julius Wernere00ba212013-09-24 20:03:54 -0700258usb_decode_interval(usb_speed speed, const endpoint_type type, const unsigned char bInterval)
Nico Huberaee44fa2013-06-06 10:20:35 +0200259{
260#define LOG2(a) ((sizeof(unsigned) << 3) - __builtin_clz(a) - 1)
261 switch (speed) {
262 case LOW_SPEED:
263 switch (type) {
264 case ISOCHRONOUS: case INTERRUPT:
265 return LOG2(bInterval) + 3;
266 default:
267 return 0;
268 }
269 case FULL_SPEED:
270 switch (type) {
271 case ISOCHRONOUS:
272 return (bInterval - 1) + 3;
273 case INTERRUPT:
274 return LOG2(bInterval) + 3;
275 default:
276 return 0;
277 }
278 case HIGH_SPEED:
279 switch (type) {
280 case ISOCHRONOUS: case INTERRUPT:
281 return bInterval - 1;
282 default:
283 return LOG2(bInterval);
284 }
285 case SUPER_SPEED:
286 switch (type) {
287 case ISOCHRONOUS: case INTERRUPT:
288 return bInterval - 1;
289 default:
290 return 0;
291 }
292 default:
293 return 0;
294 }
295#undef LOG2
296}
297
Julius Wernerd13e2c42013-09-17 22:16:04 -0700298usbdev_t *
Julius Wernere00ba212013-09-24 20:03:54 -0700299generic_set_address (hci_t *controller, usb_speed speed,
300 int hubport, int hubaddr)
301{
302 int adr = get_free_address (controller); // address to set
303 dev_req_t dr;
304
305 memset (&dr, 0, sizeof (dr));
306 dr.data_dir = host_to_device;
307 dr.req_type = standard_type;
308 dr.req_recp = dev_recp;
309 dr.bRequest = SET_ADDRESS;
310 dr.wValue = adr;
311 dr.wIndex = 0;
312 dr.wLength = 0;
313
Julius Wernerd13e2c42013-09-17 22:16:04 -0700314 usbdev_t *dev = init_device_entry(controller, adr);
315 if (!dev)
316 return NULL;
317
Julius Wernere00ba212013-09-24 20:03:54 -0700318 // dummy values for registering the address
319 dev->address = 0;
320 dev->hub = hubaddr;
321 dev->port = hubport;
322 dev->speed = speed;
323 dev->endpoints[0].dev = dev;
324 dev->endpoints[0].endpoint = 0;
325 dev->endpoints[0].maxpacketsize = 8;
326 dev->endpoints[0].toggle = 0;
327 dev->endpoints[0].direction = SETUP;
Julius Wernerd13e2c42013-09-17 22:16:04 -0700328 dev->endpoints[0].type = CONTROL;
Julius Wernere00ba212013-09-24 20:03:54 -0700329 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0) {
330 usb_debug ("set_address failed\n");
Julius Wernerd13e2c42013-09-17 22:16:04 -0700331 usb_detach_device (controller, adr);
332 return NULL;
Julius Wernere00ba212013-09-24 20:03:54 -0700333 }
334 mdelay (SET_ADDRESS_MDELAY);
335
Julius Wernerd13e2c42013-09-17 22:16:04 -0700336 u8 buf[8];
337 dev->address = adr;
338 if (get_descriptor (dev, DR_DESC, DT_DEV, 0, buf, sizeof(buf))
339 != sizeof(buf)) {
340 usb_debug("first get_descriptor(DT_DEV) failed\n");
341 usb_detach_device (controller, adr);
342 return NULL;
343 }
344 dev->endpoints[0].maxpacketsize = usb_decode_mps0(speed, buf[7]);
345
346 return dev;
Julius Wernere00ba212013-09-24 20:03:54 -0700347}
348
Patrick Georgi482af6d2013-05-24 15:48:56 +0200349static int
Julius Wernere00ba212013-09-24 20:03:54 -0700350set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
Patrick Georgi482af6d2013-05-24 15:48:56 +0200351{
Julius Wernerd13e2c42013-09-17 22:16:04 -0700352 usbdev_t *dev = controller->set_address(controller, speed,
353 hubport, hubaddr);
354 if (!dev) {
Patrick Georgi482af6d2013-05-24 15:48:56 +0200355 usb_debug ("set_address failed\n");
356 return -1;
357 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200358
Julius Wernerd13e2c42013-09-17 22:16:04 -0700359 dev->descriptor = malloc(sizeof(*dev->descriptor));
360 if (!dev->descriptor || get_descriptor (dev, DR_DESC, DT_DEV, 0,
361 dev->descriptor, sizeof(*dev->descriptor))
362 != sizeof(*dev->descriptor)) {
363 usb_debug ("get_descriptor(DT_DEV) failed\n");
364 usb_detach_device (controller, dev->address);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000365 return -1;
366 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000367
Julius Wernerd13e2c42013-09-17 22:16:04 -0700368 usb_debug ("* found device (0x%04x:0x%04x, USB %x.%x, MPS0: %d)\n",
369 dev->descriptor->idVendor, dev->descriptor->idProduct,
370 dev->descriptor->bcdUSB >> 8, dev->descriptor->bcdUSB & 0xff,
371 dev->endpoints[0].maxpacketsize);
372 dev->quirks = usb_quirk_check(dev->descriptor->idVendor,
373 dev->descriptor->idProduct);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000374
Julius Wernerd13e2c42013-09-17 22:16:04 -0700375 usb_debug ("device has %d configurations\n",
376 dev->descriptor->bNumConfigurations);
377 if (dev->descriptor->bNumConfigurations == 0) {
378 /* device isn't usable */
379 usb_debug ("... no usable configuration!\n");
380 usb_detach_device (controller, dev->address);
381 return -1;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000382 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000383
Julius Wernerd13e2c42013-09-17 22:16:04 -0700384 u16 buf[2];
385 if (get_descriptor (dev, DR_DESC, DT_CFG, 0, buf, sizeof(buf))
386 != sizeof(buf)) {
387 usb_debug ("first get_descriptor(DT_CFG) failed\n");
388 usb_detach_device (controller, dev->address);
389 return -1;
390 }
391 dev->configuration = malloc(buf[1]);
392 if (!dev->configuration) {
393 usb_debug ("could not allocate %d bytes for DT_CFG\n", buf[1]);
394 usb_detach_device (controller, dev->address);
395 return -1;
396 }
397 if (get_descriptor (dev, DR_DESC, DT_CFG, 0, dev->configuration,
398 buf[1]) != buf[1]) {
399 usb_debug ("get_descriptor(DT_CFG) failed\n");
400 usb_detach_device (controller, dev->address);
401 return -1;
402 }
403 configuration_descriptor_t *cd = dev->configuration;
404 if (cd->wTotalLength != buf[1]) {
405 usb_debug ("configuration descriptor size changed, aborting\n");
406 usb_detach_device (controller, dev->address);
407 return -1;
408 }
Patrick Georgi482af6d2013-05-24 15:48:56 +0200409
Julius Wernerd13e2c42013-09-17 22:16:04 -0700410 /*
411 * If the device is not well known (ifnum == -1), we use the first
412 * interface we encounter, as there was no need to implement something
413 * else for the time being. If you need it, see the SetInterface and
414 * GetInterface functions in the USB specification and set it yourself.
415 */
416 usb_debug ("device has %x interfaces\n", cd->bNumInterfaces);
417 int ifnum = usb_interface_check(dev->descriptor->idVendor,
418 dev->descriptor->idProduct);
419 if (cd->bNumInterfaces > 1 && ifnum < 0)
420 usb_debug ("NOTICE: Your device has multiple interfaces and\n"
421 "this driver will only use the first one. That may\n"
422 "be the wrong choice and cause the device to not\n"
423 "work correctly. Please report this case\n"
424 "(including the above debugging output) to\n"
425 "coreboot@coreboot.org to have the device added to\n"
426 "the list of well-known quirks.\n");
Patrick Georgi482af6d2013-05-24 15:48:56 +0200427
Julius Wernerd13e2c42013-09-17 22:16:04 -0700428 u8 *end = (void *)dev->configuration + cd->wTotalLength;
429 interface_descriptor_t *intf;
430 u8 *ptr;
431
432 /* Find our interface (or the first good one if we don't know) */
433 for (ptr = (void *)dev->configuration + sizeof(*cd); ; ptr += ptr[0]) {
434 if (ptr + 2 > end || !ptr[0] || ptr + ptr[0] > end) {
435 usb_debug ("Couldn't find usable DT_INTF\n");
436 usb_detach_device (controller, dev->address);
437 return -1;
438 }
439 if (ptr[1] != DT_INTF)
440 continue;
441 intf = (void *)ptr;
442 if (intf->bLength != sizeof(*intf)) {
443 usb_debug ("Skipping broken DT_INTF\n");
444 continue;
445 }
446 if (ifnum >= 0 && intf->bInterfaceNumber != ifnum)
447 continue;
448 usb_debug ("Interface %d: class 0x%x, sub 0x%x. proto 0x%x\n",
449 intf->bInterfaceNumber, intf->bInterfaceClass,
450 intf->bInterfaceSubClass, intf->bInterfaceProtocol);
451 ptr += sizeof(*intf);
452 break;
453 }
454
455 /* Gather up all endpoints belonging to this inteface */
456 dev->num_endp = 1;
457 for (; ptr + 2 <= end && ptr[0] && ptr + ptr[0] <= end; ptr += ptr[0]) {
458 if (ptr[1] == DT_INTF || ptr[1] == DT_CFG ||
459 dev->num_endp >= ARRAY_SIZE(dev->endpoints))
460 break;
461 if (ptr[1] != DT_ENDP)
462 continue;
463
464 endpoint_descriptor_t *desc = (void *)ptr;
465 static const char *transfertypes[4] = {
466 "control", "isochronous", "bulk", "interrupt"
467 };
468 usb_debug (" #Endpoint %d (%s), max packet size %x, type %s\n",
469 desc->bEndpointAddress & 0x7f,
470 (desc->bEndpointAddress & 0x80) ? "in" : "out",
471 desc->wMaxPacketSize,
472 transfertypes[desc->bmAttributes & 0x3]);
473
474 endpoint_t *ep = &dev->endpoints[dev->num_endp++];
475 ep->dev = dev;
476 ep->endpoint = desc->bEndpointAddress;
477 ep->toggle = 0;
478 ep->maxpacketsize = desc->wMaxPacketSize;
479 ep->direction = (desc->bEndpointAddress & 0x80) ? IN : OUT;
480 ep->type = desc->bmAttributes & 0x3;
481 ep->interval = usb_decode_interval (dev->speed, ep->type,
482 desc->bInterval);
483 }
484
485 if ((controller->finish_device_config &&
486 controller->finish_device_config(dev)) ||
487 set_configuration(dev) < 0) {
488 usb_debug ("Could not finalize device configuration\n");
489 usb_detach_device (controller, dev->address);
490 return -1;
491 }
492
493 int class = dev->descriptor->bDeviceClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000494 if (class == 0)
Julius Wernerd13e2c42013-09-17 22:16:04 -0700495 class = intf->bInterfaceClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000496
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000497 enum {
498 audio_device = 0x01,
499 comm_device = 0x02,
500 hid_device = 0x03,
501 physical_device = 0x05,
502 imaging_device = 0x06,
503 printer_device = 0x07,
504 msc_device = 0x08,
505 hub_device = 0x09,
506 cdc_device = 0x0a,
507 ccid_device = 0x0b,
508 security_device = 0x0d,
509 video_device = 0x0e,
510 healthcare_device = 0x0f,
511 diagnostic_device = 0xdc,
512 wireless_device = 0xe0,
513 misc_device = 0xef,
514 };
Julius Wernerd13e2c42013-09-17 22:16:04 -0700515 usb_debug("Class: ");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000516 switch (class) {
517 case audio_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700518 usb_debug("audio\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000519 break;
520 case comm_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700521 usb_debug("communication\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000522 break;
523 case hid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700524 usb_debug ("HID\n");
Gabe Black1ee2c6d2013-08-09 04:27:35 -0700525#ifdef CONFIG_LP_USB_HID
Julius Wernerd13e2c42013-09-17 22:16:04 -0700526 dev->init = usb_hid_init;
527 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000528#else
Gabe Black93ded592012-11-01 15:44:10 -0700529 usb_debug ("NOTICE: USB HID support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000530#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000531 break;
532 case physical_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700533 usb_debug("physical\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000534 break;
535 case imaging_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700536 usb_debug("camera\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000537 break;
538 case printer_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700539 usb_debug("printer\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000540 break;
541 case msc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700542 usb_debug ("MSC\n");
Gabe Black1ee2c6d2013-08-09 04:27:35 -0700543#ifdef CONFIG_LP_USB_MSC
Julius Wernerd13e2c42013-09-17 22:16:04 -0700544 dev->init = usb_msc_init;
545 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000546#else
Gabe Black93ded592012-11-01 15:44:10 -0700547 usb_debug ("NOTICE: USB MSC support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000548#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000549 break;
550 case hub_device:
Julius Wernerd13e2c42013-09-17 22:16:04 -0700551 if (speed < SUPER_SPEED) {
552 usb_debug ("hub (2.0)\n");
Gabe Black1ee2c6d2013-08-09 04:27:35 -0700553#ifdef CONFIG_LP_USB_HUB
Julius Wernerd13e2c42013-09-17 22:16:04 -0700554 dev->init = usb_hub_init;
555 return dev->address;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000556#else
Julius Wernerd13e2c42013-09-17 22:16:04 -0700557 usb_debug ("NOTICE: USB hub support not compiled in\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000558#endif
Julius Wernerd13e2c42013-09-17 22:16:04 -0700559 } else {
560 usb_debug ("hub (3.0) - not yet supported!\n");
561 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000562 break;
563 case cdc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700564 usb_debug("CDC\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000565 break;
566 case ccid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700567 usb_debug("smartcard / CCID\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000568 break;
569 case security_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700570 usb_debug("content security\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000571 break;
572 case video_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700573 usb_debug("video\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000574 break;
575 case healthcare_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700576 usb_debug("healthcare\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000577 break;
578 case diagnostic_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700579 usb_debug("diagnostic\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000580 break;
581 case wireless_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700582 usb_debug("wireless\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000583 break;
584 default:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700585 usb_debug("unsupported class %x\n", class);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000586 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000587 }
Julius Wernerd13e2c42013-09-17 22:16:04 -0700588 dev->init = usb_generic_init;
589 return dev->address;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000590}
Patrick Georgi4727c072008-10-16 19:20:51 +0000591
Nico Huber79e1f2f2012-06-01 09:50:11 +0200592/*
593 * Should be called by the hub drivers whenever a physical detach occurs
594 * and can be called by usb class drivers if they are unsatisfied with a
595 * malfunctioning device.
596 */
Patrick Georgi4727c072008-10-16 19:20:51 +0000597void
598usb_detach_device(hci_t *controller, int devno)
599{
Nico Huber79e1f2f2012-06-01 09:50:11 +0200600 /* check if device exists, as we may have
601 been called yet by the usb class driver */
602 if (controller->devices[devno]) {
603 controller->devices[devno]->destroy (controller->devices[devno]);
Julius Wernerd609e892013-09-25 12:30:07 -0700604 free(controller->devices[devno]);
605 controller->devices[devno] = NULL;
Julius Wernere00ba212013-09-24 20:03:54 -0700606 if (controller->destroy_device)
607 controller->destroy_device(controller, devno);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200608 }
Patrick Georgi4727c072008-10-16 19:20:51 +0000609}
610
611int
Julius Wernere00ba212013-09-24 20:03:54 -0700612usb_attach_device(hci_t *controller, int hubaddress, int port, usb_speed speed)
Patrick Georgi4727c072008-10-16 19:20:51 +0000613{
Julius Wernere00ba212013-09-24 20:03:54 -0700614 static const char* speeds[] = { "full", "low", "high", "super" };
615 usb_debug ("%sspeed device\n", (speed < sizeof(speeds) / sizeof(char*))
616 ? speeds[speed] : "invalid value - no");
Nico Huber1ab60752012-05-23 09:21:54 +0200617 int newdev = set_address (controller, speed, port, hubaddress);
Patrick Georgi4727c072008-10-16 19:20:51 +0000618 if (newdev == -1)
619 return -1;
620 usbdev_t *newdev_t = controller->devices[newdev];
Patrick Georgi4727c072008-10-16 19:20:51 +0000621 // determine responsible driver - current done in set_address
622 newdev_t->init (newdev_t);
Nico Huberd8a66802012-06-21 11:21:23 +0200623 /* init() may have called usb_detach_device() yet, so check */
624 return controller->devices[newdev] ? newdev : -1;
Patrick Georgi4727c072008-10-16 19:20:51 +0000625}
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000626
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800627static void
628usb_generic_destroy (usbdev_t *dev)
629{
630 if (usb_generic_remove)
631 usb_generic_remove(dev);
632}
633
634void
635usb_generic_init (usbdev_t *dev)
636{
637 dev->data = NULL;
638 dev->destroy = usb_generic_destroy;
639
640 if (usb_generic_create)
641 usb_generic_create(dev);
642}