ae6b06ab65
Replace the keymap_qcode table with automatically generated tables. Missing entries in keymap_qcode now fixed: Q_KEY_CODE_ASTERISK -> KEY_KPASTERISK Q_KEY_CODE_KP_MULTIPLY -> KEY_KPASTERISK Q_KEY_CODE_STOP -> KEY_STOP Q_KEY_CODE_AGAIN -> KEY_AGAIN Q_KEY_CODE_PROPS -> KEY_PROPS Q_KEY_CODE_UNDO -> KEY_UNDO Q_KEY_CODE_FRONT -> KEY_FRONT Q_KEY_CODE_COPY -> KEY_COPY Q_KEY_CODE_OPEN -> KEY_OPEN Q_KEY_CODE_PASTE -> KEY_PASTE Q_KEY_CODE_FIND -> KEY_FIND Q_KEY_CODE_CUT -> KEY_CUT Q_KEY_CODE_LF -> KEY_LINEFEED Q_KEY_CODE_HELP -> KEY_HELP Q_KEY_CODE_COMPOSE -> KEY_COMPOSE Q_KEY_CODE_RO -> KEY_RO Q_KEY_CODE_HIRAGANA -> KEY_HIRAGANA Q_KEY_CODE_HENKAN -> KEY_HENKAN Q_KEY_CODE_YEN -> KEY_YEN Q_KEY_CODE_KP_COMMA -> KEY_KPCOMMA Q_KEY_CODE_KP_EQUALS -> KEY_KPEQUAL Q_KEY_CODE_POWER -> KEY_POWER Q_KEY_CODE_SLEEP -> KEY_SLEEP Q_KEY_CODE_WAKE -> KEY_WAKEUP Q_KEY_CODE_AUDIONEXT -> KEY_NEXTSONG Q_KEY_CODE_AUDIOPREV -> KEY_PREVIOUSSONG Q_KEY_CODE_AUDIOSTOP -> KEY_STOPCD Q_KEY_CODE_AUDIOPLAY -> KEY_PLAYPAUSE Q_KEY_CODE_AUDIOMUTE -> KEY_MUTE Q_KEY_CODE_VOLUMEUP -> KEY_VOLUMEUP Q_KEY_CODE_VOLUMEDOWN -> KEY_VOLUMEDOWN Q_KEY_CODE_MEDIASELECT -> KEY_MEDIA Q_KEY_CODE_MAIL -> KEY_MAIL Q_KEY_CODE_CALCULATOR -> KEY_CALC Q_KEY_CODE_COMPUTER -> KEY_COMPUTER Q_KEY_CODE_AC_HOME -> KEY_HOMEPAGE Q_KEY_CODE_AC_BACK -> KEY_BACK Q_KEY_CODE_AC_FORWARD -> KEY_FORWARD Q_KEY_CODE_AC_REFRESH -> KEY_REFRESH Q_KEY_CODE_AC_BOOKMARKS -> KEY_BOOKMARKS NB, the virtio-input device reports a bitmask to the guest driver that has a bit set for each Linux keycode that the host is able to send to the guest. Thus by adding these extra key mappings we are technically changing the host<->guest ABI. This would also happen any time we defined new mappings for QEMU keycodes in future. When a keycode is removed from the list of possible keycodes that host can send to the guest, it means that the guest OS will think it is possible to receive a key that in pratice can never be generated, which is harmless. When a keycode is added to the list of possible keycodes that the host can send to the guest, it means that the guest OS can see an unexpected event. The Linux virtio_input.c driver code simply forwards this event to the input_event() method in the Linux input subsystem. This in turn calls input_handle_event(), which then calls input_get_disposition(). This method checks if the input event is present in the permitted keys bitmap, and if not returns INPUT_IGNORE_EVENT. Thus the unexpected event will get dropped, which is harmless. If the guest OS reboots, or otherwise re-initializes the virt-input device, it will read the new keycode bitmap. No matter how many keys are defined, the config space has a fixed 128 byte bitmap. There is, however, a size field defiend which says how many bytes in the bitmap are used. So the guest OS reads the size of the bitmap, and then it reads the data from bitmap upto the designated size. So if the guest OS re-initializes at precisely the time that QEMU is migrated across versions, in the worst case, it could conceivably read the old size field, but then get the newly updated bitmap. If a key were added this is harmless, since it simply means it may not process the newly added key. If a key were removed, then it could be readnig a byte from the bitmap that was not initialized. Fortunately QEMU always memsets() the entire bitmap to 0, prior to setting keybits. Thus the guest OS will simply read zeros, which is again harmless. Based on this analysis, it is believed that there is no need to preserve the virtio-input-hid keymaps across migration, as the host<->guest ABI change is harmless and self-resolving at time of guest reboot. NB, this behaviour should perhaps be formalized in the virtio-input spec to declare how guest OS drivers should be written to be robust in their handling of the potentially changable key bitmaps. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Message-id: 20180117164118.8510-5-berrange@redhat.com Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
523 lines
16 KiB
C
523 lines
16 KiB
C
/*
|
|
* 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/osdep.h"
|
|
#include "qemu/iov.h"
|
|
|
|
#include "hw/qdev.h"
|
|
#include "hw/virtio/virtio.h"
|
|
#include "hw/virtio/virtio-input.h"
|
|
|
|
#undef CONFIG_CURSES
|
|
#include "ui/console.h"
|
|
|
|
#include "standard-headers/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 short 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,
|
|
[INPUT_BUTTON_SIDE] = BTN_SIDE,
|
|
[INPUT_BUTTON_EXTRA] = BTN_EXTRA,
|
|
};
|
|
|
|
static const unsigned short axismap_rel[INPUT_AXIS__MAX] = {
|
|
[INPUT_AXIS_X] = REL_X,
|
|
[INPUT_AXIS_Y] = REL_Y,
|
|
};
|
|
|
|
static const unsigned short axismap_abs[INPUT_AXIS__MAX] = {
|
|
[INPUT_AXIS_X] = ABS_X,
|
|
[INPUT_AXIS_Y] = ABS_Y,
|
|
};
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
|
|
static void virtio_input_key_config(VirtIOInput *vinput,
|
|
const unsigned short *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)
|
|
{
|
|
VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
|
|
VirtIOInput *vinput = VIRTIO_INPUT(dev);
|
|
virtio_input_event event;
|
|
int qcode;
|
|
InputKeyEvent *key;
|
|
InputMoveEvent *move;
|
|
InputBtnEvent *btn;
|
|
|
|
switch (evt->type) {
|
|
case INPUT_EVENT_KIND_KEY:
|
|
key = evt->u.key.data;
|
|
qcode = qemu_input_key_value_to_qcode(key->key);
|
|
if (qcode < qemu_input_map_qcode_to_linux_len &&
|
|
qemu_input_map_qcode_to_linux[qcode]) {
|
|
event.type = cpu_to_le16(EV_KEY);
|
|
event.code = cpu_to_le16(qemu_input_map_qcode_to_linux[qcode]);
|
|
event.value = cpu_to_le32(key->down ? 1 : 0);
|
|
virtio_input_send(vinput, &event);
|
|
} else {
|
|
if (key->down) {
|
|
fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__,
|
|
qcode, QKeyCode_str(qcode));
|
|
}
|
|
}
|
|
break;
|
|
case INPUT_EVENT_KIND_BTN:
|
|
btn = evt->u.btn.data;
|
|
if (vhid->wheel_axis &&
|
|
(btn->button == INPUT_BUTTON_WHEEL_UP ||
|
|
btn->button == INPUT_BUTTON_WHEEL_DOWN) &&
|
|
btn->down) {
|
|
event.type = cpu_to_le16(EV_REL);
|
|
event.code = cpu_to_le16(REL_WHEEL);
|
|
event.value = cpu_to_le32(btn->button == INPUT_BUTTON_WHEEL_UP
|
|
? 1 : -1);
|
|
virtio_input_send(vinput, &event);
|
|
} else if (keymap_button[btn->button]) {
|
|
event.type = cpu_to_le16(EV_KEY);
|
|
event.code = cpu_to_le16(keymap_button[btn->button]);
|
|
event.value = cpu_to_le32(btn->down ? 1 : 0);
|
|
virtio_input_send(vinput, &event);
|
|
} else {
|
|
if (btn->down) {
|
|
fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__,
|
|
btn->button,
|
|
InputButton_str(btn->button));
|
|
}
|
|
}
|
|
break;
|
|
case INPUT_EVENT_KIND_REL:
|
|
move = evt->u.rel.data;
|
|
event.type = cpu_to_le16(EV_REL);
|
|
event.code = cpu_to_le16(axismap_rel[move->axis]);
|
|
event.value = cpu_to_le32(move->value);
|
|
virtio_input_send(vinput, &event);
|
|
break;
|
|
case INPUT_EVENT_KIND_ABS:
|
|
move = evt->u.abs.data;
|
|
event.type = cpu_to_le16(EV_ABS);
|
|
event.code = cpu_to_le16(axismap_abs[move->axis]);
|
|
event.value = cpu_to_le32(move->value);
|
|
virtio_input_send(vinput, &event);
|
|
break;
|
|
default:
|
|
/* keep gcc happy */
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void virtio_input_handle_sync(DeviceState *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);
|
|
}
|
|
|
|
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);
|
|
if (vhid->display && vhid->hs) {
|
|
qemu_input_handler_bind(vhid->hs, vhid->display, vhid->head, NULL);
|
|
}
|
|
}
|
|
|
|
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);
|
|
break;
|
|
default:
|
|
fprintf(stderr, "%s: unknown type %d\n", __func__,
|
|
le16_to_cpu(event->type));
|
|
break;
|
|
}
|
|
}
|
|
|
|
static Property virtio_input_hid_properties[] = {
|
|
DEFINE_PROP_STRING("display", VirtIOInputHID, display),
|
|
DEFINE_PROP_UINT32("head", VirtIOInputHID, head, 0),
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
};
|
|
|
|
static void virtio_input_hid_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
|
|
|
|
dc->props = virtio_input_hid_properties;
|
|
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_ID_DEVIDS,
|
|
.size = sizeof(struct virtio_input_devids),
|
|
.u.ids = {
|
|
.bustype = const_le16(BUS_VIRTUAL),
|
|
.vendor = const_le16(0x0627), /* same we use for usb hid devices */
|
|
.product = const_le16(0x0001),
|
|
.version = const_le16(0x0001),
|
|
},
|
|
},{
|
|
.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, qemu_input_map_qcode_to_linux,
|
|
qemu_input_map_qcode_to_linux_len);
|
|
}
|
|
|
|
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_v1[] = {
|
|
{
|
|
.select = VIRTIO_INPUT_CFG_ID_NAME,
|
|
.size = sizeof(VIRTIO_ID_NAME_MOUSE),
|
|
.u.string = VIRTIO_ID_NAME_MOUSE,
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_ID_DEVIDS,
|
|
.size = sizeof(struct virtio_input_devids),
|
|
.u.ids = {
|
|
.bustype = const_le16(BUS_VIRTUAL),
|
|
.vendor = const_le16(0x0627), /* same we use for usb hid devices */
|
|
.product = const_le16(0x0002),
|
|
.version = const_le16(0x0001),
|
|
},
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_EV_BITS,
|
|
.subsel = EV_REL,
|
|
.size = 1,
|
|
.u.bitmap = {
|
|
(1 << REL_X) | (1 << REL_Y),
|
|
},
|
|
},
|
|
{ /* end of list */ },
|
|
};
|
|
|
|
static struct virtio_input_config virtio_mouse_config_v2[] = {
|
|
{
|
|
.select = VIRTIO_INPUT_CFG_ID_NAME,
|
|
.size = sizeof(VIRTIO_ID_NAME_MOUSE),
|
|
.u.string = VIRTIO_ID_NAME_MOUSE,
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_ID_DEVIDS,
|
|
.size = sizeof(struct virtio_input_devids),
|
|
.u.ids = {
|
|
.bustype = const_le16(BUS_VIRTUAL),
|
|
.vendor = const_le16(0x0627), /* same we use for usb hid devices */
|
|
.product = const_le16(0x0002),
|
|
.version = const_le16(0x0002),
|
|
},
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_EV_BITS,
|
|
.subsel = EV_REL,
|
|
.size = 2,
|
|
.u.bitmap = {
|
|
(1 << REL_X) | (1 << REL_Y),
|
|
(1 << (REL_WHEEL - 8))
|
|
},
|
|
},
|
|
{ /* end of list */ },
|
|
};
|
|
|
|
static Property virtio_mouse_properties[] = {
|
|
DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
};
|
|
|
|
static void virtio_mouse_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
dc->props = virtio_mouse_properties;
|
|
}
|
|
|
|
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, vhid->wheel_axis
|
|
? virtio_mouse_config_v2
|
|
: virtio_mouse_config_v1);
|
|
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,
|
|
.class_init = virtio_mouse_class_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_v1[] = {
|
|
{
|
|
.select = VIRTIO_INPUT_CFG_ID_NAME,
|
|
.size = sizeof(VIRTIO_ID_NAME_TABLET),
|
|
.u.string = VIRTIO_ID_NAME_TABLET,
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_ID_DEVIDS,
|
|
.size = sizeof(struct virtio_input_devids),
|
|
.u.ids = {
|
|
.bustype = const_le16(BUS_VIRTUAL),
|
|
.vendor = const_le16(0x0627), /* same we use for usb hid devices */
|
|
.product = const_le16(0x0003),
|
|
.version = const_le16(0x0001),
|
|
},
|
|
},{
|
|
.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),
|
|
.u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
|
|
.u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_ABS_INFO,
|
|
.subsel = ABS_Y,
|
|
.size = sizeof(virtio_input_absinfo),
|
|
.u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
|
|
.u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
|
|
},
|
|
{ /* end of list */ },
|
|
};
|
|
|
|
static struct virtio_input_config virtio_tablet_config_v2[] = {
|
|
{
|
|
.select = VIRTIO_INPUT_CFG_ID_NAME,
|
|
.size = sizeof(VIRTIO_ID_NAME_TABLET),
|
|
.u.string = VIRTIO_ID_NAME_TABLET,
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_ID_DEVIDS,
|
|
.size = sizeof(struct virtio_input_devids),
|
|
.u.ids = {
|
|
.bustype = const_le16(BUS_VIRTUAL),
|
|
.vendor = const_le16(0x0627), /* same we use for usb hid devices */
|
|
.product = const_le16(0x0003),
|
|
.version = const_le16(0x0002),
|
|
},
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_EV_BITS,
|
|
.subsel = EV_ABS,
|
|
.size = 1,
|
|
.u.bitmap = {
|
|
(1 << ABS_X) | (1 << ABS_Y),
|
|
},
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_EV_BITS,
|
|
.subsel = EV_REL,
|
|
.size = 2,
|
|
.u.bitmap = {
|
|
0,
|
|
(1 << (REL_WHEEL - 8))
|
|
},
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_ABS_INFO,
|
|
.subsel = ABS_X,
|
|
.size = sizeof(virtio_input_absinfo),
|
|
.u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
|
|
.u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
|
|
},{
|
|
.select = VIRTIO_INPUT_CFG_ABS_INFO,
|
|
.subsel = ABS_Y,
|
|
.size = sizeof(virtio_input_absinfo),
|
|
.u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
|
|
.u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
|
|
},
|
|
{ /* end of list */ },
|
|
};
|
|
|
|
static Property virtio_tablet_properties[] = {
|
|
DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
};
|
|
|
|
static void virtio_tablet_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
dc->props = virtio_tablet_properties;
|
|
}
|
|
|
|
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, vhid->wheel_axis
|
|
? virtio_tablet_config_v2
|
|
: virtio_tablet_config_v1);
|
|
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,
|
|
.class_init = virtio_tablet_class_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)
|