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