1*7bcceb95SPekka Enberg #include "kvm/gtk3.h" 2*7bcceb95SPekka Enberg 3*7bcceb95SPekka Enberg #include "kvm/framebuffer.h" 4*7bcceb95SPekka Enberg #include "kvm/kvm-cpu.h" 5*7bcceb95SPekka Enberg #include "kvm/i8042.h" 6*7bcceb95SPekka Enberg #include "kvm/vesa.h" 7*7bcceb95SPekka Enberg #include "kvm/kvm.h" 8*7bcceb95SPekka Enberg 9*7bcceb95SPekka Enberg #include <gtk/gtk.h> 10*7bcceb95SPekka Enberg #include <pthread.h> 11*7bcceb95SPekka Enberg #include <linux/err.h> 12*7bcceb95SPekka Enberg 13*7bcceb95SPekka Enberg #define FRAME_RATE 25 14*7bcceb95SPekka Enberg 15*7bcceb95SPekka Enberg #define SCANCODE_UNKNOWN 0 16*7bcceb95SPekka Enberg #define SCANCODE_NORMAL 1 17*7bcceb95SPekka Enberg #define SCANCODE_ESCAPED 2 18*7bcceb95SPekka Enberg #define SCANCODE_KEY_PAUSE 3 19*7bcceb95SPekka Enberg #define SCANCODE_KEY_PRNTSCRN 4 20*7bcceb95SPekka Enberg 21*7bcceb95SPekka Enberg struct set2_scancode { 22*7bcceb95SPekka Enberg u8 code; 23*7bcceb95SPekka Enberg u8 type; 24*7bcceb95SPekka Enberg }; 25*7bcceb95SPekka Enberg 26*7bcceb95SPekka Enberg #define DEFINE_SC(_code) { \ 27*7bcceb95SPekka Enberg .code = _code, \ 28*7bcceb95SPekka Enberg .type = SCANCODE_NORMAL, \ 29*7bcceb95SPekka Enberg } 30*7bcceb95SPekka Enberg 31*7bcceb95SPekka Enberg /* escaped scancodes */ 32*7bcceb95SPekka Enberg #define DEFINE_ESC(_code) { \ 33*7bcceb95SPekka Enberg .code = _code, \ 34*7bcceb95SPekka Enberg .type = SCANCODE_ESCAPED, \ 35*7bcceb95SPekka Enberg } 36*7bcceb95SPekka Enberg 37*7bcceb95SPekka Enberg static const struct set2_scancode const keymap[256] = { 38*7bcceb95SPekka Enberg [9] = DEFINE_SC(0x76), /* <esc> */ 39*7bcceb95SPekka Enberg [10] = DEFINE_SC(0x16), /* 1 */ 40*7bcceb95SPekka Enberg [11] = DEFINE_SC(0x1e), /* 2 */ 41*7bcceb95SPekka Enberg [12] = DEFINE_SC(0x26), /* 3 */ 42*7bcceb95SPekka Enberg [13] = DEFINE_SC(0x25), /* 4 */ 43*7bcceb95SPekka Enberg [14] = DEFINE_SC(0x2e), /* 5 */ 44*7bcceb95SPekka Enberg [15] = DEFINE_SC(0x36), /* 6 */ 45*7bcceb95SPekka Enberg [16] = DEFINE_SC(0x3d), /* 7 */ 46*7bcceb95SPekka Enberg [17] = DEFINE_SC(0x3e), /* 8 */ 47*7bcceb95SPekka Enberg [18] = DEFINE_SC(0x46), /* 9 */ 48*7bcceb95SPekka Enberg [19] = DEFINE_SC(0x45), /* 9 */ 49*7bcceb95SPekka Enberg [20] = DEFINE_SC(0x4e), /* - */ 50*7bcceb95SPekka Enberg [21] = DEFINE_SC(0x55), /* + */ 51*7bcceb95SPekka Enberg [22] = DEFINE_SC(0x66), /* <backspace> */ 52*7bcceb95SPekka Enberg [23] = DEFINE_SC(0x0d), /* <tab> */ 53*7bcceb95SPekka Enberg [24] = DEFINE_SC(0x15), /* q */ 54*7bcceb95SPekka Enberg [25] = DEFINE_SC(0x1d), /* w */ 55*7bcceb95SPekka Enberg [26] = DEFINE_SC(0x24), /* e */ 56*7bcceb95SPekka Enberg [27] = DEFINE_SC(0x2d), /* r */ 57*7bcceb95SPekka Enberg [28] = DEFINE_SC(0x2c), /* t */ 58*7bcceb95SPekka Enberg [29] = DEFINE_SC(0x35), /* y */ 59*7bcceb95SPekka Enberg [30] = DEFINE_SC(0x3c), /* u */ 60*7bcceb95SPekka Enberg [31] = DEFINE_SC(0x43), /* i */ 61*7bcceb95SPekka Enberg [32] = DEFINE_SC(0x44), /* o */ 62*7bcceb95SPekka Enberg [33] = DEFINE_SC(0x4d), /* p */ 63*7bcceb95SPekka Enberg [34] = DEFINE_SC(0x54), /* [ */ 64*7bcceb95SPekka Enberg [35] = DEFINE_SC(0x5b), /* ] */ 65*7bcceb95SPekka Enberg [36] = DEFINE_SC(0x5a), /* <enter> */ 66*7bcceb95SPekka Enberg [37] = DEFINE_SC(0x14), /* <left ctrl> */ 67*7bcceb95SPekka Enberg [38] = DEFINE_SC(0x1c), /* a */ 68*7bcceb95SPekka Enberg [39] = DEFINE_SC(0x1b), /* s */ 69*7bcceb95SPekka Enberg [40] = DEFINE_SC(0x23), /* d */ 70*7bcceb95SPekka Enberg [41] = DEFINE_SC(0x2b), /* f */ 71*7bcceb95SPekka Enberg [42] = DEFINE_SC(0x34), /* g */ 72*7bcceb95SPekka Enberg [43] = DEFINE_SC(0x33), /* h */ 73*7bcceb95SPekka Enberg [44] = DEFINE_SC(0x3b), /* j */ 74*7bcceb95SPekka Enberg [45] = DEFINE_SC(0x42), /* k */ 75*7bcceb95SPekka Enberg [46] = DEFINE_SC(0x4b), /* l */ 76*7bcceb95SPekka Enberg [47] = DEFINE_SC(0x4c), /* ; */ 77*7bcceb95SPekka Enberg [48] = DEFINE_SC(0x52), /* ' */ 78*7bcceb95SPekka Enberg [49] = DEFINE_SC(0x0e), /* ` */ 79*7bcceb95SPekka Enberg [50] = DEFINE_SC(0x12), /* <left shift> */ 80*7bcceb95SPekka Enberg [51] = DEFINE_SC(0x5d), /* \ */ 81*7bcceb95SPekka Enberg [52] = DEFINE_SC(0x1a), /* z */ 82*7bcceb95SPekka Enberg [53] = DEFINE_SC(0x22), /* x */ 83*7bcceb95SPekka Enberg [54] = DEFINE_SC(0x21), /* c */ 84*7bcceb95SPekka Enberg [55] = DEFINE_SC(0x2a), /* v */ 85*7bcceb95SPekka Enberg [56] = DEFINE_SC(0x32), /* b */ 86*7bcceb95SPekka Enberg [57] = DEFINE_SC(0x31), /* n */ 87*7bcceb95SPekka Enberg [58] = DEFINE_SC(0x3a), /* m */ 88*7bcceb95SPekka Enberg [59] = DEFINE_SC(0x41), /* < */ 89*7bcceb95SPekka Enberg [60] = DEFINE_SC(0x49), /* > */ 90*7bcceb95SPekka Enberg [61] = DEFINE_SC(0x4a), /* / */ 91*7bcceb95SPekka Enberg [62] = DEFINE_SC(0x59), /* <right shift> */ 92*7bcceb95SPekka Enberg [63] = DEFINE_SC(0x7c), /* keypad * */ 93*7bcceb95SPekka Enberg [64] = DEFINE_SC(0x11), /* <left alt> */ 94*7bcceb95SPekka Enberg [65] = DEFINE_SC(0x29), /* <space> */ 95*7bcceb95SPekka Enberg 96*7bcceb95SPekka Enberg [67] = DEFINE_SC(0x05), /* <F1> */ 97*7bcceb95SPekka Enberg [68] = DEFINE_SC(0x06), /* <F2> */ 98*7bcceb95SPekka Enberg [69] = DEFINE_SC(0x04), /* <F3> */ 99*7bcceb95SPekka Enberg [70] = DEFINE_SC(0x0c), /* <F4> */ 100*7bcceb95SPekka Enberg [71] = DEFINE_SC(0x03), /* <F5> */ 101*7bcceb95SPekka Enberg [72] = DEFINE_SC(0x0b), /* <F6> */ 102*7bcceb95SPekka Enberg [73] = DEFINE_SC(0x83), /* <F7> */ 103*7bcceb95SPekka Enberg [74] = DEFINE_SC(0x0a), /* <F8> */ 104*7bcceb95SPekka Enberg [75] = DEFINE_SC(0x01), /* <F9> */ 105*7bcceb95SPekka Enberg [76] = DEFINE_SC(0x09), /* <F10> */ 106*7bcceb95SPekka Enberg 107*7bcceb95SPekka Enberg [79] = DEFINE_SC(0x6c), /* keypad 7 */ 108*7bcceb95SPekka Enberg [80] = DEFINE_SC(0x75), /* keypad 8 */ 109*7bcceb95SPekka Enberg [81] = DEFINE_SC(0x7d), /* keypad 9 */ 110*7bcceb95SPekka Enberg [82] = DEFINE_SC(0x7b), /* keypad - */ 111*7bcceb95SPekka Enberg [83] = DEFINE_SC(0x6b), /* keypad 4 */ 112*7bcceb95SPekka Enberg [84] = DEFINE_SC(0x73), /* keypad 5 */ 113*7bcceb95SPekka Enberg [85] = DEFINE_SC(0x74), /* keypad 6 */ 114*7bcceb95SPekka Enberg [86] = DEFINE_SC(0x79), /* keypad + */ 115*7bcceb95SPekka Enberg [87] = DEFINE_SC(0x69), /* keypad 1 */ 116*7bcceb95SPekka Enberg [88] = DEFINE_SC(0x72), /* keypad 2 */ 117*7bcceb95SPekka Enberg [89] = DEFINE_SC(0x7a), /* keypad 3 */ 118*7bcceb95SPekka Enberg [90] = DEFINE_SC(0x70), /* keypad 0 */ 119*7bcceb95SPekka Enberg [91] = DEFINE_SC(0x71), /* keypad . */ 120*7bcceb95SPekka Enberg 121*7bcceb95SPekka Enberg [94] = DEFINE_SC(0x61), /* <INT 1> */ 122*7bcceb95SPekka Enberg [95] = DEFINE_SC(0x78), /* <F11> */ 123*7bcceb95SPekka Enberg [96] = DEFINE_SC(0x07), /* <F12> */ 124*7bcceb95SPekka Enberg 125*7bcceb95SPekka Enberg [104] = DEFINE_ESC(0x5a), /* keypad <enter> */ 126*7bcceb95SPekka Enberg [105] = DEFINE_ESC(0x14), /* <right ctrl> */ 127*7bcceb95SPekka Enberg [106] = DEFINE_ESC(0x4a), /* keypad / */ 128*7bcceb95SPekka Enberg [108] = DEFINE_ESC(0x11), /* <right alt> */ 129*7bcceb95SPekka Enberg [110] = DEFINE_ESC(0x6c), /* <home> */ 130*7bcceb95SPekka Enberg [111] = DEFINE_ESC(0x75), /* <up> */ 131*7bcceb95SPekka Enberg [112] = DEFINE_ESC(0x7d), /* <pag up> */ 132*7bcceb95SPekka Enberg [113] = DEFINE_ESC(0x6b), /* <left> */ 133*7bcceb95SPekka Enberg [114] = DEFINE_ESC(0x74), /* <right> */ 134*7bcceb95SPekka Enberg [115] = DEFINE_ESC(0x69), /* <end> */ 135*7bcceb95SPekka Enberg [116] = DEFINE_ESC(0x72), /* <down> */ 136*7bcceb95SPekka Enberg [117] = DEFINE_ESC(0x7a), /* <pag down> */ 137*7bcceb95SPekka Enberg [118] = DEFINE_ESC(0x70), /* <ins> */ 138*7bcceb95SPekka Enberg [119] = DEFINE_ESC(0x71), /* <delete> */ 139*7bcceb95SPekka Enberg }; 140*7bcceb95SPekka Enberg 141*7bcceb95SPekka Enberg static cairo_surface_t *surface; 142*7bcceb95SPekka Enberg static bool done; 143*7bcceb95SPekka Enberg 144*7bcceb95SPekka Enberg static const struct set2_scancode *to_code(u8 scancode) 145*7bcceb95SPekka Enberg { 146*7bcceb95SPekka Enberg return &keymap[scancode]; 147*7bcceb95SPekka Enberg } 148*7bcceb95SPekka Enberg 149*7bcceb95SPekka Enberg static gboolean 150*7bcceb95SPekka Enberg kvm_gtk_configure_event(GtkWidget * widget, GdkEventConfigure * event, gpointer data) 151*7bcceb95SPekka Enberg { 152*7bcceb95SPekka Enberg struct framebuffer *fb = data; 153*7bcceb95SPekka Enberg int stride; 154*7bcceb95SPekka Enberg 155*7bcceb95SPekka Enberg if (surface) 156*7bcceb95SPekka Enberg cairo_surface_destroy(surface); 157*7bcceb95SPekka Enberg 158*7bcceb95SPekka Enberg stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, fb->width); 159*7bcceb95SPekka Enberg 160*7bcceb95SPekka Enberg surface = 161*7bcceb95SPekka Enberg cairo_image_surface_create_for_data((void *) fb->mem, 162*7bcceb95SPekka Enberg CAIRO_FORMAT_RGB24, 163*7bcceb95SPekka Enberg fb->width, 164*7bcceb95SPekka Enberg fb->height, 165*7bcceb95SPekka Enberg stride); 166*7bcceb95SPekka Enberg 167*7bcceb95SPekka Enberg return TRUE; 168*7bcceb95SPekka Enberg } 169*7bcceb95SPekka Enberg 170*7bcceb95SPekka Enberg static gboolean kvm_gtk_draw(GtkWidget *widget, cairo_t *cr, gpointer data) 171*7bcceb95SPekka Enberg { 172*7bcceb95SPekka Enberg cairo_set_source_surface(cr, surface, 0, 0); 173*7bcceb95SPekka Enberg 174*7bcceb95SPekka Enberg cairo_paint(cr); 175*7bcceb95SPekka Enberg 176*7bcceb95SPekka Enberg return FALSE; 177*7bcceb95SPekka Enberg } 178*7bcceb95SPekka Enberg 179*7bcceb95SPekka Enberg static void kvm_gtk_destroy(void) 180*7bcceb95SPekka Enberg { 181*7bcceb95SPekka Enberg if (surface) 182*7bcceb95SPekka Enberg cairo_surface_destroy(surface); 183*7bcceb95SPekka Enberg 184*7bcceb95SPekka Enberg gtk_main_quit(); 185*7bcceb95SPekka Enberg } 186*7bcceb95SPekka Enberg 187*7bcceb95SPekka Enberg static gboolean kvm_gtk_redraw(GtkWidget * window) 188*7bcceb95SPekka Enberg { 189*7bcceb95SPekka Enberg gtk_widget_queue_draw(window); 190*7bcceb95SPekka Enberg 191*7bcceb95SPekka Enberg return TRUE; 192*7bcceb95SPekka Enberg } 193*7bcceb95SPekka Enberg 194*7bcceb95SPekka Enberg static gboolean 195*7bcceb95SPekka Enberg kvm_gtk_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data) 196*7bcceb95SPekka Enberg { 197*7bcceb95SPekka Enberg const struct set2_scancode *sc = to_code(event->hardware_keycode); 198*7bcceb95SPekka Enberg 199*7bcceb95SPekka Enberg switch (sc->type) { 200*7bcceb95SPekka Enberg case SCANCODE_ESCAPED: 201*7bcceb95SPekka Enberg kbd_queue(0xe0); 202*7bcceb95SPekka Enberg /* fallthrough */ 203*7bcceb95SPekka Enberg case SCANCODE_NORMAL: 204*7bcceb95SPekka Enberg kbd_queue(sc->code); 205*7bcceb95SPekka Enberg break; 206*7bcceb95SPekka Enberg case SCANCODE_KEY_PAUSE: 207*7bcceb95SPekka Enberg kbd_queue(0xe1); 208*7bcceb95SPekka Enberg kbd_queue(0x14); 209*7bcceb95SPekka Enberg kbd_queue(0x77); 210*7bcceb95SPekka Enberg kbd_queue(0xe1); 211*7bcceb95SPekka Enberg kbd_queue(0xf0); 212*7bcceb95SPekka Enberg kbd_queue(0x14); 213*7bcceb95SPekka Enberg kbd_queue(0x77); 214*7bcceb95SPekka Enberg break; 215*7bcceb95SPekka Enberg case SCANCODE_KEY_PRNTSCRN: 216*7bcceb95SPekka Enberg kbd_queue(0xe0); 217*7bcceb95SPekka Enberg kbd_queue(0x12); 218*7bcceb95SPekka Enberg kbd_queue(0xe0); 219*7bcceb95SPekka Enberg kbd_queue(0x7c); 220*7bcceb95SPekka Enberg break; 221*7bcceb95SPekka Enberg } 222*7bcceb95SPekka Enberg 223*7bcceb95SPekka Enberg return TRUE; 224*7bcceb95SPekka Enberg } 225*7bcceb95SPekka Enberg 226*7bcceb95SPekka Enberg static void *kvm_gtk_thread(void *p) 227*7bcceb95SPekka Enberg { 228*7bcceb95SPekka Enberg struct framebuffer *fb = p; 229*7bcceb95SPekka Enberg GtkWidget *window; 230*7bcceb95SPekka Enberg GtkWidget *frame; 231*7bcceb95SPekka Enberg GtkWidget *da; 232*7bcceb95SPekka Enberg 233*7bcceb95SPekka Enberg gtk_init(NULL, NULL); 234*7bcceb95SPekka Enberg 235*7bcceb95SPekka Enberg window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 236*7bcceb95SPekka Enberg 237*7bcceb95SPekka Enberg gtk_window_set_title(GTK_WINDOW(window), "VM"); 238*7bcceb95SPekka Enberg 239*7bcceb95SPekka Enberg g_signal_connect(window, "destroy", G_CALLBACK(kvm_gtk_destroy), NULL); 240*7bcceb95SPekka Enberg 241*7bcceb95SPekka Enberg gtk_container_set_border_width(GTK_CONTAINER(window), 8); 242*7bcceb95SPekka Enberg 243*7bcceb95SPekka Enberg frame = gtk_frame_new(NULL); 244*7bcceb95SPekka Enberg 245*7bcceb95SPekka Enberg gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); 246*7bcceb95SPekka Enberg gtk_container_add(GTK_CONTAINER(window), frame); 247*7bcceb95SPekka Enberg 248*7bcceb95SPekka Enberg da = gtk_drawing_area_new(); 249*7bcceb95SPekka Enberg 250*7bcceb95SPekka Enberg gtk_widget_set_size_request(da, 100, 100); 251*7bcceb95SPekka Enberg 252*7bcceb95SPekka Enberg gtk_container_add(GTK_CONTAINER(frame), da); 253*7bcceb95SPekka Enberg 254*7bcceb95SPekka Enberg g_signal_connect(da, "draw", G_CALLBACK(kvm_gtk_draw), NULL); 255*7bcceb95SPekka Enberg g_signal_connect(da, "configure-event", 256*7bcceb95SPekka Enberg G_CALLBACK(kvm_gtk_configure_event), fb); 257*7bcceb95SPekka Enberg g_signal_connect(G_OBJECT (window), "key_press_event", G_CALLBACK(kvm_gtk_key_press), NULL); 258*7bcceb95SPekka Enberg 259*7bcceb95SPekka Enberg 260*7bcceb95SPekka Enberg gtk_widget_set_events(da, gtk_widget_get_events(da) 261*7bcceb95SPekka Enberg | GDK_BUTTON_PRESS_MASK 262*7bcceb95SPekka Enberg | GDK_POINTER_MOTION_MASK 263*7bcceb95SPekka Enberg | GDK_POINTER_MOTION_HINT_MASK); 264*7bcceb95SPekka Enberg 265*7bcceb95SPekka Enberg gtk_widget_show_all(window); 266*7bcceb95SPekka Enberg 267*7bcceb95SPekka Enberg g_timeout_add(1000 / FRAME_RATE, (GSourceFunc) kvm_gtk_redraw, window); 268*7bcceb95SPekka Enberg 269*7bcceb95SPekka Enberg gtk_main(); 270*7bcceb95SPekka Enberg 271*7bcceb95SPekka Enberg done = true; 272*7bcceb95SPekka Enberg 273*7bcceb95SPekka Enberg return NULL; 274*7bcceb95SPekka Enberg } 275*7bcceb95SPekka Enberg 276*7bcceb95SPekka Enberg static int kvm_gtk_start(struct framebuffer *fb) 277*7bcceb95SPekka Enberg { 278*7bcceb95SPekka Enberg pthread_t thread; 279*7bcceb95SPekka Enberg 280*7bcceb95SPekka Enberg if (pthread_create(&thread, NULL, kvm_gtk_thread, fb) != 0) 281*7bcceb95SPekka Enberg return -1; 282*7bcceb95SPekka Enberg 283*7bcceb95SPekka Enberg return 0; 284*7bcceb95SPekka Enberg } 285*7bcceb95SPekka Enberg 286*7bcceb95SPekka Enberg static int kvm_gtk_stop(struct framebuffer *fb) 287*7bcceb95SPekka Enberg { 288*7bcceb95SPekka Enberg gtk_main_quit(); 289*7bcceb95SPekka Enberg 290*7bcceb95SPekka Enberg while (!done) 291*7bcceb95SPekka Enberg sleep(0); 292*7bcceb95SPekka Enberg 293*7bcceb95SPekka Enberg return 0; 294*7bcceb95SPekka Enberg } 295*7bcceb95SPekka Enberg 296*7bcceb95SPekka Enberg static struct fb_target_operations kvm_gtk_ops = { 297*7bcceb95SPekka Enberg .start = kvm_gtk_start, 298*7bcceb95SPekka Enberg .stop = kvm_gtk_stop, 299*7bcceb95SPekka Enberg }; 300*7bcceb95SPekka Enberg 301*7bcceb95SPekka Enberg int kvm_gtk_init(struct kvm *kvm) 302*7bcceb95SPekka Enberg { 303*7bcceb95SPekka Enberg struct framebuffer *fb; 304*7bcceb95SPekka Enberg 305*7bcceb95SPekka Enberg if (!kvm->cfg.gtk) 306*7bcceb95SPekka Enberg return 0; 307*7bcceb95SPekka Enberg 308*7bcceb95SPekka Enberg fb = vesa__init(kvm); 309*7bcceb95SPekka Enberg if (IS_ERR(fb)) { 310*7bcceb95SPekka Enberg pr_err("vesa__init() failed with error %ld\n", PTR_ERR(fb)); 311*7bcceb95SPekka Enberg return PTR_ERR(fb); 312*7bcceb95SPekka Enberg } 313*7bcceb95SPekka Enberg 314*7bcceb95SPekka Enberg return fb__attach(fb, &kvm_gtk_ops); 315*7bcceb95SPekka Enberg } 316*7bcceb95SPekka Enberg 317*7bcceb95SPekka Enberg int kvm_gtk_exit(struct kvm *kvm) 318*7bcceb95SPekka Enberg { 319*7bcceb95SPekka Enberg if (kvm->cfg.gtk) 320*7bcceb95SPekka Enberg return kvm_gtk_stop(NULL); 321*7bcceb95SPekka Enberg 322*7bcceb95SPekka Enberg return 0; 323*7bcceb95SPekka Enberg } 324*7bcceb95SPekka Enberg 325*7bcceb95SPekka Enberg dev_init(kvm_gtk_init); 326*7bcceb95SPekka Enberg dev_exit(kvm_gtk_exit); 327