- reduced memory requirements a lot (from >100kb/controller to
[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 <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                 num = (num > 5) ? 5 : num;
285                 for (i = 0; i < num; i++) {
286                         int j;
287                         printf (" #%x has %x endpoints, interface %x:%x, protocol %x\n", current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
288                         endpoint_descriptor_t *endp =
289                                 (endpoint_descriptor_t *) (((char *) current)
290                                                            +
291                                                            current->bLength);
292                         if (interface->bInterfaceClass == 0x3)
293                                 endp = (endpoint_descriptor_t *) (((char *) endp) + ((char *) endp)[0]);        // ignore HID descriptor
294                         memset (dev->endpoints, 0, sizeof (dev->endpoints));
295                         dev->num_endp = 1;      // 0 always exists
296                         dev->endpoints[0].dev = dev;
297                         dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
298                         dev->endpoints[0].direction = SETUP;
299                         dev->endpoints[0].type = CONTROL;
300                         for (j = 1; j <= current->bNumEndpoints; j++) {
301                                 static const char *transfertypes[4] =
302                                         { "control", "isochronous", "bulk",
303                                         "interrupt"
304                                 };
305                                 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]);
306                                 endpoint_t *ep =
307                                         &dev->endpoints[dev->num_endp++];
308                                 ep->dev = dev;
309                                 ep->endpoint = endp->bEndpointAddress;
310                                 ep->toggle = 0;
311                                 ep->maxpacketsize = endp->wMaxPacketSize;
312                                 ep->direction =
313                                         ((endp->bEndpointAddress & 0x80) ==
314                                          0) ? OUT : IN;
315                                 ep->type = endp->bmAttributes;
316                                 endp = (endpoint_descriptor_t
317                                         *) (((char *) endp) + endp->bLength);
318                         }
319                         current = (interface_descriptor_t *) endp;
320                 }
321         }
322         int class = dd->bDeviceClass;
323         if (class == 0)
324                 class = interface->bInterfaceClass;
325
326         enum { hid_device = 0x3, msc_device = 0x8, hub_device = 0x9 };
327
328         printf ("device of class %x found\n", class);
329         if (class == hub_device) {
330                 printf ("hub found\n");
331 #ifdef CONFIG_USB_HUB
332                 controller->devices[adr]->init = usb_hub_init;
333 #else
334                 printf ("support not compiled in\n");
335 #endif
336         }
337         if (class == hid_device) {
338                 printf ("HID found\n");
339 #ifdef CONFIG_USB_HID
340                 controller->devices[adr]->init = usb_hid_init;
341 #else
342                 printf ("support not compiled in\n");
343 #endif
344         }
345         if (class == msc_device) {
346                 printf ("MSC found\n");
347 #ifdef CONFIG_USB_MSC
348                 controller->devices[adr]->init = usb_msc_init;
349 #else
350                 printf ("support not compiled in\n");
351 #endif
352         }
353         return adr;
354 }
355
356 void
357 usb_detach_device(hci_t *controller, int devno)
358 {
359         controller->devices[devno]->destroy (controller->devices[devno]);
360         free(controller->devices[devno]);
361         controller->devices[devno] = 0;
362 }
363
364 int
365 usb_attach_device(hci_t *controller, int hubaddress, int port, int lowspeed)
366 {
367         printf ("%sspeed device\n", (lowspeed == 1) ? "low" : "full");
368         int newdev = set_address (controller, lowspeed);
369         if (newdev == -1)
370                 return -1;
371         usbdev_t *newdev_t = controller->devices[newdev];
372
373         newdev_t->address = newdev;
374         newdev_t->hub = hubaddress;
375         newdev_t->port = port;
376         // determine responsible driver - current done in set_address
377         newdev_t->init (newdev_t);
378         return newdev;
379 }