qemu/hw/input/virtio-input-hid.c

517 lines
17 KiB
C
Raw Normal View History

/*
* 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 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,
};
static const unsigned int keymap_button[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = BTN_LEFT,
[INPUT_BUTTON_RIGHT] = BTN_RIGHT,
[INPUT_BUTTON_MIDDLE] = BTN_MIDDLE,
qapi: Change munging of CamelCase enum values When munging enum values, the fact that we were passing the entire prefix + value through camel_to_upper() meant that enum values spelled with CamelCase could be turned into CAMEL_CASE. However, this provides a potential collision (both OneTwo and One-Two would munge into ONE_TWO) for enum types, when the same two names are valid side-by-side as QAPI member names. By changing the generation of enum constants to always be prefix + '_' + c_name(value, False).upper(), and ensuring that there are no case collisions (in the next patches), we no longer have to worry about names that would be distinct as QAPI members but collide as variant tag names, without having to think about what munging the heuristics in camel_to_upper() will actually perform on an enum value. Making the change will affect enums that did not follow coding conventions, using 'CamelCase' rather than desired 'lower-case'. Thankfully, there are only two culprits: InputButton and ErrorClass. We already tweaked ErrorClass to make it an alias of QapiErrorClass, where only the alias needs changing rather than the whole tree. So the bulk of this change is modifying INPUT_BUTTON_WHEEL_UP to the new INPUT_BUTTON_WHEELUP (and likewise for WHEELDOWN). That part of this commit may later need reverting if we rename the enum constants from 'WheelUp' to 'wheel-up' as part of moving x-input-send-event to a stable interface; but at least we have documentation bread crumbs in place to remind us (commit 513e7cd), and it matches the fact that SDL constants are also spelled SDL_BUTTON_WHEELUP. Suggested by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-27-git-send-email-eblake@redhat.com> [Commit message tweaked] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 11:53:01 +03:00
[INPUT_BUTTON_WHEELUP] = BTN_GEAR_UP,
[INPUT_BUTTON_WHEELDOWN] = 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,
};
/* ----------------------------------------------------------------- */
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->type) {
case INPUT_EVENT_KIND_KEY:
qcode = qemu_input_key_value_to_qcode(evt->u.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->u.key->down ? 1 : 0);
virtio_input_send(vinput, &event);
} else {
if (evt->u.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->u.btn->button]) {
event.type = cpu_to_le16(EV_KEY);
event.code = cpu_to_le16(keymap_button[evt->u.btn->button]);
event.value = cpu_to_le32(evt->u.btn->down ? 1 : 0);
virtio_input_send(vinput, &event);
} else {
if (evt->u.btn->down) {
fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__,
evt->u.btn->button,
InputButton_lookup[evt->u.btn->button]);
}
}
break;
case INPUT_EVENT_KIND_REL:
event.type = cpu_to_le16(EV_REL);
event.code = cpu_to_le16(axismap_rel[evt->u.rel->axis]);
event.value = cpu_to_le32(evt->u.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->u.abs->axis]);
event.value = cpu_to_le32(evt->u.abs->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, 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_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 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_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.max = const_le32(INPUT_EVENT_ABS_SIZE),
},{
.select = VIRTIO_INPUT_CFG_ABS_INFO,
.subsel = ABS_Y,
.size = sizeof(virtio_input_absinfo),
.u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE),
},
{ /* 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)