diff options
author | Julius Werner <jwerner@chromium.org> | 2013-09-17 22:16:04 -0700 |
---|---|---|
committer | Isaac Christensen <isaac.christensen@se-eng.com> | 2014-09-04 01:59:15 +0200 |
commit | d13e2c4ab769e526e6b2c0ae568bd84b34688c58 (patch) | |
tree | cfe914006c840264d6a1ca97004c7aecf250ab96 /payloads/libpayload/include | |
parent | e231de2134440eedb00136a5a373480c5d4ec209 (diff) | |
download | coreboot-d13e2c4ab769e526e6b2c0ae568bd84b34688c58.tar.xz |
libpayload: usb: Refactor USB enumeration to fix SuperSpeed devices
This patch represents a major overhaul of the USB enumeration code in
order to make it cleaner and much more robust to weird or malicious
devices. The main improvement is that it correctly parses the USB
descriptors even if there are unknown descriptors interspersed within,
which is perfectly legal and in particular present on all SuperSpeed
devices (due to the SuperSpeed Endpoint Companion Descriptor).
In addition, it gets rid of the really whacky and special cased
get_descriptor() function, which would read every descriptor twice
whether it made sense or not. The new code makes the callers allocate
descriptor memory and only read stuff twice when it's really necessary
(i.e. the device and configuration descriptors).
Finally, it also moves some more responsibilities into the
controller-specific set_address() function in order to make sure things
are initialized at the same stage for all controllers. In the new model
it initializes the device entry (which zeroes the endpoint array), sets
up endpoint 0 (including MPS), sets the device address and finally
returns the whole usbdev_t structure with that address correctly set.
Note that this should make SuperSpeed devices work, but SuperSpeed hubs
are a wholly different story and would require a custom hub driver
(since the hub descriptor and port status formats are different for USB
3.0 ports, and the whole issue about the same hub showing up as two
different devices on two different ports might present additional
challenges). The stack currently just issues a warning and refuses to
initialize this part of the hub, which means that 3.0 devices connected
through a 3.0 hub may not work correctly.
Change-Id: Ie0b82dca23b7a750658ccc1a85f9daae5fbc20e1
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/170666
Reviewed-by: Kees Cook <keescook@chromium.org>
(cherry picked from commit ecec80e062f7efe32a9a17479dcf8cb678a4a98b)
Signed-off-by: Isaac Christensen <isaac.christensen@se-eng.com>
Reviewed-on: http://review.coreboot.org/6780
Tested-by: build bot (Jenkins)
Diffstat (limited to 'payloads/libpayload/include')
-rw-r--r-- | payloads/libpayload/include/usb/usb.h | 39 |
1 files changed, 23 insertions, 16 deletions
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); |