[SeaBIOS] [PATCH] xhci: Hack to get hubs working.
Kevin O'Connor
kevin at koconnor.net
Mon Dec 30 02:30:29 CET 2013
Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
This patch is for testing. It allows me to use low speed devices
behind a high speed hub attached to an xhci controller.
Interestingly, high speed devices behind a high speed hub didn't
require any changes on my xhci controller. I don't have a super speed
hub to test with.
I've also pushed this to:
https://github.com/KevinOConnor/seabios/tree/xhci-testing
---
src/hw/usb-xhci.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 57 insertions(+), 10 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c
index 4529724..78ad03c 100644
--- a/src/hw/usb-xhci.c
+++ b/src/hw/usb-xhci.c
@@ -818,24 +818,65 @@ xhci_alloc_inctx(struct usbdevice_s *usbdev)
}
memset(in, 0, size);
- u32 route = 0;
- while (usbdev->hub->usbdev) {
- route <<= 4;
- route |= (usbdev->port+1) & 0xf;
- usbdev = usbdev->hub->usbdev;
- }
-
in->add = 0x01;
struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64];
slot->ctx[0] |= (1 << 27); // context entries
slot->ctx[0] |= speed_to_xhci[usbdev->speed] << 20;
- slot->ctx[0] |= route;
+
+ // Set high-speed hub flags.
+ struct usbdevice_s *hubdev = usbdev->hub->usbdev;
+ if (hubdev) {
+ if (usbdev->speed == USB_LOWSPEED || usbdev->speed == USB_FULLSPEED) {
+ struct xhci_pipe *hpipe = container_of(
+ hubdev->defpipe, struct xhci_pipe, pipe);
+ if (hubdev->speed == USB_HIGHSPEED) {
+ slot->ctx[2] |= hpipe->slotid;
+ slot->ctx[2] |= (usbdev->port+1) << 8;
+ } else {
+ struct xhci_slotctx *hslot = (void*)xhci->devs[hpipe->slotid].ptr_low;
+ slot->ctx[2] = hslot->ctx[2];
+ }
+ }
+ u32 route = 0;
+ while (usbdev->hub->usbdev) {
+ route <<= 4;
+ route |= (usbdev->port+1) & 0xf;
+ usbdev = usbdev->hub->usbdev;
+ }
+ slot->ctx[0] |= route;
+ }
+
slot->ctx[1] |= (usbdev->port+1) << 16;
- /* TODO ctx0: hub bit */
- /* TODO ctx1: hub ports */
+
return in;
}
+static int xhci_config_hub(struct usbhub_s *hub)
+{
+ struct usb_xhci_s *xhci = container_of(
+ hub->cntl, struct usb_xhci_s, usb);
+ struct xhci_pipe *pipe = container_of(
+ hub->usbdev->defpipe, struct xhci_pipe, pipe);
+ struct xhci_slotctx *hdslot = (void*)xhci->devs[pipe->slotid].ptr_low;
+ if ((hdslot->ctx[3] >> 27) == 3)
+ // Already configured
+ return 0;
+ struct xhci_inctx *in = xhci_alloc_inctx(hub->usbdev);
+ if (!in)
+ return -1;
+ struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64];
+ slot->ctx[0] |= 1 << 26;
+ slot->ctx[1] |= hub->portcount << 24;
+
+ int cc = xhci_cmd_configure_endpoint(xhci, pipe->slotid, in);
+ free(in);
+ if (cc != CC_SUCCESS) {
+ dprintf(1, "%s: configure hub: failed (cc %d)\n", __func__, cc);
+ return -1;
+ }
+ return 0;
+}
+
struct usb_pipe *
xhci_alloc_pipe(struct usbdevice_s *usbdev
, struct usb_endpoint_descriptor *epdesc)
@@ -875,6 +916,12 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev
dprintf(3, "%s: usbdev %p, ring %p, slotid %d, epid %d\n", __func__,
usbdev, &pipe->reqs, pipe->slotid, pipe->epid);
if (pipe->epid == 1) {
+ if (usbdev->hub->usbdev) {
+ // Ugly hack to enable hub ports.
+ int ret = xhci_config_hub(usbdev->hub);
+ if (ret)
+ goto fail;
+ }
// Enable slot and send set_address command.
u32 size = (sizeof(struct xhci_slotctx) * 32) << xhci->context64;
struct xhci_slotctx *dev = memalign_high(1024 << xhci->context64, size);
--
1.8.3.1
More information about the SeaBIOS
mailing list