sandbox: Add comments to the sdl struct
[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.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 /**
28  * struct sdl_info - Information about our use of the SDL library
29  *
30  * @screen: Surface used to draw on the screen
31  * @width: Width of simulated LCD display
32  * @height: Height of simulated LCD display
33  * @depth: Depth of the display in bits per pixel (16 or 32)
34  * @pitch: Number of bytes per line of the display
35  * @sample_rate: Current sample rate for audio
36  * @audio_active: true if audio can be used
37  * @inited: true if this module is initialised
38  * @cur_buf: Current audio buffer being used by sandbox_sdl_fill_audio (0 or 1)
39  * @buf: The two available audio buffers. SDL can be reading from one while we
40  *      are setting up the next
41  * @running: true if audio is running
42  */
43 static struct sdl_info {
44         SDL_Surface *screen;
45         int width;
46         int height;
47         int depth;
48         int pitch;
49         uint sample_rate;
50         bool audio_active;
51         bool inited;
52         int cur_buf;
53         struct buf_info buf[2];
54         bool running;
55 } sdl;
56
57 static void sandbox_sdl_poll_events(void)
58 {
59         /*
60          * We don't want to include common.h in this file since it uses
61          * system headers. So add a declation here.
62          */
63         extern void reset_cpu(unsigned long addr);
64         SDL_Event event;
65
66         while (SDL_PollEvent(&event)) {
67                 switch (event.type) {
68                 case SDL_QUIT:
69                         puts("LCD window closed - quitting\n");
70                         reset_cpu(1);
71                         break;
72                 }
73         }
74 }
75
76 static int sandbox_sdl_ensure_init(void)
77 {
78         if (!sdl.inited) {
79                 if (SDL_Init(0) < 0) {
80                         printf("Unable to initialize SDL: %s\n",
81                                SDL_GetError());
82                         return -EIO;
83                 }
84
85                 atexit(SDL_Quit);
86
87                 sdl.inited = true;
88         }
89         return 0;
90 }
91
92 int sandbox_sdl_init_display(int width, int height, int log2_bpp)
93 {
94         struct sandbox_state *state = state_get_current();
95         int err;
96
97         if (!width || !state->show_lcd)
98                 return 0;
99         err = sandbox_sdl_ensure_init();
100         if (err)
101                 return err;
102         if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
103                 printf("Unable to initialize SDL LCD: %s\n", SDL_GetError());
104                 return -EPERM;
105         }
106         SDL_WM_SetCaption("U-Boot", "U-Boot");
107
108         sdl.width = width;
109         sdl.height = height;
110         sdl.depth = 1 << log2_bpp;
111         sdl.pitch = sdl.width * sdl.depth / 8;
112         sdl.screen = SDL_SetVideoMode(width, height, 0, 0);
113         sandbox_sdl_poll_events();
114
115         return 0;
116 }
117
118 int sandbox_sdl_sync(void *lcd_base)
119 {
120         SDL_Surface *frame;
121
122         frame = SDL_CreateRGBSurfaceFrom(lcd_base, sdl.width, sdl.height,
123                         sdl.depth, sdl.pitch,
124                         0x1f << 11, 0x3f << 5, 0x1f << 0, 0);
125         SDL_BlitSurface(frame, NULL, sdl.screen, NULL);
126         SDL_FreeSurface(frame);
127         SDL_UpdateRect(sdl.screen, 0, 0, 0, 0);
128         sandbox_sdl_poll_events();
129
130         return 0;
131 }
132
133 #define NONE (-1)
134 #define NUM_SDL_CODES   (SDLK_UNDO + 1)
135
136 static int16_t sdl_to_keycode[NUM_SDL_CODES] = {
137         /* 0 */
138         NONE, NONE, NONE, NONE, NONE,
139         NONE, NONE, NONE, KEY_BACKSPACE, KEY_TAB,
140         NONE, NONE, NONE, KEY_ENTER, NONE,
141         NONE, NONE, NONE, NONE, KEY_POWER,      /* use PAUSE as POWER */
142
143         /* 20 */
144         NONE, NONE, NONE, NONE, NONE,
145         NONE, NONE, KEY_ESC, NONE, NONE,
146         NONE, NONE, KEY_SPACE, NONE, NONE,
147         NONE, NONE, NONE, NONE, NONE,
148
149         /* 40 */
150         NONE, NONE, NONE, NONE, KEY_COMMA,
151         KEY_MINUS, KEY_DOT, KEY_SLASH, KEY_0, KEY_1,
152         KEY_2, KEY_3, KEY_4, KEY_5, KEY_6,
153         KEY_7, KEY_8, KEY_9, NONE, KEY_SEMICOLON,
154
155         /* 60 */
156         NONE, KEY_EQUAL, NONE, NONE, NONE,
157         NONE, NONE, NONE, NONE, NONE,
158         NONE, NONE, NONE, NONE, NONE,
159         NONE, NONE, NONE, NONE, NONE,
160
161         /* 80 */
162         NONE, NONE, NONE, NONE, NONE,
163         NONE, NONE, NONE, NONE, NONE,
164         NONE, NONE, KEY_BACKSLASH, NONE, NONE,
165         NONE, KEY_GRAVE, KEY_A, KEY_B, KEY_C,
166
167         /* 100 */
168         KEY_D, KEY_E, KEY_F, KEY_G, KEY_H,
169         KEY_I, KEY_J, KEY_K, KEY_L, KEY_M,
170         KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R,
171         KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
172
173         /* 120 */
174         KEY_X, KEY_Y, KEY_Z, NONE, NONE,
175         NONE, NONE, KEY_DELETE, NONE, NONE,
176         NONE, NONE, NONE, NONE, NONE,
177         NONE, NONE, NONE, NONE, NONE,
178
179         /* 140 */
180         NONE, NONE, NONE, NONE, NONE,
181         NONE, NONE, NONE, NONE, NONE,
182         NONE, NONE, NONE, NONE, NONE,
183         NONE, NONE, NONE, NONE, NONE,
184
185         /* 160 */
186         NONE, NONE, NONE, NONE, NONE,
187         NONE, NONE, NONE, NONE, NONE,
188         NONE, NONE, NONE, NONE, NONE,
189         NONE, NONE, NONE, NONE, NONE,
190
191         /* 180 */
192         NONE, NONE, NONE, NONE, NONE,
193         NONE, NONE, NONE, NONE, NONE,
194         NONE, NONE, NONE, NONE, NONE,
195         NONE, NONE, NONE, NONE, NONE,
196
197         /* 200 */
198         NONE, NONE, NONE, NONE, NONE,
199         NONE, NONE, NONE, NONE, NONE,
200         NONE, NONE, NONE, NONE, NONE,
201         NONE, NONE, NONE, NONE, NONE,
202
203         /* 220 */
204         NONE, NONE, NONE, NONE, NONE,
205         NONE, NONE, NONE, NONE, NONE,
206         NONE, NONE, NONE, NONE, NONE,
207         NONE, NONE, NONE, NONE, NONE,
208
209         /* 240 */
210         NONE, NONE, NONE, NONE, NONE,
211         NONE, NONE, NONE, NONE, NONE,
212         NONE, NONE, NONE, NONE, NONE,
213         NONE, KEY_KP0, KEY_KP1, KEY_KP2, KEY_KP3,
214
215         /* 260 */
216         KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8,
217         KEY_KP9, KEY_KPDOT, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS,
218         KEY_KPPLUS, KEY_KPENTER, KEY_KPEQUAL, KEY_UP, KEY_DOWN,
219         KEY_RIGHT, KEY_LEFT, KEY_INSERT, KEY_HOME, KEY_END,
220
221         /* 280 */
222         KEY_PAGEUP, KEY_PAGEDOWN, KEY_F1, KEY_F2, KEY_F3,
223         KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8,
224         KEY_F9, KEY_F10, KEY_F11, KEY_F12, NONE,
225         NONE, NONE, NONE, NONE, NONE,
226
227         /* 300 */
228         KEY_NUMLOCK, KEY_CAPSLOCK, KEY_SCROLLLOCK, KEY_RIGHTSHIFT,
229                 KEY_LEFTSHIFT,
230         KEY_RIGHTCTRL, KEY_LEFTCTRL, KEY_RIGHTALT, KEY_LEFTALT, KEY_RIGHTMETA,
231         KEY_LEFTMETA, NONE, KEY_FN, NONE, KEY_COMPOSE,
232         NONE, KEY_PRINT, KEY_SYSRQ, KEY_PAUSE, NONE,
233
234         /* 320 */
235         NONE, NONE, NONE,
236 };
237
238 int sandbox_sdl_scan_keys(int key[], int max_keys)
239 {
240         Uint8 *keystate;
241         int i, count;
242
243         sandbox_sdl_poll_events();
244         keystate = SDL_GetKeyState(NULL);
245         for (i = count = 0; i < NUM_SDL_CODES; i++) {
246                 if (count >= max_keys)
247                         break;
248                 else if (keystate[i])
249                         key[count++] = sdl_to_keycode[i];
250         }
251
252         return count;
253 }
254
255 int sandbox_sdl_key_pressed(int keycode)
256 {
257         int key[8];     /* allow up to 8 keys to be pressed at once */
258         int count;
259         int i;
260
261         count = sandbox_sdl_scan_keys(key, sizeof(key) / sizeof(key[0]));
262         for (i = 0; i < count; i++) {
263                 if (key[i] == keycode)
264                         return 0;
265         }
266
267         return -ENOENT;
268 }
269
270 void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
271 {
272         struct buf_info *buf;
273         int avail;
274         int i;
275
276         for (i = 0; i < 2; i++) {
277                 buf = &sdl.buf[sdl.cur_buf];
278                 avail = buf->size - buf->pos;
279                 if (avail <= 0) {
280                         sdl.cur_buf = 1 - sdl.cur_buf;
281                         continue;
282                 }
283                 if (avail > len)
284                         avail = len;
285
286                 SDL_MixAudio(stream, buf->data + buf->pos, avail,
287                              SDL_MIX_MAXVOLUME);
288                 buf->pos += avail;
289                 len -= avail;
290
291                 /* Move to next buffer if we are at the end */
292                 if (buf->pos == buf->size)
293                         buf->size = 0;
294                 else
295                         break;
296         }
297 }
298
299 int sandbox_sdl_sound_init(int rate, int channels)
300 {
301         SDL_AudioSpec wanted;
302         int i;
303
304         if (sandbox_sdl_ensure_init())
305                 return -1;
306
307         if (sdl.audio_active)
308                 return 0;
309
310         /* Set the audio format */
311         wanted.freq = rate;
312         wanted.format = AUDIO_S16;
313         wanted.channels = channels;
314         wanted.samples = 1024;  /* Good low-latency value for callback */
315         wanted.callback = sandbox_sdl_fill_audio;
316         wanted.userdata = NULL;
317
318         for (i = 0; i < 2; i++) {
319                 struct buf_info *buf = &sdl.buf[i];
320
321                 buf->alloced = sizeof(uint16_t) * wanted.freq * wanted.channels;
322                 buf->data = malloc(buf->alloced);
323                 if (!buf->data) {
324                         printf("%s: Out of memory\n", __func__);
325                         if (i == 1)
326                                 free(sdl.buf[0].data);
327                         return -1;
328                 }
329                 buf->pos = 0;
330                 buf->size = 0;
331         }
332
333         if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
334                 printf("Unable to initialize SDL audio: %s\n", SDL_GetError());
335                 goto err;
336         }
337
338         /* Open the audio device, forcing the desired format */
339         if (SDL_OpenAudio(&wanted, NULL) < 0) {
340                 printf("Couldn't open audio: %s\n", SDL_GetError());
341                 goto err;
342         }
343         sdl.audio_active = true;
344         sdl.sample_rate = wanted.freq;
345         sdl.cur_buf = 0;
346         sdl.running = 0;
347
348         return 0;
349
350 err:
351         for (i = 0; i < 2; i++)
352                 free(sdl.buf[i].data);
353         return -1;
354 }
355
356 int sandbox_sdl_sound_play(const void *data, uint size)
357 {
358         struct buf_info *buf;
359
360         if (!sdl.audio_active)
361                 return 0;
362
363         buf = &sdl.buf[0];
364         if (buf->size)
365                 buf = &sdl.buf[1];
366         while (buf->size)
367                 usleep(1000);
368
369         if (size > buf->alloced)
370                 return -E2BIG;
371
372         memcpy(buf->data, data, size);
373         buf->size = size;
374         buf->pos = 0;
375         if (!sdl.running) {
376                 SDL_PauseAudio(0);
377                 sdl.running = 1;
378         }
379
380         return 0;
381 }
382
383 int sandbox_sdl_sound_stop(void)
384 {
385         if (sdl.running) {
386                 SDL_PauseAudio(1);
387                 sdl.running = 0;
388         }
389
390         return 0;
391 }