qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices


From: Michael S. Tsirkin
Subject: Re: [Qemu-devel] [PATCH qemu 4/6] virtio-input: emulated devices
Date: Thu, 10 Apr 2014 13:55:33 +0300

On Thu, Apr 10, 2014 at 11:07:52AM +0200, Gerd Hoffmann wrote:
> This patch adds the virtio-input-hid base class and
> virtio-{keyboard,mouse,tablet} subclasses building on the base class.
> They are hooked up to the qemu input core and deliver input events
> to the guest like all other hid devices (ps/2 kbd, usb tablet, ...).
> 
> Using them is as simple as adding "-device virtio-tablet-pci" to your
> command line.  If you want add multiple devices but don't want waste
> a pci slot for each you can compose a multifunction device this way:
> 
> qemu -device virtio-keyboard-pci,addr=0d.0,multifunction=on \
>      -device virtio-tablet-pci,addr=0d.1,multifunction=on
> 
> Signed-off-by: Gerd Hoffmann <address@hidden>

Hmm - that's interesting.
I was under the impression that a single pci function can be
a keyboard, mouse and tablet at the same time.

If they aren't why don't we assign distinct device IDs to them
after all?

> ---
>  hw/input/Makefile.objs           |   1 +
>  hw/input/virtio-input-hid.c      | 486 
> +++++++++++++++++++++++++++++++++++++++
>  hw/virtio/virtio-pci.c           |  68 ++++++
>  hw/virtio/virtio-pci.h           |  13 ++
>  include/hw/virtio/virtio-input.h |  22 ++
>  5 files changed, 590 insertions(+)
>  create mode 100644 hw/input/virtio-input-hid.c
> 
> diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
> index ee8bba9..0dae710 100644
> --- a/hw/input/Makefile.objs
> +++ b/hw/input/Makefile.objs
> @@ -10,6 +10,7 @@ common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
>  
>  ifeq ($(CONFIG_LINUX),y)
>  common-obj-$(CONFIG_VIRTIO) += virtio-input.o
> +common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
>  endif
>  
>  obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
> diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
> new file mode 100644
> index 0000000..2db993e
> --- /dev/null
> +++ b/hw/input/virtio-input-hid.c
> @@ -0,0 +1,486 @@
> +/*
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> + * (at your option) any later version.  See the COPYING file in the
> + * top-level directory.
> + */
> +
> +#include "qemu/iov.h"
> +
> +#include "hw/qdev.h"
> +#include "hw/virtio/virtio.h"
> +#include "hw/virtio/virtio-input.h"
> +
> +#include "ui/console.h"
> +
> +#include <linux/input.h>
> +
> +#define VIRTIO_ID_NAME_KEYBOARD "QEMU Virtio Keyboard"
> +#define VIRTIO_ID_NAME_MOUSE    "QEMU Virtio Mouse"
> +#define VIRTIO_ID_NAME_TABLET   "QEMU Virtio Tablet"
> +
> +/* ----------------------------------------------------------------- */
> +
> +static const unsigned int keymap_qcode[Q_KEY_CODE_MAX] = {
> +    [Q_KEY_CODE_ESC]                 = KEY_ESC,
> +    [Q_KEY_CODE_1]                   = KEY_1,
> +    [Q_KEY_CODE_2]                   = KEY_2,
> +    [Q_KEY_CODE_3]                   = KEY_3,
> +    [Q_KEY_CODE_4]                   = KEY_4,
> +    [Q_KEY_CODE_5]                   = KEY_5,
> +    [Q_KEY_CODE_6]                   = KEY_6,
> +    [Q_KEY_CODE_7]                   = KEY_7,
> +    [Q_KEY_CODE_8]                   = KEY_8,
> +    [Q_KEY_CODE_9]                   = KEY_9,
> +    [Q_KEY_CODE_0]                   = KEY_0,
> +    [Q_KEY_CODE_MINUS]               = KEY_MINUS,
> +    [Q_KEY_CODE_EQUAL]               = KEY_EQUAL,
> +    [Q_KEY_CODE_BACKSPACE]           = KEY_BACKSPACE,
> +
> +    [Q_KEY_CODE_TAB]                 = KEY_TAB,
> +    [Q_KEY_CODE_Q]                   = KEY_Q,
> +    [Q_KEY_CODE_W]                   = KEY_W,
> +    [Q_KEY_CODE_E]                   = KEY_E,
> +    [Q_KEY_CODE_R]                   = KEY_R,
> +    [Q_KEY_CODE_T]                   = KEY_T,
> +    [Q_KEY_CODE_Y]                   = KEY_Y,
> +    [Q_KEY_CODE_U]                   = KEY_U,
> +    [Q_KEY_CODE_I]                   = KEY_I,
> +    [Q_KEY_CODE_O]                   = KEY_O,
> +    [Q_KEY_CODE_P]                   = KEY_P,
> +    [Q_KEY_CODE_BRACKET_LEFT]        = KEY_LEFTBRACE,
> +    [Q_KEY_CODE_BRACKET_RIGHT]       = KEY_RIGHTBRACE,
> +    [Q_KEY_CODE_RET]                 = KEY_ENTER,
> +
> +    [Q_KEY_CODE_CTRL]                = KEY_LEFTCTRL,
> +    [Q_KEY_CODE_A]                   = KEY_A,
> +    [Q_KEY_CODE_S]                   = KEY_S,
> +    [Q_KEY_CODE_D]                   = KEY_D,
> +    [Q_KEY_CODE_F]                   = KEY_F,
> +    [Q_KEY_CODE_G]                   = KEY_G,
> +    [Q_KEY_CODE_H]                   = KEY_H,
> +    [Q_KEY_CODE_J]                   = KEY_J,
> +    [Q_KEY_CODE_K]                   = KEY_K,
> +    [Q_KEY_CODE_L]                   = KEY_L,
> +    [Q_KEY_CODE_SEMICOLON]           = KEY_SEMICOLON,
> +    [Q_KEY_CODE_APOSTROPHE]          = KEY_APOSTROPHE,
> +    [Q_KEY_CODE_GRAVE_ACCENT]        = KEY_GRAVE,
> +
> +    [Q_KEY_CODE_SHIFT]               = KEY_LEFTSHIFT,
> +    [Q_KEY_CODE_BACKSLASH]           = KEY_BACKSLASH,
> +    [Q_KEY_CODE_LESS]                = KEY_102ND,
> +    [Q_KEY_CODE_Z]                   = KEY_Z,
> +    [Q_KEY_CODE_X]                   = KEY_X,
> +    [Q_KEY_CODE_C]                   = KEY_C,
> +    [Q_KEY_CODE_V]                   = KEY_V,
> +    [Q_KEY_CODE_B]                   = KEY_B,
> +    [Q_KEY_CODE_N]                   = KEY_N,
> +    [Q_KEY_CODE_M]                   = KEY_M,
> +    [Q_KEY_CODE_COMMA]               = KEY_COMMA,
> +    [Q_KEY_CODE_DOT]                 = KEY_DOT,
> +    [Q_KEY_CODE_SLASH]               = KEY_SLASH,
> +    [Q_KEY_CODE_SHIFT_R]             = KEY_RIGHTSHIFT,
> +
> +    [Q_KEY_CODE_ALT]                 = KEY_LEFTALT,
> +    [Q_KEY_CODE_SPC]                 = KEY_SPACE,
> +    [Q_KEY_CODE_CAPS_LOCK]           = KEY_CAPSLOCK,
> +
> +    [Q_KEY_CODE_F1]                  = KEY_F1,
> +    [Q_KEY_CODE_F2]                  = KEY_F2,
> +    [Q_KEY_CODE_F3]                  = KEY_F3,
> +    [Q_KEY_CODE_F4]                  = KEY_F4,
> +    [Q_KEY_CODE_F5]                  = KEY_F5,
> +    [Q_KEY_CODE_F6]                  = KEY_F6,
> +    [Q_KEY_CODE_F7]                  = KEY_F7,
> +    [Q_KEY_CODE_F8]                  = KEY_F8,
> +    [Q_KEY_CODE_F9]                  = KEY_F9,
> +    [Q_KEY_CODE_F10]                 = KEY_F10,
> +    [Q_KEY_CODE_NUM_LOCK]            = KEY_NUMLOCK,
> +    [Q_KEY_CODE_SCROLL_LOCK]         = KEY_SCROLLLOCK,
> +
> +    [Q_KEY_CODE_KP_0]                = KEY_KP0,
> +    [Q_KEY_CODE_KP_1]                = KEY_KP1,
> +    [Q_KEY_CODE_KP_2]                = KEY_KP2,
> +    [Q_KEY_CODE_KP_3]                = KEY_KP3,
> +    [Q_KEY_CODE_KP_4]                = KEY_KP4,
> +    [Q_KEY_CODE_KP_5]                = KEY_KP5,
> +    [Q_KEY_CODE_KP_6]                = KEY_KP6,
> +    [Q_KEY_CODE_KP_7]                = KEY_KP7,
> +    [Q_KEY_CODE_KP_8]                = KEY_KP8,
> +    [Q_KEY_CODE_KP_9]                = KEY_KP9,
> +    [Q_KEY_CODE_KP_SUBTRACT]         = KEY_KPMINUS,
> +    [Q_KEY_CODE_KP_ADD]              = KEY_KPPLUS,
> +    [Q_KEY_CODE_KP_DECIMAL]          = KEY_KPDOT,
> +    [Q_KEY_CODE_KP_ENTER]            = KEY_KPENTER,
> +    [Q_KEY_CODE_KP_DIVIDE]           = KEY_KPSLASH,
> +    [Q_KEY_CODE_KP_MULTIPLY]         = KEY_KPASTERISK,
> +
> +    [Q_KEY_CODE_F11]                 = KEY_F11,
> +    [Q_KEY_CODE_F12]                 = KEY_F12,
> +
> +    [Q_KEY_CODE_CTRL_R]              = KEY_RIGHTCTRL,
> +    [Q_KEY_CODE_SYSRQ]               = KEY_SYSRQ,
> +    [Q_KEY_CODE_ALT_R]               = KEY_RIGHTALT,
> +
> +    [Q_KEY_CODE_HOME]                = KEY_HOME,
> +    [Q_KEY_CODE_UP]                  = KEY_UP,
> +    [Q_KEY_CODE_PGUP]                = KEY_PAGEUP,
> +    [Q_KEY_CODE_LEFT]                = KEY_LEFT,
> +    [Q_KEY_CODE_RIGHT]               = KEY_RIGHT,
> +    [Q_KEY_CODE_END]                 = KEY_END,
> +    [Q_KEY_CODE_DOWN]                = KEY_DOWN,
> +    [Q_KEY_CODE_PGDN]                = KEY_PAGEDOWN,
> +    [Q_KEY_CODE_INSERT]              = KEY_INSERT,
> +    [Q_KEY_CODE_DELETE]              = KEY_DELETE,
> +
> +    [Q_KEY_CODE_META_L]              = KEY_LEFTMETA,
> +    [Q_KEY_CODE_META_R]              = KEY_RIGHTMETA,
> +    [Q_KEY_CODE_MENU]                = KEY_MENU,
> +};

OK these are values send to guest, right?
And they are from linux/input.h, right? But are these
reasonable in a cross-platform device?

E.g. Linux is pretty good at backwards compatibility
but less good at versioning.

That header says "Most of the keys/buttons are modeled after USB HUT
1.12" but as far as I could see the codes are not from HUT, correct?

Would it be a good idea to use codes from HUT directly?
This way we could extend functionality without adding lots of
text to the spec, simply by referring to HUT.

Also what defines the subset selected?
I'm a bit worried that we'll get into an endless cycle of spec
updates with each new button missing above.

> +
> +static const unsigned int keymap_button[INPUT_BUTTON_MAX] = {
> +    [INPUT_BUTTON_LEFT]              = BTN_LEFT,
> +    [INPUT_BUTTON_RIGHT]             = BTN_RIGHT,
> +    [INPUT_BUTTON_MIDDLE]            = BTN_MIDDLE,
> +    [INPUT_BUTTON_WHEEL_UP]          = BTN_GEAR_UP,
> +    [INPUT_BUTTON_WHEEL_DOWN]        = BTN_GEAR_DOWN,
> +};
> +
> +static const unsigned int axismap_rel[INPUT_AXIS_MAX] = {
> +    [INPUT_AXIS_X]                   = REL_X,
> +    [INPUT_AXIS_Y]                   = REL_Y,
> +};
> +
> +static const unsigned int axismap_abs[INPUT_AXIS_MAX] = {
> +    [INPUT_AXIS_X]                   = ABS_X,
> +    [INPUT_AXIS_Y]                   = ABS_Y,
> +};
> +

In the future, it seems like a good idea to report raw
multi-touch events to guests - this would need a different
interface along the lines of
Documentation/input/multi-touch-protocol.txt

How would we handle such an extension?
Do MT devices generate ST events as well so it's ok to just
filter out everything we don't recognize?


> +/* ----------------------------------------------------------------- */
> +
> +static void virtio_input_key_config(VirtIOInput *vinput,
> +                                    const unsigned int *keymap,
> +                                    size_t mapsize)
> +{
> +    virtio_input_config keys;
> +    int i, bit, byte, bmax = 0;
> +
> +    memset(&keys, 0, sizeof(keys));
> +    for (i = 0; i < mapsize; i++) {
> +        bit = keymap[i];
> +        if (!bit) {
> +            continue;
> +        }
> +        byte = bit / 8;
> +        bit  = bit % 8;
> +        keys.u.bitmap[byte] |= (1 << bit);
> +        if (bmax < byte+1) {
> +            bmax = byte+1;
> +        }
> +    }
> +    keys.select = VIRTIO_INPUT_CFG_EV_BITS;
> +    keys.subsel = EV_KEY;
> +    keys.size   = bmax;
> +    virtio_input_add_config(vinput, &keys);
> +}
> +
> +static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
> +                                      InputEvent *evt)
> +{
> +    VirtIOInput *vinput = VIRTIO_INPUT(dev);
> +    virtio_input_event event;
> +    int qcode;
> +
> +    switch (evt->kind) {
> +    case INPUT_EVENT_KIND_KEY:
> +        qcode = qemu_input_key_value_to_qcode(evt->key->key);
> +        if (qcode && keymap_qcode[qcode]) {
> +            event.type  = cpu_to_le16(EV_KEY);
> +            event.code  = cpu_to_le16(keymap_qcode[qcode]);
> +            event.value = cpu_to_le32(evt->key->down ? 1 : 0);
> +            virtio_input_send(vinput, &event);
> +        } else {
> +            if (evt->key->down) {
> +                fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__,
> +                        qcode, QKeyCode_lookup[qcode]);
> +            }
> +        }
> +        break;
> +    case INPUT_EVENT_KIND_BTN:
> +        if (keymap_button[evt->btn->button]) {
> +            event.type  = cpu_to_le16(EV_KEY);
> +            event.code  = cpu_to_le16(keymap_button[evt->btn->button]);
> +            event.value = cpu_to_le32(evt->btn->down ? 1 : 0);
> +            virtio_input_send(vinput, &event);
> +        } else {
> +            if (evt->btn->down) {
> +                fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__,
> +                        evt->btn->button, 
> InputButton_lookup[evt->btn->button]);
> +            }
> +        }
> +        break;
> +    case INPUT_EVENT_KIND_REL:
> +        event.type  = cpu_to_le16(EV_REL);
> +        event.code  = cpu_to_le16(axismap_rel[evt->rel->axis]);
> +        event.value = cpu_to_le32(evt->rel->value);
> +        virtio_input_send(vinput, &event);
> +        break;
> +    case INPUT_EVENT_KIND_ABS:
> +        event.type  = cpu_to_le16(EV_ABS);
> +        event.code  = cpu_to_le16(axismap_abs[evt->abs->axis]);
> +        event.value = cpu_to_le32(evt->abs->value);
> +        virtio_input_send(vinput, &event);
> +        break;
> +    default:
> +        /* keep gcc happy */
> +        break;
> +    }
> +}
> +
> +static void virtio_input_handle_sync(DeviceState *dev)
> +{
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIOInput *vinput = VIRTIO_INPUT(dev);
> +    virtio_input_event event = {
> +        .type  = cpu_to_le16(EV_SYN),
> +        .code  = cpu_to_le16(SYN_REPORT),
> +        .value = 0,
> +    };
> +
> +    virtio_input_send(vinput, &event);
> +    virtio_notify(vdev, vinput->evt);
> +}
> +
> +static void virtio_input_hid_realize(DeviceState *dev, Error **errp)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
> +    vhid->hs = qemu_input_handler_register(dev, vhid->handler);
> +}
> +
> +static void virtio_input_hid_unrealize(DeviceState *dev, Error **errp)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
> +    qemu_input_handler_unregister(vhid->hs);
> +}
> +
> +static void virtio_input_hid_change_active(VirtIOInput *vinput)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
> +
> +    if (vinput->active) {
> +        qemu_input_handler_activate(vhid->hs);
> +    } else {
> +        qemu_input_handler_deactivate(vhid->hs);
> +    }
> +}
> +
> +static void virtio_input_hid_handle_status(VirtIOInput *vinput,
> +                                           virtio_input_event *event)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
> +    int ledbit = 0;
> +
> +    switch (le16_to_cpu(event->type)) {
> +    case EV_LED:
> +        if (event->code == LED_NUML) {
> +            ledbit = QEMU_NUM_LOCK_LED;
> +        } else if (event->code == LED_CAPSL) {
> +            ledbit = QEMU_CAPS_LOCK_LED;
> +        } else if (event->code == LED_SCROLLL) {
> +            ledbit = QEMU_SCROLL_LOCK_LED;
> +        }
> +        if (event->value) {
> +            vhid->ledstate |= ledbit;
> +        } else {
> +            vhid->ledstate &= ~ledbit;
> +        }
> +        kbd_put_ledstate(vhid->ledstate);


What does this do? notice led light up on one keyboard and propagate
state to all keyboards?

> +        break;
> +    default:
> +        fprintf(stderr, "%s: unknown type %d\n", __func__,
> +                le16_to_cpu(event->type));
> +        break;
> +    }
> +}
> +
> +static void virtio_input_hid_class_init(ObjectClass *klass, void *data)
> +{
> +    VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
> +
> +    vic->realize       = virtio_input_hid_realize;
> +    vic->unrealize     = virtio_input_hid_unrealize;
> +    vic->change_active = virtio_input_hid_change_active;
> +    vic->handle_status = virtio_input_hid_handle_status;
> +}
> +
> +static const TypeInfo virtio_input_hid_info = {
> +    .name          = TYPE_VIRTIO_INPUT_HID,
> +    .parent        = TYPE_VIRTIO_INPUT,
> +    .instance_size = sizeof(VirtIOInputHID),
> +    .class_init    = virtio_input_hid_class_init,
> +    .abstract      = true,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static QemuInputHandler virtio_keyboard_handler = {
> +    .name  = VIRTIO_ID_NAME_KEYBOARD,
> +    .mask  = INPUT_EVENT_MASK_KEY,
> +    .event = virtio_input_handle_event,
> +    .sync  = virtio_input_handle_sync,
> +};
> +
> +static struct virtio_input_config virtio_keyboard_config[] = {
> +    {
> +        .select    = VIRTIO_INPUT_CFG_ID_NAME,
> +        .size      = sizeof(VIRTIO_ID_NAME_KEYBOARD),
> +        .u.string  = VIRTIO_ID_NAME_KEYBOARD,
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_EV_BITS,
> +        .subsel    = EV_REP,
> +        .size      = 1,
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_EV_BITS,
> +        .subsel    = EV_LED,
> +        .size      = 1,
> +        .u.bitmap  = {
> +            (1 << LED_NUML) | (1 << LED_CAPSL) | (1 << LED_SCROLLL),
> +        },
> +    },
> +    { /* end of list */ },
> +};
> +
> +static void virtio_keyboard_init(Object *obj)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
> +    VirtIOInput *vinput = VIRTIO_INPUT(obj);
> +
> +    vhid->handler = &virtio_keyboard_handler;
> +    virtio_input_init_config(vinput, virtio_keyboard_config);
> +    virtio_input_key_config(vinput, keymap_qcode,
> +                            ARRAY_SIZE(keymap_qcode));
> +}
> +
> +static const TypeInfo virtio_keyboard_info = {
> +    .name          = TYPE_VIRTIO_KEYBOARD,
> +    .parent        = TYPE_VIRTIO_INPUT_HID,
> +    .instance_size = sizeof(VirtIOInputHID),
> +    .instance_init = virtio_keyboard_init,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static QemuInputHandler virtio_mouse_handler = {
> +    .name  = VIRTIO_ID_NAME_MOUSE,
> +    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
> +    .event = virtio_input_handle_event,
> +    .sync  = virtio_input_handle_sync,
> +};
> +
> +static struct virtio_input_config virtio_mouse_config[] = {
> +    {
> +        .select    = VIRTIO_INPUT_CFG_ID_NAME,
> +        .size      = sizeof(VIRTIO_ID_NAME_MOUSE),
> +        .u.string  = VIRTIO_ID_NAME_MOUSE,
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_EV_BITS,
> +        .subsel    = EV_REL,
> +        .size      = 1,
> +        .u.bitmap  = {
> +            (1 << REL_X) | (1 << REL_Y),
> +        },
> +    },
> +    { /* end of list */ },
> +};
> +
> +static void virtio_mouse_init(Object *obj)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
> +    VirtIOInput *vinput = VIRTIO_INPUT(obj);
> +
> +    vhid->handler = &virtio_mouse_handler;
> +    virtio_input_init_config(vinput, virtio_mouse_config);
> +    virtio_input_key_config(vinput, keymap_button,
> +                            ARRAY_SIZE(keymap_button));
> +}
> +
> +static const TypeInfo virtio_mouse_info = {
> +    .name          = TYPE_VIRTIO_MOUSE,
> +    .parent        = TYPE_VIRTIO_INPUT_HID,
> +    .instance_size = sizeof(VirtIOInputHID),
> +    .instance_init = virtio_mouse_init,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static QemuInputHandler virtio_tablet_handler = {
> +    .name  = VIRTIO_ID_NAME_TABLET,
> +    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
> +    .event = virtio_input_handle_event,
> +    .sync  = virtio_input_handle_sync,
> +};
> +
> +static struct virtio_input_config virtio_tablet_config[] = {
> +    {
> +        .select    = VIRTIO_INPUT_CFG_ID_NAME,
> +        .size      = sizeof(VIRTIO_ID_NAME_TABLET),
> +        .u.string  = VIRTIO_ID_NAME_TABLET,
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_EV_BITS,
> +        .subsel    = EV_ABS,
> +        .size      = 1,
> +        .u.bitmap  = {
> +            (1 << ABS_X) | (1 << ABS_Y),
> +        },
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_ABS_INFO,
> +        .subsel    = ABS_X,
> +        .size      = sizeof(virtio_input_absinfo),
> +#if 0
> +        /* FIXME */
> +        .u.abs.max = cpu_to_le32(INPUT_EVENT_ABS_SIZE),
> +#else
> +        .u.abs.max = INPUT_EVENT_ABS_SIZE,
> +#endif
> +    },{
> +        .select    = VIRTIO_INPUT_CFG_ABS_INFO,
> +        .subsel    = ABS_Y,
> +        .size      = sizeof(virtio_input_absinfo),
> +#if 0
> +        /* FIXME */
> +        .u.abs.max = cpu_to_le32(INPUT_EVENT_ABS_SIZE),
> +#else
> +        .u.abs.max = INPUT_EVENT_ABS_SIZE,
> +#endif
> +    },
> +    { /* end of list */ },
> +};
> +
> +static void virtio_tablet_init(Object *obj)
> +{
> +    VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
> +    VirtIOInput *vinput = VIRTIO_INPUT(obj);
> +
> +    vhid->handler = &virtio_tablet_handler;
> +    virtio_input_init_config(vinput, virtio_tablet_config);
> +    virtio_input_key_config(vinput, keymap_button,
> +                            ARRAY_SIZE(keymap_button));
> +}
> +
> +static const TypeInfo virtio_tablet_info = {
> +    .name          = TYPE_VIRTIO_TABLET,
> +    .parent        = TYPE_VIRTIO_INPUT_HID,
> +    .instance_size = sizeof(VirtIOInputHID),
> +    .instance_init = virtio_tablet_init,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static void virtio_register_types(void)
> +{
> +    type_register_static(&virtio_input_hid_info);
> +    type_register_static(&virtio_keyboard_info);
> +    type_register_static(&virtio_mouse_info);
> +    type_register_static(&virtio_tablet_info);
> +}
> +
> +type_init(virtio_register_types)
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index 5518192..b421c01 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -1534,6 +1534,13 @@ static const TypeInfo virtio_rng_pci_info = {
>  
>  /* virtio-input-pci */
>  
> +static Property virtio_input_hid_pci_properties[] = {
> +    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
> +    DEFINE_VIRTIO_INPUT_PROPERTIES(VirtIOInputPCI, vdev.input),
> +    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
>  static int virtio_input_pci_init(VirtIOPCIProxy *vpci_dev)
>  {
>      VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
> @@ -1558,6 +1565,34 @@ static void virtio_input_pci_class_init(ObjectClass 
> *klass, void *data)
>      pcidev_k->class_id = PCI_CLASS_OTHERS;
>  }
>  
> +static void virtio_input_hid_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->props = virtio_input_hid_pci_properties;
> +}
> +
> +static void virtio_keyboard_initfn(Object *obj)
> +{
> +    VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
> +    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_KEYBOARD);
> +    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), 
> NULL);
> +}
> +
> +static void virtio_mouse_initfn(Object *obj)
> +{
> +    VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
> +    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_MOUSE);
> +    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), 
> NULL);
> +}
> +
> +static void virtio_tablet_initfn(Object *obj)
> +{
> +    VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
> +    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TABLET);
> +    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), 
> NULL);
> +}
> +
>  static const TypeInfo virtio_input_pci_info = {
>      .name          = TYPE_VIRTIO_INPUT_PCI,
>      .parent        = TYPE_VIRTIO_PCI,
> @@ -1566,6 +1601,35 @@ static const TypeInfo virtio_input_pci_info = {
>      .abstract      = true,
>  };
>  
> +static const TypeInfo virtio_input_hid_pci_info = {
> +    .name          = TYPE_VIRTIO_INPUT_HID_PCI,
> +    .parent        = TYPE_VIRTIO_INPUT_PCI,
> +    .instance_size = sizeof(VirtIOInputHIDPCI),
> +    .class_init    = virtio_input_hid_pci_class_init,
> +    .abstract      = true,
> +};
> +
> +static const TypeInfo virtio_keyboard_pci_info = {
> +    .name          = TYPE_VIRTIO_KEYBOARD_PCI,
> +    .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
> +    .instance_size = sizeof(VirtIOInputHIDPCI),
> +    .instance_init = virtio_keyboard_initfn,
> +};
> +
> +static const TypeInfo virtio_mouse_pci_info = {
> +    .name          = TYPE_VIRTIO_MOUSE_PCI,
> +    .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
> +    .instance_size = sizeof(VirtIOInputHIDPCI),
> +    .instance_init = virtio_mouse_initfn,
> +};
> +
> +static const TypeInfo virtio_tablet_pci_info = {
> +    .name          = TYPE_VIRTIO_TABLET_PCI,
> +    .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
> +    .instance_size = sizeof(VirtIOInputHIDPCI),
> +    .instance_init = virtio_tablet_initfn,
> +};
> +
>  /* virtio-pci-bus */
>  
>  static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
> @@ -1611,6 +1675,10 @@ static void virtio_pci_register_types(void)
>  {
>      type_register_static(&virtio_rng_pci_info);
>      type_register_static(&virtio_input_pci_info);
> +    type_register_static(&virtio_input_hid_pci_info);
> +    type_register_static(&virtio_keyboard_pci_info);
> +    type_register_static(&virtio_mouse_pci_info);
> +    type_register_static(&virtio_tablet_pci_info);
>      type_register_static(&virtio_pci_bus_info);
>      type_register_static(&virtio_pci_info);
>  #ifdef CONFIG_VIRTFS
> diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
> index f1e75ad..f615ae6 100644
> --- a/hw/virtio/virtio-pci.h
> +++ b/hw/virtio/virtio-pci.h
> @@ -41,6 +41,7 @@ typedef struct VirtIONetPCI VirtIONetPCI;
>  typedef struct VHostSCSIPCI VHostSCSIPCI;
>  typedef struct VirtIORngPCI VirtIORngPCI;
>  typedef struct VirtIOInputPCI VirtIOInputPCI;
> +typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
>  
>  /* virtio-pci-bus */
>  
> @@ -213,6 +214,18 @@ struct VirtIOInputPCI {
>      VirtIOInput vdev;
>  };
>  
> +#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci"
> +#define TYPE_VIRTIO_KEYBOARD_PCI  "virtio-keyboard-pci"
> +#define TYPE_VIRTIO_MOUSE_PCI     "virtio-mouse-pci"
> +#define TYPE_VIRTIO_TABLET_PCI    "virtio-tablet-pci"
> +#define VIRTIO_INPUT_HID_PCI(obj) \
> +        OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI)
> +
> +struct VirtIOInputHIDPCI {
> +    VirtIOPCIProxy parent_obj;
> +    VirtIOInputHID vdev;
> +};
> +
>  /* Virtio ABI version, if we increment this, we break the guest driver. */
>  #define VIRTIO_PCI_ABI_VERSION          0
>  
> diff --git a/include/hw/virtio/virtio-input.h 
> b/include/hw/virtio/virtio-input.h
> index 5d37a70..4b819c3 100644
> --- a/include/hw/virtio/virtio-input.h
> +++ b/include/hw/virtio/virtio-input.h
> @@ -57,9 +57,24 @@ typedef struct virtio_input_event {
>  #define VIRTIO_INPUT_CLASS(klass) \
>          OBJECT_CLASS_CHECK(VirtIOInputClass, klass, TYPE_VIRTIO_INPUT)
>  
> +#define TYPE_VIRTIO_INPUT_HID "virtio-input-hid"
> +#define TYPE_VIRTIO_KEYBOARD  "virtio-keyboard"
> +#define TYPE_VIRTIO_MOUSE     "virtio-mouse"
> +#define TYPE_VIRTIO_TABLET    "virtio-tablet"
> +
> +#define VIRTIO_INPUT_HID(obj) \
> +        OBJECT_CHECK(VirtIOInputHID, (obj), TYPE_VIRTIO_INPUT_HID)
> +#define VIRTIO_INPUT_HID_GET_PARENT_CLASS(obj) \
> +        OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HID)
> +
> +#define DEFINE_VIRTIO_INPUT_PROPERTIES(_state, _field)       \
> +        DEFINE_PROP_STRING("serial", _state, _field.serial), \
> +        DEFINE_PROP_STRING("seat", _state, _field.seat)
> +
>  typedef struct VirtIOInput VirtIOInput;
>  typedef struct VirtIOInputClass VirtIOInputClass;
>  typedef struct VirtIOInputConfig VirtIOInputConfig;
> +typedef struct VirtIOInputHID VirtIOInputHID;
>  
>  struct virtio_input_conf {
>      char *serial;
> @@ -94,6 +109,13 @@ struct VirtIOInputClass {
>      void (*handle_status)(VirtIOInput *vinput, virtio_input_event *event);
>  };
>  
> +struct VirtIOInputHID {
> +    VirtIOInput                       parent_obj;
> +    QemuInputHandler                  *handler;
> +    QemuInputHandlerState             *hs;
> +    int                               ledstate;
> +};
> +
>  void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event);
>  void virtio_input_init_config(VirtIOInput *vinput,
>                                virtio_input_config *config);
> -- 
> 1.8.3.1



reply via email to

[Prev in Thread] Current Thread [Next in Thread]