1 /* 2 * Copyright (c) 2013 Google, Inc 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <errno.h> 8 #include <linux/input.h> 9 #include <SDL/SDL.h> 10 #include <sound.h> 11 #include <asm/state.h> 12 13 static struct sdl_info { 14 SDL_Surface *screen; 15 int width; 16 int height; 17 int depth; 18 int pitch; 19 uint frequency; 20 uint audio_pos; 21 uint audio_size; 22 uint8_t *audio_data; 23 bool audio_active; 24 bool inited; 25 } sdl; 26 27 static void sandbox_sdl_poll_events(void) 28 { 29 /* 30 * We don't want to include common.h in this file since it uses 31 * system headers. So add a declation here. 32 */ 33 extern void reset_cpu(unsigned long addr); 34 SDL_Event event; 35 36 while (SDL_PollEvent(&event)) { 37 switch (event.type) { 38 case SDL_QUIT: 39 puts("LCD window closed - quitting\n"); 40 reset_cpu(1); 41 break; 42 } 43 } 44 } 45 46 static int sandbox_sdl_ensure_init(void) 47 { 48 if (!sdl.inited) { 49 if (SDL_Init(0) < 0) { 50 printf("Unable to initialize SDL: %s\n", 51 SDL_GetError()); 52 return -EIO; 53 } 54 55 atexit(SDL_Quit); 56 57 sdl.inited = true; 58 } 59 return 0; 60 } 61 62 int sandbox_sdl_init_display(int width, int height, int log2_bpp) 63 { 64 struct sandbox_state *state = state_get_current(); 65 int err; 66 67 if (!width || !state->show_lcd) 68 return 0; 69 err = sandbox_sdl_ensure_init(); 70 if (err) 71 return err; 72 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { 73 printf("Unable to initialize SDL LCD: %s\n", SDL_GetError()); 74 return -EPERM; 75 } 76 SDL_WM_SetCaption("U-Boot", "U-Boot"); 77 78 sdl.width = width; 79 sdl.height = height; 80 sdl.depth = 1 << log2_bpp; 81 sdl.pitch = sdl.width * sdl.depth / 8; 82 sdl.screen = SDL_SetVideoMode(width, height, 0, 0); 83 sandbox_sdl_poll_events(); 84 85 return 0; 86 } 87 88 int sandbox_sdl_sync(void *lcd_base) 89 { 90 SDL_Surface *frame; 91 92 frame = SDL_CreateRGBSurfaceFrom(lcd_base, sdl.width, sdl.height, 93 sdl.depth, sdl.pitch, 94 0x1f << 11, 0x3f << 5, 0x1f << 0, 0); 95 SDL_BlitSurface(frame, NULL, sdl.screen, NULL); 96 SDL_FreeSurface(frame); 97 SDL_UpdateRect(sdl.screen, 0, 0, 0, 0); 98 sandbox_sdl_poll_events(); 99 100 return 0; 101 } 102 103 #define NONE (-1) 104 #define NUM_SDL_CODES (SDLK_UNDO + 1) 105 106 static int16_t sdl_to_keycode[NUM_SDL_CODES] = { 107 /* 0 */ 108 NONE, NONE, NONE, NONE, NONE, 109 NONE, NONE, NONE, KEY_BACKSPACE, KEY_TAB, 110 NONE, NONE, NONE, KEY_ENTER, NONE, 111 NONE, NONE, NONE, NONE, KEY_POWER, /* use PAUSE as POWER */ 112 113 /* 20 */ 114 NONE, NONE, NONE, NONE, NONE, 115 NONE, NONE, KEY_ESC, NONE, NONE, 116 NONE, NONE, KEY_SPACE, NONE, NONE, 117 NONE, NONE, NONE, NONE, NONE, 118 119 /* 40 */ 120 NONE, NONE, NONE, NONE, KEY_COMMA, 121 KEY_MINUS, KEY_DOT, KEY_SLASH, KEY_0, KEY_1, 122 KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, 123 KEY_7, KEY_8, KEY_9, NONE, KEY_SEMICOLON, 124 125 /* 60 */ 126 NONE, KEY_EQUAL, NONE, NONE, NONE, 127 NONE, NONE, NONE, NONE, NONE, 128 NONE, NONE, NONE, NONE, NONE, 129 NONE, NONE, NONE, NONE, NONE, 130 131 /* 80 */ 132 NONE, NONE, NONE, NONE, NONE, 133 NONE, NONE, NONE, NONE, NONE, 134 NONE, NONE, KEY_BACKSLASH, NONE, NONE, 135 NONE, KEY_GRAVE, KEY_A, KEY_B, KEY_C, 136 137 /* 100 */ 138 KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, 139 KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, 140 KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, 141 KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, 142 143 /* 120 */ 144 KEY_X, KEY_Y, KEY_Z, NONE, NONE, 145 NONE, NONE, KEY_DELETE, NONE, NONE, 146 NONE, NONE, NONE, NONE, NONE, 147 NONE, NONE, NONE, NONE, NONE, 148 149 /* 140 */ 150 NONE, NONE, NONE, NONE, NONE, 151 NONE, NONE, NONE, NONE, NONE, 152 NONE, NONE, NONE, NONE, NONE, 153 NONE, NONE, NONE, NONE, NONE, 154 155 /* 160 */ 156 NONE, NONE, NONE, NONE, NONE, 157 NONE, NONE, NONE, NONE, NONE, 158 NONE, NONE, NONE, NONE, NONE, 159 NONE, NONE, NONE, NONE, NONE, 160 161 /* 180 */ 162 NONE, NONE, NONE, NONE, NONE, 163 NONE, NONE, NONE, NONE, NONE, 164 NONE, NONE, NONE, NONE, NONE, 165 NONE, NONE, NONE, NONE, NONE, 166 167 /* 200 */ 168 NONE, NONE, NONE, NONE, NONE, 169 NONE, NONE, NONE, NONE, NONE, 170 NONE, NONE, NONE, NONE, NONE, 171 NONE, NONE, NONE, NONE, NONE, 172 173 /* 220 */ 174 NONE, NONE, NONE, NONE, NONE, 175 NONE, NONE, NONE, NONE, NONE, 176 NONE, NONE, NONE, NONE, NONE, 177 NONE, NONE, NONE, NONE, NONE, 178 179 /* 240 */ 180 NONE, NONE, NONE, NONE, NONE, 181 NONE, NONE, NONE, NONE, NONE, 182 NONE, NONE, NONE, NONE, NONE, 183 NONE, KEY_KP0, KEY_KP1, KEY_KP2, KEY_KP3, 184 185 /* 260 */ 186 KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8, 187 KEY_KP9, KEY_KPDOT, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, 188 KEY_KPPLUS, KEY_KPENTER, KEY_KPEQUAL, KEY_UP, KEY_DOWN, 189 KEY_RIGHT, KEY_LEFT, KEY_INSERT, KEY_HOME, KEY_END, 190 191 /* 280 */ 192 KEY_PAGEUP, KEY_PAGEDOWN, KEY_F1, KEY_F2, KEY_F3, 193 KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, 194 KEY_F9, KEY_F10, KEY_F11, KEY_F12, NONE, 195 NONE, NONE, NONE, NONE, NONE, 196 197 /* 300 */ 198 KEY_NUMLOCK, KEY_CAPSLOCK, KEY_SCROLLLOCK, KEY_RIGHTSHIFT, 199 KEY_LEFTSHIFT, 200 KEY_RIGHTCTRL, KEY_LEFTCTRL, KEY_RIGHTALT, KEY_LEFTALT, KEY_RIGHTMETA, 201 KEY_LEFTMETA, NONE, KEY_FN, NONE, KEY_COMPOSE, 202 NONE, KEY_PRINT, KEY_SYSRQ, KEY_PAUSE, NONE, 203 204 /* 320 */ 205 NONE, NONE, NONE, 206 }; 207 208 int sandbox_sdl_scan_keys(int key[], int max_keys) 209 { 210 Uint8 *keystate; 211 int i, count; 212 213 sandbox_sdl_poll_events(); 214 keystate = SDL_GetKeyState(NULL); 215 for (i = count = 0; i < NUM_SDL_CODES; i++) { 216 if (count >= max_keys) 217 break; 218 else if (keystate[i]) 219 key[count++] = sdl_to_keycode[i]; 220 } 221 222 return count; 223 } 224 225 int sandbox_sdl_key_pressed(int keycode) 226 { 227 int key[8]; /* allow up to 8 keys to be pressed at once */ 228 int count; 229 int i; 230 231 count = sandbox_sdl_scan_keys(key, sizeof(key) / sizeof(key[0])); 232 for (i = 0; i < count; i++) { 233 if (key[i] == keycode) 234 return 0; 235 } 236 237 return -ENOENT; 238 } 239 240 void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len) 241 { 242 int avail; 243 244 avail = sdl.audio_size - sdl.audio_pos; 245 if (avail < len) 246 len = avail; 247 248 SDL_MixAudio(stream, sdl.audio_data + sdl.audio_pos, len, 249 SDL_MIX_MAXVOLUME); 250 sdl.audio_pos += len; 251 252 /* Loop if we are at the end */ 253 if (sdl.audio_pos == sdl.audio_size) 254 sdl.audio_pos = 0; 255 } 256 257 int sandbox_sdl_sound_init(void) 258 { 259 SDL_AudioSpec wanted; 260 261 if (sandbox_sdl_ensure_init()) 262 return -1; 263 264 if (sdl.audio_active) 265 return 0; 266 267 /* 268 * At present all sandbox sounds crash. This is probably due to 269 * symbol name conflicts with U-Boot. We can remove the malloc() 270 * probles with: 271 * 272 * #define USE_DL_PREFIX 273 * 274 * and get this: 275 * 276 * Assertion 'e->pollfd->fd == e->fd' failed at pulse/mainloop.c:676, 277 * function dispatch_pollfds(). Aborting. 278 * 279 * The right solution is probably to make U-Boot's names private or 280 * link os.c and sdl.c against their libraries before liking with 281 * U-Boot. TBD. For now sound is disabled. 282 */ 283 printf("(Warning: sandbox sound disabled)\n"); 284 return 0; 285 286 /* Set the audio format */ 287 wanted.freq = 22050; 288 wanted.format = AUDIO_S16; 289 wanted.channels = 1; /* 1 = mono, 2 = stereo */ 290 wanted.samples = 1024; /* Good low-latency value for callback */ 291 wanted.callback = sandbox_sdl_fill_audio; 292 wanted.userdata = NULL; 293 294 sdl.audio_size = sizeof(uint16_t) * wanted.freq; 295 sdl.audio_data = malloc(sdl.audio_size); 296 if (!sdl.audio_data) { 297 printf("%s: Out of memory\n", __func__); 298 return -1; 299 } 300 sdl.audio_pos = 0; 301 302 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { 303 printf("Unable to initialize SDL audio: %s\n", SDL_GetError()); 304 goto err; 305 } 306 307 /* Open the audio device, forcing the desired format */ 308 if (SDL_OpenAudio(&wanted, NULL) < 0) { 309 printf("Couldn't open audio: %s\n", SDL_GetError()); 310 goto err; 311 } 312 sdl.audio_active = true; 313 314 return 0; 315 316 err: 317 free(sdl.audio_data); 318 return -1; 319 } 320 321 int sandbox_sdl_sound_start(uint frequency) 322 { 323 if (!sdl.audio_active) 324 return -1; 325 sdl.frequency = frequency; 326 sound_create_square_wave((unsigned short *)sdl.audio_data, 327 sdl.audio_size, frequency); 328 sdl.audio_pos = 0; 329 SDL_PauseAudio(0); 330 331 return 0; 332 } 333 334 int sandbox_sdl_sound_stop(void) 335 { 336 if (!sdl.audio_active) 337 return -1; 338 SDL_PauseAudio(1); 339 340 return 0; 341 } 342