diff --git a/payloads/libpayload/Config.in b/payloads/libpayload/Config.in index ecefe28215..4af3114ce0 100644 --- a/payloads/libpayload/Config.in +++ b/payloads/libpayload/Config.in @@ -400,7 +400,8 @@ config USB_XHCI_BASE_ADDRESS config USB_GEN_HUB bool - default n + default n if (!USB_HUB) + default y if (USB_HUB) endmenu diff --git a/payloads/libpayload/configs/config.bolt b/payloads/libpayload/configs/config.bolt index 1cdbb22b37..b6e566949e 100644 --- a/payloads/libpayload/configs/config.bolt +++ b/payloads/libpayload/configs/config.bolt @@ -65,6 +65,7 @@ CONFIG_LP_USB_HUB=y CONFIG_LP_USB_MSC=y CONFIG_LP_USB_PCI=y # CONFIG_LP_USB_MEMORY is not set +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y CONFIG_LP_IO_ADDRESS_SPACE=y diff --git a/payloads/libpayload/configs/config.daisy b/payloads/libpayload/configs/config.daisy index 11b84b1963..4103bfa40c 100644 --- a/payloads/libpayload/configs/config.daisy +++ b/payloads/libpayload/configs/config.daisy @@ -56,6 +56,7 @@ CONFIG_LP_USB_MSC=y CONFIG_LP_USB_MEMORY=y CONFIG_LP_USB_OHCI_BASE_ADDRESS=0x12120000 CONFIG_LP_USB_EHCI_BASE_ADDRESS=0x12110000 +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y # CONFIG_LP_IO_ADDRESS_SPACE is not set diff --git a/payloads/libpayload/configs/config.falco b/payloads/libpayload/configs/config.falco index 1cdbb22b37..b6e566949e 100644 --- a/payloads/libpayload/configs/config.falco +++ b/payloads/libpayload/configs/config.falco @@ -65,6 +65,7 @@ CONFIG_LP_USB_HUB=y CONFIG_LP_USB_MSC=y CONFIG_LP_USB_PCI=y # CONFIG_LP_USB_MEMORY is not set +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y CONFIG_LP_IO_ADDRESS_SPACE=y diff --git a/payloads/libpayload/configs/config.fox_baskingridge b/payloads/libpayload/configs/config.fox_baskingridge index 70d95b41cb..531259cbef 100644 --- a/payloads/libpayload/configs/config.fox_baskingridge +++ b/payloads/libpayload/configs/config.fox_baskingridge @@ -65,6 +65,7 @@ CONFIG_LP_USB_HUB=y CONFIG_LP_USB_MSC=y CONFIG_LP_USB_PCI=y # CONFIG_LP_USB_MEMORY is not set +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y CONFIG_LP_IO_ADDRESS_SPACE=y diff --git a/payloads/libpayload/configs/config.fox_wtm2 b/payloads/libpayload/configs/config.fox_wtm2 index 1cdbb22b37..b6e566949e 100644 --- a/payloads/libpayload/configs/config.fox_wtm2 +++ b/payloads/libpayload/configs/config.fox_wtm2 @@ -65,6 +65,7 @@ CONFIG_LP_USB_HUB=y CONFIG_LP_USB_MSC=y CONFIG_LP_USB_PCI=y # CONFIG_LP_USB_MEMORY is not set +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y CONFIG_LP_IO_ADDRESS_SPACE=y diff --git a/payloads/libpayload/configs/config.link b/payloads/libpayload/configs/config.link index 70d95b41cb..531259cbef 100644 --- a/payloads/libpayload/configs/config.link +++ b/payloads/libpayload/configs/config.link @@ -65,6 +65,7 @@ CONFIG_LP_USB_HUB=y CONFIG_LP_USB_MSC=y CONFIG_LP_USB_PCI=y # CONFIG_LP_USB_MEMORY is not set +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y CONFIG_LP_IO_ADDRESS_SPACE=y diff --git a/payloads/libpayload/configs/config.lumpy b/payloads/libpayload/configs/config.lumpy index 70d95b41cb..531259cbef 100644 --- a/payloads/libpayload/configs/config.lumpy +++ b/payloads/libpayload/configs/config.lumpy @@ -65,6 +65,7 @@ CONFIG_LP_USB_HUB=y CONFIG_LP_USB_MSC=y CONFIG_LP_USB_PCI=y # CONFIG_LP_USB_MEMORY is not set +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y CONFIG_LP_IO_ADDRESS_SPACE=y diff --git a/payloads/libpayload/configs/config.peach_kirby b/payloads/libpayload/configs/config.peach_kirby index baf2d68542..a068bdd9c1 100644 --- a/payloads/libpayload/configs/config.peach_kirby +++ b/payloads/libpayload/configs/config.peach_kirby @@ -56,6 +56,7 @@ CONFIG_LP_USB_MSC=y CONFIG_LP_USB_MEMORY=y CONFIG_LP_USB_OHCI_BASE_ADDRESS=0x12120000 CONFIG_LP_USB_EHCI_BASE_ADDRESS=0x12110000 +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y # CONFIG_LP_IO_ADDRESS_SPACE is not set diff --git a/payloads/libpayload/configs/config.peach_pit b/payloads/libpayload/configs/config.peach_pit index 69bda81366..3c63dfdf7a 100644 --- a/payloads/libpayload/configs/config.peach_pit +++ b/payloads/libpayload/configs/config.peach_pit @@ -56,6 +56,7 @@ CONFIG_LP_USB_MSC=y CONFIG_LP_USB_MEMORY=y CONFIG_LP_USB_OHCI_BASE_ADDRESS=0x12120000 CONFIG_LP_USB_EHCI_BASE_ADDRESS=0x12110000 +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y # CONFIG_LP_IO_ADDRESS_SPACE is not set diff --git a/payloads/libpayload/configs/config.peppy b/payloads/libpayload/configs/config.peppy index 1cdbb22b37..b6e566949e 100644 --- a/payloads/libpayload/configs/config.peppy +++ b/payloads/libpayload/configs/config.peppy @@ -65,6 +65,7 @@ CONFIG_LP_USB_HUB=y CONFIG_LP_USB_MSC=y CONFIG_LP_USB_PCI=y # CONFIG_LP_USB_MEMORY is not set +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y CONFIG_LP_IO_ADDRESS_SPACE=y diff --git a/payloads/libpayload/configs/config.slippy b/payloads/libpayload/configs/config.slippy index 1cdbb22b37..b6e566949e 100644 --- a/payloads/libpayload/configs/config.slippy +++ b/payloads/libpayload/configs/config.slippy @@ -65,6 +65,7 @@ CONFIG_LP_USB_HUB=y CONFIG_LP_USB_MSC=y CONFIG_LP_USB_PCI=y # CONFIG_LP_USB_MEMORY is not set +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y CONFIG_LP_IO_ADDRESS_SPACE=y diff --git a/payloads/libpayload/configs/defconfig b/payloads/libpayload/configs/defconfig index 30213d1476..a8fca141c0 100644 --- a/payloads/libpayload/configs/defconfig +++ b/payloads/libpayload/configs/defconfig @@ -72,6 +72,7 @@ CONFIG_LP_USB_HUB=y CONFIG_LP_USB_MSC=y CONFIG_LP_USB_PCI=y # CONFIG_LP_USB_MEMORY is not set +CONFIG_LP_USB_GEN_HUB=y # CONFIG_LP_BIG_ENDIAN is not set CONFIG_LP_LITTLE_ENDIAN=y CONFIG_LP_IO_ADDRESS_SPACE=y diff --git a/payloads/libpayload/drivers/usb/usbhub.c b/payloads/libpayload/drivers/usb/usbhub.c index 6ba1ed61c3..4e077f6848 100644 --- a/payloads/libpayload/drivers/usb/usbhub.c +++ b/payloads/libpayload/drivers/usb/usbhub.c @@ -1,7 +1,7 @@ /* * This file is part of the libpayload project. * - * Copyright (C) 2008-2010 coresystems GmbH + * Copyright (C) 2013 secunet Security Networks AG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,170 +30,110 @@ //#define USB_DEBUG #include +#include "generic_hub.h" -// assume that host_to_device is overwritten if necessary +/* assume that host_to_device is overwritten if necessary */ #define DR_PORT gen_bmRequestType(host_to_device, class_type, other_recp) -/* status bits */ +/* status (and status change) bits */ #define PORT_CONNECTION 0x1 #define PORT_ENABLE 0x2 #define PORT_RESET 0x10 -/* status change bits */ -#define C_PORT_CONNECTION 0x1 /* feature selectors (for setting / clearing features) */ #define SEL_PORT_RESET 0x4 #define SEL_PORT_POWER 0x8 #define SEL_C_PORT_CONNECTION 0x10 -typedef struct { - int num_ports; - int *ports; - hub_descriptor_t *descriptor; -} usbhub_inst_t; - -#define HUB_INST(dev) ((usbhub_inst_t*)(dev)->data) - -static void -usb_hub_destroy (usbdev_t *dev) +static int +usb_hub_port_status_changed(usbdev_t *const dev, const int port) { - int i; - - /* First, detach all devices behind this hub. */ - int *const ports = HUB_INST (dev)->ports; - for (i = 1; i <= HUB_INST (dev)->num_ports; i++) { - if (ports[i] != -1) { - usb_detach_device(dev->controller, ports[i]); - ports[i] = -1; - } - } - - free (HUB_INST (dev)->ports); - free (HUB_INST (dev)->descriptor); - free (HUB_INST (dev)); -} - -static void -usb_hub_scanport (usbdev_t *dev, int port) -{ - int timeout; - - unsigned short buf[2]; + unsigned short buf[2] = { 0, 0 }; get_status (dev, port, DR_PORT, 4, buf); - if (!(buf[1] & C_PORT_CONNECTION)) - /* no change */ - return; - - /* clear Port Connection status change */ - clear_feature (dev, port, SEL_C_PORT_CONNECTION, DR_PORT); - - int devno = HUB_INST (dev)->ports[port]; - if (devno != -1) { - /* detach device, either because of re-/ or disconnect */ - usb_detach_device(dev->controller, devno); - HUB_INST (dev)->ports[port] = -1; - } - - if (!(buf[0] & PORT_CONNECTION)) - /* no device connected, nothing to do */ - return; - - /* wait 100ms for port to become stable */ - mdelay (100); // usb20 spec 9.1.2 - - /* reset port */ - set_feature (dev, port, SEL_PORT_RESET, DR_PORT); - /* wait at least 10ms (usb2.0 spec 11.5.1.5: 10ms to 20ms) */ - mdelay (10); - /* wait for hub to finish reset */ - timeout = 30; /* time out after 10ms (spec) + 20ms (kindly) */ - do { - get_status (dev, port, DR_PORT, 4, buf); - mdelay(1); timeout--; - } while ((buf[0] & PORT_RESET) && timeout); - if (!timeout) - usb_debug("Warning: usbhub: port reset timed out.\n"); - - /* wait for port to be enabled. the hub is responsible for this */ - timeout = 500; /* time out after 500ms */ - do { - get_status (dev, port, DR_PORT, 4, buf); - mdelay(1); timeout--; - } while (!(buf[0] & PORT_ENABLE) && timeout); - if (!timeout) - usb_debug("Warning: usbhub: port enabling timed out.\n"); - - get_status (dev, port, DR_PORT, 4, buf); - /* bit 10 9 - * 0 0 full speed - * 0 1 low speed - * 1 0 high speed - */ - int speed = ((buf[0] >> 9) & 3) ; - - HUB_INST (dev)->ports[port] = usb_attach_device(dev->controller, dev->address, port, speed); - - /* clear Port Connection status change */ clear_feature (dev, port, SEL_C_PORT_CONNECTION, DR_PORT); + return buf[1] & PORT_CONNECTION; } static int -usb_hub_report_port_changes (usbdev_t *dev) +usb_hub_port_connected(usbdev_t *const dev, const int port) { - int port; - unsigned short buf[2]; - for (port = 1; port <= HUB_INST (dev)->num_ports; port++) { - get_status (dev, port, DR_PORT, 4, buf); - if (buf[1] & C_PORT_CONNECTION) - return port; + unsigned short buf[2] = { 0, 0 }; + get_status (dev, port, DR_PORT, 4, buf); + return buf[0] & PORT_CONNECTION; +} + +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; +} + +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; +} + +static int +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) { + /* bit 10 9 + * 0 0 full speed + * 0 1 low speed + * 1 0 high speed + */ + return (buf[0] >> 9) & 0x3; + } else { + return -1; } - - // no change - return -1; } -static void -usb_hub_enable_port (usbdev_t *dev, int port) +static int +usb_hub_enable_port(usbdev_t *const dev, const int port) { - set_feature (dev, port, SEL_PORT_POWER, DR_PORT); - mdelay (20); + set_feature(dev, port, SEL_PORT_POWER, DR_PORT); + return 0; } -#if 0 -static void -usb_hub_disable_port (usbdev_t *dev, int 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; } -#endif -static void -usb_hub_poll (usbdev_t *dev) -{ - int port; - while ((port = usb_hub_report_port_changes (dev)) != -1) - usb_hub_scanport (dev, port); -} +static const generic_hub_ops_t usb_hub_ops = { + .hub_status_changed = NULL, + .port_status_changed = usb_hub_port_status_changed, + .port_connected = usb_hub_port_connected, + .port_in_reset = usb_hub_port_in_reset, + .port_enabled = usb_hub_port_enabled, + .port_speed = usb_hub_port_speed, + .enable_port = usb_hub_enable_port, + .disable_port = NULL, + .start_port_reset = usb_hub_start_port_reset, + .reset_port = generic_hub_resetport, +}; void -usb_hub_init (usbdev_t *dev) +usb_hub_init(usbdev_t *const dev) { - int i; - dev->destroy = usb_hub_destroy; - dev->poll = usb_hub_poll; + 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"); + return; + } + const int num_ports = descriptor->bNbrPorts; + free(descriptor); - dev->data = malloc (sizeof (usbhub_inst_t)); - - if (!dev->data) - fatal("Not enough memory for USB hub.\n"); - - HUB_INST (dev)->descriptor = (hub_descriptor_t *) get_descriptor(dev, - gen_bmRequestType(device_to_host, class_type, dev_recp), 0x29, 0, 0); - HUB_INST (dev)->num_ports = HUB_INST (dev)->descriptor->bNbrPorts; - HUB_INST (dev)->ports = - malloc (sizeof (int) * (HUB_INST (dev)->num_ports + 1)); - if (! HUB_INST (dev)->ports) - fatal("Not enough memory for USB hub ports.\n"); - - for (i = 1; i <= HUB_INST (dev)->num_ports; i++) - HUB_INST (dev)->ports[i] = -1; - for (i = 1; i <= HUB_INST (dev)->num_ports; i++) - usb_hub_enable_port (dev, i); + generic_hub_init(dev, num_ports, &usb_hub_ops); }