Merge branch 'master' of git://git.denx.de/u-boot-spi
[platform/kernel/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 <linux/input.h>
8 #include <SDL/SDL.h>
9 #include <sound.h>
10 #include <asm/state.h>
11
12 enum {
13         SAMPLE_RATE     = 22050,
14 };
15
16 static 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;
25         uint sample_rate;
26         uint8_t *audio_data;
27         bool audio_active;
28         bool inited;
29 } sdl;
30
31 static 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
50 static 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
66 int 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
92 int 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
110 static 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
212 int 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
229 int 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
244 void 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
261 int 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
271         /* Set the audio format */
272         wanted.freq = SAMPLE_RATE;
273         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;
298         sdl.sample_rate = wanted.freq;
299
300         return 0;
301
302 err:
303         free(sdl.audio_data);
304         return -1;
305 }
306
307 int sandbox_sdl_sound_start(uint frequency)
308 {
309         if (!sdl.audio_active)
310                 return -1;
311         sdl.frequency = frequency;
312         sound_create_square_wave(sdl.sample_rate,
313                                  (unsigned short *)sdl.audio_data,
314                                  sdl.audio_size, frequency);
315         sdl.audio_pos = 0;
316         SDL_PauseAudio(0);
317
318         return 0;
319 }
320
321 int sandbox_sdl_sound_stop(void)
322 {
323         if (!sdl.audio_active)
324                 return -1;
325         SDL_PauseAudio(1);
326
327         return 0;
328 }