aboutsummaryrefslogtreecommitdiff
path: root/hw/usb
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb')
-rw-r--r--hw/usb/bus.c8
-rw-r--r--hw/usb/core.c4
-rw-r--r--hw/usb/hcd-ehci.c4
-rw-r--r--hw/usb/hcd-musb.c1
-rw-r--r--hw/usb/hcd-ohci.c2
-rw-r--r--hw/usb/hcd-uhci.c16
-rw-r--r--hw/usb/hcd-xhci.c6
7 files changed, 36 insertions, 5 deletions
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index b649360..8066291 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -181,6 +181,14 @@ void usb_device_set_interface(USBDevice *dev, int interface,
}
}
+void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->flush_ep_queue) {
+ klass->flush_ep_queue(dev, ep);
+ }
+}
+
static int usb_qdev_init(DeviceState *qdev)
{
USBDevice *dev = USB_DEVICE(qdev);
diff --git a/hw/usb/core.c b/hw/usb/core.c
index e2e31ca..014e3ac 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -393,6 +393,10 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
if (ret == USB_RET_ASYNC) {
usb_packet_set_state(p, USB_PACKET_ASYNC);
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
+ } else if (ret == USB_RET_ADD_TO_QUEUE) {
+ usb_packet_set_state(p, USB_PACKET_QUEUED);
+ QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
+ ret = USB_RET_ASYNC;
} else {
/*
* When pipelining is enabled usb-devices must always return async,
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index a02fe96..d11311e 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -2072,6 +2072,7 @@ static int ehci_state_horizqh(EHCIQueue *q)
static int ehci_fill_queue(EHCIPacket *p)
{
+ USBEndpoint *ep = p->packet.ep;
EHCIQueue *q = p->queue;
EHCIqtd qtd = p->qtd;
uint32_t qtdaddr, start_addr = p->qtdaddr;
@@ -2107,6 +2108,9 @@ static int ehci_fill_queue(EHCIPacket *p)
assert(p->usb_status == USB_RET_ASYNC);
p->async = EHCI_ASYNC_INFLIGHT;
}
+ if (p->usb_status != USB_RET_PROCERR) {
+ usb_device_flush_ep_queue(ep->dev, ep);
+ }
return p->usb_status;
}
diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c
index dc114fe..212dd12 100644
--- a/hw/usb/hcd-musb.c
+++ b/hw/usb/hcd-musb.c
@@ -635,6 +635,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ret = usb_handle_packet(dev, &ep->packey[dir].p);
if (ret == USB_RET_ASYNC) {
+ usb_device_flush_ep_queue(dev, uep);
ep->status[dir] = len;
return;
}
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index 0cc1e5d..31dcfbb 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -816,6 +816,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret == USB_RET_ASYNC) {
+ usb_device_flush_ep_queue(dev, ep);
return 1;
}
}
@@ -1018,6 +1019,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
DPRINTF("ret=%d\n", ret);
#endif
if (ret == USB_RET_ASYNC) {
+ usb_device_flush_ep_queue(dev, ep);
ohci->async_td = addr;
return 1;
}
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 600d095..46e544b 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -818,7 +818,8 @@ out:
}
static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
- uint32_t *int_mask, bool queuing)
+ uint32_t *int_mask, bool queuing,
+ struct USBEndpoint **ep_ret)
{
UHCIAsync *async;
int len = 0, max_len;
@@ -870,6 +871,9 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
+ if (ep_ret) {
+ *ep_ret = ep;
+ }
usb_packet_setup(&async->packet, pid, ep, addr);
qemu_sglist_add(&async->sgl, td->buffer, max_len);
usb_packet_map(&async->packet, &async->sgl);
@@ -983,7 +987,7 @@ static int qhdb_insert(QhDb *db, uint32_t addr)
return 0;
}
-static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
+static void uhci_fill_queue(UHCIState *s, UHCI_TD *td, struct USBEndpoint *ep)
{
uint32_t int_mask = 0;
uint32_t plink = td->link;
@@ -1005,7 +1009,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
break;
}
trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
- ret = uhci_handle_td(s, plink, &ptd, &int_mask, true);
+ ret = uhci_handle_td(s, plink, &ptd, &int_mask, true, NULL);
if (ret == TD_RESULT_ASYNC_CONT) {
break;
}
@@ -1013,12 +1017,14 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
assert(int_mask == 0);
plink = ptd.link;
}
+ usb_device_flush_ep_queue(ep->dev, ep);
}
static void uhci_process_frame(UHCIState *s)
{
uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
uint32_t curr_qh, td_count = 0;
+ struct USBEndpoint *curr_ep;
int cnt, ret;
UHCI_TD td;
UHCI_QH qh;
@@ -1089,7 +1095,7 @@ static void uhci_process_frame(UHCIState *s)
trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
old_td_ctrl = td.ctrl;
- ret = uhci_handle_td(s, link, &td, &int_mask, false);
+ ret = uhci_handle_td(s, link, &td, &int_mask, false, &curr_ep);
if (old_td_ctrl != td.ctrl) {
/* update the status bits of the TD */
val = cpu_to_le32(td.ctrl);
@@ -1108,7 +1114,7 @@ static void uhci_process_frame(UHCIState *s)
case TD_RESULT_ASYNC_START:
trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
- uhci_fill_queue(s, &td);
+ uhci_fill_queue(s, &td, curr_ep);
link = curr_qh ? qh.link : td.link;
continue;
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 47d5702..e8929a0 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1652,6 +1652,7 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
{
XHCIEPContext *epctx;
+ USBEndpoint *ep = NULL;
uint64_t mfindex;
int length;
int i;
@@ -1745,12 +1746,14 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
if (epid == 1) {
if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
+ ep = xfer->packet.ep;
} else {
fprintf(stderr, "xhci: error firing CTL transfer\n");
}
} else {
if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) {
epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
+ ep = xfer->packet.ep;
} else {
if (!xfer->iso_xfer) {
fprintf(stderr, "xhci: error firing data transfer\n");
@@ -1767,6 +1770,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
break;
}
}
+ if (ep) {
+ usb_device_flush_ep_queue(ep->dev, ep);
+ }
}
static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid)