aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-01-31 12:53:21 +0000
committerPeter Maydell <peter.maydell@linaro.org>2019-01-31 12:53:21 +0000
commitaefcd2836620363020d53b18e712a3350116f332 (patch)
tree44b3ad3fbba64a4f494463d7755daf43c8e396ff /hw
parent460da1005d90beaab09f34a802976c0539d30587 (diff)
parent49f9e8d660d41cbe325d554e742d7100d59a7abf (diff)
Merge remote-tracking branch 'remotes/kraxel/tags/usb-20190130-pull-request' into staging
usb: xhci: fix iso transfers. usb: mtp: break up writes, bugfixes. usb: fix lgpl info in headers. usb: hid: unique serials. # gpg: Signature made Wed 30 Jan 2019 07:33:21 GMT # gpg: using RSA key 4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/usb-20190130-pull-request: usb-mtp: replace the homebrew write with qemu_write_full usb-mtp: breakup MTP write into smaller chunks usb-mtp: Reallocate buffer in multiples of MTP_WRITE_BUF_SZ usb: implement XHCI underrun/overrun events usb: XHCI shall not halt isochronous endpoints hw/usb: Fix LGPL information in the file headers usb: dev-mtp: close fd in usb_mtp_object_readdir() usb: assign unique serial numbers to hid devices Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/core/machine.c3
-rw-r--r--hw/usb/combined-packet.c4
-rw-r--r--hw/usb/dev-hid.c26
-rw-r--r--hw/usb/dev-mtp.c168
-rw-r--r--hw/usb/hcd-ehci-pci.c4
-rw-r--r--hw/usb/hcd-ehci-sysbus.c4
-rw-r--r--hw/usb/hcd-ehci.c5
-rw-r--r--hw/usb/hcd-ehci.h4
-rw-r--r--hw/usb/hcd-xhci.c22
-rw-r--r--hw/usb/hcd-xhci.h1
10 files changed, 153 insertions, 88 deletions
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 2629515363..077fbd182a 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -30,6 +30,9 @@ GlobalProperty hw_compat_3_1[] = {
{ "memory-backend-memfd", "x-use-canonical-path-for-ramblock-id", "true" },
{ "tpm-crb", "ppi", "false" },
{ "tpm-tis", "ppi", "false" },
+ { "usb-kbd", "serial", "42" },
+ { "usb-mouse", "serial", "42" },
+ { "usb-kbd", "serial", "42" },
};
const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1);
diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c
index fc98383d30..37b23e20ef 100644
--- a/hw/usb/combined-packet.c
+++ b/hw/usb/combined-packet.c
@@ -9,14 +9,14 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index 90cd745f06..f9ea3033a1 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -61,10 +61,13 @@ enum {
STR_PRODUCT_MOUSE,
STR_PRODUCT_TABLET,
STR_PRODUCT_KEYBOARD,
- STR_SERIALNUMBER,
+ STR_SERIAL_COMPAT,
STR_CONFIG_MOUSE,
STR_CONFIG_TABLET,
STR_CONFIG_KEYBOARD,
+ STR_SERIAL_MOUSE,
+ STR_SERIAL_TABLET,
+ STR_SERIAL_KEYBOARD,
};
static const USBDescStrings desc_strings = {
@@ -72,10 +75,13 @@ static const USBDescStrings desc_strings = {
[STR_PRODUCT_MOUSE] = "QEMU USB Mouse",
[STR_PRODUCT_TABLET] = "QEMU USB Tablet",
[STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
- [STR_SERIALNUMBER] = "42", /* == remote wakeup works */
+ [STR_SERIAL_COMPAT] = "42",
[STR_CONFIG_MOUSE] = "HID Mouse",
[STR_CONFIG_TABLET] = "HID Tablet",
[STR_CONFIG_KEYBOARD] = "HID Keyboard",
+ [STR_SERIAL_MOUSE] = "89126",
+ [STR_SERIAL_TABLET] = "28754",
+ [STR_SERIAL_KEYBOARD] = "68284",
};
static const USBDescIface desc_iface_mouse = {
@@ -375,7 +381,7 @@ static const USBDesc desc_mouse = {
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT_MOUSE,
- .iSerialNumber = STR_SERIALNUMBER,
+ .iSerialNumber = STR_SERIAL_MOUSE,
},
.full = &desc_device_mouse,
.str = desc_strings,
@@ -389,7 +395,7 @@ static const USBDesc desc_mouse2 = {
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT_MOUSE,
- .iSerialNumber = STR_SERIALNUMBER,
+ .iSerialNumber = STR_SERIAL_MOUSE,
},
.full = &desc_device_mouse,
.high = &desc_device_mouse2,
@@ -404,7 +410,7 @@ static const USBDesc desc_tablet = {
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT_TABLET,
- .iSerialNumber = STR_SERIALNUMBER,
+ .iSerialNumber = STR_SERIAL_TABLET,
},
.full = &desc_device_tablet,
.str = desc_strings,
@@ -418,7 +424,7 @@ static const USBDesc desc_tablet2 = {
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT_TABLET,
- .iSerialNumber = STR_SERIALNUMBER,
+ .iSerialNumber = STR_SERIAL_TABLET,
},
.full = &desc_device_tablet,
.high = &desc_device_tablet2,
@@ -433,7 +439,7 @@ static const USBDesc desc_keyboard = {
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT_KEYBOARD,
- .iSerialNumber = STR_SERIALNUMBER,
+ .iSerialNumber = STR_SERIAL_KEYBOARD,
},
.full = &desc_device_keyboard,
.str = desc_strings,
@@ -447,7 +453,7 @@ static const USBDesc desc_keyboard2 = {
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT_KEYBOARD,
- .iSerialNumber = STR_SERIALNUMBER,
+ .iSerialNumber = STR_SERIAL_KEYBOARD,
},
.full = &desc_device_keyboard,
.high = &desc_device_keyboard2,
@@ -718,9 +724,7 @@ static void usb_hid_initfn(USBDevice *dev, int kind,
return;
}
- if (dev->serial) {
- usb_desc_set_string(dev, STR_SERIALNUMBER, dev->serial);
- }
+ usb_desc_create_serial(dev);
usb_desc_init(dev);
us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
hid_init(&us->hid, kind, usb_hid_changed);
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 68c5eb8eaa..f1d20fa1b9 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -25,6 +25,7 @@
#include "trace.h"
#include "hw/usb.h"
#include "desc.h"
+#include "qemu/units.h"
/* ----------------------------------------------------------------------- */
@@ -35,6 +36,13 @@ enum mtp_container_type {
TYPE_EVENT = 4,
};
+/* MTP write stage, for internal use only */
+enum mtp_write_status {
+ WRITE_START = 1,
+ WRITE_CONTINUE = 2,
+ WRITE_END = 3,
+};
+
enum mtp_code {
/* command codes */
CMD_GET_DEVICE_INFO = 0x1001,
@@ -152,8 +160,10 @@ struct MTPData {
bool first;
/* Used for >4G file sizes */
bool pending;
- uint64_t cached_length;
int fd;
+ uint8_t write_status;
+ /* Internal pointer per every MTP_WRITE_BUF_SZ */
+ uint64_t data_offset;
};
struct MTPObject {
@@ -244,6 +254,7 @@ typedef struct {
#define MTP_MANUFACTURER "QEMU"
#define MTP_PRODUCT "QEMU filesharing"
+#define MTP_WRITE_BUF_SZ (512 * KiB)
enum {
STR_MANUFACTURER = 1,
@@ -666,6 +677,7 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
}
dir = fdopendir(fd);
if (!dir) {
+ close(fd);
return;
}
#ifdef CONFIG_INOTIFY1
@@ -1618,21 +1630,28 @@ static char *utf16_to_str(uint8_t len, uint16_t *arr)
}
/* Wrapper around write, returns 0 on failure */
-static uint64_t write_retry(int fd, void *buf, uint64_t size)
+static uint64_t write_retry(int fd, void *buf, uint64_t size, off_t offset)
{
- uint64_t bytes_left = size, ret;
+ uint64_t ret = 0;
- while (bytes_left > 0) {
- ret = write(fd, buf, bytes_left);
- if ((ret == -1) && (errno != EINTR || errno != EAGAIN ||
- errno != EWOULDBLOCK)) {
- break;
- }
- bytes_left -= ret;
- buf += ret;
+ if (lseek(fd, offset, SEEK_SET) < 0) {
+ goto done;
}
- return size - bytes_left;
+ ret = qemu_write_full(fd, buf, size);
+
+done:
+ return ret;
+}
+
+static void usb_mtp_update_object(MTPObject *parent, char *name)
+{
+ MTPObject *o =
+ usb_mtp_object_lookup_name(parent, name, strlen(name));
+
+ if (o) {
+ lstat(o->path, &o->stat);
+ }
}
static void usb_mtp_write_data(MTPState *s)
@@ -1646,48 +1665,56 @@ static void usb_mtp_write_data(MTPState *s)
assert(d != NULL);
- if (parent == NULL || !s->write_pending) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, d->trans,
- 0, 0, 0, 0);
+ switch (d->write_status) {
+ case WRITE_START:
+ if (!parent || !s->write_pending) {
+ usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, d->trans,
+ 0, 0, 0, 0);
return;
- }
-
- if (s->dataset.filename) {
- path = g_strdup_printf("%s/%s", parent->path, s->dataset.filename);
- if (s->dataset.format == FMT_ASSOCIATION) {
- d->fd = mkdir(path, mask);
- goto free;
- }
- if ((s->dataset.size != 0xFFFFFFFF) && (s->dataset.size < d->length)) {
- usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
- 0, 0, 0, 0);
- goto done;
- }
- d->fd = open(path, O_CREAT | O_WRONLY | O_CLOEXEC | O_NOFOLLOW, mask);
- if (d->fd == -1) {
- usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
- 0, 0, 0, 0);
- goto done;
}
- /*
- * Return success if initiator sent 0 sized data
- */
- if (!s->dataset.size) {
- goto success;
- }
+ if (s->dataset.filename) {
+ path = g_strdup_printf("%s/%s", parent->path, s->dataset.filename);
+ if (s->dataset.format == FMT_ASSOCIATION) {
+ d->fd = mkdir(path, mask);
+ goto free;
+ }
+ d->fd = open(path, O_CREAT | O_WRONLY |
+ O_CLOEXEC | O_NOFOLLOW, mask);
+ if (d->fd == -1) {
+ usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
+ 0, 0, 0, 0);
+ goto done;
+ }
- rc = write_retry(d->fd, d->data, d->offset);
- if (rc != d->offset) {
+ /* Return success if initiator sent 0 sized data */
+ if (!s->dataset.size) {
+ goto success;
+ }
+ if (d->length != MTP_WRITE_BUF_SZ && !d->pending) {
+ d->write_status = WRITE_END;
+ }
+ }
+ /* fall through */
+ case WRITE_CONTINUE:
+ case WRITE_END:
+ rc = write_retry(d->fd, d->data, d->data_offset,
+ d->offset - d->data_offset);
+ if (rc != d->data_offset) {
usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
0, 0, 0, 0);
goto done;
+ }
+ if (d->write_status != WRITE_END) {
+ return;
+ } else {
+ /* Only for < 4G file sizes */
+ if (s->dataset.size != 0xFFFFFFFF && d->offset != s->dataset.size) {
+ usb_mtp_queue_result(s, RES_INCOMPLETE_TRANSFER, d->trans,
+ 0, 0, 0, 0);
+ goto done;
}
- /* Only for < 4G file sizes */
- if (s->dataset.size != 0xFFFFFFFF && rc != s->dataset.size) {
- usb_mtp_queue_result(s, RES_INCOMPLETE_TRANSFER, d->trans,
- 0, 0, 0, 0);
- goto done;
+ usb_mtp_update_object(parent, s->dataset.filename);
}
}
@@ -1776,37 +1803,43 @@ static void usb_mtp_get_data(MTPState *s, mtp_container *container,
total_len = cpu_to_le32(container->length) - sizeof(mtp_container);
/* Length of data in this packet */
data_len -= sizeof(mtp_container);
- usb_mtp_realloc(d, total_len);
- d->length += total_len;
+ if (total_len < MTP_WRITE_BUF_SZ) {
+ usb_mtp_realloc(d, total_len);
+ d->length += total_len;
+ } else {
+ usb_mtp_realloc(d, MTP_WRITE_BUF_SZ - sizeof(mtp_container));
+ d->length += MTP_WRITE_BUF_SZ - sizeof(mtp_container);
+ }
d->offset = 0;
- d->cached_length = total_len;
d->first = false;
d->pending = false;
+ d->data_offset = 0;
+ d->write_status = WRITE_START;
}
if (d->pending) {
- usb_mtp_realloc(d, d->cached_length);
- d->length += d->cached_length;
+ memset(d->data, 0, d->length);
+ if (d->length != MTP_WRITE_BUF_SZ) {
+ usb_mtp_realloc(d, MTP_WRITE_BUF_SZ - d->length);
+ d->length += (MTP_WRITE_BUF_SZ - d->length);
+ }
d->pending = false;
+ d->write_status = WRITE_CONTINUE;
+ d->data_offset = 0;
}
- if (d->length - d->offset > data_len) {
+ if (d->length - d->data_offset > data_len) {
dlen = data_len;
} else {
- dlen = d->length - d->offset;
- /* Check for cached data for large files */
- if ((s->dataset.size == 0xFFFFFFFF) && (dlen < p->iov.size)) {
- usb_mtp_realloc(d, p->iov.size - dlen);
- d->length += p->iov.size - dlen;
- dlen = p->iov.size;
- }
+ dlen = d->length - d->data_offset;
}
switch (d->code) {
case CMD_SEND_OBJECT_INFO:
- usb_packet_copy(p, d->data + d->offset, dlen);
+ usb_packet_copy(p, d->data + d->data_offset, dlen);
d->offset += dlen;
- if (d->offset == d->length) {
+ d->data_offset += dlen;
+ if (d->data_offset == d->length) {
/* The operation might have already failed */
if (!s->result) {
usb_mtp_write_metadata(s, dlen);
@@ -1817,19 +1850,26 @@ static void usb_mtp_get_data(MTPState *s, mtp_container *container,
}
break;
case CMD_SEND_OBJECT:
- usb_packet_copy(p, d->data + d->offset, dlen);
+ usb_packet_copy(p, d->data + d->data_offset, dlen);
d->offset += dlen;
+ d->data_offset += dlen;
if ((p->iov.size % 64) || !p->iov.size) {
assert((s->dataset.size == 0xFFFFFFFF) ||
- (s->dataset.size == d->length));
+ (s->dataset.size == d->offset));
+ if (d->length == MTP_WRITE_BUF_SZ) {
+ d->write_status = WRITE_END;
+ } else {
+ d->write_status = WRITE_START;
+ }
usb_mtp_write_data(s);
usb_mtp_data_free(s->data_out);
s->data_out = NULL;
return;
}
- if (d->offset == d->length) {
+ if (d->data_offset == d->length) {
d->pending = true;
+ usb_mtp_write_data(s);
}
break;
default:
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index 69abbf7b7b..38b24b160a 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -4,14 +4,14 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
index 331faf8bc3..9f7f128f19 100644
--- a/hw/usb/hcd-ehci-sysbus.c
+++ b/hw/usb/hcd-ehci-sysbus.c
@@ -4,14 +4,14 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index e233681962..9b132cb0d3 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -12,18 +12,17 @@
* Niels de Vos. David S. Ahern continued working on it. Kevin Wolf,
* Jan Kiszka and Vincent Palatin contributed bugfixes.
*
- *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index d6601706ee..fedf82c611 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -4,14 +4,14 @@
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 8f1a01a405..19c64f7ff4 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1571,6 +1571,11 @@ static void xhci_stall_ep(XHCITransfer *xfer)
uint32_t err;
XHCIStreamContext *sctx;
+ if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) {
+ /* never halt isoch endpoints, 4.10.2 */
+ return;
+ }
+
if (epctx->nr_pstreams) {
sctx = xhci_find_stream(epctx, xfer->streamid, &err);
if (sctx == NULL) {
@@ -1944,6 +1949,16 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
while (1) {
length = xhci_ring_chain_length(xhci, ring);
if (length <= 0) {
+ if (epctx->type == ET_ISO_OUT || epctx->type == ET_ISO_IN) {
+ /* 4.10.3.1 */
+ XHCIEvent ev = { ER_TRANSFER };
+ ev.ccode = epctx->type == ET_ISO_IN ?
+ CC_RING_OVERRUN : CC_RING_UNDERRUN;
+ ev.slotid = epctx->slotid;
+ ev.epid = epctx->epid;
+ ev.ptr = epctx->ring.dequeue;
+ xhci_event(xhci, &ev, xhci->slots[epctx->slotid-1].intr);
+ }
break;
}
xfer = xhci_ep_alloc_xfer(epctx, length);
@@ -2023,6 +2038,7 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
xhci->slots[slotid-1].enabled = 0;
xhci->slots[slotid-1].addressed = 0;
xhci->slots[slotid-1].uport = NULL;
+ xhci->slots[slotid-1].intr = 0;
return CC_SUCCESS;
}
@@ -2122,6 +2138,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
slot = &xhci->slots[slotid-1];
slot->uport = uport;
slot->ctx = octx;
+ slot->intr = get_field(slot_ctx[2], TRB_INTR);
/* Make sure device is in USB_STATE_DEFAULT state */
usb_device_reset(dev);
@@ -2295,8 +2312,9 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
slot_ctx[1] &= ~0xFFFF; /* max exit latency */
slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
- slot_ctx[2] &= ~0xFF00000; /* interrupter target */
- slot_ctx[2] |= islot_ctx[2] & 0xFF000000;
+ /* update interrupter target field */
+ xhci->slots[slotid-1].intr = get_field(islot_ctx[2], TRB_INTR);
+ set_field(&slot_ctx[2], xhci->slots[slotid-1].intr, TRB_INTR);
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h
index fc36a4c787..240caa4e51 100644
--- a/hw/usb/hcd-xhci.h
+++ b/hw/usb/hcd-xhci.h
@@ -140,6 +140,7 @@ typedef struct XHCIPort {
typedef struct XHCISlot {
bool enabled;
bool addressed;
+ uint16_t intr;
dma_addr_t ctx;
USBPort *uport;
XHCIEPContext *eps[31];