blob: 4f9a852cbc7d4da1f18fb37ceb067c66ae7192d9 [file] [log] [blame]
Kevin O'Connor114592f2009-09-28 21:32:08 -04001// Main code for handling USB controllers and devices.
2//
Kevin O'Connorec443ff2013-12-05 18:43:20 -05003// Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net>
Kevin O'Connor114592f2009-09-28 21:32:08 -04004//
5// This file may be distributed under the terms of the GNU LGPLv3 license.
6
Kevin O'Connor2d2fa312013-09-14 21:55:26 -04007#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor114592f2009-09-28 21:32:08 -04008#include "config.h" // CONFIG_*
Kevin O'Connor2d2fa312013-09-14 21:55:26 -04009#include "malloc.h" // free
10#include "output.h" // dprintf
Kevin O'Connor45b594a2015-11-09 12:00:52 -050011#include "romfile.h" // romfile_loadint
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040012#include "string.h" // memset
13#include "usb.h" // struct usb_s
Kevin O'Connord83c87b2013-01-21 01:14:12 -050014#include "usb-ehci.h" // ehci_setup
Gerd Hoffmanne144bb72013-06-03 16:30:18 +020015#include "usb-xhci.h" // xhci_setup
Kevin O'Connor114592f2009-09-28 21:32:08 -040016#include "usb-hid.h" // usb_keyboard_setup
Kevin O'Connord83c87b2013-01-21 01:14:12 -050017#include "usb-hub.h" // usb_hub_setup
18#include "usb-msc.h" // usb_msc_setup
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040019#include "usb-ohci.h" // ohci_setup
Kevin O'Connord83c87b2013-01-21 01:14:12 -050020#include "usb-uas.h" // usb_uas_setup
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040021#include "usb-uhci.h" // uhci_setup
22#include "util.h" // msleep
Kevin O'Connorb9c6a962013-09-14 13:01:30 -040023#include "x86.h" // __fls
Kevin O'Connor114592f2009-09-28 21:32:08 -040024
Kevin O'Connor3c160dd2010-02-17 23:06:52 -050025
26/****************************************************************
27 * Controller function wrappers
28 ****************************************************************/
29
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -040030// Allocate, update, or free a usb pipe.
31static struct usb_pipe *
32usb_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *pipe
33 , struct usb_endpoint_descriptor *epdesc)
Kevin O'Connor54bf2072012-03-09 07:52:33 -050034{
35 switch (usbdev->hub->cntl->type) {
Kevin O'Connor59f02832009-10-12 10:09:15 -040036 default:
37 case USB_TYPE_UHCI:
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -040038 return uhci_realloc_pipe(usbdev, pipe, epdesc);
Kevin O'Connor59f02832009-10-12 10:09:15 -040039 case USB_TYPE_OHCI:
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -040040 return ohci_realloc_pipe(usbdev, pipe, epdesc);
Kevin O'Connor190cc622010-03-09 19:43:52 -050041 case USB_TYPE_EHCI:
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -040042 return ehci_realloc_pipe(usbdev, pipe, epdesc);
Gerd Hoffmanne144bb72013-06-03 16:30:18 +020043 case USB_TYPE_XHCI:
Kevin O'Connorc427def2014-10-16 13:23:08 -040044 return xhci_realloc_pipe(usbdev, pipe, epdesc);
Gerd Hoffmann63cbab12013-08-21 13:59:21 +020045 }
46}
47
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050048// Send a message on a control pipe using the default control descriptor.
49static int
Kevin O'Connor2891a832014-12-31 17:41:14 -050050usb_send_pipe(struct usb_pipe *pipe_fl, int dir, const void *cmd
Kevin O'Connorda64e862014-12-31 02:11:36 -050051 , void *data, int datasize)
Kevin O'Connor7149fc82010-02-17 23:24:42 -050052{
Kevin O'Connor1e3bd4f2012-05-24 23:56:19 -040053 switch (GET_LOWFLAT(pipe_fl->type)) {
Kevin O'Connor7149fc82010-02-17 23:24:42 -050054 default:
55 case USB_TYPE_UHCI:
Kevin O'Connor2891a832014-12-31 17:41:14 -050056 return uhci_send_pipe(pipe_fl, dir, cmd, data, datasize);
Kevin O'Connor7149fc82010-02-17 23:24:42 -050057 case USB_TYPE_OHCI:
Kevin O'Connor746d0a72014-12-29 13:06:23 -050058 if (MODESEGMENT)
59 return -1;
Kevin O'Connor2891a832014-12-31 17:41:14 -050060 return ohci_send_pipe(pipe_fl, dir, cmd, data, datasize);
Kevin O'Connor190cc622010-03-09 19:43:52 -050061 case USB_TYPE_EHCI:
Kevin O'Connor2891a832014-12-31 17:41:14 -050062 return ehci_send_pipe(pipe_fl, dir, cmd, data, datasize);
Gerd Hoffmanne144bb72013-06-03 16:30:18 +020063 case USB_TYPE_XHCI:
Kevin O'Connorde30dad2013-12-30 22:09:04 -050064 if (MODESEGMENT)
65 return -1;
Kevin O'Connor2891a832014-12-31 17:41:14 -050066 return xhci_send_pipe(pipe_fl, dir, cmd, data, datasize);
Kevin O'Connor7149fc82010-02-17 23:24:42 -050067 }
68}
69
Kevin O'Connorac7eb5e2012-05-28 14:42:16 -040070int
Kevin O'Connor4547eb92010-02-28 02:17:28 -050071usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
Kevin O'Connor114592f2009-09-28 21:32:08 -040072{
Kevin O'Connorde30dad2013-12-30 22:09:04 -050073 ASSERT16();
Kevin O'Connor1e3bd4f2012-05-24 23:56:19 -040074 switch (GET_LOWFLAT(pipe_fl->type)) {
Kevin O'Connor59f02832009-10-12 10:09:15 -040075 default:
76 case USB_TYPE_UHCI:
Kevin O'Connor4547eb92010-02-28 02:17:28 -050077 return uhci_poll_intr(pipe_fl, data);
Kevin O'Connor59f02832009-10-12 10:09:15 -040078 case USB_TYPE_OHCI:
Kevin O'Connor4547eb92010-02-28 02:17:28 -050079 return ohci_poll_intr(pipe_fl, data);
Kevin O'Connor190cc622010-03-09 19:43:52 -050080 case USB_TYPE_EHCI:
81 return ehci_poll_intr(pipe_fl, data);
Kevin O'Connorde30dad2013-12-30 22:09:04 -050082 case USB_TYPE_XHCI: ;
Kevin O'Connorb4cca862015-10-09 11:53:02 -040083 return call32_params(xhci_poll_intr, pipe_fl
84 , MAKE_FLATPTR(GET_SEG(SS), data), 0, -1);
Kevin O'Connor59f02832009-10-12 10:09:15 -040085 }
Kevin O'Connor114592f2009-09-28 21:32:08 -040086}
87
Kevin O'Connorde30dad2013-12-30 22:09:04 -050088int usb_32bit_pipe(struct usb_pipe *pipe_fl)
89{
Kevin O'Connor746d0a72014-12-29 13:06:23 -050090 return (CONFIG_USB_XHCI && GET_LOWFLAT(pipe_fl->type) == USB_TYPE_XHCI)
91 || (CONFIG_USB_OHCI && GET_LOWFLAT(pipe_fl->type) == USB_TYPE_OHCI);
Kevin O'Connorde30dad2013-12-30 22:09:04 -050092}
Kevin O'Connor3c160dd2010-02-17 23:06:52 -050093
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -040094
Kevin O'Connor3c160dd2010-02-17 23:06:52 -050095/****************************************************************
96 * Helper functions
97 ****************************************************************/
98
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -040099// Allocate a usb pipe.
100struct usb_pipe *
101usb_alloc_pipe(struct usbdevice_s *usbdev
102 , struct usb_endpoint_descriptor *epdesc)
103{
104 return usb_realloc_pipe(usbdev, NULL, epdesc);
105}
106
107// Free an allocated control or bulk pipe.
108void
109usb_free_pipe(struct usbdevice_s *usbdev, struct usb_pipe *pipe)
110{
111 if (!pipe)
112 return;
113 usb_realloc_pipe(usbdev, pipe, NULL);
114}
115
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500116// Send a message to the default control pipe of a device.
117int
Kevin O'Connor222bad42014-10-16 12:11:12 -0400118usb_send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
119 , void *data)
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500120{
Kevin O'Connor2891a832014-12-31 17:41:14 -0500121 return usb_send_pipe(pipe, req->bRequestType & USB_DIR_IN, req
122 , data, req->wLength);
Kevin O'Connorda64e862014-12-31 02:11:36 -0500123}
124
125// Send a message to a bulk endpoint
126int
127usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize)
128{
Kevin O'Connor2891a832014-12-31 17:41:14 -0500129 return usb_send_pipe(pipe_fl, dir, NULL, data, datasize);
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500130}
131
Kevin O'Connor2bfd1702014-10-16 12:31:42 -0400132// Check if a pipe for a given controller is on the freelist
133int
134usb_is_freelist(struct usb_s *cntl, struct usb_pipe *pipe)
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500135{
Kevin O'Connor2bfd1702014-10-16 12:31:42 -0400136 return pipe->cntl != cntl;
137}
138
139// Add a pipe to the controller's freelist
140void
141usb_add_freelist(struct usb_pipe *pipe)
142{
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500143 if (!pipe)
144 return;
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500145 struct usb_s *cntl = pipe->cntl;
146 pipe->freenext = cntl->freelist;
147 cntl->freelist = pipe;
148}
149
150// Check for an available pipe on the freelist.
151struct usb_pipe *
Kevin O'Connor2bfd1702014-10-16 12:31:42 -0400152usb_get_freelist(struct usb_s *cntl, u8 eptype)
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500153{
154 struct usb_pipe **pfree = &cntl->freelist;
155 for (;;) {
156 struct usb_pipe *pipe = *pfree;
157 if (!pipe)
158 return NULL;
159 if (pipe->eptype == eptype) {
160 *pfree = pipe->freenext;
161 return pipe;
162 }
163 pfree = &pipe->freenext;
164 }
165}
166
167// Fill "pipe" endpoint info from an endpoint descriptor.
168void
169usb_desc2pipe(struct usb_pipe *pipe, struct usbdevice_s *usbdev
170 , struct usb_endpoint_descriptor *epdesc)
171{
172 pipe->cntl = usbdev->hub->cntl;
173 pipe->type = usbdev->hub->cntl->type;
174 pipe->ep = epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
175 pipe->devaddr = usbdev->devaddr;
176 pipe->speed = usbdev->speed;
177 pipe->maxpacket = epdesc->wMaxPacketSize;
178 pipe->eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500179}
180
181// Find the exponential period of the requested interrupt end point.
182int
Kevin O'Connor98cdad32014-10-16 12:05:09 -0400183usb_get_period(struct usbdevice_s *usbdev
184 , struct usb_endpoint_descriptor *epdesc)
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500185{
186 int period = epdesc->bInterval;
187 if (usbdev->speed != USB_HIGHSPEED)
188 return (period <= 0) ? 0 : __fls(period);
189 return (period <= 4) ? 0 : period - 4;
190}
191
Kevin O'Connor88fa2272014-06-14 12:25:17 -0400192// Maximum time (in ms) a data transfer should take
193int
194usb_xfer_time(struct usb_pipe *pipe, int datalen)
195{
196 // Use the maximum command time (5 seconds), except for
197 // set_address commands where we don't want to stall the boot if
198 // the device doesn't actually exist. Add 100ms to account for
199 // any controller delays.
Kevin O'Connor0806e9e2014-09-09 18:24:00 -0400200 if (!GET_LOWFLAT(pipe->devaddr))
Kevin O'Connor88fa2272014-06-14 12:25:17 -0400201 return USB_TIME_STATUS + 100;
202 return USB_TIME_COMMAND + 100;
203}
204
Kevin O'Connor674f1402014-10-16 12:08:00 -0400205// Find the first endpoint of a given type in an interface description.
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500206struct usb_endpoint_descriptor *
Kevin O'Connor674f1402014-10-16 12:08:00 -0400207usb_find_desc(struct usbdevice_s *usbdev, int type, int dir)
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500208{
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500209 struct usb_endpoint_descriptor *epdesc = (void*)&usbdev->iface[1];
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500210 for (;;) {
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500211 if ((void*)epdesc >= (void*)usbdev->iface + usbdev->imax
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500212 || epdesc->bDescriptorType == USB_DT_INTERFACE) {
213 return NULL;
214 }
215 if (epdesc->bDescriptorType == USB_DT_ENDPOINT
216 && (epdesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir
217 && (epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type)
218 return epdesc;
219 epdesc = (void*)epdesc + epdesc->bLength;
220 }
221}
222
Kevin O'Connor114592f2009-09-28 21:32:08 -0400223// Get the first 8 bytes of the device descriptor.
224static int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500225get_device_info8(struct usb_pipe *pipe, struct usb_device_descriptor *dinfo)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400226{
227 struct usb_ctrlrequest req;
228 req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
229 req.bRequest = USB_REQ_GET_DESCRIPTOR;
230 req.wValue = USB_DT_DEVICE<<8;
231 req.wIndex = 0;
232 req.wLength = 8;
Kevin O'Connor222bad42014-10-16 12:11:12 -0400233 return usb_send_default_control(pipe, &req, dinfo);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400234}
235
236static struct usb_config_descriptor *
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500237get_device_config(struct usb_pipe *pipe)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400238{
239 struct usb_config_descriptor cfg;
240
241 struct usb_ctrlrequest req;
242 req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
243 req.bRequest = USB_REQ_GET_DESCRIPTOR;
244 req.wValue = USB_DT_CONFIG<<8;
245 req.wIndex = 0;
246 req.wLength = sizeof(cfg);
Kevin O'Connor222bad42014-10-16 12:11:12 -0400247 int ret = usb_send_default_control(pipe, &req, &cfg);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400248 if (ret)
249 return NULL;
250
251 void *config = malloc_tmphigh(cfg.wTotalLength);
Kevin O'Connor3abdc7c2015-06-30 11:10:41 -0400252 if (!config) {
253 warn_noalloc();
Kevin O'Connor114592f2009-09-28 21:32:08 -0400254 return NULL;
Kevin O'Connor3abdc7c2015-06-30 11:10:41 -0400255 }
Kevin O'Connor114592f2009-09-28 21:32:08 -0400256 req.wLength = cfg.wTotalLength;
Kevin O'Connor222bad42014-10-16 12:11:12 -0400257 ret = usb_send_default_control(pipe, &req, config);
Kevin O'Connor301dd092015-01-01 13:47:28 -0500258 if (ret) {
259 free(config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400260 return NULL;
Kevin O'Connor301dd092015-01-01 13:47:28 -0500261 }
Kevin O'Connor114592f2009-09-28 21:32:08 -0400262 //hexdump(config, cfg.wTotalLength);
263 return config;
264}
265
Kevin O'Connor114592f2009-09-28 21:32:08 -0400266static int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500267set_configuration(struct usb_pipe *pipe, u16 val)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400268{
269 struct usb_ctrlrequest req;
270 req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
271 req.bRequest = USB_REQ_SET_CONFIGURATION;
272 req.wValue = val;
273 req.wIndex = 0;
274 req.wLength = 0;
Kevin O'Connor222bad42014-10-16 12:11:12 -0400275 return usb_send_default_control(pipe, &req, NULL);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400276}
277
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500278
279/****************************************************************
280 * Initialization and enumeration
281 ****************************************************************/
282
Kevin O'Connor3de73822014-01-26 17:28:04 -0500283static const int speed_to_ctlsize[] = {
284 [ USB_FULLSPEED ] = 8,
285 [ USB_LOWSPEED ] = 8,
286 [ USB_HIGHSPEED ] = 64,
287 [ USB_SUPERSPEED ] = 512,
288};
289
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500290// Assign an address to a device in the default state on the given
291// controller.
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500292static int
293usb_set_address(struct usbdevice_s *usbdev)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400294{
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500295 ASSERT32FLAT();
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500296 struct usb_s *cntl = usbdev->hub->cntl;
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500297 dprintf(3, "set_address %p\n", cntl);
298 if (cntl->maxaddr >= USB_MAXADDR)
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500299 return -1;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400300
Kevin O'Connor4ea2fa92013-12-27 19:25:46 -0500301 msleep(USB_TIME_RSTRCY);
302
Kevin O'Connor92650f22012-03-05 22:03:03 -0500303 // Create a pipe for the default address.
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500304 struct usb_endpoint_descriptor epdesc = {
Kevin O'Connor3de73822014-01-26 17:28:04 -0500305 .wMaxPacketSize = speed_to_ctlsize[usbdev->speed],
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500306 .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
307 };
Kevin O'Connorc3d96c22012-03-10 09:03:25 -0500308 usbdev->defpipe = usb_alloc_pipe(usbdev, &epdesc);
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500309 if (!usbdev->defpipe)
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500310 return -1;
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500311
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500312 // Send set_address command.
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500313 struct usb_ctrlrequest req;
314 req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
315 req.bRequest = USB_REQ_SET_ADDRESS;
316 req.wValue = cntl->maxaddr + 1;
317 req.wIndex = 0;
318 req.wLength = 0;
Kevin O'Connor222bad42014-10-16 12:11:12 -0400319 int ret = usb_send_default_control(usbdev->defpipe, &req, NULL);
Gerd Hoffmann63cbab12013-08-21 13:59:21 +0200320 if (ret) {
Kevin O'Connorf3329432014-10-16 11:59:45 -0400321 usb_free_pipe(usbdev, usbdev->defpipe);
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500322 return -1;
Gerd Hoffmann63cbab12013-08-21 13:59:21 +0200323 }
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500324
325 msleep(USB_TIME_SETADDR_RECOVERY);
326
327 cntl->maxaddr++;
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500328 usbdev->devaddr = cntl->maxaddr;
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -0400329 usbdev->defpipe = usb_realloc_pipe(usbdev, usbdev->defpipe, &epdesc);
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500330 if (!usbdev->defpipe)
331 return -1;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500332 return 0;
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500333}
334
335// Called for every found device - see if a driver is available for
336// this device and do setup if so.
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400337static int
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500338configure_usb_device(struct usbdevice_s *usbdev)
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500339{
340 ASSERT32FLAT();
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500341 dprintf(3, "config_usb: %p\n", usbdev->defpipe);
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500342
343 // Set the max packet size for endpoint 0 of this device.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400344 struct usb_device_descriptor dinfo;
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500345 int ret = get_device_info8(usbdev->defpipe, &dinfo);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400346 if (ret)
347 return 0;
Kevin O'Connor828ef122014-01-24 14:34:00 -0500348 u16 maxpacket = dinfo.bMaxPacketSize0;
349 if (dinfo.bcdUSB >= 0x0300)
350 maxpacket = 1 << dinfo.bMaxPacketSize0;
351 dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%d\n"
Kevin O'Connor114592f2009-09-28 21:32:08 -0400352 , dinfo.bcdUSB, dinfo.bDeviceClass, dinfo.bDeviceSubClass
Kevin O'Connor828ef122014-01-24 14:34:00 -0500353 , dinfo.bDeviceProtocol, maxpacket);
354 if (maxpacket < 8)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400355 return 0;
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500356 struct usb_endpoint_descriptor epdesc = {
Kevin O'Connor828ef122014-01-24 14:34:00 -0500357 .wMaxPacketSize = maxpacket,
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500358 .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
359 };
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -0400360 usbdev->defpipe = usb_realloc_pipe(usbdev, usbdev->defpipe, &epdesc);
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500361 if (!usbdev->defpipe)
362 return -1;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400363
364 // Get configuration
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500365 struct usb_config_descriptor *config = get_device_config(usbdev->defpipe);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400366 if (!config)
367 return 0;
368
369 // Determine if a driver exists for this device - only look at the
370 // first interface of the first configuration.
371 struct usb_interface_descriptor *iface = (void*)(&config[1]);
Kevin O'Connor0e885762010-05-01 22:14:40 -0400372 if (iface->bInterfaceClass != USB_CLASS_HID
373 && iface->bInterfaceClass != USB_CLASS_MASS_STORAGE
374 && iface->bInterfaceClass != USB_CLASS_HUB)
Kevin O'Connor54671c12010-02-15 18:58:12 -0500375 // Not a supported device.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400376 goto fail;
377
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500378 // Set the configuration.
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500379 ret = set_configuration(usbdev->defpipe, config->bConfigurationValue);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400380 if (ret)
381 goto fail;
382
383 // Configure driver.
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500384 usbdev->config = config;
385 usbdev->iface = iface;
386 usbdev->imax = (void*)config + config->wTotalLength - (void*)iface;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500387 if (iface->bInterfaceClass == USB_CLASS_HUB)
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500388 ret = usb_hub_setup(usbdev);
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +0200389 else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE) {
390 if (iface->bInterfaceProtocol == US_PR_BULK)
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500391 ret = usb_msc_setup(usbdev);
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +0200392 if (iface->bInterfaceProtocol == US_PR_UAS)
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500393 ret = usb_uas_setup(usbdev);
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +0200394 } else
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500395 ret = usb_hid_setup(usbdev);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400396 if (ret)
397 goto fail;
398
Kevin O'Connor1c46a542009-10-17 23:53:32 -0400399 free(config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400400 return 1;
401fail:
Kevin O'Connor1c46a542009-10-17 23:53:32 -0400402 free(config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400403 return 0;
404}
405
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400406static void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500407usb_hub_port_setup(void *data)
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400408{
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500409 struct usbdevice_s *usbdev = data;
410 struct usbhub_s *hub = usbdev->hub;
411 u32 port = usbdev->port;
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400412
Kevin O'Connor0f681302014-09-10 11:33:01 -0400413 for (;;) {
414 // Detect if device present (and possibly start reset)
415 int ret = hub->op->detect(hub, port);
416 if (ret > 0)
417 // Device connected.
418 break;
419 if (ret < 0 || timer_check(hub->detectend))
420 // No device found.
421 goto done;
422 msleep(5);
423 }
424
425 // XXX - wait USB_TIME_ATTDB time?
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400426
427 // Reset port and determine device speed
428 mutex_lock(&hub->cntl->resetlock);
Kevin O'Connor0f681302014-09-10 11:33:01 -0400429 int ret = hub->op->reset(hub, port);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400430 if (ret < 0)
431 // Reset failed
432 goto resetfail;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500433 usbdev->speed = ret;
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400434
435 // Set address of port
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500436 ret = usb_set_address(usbdev);
437 if (ret) {
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400438 hub->op->disconnect(hub, port);
439 goto resetfail;
440 }
441 mutex_unlock(&hub->cntl->resetlock);
442
443 // Configure the device
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500444 int count = configure_usb_device(usbdev);
Kevin O'Connorf3329432014-10-16 11:59:45 -0400445 usb_free_pipe(usbdev, usbdev->defpipe);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400446 if (!count)
447 hub->op->disconnect(hub, port);
448 hub->devcount += count;
449done:
450 hub->threads--;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500451 free(usbdev);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400452 return;
453
454resetfail:
455 mutex_unlock(&hub->cntl->resetlock);
456 goto done;
457}
458
Kevin O'Connorc5e56b22016-10-26 12:43:12 -0400459static u32 usb_time_sigatt;
Kevin O'Connor45b594a2015-11-09 12:00:52 -0500460
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400461void
462usb_enumerate(struct usbhub_s *hub)
463{
464 u32 portcount = hub->portcount;
465 hub->threads = portcount;
Kevin O'Connor45b594a2015-11-09 12:00:52 -0500466 hub->detectend = timer_calc(usb_time_sigatt);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400467
468 // Launch a thread for every port.
469 int i;
470 for (i=0; i<portcount; i++) {
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500471 struct usbdevice_s *usbdev = malloc_tmphigh(sizeof(*usbdev));
472 if (!usbdev) {
473 warn_noalloc();
474 continue;
475 }
476 memset(usbdev, 0, sizeof(*usbdev));
477 usbdev->hub = hub;
478 usbdev->port = i;
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500479 run_thread(usb_hub_port_setup, usbdev);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400480 }
481
482 // Wait for threads to complete.
483 while (hub->threads)
484 yield();
485}
486
Kevin O'Connor114592f2009-09-28 21:32:08 -0400487void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500488usb_setup(void)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400489{
Kevin O'Connor59c75742010-02-13 18:49:24 -0500490 ASSERT32FLAT();
Kevin O'Connor114592f2009-09-28 21:32:08 -0400491 if (! CONFIG_USB)
492 return;
Kevin O'Connor88e9bd72016-02-02 14:35:55 -0500493 dprintf(3, "init usb\n");
Kevin O'Connor45b594a2015-11-09 12:00:52 -0500494 usb_time_sigatt = romfile_loadint("etc/usb-time-sigatt", USB_TIME_SIGATT);
Kevin O'Connor88e9bd72016-02-02 14:35:55 -0500495 xhci_setup();
496 ehci_setup();
497 uhci_setup();
498 ohci_setup();
Kevin O'Connor114592f2009-09-28 21:32:08 -0400499}