blob: 1f21e6a9940d7716e7eadaf2adca6d13119714f4 [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 }
66 }
67 }
68}
69
70/**
Patrick Georgibbc52312011-11-04 12:06:06 +010071 * Shut down all controllers
72 */
73int
74usb_exit (void)
75{
76 if (usb_hcs == 0)
77 return 0;
78 hci_t *controller = usb_hcs;
Patrick Georgidb89ec92011-11-18 11:56:38 +010079 while (controller != NULL) {
Patrick Georgibbc52312011-11-04 12:06:06 +010080 controller->shutdown(controller);
81 controller = controller->next;
82 }
83 return 0;
84}
85
86/**
Patrick Georgid21f68b2008-09-02 16:06:22 +000087 * Polls all hubs on all USB controllers, to find out about device changes
88 */
89void
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000090usb_poll (void)
Patrick Georgid21f68b2008-09-02 16:06:22 +000091{
92 if (usb_hcs == 0)
93 return;
94 hci_t *controller = usb_hcs;
Patrick Georgidb89ec92011-11-18 11:56:38 +010095 while (controller != NULL) {
Patrick Georgid21f68b2008-09-02 16:06:22 +000096 int i;
97 for (i = 0; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +000098 if (controller->devices[i] != 0) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000099 controller->devices[i]->poll (controller->devices[i]);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000100 }
101 }
102 controller = controller->next;
103 }
104}
105
106void
107init_device_entry (hci_t *controller, int i)
108{
Patrick Georgi4727c072008-10-16 19:20:51 +0000109 if (controller->devices[i] != 0)
Mathias Krausec4716b42011-06-08 15:36:55 +0200110 debug("warning: device %d reassigned?\n", i);
Patrick Georgi4727c072008-10-16 19:20:51 +0000111 controller->devices[i] = malloc(sizeof(usbdev_t));
112 controller->devices[i]->controller = controller;
113 controller->devices[i]->address = -1;
114 controller->devices[i]->hub = -1;
115 controller->devices[i]->port = -1;
116 controller->devices[i]->init = usb_nop_init;
117 controller->devices[i]->init (controller->devices[i]);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000118}
119
120void
121set_feature (usbdev_t *dev, int endp, int feature, int rtype)
122{
123 dev_req_t dr;
124
125 dr.bmRequestType = rtype;
126 dr.data_dir = host_to_device;
127 dr.bRequest = SET_FEATURE;
128 dr.wValue = feature;
129 dr.wIndex = endp;
130 dr.wLength = 0;
131 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
132}
133
134void
135get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
136{
137 dev_req_t dr;
138
139 dr.bmRequestType = rtype;
140 dr.data_dir = device_to_host;
141 dr.bRequest = GET_STATUS;
142 dr.wValue = 0;
143 dr.wIndex = intf;
144 dr.wLength = len;
145 dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
146}
147
148u8 *
149get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
150 int descIdx, int langID)
151{
152 u8 buf[8];
153 u8 *result;
154 dev_req_t dr;
155 int size;
156
157 dr.bmRequestType = bmRequestType;
158 dr.data_dir = device_to_host; // always like this for descriptors
159 dr.bRequest = GET_DESCRIPTOR;
160 dr.wValue = (descType << 8) | descIdx;
161 dr.wIndex = langID;
162 dr.wLength = 8;
163 if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf)) {
Mathias Krausec4716b42011-06-08 15:36:55 +0200164 debug ("getting descriptor size (type %x) failed\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000165 descType);
166 }
167
168 if (descType == 1) {
169 device_descriptor_t *dd = (device_descriptor_t *) buf;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000170 debug ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000171 if (dd->bMaxPacketSize0 != 0)
172 dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
173 }
174
175 /* special case for configuration descriptors: they carry all their
176 subsequent descriptors with them, and keep the entire size at a
177 different location */
178 size = buf[0];
179 if (buf[1] == 2) {
180 int realsize = ((unsigned short *) (buf + 2))[0];
181 size = realsize;
182 }
183 result = malloc (size);
184 memset (result, 0, size);
185 dr.wLength = size;
186 if (dev->controller->
187 control (dev, IN, sizeof (dr), &dr, size, result)) {
Mathias Krausec4716b42011-06-08 15:36:55 +0200188 debug ("getting descriptor (type %x, size %x) failed\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000189 descType, size);
190 }
191
192 return result;
193}
194
195void
196set_configuration (usbdev_t *dev)
197{
198 dev_req_t dr;
199
200 dr.bmRequestType = 0;
201 dr.bRequest = SET_CONFIGURATION;
202 dr.wValue = dev->configuration[5];
203 dr.wIndex = 0;
204 dr.wLength = 0;
205 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
206}
207
208int
209clear_stall (endpoint_t *ep)
210{
211 usbdev_t *dev = ep->dev;
212 int endp = ep->endpoint;
213 dev_req_t dr;
214
215 dr.bmRequestType = 0;
216 if (endp != 0) {
217 dr.req_recp = endp_recp;
218 }
219 dr.bRequest = CLEAR_FEATURE;
220 dr.wValue = ENDPOINT_HALT;
221 dr.wIndex = endp;
222 dr.wLength = 0;
223 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000224 ep->toggle = 0;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000225 return 0;
226}
227
228/* returns free address or -1 */
229static int
230get_free_address (hci_t *controller)
231{
232 int i;
233 for (i = 1; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +0000234 if (controller->devices[i] == 0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000235 return i;
236 }
Mathias Krausec4716b42011-06-08 15:36:55 +0200237 debug ("no free address found\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000238 return -1; // no free address
239}
240
241int
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000242set_address (hci_t *controller, int speed)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000243{
244 int adr = get_free_address (controller); // address to set
245 dev_req_t dr;
246 configuration_descriptor_t *cd;
247 device_descriptor_t *dd;
248
249 memset (&dr, 0, sizeof (dr));
250 dr.data_dir = host_to_device;
251 dr.req_type = standard_type;
252 dr.req_recp = dev_recp;
253 dr.bRequest = SET_ADDRESS;
254 dr.wValue = adr;
255 dr.wIndex = 0;
256 dr.wLength = 0;
257
Patrick Georgi4727c072008-10-16 19:20:51 +0000258 init_device_entry(controller, adr);
259 usbdev_t *dev = controller->devices[adr];
Patrick Georgid21f68b2008-09-02 16:06:22 +0000260 // dummy values for registering the address
261 dev->address = 0;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000262 dev->speed = speed;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000263 dev->endpoints[0].dev = dev;
264 dev->endpoints[0].endpoint = 0;
265 dev->endpoints[0].maxpacketsize = 8;
266 dev->endpoints[0].toggle = 0;
267 dev->endpoints[0].direction = SETUP;
268 mdelay (50);
269 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0)) {
Mathias Krausec4716b42011-06-08 15:36:55 +0200270 debug ("set_address failed\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000271 return -1;
272 }
273 mdelay (50);
274 dev->address = adr;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000275 dev->descriptor = get_descriptor (dev, gen_bmRequestType
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000276 (device_to_host, standard_type, dev_recp), 1, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000277 dd = (device_descriptor_t *) dev->descriptor;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000278
Mathias Krausec4716b42011-06-08 15:36:55 +0200279 printf ("* found device (0x%04x:0x%04x, USB %x.%x)",
Stefan Reinauer14e22772010-04-27 06:56:47 +0000280 dd->idVendor, dd->idProduct,
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000281 dd->bcdUSB >> 8, dd->bcdUSB & 0xff);
282 dev->quirks = usb_quirk_check(dd->idVendor, dd->idProduct);
283
284 debug ("\ndevice has %x configurations\n", dd->bNumConfigurations);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000285 if (dd->bNumConfigurations == 0) {
286 /* device isn't usable */
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000287 printf ("... no usable configuration!\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000288 dev->address = 0;
289 return -1;
290 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000291
292 dev->configuration = get_descriptor (dev, gen_bmRequestType
293 (device_to_host, standard_type, dev_recp), 2, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000294 cd = (configuration_descriptor_t *) dev->configuration;
295 set_configuration (dev);
296 interface_descriptor_t *interface =
297 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
298 {
299 int i;
300 int num = cd->bNumInterfaces;
301 interface_descriptor_t *current = interface;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000302 debug ("device has %x interfaces\n", num);
303 if (num > 1) {
304 int interfaces = usb_interface_check(dd->idVendor, dd->idProduct);
305 if (interfaces) {
306 /* Well known device, don't warn */
307 num = interfaces;
308 } else {
309
310 printf ("\nNOTICE: This driver defaults to using the first interface.\n"
311 "This might be the wrong choice and lead to limited functionality\n"
312 "of the device. Please report such a case to coreboot@coreboot.org\n"
313 "as you might be the first.\n");
314 /* we limit to the first interface, as there was no need to
315 * implement something else for the time being. If you need
316 * it, see the SetInterface and GetInterface functions in
317 * the USB specification, and adapt appropriately.
318 */
319 num = (num > 1) ? 1 : num;
320 }
321 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000322 for (i = 0; i < num; i++) {
323 int j;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000324 debug (" #%x has %x endpoints, interface %x:%x, protocol %x\n",
325 current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000326 endpoint_descriptor_t *endp =
327 (endpoint_descriptor_t *) (((char *) current)
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000328 + current->bLength);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000329 if (interface->bInterfaceClass == 0x3)
330 endp = (endpoint_descriptor_t *) (((char *) endp) + ((char *) endp)[0]); // ignore HID descriptor
331 memset (dev->endpoints, 0, sizeof (dev->endpoints));
332 dev->num_endp = 1; // 0 always exists
333 dev->endpoints[0].dev = dev;
334 dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
335 dev->endpoints[0].direction = SETUP;
336 dev->endpoints[0].type = CONTROL;
337 for (j = 1; j <= current->bNumEndpoints; j++) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000338#ifdef USB_DEBUG
339 static const char *transfertypes[4] = {
340 "control", "isochronous", "bulk", "interrupt"
Patrick Georgid21f68b2008-09-02 16:06:22 +0000341 };
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000342 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]);
343#endif
Patrick Georgid21f68b2008-09-02 16:06:22 +0000344 endpoint_t *ep =
345 &dev->endpoints[dev->num_endp++];
346 ep->dev = dev;
347 ep->endpoint = endp->bEndpointAddress;
348 ep->toggle = 0;
349 ep->maxpacketsize = endp->wMaxPacketSize;
350 ep->direction =
351 ((endp->bEndpointAddress & 0x80) ==
352 0) ? OUT : IN;
353 ep->type = endp->bmAttributes;
354 endp = (endpoint_descriptor_t
355 *) (((char *) endp) + endp->bLength);
356 }
357 current = (interface_descriptor_t *) endp;
358 }
359 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000360
Patrick Georgid21f68b2008-09-02 16:06:22 +0000361 int class = dd->bDeviceClass;
362 if (class == 0)
363 class = interface->bInterfaceClass;
364
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000365 enum {
366 audio_device = 0x01,
367 comm_device = 0x02,
368 hid_device = 0x03,
369 physical_device = 0x05,
370 imaging_device = 0x06,
371 printer_device = 0x07,
372 msc_device = 0x08,
373 hub_device = 0x09,
374 cdc_device = 0x0a,
375 ccid_device = 0x0b,
376 security_device = 0x0d,
377 video_device = 0x0e,
378 healthcare_device = 0x0f,
379 diagnostic_device = 0xdc,
380 wireless_device = 0xe0,
381 misc_device = 0xef,
382 };
Mathias Krausec4716b42011-06-08 15:36:55 +0200383 printf(", class: ");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000384 switch (class) {
385 case audio_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200386 printf("audio\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000387 break;
388 case comm_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200389 printf("communication\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000390 break;
391 case hid_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200392 printf ("HID\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000393#ifdef CONFIG_USB_HID
Patrick Georgi4727c072008-10-16 19:20:51 +0000394 controller->devices[adr]->init = usb_hid_init;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000395#else
Mathias Krausec4716b42011-06-08 15:36:55 +0200396 debug ("NOTICE: USB HID support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000397#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000398 break;
399 case physical_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200400 printf("physical\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000401 break;
402 case imaging_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200403 printf("camera\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000404 break;
405 case printer_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200406 printf("printer\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000407 break;
408 case msc_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200409 printf ("MSC\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000410#ifdef CONFIG_USB_MSC
Patrick Georgi4727c072008-10-16 19:20:51 +0000411 controller->devices[adr]->init = usb_msc_init;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000412#else
Mathias Krausec4716b42011-06-08 15:36:55 +0200413 debug ("NOTICE: USB MSC support not compiled in\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000414#endif
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000415 break;
416 case hub_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200417 printf ("hub\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000418#ifdef CONFIG_USB_HUB
419 controller->devices[adr]->init = usb_hub_init;
420#else
Mathias Krausec4716b42011-06-08 15:36:55 +0200421 debug ("NOTICE: USB hub support not compiled in.\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000422#endif
423 break;
424 case cdc_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200425 printf("CDC\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000426 break;
427 case ccid_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200428 printf("smartcard / CCID\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000429 break;
430 case security_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200431 printf("content security\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000432 break;
433 case video_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200434 printf("video\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000435 break;
436 case healthcare_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200437 printf("healthcare\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000438 break;
439 case diagnostic_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200440 printf("diagnostic\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000441 break;
442 case wireless_device:
Mathias Krausec4716b42011-06-08 15:36:55 +0200443 printf("wireless\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000444 break;
445 default:
Mathias Krausec4716b42011-06-08 15:36:55 +0200446 printf("unsupported class %x\n", class);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000447 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000448 }
449 return adr;
450}
Patrick Georgi4727c072008-10-16 19:20:51 +0000451
452void
453usb_detach_device(hci_t *controller, int devno)
454{
455 controller->devices[devno]->destroy (controller->devices[devno]);
456 free(controller->devices[devno]);
457 controller->devices[devno] = 0;
458}
459
460int
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000461usb_attach_device(hci_t *controller, int hubaddress, int port, int speed)
Patrick Georgi4727c072008-10-16 19:20:51 +0000462{
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000463 static const char* speeds[] = { "full", "low", "high" };
Mathias Krausec4716b42011-06-08 15:36:55 +0200464 debug ("%sspeed device\n", (speed <= 2) ? speeds[speed] : "invalid value - no");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000465 int newdev = set_address (controller, speed);
Patrick Georgi4727c072008-10-16 19:20:51 +0000466 if (newdev == -1)
467 return -1;
468 usbdev_t *newdev_t = controller->devices[newdev];
469
470 newdev_t->address = newdev;
471 newdev_t->hub = hubaddress;
472 newdev_t->port = port;
473 // determine responsible driver - current done in set_address
474 newdev_t->init (newdev_t);
475 return newdev;
476}
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000477