Revision 7c605a23 hw/usb-xhci.c
b/hw/usb-xhci.c | ||
---|---|---|
307 | 307 |
typedef struct XHCITransfer { |
308 | 308 |
XHCIState *xhci; |
309 | 309 |
USBPacket packet; |
310 |
bool running; |
|
310 |
bool running_async; |
|
311 |
bool running_retry; |
|
311 | 312 |
bool cancelled; |
312 | 313 |
bool complete; |
313 | 314 |
bool backgrounded; |
... | ... | |
338 | 339 |
unsigned int next_xfer; |
339 | 340 |
unsigned int comp_xfer; |
340 | 341 |
XHCITransfer transfers[TD_QUEUE]; |
342 |
XHCITransfer *retry; |
|
341 | 343 |
bool bg_running; |
342 | 344 |
bool bg_updating; |
343 | 345 |
unsigned int next_bg; |
... | ... | |
915 | 917 |
xferi = epctx->next_xfer; |
916 | 918 |
for (i = 0; i < TD_QUEUE; i++) { |
917 | 919 |
XHCITransfer *t = &epctx->transfers[xferi]; |
918 |
if (t->running) { |
|
920 |
if (t->running_async) { |
|
921 |
usb_cancel_packet(&t->packet); |
|
922 |
t->running_async = 0; |
|
919 | 923 |
t->cancelled = 1; |
920 |
/* libusb_cancel_transfer(t->usbxfer) */ |
|
921 | 924 |
DPRINTF("xhci: cancelling transfer %d, waiting for it to complete...\n", i); |
922 | 925 |
killed++; |
923 | 926 |
} |
927 |
if (t->running_retry) { |
|
928 |
t->running_retry = 0; |
|
929 |
epctx->retry = NULL; |
|
930 |
} |
|
924 | 931 |
if (t->backgrounded) { |
925 | 932 |
t->backgrounded = 0; |
926 | 933 |
} |
... | ... | |
941 | 948 |
xferi = epctx->next_bg; |
942 | 949 |
for (i = 0; i < BG_XFERS; i++) { |
943 | 950 |
XHCITransfer *t = &epctx->bg_transfers[xferi]; |
944 |
if (t->running) { |
|
951 |
if (t->running_async) { |
|
952 |
usb_cancel_packet(&t->packet); |
|
953 |
t->running_async = 0; |
|
945 | 954 |
t->cancelled = 1; |
946 |
/* libusb_cancel_transfer(t->usbxfer); */ |
|
947 | 955 |
DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i); |
948 | 956 |
killed++; |
949 | 957 |
} |
... | ... | |
1409 | 1417 |
static int xhci_complete_packet(XHCITransfer *xfer, int ret) |
1410 | 1418 |
{ |
1411 | 1419 |
if (ret == USB_RET_ASYNC) { |
1412 |
xfer->running = 1; |
|
1420 |
xfer->running_async = 1; |
|
1421 |
xfer->running_retry = 0; |
|
1422 |
xfer->complete = 0; |
|
1423 |
xfer->cancelled = 0; |
|
1424 |
return 0; |
|
1425 |
} else if (ret == USB_RET_NAK) { |
|
1426 |
xfer->running_async = 0; |
|
1427 |
xfer->running_retry = 1; |
|
1413 | 1428 |
xfer->complete = 0; |
1414 | 1429 |
xfer->cancelled = 0; |
1415 | 1430 |
return 0; |
1416 | 1431 |
} else { |
1417 |
xfer->running = 0; |
|
1432 |
xfer->running_async = 0; |
|
1433 |
xfer->running_retry = 0; |
|
1418 | 1434 |
xfer->complete = 1; |
1419 | 1435 |
} |
1420 | 1436 |
|
... | ... | |
1529 | 1545 |
wValue, wIndex, wLength, xfer->data); |
1530 | 1546 |
|
1531 | 1547 |
xhci_complete_packet(xfer, ret); |
1532 |
if (!xfer->running) { |
|
1548 |
if (!xfer->running_async && !xfer->running_retry) {
|
|
1533 | 1549 |
xhci_kick_ep(xhci, xfer->slotid, xfer->epid); |
1534 | 1550 |
} |
1535 | 1551 |
return 0; |
... | ... | |
1596 | 1612 |
ret = usb_handle_packet(dev, &xfer->packet); |
1597 | 1613 |
|
1598 | 1614 |
xhci_complete_packet(xfer, ret); |
1599 |
if (!xfer->running) { |
|
1615 |
if (!xfer->running_async && !xfer->running_retry) {
|
|
1600 | 1616 |
xhci_kick_ep(xhci, xfer->slotid, xfer->epid); |
1601 | 1617 |
} |
1602 | 1618 |
return 0; |
... | ... | |
1667 | 1683 |
return; |
1668 | 1684 |
} |
1669 | 1685 |
|
1686 |
if (epctx->retry) { |
|
1687 |
/* retry nak'ed transfer */ |
|
1688 |
XHCITransfer *xfer = epctx->retry; |
|
1689 |
int result; |
|
1690 |
|
|
1691 |
DPRINTF("xhci: retry nack'ed transfer ...\n"); |
|
1692 |
assert(xfer->running_retry); |
|
1693 |
xhci_setup_packet(xfer, xfer->packet.ep->dev); |
|
1694 |
result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); |
|
1695 |
if (result == USB_RET_NAK) { |
|
1696 |
DPRINTF("xhci: ... xfer still nacked\n"); |
|
1697 |
return; |
|
1698 |
} |
|
1699 |
DPRINTF("xhci: ... result %d\n", result); |
|
1700 |
xhci_complete_packet(xfer, result); |
|
1701 |
assert(!xfer->running_retry); |
|
1702 |
epctx->retry = NULL; |
|
1703 |
} |
|
1704 |
|
|
1670 | 1705 |
if (epctx->state == EP_HALTED) { |
1671 | 1706 |
DPRINTF("xhci: ep halted, not running schedule\n"); |
1672 | 1707 |
return; |
... | ... | |
1676 | 1711 |
|
1677 | 1712 |
while (1) { |
1678 | 1713 |
XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; |
1679 |
if (xfer->running || xfer->backgrounded) { |
|
1680 |
DPRINTF("xhci: ep is busy\n"); |
|
1714 |
if (xfer->running_async || xfer->running_retry || xfer->backgrounded) { |
|
1715 |
DPRINTF("xhci: ep is busy (#%d,%d,%d,%d)\n", |
|
1716 |
epctx->next_xfer, xfer->running_async, |
|
1717 |
xfer->running_retry, xfer->backgrounded); |
|
1681 | 1718 |
break; |
1719 |
} else { |
|
1720 |
DPRINTF("xhci: ep: using #%d\n", epctx->next_xfer); |
|
1682 | 1721 |
} |
1683 | 1722 |
length = xhci_ring_chain_length(xhci, &epctx->ring); |
1684 | 1723 |
if (length < 0) { |
... | ... | |
1725 | 1764 |
DPRINTF("xhci: ep halted, stopping schedule\n"); |
1726 | 1765 |
break; |
1727 | 1766 |
} |
1767 |
if (xfer->running_retry) { |
|
1768 |
DPRINTF("xhci: xfer nacked, stopping schedule\n"); |
|
1769 |
epctx->retry = xfer; |
|
1770 |
break; |
|
1771 |
} |
|
1728 | 1772 |
|
1729 | 1773 |
/* |
1730 | 1774 |
* Qemu usb can't handle multiple in-flight xfers. |
... | ... | |
2739 | 2783 |
.child_detach = xhci_child_detach, |
2740 | 2784 |
}; |
2741 | 2785 |
|
2786 |
static int xhci_find_slotid(XHCIState *xhci, USBDevice *dev) |
|
2787 |
{ |
|
2788 |
XHCISlot *slot; |
|
2789 |
int slotid; |
|
2790 |
|
|
2791 |
for (slotid = 1; slotid <= MAXSLOTS; slotid++) { |
|
2792 |
slot = &xhci->slots[slotid-1]; |
|
2793 |
if (slot->devaddr == dev->addr) { |
|
2794 |
return slotid; |
|
2795 |
} |
|
2796 |
} |
|
2797 |
return 0; |
|
2798 |
} |
|
2799 |
|
|
2800 |
static int xhci_find_epid(USBEndpoint *ep) |
|
2801 |
{ |
|
2802 |
if (ep->nr == 0) { |
|
2803 |
return 1; |
|
2804 |
} |
|
2805 |
if (ep->pid == USB_TOKEN_IN) { |
|
2806 |
return ep->nr * 2 + 1; |
|
2807 |
} else { |
|
2808 |
return ep->nr * 2; |
|
2809 |
} |
|
2810 |
} |
|
2811 |
|
|
2812 |
static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep) |
|
2813 |
{ |
|
2814 |
XHCIState *xhci = container_of(bus, XHCIState, bus); |
|
2815 |
int slotid; |
|
2816 |
|
|
2817 |
DPRINTF("%s\n", __func__); |
|
2818 |
slotid = xhci_find_slotid(xhci, ep->dev); |
|
2819 |
if (slotid == 0 || !xhci->slots[slotid-1].enabled) { |
|
2820 |
DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr); |
|
2821 |
return; |
|
2822 |
} |
|
2823 |
xhci_kick_ep(xhci, slotid, xhci_find_epid(ep)); |
|
2824 |
} |
|
2825 |
|
|
2742 | 2826 |
static USBBusOps xhci_bus_ops = { |
2827 |
.wakeup_endpoint = xhci_wakeup_endpoint, |
|
2743 | 2828 |
}; |
2744 | 2829 |
|
2745 | 2830 |
static void usb_xhci_init(XHCIState *xhci, DeviceState *dev) |
Also available in: Unified diff