aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-02-06 11:44:08 +0000
committerPeter Maydell <peter.maydell@linaro.org>2017-02-06 11:44:08 +0000
commit7d2c6c95511e42dffe2b263275e09957723d0ff4 (patch)
treeb35733bdd9ea20a32fe2a3dcd96055880c856f1b
parentc192325242f0040a9c3d245f843bb5552b391c15 (diff)
parent7da76e12cc5cc902dda4c168d8d608fd4e61cbc5 (diff)
Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20170206-1' into staging
usb: various bugfixes, mostly xhci. # gpg: Signature made Mon 06 Feb 2017 11:26:35 GMT # gpg: using RSA key 0x4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/pull-usb-20170206-1: xhci: fix event queue IRQ handling usb: ccid: check ccid apdu length xhci: guard xhci_kick_epctx against recursive calls xhci: don't kick in xhci_submit and xhci_fire_ctl_transfer xhci: rename xhci_complete_packet to xhci_try_complete_packet xhci: only free completed transfers usb: accept usb3 control requests usb/uas: more verbose error message hw/usb/dev-hid: Improve guest compatibility of usb-tablet Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/usb/desc.c7
-rw-r--r--hw/usb/dev-hid.c6
-rw-r--r--hw/usb/dev-smartcard-reader.c2
-rw-r--r--hw/usb/dev-uas.c3
-rw-r--r--hw/usb/hcd-xhci.c44
-rw-r--r--include/hw/usb.h2
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