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