blob: d9727f01b0d8cb1642dc44281eca29ad41b916e5 [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
35hci_t *usb_hcs = 0;
36
37hci_t *
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000038new_controller (void)
Patrick Georgid21f68b2008-09-02 16:06:22 +000039{
40 hci_t *controller = malloc (sizeof (hci_t));
41
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000042 if (controller) {
43 /* atomic */
44 controller->next = usb_hcs;
45 usb_hcs = controller;
46 /* atomic end */
47 }
Patrick Georgid21f68b2008-09-02 16:06:22 +000048
49 return controller;
50}
51
52void
53detach_controller (hci_t *controller)
54{
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000055 if (controller == NULL)
Patrick Georgid21f68b2008-09-02 16:06:22 +000056 return;
57 if (usb_hcs == controller) {
58 usb_hcs = controller->next;
59 } else {
60 hci_t *it = usb_hcs;
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000061 while (it != NULL) {
Patrick Georgid21f68b2008-09-02 16:06:22 +000062 if (it->next == controller) {
63 it->next = controller->next;
64 return;
65 }
Anton Kochkov421303a2012-06-20 03:57:18 +040066 it = it->next;
Patrick Georgid21f68b2008-09-02 16:06:22 +000067 }
68 }
69}
70
71/**
Patrick Georgibbc52312011-11-04 12:06:06 +010072 * Shut down all controllers
73 */
74int
75usb_exit (void)
76{
Mathias Krause59c020a2013-03-24 19:40:02 +010077 while (usb_hcs != NULL) {
78 usb_hcs->shutdown(usb_hcs);
Patrick Georgibbc52312011-11-04 12:06:06 +010079 }
80 return 0;
81}
82
83/**
Patrick Georgid21f68b2008-09-02 16:06:22 +000084 * Polls all hubs on all USB controllers, to find out about device changes
85 */
86void
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000087usb_poll (void)
Patrick Georgid21f68b2008-09-02 16:06:22 +000088{
89 if (usb_hcs == 0)
90 return;
91 hci_t *controller = usb_hcs;
Patrick Georgidb89ec92011-11-18 11:56:38 +010092 while (controller != NULL) {
Patrick Georgid21f68b2008-09-02 16:06:22 +000093 int i;
94 for (i = 0; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +000095 if (controller->devices[i] != 0) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000096 controller->devices[i]->poll (controller->devices[i]);
Patrick Georgid21f68b2008-09-02 16:06:22 +000097 }
98 }
99 controller = controller->next;
100 }
101}
102
103void
104init_device_entry (hci_t *controller, int i)
105{
Patrick Georgi4727c072008-10-16 19:20:51 +0000106 if (controller->devices[i] != 0)
Gabe Black93ded592012-11-01 15:44:10 -0700107 usb_debug("warning: device %d reassigned?\n", i);
Patrick Georgi4727c072008-10-16 19:20:51 +0000108 controller->devices[i] = malloc(sizeof(usbdev_t));
109 controller->devices[i]->controller = controller;
110 controller->devices[i]->address = -1;
111 controller->devices[i]->hub = -1;
112 controller->devices[i]->port = -1;
113 controller->devices[i]->init = usb_nop_init;
114 controller->devices[i]->init (controller->devices[i]);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000115}
116
117void
118set_feature (usbdev_t *dev, int endp, int feature, int rtype)
119{
120 dev_req_t dr;
121
122 dr.bmRequestType = rtype;
123 dr.data_dir = host_to_device;
124 dr.bRequest = SET_FEATURE;
125 dr.wValue = feature;
126 dr.wIndex = endp;
127 dr.wLength = 0;
128 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
129}
130
131void
132get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
133{
134 dev_req_t dr;
135
136 dr.bmRequestType = rtype;
137 dr.data_dir = device_to_host;
138 dr.bRequest = GET_STATUS;
139 dr.wValue = 0;
140 dr.wIndex = intf;
141 dr.wLength = len;
142 dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
143}
144
145u8 *
146get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
147 int descIdx, int langID)
148{
149 u8 buf[8];
150 u8 *result;
151 dev_req_t dr;
152 int size;
153
154 dr.bmRequestType = bmRequestType;
155 dr.data_dir = device_to_host; // always like this for descriptors
156 dr.bRequest = GET_DESCRIPTOR;
157 dr.wValue = (descType << 8) | descIdx;
158 dr.wIndex = langID;
159 dr.wLength = 8;
Julius Wernere9738db2013-02-21 13:41:40 -0800160 if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf) < 0) {
Gabe Black93ded592012-11-01 15:44:10 -0700161 usb_debug ("getting descriptor size (type %x) failed\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000162 descType);
163 }
164
165 if (descType == 1) {
166 device_descriptor_t *dd = (device_descriptor_t *) buf;
Gabe Black93ded592012-11-01 15:44:10 -0700167 usb_debug ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000168 if (dd->bMaxPacketSize0 != 0)
169 dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
170 }
171
172 /* special case for configuration descriptors: they carry all their
173 subsequent descriptors with them, and keep the entire size at a
174 different location */
175 size = buf[0];
176 if (buf[1] == 2) {
177 int realsize = ((unsigned short *) (buf + 2))[0];
178 size = realsize;
179 }
180 result = malloc (size);
181 memset (result, 0, size);
182 dr.wLength = size;
183 if (dev->controller->
Julius Wernere9738db2013-02-21 13:41:40 -0800184 control (dev, IN, sizeof (dr), &dr, size, result) < 0) {
Gabe Black93ded592012-11-01 15:44:10 -0700185 usb_debug ("getting descriptor (type %x, size %x) failed\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000186 descType, size);
187 }
188
189 return result;
190}
191
192void
193set_configuration (usbdev_t *dev)
194{
195 dev_req_t dr;
196
197 dr.bmRequestType = 0;
198 dr.bRequest = SET_CONFIGURATION;
199 dr.wValue = dev->configuration[5];
200 dr.wIndex = 0;
201 dr.wLength = 0;
202 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
203}
204
Nico Huber79e1f2f2012-06-01 09:50:11 +0200205int
Nico Huber5f595cb2012-05-21 16:19:05 +0200206clear_feature (usbdev_t *dev, int endp, int feature, int rtype)
207{
208 dev_req_t dr;
209
210 dr.bmRequestType = rtype;
211 dr.data_dir = host_to_device;
212 dr.bRequest = CLEAR_FEATURE;
213 dr.wValue = feature;
214 dr.wIndex = endp;
215 dr.wLength = 0;
Julius Wernere9738db2013-02-21 13:41:40 -0800216 return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0;
Nico Huber5f595cb2012-05-21 16:19:05 +0200217}
218
Patrick Georgid21f68b2008-09-02 16:06:22 +0000219int
220clear_stall (endpoint_t *ep)
221{
222 usbdev_t *dev = ep->dev;
223 int endp = ep->endpoint;
Nico Huber5f595cb2012-05-21 16:19:05 +0200224 int rtype = gen_bmRequestType (host_to_device, standard_type,
225 endp ? endp_recp : dev_recp);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000226
Nico Huber79e1f2f2012-06-01 09:50:11 +0200227 int ret = clear_feature (dev, endp, ENDPOINT_HALT, rtype);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000228 ep->toggle = 0;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200229 return ret;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000230}
231
232/* returns free address or -1 */
233static int
234get_free_address (hci_t *controller)
235{
236 int i;
237 for (i = 1; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +0000238 if (controller->devices[i] == 0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000239 return i;
240 }
Gabe Black93ded592012-11-01 15:44:10 -0700241 usb_debug ("no free address found\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000242 return -1; // no free address
243}
244
Patrick Georgi482af6d2013-05-24 15:48:56 +0200245int
246generic_set_address (hci_t *controller, int speed, int hubport, int hubaddr)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000247{
248 int adr = get_free_address (controller); // address to set
249 dev_req_t dr;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000250
251 memset (&dr, 0, sizeof (dr));
252 dr.data_dir = host_to_device;
253 dr.req_type = standard_type;
254 dr.req_recp = dev_recp;
255 dr.bRequest = SET_ADDRESS;
256 dr.wValue = adr;
257 dr.wIndex = 0;
258 dr.wLength = 0;
259
Patrick Georgi4727c072008-10-16 19:20:51 +0000260 init_device_entry(controller, adr);
261 usbdev_t *dev = controller->devices[adr];
Patrick Georgid21f68b2008-09-02 16:06:22 +0000262 // dummy values for registering the address
263 dev->address = 0;
Nico Huber1ab60752012-05-23 09:21:54 +0200264 dev->hub = hubaddr;
265 dev->port = hubport;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000266 dev->speed = speed;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000267 dev->endpoints[0].dev = dev;
268 dev->endpoints[0].endpoint = 0;
269 dev->endpoints[0].maxpacketsize = 8;
270 dev->endpoints[0].toggle = 0;
271 dev->endpoints[0].direction = SETUP;
272 mdelay (50);
Julius Wernere9738db2013-02-21 13:41:40 -0800273 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0) {
Patrick Georgid21f68b2008-09-02 16:06:22 +0000274 return -1;
275 }
276 mdelay (50);
Patrick Georgi482af6d2013-05-24 15:48:56 +0200277
278 return adr;
279}
280
Nico Huberaee44fa2013-06-06 10:20:35 +0200281/* Normalize bInterval to log2 of microframes */
282static int
283usb_decode_interval(const int speed, const endpoint_type type, const unsigned char bInterval)
284{
285#define LOG2(a) ((sizeof(unsigned) << 3) - __builtin_clz(a) - 1)
286 switch (speed) {
287 case LOW_SPEED:
288 switch (type) {
289 case ISOCHRONOUS: case INTERRUPT:
290 return LOG2(bInterval) + 3;
291 default:
292 return 0;
293 }
294 case FULL_SPEED:
295 switch (type) {
296 case ISOCHRONOUS:
297 return (bInterval - 1) + 3;
298 case INTERRUPT:
299 return LOG2(bInterval) + 3;
300 default:
301 return 0;
302 }
303 case HIGH_SPEED:
304 switch (type) {
305 case ISOCHRONOUS: case INTERRUPT:
306 return bInterval - 1;
307 default:
308 return LOG2(bInterval);
309 }
310 case SUPER_SPEED:
311 switch (type) {
312 case ISOCHRONOUS: case INTERRUPT:
313 return bInterval - 1;
314 default:
315 return 0;
316 }
317 default:
318 return 0;
319 }
320#undef LOG2
321}
322
Patrick Georgi482af6d2013-05-24 15:48:56 +0200323static int
324set_address (hci_t *controller, int speed, int hubport, int hubaddr)
325{
326 int adr = controller->set_address(controller, speed, hubport, hubaddr);
327 if (adr < 0 || !controller->devices[adr]) {
328 usb_debug ("set_address failed\n");
329 return -1;
330 }
331 configuration_descriptor_t *cd;
332 device_descriptor_t *dd;
333
334 usbdev_t *dev = controller->devices[adr];
Patrick Georgid21f68b2008-09-02 16:06:22 +0000335 dev->address = adr;
Patrick Georgi482af6d2013-05-24 15:48:56 +0200336 dev->hub = hubaddr;
337 dev->port = hubport;
338 dev->speed = speed;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000339 dev->descriptor = get_descriptor (dev, gen_bmRequestType
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000340 (device_to_host, standard_type, dev_recp), 1, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000341 dd = (device_descriptor_t *) dev->descriptor;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000342
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700343 usb_debug ("* found device (0x%04x:0x%04x, USB %x.%x)",
Stefan Reinauer14e22772010-04-27 06:56:47 +0000344 dd->idVendor, dd->idProduct,
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000345 dd->bcdUSB >> 8, dd->bcdUSB & 0xff);
346 dev->quirks = usb_quirk_check(dd->idVendor, dd->idProduct);
347
Gabe Black93ded592012-11-01 15:44:10 -0700348 usb_debug ("\ndevice has %x configurations\n", dd->bNumConfigurations);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000349 if (dd->bNumConfigurations == 0) {
350 /* device isn't usable */
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700351 usb_debug ("... no usable configuration!\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000352 dev->address = 0;
353 return -1;
354 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000355
356 dev->configuration = get_descriptor (dev, gen_bmRequestType
357 (device_to_host, standard_type, dev_recp), 2, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000358 cd = (configuration_descriptor_t *) dev->configuration;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000359 interface_descriptor_t *interface =
360 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
361 {
362 int i;
363 int num = cd->bNumInterfaces;
364 interface_descriptor_t *current = interface;
Gabe Black93ded592012-11-01 15:44:10 -0700365 usb_debug ("device has %x interfaces\n", num);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000366 if (num > 1) {
367 int interfaces = usb_interface_check(dd->idVendor, dd->idProduct);
368 if (interfaces) {
369 /* Well known device, don't warn */
370 num = interfaces;
371 } else {
372
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700373 usb_debug ("\nNOTICE: This driver defaults to using the first interface.\n"
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000374 "This might be the wrong choice and lead to limited functionality\n"
375 "of the device. Please report such a case to coreboot@coreboot.org\n"
376 "as you might be the first.\n");
377 /* we limit to the first interface, as there was no need to
378 * implement something else for the time being. If you need
379 * it, see the SetInterface and GetInterface functions in
380 * the USB specification, and adapt appropriately.
381 */
382 num = (num > 1) ? 1 : num;
383 }
384 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000385 for (i = 0; i < num; i++) {
386 int j;
Gabe Black93ded592012-11-01 15:44:10 -0700387 usb_debug (" #%x has %x endpoints, interface %x:%x, protocol %x\n",
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000388 current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000389 endpoint_descriptor_t *endp =
390 (endpoint_descriptor_t *) (((char *) current)
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000391 + current->bLength);
Nico Huber735f55c2013-06-10 13:43:29 +0200392 /* Skip any non-endpoint descriptor */
393 if (endp->bDescriptorType != 0x05)
394 endp = (endpoint_descriptor_t *)(((char *)endp) + ((char *)endp)[0]);
395
Patrick Georgid21f68b2008-09-02 16:06:22 +0000396 memset (dev->endpoints, 0, sizeof (dev->endpoints));
397 dev->num_endp = 1; // 0 always exists
398 dev->endpoints[0].dev = dev;
399 dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
400 dev->endpoints[0].direction = SETUP;
401 dev->endpoints[0].type = CONTROL;
Nico Huberaee44fa2013-06-06 10:20:35 +0200402 dev->endpoints[0].interval = usb_decode_interval(dev->speed, CONTROL, endp->bInterval);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000403 for (j = 1; j <= current->bNumEndpoints; j++) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000404#ifdef USB_DEBUG
405 static const char *transfertypes[4] = {
406 "control", "isochronous", "bulk", "interrupt"
Patrick Georgid21f68b2008-09-02 16:06:22 +0000407 };
Gabe Black93ded592012-11-01 15:44:10 -0700408 usb_debug (" #%x: Endpoint %x (%s), max packet size %x, type %s\n", j, endp->bEndpointAddress & 0x7f, ((endp->bEndpointAddress & 0x80) != 0) ? "in" : "out", endp->wMaxPacketSize, transfertypes[endp->bmAttributes]);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000409#endif
Patrick Georgid21f68b2008-09-02 16:06:22 +0000410 endpoint_t *ep =
411 &dev->endpoints[dev->num_endp++];
412 ep->dev = dev;
413 ep->endpoint = endp->bEndpointAddress;
414 ep->toggle = 0;
415 ep->maxpacketsize = endp->wMaxPacketSize;
416 ep->direction =
417 ((endp->bEndpointAddress & 0x80) ==
418 0) ? OUT : IN;
419 ep->type = endp->bmAttributes;
Nico Huberaee44fa2013-06-06 10:20:35 +0200420 ep->interval = usb_decode_interval(dev->speed, ep->type, endp->bInterval);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000421 endp = (endpoint_descriptor_t
422 *) (((char *) endp) + endp->bLength);
423 }
424 current = (interface_descriptor_t *) endp;
425 }
426 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000427
Patrick Georgi482af6d2013-05-24 15:48:56 +0200428 if (controller->finish_device_config &&
429 controller->finish_device_config(dev))
430 return adr; /* Device isn't configured correctly,
431 only control transfers may work. */
432
433 set_configuration(dev);
434
Patrick Georgid21f68b2008-09-02 16:06:22 +0000435 int class = dd->bDeviceClass;
436 if (class == 0)
437 class = interface->bInterfaceClass;
438
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000439 enum {
440 audio_device = 0x01,
441 comm_device = 0x02,
442 hid_device = 0x03,
443 physical_device = 0x05,
444 imaging_device = 0x06,
445 printer_device = 0x07,
446 msc_device = 0x08,
447 hub_device = 0x09,
448 cdc_device = 0x0a,
449 ccid_device = 0x0b,
450 security_device = 0x0d,
451 video_device = 0x0e,
452 healthcare_device = 0x0f,
453 diagnostic_device = 0xdc,
454 wireless_device = 0xe0,
455 misc_device = 0xef,
456 };
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700457 usb_debug(", class: ");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000458 switch (class) {
459 case audio_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700460 usb_debug("audio\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000461 break;
462 case comm_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700463 usb_debug("communication\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000464 break;
465 case hid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700466 usb_debug ("HID\n");
Gabe Black1ee2c6d2013-08-09 04:27:35 -0700467#ifdef CONFIG_LP_USB_HID
Patrick Georgi4727c072008-10-16 19:20:51 +0000468 controller->devices[adr]->init = usb_hid_init;
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800469 return adr;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000470#else
Gabe Black93ded592012-11-01 15:44:10 -0700471 usb_debug ("NOTICE: USB HID support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000472#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000473 break;
474 case physical_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700475 usb_debug("physical\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000476 break;
477 case imaging_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700478 usb_debug("camera\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000479 break;
480 case printer_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700481 usb_debug("printer\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000482 break;
483 case msc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700484 usb_debug ("MSC\n");
Gabe Black1ee2c6d2013-08-09 04:27:35 -0700485#ifdef CONFIG_LP_USB_MSC
Patrick Georgi4727c072008-10-16 19:20:51 +0000486 controller->devices[adr]->init = usb_msc_init;
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800487 return adr;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000488#else
Gabe Black93ded592012-11-01 15:44:10 -0700489 usb_debug ("NOTICE: USB MSC support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000490#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000491 break;
492 case hub_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700493 usb_debug ("hub\n");
Gabe Black1ee2c6d2013-08-09 04:27:35 -0700494#ifdef CONFIG_LP_USB_HUB
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000495 controller->devices[adr]->init = usb_hub_init;
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800496 return adr;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000497#else
Gabe Black93ded592012-11-01 15:44:10 -0700498 usb_debug ("NOTICE: USB hub support not compiled in.\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000499#endif
500 break;
501 case cdc_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700502 usb_debug("CDC\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000503 break;
504 case ccid_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700505 usb_debug("smartcard / CCID\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000506 break;
507 case security_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700508 usb_debug("content security\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000509 break;
510 case video_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700511 usb_debug("video\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000512 break;
513 case healthcare_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700514 usb_debug("healthcare\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000515 break;
516 case diagnostic_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700517 usb_debug("diagnostic\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000518 break;
519 case wireless_device:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700520 usb_debug("wireless\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000521 break;
522 default:
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700523 usb_debug("unsupported class %x\n", class);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000524 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000525 }
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800526 controller->devices[adr]->init = usb_generic_init;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000527 return adr;
528}
Patrick Georgi4727c072008-10-16 19:20:51 +0000529
Nico Huber79e1f2f2012-06-01 09:50:11 +0200530/*
531 * Should be called by the hub drivers whenever a physical detach occurs
532 * and can be called by usb class drivers if they are unsatisfied with a
533 * malfunctioning device.
534 */
Patrick Georgi4727c072008-10-16 19:20:51 +0000535void
536usb_detach_device(hci_t *controller, int devno)
537{
Nico Huber79e1f2f2012-06-01 09:50:11 +0200538 /* check if device exists, as we may have
539 been called yet by the usb class driver */
540 if (controller->devices[devno]) {
541 controller->devices[devno]->destroy (controller->devices[devno]);
542 free(controller->devices[devno]);
543 controller->devices[devno] = NULL;
Patrick Georgi482af6d2013-05-24 15:48:56 +0200544 if (controller->destroy_device)
545 controller->destroy_device(controller, devno);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200546 }
Patrick Georgi4727c072008-10-16 19:20:51 +0000547}
548
549int
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000550usb_attach_device(hci_t *controller, int hubaddress, int port, int speed)
Patrick Georgi4727c072008-10-16 19:20:51 +0000551{
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000552 static const char* speeds[] = { "full", "low", "high" };
Gabe Black93ded592012-11-01 15:44:10 -0700553 usb_debug ("%sspeed device\n", (speed <= 2) ? speeds[speed] : "invalid value - no");
Nico Huber1ab60752012-05-23 09:21:54 +0200554 int newdev = set_address (controller, speed, port, hubaddress);
Patrick Georgi4727c072008-10-16 19:20:51 +0000555 if (newdev == -1)
556 return -1;
557 usbdev_t *newdev_t = controller->devices[newdev];
Patrick Georgi4727c072008-10-16 19:20:51 +0000558 // determine responsible driver - current done in set_address
559 newdev_t->init (newdev_t);
Nico Huberd8a66802012-06-21 11:21:23 +0200560 /* init() may have called usb_detach_device() yet, so check */
561 return controller->devices[newdev] ? newdev : -1;
Patrick Georgi4727c072008-10-16 19:20:51 +0000562}
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000563
Gabe Blackdc9e77f2013-02-01 20:19:27 -0800564static void
565usb_generic_destroy (usbdev_t *dev)
566{
567 if (usb_generic_remove)
568 usb_generic_remove(dev);
569}
570
571void
572usb_generic_init (usbdev_t *dev)
573{
574 dev->data = NULL;
575 dev->destroy = usb_generic_destroy;
576
577 if (usb_generic_create)
578 usb_generic_create(dev);
579}