blob: 3820180cbcc1636ca22464adb29043e2709be98f [file] [log] [blame]
Patrick Georgid21f68b2008-09-02 16:06:22 +00001/*
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
Jordan Crousedb8c0ab2008-11-24 17:54:46 +000030#include <libpayload-config.h>
Jordan Crouse29061a52008-09-11 17:29:00 +000031#include <usb/usb.h>
Patrick Georgid21f68b2008-09-02 16:06:22 +000032
33hci_t *usb_hcs = 0;
34
35hci_t *
36new_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
48void
49detach_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 */
69void
70usb_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++) {
Patrick Georgi4727c072008-10-16 19:20:51 +000078 if (controller->devices[i] != 0) {
79 controller->devices[i]->poll (controller->
Patrick Georgid21f68b2008-09-02 16:06:22 +000080 devices[i]);
81 }
82 }
83 controller = controller->next;
84 }
85}
86
87void
88init_device_entry (hci_t *controller, int i)
89{
Patrick Georgi4727c072008-10-16 19:20:51 +000090 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]);
Patrick Georgid21f68b2008-09-02 16:06:22 +000099}
100
101void
102set_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
115void
116get_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
129u8 *
130get_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
176void
177set_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
189int
190clear_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 */
209static int
210get_free_address (hci_t *controller)
211{
212 int i;
213 for (i = 1; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +0000214 if (controller->devices[i] == 0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000215 return i;
216 }
217 printf ("no free address found\n");
218 return -1; // no free address
219}
220
221int
222set_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
Patrick Georgi4727c072008-10-16 19:20:51 +0000238 init_device_entry(controller, adr);
239 usbdev_t *dev = controller->devices[adr];
Patrick Georgid21f68b2008-09-02 16:06:22 +0000240 // 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
Patrick Georgi4727c072008-10-16 19:20:51 +0000332 controller->devices[adr]->init = usb_hub_init;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000333#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
Patrick Georgi4727c072008-10-16 19:20:51 +0000340 controller->devices[adr]->init = usb_hid_init;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000341#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
Patrick Georgi4727c072008-10-16 19:20:51 +0000348 controller->devices[adr]->init = usb_msc_init;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000349#else
350 printf ("support not compiled in\n");
351#endif
352 }
353 return adr;
354}
Patrick Georgi4727c072008-10-16 19:20:51 +0000355
356void
357usb_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
364int
365usb_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}