xref: /kvmtool/ui/gtk3.c (revision 7bcceb95fd5435ef6f27c2f4caff134b9060257e)
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