Signed-off-by: Kevin O'Connor <kevin(a)koconnor.net>
---
src/hw/usb-xhci.c | 74 ++++++++++++++++++++++---------------------------------
1 file changed, 29 insertions(+), 45 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c
index 3366f09..b307c5e 100644
--- a/src/hw/usb-xhci.c
+++ b/src/hw/usb-xhci.c
@@ -804,7 +804,7 @@ static struct usbhub_op_s xhci_hub_ops = {
static struct xhci_inctx *
-xhci_alloc_inctx(struct usbdevice_s *usbdev)
+xhci_alloc_inctx(struct usbdevice_s *usbdev, int maxepid)
{
struct usb_xhci_s *xhci = container_of(
usbdev->hub->cntl, struct usb_xhci_s, usb);
@@ -816,9 +816,8 @@ xhci_alloc_inctx(struct usbdevice_s *usbdev)
}
memset(in, 0, size);
- in->add = 0x01;
struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64];
- slot->ctx[0] |= (1 << 27); // context entries
+ slot->ctx[0] |= maxepid << 27; // context entries
slot->ctx[0] |= speed_to_xhci[usbdev->speed] << 20;
// Set high-speed hub flags.
@@ -859,9 +858,10 @@ static int xhci_config_hub(struct usbhub_s *hub)
if ((hdslot->ctx[3] >> 27) == 3)
// Already configured
return 0;
- struct xhci_inctx *in = xhci_alloc_inctx(hub->usbdev);
+ struct xhci_inctx *in = xhci_alloc_inctx(hub->usbdev, 1);
if (!in)
return -1;
+ in->add = 0x01;
struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64];
slot->ctx[0] |= 1 << 26;
slot->ctx[1] |= hub->portcount << 24;
@@ -911,6 +911,23 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev
if (eptype == USB_ENDPOINT_XFER_INT)
pipe->buf = malloc_low(pipe->pipe.maxpacket);
+ // Allocate input context and initialize endpoint info.
+ struct xhci_inctx *in = xhci_alloc_inctx(usbdev, epid);
+ if (!in)
+ goto fail;
+ in->add = 0x01 | (1 << epid);
+ struct xhci_epctx *ep = (void*)&in[(pipe->epid+1) << xhci->context64];
+ if (eptype == USB_ENDPOINT_XFER_INT)
+ ep->ctx[0] = (usb_getFrameExp(usbdev, epdesc) + 3) << 16;
+ ep->ctx[1] |= eptype << 3;
+ if (epdesc->bEndpointAddress & USB_DIR_IN
+ || eptype == USB_ENDPOINT_XFER_CONTROL)
+ ep->ctx[1] |= 1 << 5;
+ ep->ctx[1] |= pipe->pipe.maxpacket << 16;
+ ep->deq_low = (u32)&pipe->reqs.ring[0];
+ ep->deq_low |= 1; // dcs
+ ep->length = pipe->pipe.maxpacket;
+
dprintf(3, "%s: usbdev %p, ring %p, slotid %d, epid %d\n", __func__,
usbdev, &pipe->reqs, pipe->slotid, pipe->epid);
if (pipe->epid == 1) {
@@ -920,7 +937,7 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev
if (ret)
goto fail;
}
- // Enable slot and send set_address command.
+ // Enable slot.
u32 size = (sizeof(struct xhci_slotctx) * 32) << xhci->context64;
struct xhci_slotctx *dev = memalign_high(1024 << xhci->context64, size);
if (!dev) {
@@ -934,65 +951,32 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev
goto fail;
}
dprintf(3, "%s: enable slot: got slotid %d\n", __func__, slotid);
-
memset(dev, 0, size);
pipe->slotid = usbdev->slotid = slotid;
xhci->devs[slotid].ptr_low = (u32)dev;
xhci->devs[slotid].ptr_high = 0;
- struct xhci_inctx *in = xhci_alloc_inctx(usbdev);
- if (!in)
- goto fail;
- in->add |= (1 << 1);
-
- struct xhci_epctx *ep = (void*)&in[2 << xhci->context64];
- ep->ctx[0] |= (3 << 16); // interval: 1ms
- ep->ctx[1] |= (4 << 3); // control pipe
- ep->ctx[1] |= (pipe->pipe.maxpacket << 16);
-
- ep->deq_low = (u32)&pipe->reqs.ring[0];
- ep->deq_low |= 1; // dcs
- ep->deq_high = 0;
- ep->length = pipe->pipe.maxpacket;
-
+ // Send set_address command.
int cc = xhci_cmd_address_device(xhci, slotid, in);
- free(in);
if (cc != CC_SUCCESS) {
dprintf(1, "%s: address device: failed (cc %d)\n", __func__, cc);
goto fail;
}
} else {
- struct xhci_inctx *in = xhci_alloc_inctx(usbdev);
- if (!in)
- goto fail;
- in->add |= (1 << pipe->epid);
- struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64];
- slot->ctx[0] = (slot->ctx[0] & ~0xf8000000) | (pipe->epid << 27);
-
- struct xhci_epctx *ep = (void*)&in[(pipe->epid+1) << xhci->context64];
- if (eptype == USB_ENDPOINT_XFER_INT)
- ep->ctx[0] = (usb_getFrameExp(usbdev, epdesc) + 3) << 16;
- ep->ctx[1] |= (eptype << 3);
- if (epdesc->bEndpointAddress & USB_DIR_IN)
- ep->ctx[1] |= (1 << 5);
- ep->ctx[1] |= (pipe->pipe.maxpacket << 16);
- ep->deq_low = (u32)&pipe->reqs.ring[0];
- ep->deq_low |= 1; // dcs
- ep->deq_high = 0;
- ep->length = pipe->pipe.maxpacket;
-
pipe->slotid = usbdev->slotid;
+ // Send configure command.
int cc = xhci_cmd_configure_endpoint(xhci, pipe->slotid, in);
- free(in);
if (cc != CC_SUCCESS) {
dprintf(1, "%s: configure endpoint: failed (cc %d)\n", __func__, cc);
goto fail;
}
}
-
+ free(in);
return &pipe->pipe;
+
fail:
free(pipe);
+ free(in);
return NULL;
}
@@ -1010,11 +994,11 @@ xhci_update_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe
dprintf(3, "%s: usbdev %p, ring %p, slotid %d, epid %d\n", __func__,
usbdev, &pipe->reqs, pipe->slotid, pipe->epid);
if (eptype == USB_ENDPOINT_XFER_CONTROL &&
- pipe->pipe.maxpacket != epdesc->wMaxPacketSize) {
+ pipe->pipe.maxpacket != epdesc->wMaxPacketSize) {
dprintf(1, "%s: reconf ctl endpoint pkt size: %d -> %d\n",
__func__, pipe->pipe.maxpacket, epdesc->wMaxPacketSize);
pipe->pipe.maxpacket = epdesc->wMaxPacketSize;
- struct xhci_inctx *in = xhci_alloc_inctx(usbdev);
+ struct xhci_inctx *in = xhci_alloc_inctx(usbdev, 1);
if (!in)
return upipe;
in->add = (1 << 1);
--
1.8.5.3