xref: /kvmtool/ui/gtk3.c (revision 369c27e68300a6cf0a98f7455a81b7e4473c7a8b)
17bcceb95SPekka Enberg #include "kvm/gtk3.h"
27bcceb95SPekka Enberg 
37bcceb95SPekka Enberg #include "kvm/framebuffer.h"
47bcceb95SPekka Enberg #include "kvm/kvm-cpu.h"
57bcceb95SPekka Enberg #include "kvm/i8042.h"
67bcceb95SPekka Enberg #include "kvm/vesa.h"
77bcceb95SPekka Enberg #include "kvm/kvm.h"
87bcceb95SPekka Enberg 
97bcceb95SPekka Enberg #include <gtk/gtk.h>
107bcceb95SPekka Enberg #include <pthread.h>
117bcceb95SPekka Enberg #include <linux/err.h>
127bcceb95SPekka Enberg 
137bcceb95SPekka Enberg #define FRAME_RATE			25
147bcceb95SPekka Enberg 
157bcceb95SPekka Enberg #define SCANCODE_UNKNOWN		0
167bcceb95SPekka Enberg #define SCANCODE_NORMAL			1
177bcceb95SPekka Enberg #define SCANCODE_ESCAPED		2
187bcceb95SPekka Enberg #define SCANCODE_KEY_PAUSE		3
197bcceb95SPekka Enberg #define SCANCODE_KEY_PRNTSCRN		4
207bcceb95SPekka Enberg 
217bcceb95SPekka Enberg struct set2_scancode {
227bcceb95SPekka Enberg 	u8 code;
237bcceb95SPekka Enberg 	u8 type;
247bcceb95SPekka Enberg };
257bcceb95SPekka Enberg 
267bcceb95SPekka Enberg #define DEFINE_SC(_code) {		\
277bcceb95SPekka Enberg 	.code = _code,			\
287bcceb95SPekka Enberg 	.type = SCANCODE_NORMAL,	\
297bcceb95SPekka Enberg }
307bcceb95SPekka Enberg 
317bcceb95SPekka Enberg /* escaped scancodes */
327bcceb95SPekka Enberg #define DEFINE_ESC(_code) {		\
337bcceb95SPekka Enberg 	.code = _code,			\
347bcceb95SPekka Enberg 	.type = SCANCODE_ESCAPED,	\
357bcceb95SPekka Enberg }
367bcceb95SPekka Enberg 
37*369c27e6SAndre Przywara static const struct set2_scancode keymap[256] = {
387bcceb95SPekka Enberg 	[9]	= DEFINE_SC(0x76),	/* <esc> */
397bcceb95SPekka Enberg 	[10]	= DEFINE_SC(0x16),	/* 1 */
407bcceb95SPekka Enberg 	[11]	= DEFINE_SC(0x1e),	/* 2 */
417bcceb95SPekka Enberg 	[12]	= DEFINE_SC(0x26),	/* 3 */
427bcceb95SPekka Enberg 	[13]	= DEFINE_SC(0x25),	/* 4 */
437bcceb95SPekka Enberg 	[14]	= DEFINE_SC(0x2e),	/* 5 */
447bcceb95SPekka Enberg 	[15]	= DEFINE_SC(0x36),	/* 6 */
457bcceb95SPekka Enberg 	[16]	= DEFINE_SC(0x3d),	/* 7 */
467bcceb95SPekka Enberg 	[17]	= DEFINE_SC(0x3e),	/* 8 */
477bcceb95SPekka Enberg 	[18]	= DEFINE_SC(0x46),	/* 9 */
487bcceb95SPekka Enberg 	[19]	= DEFINE_SC(0x45),	/* 9 */
497bcceb95SPekka Enberg 	[20]	= DEFINE_SC(0x4e),	/* - */
507bcceb95SPekka Enberg 	[21]	= DEFINE_SC(0x55),	/* + */
517bcceb95SPekka Enberg 	[22]	= DEFINE_SC(0x66),	/* <backspace> */
527bcceb95SPekka Enberg 	[23]	= DEFINE_SC(0x0d),	/* <tab> */
537bcceb95SPekka Enberg 	[24]	= DEFINE_SC(0x15),	/* q */
547bcceb95SPekka Enberg 	[25]	= DEFINE_SC(0x1d),	/* w */
557bcceb95SPekka Enberg 	[26]	= DEFINE_SC(0x24),	/* e */
567bcceb95SPekka Enberg 	[27]	= DEFINE_SC(0x2d),	/* r */
577bcceb95SPekka Enberg 	[28]	= DEFINE_SC(0x2c),	/* t */
587bcceb95SPekka Enberg 	[29]	= DEFINE_SC(0x35),	/* y */
597bcceb95SPekka Enberg 	[30]	= DEFINE_SC(0x3c),	/* u */
607bcceb95SPekka Enberg 	[31]	= DEFINE_SC(0x43),	/* i */
617bcceb95SPekka Enberg 	[32]	= DEFINE_SC(0x44),	/* o */
627bcceb95SPekka Enberg 	[33]	= DEFINE_SC(0x4d),	/* p */
637bcceb95SPekka Enberg 	[34]	= DEFINE_SC(0x54),	/* [ */
647bcceb95SPekka Enberg 	[35]	= DEFINE_SC(0x5b),	/* ] */
657bcceb95SPekka Enberg 	[36]	= DEFINE_SC(0x5a),	/* <enter> */
667bcceb95SPekka Enberg 	[37]	= DEFINE_SC(0x14),	/* <left ctrl> */
677bcceb95SPekka Enberg 	[38]	= DEFINE_SC(0x1c),	/* a */
687bcceb95SPekka Enberg 	[39]	= DEFINE_SC(0x1b),	/* s */
697bcceb95SPekka Enberg 	[40]	= DEFINE_SC(0x23),	/* d */
707bcceb95SPekka Enberg 	[41]	= DEFINE_SC(0x2b),	/* f */
717bcceb95SPekka Enberg 	[42]	= DEFINE_SC(0x34),	/* g */
727bcceb95SPekka Enberg 	[43]	= DEFINE_SC(0x33),	/* h */
737bcceb95SPekka Enberg 	[44]	= DEFINE_SC(0x3b),	/* j */
747bcceb95SPekka Enberg 	[45]	= DEFINE_SC(0x42),	/* k */
757bcceb95SPekka Enberg 	[46]	= DEFINE_SC(0x4b),	/* l */
767bcceb95SPekka Enberg 	[47]	= DEFINE_SC(0x4c),	/* ; */
777bcceb95SPekka Enberg 	[48]	= DEFINE_SC(0x52),	/* ' */
787bcceb95SPekka Enberg 	[49]	= DEFINE_SC(0x0e),	/* ` */
797bcceb95SPekka Enberg 	[50]	= DEFINE_SC(0x12),	/* <left shift> */
807bcceb95SPekka Enberg 	[51]	= DEFINE_SC(0x5d),	/* \ */
817bcceb95SPekka Enberg 	[52]	= DEFINE_SC(0x1a),	/* z */
827bcceb95SPekka Enberg 	[53]	= DEFINE_SC(0x22),	/* x */
837bcceb95SPekka Enberg 	[54]	= DEFINE_SC(0x21),	/* c */
847bcceb95SPekka Enberg 	[55]	= DEFINE_SC(0x2a),	/* v */
857bcceb95SPekka Enberg 	[56]	= DEFINE_SC(0x32),	/* b */
867bcceb95SPekka Enberg 	[57]	= DEFINE_SC(0x31),	/* n */
877bcceb95SPekka Enberg 	[58]	= DEFINE_SC(0x3a),	/* m */
887bcceb95SPekka Enberg 	[59]	= DEFINE_SC(0x41),	/* < */
897bcceb95SPekka Enberg 	[60]	= DEFINE_SC(0x49),	/* > */
907bcceb95SPekka Enberg 	[61]	= DEFINE_SC(0x4a),	/* / */
917bcceb95SPekka Enberg 	[62]	= DEFINE_SC(0x59),	/* <right shift> */
927bcceb95SPekka Enberg 	[63]	= DEFINE_SC(0x7c),	/* keypad * */
937bcceb95SPekka Enberg 	[64]	= DEFINE_SC(0x11),	/* <left alt> */
947bcceb95SPekka Enberg 	[65]	= DEFINE_SC(0x29),	/* <space> */
957bcceb95SPekka Enberg 
967bcceb95SPekka Enberg 	[67]	= DEFINE_SC(0x05),	/* <F1> */
977bcceb95SPekka Enberg 	[68]	= DEFINE_SC(0x06),	/* <F2> */
987bcceb95SPekka Enberg 	[69]	= DEFINE_SC(0x04),	/* <F3> */
997bcceb95SPekka Enberg 	[70]	= DEFINE_SC(0x0c),	/* <F4> */
1007bcceb95SPekka Enberg 	[71]	= DEFINE_SC(0x03),	/* <F5> */
1017bcceb95SPekka Enberg 	[72]	= DEFINE_SC(0x0b),	/* <F6> */
1027bcceb95SPekka Enberg 	[73]	= DEFINE_SC(0x83),	/* <F7> */
1037bcceb95SPekka Enberg 	[74]	= DEFINE_SC(0x0a),	/* <F8> */
1047bcceb95SPekka Enberg 	[75]	= DEFINE_SC(0x01),	/* <F9> */
1057bcceb95SPekka Enberg 	[76]	= DEFINE_SC(0x09),	/* <F10> */
1067bcceb95SPekka Enberg 
1077bcceb95SPekka Enberg 	[79]	= DEFINE_SC(0x6c),	/* keypad 7 */
1087bcceb95SPekka Enberg 	[80]	= DEFINE_SC(0x75),	/* keypad 8 */
1097bcceb95SPekka Enberg 	[81]	= DEFINE_SC(0x7d),	/* keypad 9 */
1107bcceb95SPekka Enberg 	[82]	= DEFINE_SC(0x7b),	/* keypad - */
1117bcceb95SPekka Enberg 	[83]	= DEFINE_SC(0x6b),	/* keypad 4 */
1127bcceb95SPekka Enberg 	[84]	= DEFINE_SC(0x73),	/* keypad 5 */
1137bcceb95SPekka Enberg 	[85]	= DEFINE_SC(0x74),	/* keypad 6 */
1147bcceb95SPekka Enberg 	[86]	= DEFINE_SC(0x79),	/* keypad + */
1157bcceb95SPekka Enberg 	[87]	= DEFINE_SC(0x69),	/* keypad 1 */
1167bcceb95SPekka Enberg 	[88]	= DEFINE_SC(0x72),	/* keypad 2 */
1177bcceb95SPekka Enberg 	[89]	= DEFINE_SC(0x7a),	/* keypad 3 */
1187bcceb95SPekka Enberg 	[90]	= DEFINE_SC(0x70),	/* keypad 0 */
1197bcceb95SPekka Enberg 	[91]	= DEFINE_SC(0x71),	/* keypad . */
1207bcceb95SPekka Enberg 
1217bcceb95SPekka Enberg 	[94]	= DEFINE_SC(0x61),	/* <INT 1> */
1227bcceb95SPekka Enberg 	[95]	= DEFINE_SC(0x78),	/* <F11> */
1237bcceb95SPekka Enberg 	[96]	= DEFINE_SC(0x07),	/* <F12> */
1247bcceb95SPekka Enberg 
1257bcceb95SPekka Enberg 	[104]	= DEFINE_ESC(0x5a),	/* keypad <enter> */
1267bcceb95SPekka Enberg 	[105]	= DEFINE_ESC(0x14),	/* <right ctrl> */
1277bcceb95SPekka Enberg 	[106]	= DEFINE_ESC(0x4a),	/* keypad / */
1287bcceb95SPekka Enberg 	[108]	= DEFINE_ESC(0x11),	/* <right alt> */
1297bcceb95SPekka Enberg 	[110]	= DEFINE_ESC(0x6c),	/* <home> */
1307bcceb95SPekka Enberg 	[111]	= DEFINE_ESC(0x75),	/* <up> */
1317bcceb95SPekka Enberg 	[112]	= DEFINE_ESC(0x7d),	/* <pag up> */
1327bcceb95SPekka Enberg 	[113]	= DEFINE_ESC(0x6b),	/* <left> */
1337bcceb95SPekka Enberg 	[114]	= DEFINE_ESC(0x74),	/* <right> */
1347bcceb95SPekka Enberg 	[115]	= DEFINE_ESC(0x69),	/* <end> */
1357bcceb95SPekka Enberg 	[116]	= DEFINE_ESC(0x72),	/* <down> */
1367bcceb95SPekka Enberg 	[117]	= DEFINE_ESC(0x7a),	/* <pag down> */
1377bcceb95SPekka Enberg 	[118]	= DEFINE_ESC(0x70),	/* <ins> */
1387bcceb95SPekka Enberg 	[119]	= DEFINE_ESC(0x71),	/* <delete> */
1397bcceb95SPekka Enberg };
1407bcceb95SPekka Enberg 
1417bcceb95SPekka Enberg static cairo_surface_t	*surface;
1427bcceb95SPekka Enberg static bool		done;
1437bcceb95SPekka Enberg 
to_code(u8 scancode)1447bcceb95SPekka Enberg static const struct set2_scancode *to_code(u8 scancode)
1457bcceb95SPekka Enberg {
1467bcceb95SPekka Enberg         return &keymap[scancode];
1477bcceb95SPekka Enberg }
1487bcceb95SPekka Enberg 
1497bcceb95SPekka Enberg static gboolean
kvm_gtk_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer data)1507bcceb95SPekka Enberg kvm_gtk_configure_event(GtkWidget * widget, GdkEventConfigure * event, gpointer data)
1517bcceb95SPekka Enberg {
1527bcceb95SPekka Enberg 	struct framebuffer *fb = data;
1537bcceb95SPekka Enberg 	int stride;
1547bcceb95SPekka Enberg 
1557bcceb95SPekka Enberg 	if (surface)
1567bcceb95SPekka Enberg 		cairo_surface_destroy(surface);
1577bcceb95SPekka Enberg 
1587bcceb95SPekka Enberg 	stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, fb->width);
1597bcceb95SPekka Enberg 
1607bcceb95SPekka Enberg 	surface =
1617bcceb95SPekka Enberg 	    cairo_image_surface_create_for_data((void *) fb->mem,
1627bcceb95SPekka Enberg 						CAIRO_FORMAT_RGB24,
1637bcceb95SPekka Enberg 						fb->width,
1647bcceb95SPekka Enberg 						fb->height,
1657bcceb95SPekka Enberg 						stride);
1667bcceb95SPekka Enberg 
1677bcceb95SPekka Enberg 	return TRUE;
1687bcceb95SPekka Enberg }
1697bcceb95SPekka Enberg 
kvm_gtk_draw(GtkWidget * widget,cairo_t * cr,gpointer data)1707bcceb95SPekka Enberg static gboolean kvm_gtk_draw(GtkWidget *widget, cairo_t *cr, gpointer data)
1717bcceb95SPekka Enberg {
1727bcceb95SPekka Enberg 	cairo_set_source_surface(cr, surface, 0, 0);
1737bcceb95SPekka Enberg 
1747bcceb95SPekka Enberg 	cairo_paint(cr);
1757bcceb95SPekka Enberg 
1767bcceb95SPekka Enberg 	return FALSE;
1777bcceb95SPekka Enberg }
1787bcceb95SPekka Enberg 
kvm_gtk_destroy(void)1797bcceb95SPekka Enberg static void kvm_gtk_destroy(void)
1807bcceb95SPekka Enberg {
1817bcceb95SPekka Enberg 	if (surface)
1827bcceb95SPekka Enberg 		cairo_surface_destroy(surface);
1837bcceb95SPekka Enberg 
1847bcceb95SPekka Enberg 	gtk_main_quit();
1857bcceb95SPekka Enberg }
1867bcceb95SPekka Enberg 
kvm_gtk_redraw(GtkWidget * window)1877bcceb95SPekka Enberg static gboolean kvm_gtk_redraw(GtkWidget * window)
1887bcceb95SPekka Enberg {
1897bcceb95SPekka Enberg 	gtk_widget_queue_draw(window);
1907bcceb95SPekka Enberg 
1917bcceb95SPekka Enberg 	return TRUE;
1927bcceb95SPekka Enberg }
1937bcceb95SPekka Enberg 
1947bcceb95SPekka Enberg static gboolean
kvm_gtk_key_press(GtkWidget * widget,GdkEventKey * event,gpointer user_data)1957bcceb95SPekka Enberg kvm_gtk_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
1967bcceb95SPekka Enberg {
1977bcceb95SPekka Enberg 	const struct set2_scancode *sc = to_code(event->hardware_keycode);
1987bcceb95SPekka Enberg 
1997bcceb95SPekka Enberg         switch (sc->type) {
2007bcceb95SPekka Enberg         case SCANCODE_ESCAPED:
2017bcceb95SPekka Enberg                 kbd_queue(0xe0);
2027bcceb95SPekka Enberg                 /* fallthrough */
2037bcceb95SPekka Enberg         case SCANCODE_NORMAL:
2047bcceb95SPekka Enberg                 kbd_queue(sc->code);
2057bcceb95SPekka Enberg                 break;
2067bcceb95SPekka Enberg         case SCANCODE_KEY_PAUSE:
2077bcceb95SPekka Enberg                 kbd_queue(0xe1);
2087bcceb95SPekka Enberg                 kbd_queue(0x14);
2097bcceb95SPekka Enberg                 kbd_queue(0x77);
2107bcceb95SPekka Enberg                 kbd_queue(0xe1);
2117bcceb95SPekka Enberg                 kbd_queue(0xf0);
2127bcceb95SPekka Enberg                 kbd_queue(0x14);
2137bcceb95SPekka Enberg                 kbd_queue(0x77);
2147bcceb95SPekka Enberg                 break;
2157bcceb95SPekka Enberg         case SCANCODE_KEY_PRNTSCRN:
2167bcceb95SPekka Enberg                 kbd_queue(0xe0);
2177bcceb95SPekka Enberg                 kbd_queue(0x12);
2187bcceb95SPekka Enberg                 kbd_queue(0xe0);
2197bcceb95SPekka Enberg                 kbd_queue(0x7c);
2207bcceb95SPekka Enberg                 break;
2217bcceb95SPekka Enberg         }
2227bcceb95SPekka Enberg 
2237bcceb95SPekka Enberg 	return TRUE;
2247bcceb95SPekka Enberg }
2257bcceb95SPekka Enberg 
kvm_gtk_thread(void * p)2267bcceb95SPekka Enberg static void *kvm_gtk_thread(void *p)
2277bcceb95SPekka Enberg {
2287bcceb95SPekka Enberg 	struct framebuffer *fb = p;
2297bcceb95SPekka Enberg 	GtkWidget *window;
2307bcceb95SPekka Enberg 	GtkWidget *frame;
2317bcceb95SPekka Enberg 	GtkWidget *da;
2327bcceb95SPekka Enberg 
2337bcceb95SPekka Enberg 	gtk_init(NULL, NULL);
2347bcceb95SPekka Enberg 
2357bcceb95SPekka Enberg 	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2367bcceb95SPekka Enberg 
2377bcceb95SPekka Enberg 	gtk_window_set_title(GTK_WINDOW(window), "VM");
2387bcceb95SPekka Enberg 
2397bcceb95SPekka Enberg 	g_signal_connect(window, "destroy", G_CALLBACK(kvm_gtk_destroy), NULL);
2407bcceb95SPekka Enberg 
2417bcceb95SPekka Enberg 	gtk_container_set_border_width(GTK_CONTAINER(window), 8);
2427bcceb95SPekka Enberg 
2437bcceb95SPekka Enberg 	frame = gtk_frame_new(NULL);
2447bcceb95SPekka Enberg 
2457bcceb95SPekka Enberg 	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
2467bcceb95SPekka Enberg 	gtk_container_add(GTK_CONTAINER(window), frame);
2477bcceb95SPekka Enberg 
2487bcceb95SPekka Enberg 	da = gtk_drawing_area_new();
2497bcceb95SPekka Enberg 
2507bcceb95SPekka Enberg 	gtk_widget_set_size_request(da, 100, 100);
2517bcceb95SPekka Enberg 
2527bcceb95SPekka Enberg 	gtk_container_add(GTK_CONTAINER(frame), da);
2537bcceb95SPekka Enberg 
2547bcceb95SPekka Enberg 	g_signal_connect(da, "draw", G_CALLBACK(kvm_gtk_draw), NULL);
2557bcceb95SPekka Enberg 	g_signal_connect(da, "configure-event",
2567bcceb95SPekka Enberg 			 G_CALLBACK(kvm_gtk_configure_event), fb);
2577bcceb95SPekka Enberg 	g_signal_connect(G_OBJECT (window), "key_press_event", G_CALLBACK(kvm_gtk_key_press), NULL);
2587bcceb95SPekka Enberg 
2597bcceb95SPekka Enberg 
2607bcceb95SPekka Enberg 	gtk_widget_set_events(da, gtk_widget_get_events(da)
2617bcceb95SPekka Enberg 			      | GDK_BUTTON_PRESS_MASK
2627bcceb95SPekka Enberg 			      | GDK_POINTER_MOTION_MASK
2637bcceb95SPekka Enberg 			      | GDK_POINTER_MOTION_HINT_MASK);
2647bcceb95SPekka Enberg 
2657bcceb95SPekka Enberg 	gtk_widget_show_all(window);
2667bcceb95SPekka Enberg 
2677bcceb95SPekka Enberg 	g_timeout_add(1000 / FRAME_RATE, (GSourceFunc) kvm_gtk_redraw, window);
2687bcceb95SPekka Enberg 
2697bcceb95SPekka Enberg 	gtk_main();
2707bcceb95SPekka Enberg 
2717bcceb95SPekka Enberg 	done = true;
2727bcceb95SPekka Enberg 
2737bcceb95SPekka Enberg 	return NULL;
2747bcceb95SPekka Enberg }
2757bcceb95SPekka Enberg 
kvm_gtk_start(struct framebuffer * fb)2767bcceb95SPekka Enberg static int kvm_gtk_start(struct framebuffer *fb)
2777bcceb95SPekka Enberg {
2787bcceb95SPekka Enberg 	pthread_t thread;
2797bcceb95SPekka Enberg 
2807bcceb95SPekka Enberg 	if (pthread_create(&thread, NULL, kvm_gtk_thread, fb) != 0)
2817bcceb95SPekka Enberg 		return -1;
2827bcceb95SPekka Enberg 
2837bcceb95SPekka Enberg 	return 0;
2847bcceb95SPekka Enberg }
2857bcceb95SPekka Enberg 
kvm_gtk_stop(struct framebuffer * fb)2867bcceb95SPekka Enberg static int kvm_gtk_stop(struct framebuffer *fb)
2877bcceb95SPekka Enberg {
2887bcceb95SPekka Enberg 	gtk_main_quit();
2897bcceb95SPekka Enberg 
2907bcceb95SPekka Enberg 	while (!done)
2917bcceb95SPekka Enberg 		sleep(0);
2927bcceb95SPekka Enberg 
2937bcceb95SPekka Enberg 	return 0;
2947bcceb95SPekka Enberg }
2957bcceb95SPekka Enberg 
2967bcceb95SPekka Enberg static struct fb_target_operations kvm_gtk_ops = {
2977bcceb95SPekka Enberg 	.start		= kvm_gtk_start,
2987bcceb95SPekka Enberg 	.stop		= kvm_gtk_stop,
2997bcceb95SPekka Enberg };
3007bcceb95SPekka Enberg 
kvm_gtk_init(struct kvm * kvm)3017bcceb95SPekka Enberg int kvm_gtk_init(struct kvm *kvm)
3027bcceb95SPekka Enberg {
3037bcceb95SPekka Enberg 	struct framebuffer *fb;
3047bcceb95SPekka Enberg 
3057bcceb95SPekka Enberg 	if (!kvm->cfg.gtk)
3067bcceb95SPekka Enberg 		return 0;
3077bcceb95SPekka Enberg 
3087bcceb95SPekka Enberg 	fb = vesa__init(kvm);
3097bcceb95SPekka Enberg 	if (IS_ERR(fb)) {
3107bcceb95SPekka Enberg 		pr_err("vesa__init() failed with error %ld\n", PTR_ERR(fb));
3117bcceb95SPekka Enberg 		return PTR_ERR(fb);
3127bcceb95SPekka Enberg 	}
3137bcceb95SPekka Enberg 
3147bcceb95SPekka Enberg 	return fb__attach(fb, &kvm_gtk_ops);
3157bcceb95SPekka Enberg }
3167bcceb95SPekka Enberg 
kvm_gtk_exit(struct kvm * kvm)3177bcceb95SPekka Enberg int kvm_gtk_exit(struct kvm *kvm)
3187bcceb95SPekka Enberg {
3197bcceb95SPekka Enberg 	if (kvm->cfg.gtk)
3207bcceb95SPekka Enberg 		return kvm_gtk_stop(NULL);
3217bcceb95SPekka Enberg 
3227bcceb95SPekka Enberg 	return 0;
3237bcceb95SPekka Enberg }
3247bcceb95SPekka Enberg 
3257bcceb95SPekka Enberg dev_init(kvm_gtk_init);
3267bcceb95SPekka Enberg dev_exit(kvm_gtk_exit);
327