#include "kvm/gtk3.h" #include "kvm/framebuffer.h" #include "kvm/kvm-cpu.h" #include "kvm/i8042.h" #include "kvm/vesa.h" #include "kvm/kvm.h" #include #include #include #define FRAME_RATE 25 #define SCANCODE_UNKNOWN 0 #define SCANCODE_NORMAL 1 #define SCANCODE_ESCAPED 2 #define SCANCODE_KEY_PAUSE 3 #define SCANCODE_KEY_PRNTSCRN 4 struct set2_scancode { u8 code; u8 type; }; #define DEFINE_SC(_code) { \ .code = _code, \ .type = SCANCODE_NORMAL, \ } /* escaped scancodes */ #define DEFINE_ESC(_code) { \ .code = _code, \ .type = SCANCODE_ESCAPED, \ } static const struct set2_scancode keymap[256] = { [9] = DEFINE_SC(0x76), /* */ [10] = DEFINE_SC(0x16), /* 1 */ [11] = DEFINE_SC(0x1e), /* 2 */ [12] = DEFINE_SC(0x26), /* 3 */ [13] = DEFINE_SC(0x25), /* 4 */ [14] = DEFINE_SC(0x2e), /* 5 */ [15] = DEFINE_SC(0x36), /* 6 */ [16] = DEFINE_SC(0x3d), /* 7 */ [17] = DEFINE_SC(0x3e), /* 8 */ [18] = DEFINE_SC(0x46), /* 9 */ [19] = DEFINE_SC(0x45), /* 9 */ [20] = DEFINE_SC(0x4e), /* - */ [21] = DEFINE_SC(0x55), /* + */ [22] = DEFINE_SC(0x66), /* */ [23] = DEFINE_SC(0x0d), /* */ [24] = DEFINE_SC(0x15), /* q */ [25] = DEFINE_SC(0x1d), /* w */ [26] = DEFINE_SC(0x24), /* e */ [27] = DEFINE_SC(0x2d), /* r */ [28] = DEFINE_SC(0x2c), /* t */ [29] = DEFINE_SC(0x35), /* y */ [30] = DEFINE_SC(0x3c), /* u */ [31] = DEFINE_SC(0x43), /* i */ [32] = DEFINE_SC(0x44), /* o */ [33] = DEFINE_SC(0x4d), /* p */ [34] = DEFINE_SC(0x54), /* [ */ [35] = DEFINE_SC(0x5b), /* ] */ [36] = DEFINE_SC(0x5a), /* */ [37] = DEFINE_SC(0x14), /* */ [38] = DEFINE_SC(0x1c), /* a */ [39] = DEFINE_SC(0x1b), /* s */ [40] = DEFINE_SC(0x23), /* d */ [41] = DEFINE_SC(0x2b), /* f */ [42] = DEFINE_SC(0x34), /* g */ [43] = DEFINE_SC(0x33), /* h */ [44] = DEFINE_SC(0x3b), /* j */ [45] = DEFINE_SC(0x42), /* k */ [46] = DEFINE_SC(0x4b), /* l */ [47] = DEFINE_SC(0x4c), /* ; */ [48] = DEFINE_SC(0x52), /* ' */ [49] = DEFINE_SC(0x0e), /* ` */ [50] = DEFINE_SC(0x12), /* */ [51] = DEFINE_SC(0x5d), /* \ */ [52] = DEFINE_SC(0x1a), /* z */ [53] = DEFINE_SC(0x22), /* x */ [54] = DEFINE_SC(0x21), /* c */ [55] = DEFINE_SC(0x2a), /* v */ [56] = DEFINE_SC(0x32), /* b */ [57] = DEFINE_SC(0x31), /* n */ [58] = DEFINE_SC(0x3a), /* m */ [59] = DEFINE_SC(0x41), /* < */ [60] = DEFINE_SC(0x49), /* > */ [61] = DEFINE_SC(0x4a), /* / */ [62] = DEFINE_SC(0x59), /* */ [63] = DEFINE_SC(0x7c), /* keypad * */ [64] = DEFINE_SC(0x11), /* */ [65] = DEFINE_SC(0x29), /* */ [67] = DEFINE_SC(0x05), /* */ [68] = DEFINE_SC(0x06), /* */ [69] = DEFINE_SC(0x04), /* */ [70] = DEFINE_SC(0x0c), /* */ [71] = DEFINE_SC(0x03), /* */ [72] = DEFINE_SC(0x0b), /* */ [73] = DEFINE_SC(0x83), /* */ [74] = DEFINE_SC(0x0a), /* */ [75] = DEFINE_SC(0x01), /* */ [76] = DEFINE_SC(0x09), /* */ [79] = DEFINE_SC(0x6c), /* keypad 7 */ [80] = DEFINE_SC(0x75), /* keypad 8 */ [81] = DEFINE_SC(0x7d), /* keypad 9 */ [82] = DEFINE_SC(0x7b), /* keypad - */ [83] = DEFINE_SC(0x6b), /* keypad 4 */ [84] = DEFINE_SC(0x73), /* keypad 5 */ [85] = DEFINE_SC(0x74), /* keypad 6 */ [86] = DEFINE_SC(0x79), /* keypad + */ [87] = DEFINE_SC(0x69), /* keypad 1 */ [88] = DEFINE_SC(0x72), /* keypad 2 */ [89] = DEFINE_SC(0x7a), /* keypad 3 */ [90] = DEFINE_SC(0x70), /* keypad 0 */ [91] = DEFINE_SC(0x71), /* keypad . */ [94] = DEFINE_SC(0x61), /* */ [95] = DEFINE_SC(0x78), /* */ [96] = DEFINE_SC(0x07), /* */ [104] = DEFINE_ESC(0x5a), /* keypad */ [105] = DEFINE_ESC(0x14), /* */ [106] = DEFINE_ESC(0x4a), /* keypad / */ [108] = DEFINE_ESC(0x11), /* */ [110] = DEFINE_ESC(0x6c), /* */ [111] = DEFINE_ESC(0x75), /* */ [112] = DEFINE_ESC(0x7d), /* */ [113] = DEFINE_ESC(0x6b), /* */ [114] = DEFINE_ESC(0x74), /* */ [115] = DEFINE_ESC(0x69), /* */ [116] = DEFINE_ESC(0x72), /* */ [117] = DEFINE_ESC(0x7a), /* */ [118] = DEFINE_ESC(0x70), /* */ [119] = DEFINE_ESC(0x71), /* */ }; static cairo_surface_t *surface; static bool done; static const struct set2_scancode *to_code(u8 scancode) { return &keymap[scancode]; } static gboolean kvm_gtk_configure_event(GtkWidget * widget, GdkEventConfigure * event, gpointer data) { struct framebuffer *fb = data; int stride; if (surface) cairo_surface_destroy(surface); stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, fb->width); surface = cairo_image_surface_create_for_data((void *) fb->mem, CAIRO_FORMAT_RGB24, fb->width, fb->height, stride); return TRUE; } static gboolean kvm_gtk_draw(GtkWidget *widget, cairo_t *cr, gpointer data) { cairo_set_source_surface(cr, surface, 0, 0); cairo_paint(cr); return FALSE; } static void kvm_gtk_destroy(void) { if (surface) cairo_surface_destroy(surface); gtk_main_quit(); } static gboolean kvm_gtk_redraw(GtkWidget * window) { gtk_widget_queue_draw(window); return TRUE; } static gboolean kvm_gtk_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { const struct set2_scancode *sc = to_code(event->hardware_keycode); switch (sc->type) { case SCANCODE_ESCAPED: kbd_queue(0xe0); /* fallthrough */ case SCANCODE_NORMAL: kbd_queue(sc->code); break; case SCANCODE_KEY_PAUSE: kbd_queue(0xe1); kbd_queue(0x14); kbd_queue(0x77); kbd_queue(0xe1); kbd_queue(0xf0); kbd_queue(0x14); kbd_queue(0x77); break; case SCANCODE_KEY_PRNTSCRN: kbd_queue(0xe0); kbd_queue(0x12); kbd_queue(0xe0); kbd_queue(0x7c); break; } return TRUE; } static void *kvm_gtk_thread(void *p) { struct framebuffer *fb = p; GtkWidget *window; GtkWidget *frame; GtkWidget *da; gtk_init(NULL, NULL); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "VM"); g_signal_connect(window, "destroy", G_CALLBACK(kvm_gtk_destroy), NULL); gtk_container_set_border_width(GTK_CONTAINER(window), 8); frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(window), frame); da = gtk_drawing_area_new(); gtk_widget_set_size_request(da, 100, 100); gtk_container_add(GTK_CONTAINER(frame), da); g_signal_connect(da, "draw", G_CALLBACK(kvm_gtk_draw), NULL); g_signal_connect(da, "configure-event", G_CALLBACK(kvm_gtk_configure_event), fb); g_signal_connect(G_OBJECT (window), "key_press_event", G_CALLBACK(kvm_gtk_key_press), NULL); gtk_widget_set_events(da, gtk_widget_get_events(da) | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); gtk_widget_show_all(window); g_timeout_add(1000 / FRAME_RATE, (GSourceFunc) kvm_gtk_redraw, window); gtk_main(); done = true; return NULL; } static int kvm_gtk_start(struct framebuffer *fb) { pthread_t thread; if (pthread_create(&thread, NULL, kvm_gtk_thread, fb) != 0) return -1; return 0; } static int kvm_gtk_stop(struct framebuffer *fb) { gtk_main_quit(); while (!done) sleep(0); return 0; } static struct fb_target_operations kvm_gtk_ops = { .start = kvm_gtk_start, .stop = kvm_gtk_stop, }; int kvm_gtk_init(struct kvm *kvm) { struct framebuffer *fb; if (!kvm->cfg.gtk) return 0; fb = vesa__init(kvm); if (IS_ERR(fb)) { pr_err("vesa__init() failed with error %ld\n", PTR_ERR(fb)); return PTR_ERR(fb); } return fb__attach(fb, &kvm_gtk_ops); } int kvm_gtk_exit(struct kvm *kvm) { if (kvm->cfg.gtk) return kvm_gtk_stop(NULL); return 0; } dev_init(kvm_gtk_init); dev_exit(kvm_gtk_exit);