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