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 } 329