* [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
* 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
* [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
* 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
* [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
* 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
* [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] [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