]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
bbc09bf2 SG |
2 | /* |
3 | * Copyright (c) 2013 Google, Inc | |
bbc09bf2 SG |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | } |