blob: 81aa42944132a5ee0e5532e59c095230a72f933d [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
Kevin O'Connor9931bcc2011-06-20 22:23:02 -04008#include "pci.h" // foreachpci
Kevin O'Connor114592f2009-09-28 21:32:08 -04009#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'Connor190cc622010-03-09 19:43:52 -050014#include "usb-ehci.h" // ehci_init
Kevin O'Connor114592f2009-09-28 21:32:08 -040015#include "usb-hid.h" // usb_keyboard_setup
Kevin O'Connor54671c12010-02-15 18:58:12 -050016#include "usb-hub.h" // usb_hub_init
Kevin O'Connor7149fc82010-02-17 23:24:42 -050017#include "usb-msc.h" // usb_msc_init
Kevin O'Connor114592f2009-09-28 21:32:08 -040018#include "usb.h" // struct usb_s
Kevin O'Connor1c46a542009-10-17 23:53:32 -040019#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor114592f2009-09-28 21:32:08 -040020
Kevin O'Connor3c160dd2010-02-17 23:06:52 -050021
22/****************************************************************
23 * Controller function wrappers
24 ****************************************************************/
25
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050026// Free an allocated control or bulk pipe.
27void
28free_pipe(struct usb_pipe *pipe)
29{
30 ASSERT32FLAT();
31 if (!pipe)
32 return;
Kevin O'Connorae0ed622012-03-05 21:48:34 -050033 // Add to controller's free list.
34 struct usb_s *cntl = pipe->cntl;
35 pipe->freenext = cntl->freelist;
36 cntl->freelist = pipe;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050037}
38
Kevin O'Connor01de9bd2012-03-05 22:41:21 -050039// Allocate an async pipe (control or bulk).
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050040static struct usb_pipe *
Kevin O'Connor01de9bd2012-03-05 22:41:21 -050041alloc_async_pipe(struct usb_pipe *dummy)
Kevin O'Connor114592f2009-09-28 21:32:08 -040042{
Kevin O'Connor01de9bd2012-03-05 22:41:21 -050043 // Check for an available pipe on the freelist.
44 struct usb_pipe **pfree = &dummy->cntl->freelist;
45 for (;;) {
46 struct usb_pipe *pipe = *pfree;
47 if (!pipe)
48 break;
49 if (pipe->eptype == dummy->eptype) {
50 // Use previously allocated pipe.
51 *pfree = pipe->freenext;
52 memcpy(pipe, dummy, sizeof(*pipe));
53 return pipe;
54 }
55 pfree = &pipe->freenext;
56 }
57
58 // Allocate a new pipe.
Kevin O'Connor4547eb92010-02-28 02:17:28 -050059 switch (dummy->type) {
Kevin O'Connor59f02832009-10-12 10:09:15 -040060 default:
61 case USB_TYPE_UHCI:
Kevin O'Connor01de9bd2012-03-05 22:41:21 -050062 return uhci_alloc_async_pipe(dummy);
Kevin O'Connor59f02832009-10-12 10:09:15 -040063 case USB_TYPE_OHCI:
Kevin O'Connor01de9bd2012-03-05 22:41:21 -050064 return ohci_alloc_async_pipe(dummy);
Kevin O'Connor190cc622010-03-09 19:43:52 -050065 case USB_TYPE_EHCI:
Kevin O'Connor01de9bd2012-03-05 22:41:21 -050066 return ehci_alloc_async_pipe(dummy);
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050067 }
68}
69
70// Send a message on a control pipe using the default control descriptor.
71static int
72send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize
73 , void *data, int datasize)
74{
75 ASSERT32FLAT();
Kevin O'Connor4547eb92010-02-28 02:17:28 -050076 switch (pipe->type) {
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050077 default:
78 case USB_TYPE_UHCI:
79 return uhci_control(pipe, dir, cmd, cmdsize, data, datasize);
80 case USB_TYPE_OHCI:
81 return ohci_control(pipe, dir, cmd, cmdsize, data, datasize);
Kevin O'Connor190cc622010-03-09 19:43:52 -050082 case USB_TYPE_EHCI:
83 return ehci_control(pipe, dir, cmd, cmdsize, data, datasize);
Kevin O'Connor59f02832009-10-12 10:09:15 -040084 }
Kevin O'Connor114592f2009-09-28 21:32:08 -040085}
86
Kevin O'Connor4547eb92010-02-28 02:17:28 -050087// Fill "pipe" endpoint info from an endpoint descriptor.
88static void
89desc2pipe(struct usb_pipe *newpipe, struct usb_pipe *origpipe
90 , struct usb_endpoint_descriptor *epdesc)
Kevin O'Connor7149fc82010-02-17 23:24:42 -050091{
Kevin O'Connor4547eb92010-02-28 02:17:28 -050092 memcpy(newpipe, origpipe, sizeof(*newpipe));
93 newpipe->ep = epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
94 newpipe->maxpacket = epdesc->wMaxPacketSize;
95}
96
97struct usb_pipe *
98alloc_bulk_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
99{
100 struct usb_pipe dummy;
101 desc2pipe(&dummy, pipe, epdesc);
Kevin O'Connor01de9bd2012-03-05 22:41:21 -0500102 dummy.eptype = USB_ENDPOINT_XFER_BULK;
103 return alloc_async_pipe(&dummy);
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500104}
105
106int
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500107usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize)
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500108{
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500109 switch (GET_FLATPTR(pipe_fl->type)) {
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500110 default:
111 case USB_TYPE_UHCI:
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500112 return uhci_send_bulk(pipe_fl, dir, data, datasize);
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500113 case USB_TYPE_OHCI:
Kevin O'Connor2f968002010-09-19 22:10:08 -0400114 return ohci_send_bulk(pipe_fl, dir, data, datasize);
Kevin O'Connor190cc622010-03-09 19:43:52 -0500115 case USB_TYPE_EHCI:
116 return ehci_send_bulk(pipe_fl, dir, data, datasize);
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500117 }
118}
119
120struct usb_pipe *
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500121alloc_intr_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400122{
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500123 struct usb_pipe dummy;
124 desc2pipe(&dummy, pipe, epdesc);
Kevin O'Connor991eaff2010-02-13 21:51:47 -0500125 // Find the exponential period of the requested time.
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500126 int period = epdesc->bInterval;
Kevin O'Connor190cc622010-03-09 19:43:52 -0500127 int frameexp;
128 if (pipe->speed != USB_HIGHSPEED)
129 frameexp = (period <= 0) ? 0 : __fls(period);
130 else
131 frameexp = (period <= 4) ? 0 : period - 4;
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500132 switch (pipe->type) {
Kevin O'Connor59f02832009-10-12 10:09:15 -0400133 default:
134 case USB_TYPE_UHCI:
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500135 return uhci_alloc_intr_pipe(&dummy, frameexp);
Kevin O'Connor59f02832009-10-12 10:09:15 -0400136 case USB_TYPE_OHCI:
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500137 return ohci_alloc_intr_pipe(&dummy, frameexp);
Kevin O'Connor190cc622010-03-09 19:43:52 -0500138 case USB_TYPE_EHCI:
139 return ehci_alloc_intr_pipe(&dummy, frameexp);
Kevin O'Connor59f02832009-10-12 10:09:15 -0400140 }
Kevin O'Connor114592f2009-09-28 21:32:08 -0400141}
142
Kevin O'Connor84a4d4b2010-02-11 22:32:12 -0500143int noinline
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500144usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400145{
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500146 switch (GET_FLATPTR(pipe_fl->type)) {
Kevin O'Connor59f02832009-10-12 10:09:15 -0400147 default:
148 case USB_TYPE_UHCI:
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500149 return uhci_poll_intr(pipe_fl, data);
Kevin O'Connor59f02832009-10-12 10:09:15 -0400150 case USB_TYPE_OHCI:
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500151 return ohci_poll_intr(pipe_fl, data);
Kevin O'Connor190cc622010-03-09 19:43:52 -0500152 case USB_TYPE_EHCI:
153 return ehci_poll_intr(pipe_fl, data);
Kevin O'Connor59f02832009-10-12 10:09:15 -0400154 }
Kevin O'Connor114592f2009-09-28 21:32:08 -0400155}
156
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500157
158/****************************************************************
159 * Helper functions
160 ****************************************************************/
161
162// Find the first endpoing of a given type in an interface description.
163struct usb_endpoint_descriptor *
164findEndPointDesc(struct usb_interface_descriptor *iface, int imax
165 , int type, int dir)
166{
167 struct usb_endpoint_descriptor *epdesc = (void*)&iface[1];
168 for (;;) {
169 if ((void*)epdesc >= (void*)iface + imax
170 || epdesc->bDescriptorType == USB_DT_INTERFACE) {
171 return NULL;
172 }
173 if (epdesc->bDescriptorType == USB_DT_ENDPOINT
174 && (epdesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir
175 && (epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type)
176 return epdesc;
177 epdesc = (void*)epdesc + epdesc->bLength;
178 }
179}
180
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500181// Send a message to the default control pipe of a device.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400182int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500183send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
184 , void *data)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400185{
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500186 return send_control(pipe, req->bRequestType & USB_DIR_IN
Kevin O'Connor114592f2009-09-28 21:32:08 -0400187 , req, sizeof(*req), data, req->wLength);
188}
189
190// Get the first 8 bytes of the device descriptor.
191static int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500192get_device_info8(struct usb_pipe *pipe, struct usb_device_descriptor *dinfo)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400193{
194 struct usb_ctrlrequest req;
195 req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
196 req.bRequest = USB_REQ_GET_DESCRIPTOR;
197 req.wValue = USB_DT_DEVICE<<8;
198 req.wIndex = 0;
199 req.wLength = 8;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500200 return send_default_control(pipe, &req, dinfo);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400201}
202
203static struct usb_config_descriptor *
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500204get_device_config(struct usb_pipe *pipe)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400205{
206 struct usb_config_descriptor cfg;
207
208 struct usb_ctrlrequest req;
209 req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
210 req.bRequest = USB_REQ_GET_DESCRIPTOR;
211 req.wValue = USB_DT_CONFIG<<8;
212 req.wIndex = 0;
213 req.wLength = sizeof(cfg);
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500214 int ret = send_default_control(pipe, &req, &cfg);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400215 if (ret)
216 return NULL;
217
218 void *config = malloc_tmphigh(cfg.wTotalLength);
219 if (!config)
220 return NULL;
221 req.wLength = cfg.wTotalLength;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500222 ret = send_default_control(pipe, &req, config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400223 if (ret)
224 return NULL;
225 //hexdump(config, cfg.wTotalLength);
226 return config;
227}
228
Kevin O'Connor114592f2009-09-28 21:32:08 -0400229static int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500230set_configuration(struct usb_pipe *pipe, u16 val)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400231{
232 struct usb_ctrlrequest req;
233 req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
234 req.bRequest = USB_REQ_SET_CONFIGURATION;
235 req.wValue = val;
236 req.wIndex = 0;
237 req.wLength = 0;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500238 return send_default_control(pipe, &req, NULL);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400239}
240
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500241
242/****************************************************************
243 * Initialization and enumeration
244 ****************************************************************/
245
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500246// Assign an address to a device in the default state on the given
247// controller.
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500248static int
249usb_set_address(struct usbdevice_s *usbdev)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400250{
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500251 ASSERT32FLAT();
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500252 struct usbhub_s *hub = usbdev->hub;
Kevin O'Connor190cc622010-03-09 19:43:52 -0500253 struct usb_s *cntl = hub->cntl;
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500254 dprintf(3, "set_address %p\n", cntl);
255 if (cntl->maxaddr >= USB_MAXADDR)
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500256 return -1;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400257
Kevin O'Connor92650f22012-03-05 22:03:03 -0500258 // Create a pipe for the default address.
259 struct usb_pipe dummy;
260 memset(&dummy, 0, sizeof(dummy));
261 dummy.cntl = cntl;
262 dummy.type = cntl->type;
263 dummy.maxpacket = 8;
264 dummy.path = (u64)-1;
Kevin O'Connor01de9bd2012-03-05 22:41:21 -0500265 dummy.eptype = USB_ENDPOINT_XFER_CONTROL;
266 struct usb_pipe *defpipe = alloc_async_pipe(&dummy);
Kevin O'Connor92650f22012-03-05 22:03:03 -0500267 if (!defpipe)
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500268 return -1;
269 usbdev->defpipe = defpipe;
270 defpipe->speed = usbdev->speed;
Kevin O'Connor190cc622010-03-09 19:43:52 -0500271 if (hub->pipe) {
272 if (hub->pipe->speed == USB_HIGHSPEED) {
273 defpipe->tt_devaddr = hub->pipe->devaddr;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500274 defpipe->tt_port = usbdev->port;
Kevin O'Connor190cc622010-03-09 19:43:52 -0500275 } else {
276 defpipe->tt_devaddr = hub->pipe->tt_devaddr;
277 defpipe->tt_port = hub->pipe->tt_port;
278 }
279 } else {
280 defpipe->tt_devaddr = defpipe->tt_port = 0;
281 }
Kevin O'Connor92650f22012-03-05 22:03:03 -0500282 if (hub->pipe)
283 defpipe->path = hub->pipe->path;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500284 defpipe->path = (defpipe->path << 8) | usbdev->port;
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500285
286 msleep(USB_TIME_RSTRCY);
287
288 struct usb_ctrlrequest req;
289 req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
290 req.bRequest = USB_REQ_SET_ADDRESS;
291 req.wValue = cntl->maxaddr + 1;
292 req.wIndex = 0;
293 req.wLength = 0;
294 int ret = send_default_control(defpipe, &req, NULL);
Kevin O'Connor92650f22012-03-05 22:03:03 -0500295 if (ret) {
296 free_pipe(defpipe);
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500297 return -1;
Kevin O'Connor92650f22012-03-05 22:03:03 -0500298 }
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500299
300 msleep(USB_TIME_SETADDR_RECOVERY);
301
302 cntl->maxaddr++;
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500303 defpipe->devaddr = cntl->maxaddr;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500304 return 0;
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500305}
306
307// Called for every found device - see if a driver is available for
308// this device and do setup if so.
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400309static int
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500310configure_usb_device(struct usbdevice_s *usbdev)
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500311{
312 ASSERT32FLAT();
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500313 struct usb_pipe *pipe = usbdev->defpipe;
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500314 dprintf(3, "config_usb: %p\n", pipe);
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500315
316 // Set the max packet size for endpoint 0 of this device.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400317 struct usb_device_descriptor dinfo;
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500318 int ret = get_device_info8(pipe, &dinfo);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400319 if (ret)
320 return 0;
321 dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%02x\n"
322 , dinfo.bcdUSB, dinfo.bDeviceClass, dinfo.bDeviceSubClass
323 , dinfo.bDeviceProtocol, dinfo.bMaxPacketSize0);
324 if (dinfo.bMaxPacketSize0 < 8 || dinfo.bMaxPacketSize0 > 64)
325 return 0;
Kevin O'Connor4547eb92010-02-28 02:17:28 -0500326 pipe->maxpacket = dinfo.bMaxPacketSize0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400327
328 // Get configuration
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500329 struct usb_config_descriptor *config = get_device_config(pipe);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400330 if (!config)
331 return 0;
332
333 // Determine if a driver exists for this device - only look at the
334 // first interface of the first configuration.
335 struct usb_interface_descriptor *iface = (void*)(&config[1]);
Kevin O'Connor0e885762010-05-01 22:14:40 -0400336 if (iface->bInterfaceClass != USB_CLASS_HID
337 && iface->bInterfaceClass != USB_CLASS_MASS_STORAGE
338 && iface->bInterfaceClass != USB_CLASS_HUB)
Kevin O'Connor54671c12010-02-15 18:58:12 -0500339 // Not a supported device.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400340 goto fail;
341
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500342 // Set the configuration.
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500343 ret = set_configuration(pipe, config->bConfigurationValue);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400344 if (ret)
345 goto fail;
346
347 // Configure driver.
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500348 int imax = (void*)config + config->wTotalLength - (void*)iface;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500349 if (iface->bInterfaceClass == USB_CLASS_HUB)
350 ret = usb_hub_init(pipe);
351 else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE)
352 ret = usb_msc_init(pipe, iface, imax);
Kevin O'Connor7149fc82010-02-17 23:24:42 -0500353 else
Kevin O'Connor0e885762010-05-01 22:14:40 -0400354 ret = usb_hid_init(pipe, iface, imax);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400355 if (ret)
356 goto fail;
357
Kevin O'Connor1c46a542009-10-17 23:53:32 -0400358 free(config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400359 return 1;
360fail:
Kevin O'Connor1c46a542009-10-17 23:53:32 -0400361 free(config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400362 return 0;
363}
364
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400365static void
366usb_init_hub_port(void *data)
367{
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500368 struct usbdevice_s *usbdev = data;
369 struct usbhub_s *hub = usbdev->hub;
370 u32 port = usbdev->port;
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400371
372 // Detect if device present (and possibly start reset)
373 int ret = hub->op->detect(hub, port);
374 if (ret)
375 // No device present
376 goto done;
377
378 // Reset port and determine device speed
379 mutex_lock(&hub->cntl->resetlock);
380 ret = hub->op->reset(hub, port);
381 if (ret < 0)
382 // Reset failed
383 goto resetfail;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500384 usbdev->speed = ret;
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400385
386 // Set address of port
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500387 ret = usb_set_address(usbdev);
388 if (ret) {
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400389 hub->op->disconnect(hub, port);
390 goto resetfail;
391 }
392 mutex_unlock(&hub->cntl->resetlock);
393
394 // Configure the device
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500395 int count = configure_usb_device(usbdev);
396 free_pipe(usbdev->defpipe);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400397 if (!count)
398 hub->op->disconnect(hub, port);
399 hub->devcount += count;
400done:
401 hub->threads--;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500402 free(usbdev);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400403 return;
404
405resetfail:
406 mutex_unlock(&hub->cntl->resetlock);
407 goto done;
408}
409
410void
411usb_enumerate(struct usbhub_s *hub)
412{
413 u32 portcount = hub->portcount;
414 hub->threads = portcount;
415
416 // Launch a thread for every port.
417 int i;
418 for (i=0; i<portcount; i++) {
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500419 struct usbdevice_s *usbdev = malloc_tmphigh(sizeof(*usbdev));
420 if (!usbdev) {
421 warn_noalloc();
422 continue;
423 }
424 memset(usbdev, 0, sizeof(*usbdev));
425 usbdev->hub = hub;
426 usbdev->port = i;
427 run_thread(usb_init_hub_port, usbdev);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400428 }
429
430 // Wait for threads to complete.
431 while (hub->threads)
432 yield();
433}
434
Kevin O'Connor114592f2009-09-28 21:32:08 -0400435void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500436usb_setup(void)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400437{
Kevin O'Connor59c75742010-02-13 18:49:24 -0500438 ASSERT32FLAT();
Kevin O'Connor114592f2009-09-28 21:32:08 -0400439 if (! CONFIG_USB)
440 return;
441
442 dprintf(3, "init usb\n");
443
Kevin O'Connor114592f2009-09-28 21:32:08 -0400444 // Look for USB controllers
445 int count = 0;
Kevin O'Connor9931bcc2011-06-20 22:23:02 -0400446 struct pci_device *ehcipci = PCIDevices;
447 struct pci_device *pci;
448 foreachpci(pci) {
449 if (pci->class != PCI_CLASS_SERIAL_USB)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400450 continue;
451
Kevin O'Connor9931bcc2011-06-20 22:23:02 -0400452 if (pci->bdf >= ehcipci->bdf) {
Kevin O'Connor190cc622010-03-09 19:43:52 -0500453 // Check to see if this device has an ehci controller
Kevin O'Connor190cc622010-03-09 19:43:52 -0500454 int found = 0;
Kevin O'Connor9931bcc2011-06-20 22:23:02 -0400455 ehcipci = pci;
Kevin O'Connor190cc622010-03-09 19:43:52 -0500456 for (;;) {
Kevin O'Connor9931bcc2011-06-20 22:23:02 -0400457 if (pci_classprog(ehcipci) == PCI_CLASS_SERIAL_USB_EHCI) {
Kevin O'Connor190cc622010-03-09 19:43:52 -0500458 // Found an ehci controller.
Kevin O'Connor8ff8e012011-07-09 14:11:21 -0400459 int ret = ehci_init(ehcipci, count++, pci);
Kevin O'Connor190cc622010-03-09 19:43:52 -0500460 if (ret)
461 // Error
462 break;
463 count += found;
Kevin O'Connor9931bcc2011-06-20 22:23:02 -0400464 pci = ehcipci;
Kevin O'Connor190cc622010-03-09 19:43:52 -0500465 break;
466 }
Kevin O'Connor9931bcc2011-06-20 22:23:02 -0400467 if (ehcipci->class == PCI_CLASS_SERIAL_USB)
Kevin O'Connor190cc622010-03-09 19:43:52 -0500468 found++;
Kevin O'Connor9931bcc2011-06-20 22:23:02 -0400469 ehcipci = ehcipci->next;
470 if (!ehcipci || (pci_bdf_to_busdev(ehcipci->bdf)
471 != pci_bdf_to_busdev(pci->bdf)))
Kevin O'Connor190cc622010-03-09 19:43:52 -0500472 // No ehci controller found.
473 break;
Kevin O'Connor190cc622010-03-09 19:43:52 -0500474 }
475 }
Kevin O'Connor114592f2009-09-28 21:32:08 -0400476
Kevin O'Connor9931bcc2011-06-20 22:23:02 -0400477 if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI)
Kevin O'Connor8ff8e012011-07-09 14:11:21 -0400478 uhci_init(pci, count++);
Kevin O'Connor9931bcc2011-06-20 22:23:02 -0400479 else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI)
Kevin O'Connor8ff8e012011-07-09 14:11:21 -0400480 ohci_init(pci, count++);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400481 }
482}