All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes
@ 2011-08-04 15:10 Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 01/16] re-activate usb-host for bsd Gerd Hoffmann
                   ` (16 more replies)
  0 siblings, 17 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

  Hi,

Major changes in the USB patch queue:

 * The USBPacket payload is represented as iovec instead of a linear
   buffer.  This allows to kill some copying and buffering.
 * The HID code is splitted into hw/hid.[ch], keeping only the usb
   interfaacing in hw/usb-hid.c.  This allows easy reuse in other
   contexts such as bluetooth.

please pull,
  Gerd

The following changes since commit a6f4e09d90cef88be07cd597c2f2a9f0b3ed0763:

  lm32: softusb: claim to support full speed (2011-08-04 01:14:22 +0200)

are available in the git repository at:
  git://git.kraxel.org/qemu usb.22

Gerd Hoffmann (16):
      re-activate usb-host for bsd
      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
      usb-hid: create & use HIDState
      usb-hid: add event callback
      usb-hid: add hid_has_events()
      usb-hid: split hid code to hw/hid.[ch]
      hid: move idle+protocol from usb-hid to hid too.
      bluetooth: kill dummy usb device, use hid code directly.

 Makefile.objs          |    2 +
 dma.h                  |    4 +-
 hw/bt-hid.c            |   62 ++----
 hw/hid.c               |  403 +++++++++++++++++++++++++++++++++++++
 hw/hid.h               |   58 ++++++
 hw/milkymist-softusb.c |    8 +-
 hw/usb-bt.c            |   31 +--
 hw/usb-ccid.c          |   46 +++--
 hw/usb-ehci.c          |  160 ++++++---------
 hw/usb-hid.c           |  519 +++++++----------------------------------------
 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-bsd.c              |   14 +-
 usb-linux.c            |   48 +++--
 usb-redir.c            |   59 +++---
 27 files changed, 1087 insertions(+), 858 deletions(-)
 create mode 100644 hw/hid.c
 create mode 100644 hw/hid.h
 create mode 100644 hw/usb-libhw.c

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 01/16] re-activate usb-host for bsd
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 18:50   ` Blue Swirl
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 02/16] Add iov_hexdump() Gerd Hoffmann
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

A bunch of code was disabled via #if 0, for a quite long time (since
Sept 2009).  Surprisingly the code builds just fine when they are
removed (tested on OpenBSD).  /me wonders nevertheless whenever there
are any users of those bits when this went unnoticed for almost two
years ...

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 usb-bsd.c |   10 ++--------
 1 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/usb-bsd.c b/usb-bsd.c
index 3b97eb4..ab8e3b7 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -62,7 +62,6 @@ typedef struct USBHostDevice {
 } USBHostDevice;
 
 
-#if 0
 static int ensure_ep_open(USBHostDevice *dev, int ep, int mode)
 {
     char buf[32];
@@ -110,7 +109,6 @@ static void ensure_eps_closed(USBHostDevice *dev)
         epnum++;
     }
 }
-#endif
 
 static void usb_host_handle_reset(USBDevice *dev)
 {
@@ -119,7 +117,6 @@ static void usb_host_handle_reset(USBDevice *dev)
 #endif
 }
 
-#if 0
 /* XXX:
  * -check device states against transfer requests
  *  and return appropriate response
@@ -278,7 +275,6 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
         return ret;
     }
 }
-#endif
 
 static void usb_host_handle_destroy(USBDevice *opaque)
 {
@@ -305,8 +301,8 @@ static int usb_host_initfn(USBDevice *dev)
 USBDevice *usb_host_device_open(const char *devname)
 {
     struct usb_device_info bus_info, dev_info;
-    USBDevice *d = NULL;
-    USBHostDevice *dev, *ret = NULL;
+    USBDevice *d = NULL, *ret = NULL;
+    USBHostDevice *dev;
     char ctlpath[PATH_MAX + 1];
     char buspath[PATH_MAX + 1];
     int bfd, dfd, bus, address, i;
@@ -408,10 +404,8 @@ static struct USBDeviceInfo usb_host_dev_info = {
     .init           = usb_host_initfn,
     .handle_packet  = usb_generic_handle_packet,
     .handle_reset   = usb_host_handle_reset,
-#if 0
     .handle_control = usb_host_handle_control,
     .handle_data    = usb_host_handle_data,
-#endif
     .handle_destroy = usb_host_handle_destroy,
 };
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 02/16] Add iov_hexdump()
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 01/16] re-activate usb-host for bsd Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 03/16] Add iov_clear() Gerd Hoffmann
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 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] 25+ messages in thread

* [Qemu-devel] [PATCH 03/16] Add iov_clear()
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 01/16] re-activate usb-host for bsd Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 02/16] Add iov_hexdump() Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-05 11:30   ` Kevin Wolf
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 04/16] move QEMUSGList typedef Gerd Hoffmann
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 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] 25+ messages in thread

* [Qemu-devel] [PATCH 04/16] move QEMUSGList typedef
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 03/16] Add iov_clear() Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 05/16] usb: use iovecs in USBPacket Gerd Hoffmann
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 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 1e3c665..c7064d3 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -270,6 +270,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] 25+ messages in thread

* [Qemu-devel] [PATCH 05/16] usb: use iovecs in USBPacket
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 04/16] move QEMUSGList typedef Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 06/16] usb-serial: iovec support Gerd Hoffmann
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 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-bsd.c              |    4 +-
 usb-linux.c            |   27 ++++++++-------
 usb-redir.c            |   59 ++++++++++++++++++--------------
 21 files changed, 338 insertions(+), 222 deletions(-)
 create mode 100644 hw/usb-libhw.c

diff --git a/Makefile.objs b/Makefile.objs
index 6991a9f..3d1a4de 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -172,6 +172,7 @@ user-obj-y += cutils.o cache-utils.o
 hw-obj-y =
 hw-obj-y += vl.o loader.o
 hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
+hw-obj-y += usb-libhw.o
 hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
 hw-obj-y += fw_cfg.o
 hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.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 abf7b59..75c85ae 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 4557802..529fa33 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 4dda2c4..66aeb21 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 8b0dcc3..799e31a 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 9008320..541644a 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -816,6 +816,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) {
@@ -826,11 +827,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 cdeac58..48e0b34 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)
@@ -222,6 +223,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.  */
@@ -257,6 +259,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);
@@ -342,9 +345,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 4212e5b..0cb47d6 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 337b250..d39bcb0 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;
@@ -1761,6 +1759,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 298c1e9..09731da 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 d76ee97..2558006 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-bsd.c b/usb-bsd.c
index ab8e3b7..ab84d93 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -253,9 +253,9 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
     }
 
     if (p->pid == USB_TOKEN_IN)
-        ret = read(fd, p->data, p->len);
+        ret = readv(fd, p->iov.iov, p->iov.niov);
     else
-        ret = write(fd, p->data, p->len);
+        ret = writev(fd, p->iov.iov, p->iov.niov);
 
     sigprocmask(SIG_SETMASK, &old_mask, NULL);
 
diff --git a/usb-linux.c b/usb-linux.c
index 53cc5fc..184f56f 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;
diff --git a/usb-redir.c b/usb-redir.c
index e212993..9e5fce2 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -365,12 +365,12 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
         }
 
         len = isop->len;
-        if (len > p->len) {
+        if (len > p->iov.size) {
             ERROR("received iso data is larger then packet ep %02X\n", ep);
             bufp_free(dev, isop, ep);
             return USB_RET_NAK;
         }
-        memcpy(p->data, isop->data, len);
+        usb_packet_copy(p, isop->data, len);
         bufp_free(dev, isop, ep);
         return len;
     } else {
@@ -379,18 +379,20 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
         if (dev->endpoint[EP2I(ep)].iso_started) {
             struct usb_redir_iso_packet_header iso_packet = {
                 .endpoint = ep,
-                .length = p->len
+                .length = p->iov.size
             };
+            uint8_t buf[p->iov.size];
             /* No id, we look at the ep when receiving a status back */
+            usb_packet_copy(p, buf, p->iov.size);
             usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet,
-                                           p->data, p->len);
+                                           buf, p->iov.size);
             usbredirparser_do_write(dev->parser);
         }
         status = dev->endpoint[EP2I(ep)].iso_error;
         dev->endpoint[EP2I(ep)].iso_error = 0;
-        DPRINTF2("iso-token-out ep %02X status %d len %d\n", ep, status,
-                 p->len);
-        return usbredir_handle_status(dev, status, p->len);
+        DPRINTF2("iso-token-out ep %02X status %d len %zd\n", ep, status,
+                 p->iov.size);
+        return usbredir_handle_status(dev, status, p->iov.size);
     }
 }
 
@@ -413,10 +415,11 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
     AsyncURB *aurb = async_alloc(dev, p);
     struct usb_redir_bulk_packet_header bulk_packet;
 
-    DPRINTF("bulk-out ep %02X len %d id %u\n", ep, p->len, aurb->packet_id);
+    DPRINTF("bulk-out ep %02X len %zd id %u\n", ep,
+            p->iov.size, aurb->packet_id);
 
     bulk_packet.endpoint  = ep;
-    bulk_packet.length    = p->len;
+    bulk_packet.length    = p->iov.size;
     bulk_packet.stream_id = 0;
     aurb->bulk_packet = bulk_packet;
 
@@ -424,9 +427,11 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
         usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
                                         &bulk_packet, NULL, 0);
     } else {
-        usbredir_log_data(dev, "bulk data out:", p->data, p->len);
+        uint8_t buf[p->iov.size];
+        usb_packet_copy(p, buf, p->iov.size);
+        usbredir_log_data(dev, "bulk data out:", buf, p->iov.size);
         usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
-                                        &bulk_packet, p->data, p->len);
+                                        &bulk_packet, buf, p->iov.size);
     }
     usbredirparser_do_write(dev->parser);
     return USB_RET_ASYNC;
@@ -471,29 +476,31 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
         }
 
         len = intp->len;
-        if (len > p->len) {
+        if (len > p->iov.size) {
             ERROR("received int data is larger then packet ep %02X\n", ep);
             bufp_free(dev, intp, ep);
             return USB_RET_NAK;
         }
-        memcpy(p->data, intp->data, len);
+        usb_packet_copy(p, intp->data, len);
         bufp_free(dev, intp, ep);
         return len;
     } else {
         /* Output interrupt endpoint, normal async operation */
         AsyncURB *aurb = async_alloc(dev, p);
         struct usb_redir_interrupt_packet_header interrupt_packet;
+        uint8_t buf[p->iov.size];
 
-        DPRINTF("interrupt-out ep %02X len %d id %u\n", ep, p->len,
+        DPRINTF("interrupt-out ep %02X len %zd id %u\n", ep, p->iov.size,
                 aurb->packet_id);
 
         interrupt_packet.endpoint  = ep;
-        interrupt_packet.length    = p->len;
+        interrupt_packet.length    = p->iov.size;
         aurb->interrupt_packet     = interrupt_packet;
 
-        usbredir_log_data(dev, "interrupt data out:", p->data, p->len);
+        usb_packet_copy(p, buf, p->iov.size);
+        usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
         usbredirparser_send_interrupt_packet(dev->parser, aurb->packet_id,
-                                        &interrupt_packet, p->data, p->len);
+                                        &interrupt_packet, buf, p->iov.size);
         usbredirparser_do_write(dev->parser);
         return USB_RET_ASYNC;
     }
@@ -959,7 +966,7 @@ static void usbredir_configuration_status(void *priv, uint32_t id,
             dev->dev.data_buf[0] = config_status->configuration;
             len = 1;
         }
-        aurb->packet->len =
+        aurb->packet->result =
             usbredir_handle_status(dev, config_status->status, len);
         usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
     }
@@ -987,7 +994,7 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id,
             dev->dev.data_buf[0] = alt_setting_status->alt;
             len = 1;
         }
-        aurb->packet->len =
+        aurb->packet->result =
             usbredir_handle_status(dev, alt_setting_status->status, len);
         usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
     }
@@ -1070,7 +1077,7 @@ static void usbredir_control_packet(void *priv, uint32_t id,
                 len = USB_RET_STALL;
             }
         }
-        aurb->packet->len = len;
+        aurb->packet->result = len;
         usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
     }
     async_free(dev, aurb);
@@ -1105,15 +1112,15 @@ static void usbredir_bulk_packet(void *priv, uint32_t id,
         len = usbredir_handle_status(dev, bulk_packet->status, len);
         if (len > 0) {
             usbredir_log_data(dev, "bulk data in:", data, data_len);
-            if (data_len <= aurb->packet->len) {
-                memcpy(aurb->packet->data, data, data_len);
+            if (data_len <= aurb->packet->iov.size) {
+                usb_packet_copy(aurb->packet, data, data_len);
             } else {
-                ERROR("bulk buffer too small (%d > %d)\n", data_len,
-                      aurb->packet->len);
+                ERROR("bulk buffer too small (%d > %zd)\n", data_len,
+                      aurb->packet->iov.size);
                 len = USB_RET_STALL;
             }
         }
-        aurb->packet->len = len;
+        aurb->packet->result = len;
         usb_packet_complete(&dev->dev, aurb->packet);
     }
     async_free(dev, aurb);
@@ -1185,7 +1192,7 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
         }
 
         if (aurb->packet) {
-            aurb->packet->len = usbredir_handle_status(dev,
+            aurb->packet->result = usbredir_handle_status(dev,
                                                interrupt_packet->status, len);
             usb_packet_complete(&dev->dev, aurb->packet);
         }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 06/16] usb-serial: iovec support
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 05/16] usb: use iovecs in USBPacket Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 07/16] usb-host: " Gerd Hoffmann
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 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 09731da..bf2b775 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] 25+ messages in thread

* [Qemu-devel] [PATCH 07/16] usb-host: iovec support
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 06/16] usb-serial: iovec support Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 08/16] usb-storage: " Gerd Hoffmann
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 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 184f56f..5562187 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] 25+ messages in thread

* [Qemu-devel] [PATCH 08/16] usb-storage: iovec support
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (6 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 07/16] usb-host: " Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 09/16] uhci: remove buffer Gerd Hoffmann
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 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 48e0b34..90e57fb 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) {
@@ -221,9 +213,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.  */
@@ -250,16 +242,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);
@@ -345,10 +334,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)
@@ -356,11 +342,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));
@@ -391,36 +377,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;
@@ -431,18 +420,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;
@@ -450,32 +441,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] 25+ messages in thread

* [Qemu-devel] [PATCH 09/16] uhci: remove buffer
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (7 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 08/16] usb-storage: " Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 10/16] ehci: iovec support, " Gerd Hoffmann
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 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] 25+ messages in thread

* [Qemu-devel] [PATCH 10/16] ehci: iovec support, remove buffer
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (8 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 09/16] uhci: remove buffer Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 11/16] usb-hid: create & use HIDState Gerd Hoffmann
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 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 799e31a..2b43895 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] 25+ messages in thread

* [Qemu-devel] [PATCH 11/16] usb-hid: create & use HIDState
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (9 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 10/16] ehci: iovec support, " Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 12/16] usb-hid: add event callback Gerd Hoffmann
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

First step in separating out the HID emulation code from usb-hid, so it
can be reused without creating a dummy usb device like bluetooth does.

This creates a HIDState struct, moves the non-usbish fields from
USBHIDStruct there.  Renames non-usbish structs, defines and functions
from usb* to hid*.  Adapts the code to that.

Also cleans up a bunch of code style issues along the way.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb-hid.c |  316 +++++++++++++++++++++++++++++++---------------------------
 1 files changed, 168 insertions(+), 148 deletions(-)

diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 541644a..f5d6c61 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -41,42 +41,46 @@
 #define USB_DT_REPORT 0x22
 #define USB_DT_PHY    0x23
 
-#define USB_MOUSE     1
-#define USB_TABLET    2
-#define USB_KEYBOARD  3
+#define HID_MOUSE     1
+#define HID_TABLET    2
+#define HID_KEYBOARD  3
 
-typedef struct USBPointerEvent {
+typedef struct HIDPointerEvent {
     int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
     int32_t dz, buttons_state;
-} USBPointerEvent;
+} HIDPointerEvent;
 
 #define QUEUE_LENGTH    16 /* should be enough for a triple-click */
 #define QUEUE_MASK      (QUEUE_LENGTH-1u)
 #define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
 
-typedef struct USBMouseState {
-    USBPointerEvent queue[QUEUE_LENGTH];
+typedef struct HIDMouseState {
+    HIDPointerEvent queue[QUEUE_LENGTH];
     int mouse_grabbed;
     QEMUPutMouseEntry *eh_entry;
-} USBMouseState;
+} HIDMouseState;
 
-typedef struct USBKeyboardState {
+typedef struct HIDKeyboardState {
     uint32_t keycodes[QUEUE_LENGTH];
     uint16_t modifiers;
     uint8_t leds;
     uint8_t key[16];
     int32_t keys;
-} USBKeyboardState;
+} HIDKeyboardState;
 
-typedef struct USBHIDState {
-    USBDevice dev;
+typedef struct HIDState {
     union {
-        USBMouseState ptr;
-        USBKeyboardState kbd;
+        HIDMouseState ptr;
+        HIDKeyboardState kbd;
     };
     uint32_t head; /* index into circular queue */
     uint32_t n;
     int kind;
+} HIDState;
+
+typedef struct USBHIDState {
+    USBDevice dev;
+    HIDState hid;
     int32_t protocol;
     uint8_t idle;
     int64_t next_idle_clock;
@@ -446,12 +450,13 @@ static void usb_hid_changed(USBHIDState *hs)
     usb_wakeup(&hs->dev);
 }
 
-static void usb_pointer_event_clear(USBPointerEvent *e, int buttons) {
+static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
+{
     e->xdx = e->ydy = e->dz = 0;
     e->buttons_state = buttons;
 }
 
-static void usb_pointer_event_combine(USBPointerEvent *e, int xyrel,
+static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
                                       int x1, int y1, int z1) {
     if (xyrel) {
         e->xdx += x1;
@@ -471,8 +476,8 @@ static void usb_pointer_event_combine(USBPointerEvent *e, int xyrel,
 static void usb_pointer_event(void *opaque,
                               int x1, int y1, int z1, int buttons_state)
 {
-    USBHIDState *hs = opaque;
-    USBMouseState *s = &hs->ptr;
+    USBHIDState *us = opaque;
+    HIDState *hs = &us->hid;
     unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
     unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
 
@@ -483,25 +488,26 @@ static void usb_pointer_event(void *opaque,
      * the first event changed the button state.  */
     if (hs->n == QUEUE_LENGTH) {
         /* Queue full.  Discard old button state, combine motion normally.  */
-        s->queue[use_slot].buttons_state = buttons_state;
+        hs->ptr.queue[use_slot].buttons_state = buttons_state;
     } else if (hs->n < 2 ||
-               s->queue[use_slot].buttons_state != buttons_state ||
-               s->queue[previous_slot].buttons_state != s->queue[use_slot].buttons_state) {
+               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
+               hs->ptr.queue[previous_slot].buttons_state !=
+               hs->ptr.queue[use_slot].buttons_state) {
         /* Cannot or should not combine, so add an empty item to the queue.  */
         QUEUE_INCR(use_slot);
         hs->n++;
-        usb_pointer_event_clear(&s->queue[use_slot], buttons_state);
+        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
     }
-    usb_pointer_event_combine(&s->queue[use_slot],
-                              hs->kind == USB_MOUSE,
+    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
+                              hs->kind == HID_MOUSE,
                               x1, y1, z1);
-    usb_hid_changed(hs);
+    usb_hid_changed(us);
 }
 
 static void usb_keyboard_event(void *opaque, int keycode)
 {
-    USBHIDState *hs = opaque;
-    USBKeyboardState *s = &hs->kbd;
+    USBHIDState *us = opaque;
+    HIDState *hs = &us->hid;
     int slot;
 
     if (hs->n == QUEUE_LENGTH) {
@@ -509,13 +515,12 @@ static void usb_keyboard_event(void *opaque, int keycode)
         return;
     }
     slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
-    s->keycodes[slot] = keycode;
-    usb_hid_changed(hs);
+    hs->kbd.keycodes[slot] = keycode;
+    usb_hid_changed(us);
 }
 
-static void usb_keyboard_process_keycode(USBHIDState *hs)
+static void hid_keyboard_process_keycode(HIDState *hs)
 {
-    USBKeyboardState *s = &hs->kbd;
     uint8_t hid_code, key;
     int i, keycode, slot;
 
@@ -523,49 +528,55 @@ static void usb_keyboard_process_keycode(USBHIDState *hs)
         return;
     }
     slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
-    keycode = s->keycodes[slot];
+    keycode = hs->kbd.keycodes[slot];
 
     key = keycode & 0x7f;
-    hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
-    s->modifiers &= ~(1 << 8);
+    hid_code = usb_hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
+    hs->kbd.modifiers &= ~(1 << 8);
 
     switch (hid_code) {
     case 0x00:
         return;
 
     case 0xe0:
-        if (s->modifiers & (1 << 9)) {
-            s->modifiers ^= 3 << 8;
+        if (hs->kbd.modifiers & (1 << 9)) {
+            hs->kbd.modifiers ^= 3 << 8;
             return;
         }
     case 0xe1 ... 0xe7:
         if (keycode & (1 << 7)) {
-            s->modifiers &= ~(1 << (hid_code & 0x0f));
+            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
             return;
         }
     case 0xe8 ... 0xef:
-        s->modifiers |= 1 << (hid_code & 0x0f);
+        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
         return;
     }
 
     if (keycode & (1 << 7)) {
-        for (i = s->keys - 1; i >= 0; i --)
-            if (s->key[i] == hid_code) {
-                s->key[i] = s->key[-- s->keys];
-                s->key[s->keys] = 0x00;
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
+                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
+                hs->kbd.key[hs->kbd.keys] = 0x00;
                 break;
             }
-        if (i < 0)
+        }
+        if (i < 0) {
             return;
+        }
     } else {
-        for (i = s->keys - 1; i >= 0; i --)
-            if (s->key[i] == hid_code)
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
                 break;
+            }
+        }
         if (i < 0) {
-            if (s->keys < sizeof(s->key))
-                s->key[s->keys ++] = hid_code;
-        } else
+            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
+                hs->kbd.key[hs->kbd.keys++] = hid_code;
+            }
+        } else {
             return;
+        }
     }
 }
 
@@ -579,24 +590,23 @@ static inline int int_clamp(int val, int vmin, int vmax)
         return val;
 }
 
-static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
+static int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
 {
     int dx, dy, dz, b, l;
     int index;
-    USBMouseState *s = &hs->ptr;
-    USBPointerEvent *e;
+    HIDPointerEvent *e;
 
-    if (!s->mouse_grabbed) {
-        qemu_activate_mouse_event_handler(s->eh_entry);
-        s->mouse_grabbed = 1;
+    if (!hs->ptr.mouse_grabbed) {
+        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
+        hs->ptr.mouse_grabbed = 1;
     }
 
     /* When the buffer is empty, return the last event.  Relative
        movements will all be zero.  */
     index = (hs->n ? hs->head : hs->head - 1);
-    e = &s->queue[index & QUEUE_MASK];
+    e = &hs->ptr.queue[index & QUEUE_MASK];
 
-    if (hs->kind == USB_MOUSE) {
+    if (hs->kind == HID_MOUSE) {
         dx = int_clamp(e->xdx, -127, 127);
         dy = int_clamp(e->ydy, -127, 127);
         e->xdx -= dx;
@@ -618,7 +628,7 @@ static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
 
     if (hs->n &&
         !e->dz &&
-        (hs->kind == USB_TABLET || (!e->xdx && !e->ydy))) {
+        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
         /* that deals with this event */
         QUEUE_INCR(hs->head);
         hs->n--;
@@ -628,7 +638,7 @@ static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
     dz = 0 - dz;
     l = 0;
     switch (hs->kind) {
-    case USB_MOUSE:
+    case HID_MOUSE:
         if (len > l)
             buf[l++] = b;
         if (len > l)
@@ -639,7 +649,7 @@ static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
             buf[l++] = dz;
         break;
 
-    case USB_TABLET:
+    case HID_TABLET:
         if (len > l)
             buf[l++] = b;
         if (len > l)
@@ -661,25 +671,25 @@ static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
     return l;
 }
 
-static int usb_keyboard_poll(USBHIDState *hs, uint8_t *buf, int len)
+static int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
 {
-    USBKeyboardState *s = &hs->kbd;
     if (len < 2)
         return 0;
 
-    usb_keyboard_process_keycode(hs);
+    hid_keyboard_process_keycode(hs);
 
-    buf[0] = s->modifiers & 0xff;
+    buf[0] = hs->kbd.modifiers & 0xff;
     buf[1] = 0;
-    if (s->keys > 6)
+    if (hs->kbd.keys > 6) {
         memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
-    else
-        memcpy(buf + 2, s->key, MIN(8, len) - 2);
+    } else {
+        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
+    }
 
     return MIN(8, len);
 }
 
-static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
+static int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
 {
     if (len > 0) {
         int ledstate = 0;
@@ -688,13 +698,16 @@ static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
          * 0x04: Scroll Lock LED
          * 0x08: Compose LED
          * 0x10: Kana LED */
-        s->leds = buf[0];
-        if (s->leds & 0x04)
+        hs->kbd.leds = buf[0];
+        if (hs->kbd.leds & 0x04) {
             ledstate |= QEMU_SCROLL_LOCK_LED;
-        if (s->leds & 0x01)
+        }
+        if (hs->kbd.leds & 0x01) {
             ledstate |= QEMU_NUM_LOCK_LED;
-        if (s->leds & 0x02)
+        }
+        if (hs->kbd.leds & 0x02) {
             ledstate |= QEMU_CAPS_LOCK_LED;
+        }
         kbd_put_ledstate(ledstate);
     }
     return 0;
@@ -702,25 +715,25 @@ static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
 
 static void usb_mouse_handle_reset(USBDevice *dev)
 {
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
-    memset(s->ptr.queue, 0, sizeof (s->ptr.queue));
-    s->head = 0;
-    s->n = 0;
-    s->protocol = 1;
+    memset(us->hid.ptr.queue, 0, sizeof(us->hid.ptr.queue));
+    us->hid.head = 0;
+    us->hid.n = 0;
+    us->protocol = 1;
 }
 
 static void usb_keyboard_handle_reset(USBDevice *dev)
 {
-    USBHIDState *s = (USBHIDState *)dev;
-
-    qemu_add_kbd_event_handler(usb_keyboard_event, s);
-    memset(s->kbd.keycodes, 0, sizeof (s->kbd.keycodes));
-    s->head = 0;
-    s->n = 0;
-    memset(s->kbd.key, 0, sizeof (s->kbd.key));
-    s->kbd.keys = 0;
-    s->protocol = 1;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+
+    qemu_add_kbd_event_handler(usb_keyboard_event, us);
+    memset(us->hid.kbd.keycodes, 0, sizeof(us->hid.kbd.keycodes));
+    us->hid.head = 0;
+    us->hid.n = 0;
+    memset(us->hid.kbd.key, 0, sizeof(us->hid.kbd.key));
+    us->hid.kbd.keys = 0;
+    us->protocol = 1;
 }
 
 static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
@@ -731,7 +744,8 @@ static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
 static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
                int request, int value, int index, int length, uint8_t *data)
 {
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+    HIDState *hs = &us->hid;
     int ret;
 
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
@@ -740,7 +754,7 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
     }
 
     ret = 0;
-    switch(request) {
+    switch (request) {
     case DeviceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
         ret = 1;
@@ -750,17 +764,17 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
         break;
         /* hid specific requests */
     case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
-        switch(value >> 8) {
+        switch (value >> 8) {
         case 0x22:
-	    if (s->kind == USB_MOUSE) {
+            if (hs->kind == HID_MOUSE) {
 		memcpy(data, qemu_mouse_hid_report_descriptor,
 		       sizeof(qemu_mouse_hid_report_descriptor));
 		ret = sizeof(qemu_mouse_hid_report_descriptor);
-	    } else if (s->kind == USB_TABLET) {
-		memcpy(data, qemu_tablet_hid_report_descriptor,
+            } else if (hs->kind == HID_TABLET) {
+                memcpy(data, qemu_tablet_hid_report_descriptor,
 		       sizeof(qemu_tablet_hid_report_descriptor));
 		ret = sizeof(qemu_tablet_hid_report_descriptor);
-            } else if (s->kind == USB_KEYBOARD) {
+            } else if (hs->kind == HID_KEYBOARD) {
                 memcpy(data, qemu_keyboard_hid_report_descriptor,
                        sizeof(qemu_keyboard_hid_report_descriptor));
                 ret = sizeof(qemu_keyboard_hid_report_descriptor);
@@ -771,38 +785,41 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
         }
         break;
     case GET_REPORT:
-        if (s->kind == USB_MOUSE || s->kind == USB_TABLET) {
-            ret = usb_pointer_poll(s, data, length);
-        } else if (s->kind == USB_KEYBOARD) {
-            ret = usb_keyboard_poll(s, data, length);
+        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+            ret = hid_pointer_poll(hs, data, length);
+        } else if (hs->kind == HID_KEYBOARD) {
+            ret = hid_keyboard_poll(hs, data, length);
         }
-        s->changed = s->n > 0;
+        us->changed = hs->n > 0;
         break;
     case SET_REPORT:
-        if (s->kind == USB_KEYBOARD)
-            ret = usb_keyboard_write(&s->kbd, data, length);
-        else
+        if (hs->kind == HID_KEYBOARD) {
+            ret = hid_keyboard_write(hs, data, length);
+        } else {
             goto fail;
+        }
         break;
     case GET_PROTOCOL:
-        if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
+        if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
             goto fail;
+        }
         ret = 1;
-        data[0] = s->protocol;
+        data[0] = us->protocol;
         break;
     case SET_PROTOCOL:
-        if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
+        if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
             goto fail;
+        }
         ret = 0;
-        s->protocol = value;
+        us->protocol = value;
         break;
     case GET_IDLE:
         ret = 1;
-        data[0] = s->idle;
+        data[0] = us->idle;
         break;
     case SET_IDLE:
-        s->idle = (uint8_t) (value >> 8);
-        usb_hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
+        us->idle = (uint8_t) (value >> 8);
+        usb_hid_set_next_idle(us, qemu_get_clock_ns(vm_clock));
         ret = 0;
         break;
     default:
@@ -815,25 +832,27 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
 
 static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
 {
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+    HIDState *hs = &us->hid;
     uint8_t buf[p->iov.size];
     int ret = 0;
 
-    switch(p->pid) {
+    switch (p->pid) {
     case USB_TOKEN_IN:
         if (p->devep == 1) {
             int64_t curtime = qemu_get_clock_ns(vm_clock);
-            if (!s->changed && (!s->idle || s->next_idle_clock - curtime > 0))
+            if (!us->changed &&
+                (!us->idle || us->next_idle_clock - curtime > 0)) {
                 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, buf, p->iov.size);
             }
-            else if (s->kind == USB_KEYBOARD) {
-                ret = usb_keyboard_poll(s, buf, p->iov.size);
+            usb_hid_set_next_idle(us, curtime);
+            if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+                ret = hid_pointer_poll(hs, buf, p->iov.size);
+            } else if (hs->kind == HID_KEYBOARD) {
+                ret = hid_keyboard_poll(hs, buf, p->iov.size);
             }
             usb_packet_copy(p, buf, ret);
-            s->changed = s->n > 0;
+            us->changed = hs->n > 0;
         } else {
             goto fail;
         }
@@ -849,50 +868,51 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
 
 static void usb_hid_handle_destroy(USBDevice *dev)
 {
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
-    switch(s->kind) {
-    case USB_KEYBOARD:
+    switch (us->hid.kind) {
+    case HID_KEYBOARD:
         qemu_remove_kbd_event_handler();
         break;
     default:
-        qemu_remove_mouse_event_handler(s->ptr.eh_entry);
+        qemu_remove_mouse_event_handler(us->hid.ptr.eh_entry);
     }
 }
 
 static int usb_hid_initfn(USBDevice *dev, int kind)
 {
-    USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev);
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+    HIDState *hs = &us->hid;
 
     usb_desc_init(dev);
-    s->kind = kind;
-
-    if (s->kind == USB_MOUSE) {
-        s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, s,
-                                                       0, "QEMU USB Mouse");
-    } else if (s->kind == USB_TABLET) {
-        s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, s,
-                                                       1, "QEMU USB Tablet");
+    hs->kind = kind;
+
+    if (hs->kind == HID_MOUSE) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, us,
+                                                        0, "QEMU HID Mouse");
+    } else if (hs->kind == HID_TABLET) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, us,
+                                                        1, "QEMU HID Tablet");
     }
 
     /* Force poll routine to be run and grab input the first time.  */
-    s->changed = 1;
+    us->changed = 1;
     return 0;
 }
 
 static int usb_tablet_initfn(USBDevice *dev)
 {
-    return usb_hid_initfn(dev, USB_TABLET);
+    return usb_hid_initfn(dev, HID_TABLET);
 }
 
 static int usb_mouse_initfn(USBDevice *dev)
 {
-    return usb_hid_initfn(dev, USB_MOUSE);
+    return usb_hid_initfn(dev, HID_MOUSE);
 }
 
 static int usb_keyboard_initfn(USBDevice *dev)
 {
-    return usb_hid_initfn(dev, USB_KEYBOARD);
+    return usb_hid_initfn(dev, HID_KEYBOARD);
 }
 
 void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
@@ -918,10 +938,10 @@ static const VMStateDescription vmstate_usb_ptr_queue = {
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (VMStateField []) {
-        VMSTATE_INT32(xdx, USBPointerEvent),
-        VMSTATE_INT32(ydy, USBPointerEvent),
-        VMSTATE_INT32(dz, USBPointerEvent),
-        VMSTATE_INT32(buttons_state, USBPointerEvent),
+        VMSTATE_INT32(xdx, HIDPointerEvent),
+        VMSTATE_INT32(ydy, HIDPointerEvent),
+        VMSTATE_INT32(dz, HIDPointerEvent),
+        VMSTATE_INT32(buttons_state, HIDPointerEvent),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -932,10 +952,10 @@ static const VMStateDescription vmstate_usb_ptr = {
     .post_load = usb_hid_post_load,
     .fields = (VMStateField []) {
         VMSTATE_USB_DEVICE(dev, USBHIDState),
-        VMSTATE_STRUCT_ARRAY(ptr.queue, USBHIDState, QUEUE_LENGTH, 0,
-                             vmstate_usb_ptr_queue, USBPointerEvent),
-        VMSTATE_UINT32(head, USBHIDState),
-        VMSTATE_UINT32(n, USBHIDState),
+        VMSTATE_STRUCT_ARRAY(hid.ptr.queue, USBHIDState, QUEUE_LENGTH, 0,
+                             vmstate_usb_ptr_queue, HIDPointerEvent),
+        VMSTATE_UINT32(hid.head, USBHIDState),
+        VMSTATE_UINT32(hid.n, USBHIDState),
         VMSTATE_INT32(protocol, USBHIDState),
         VMSTATE_UINT8(idle, USBHIDState),
         VMSTATE_END_OF_LIST()
@@ -949,13 +969,13 @@ static const VMStateDescription vmstate_usb_kbd = {
     .post_load = usb_hid_post_load,
     .fields = (VMStateField []) {
         VMSTATE_USB_DEVICE(dev, USBHIDState),
-        VMSTATE_UINT32_ARRAY(kbd.keycodes, USBHIDState, QUEUE_LENGTH),
-        VMSTATE_UINT32(head, USBHIDState),
-        VMSTATE_UINT32(n, USBHIDState),
-        VMSTATE_UINT16(kbd.modifiers, USBHIDState),
-        VMSTATE_UINT8(kbd.leds, USBHIDState),
-        VMSTATE_UINT8_ARRAY(kbd.key, USBHIDState, 16),
-        VMSTATE_INT32(kbd.keys, USBHIDState),
+        VMSTATE_UINT32_ARRAY(hid.kbd.keycodes, USBHIDState, QUEUE_LENGTH),
+        VMSTATE_UINT32(hid.head, USBHIDState),
+        VMSTATE_UINT32(hid.n, USBHIDState),
+        VMSTATE_UINT16(hid.kbd.modifiers, USBHIDState),
+        VMSTATE_UINT8(hid.kbd.leds, USBHIDState),
+        VMSTATE_UINT8_ARRAY(hid.kbd.key, USBHIDState, 16),
+        VMSTATE_INT32(hid.kbd.keys, USBHIDState),
         VMSTATE_INT32(protocol, USBHIDState),
         VMSTATE_UINT8(idle, USBHIDState),
         VMSTATE_END_OF_LIST()
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 12/16] usb-hid: add event callback
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (10 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 11/16] usb-hid: create & use HIDState Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 13/16] usb-hid: add hid_has_events() Gerd Hoffmann
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add callback for event notification, which allows to un-usbify more
functions.  Also split separate hid_* functions for reset and release.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb-hid.c |  106 ++++++++++++++++++++++++++++++++++-----------------------
 1 files changed, 63 insertions(+), 43 deletions(-)

diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index f5d6c61..870cc66 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -54,6 +54,9 @@ typedef struct HIDPointerEvent {
 #define QUEUE_MASK      (QUEUE_LENGTH-1u)
 #define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
 
+typedef struct HIDState HIDState;
+typedef void (*HIDEventFunc)(HIDState *s);
+
 typedef struct HIDMouseState {
     HIDPointerEvent queue[QUEUE_LENGTH];
     int mouse_grabbed;
@@ -68,7 +71,7 @@ typedef struct HIDKeyboardState {
     int32_t keys;
 } HIDKeyboardState;
 
-typedef struct HIDState {
+struct HIDState {
     union {
         HIDMouseState ptr;
         HIDKeyboardState kbd;
@@ -76,7 +79,8 @@ typedef struct HIDState {
     uint32_t head; /* index into circular queue */
     uint32_t n;
     int kind;
-} HIDState;
+    HIDEventFunc event;
+};
 
 typedef struct USBHIDState {
     USBDevice dev;
@@ -440,14 +444,17 @@ static const uint8_t usb_hid_usage_keys[0x100] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-static void usb_hid_changed(USBHIDState *hs)
+static void usb_hid_changed(HIDState *hs)
 {
-    hs->changed = 1;
+    USBHIDState *us = container_of(hs, USBHIDState, hid);
 
-    if (hs->datain)
-        hs->datain(hs->datain_opaque);
+    us->changed = 1;
+
+    if (us->datain) {
+        us->datain(us->datain_opaque);
+    }
 
-    usb_wakeup(&hs->dev);
+    usb_wakeup(&us->dev);
 }
 
 static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
@@ -473,11 +480,10 @@ static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
     e->dz += z1;
 }
 
-static void usb_pointer_event(void *opaque,
+static void hid_pointer_event(void *opaque,
                               int x1, int y1, int z1, int buttons_state)
 {
-    USBHIDState *us = opaque;
-    HIDState *hs = &us->hid;
+    HIDState *hs = opaque;
     unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
     unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
 
@@ -501,13 +507,12 @@ static void usb_pointer_event(void *opaque,
     hid_pointer_event_combine(&hs->ptr.queue[use_slot],
                               hs->kind == HID_MOUSE,
                               x1, y1, z1);
-    usb_hid_changed(us);
+    hs->event(hs);
 }
 
-static void usb_keyboard_event(void *opaque, int keycode)
+static void hid_keyboard_event(void *opaque, int keycode)
 {
-    USBHIDState *us = opaque;
-    HIDState *hs = &us->hid;
+    HIDState *hs = opaque;
     int slot;
 
     if (hs->n == QUEUE_LENGTH) {
@@ -516,7 +521,7 @@ static void usb_keyboard_event(void *opaque, int keycode)
     }
     slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
     hs->kbd.keycodes[slot] = keycode;
-    usb_hid_changed(us);
+    hs->event(hs);
 }
 
 static void hid_keyboard_process_keycode(HIDState *hs)
@@ -713,26 +718,29 @@ static int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
     return 0;
 }
 
-static void usb_mouse_handle_reset(USBDevice *dev)
+static void hid_handle_reset(HIDState *hs)
 {
-    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
-
-    memset(us->hid.ptr.queue, 0, sizeof(us->hid.ptr.queue));
-    us->hid.head = 0;
-    us->hid.n = 0;
-    us->protocol = 1;
+    switch (hs->kind) {
+    case HID_KEYBOARD:
+        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
+        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
+        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
+        hs->kbd.keys = 0;
+        break;
+    case HID_MOUSE:
+    case HID_TABLET:
+        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
+        break;
+    }
+    hs->head = 0;
+    hs->n = 0;
 }
 
-static void usb_keyboard_handle_reset(USBDevice *dev)
+static void usb_hid_handle_reset(USBDevice *dev)
 {
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
-    qemu_add_kbd_event_handler(usb_keyboard_event, us);
-    memset(us->hid.kbd.keycodes, 0, sizeof(us->hid.kbd.keycodes));
-    us->hid.head = 0;
-    us->hid.n = 0;
-    memset(us->hid.kbd.key, 0, sizeof(us->hid.kbd.key));
-    us->hid.kbd.keys = 0;
+    hid_handle_reset(&us->hid);
     us->protocol = 1;
 }
 
@@ -866,34 +874,46 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
     return ret;
 }
 
-static void usb_hid_handle_destroy(USBDevice *dev)
+static void hid_free(HIDState *hs)
 {
-    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
-
-    switch (us->hid.kind) {
+    switch (hs->kind) {
     case HID_KEYBOARD:
         qemu_remove_kbd_event_handler();
         break;
-    default:
-        qemu_remove_mouse_event_handler(us->hid.ptr.eh_entry);
+    case HID_MOUSE:
+    case HID_TABLET:
+        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
+        break;
     }
 }
 
-static int usb_hid_initfn(USBDevice *dev, int kind)
+static void usb_hid_handle_destroy(USBDevice *dev)
 {
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
-    HIDState *hs = &us->hid;
 
-    usb_desc_init(dev);
+    hid_free(&us->hid);
+}
+
+static void hid_init(HIDState *hs, int kind, HIDEventFunc event)
+{
     hs->kind = kind;
+    hs->event = event;
 
     if (hs->kind == HID_MOUSE) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, us,
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
                                                         0, "QEMU HID Mouse");
     } else if (hs->kind == HID_TABLET) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, us,
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
                                                         1, "QEMU HID Tablet");
     }
+}
+
+static int usb_hid_initfn(USBDevice *dev, int kind)
+{
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+
+    usb_desc_init(dev);
+    hid_init(&us->hid, kind, usb_hid_changed);
 
     /* Force poll routine to be run and grab input the first time.  */
     us->changed = 1;
@@ -992,7 +1012,7 @@ static struct USBDeviceInfo hid_info[] = {
         .usb_desc       = &desc_tablet,
         .init           = usb_tablet_initfn,
         .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_mouse_handle_reset,
+        .handle_reset   = usb_hid_handle_reset,
         .handle_control = usb_hid_handle_control,
         .handle_data    = usb_hid_handle_data,
         .handle_destroy = usb_hid_handle_destroy,
@@ -1005,7 +1025,7 @@ static struct USBDeviceInfo hid_info[] = {
         .usb_desc       = &desc_mouse,
         .init           = usb_mouse_initfn,
         .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_mouse_handle_reset,
+        .handle_reset   = usb_hid_handle_reset,
         .handle_control = usb_hid_handle_control,
         .handle_data    = usb_hid_handle_data,
         .handle_destroy = usb_hid_handle_destroy,
@@ -1018,7 +1038,7 @@ static struct USBDeviceInfo hid_info[] = {
         .usb_desc       = &desc_keyboard,
         .init           = usb_keyboard_initfn,
         .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_keyboard_handle_reset,
+        .handle_reset   = usb_hid_handle_reset,
         .handle_control = usb_hid_handle_control,
         .handle_data    = usb_hid_handle_data,
         .handle_destroy = usb_hid_handle_destroy,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 13/16] usb-hid: add hid_has_events()
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (11 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 12/16] usb-hid: add event callback Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-08  8:32   ` TeLeMan
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 14/16] usb-hid: split hid code to hw/hid.[ch] Gerd Hoffmann
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add hid_has_events function, use it to figure whenever there are pending
events instead of checking and updating USBHIDState->changed.

Setting ->changed to 1 on init is removed, that should have absolutely
no effect as the initial state of ->idle is 0 so we report hid state
anyway until the guest configures some idle time.  Also should clear
->idle on reset.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb-hid.c |   16 +++++++---------
 1 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 870cc66..b730692 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -88,7 +88,6 @@ typedef struct USBHIDState {
     int32_t protocol;
     uint8_t idle;
     int64_t next_idle_clock;
-    int changed;
     void *datain_opaque;
     void (*datain)(void *);
 } USBHIDState;
@@ -444,12 +443,15 @@ static const uint8_t usb_hid_usage_keys[0x100] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
+static bool hid_has_events(HIDState *hs)
+{
+    return hs->n > 0;
+}
+
 static void usb_hid_changed(HIDState *hs)
 {
     USBHIDState *us = container_of(hs, USBHIDState, hid);
 
-    us->changed = 1;
-
     if (us->datain) {
         us->datain(us->datain_opaque);
     }
@@ -742,6 +744,7 @@ static void usb_hid_handle_reset(USBDevice *dev)
 
     hid_handle_reset(&us->hid);
     us->protocol = 1;
+    us->idle = 0;
 }
 
 static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
@@ -798,7 +801,6 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
         } else if (hs->kind == HID_KEYBOARD) {
             ret = hid_keyboard_poll(hs, data, length);
         }
-        us->changed = hs->n > 0;
         break;
     case SET_REPORT:
         if (hs->kind == HID_KEYBOARD) {
@@ -849,7 +851,7 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
     case USB_TOKEN_IN:
         if (p->devep == 1) {
             int64_t curtime = qemu_get_clock_ns(vm_clock);
-            if (!us->changed &&
+            if (!hid_has_events(hs) &&
                 (!us->idle || us->next_idle_clock - curtime > 0)) {
                 return USB_RET_NAK;
             }
@@ -860,7 +862,6 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
                 ret = hid_keyboard_poll(hs, buf, p->iov.size);
             }
             usb_packet_copy(p, buf, ret);
-            us->changed = hs->n > 0;
         } else {
             goto fail;
         }
@@ -914,9 +915,6 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
 
     usb_desc_init(dev);
     hid_init(&us->hid, kind, usb_hid_changed);
-
-    /* Force poll routine to be run and grab input the first time.  */
-    us->changed = 1;
     return 0;
 }
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 14/16] usb-hid: split hid code to hw/hid.[ch]
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (12 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 13/16] usb-hid: add hid_has_events() Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 15/16] hid: move idle+protocol from usb-hid to hid too Gerd Hoffmann
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Almost pure code motion.  Unstatic hid interface functions and add
them to the header file.  Some renames.  Some code style cleanups.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.objs |    1 +
 hw/hid.c      |  395 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/hid.h      |   54 ++++++++
 hw/usb-hid.c  |  397 +--------------------------------------------------------
 4 files changed, 452 insertions(+), 395 deletions(-)
 create mode 100644 hw/hid.c
 create mode 100644 hw/hid.h

diff --git a/Makefile.objs b/Makefile.objs
index 3d1a4de..eb5e1dc 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -89,6 +89,7 @@ common-obj-y += i2c.o smbus.o smbus_eeprom.o
 common-obj-y += eeprom93xx.o
 common-obj-y += scsi-disk.o cdrom.o
 common-obj-y += scsi-generic.o scsi-bus.o
+common-obj-y += hid.o
 common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
 common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o
 common-obj-$(CONFIG_SSI) += ssi.o
diff --git a/hw/hid.c b/hw/hid.c
new file mode 100644
index 0000000..1893ae5
--- /dev/null
+++ b/hw/hid.c
@@ -0,0 +1,395 @@
+/*
+ * QEMU HID devices
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.com)
+ *
+ * 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 "hw.h"
+#include "console.h"
+#include "hid.h"
+
+#define HID_USAGE_ERROR_ROLLOVER        0x01
+#define HID_USAGE_POSTFAIL              0x02
+#define HID_USAGE_ERROR_UNDEFINED       0x03
+
+/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
+ * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
+static const uint8_t hid_usage_keys[0x100] = {
+    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
+    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
+    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
+    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
+    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
+    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
+    0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
+    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
+    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
+    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
+
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
+    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
+    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
+    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+bool hid_has_events(HIDState *hs)
+{
+    return hs->n > 0;
+}
+
+static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
+{
+    e->xdx = e->ydy = e->dz = 0;
+    e->buttons_state = buttons;
+}
+
+static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
+                                      int x1, int y1, int z1) {
+    if (xyrel) {
+        e->xdx += x1;
+        e->ydy += y1;
+    } else {
+        e->xdx = x1;
+        e->ydy = y1;
+        /* Windows drivers do not like the 0/0 position and ignore such
+         * events. */
+        if (!(x1 | y1)) {
+            x1 = 1;
+        }
+    }
+    e->dz += z1;
+}
+
+static void hid_pointer_event(void *opaque,
+                              int x1, int y1, int z1, int buttons_state)
+{
+    HIDState *hs = opaque;
+    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
+    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
+
+    /* We combine events where feasible to keep the queue small.  We shouldn't
+     * combine anything with the first event of a particular button state, as
+     * that would change the location of the button state change.  When the
+     * queue is empty, a second event is needed because we don't know if
+     * the first event changed the button state.  */
+    if (hs->n == QUEUE_LENGTH) {
+        /* Queue full.  Discard old button state, combine motion normally.  */
+        hs->ptr.queue[use_slot].buttons_state = buttons_state;
+    } else if (hs->n < 2 ||
+               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
+               hs->ptr.queue[previous_slot].buttons_state !=
+               hs->ptr.queue[use_slot].buttons_state) {
+        /* Cannot or should not combine, so add an empty item to the queue.  */
+        QUEUE_INCR(use_slot);
+        hs->n++;
+        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
+    }
+    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
+                              hs->kind == HID_MOUSE,
+                              x1, y1, z1);
+    hs->event(hs);
+}
+
+static void hid_keyboard_event(void *opaque, int keycode)
+{
+    HIDState *hs = opaque;
+    int slot;
+
+    if (hs->n == QUEUE_LENGTH) {
+        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
+        return;
+    }
+    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
+    hs->kbd.keycodes[slot] = keycode;
+    hs->event(hs);
+}
+
+static void hid_keyboard_process_keycode(HIDState *hs)
+{
+    uint8_t hid_code, key;
+    int i, keycode, slot;
+
+    if (hs->n == 0) {
+        return;
+    }
+    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
+    keycode = hs->kbd.keycodes[slot];
+
+    key = keycode & 0x7f;
+    hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
+    hs->kbd.modifiers &= ~(1 << 8);
+
+    switch (hid_code) {
+    case 0x00:
+        return;
+
+    case 0xe0:
+        if (hs->kbd.modifiers & (1 << 9)) {
+            hs->kbd.modifiers ^= 3 << 8;
+            return;
+        }
+    case 0xe1 ... 0xe7:
+        if (keycode & (1 << 7)) {
+            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
+            return;
+        }
+    case 0xe8 ... 0xef:
+        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
+        return;
+    }
+
+    if (keycode & (1 << 7)) {
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
+                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
+                hs->kbd.key[hs->kbd.keys] = 0x00;
+                break;
+            }
+        }
+        if (i < 0) {
+            return;
+        }
+    } else {
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
+                break;
+            }
+        }
+        if (i < 0) {
+            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
+                hs->kbd.key[hs->kbd.keys++] = hid_code;
+            }
+        } else {
+            return;
+        }
+    }
+}
+
+static inline int int_clamp(int val, int vmin, int vmax)
+{
+    if (val < vmin) {
+        return vmin;
+    } else if (val > vmax) {
+        return vmax;
+    } else {
+        return val;
+    }
+}
+
+int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
+{
+    int dx, dy, dz, b, l;
+    int index;
+    HIDPointerEvent *e;
+
+    if (!hs->ptr.mouse_grabbed) {
+        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
+        hs->ptr.mouse_grabbed = 1;
+    }
+
+    /* When the buffer is empty, return the last event.  Relative
+       movements will all be zero.  */
+    index = (hs->n ? hs->head : hs->head - 1);
+    e = &hs->ptr.queue[index & QUEUE_MASK];
+
+    if (hs->kind == HID_MOUSE) {
+        dx = int_clamp(e->xdx, -127, 127);
+        dy = int_clamp(e->ydy, -127, 127);
+        e->xdx -= dx;
+        e->ydy -= dy;
+    } else {
+        dx = e->xdx;
+        dy = e->ydy;
+    }
+    dz = int_clamp(e->dz, -127, 127);
+    e->dz -= dz;
+
+    b = 0;
+    if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
+        b |= 0x01;
+    }
+    if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
+        b |= 0x02;
+    }
+    if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
+        b |= 0x04;
+    }
+
+    if (hs->n &&
+        !e->dz &&
+        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
+        /* that deals with this event */
+        QUEUE_INCR(hs->head);
+        hs->n--;
+    }
+
+    /* Appears we have to invert the wheel direction */
+    dz = 0 - dz;
+    l = 0;
+    switch (hs->kind) {
+    case HID_MOUSE:
+        if (len > l) {
+            buf[l++] = b;
+        }
+        if (len > l) {
+            buf[l++] = dx;
+        }
+        if (len > l) {
+            buf[l++] = dy;
+        }
+        if (len > l) {
+            buf[l++] = dz;
+        }
+        break;
+
+    case HID_TABLET:
+        if (len > l) {
+            buf[l++] = b;
+        }
+        if (len > l) {
+            buf[l++] = dx & 0xff;
+        }
+        if (len > l) {
+            buf[l++] = dx >> 8;
+        }
+        if (len > l) {
+            buf[l++] = dy & 0xff;
+        }
+        if (len > l) {
+            buf[l++] = dy >> 8;
+        }
+        if (len > l) {
+            buf[l++] = dz;
+        }
+        break;
+
+    default:
+        abort();
+    }
+
+    return l;
+}
+
+int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
+{
+    if (len < 2) {
+        return 0;
+    }
+
+    hid_keyboard_process_keycode(hs);
+
+    buf[0] = hs->kbd.modifiers & 0xff;
+    buf[1] = 0;
+    if (hs->kbd.keys > 6) {
+        memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
+    } else {
+        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
+    }
+
+    return MIN(8, len);
+}
+
+int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
+{
+    if (len > 0) {
+        int ledstate = 0;
+        /* 0x01: Num Lock LED
+         * 0x02: Caps Lock LED
+         * 0x04: Scroll Lock LED
+         * 0x08: Compose LED
+         * 0x10: Kana LED */
+        hs->kbd.leds = buf[0];
+        if (hs->kbd.leds & 0x04) {
+            ledstate |= QEMU_SCROLL_LOCK_LED;
+        }
+        if (hs->kbd.leds & 0x01) {
+            ledstate |= QEMU_NUM_LOCK_LED;
+        }
+        if (hs->kbd.leds & 0x02) {
+            ledstate |= QEMU_CAPS_LOCK_LED;
+        }
+        kbd_put_ledstate(ledstate);
+    }
+    return 0;
+}
+
+void hid_reset(HIDState *hs)
+{
+    switch (hs->kind) {
+    case HID_KEYBOARD:
+        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
+        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
+        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
+        hs->kbd.keys = 0;
+        break;
+    case HID_MOUSE:
+    case HID_TABLET:
+        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
+        break;
+    }
+    hs->head = 0;
+    hs->n = 0;
+}
+
+void hid_free(HIDState *hs)
+{
+    switch (hs->kind) {
+    case HID_KEYBOARD:
+        qemu_remove_kbd_event_handler();
+        break;
+    case HID_MOUSE:
+    case HID_TABLET:
+        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
+        break;
+    }
+}
+
+void hid_init(HIDState *hs, int kind, HIDEventFunc event)
+{
+    hs->kind = kind;
+    hs->event = event;
+
+    if (hs->kind == HID_MOUSE) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
+                                                        0, "QEMU HID Mouse");
+    } else if (hs->kind == HID_TABLET) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
+                                                        1, "QEMU HID Tablet");
+    }
+}
diff --git a/hw/hid.h b/hw/hid.h
new file mode 100644
index 0000000..99910c3
--- /dev/null
+++ b/hw/hid.h
@@ -0,0 +1,54 @@
+#ifndef QEMU_HID_H
+#define QEMU_HID_H
+
+#define HID_MOUSE     1
+#define HID_TABLET    2
+#define HID_KEYBOARD  3
+
+typedef struct HIDPointerEvent {
+    int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
+    int32_t dz, buttons_state;
+} HIDPointerEvent;
+
+#define QUEUE_LENGTH    16 /* should be enough for a triple-click */
+#define QUEUE_MASK      (QUEUE_LENGTH-1u)
+#define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
+
+typedef struct HIDState HIDState;
+typedef void (*HIDEventFunc)(HIDState *s);
+
+typedef struct HIDMouseState {
+    HIDPointerEvent queue[QUEUE_LENGTH];
+    int mouse_grabbed;
+    QEMUPutMouseEntry *eh_entry;
+} HIDMouseState;
+
+typedef struct HIDKeyboardState {
+    uint32_t keycodes[QUEUE_LENGTH];
+    uint16_t modifiers;
+    uint8_t leds;
+    uint8_t key[16];
+    int32_t keys;
+} HIDKeyboardState;
+
+struct HIDState {
+    union {
+        HIDMouseState ptr;
+        HIDKeyboardState kbd;
+    };
+    uint32_t head; /* index into circular queue */
+    uint32_t n;
+    int kind;
+    HIDEventFunc event;
+};
+
+void hid_init(HIDState *hs, int kind, HIDEventFunc event);
+void hid_reset(HIDState *hs);
+void hid_free(HIDState *hs);
+
+bool hid_has_events(HIDState *hs);
+int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
+int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
+int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len);
+
+#endif /* QEMU_HID_H */
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index b730692..48ce743 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -27,6 +27,7 @@
 #include "usb.h"
 #include "usb-desc.h"
 #include "qemu-timer.h"
+#include "hid.h"
 
 /* HID interface requests */
 #define GET_REPORT   0xa101
@@ -41,47 +42,6 @@
 #define USB_DT_REPORT 0x22
 #define USB_DT_PHY    0x23
 
-#define HID_MOUSE     1
-#define HID_TABLET    2
-#define HID_KEYBOARD  3
-
-typedef struct HIDPointerEvent {
-    int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
-    int32_t dz, buttons_state;
-} HIDPointerEvent;
-
-#define QUEUE_LENGTH    16 /* should be enough for a triple-click */
-#define QUEUE_MASK      (QUEUE_LENGTH-1u)
-#define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
-
-typedef struct HIDState HIDState;
-typedef void (*HIDEventFunc)(HIDState *s);
-
-typedef struct HIDMouseState {
-    HIDPointerEvent queue[QUEUE_LENGTH];
-    int mouse_grabbed;
-    QEMUPutMouseEntry *eh_entry;
-} HIDMouseState;
-
-typedef struct HIDKeyboardState {
-    uint32_t keycodes[QUEUE_LENGTH];
-    uint16_t modifiers;
-    uint8_t leds;
-    uint8_t key[16];
-    int32_t keys;
-} HIDKeyboardState;
-
-struct HIDState {
-    union {
-        HIDMouseState ptr;
-        HIDKeyboardState kbd;
-    };
-    uint32_t head; /* index into circular queue */
-    uint32_t n;
-    int kind;
-    HIDEventFunc event;
-};
-
 typedef struct USBHIDState {
     USBDevice dev;
     HIDState hid;
@@ -401,53 +361,6 @@ static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
     0xc0,		/* End Collection */
 };
 
-#define USB_HID_USAGE_ERROR_ROLLOVER	0x01
-#define USB_HID_USAGE_POSTFAIL		0x02
-#define USB_HID_USAGE_ERROR_UNDEFINED	0x03
-
-/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
- * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
-static const uint8_t usb_hid_usage_keys[0x100] = {
-    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
-    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
-    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
-    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
-    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
-    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
-    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
-    0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
-    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
-    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
-    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
-    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
-    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
-
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
-    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
-    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
-    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static bool hid_has_events(HIDState *hs)
-{
-    return hs->n > 0;
-}
-
 static void usb_hid_changed(HIDState *hs)
 {
     USBHIDState *us = container_of(hs, USBHIDState, hid);
@@ -459,290 +372,11 @@ static void usb_hid_changed(HIDState *hs)
     usb_wakeup(&us->dev);
 }
 
-static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
-{
-    e->xdx = e->ydy = e->dz = 0;
-    e->buttons_state = buttons;
-}
-
-static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
-                                      int x1, int y1, int z1) {
-    if (xyrel) {
-        e->xdx += x1;
-        e->ydy += y1;
-    } else {
-        e->xdx = x1;
-        e->ydy = y1;
-        /* Windows drivers do not like the 0/0 position and ignore such
-         * events. */
-        if (!(x1 | y1)) {
-            x1 = 1;
-        }
-    }
-    e->dz += z1;
-}
-
-static void hid_pointer_event(void *opaque,
-                              int x1, int y1, int z1, int buttons_state)
-{
-    HIDState *hs = opaque;
-    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
-    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
-
-    /* We combine events where feasible to keep the queue small.  We shouldn't
-     * combine anything with the first event of a particular button state, as
-     * that would change the location of the button state change.  When the
-     * queue is empty, a second event is needed because we don't know if
-     * the first event changed the button state.  */
-    if (hs->n == QUEUE_LENGTH) {
-        /* Queue full.  Discard old button state, combine motion normally.  */
-        hs->ptr.queue[use_slot].buttons_state = buttons_state;
-    } else if (hs->n < 2 ||
-               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
-               hs->ptr.queue[previous_slot].buttons_state !=
-               hs->ptr.queue[use_slot].buttons_state) {
-        /* Cannot or should not combine, so add an empty item to the queue.  */
-        QUEUE_INCR(use_slot);
-        hs->n++;
-        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
-    }
-    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
-                              hs->kind == HID_MOUSE,
-                              x1, y1, z1);
-    hs->event(hs);
-}
-
-static void hid_keyboard_event(void *opaque, int keycode)
-{
-    HIDState *hs = opaque;
-    int slot;
-
-    if (hs->n == QUEUE_LENGTH) {
-        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
-        return;
-    }
-    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
-    hs->kbd.keycodes[slot] = keycode;
-    hs->event(hs);
-}
-
-static void hid_keyboard_process_keycode(HIDState *hs)
-{
-    uint8_t hid_code, key;
-    int i, keycode, slot;
-
-    if (hs->n == 0) {
-        return;
-    }
-    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
-    keycode = hs->kbd.keycodes[slot];
-
-    key = keycode & 0x7f;
-    hid_code = usb_hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
-    hs->kbd.modifiers &= ~(1 << 8);
-
-    switch (hid_code) {
-    case 0x00:
-        return;
-
-    case 0xe0:
-        if (hs->kbd.modifiers & (1 << 9)) {
-            hs->kbd.modifiers ^= 3 << 8;
-            return;
-        }
-    case 0xe1 ... 0xe7:
-        if (keycode & (1 << 7)) {
-            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
-            return;
-        }
-    case 0xe8 ... 0xef:
-        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
-        return;
-    }
-
-    if (keycode & (1 << 7)) {
-        for (i = hs->kbd.keys - 1; i >= 0; i--) {
-            if (hs->kbd.key[i] == hid_code) {
-                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
-                hs->kbd.key[hs->kbd.keys] = 0x00;
-                break;
-            }
-        }
-        if (i < 0) {
-            return;
-        }
-    } else {
-        for (i = hs->kbd.keys - 1; i >= 0; i--) {
-            if (hs->kbd.key[i] == hid_code) {
-                break;
-            }
-        }
-        if (i < 0) {
-            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
-                hs->kbd.key[hs->kbd.keys++] = hid_code;
-            }
-        } else {
-            return;
-        }
-    }
-}
-
-static inline int int_clamp(int val, int vmin, int vmax)
-{
-    if (val < vmin)
-        return vmin;
-    else if (val > vmax)
-        return vmax;
-    else
-        return val;
-}
-
-static int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
-{
-    int dx, dy, dz, b, l;
-    int index;
-    HIDPointerEvent *e;
-
-    if (!hs->ptr.mouse_grabbed) {
-        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
-        hs->ptr.mouse_grabbed = 1;
-    }
-
-    /* When the buffer is empty, return the last event.  Relative
-       movements will all be zero.  */
-    index = (hs->n ? hs->head : hs->head - 1);
-    e = &hs->ptr.queue[index & QUEUE_MASK];
-
-    if (hs->kind == HID_MOUSE) {
-        dx = int_clamp(e->xdx, -127, 127);
-        dy = int_clamp(e->ydy, -127, 127);
-        e->xdx -= dx;
-        e->ydy -= dy;
-    } else {
-        dx = e->xdx;
-        dy = e->ydy;
-    }
-    dz = int_clamp(e->dz, -127, 127);
-    e->dz -= dz;
-
-    b = 0;
-    if (e->buttons_state & MOUSE_EVENT_LBUTTON)
-        b |= 0x01;
-    if (e->buttons_state & MOUSE_EVENT_RBUTTON)
-        b |= 0x02;
-    if (e->buttons_state & MOUSE_EVENT_MBUTTON)
-        b |= 0x04;
-
-    if (hs->n &&
-        !e->dz &&
-        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
-        /* that deals with this event */
-        QUEUE_INCR(hs->head);
-        hs->n--;
-    }
-
-    /* Appears we have to invert the wheel direction */
-    dz = 0 - dz;
-    l = 0;
-    switch (hs->kind) {
-    case HID_MOUSE:
-        if (len > l)
-            buf[l++] = b;
-        if (len > l)
-            buf[l++] = dx;
-        if (len > l)
-            buf[l++] = dy;
-        if (len > l)
-            buf[l++] = dz;
-        break;
-
-    case HID_TABLET:
-        if (len > l)
-            buf[l++] = b;
-        if (len > l)
-            buf[l++] = dx & 0xff;
-        if (len > l)
-            buf[l++] = dx >> 8;
-        if (len > l)
-            buf[l++] = dy & 0xff;
-        if (len > l)
-            buf[l++] = dy >> 8;
-        if (len > l)
-            buf[l++] = dz;
-        break;
-
-    default:
-        abort();
-    }
-
-    return l;
-}
-
-static int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
-{
-    if (len < 2)
-        return 0;
-
-    hid_keyboard_process_keycode(hs);
-
-    buf[0] = hs->kbd.modifiers & 0xff;
-    buf[1] = 0;
-    if (hs->kbd.keys > 6) {
-        memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
-    } else {
-        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
-    }
-
-    return MIN(8, len);
-}
-
-static int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
-{
-    if (len > 0) {
-        int ledstate = 0;
-        /* 0x01: Num Lock LED
-         * 0x02: Caps Lock LED
-         * 0x04: Scroll Lock LED
-         * 0x08: Compose LED
-         * 0x10: Kana LED */
-        hs->kbd.leds = buf[0];
-        if (hs->kbd.leds & 0x04) {
-            ledstate |= QEMU_SCROLL_LOCK_LED;
-        }
-        if (hs->kbd.leds & 0x01) {
-            ledstate |= QEMU_NUM_LOCK_LED;
-        }
-        if (hs->kbd.leds & 0x02) {
-            ledstate |= QEMU_CAPS_LOCK_LED;
-        }
-        kbd_put_ledstate(ledstate);
-    }
-    return 0;
-}
-
-static void hid_handle_reset(HIDState *hs)
-{
-    switch (hs->kind) {
-    case HID_KEYBOARD:
-        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
-        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
-        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
-        hs->kbd.keys = 0;
-        break;
-    case HID_MOUSE:
-    case HID_TABLET:
-        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
-        break;
-    }
-    hs->head = 0;
-    hs->n = 0;
-}
-
 static void usb_hid_handle_reset(USBDevice *dev)
 {
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
-    hid_handle_reset(&us->hid);
+    hid_reset(&us->hid);
     us->protocol = 1;
     us->idle = 0;
 }
@@ -875,19 +509,6 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
     return ret;
 }
 
-static void hid_free(HIDState *hs)
-{
-    switch (hs->kind) {
-    case HID_KEYBOARD:
-        qemu_remove_kbd_event_handler();
-        break;
-    case HID_MOUSE:
-    case HID_TABLET:
-        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
-        break;
-    }
-}
-
 static void usb_hid_handle_destroy(USBDevice *dev)
 {
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
@@ -895,20 +516,6 @@ static void usb_hid_handle_destroy(USBDevice *dev)
     hid_free(&us->hid);
 }
 
-static void hid_init(HIDState *hs, int kind, HIDEventFunc event)
-{
-    hs->kind = kind;
-    hs->event = event;
-
-    if (hs->kind == HID_MOUSE) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
-                                                        0, "QEMU HID Mouse");
-    } else if (hs->kind == HID_TABLET) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
-                                                        1, "QEMU HID Tablet");
-    }
-}
-
 static int usb_hid_initfn(USBDevice *dev, int kind)
 {
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 15/16] hid: move idle+protocol from usb-hid to hid too.
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (13 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 14/16] usb-hid: split hid code to hw/hid.[ch] Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 16/16] bluetooth: kill dummy usb device, use hid code directly Gerd Hoffmann
  2011-08-04 22:42 ` [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Anthony Liguori
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/hid.c     |    8 ++++++++
 hw/hid.h     |    4 ++++
 hw/usb-hid.c |   36 +++++++++++++-----------------------
 3 files changed, 25 insertions(+), 23 deletions(-)

diff --git a/hw/hid.c b/hw/hid.c
index 1893ae5..7b5ef5f 100644
--- a/hw/hid.c
+++ b/hw/hid.c
@@ -24,6 +24,7 @@
  */
 #include "hw.h"
 #include "console.h"
+#include "qemu-timer.h"
 #include "hid.h"
 
 #define HID_USAGE_ERROR_ROLLOVER        0x01
@@ -73,6 +74,11 @@ bool hid_has_events(HIDState *hs)
     return hs->n > 0;
 }
 
+void hid_set_next_idle(HIDState *hs, int64_t curtime)
+{
+    hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000;
+}
+
 static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
 {
     e->xdx = e->ydy = e->dz = 0;
@@ -365,6 +371,8 @@ void hid_reset(HIDState *hs)
     }
     hs->head = 0;
     hs->n = 0;
+    hs->protocol = 1;
+    hs->idle = 0;
 }
 
 void hid_free(HIDState *hs)
diff --git a/hw/hid.h b/hw/hid.h
index 99910c3..4a8fa5b 100644
--- a/hw/hid.h
+++ b/hw/hid.h
@@ -39,6 +39,9 @@ struct HIDState {
     uint32_t head; /* index into circular queue */
     uint32_t n;
     int kind;
+    int32_t protocol;
+    uint8_t idle;
+    int64_t next_idle_clock;
     HIDEventFunc event;
 };
 
@@ -47,6 +50,7 @@ void hid_reset(HIDState *hs);
 void hid_free(HIDState *hs);
 
 bool hid_has_events(HIDState *hs);
+void hid_set_next_idle(HIDState *hs, int64_t curtime);
 int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
 int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
 int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 48ce743..e5d57de 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -45,9 +45,6 @@
 typedef struct USBHIDState {
     USBDevice dev;
     HIDState hid;
-    int32_t protocol;
-    uint8_t idle;
-    int64_t next_idle_clock;
     void *datain_opaque;
     void (*datain)(void *);
 } USBHIDState;
@@ -377,13 +374,6 @@ static void usb_hid_handle_reset(USBDevice *dev)
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
     hid_reset(&us->hid);
-    us->protocol = 1;
-    us->idle = 0;
-}
-
-static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
-{
-    s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000;
 }
 
 static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
@@ -448,22 +438,22 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
             goto fail;
         }
         ret = 1;
-        data[0] = us->protocol;
+        data[0] = hs->protocol;
         break;
     case SET_PROTOCOL:
         if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
             goto fail;
         }
         ret = 0;
-        us->protocol = value;
+        hs->protocol = value;
         break;
     case GET_IDLE:
         ret = 1;
-        data[0] = us->idle;
+        data[0] = hs->idle;
         break;
     case SET_IDLE:
-        us->idle = (uint8_t) (value >> 8);
-        usb_hid_set_next_idle(us, qemu_get_clock_ns(vm_clock));
+        hs->idle = (uint8_t) (value >> 8);
+        hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock));
         ret = 0;
         break;
     default:
@@ -486,10 +476,10 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
         if (p->devep == 1) {
             int64_t curtime = qemu_get_clock_ns(vm_clock);
             if (!hid_has_events(hs) &&
-                (!us->idle || us->next_idle_clock - curtime > 0)) {
+                (!hs->idle || hs->next_idle_clock - curtime > 0)) {
                 return USB_RET_NAK;
             }
-            usb_hid_set_next_idle(us, curtime);
+            hid_set_next_idle(hs, curtime);
             if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
                 ret = hid_pointer_poll(hs, buf, p->iov.size);
             } else if (hs->kind == HID_KEYBOARD) {
@@ -552,8 +542,8 @@ static int usb_hid_post_load(void *opaque, int version_id)
 {
     USBHIDState *s = opaque;
 
-    if (s->idle) {
-        usb_hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
+    if (s->hid.idle) {
+        hid_set_next_idle(&s->hid, qemu_get_clock_ns(vm_clock));
     }
     return 0;
 }
@@ -581,8 +571,8 @@ static const VMStateDescription vmstate_usb_ptr = {
                              vmstate_usb_ptr_queue, HIDPointerEvent),
         VMSTATE_UINT32(hid.head, USBHIDState),
         VMSTATE_UINT32(hid.n, USBHIDState),
-        VMSTATE_INT32(protocol, USBHIDState),
-        VMSTATE_UINT8(idle, USBHIDState),
+        VMSTATE_INT32(hid.protocol, USBHIDState),
+        VMSTATE_UINT8(hid.idle, USBHIDState),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -601,8 +591,8 @@ static const VMStateDescription vmstate_usb_kbd = {
         VMSTATE_UINT8(hid.kbd.leds, USBHIDState),
         VMSTATE_UINT8_ARRAY(hid.kbd.key, USBHIDState, 16),
         VMSTATE_INT32(hid.kbd.keys, USBHIDState),
-        VMSTATE_INT32(protocol, USBHIDState),
-        VMSTATE_UINT8(idle, USBHIDState),
+        VMSTATE_INT32(hid.protocol, USBHIDState),
+        VMSTATE_UINT8(hid.idle, USBHIDState),
         VMSTATE_END_OF_LIST()
     }
 };
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Qemu-devel] [PATCH 16/16] bluetooth: kill dummy usb device, use hid code directly.
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (14 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 15/16] hid: move idle+protocol from usb-hid to hid too Gerd Hoffmann
@ 2011-08-04 15:10 ` Gerd Hoffmann
  2011-08-04 22:42 ` [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Anthony Liguori
  16 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 15:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/bt-hid.c |   62 ++++++++++++++++++++--------------------------------------
 1 files changed, 22 insertions(+), 40 deletions(-)

diff --git a/hw/bt-hid.c b/hw/bt-hid.c
index a4204f9..5f1afe3 100644
--- a/hw/bt-hid.c
+++ b/hw/bt-hid.c
@@ -19,7 +19,9 @@
  */
 
 #include "qemu-common.h"
-#include "usb.h"
+#include "qemu-timer.h"
+#include "console.h"
+#include "hid.h"
 #include "bt.h"
 
 enum hid_transaction_req {
@@ -86,7 +88,7 @@ struct bt_hid_device_s {
     struct bt_l2cap_device_s btdev;
     struct bt_l2cap_conn_params_s *control;
     struct bt_l2cap_conn_params_s *interrupt;
-    USBDevice *usbdev;
+    HIDState hid;
 
     int proto;
     int connected;
@@ -111,7 +113,7 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
     bt_l2cap_device_done(&s->btdev);
     bt_l2cap_device_init(&s->btdev, net);
 
-    s->usbdev->info->handle_reset(s->usbdev);
+    hid_reset(&s->hid);
     s->proto = BT_HID_PROTO_REPORT;
     s->state = bt_state_ready;
     s->dataother.len = 0;
@@ -124,23 +126,16 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
 
 static int bt_hid_out(struct bt_hid_device_s *s)
 {
-    USBPacket p;
-
     if (s->data_type == BT_DATA_OUTPUT) {
-        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;
+        /* nothing */
+        ;
     }
 
     if (s->data_type == BT_DATA_FEATURE) {
         /* XXX:
          * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
          * or a SET_REPORT? */
-        p.devep = 0;
+        ;
     }
 
     return -1;
@@ -148,14 +143,8 @@ static int bt_hid_out(struct bt_hid_device_s *s)
 
 static int bt_hid_in(struct bt_hid_device_s *s)
 {
-    USBPacket p;
-
-    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);
-
+    s->datain.len = hid_keyboard_poll(&s->hid, s->datain.buffer,
+                                      sizeof(s->datain.buffer));
     return s->datain.len;
 }
 
@@ -323,8 +312,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
             break;
         }
         s->proto = parameter;
-        s->usbdev->info->handle_control(s->usbdev, NULL, SET_PROTOCOL, s->proto, 0, 0,
-                                        NULL);
+        s->hid.protocol = parameter;
         ret = BT_HS_SUCCESSFUL;
         break;
 
@@ -333,8 +321,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
             ret = BT_HS_ERR_INVALID_PARAMETER;
             break;
         }
-        s->usbdev->info->handle_control(s->usbdev, NULL, GET_IDLE, 0, 0, 1,
-                        s->control->sdu_out(s->control, 1));
+        *s->control->sdu_out(s->control, 1) = s->hid.idle;
         s->control->sdu_submit(s->control);
         break;
 
@@ -344,11 +331,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
             break;
         }
 
-        /* We don't need to know about the Idle Rate here really,
-         * so just pass it on to the device.  */
-        ret = s->usbdev->info->handle_control(s->usbdev, NULL,
-                        SET_IDLE, data[1], 0, 0, NULL) ?
-                BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
+        s->hid.idle = data[1];
         /* XXX: Does this generate a handshake? */
         break;
 
@@ -385,9 +368,10 @@ static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
     bt_hid_control_transaction(hid, data, len);
 }
 
-static void bt_hid_datain(void *opaque)
+static void bt_hid_datain(HIDState *hs)
 {
-    struct bt_hid_device_s *hid = opaque;
+    struct bt_hid_device_s *hid =
+        container_of(hs, struct bt_hid_device_s, hid);
 
     /* If suspended, wake-up and send a wake-up event first.  We might
      * want to also inspect the input report and ignore event like
@@ -450,7 +434,7 @@ static void bt_hid_connected_update(struct bt_hid_device_s *hid)
     hid->btdev.device.inquiry_scan = !hid->connected;
 
     if (hid->connected && !prev) {
-        hid->usbdev->info->handle_reset(hid->usbdev);
+        hid_reset(&hid->hid);
         hid->proto = BT_HID_PROTO_REPORT;
     }
 
@@ -518,7 +502,7 @@ static void bt_hid_destroy(struct bt_device_s *dev)
         bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
     bt_l2cap_device_done(&hid->btdev);
 
-    hid->usbdev->info->handle_destroy(hid->usbdev);
+    hid_free(&hid->hid);
 
     qemu_free(hid);
 }
@@ -531,7 +515,7 @@ enum peripheral_minor_class {
 };
 
 static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
-                USBDevice *dev, enum peripheral_minor_class minor)
+                                       enum peripheral_minor_class minor)
 {
     struct bt_hid_device_s *s = qemu_mallocz(sizeof(*s));
     uint32_t class =
@@ -551,9 +535,8 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
     bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
                     BT_HID_MTU, bt_hid_new_interrupt_ch);
 
-    s->usbdev = dev;
-    s->btdev.device.lmp_name = s->usbdev->product_desc;
-    usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
+    hid_init(&s->hid, HID_KEYBOARD, bt_hid_datain);
+    s->btdev.device.lmp_name = "BT Keyboard";
 
     s->btdev.device.handle_destroy = bt_hid_destroy;
 
@@ -566,6 +549,5 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
 
 struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
 {
-    USBDevice *dev = usb_create_simple(NULL /* FIXME */, "usb-kbd");
-    return bt_hid_init(net, dev, class_keyboard);
+    return bt_hid_init(net, class_keyboard);
 }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 01/16] re-activate usb-host for bsd
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 01/16] re-activate usb-host for bsd Gerd Hoffmann
@ 2011-08-04 18:50   ` Blue Swirl
  2011-08-04 18:53     ` Gerd Hoffmann
  0 siblings, 1 reply; 25+ messages in thread
From: Blue Swirl @ 2011-08-04 18:50 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On Thu, Aug 4, 2011 at 3:10 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> A bunch of code was disabled via #if 0, for a quite long time (since
> Sept 2009).  Surprisingly the code builds just fine when they are
> removed (tested on OpenBSD).  /me wonders nevertheless whenever there
> are any users of those bits when this went unnoticed for almost two
> years ...

I added the #ifdeffery. The build was broken by some previous commit
but since my OpenBSD machine doesn't have USB so I couldn't test it.
Did you test if USB works now or just that code builds?

> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  usb-bsd.c |   10 ++--------
>  1 files changed, 2 insertions(+), 8 deletions(-)
>
> diff --git a/usb-bsd.c b/usb-bsd.c
> index 3b97eb4..ab8e3b7 100644
> --- a/usb-bsd.c
> +++ b/usb-bsd.c
> @@ -62,7 +62,6 @@ typedef struct USBHostDevice {
>  } USBHostDevice;
>
>
> -#if 0
>  static int ensure_ep_open(USBHostDevice *dev, int ep, int mode)
>  {
>     char buf[32];
> @@ -110,7 +109,6 @@ static void ensure_eps_closed(USBHostDevice *dev)
>         epnum++;
>     }
>  }
> -#endif
>
>  static void usb_host_handle_reset(USBDevice *dev)
>  {
> @@ -119,7 +117,6 @@ static void usb_host_handle_reset(USBDevice *dev)
>  #endif
>  }
>
> -#if 0
>  /* XXX:
>  * -check device states against transfer requests
>  *  and return appropriate response
> @@ -278,7 +275,6 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
>         return ret;
>     }
>  }
> -#endif
>
>  static void usb_host_handle_destroy(USBDevice *opaque)
>  {
> @@ -305,8 +301,8 @@ static int usb_host_initfn(USBDevice *dev)
>  USBDevice *usb_host_device_open(const char *devname)
>  {
>     struct usb_device_info bus_info, dev_info;
> -    USBDevice *d = NULL;
> -    USBHostDevice *dev, *ret = NULL;
> +    USBDevice *d = NULL, *ret = NULL;
> +    USBHostDevice *dev;
>     char ctlpath[PATH_MAX + 1];
>     char buspath[PATH_MAX + 1];
>     int bfd, dfd, bus, address, i;
> @@ -408,10 +404,8 @@ static struct USBDeviceInfo usb_host_dev_info = {
>     .init           = usb_host_initfn,
>     .handle_packet  = usb_generic_handle_packet,
>     .handle_reset   = usb_host_handle_reset,
> -#if 0
>     .handle_control = usb_host_handle_control,
>     .handle_data    = usb_host_handle_data,
> -#endif
>     .handle_destroy = usb_host_handle_destroy,
>  };
>
> --
> 1.7.1
>
>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 01/16] re-activate usb-host for bsd
  2011-08-04 18:50   ` Blue Swirl
@ 2011-08-04 18:53     ` Gerd Hoffmann
  0 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-04 18:53 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

On 08/04/11 20:50, Blue Swirl wrote:
> On Thu, Aug 4, 2011 at 3:10 PM, Gerd Hoffmann<kraxel@redhat.com>  wrote:
>> A bunch of code was disabled via #if 0, for a quite long time (since
>> Sept 2009).  Surprisingly the code builds just fine when they are
>> removed (tested on OpenBSD).  /me wonders nevertheless whenever there
>> are any users of those bits when this went unnoticed for almost two
>> years ...
>
> I added the #ifdeffery. The build was broken by some previous commit
> but since my OpenBSD machine doesn't have USB so I couldn't test it.
> Did you test if USB works now or just that code builds?

Did just a build test, with OpenBSD itself in a virtual machine.

cheers,
   Gerd

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes
  2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
                   ` (15 preceding siblings ...)
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 16/16] bluetooth: kill dummy usb device, use hid code directly Gerd Hoffmann
@ 2011-08-04 22:42 ` Anthony Liguori
  16 siblings, 0 replies; 25+ messages in thread
From: Anthony Liguori @ 2011-08-04 22:42 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On 08/04/2011 10:10 AM, Gerd Hoffmann wrote:
>    Hi,
>
> Major changes in the USB patch queue:
>
>   * The USBPacket payload is represented as iovec instead of a linear
>     buffer.  This allows to kill some copying and buffering.
>   * The HID code is splitted into hw/hid.[ch], keeping only the usb
>     interfaacing in hw/usb-hid.c.  This allows easy reuse in other
>     contexts such as bluetooth.
>
> please pull,
>    Gerd

Pulled.  Thanks.

Regards,

Anthony Liguori

>
> The following changes since commit a6f4e09d90cef88be07cd597c2f2a9f0b3ed0763:
>
>    lm32: softusb: claim to support full speed (2011-08-04 01:14:22 +0200)
>
> are available in the git repository at:
>    git://git.kraxel.org/qemu usb.22
>
> Gerd Hoffmann (16):
>        re-activate usb-host for bsd
>        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
>        usb-hid: create&  use HIDState
>        usb-hid: add event callback
>        usb-hid: add hid_has_events()
>        usb-hid: split hid code to hw/hid.[ch]
>        hid: move idle+protocol from usb-hid to hid too.
>        bluetooth: kill dummy usb device, use hid code directly.
>
>   Makefile.objs          |    2 +
>   dma.h                  |    4 +-
>   hw/bt-hid.c            |   62 ++----
>   hw/hid.c               |  403 +++++++++++++++++++++++++++++++++++++
>   hw/hid.h               |   58 ++++++
>   hw/milkymist-softusb.c |    8 +-
>   hw/usb-bt.c            |   31 +--
>   hw/usb-ccid.c          |   46 +++--
>   hw/usb-ehci.c          |  160 ++++++---------
>   hw/usb-hid.c           |  519 +++++++----------------------------------------
>   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-bsd.c              |   14 +-
>   usb-linux.c            |   48 +++--
>   usb-redir.c            |   59 +++---
>   27 files changed, 1087 insertions(+), 858 deletions(-)
>   create mode 100644 hw/hid.c
>   create mode 100644 hw/hid.h
>   create mode 100644 hw/usb-libhw.c
>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 03/16] Add iov_clear()
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 03/16] Add iov_clear() Gerd Hoffmann
@ 2011-08-05 11:30   ` Kevin Wolf
  2011-08-05 14:19     ` Gerd Hoffmann
  0 siblings, 1 reply; 25+ messages in thread
From: Kevin Wolf @ 2011-08-05 11:30 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

Am 04.08.2011 17:10, schrieb Gerd Hoffmann:
> Fill the spefified area with zeros.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

Looks like we're starting to duplicate everything in qemu_iovec_* and
iov_*...

Any reason not to use QEMUIOVector?

Kevin

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 03/16] Add iov_clear()
  2011-08-05 11:30   ` Kevin Wolf
@ 2011-08-05 14:19     ` Gerd Hoffmann
  0 siblings, 0 replies; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-05 14:19 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 600 bytes --]

On 08/05/11 13:30, Kevin Wolf wrote:
> Am 04.08.2011 17:10, schrieb Gerd Hoffmann:
>> Fill the spefified area with zeros.
>>
>> Signed-off-by: Gerd Hoffmann<kraxel@redhat.com>
>
> Looks like we're starting to duplicate everything in qemu_iovec_* and
> iov_*...
>
> Any reason not to use QEMUIOVector?

I *do* use QEMUIOVector, but for the actual copy I'm using 
iov_{from,to}_buf() instead of qemu_iovec_{from,to}_buffer because the 
former allows to specify an offset.

But, yea, we have some duplication here, qemu_iovec_* can just call 
iov_* instead of reimplementing stuff ...

cheers,
   Gerd


[-- Attachment #2: x --]
[-- Type: text/plain, Size: 1196 bytes --]

diff --git a/cutils.c b/cutils.c
index f9a7e36..b8ca4c2 100644
--- a/cutils.c
+++ b/cutils.c
@@ -24,6 +24,7 @@
 #include "qemu-common.h"
 #include "host-utils.h"
 #include <math.h>
+#include "iov.h"
 
 void pstrcpy(char *buf, int buf_size, const char *str)
 {
@@ -230,29 +231,12 @@ void qemu_iovec_reset(QEMUIOVector *qiov)
 
 void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf)
 {
-    uint8_t *p = (uint8_t *)buf;
-    int i;
-
-    for (i = 0; i < qiov->niov; ++i) {
-        memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len);
-        p += qiov->iov[i].iov_len;
-    }
+    iov_to_buf(qiov->iov, qiov->niov, buf, 0, qiov->size);
 }
 
 void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count)
 {
-    const uint8_t *p = (const uint8_t *)buf;
-    size_t copy;
-    int i;
-
-    for (i = 0; i < qiov->niov && count; ++i) {
-        copy = count;
-        if (copy > qiov->iov[i].iov_len)
-            copy = qiov->iov[i].iov_len;
-        memcpy(qiov->iov[i].iov_base, p, copy);
-        p     += copy;
-        count -= copy;
-    }
+    iov_from_buf(qiov->iov, qiov->niov, buf, 0, count);
 }
 
 void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count)

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 13/16] usb-hid: add hid_has_events()
  2011-08-04 15:10 ` [Qemu-devel] [PATCH 13/16] usb-hid: add hid_has_events() Gerd Hoffmann
@ 2011-08-08  8:32   ` TeLeMan
  2011-08-10 15:17     ` Gerd Hoffmann
  0 siblings, 1 reply; 25+ messages in thread
From: TeLeMan @ 2011-08-08  8:32 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On Thu, Aug 4, 2011 at 23:10, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Add hid_has_events function, use it to figure whenever there are pending
> events instead of checking and updating USBHIDState->changed.
>
> Setting ->changed to 1 on init is removed, that should have absolutely
> no effect as the initial state of ->idle is 0 so we report hid state
> anyway until the guest configures some idle time.  Also should clear
> ->idle on reset.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  hw/usb-hid.c |   16 +++++++---------
>  1 files changed, 7 insertions(+), 9 deletions(-)
>
> diff --git a/hw/usb-hid.c b/hw/usb-hid.c
> index 870cc66..b730692 100644
> --- a/hw/usb-hid.c
> +++ b/hw/usb-hid.c
> @@ -88,7 +88,6 @@ typedef struct USBHIDState {
>     int32_t protocol;
>     uint8_t idle;
>     int64_t next_idle_clock;
> -    int changed;
>     void *datain_opaque;
>     void (*datain)(void *);
>  } USBHIDState;
> @@ -444,12 +443,15 @@ static const uint8_t usb_hid_usage_keys[0x100] = {
>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>  };
>
> +static bool hid_has_events(HIDState *hs)
> +{
> +    return hs->n > 0;
> +}
> +
>  static void usb_hid_changed(HIDState *hs)
>  {
>     USBHIDState *us = container_of(hs, USBHIDState, hid);
>
> -    us->changed = 1;
> -
>     if (us->datain) {
>         us->datain(us->datain_opaque);
>     }
> @@ -742,6 +744,7 @@ static void usb_hid_handle_reset(USBDevice *dev)
>
>     hid_handle_reset(&us->hid);
>     us->protocol = 1;
> +    us->idle = 0;
>  }
>
>  static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
> @@ -798,7 +801,6 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
>         } else if (hs->kind == HID_KEYBOARD) {
>             ret = hid_keyboard_poll(hs, data, length);
>         }
> -        us->changed = hs->n > 0;
>         break;
>     case SET_REPORT:
>         if (hs->kind == HID_KEYBOARD) {
> @@ -849,7 +851,7 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
>     case USB_TOKEN_IN:
>         if (p->devep == 1) {
>             int64_t curtime = qemu_get_clock_ns(vm_clock);
> -            if (!us->changed &&
> +            if (!hid_has_events(hs) &&
>                 (!us->idle || us->next_idle_clock - curtime > 0)) {
>                 return USB_RET_NAK;
>             }
> @@ -860,7 +862,6 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
>                 ret = hid_keyboard_poll(hs, buf, p->iov.size);
>             }
>             usb_packet_copy(p, buf, ret);
> -            us->changed = hs->n > 0;
>         } else {
>             goto fail;
>         }
> @@ -914,9 +915,6 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
>
>     usb_desc_init(dev);
>     hid_init(&us->hid, kind, usb_hid_changed);
> -
> -    /* Force poll routine to be run and grab input the first time.  */
> -    us->changed = 1;
USB tablet does not work on the winxp guest. I think this code can't be removed.

>     return 0;
>  }
>
> --
> 1.7.1
>
>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 13/16] usb-hid: add hid_has_events()
  2011-08-08  8:32   ` TeLeMan
@ 2011-08-10 15:17     ` Gerd Hoffmann
  2011-08-11  5:45       ` TeLeMan
  0 siblings, 1 reply; 25+ messages in thread
From: Gerd Hoffmann @ 2011-08-10 15:17 UTC (permalink / raw)
  To: TeLeMan; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 248 bytes --]

   Hi,

>> -
>> -    /* Force poll routine to be run and grab input the first time.  */
>> -    us->changed = 1;
> USB tablet does not work on the winxp guest. I think this code can't be removed.
>

Attached patch should fix that.

cheers,
   Gerd

[-- Attachment #2: x --]
[-- Type: text/plain, Size: 2498 bytes --]

commit 21635e121ae0f0ab7874152a7c2f96e9d8cd642f
Author: Gerd Hoffmann <kraxel@redhat.com>
Date:   Tue Aug 9 12:35:57 2011 +0200

    usb/hid: add hid_pointer_activate, use it
    
    HID reorganziation broke the usb tablet in windows xp.  The reason is
    that xp activates idle before it starts polling, which creates a
    chicken-and-egg issue:  We don't call hid_pointer_poll because there are
    no pending events.  We don't get any events because the activation code
    in hid_pointer_poll is never executed and thus all pointer events are
    routed to the PS/2 mouse by qemu.
    
    Fix this by creating a hid_pointer_activate function and call it from
    usb-hid when the guest sets the idle state.
    
    Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

diff --git a/hw/hid.c b/hw/hid.c
index 7b5ef5f..77339f7 100644
--- a/hw/hid.c
+++ b/hw/hid.c
@@ -218,16 +218,21 @@ static inline int int_clamp(int val, int vmin, int vmax)
     }
 }
 
+void hid_pointer_activate(HIDState *hs)
+{
+    if (!hs->ptr.mouse_grabbed) {
+        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
+        hs->ptr.mouse_grabbed = 1;
+    }
+}
+
 int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
 {
     int dx, dy, dz, b, l;
     int index;
     HIDPointerEvent *e;
 
-    if (!hs->ptr.mouse_grabbed) {
-        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
-        hs->ptr.mouse_grabbed = 1;
-    }
+    hid_pointer_activate(hs);
 
     /* When the buffer is empty, return the last event.  Relative
        movements will all be zero.  */
diff --git a/hw/hid.h b/hw/hid.h
index 4a8fa5b..9ce03b1 100644
--- a/hw/hid.h
+++ b/hw/hid.h
@@ -51,6 +51,7 @@ void hid_free(HIDState *hs);
 
 bool hid_has_events(HIDState *hs);
 void hid_set_next_idle(HIDState *hs, int64_t curtime);
+void hid_pointer_activate(HIDState *hs);
 int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
 int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
 int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index e5d57de..6f12751 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -454,6 +454,9 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
     case SET_IDLE:
         hs->idle = (uint8_t) (value >> 8);
         hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock));
+        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+            hid_pointer_activate(hs);
+        }
         ret = 0;
         break;
     default:

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [Qemu-devel] [PATCH 13/16] usb-hid: add hid_has_events()
  2011-08-10 15:17     ` Gerd Hoffmann
@ 2011-08-11  5:45       ` TeLeMan
  0 siblings, 0 replies; 25+ messages in thread
From: TeLeMan @ 2011-08-11  5:45 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On Wed, Aug 10, 2011 at 23:17, Gerd Hoffmann <kraxel@redhat.com> wrote:
>  Hi,
>
>>> -
>>> -    /* Force poll routine to be run and grab input the first time.  */
>>> -    us->changed = 1;
>>
>> USB tablet does not work on the winxp guest. I think this code can't be
>> removed.
>>
>
> Attached patch should fix that.
Thanks, it works.

> cheers,
>  Gerd
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2011-08-11  5:45 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-04 15:10 [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 01/16] re-activate usb-host for bsd Gerd Hoffmann
2011-08-04 18:50   ` Blue Swirl
2011-08-04 18:53     ` Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 02/16] Add iov_hexdump() Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 03/16] Add iov_clear() Gerd Hoffmann
2011-08-05 11:30   ` Kevin Wolf
2011-08-05 14:19     ` Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 04/16] move QEMUSGList typedef Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 05/16] usb: use iovecs in USBPacket Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 06/16] usb-serial: iovec support Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 07/16] usb-host: " Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 08/16] usb-storage: " Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 09/16] uhci: remove buffer Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 10/16] ehci: iovec support, " Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 11/16] usb-hid: create & use HIDState Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 12/16] usb-hid: add event callback Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 13/16] usb-hid: add hid_has_events() Gerd Hoffmann
2011-08-08  8:32   ` TeLeMan
2011-08-10 15:17     ` Gerd Hoffmann
2011-08-11  5:45       ` TeLeMan
2011-08-04 15:10 ` [Qemu-devel] [PATCH 14/16] usb-hid: split hid code to hw/hid.[ch] Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 15/16] hid: move idle+protocol from usb-hid to hid too Gerd Hoffmann
2011-08-04 15:10 ` [Qemu-devel] [PATCH 16/16] bluetooth: kill dummy usb device, use hid code directly Gerd Hoffmann
2011-08-04 22:42 ` [Qemu-devel] [PULL] usb patch queue: iovecs, hid split, misc fixes Anthony Liguori

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.