aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--payloads/libpayload/drivers/usb/quirks.c9
-rw-r--r--payloads/libpayload/drivers/usb/usb.c368
-rw-r--r--payloads/libpayload/drivers/usb/usbhid.c18
-rw-r--r--payloads/libpayload/drivers/usb/usbhub.c71
-rw-r--r--payloads/libpayload/drivers/usb/xhci_devconf.c82
-rw-r--r--payloads/libpayload/drivers/usb/xhci_private.h2
-rw-r--r--payloads/libpayload/include/usb/usb.h39
7 files changed, 310 insertions, 279 deletions
diff --git a/payloads/libpayload/drivers/usb/quirks.c b/payloads/libpayload/drivers/usb/quirks.c
index a8f2622e31..a426a8f8de 100644
--- a/payloads/libpayload/drivers/usb/quirks.c
+++ b/payloads/libpayload/drivers/usb/quirks.c
@@ -47,10 +47,11 @@ usb_quirks_t usb_quirks[] = {
{ 0x13fd, 0x0841, USB_QUIRK_NONE, 0 }, // Samsung SE-S084
/* Silence the warning for known devices with more
- * than one interface
+ * than one interface. The 'interface' value should specify the
+ * interface we want to use (interface numbers usually start at 0).
*/
- { 0x1267, 0x0103, USB_QUIRK_NONE, 1 }, // Keyboard Trust KB-1800S
- { 0x0a12, 0x0001, USB_QUIRK_NONE, 1 }, // Bluetooth Allnet ALL1575
+ { 0x1267, 0x0103, USB_QUIRK_NONE, 0 }, // Keyboard Trust KB-1800S
+ { 0x0a12, 0x0001, USB_QUIRK_NONE, 0 }, // Bluetooth Allnet ALL1575
/* Currently unsupported, possibly interesting devices:
* FTDI serial: device 0x0403:0x6001 is USB 1.10 (class ff)
@@ -83,6 +84,6 @@ int usb_interface_check(u16 vendor, u16 device)
}
}
- return 0;
+ return -1;
}
diff --git a/payloads/libpayload/drivers/usb/usb.c b/payloads/libpayload/drivers/usb/usb.c
index 0ec6f5c69e..4f21e0cf3b 100644
--- a/payloads/libpayload/drivers/usb/usb.c
+++ b/payloads/libpayload/drivers/usb/usb.c
@@ -32,6 +32,8 @@
#include <libpayload-config.h>
#include <usb/usb.h>
+#define DR_DESC gen_bmRequestType(device_to_host, standard_type, dev_recp)
+
hci_t *usb_hcs = 0;
hci_t *
@@ -100,21 +102,27 @@ usb_poll (void)
}
}
-void
+usbdev_t *
init_device_entry (hci_t *controller, int i)
{
+ usbdev_t *dev = calloc(1, sizeof(usbdev_t));
+ if (!dev) {
+ usb_debug("no memory to allocate device structure\n");
+ return NULL;
+ }
if (controller->devices[i] != 0)
usb_debug("warning: device %d reassigned?\n", i);
- controller->devices[i] = malloc(sizeof(usbdev_t));
- controller->devices[i]->controller = controller;
- controller->devices[i]->address = -1;
- controller->devices[i]->hub = -1;
- controller->devices[i]->port = -1;
- controller->devices[i]->init = usb_nop_init;
- controller->devices[i]->init (controller->devices[i]);
+ controller->devices[i] = dev;
+ dev->controller = controller;
+ dev->address = -1;
+ dev->hub = -1;
+ dev->port = -1;
+ dev->init = usb_nop_init;
+ dev->init (controller->devices[i]);
+ return dev;
}
-void
+int
set_feature (usbdev_t *dev, int endp, int feature, int rtype)
{
dev_req_t dr;
@@ -125,10 +133,11 @@ set_feature (usbdev_t *dev, int endp, int feature, int rtype)
dr.wValue = feature;
dr.wIndex = endp;
dr.wLength = 0;
- dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
+
+ return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
}
-void
+int
get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
{
dev_req_t dr;
@@ -139,67 +148,37 @@ get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
dr.wValue = 0;
dr.wIndex = intf;
dr.wLength = len;
- dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
+
+ return dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
}
-u8 *
-get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
- int descIdx, int langID)
+int
+get_descriptor (usbdev_t *dev, int rtype, int descType, int descIdx,
+ void *data, size_t len)
{
- u8 buf[8];
- u8 *result;
dev_req_t dr;
- int size;
- dr.bmRequestType = bmRequestType;
- dr.data_dir = device_to_host; // always like this for descriptors
+ dr.bmRequestType = rtype;
dr.bRequest = GET_DESCRIPTOR;
- dr.wValue = (descType << 8) | descIdx;
- dr.wIndex = langID;
- dr.wLength = 8;
- if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf) < 0) {
- usb_debug ("getting descriptor size (type %x) failed\n",
- descType);
- }
-
- if (descType == 1) {
- device_descriptor_t *dd = (device_descriptor_t *) buf;
- usb_debug ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
- if (dd->bMaxPacketSize0 != 0)
- dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
- }
-
- /* special case for configuration descriptors: they carry all their
- subsequent descriptors with them, and keep the entire size at a
- different location */
- size = buf[0];
- if (buf[1] == 2) {
- int realsize = ((unsigned short *) (buf + 2))[0];
- size = realsize;
- }
- result = malloc (size);
- memset (result, 0, size);
- dr.wLength = size;
- if (dev->controller->
- control (dev, IN, sizeof (dr), &dr, size, result) < 0) {
- usb_debug ("getting descriptor (type %x, size %x) failed\n",
- descType, size);
- }
+ dr.wValue = descType << 8 | descIdx;
+ dr.wIndex = 0;
+ dr.wLength = len;
- return result;
+ return dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
}
-void
+int
set_configuration (usbdev_t *dev)
{
dev_req_t dr;
dr.bmRequestType = 0;
dr.bRequest = SET_CONFIGURATION;
- dr.wValue = dev->configuration[5];
+ dr.wValue = dev->configuration->bConfigurationValue;
dr.wIndex = 0;
dr.wLength = 0;
- dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
+
+ return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
}
int
@@ -213,18 +192,15 @@ clear_feature (usbdev_t *dev, int endp, int feature, int rtype)
dr.wValue = feature;
dr.wIndex = endp;
dr.wLength = 0;
+
return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0;
}
int
clear_stall (endpoint_t *ep)
{
- usbdev_t *dev = ep->dev;
- int endp = ep->endpoint;
- int rtype = gen_bmRequestType (host_to_device, standard_type,
- endp ? endp_recp : dev_recp);
-
- int ret = clear_feature (dev, endp, ENDPOINT_HALT, rtype);
+ int ret = clear_feature (ep->dev, ep->endpoint, ENDPOINT_HALT,
+ gen_bmRequestType (host_to_device, standard_type, endp_recp));
ep->toggle = 0;
return ret;
}
@@ -319,7 +295,7 @@ usb_decode_interval(usb_speed speed, const endpoint_type type, const unsigned ch
#undef LOG2
}
-int
+usbdev_t *
generic_set_address (hci_t *controller, usb_speed speed,
int hubport, int hubaddr)
{
@@ -335,8 +311,10 @@ generic_set_address (hci_t *controller, usb_speed speed,
dr.wIndex = 0;
dr.wLength = 0;
- init_device_entry(controller, adr);
- usbdev_t *dev = controller->devices[adr];
+ usbdev_t *dev = init_device_entry(controller, adr);
+ if (!dev)
+ return NULL;
+
// dummy values for registering the address
dev->address = 0;
dev->hub = hubaddr;
@@ -347,130 +325,174 @@ generic_set_address (hci_t *controller, usb_speed speed,
dev->endpoints[0].maxpacketsize = 8;
dev->endpoints[0].toggle = 0;
dev->endpoints[0].direction = SETUP;
+ dev->endpoints[0].type = CONTROL;
if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0) {
usb_debug ("set_address failed\n");
- return -1;
+ usb_detach_device (controller, adr);
+ return NULL;
}
mdelay (SET_ADDRESS_MDELAY);
- return adr;
+ u8 buf[8];
+ dev->address = adr;
+ if (get_descriptor (dev, DR_DESC, DT_DEV, 0, buf, sizeof(buf))
+ != sizeof(buf)) {
+ usb_debug("first get_descriptor(DT_DEV) failed\n");
+ usb_detach_device (controller, adr);
+ return NULL;
+ }
+ dev->endpoints[0].maxpacketsize = usb_decode_mps0(speed, buf[7]);
+
+ return dev;
}
static int
set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
{
- int adr = controller->set_address(controller, speed, hubport, hubaddr);
- if (adr < 0 || !controller->devices[adr]) {
+ usbdev_t *dev = controller->set_address(controller, speed,
+ hubport, hubaddr);
+ if (!dev) {
usb_debug ("set_address failed\n");
return -1;
}
- configuration_descriptor_t *cd;
- device_descriptor_t *dd;
- usbdev_t *dev = controller->devices[adr];
- dev->address = adr;
- dev->hub = hubaddr;
- dev->port = hubport;
- dev->speed = speed;
- dev->descriptor = get_descriptor (dev, gen_bmRequestType
- (device_to_host, standard_type, dev_recp), 1, 0, 0);
- dd = (device_descriptor_t *) dev->descriptor;
+ dev->descriptor = malloc(sizeof(*dev->descriptor));
+ if (!dev->descriptor || get_descriptor (dev, DR_DESC, DT_DEV, 0,
+ dev->descriptor, sizeof(*dev->descriptor))
+ != sizeof(*dev->descriptor)) {
+ usb_debug ("get_descriptor(DT_DEV) failed\n");
+ usb_detach_device (controller, dev->address);
+ return -1;
+ }
- usb_debug ("* found device (0x%04x:0x%04x, USB %x.%x)",
- dd->idVendor, dd->idProduct,
- dd->bcdUSB >> 8, dd->bcdUSB & 0xff);
- dev->quirks = usb_quirk_check(dd->idVendor, dd->idProduct);
+ usb_debug ("* found device (0x%04x:0x%04x, USB %x.%x, MPS0: %d)\n",
+ dev->descriptor->idVendor, dev->descriptor->idProduct,
+ dev->descriptor->bcdUSB >> 8, dev->descriptor->bcdUSB & 0xff,
+ dev->endpoints[0].maxpacketsize);
+ dev->quirks = usb_quirk_check(dev->descriptor->idVendor,
+ dev->descriptor->idProduct);
- usb_debug ("\ndevice has %x configurations\n", dd->bNumConfigurations);
- if (dd->bNumConfigurations == 0) {
+ usb_debug ("device has %d configurations\n",
+ dev->descriptor->bNumConfigurations);
+ if (dev->descriptor->bNumConfigurations == 0) {
/* device isn't usable */
usb_debug ("... no usable configuration!\n");
- dev->address = 0;
+ usb_detach_device (controller, dev->address);
return -1;
}
- dev->configuration = get_descriptor (dev, gen_bmRequestType
- (device_to_host, standard_type, dev_recp), 2, 0, 0);
- cd = (configuration_descriptor_t *) dev->configuration;
- interface_descriptor_t *interface =
- (interface_descriptor_t *) (((char *) cd) + cd->bLength);
- {
- int i;
- int num = cd->bNumInterfaces;
- interface_descriptor_t *current = interface;
- usb_debug ("device has %x interfaces\n", num);
- if (num > 1) {
- int interfaces = usb_interface_check(dd->idVendor, dd->idProduct);
- if (interfaces) {
- /* Well known device, don't warn */
- num = interfaces;
- } else {
-
- usb_debug ("\nNOTICE: This driver defaults to using the first interface.\n"
- "This might be the wrong choice and lead to limited functionality\n"
- "of the device. Please report such a case to coreboot@coreboot.org\n"
- "as you might be the first.\n");
- /* we limit to the first interface, as there was no need to
- * implement something else for the time being. If you need
- * it, see the SetInterface and GetInterface functions in
- * the USB specification, and adapt appropriately.
- */
- num = (num > 1) ? 1 : num;
- }
+ u16 buf[2];
+ if (get_descriptor (dev, DR_DESC, DT_CFG, 0, buf, sizeof(buf))
+ != sizeof(buf)) {
+ usb_debug ("first get_descriptor(DT_CFG) failed\n");
+ usb_detach_device (controller, dev->address);
+ return -1;
+ }
+ dev->configuration = malloc(buf[1]);
+ if (!dev->configuration) {
+ usb_debug ("could not allocate %d bytes for DT_CFG\n", buf[1]);
+ usb_detach_device (controller, dev->address);
+ return -1;
+ }
+ if (get_descriptor (dev, DR_DESC, DT_CFG, 0, dev->configuration,
+ buf[1]) != buf[1]) {
+ usb_debug ("get_descriptor(DT_CFG) failed\n");
+ usb_detach_device (controller, dev->address);
+ return -1;
+ }
+ configuration_descriptor_t *cd = dev->configuration;
+ if (cd->wTotalLength != buf[1]) {
+ usb_debug ("configuration descriptor size changed, aborting\n");
+ usb_detach_device (controller, dev->address);
+ return -1;
+ }
+
+ /*
+ * If the device is not well known (ifnum == -1), we use the first
+ * interface we encounter, as there was no need to implement something
+ * else for the time being. If you need it, see the SetInterface and
+ * GetInterface functions in the USB specification and set it yourself.
+ */
+ usb_debug ("device has %x interfaces\n", cd->bNumInterfaces);
+ int ifnum = usb_interface_check(dev->descriptor->idVendor,
+ dev->descriptor->idProduct);
+ if (cd->bNumInterfaces > 1 && ifnum < 0)
+ usb_debug ("NOTICE: Your device has multiple interfaces and\n"
+ "this driver will only use the first one. That may\n"
+ "be the wrong choice and cause the device to not\n"
+ "work correctly. Please report this case\n"
+ "(including the above debugging output) to\n"
+ "coreboot@coreboot.org to have the device added to\n"
+ "the list of well-known quirks.\n");
+
+ u8 *end = (void *)dev->configuration + cd->wTotalLength;
+ interface_descriptor_t *intf;
+ u8 *ptr;
+
+ /* Find our interface (or the first good one if we don't know) */
+ for (ptr = (void *)dev->configuration + sizeof(*cd); ; ptr += ptr[0]) {
+ if (ptr + 2 > end || !ptr[0] || ptr + ptr[0] > end) {
+ usb_debug ("Couldn't find usable DT_INTF\n");
+ usb_detach_device (controller, dev->address);
+ return -1;
}
- for (i = 0; i < num; i++) {
- int j;
- usb_debug (" #%x has %x endpoints, interface %x:%x, protocol %x\n",
- current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
- endpoint_descriptor_t *endp =
- (endpoint_descriptor_t *) (((char *) current)
- + current->bLength);
- /* Skip any non-endpoint descriptor */
- if (endp->bDescriptorType != 0x05)
- endp = (endpoint_descriptor_t *)(((char *)endp) + ((char *)endp)[0]);
-
- memset (dev->endpoints, 0, sizeof (dev->endpoints));
- dev->num_endp = 1; // 0 always exists
- dev->endpoints[0].dev = dev;
- dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
- dev->endpoints[0].direction = SETUP;
- dev->endpoints[0].type = CONTROL;
- dev->endpoints[0].interval = usb_decode_interval(dev->speed, CONTROL, endp->bInterval);
- for (j = 1; j <= current->bNumEndpoints; j++) {
-#ifdef USB_DEBUG
- static const char *transfertypes[4] = {
- "control", "isochronous", "bulk", "interrupt"
- };
- usb_debug (" #%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]);
-#endif
- endpoint_t *ep =
- &dev->endpoints[dev->num_endp++];
- ep->dev = dev;
- ep->endpoint = endp->bEndpointAddress;
- ep->toggle = 0;
- ep->maxpacketsize = endp->wMaxPacketSize;
- ep->direction =
- ((endp->bEndpointAddress & 0x80) ==
- 0) ? OUT : IN;
- ep->type = endp->bmAttributes;
- ep->interval = usb_decode_interval(dev->speed, ep->type, endp->bInterval);
- endp = (endpoint_descriptor_t
- *) (((char *) endp) + endp->bLength);
- }
- current = (interface_descriptor_t *) endp;
+ if (ptr[1] != DT_INTF)
+ continue;
+ intf = (void *)ptr;
+ if (intf->bLength != sizeof(*intf)) {
+ usb_debug ("Skipping broken DT_INTF\n");
+ continue;
}
+ if (ifnum >= 0 && intf->bInterfaceNumber != ifnum)
+ continue;
+ usb_debug ("Interface %d: class 0x%x, sub 0x%x. proto 0x%x\n",
+ intf->bInterfaceNumber, intf->bInterfaceClass,
+ intf->bInterfaceSubClass, intf->bInterfaceProtocol);
+ ptr += sizeof(*intf);
+ break;
}
- if (controller->finish_device_config &&
- controller->finish_device_config(dev))
- return adr; /* Device isn't configured correctly,
- only control transfers may work. */
+ /* Gather up all endpoints belonging to this inteface */
+ dev->num_endp = 1;
+ for (; ptr + 2 <= end && ptr[0] && ptr + ptr[0] <= end; ptr += ptr[0]) {
+ if (ptr[1] == DT_INTF || ptr[1] == DT_CFG ||
+ dev->num_endp >= ARRAY_SIZE(dev->endpoints))
+ break;
+ if (ptr[1] != DT_ENDP)
+ continue;
+
+ endpoint_descriptor_t *desc = (void *)ptr;
+ static const char *transfertypes[4] = {
+ "control", "isochronous", "bulk", "interrupt"
+ };
+ usb_debug (" #Endpoint %d (%s), max packet size %x, type %s\n",
+ desc->bEndpointAddress & 0x7f,
+ (desc->bEndpointAddress & 0x80) ? "in" : "out",
+ desc->wMaxPacketSize,
+ transfertypes[desc->bmAttributes & 0x3]);
+
+ endpoint_t *ep = &dev->endpoints[dev->num_endp++];
+ ep->dev = dev;
+ ep->endpoint = desc->bEndpointAddress;
+ ep->toggle = 0;
+ ep->maxpacketsize = desc->wMaxPacketSize;
+ ep->direction = (desc->bEndpointAddress & 0x80) ? IN : OUT;
+ ep->type = desc->bmAttributes & 0x3;
+ ep->interval = usb_decode_interval (dev->speed, ep->type,
+ desc->bInterval);
+ }
- set_configuration(dev);
+ if ((controller->finish_device_config &&
+ controller->finish_device_config(dev)) ||
+ set_configuration(dev) < 0) {
+ usb_debug ("Could not finalize device configuration\n");
+ usb_detach_device (controller, dev->address);
+ return -1;
+ }
- int class = dd->bDeviceClass;
+ int class = dev->descriptor->bDeviceClass;
if (class == 0)
- class = interface->bInterfaceClass;
+ class = intf->bInterfaceClass;
enum {
audio_device = 0x01,
@@ -490,7 +512,7 @@ set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
wireless_device = 0xe0,
misc_device = 0xef,
};
- usb_debug(", class: ");
+ usb_debug("Class: ");
switch (class) {
case audio_device:
usb_debug("audio\n");
@@ -501,8 +523,8 @@ set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
case hid_device:
usb_debug ("HID\n");
#ifdef CONFIG_LP_USB_HID
- controller->devices[adr]->init = usb_hid_init;
- return adr;
+ dev->init = usb_hid_init;
+ return dev->address;
#else
usb_debug ("NOTICE: USB HID support not compiled in\n");
#endif
@@ -519,20 +541,24 @@ set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
case msc_device:
usb_debug ("MSC\n");
#ifdef CONFIG_LP_USB_MSC
- controller->devices[adr]->init = usb_msc_init;
- return adr;
+ dev->init = usb_msc_init;
+ return dev->address;
#else
usb_debug ("NOTICE: USB MSC support not compiled in\n");
#endif
break;
case hub_device:
- usb_debug ("hub\n");
+ if (speed < SUPER_SPEED) {
+ usb_debug ("hub (2.0)\n");
#ifdef CONFIG_LP_USB_HUB
- controller->devices[adr]->init = usb_hub_init;
- return adr;
+ dev->init = usb_hub_init;
+ return dev->address;
#else
- usb_debug ("NOTICE: USB hub support not compiled in.\n");
+ usb_debug ("NOTICE: USB hub support not compiled in\n");
#endif
+ } else {
+ usb_debug ("hub (3.0) - not yet supported!\n");
+ }
break;
case cdc_device:
usb_debug("CDC\n");
@@ -559,8 +585,8 @@ set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
usb_debug("unsupported class %x\n", class);
break;
}
- controller->devices[adr]->init = usb_generic_init;
- return adr;
+ dev->init = usb_generic_init;
+ return dev->address;
}
/*
diff --git a/payloads/libpayload/drivers/usb/usbhid.c b/payloads/libpayload/drivers/usb/usbhid.c
index 0785df7b58..7ae40a8b35 100644
--- a/payloads/libpayload/drivers/usb/usbhid.c
+++ b/payloads/libpayload/drivers/usb/usbhid.c
@@ -449,14 +449,18 @@ usb_hid_init (usbdev_t *dev)
usb_hid_set_idle(dev, interface, KEYBOARD_REPEAT_MS);
usb_debug (" activating...\n");
- HID_INST (dev)->descriptor =
- (hid_descriptor_t *)
- get_descriptor(dev, gen_bmRequestType
- (device_to_host, standard_type, iface_recp),
- 0x21, 0, 0);
- countrycode = HID_INST(dev)->descriptor->bCountryCode;
+ hid_descriptor_t *desc = malloc(sizeof(hid_descriptor_t));
+ if (!desc || get_descriptor(dev, gen_bmRequestType(
+ device_to_host, standard_type, iface_recp),
+ 0x21, 0, desc, sizeof(*desc)) != sizeof(desc)) {
+ usb_debug ("get_descriptor(HID) failed\n");
+ usb_detach_device (dev->controller, dev->address);
+ return;
+ }
+ HID_INST (dev)->descriptor = desc;
+ countrycode = desc->bCountryCode;
/* 35 countries defined: */
- if (countrycode > 35)
+ if (countrycode >= ARRAY_SIZE(countries))
countrycode = 0;
usb_debug (" Keyboard has %s layout (country code %02x)\n",
countries[countrycode][0], countrycode);
diff --git a/payloads/libpayload/drivers/usb/usbhub.c b/payloads/libpayload/drivers/usb/usbhub.c
index 503a9a8528..e12fd92c3f 100644
--- a/payloads/libpayload/drivers/usb/usbhub.c
+++ b/payloads/libpayload/drivers/usb/usbhub.c
@@ -46,67 +46,76 @@
static int
usb_hub_port_status_changed(usbdev_t *const dev, const int port)
{
- unsigned short buf[2] = { 0, 0 };
- get_status (dev, port, DR_PORT, 4, buf);
- if (buf[1] & PORT_CONNECTION)
- clear_feature (dev, port, SEL_C_PORT_CONNECTION, DR_PORT);
- return buf[1] & PORT_CONNECTION;
+ unsigned short buf[2];
+ int ret = get_status (dev, port, DR_PORT, sizeof(buf), buf);
+ if (ret >= 0) {
+ ret = buf[1] & PORT_CONNECTION;
+ if (ret)
+ clear_feature (dev, port, SEL_C_PORT_CONNECTION,
+ DR_PORT);
+ }
+ return ret;
}
static int
usb_hub_port_connected(usbdev_t *const dev, const int port)
{
- unsigned short buf[2] = { 0, 0 };
- get_status (dev, port, DR_PORT, 4, buf);
- return buf[0] & PORT_CONNECTION;
+ unsigned short buf[2];
+ int ret = get_status (dev, port, DR_PORT, sizeof(buf), buf);
+ if (ret >= 0)
+ ret = buf[0] & PORT_CONNECTION;
+ return ret;
}
static int
usb_hub_port_in_reset(usbdev_t *const dev, const int port)
{
- unsigned short buf[2] = { 0, 0 };
- get_status (dev, port, DR_PORT, 4, buf);
- return buf[0] & PORT_RESET;
+ unsigned short buf[2];
+ int ret = get_status (dev, port, DR_PORT, sizeof(buf), buf);
+ if (ret >= 0)
+ ret = buf[0] & PORT_RESET;
+ return ret;
}
static int
usb_hub_port_enabled(usbdev_t *const dev, const int port)
{
- unsigned short buf[2] = { 0, 0 };
- get_status (dev, port, DR_PORT, 4, buf);
- return (buf[0] & PORT_ENABLE) != 0;
+ unsigned short buf[2];
+ int ret = get_status (dev, port, DR_PORT, sizeof(buf), buf);
+ if (ret >= 0)
+ ret = buf[0] & PORT_ENABLE;
+ return ret;
}
static usb_speed
usb_hub_port_speed(usbdev_t *const dev, const int port)
{
- unsigned short buf[2] = { 0, 0 };
- get_status (dev, port, DR_PORT, 4, buf);
- if (buf[0] & PORT_ENABLE) {
+ unsigned short buf[2];
+ int ret = get_status (dev, port, DR_PORT, sizeof(buf), buf);
+ if (ret >= 0 && (buf[0] & PORT_ENABLE)) {
/* bit 10 9
* 0 0 full speed
* 0 1 low speed
* 1 0 high speed
* 1 1 super speed (hack, not in spec!)
*/
- return (buf[0] >> 9) & 0x3;
+ ret = (buf[0] >> 9) & 0x3;
} else {
- return -1;
+ ret = -1;
}
+ return ret;
}
static int
usb_hub_enable_port(usbdev_t *const dev, const int port)
{
- set_feature(dev, port, SEL_PORT_POWER, DR_PORT);
- return 0;
+ return set_feature(dev, port, SEL_PORT_POWER, DR_PORT);
}
static int
usb_hub_start_port_reset(usbdev_t *const dev, const int port)
{
- set_feature (dev, port, SEL_PORT_RESET, DR_PORT);
- return 0;
+ return set_feature (dev, port, SEL_PORT_RESET, DR_PORT);
}
static const generic_hub_ops_t usb_hub_ops = {
@@ -125,17 +134,13 @@ static const generic_hub_ops_t usb_hub_ops = {
void
usb_hub_init(usbdev_t *const dev)
{
- hub_descriptor_t *const descriptor = (hub_descriptor_t *)
- get_descriptor(
- dev,
- gen_bmRequestType(device_to_host, class_type, dev_recp),
- 0x29, 0, 0);
- if (!descriptor) {
- usb_debug("usbhub: ERROR: Failed to fetch hub descriptor\n");
+ hub_descriptor_t desc; /* won't fit the whole thing, we don't care */
+ if (get_descriptor(dev, gen_bmRequestType(device_to_host, class_type,
+ dev_recp), 0x29, 0, &desc, sizeof(desc)) != sizeof(desc)) {
+ usb_debug("get_descriptor(HUB) failed\n");
+ usb_detach_device(dev->controller, dev->address);
return;
}
- const int num_ports = descriptor->bNbrPorts;
- free(descriptor);
- generic_hub_init(dev, num_ports, &usb_hub_ops);
+ generic_hub_init(dev, desc.bNbrPorts, &usb_hub_ops);
}
diff --git a/payloads/libpayload/drivers/usb/xhci_devconf.c b/payloads/libpayload/drivers/usb/xhci_devconf.c
index 2b1de3bf9e..5699499f26 100644
--- a/payloads/libpayload/drivers/usb/xhci_devconf.c
+++ b/payloads/libpayload/drivers/usb/xhci_devconf.c
@@ -75,27 +75,6 @@ xhci_get_tt(xhci_t *const xhci, const usb_speed speed,
return *tt != 0;
}
-static long
-xhci_get_mps0(usbdev_t *const dev, const int speed)
-{
- u8 buf[8];
- dev_req_t dr = {
- .bmRequestType = gen_bmRequestType(
- device_to_host, standard_type, dev_recp),
- .data_dir = device_to_host,
- .bRequest = GET_DESCRIPTOR,
- .wValue = (1 << 8),
- .wIndex = 0,
- .wLength = 8,
- };
- if (dev->controller->control(dev, IN, sizeof(dr), &dr, 8, buf)) {
- xhci_debug("Failed to read MPS0\n");
- return COMMUNICATION_ERROR;
- } else {
- return usb_decode_mps0(speed, buf[7]);
- }
-}
-
static inputctx_t *
xhci_make_inputctx(const size_t ctxsize)
{
@@ -120,14 +99,14 @@ xhci_make_inputctx(const size_t ctxsize)
return ic;
}
-int
+usbdev_t *
xhci_set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
{
xhci_t *const xhci = XHCI_INST(controller);
const size_t ctxsize = CTXSIZE(xhci);
devinfo_t *di = NULL;
-
- int i, ret = -1;
+ usbdev_t *dev = NULL;
+ int i;
inputctx_t *const ic = xhci_make_inputctx(ctxsize);
transfer_ring_t *const tr = malloc(sizeof(*tr));
@@ -193,33 +172,46 @@ xhci_set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
}
mdelay(SET_ADDRESS_MDELAY);
- init_device_entry(controller, slot_id);
- controller->devices[slot_id]->address = slot_id;
+ dev = init_device_entry(controller, slot_id);
+ if (!dev)
+ goto _disable_return;
+
+ dev->address = slot_id;
+ dev->hub = hubaddr;
+ dev->port = hubport;
+ dev->speed = speed;
+ dev->endpoints[0].dev = dev;
+ dev->endpoints[0].endpoint = 0;
+ dev->endpoints[0].toggle = 0;
+ dev->endpoints[0].direction = SETUP;
+ dev->endpoints[0].type = CONTROL;
- const long mps0 = xhci_get_mps0(
- controller->devices[slot_id], speed);
- if (mps0 < 0) {
+ u8 buf[8];
+ if (get_descriptor(dev, gen_bmRequestType(device_to_host, standard_type,
+ dev_recp), DT_DEV, 0, buf, sizeof(buf)) != sizeof(buf)) {
+ usb_debug("first get_descriptor(DT_DEV) failed\n");
goto _disable_return;
- } else if (mps0 != 8) {
+ }
+
+ dev->endpoints[0].maxpacketsize = usb_decode_mps0(speed, buf[7]);
+ if (dev->endpoints[0].maxpacketsize != 8) {
memset((void *)ic->dev.ep0, 0x00, ctxsize);
*ic->add = (1 << 1); /* EP0 Context */
- EC_SET(MPS, ic->dev.ep0, mps0);
+ EC_SET(MPS, ic->dev.ep0, dev->endpoints[0].maxpacketsize);
cc = xhci_cmd_evaluate_context(xhci, slot_id, ic);
if (cc != CC_SUCCESS) {
xhci_debug("Context evaluation failed: %d\n", cc);
goto _disable_return;
- } else {
- xhci_debug("Set MPS0 to %dB\n", mps0);
}
}
- ret = slot_id;
goto _free_ic_return;
_disable_return:
xhci_cmd_disable_slot(xhci, slot_id);
xhci->dcbaa[slot_id] = 0;
usb_detach_device(controller, slot_id);
+ dev = NULL;
_free_return:
if (tr)
free((void *)tr->ring);
@@ -231,30 +223,27 @@ _free_ic_return:
if (ic)
free(ic->raw);
free(ic);
- return ret;
+ return dev;
}
static int
xhci_finish_hub_config(usbdev_t *const dev, inputctx_t *const ic)
{
- hub_descriptor_t *const descriptor = (hub_descriptor_t *)
- get_descriptor(
- dev,
- gen_bmRequestType(device_to_host, class_type, dev_recp),
- 0x29, 0, 0);
- if (!descriptor) {
+ hub_descriptor_t desc;
+
+ if (get_descriptor(dev, gen_bmRequestType(device_to_host, class_type,
+ dev_recp), 0x29, 0, &desc, sizeof(desc)) != sizeof(desc)) {
xhci_debug("Failed to fetch hub descriptor\n");
return COMMUNICATION_ERROR;
}
SC_SET(HUB, ic->dev.slot, 1);
SC_SET(MTT, ic->dev.slot, 0); /* No support for Multi-TT */
- SC_SET(NPORTS, ic->dev.slot, descriptor->bNbrPorts);
+ SC_SET(NPORTS, ic->dev.slot, desc.bNbrPorts);
if (dev->speed == HIGH_SPEED)
SC_SET(TTT, ic->dev.slot,
- (descriptor->wHubCharacteristics >> 5) & 0x0003);
+ (desc.wHubCharacteristics >> 5) & 0x0003);
- free(descriptor);
return 0;
}
@@ -349,7 +338,7 @@ xhci_finish_device_config(usbdev_t *const dev)
ic->dev.slot->f2 = di->ctx.slot->f2;
ic->dev.slot->f3 = di->ctx.slot->f3;
- if (((device_descriptor_t *)dev->descriptor)->bDeviceClass == 0x09) {
+ if (dev->descriptor->bDeviceClass == 0x09 && dev->speed < SUPER_SPEED) {
ret = xhci_finish_hub_config(dev, ic);
if (ret)
goto _free_return;
@@ -363,8 +352,7 @@ xhci_finish_device_config(usbdev_t *const dev)
xhci_dump_inputctx(ic);
- const int config_id = ((configuration_descriptor_t *)
- dev->configuration)->bConfigurationValue;
+ const int config_id = dev->configuration->bConfigurationValue;
xhci_debug("config_id: %d\n", config_id);
const int cc =
xhci_cmd_configure_endpoint(xhci, dev->address, config_id, ic);
diff --git a/payloads/libpayload/drivers/usb/xhci_private.h b/payloads/libpayload/drivers/usb/xhci_private.h
index 096ed2b8af..09312ba3fd 100644
--- a/payloads/libpayload/drivers/usb/xhci_private.h
+++ b/payloads/libpayload/drivers/usb/xhci_private.h
@@ -470,7 +470,7 @@ typedef struct xhci {
void *xhci_align(const size_t min_align, const size_t size);
void xhci_init_cycle_ring(transfer_ring_t *, const size_t ring_size);
-int xhci_set_address (hci_t *, usb_speed speed, int hubport, int hubaddr);
+usbdev_t *xhci_set_address (hci_t *, usb_speed speed, int hubport, int hubaddr);
int xhci_finish_device_config(usbdev_t *);
void xhci_destroy_dev(hci_t *, int slot_id);
diff --git a/payloads/libpayload/include/usb/usb.h b/payloads/libpayload/include/usb/usb.h
index 83d4a85759..381d0399ed 100644
--- a/payloads/libpayload/include/usb/usb.h
+++ b/payloads/libpayload/include/usb/usb.h
@@ -39,6 +39,14 @@ typedef enum { standard_type = 0, class_type = 1, vendor_type =
typedef enum { dev_recp = 0, iface_recp = 1, endp_recp = 2, other_recp = 3
} dev_req_recp;
+enum {
+ DT_DEV = 1,
+ DT_CFG = 2,
+ DT_STR = 3,
+ DT_INTF = 4,
+ DT_ENDP = 5,
+};
+
typedef enum {
GET_STATUS = 0,
CLEAR_FEATURE = 1,
@@ -191,8 +199,8 @@ struct usbdev {
usb_speed speed;
u32 quirks; // quirks field. got to love usb
void *data;
- u8 *descriptor;
- u8 *configuration;
+ device_descriptor_t *descriptor;
+ configuration_descriptor_t *configuration;
void (*init) (usbdev_t *dev);
void (*destroy) (usbdev_t *dev);
void (*poll) (usbdev_t *dev);
@@ -230,12 +238,12 @@ struct usbdev_hc {
u8* (*poll_intr_queue) (void *queue);
void *instance;
- /* set_address(): Tell the usb device its address and
- return it. xHCI controllers want to
- do this by themself. Also, the usbdev
- structure has to be allocated and
- initialized. */
- int (*set_address) (hci_t *controller, usb_speed speed,
+ /* set_address(): Tell the usb device its address (xHCI
+ controllers want to do this by
+ themselves). Also, allocate the usbdev
+ structure, initialize enpoint 0
+ (including MPS) and return it. */
+ usbdev_t *(*set_address) (hci_t *controller, usb_speed speed,
int hubport, int hubaddr);
/* finish_device_config(): Another hook for xHCI,
returns 0 on success. */
@@ -250,12 +258,14 @@ hci_t *usb_add_mmio_hc(hc_type type, void *bar);
hci_t *new_controller (void);
void detach_controller (hci_t *controller);
void usb_poll (void);
-void init_device_entry (hci_t *controller, int num);
+usbdev_t *init_device_entry (hci_t *controller, int num);
int usb_decode_mps0 (usb_speed speed, u8 bMaxPacketSize0);
-void set_feature (usbdev_t *dev, int endp, int feature, int rtype);
-void get_status (usbdev_t *dev, int endp, int rtype, int len, void *data);
-void set_configuration (usbdev_t *dev);
+int set_feature (usbdev_t *dev, int endp, int feature, int rtype);
+int get_status (usbdev_t *dev, int endp, int rtype, int len, void *data);
+int get_descriptor (usbdev_t *dev, int rtype, int descType, int descIdx,
+ void *data, size_t len);
+int set_configuration (usbdev_t *dev);
int clear_feature (usbdev_t *dev, int endp, int feature, int rtype);
int clear_stall (endpoint_t *ep);
@@ -265,9 +275,6 @@ void usb_hid_init (usbdev_t *dev);
void usb_msc_init (usbdev_t *dev);
void usb_generic_init (usbdev_t *dev);
-u8 *get_descriptor (usbdev_t *dev, unsigned char bmRequestType,
- int descType, int descIdx, int langID);
-
static inline unsigned char
gen_bmRequestType (dev_req_dir dir, dev_req_type type, dev_req_recp recp)
{
@@ -275,7 +282,7 @@ gen_bmRequestType (dev_req_dir dir, dev_req_type type, dev_req_recp recp)
}
/* default "set address" handler */
-int generic_set_address (hci_t *controller, usb_speed speed,
+usbdev_t *generic_set_address (hci_t *controller, usb_speed speed,
int hubport, int hubaddr);
void usb_detach_device(hci_t *controller, int devno);