xref: /kvmtool/ui/sdl.c (revision 07d52d7721f17a0f59e12773517d7975c3af349e)
13f838fecSPekka Enberg #include "kvm/sdl.h"
23f838fecSPekka Enberg 
33f838fecSPekka Enberg #include "kvm/framebuffer.h"
4175f8e86SPekka Enberg #include "kvm/i8042.h"
53f838fecSPekka Enberg #include "kvm/util.h"
61c48f5f8SPekka Enberg #include "kvm/kvm.h"
7f9911ebaSSasha Levin #include "kvm/kvm-cpu.h"
8*07d52d77SSasha Levin #include "kvm/vesa.h"
93f838fecSPekka Enberg 
103f838fecSPekka Enberg #include <SDL/SDL.h>
113f838fecSPekka Enberg #include <pthread.h>
121c48f5f8SPekka Enberg #include <signal.h>
13*07d52d77SSasha Levin #include <linux/err.h>
143f838fecSPekka Enberg 
153f838fecSPekka Enberg #define FRAME_RATE		25
163f838fecSPekka Enberg 
17571cf4baSAlessandro Guido #define SCANCODE_UNKNOWN      0
18571cf4baSAlessandro Guido #define SCANCODE_NORMAL       1
19571cf4baSAlessandro Guido #define SCANCODE_ESCAPED      2
20571cf4baSAlessandro Guido #define SCANCODE_KEY_PAUSE    3
21571cf4baSAlessandro Guido #define SCANCODE_KEY_PRNTSCRN 4
22175f8e86SPekka Enberg 
23571cf4baSAlessandro Guido struct set2_scancode {
24571cf4baSAlessandro Guido 	u8 code;
25571cf4baSAlessandro Guido 	u8 type;
26175f8e86SPekka Enberg };
27175f8e86SPekka Enberg 
28571cf4baSAlessandro Guido #define DEFINE_SC(_code) {\
29571cf4baSAlessandro Guido 	.code = _code,\
30571cf4baSAlessandro Guido 	.type = SCANCODE_NORMAL,\
31571cf4baSAlessandro Guido }
32571cf4baSAlessandro Guido 
33571cf4baSAlessandro Guido /* escaped scancodes */
34571cf4baSAlessandro Guido #define DEFINE_ESC(_code) {\
35571cf4baSAlessandro Guido 	.code = _code,\
36571cf4baSAlessandro Guido 	.type = SCANCODE_ESCAPED,\
37571cf4baSAlessandro Guido }
38571cf4baSAlessandro Guido 
394c61e7f8SCyrill Gorcunov static const struct set2_scancode const keymap[256] = {
40571cf4baSAlessandro Guido 	[9]	= DEFINE_SC(0x76),	/* <esc> */
41571cf4baSAlessandro Guido 	[10]	= DEFINE_SC(0x16),	/* 1 */
42571cf4baSAlessandro Guido 	[11]	= DEFINE_SC(0x1e),	/* 2 */
43571cf4baSAlessandro Guido 	[12]	= DEFINE_SC(0x26),	/* 3 */
44571cf4baSAlessandro Guido 	[13]	= DEFINE_SC(0x25),	/* 4 */
45a022099dSAlessandro Guido 	[14]	= DEFINE_SC(0x2e),	/* 5 */
46571cf4baSAlessandro Guido 	[15]	= DEFINE_SC(0x36),	/* 6 */
47571cf4baSAlessandro Guido 	[16]	= DEFINE_SC(0x3d),	/* 7 */
48571cf4baSAlessandro Guido 	[17]	= DEFINE_SC(0x3e),	/* 8 */
49571cf4baSAlessandro Guido 	[18]	= DEFINE_SC(0x46),	/* 9 */
50571cf4baSAlessandro Guido 	[19]	= DEFINE_SC(0x45),	/* 9 */
51571cf4baSAlessandro Guido 	[20]	= DEFINE_SC(0x4e),	/* - */
52571cf4baSAlessandro Guido 	[21]	= DEFINE_SC(0x55),	/* + */
53571cf4baSAlessandro Guido 	[22]	= DEFINE_SC(0x66),	/* <backspace> */
54571cf4baSAlessandro Guido 	[23]	= DEFINE_SC(0x0d),	/* <tab> */
55571cf4baSAlessandro Guido 	[24]	= DEFINE_SC(0x15),	/* q */
56571cf4baSAlessandro Guido 	[25]	= DEFINE_SC(0x1d),	/* w */
57571cf4baSAlessandro Guido 	[26]	= DEFINE_SC(0x24),	/* e */
58571cf4baSAlessandro Guido 	[27]	= DEFINE_SC(0x2d),	/* r */
59571cf4baSAlessandro Guido 	[28]	= DEFINE_SC(0x2c),	/* t */
60571cf4baSAlessandro Guido 	[29]	= DEFINE_SC(0x35),	/* y */
61571cf4baSAlessandro Guido 	[30]	= DEFINE_SC(0x3c),	/* u */
62571cf4baSAlessandro Guido 	[31]	= DEFINE_SC(0x43),	/* i */
63571cf4baSAlessandro Guido 	[32]	= DEFINE_SC(0x44),	/* o */
64571cf4baSAlessandro Guido 	[33]	= DEFINE_SC(0x4d),	/* p */
65571cf4baSAlessandro Guido 	[34]	= DEFINE_SC(0x54),	/* [ */
66571cf4baSAlessandro Guido 	[35]	= DEFINE_SC(0x5b),	/* ] */
67571cf4baSAlessandro Guido 	[36]	= DEFINE_SC(0x5a),	/* <enter> */
68571cf4baSAlessandro Guido 	[37]	= DEFINE_SC(0x14),	/* <left ctrl> */
69571cf4baSAlessandro Guido 	[38]	= DEFINE_SC(0x1c),	/* a */
70571cf4baSAlessandro Guido 	[39]	= DEFINE_SC(0x1b),	/* s */
71571cf4baSAlessandro Guido 	[40]	= DEFINE_SC(0x23),	/* d */
72571cf4baSAlessandro Guido 	[41]	= DEFINE_SC(0x2b),	/* f */
73571cf4baSAlessandro Guido 	[42]	= DEFINE_SC(0x34),	/* g */
74571cf4baSAlessandro Guido 	[43]	= DEFINE_SC(0x33),	/* h */
75571cf4baSAlessandro Guido 	[44]	= DEFINE_SC(0x3b),	/* j */
76571cf4baSAlessandro Guido 	[45]	= DEFINE_SC(0x42),	/* k */
77571cf4baSAlessandro Guido 	[46]	= DEFINE_SC(0x4b),	/* l */
78571cf4baSAlessandro Guido 	[47]	= DEFINE_SC(0x4c),	/* ; */
79571cf4baSAlessandro Guido 	[48]	= DEFINE_SC(0x52),	/* ' */
80571cf4baSAlessandro Guido 	[49]	= DEFINE_SC(0x0e),	/* ` */
81571cf4baSAlessandro Guido 	[50]	= DEFINE_SC(0x12),	/* <left shift> */
82571cf4baSAlessandro Guido 	[51]	= DEFINE_SC(0x5d),	/* \ */
83571cf4baSAlessandro Guido 	[52]	= DEFINE_SC(0x1a),	/* z */
84571cf4baSAlessandro Guido 	[53]	= DEFINE_SC(0x22),	/* x */
85571cf4baSAlessandro Guido 	[54]	= DEFINE_SC(0x21),	/* c */
86571cf4baSAlessandro Guido 	[55]	= DEFINE_SC(0x2a),	/* v */
87571cf4baSAlessandro Guido 	[56]	= DEFINE_SC(0x32),	/* b */
88571cf4baSAlessandro Guido 	[57]	= DEFINE_SC(0x31),	/* n */
89571cf4baSAlessandro Guido 	[58]	= DEFINE_SC(0x3a),	/* m */
90571cf4baSAlessandro Guido 	[59]	= DEFINE_SC(0x41),	/* < */
91571cf4baSAlessandro Guido 	[60]	= DEFINE_SC(0x49),	/* > */
92571cf4baSAlessandro Guido 	[61]	= DEFINE_SC(0x4a),	/* / */
93571cf4baSAlessandro Guido 	[62]	= DEFINE_SC(0x59),	/* <right shift> */
94571cf4baSAlessandro Guido 	[63]	= DEFINE_SC(0x7c),	/* keypad * */
95571cf4baSAlessandro Guido 	[64]	= DEFINE_SC(0x11),	/* <left alt> */
96571cf4baSAlessandro Guido 	[65]	= DEFINE_SC(0x29),	/* <space> */
97571cf4baSAlessandro Guido 
98571cf4baSAlessandro Guido 	[67]	= DEFINE_SC(0x05),	/* <F1> */
99571cf4baSAlessandro Guido 	[68]	= DEFINE_SC(0x06),	/* <F2> */
100571cf4baSAlessandro Guido 	[69]	= DEFINE_SC(0x04),	/* <F3> */
101571cf4baSAlessandro Guido 	[70]	= DEFINE_SC(0x0c),	/* <F4> */
102571cf4baSAlessandro Guido 	[71]	= DEFINE_SC(0x03),	/* <F5> */
103571cf4baSAlessandro Guido 	[72]	= DEFINE_SC(0x0b),	/* <F6> */
104571cf4baSAlessandro Guido 	[73]	= DEFINE_SC(0x83),	/* <F7> */
105571cf4baSAlessandro Guido 	[74]	= DEFINE_SC(0x0a),	/* <F8> */
106571cf4baSAlessandro Guido 	[75]	= DEFINE_SC(0x01),	/* <F9> */
107571cf4baSAlessandro Guido 	[76]	= DEFINE_SC(0x09),	/* <F10> */
108571cf4baSAlessandro Guido 
109571cf4baSAlessandro Guido 	[79]	= DEFINE_SC(0x6c),	/* keypad 7 */
110571cf4baSAlessandro Guido 	[80]	= DEFINE_SC(0x75),	/* keypad 8 */
111571cf4baSAlessandro Guido 	[81]	= DEFINE_SC(0x7d),	/* keypad 9 */
112571cf4baSAlessandro Guido 	[82]	= DEFINE_SC(0x7b),	/* keypad - */
113571cf4baSAlessandro Guido 	[83]	= DEFINE_SC(0x6b),	/* keypad 4 */
114571cf4baSAlessandro Guido 	[84]	= DEFINE_SC(0x73),	/* keypad 5 */
115571cf4baSAlessandro Guido 	[85]	= DEFINE_SC(0x74),	/* keypad 6 */
116571cf4baSAlessandro Guido 	[86]	= DEFINE_SC(0x79),	/* keypad + */
117571cf4baSAlessandro Guido 	[87]	= DEFINE_SC(0x69),	/* keypad 1 */
118571cf4baSAlessandro Guido 	[88]	= DEFINE_SC(0x72),	/* keypad 2 */
119571cf4baSAlessandro Guido 	[89]	= DEFINE_SC(0x7a),	/* keypad 3 */
120571cf4baSAlessandro Guido 	[90]	= DEFINE_SC(0x70),	/* keypad 0 */
121571cf4baSAlessandro Guido 	[91]	= DEFINE_SC(0x71),	/* keypad . */
122571cf4baSAlessandro Guido 
123571cf4baSAlessandro Guido 	[94]	= DEFINE_SC(0x61),	/* <INT 1> */
124571cf4baSAlessandro Guido 	[95]	= DEFINE_SC(0x78),	/* <F11> */
125571cf4baSAlessandro Guido 	[96]	= DEFINE_SC(0x07),	/* <F12> */
126571cf4baSAlessandro Guido 
127571cf4baSAlessandro Guido 	[104]	= DEFINE_ESC(0x5a),	/* keypad <enter> */
128571cf4baSAlessandro Guido 	[105]	= DEFINE_ESC(0x14),	/* <right ctrl> */
129571cf4baSAlessandro Guido 	[106]	= DEFINE_ESC(0x4a),	/* keypad / */
130571cf4baSAlessandro Guido 	[108]	= DEFINE_ESC(0x11),	/* <right alt> */
131571cf4baSAlessandro Guido 	[110]	= DEFINE_ESC(0x6c),	/* <home> */
132571cf4baSAlessandro Guido 	[111]	= DEFINE_ESC(0x75),	/* <up> */
133571cf4baSAlessandro Guido 	[112]	= DEFINE_ESC(0x7d),	/* <pag up> */
134571cf4baSAlessandro Guido 	[113]	= DEFINE_ESC(0x6b),	/* <left> */
135571cf4baSAlessandro Guido 	[114]	= DEFINE_ESC(0x74),	/* <right> */
136571cf4baSAlessandro Guido 	[115]	= DEFINE_ESC(0x69),	/* <end> */
137571cf4baSAlessandro Guido 	[116]	= DEFINE_ESC(0x72),	/* <down> */
138571cf4baSAlessandro Guido 	[117]	= DEFINE_ESC(0x7a),	/* <pag down> */
139571cf4baSAlessandro Guido 	[118]	= DEFINE_ESC(0x70),	/* <ins> */
140571cf4baSAlessandro Guido 	[119]	= DEFINE_ESC(0x71),	/* <delete> */
141571cf4baSAlessandro Guido };
14248d9e01aSSasha Levin static bool running, done;
143571cf4baSAlessandro Guido 
144571cf4baSAlessandro Guido static const struct set2_scancode *to_code(u8 scancode)
145175f8e86SPekka Enberg {
146571cf4baSAlessandro Guido 	return &keymap[scancode];
147571cf4baSAlessandro Guido }
148571cf4baSAlessandro Guido 
149571cf4baSAlessandro Guido static void key_press(const struct set2_scancode *sc)
150571cf4baSAlessandro Guido {
151571cf4baSAlessandro Guido 	switch (sc->type) {
152571cf4baSAlessandro Guido 	case SCANCODE_ESCAPED:
153571cf4baSAlessandro Guido 		kbd_queue(0xe0);
154571cf4baSAlessandro Guido 		/* fallthrough */
155571cf4baSAlessandro Guido 	case SCANCODE_NORMAL:
156571cf4baSAlessandro Guido 		kbd_queue(sc->code);
157571cf4baSAlessandro Guido 		break;
158571cf4baSAlessandro Guido 	case SCANCODE_KEY_PAUSE:
159571cf4baSAlessandro Guido 		kbd_queue(0xe1);
160571cf4baSAlessandro Guido 		kbd_queue(0x14);
161571cf4baSAlessandro Guido 		kbd_queue(0x77);
162571cf4baSAlessandro Guido 		kbd_queue(0xe1);
163571cf4baSAlessandro Guido 		kbd_queue(0xf0);
164571cf4baSAlessandro Guido 		kbd_queue(0x14);
165571cf4baSAlessandro Guido 		kbd_queue(0x77);
166571cf4baSAlessandro Guido 		break;
167571cf4baSAlessandro Guido 	case SCANCODE_KEY_PRNTSCRN:
168571cf4baSAlessandro Guido 		kbd_queue(0xe0);
169571cf4baSAlessandro Guido 		kbd_queue(0x12);
170571cf4baSAlessandro Guido 		kbd_queue(0xe0);
171571cf4baSAlessandro Guido 		kbd_queue(0x7c);
172571cf4baSAlessandro Guido 		break;
173571cf4baSAlessandro Guido 	}
174571cf4baSAlessandro Guido }
175571cf4baSAlessandro Guido 
176571cf4baSAlessandro Guido static void key_release(const struct set2_scancode *sc)
177571cf4baSAlessandro Guido {
178571cf4baSAlessandro Guido 	switch (sc->type) {
179571cf4baSAlessandro Guido 	case SCANCODE_ESCAPED:
180571cf4baSAlessandro Guido 		kbd_queue(0xe0);
181571cf4baSAlessandro Guido 		/* fallthrough */
182571cf4baSAlessandro Guido 	case SCANCODE_NORMAL:
183571cf4baSAlessandro Guido 		kbd_queue(0xf0);
184571cf4baSAlessandro Guido 		kbd_queue(sc->code);
185571cf4baSAlessandro Guido 		break;
186571cf4baSAlessandro Guido 	case SCANCODE_KEY_PAUSE:
187571cf4baSAlessandro Guido 		/* nothing to do */
188571cf4baSAlessandro Guido 		break;
189571cf4baSAlessandro Guido 	case SCANCODE_KEY_PRNTSCRN:
190571cf4baSAlessandro Guido 		kbd_queue(0xe0);
191571cf4baSAlessandro Guido 		kbd_queue(0xf0);
192571cf4baSAlessandro Guido 		kbd_queue(0x7c);
193571cf4baSAlessandro Guido 		kbd_queue(0xe0);
194571cf4baSAlessandro Guido 		kbd_queue(0xf0);
195571cf4baSAlessandro Guido 		kbd_queue(0x12);
196571cf4baSAlessandro Guido 		break;
197571cf4baSAlessandro Guido 	}
198175f8e86SPekka Enberg }
199175f8e86SPekka Enberg 
2003f838fecSPekka Enberg static void *sdl__thread(void *p)
2013f838fecSPekka Enberg {
2023f838fecSPekka Enberg 	Uint32 rmask, gmask, bmask, amask;
2033f838fecSPekka Enberg 	struct framebuffer *fb = p;
2043f838fecSPekka Enberg 	SDL_Surface *guest_screen;
2053f838fecSPekka Enberg 	SDL_Surface *screen;
2063f838fecSPekka Enberg 	SDL_Event ev;
2073f838fecSPekka Enberg 	Uint32 flags;
2083f838fecSPekka Enberg 
2093f838fecSPekka Enberg 	if (SDL_Init(SDL_INIT_VIDEO) != 0)
2103f838fecSPekka Enberg 		die("Unable to initialize SDL");
2113f838fecSPekka Enberg 
2123f838fecSPekka Enberg 	rmask = 0x000000ff;
2133f838fecSPekka Enberg 	gmask = 0x0000ff00;
2143f838fecSPekka Enberg 	bmask = 0x00ff0000;
2153f838fecSPekka Enberg 	amask = 0x00000000;
2163f838fecSPekka Enberg 
2173f838fecSPekka Enberg 	guest_screen = SDL_CreateRGBSurfaceFrom(fb->mem, fb->width, fb->height, fb->depth, fb->width * fb->depth / 8, rmask, gmask, bmask, amask);
2183f838fecSPekka Enberg 	if (!guest_screen)
2193f838fecSPekka Enberg 		die("Unable to create SDL RBG surface");
2203f838fecSPekka Enberg 
221268d0f1bSSasha Levin 	flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_DOUBLEBUF;
2223f838fecSPekka Enberg 
2232a77516bSPekka Enberg 	SDL_WM_SetCaption("KVM tool", "KVM tool");
2242a77516bSPekka Enberg 
2253f838fecSPekka Enberg 	screen = SDL_SetVideoMode(fb->width, fb->height, fb->depth, flags);
2263f838fecSPekka Enberg 	if (!screen)
2273f838fecSPekka Enberg 		die("Unable to set SDL video mode");
2283f838fecSPekka Enberg 
22968770058SLiming Wang 	SDL_EnableKeyRepeat(200, 50);
23068770058SLiming Wang 
23148d9e01aSSasha Levin 	while (running) {
2323f838fecSPekka Enberg 		SDL_BlitSurface(guest_screen, NULL, screen, NULL);
233268d0f1bSSasha Levin 		SDL_Flip(screen);
234175f8e86SPekka Enberg 
2353f838fecSPekka Enberg 		while (SDL_PollEvent(&ev)) {
2363f838fecSPekka Enberg 			switch (ev.type) {
237175f8e86SPekka Enberg 			case SDL_KEYDOWN: {
238571cf4baSAlessandro Guido 				const struct set2_scancode *sc = to_code(ev.key.keysym.scancode);
239571cf4baSAlessandro Guido 				if (sc->type == SCANCODE_UNKNOWN) {
240175f8e86SPekka Enberg 					pr_warning("key '%d' not found in keymap", ev.key.keysym.scancode);
241175f8e86SPekka Enberg 					break;
242175f8e86SPekka Enberg 				}
243571cf4baSAlessandro Guido 				key_press(sc);
244571cf4baSAlessandro Guido 				break;
245175f8e86SPekka Enberg 			}
246571cf4baSAlessandro Guido 			case SDL_KEYUP: {
247571cf4baSAlessandro Guido 				const struct set2_scancode *sc = to_code(ev.key.keysym.scancode);
248571cf4baSAlessandro Guido 				if (sc->type == SCANCODE_UNKNOWN)
249571cf4baSAlessandro Guido 					break;
250571cf4baSAlessandro Guido 				key_release(sc);
251175f8e86SPekka Enberg 				break;
252175f8e86SPekka Enberg 			}
2533f838fecSPekka Enberg 			case SDL_QUIT:
2543f838fecSPekka Enberg 				goto exit;
2553f838fecSPekka Enberg 			}
2563f838fecSPekka Enberg 		}
257175f8e86SPekka Enberg 
2583f838fecSPekka Enberg 		SDL_Delay(1000 / FRAME_RATE);
2593f838fecSPekka Enberg 	}
26048d9e01aSSasha Levin 
26148d9e01aSSasha Levin 	if (running == false && done == false) {
26248d9e01aSSasha Levin 		done = true;
26348d9e01aSSasha Levin 		return NULL;
26448d9e01aSSasha Levin 	}
2653f838fecSPekka Enberg exit:
266df4239fbSSasha Levin 	kvm_cpu__reboot(fb->kvm);
2671c48f5f8SPekka Enberg 
2683f838fecSPekka Enberg 	return NULL;
2693f838fecSPekka Enberg }
2703f838fecSPekka Enberg 
2713f838fecSPekka Enberg static int sdl__start(struct framebuffer *fb)
2723f838fecSPekka Enberg {
2733f838fecSPekka Enberg 	pthread_t thread;
2743f838fecSPekka Enberg 
27548d9e01aSSasha Levin 	running = true;
27648d9e01aSSasha Levin 
2773f838fecSPekka Enberg 	if (pthread_create(&thread, NULL, sdl__thread, fb) != 0)
2783f838fecSPekka Enberg 		return -1;
2793f838fecSPekka Enberg 
2803f838fecSPekka Enberg 	return 0;
2813f838fecSPekka Enberg }
2823f838fecSPekka Enberg 
28348d9e01aSSasha Levin static int sdl__stop(struct framebuffer *fb)
28448d9e01aSSasha Levin {
28548d9e01aSSasha Levin 	running = false;
28648d9e01aSSasha Levin 	while (done == false)
28748d9e01aSSasha Levin 		sleep(0);
28848d9e01aSSasha Levin 
28948d9e01aSSasha Levin 	return 0;
29048d9e01aSSasha Levin }
29148d9e01aSSasha Levin 
2923f838fecSPekka Enberg static struct fb_target_operations sdl_ops = {
2933f838fecSPekka Enberg 	.start	= sdl__start,
2948fbd1187SAsias He 	.stop	= sdl__stop,
2953f838fecSPekka Enberg };
2963f838fecSPekka Enberg 
297*07d52d77SSasha Levin int sdl__init(struct kvm *kvm)
2983f838fecSPekka Enberg {
299*07d52d77SSasha Levin 	struct framebuffer *fb;
300*07d52d77SSasha Levin 
301*07d52d77SSasha Levin 	if (!kvm->cfg.sdl)
302*07d52d77SSasha Levin 		return 0;
303*07d52d77SSasha Levin 
304*07d52d77SSasha Levin 	fb = vesa__init(kvm);
305*07d52d77SSasha Levin 	if (IS_ERR(fb)) {
306*07d52d77SSasha Levin 		pr_err("vesa__init() failed with error %ld\n", PTR_ERR(fb));
307*07d52d77SSasha Levin 		return PTR_ERR(fb);
308*07d52d77SSasha Levin 	}
309*07d52d77SSasha Levin 
31048d9e01aSSasha Levin 	return fb__attach(fb, &sdl_ops);
31148d9e01aSSasha Levin }
31248d9e01aSSasha Levin 
313*07d52d77SSasha Levin int sdl__exit(struct kvm *kvm)
31448d9e01aSSasha Levin {
315*07d52d77SSasha Levin 	return sdl__stop(NULL);
3163f838fecSPekka Enberg }
317