Compare commits
	
		
			5 Commits
		
	
	
		
			pull-gtk-2
			...
			pull-input
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 55a1d80a41 | ||
|  | f73ddbad39 | ||
|  | 2fe7c31832 | ||
|  | 33aa30cafc | ||
|  | b771f470f3 | 
							
								
								
									
										4
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -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="" | ||||
|   | ||||
| @@ -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
									
								
							
							
						
						
									
										502
									
								
								hw/input/virtio-input-hid.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										282
									
								
								hw/input/virtio-input.c
									
									
									
									
									
										Normal 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) | ||||
							
								
								
									
										105
									
								
								include/hw/virtio/virtio-input.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								include/hw/virtio/virtio-input.h
									
									
									
									
									
										Normal 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 */ | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
							
								
								
									
										1198
									
								
								include/standard-headers/linux/input.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1198
									
								
								include/standard-headers/linux/input.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -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 | ||||
|   | ||||
| @@ -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 */ | ||||
| @@ -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 */ | ||||
|   | ||||
| @@ -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 */ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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"/' \ | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
							
								
								
									
										148
									
								
								ui/egl-helpers.c
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								ui/egl-helpers.c
									
									
									
									
									
								
							| @@ -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; | ||||
| } | ||||
							
								
								
									
										141
									
								
								ui/gtk-egl.c
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								ui/gtk-egl.c
									
									
									
									
									
								
							| @@ -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; | ||||
| } | ||||
							
								
								
									
										95
									
								
								ui/gtk.c
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								ui/gtk.c
									
									
									
									
									
								
							| @@ -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 | ||||
|   | ||||
| @@ -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, | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								vl.c
									
									
									
									
									
								
							| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user