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