blob: 080c7c8d74d21dcf892e8aec7748823cf350f9ed [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass0d10f292014-02-27 13:26:17 -07002/*
3 * Copyright (c) 2013 Google, Inc
Simon Glass0d10f292014-02-27 13:26:17 -07004 */
5
6#include <errno.h>
Simon Glass3e610172018-12-10 10:37:45 -07007#include <unistd.h>
Simon Glass0d10f292014-02-27 13:26:17 -07008#include <linux/input.h>
Simon Glass0948af22018-12-17 09:12:16 -07009#include <SDL.h>
Simon Glass0d10f292014-02-27 13:26:17 -070010#include <asm/state.h>
11
Simon Glass0d22f412018-12-10 10:37:35 -070012/**
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 */
20struct buf_info {
21 uint pos;
22 uint size;
23 uint alloced;
24 uint8_t *data;
25};
26
Simon Glass0d10f292014-02-27 13:26:17 -070027static struct sdl_info {
28 SDL_Surface *screen;
29 int width;
30 int height;
31 int depth;
32 int pitch;
33 uint frequency;
Simon Glass0d7e6812018-11-15 19:56:14 -070034 uint sample_rate;
Simon Glass0d10f292014-02-27 13:26:17 -070035 bool audio_active;
36 bool inited;
Simon Glass0d22f412018-12-10 10:37:35 -070037 int cur_buf;
38 struct buf_info buf[2];
Simon Glass3e610172018-12-10 10:37:45 -070039 bool running;
Simon Glass0d10f292014-02-27 13:26:17 -070040} sdl;
41
42static 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
61static 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
77int 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
103int 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
121static 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
223int 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
240int 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
255void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
256{
Simon Glass0d22f412018-12-10 10:37:35 -0700257 struct buf_info *buf;
Simon Glass0d10f292014-02-27 13:26:17 -0700258 int avail;
Simon Glass0d22f412018-12-10 10:37:35 -0700259 int i;
Simon Glass0d10f292014-02-27 13:26:17 -0700260
Simon Glass0d22f412018-12-10 10:37:35 -0700261 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;
Simon Glass0d10f292014-02-27 13:26:17 -0700270
Simon Glass0d22f412018-12-10 10:37:35 -0700271 SDL_MixAudio(stream, buf->data + buf->pos, avail,
272 SDL_MIX_MAXVOLUME);
273 buf->pos += avail;
274 len -= avail;
Simon Glass0d10f292014-02-27 13:26:17 -0700275
Simon Glass0d22f412018-12-10 10:37:35 -0700276 /* 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 }
Simon Glass0d10f292014-02-27 13:26:17 -0700282}
283
Simon Glass658a8742018-12-10 10:37:50 -0700284int sandbox_sdl_sound_init(int rate, int channels)
Simon Glass0d10f292014-02-27 13:26:17 -0700285{
286 SDL_AudioSpec wanted;
Simon Glass0d22f412018-12-10 10:37:35 -0700287 int i;
Simon Glass0d10f292014-02-27 13:26:17 -0700288
289 if (sandbox_sdl_ensure_init())
290 return -1;
291
292 if (sdl.audio_active)
293 return 0;
294
Simon Glass0d10f292014-02-27 13:26:17 -0700295 /* Set the audio format */
Simon Glass658a8742018-12-10 10:37:50 -0700296 wanted.freq = rate;
Simon Glass0d10f292014-02-27 13:26:17 -0700297 wanted.format = AUDIO_S16;
Simon Glass658a8742018-12-10 10:37:50 -0700298 wanted.channels = channels;
Simon Glass0d10f292014-02-27 13:26:17 -0700299 wanted.samples = 1024; /* Good low-latency value for callback */
300 wanted.callback = sandbox_sdl_fill_audio;
301 wanted.userdata = NULL;
302
Simon Glass0d22f412018-12-10 10:37:35 -0700303 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;
Simon Glass0d10f292014-02-27 13:26:17 -0700316 }
Simon Glass0d10f292014-02-27 13:26:17 -0700317
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;
Simon Glass0d7e6812018-11-15 19:56:14 -0700329 sdl.sample_rate = wanted.freq;
Simon Glass0d22f412018-12-10 10:37:35 -0700330 sdl.cur_buf = 0;
Simon Glass3e610172018-12-10 10:37:45 -0700331 sdl.running = 0;
Simon Glass0d10f292014-02-27 13:26:17 -0700332
333 return 0;
334
335err:
Simon Glass0d22f412018-12-10 10:37:35 -0700336 for (i = 0; i < 2; i++)
337 free(sdl.buf[i].data);
Simon Glass0d10f292014-02-27 13:26:17 -0700338 return -1;
339}
340
Simon Glass3e610172018-12-10 10:37:45 -0700341int sandbox_sdl_sound_play(const void *data, uint size)
Simon Glass0d10f292014-02-27 13:26:17 -0700342{
Simon Glass3e610172018-12-10 10:37:45 -0700343 struct buf_info *buf;
Simon Glass0d22f412018-12-10 10:37:35 -0700344
Simon Glass0d10f292014-02-27 13:26:17 -0700345 if (!sdl.audio_active)
Simon Glass3e610172018-12-10 10:37:45 -0700346 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;
Simon Glass0d22f412018-12-10 10:37:35 -0700359 buf->pos = 0;
Simon Glass3e610172018-12-10 10:37:45 -0700360 if (!sdl.running) {
361 SDL_PauseAudio(0);
362 sdl.running = 1;
363 }
Simon Glass0d10f292014-02-27 13:26:17 -0700364
365 return 0;
366}
367
368int sandbox_sdl_sound_stop(void)
369{
Simon Glass3e610172018-12-10 10:37:45 -0700370 if (sdl.running) {
371 SDL_PauseAudio(1);
372 sdl.running = 0;
373 }
Simon Glass0d10f292014-02-27 13:26:17 -0700374
375 return 0;
376}