Merge tag 'u-boot-imx-20190101' of git://www.denx.de/git/u-boot-imx
[oweals/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 <asm/state.h>
11
12 /**
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  */
20 struct buf_info {
21         uint pos;
22         uint size;
23         uint alloced;
24         uint8_t *data;
25 };
26
27 static struct sdl_info {
28         SDL_Surface *screen;
29         int width;
30         int height;
31         int depth;
32         int pitch;
33         uint frequency;
34         uint sample_rate;
35         bool audio_active;
36         bool inited;
37         int cur_buf;
38         struct buf_info buf[2];
39         bool running;
40 } sdl;
41
42 static 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
61 static 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
77 int 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
103 int 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
121 static 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
223 int 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
240 int 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
255 void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
256 {
257         struct buf_info *buf;
258         int avail;
259         int i;
260
261         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;
270
271                 SDL_MixAudio(stream, buf->data + buf->pos, avail,
272                              SDL_MIX_MAXVOLUME);
273                 buf->pos += avail;
274                 len -= avail;
275
276                 /* 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         }
282 }
283
284 int sandbox_sdl_sound_init(int rate, int channels)
285 {
286         SDL_AudioSpec wanted;
287         int i;
288
289         if (sandbox_sdl_ensure_init())
290                 return -1;
291
292         if (sdl.audio_active)
293                 return 0;
294
295         /* Set the audio format */
296         wanted.freq = rate;
297         wanted.format = AUDIO_S16;
298         wanted.channels = channels;
299         wanted.samples = 1024;  /* Good low-latency value for callback */
300         wanted.callback = sandbox_sdl_fill_audio;
301         wanted.userdata = NULL;
302
303         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;
316         }
317
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;
329         sdl.sample_rate = wanted.freq;
330         sdl.cur_buf = 0;
331         sdl.running = 0;
332
333         return 0;
334
335 err:
336         for (i = 0; i < 2; i++)
337                 free(sdl.buf[i].data);
338         return -1;
339 }
340
341 int sandbox_sdl_sound_play(const void *data, uint size)
342 {
343         struct buf_info *buf;
344
345         if (!sdl.audio_active)
346                 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;
359         buf->pos = 0;
360         if (!sdl.running) {
361                 SDL_PauseAudio(0);
362                 sdl.running = 1;
363         }
364
365         return 0;
366 }
367
368 int sandbox_sdl_sound_stop(void)
369 {
370         if (sdl.running) {
371                 SDL_PauseAudio(1);
372                 sdl.running = 0;
373         }
374
375         return 0;
376 }