2 * This file is part of the libpayload project.
4 * Copyright (C) 2008 coresystems GmbH
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
30 #include <libpayload-config.h>
38 hci_t *controller = malloc (sizeof (hci_t));
41 controller->next = usb_hcs;
49 detach_controller (hci_t *controller)
53 if (usb_hcs == controller) {
54 usb_hcs = controller->next;
58 if (it->next == controller) {
59 it->next = controller->next;
67 * Polls all hubs on all USB controllers, to find out about device changes
74 hci_t *controller = usb_hcs;
75 while (controller != 0) {
77 for (i = 0; i < 128; i++) {
78 if (controller->devices[i] != 0) {
79 controller->devices[i]->poll (controller->
83 controller = controller->next;
88 init_device_entry (hci_t *controller, int i)
90 if (controller->devices[i] != 0)
91 printf("warning: device %d reassigned?\n", i);
92 controller->devices[i] = malloc(sizeof(usbdev_t));
93 controller->devices[i]->controller = controller;
94 controller->devices[i]->address = -1;
95 controller->devices[i]->hub = -1;
96 controller->devices[i]->port = -1;
97 controller->devices[i]->init = usb_nop_init;
98 controller->devices[i]->init (controller->devices[i]);
102 set_feature (usbdev_t *dev, int endp, int feature, int rtype)
106 dr.bmRequestType = rtype;
107 dr.data_dir = host_to_device;
108 dr.bRequest = SET_FEATURE;
112 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
116 get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
120 dr.bmRequestType = rtype;
121 dr.data_dir = device_to_host;
122 dr.bRequest = GET_STATUS;
126 dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
130 get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
131 int descIdx, int langID)
138 dr.bmRequestType = bmRequestType;
139 dr.data_dir = device_to_host; // always like this for descriptors
140 dr.bRequest = GET_DESCRIPTOR;
141 dr.wValue = (descType << 8) | descIdx;
144 if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf)) {
145 printf ("getting descriptor size (type %x) failed\n",
150 device_descriptor_t *dd = (device_descriptor_t *) buf;
151 printf ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
152 if (dd->bMaxPacketSize0 != 0)
153 dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
156 /* special case for configuration descriptors: they carry all their
157 subsequent descriptors with them, and keep the entire size at a
158 different location */
161 int realsize = ((unsigned short *) (buf + 2))[0];
164 result = malloc (size);
165 memset (result, 0, size);
167 if (dev->controller->
168 control (dev, IN, sizeof (dr), &dr, size, result)) {
169 printf ("getting descriptor (type %x, size %x) failed\n",
177 set_configuration (usbdev_t *dev)
181 dr.bmRequestType = 0;
182 dr.bRequest = SET_CONFIGURATION;
183 dr.wValue = dev->configuration[5];
186 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
190 clear_stall (endpoint_t *ep)
192 usbdev_t *dev = ep->dev;
193 int endp = ep->endpoint;
196 dr.bmRequestType = 0;
198 dr.req_recp = endp_recp;
200 dr.bRequest = CLEAR_FEATURE;
201 dr.wValue = ENDPOINT_HALT;
204 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
208 /* returns free address or -1 */
210 get_free_address (hci_t *controller)
213 for (i = 1; i < 128; i++) {
214 if (controller->devices[i] == 0)
217 printf ("no free address found\n");
218 return -1; // no free address
222 set_address (hci_t *controller, int lowspeed)
224 int adr = get_free_address (controller); // address to set
226 configuration_descriptor_t *cd;
227 device_descriptor_t *dd;
229 memset (&dr, 0, sizeof (dr));
230 dr.data_dir = host_to_device;
231 dr.req_type = standard_type;
232 dr.req_recp = dev_recp;
233 dr.bRequest = SET_ADDRESS;
238 init_device_entry(controller, adr);
239 usbdev_t *dev = controller->devices[adr];
240 // dummy values for registering the address
242 dev->lowspeed = lowspeed;
243 dev->endpoints[0].dev = dev;
244 dev->endpoints[0].endpoint = 0;
245 dev->endpoints[0].maxpacketsize = 8;
246 dev->endpoints[0].toggle = 0;
247 dev->endpoints[0].direction = SETUP;
249 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0)) {
250 printf ("set_address failed\n");
257 gen_bmRequestType (device_to_host,
258 standard_type, dev_recp),
260 dd = (device_descriptor_t *) dev->descriptor;
261 printf ("device version: %x.%x\n", dd->bcdUSB >> 8,
263 printf ("device has %x configurations\n", dd->bNumConfigurations);
264 if (dd->bNumConfigurations == 0) {
265 /* device isn't usable */
266 printf ("no usable configuration!\n");
272 gen_bmRequestType (device_to_host,
273 standard_type, dev_recp),
275 cd = (configuration_descriptor_t *) dev->configuration;
276 set_configuration (dev);
277 interface_descriptor_t *interface =
278 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
281 int num = cd->bNumInterfaces;
282 interface_descriptor_t *current = interface;
283 printf ("device has %x interfaces\n", num);
285 printf ("NOTICE: This driver defaults to using the first interface.\n"
286 "This might be the wrong choice and lead to limited functionality\n"
287 "of the device. Please report such a case to coreboot@coreboot.org\n"
288 "as you might be the first.\n");
289 /* we limit to the first interface, as there was no need to
290 implement something else for the time being. If you need
291 it, see the SetInterface and GetInterface functions in
292 the USB specification, and adapt appropriately. */
293 num = (num > 1) ? 1 : num;
294 for (i = 0; i < num; i++) {
296 printf (" #%x has %x endpoints, interface %x:%x, protocol %x\n", current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
297 endpoint_descriptor_t *endp =
298 (endpoint_descriptor_t *) (((char *) current)
301 if (interface->bInterfaceClass == 0x3)
302 endp = (endpoint_descriptor_t *) (((char *) endp) + ((char *) endp)[0]); // ignore HID descriptor
303 memset (dev->endpoints, 0, sizeof (dev->endpoints));
304 dev->num_endp = 1; // 0 always exists
305 dev->endpoints[0].dev = dev;
306 dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
307 dev->endpoints[0].direction = SETUP;
308 dev->endpoints[0].type = CONTROL;
309 for (j = 1; j <= current->bNumEndpoints; j++) {
310 static const char *transfertypes[4] =
311 { "control", "isochronous", "bulk",
314 printf (" #%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]);
316 &dev->endpoints[dev->num_endp++];
318 ep->endpoint = endp->bEndpointAddress;
320 ep->maxpacketsize = endp->wMaxPacketSize;
322 ((endp->bEndpointAddress & 0x80) ==
324 ep->type = endp->bmAttributes;
325 endp = (endpoint_descriptor_t
326 *) (((char *) endp) + endp->bLength);
328 current = (interface_descriptor_t *) endp;
331 int class = dd->bDeviceClass;
333 class = interface->bInterfaceClass;
335 enum { hid_device = 0x3, msc_device = 0x8, hub_device = 0x9 };
337 printf ("device of class %x found\n", class);
338 if (class == hub_device) {
339 printf ("hub found\n");
340 #ifdef CONFIG_USB_HUB
341 controller->devices[adr]->init = usb_hub_init;
343 printf ("support not compiled in\n");
346 if (class == hid_device) {
347 printf ("HID found\n");
348 #ifdef CONFIG_USB_HID
349 controller->devices[adr]->init = usb_hid_init;
351 printf ("support not compiled in\n");
354 if (class == msc_device) {
355 printf ("MSC found\n");
356 #ifdef CONFIG_USB_MSC
357 controller->devices[adr]->init = usb_msc_init;
359 printf ("support not compiled in\n");
366 usb_detach_device(hci_t *controller, int devno)
368 controller->devices[devno]->destroy (controller->devices[devno]);
369 free(controller->devices[devno]);
370 controller->devices[devno] = 0;
374 usb_attach_device(hci_t *controller, int hubaddress, int port, int lowspeed)
376 printf ("%sspeed device\n", (lowspeed == 1) ? "low" : "full");
377 int newdev = set_address (controller, lowspeed);
380 usbdev_t *newdev_t = controller->devices[newdev];
382 newdev_t->address = newdev;
383 newdev_t->hub = hubaddress;
384 newdev_t->port = port;
385 // determine responsible driver - current done in set_address
386 newdev_t->init (newdev_t);