xref: /openbmc/u-boot/arch/sandbox/cpu/sdl.c (revision 286a5c44)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2013 Google, Inc
4  */
5 
6 #include <errno.h>
7 #include <linux/input.h>
8 #include <SDL/SDL.h>
9 #include <sound.h>
10 #include <asm/state.h>
11 
12 enum {
13 	SAMPLE_RATE	= 22050,
14 };
15 
16 static struct sdl_info {
17 	SDL_Surface *screen;
18 	int width;
19 	int height;
20 	int depth;
21 	int pitch;
22 	uint frequency;
23 	uint audio_pos;
24 	uint audio_size;
25 	uint sample_rate;
26 	uint8_t *audio_data;
27 	bool audio_active;
28 	bool inited;
29 } sdl;
30 
31 static void sandbox_sdl_poll_events(void)
32 {
33 	/*
34 	 * We don't want to include common.h in this file since it uses
35 	 * system headers. So add a declation here.
36 	 */
37 	extern void reset_cpu(unsigned long addr);
38 	SDL_Event event;
39 
40 	while (SDL_PollEvent(&event)) {
41 		switch (event.type) {
42 		case SDL_QUIT:
43 			puts("LCD window closed - quitting\n");
44 			reset_cpu(1);
45 			break;
46 		}
47 	}
48 }
49 
50 static int sandbox_sdl_ensure_init(void)
51 {
52 	if (!sdl.inited) {
53 		if (SDL_Init(0) < 0) {
54 			printf("Unable to initialize SDL: %s\n",
55 			       SDL_GetError());
56 			return -EIO;
57 		}
58 
59 		atexit(SDL_Quit);
60 
61 		sdl.inited = true;
62 	}
63 	return 0;
64 }
65 
66 int sandbox_sdl_init_display(int width, int height, int log2_bpp)
67 {
68 	struct sandbox_state *state = state_get_current();
69 	int err;
70 
71 	if (!width || !state->show_lcd)
72 		return 0;
73 	err = sandbox_sdl_ensure_init();
74 	if (err)
75 		return err;
76 	if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
77 		printf("Unable to initialize SDL LCD: %s\n", SDL_GetError());
78 		return -EPERM;
79 	}
80 	SDL_WM_SetCaption("U-Boot", "U-Boot");
81 
82 	sdl.width = width;
83 	sdl.height = height;
84 	sdl.depth = 1 << log2_bpp;
85 	sdl.pitch = sdl.width * sdl.depth / 8;
86 	sdl.screen = SDL_SetVideoMode(width, height, 0, 0);
87 	sandbox_sdl_poll_events();
88 
89 	return 0;
90 }
91 
92 int sandbox_sdl_sync(void *lcd_base)
93 {
94 	SDL_Surface *frame;
95 
96 	frame = SDL_CreateRGBSurfaceFrom(lcd_base, sdl.width, sdl.height,
97 			sdl.depth, sdl.pitch,
98 			0x1f << 11, 0x3f << 5, 0x1f << 0, 0);
99 	SDL_BlitSurface(frame, NULL, sdl.screen, NULL);
100 	SDL_FreeSurface(frame);
101 	SDL_UpdateRect(sdl.screen, 0, 0, 0, 0);
102 	sandbox_sdl_poll_events();
103 
104 	return 0;
105 }
106 
107 #define NONE (-1)
108 #define NUM_SDL_CODES	(SDLK_UNDO + 1)
109 
110 static int16_t sdl_to_keycode[NUM_SDL_CODES] = {
111 	/* 0 */
112 	NONE, NONE, NONE, NONE, NONE,
113 	NONE, NONE, NONE, KEY_BACKSPACE, KEY_TAB,
114 	NONE, NONE, NONE, KEY_ENTER, NONE,
115 	NONE, NONE, NONE, NONE, KEY_POWER,	/* use PAUSE as POWER */
116 
117 	/* 20 */
118 	NONE, NONE, NONE, NONE, NONE,
119 	NONE, NONE, KEY_ESC, NONE, NONE,
120 	NONE, NONE, KEY_SPACE, NONE, NONE,
121 	NONE, NONE, NONE, NONE, NONE,
122 
123 	/* 40 */
124 	NONE, NONE, NONE, NONE, KEY_COMMA,
125 	KEY_MINUS, KEY_DOT, KEY_SLASH, KEY_0, KEY_1,
126 	KEY_2, KEY_3, KEY_4, KEY_5, KEY_6,
127 	KEY_7, KEY_8, KEY_9, NONE, KEY_SEMICOLON,
128 
129 	/* 60 */
130 	NONE, KEY_EQUAL, NONE, NONE, NONE,
131 	NONE, NONE, NONE, NONE, NONE,
132 	NONE, NONE, NONE, NONE, NONE,
133 	NONE, NONE, NONE, NONE, NONE,
134 
135 	/* 80 */
136 	NONE, NONE, NONE, NONE, NONE,
137 	NONE, NONE, NONE, NONE, NONE,
138 	NONE, NONE, KEY_BACKSLASH, NONE, NONE,
139 	NONE, KEY_GRAVE, KEY_A, KEY_B, KEY_C,
140 
141 	/* 100 */
142 	KEY_D, KEY_E, KEY_F, KEY_G, KEY_H,
143 	KEY_I, KEY_J, KEY_K, KEY_L, KEY_M,
144 	KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R,
145 	KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
146 
147 	/* 120 */
148 	KEY_X, KEY_Y, KEY_Z, NONE, NONE,
149 	NONE, NONE, KEY_DELETE, NONE, NONE,
150 	NONE, NONE, NONE, NONE, NONE,
151 	NONE, NONE, NONE, NONE, NONE,
152 
153 	/* 140 */
154 	NONE, NONE, NONE, NONE, NONE,
155 	NONE, NONE, NONE, NONE, NONE,
156 	NONE, NONE, NONE, NONE, NONE,
157 	NONE, NONE, NONE, NONE, NONE,
158 
159 	/* 160 */
160 	NONE, NONE, NONE, NONE, NONE,
161 	NONE, NONE, NONE, NONE, NONE,
162 	NONE, NONE, NONE, NONE, NONE,
163 	NONE, NONE, NONE, NONE, NONE,
164 
165 	/* 180 */
166 	NONE, NONE, NONE, NONE, NONE,
167 	NONE, NONE, NONE, NONE, NONE,
168 	NONE, NONE, NONE, NONE, NONE,
169 	NONE, NONE, NONE, NONE, NONE,
170 
171 	/* 200 */
172 	NONE, NONE, NONE, NONE, NONE,
173 	NONE, NONE, NONE, NONE, NONE,
174 	NONE, NONE, NONE, NONE, NONE,
175 	NONE, NONE, NONE, NONE, NONE,
176 
177 	/* 220 */
178 	NONE, NONE, NONE, NONE, NONE,
179 	NONE, NONE, NONE, NONE, NONE,
180 	NONE, NONE, NONE, NONE, NONE,
181 	NONE, NONE, NONE, NONE, NONE,
182 
183 	/* 240 */
184 	NONE, NONE, NONE, NONE, NONE,
185 	NONE, NONE, NONE, NONE, NONE,
186 	NONE, NONE, NONE, NONE, NONE,
187 	NONE, KEY_KP0, KEY_KP1, KEY_KP2, KEY_KP3,
188 
189 	/* 260 */
190 	KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8,
191 	KEY_KP9, KEY_KPDOT, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS,
192 	KEY_KPPLUS, KEY_KPENTER, KEY_KPEQUAL, KEY_UP, KEY_DOWN,
193 	KEY_RIGHT, KEY_LEFT, KEY_INSERT, KEY_HOME, KEY_END,
194 
195 	/* 280 */
196 	KEY_PAGEUP, KEY_PAGEDOWN, KEY_F1, KEY_F2, KEY_F3,
197 	KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8,
198 	KEY_F9, KEY_F10, KEY_F11, KEY_F12, NONE,
199 	NONE, NONE, NONE, NONE, NONE,
200 
201 	/* 300 */
202 	KEY_NUMLOCK, KEY_CAPSLOCK, KEY_SCROLLLOCK, KEY_RIGHTSHIFT,
203 		KEY_LEFTSHIFT,
204 	KEY_RIGHTCTRL, KEY_LEFTCTRL, KEY_RIGHTALT, KEY_LEFTALT, KEY_RIGHTMETA,
205 	KEY_LEFTMETA, NONE, KEY_FN, NONE, KEY_COMPOSE,
206 	NONE, KEY_PRINT, KEY_SYSRQ, KEY_PAUSE, NONE,
207 
208 	/* 320 */
209 	NONE, NONE, NONE,
210 };
211 
212 int sandbox_sdl_scan_keys(int key[], int max_keys)
213 {
214 	Uint8 *keystate;
215 	int i, count;
216 
217 	sandbox_sdl_poll_events();
218 	keystate = SDL_GetKeyState(NULL);
219 	for (i = count = 0; i < NUM_SDL_CODES; i++) {
220 		if (count >= max_keys)
221 			break;
222 		else if (keystate[i])
223 			key[count++] = sdl_to_keycode[i];
224 	}
225 
226 	return count;
227 }
228 
229 int sandbox_sdl_key_pressed(int keycode)
230 {
231 	int key[8];	/* allow up to 8 keys to be pressed at once */
232 	int count;
233 	int i;
234 
235 	count = sandbox_sdl_scan_keys(key, sizeof(key) / sizeof(key[0]));
236 	for (i = 0; i < count; i++) {
237 		if (key[i] == keycode)
238 			return 0;
239 	}
240 
241 	return -ENOENT;
242 }
243 
244 void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
245 {
246 	int avail;
247 
248 	avail = sdl.audio_size - sdl.audio_pos;
249 	if (avail < len)
250 		len = avail;
251 
252 	SDL_MixAudio(stream, sdl.audio_data + sdl.audio_pos, len,
253 		     SDL_MIX_MAXVOLUME);
254 	sdl.audio_pos += len;
255 
256 	/* Loop if we are at the end */
257 	if (sdl.audio_pos == sdl.audio_size)
258 		sdl.audio_pos = 0;
259 }
260 
261 int sandbox_sdl_sound_init(void)
262 {
263 	SDL_AudioSpec wanted;
264 
265 	if (sandbox_sdl_ensure_init())
266 		return -1;
267 
268 	if (sdl.audio_active)
269 		return 0;
270 
271 	/* Set the audio format */
272 	wanted.freq = SAMPLE_RATE;
273 	wanted.format = AUDIO_S16;
274 	wanted.channels = 1;    /* 1 = mono, 2 = stereo */
275 	wanted.samples = 1024;  /* Good low-latency value for callback */
276 	wanted.callback = sandbox_sdl_fill_audio;
277 	wanted.userdata = NULL;
278 
279 	sdl.audio_size = sizeof(uint16_t) * wanted.freq;
280 	sdl.audio_data = malloc(sdl.audio_size);
281 	if (!sdl.audio_data) {
282 		printf("%s: Out of memory\n", __func__);
283 		return -1;
284 	}
285 	sdl.audio_pos = 0;
286 
287 	if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
288 		printf("Unable to initialize SDL audio: %s\n", SDL_GetError());
289 		goto err;
290 	}
291 
292 	/* Open the audio device, forcing the desired format */
293 	if (SDL_OpenAudio(&wanted, NULL) < 0) {
294 		printf("Couldn't open audio: %s\n", SDL_GetError());
295 		goto err;
296 	}
297 	sdl.audio_active = true;
298 	sdl.sample_rate = wanted.freq;
299 
300 	return 0;
301 
302 err:
303 	free(sdl.audio_data);
304 	return -1;
305 }
306 
307 int sandbox_sdl_sound_start(uint frequency)
308 {
309 	if (!sdl.audio_active)
310 		return -1;
311 	sdl.frequency = frequency;
312 	sound_create_square_wave(sdl.sample_rate,
313 				 (unsigned short *)sdl.audio_data,
314 				 sdl.audio_size, frequency);
315 	sdl.audio_pos = 0;
316 	SDL_PauseAudio(0);
317 
318 	return 0;
319 }
320 
321 int sandbox_sdl_sound_stop(void)
322 {
323 	if (!sdl.audio_active)
324 		return -1;
325 	SDL_PauseAudio(1);
326 
327 	return 0;
328 }
329