blob: d5514f980ccaa9264643448ac0aabdf49a50be32 [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{
77 if (usb_hcs == 0)
78 return 0;
79 hci_t *controller = usb_hcs;
Patrick Georgidb89ec92011-11-18 11:56:38 +010080 while (controller != NULL) {
Patrick Georgibbc52312011-11-04 12:06:06 +010081 controller->shutdown(controller);
82 controller = controller->next;
83 }
84 return 0;
85}
86
87/**
Patrick Georgid21f68b2008-09-02 16:06:22 +000088 * Polls all hubs on all USB controllers, to find out about device changes
89 */
90void
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000091usb_poll (void)
Patrick Georgid21f68b2008-09-02 16:06:22 +000092{
93 if (usb_hcs == 0)
94 return;
95 hci_t *controller = usb_hcs;
Patrick Georgidb89ec92011-11-18 11:56:38 +010096 while (controller != NULL) {
Patrick Georgid21f68b2008-09-02 16:06:22 +000097 int i;
98 for (i = 0; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +000099 if (controller->devices[i] != 0) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000100 controller->devices[i]->poll (controller->devices[i]);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000101 }
102 }
103 controller = controller->next;
104 }
105}
106
107void
108init_device_entry (hci_t *controller, int i)
109{
Patrick Georgi4727c072008-10-16 19:20:51 +0000110 if (controller->devices[i] != 0)
Mathias Krausec4716b42011-06-08 15:36:55 +0200111 debug("warning: device %d reassigned?\n", i);
Patrick Georgi4727c072008-10-16 19:20:51 +0000112 controller->devices[i] = malloc(sizeof(usbdev_t));
113 controller->devices[i]->controller = controller;
114 controller->devices[i]->address = -1;
115 controller->devices[i]->hub = -1;
116 controller->devices[i]->port = -1;
117 controller->devices[i]->init = usb_nop_init;
118 controller->devices[i]->init (controller->devices[i]);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000119}
120
121void
122set_feature (usbdev_t *dev, int endp, int feature, int rtype)
123{
124 dev_req_t dr;
125
126 dr.bmRequestType = rtype;
127 dr.data_dir = host_to_device;
128 dr.bRequest = SET_FEATURE;
129 dr.wValue = feature;
130 dr.wIndex = endp;
131 dr.wLength = 0;
132 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
133}
134
135void
136get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
137{
138 dev_req_t dr;
139
140 dr.bmRequestType = rtype;
141 dr.data_dir = device_to_host;
142 dr.bRequest = GET_STATUS;
143 dr.wValue = 0;
144 dr.wIndex = intf;
145 dr.wLength = len;
146 dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
147}
148
149u8 *
150get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
151 int descIdx, int langID)
152{
153 u8 buf[8];
154 u8 *result;
155 dev_req_t dr;
156 int size;
157
158 dr.bmRequestType = bmRequestType;
159 dr.data_dir = device_to_host; // always like this for descriptors
160 dr.bRequest = GET_DESCRIPTOR;
161 dr.wValue = (descType << 8) | descIdx;
162 dr.wIndex = langID;
163 dr.wLength = 8;
164 if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf)) {
Mathias Krausec4716b42011-06-08 15:36:55 +0200165 debug ("getting descriptor size (type %x) failed\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000166 descType);
167 }
168
169 if (descType == 1) {
170 device_descriptor_t *dd = (device_descriptor_t *) buf;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000171 debug ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000172 if (dd->bMaxPacketSize0 != 0)
173 dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
174 }
175
176 /* special case for configuration descriptors: they carry all their
177 subsequent descriptors with them, and keep the entire size at a
178 different location */
179 size = buf[0];
180 if (buf[1] == 2) {
181 int realsize = ((unsigned short *) (buf + 2))[0];
182 size = realsize;
183 }
184 result = malloc (size);
185 memset (result, 0, size);
186 dr.wLength = size;
187 if (dev->controller->
188 control (dev, IN, sizeof (dr), &dr, size, result)) {
Mathias Krausec4716b42011-06-08 15:36:55 +0200189 debug ("getting descriptor (type %x, size %x) failed\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000190 descType, size);
191 }
192
193 return result;
194}
195
196void
197set_configuration (usbdev_t *dev)
198{
199 dev_req_t dr;
200
201 dr.bmRequestType = 0;
202 dr.bRequest = SET_CONFIGURATION;
203 dr.wValue = dev->configuration[5];
204 dr.wIndex = 0;
205 dr.wLength = 0;
206 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
207}
208
Nico Huber79e1f2f2012-06-01 09:50:11 +0200209int
Nico Huber5f595cb2012-05-21 16:19:05 +0200210clear_feature (usbdev_t *dev, int endp, int feature, int rtype)
211{
212 dev_req_t dr;
213
214 dr.bmRequestType = rtype;
215 dr.data_dir = host_to_device;
216 dr.bRequest = CLEAR_FEATURE;
217 dr.wValue = feature;
218 dr.wIndex = endp;
219 dr.wLength = 0;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200220 return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
Nico Huber5f595cb2012-05-21 16:19:05 +0200221}
222
Patrick Georgid21f68b2008-09-02 16:06:22 +0000223int
224clear_stall (endpoint_t *ep)
225{
226 usbdev_t *dev = ep->dev;
227 int endp = ep->endpoint;
Nico Huber5f595cb2012-05-21 16:19:05 +0200228 int rtype = gen_bmRequestType (host_to_device, standard_type,
229 endp ? endp_recp : dev_recp);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000230
Nico Huber79e1f2f2012-06-01 09:50:11 +0200231 int ret = clear_feature (dev, endp, ENDPOINT_HALT, rtype);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000232 ep->toggle = 0;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200233 return ret;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000234}
235
236/* returns free address or -1 */
237static int
238get_free_address (hci_t *controller)
239{
240 int i;
241 for (i = 1; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +0000242 if (controller->devices[i] == 0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000243 return i;
244 }
Mathias Krausec4716b42011-06-08 15:36:55 +0200245 debug ("no free address found\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000246 return -1; // no free address
247}
248
Nico Huber1ab60752012-05-23 09:21:54 +0200249static int
250set_address (hci_t *controller, int speed, int hubport, int hubaddr)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000251{
252 int adr = get_free_address (controller); // address to set
253 dev_req_t dr;
254 configuration_descriptor_t *cd;
255 device_descriptor_t *dd;
256
257 memset (&dr, 0, sizeof (dr));
258 dr.data_dir = host_to_device;
259 dr.req_type = standard_type;
260 dr.req_recp = dev_recp;
261 dr.bRequest = SET_ADDRESS;
262 dr.wValue = adr;
263 dr.wIndex = 0;
264 dr.wLength = 0;
265
Patrick Georgi4727c072008-10-16 19:20:51 +0000266 init_device_entry(controller, adr);
267 usbdev_t *dev = controller->devices[adr];
Patrick Georgid21f68b2008-09-02 16:06:22 +0000268 // dummy values for registering the address
269 dev->address = 0;
Nico Huber1ab60752012-05-23 09:21:54 +0200270 dev->hub = hubaddr;
271 dev->port = hubport;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000272 dev->speed = speed;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000273 dev->endpoints[0].dev = dev;
274 dev->endpoints[0].endpoint = 0;
275 dev->endpoints[0].maxpacketsize = 8;
276 dev->endpoints[0].toggle = 0;
277 dev->endpoints[0].direction = SETUP;
278 mdelay (50);
279 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0)) {
Mathias Krausec4716b42011-06-08 15:36:55 +0200280 debug ("set_address failed\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000281 return -1;
282 }
283 mdelay (50);
284 dev->address = adr;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000285 dev->descriptor = get_descriptor (dev, gen_bmRequestType
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000286 (device_to_host, standard_type, dev_recp), 1, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000287 dd = (device_descriptor_t *) dev->descriptor;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000288
Mathias Krausec4716b42011-06-08 15:36:55 +0200289 printf ("* found device (0x%04x:0x%04x, USB %x.%x)",
Stefan Reinauer14e22772010-04-27 06:56:47 +0000290 dd->idVendor, dd->idProduct,
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000291 dd->bcdUSB >> 8, dd->bcdUSB & 0xff);
292 dev->quirks = usb_quirk_check(dd->idVendor, dd->idProduct);
293
294 debug ("\ndevice has %x configurations\n", dd->bNumConfigurations);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000295 if (dd->bNumConfigurations == 0) {
296 /* device isn't usable */
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000297 printf ("... no usable configuration!\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000298 dev->address = 0;
299 return -1;
300 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000301
302 dev->configuration = get_descriptor (dev, gen_bmRequestType
303 (device_to_host, standard_type, dev_recp), 2, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000304 cd = (configuration_descriptor_t *) dev->configuration;
305 set_configuration (dev);
306 interface_descriptor_t *interface =
307 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
308 {
309 int i;
310 int num = cd->bNumInterfaces;
311 interface_descriptor_t *current = interface;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000312 debug ("device has %x interfaces\n", num);
313 if (num > 1) {
314 int interfaces = usb_interface_check(dd->idVendor, dd->idProduct);
315 if (interfaces) {
316 /* Well known device, don't warn */
317 num = interfaces;
318 } else {
319
320 printf ("\nNOTICE: This driver defaults to using the first interface.\n"
321 "This might be the wrong choice and lead to limited functionality\n"
322 "of the device. Please report such a case to coreboot@coreboot.org\n"
323 "as you might be the first.\n");
324 /* we limit to the first interface, as there was no need to
325 * implement something else for the time being. If you need
326 * it, see the SetInterface and GetInterface functions in
327 * the USB specification, and adapt appropriately.
328 */
329 num = (num > 1) ? 1 : num;
330 }
331 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000332 for (i = 0; i < num; i++) {
333 int j;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000334 debug (" #%x has %x endpoints, interface %x:%x, protocol %x\n",
335 current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000336 endpoint_descriptor_t *endp =
337 (endpoint_descriptor_t *) (((char *) current)
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000338 + current->bLength);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000339 if (interface->bInterfaceClass == 0x3)
340 endp = (endpoint_descriptor_t *) (((char *) endp) + ((char *) endp)[0]); // ignore HID descriptor
341 memset (dev->endpoints, 0, sizeof (dev->endpoints));
342 dev->num_endp = 1; // 0 always exists
343 dev->endpoints[0].dev = dev;
344 dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
345 dev->endpoints[0].direction = SETUP;
346 dev->endpoints[0].type = CONTROL;
347 for (j = 1; j <= current->bNumEndpoints; j++) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000348#ifdef USB_DEBUG
349 static const char *transfertypes[4] = {
350 "control", "isochronous", "bulk", "interrupt"
Patrick Georgid21f68b2008-09-02 16:06:22 +0000351 };
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000352 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]);
353#endif
Patrick Georgid21f68b2008-09-02 16:06:22 +0000354 endpoint_t *ep =
355 &dev->endpoints[dev->num_endp++];
356 ep->dev = dev;
357 ep->endpoint = endp->bEndpointAddress;
358 ep->toggle = 0;
359 ep->maxpacketsize = endp->wMaxPacketSize;
360 ep->direction =
361 ((endp->bEndpointAddress & 0x80) ==
362 0) ? OUT : IN;
363 ep->type = endp->bmAttributes;
364 endp = (endpoint_descriptor_t
365 *) (((char *) endp) + endp->bLength);
366 }
367 current = (interface_descriptor_t *) endp;
368 }
369 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000370
Patrick Georgid21f68b2008-09-02 16:06:22 +0000371 int class = dd->bDeviceClass;
372 if (class == 0)
373 class = interface->bInterfaceClass;
374
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000375 enum {
376 audio_device = 0x01,
377 comm_device = 0x02,
378 hid_device = 0x03,
379 physical_device = 0x05,
380 imaging_device = 0x06,
381 printer_device = 0x07,
382 msc_device = 0x08,
383 hub_device = 0x09,
384 cdc_device = 0x0a,
385 ccid_device = 0x0b,
386 security_device = 0x0d,
387 video_device = 0x0e,
388 healthcare_device = 0x0f,
389 diagnostic_device = 0xdc,
390 wireless_device = 0xe0,
391 misc_device = 0xef,
392 };
Mathias Krausec4716b42011-06-08 15:36:55 +0200393 printf(", class: ");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000394 switch (class) {
395 case audio_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200396 printf("audio\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000397 break;
398 case comm_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200399 printf("communication\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000400 break;
401 case hid_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200402 printf ("HID\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000403#ifdef CONFIG_USB_HID
Patrick Georgi4727c072008-10-16 19:20:51 +0000404 controller->devices[adr]->init = usb_hid_init;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000405#else
Mathias Krausec4716b42011-06-08 15:36:55 +0200406 debug ("NOTICE: USB HID support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000407#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000408 break;
409 case physical_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200410 printf("physical\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000411 break;
412 case imaging_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200413 printf("camera\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000414 break;
415 case printer_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200416 printf("printer\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000417 break;
418 case msc_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200419 printf ("MSC\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000420#ifdef CONFIG_USB_MSC
Patrick Georgi4727c072008-10-16 19:20:51 +0000421 controller->devices[adr]->init = usb_msc_init;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000422#else
Mathias Krausec4716b42011-06-08 15:36:55 +0200423 debug ("NOTICE: USB MSC support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000424#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000425 break;
426 case hub_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200427 printf ("hub\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000428#ifdef CONFIG_USB_HUB
429 controller->devices[adr]->init = usb_hub_init;
430#else
Mathias Krausec4716b42011-06-08 15:36:55 +0200431 debug ("NOTICE: USB hub support not compiled in.\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000432#endif
433 break;
434 case cdc_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200435 printf("CDC\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000436 break;
437 case ccid_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200438 printf("smartcard / CCID\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000439 break;
440 case security_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200441 printf("content security\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000442 break;
443 case video_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200444 printf("video\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000445 break;
446 case healthcare_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200447 printf("healthcare\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000448 break;
449 case diagnostic_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200450 printf("diagnostic\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000451 break;
452 case wireless_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200453 printf("wireless\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000454 break;
455 default:
Mathias Krausec4716b42011-06-08 15:36:55 +0200456 printf("unsupported class %x\n", class);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000457 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000458 }
459 return adr;
460}
Patrick Georgi4727c072008-10-16 19:20:51 +0000461
Nico Huber79e1f2f2012-06-01 09:50:11 +0200462/*
463 * Should be called by the hub drivers whenever a physical detach occurs
464 * and can be called by usb class drivers if they are unsatisfied with a
465 * malfunctioning device.
466 */
Patrick Georgi4727c072008-10-16 19:20:51 +0000467void
468usb_detach_device(hci_t *controller, int devno)
469{
Nico Huber79e1f2f2012-06-01 09:50:11 +0200470 /* check if device exists, as we may have
471 been called yet by the usb class driver */
472 if (controller->devices[devno]) {
473 controller->devices[devno]->destroy (controller->devices[devno]);
474 free(controller->devices[devno]);
475 controller->devices[devno] = NULL;
476 }
Patrick Georgi4727c072008-10-16 19:20:51 +0000477}
478
479int
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000480usb_attach_device(hci_t *controller, int hubaddress, int port, int speed)
Patrick Georgi4727c072008-10-16 19:20:51 +0000481{
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000482 static const char* speeds[] = { "full", "low", "high" };
Mathias Krausec4716b42011-06-08 15:36:55 +0200483 debug ("%sspeed device\n", (speed <= 2) ? speeds[speed] : "invalid value - no");
Nico Huber1ab60752012-05-23 09:21:54 +0200484 int newdev = set_address (controller, speed, port, hubaddress);
Patrick Georgi4727c072008-10-16 19:20:51 +0000485 if (newdev == -1)
486 return -1;
487 usbdev_t *newdev_t = controller->devices[newdev];
Patrick Georgi4727c072008-10-16 19:20:51 +0000488 // determine responsible driver - current done in set_address
489 newdev_t->init (newdev_t);
Nico Huberd8a66802012-06-21 11:21:23 +0200490 /* init() may have called usb_detach_device() yet, so check */
491 return controller->devices[newdev] ? newdev : -1;
Patrick Georgi4727c072008-10-16 19:20:51 +0000492}
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000493