Some driver fixes for libpayload:
[coreboot.git] / payloads / libpayload / drivers / usb / usb.c
1 /*
2  * This file is part of the libpayload project.
3  *
4  * Copyright (C) 2008 coresystems GmbH
5  *
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
30 #include <libpayload-config.h>
31 #include <usb/usb.h>
32
33 hci_t *usb_hcs = 0;
34
35 hci_t *
36 new_controller ()
37 {
38         hci_t *controller = malloc (sizeof (hci_t));
39
40         /* atomic */
41         controller->next = usb_hcs;
42         usb_hcs = controller;
43         /* atomic end */
44
45         return controller;
46 }
47
48 void
49 detach_controller (hci_t *controller)
50 {
51         if (controller == 0)
52                 return;
53         if (usb_hcs == controller) {
54                 usb_hcs = controller->next;
55         } else {
56                 hci_t *it = usb_hcs;
57                 while (it != 0) {
58                         if (it->next == controller) {
59                                 it->next = controller->next;
60                                 return;
61                         }
62                 }
63         }
64 }
65
66 /**
67  * Polls all hubs on all USB controllers, to find out about device changes
68  */
69 void
70 usb_poll ()
71 {
72         if (usb_hcs == 0)
73                 return;
74         hci_t *controller = usb_hcs;
75         while (controller != 0) {
76                 int i;
77                 for (i = 0; i < 128; i++) {
78                         if (controller->devices[i] != 0) {
79                                 controller->devices[i]->poll (controller->
80                                                              devices[i]);
81                         }
82                 }
83                 controller = controller->next;
84         }
85 }
86
87 void
88 init_device_entry (hci_t *controller, int i)
89 {
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]);
99 }
100
101 void
102 set_feature (usbdev_t *dev, int endp, int feature, int rtype)
103 {
104         dev_req_t dr;
105
106         dr.bmRequestType = rtype;
107         dr.data_dir = host_to_device;
108         dr.bRequest = SET_FEATURE;
109         dr.wValue = feature;
110         dr.wIndex = endp;
111         dr.wLength = 0;
112         dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
113 }
114
115 void
116 get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
117 {
118         dev_req_t dr;
119
120         dr.bmRequestType = rtype;
121         dr.data_dir = device_to_host;
122         dr.bRequest = GET_STATUS;
123         dr.wValue = 0;
124         dr.wIndex = intf;
125         dr.wLength = len;
126         dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
127 }
128
129 u8 *
130 get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
131                 int descIdx, int langID)
132 {
133         u8 buf[8];
134         u8 *result;
135         dev_req_t dr;
136         int size;
137
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;
142         dr.wIndex = langID;
143         dr.wLength = 8;
144         if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf)) {
145                 printf ("getting descriptor size (type %x) failed\n",
146                         descType);
147         }
148
149         if (descType == 1) {
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;
154         }
155
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 */
159         size = buf[0];
160         if (buf[1] == 2) {
161                 int realsize = ((unsigned short *) (buf + 2))[0];
162                 size = realsize;
163         }
164         result = malloc (size);
165         memset (result, 0, size);
166         dr.wLength = size;
167         if (dev->controller->
168             control (dev, IN, sizeof (dr), &dr, size, result)) {
169                 printf ("getting descriptor (type %x, size %x) failed\n",
170                         descType, size);
171         }
172
173         return result;
174 }
175
176 void
177 set_configuration (usbdev_t *dev)
178 {
179         dev_req_t dr;
180
181         dr.bmRequestType = 0;
182         dr.bRequest = SET_CONFIGURATION;
183         dr.wValue = dev->configuration[5];
184         dr.wIndex = 0;
185         dr.wLength = 0;
186         dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
187 }
188
189 int
190 clear_stall (endpoint_t *ep)
191 {
192         usbdev_t *dev = ep->dev;
193         int endp = ep->endpoint;
194         dev_req_t dr;
195
196         dr.bmRequestType = 0;
197         if (endp != 0) {
198                 dr.req_recp = endp_recp;
199         }
200         dr.bRequest = CLEAR_FEATURE;
201         dr.wValue = ENDPOINT_HALT;
202         dr.wIndex = endp;
203         dr.wLength = 0;
204         dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
205         return 0;
206 }
207
208 /* returns free address or -1 */
209 static int
210 get_free_address (hci_t *controller)
211 {
212         int i;
213         for (i = 1; i < 128; i++) {
214                 if (controller->devices[i] == 0)
215                         return i;
216         }
217         printf ("no free address found\n");
218         return -1;              // no free address
219 }
220
221 int
222 set_address (hci_t *controller, int lowspeed)
223 {
224         int adr = get_free_address (controller);        // address to set
225         dev_req_t dr;
226         configuration_descriptor_t *cd;
227         device_descriptor_t *dd;
228
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;
234         dr.wValue = adr;
235         dr.wIndex = 0;
236         dr.wLength = 0;
237
238         init_device_entry(controller, adr);
239         usbdev_t *dev = controller->devices[adr];
240         // dummy values for registering the address
241         dev->address = 0;
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;
248         mdelay (50);
249         if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0)) {
250                 printf ("set_address failed\n");
251                 return -1;
252         }
253         mdelay (50);
254         dev->address = adr;
255         dev->descriptor =
256                 get_descriptor (dev,
257                                 gen_bmRequestType (device_to_host,
258                                                    standard_type, dev_recp),
259                                 1, 0, 0);
260         dd = (device_descriptor_t *) dev->descriptor;
261         printf ("device version: %x.%x\n", dd->bcdUSB >> 8,
262                 dd->bcdUSB & 0xff);
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");
267                 dev->address = 0;
268                 return -1;
269         }
270         dev->configuration =
271                 get_descriptor (dev,
272                                 gen_bmRequestType (device_to_host,
273                                                    standard_type, dev_recp),
274                                 2, 0, 0);
275         cd = (configuration_descriptor_t *) dev->configuration;
276         set_configuration (dev);
277         interface_descriptor_t *interface =
278                 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
279         {
280                 int i;
281                 int num = cd->bNumInterfaces;
282                 interface_descriptor_t *current = interface;
283                 printf ("device has %x interfaces\n", num);
284                 if (num>1)
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++) {
295                         int j;
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)
299                                                            +
300                                                            current->bLength);
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",
312                                         "interrupt"
313                                 };
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]);
315                                 endpoint_t *ep =
316                                         &dev->endpoints[dev->num_endp++];
317                                 ep->dev = dev;
318                                 ep->endpoint = endp->bEndpointAddress;
319                                 ep->toggle = 0;
320                                 ep->maxpacketsize = endp->wMaxPacketSize;
321                                 ep->direction =
322                                         ((endp->bEndpointAddress & 0x80) ==
323                                          0) ? OUT : IN;
324                                 ep->type = endp->bmAttributes;
325                                 endp = (endpoint_descriptor_t
326                                         *) (((char *) endp) + endp->bLength);
327                         }
328                         current = (interface_descriptor_t *) endp;
329                 }
330         }
331         int class = dd->bDeviceClass;
332         if (class == 0)
333                 class = interface->bInterfaceClass;
334
335         enum { hid_device = 0x3, msc_device = 0x8, hub_device = 0x9 };
336
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;
342 #else
343                 printf ("support not compiled in\n");
344 #endif
345         }
346         if (class == hid_device) {
347                 printf ("HID found\n");
348 #ifdef CONFIG_USB_HID
349                 controller->devices[adr]->init = usb_hid_init;
350 #else
351                 printf ("support not compiled in\n");
352 #endif
353         }
354         if (class == msc_device) {
355                 printf ("MSC found\n");
356 #ifdef CONFIG_USB_MSC
357                 controller->devices[adr]->init = usb_msc_init;
358 #else
359                 printf ("support not compiled in\n");
360 #endif
361         }
362         return adr;
363 }
364
365 void
366 usb_detach_device(hci_t *controller, int devno)
367 {
368         controller->devices[devno]->destroy (controller->devices[devno]);
369         free(controller->devices[devno]);
370         controller->devices[devno] = 0;
371 }
372
373 int
374 usb_attach_device(hci_t *controller, int hubaddress, int port, int lowspeed)
375 {
376         printf ("%sspeed device\n", (lowspeed == 1) ? "low" : "full");
377         int newdev = set_address (controller, lowspeed);
378         if (newdev == -1)
379                 return -1;
380         usbdev_t *newdev_t = controller->devices[newdev];
381
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);
387         return newdev;
388 }