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