usb: various bugfixes, mostly xhci.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJYmF1rAAoJEEy22O7T6HE4UQgP/RGWAnt4dJAk3SDzZilYexS7
 rol3cNAUuhLI/sV6syh8paFdSiD0+mDw8h0n+QLS+bgP50WmRhu4xJTHpnzWdXfV
 7EGvZI2Gnjy2XMccr5q8hfSragI8MJKgUkW/32v9nvTmA+1lnvK2t6PeSjhwD7zf
 WTsdv7mi3D5LMbCCtTCy7X0ojIHZ009nU9sroz8KEzF752j6NRLiCn7UfRjT+m24
 IHYhUX2TLU7dw+TzhnQPzFalaZMj0mGowtP517Ugw3lsXxtxsRStpKmp5Js0+d4N
 amH/PPmZmaESfrv3OKvcZ6C4VCCgXAWa88nQZt1oST5/oQbskNYR+SS/rHUL4JJ0
 Y4Ta0euwQGwCJVyFhOHJPoZM64L+3SzeQJQXNAiiYxy9427y+UZ+VA2ffHpUr3+4
 zc6x9Jc43+l0YE9eRlkwv8dr7S3xzWoMqaUJag941VRg0M6F+Ox74r9dnFC9UW+L
 JIP4wFMGnJflSQsl6KlAaGd+sUnArOcwZHIyp47TauEx4bGoUeVzTbvz8a+VZ+22
 rkMdR5JuHbw65fjxfAXgaqxmEA8+eYzyjO4CbWmBdcuZbIhrDRvUcBCTSQaxVg8T
 nrBesIsHKFTuKywHGHrpli1d9SqO9tOo9nM3voD+mpKXeTLYtJ1/2RX6487JkTob
 flY8/lupvCLEtzXH3Fyg
 =gltI
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2017-02-06 11:44:08 +00:00
commit 7d2c6c9551
6 changed files with 44 additions and 20 deletions

View File

@ -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;

View File

@ -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) */

View File

@ -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");

View File

@ -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;
}

View File

@ -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);

View File

@ -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