aboutsummaryrefslogtreecommitdiffstats
path: root/hw/usb-ehci.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb-ehci.c')
-rw-r--r--hw/usb-ehci.c71
1 files changed, 32 insertions, 39 deletions
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index e69981430..afc8ccf45 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -912,6 +912,7 @@ static void ehci_reset(void *opaque)
}
}
ehci_queues_rip_all(s);
+ qemu_del_timer(s->frame_timer);
}
static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
@@ -1070,7 +1071,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
if (val & USBCMD_HCRESET) {
ehci_reset(s);
- val &= ~USBCMD_HCRESET;
+ val = s->usbcmd;
}
/* not supporting dynamic frame list size at the moment */
@@ -1458,44 +1459,22 @@ static int ehci_process_itd(EHCIState *ehci,
dev = ehci_find_device(ehci, devaddr);
ep = usb_ep_get(dev, pid, endp);
- usb_packet_setup(&ehci->ipacket, pid, ep);
- usb_packet_map(&ehci->ipacket, &ehci->isgl);
-
- ret = usb_handle_packet(dev, &ehci->ipacket);
-
- usb_packet_unmap(&ehci->ipacket);
- qemu_sglist_destroy(&ehci->isgl);
-
-#if 0
- /* In isoch, there is no facility to indicate a NAK so let's
- * instead just complete a zero-byte transaction. Setting
- * DBERR seems too draconian.
- */
-
- if (ret == USB_RET_NAK) {
- if (ehci->isoch_pause > 0) {
- DPRINTF("ISOCH: received a NAK but paused so returning\n");
- ehci->isoch_pause--;
- return 0;
- } else if (ehci->isoch_pause == -1) {
- DPRINTF("ISOCH: recv NAK & isoch pause inactive, setting\n");
- // Pause frindex for up to 50 msec waiting for data from
- // remote
- ehci->isoch_pause = 50;
- return 0;
- } else {
- DPRINTF("ISOCH: isoch pause timeout! return 0\n");
- ret = 0;
- }
+ if (ep->type == USB_ENDPOINT_XFER_ISOC) {
+ usb_packet_setup(&ehci->ipacket, pid, ep);
+ usb_packet_map(&ehci->ipacket, &ehci->isgl);
+ ret = usb_handle_packet(dev, &ehci->ipacket);
+ assert(ret != USB_RET_ASYNC);
+ usb_packet_unmap(&ehci->ipacket);
} else {
- DPRINTF("ISOCH: received ACK, clearing pause\n");
- ehci->isoch_pause = -1;
+ DPRINTF("ISOCH: attempt to addess non-iso endpoint\n");
+ ret = USB_RET_NAK;
}
-#else
+ qemu_sglist_destroy(&ehci->isgl);
+
if (ret == USB_RET_NAK) {
+ /* no data for us, so do a zero-length transfer */
ret = 0;
}
-#endif
if (ret >= 0) {
if (!dir) {
@@ -1505,11 +1484,27 @@ static int ehci_process_itd(EHCIState *ehci,
/* IN */
set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
}
-
- if (itd->transact[i] & ITD_XACT_IOC) {
- ehci_record_interrupt(ehci, USBSTS_INT);
+ } else {
+ switch (ret) {
+ default:
+ fprintf(stderr, "Unexpected iso usb result: %d\n", ret);
+ /* Fall through */
+ case USB_RET_NODEV:
+ /* 3.3.2: XACTERR is only allowed on IN transactions */
+ if (dir) {
+ itd->transact[i] |= ITD_XACT_XACTERR;
+ ehci_record_interrupt(ehci, USBSTS_ERRINT);
+ }
+ break;
+ case USB_RET_BABBLE:
+ itd->transact[i] |= ITD_XACT_BABBLE;
+ ehci_record_interrupt(ehci, USBSTS_ERRINT);
+ break;
}
}
+ if (itd->transact[i] & ITD_XACT_IOC) {
+ ehci_record_interrupt(ehci, USBSTS_INT);
+ }
itd->transact[i] &= ~ITD_XACT_ACTIVE;
}
}
@@ -2368,8 +2363,6 @@ static int usb_ehci_initfn(PCIDevice *dev)
memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE);
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
- fprintf(stderr, "*** EHCI support is under development ***\n");
-
return 0;
}