Signed-off-by: Hans de Goede <hdego...@redhat.com> --- hw/usb/hcd-uhci.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 124d43a..63f2161 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -678,6 +678,13 @@ static void uhci_wakeup(USBPort *port1) } } +static void uhci_remove_from_queue(USBPort *port, USBPacket *p) +{ + UHCIAsync *async = DO_UPCAST(UHCIAsync, packet, p); + uhci_async_unlink(async); + uhci_async_cancel(async); +} + static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr) { USBDevice *dev; @@ -818,7 +825,8 @@ out: } static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, - uint32_t *int_mask, bool queuing) + uint32_t *int_mask, bool queuing, + struct USBEndpoint **ep_ret) { UHCIAsync *async; int len = 0, max_len; @@ -862,6 +870,9 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, dev = uhci_find_device(s, (td->token >> 8) & 0x7f); ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf); + if (ep_ret) { + *ep_ret = ep; + } usb_packet_setup(&async->packet, pid, ep, addr); qemu_sglist_add(&async->sgl, td->buffer, max_len); usb_packet_map(&async->packet, &async->sgl); @@ -875,6 +886,8 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, break; case USB_TOKEN_IN: + async->packet.short_not_ok = ((td->ctrl & TD_CTRL_SPD) != 0); + async->packet.int_req = ((td->ctrl & TD_CTRL_IOC) != 0); len = usb_handle_packet(dev, &async->packet); break; @@ -975,7 +988,7 @@ static int qhdb_insert(QhDb *db, uint32_t addr) return 0; } -static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) +static void uhci_fill_queue(UHCIState *s, UHCI_TD *td, struct USBEndpoint *ep) { uint32_t int_mask = 0; uint32_t plink = td->link; @@ -984,7 +997,8 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) int ret; ptd.ctrl = td->ctrl; - while (is_valid(plink) && !(ptd.ctrl & TD_CTRL_SPD)) { + while (is_valid(plink) && + (usb_ep_input_pipeline(ep) || !(ptd.ctrl & TD_CTRL_SPD))) { pci_dma_read(&s->dev, plink & ~0xf, &ptd, sizeof(ptd)); le32_to_cpus(&ptd.link); le32_to_cpus(&ptd.ctrl); @@ -997,7 +1011,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) break; } trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token); - ret = uhci_handle_td(s, plink, &ptd, &int_mask, true); + ret = uhci_handle_td(s, plink, &ptd, &int_mask, true, NULL); if (ret == TD_RESULT_ASYNC_CONT) { break; } @@ -1005,12 +1019,14 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) assert(int_mask == 0); plink = ptd.link; } + usb_ep_process_queue(ep); } static void uhci_process_frame(UHCIState *s) { uint32_t frame_addr, link, old_td_ctrl, val, int_mask; uint32_t curr_qh, td_count = 0; + struct USBEndpoint *curr_ep; int cnt, ret; UHCI_TD td; UHCI_QH qh; @@ -1081,7 +1097,7 @@ static void uhci_process_frame(UHCIState *s) trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token); old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, link, &td, &int_mask, false); + ret = uhci_handle_td(s, link, &td, &int_mask, false, &curr_ep); if (old_td_ctrl != td.ctrl) { /* update the status bits of the TD */ val = cpu_to_le32(td.ctrl); @@ -1100,7 +1116,7 @@ static void uhci_process_frame(UHCIState *s) case TD_RESULT_ASYNC_START: trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf); - uhci_fill_queue(s, &td); + uhci_fill_queue(s, &td, curr_ep); link = curr_qh ? qh.link : td.link; continue; @@ -1202,6 +1218,7 @@ static USBPortOps uhci_port_ops = { .child_detach = uhci_child_detach, .wakeup = uhci_wakeup, .complete = uhci_async_complete, + .remove_from_queue = uhci_remove_from_queue, }; static USBBusOps uhci_bus_ops = { @@ -1238,6 +1255,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev) USBPort *ports[NB_PORTS]; for(i = 0; i < NB_PORTS; i++) { ports[i] = &s->ports[i].port; + ports[i]->supports_queuing = true; } if (usb_register_companion(s->masterbus, ports, NB_PORTS, s->firstport, s, &uhci_port_ops, @@ -1247,6 +1265,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev) } else { usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev); for (i = 0; i < NB_PORTS; i++) { + s->ports[i].port.supports_queuing = true; usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); } -- 1.7.12.1