diff options
Diffstat (limited to 'payloads')
-rw-r--r-- | payloads/libpayload/drivers/usb/quirks.c | 9 | ||||
-rw-r--r-- | payloads/libpayload/drivers/usb/usb.c | 368 | ||||
-rw-r--r-- | payloads/libpayload/drivers/usb/usbhid.c | 18 | ||||
-rw-r--r-- | payloads/libpayload/drivers/usb/usbhub.c | 71 | ||||
-rw-r--r-- | payloads/libpayload/drivers/usb/xhci_devconf.c | 82 | ||||
-rw-r--r-- | payloads/libpayload/drivers/usb/xhci_private.h | 2 | ||||
-rw-r--r-- | payloads/libpayload/include/usb/usb.h | 39 |
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); |