Revision 01e26b0e
b/hw/usb/hcd-ehci.c | ||
---|---|---|
29 | 29 |
|
30 | 30 |
#include "hw/usb/hcd-ehci.h" |
31 | 31 |
|
32 |
/* internal processing - reset HC to try and recover */ |
|
33 |
#define USB_RET_PROCERR (-99) |
|
34 |
|
|
35 | 32 |
/* Capability Registers Base Address - section 2.2 */ |
36 | 33 |
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */ |
37 | 34 |
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */ |
... | ... | |
1111 | 1108 |
while (bytes > 0) { |
1112 | 1109 |
if (cpage > 4) { |
1113 | 1110 |
fprintf(stderr, "cpage out of range (%d)\n", cpage); |
1114 |
return USB_RET_PROCERR;
|
|
1111 |
return -1;
|
|
1115 | 1112 |
} |
1116 | 1113 |
|
1117 | 1114 |
page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK; |
... | ... | |
1248 | 1245 |
} |
1249 | 1246 |
} |
1250 | 1247 |
|
1251 |
// 4.10.3 |
|
1252 |
|
|
1248 |
/* 4.10.3 returns "again" */ |
|
1253 | 1249 |
static int ehci_execute(EHCIPacket *p, const char *action) |
1254 | 1250 |
{ |
1255 | 1251 |
USBEndpoint *ep; |
... | ... | |
1261 | 1257 |
|
1262 | 1258 |
if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) { |
1263 | 1259 |
fprintf(stderr, "Attempting to execute inactive qtd\n"); |
1264 |
return USB_RET_PROCERR;
|
|
1260 |
return -1;
|
|
1265 | 1261 |
} |
1266 | 1262 |
|
1267 | 1263 |
if (get_field(p->qtd.token, QTD_TOKEN_TBYTES) > BUFF_SIZE) { |
1268 | 1264 |
ehci_trace_guest_bug(p->queue->ehci, |
1269 | 1265 |
"guest requested more bytes than allowed"); |
1270 |
return USB_RET_PROCERR;
|
|
1266 |
return -1;
|
|
1271 | 1267 |
} |
1272 | 1268 |
|
1273 | 1269 |
p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH; |
... | ... | |
1291 | 1287 |
|
1292 | 1288 |
if (p->async == EHCI_ASYNC_NONE) { |
1293 | 1289 |
if (ehci_init_transfer(p) != 0) { |
1294 |
return USB_RET_PROCERR;
|
|
1290 |
return -1;
|
|
1295 | 1291 |
} |
1296 | 1292 |
|
1297 | 1293 |
spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0); |
... | ... | |
1310 | 1306 |
|
1311 | 1307 |
if (p->packet.actual_length > BUFF_SIZE) { |
1312 | 1308 |
fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n"); |
1313 |
return USB_RET_PROCERR;
|
|
1309 |
return -1;
|
|
1314 | 1310 |
} |
1315 | 1311 |
|
1316 |
if (p->packet.status == USB_RET_SUCCESS) { |
|
1317 |
return p->packet.actual_length; |
|
1318 |
} else { |
|
1319 |
return p->packet.status; |
|
1320 |
} |
|
1312 |
return 1; |
|
1321 | 1313 |
} |
1322 | 1314 |
|
1323 | 1315 |
/* 4.7.2 |
... | ... | |
1352 | 1344 |
} |
1353 | 1345 |
|
1354 | 1346 |
if (len > BUFF_SIZE) { |
1355 |
return USB_RET_PROCERR;
|
|
1347 |
return -1;
|
|
1356 | 1348 |
} |
1357 | 1349 |
|
1358 | 1350 |
qemu_sglist_init(&ehci->isgl, 2, ehci->dma); |
... | ... | |
1752 | 1744 |
break; |
1753 | 1745 |
case EHCI_ASYNC_INFLIGHT: |
1754 | 1746 |
/* Check if the guest has added new tds to the queue */ |
1755 |
again = (ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head)) == |
|
1756 |
USB_RET_PROCERR) ? -1 : 1; |
|
1747 |
again = ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head)); |
|
1757 | 1748 |
/* Unfinished async handled packet, go horizontal */ |
1758 | 1749 |
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); |
1759 | 1750 |
break; |
... | ... | |
1790 | 1781 |
return again; |
1791 | 1782 |
} |
1792 | 1783 |
|
1784 |
/* Returns "again" */ |
|
1793 | 1785 |
static int ehci_fill_queue(EHCIPacket *p) |
1794 | 1786 |
{ |
1795 | 1787 |
USBEndpoint *ep = p->packet.ep; |
... | ... | |
1818 | 1810 |
p = ehci_alloc_packet(q); |
1819 | 1811 |
p->qtdaddr = qtdaddr; |
1820 | 1812 |
p->qtd = qtd; |
1821 |
p->usb_status = ehci_execute(p, "queue"); |
|
1822 |
if (p->usb_status == USB_RET_PROCERR) { |
|
1823 |
break; |
|
1813 |
if (ehci_execute(p, "queue") == -1) { |
|
1814 |
return -1; |
|
1824 | 1815 |
} |
1825 |
assert(p->usb_status == USB_RET_ASYNC);
|
|
1816 |
assert(p->packet.status == USB_RET_ASYNC);
|
|
1826 | 1817 |
p->async = EHCI_ASYNC_INFLIGHT; |
1827 | 1818 |
} |
1828 |
if (p->usb_status != USB_RET_PROCERR) { |
|
1829 |
usb_device_flush_ep_queue(ep->dev, ep); |
|
1830 |
} |
|
1831 |
return p->usb_status; |
|
1819 |
usb_device_flush_ep_queue(ep->dev, ep); |
|
1820 |
return 1; |
|
1832 | 1821 |
} |
1833 | 1822 |
|
1834 | 1823 |
static int ehci_state_execute(EHCIQueue *q) |
... | ... | |
1857 | 1846 |
ehci_set_usbsts(q->ehci, USBSTS_REC); |
1858 | 1847 |
} |
1859 | 1848 |
|
1860 |
p->usb_status = ehci_execute(p, "process"); |
|
1861 |
if (p->usb_status == USB_RET_PROCERR) { |
|
1862 |
again = -1; |
|
1849 |
again = ehci_execute(p, "process"); |
|
1850 |
if (again == -1) { |
|
1863 | 1851 |
goto out; |
1864 | 1852 |
} |
1865 |
if (p->usb_status == USB_RET_ASYNC) {
|
|
1853 |
if (p->packet.status == USB_RET_ASYNC) {
|
|
1866 | 1854 |
ehci_flush_qh(q); |
1867 | 1855 |
trace_usb_ehci_packet_action(p->queue, p, "async"); |
1868 | 1856 |
p->async = EHCI_ASYNC_INFLIGHT; |
1869 | 1857 |
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); |
1870 | 1858 |
if (q->async) { |
1871 |
again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
|
|
1859 |
again = ehci_fill_queue(p);
|
|
1872 | 1860 |
} else { |
1873 | 1861 |
again = 1; |
1874 | 1862 |
} |
1875 | 1863 |
goto out; |
1876 | 1864 |
} |
1865 |
if (p->packet.status == USB_RET_SUCCESS) { |
|
1866 |
p->usb_status = p->packet.actual_length; |
|
1867 |
} else { |
|
1868 |
p->usb_status = p->packet.status; |
|
1869 |
} |
|
1877 | 1870 |
|
1878 | 1871 |
ehci_set_state(q->ehci, q->async, EST_EXECUTING); |
1879 | 1872 |
again = 1; |
Also available in: Unified diff