Commit 7d2c6c95 authored by Peter Maydell's avatar Peter Maydell
Browse files

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: default avatarPeter Maydell <peter.maydell@linaro.org>
parents c1923252 7da76e12
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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;
+3 −3
Original line number Diff line number Diff line
@@ -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) */
+1 −1
Original line number Diff line number Diff line
@@ -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");
+2 −1
Original line number Diff line number Diff line
@@ -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;
}

+29 −15
Original line number Diff line number Diff line
@@ -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);
        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);
Loading