blob: 5b3649c3da4d5e5c90de50b6229949d89ce75f8e [file] [log] [blame]
Kevin O'Connor114592f2009-09-28 21:32:08 -04001// Main code for handling USB controllers and devices.
2//
3// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
4//
5// This file may be distributed under the terms of the GNU LGPLv3 license.
6
7#include "util.h" // dprintf
8#include "pci.h" // foreachpci
9#include "config.h" // CONFIG_*
10#include "pci_regs.h" // PCI_CLASS_REVISION
11#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
12#include "usb-uhci.h" // uhci_init
Kevin O'Connor59f02832009-10-12 10:09:15 -040013#include "usb-ohci.h" // ohci_init
Kevin O'Connor114592f2009-09-28 21:32:08 -040014#include "usb-hid.h" // usb_keyboard_setup
Kevin O'Connor54671c12010-02-15 18:58:12 -050015#include "usb-hub.h" // usb_hub_init
Kevin O'Connor7149fc82010-02-17 23:24:42 -050016#include "usb-msc.h" // usb_msc_init
Kevin O'Connor114592f2009-09-28 21:32:08 -040017#include "usb.h" // struct usb_s
Kevin O'Connor1c46a542009-10-17 23:53:32 -040018#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor114592f2009-09-28 21:32:08 -040019
20struct usb_s USBControllers[16] VAR16VISIBLE;
21
Kevin O'Connor3c160dd2010-02-17 23:06:52 -050022
23/****************************************************************
24 * Controller function wrappers
25 ****************************************************************/
26
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050027// Free an allocated control or bulk pipe.
28void
29free_pipe(struct usb_pipe *pipe)
30{
31 ASSERT32FLAT();
32 if (!pipe)
33 return;
34 struct usb_s *cntl = endp2cntl(pipe->endp);
35 switch (cntl->type) {
36 default:
37 case USB_TYPE_UHCI:
38 return uhci_free_pipe(pipe);
39 case USB_TYPE_OHCI:
40 return ohci_free_pipe(pipe);
41 }
42}
43
44// Allocate a control pipe (which can only be used by 32bit code)
45static struct usb_pipe *
46alloc_control_pipe(u32 endp)
Kevin O'Connor114592f2009-09-28 21:32:08 -040047{
Kevin O'Connor59f02832009-10-12 10:09:15 -040048 struct usb_s *cntl = endp2cntl(endp);
49 switch (cntl->type) {
50 default:
51 case USB_TYPE_UHCI:
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050052 return uhci_alloc_control_pipe(endp);
Kevin O'Connor59f02832009-10-12 10:09:15 -040053 case USB_TYPE_OHCI:
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050054 return ohci_alloc_control_pipe(endp);
55 }
56}
57
58// Send a message on a control pipe using the default control descriptor.
59static int
60send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize
61 , void *data, int datasize)
62{
63 ASSERT32FLAT();
64 struct usb_s *cntl = endp2cntl(pipe->endp);
65 switch (cntl->type) {
66 default:
67 case USB_TYPE_UHCI:
68 return uhci_control(pipe, dir, cmd, cmdsize, data, datasize);
69 case USB_TYPE_OHCI:
70 return ohci_control(pipe, dir, cmd, cmdsize, data, datasize);
Kevin O'Connor59f02832009-10-12 10:09:15 -040071 }
Kevin O'Connor114592f2009-09-28 21:32:08 -040072}
73
Kevin O'Connor59f02832009-10-12 10:09:15 -040074struct usb_pipe *
Kevin O'Connor7149fc82010-02-17 23:24:42 -050075alloc_bulk_pipe(u32 endp)
76{
77 struct usb_s *cntl = endp2cntl(endp);
78 switch (cntl->type) {
79 default:
80 case USB_TYPE_UHCI:
81 return uhci_alloc_bulk_pipe(endp);
82 case USB_TYPE_OHCI:
83 return NULL;
84 }
85}
86
87int
88usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize)
89{
90 u32 endp = GET_FLATPTR(pipe->endp);
91 struct usb_s *cntl = endp2cntl(endp);
92 switch (cntl->type) {
93 default:
94 case USB_TYPE_UHCI:
95 return uhci_send_bulk(pipe, dir, data, datasize);
96 case USB_TYPE_OHCI:
97 return -1;
98 }
99}
100
101struct usb_pipe *
Kevin O'Connor114592f2009-09-28 21:32:08 -0400102alloc_intr_pipe(u32 endp, int period)
103{
Kevin O'Connor59f02832009-10-12 10:09:15 -0400104 struct usb_s *cntl = endp2cntl(endp);
Kevin O'Connor991eaff2010-02-13 21:51:47 -0500105 // Find the exponential period of the requested time.
106 if (period <= 0)
107 period = 1;
108 int frameexp = __fls(period);
Kevin O'Connor59f02832009-10-12 10:09:15 -0400109 switch (cntl->type) {
110 default:
111 case USB_TYPE_UHCI:
Kevin O'Connor991eaff2010-02-13 21:51:47 -0500112 return uhci_alloc_intr_pipe(endp, frameexp);
Kevin O'Connor59f02832009-10-12 10:09:15 -0400113 case USB_TYPE_OHCI:
Kevin O'Connor991eaff2010-02-13 21:51:47 -0500114 return ohci_alloc_intr_pipe(endp, frameexp);
Kevin O'Connor59f02832009-10-12 10:09:15 -0400115 }
Kevin O'Connor114592f2009-09-28 21:32:08 -0400116}
117
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500118int noinline
Kevin O'Connor59f02832009-10-12 10:09:15 -0400119usb_poll_intr(struct usb_pipe *pipe, void *data)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400120{
Kevin O'Connor1c46a542009-10-17 23:53:32 -0400121 u32 endp = GET_FLATPTR(pipe->endp);
122 struct usb_s *cntl = endp2cntl(endp);
123 switch (GET_GLOBAL(cntl->type)) {
Kevin O'Connor59f02832009-10-12 10:09:15 -0400124 default:
125 case USB_TYPE_UHCI:
126 return uhci_poll_intr(pipe, data);
127 case USB_TYPE_OHCI:
128 return ohci_poll_intr(pipe, data);
129 }
Kevin O'Connor114592f2009-09-28 21:32:08 -0400130}
131
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500132
133/****************************************************************
134 * Helper functions
135 ****************************************************************/
136
137// Find the first endpoing of a given type in an interface description.
138struct usb_endpoint_descriptor *
139findEndPointDesc(struct usb_interface_descriptor *iface, int imax
140 , int type, int dir)
141{
142 struct usb_endpoint_descriptor *epdesc = (void*)&iface[1];
143 for (;;) {
144 if ((void*)epdesc >= (void*)iface + imax
145 || epdesc->bDescriptorType == USB_DT_INTERFACE) {
146 return NULL;
147 }
148 if (epdesc->bDescriptorType == USB_DT_ENDPOINT
149 && (epdesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir
150 && (epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type)
151 return epdesc;
152 epdesc = (void*)epdesc + epdesc->bLength;
153 }
154}
155
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500156// Change endpoint characteristics of the default control pipe.
157static void
158usb_alter_control(struct usb_pipe *pipe, u32 endp)
159{
160 pipe->endp = endp;
161}
162
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500163// Build an encoded "endp" from an endpoint descriptor.
164u32
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500165mkendpFromDesc(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500166{
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500167 u32 endp = pipe->endp;
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500168 return mkendp(endp2cntl(endp), endp2devaddr(endp)
169 , epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK
170 , endp2speed(endp), epdesc->wMaxPacketSize);
171}
172
173// Send a message to the default control pipe of a device.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400174int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500175send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
176 , void *data)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400177{
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500178 return send_control(pipe, req->bRequestType & USB_DIR_IN
Kevin O'Connor114592f2009-09-28 21:32:08 -0400179 , req, sizeof(*req), data, req->wLength);
180}
181
182// Get the first 8 bytes of the device descriptor.
183static int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500184get_device_info8(struct usb_pipe *pipe, struct usb_device_descriptor *dinfo)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400185{
186 struct usb_ctrlrequest req;
187 req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
188 req.bRequest = USB_REQ_GET_DESCRIPTOR;
189 req.wValue = USB_DT_DEVICE<<8;
190 req.wIndex = 0;
191 req.wLength = 8;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500192 return send_default_control(pipe, &req, dinfo);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400193}
194
195static struct usb_config_descriptor *
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500196get_device_config(struct usb_pipe *pipe)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400197{
198 struct usb_config_descriptor cfg;
199
200 struct usb_ctrlrequest req;
201 req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
202 req.bRequest = USB_REQ_GET_DESCRIPTOR;
203 req.wValue = USB_DT_CONFIG<<8;
204 req.wIndex = 0;
205 req.wLength = sizeof(cfg);
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500206 int ret = send_default_control(pipe, &req, &cfg);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400207 if (ret)
208 return NULL;
209
210 void *config = malloc_tmphigh(cfg.wTotalLength);
211 if (!config)
212 return NULL;
213 req.wLength = cfg.wTotalLength;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500214 ret = send_default_control(pipe, &req, config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400215 if (ret)
216 return NULL;
217 //hexdump(config, cfg.wTotalLength);
218 return config;
219}
220
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500221static struct usb_pipe *
222set_address(struct usb_pipe *pipe)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400223{
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500224 ASSERT32FLAT();
225 dprintf(3, "set_address %x\n", pipe->endp);
226 struct usb_s *cntl = endp2cntl(pipe->endp);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400227 if (cntl->maxaddr >= USB_MAXADDR)
228 return 0;
229
230 struct usb_ctrlrequest req;
231 req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
232 req.bRequest = USB_REQ_SET_ADDRESS;
233 req.wValue = cntl->maxaddr + 1;
234 req.wIndex = 0;
235 req.wLength = 0;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500236 int ret = send_default_control(pipe, &req, NULL);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400237 if (ret)
238 return 0;
Kevin O'Connor8bbc79c2010-02-14 12:16:32 -0500239 msleep(USB_TIME_SETADDR_RECOVERY);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400240
241 cntl->maxaddr++;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500242 u32 endp = mkendp(cntl, cntl->maxaddr, 0
243 , endp2speed(pipe->endp), endp2maxsize(pipe->endp));
244 return alloc_control_pipe(endp);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400245}
246
247static int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500248set_configuration(struct usb_pipe *pipe, u16 val)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400249{
250 struct usb_ctrlrequest req;
251 req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
252 req.bRequest = USB_REQ_SET_CONFIGURATION;
253 req.wValue = val;
254 req.wIndex = 0;
255 req.wLength = 0;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500256 return send_default_control(pipe, &req, NULL);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400257}
258
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500259
260/****************************************************************
261 * Initialization and enumeration
262 ****************************************************************/
263
Kevin O'Connor114592f2009-09-28 21:32:08 -0400264// Called for every found device - see if a driver is available for
265// this device and do setup if so.
266int
267configure_usb_device(struct usb_s *cntl, int lowspeed)
268{
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500269 ASSERT32FLAT();
Kevin O'Connor78523312010-02-14 19:07:43 -0500270 dprintf(3, "config_usb: %p %d\n", cntl, lowspeed);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400271
272 // Get device info
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500273 struct usb_pipe *defpipe = cntl->defaultpipe;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400274 u32 endp = mkendp(cntl, 0, 0, lowspeed, 8);
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500275 if (!defpipe) {
276 cntl->defaultpipe = defpipe = alloc_control_pipe(endp);
277 if (!defpipe)
278 return 0;
279 }
280 usb_alter_control(defpipe, endp);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400281 struct usb_device_descriptor dinfo;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500282 int ret = get_device_info8(defpipe, &dinfo);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400283 if (ret)
284 return 0;
285 dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%02x\n"
286 , dinfo.bcdUSB, dinfo.bDeviceClass, dinfo.bDeviceSubClass
287 , dinfo.bDeviceProtocol, dinfo.bMaxPacketSize0);
288 if (dinfo.bMaxPacketSize0 < 8 || dinfo.bMaxPacketSize0 > 64)
289 return 0;
290 endp = mkendp(cntl, 0, 0, lowspeed, dinfo.bMaxPacketSize0);
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500291 usb_alter_control(defpipe, endp);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400292
293 // Get configuration
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500294 struct usb_pipe *pipe = NULL;
295 struct usb_config_descriptor *config = get_device_config(defpipe);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400296 if (!config)
297 return 0;
298
299 // Determine if a driver exists for this device - only look at the
300 // first interface of the first configuration.
301 struct usb_interface_descriptor *iface = (void*)(&config[1]);
Kevin O'Connor54671c12010-02-15 18:58:12 -0500302 if ((iface->bInterfaceClass != USB_CLASS_HID
303 || iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT
304 || iface->bInterfaceProtocol != USB_INTERFACE_PROTOCOL_KEYBOARD)
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500305 && (iface->bInterfaceClass != USB_CLASS_MASS_STORAGE)
Kevin O'Connor54671c12010-02-15 18:58:12 -0500306 && (iface->bInterfaceClass != USB_CLASS_HUB))
307 // Not a supported device.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400308 goto fail;
309
310 // Set the address and configure device.
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500311 pipe = set_address(defpipe);
312 if (!pipe)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400313 goto fail;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500314 ret = set_configuration(pipe, config->bConfigurationValue);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400315 if (ret)
316 goto fail;
317
318 // Configure driver.
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500319 int imax = (void*)config + config->wTotalLength - (void*)iface;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500320 if (iface->bInterfaceClass == USB_CLASS_HUB)
321 ret = usb_hub_init(pipe);
322 else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE)
323 ret = usb_msc_init(pipe, iface, imax);
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500324 else
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500325 ret = usb_keyboard_init(pipe, iface, imax);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400326 if (ret)
327 goto fail;
328
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500329 free_pipe(pipe);
Kevin O'Connor1c46a542009-10-17 23:53:32 -0400330 free(config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400331 return 1;
332fail:
Kevin O'Connor1c46a542009-10-17 23:53:32 -0400333 free(config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400334 return 0;
335}
336
337void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500338usb_setup(void)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400339{
Kevin O'Connor59c75742010-02-13 18:49:24 -0500340 ASSERT32FLAT();
Kevin O'Connor114592f2009-09-28 21:32:08 -0400341 if (! CONFIG_USB)
342 return;
343
344 dprintf(3, "init usb\n");
345
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500346 memset(&USBControllers, 0, sizeof(USBControllers));
Kevin O'Connor114592f2009-09-28 21:32:08 -0400347 usb_keyboard_setup();
348
349 // Look for USB controllers
350 int count = 0;
351 int bdf, max;
352 foreachpci(bdf, max) {
353 u32 code = pci_config_readl(bdf, PCI_CLASS_REVISION) >> 8;
354
355 if (code >> 8 != PCI_CLASS_SERIAL_USB)
356 continue;
357
358 struct usb_s *cntl = &USBControllers[count];
359 cntl->bdf = bdf;
360
Kevin O'Connor114592f2009-09-28 21:32:08 -0400361 if (code == PCI_CLASS_SERIAL_USB_UHCI)
Kevin O'Connora5826b52009-10-24 17:57:29 -0400362 run_thread(uhci_init, cntl);
Kevin O'Connor59f02832009-10-12 10:09:15 -0400363 else if (code == PCI_CLASS_SERIAL_USB_OHCI)
Kevin O'Connora5826b52009-10-24 17:57:29 -0400364 run_thread(ohci_init, cntl);
365 else
366 continue;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400367
Kevin O'Connora5826b52009-10-24 17:57:29 -0400368 count++;
369 if (count >= ARRAY_SIZE(USBControllers))
370 break;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400371 }
372}