* [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs.
@ 2011-07-18 15:51 Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 1/9] Add iov_hexdump() Gerd Hoffmann
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Gerd Hoffmann @ 2011-07-18 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Hi,
This patch series introduces iovecs to the USB subsystem, usb packet
payload is passed around as iovec instead of a linear buffer. This
allows the host controllers to use scatter lists and to pass on data
buffers directly, so we can avoid an extra copy.
please review,
Gerd
Gerd Hoffmann (9):
Add iov_hexdump()
Add iov_clear()
move QEMUSGList typedef
usb: use iovecs in USBPacket
usb-serial: iovec support
usb-host: iovec support
usb-storage: iovec support
uhci: remove buffer
ehci: iovec support, remove buffer
Makefile.objs | 1 +
dma.h | 4 +-
hw/bt-hid.c | 16 +++---
hw/milkymist-softusb.c | 8 +-
hw/usb-bt.c | 31 ++++------
hw/usb-ccid.c | 46 ++++++++------
hw/usb-ehci.c | 160 ++++++++++++++++++++----------------------------
hw/usb-hid.c | 6 +-
hw/usb-hub.c | 8 ++-
hw/usb-libhw.c | 63 +++++++++++++++++++
hw/usb-msd.c | 109 ++++++++++++++++-----------------
hw/usb-musb.c | 22 +++---
hw/usb-net.c | 65 +++++++-------------
hw/usb-ohci.c | 23 +++----
hw/usb-serial.c | 26 +++++---
hw/usb-uhci.c | 51 +++++++--------
hw/usb-wacom.c | 6 +-
hw/usb.c | 86 +++++++++++++++++++++----
hw/usb.h | 13 +++-
iov.c | 54 ++++++++++++++++
iov.h | 4 +
qemu-common.h | 1 +
usb-linux.c | 48 +++++++++------
23 files changed, 500 insertions(+), 351 deletions(-)
create mode 100644 hw/usb-libhw.c
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 1/9] Add iov_hexdump()
2011-07-18 15:51 [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs Gerd Hoffmann
@ 2011-07-18 15:51 ` Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 2/9] Add iov_clear() Gerd Hoffmann
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gerd Hoffmann @ 2011-07-18 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Useful for debugging purposes.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
iov.c | 31 +++++++++++++++++++++++++++++++
iov.h | 2 ++
2 files changed, 33 insertions(+), 0 deletions(-)
diff --git a/iov.c b/iov.c
index 1e02791..60553c7 100644
--- a/iov.c
+++ b/iov.c
@@ -73,3 +73,34 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
}
return len;
}
+
+void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
+ FILE *fp, const char *prefix, size_t limit)
+{
+ unsigned int i, v, b;
+ uint8_t *c;
+
+ c = iov[0].iov_base;
+ for (i = 0, v = 0, b = 0; b < limit; i++, b++) {
+ if (i == iov[v].iov_len) {
+ i = 0; v++;
+ if (v == iov_cnt) {
+ break;
+ }
+ c = iov[v].iov_base;
+ }
+ if ((b % 16) == 0) {
+ fprintf(fp, "%s: %04x:", prefix, b);
+ }
+ if ((b % 4) == 0) {
+ fprintf(fp, " ");
+ }
+ fprintf(fp, " %02x", c[i]);
+ if ((b % 16) == 15) {
+ fprintf(fp, "\n");
+ }
+ }
+ if ((b % 16) != 0) {
+ fprintf(fp, "\n");
+ }
+}
diff --git a/iov.h b/iov.h
index 110f67a..c2c5b39 100644
--- a/iov.h
+++ b/iov.h
@@ -17,3 +17,5 @@ size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
void *buf, size_t iov_off, size_t size);
size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
+void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
+ FILE *fp, const char *prefix, size_t limit);
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 2/9] Add iov_clear()
2011-07-18 15:51 [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 1/9] Add iov_hexdump() Gerd Hoffmann
@ 2011-07-18 15:51 ` Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 3/9] move QEMUSGList typedef Gerd Hoffmann
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gerd Hoffmann @ 2011-07-18 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Fill the spefified area with zeros.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
iov.c | 23 +++++++++++++++++++++++
iov.h | 2 ++
2 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/iov.c b/iov.c
index 60553c7..e7385c4 100644
--- a/iov.c
+++ b/iov.c
@@ -62,6 +62,29 @@ size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
return buf_off;
}
+size_t iov_clear(const struct iovec *iov, const unsigned int iov_cnt,
+ size_t iov_off, size_t size)
+{
+ size_t iovec_off, buf_off;
+ unsigned int i;
+
+ iovec_off = 0;
+ buf_off = 0;
+ for (i = 0; i < iov_cnt && size; i++) {
+ if (iov_off < (iovec_off + iov[i].iov_len)) {
+ size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size);
+
+ memset(iov[i].iov_base + (iov_off - iovec_off), 0, len);
+
+ buf_off += len;
+ iov_off += len;
+ size -= len;
+ }
+ iovec_off += iov[i].iov_len;
+ }
+ return buf_off;
+}
+
size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
{
size_t len;
diff --git a/iov.h b/iov.h
index c2c5b39..94d2f78 100644
--- a/iov.h
+++ b/iov.h
@@ -17,5 +17,7 @@ size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
void *buf, size_t iov_off, size_t size);
size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
+size_t iov_clear(const struct iovec *iov, const unsigned int iov_cnt,
+ size_t iov_off, size_t size);
void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
FILE *fp, const char *prefix, size_t limit);
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 3/9] move QEMUSGList typedef
2011-07-18 15:51 [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 1/9] Add iov_hexdump() Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 2/9] Add iov_clear() Gerd Hoffmann
@ 2011-07-18 15:51 ` Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 4/9] usb: use iovecs in USBPacket Gerd Hoffmann
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gerd Hoffmann @ 2011-07-18 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Move the QEMUSGList typedef to qemu-common so it can easily be used.
The actual struct definition stays in dma.h.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
dma.h | 4 ++--
qemu-common.h | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/dma.h b/dma.h
index 3d8324b..a6db5ba 100644
--- a/dma.h
+++ b/dma.h
@@ -20,12 +20,12 @@ typedef struct {
target_phys_addr_t len;
} ScatterGatherEntry;
-typedef struct {
+struct QEMUSGList {
ScatterGatherEntry *sg;
int nsg;
int nalloc;
target_phys_addr_t size;
-} QEMUSGList;
+};
void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint);
void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
diff --git a/qemu-common.h b/qemu-common.h
index abd7a75..565b4b6 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -284,6 +284,7 @@ typedef struct I2SCodec I2SCodec;
typedef struct SSIBus SSIBus;
typedef struct EventNotifier EventNotifier;
typedef struct VirtIODevice VirtIODevice;
+typedef struct QEMUSGList QEMUSGList;
typedef uint64_t pcibus_t;
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 4/9] usb: use iovecs in USBPacket
2011-07-18 15:51 [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs Gerd Hoffmann
` (2 preceding siblings ...)
2011-07-18 15:51 ` [Qemu-devel] [PATCH 3/9] move QEMUSGList typedef Gerd Hoffmann
@ 2011-07-18 15:51 ` Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 5/9] usb-serial: iovec support Gerd Hoffmann
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gerd Hoffmann @ 2011-07-18 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Zap data pointer from USBPacket, add a QEMUIOVector instead.
Add a bunch of helper functions to manage USBPacket data.
Switch over users to the new interface.
Note that USBPacket->len was used for two purposes: First to
pass in the buffer size and second to return the number of
transfered bytes or the status code on async transfers. There
is a new result variable for the latter. A new status code
was added to catch uninitialized result.
Nobody creates iovecs with more than one element (yet).
Some users are (temporarely) limited to iovecs with a single
element to keep the patch size as small as possible.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
Makefile.objs | 1 +
hw/bt-hid.c | 16 ++++----
hw/milkymist-softusb.c | 8 ++--
hw/usb-bt.c | 31 +++++++----------
hw/usb-ccid.c | 46 ++++++++++++++------------
hw/usb-ehci.c | 21 ++++-------
hw/usb-hid.c | 6 ++-
hw/usb-hub.c | 8 +++--
hw/usb-libhw.c | 63 +++++++++++++++++++++++++++++++++++
hw/usb-msd.c | 12 ++++--
hw/usb-musb.c | 22 ++++++------
hw/usb-net.c | 65 ++++++++++++------------------------
hw/usb-ohci.c | 23 ++++++-------
hw/usb-serial.c | 5 ++-
hw/usb-uhci.c | 38 +++++++++------------
hw/usb-wacom.c | 6 ++-
hw/usb.c | 86 ++++++++++++++++++++++++++++++++++++++++--------
hw/usb.h | 13 ++++++-
usb-linux.c | 27 ++++++++-------
19 files changed, 303 insertions(+), 194 deletions(-)
create mode 100644 hw/usb-libhw.c
diff --git a/Makefile.objs b/Makefile.objs
index cea15e4..d8a8d27 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -171,6 +171,7 @@ user-obj-y += cutils.o cache-utils.o
hw-obj-y =
hw-obj-y += vl.o loader.o
+hw-obj-y += usb-libhw.o
hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o
hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
hw-obj-y += fw_cfg.o
diff --git a/hw/bt-hid.c b/hw/bt-hid.c
index 09120af..a4204f9 100644
--- a/hw/bt-hid.c
+++ b/hw/bt-hid.c
@@ -127,11 +127,11 @@ static int bt_hid_out(struct bt_hid_device_s *s)
USBPacket p;
if (s->data_type == BT_DATA_OUTPUT) {
- p.pid = USB_TOKEN_OUT;
- p.devep = 1;
- p.data = s->dataout.buffer;
- p.len = s->dataout.len;
+ usb_packet_init(&p);
+ usb_packet_setup(&p, USB_TOKEN_OUT, 0, 1);
+ usb_packet_addbuf(&p, s->dataout.buffer, s->dataout.len);
s->dataout.len = s->usbdev->info->handle_data(s->usbdev, &p);
+ usb_packet_cleanup(&p);
return s->dataout.len;
}
@@ -150,11 +150,11 @@ static int bt_hid_in(struct bt_hid_device_s *s)
{
USBPacket p;
- p.pid = USB_TOKEN_IN;
- p.devep = 1;
- p.data = s->datain.buffer;
- p.len = sizeof(s->datain.buffer);
+ usb_packet_init(&p);
+ usb_packet_setup(&p, USB_TOKEN_IN, 0, 1);
+ usb_packet_addbuf(&p, s->dataout.buffer, sizeof(s->datain.buffer));
s->datain.len = s->usbdev->info->handle_data(s->usbdev, &p);
+ usb_packet_cleanup(&p);
return s->datain.len;
}
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index ce2bfc6..03f039b 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -234,11 +234,11 @@ static void softusb_usbdev_datain(void *opaque)
USBPacket p;
- p.pid = USB_TOKEN_IN;
- p.devep = 1;
- p.data = s->kbd_usb_buffer;
- p.len = sizeof(s->kbd_usb_buffer);
+ usb_packet_init(&p);
+ usb_packet_setup(&p, USB_TOKEN_IN, 0, 1);
+ usb_packet_addbuf(&p, s->kbd_usb_buffer, sizeof(s->kbd_usb_buffer));
s->usbdev->info->handle_data(s->usbdev, &p);
+ usb_packet_cleanup(&p);
softusb_kbd_changed(s);
}
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index e364513..6bebc7a 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -294,9 +294,9 @@ static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
if (likely(!fifo->len))
return USB_RET_STALL;
- len = MIN(p->len, fifo->fifo[fifo->start].len);
- memcpy(p->data, fifo->fifo[fifo->start].data, len);
- if (len == p->len) {
+ len = MIN(p->iov.size, fifo->fifo[fifo->start].len);
+ usb_packet_copy(p, fifo->fifo[fifo->start].data, len);
+ if (len == p->iov.size) {
fifo->fifo[fifo->start].len -= len;
fifo->fifo[fifo->start].data += len;
} else {
@@ -319,20 +319,13 @@ static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
struct usb_hci_out_fifo_s *fifo,
void (*send)(struct HCIInfo *, const uint8_t *, int),
int (*complete)(const uint8_t *, int),
- const uint8_t *data, int len)
+ USBPacket *p)
{
- if (fifo->len) {
- memcpy(fifo->data + fifo->len, data, len);
- fifo->len += len;
- if (complete(fifo->data, fifo->len)) {
- send(s->hci, fifo->data, fifo->len);
- fifo->len = 0;
- }
- } else if (complete(data, len))
- send(s->hci, data, len);
- else {
- memcpy(fifo->data, data, len);
- fifo->len = len;
+ usb_packet_copy(p, fifo->data + fifo->len, p->iov.size);
+ fifo->len += p->iov.size;
+ if (complete(fifo->data, fifo->len)) {
+ send(s->hci, fifo->data, fifo->len);
+ fifo->len = 0;
}
/* TODO: do we need to loop? */
@@ -432,7 +425,7 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
if (s->config)
usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
- usb_bt_hci_cmd_complete, data, length);
+ usb_bt_hci_cmd_complete, p);
break;
default:
fail:
@@ -474,12 +467,12 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
switch (p->devep & 0xf) {
case USB_ACL_EP:
usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send,
- usb_bt_hci_acl_complete, p->data, p->len);
+ usb_bt_hci_acl_complete, p);
break;
case USB_SCO_EP:
usb_bt_fifo_out_enqueue(s, &s->outsco, s->hci->sco_send,
- usb_bt_hci_sco_complete, p->data, p->len);
+ usb_bt_hci_sco_complete, p);
break;
default:
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index d392299..32ab3a6 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -934,16 +934,16 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
{
CCID_Header *ccid_header;
- if (p->len + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
+ if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
return USB_RET_STALL;
}
ccid_header = (CCID_Header *)s->bulk_out_data;
- memcpy(s->bulk_out_data + s->bulk_out_pos, p->data, p->len);
- s->bulk_out_pos += p->len;
- if (p->len == CCID_MAX_PACKET_SIZE) {
+ usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
+ s->bulk_out_pos += p->iov.size;
+ if (p->iov.size == CCID_MAX_PACKET_SIZE) {
DPRINTF(s, D_VERBOSE,
- "usb-ccid: bulk_in: expecting more packets (%d/%d)\n",
- p->len, ccid_header->dwLength);
+ "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
+ p->iov.size, ccid_header->dwLength);
return 0;
}
if (s->bulk_out_pos < 10) {
@@ -1006,15 +1006,17 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
return 0;
}
-static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, uint8_t *data, int len)
+static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
{
int ret = 0;
- assert(len > 0);
+ assert(p->iov.size > 0);
ccid_bulk_in_get(s);
if (s->current_bulk_in != NULL) {
- ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, len);
- memcpy(data, s->current_bulk_in->data + s->current_bulk_in->pos, ret);
+ ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
+ p->iov.size);
+ usb_packet_copy(p, s->current_bulk_in->data +
+ s->current_bulk_in->pos, ret);
s->current_bulk_in->pos += ret;
if (s->current_bulk_in->pos == s->current_bulk_in->len) {
ccid_bulk_in_release(s);
@@ -1025,11 +1027,13 @@ static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, uint8_t *data, int len)
}
if (ret > 0) {
DPRINTF(s, D_MORE_INFO,
- "%s: %d/%d req/act to guest (BULK_IN)\n", __func__, len, ret);
+ "%s: %zd/%d req/act to guest (BULK_IN)\n",
+ __func__, p->iov.size, ret);
}
- if (ret != USB_RET_NAK && ret < len) {
+ if (ret != USB_RET_NAK && ret < p->iov.size) {
DPRINTF(s, 1,
- "%s: returning short (EREMOTEIO) %d < %d\n", __func__, ret, len);
+ "%s: returning short (EREMOTEIO) %d < %zd\n",
+ __func__, ret, p->iov.size);
}
return ret;
}
@@ -1038,8 +1042,7 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
int ret = 0;
- uint8_t *data = p->data;
- int len = p->len;
+ uint8_t buf[2];
switch (p->pid) {
case USB_TOKEN_OUT:
@@ -1049,24 +1052,25 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
case USB_TOKEN_IN:
switch (p->devep & 0xf) {
case CCID_BULK_IN_EP:
- if (!len) {
+ if (!p->iov.size) {
ret = USB_RET_NAK;
} else {
- ret = ccid_bulk_in_copy_to_guest(s, data, len);
+ ret = ccid_bulk_in_copy_to_guest(s, p);
}
break;
case CCID_INT_IN_EP:
if (s->notify_slot_change) {
/* page 56, RDR_to_PC_NotifySlotChange */
- data[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
- data[1] = s->bmSlotICCState;
+ buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
+ buf[1] = s->bmSlotICCState;
+ usb_packet_copy(p, buf, 2);
ret = 2;
s->notify_slot_change = false;
s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
DPRINTF(s, D_INFO,
"handle_data: int_in: notify_slot_change %X, "
- "requested len %d\n",
- s->bmSlotICCState, len);
+ "requested len %zd\n",
+ s->bmSlotICCState, p->iov.size);
}
break;
default:
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index a4758f9..f01d1b0 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -1235,7 +1235,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
trace_usb_ehci_queue_action(q, "wakeup");
assert(q->async == EHCI_ASYNC_INFLIGHT);
q->async = EHCI_ASYNC_FINISHED;
- q->usb_status = packet->len;
+ q->usb_status = packet->result;
}
static void ehci_execute_complete(EHCIQueue *q)
@@ -1367,17 +1367,15 @@ static int ehci_execute(EHCIQueue *q)
continue;
}
- q->packet.pid = q->pid;
- q->packet.devaddr = devadr;
- q->packet.devep = endp;
- q->packet.data = q->buffer;
- q->packet.len = q->tbytes;
+ usb_packet_setup(&q->packet, q->pid, devadr, endp);
+ usb_packet_addbuf(&q->packet, q->buffer, q->tbytes);
ret = usb_handle_packet(dev, &q->packet);
- DPRINTF("submit: qh %x next %x qtd %x pid %x len %d (total %d) endp %x ret %d\n",
+ DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
+ "(total %d) endp %x ret %d\n",
q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
- q->packet.len, q->tbytes, endp, ret);
+ q->packet.iov.size, q->tbytes, endp, ret);
if (ret != USB_RET_NODEV) {
break;
@@ -1457,11 +1455,8 @@ static int ehci_process_itd(EHCIState *ehci,
continue;
}
- ehci->ipacket.pid = pid;
- ehci->ipacket.devaddr = devaddr;
- ehci->ipacket.devep = endp;
- ehci->ipacket.data = ehci->ibuffer;
- ehci->ipacket.len = len;
+ usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
+ usb_packet_addbuf(&ehci->ipacket, ehci->ibuffer, len);
ret = usb_handle_packet(dev, &ehci->ipacket);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index b812da2..590b0c3 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -811,6 +811,7 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
{
USBHIDState *s = (USBHIDState *)dev;
+ uint8_t buf[p->iov.size];
int ret = 0;
switch(p->pid) {
@@ -821,11 +822,12 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
return USB_RET_NAK;
usb_hid_set_next_idle(s, curtime);
if (s->kind == USB_MOUSE || s->kind == USB_TABLET) {
- ret = usb_pointer_poll(s, p->data, p->len);
+ ret = usb_pointer_poll(s, buf, p->iov.size);
}
else if (s->kind == USB_KEYBOARD) {
- ret = usb_keyboard_poll(s, p->data, p->len);
+ ret = usb_keyboard_poll(s, buf, p->iov.size);
}
+ usb_packet_copy(p, buf, ret);
s->changed = s->n > 0;
} else {
goto fail;
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index b49a2fe..c49c547 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -394,11 +394,12 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
if (p->devep == 1) {
USBHubPort *port;
unsigned int status;
+ uint8_t buf[4];
int i, n;
n = (NUM_PORTS + 1 + 7) / 8;
- if (p->len == 1) { /* FreeBSD workaround */
+ if (p->iov.size == 1) { /* FreeBSD workaround */
n = 1;
- } else if (n > p->len) {
+ } else if (n > p->iov.size) {
return USB_RET_BABBLE;
}
status = 0;
@@ -409,8 +410,9 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
}
if (status != 0) {
for(i = 0; i < n; i++) {
- p->data[i] = status >> (8 * i);
+ buf[i] = status >> (8 * i);
}
+ usb_packet_copy(p, buf, n);
ret = n;
} else {
ret = USB_RET_NAK; /* usb11 11.13.1 */
diff --git a/hw/usb-libhw.c b/hw/usb-libhw.c
new file mode 100644
index 0000000..162b42b
--- /dev/null
+++ b/hw/usb-libhw.c
@@ -0,0 +1,63 @@
+/*
+ * QEMU USB emulation, libhw bits.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "cpu-common.h"
+#include "usb.h"
+#include "dma.h"
+
+int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
+{
+ int is_write = (p->pid == USB_TOKEN_IN);
+ target_phys_addr_t len;
+ void *mem;
+ int i;
+
+ for (i = 0; i < sgl->nsg; i++) {
+ len = sgl->sg[i].len;
+ mem = cpu_physical_memory_map(sgl->sg[i].base, &len,
+ is_write);
+ if (!mem) {
+ goto err;
+ }
+ qemu_iovec_add(&p->iov, mem, len);
+ if (len != sgl->sg[i].len) {
+ goto err;
+ }
+ }
+ return 0;
+
+err:
+ usb_packet_unmap(p);
+ return -1;
+}
+
+void usb_packet_unmap(USBPacket *p)
+{
+ int is_write = (p->pid == USB_TOKEN_IN);
+ int i;
+
+ for (i = 0; i < p->iov.niov; i++) {
+ cpu_physical_memory_unmap(p->iov.iov[i].iov_base,
+ p->iov.iov[i].iov_len, is_write,
+ p->iov.iov[i].iov_len);
+ }
+}
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 86582cc..64fb9f8 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -207,8 +207,9 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p)
csw.residue = s->residue;
csw.status = s->result;
- len = MIN(sizeof(csw), p->len);
- memcpy(p->data, &csw, len);
+ len = MIN(sizeof(csw), p->iov.size);
+ usb_packet_copy(p, &csw, len);
+ p->result = len;
}
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
@@ -226,6 +227,7 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
if (p) {
usb_msd_copy_data(s);
if (s->packet && s->usb_len == 0) {
+ p->result = p->iov.size;
/* Set s->packet to NULL before calling usb_packet_complete
because another request may be issued before
usb_packet_complete returns. */
@@ -264,6 +266,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
}
+ p->result = p->iov.size;
}
s->packet = NULL;
usb_packet_complete(&s->dev, p);
@@ -349,9 +352,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
int ret = 0;
struct usb_msd_cbw cbw;
uint8_t devep = p->devep;
- uint8_t *data = p->data;
- int len = p->len;
+ uint8_t *data = p->iov.iov[0].iov_base;
+ int len = p->iov.iov[0].iov_len;
+ assert(p->iov.niov == 1); /* temporary */
switch (p->pid) {
case USB_TOKEN_OUT:
if (devep != 2)
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 035dda8..d3ccde9 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -365,6 +365,8 @@ struct MUSBState *musb_init(qemu_irq *irqs)
s->ep[i].maxp[1] = 0x40;
s->ep[i].musb = s;
s->ep[i].epnum = i;
+ usb_packet_init(&s->ep[i].packey[0].p);
+ usb_packet_init(&s->ep[i].packey[1].p);
}
usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */);
@@ -605,12 +607,10 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
ep->delayed_cb[dir] = cb;
- ep->packey[dir].p.pid = pid;
/* A wild guess on the FADDR semantics... */
- ep->packey[dir].p.devaddr = ep->faddr[idx];
- ep->packey[dir].p.devep = ep->type[idx] & 0xf;
- ep->packey[dir].p.data = (void *) ep->buf[idx];
- ep->packey[dir].p.len = len;
+ usb_packet_setup(&ep->packey[dir].p, pid, ep->faddr[idx],
+ ep->type[idx] & 0xf);
+ usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
ep->packey[dir].ep = ep;
ep->packey[dir].dir = dir;
@@ -738,7 +738,7 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
if (ep->status[1] == USB_RET_STALL) {
ep->status[1] = 0;
- packey->len = 0;
+ packey->result = 0;
ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
if (!epnum)
@@ -752,7 +752,7 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
* Data-errors in Isochronous. */
if (ep->interrupt[1])
return musb_packet(s, ep, epnum, USB_TOKEN_IN,
- packey->len, musb_rx_packet_complete, 1);
+ packey->iov.size, musb_rx_packet_complete, 1);
ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
if (!epnum)
@@ -777,14 +777,14 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
/* TODO: check len for over/underruns of an OUT packet? */
/* TODO: perhaps make use of e->ext_size[1] here. */
- packey->len = ep->status[1];
+ packey->result = ep->status[1];
if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
if (!epnum)
ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
- ep->rxcount = packey->len; /* XXX: MIN(packey->len, ep->maxp[1]); */
+ ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */
/* In DMA mode: assert DMA request for this EP */
}
@@ -856,12 +856,12 @@ static void musb_rx_req(MUSBState *s, int epnum)
* 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
(ep->fifostart[1]) + ep->rxcount <
- ep->packey[1].p.len) {
+ ep->packey[1].p.iov.size) {
TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount );
ep->fifostart[1] += ep->rxcount;
ep->fifolen[1] = 0;
- ep->rxcount = MIN(ep->packey[0].p.len - (ep->fifostart[1]),
+ ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
ep->maxp[1]);
ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 9be709f..77065c2 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -29,6 +29,7 @@
#include "net.h"
#include "qemu-queue.h"
#include "sysemu.h"
+#include "iov.h"
/*#define TRAFFIC_DEBUG*/
/* Thanks to NetChip Technologies for donating this product ID.
@@ -1121,28 +1122,23 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
static int usb_net_handle_statusin(USBNetState *s, USBPacket *p)
{
+ le32 buf[2];
int ret = 8;
- if (p->len < 8)
+ if (p->iov.size < 8) {
return USB_RET_STALL;
+ }
- ((le32 *) p->data)[0] = cpu_to_le32(1);
- ((le32 *) p->data)[1] = cpu_to_le32(0);
+ buf[0] = cpu_to_le32(1);
+ buf[1] = cpu_to_le32(0);
+ usb_packet_copy(p, buf, 8);
if (!s->rndis_resp.tqh_first)
ret = USB_RET_NAK;
#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: interrupt poll len %u return %d", p->len, ret);
- {
- int i;
- fprintf(stderr, ":");
- for (i = 0; i < ret; i++) {
- if (!(i & 15))
- fprintf(stderr, "\n%04x:", i);
- fprintf(stderr, " %02x", p->data[i]);
- }
- fprintf(stderr, "\n\n");
- }
+ fprintf(stderr, "usbnet: interrupt poll len %zu return %d",
+ p->iov.size, ret);
+ iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
#endif
return ret;
@@ -1162,9 +1158,10 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
return ret;
}
ret = s->in_len - s->in_ptr;
- if (ret > p->len)
- ret = p->len;
- memcpy(p->data, &s->in_buf[s->in_ptr], ret);
+ if (ret > p->iov.size) {
+ ret = p->iov.size;
+ }
+ usb_packet_copy(p, &s->in_buf[s->in_ptr], ret);
s->in_ptr += ret;
if (s->in_ptr >= s->in_len &&
(is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
@@ -1173,17 +1170,8 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
}
#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: data in len %u return %d", p->len, ret);
- {
- int i;
- fprintf(stderr, ":");
- for (i = 0; i < ret; i++) {
- if (!(i & 15))
- fprintf(stderr, "\n%04x:", i);
- fprintf(stderr, " %02x", p->data[i]);
- }
- fprintf(stderr, "\n\n");
- }
+ fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, ret);
+ iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
#endif
return ret;
@@ -1191,29 +1179,20 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
{
- int ret = p->len;
+ int ret = p->iov.size;
int sz = sizeof(s->out_buf) - s->out_ptr;
struct rndis_packet_msg_type *msg =
(struct rndis_packet_msg_type *) s->out_buf;
uint32_t len;
#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: data out len %u\n", p->len);
- {
- int i;
- fprintf(stderr, ":");
- for (i = 0; i < p->len; i++) {
- if (!(i & 15))
- fprintf(stderr, "\n%04x:", i);
- fprintf(stderr, " %02x", p->data[i]);
- }
- fprintf(stderr, "\n\n");
- }
+ fprintf(stderr, "usbnet: data out len %zu\n", p->iov.size);
+ iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size);
#endif
if (sz > ret)
sz = ret;
- memcpy(&s->out_buf[s->out_ptr], p->data, sz);
+ usb_packet_copy(p, &s->out_buf[s->out_ptr], sz);
s->out_ptr += sz;
if (!is_rndis(s)) {
@@ -1277,8 +1256,8 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
}
if (ret == USB_RET_STALL)
fprintf(stderr, "usbnet: failed data transaction: "
- "pid 0x%x ep 0x%x len 0x%x\n",
- p->pid, p->devep, p->len);
+ "pid 0x%x ep 0x%x len 0x%zx\n",
+ p->pid, p->devep, p->iov.size);
return ret;
}
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 8491d59..272b162 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -777,18 +777,17 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
}
if (completion) {
- ret = ohci->usb_packet.len;
+ ret = ohci->usb_packet.result;
} else {
ret = USB_RET_NODEV;
for (i = 0; i < ohci->num_ports; i++) {
dev = ohci->rhport[i].port.dev;
if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
continue;
- ohci->usb_packet.pid = pid;
- ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
- ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
- ohci->usb_packet.data = ohci->usb_buf;
- ohci->usb_packet.len = len;
+ usb_packet_setup(&ohci->usb_packet, pid,
+ OHCI_BM(ed->flags, ED_FA),
+ OHCI_BM(ed->flags, ED_EN));
+ usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
@@ -959,7 +958,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
#endif
if (completion) {
- ret = ohci->usb_packet.len;
+ ret = ohci->usb_packet.result;
ohci->async_td = 0;
ohci->async_complete = 0;
} else {
@@ -980,11 +979,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
#endif
return 1;
}
- ohci->usb_packet.pid = pid;
- ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
- ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
- ohci->usb_packet.data = ohci->usb_buf;
- ohci->usb_packet.len = len;
+ usb_packet_setup(&ohci->usb_packet, pid,
+ OHCI_BM(ed->flags, ED_FA),
+ OHCI_BM(ed->flags, ED_EN));
+ usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
@@ -1769,6 +1767,7 @@ static int usb_ohci_init(OHCIState *ohci, DeviceState *dev,
ohci->localmem_base = localmem_base;
ohci->name = dev->info->name;
+ usb_packet_init(&ohci->usb_packet);
ohci->async_td = 0;
qemu_register_reset(ohci_reset, ohci);
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 59cb0fb..4a00211 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -361,10 +361,11 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
USBSerialState *s = (USBSerialState *)dev;
int ret = 0;
uint8_t devep = p->devep;
- uint8_t *data = p->data;
- int len = p->len;
+ uint8_t *data = p->iov.iov[0].iov_base;
+ int len = p->iov.iov[0].iov_len;
int first_len;
+ assert(p->iov.niov == 1); /* temporary */
switch (p->pid) {
case USB_TOKEN_OUT:
if (devep != 2)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index da74c57..20b829b 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -30,6 +30,7 @@
#include "pci.h"
#include "qemu-timer.h"
#include "usb-uhci.h"
+#include "iov.h"
//#define DEBUG
//#define DEBUG_DUMP_DATA
@@ -93,17 +94,12 @@ static const char *pid2str(int pid)
#endif
#ifdef DEBUG_DUMP_DATA
-static void dump_data(const uint8_t *data, int len)
+static void dump_data(USBPacket *p, int ret)
{
- int i;
-
- printf("uhci: data: ");
- for(i = 0; i < len; i++)
- printf(" %02x", data[i]);
- printf("\n");
+ iov_hexdump(p->iov.iov, p->iov.niov, stderr, "uhci", ret);
}
#else
-static void dump_data(const uint8_t *data, int len) {}
+static void dump_data(USBPacket *p, int ret) {}
#endif
typedef struct UHCIState UHCIState;
@@ -179,12 +175,14 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s)
async->token = 0;
async->done = 0;
async->isoc = 0;
+ usb_packet_init(&async->packet);
return async;
}
static void uhci_async_free(UHCIState *s, UHCIAsync *async)
{
+ usb_packet_cleanup(&async->packet);
qemu_free(async);
}
@@ -648,10 +646,10 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
{
int i, ret;
- DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %d\n",
- pid2str(p->pid), p->devaddr, p->devep, p->len);
+ DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %zd\n",
+ pid2str(p->pid), p->devaddr, p->devep, p->iov.size);
if (p->pid == USB_TOKEN_OUT || p->pid == USB_TOKEN_SETUP)
- dump_data(p->data, p->len);
+ dump_data(p, 0);
ret = USB_RET_NODEV;
for (i = 0; i < NB_PORTS && ret == USB_RET_NODEV; i++) {
@@ -662,9 +660,9 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
ret = usb_handle_packet(dev, p);
}
- DPRINTF("uhci: packet exit. ret %d len %d\n", ret, p->len);
+ DPRINTF("uhci: packet exit. ret %d len %zd\n", ret, p->iov.size);
if (p->pid == USB_TOKEN_IN && ret > 0)
- dump_data(p->data, ret);
+ dump_data(p, ret);
return ret;
}
@@ -684,7 +682,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
- ret = async->packet.len;
+ ret = async->packet.result;
if (td->ctrl & TD_CTRL_IOS)
td->ctrl &= ~TD_CTRL_ACTIVE;
@@ -692,7 +690,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
if (ret < 0)
goto out;
- len = async->packet.len;
+ len = async->packet.result;
td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
/* The NAK bit may have been set by a previous frame, so clear it
@@ -827,11 +825,9 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
- async->packet.pid = pid;
- async->packet.devaddr = (td->token >> 8) & 0x7f;
- async->packet.devep = (td->token >> 15) & 0xf;
- async->packet.data = async->buffer;
- async->packet.len = max_len;
+ usb_packet_setup(&async->packet, pid, (td->token >> 8) & 0x7f,
+ (td->token >> 15) & 0xf);
+ usb_packet_addbuf(&async->packet, async->buffer, max_len);
switch(pid) {
case USB_TOKEN_OUT:
@@ -859,7 +855,7 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
return 2;
}
- async->packet.len = len;
+ async->packet.result = len;
done:
len = uhci_complete_td(s, td, async, int_mask);
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 9d348e1..52bdc58 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -308,6 +308,7 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
{
USBWacomState *s = (USBWacomState *) dev;
+ uint8_t buf[p->iov.size];
int ret = 0;
switch (p->pid) {
@@ -317,9 +318,10 @@ static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
return USB_RET_NAK;
s->changed = 0;
if (s->mode == WACOM_MODE_HID)
- ret = usb_mouse_poll(s, p->data, p->len);
+ ret = usb_mouse_poll(s, buf, p->iov.size);
else if (s->mode == WACOM_MODE_WACOM)
- ret = usb_wacom_poll(s, p->data, p->len);
+ ret = usb_wacom_poll(s, buf, p->iov.size);
+ usb_packet_copy(p, buf, ret);
break;
}
/* Fall through. */
diff --git a/hw/usb.c b/hw/usb.c
index 27a983c..685e775 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -25,6 +25,7 @@
*/
#include "qemu-common.h"
#include "usb.h"
+#include "iov.h"
void usb_attach(USBPort *port, USBDevice *dev)
{
@@ -72,10 +73,11 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
int request, value, index;
int ret = 0;
- if (p->len != 8)
+ if (p->iov.size != 8) {
return USB_RET_STALL;
-
- memcpy(s->setup_buf, p->data, 8);
+ }
+
+ usb_packet_copy(p, s->setup_buf, p->iov.size);
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
s->setup_index = 0;
@@ -144,9 +146,10 @@ static int do_token_in(USBDevice *s, USBPacket *p)
case SETUP_STATE_DATA:
if (s->setup_buf[0] & USB_DIR_IN) {
int len = s->setup_len - s->setup_index;
- if (len > p->len)
- len = p->len;
- memcpy(p->data, s->data_buf + s->setup_index, len);
+ if (len > p->iov.size) {
+ len = p->iov.size;
+ }
+ usb_packet_copy(p, s->data_buf + s->setup_index, len);
s->setup_index += len;
if (s->setup_index >= s->setup_len)
s->setup_state = SETUP_STATE_ACK;
@@ -179,9 +182,10 @@ static int do_token_out(USBDevice *s, USBPacket *p)
case SETUP_STATE_DATA:
if (!(s->setup_buf[0] & USB_DIR_IN)) {
int len = s->setup_len - s->setup_index;
- if (len > p->len)
- len = p->len;
- memcpy(s->data_buf + s->setup_index, p->data, len);
+ if (len > p->iov.size) {
+ len = p->iov.size;
+ }
+ usb_packet_copy(p, s->data_buf + s->setup_index, len);
s->setup_index += len;
if (s->setup_index >= s->setup_len)
s->setup_state = SETUP_STATE_ACK;
@@ -251,22 +255,22 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
usb_packet_complete to complete their async control packets. */
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
{
- if (p->len < 0) {
+ if (p->result < 0) {
s->setup_state = SETUP_STATE_IDLE;
}
switch (s->setup_state) {
case SETUP_STATE_SETUP:
- if (p->len < s->setup_len) {
- s->setup_len = p->len;
+ if (p->result < s->setup_len) {
+ s->setup_len = p->result;
}
s->setup_state = SETUP_STATE_DATA;
- p->len = 8;
+ p->result = 8;
break;
case SETUP_STATE_ACK:
s->setup_state = SETUP_STATE_IDLE;
- p->len = 0;
+ p->result = 0;
break;
default:
@@ -347,3 +351,57 @@ void usb_cancel_packet(USBPacket * p)
p->owner->info->cancel_packet(p->owner, p);
p->owner = NULL;
}
+
+
+void usb_packet_init(USBPacket *p)
+{
+ qemu_iovec_init(&p->iov, 1);
+}
+
+void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep)
+{
+ p->pid = pid;
+ p->devaddr = addr;
+ p->devep = ep;
+ p->result = 0;
+ qemu_iovec_reset(&p->iov);
+}
+
+void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
+{
+ qemu_iovec_add(&p->iov, ptr, len);
+}
+
+void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
+{
+ assert(p->result >= 0);
+ assert(p->result + bytes <= p->iov.size);
+ switch (p->pid) {
+ case USB_TOKEN_SETUP:
+ case USB_TOKEN_OUT:
+ iov_to_buf(p->iov.iov, p->iov.niov, ptr, p->result, bytes);
+ break;
+ case USB_TOKEN_IN:
+ iov_from_buf(p->iov.iov, p->iov.niov, ptr, p->result, bytes);
+ break;
+ default:
+ fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
+ abort();
+ }
+ p->result += bytes;
+}
+
+void usb_packet_skip(USBPacket *p, size_t bytes)
+{
+ assert(p->result >= 0);
+ assert(p->result + bytes <= p->iov.size);
+ if (p->pid == USB_TOKEN_IN) {
+ iov_clear(p->iov.iov, p->iov.niov, p->result, bytes);
+ }
+ p->result += bytes;
+}
+
+void usb_packet_cleanup(USBPacket *p)
+{
+ qemu_iovec_destroy(&p->iov);
+}
diff --git a/hw/usb.h b/hw/usb.h
index ded2de2..84d04df 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -285,12 +285,21 @@ struct USBPacket {
int pid;
uint8_t devaddr;
uint8_t devep;
- uint8_t *data;
- int len;
+ QEMUIOVector iov;
+ int result; /* transfer length or USB_RET_* status code */
/* Internal use by the USB layer. */
USBDevice *owner;
};
+void usb_packet_init(USBPacket *p);
+void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep);
+void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
+int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
+void usb_packet_unmap(USBPacket *p);
+void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
+void usb_packet_skip(USBPacket *p, size_t bytes);
+void usb_packet_cleanup(USBPacket *p);
+
int usb_handle_packet(USBDevice *dev, USBPacket *p);
void usb_packet_complete(USBDevice *dev, USBPacket *p);
void usb_cancel_packet(USBPacket * p);
diff --git a/usb-linux.c b/usb-linux.c
index 1a2deb3..83ebf6e 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -341,16 +341,16 @@ static void async_complete(void *opaque)
if (p) {
switch (aurb->urb.status) {
case 0:
- p->len += aurb->urb.actual_length;
+ p->result += aurb->urb.actual_length;
break;
case -EPIPE:
set_halt(s, p->devep);
- p->len = USB_RET_STALL;
+ p->result = USB_RET_STALL;
break;
default:
- p->len = USB_RET_NAK;
+ p->result = USB_RET_NAK;
break;
}
@@ -604,6 +604,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
{
AsyncURB *aurb;
int i, j, ret, max_packet_size, offset, len = 0;
+ uint8_t *buf;
max_packet_size = get_max_packet_size(s, p->devep);
if (max_packet_size == 0)
@@ -628,19 +629,19 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
len = urb_status_to_usb_ret(
aurb[i].urb.iso_frame_desc[j].status);
/* Check the frame fits */
- } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
+ } else if (aurb[i].urb.iso_frame_desc[j].actual_length
+ > p->iov.size) {
printf("husb: received iso data is larger then packet\n");
len = USB_RET_NAK;
/* All good copy data over */
} else {
len = aurb[i].urb.iso_frame_desc[j].actual_length;
- memcpy(p->data,
- aurb[i].urb.buffer +
- j * aurb[i].urb.iso_frame_desc[0].length,
- len);
+ buf = aurb[i].urb.buffer +
+ j * aurb[i].urb.iso_frame_desc[0].length;
+ usb_packet_copy(p, buf, len);
}
} else {
- len = p->len;
+ len = p->iov.size;
offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
/* Check the frame fits */
@@ -650,7 +651,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
}
/* All good copy data over */
- memcpy(aurb[i].urb.buffer + offset, p->data, len);
+ usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
aurb[i].urb.iso_frame_desc[j].length = len;
offset += len;
set_iso_buffer_used(s, p->devep, offset);
@@ -734,9 +735,9 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
}
- rem = p->len;
- pbuf = p->data;
- p->len = 0;
+ assert(p->iov.niov == 1); /* temporary */
+ rem = p->iov.iov[0].iov_len;
+ pbuf = p->iov.iov[0].iov_base;
while (rem) {
aurb = async_alloc(s);
aurb->packet = p;
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 5/9] usb-serial: iovec support
2011-07-18 15:51 [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs Gerd Hoffmann
` (3 preceding siblings ...)
2011-07-18 15:51 ` [Qemu-devel] [PATCH 4/9] usb: use iovecs in USBPacket Gerd Hoffmann
@ 2011-07-18 15:51 ` Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 6/9] usb-host: " Gerd Hoffmann
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gerd Hoffmann @ 2011-07-18 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Add full support for iovecs to usb-serial.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-serial.c | 27 ++++++++++++++++-----------
1 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 4a00211..1133e8d 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -359,38 +359,42 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
{
USBSerialState *s = (USBSerialState *)dev;
- int ret = 0;
+ int i, ret = 0;
uint8_t devep = p->devep;
- uint8_t *data = p->iov.iov[0].iov_base;
- int len = p->iov.iov[0].iov_len;
- int first_len;
+ struct iovec *iov;
+ uint8_t header[2];
+ int first_len, len;
- assert(p->iov.niov == 1); /* temporary */
switch (p->pid) {
case USB_TOKEN_OUT:
if (devep != 2)
goto fail;
- qemu_chr_write(s->cs, data, len);
+ for (i = 0; i < p->iov.niov; i++) {
+ iov = p->iov.iov + i;
+ qemu_chr_write(s->cs, iov->iov_base, iov->iov_len);
+ }
break;
case USB_TOKEN_IN:
if (devep != 1)
goto fail;
first_len = RECV_BUF - s->recv_ptr;
+ len = p->iov.size;
if (len <= 2) {
ret = USB_RET_NAK;
break;
}
- *data++ = usb_get_modem_lines(s) | 1;
+ header[0] = usb_get_modem_lines(s) | 1;
/* We do not have the uart details */
/* handle serial break */
if (s->event_trigger && s->event_trigger & FTDI_BI) {
s->event_trigger &= ~FTDI_BI;
- *data = FTDI_BI;
+ header[1] = FTDI_BI;
+ usb_packet_copy(p, header, 2);
ret = 2;
break;
} else {
- *data++ = 0;
+ header[1] = 0;
}
len -= 2;
if (len > s->recv_used)
@@ -401,9 +405,10 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
}
if (first_len > len)
first_len = len;
- memcpy(data, s->recv_buf + s->recv_ptr, first_len);
+ usb_packet_copy(p, header, 2);
+ usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
if (len > first_len)
- memcpy(data + first_len, s->recv_buf, len - first_len);
+ usb_packet_copy(p, s->recv_buf, len - first_len);
s->recv_used -= len;
s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
ret = len + 2;
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 6/9] usb-host: iovec support
2011-07-18 15:51 [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs Gerd Hoffmann
` (4 preceding siblings ...)
2011-07-18 15:51 ` [Qemu-devel] [PATCH 5/9] usb-serial: iovec support Gerd Hoffmann
@ 2011-07-18 15:51 ` Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 7/9] usb-storage: " Gerd Hoffmann
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Gerd Hoffmann @ 2011-07-18 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Add full support for iovecs to usb-host. The code can split large
transfers into smaller ones already, we are using this to also split
requests at iovec borders.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
usb-linux.c | 27 ++++++++++++++++++---------
1 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/usb-linux.c b/usb-linux.c
index 83ebf6e..536d93c 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -707,7 +707,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
struct usbdevfs_urb *urb;
AsyncURB *aurb;
- int ret, rem;
+ int ret, rem, prem, v;
uint8_t *pbuf;
uint8_t ep;
@@ -735,10 +735,18 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
}
- assert(p->iov.niov == 1); /* temporary */
- rem = p->iov.iov[0].iov_len;
- pbuf = p->iov.iov[0].iov_base;
+ v = 0;
+ prem = p->iov.iov[v].iov_len;
+ pbuf = p->iov.iov[v].iov_base;
+ rem = p->iov.size;
while (rem) {
+ if (prem == 0) {
+ v++;
+ assert(v < p->iov.niov);
+ prem = p->iov.iov[v].iov_len;
+ pbuf = p->iov.iov[v].iov_base;
+ assert(prem <= rem);
+ }
aurb = async_alloc(s);
aurb->packet = p;
@@ -747,16 +755,17 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
urb->type = USBDEVFS_URB_TYPE_BULK;
urb->usercontext = s;
urb->buffer = pbuf;
+ urb->buffer_length = prem;
- if (rem > MAX_USBFS_BUFFER_SIZE) {
+ if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
- aurb->more = 1;
- } else {
- urb->buffer_length = rem;
- aurb->more = 0;
}
pbuf += urb->buffer_length;
+ prem -= urb->buffer_length;
rem -= urb->buffer_length;
+ if (rem) {
+ aurb->more = 1;
+ }
ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 7/9] usb-storage: iovec support
2011-07-18 15:51 [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs Gerd Hoffmann
` (5 preceding siblings ...)
2011-07-18 15:51 ` [Qemu-devel] [PATCH 6/9] usb-host: " Gerd Hoffmann
@ 2011-07-18 15:51 ` Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 8/9] uhci: remove buffer Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 9/9] ehci: ioven support, " Gerd Hoffmann
8 siblings, 0 replies; 10+ messages in thread
From: Gerd Hoffmann @ 2011-07-18 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Add full iovec support to usb-storage.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-msd.c | 107 ++++++++++++++++++++++++++-------------------------------
1 files changed, 49 insertions(+), 58 deletions(-)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 64fb9f8..91c4552 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -43,8 +43,6 @@ typedef struct {
enum USBMSDMode mode;
uint32_t scsi_len;
uint8_t *scsi_buf;
- uint32_t usb_len;
- uint8_t *usb_buf;
uint32_t data_len;
uint32_t residue;
uint32_t tag;
@@ -176,20 +174,14 @@ static const USBDesc desc = {
.str = desc_strings,
};
-static void usb_msd_copy_data(MSDState *s)
+static void usb_msd_copy_data(MSDState *s, USBPacket *p)
{
uint32_t len;
- len = s->usb_len;
+ len = p->iov.size - p->result;
if (len > s->scsi_len)
len = s->scsi_len;
- if (s->mode == USB_MSDM_DATAIN) {
- memcpy(s->usb_buf, s->scsi_buf, len);
- } else {
- memcpy(s->scsi_buf, s->usb_buf, len);
- }
- s->usb_len -= len;
+ usb_packet_copy(p, s->scsi_buf, len);
s->scsi_len -= len;
- s->usb_buf += len;
s->scsi_buf += len;
s->data_len -= len;
if (s->scsi_len == 0 || s->data_len == 0) {
@@ -225,9 +217,9 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
s->scsi_len = len;
s->scsi_buf = scsi_req_get_buf(req);
if (p) {
- usb_msd_copy_data(s);
- if (s->packet && s->usb_len == 0) {
- p->result = p->iov.size;
+ usb_msd_copy_data(s, p);
+ p = s->packet;
+ if (p && p->result == p->iov.size) {
/* Set s->packet to NULL before calling usb_packet_complete
because another request may be issued before
usb_packet_complete returns. */
@@ -257,16 +249,13 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
s->mode = USB_MSDM_CBW;
} else {
if (s->data_len) {
- s->data_len -= s->usb_len;
- if (s->mode == USB_MSDM_DATAIN) {
- memset(s->usb_buf, 0, s->usb_len);
- }
- s->usb_len = 0;
+ int len = (p->iov.size - p->result);
+ usb_packet_skip(p, len);
+ s->data_len -= len;
}
if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
}
- p->result = p->iov.size;
}
s->packet = NULL;
usb_packet_complete(&s->dev, p);
@@ -352,10 +341,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
int ret = 0;
struct usb_msd_cbw cbw;
uint8_t devep = p->devep;
- uint8_t *data = p->iov.iov[0].iov_base;
- int len = p->iov.iov[0].iov_len;
- assert(p->iov.niov == 1); /* temporary */
switch (p->pid) {
case USB_TOKEN_OUT:
if (devep != 2)
@@ -363,11 +349,11 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
switch (s->mode) {
case USB_MSDM_CBW:
- if (len != 31) {
+ if (p->iov.size != 31) {
fprintf(stderr, "usb-msd: Bad CBW size");
goto fail;
}
- memcpy(&cbw, data, 31);
+ usb_packet_copy(p, &cbw, 31);
if (le32_to_cpu(cbw.sig) != 0x43425355) {
fprintf(stderr, "usb-msd: Bad signature %08x\n",
le32_to_cpu(cbw.sig));
@@ -398,36 +384,39 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
if (s->mode != USB_MSDM_CSW && s->residue == 0) {
scsi_req_continue(s->req);
}
- ret = len;
+ ret = p->result;
break;
case USB_MSDM_DATAOUT:
- DPRINTF("Data out %d/%d\n", len, s->data_len);
- if (len > s->data_len)
+ DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
+ if (p->iov.size > s->data_len) {
goto fail;
+ }
- s->usb_buf = data;
- s->usb_len = len;
if (s->scsi_len) {
- usb_msd_copy_data(s);
+ usb_msd_copy_data(s, p);
}
- if (s->residue && s->usb_len) {
- s->data_len -= s->usb_len;
- if (s->data_len == 0)
- s->mode = USB_MSDM_CSW;
- s->usb_len = 0;
+ if (s->residue) {
+ int len = p->iov.size - p->result;
+ if (len) {
+ usb_packet_skip(p, len);
+ s->data_len -= len;
+ if (s->data_len == 0) {
+ s->mode = USB_MSDM_CSW;
+ }
+ }
}
- if (s->usb_len) {
+ if (p->result < p->iov.size) {
DPRINTF("Deferring packet %p\n", p);
s->packet = p;
ret = USB_RET_ASYNC;
} else {
- ret = len;
+ ret = p->result;
}
break;
default:
- DPRINTF("Unexpected write (len %d)\n", len);
+ DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
goto fail;
}
break;
@@ -438,18 +427,20 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
switch (s->mode) {
case USB_MSDM_DATAOUT:
- if (s->data_len != 0 || len < 13)
+ if (s->data_len != 0 || p->iov.size < 13) {
goto fail;
+ }
/* Waiting for SCSI write to complete. */
s->packet = p;
ret = USB_RET_ASYNC;
break;
case USB_MSDM_CSW:
- DPRINTF("Command status %d tag 0x%x, len %d\n",
- s->result, s->tag, len);
- if (len < 13)
+ DPRINTF("Command status %d tag 0x%x, len %zd\n",
+ s->result, s->tag, p->iov.size);
+ if (p->iov.size < 13) {
goto fail;
+ }
usb_msd_send_status(s, p);
s->mode = USB_MSDM_CBW;
@@ -457,32 +448,32 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
break;
case USB_MSDM_DATAIN:
- DPRINTF("Data in %d/%d, scsi_len %d\n", len, s->data_len, s->scsi_len);
- if (len > s->data_len)
- len = s->data_len;
- s->usb_buf = data;
- s->usb_len = len;
+ DPRINTF("Data in %zd/%d, scsi_len %d\n",
+ p->iov.size, s->data_len, s->scsi_len);
if (s->scsi_len) {
- usb_msd_copy_data(s);
+ usb_msd_copy_data(s, p);
}
- if (s->residue && s->usb_len) {
- s->data_len -= s->usb_len;
- memset(s->usb_buf, 0, s->usb_len);
- if (s->data_len == 0)
- s->mode = USB_MSDM_CSW;
- s->usb_len = 0;
+ if (s->residue) {
+ int len = p->iov.size - p->result;
+ if (len) {
+ usb_packet_skip(p, len);
+ s->data_len -= len;
+ if (s->data_len == 0) {
+ s->mode = USB_MSDM_CSW;
+ }
+ }
}
- if (s->usb_len) {
+ if (p->result < p->iov.size) {
DPRINTF("Deferring packet %p\n", p);
s->packet = p;
ret = USB_RET_ASYNC;
} else {
- ret = len;
+ ret = p->result;
}
break;
default:
- DPRINTF("Unexpected read (len %d)\n", len);
+ DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
goto fail;
}
break;
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 8/9] uhci: remove buffer
2011-07-18 15:51 [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs Gerd Hoffmann
` (6 preceding siblings ...)
2011-07-18 15:51 ` [Qemu-devel] [PATCH 7/9] usb-storage: " Gerd Hoffmann
@ 2011-07-18 15:51 ` Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 9/9] ehci: ioven support, " Gerd Hoffmann
8 siblings, 0 replies; 10+ messages in thread
From: Gerd Hoffmann @ 2011-07-18 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Map guest memory and pass on a direct pointer instead of copying
the bits to a indirect buffer.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-uhci.c | 15 +++++++--------
1 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 20b829b..824e3a5 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -31,6 +31,7 @@
#include "qemu-timer.h"
#include "usb-uhci.h"
#include "iov.h"
+#include "dma.h"
//#define DEBUG
//#define DEBUG_DUMP_DATA
@@ -111,6 +112,7 @@ typedef struct UHCIState UHCIState;
*/
typedef struct UHCIAsync {
USBPacket packet;
+ QEMUSGList sgl;
UHCIState *uhci;
QTAILQ_ENTRY(UHCIAsync) next;
uint32_t td;
@@ -118,7 +120,6 @@ typedef struct UHCIAsync {
int8_t valid;
uint8_t isoc;
uint8_t done;
- uint8_t buffer[2048];
} UHCIAsync;
typedef struct UHCIPort {
@@ -176,6 +177,7 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s)
async->done = 0;
async->isoc = 0;
usb_packet_init(&async->packet);
+ qemu_sglist_init(&async->sgl, 1);
return async;
}
@@ -183,6 +185,7 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s)
static void uhci_async_free(UHCIState *s, UHCIAsync *async)
{
usb_packet_cleanup(&async->packet);
+ qemu_sglist_destroy(&async->sgl);
qemu_free(async);
}
@@ -706,11 +709,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
goto out;
}
- if (len > 0) {
- /* write the data back */
- cpu_physical_memory_write(td->buffer, async->buffer, len);
- }
-
if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
*int_mask |= 0x02;
/* short packet: do not update QH */
@@ -827,12 +825,12 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
usb_packet_setup(&async->packet, pid, (td->token >> 8) & 0x7f,
(td->token >> 15) & 0xf);
- usb_packet_addbuf(&async->packet, async->buffer, max_len);
+ qemu_sglist_add(&async->sgl, td->buffer, max_len);
+ usb_packet_map(&async->packet, &async->sgl);
switch(pid) {
case USB_TOKEN_OUT:
case USB_TOKEN_SETUP:
- cpu_physical_memory_read(td->buffer, async->buffer, max_len);
len = uhci_broadcast_packet(s, &async->packet);
if (len >= 0)
len = max_len;
@@ -859,6 +857,7 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
done:
len = uhci_complete_td(s, td, async, int_mask);
+ usb_packet_unmap(&async->packet);
uhci_async_free(s, async);
return len;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 9/9] ehci: ioven support, remove buffer
2011-07-18 15:51 [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs Gerd Hoffmann
` (7 preceding siblings ...)
2011-07-18 15:51 ` [Qemu-devel] [PATCH 8/9] uhci: remove buffer Gerd Hoffmann
@ 2011-07-18 15:51 ` Gerd Hoffmann
8 siblings, 0 replies; 10+ messages in thread
From: Gerd Hoffmann @ 2011-07-18 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Map guest memory and pass on a direct pointer instead of copying
the bits to a indirect buffer. EHCI transfer descriptors can
reference multiple (physical guest) pages so we'll actually start
seeing usb packets wich carry iovec with more than one element.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb-ehci.c | 147 ++++++++++++++++++++++++---------------------------------
1 files changed, 62 insertions(+), 85 deletions(-)
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index f01d1b0..194fb89 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -28,6 +28,7 @@
#include "pci.h"
#include "monitor.h"
#include "trace.h"
+#include "dma.h"
#define EHCI_DEBUG 0
@@ -269,6 +270,7 @@ typedef struct EHCIqtd {
uint32_t bufptr[5]; // Standard buffer pointer
#define QTD_BUFPTR_MASK 0xfffff000
+#define QTD_BUFPTR_SH 12
} EHCIqtd;
/* EHCI spec version 1.0 Section 3.6
@@ -357,7 +359,7 @@ struct EHCIQueue {
uint32_t qtdaddr; // address QTD read from
USBPacket packet;
- uint8_t buffer[BUFF_SIZE];
+ QEMUSGList sgl;
int pid;
uint32_t tbytes;
enum async_state async;
@@ -414,7 +416,7 @@ struct EHCIState {
uint32_t p_fetch_addr; // which address to look at next
USBPacket ipacket;
- uint8_t ibuffer[BUFF_SIZE];
+ QEMUSGList isgl;
int isoch_pause;
uint64_t last_run_ns;
@@ -1165,58 +1167,56 @@ static int ehci_qh_do_overlay(EHCIQueue *q)
return 0;
}
-static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw)
+static int ehci_init_transfer(EHCIQueue *q)
{
- int bufpos = 0;
- int cpage, offset;
- uint32_t head;
- uint32_t tail;
-
-
- if (!bytes) {
- return 0;
- }
-
- cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
- if (cpage > 4) {
- fprintf(stderr, "cpage out of range (%d)\n", cpage);
- return USB_RET_PROCERR;
- }
+ uint32_t cpage, offset, bytes, plen;
+ target_phys_addr_t page;
+ cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
+ bytes = get_field(q->qh.token, QTD_TOKEN_TBYTES);
offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
+ qemu_sglist_init(&q->sgl, 5);
- do {
- /* start and end of this page */
- head = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK;
- tail = head + ~QTD_BUFPTR_MASK + 1;
- /* add offset into page */
- head |= offset;
-
- if (bytes <= (tail - head)) {
- tail = head + bytes;
+ while (bytes > 0) {
+ if (cpage > 4) {
+ fprintf(stderr, "cpage out of range (%d)\n", cpage);
+ return USB_RET_PROCERR;
}
- trace_usb_ehci_data(rw, cpage, offset, head, tail-head, bufpos);
- cpu_physical_memory_rw(head, q->buffer + bufpos, tail - head, rw);
-
- bufpos += (tail - head);
- offset += (tail - head);
- bytes -= (tail - head);
-
- if (bytes > 0) {
- cpage++;
+ page = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK;
+ page += offset;
+ plen = bytes;
+ if (plen > 4096 - offset) {
+ plen = 4096 - offset;
offset = 0;
+ cpage++;
}
- } while (bytes > 0);
- /* save cpage */
- set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
+ qemu_sglist_add(&q->sgl, page, plen);
+ bytes -= plen;
+ }
+ return 0;
+}
- /* save offset into cpage */
- q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
- q->qh.bufptr[0] |= offset;
+static void ehci_finish_transfer(EHCIQueue *q, int status)
+{
+ uint32_t cpage, offset;
- return 0;
+ qemu_sglist_destroy(&q->sgl);
+
+ if (status > 0) {
+ /* update cpage & offset */
+ cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
+ offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
+
+ offset += status;
+ cpage += offset >> QTD_BUFPTR_SH;
+ offset &= ~QTD_BUFPTR_MASK;
+
+ set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
+ q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
+ q->qh.bufptr[0] |= offset;
+ }
}
static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
@@ -1295,10 +1295,6 @@ err:
}
if (q->tbytes && q->pid == USB_TOKEN_IN) {
- if (ehci_buffer_rw(q, q->usb_status, 1) != 0) {
- q->usb_status = USB_RET_PROCERR;
- return;
- }
q->tbytes -= q->usb_status;
} else {
q->tbytes = 0;
@@ -1307,6 +1303,8 @@ err:
DPRINTF("updating tbytes to %d\n", q->tbytes);
set_field(&q->qh.token, q->tbytes, QTD_TOKEN_TBYTES);
}
+ ehci_finish_transfer(q, q->usb_status);
+ usb_packet_unmap(&q->packet);
q->qh.token ^= QTD_TOKEN_DTOGGLE;
q->qh.token &= ~QTD_TOKEN_ACTIVE;
@@ -1346,8 +1344,7 @@ static int ehci_execute(EHCIQueue *q)
default: fprintf(stderr, "bad token\n"); break;
}
- if ((q->tbytes && q->pid != USB_TOKEN_IN) &&
- (ehci_buffer_rw(q, q->tbytes, 0) != 0)) {
+ if (ehci_init_transfer(q) != 0) {
return USB_RET_PROCERR;
}
@@ -1356,6 +1353,9 @@ static int ehci_execute(EHCIQueue *q)
ret = USB_RET_NODEV;
+ usb_packet_setup(&q->packet, q->pid, devadr, endp);
+ usb_packet_map(&q->packet, &q->sgl);
+
// TO-DO: associating device with ehci port
for(i = 0; i < NB_PORTS; i++) {
port = &q->ehci->ports[i];
@@ -1367,9 +1367,6 @@ static int ehci_execute(EHCIQueue *q)
continue;
}
- usb_packet_setup(&q->packet, q->pid, devadr, endp);
- usb_packet_addbuf(&q->packet, q->buffer, q->tbytes);
-
ret = usb_handle_packet(dev, &q->packet);
DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
@@ -1399,7 +1396,7 @@ static int ehci_process_itd(EHCIState *ehci,
USBPort *port;
USBDevice *dev;
int ret;
- uint32_t i, j, len, len1, len2, pid, dir, devaddr, endp;
+ uint32_t i, j, len, pid, dir, devaddr, endp;
uint32_t pg, off, ptr1, ptr2, max, mult;
dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
@@ -1424,29 +1421,23 @@ static int ehci_process_itd(EHCIState *ehci,
return USB_RET_PROCERR;
}
+ qemu_sglist_init(&ehci->isgl, 2);
if (off + len > 4096) {
/* transfer crosses page border */
- len2 = off + len - 4096;
- len1 = len - len2;
+ uint32_t len2 = off + len - 4096;
+ uint32_t len1 = len - len2;
+ qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);
+ qemu_sglist_add(&ehci->isgl, ptr2, len2);
} else {
- len1 = len;
- len2 = 0;
+ qemu_sglist_add(&ehci->isgl, ptr1 + off, len);
}
- if (!dir) {
- pid = USB_TOKEN_OUT;
- trace_usb_ehci_data(0, pg, off, ptr1 + off, len1, 0);
- cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 0);
- if (len2) {
- trace_usb_ehci_data(0, pg+1, 0, ptr2, len2, len1);
- cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 0);
- }
- } else {
- pid = USB_TOKEN_IN;
- }
+ pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
- ret = USB_RET_NODEV;
+ usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
+ usb_packet_map(&ehci->ipacket, &ehci->isgl);
+ ret = USB_RET_NODEV;
for (j = 0; j < NB_PORTS; j++) {
port = &ehci->ports[j];
dev = port->dev;
@@ -1455,9 +1446,6 @@ static int ehci_process_itd(EHCIState *ehci,
continue;
}
- usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
- usb_packet_addbuf(&ehci->ipacket, ehci->ibuffer, len);
-
ret = usb_handle_packet(dev, &ehci->ipacket);
if (ret != USB_RET_NODEV) {
@@ -1465,6 +1453,9 @@ static int ehci_process_itd(EHCIState *ehci,
}
}
+ usb_packet_unmap(&ehci->ipacket);
+ qemu_sglist_destroy(&ehci->isgl);
+
#if 0
/* In isoch, there is no facility to indicate a NAK so let's
* instead just complete a zero-byte transaction. Setting
@@ -1502,20 +1493,6 @@ static int ehci_process_itd(EHCIState *ehci,
set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
} else {
/* IN */
- if (len1 > ret) {
- len1 = ret;
- }
- if (len2 > ret - len1) {
- len2 = ret - len1;
- }
- if (len1) {
- trace_usb_ehci_data(1, pg, off, ptr1 + off, len1, 0);
- cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 1);
- }
- if (len2) {
- trace_usb_ehci_data(1, pg+1, 0, ptr2, len2, len1);
- cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 1);
- }
set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2011-07-18 15:51 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-07-18 15:51 [Qemu-devel] [PATCH 0/9] usb: replace buffers with iovecs Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 1/9] Add iov_hexdump() Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 2/9] Add iov_clear() Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 3/9] move QEMUSGList typedef Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 4/9] usb: use iovecs in USBPacket Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 5/9] usb-serial: iovec support Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 6/9] usb-host: " Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 7/9] usb-storage: " Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 8/9] uhci: remove buffer Gerd Hoffmann
2011-07-18 15:51 ` [Qemu-devel] [PATCH 9/9] ehci: ioven support, " Gerd Hoffmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).