From a263bac1928cbb34d6fceb4f7569ad76ced37cc1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 12 Apr 2016 07:51:39 +0200 Subject: [PATCH 1/9] virtio-input: add parenthesis to const_le{16, 32} "_x" must be "(_x)" otherwise things fail if you pass in expressions. Signed-off-by: Gerd Hoffmann Reviewed-by: Eric Blake Message-id: 1460440299-26654-1-git-send-email-kraxel@redhat.com --- include/hw/virtio/virtio-input.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/hw/virtio/virtio-input.h b/include/hw/virtio/virtio-input.h index af1c207ab1..169adee1fb 100644 --- a/include/hw/virtio/virtio-input.h +++ b/include/hw/virtio/virtio-input.h @@ -15,13 +15,13 @@ typedef struct virtio_input_event virtio_input_event; #if defined(HOST_WORDS_BIGENDIAN) # define const_le32(_x) \ - (((_x & 0x000000ffU) << 24) | \ - ((_x & 0x0000ff00U) << 8) | \ - ((_x & 0x00ff0000U) >> 8) | \ - ((_x & 0xff000000U) >> 24)) + ((((_x) & 0x000000ffU) << 24) | \ + (((_x) & 0x0000ff00U) << 8) | \ + (((_x) & 0x00ff0000U) >> 8) | \ + (((_x) & 0xff000000U) >> 24)) # define const_le16(_x) \ - (((_x & 0x00ff) << 8) | \ - ((_x & 0xff00) >> 8)) + ((((_x) & 0x00ff) << 8) | \ + (((_x) & 0xff00) >> 8)) #else # define const_le32(_x) (_x) # define const_le16(_x) (_x) From 441330f7146c5b5422e52729188d1d62e2f47862 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 12 Apr 2016 08:07:19 +0200 Subject: [PATCH 2/9] move const_le{16, 23} to qemu/bswap.h, add comment Signed-off-by: Gerd Hoffmann Reviewed-by: Eric Blake Message-id: 1460441239-867-1-git-send-email-kraxel@redhat.com --- include/hw/virtio/virtio-input.h | 14 -------------- include/qemu/bswap.h | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/include/hw/virtio/virtio-input.h b/include/hw/virtio/virtio-input.h index 169adee1fb..1b414c4217 100644 --- a/include/hw/virtio/virtio-input.h +++ b/include/hw/virtio/virtio-input.h @@ -13,20 +13,6 @@ typedef struct virtio_input_absinfo virtio_input_absinfo; typedef struct virtio_input_config virtio_input_config; typedef struct virtio_input_event virtio_input_event; -#if defined(HOST_WORDS_BIGENDIAN) -# define const_le32(_x) \ - ((((_x) & 0x000000ffU) << 24) | \ - (((_x) & 0x0000ff00U) << 8) | \ - (((_x) & 0x00ff0000U) >> 8) | \ - (((_x) & 0xff000000U) >> 24)) -# define const_le16(_x) \ - ((((_x) & 0x00ff) << 8) | \ - (((_x) & 0xff00) >> 8)) -#else -# define const_le32(_x) (_x) -# define const_le16(_x) (_x) -#endif - /* ----------------------------------------------------------------- */ /* qemu internals */ diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index fcedf0d249..ce3c42e4d9 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -125,6 +125,25 @@ static inline uint32_t qemu_bswap_len(uint32_t value, int len) return bswap32(value) >> (32 - 8 * len); } +/* + * Same as cpu_to_le{16,23}, except that gcc will figure the result is + * a compile-time constant if you pass in a constant. So this can be + * used to initialize static variables. + */ +#if defined(HOST_WORDS_BIGENDIAN) +# define const_le32(_x) \ + ((((_x) & 0x000000ffU) << 24) | \ + (((_x) & 0x0000ff00U) << 8) | \ + (((_x) & 0x00ff0000U) >> 8) | \ + (((_x) & 0xff000000U) >> 24)) +# define const_le16(_x) \ + ((((_x) & 0x00ff) << 8) | \ + (((_x) & 0xff00) >> 8)) +#else +# define const_le32(_x) (_x) +# define const_le16(_x) (_x) +#endif + /* Unions for reinterpreting between floats and integers. */ typedef union { From 27a7bbcdf9483be3b4c0b816d59676c8715c2af3 Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Wed, 30 Mar 2016 15:07:20 +0200 Subject: [PATCH 3/9] virtio-input: add missing key mappings KEY_PAUSE is flat out missing. KEY_SYSRQ already has a keycode assigned but it's not what I'm seeing on my system. The mapping doesn't appear to have to be unique so both keycodes now map to KEY_SYSRQ which is what the "Keyboard PrintScreen", HID usage ID 0x46, translates to. Signed-off-by: Ladi Prosek Message-id: 1459343240-19483-1-git-send-email-lprosek@redhat.com Signed-off-by: Gerd Hoffmann --- hw/input/virtio-input-hid.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c index 5d12157114..fe6d37fd73 100644 --- a/hw/input/virtio-input-hid.c +++ b/hw/input/virtio-input-hid.c @@ -121,6 +121,8 @@ static const unsigned int keymap_qcode[Q_KEY_CODE__MAX] = { [Q_KEY_CODE_CTRL_R] = KEY_RIGHTCTRL, [Q_KEY_CODE_SYSRQ] = KEY_SYSRQ, + [Q_KEY_CODE_PRINT] = KEY_SYSRQ, + [Q_KEY_CODE_PAUSE] = KEY_PAUSE, [Q_KEY_CODE_ALT_R] = KEY_RIGHTALT, [Q_KEY_CODE_HOME] = KEY_HOME, From 848c4d4480561154ada54851ba411aea3977c771 Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Thu, 31 Mar 2016 11:53:48 +0200 Subject: [PATCH 4/9] virtio-input: retrieve EV_LED host config bits VIRTIO_INPUT_CFG_EV_BITS with subsel of EV_LED was always returning an empty bitmap for pass-through input devices. Signed-off-by: Ladi Prosek Message-id: 1459418028-7473-1-git-send-email-lprosek@redhat.com Signed-off-by: Gerd Hoffmann --- hw/input/virtio-input-host.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c index 9e0f46d88f..97b7dd6b5c 100644 --- a/hw/input/virtio-input-host.c +++ b/hw/input/virtio-input-host.c @@ -125,6 +125,7 @@ static void virtio_input_host_realize(DeviceState *dev, Error **errp) virtio_input_bits_config(vih, EV_ABS, ABS_CNT); virtio_input_bits_config(vih, EV_MSC, MSC_CNT); virtio_input_bits_config(vih, EV_SW, SW_CNT); + virtio_input_bits_config(vih, EV_LED, LED_CNT); qemu_set_fd_handler(vih->fd, virtio_input_host_event, NULL, vih); return; From 1a782629f668875955f4f08ac8f11de752d71298 Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Fri, 1 Apr 2016 13:45:46 +0200 Subject: [PATCH 5/9] virtio-input: implement pass-through evdev writes The write path for pass-through devices, commonly used for controlling keyboard LEDs via EV_LED, was not implemented. This commit adds the necessary plumbing to connect the status virtio queue to the host evdev file descriptor. Signed-off-by: Ladi Prosek Message-id: 1459511146-12060-1-git-send-email-lprosek@redhat.com Signed-off-by: Gerd Hoffmann --- hw/input/virtio-input-host.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c index 97b7dd6b5c..96124f47c1 100644 --- a/hw/input/virtio-input-host.c +++ b/hw/input/virtio-input-host.c @@ -146,6 +146,28 @@ static void virtio_input_host_unrealize(DeviceState *dev, Error **errp) } } +static void virtio_input_host_handle_status(VirtIOInput *vinput, + virtio_input_event *event) +{ + VirtIOInputHost *vih = VIRTIO_INPUT_HOST(vinput); + struct input_event evdev; + int rc; + + if (gettimeofday(&evdev.time, NULL)) { + perror("virtio_input_host_handle_status: gettimeofday"); + return; + } + + evdev.type = le16_to_cpu(event->type); + evdev.code = le16_to_cpu(event->code); + evdev.value = le32_to_cpu(event->value); + + rc = write(vih->fd, &evdev, sizeof(evdev)); + if (rc == -1) { + perror("virtio_input_host_handle_status: write"); + } +} + static const VMStateDescription vmstate_virtio_input_host = { .name = "virtio-input-host", .unmigratable = 1, @@ -165,6 +187,7 @@ static void virtio_input_host_class_init(ObjectClass *klass, void *data) dc->props = virtio_input_host_properties; vic->realize = virtio_input_host_realize; vic->unrealize = virtio_input_host_unrealize; + vic->handle_status = virtio_input_host_handle_status; } static void virtio_input_host_init(Object *obj) From 2d738374665ede5b7c08545e5b44a411e7c3e943 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 5 Apr 2016 14:31:41 +0200 Subject: [PATCH 6/9] virtio-input: add live migration support virtio-input is simple enough that it doesn't need to xfer any state. Still we have to wire up savevm manually, so the generic pci and virtio are saved correctly. Additionally we need to do some post-load processing to figure whenever the guest uses the device or not, so we can give input routing hints to the qemu input layer using qemu_input_handler_{activate,deactivate}. Signed-off-by: Gerd Hoffmann Message-id: 1459859501-16965-1-git-send-email-kraxel@redhat.com --- hw/input/virtio-input.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 672c207eb5..ac019c7d23 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -14,6 +14,8 @@ #include "standard-headers/linux/input.h" +#define VIRTIO_INPUT_VM_VERSION 1 + /* ----------------------------------------------------------------- */ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) @@ -214,6 +216,38 @@ static void virtio_input_reset(VirtIODevice *vdev) } } +static void virtio_input_save(QEMUFile *f, void *opaque) +{ + VirtIOInput *vinput = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(vinput); + + virtio_save(vdev, f); +} + +static int virtio_input_load(QEMUFile *f, void *opaque, int version_id) +{ + VirtIOInput *vinput = opaque; + VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vinput); + VirtIODevice *vdev = VIRTIO_DEVICE(vinput); + int ret; + + if (version_id != VIRTIO_INPUT_VM_VERSION) { + return -EINVAL; + } + + ret = virtio_load(vdev, f, version_id); + if (ret) { + return ret; + } + + /* post_load() */ + vinput->active = vdev->status & VIRTIO_CONFIG_S_DRIVER_OK; + if (vic->change_active) { + vic->change_active(vinput); + } + return 0; +} + static void virtio_input_device_realize(DeviceState *dev, Error **errp) { VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev); @@ -245,14 +279,20 @@ static void virtio_input_device_realize(DeviceState *dev, Error **errp) vinput->cfg_size); vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt); vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts); + + register_savevm(dev, "virtio-input", -1, VIRTIO_INPUT_VM_VERSION, + virtio_input_save, virtio_input_load, vinput); } static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) { VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOInput *vinput = VIRTIO_INPUT(dev); Error *local_err = NULL; + unregister_savevm(dev, "virtio-input", vinput); + if (vic->unrealize) { vic->unrealize(dev, &local_err); if (local_err) { From 0263b3a72fbd2ac9ba59ecc2449a9bc53ccf6fb3 Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Fri, 8 Apr 2016 17:21:33 +0200 Subject: [PATCH 7/9] virtio-input: fix emulated tablet axis ranges The reported maximum was wrong. The X and Y coordinates are 0-based so if size is 8000 maximum must be 7FFF. Signed-off-by: Ladi Prosek Message-id: 1460128893-10244-1-git-send-email-lprosek@redhat.com Signed-off-by: Gerd Hoffmann --- hw/input/virtio-input-hid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c index fe6d37fd73..3ee0c1814a 100644 --- a/hw/input/virtio-input-hid.c +++ b/hw/input/virtio-input-hid.c @@ -484,12 +484,12 @@ static struct virtio_input_config virtio_tablet_config[] = { .select = VIRTIO_INPUT_CFG_ABS_INFO, .subsel = ABS_X, .size = sizeof(virtio_input_absinfo), - .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE), + .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1), },{ .select = VIRTIO_INPUT_CFG_ABS_INFO, .subsel = ABS_Y, .size = sizeof(virtio_input_absinfo), - .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE), + .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1), }, { /* end of list */ }, }; From ce47d3d4270e9c0f87cd9a3982f1a40a4514c6e3 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 12 Apr 2016 11:21:43 +0200 Subject: [PATCH 8/9] input-linux: refine mouse detection Read absolute and relative axis information, only classify devices as mouse/tablet in case the x axis is present. Signed-off-by: Gerd Hoffmann --- ui/input-linux.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/ui/input-linux.c b/ui/input-linux.c index 9c921cc0ad..1d33b5c121 100644 --- a/ui/input-linux.c +++ b/ui/input-linux.c @@ -337,7 +337,7 @@ static void input_linux_event_mouse(void *opaque) static void input_linux_complete(UserCreatable *uc, Error **errp) { InputLinux *il = INPUT_LINUX(uc); - uint32_t evtmap; + uint32_t evtmap, relmap, absmap; int rc, ver; if (!il->evdev) { @@ -359,16 +359,36 @@ static void input_linux_complete(UserCreatable *uc, Error **errp) } rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap); + if (rc < 0) { + error_setg(errp, "%s: failed to read event bits", il->evdev); + goto err_close; + } if (evtmap & (1 << EV_REL)) { - /* has relative axis -> assume mouse */ + rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap); + if (rc < 0) { + relmap = 0; + } + } + + if (evtmap & (1 << EV_ABS)) { + ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap); + if (rc < 0) { + absmap = 0; + } + } + + if ((evtmap & (1 << EV_REL)) && + (relmap & (1 << REL_X))) { + /* has relative x axis -> assume mouse */ qemu_set_fd_handler(il->fd, input_linux_event_mouse, NULL, il); - } else if (evtmap & (1 << EV_ABS)) { - /* has absolute axis -> not supported */ + } else if ((evtmap & (1 << EV_ABS)) && + (absmap & (1 << ABS_X))) { + /* has absolute x axis -> not supported */ error_setg(errp, "tablet/touchscreen not supported"); goto err_close; } else if (evtmap & (1 << EV_KEY)) { - /* has keys/buttons (and no axis) -> assume keyboard */ + /* has keys/buttons (and no x axis) -> assume keyboard */ qemu_set_fd_handler(il->fd, input_linux_event_keyboard, NULL, il); } else { /* Huh? What is this? */ From b065e275a8066c3ec478f326f39c5fc3c9db103c Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Wed, 13 Apr 2016 16:43:23 +0200 Subject: [PATCH 9/9] virtio-input: support absolute axis config in pass-through VIRTIO_INPUT_CFG_ABS_INFO was not implemented for pass-through input devices. This patch follows the existing design and pre-fetches the config for all absolute axes using EVIOCGABS at realize time. Signed-off-by: Ladi Prosek Message-id: 1460558603-18331-1-git-send-email-lprosek@redhat.com Signed-off-by: Gerd Hoffmann --- hw/input/virtio-input-host.c | 46 ++++++++++++++++++++++++++++++-- hw/input/virtio-input.c | 6 ++--- include/hw/virtio/virtio-input.h | 3 +++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c index 96124f47c1..cb79e80024 100644 --- a/hw/input/virtio-input-host.c +++ b/hw/input/virtio-input-host.c @@ -70,13 +70,39 @@ static void virtio_input_bits_config(VirtIOInputHost *vih, virtio_input_add_config(VIRTIO_INPUT(vih), &bits); } +static void virtio_input_abs_config(VirtIOInputHost *vih, int axis) +{ + virtio_input_config config; + struct input_absinfo absinfo; + int rc; + + rc = ioctl(vih->fd, EVIOCGABS(axis), &absinfo); + if (rc < 0) { + return; + } + + memset(&config, 0, sizeof(config)); + config.select = VIRTIO_INPUT_CFG_ABS_INFO; + config.subsel = axis; + config.size = sizeof(virtio_input_absinfo); + + config.u.abs.min = cpu_to_le32(absinfo.minimum); + config.u.abs.max = cpu_to_le32(absinfo.maximum); + config.u.abs.fuzz = cpu_to_le32(absinfo.fuzz); + config.u.abs.flat = cpu_to_le32(absinfo.flat); + config.u.abs.res = cpu_to_le32(absinfo.resolution); + + virtio_input_add_config(VIRTIO_INPUT(vih), &config); +} + static void virtio_input_host_realize(DeviceState *dev, Error **errp) { VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev); VirtIOInput *vinput = VIRTIO_INPUT(dev); - virtio_input_config id; + virtio_input_config id, *abs; struct input_id ids; - int rc, ver; + int rc, ver, i, axis; + uint8_t byte; if (!vih->evdev) { error_setg(errp, "evdev property is required"); @@ -127,6 +153,22 @@ static void virtio_input_host_realize(DeviceState *dev, Error **errp) virtio_input_bits_config(vih, EV_SW, SW_CNT); virtio_input_bits_config(vih, EV_LED, LED_CNT); + abs = virtio_input_find_config(VIRTIO_INPUT(vih), + VIRTIO_INPUT_CFG_EV_BITS, EV_ABS); + if (abs) { + for (i = 0; i < abs->size; i++) { + byte = abs->u.bitmap[i]; + axis = 8 * i; + while (byte) { + if (byte & 1) { + virtio_input_abs_config(vih, axis); + } + axis++; + byte >>= 1; + } + } + } + qemu_set_fd_handler(vih->fd, virtio_input_host_event, NULL, vih); return; diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index ac019c7d23..f59749a943 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -99,9 +99,9 @@ static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq) virtio_notify(vdev, vinput->sts); } -static virtio_input_config *virtio_input_find_config(VirtIOInput *vinput, - uint8_t select, - uint8_t subsel) +virtio_input_config *virtio_input_find_config(VirtIOInput *vinput, + uint8_t select, + uint8_t subsel) { VirtIOInputConfig *cfg; diff --git a/include/hw/virtio/virtio-input.h b/include/hw/virtio/virtio-input.h index 1b414c4217..bddbd4b287 100644 --- a/include/hw/virtio/virtio-input.h +++ b/include/hw/virtio/virtio-input.h @@ -97,6 +97,9 @@ struct VirtIOInputHost { void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event); void virtio_input_init_config(VirtIOInput *vinput, virtio_input_config *config); +virtio_input_config *virtio_input_find_config(VirtIOInput *vinput, + uint8_t select, + uint8_t subsel); void virtio_input_add_config(VirtIOInput *vinput, virtio_input_config *config); void virtio_input_idstr_config(VirtIOInput *vinput,