aboutsummaryrefslogtreecommitdiff
path: root/hw/usb/core.c
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2012-10-29 10:34:29 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2012-10-29 10:34:29 -0500
commit6b0e6468e33883c1739a7474fe6baca170eec9aa (patch)
treec4d388d560aa72376c848746b38336f857934955 /hw/usb/core.c
parent90c45b30319dee7d4137f18817395454728ea2f9 (diff)
parent0ebfb144e8ad3f2da436d630fdcc5aa9ab646341 (diff)
Merge remote-tracking branch 'kraxel/usb.68' into staging
* kraxel/usb.68: (36 commits) xhci: fix usb name in caps xhci: make number of interrupters and slots configurable xhci: allow disabling interrupters xhci: flush endpoint context unconditinally xhci: fix function name in error message uhci: Use only one queue for ctrl endpoints uhci: Retry to fill the queue while waiting for td completion uhci: Always mark a queue valid when we encounter it uhci: When the guest marks a pending td non-active, cancel the queue uhci: Detect guest td re-use uhci: Verify queue has not been changed by guest uhci: Immediately free queues on device disconnect uhci: Store ep in UHCIQueue uhci: Make uhci_fill_queue() actually operate on an UHCIQueue uhci: Add uhci_read_td() helper function uhci: Rename UHCIAsync->td to UHCIAsync->td_addr uhci: Move emptying of the queue's asyncs' queue to uhci_queue_free uhci: Drop unnecessary forward declaration of some static functions uhci: Don't retry on error uhci: cleanup: Add an unlink call to uhci_async_cancel() ... Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/usb/core.c')
-rw-r--r--hw/usb/core.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/hw/usb/core.c b/hw/usb/core.c
index b9f1f7a8be..632a8efe47 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -391,8 +391,13 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
ret = usb_process_one(p);
if (ret == USB_RET_ASYNC) {
+ assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
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,
@@ -412,13 +417,14 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
return ret;
}
-static void __usb_packet_complete(USBDevice *dev, USBPacket *p)
+void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
{
USBEndpoint *ep = p->ep;
+ assert(QTAILQ_FIRST(&ep->queue) == p);
assert(p->result != USB_RET_ASYNC && p->result != USB_RET_NAK);
- if (p->result < 0) {
+ if (p->result < 0 || (p->short_not_ok && (p->result < p->iov.size))) {
ep->halted = true;
}
usb_packet_set_state(p, USB_PACKET_COMPLETE);
@@ -435,11 +441,16 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
int ret;
usb_packet_check_state(p, USB_PACKET_ASYNC);
- assert(QTAILQ_FIRST(&ep->queue) == p);
- __usb_packet_complete(dev, p);
+ usb_packet_complete_one(dev, p);
- while (!ep->halted && !QTAILQ_EMPTY(&ep->queue)) {
+ while (!QTAILQ_EMPTY(&ep->queue)) {
p = QTAILQ_FIRST(&ep->queue);
+ if (ep->halted) {
+ /* Empty the queue on a halt */
+ p->result = USB_RET_REMOVE_FROM_QUEUE;
+ dev->port->ops->complete(dev->port, p);
+ continue;
+ }
if (p->state == USB_PACKET_ASYNC) {
break;
}
@@ -450,7 +461,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
break;
}
p->result = ret;
- __usb_packet_complete(ep->dev, p);
+ usb_packet_complete_one(ep->dev, p);
}
}
@@ -522,7 +533,8 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state)
p->state = state;
}
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id)
+void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
+ bool short_not_ok, bool int_req)
{
assert(!usb_packet_is_inflight(p));
assert(p->iov.iov != NULL);
@@ -531,6 +543,8 @@ void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id)
p->ep = ep;
p->result = 0;
p->parameter = 0;
+ p->short_not_ok = short_not_ok;
+ p->int_req = int_req;
qemu_iovec_reset(&p->iov);
usb_packet_set_state(p, USB_PACKET_SETUP);
}