blob: bb646a78538a194b484e81e243f38c02911448d8 [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'Connor2d2fa312013-09-14 21:55:26 -040011#include "string.h" // memset
12#include "usb.h" // struct usb_s
Kevin O'Connord83c87b2013-01-21 01:14:12 -050013#include "usb-ehci.h" // ehci_setup
Gerd Hoffmanne144bb72013-06-03 16:30:18 +020014#include "usb-xhci.h" // xhci_setup
Kevin O'Connor114592f2009-09-28 21:32:08 -040015#include "usb-hid.h" // usb_keyboard_setup
Kevin O'Connord83c87b2013-01-21 01:14:12 -050016#include "usb-hub.h" // usb_hub_setup
17#include "usb-msc.h" // usb_msc_setup
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040018#include "usb-ohci.h" // ohci_setup
Kevin O'Connord83c87b2013-01-21 01:14:12 -050019#include "usb-uas.h" // usb_uas_setup
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040020#include "usb-uhci.h" // uhci_setup
21#include "util.h" // msleep
Kevin O'Connorb9c6a962013-09-14 13:01:30 -040022#include "x86.h" // __fls
Kevin O'Connor114592f2009-09-28 21:32:08 -040023
Kevin O'Connor3c160dd2010-02-17 23:06:52 -050024
25/****************************************************************
26 * Controller function wrappers
27 ****************************************************************/
28
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -040029// Allocate, update, or free a usb pipe.
30static struct usb_pipe *
31usb_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *pipe
32 , struct usb_endpoint_descriptor *epdesc)
Kevin O'Connor54bf2072012-03-09 07:52:33 -050033{
34 switch (usbdev->hub->cntl->type) {
Kevin O'Connor59f02832009-10-12 10:09:15 -040035 default:
36 case USB_TYPE_UHCI:
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -040037 return uhci_realloc_pipe(usbdev, pipe, epdesc);
Kevin O'Connor59f02832009-10-12 10:09:15 -040038 case USB_TYPE_OHCI:
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -040039 return ohci_realloc_pipe(usbdev, pipe, epdesc);
Kevin O'Connor190cc622010-03-09 19:43:52 -050040 case USB_TYPE_EHCI:
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -040041 return ehci_realloc_pipe(usbdev, pipe, epdesc);
Gerd Hoffmanne144bb72013-06-03 16:30:18 +020042 case USB_TYPE_XHCI:
Kevin O'Connorc427def2014-10-16 13:23:08 -040043 return xhci_realloc_pipe(usbdev, pipe, epdesc);
Gerd Hoffmann63cbab12013-08-21 13:59:21 +020044 }
45}
46
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050047// Send a message on a control pipe using the default control descriptor.
48static int
Kevin O'Connor20c9be32014-10-16 11:55:16 -040049usb_send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize
50 , void *data, int datasize)
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050051{
52 ASSERT32FLAT();
Kevin O'Connor4547eb92010-02-28 02:17:28 -050053 switch (pipe->type) {
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050054 default:
55 case USB_TYPE_UHCI:
Kevin O'Connor20c9be32014-10-16 11:55:16 -040056 return uhci_send_control(pipe, dir, cmd, cmdsize, data, datasize);
Kevin O'Connor357bdfa2010-02-26 08:57:13 -050057 case USB_TYPE_OHCI:
Kevin O'Connor20c9be32014-10-16 11:55:16 -040058 return ohci_send_control(pipe, dir, cmd, cmdsize, data, datasize);
Kevin O'Connor190cc622010-03-09 19:43:52 -050059 case USB_TYPE_EHCI:
Kevin O'Connor20c9be32014-10-16 11:55:16 -040060 return ehci_send_control(pipe, dir, cmd, cmdsize, data, datasize);
Gerd Hoffmanne144bb72013-06-03 16:30:18 +020061 case USB_TYPE_XHCI:
Kevin O'Connor20c9be32014-10-16 11:55:16 -040062 return xhci_send_control(pipe, dir, cmd, cmdsize, data, datasize);
Kevin O'Connor59f02832009-10-12 10:09:15 -040063 }
Kevin O'Connor114592f2009-09-28 21:32:08 -040064}
65
Kevin O'Connor7149fc82010-02-17 23:24:42 -050066int
Kevin O'Connor4547eb92010-02-28 02:17:28 -050067usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize)
Kevin O'Connor7149fc82010-02-17 23:24:42 -050068{
Kevin O'Connor1e3bd4f2012-05-24 23:56:19 -040069 switch (GET_LOWFLAT(pipe_fl->type)) {
Kevin O'Connor7149fc82010-02-17 23:24:42 -050070 default:
71 case USB_TYPE_UHCI:
Kevin O'Connor4547eb92010-02-28 02:17:28 -050072 return uhci_send_bulk(pipe_fl, dir, data, datasize);
Kevin O'Connor7149fc82010-02-17 23:24:42 -050073 case USB_TYPE_OHCI:
Kevin O'Connor2f968002010-09-19 22:10:08 -040074 return ohci_send_bulk(pipe_fl, dir, data, datasize);
Kevin O'Connor190cc622010-03-09 19:43:52 -050075 case USB_TYPE_EHCI:
76 return ehci_send_bulk(pipe_fl, dir, data, datasize);
Gerd Hoffmanne144bb72013-06-03 16:30:18 +020077 case USB_TYPE_XHCI:
Kevin O'Connorde30dad2013-12-30 22:09:04 -050078 if (MODESEGMENT)
79 return -1;
Gerd Hoffmanne144bb72013-06-03 16:30:18 +020080 return xhci_send_bulk(pipe_fl, dir, data, datasize);
Kevin O'Connor7149fc82010-02-17 23:24:42 -050081 }
82}
83
Kevin O'Connorac7eb5e2012-05-28 14:42:16 -040084int
Kevin O'Connor4547eb92010-02-28 02:17:28 -050085usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
Kevin O'Connor114592f2009-09-28 21:32:08 -040086{
Kevin O'Connorde30dad2013-12-30 22:09:04 -050087 ASSERT16();
Kevin O'Connor1e3bd4f2012-05-24 23:56:19 -040088 switch (GET_LOWFLAT(pipe_fl->type)) {
Kevin O'Connor59f02832009-10-12 10:09:15 -040089 default:
90 case USB_TYPE_UHCI:
Kevin O'Connor4547eb92010-02-28 02:17:28 -050091 return uhci_poll_intr(pipe_fl, data);
Kevin O'Connor59f02832009-10-12 10:09:15 -040092 case USB_TYPE_OHCI:
Kevin O'Connor4547eb92010-02-28 02:17:28 -050093 return ohci_poll_intr(pipe_fl, data);
Kevin O'Connor190cc622010-03-09 19:43:52 -050094 case USB_TYPE_EHCI:
95 return ehci_poll_intr(pipe_fl, data);
Kevin O'Connorde30dad2013-12-30 22:09:04 -050096 case USB_TYPE_XHCI: ;
97 extern void _cfunc32flat_xhci_poll_intr(void);
98 return call32_params(_cfunc32flat_xhci_poll_intr, (u32)pipe_fl
99 , (u32)MAKE_FLATPTR(GET_SEG(SS), (u32)data), 0, -1);
Kevin O'Connor59f02832009-10-12 10:09:15 -0400100 }
Kevin O'Connor114592f2009-09-28 21:32:08 -0400101}
102
Kevin O'Connorde30dad2013-12-30 22:09:04 -0500103int usb_32bit_pipe(struct usb_pipe *pipe_fl)
104{
105 return CONFIG_USB_XHCI && GET_LOWFLAT(pipe_fl->type) == USB_TYPE_XHCI;
106}
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500107
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -0400108
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500109/****************************************************************
110 * Helper functions
111 ****************************************************************/
112
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -0400113// Allocate a usb pipe.
114struct usb_pipe *
115usb_alloc_pipe(struct usbdevice_s *usbdev
116 , struct usb_endpoint_descriptor *epdesc)
117{
118 return usb_realloc_pipe(usbdev, NULL, epdesc);
119}
120
121// Free an allocated control or bulk pipe.
122void
123usb_free_pipe(struct usbdevice_s *usbdev, struct usb_pipe *pipe)
124{
125 if (!pipe)
126 return;
127 usb_realloc_pipe(usbdev, pipe, NULL);
128}
129
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500130// Send a message to the default control pipe of a device.
131int
Kevin O'Connor222bad42014-10-16 12:11:12 -0400132usb_send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
133 , void *data)
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500134{
Kevin O'Connor20c9be32014-10-16 11:55:16 -0400135 return usb_send_control(pipe, req->bRequestType & USB_DIR_IN
136 , req, sizeof(*req), data, req->wLength);
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500137}
138
Kevin O'Connor2bfd1702014-10-16 12:31:42 -0400139// Check if a pipe for a given controller is on the freelist
140int
141usb_is_freelist(struct usb_s *cntl, struct usb_pipe *pipe)
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500142{
Kevin O'Connor2bfd1702014-10-16 12:31:42 -0400143 return pipe->cntl != cntl;
144}
145
146// Add a pipe to the controller's freelist
147void
148usb_add_freelist(struct usb_pipe *pipe)
149{
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500150 if (!pipe)
151 return;
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500152 struct usb_s *cntl = pipe->cntl;
153 pipe->freenext = cntl->freelist;
154 cntl->freelist = pipe;
155}
156
157// Check for an available pipe on the freelist.
158struct usb_pipe *
Kevin O'Connor2bfd1702014-10-16 12:31:42 -0400159usb_get_freelist(struct usb_s *cntl, u8 eptype)
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500160{
161 struct usb_pipe **pfree = &cntl->freelist;
162 for (;;) {
163 struct usb_pipe *pipe = *pfree;
164 if (!pipe)
165 return NULL;
166 if (pipe->eptype == eptype) {
167 *pfree = pipe->freenext;
168 return pipe;
169 }
170 pfree = &pipe->freenext;
171 }
172}
173
174// Fill "pipe" endpoint info from an endpoint descriptor.
175void
176usb_desc2pipe(struct usb_pipe *pipe, struct usbdevice_s *usbdev
177 , struct usb_endpoint_descriptor *epdesc)
178{
179 pipe->cntl = usbdev->hub->cntl;
180 pipe->type = usbdev->hub->cntl->type;
181 pipe->ep = epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
182 pipe->devaddr = usbdev->devaddr;
183 pipe->speed = usbdev->speed;
184 pipe->maxpacket = epdesc->wMaxPacketSize;
185 pipe->eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500186}
187
188// Find the exponential period of the requested interrupt end point.
189int
Kevin O'Connor98cdad32014-10-16 12:05:09 -0400190usb_get_period(struct usbdevice_s *usbdev
191 , struct usb_endpoint_descriptor *epdesc)
Kevin O'Connorfbf66f12012-03-10 09:13:58 -0500192{
193 int period = epdesc->bInterval;
194 if (usbdev->speed != USB_HIGHSPEED)
195 return (period <= 0) ? 0 : __fls(period);
196 return (period <= 4) ? 0 : period - 4;
197}
198
Kevin O'Connor88fa2272014-06-14 12:25:17 -0400199// Maximum time (in ms) a data transfer should take
200int
201usb_xfer_time(struct usb_pipe *pipe, int datalen)
202{
203 // Use the maximum command time (5 seconds), except for
204 // set_address commands where we don't want to stall the boot if
205 // the device doesn't actually exist. Add 100ms to account for
206 // any controller delays.
Kevin O'Connor0806e9e2014-09-09 18:24:00 -0400207 if (!GET_LOWFLAT(pipe->devaddr))
Kevin O'Connor88fa2272014-06-14 12:25:17 -0400208 return USB_TIME_STATUS + 100;
209 return USB_TIME_COMMAND + 100;
210}
211
Kevin O'Connor674f1402014-10-16 12:08:00 -0400212// Find the first endpoint of a given type in an interface description.
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500213struct usb_endpoint_descriptor *
Kevin O'Connor674f1402014-10-16 12:08:00 -0400214usb_find_desc(struct usbdevice_s *usbdev, int type, int dir)
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500215{
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500216 struct usb_endpoint_descriptor *epdesc = (void*)&usbdev->iface[1];
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500217 for (;;) {
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500218 if ((void*)epdesc >= (void*)usbdev->iface + usbdev->imax
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500219 || epdesc->bDescriptorType == USB_DT_INTERFACE) {
220 return NULL;
221 }
222 if (epdesc->bDescriptorType == USB_DT_ENDPOINT
223 && (epdesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir
224 && (epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type)
225 return epdesc;
226 epdesc = (void*)epdesc + epdesc->bLength;
227 }
228}
229
Kevin O'Connor114592f2009-09-28 21:32:08 -0400230// Get the first 8 bytes of the device descriptor.
231static int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500232get_device_info8(struct usb_pipe *pipe, struct usb_device_descriptor *dinfo)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400233{
234 struct usb_ctrlrequest req;
235 req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
236 req.bRequest = USB_REQ_GET_DESCRIPTOR;
237 req.wValue = USB_DT_DEVICE<<8;
238 req.wIndex = 0;
239 req.wLength = 8;
Kevin O'Connor222bad42014-10-16 12:11:12 -0400240 return usb_send_default_control(pipe, &req, dinfo);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400241}
242
243static struct usb_config_descriptor *
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500244get_device_config(struct usb_pipe *pipe)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400245{
246 struct usb_config_descriptor cfg;
247
248 struct usb_ctrlrequest req;
249 req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
250 req.bRequest = USB_REQ_GET_DESCRIPTOR;
251 req.wValue = USB_DT_CONFIG<<8;
252 req.wIndex = 0;
253 req.wLength = sizeof(cfg);
Kevin O'Connor222bad42014-10-16 12:11:12 -0400254 int ret = usb_send_default_control(pipe, &req, &cfg);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400255 if (ret)
256 return NULL;
257
258 void *config = malloc_tmphigh(cfg.wTotalLength);
259 if (!config)
260 return NULL;
261 req.wLength = cfg.wTotalLength;
Kevin O'Connor222bad42014-10-16 12:11:12 -0400262 ret = usb_send_default_control(pipe, &req, config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400263 if (ret)
264 return NULL;
265 //hexdump(config, cfg.wTotalLength);
266 return config;
267}
268
Kevin O'Connor114592f2009-09-28 21:32:08 -0400269static int
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500270set_configuration(struct usb_pipe *pipe, u16 val)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400271{
272 struct usb_ctrlrequest req;
273 req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
274 req.bRequest = USB_REQ_SET_CONFIGURATION;
275 req.wValue = val;
276 req.wIndex = 0;
277 req.wLength = 0;
Kevin O'Connor222bad42014-10-16 12:11:12 -0400278 return usb_send_default_control(pipe, &req, NULL);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400279}
280
Kevin O'Connor3c160dd2010-02-17 23:06:52 -0500281
282/****************************************************************
283 * Initialization and enumeration
284 ****************************************************************/
285
Kevin O'Connor3de73822014-01-26 17:28:04 -0500286static const int speed_to_ctlsize[] = {
287 [ USB_FULLSPEED ] = 8,
288 [ USB_LOWSPEED ] = 8,
289 [ USB_HIGHSPEED ] = 64,
290 [ USB_SUPERSPEED ] = 512,
291};
292
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500293// Assign an address to a device in the default state on the given
294// controller.
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500295static int
296usb_set_address(struct usbdevice_s *usbdev)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400297{
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500298 ASSERT32FLAT();
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500299 struct usb_s *cntl = usbdev->hub->cntl;
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500300 dprintf(3, "set_address %p\n", cntl);
301 if (cntl->maxaddr >= USB_MAXADDR)
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500302 return -1;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400303
Kevin O'Connor4ea2fa92013-12-27 19:25:46 -0500304 msleep(USB_TIME_RSTRCY);
305
Kevin O'Connor92650f22012-03-05 22:03:03 -0500306 // Create a pipe for the default address.
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500307 struct usb_endpoint_descriptor epdesc = {
Kevin O'Connor3de73822014-01-26 17:28:04 -0500308 .wMaxPacketSize = speed_to_ctlsize[usbdev->speed],
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500309 .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
310 };
Kevin O'Connorc3d96c22012-03-10 09:03:25 -0500311 usbdev->defpipe = usb_alloc_pipe(usbdev, &epdesc);
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500312 if (!usbdev->defpipe)
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500313 return -1;
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500314
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500315 // Send set_address command.
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500316 struct usb_ctrlrequest req;
317 req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
318 req.bRequest = USB_REQ_SET_ADDRESS;
319 req.wValue = cntl->maxaddr + 1;
320 req.wIndex = 0;
321 req.wLength = 0;
Kevin O'Connor222bad42014-10-16 12:11:12 -0400322 int ret = usb_send_default_control(usbdev->defpipe, &req, NULL);
Gerd Hoffmann63cbab12013-08-21 13:59:21 +0200323 if (ret) {
Kevin O'Connorf3329432014-10-16 11:59:45 -0400324 usb_free_pipe(usbdev, usbdev->defpipe);
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500325 return -1;
Gerd Hoffmann63cbab12013-08-21 13:59:21 +0200326 }
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500327
328 msleep(USB_TIME_SETADDR_RECOVERY);
329
330 cntl->maxaddr++;
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500331 usbdev->devaddr = cntl->maxaddr;
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -0400332 usbdev->defpipe = usb_realloc_pipe(usbdev, usbdev->defpipe, &epdesc);
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500333 if (!usbdev->defpipe)
334 return -1;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500335 return 0;
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500336}
337
338// Called for every found device - see if a driver is available for
339// this device and do setup if so.
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400340static int
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500341configure_usb_device(struct usbdevice_s *usbdev)
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500342{
343 ASSERT32FLAT();
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500344 dprintf(3, "config_usb: %p\n", usbdev->defpipe);
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500345
346 // Set the max packet size for endpoint 0 of this device.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400347 struct usb_device_descriptor dinfo;
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500348 int ret = get_device_info8(usbdev->defpipe, &dinfo);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400349 if (ret)
350 return 0;
Kevin O'Connor828ef122014-01-24 14:34:00 -0500351 u16 maxpacket = dinfo.bMaxPacketSize0;
352 if (dinfo.bcdUSB >= 0x0300)
353 maxpacket = 1 << dinfo.bMaxPacketSize0;
354 dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%d\n"
Kevin O'Connor114592f2009-09-28 21:32:08 -0400355 , dinfo.bcdUSB, dinfo.bDeviceClass, dinfo.bDeviceSubClass
Kevin O'Connor828ef122014-01-24 14:34:00 -0500356 , dinfo.bDeviceProtocol, maxpacket);
357 if (maxpacket < 8)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400358 return 0;
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500359 struct usb_endpoint_descriptor epdesc = {
Kevin O'Connor828ef122014-01-24 14:34:00 -0500360 .wMaxPacketSize = maxpacket,
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500361 .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
362 };
Kevin O'Connor54a1c6d2014-10-16 14:03:39 -0400363 usbdev->defpipe = usb_realloc_pipe(usbdev, usbdev->defpipe, &epdesc);
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500364 if (!usbdev->defpipe)
365 return -1;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400366
367 // Get configuration
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500368 struct usb_config_descriptor *config = get_device_config(usbdev->defpipe);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400369 if (!config)
370 return 0;
371
372 // Determine if a driver exists for this device - only look at the
373 // first interface of the first configuration.
374 struct usb_interface_descriptor *iface = (void*)(&config[1]);
Kevin O'Connor0e885762010-05-01 22:14:40 -0400375 if (iface->bInterfaceClass != USB_CLASS_HID
376 && iface->bInterfaceClass != USB_CLASS_MASS_STORAGE
377 && iface->bInterfaceClass != USB_CLASS_HUB)
Kevin O'Connor54671c12010-02-15 18:58:12 -0500378 // Not a supported device.
Kevin O'Connor114592f2009-09-28 21:32:08 -0400379 goto fail;
380
Kevin O'Connor8ebcac02010-03-09 19:58:23 -0500381 // Set the configuration.
Kevin O'Connor77ab4e12012-03-08 08:44:32 -0500382 ret = set_configuration(usbdev->defpipe, config->bConfigurationValue);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400383 if (ret)
384 goto fail;
385
386 // Configure driver.
Kevin O'Connor6a8e8952012-03-08 07:20:30 -0500387 usbdev->config = config;
388 usbdev->iface = iface;
389 usbdev->imax = (void*)config + config->wTotalLength - (void*)iface;
Kevin O'Connor357bdfa2010-02-26 08:57:13 -0500390 if (iface->bInterfaceClass == USB_CLASS_HUB)
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500391 ret = usb_hub_setup(usbdev);
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +0200392 else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE) {
393 if (iface->bInterfaceProtocol == US_PR_BULK)
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500394 ret = usb_msc_setup(usbdev);
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +0200395 if (iface->bInterfaceProtocol == US_PR_UAS)
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500396 ret = usb_uas_setup(usbdev);
Gerd Hoffmanne53e30d2012-07-20 10:59:24 +0200397 } else
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500398 ret = usb_hid_setup(usbdev);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400399 if (ret)
400 goto fail;
401
Kevin O'Connor1c46a542009-10-17 23:53:32 -0400402 free(config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400403 return 1;
404fail:
Kevin O'Connor1c46a542009-10-17 23:53:32 -0400405 free(config);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400406 return 0;
407}
408
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400409static void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500410usb_hub_port_setup(void *data)
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400411{
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500412 struct usbdevice_s *usbdev = data;
413 struct usbhub_s *hub = usbdev->hub;
414 u32 port = usbdev->port;
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400415
Kevin O'Connor0f681302014-09-10 11:33:01 -0400416 for (;;) {
417 // Detect if device present (and possibly start reset)
418 int ret = hub->op->detect(hub, port);
419 if (ret > 0)
420 // Device connected.
421 break;
422 if (ret < 0 || timer_check(hub->detectend))
423 // No device found.
424 goto done;
425 msleep(5);
426 }
427
428 // XXX - wait USB_TIME_ATTDB time?
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400429
430 // Reset port and determine device speed
431 mutex_lock(&hub->cntl->resetlock);
Kevin O'Connor0f681302014-09-10 11:33:01 -0400432 int ret = hub->op->reset(hub, port);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400433 if (ret < 0)
434 // Reset failed
435 goto resetfail;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500436 usbdev->speed = ret;
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400437
438 // Set address of port
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500439 ret = usb_set_address(usbdev);
440 if (ret) {
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400441 hub->op->disconnect(hub, port);
442 goto resetfail;
443 }
444 mutex_unlock(&hub->cntl->resetlock);
445
446 // Configure the device
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500447 int count = configure_usb_device(usbdev);
Kevin O'Connorf3329432014-10-16 11:59:45 -0400448 usb_free_pipe(usbdev, usbdev->defpipe);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400449 if (!count)
450 hub->op->disconnect(hub, port);
451 hub->devcount += count;
452done:
453 hub->threads--;
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500454 free(usbdev);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400455 return;
456
457resetfail:
458 mutex_unlock(&hub->cntl->resetlock);
459 goto done;
460}
461
462void
463usb_enumerate(struct usbhub_s *hub)
464{
465 u32 portcount = hub->portcount;
466 hub->threads = portcount;
Kevin O'Connor0f681302014-09-10 11:33:01 -0400467 hub->detectend = timer_calc(USB_TIME_SIGATT);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400468
469 // Launch a thread for every port.
470 int i;
471 for (i=0; i<portcount; i++) {
Kevin O'Connor4f74dad2012-03-06 08:20:40 -0500472 struct usbdevice_s *usbdev = malloc_tmphigh(sizeof(*usbdev));
473 if (!usbdev) {
474 warn_noalloc();
475 continue;
476 }
477 memset(usbdev, 0, sizeof(*usbdev));
478 usbdev->hub = hub;
479 usbdev->port = i;
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500480 run_thread(usb_hub_port_setup, usbdev);
Kevin O'Connord28b0fe2010-03-28 15:11:19 -0400481 }
482
483 // Wait for threads to complete.
484 while (hub->threads)
485 yield();
486}
487
Kevin O'Connor114592f2009-09-28 21:32:08 -0400488void
Kevin O'Connorec443ff2013-12-05 18:43:20 -0500489__usb_setup(void *data)
490{
491 dprintf(3, "init usb\n");
492 xhci_setup();
493 ehci_setup();
494 uhci_setup();
495 ohci_setup();
496}
497
498void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500499usb_setup(void)
Kevin O'Connor114592f2009-09-28 21:32:08 -0400500{
Kevin O'Connor59c75742010-02-13 18:49:24 -0500501 ASSERT32FLAT();
Kevin O'Connor114592f2009-09-28 21:32:08 -0400502 if (! CONFIG_USB)
503 return;
Kevin O'Connorec443ff2013-12-05 18:43:20 -0500504 run_thread(__usb_setup, NULL);
Kevin O'Connor114592f2009-09-28 21:32:08 -0400505}