Compare commits

..

5 Commits

Author SHA1 Message Date
Gerd Hoffmann
55a1d80a41 virtio-input: emulated devices [device]
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-device" to
your command line, for use all transports except pci.  virtio-pci
support comes as separate patch, once virtio-pci got virtio 1.0
support.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-05-29 10:30:40 +02:00
Gerd Hoffmann
f73ddbad39 virtio-input: core code & base class [device]
This patch adds virtio-input support to qemu.  It brings a abstract
base class providing core support, other classes can build on it to
actually implement input devices.

virtio-input basically sends linux input layer events (evdev) over
virtio.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-05-29 10:30:26 +02:00
Gerd Hoffmann
2fe7c31832 virtio-input: add linux/input.h
Linux input layer (evdev) header file.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-05-29 10:30:06 +02:00
Gerd Hoffmann
33aa30cafc kbd: add brazil kbd keys to x11 evdev map
This patch adds the two extra brazilian keys to the evdev keymap for
X11.  This patch gets the two keys going with the vnc, gtk and sdl1
UIs.

The SDL2 library complains it doesn't know these keys, so the SDL2
library must be fixed before we can update ui/sdl2-keymap.h

Cc: qemu-stable@nongnu.org
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
2015-05-29 10:30:06 +02:00
Gerd Hoffmann
b771f470f3 kbd: add brazil kbd keys to qemu
The brazilian computer keyboard layout has two extra keys (compared to
the usual 105-key intl ps/2 keyboard).  This patch makes these two keys
known to qemu.

For historic reasons qemu has two ways to specify a key:  A QKeyCode
(name-based) or a number (ps/2 scancode based).  Therefore we have to
update multiple places to make new keys known to qemu:

  (1) The QKeyCode definition in qapi-schema.json
  (2) The QKeyCode <-> number mapping table in ui/input-keymap.c

This patch does just that.  With this patch applied you can send those
two keys to the guest using the send-key monitor command.

Cc: qemu-stable@nongnu.org
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
2015-05-29 10:30:06 +02:00
20 changed files with 2131 additions and 437 deletions

4
configure vendored
View File

@@ -3166,14 +3166,14 @@ else
fi
if test "$opengl" != "no" ; then
opengl_pkgs="gl glesv2 epoxy egl"
opengl_pkgs="gl glesv2"
if $pkg_config $opengl_pkgs x11 && test "$have_glx" = "yes"; then
opengl_cflags="$($pkg_config --cflags $opengl_pkgs) $x11_cflags"
opengl_libs="$($pkg_config --libs $opengl_pkgs) $x11_libs"
opengl=yes
else
if test "$opengl" = "yes" ; then
feature_not_found "opengl" "Please install opengl (mesa) devel pkgs: $opengl_pkgs"
feature_not_found "opengl" "Install GL devel (e.g. MESA)"
fi
opengl_cflags=""
opengl_libs=""

View File

@@ -8,6 +8,11 @@ common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
common-obj-$(CONFIG_TSC2005) += tsc2005.o
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
obj-$(CONFIG_PXA2XX) += pxa2xx_keypad.o
obj-$(CONFIG_TSC210X) += tsc210x.o

502
hw/input/virtio-input-hid.c Normal file
View File

@@ -0,0 +1,502 @@
/*
* 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"
#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,
[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,
};
/* ----------------------------------------------------------------- */
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)
{
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);
}
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 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_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)

282
hw/input/virtio-input.c Normal file
View File

@@ -0,0 +1,282 @@
/*
* 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 "standard-headers/linux/input.h"
/* ----------------------------------------------------------------- */
void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
{
VirtQueueElement elem;
unsigned have, need;
int i, len;
/* queue up events ... */
if (vinput->qindex == vinput->qsize) {
vinput->qsize++;
vinput->queue = realloc(vinput->queue, vinput->qsize *
sizeof(virtio_input_event));
}
vinput->queue[vinput->qindex++] = *event;
/* ... until we see a report sync ... */
if (event->type != cpu_to_le16(EV_SYN) ||
event->code != cpu_to_le16(SYN_REPORT)) {
return;
}
/* ... then check available space ... */
need = sizeof(virtio_input_event) * vinput->qindex;
virtqueue_get_avail_bytes(vinput->evt, &have, NULL, need, 0);
if (have < need) {
vinput->qindex = 0;
fprintf(stderr, "%s: ENOSPC in vq, dropping events\n", __func__);
return;
}
/* ... and finally pass them to the guest */
for (i = 0; i < vinput->qindex; i++) {
if (!virtqueue_pop(vinput->evt, &elem)) {
/* should not happen, we've checked for space beforehand */
fprintf(stderr, "%s: Huh? No vq elem available ...\n", __func__);
return;
}
len = iov_from_buf(elem.in_sg, elem.in_num,
0, vinput->queue+i, sizeof(virtio_input_event));
virtqueue_push(vinput->evt, &elem, len);
}
virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt);
vinput->qindex = 0;
}
static void virtio_input_handle_evt(VirtIODevice *vdev, VirtQueue *vq)
{
/* nothing */
}
static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
VirtIOInput *vinput = VIRTIO_INPUT(vdev);
virtio_input_event event;
VirtQueueElement elem;
int len;
while (virtqueue_pop(vinput->sts, &elem)) {
memset(&event, 0, sizeof(event));
len = iov_to_buf(elem.out_sg, elem.out_num,
0, &event, sizeof(event));
if (vic->handle_status) {
vic->handle_status(vinput, &event);
}
virtqueue_push(vinput->sts, &elem, len);
}
virtio_notify(vdev, vinput->sts);
}
static virtio_input_config *virtio_input_find_config(VirtIOInput *vinput,
uint8_t select,
uint8_t subsel)
{
VirtIOInputConfig *cfg;
QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
if (select == cfg->config.select &&
subsel == cfg->config.subsel) {
return &cfg->config;
}
}
return NULL;
}
void virtio_input_add_config(VirtIOInput *vinput,
virtio_input_config *config)
{
VirtIOInputConfig *cfg;
if (virtio_input_find_config(vinput, config->select, config->subsel)) {
/* should not happen */
fprintf(stderr, "%s: duplicate config: %d/%d\n",
__func__, config->select, config->subsel);
abort();
}
cfg = g_new0(VirtIOInputConfig, 1);
cfg->config = *config;
QTAILQ_INSERT_TAIL(&vinput->cfg_list, cfg, node);
}
void virtio_input_init_config(VirtIOInput *vinput,
virtio_input_config *config)
{
int i = 0;
QTAILQ_INIT(&vinput->cfg_list);
while (config[i].select) {
virtio_input_add_config(vinput, config + i);
i++;
}
}
void virtio_input_idstr_config(VirtIOInput *vinput,
uint8_t select, const char *string)
{
virtio_input_config id;
if (!string) {
return;
}
memset(&id, 0, sizeof(id));
id.select = select;
id.size = snprintf(id.u.string, sizeof(id.u.string), "%s", string);
virtio_input_add_config(vinput, &id);
}
static void virtio_input_get_config(VirtIODevice *vdev, uint8_t *config_data)
{
VirtIOInput *vinput = VIRTIO_INPUT(vdev);
virtio_input_config *config;
config = virtio_input_find_config(vinput, vinput->cfg_select,
vinput->cfg_subsel);
if (config) {
memcpy(config_data, config, vinput->cfg_size);
} else {
memset(config_data, 0, vinput->cfg_size);
}
}
static void virtio_input_set_config(VirtIODevice *vdev,
const uint8_t *config_data)
{
VirtIOInput *vinput = VIRTIO_INPUT(vdev);
virtio_input_config *config = (virtio_input_config *)config_data;
vinput->cfg_select = config->select;
vinput->cfg_subsel = config->subsel;
virtio_notify_config(vdev);
}
static uint32_t virtio_input_get_features(VirtIODevice *vdev, uint32_t f)
{
return f;
}
static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val)
{
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
VirtIOInput *vinput = VIRTIO_INPUT(vdev);
if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
if (!vinput->active) {
vinput->active = true;
if (vic->change_active) {
vic->change_active(vinput);
}
}
}
}
static void virtio_input_reset(VirtIODevice *vdev)
{
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
VirtIOInput *vinput = VIRTIO_INPUT(vdev);
if (vinput->active) {
vinput->active = false;
if (vic->change_active) {
vic->change_active(vinput);
}
}
}
static void virtio_input_device_realize(DeviceState *dev, Error **errp)
{
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOInput *vinput = VIRTIO_INPUT(dev);
VirtIOInputConfig *cfg;
Error *local_err = NULL;
if (vic->realize) {
vic->realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SERIAL,
vinput->input.serial);
QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
if (vinput->cfg_size < cfg->config.size) {
vinput->cfg_size = cfg->config.size;
}
}
vinput->cfg_size += 8;
assert(vinput->cfg_size <= sizeof(virtio_input_config));
virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT,
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);
}
static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
{
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
Error *local_err = NULL;
if (vic->unrealize) {
vic->unrealize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
virtio_cleanup(vdev);
}
static void virtio_input_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
vdc->realize = virtio_input_device_realize;
vdc->unrealize = virtio_input_device_unrealize;
vdc->get_config = virtio_input_get_config;
vdc->set_config = virtio_input_set_config;
vdc->get_features = virtio_input_get_features;
vdc->set_status = virtio_input_set_status;
vdc->reset = virtio_input_reset;
}
static const TypeInfo virtio_input_info = {
.name = TYPE_VIRTIO_INPUT,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOInput),
.class_size = sizeof(VirtIOInputClass),
.class_init = virtio_input_class_init,
.abstract = true,
};
/* ----------------------------------------------------------------- */
static void virtio_register_types(void)
{
type_register_static(&virtio_input_info);
}
type_init(virtio_register_types)

View File

@@ -0,0 +1,105 @@
#ifndef _QEMU_VIRTIO_INPUT_H
#define _QEMU_VIRTIO_INPUT_H
#include "ui/input.h"
/* ----------------------------------------------------------------- */
/* virtio input protocol */
#include "standard-headers/linux/virtio_ids.h"
#include "standard-headers/linux/virtio_input.h"
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) bswap32(_x)
# define const_le16(_x) bswap32(_x)
#else
# define const_le32(_x) (_x)
# define const_le16(_x) (_x)
#endif
/* ----------------------------------------------------------------- */
/* qemu internals */
#define TYPE_VIRTIO_INPUT "virtio-input-device"
#define VIRTIO_INPUT(obj) \
OBJECT_CHECK(VirtIOInput, (obj), TYPE_VIRTIO_INPUT)
#define VIRTIO_INPUT_GET_PARENT_CLASS(obj) \
OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT)
#define VIRTIO_INPUT_GET_CLASS(obj) \
OBJECT_GET_CLASS(VirtIOInputClass, obj, TYPE_VIRTIO_INPUT)
#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)
typedef struct VirtIOInput VirtIOInput;
typedef struct VirtIOInputClass VirtIOInputClass;
typedef struct VirtIOInputConfig VirtIOInputConfig;
typedef struct VirtIOInputHID VirtIOInputHID;
struct virtio_input_conf {
char *serial;
};
struct VirtIOInputConfig {
virtio_input_config config;
QTAILQ_ENTRY(VirtIOInputConfig) node;
};
struct VirtIOInput {
VirtIODevice parent_obj;
uint8_t cfg_select;
uint8_t cfg_subsel;
uint32_t cfg_size;
QTAILQ_HEAD(, VirtIOInputConfig) cfg_list;
VirtQueue *evt, *sts;
virtio_input_conf input;
virtio_input_event *queue;
uint32_t qindex, qsize;
bool active;
};
struct VirtIOInputClass {
/*< private >*/
VirtioDeviceClass parent;
/*< public >*/
DeviceRealize realize;
DeviceUnrealize unrealize;
void (*change_active)(VirtIOInput *vinput);
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);
void virtio_input_add_config(VirtIOInput *vinput,
virtio_input_config *config);
void virtio_input_idstr_config(VirtIOInput *vinput,
uint8_t select, const char *string);
#endif /* _QEMU_VIRTIO_INPUT_H */

View File

@@ -188,6 +188,7 @@ int virtio_set_features(VirtIODevice *vdev, uint32_t val);
typedef struct VirtIOBlkConf VirtIOBlkConf;
struct virtio_net_conf;
typedef struct virtio_serial_conf virtio_serial_conf;
typedef struct virtio_input_conf virtio_input_conf;
typedef struct VirtIOSCSIConf VirtIOSCSIConf;
typedef struct VirtIORNGConf VirtIORNGConf;

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,8 @@
#include "qapi/error.h"
#ifdef CONFIG_OPENGL
# include <epoxy/gl.h>
# include <GLES2/gl2.h>
# include <GLES2/gl2ext.h>
#endif
/* keyboard/mouse support */
@@ -393,7 +394,7 @@ void curses_display_init(DisplayState *ds, int full_screen);
int index_from_key(const char *key);
/* gtk.c */
void early_gtk_display_init(int opengl);
void early_gtk_display_init(void);
void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover);
#endif

View File

@@ -1,16 +0,0 @@
#ifndef EGL_HELPERS_H
#define EGL_HELPERS_H
#include <epoxy/gl.h>
#include <epoxy/egl.h>
extern EGLDisplay *qemu_egl_display;
extern EGLConfig qemu_egl_config;
EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win);
int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug);
EGLContext qemu_egl_init_ctx(void);
bool qemu_egl_has_ext(const char *haystack, const char *needle);
#endif /* EGL_HELPERS_H */

View File

@@ -22,10 +22,6 @@
#include <X11/XKBlib.h>
#endif
#if defined(CONFIG_OPENGL)
#include "ui/egl-helpers.h"
#endif
/* Compatibility define to let us build on both Gtk2 and Gtk3 */
#if GTK_CHECK_VERSION(3, 0, 0)
static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
@@ -45,12 +41,6 @@ typedef struct VirtualGfxConsole {
cairo_surface_t *surface;
double scale_x;
double scale_y;
#if defined(CONFIG_OPENGL)
ConsoleGLState *gls;
EGLContext ectx;
EGLSurface esurface;
int glupdates;
#endif
} VirtualGfxConsole;
#if defined(CONFIG_VTE)
@@ -83,17 +73,4 @@ typedef struct VirtualConsole {
};
} VirtualConsole;
/* ui/gtk.c */
void gd_update_windowsize(VirtualConsole *vc);
/* ui/gtk-egl.c */
void gd_egl_init(VirtualConsole *vc);
void gd_egl_draw(VirtualConsole *vc);
void gd_egl_update(DisplayChangeListener *dcl,
int x, int y, int w, int h);
void gd_egl_refresh(DisplayChangeListener *dcl);
void gd_egl_switch(DisplayChangeListener *dcl,
DisplaySurface *surface);
void gtk_egl_init(void);
#endif /* UI_GTK_H */

View File

@@ -1,7 +1,7 @@
#ifndef QEMU_SHADER_H
#define QEMU_SHADER_H
#include <epoxy/gl.h>
#ifdef CONFIG_OPENGL
# include <GLES2/gl2.h>
# include <GLES2/gl2ext.h>
#endif
void qemu_gl_run_texture_blit(GLint texture_blit_prog);
@@ -9,5 +9,3 @@ GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src);
GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag);
GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src,
const GLchar *frag_src);
#endif /* QEMU_SHADER_H */

View File

@@ -2784,6 +2784,7 @@
# Since: 1.3.0
#
# 'unmapped' and 'pause' since 2.0
# 'ro' and 'kp_comma' since 2.4
##
{ 'enum': 'QKeyCode',
'data': [ 'unmapped',
@@ -2801,7 +2802,8 @@
'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end',
'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again',
'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut',
'lf', 'help', 'meta_l', 'meta_r', 'compose', 'pause' ] }
'lf', 'help', 'meta_l', 'meta_r', 'compose', 'pause', 'ro',
'kp_comma' ] }
##
# @KeyValue

View File

@@ -31,7 +31,7 @@ fi
cp_virtio() {
from=$1
to=$2
virtio=$(find "$from" -name '*virtio*h')
virtio=$(find "$from" -name '*virtio*h' -o -name "input.h")
if [ "$virtio" ]; then
rm -rf "$to"
mkdir -p "$to"
@@ -40,6 +40,7 @@ cp_virtio() {
grep '#include' "$f" | grep -v -e 'linux/virtio' \
-e 'linux/types' \
-e 'linux/if_ether' \
-e 'sys/' \
> /dev/null
then
echo "Unexpected #include in input file $f".
@@ -48,6 +49,7 @@ cp_virtio() {
header=$(basename "$f");
sed -e 's/__u\([0-9][0-9]*\)/uint\1_t/g' \
-e 's/__s\([0-9][0-9]*\)/int\1_t/g' \
-e 's/__le\([0-9][0-9]*\)/uint\1_t/g' \
-e 's/__be\([0-9][0-9]*\)/uint\1_t/g' \
-e 's/<linux\/\([^>]*\)>/"standard-headers\/linux\/\1"/' \

View File

@@ -30,17 +30,11 @@ sdl.mo-cflags := $(SDL_CFLAGS)
ifeq ($(CONFIG_OPENGL),y)
common-obj-y += shader.o
common-obj-y += console-gl.o
common-obj-y += egl-helpers.o
common-obj-$(CONFIG_GTK) += gtk-egl.o
endif
gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
gtk-egl.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS)
shader.o-cflags += $(OPENGL_CFLAGS)
console-gl.o-cflags += $(OPENGL_CFLAGS)
egl-helpers.o-cflags += $(OPENGL_CFLAGS)
gtk-egl.o-libs += $(OPENGL_LIBS)
shader.o-libs += $(OPENGL_LIBS)
console-gl.o-libs += $(OPENGL_LIBS)
egl-helpers.o-libs += $(OPENGL_LIBS)

View File

@@ -1,148 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include "ui/egl-helpers.h"
EGLDisplay *qemu_egl_display;
EGLConfig qemu_egl_config;
/* ---------------------------------------------------------------------- */
static bool egl_gles;
static int egl_debug;
#define egl_dbg(_x ...) \
do { \
if (egl_debug) { \
fprintf(stderr, "egl: " _x); \
} \
} while (0);
/* ---------------------------------------------------------------------- */
EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win)
{
EGLSurface esurface;
EGLBoolean b;
egl_dbg("eglCreateWindowSurface (x11 win id 0x%lx) ...\n",
(unsigned long) win);
esurface = eglCreateWindowSurface(qemu_egl_display,
qemu_egl_config,
(EGLNativeWindowType)win, NULL);
if (esurface == EGL_NO_SURFACE) {
fprintf(stderr, "egl: eglCreateWindowSurface failed\n");
return NULL;
}
b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx);
if (b == EGL_FALSE) {
fprintf(stderr, "egl: eglMakeCurrent failed\n");
return NULL;
}
return esurface;
}
/* ---------------------------------------------------------------------- */
int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug)
{
static const EGLint conf_att_gl[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 5,
EGL_BLUE_SIZE, 5,
EGL_ALPHA_SIZE, 0,
EGL_NONE,
};
static const EGLint conf_att_gles[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 5,
EGL_BLUE_SIZE, 5,
EGL_ALPHA_SIZE, 0,
EGL_NONE,
};
EGLint major, minor;
EGLBoolean b;
EGLint n;
if (debug) {
egl_debug = 1;
setenv("EGL_LOG_LEVEL", "debug", true);
setenv("LIBGL_DEBUG", "verbose", true);
}
egl_dbg("eglGetDisplay (dpy %p) ...\n", dpy);
qemu_egl_display = eglGetDisplay(dpy);
if (qemu_egl_display == EGL_NO_DISPLAY) {
fprintf(stderr, "egl: eglGetDisplay failed\n");
return -1;
}
egl_dbg("eglInitialize ...\n");
b = eglInitialize(qemu_egl_display, &major, &minor);
if (b == EGL_FALSE) {
fprintf(stderr, "egl: eglInitialize failed\n");
return -1;
}
egl_dbg("eglBindAPI ...\n");
b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API);
if (b == EGL_FALSE) {
fprintf(stderr, "egl: eglBindAPI failed\n");
return -1;
}
egl_dbg("eglChooseConfig ...\n");
b = eglChooseConfig(qemu_egl_display,
gles ? conf_att_gles : conf_att_gl,
&qemu_egl_config, 1, &n);
if (b == EGL_FALSE || n != 1) {
fprintf(stderr, "egl: eglChooseConfig failed\n");
return -1;
}
egl_gles = gles;
return 0;
}
EGLContext qemu_egl_init_ctx(void)
{
static const EGLint ctx_att_gl[] = {
EGL_NONE
};
static const EGLint ctx_att_gles[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
EGLContext ectx;
EGLBoolean b;
egl_dbg("eglCreateContext ...\n");
ectx = eglCreateContext(qemu_egl_display, qemu_egl_config, EGL_NO_CONTEXT,
egl_gles ? ctx_att_gles : ctx_att_gl);
if (ectx == EGL_NO_CONTEXT) {
fprintf(stderr, "egl: eglCreateContext failed\n");
return NULL;
}
b = eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx);
if (b == EGL_FALSE) {
fprintf(stderr, "egl: eglMakeCurrent failed\n");
return NULL;
}
return ectx;
}

View File

@@ -1,141 +0,0 @@
/*
* GTK UI -- egl opengl code.
*
* Note that gtk 3.16+ (released 2015-03-23) has a GtkGLArea widget,
* which is GtkDrawingArea like widget with opengl rendering support.
*
* This code handles opengl support on older gtk versions, using egl
* to get a opengl context for the X11 window.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu-common.h"
#include "trace.h"
#include "ui/console.h"
#include "ui/gtk.h"
#include "ui/egl-helpers.h"
#include "sysemu/sysemu.h"
/** DisplayState Callbacks (opengl version) **/
void gd_egl_init(VirtualConsole *vc)
{
GdkWindow *gdk_window = gtk_widget_get_window(vc->gfx.drawing_area);
if (!gdk_window) {
return;
}
#if GTK_CHECK_VERSION(3, 0, 0)
Window x11_window = gdk_x11_window_get_xid(gdk_window);
#else
Window x11_window = gdk_x11_drawable_get_xid(gdk_window);
#endif
if (!x11_window) {
return;
}
vc->gfx.ectx = qemu_egl_init_ctx();
vc->gfx.esurface = qemu_egl_init_surface_x11(vc->gfx.ectx, x11_window);
assert(vc->gfx.esurface);
}
void gd_egl_draw(VirtualConsole *vc)
{
GdkWindow *window;
int ww, wh;
if (!vc->gfx.gls || !vc->gfx.ds) {
return;
}
eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
vc->gfx.esurface, vc->gfx.ectx);
window = gtk_widget_get_window(vc->gfx.drawing_area);
gdk_drawable_get_size(window, &ww, &wh);
surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
}
void gd_egl_update(DisplayChangeListener *dcl,
int x, int y, int w, int h)
{
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
if (!vc->gfx.gls || !vc->gfx.ds) {
return;
}
eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
vc->gfx.esurface, vc->gfx.ectx);
surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h);
vc->gfx.glupdates++;
}
void gd_egl_refresh(DisplayChangeListener *dcl)
{
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
if (!vc->gfx.esurface) {
gd_egl_init(vc);
if (!vc->gfx.esurface) {
return;
}
vc->gfx.gls = console_gl_init_context();
if (vc->gfx.ds) {
surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
}
}
graphic_hw_update(dcl->con);
if (vc->gfx.glupdates) {
vc->gfx.glupdates = 0;
gd_egl_draw(vc);
}
}
void gd_egl_switch(DisplayChangeListener *dcl,
DisplaySurface *surface)
{
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
bool resized = true;
trace_gd_switch(vc->label, surface_width(surface), surface_height(surface));
if (vc->gfx.ds &&
surface_width(vc->gfx.ds) == surface_width(surface) &&
surface_height(vc->gfx.ds) == surface_height(surface)) {
resized = false;
}
surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
vc->gfx.ds = surface;
if (vc->gfx.gls) {
surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
}
if (resized) {
gd_update_windowsize(vc);
}
}
void gtk_egl_init(void)
{
GdkDisplay *gdk_display = gdk_display_get_default();
Display *x11_display = gdk_x11_display_get_xdisplay(gdk_display);
if (qemu_egl_init_dpy(x11_display, false, false) < 0) {
return;
}
display_opengl = 1;
}

View File

@@ -339,7 +339,7 @@ static void gd_update_geometry_hints(VirtualConsole *vc)
gtk_window_set_geometry_hints(geo_window, geo_widget, &geo, mask);
}
void gd_update_windowsize(VirtualConsole *vc)
static void gd_update_windowsize(VirtualConsole *vc)
{
GtkDisplayState *s = vc->s;
@@ -581,33 +581,6 @@ static void gd_switch(DisplayChangeListener *dcl,
}
}
static const DisplayChangeListenerOps dcl_ops = {
.dpy_name = "gtk",
.dpy_gfx_update = gd_update,
.dpy_gfx_switch = gd_switch,
.dpy_gfx_check_format = qemu_pixman_check_format,
.dpy_refresh = gd_refresh,
.dpy_mouse_set = gd_mouse_set,
.dpy_cursor_define = gd_cursor_define,
};
#if defined(CONFIG_OPENGL)
/** DisplayState Callbacks (opengl version) **/
static const DisplayChangeListenerOps dcl_egl_ops = {
.dpy_name = "gtk-egl",
.dpy_gfx_update = gd_egl_update,
.dpy_gfx_switch = gd_egl_switch,
.dpy_gfx_check_format = console_gl_check_format,
.dpy_refresh = gd_egl_refresh,
.dpy_mouse_set = gd_mouse_set,
.dpy_cursor_define = gd_cursor_define,
};
#endif
/** QEMU Events **/
static void gd_change_runstate(void *opaque, int running, RunState state)
@@ -664,13 +637,6 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
int ww, wh;
int fbw, fbh;
#if defined(CONFIG_OPENGL)
if (vc->gfx.gls) {
gd_egl_draw(vc);
return TRUE;
}
#endif
if (!gtk_widget_get_realized(widget)) {
return FALSE;
}
@@ -1710,6 +1676,16 @@ static GtkWidget *gd_create_menu_machine(GtkDisplayState *s)
return machine_menu;
}
static const DisplayChangeListenerOps dcl_ops = {
.dpy_name = "gtk",
.dpy_gfx_update = gd_update,
.dpy_gfx_switch = gd_switch,
.dpy_gfx_check_format = qemu_pixman_check_format,
.dpy_refresh = gd_refresh,
.dpy_mouse_set = gd_mouse_set,
.dpy_cursor_define = gd_cursor_define,
};
static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
QemuConsole *con, int idx,
GSList *group, GtkWidget *view_menu)
@@ -1737,29 +1713,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook),
vc->tab_item, gtk_label_new(vc->label));
#if defined(CONFIG_OPENGL)
if (display_opengl) {
/*
* gtk_widget_set_double_buffered() was deprecated in 3.14.
* It is required for opengl rendering on X11 though. A
* proper replacement (native opengl support) is only
* available in 3.16+. Silence the warning if possible.
*/
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
#pragma GCC diagnostic pop
#endif
vc->gfx.dcl.ops = &dcl_egl_ops;
} else
#endif
{
vc->gfx.dcl.ops = &dcl_ops;
}
vc->gfx.dcl.ops = &dcl_ops;
vc->gfx.dcl.con = con;
register_displaychangelistener(&vc->gfx.dcl);
@@ -1921,7 +1875,8 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
{
GtkDisplayState *s = g_malloc0(sizeof(*s));
char *filename;
GdkDisplay *window_display;
gtk_init(NULL, NULL);
s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
#if GTK_CHECK_VERSION(3, 2, 0)
@@ -1938,9 +1893,7 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
bindtextdomain("qemu", CONFIG_QEMU_LOCALEDIR);
textdomain("qemu");
window_display = gtk_widget_get_display(s->window);
s->null_cursor = gdk_cursor_new_for_display(window_display,
GDK_BLANK_CURSOR);
s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
s->mouse_mode_notifier.notify = gd_mouse_mode_change;
qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
@@ -2001,24 +1954,8 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
gd_set_keycode_type(s);
}
void early_gtk_display_init(int opengl)
void early_gtk_display_init(void)
{
gtk_init(NULL, NULL);
switch (opengl) {
case -1: /* default */
case 0: /* off */
break;
case 1: /* on */
#if defined(CONFIG_OPENGL)
gtk_egl_init();
#endif
break;
default:
g_assert_not_reached();
break;
}
#if defined(CONFIG_VTE)
register_vc_handler(gd_vc_handler);
#endif

View File

@@ -128,6 +128,10 @@ static const int qcode_to_number[] = {
[Q_KEY_CODE_INSERT] = 0xd2,
[Q_KEY_CODE_DELETE] = 0xd3,
[Q_KEY_CODE_RO] = 0x73,
[Q_KEY_CODE_KP_COMMA] = 0x7e,
[Q_KEY_CODE_MAX] = 0,
};

View File

@@ -94,7 +94,7 @@ static const uint8_t x_keycode_to_pc_keycode[115] = {
*/
static const uint8_t evdev_keycode_to_pc_keycode[61] = {
0, /* 97 EVDEV - RO ("Internet" Keyboards) */
0x73, /* 97 EVDEV - RO ("Internet" Keyboards) */
0, /* 98 EVDEV - KATA (Katakana) */
0, /* 99 EVDEV - HIRA (Hiragana) */
0x79, /* 100 EVDEV - HENK (Henkan) */
@@ -126,7 +126,7 @@ static const uint8_t evdev_keycode_to_pc_keycode[61] = {
0, /* 126 EVDEV - I126 ("Internet" Keyboards) */
0, /* 127 EVDEV - PAUS */
0, /* 128 EVDEV - ???? */
0, /* 129 EVDEV - I129 ("Internet" Keyboards) */
0x7e, /* 129 EVDEV - KP_COMMA (brazilian) */
0xf1, /* 130 EVDEV - HNGL (Korean Hangul Latin toggle) */
0xf2, /* 131 EVDEV - HJCV (Korean Hangul Hanja toggle) */
0x7d, /* 132 AE13 (Yen)*/

11
vl.c
View File

@@ -2047,15 +2047,6 @@ static DisplayType select_display(const char *p)
} else {
goto invalid_gtk_args;
}
} else if (strstart(opts, ",gl=", &nextopt)) {
opts = nextopt;
if (strstart(opts, "on", &nextopt)) {
request_opengl = 1;
} else if (strstart(opts, "off", &nextopt)) {
request_opengl = 0;
} else {
goto invalid_gtk_args;
}
} else {
invalid_gtk_args:
fprintf(stderr, "Invalid GTK option string: %s\n", p);
@@ -4021,7 +4012,7 @@ int main(int argc, char **argv, char **envp)
#if defined(CONFIG_GTK)
if (display_type == DT_GTK) {
early_gtk_display_init(request_opengl);
early_gtk_display_init();
}
#endif
#if defined(CONFIG_SDL)