diff options
-rw-r--r-- | hw/usb/desc.c | 7 | ||||
-rw-r--r-- | hw/usb/dev-hid.c | 6 | ||||
-rw-r--r-- | hw/usb/dev-smartcard-reader.c | 2 | ||||
-rw-r--r-- | hw/usb/dev-uas.c | 3 | ||||
-rw-r--r-- | hw/usb/hcd-xhci.c | 44 | ||||
-rw-r--r-- | include/hw/usb.h | 2 |
6 files changed, 44 insertions, 20 deletions
diff --git a/hw/usb/desc.c b/hw/usb/desc.c index 7828e52c6f..c36bf30e4f 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -774,6 +774,13 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, trace_usb_set_device_feature(dev->addr, value, ret); break; + case DeviceOutRequest | USB_REQ_SET_SEL: + case DeviceOutRequest | USB_REQ_SET_ISOCH_DELAY: + if (dev->speed == USB_SPEED_SUPER) { + ret = 0; + } + break; + case InterfaceRequest | USB_REQ_GET_INTERFACE: if (index < 0 || index >= dev->ninterfaces) { break; diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 24d05f76f9..dda0bf0df0 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -144,7 +144,7 @@ static const USBDescIface desc_iface_tablet = { .bInterfaceNumber = 0, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_HID, - .bInterfaceProtocol = 0x02, + .bInterfaceProtocol = 0x00, .ndesc = 1, .descs = (USBDescOther[]) { { @@ -174,7 +174,7 @@ static const USBDescIface desc_iface_tablet2 = { .bInterfaceNumber = 0, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_HID, - .bInterfaceProtocol = 0x02, + .bInterfaceProtocol = 0x00, .ndesc = 1, .descs = (USBDescOther[]) { { @@ -487,7 +487,7 @@ static const uint8_t qemu_mouse_hid_report_descriptor[] = { static const uint8_t qemu_tablet_hid_report_descriptor[] = { 0x05, 0x01, /* Usage Page (Generic Desktop) */ - 0x09, 0x01, /* Usage (Pointer) */ + 0x09, 0x02, /* Usage (Mouse) */ 0xa1, 0x01, /* Collection (Application) */ 0x09, 0x01, /* Usage (Pointer) */ 0xa1, 0x00, /* Collection (Physical) */ diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index 89e11b68c4..1325ea1659 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -967,7 +967,7 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv) DPRINTF(s, 1, "%s: seq %d, len %d\n", __func__, recv->hdr.bSeq, len); ccid_add_pending_answer(s, (CCID_Header *)recv); - if (s->card) { + if (s->card && len <= BULK_OUT_DATA_SIZE) { ccid_card_apdu_from_guest(s->card, recv->abData, len); } else { DPRINTF(s, D_WARN, "warning: discarded apdu\n"); diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 3a8ff18b1b..da2fb7017e 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -653,7 +653,8 @@ static void usb_uas_handle_control(USBDevice *dev, USBPacket *p, if (ret >= 0) { return; } - error_report("%s: unhandled control request", __func__); + error_report("%s: unhandled control request (req 0x%x, val 0x%x, idx 0x%x", + __func__, request, value, index); p->status = USB_RET_STALL; } diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index f8106789d8..54b3901c8c 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -390,6 +390,7 @@ struct XHCIEPContext { dma_addr_t pctx; unsigned int max_psize; uint32_t state; + uint32_t kick_active; /* streams */ unsigned int max_pstreams; @@ -788,11 +789,15 @@ static void xhci_msix_update(XHCIState *xhci, int v) static void xhci_intr_raise(XHCIState *xhci, int v) { PCIDevice *pci_dev = PCI_DEVICE(xhci); + bool pending = (xhci->intr[v].erdp_low & ERDP_EHB); xhci->intr[v].erdp_low |= ERDP_EHB; xhci->intr[v].iman |= IMAN_IP; xhci->usbsts |= USBSTS_EINT; + if (pending) { + return; + } if (!(xhci->intr[v].iman & IMAN_IE)) { return; } @@ -1897,7 +1902,7 @@ static int xhci_setup_packet(XHCITransfer *xfer) return 0; } -static int xhci_complete_packet(XHCITransfer *xfer) +static int xhci_try_complete_packet(XHCITransfer *xfer) { if (xfer->packet.status == USB_RET_ASYNC) { trace_usb_xhci_xfer_async(xfer); @@ -2001,11 +2006,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) xfer->packet.parameter = trb_setup->parameter; usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - - xhci_complete_packet(xfer); - if (!xfer->running_async && !xfer->running_retry) { - xhci_kick_epctx(xfer->epctx, 0); - } + xhci_try_complete_packet(xfer); return 0; } @@ -2105,11 +2106,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx return -1; } usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - - xhci_complete_packet(xfer); - if (!xfer->running_async && !xfer->running_retry) { - xhci_kick_epctx(xfer->epctx, xfer->streamid); - } + xhci_try_complete_packet(xfer); return 0; } @@ -2139,6 +2136,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, return; } + if (epctx->kick_active) { + return; + } xhci_kick_epctx(epctx, streamid); } @@ -2154,6 +2154,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) int i; trace_usb_xhci_ep_kick(epctx->slotid, epctx->epid, streamid); + assert(!epctx->kick_active); /* If the device has been detached, but the guest has not noticed this yet the 2 above checks will succeed, but we must NOT continue */ @@ -2185,7 +2186,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) } usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); assert(xfer->packet.status != USB_RET_NAK); - xhci_complete_packet(xfer); + xhci_try_complete_packet(xfer); } else { /* retry nak'ed transfer */ if (xhci_setup_packet(xfer) < 0) { @@ -2195,10 +2196,12 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) if (xfer->packet.status == USB_RET_NAK) { return; } - xhci_complete_packet(xfer); + xhci_try_complete_packet(xfer); } assert(!xfer->running_retry); - xhci_ep_free_xfer(epctx->retry); + if (xfer->complete) { + xhci_ep_free_xfer(epctx->retry); + } epctx->retry = NULL; } @@ -2223,6 +2226,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) } assert(ring->dequeue != 0); + epctx->kick_active++; while (1) { length = xhci_ring_chain_length(xhci, ring); if (length <= 0) { @@ -2259,6 +2263,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) break; } } + epctx->kick_active--; ep = xhci_epid_to_usbep(epctx); if (ep) { @@ -3351,6 +3356,15 @@ static void xhci_runtime_write(void *ptr, hwaddr reg, intr->erdp_low &= ~ERDP_EHB; } intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB); + if (val & ERDP_EHB) { + dma_addr_t erdp = xhci_addr64(intr->erdp_low, intr->erdp_high); + unsigned int dp_idx = (erdp - intr->er_start) / TRB_SIZE; + if (erdp >= intr->er_start && + erdp < (intr->er_start + TRB_SIZE * intr->er_size) && + dp_idx != intr->er_ep_idx) { + xhci_intr_raise(xhci, v); + } + } break; case 0x1c: /* ERDP high */ intr->erdp_high = val; @@ -3490,7 +3504,7 @@ static void xhci_complete(USBPort *port, USBPacket *packet) xhci_ep_nuke_one_xfer(xfer, 0); return; } - xhci_complete_packet(xfer); + xhci_try_complete_packet(xfer); xhci_kick_epctx(xfer->epctx, xfer->streamid); if (xfer->complete) { xhci_ep_free_xfer(xfer); diff --git a/include/hw/usb.h b/include/hw/usb.h index 43838c9f5d..c42b29c866 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h @@ -135,6 +135,8 @@ #define USB_REQ_GET_INTERFACE 0x0A #define USB_REQ_SET_INTERFACE 0x0B #define USB_REQ_SYNCH_FRAME 0x0C +#define USB_REQ_SET_SEL 0x30 +#define USB_REQ_SET_ISOCH_DELAY 0x31 #define USB_DEVICE_SELF_POWERED 0 #define USB_DEVICE_REMOTE_WAKEUP 1 |