[Core Change] Port USB fixes from XQEMU 1.x

commit 761d06bab6
Author: espes <espes@pequalsnp.com>
Date:   Thu Sep 5 01:45:37 2013 +1000

ohci: fix handling of transfer underruns

See:
https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Devices/USB/DevOHCI.cpp#L2343
https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Devices/USB/DevOHCI.cpp#L2363

commit d532051a8e
Author: espes <espes@pequalsnp.com>
Date:   Mon Oct 19 17:38:38 2015 +1100

usb hub: don't return an overrun when there's no new status
This commit is contained in:
Matt Borgerson 2018-06-26 12:27:43 -07:00
parent eb4c0f18e9
commit 0ed317ff4b
2 changed files with 17 additions and 13 deletions

View File

@ -477,13 +477,6 @@ static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
unsigned int status;
uint8_t buf[4];
int i, n;
n = DIV_ROUND_UP(NUM_PORTS + 1, 8);
if (p->iov.size == 1) { /* FreeBSD workaround */
n = 1;
} else if (n > p->iov.size) {
p->status = USB_RET_BABBLE;
return;
}
status = 0;
for(i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
@ -491,6 +484,13 @@ static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
status |= (1 << (i + 1));
}
if (status != 0) {
n = DIV_ROUND_UP(NUM_PORTS + 1, 8);
if (p->iov.size == 1) { /* FreeBSD workaround */
n = 1;
} else if (n > p->iov.size) {
p->status = USB_RET_BABBLE;
return;
}
trace_usb_hub_status_report(s->dev.addr, status);
for(i = 0; i < n; i++) {
buf[i] = status >> (8 * i);

View File

@ -1102,17 +1102,19 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
}
if (ret >= 0) {
if ((td.cbp & 0xfff) + ret > 0xfff) {
td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff);
} else {
td.cbp += ret;
}
}
/* Writeback */
if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
/* Transmission succeeded. */
if (ret == len) {
td.cbp = 0;
} else {
if ((td.cbp & 0xfff) + ret > 0xfff) {
td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff);
} else {
td.cbp += ret;
}
}
td.flags |= OHCI_TD_T1;
td.flags ^= OHCI_TD_T0;
@ -1168,6 +1170,8 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
i = OHCI_BM(td.flags, TD_DI);
if (i < ohci->done_count)
ohci->done_count = i;
if (OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR)
ohci->done_count = 0;
exit_no_retire:
if (ohci_put_td(ohci, addr, &td)) {
ohci_die(ohci);