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