]> git.sur5r.net Git - u-boot/blob - arch/sandbox/cpu/sdl.c
SPDX: Convert all of our single license tags to Linux Kernel style
[u-boot] / 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 <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 }