summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sandbox/config.mk5
-rw-r--r--arch/sandbox/cpu/Makefile3
-rw-r--r--arch/sandbox/cpu/sdl.c341
-rw-r--r--arch/sandbox/include/asm/sdl.h118
4 files changed, 467 insertions, 0 deletions
diff --git a/arch/sandbox/config.mk b/arch/sandbox/config.mk
index 668aa71..e094ae2 100644
--- a/arch/sandbox/config.mk
+++ b/arch/sandbox/config.mk
@@ -5,6 +5,11 @@ PLATFORM_CPPFLAGS += -DCONFIG_SANDBOX -D__SANDBOX__ -U_FORTIFY_SOURCE
PLATFORM_CPPFLAGS += -DCONFIG_ARCH_MAP_SYSMEM -DCONFIG_SYS_GENERIC_BOARD
PLATFORM_LIBS += -lrt
+ifdef CONFIG_SANDBOX_SDL
+PLATFORM_LIBS += $(shell sdl-config --libs)
+PLATFORM_CPPFLAGS += $(shell sdl-config --cflags)
+endif
+
# Support generic board on sandbox
__HAVE_ARCH_GENERIC_BOARD := y
diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile
index 63deded..7d4410c 100644
--- a/arch/sandbox/cpu/Makefile
+++ b/arch/sandbox/cpu/Makefile
@@ -8,6 +8,7 @@
#
obj-y := cpu.o os.o start.o state.o
+obj-$(CONFIG_SANDBOX_SDL) += sdl.o
# os.c is build in the system environment, so needs standard includes
# CFLAGS_REMOVE_os.o cannot be used to drop header include path
@@ -17,3 +18,5 @@ cmd_cc_os.o = $(CC) $(filter-out -nostdinc, \
$(obj)/os.o: $(src)/os.c FORCE
$(call if_changed_dep,cc_os.o)
+$(obj)/sdl.o: $(src)/sdl.c FORCE
+ $(call if_changed_dep,cc_os.o)
diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c
new file mode 100644
index 0000000..18dc7ed
--- /dev/null
+++ b/arch/sandbox/cpu/sdl.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <errno.h>
+#include <linux/input.h>
+#include <SDL/SDL.h>
+#include <sound.h>
+#include <asm/state.h>
+
+static struct sdl_info {
+ SDL_Surface *screen;
+ int width;
+ int height;
+ int depth;
+ int pitch;
+ uint frequency;
+ uint audio_pos;
+ uint audio_size;
+ uint8_t *audio_data;
+ bool audio_active;
+ bool inited;
+} sdl;
+
+static void sandbox_sdl_poll_events(void)
+{
+ /*
+ * We don't want to include common.h in this file since it uses
+ * system headers. So add a declation here.
+ */
+ extern void reset_cpu(unsigned long addr);
+ SDL_Event event;
+
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_QUIT:
+ puts("LCD window closed - quitting\n");
+ reset_cpu(1);
+ break;
+ }
+ }
+}
+
+static int sandbox_sdl_ensure_init(void)
+{
+ if (!sdl.inited) {
+ if (SDL_Init(0) < 0) {
+ printf("Unable to initialize SDL: %s\n",
+ SDL_GetError());
+ return -EIO;
+ }
+
+ atexit(SDL_Quit);
+
+ sdl.inited = true;
+ }
+ return 0;
+}
+
+int sandbox_sdl_init_display(int width, int height, int log2_bpp)
+{
+ struct sandbox_state *state = state_get_current();
+ int err;
+
+ if (!width || !state->show_lcd)
+ return 0;
+ err = sandbox_sdl_ensure_init();
+ if (err)
+ return err;
+ if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
+ printf("Unable to initialize SDL LCD: %s\n", SDL_GetError());
+ return -EPERM;
+ }
+ SDL_WM_SetCaption("U-Boot", "U-Boot");
+
+ sdl.width = width;
+ sdl.height = height;
+ sdl.depth = 1 << log2_bpp;
+ sdl.pitch = sdl.width * sdl.depth / 8;
+ sdl.screen = SDL_SetVideoMode(width, height, 0, 0);
+ sandbox_sdl_poll_events();
+
+ return 0;
+}
+
+int sandbox_sdl_sync(void *lcd_base)
+{
+ SDL_Surface *frame;
+
+ frame = SDL_CreateRGBSurfaceFrom(lcd_base, sdl.width, sdl.height,
+ sdl.depth, sdl.pitch,
+ 0x1f << 11, 0x3f << 5, 0x1f << 0, 0);
+ SDL_BlitSurface(frame, NULL, sdl.screen, NULL);
+ SDL_FreeSurface(frame);
+ SDL_UpdateRect(sdl.screen, 0, 0, 0, 0);
+ sandbox_sdl_poll_events();
+
+ return 0;
+}
+
+#define NONE (-1)
+#define NUM_SDL_CODES (SDLK_UNDO + 1)
+
+static int16_t sdl_to_keycode[NUM_SDL_CODES] = {
+ /* 0 */
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, KEY_BACKSPACE, KEY_TAB,
+ NONE, NONE, NONE, KEY_ENTER, NONE,
+ NONE, NONE, NONE, NONE, KEY_POWER, /* use PAUSE as POWER */
+
+ /* 20 */
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, KEY_ESC, NONE, NONE,
+ NONE, NONE, KEY_SPACE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+
+ /* 40 */
+ NONE, NONE, NONE, NONE, KEY_COMMA,
+ KEY_MINUS, KEY_DOT, KEY_SLASH, KEY_0, KEY_1,
+ KEY_2, KEY_3, KEY_4, KEY_5, KEY_6,
+ KEY_7, KEY_8, KEY_9, NONE, KEY_SEMICOLON,
+
+ /* 60 */
+ NONE, KEY_EQUAL, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+
+ /* 80 */
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, KEY_BACKSLASH, NONE, NONE,
+ NONE, KEY_GRAVE, KEY_A, KEY_B, KEY_C,
+
+ /* 100 */
+ KEY_D, KEY_E, KEY_F, KEY_G, KEY_H,
+ KEY_I, KEY_J, KEY_K, KEY_L, KEY_M,
+ KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R,
+ KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
+
+ /* 120 */
+ KEY_X, KEY_Y, KEY_Z, NONE, NONE,
+ NONE, NONE, KEY_DELETE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+
+ /* 140 */
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+
+ /* 160 */
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+
+ /* 180 */
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+
+ /* 200 */
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+
+ /* 220 */
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+
+ /* 240 */
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+ NONE, KEY_KP0, KEY_KP1, KEY_KP2, KEY_KP3,
+
+ /* 260 */
+ KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8,
+ KEY_KP9, KEY_KPDOT, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS,
+ KEY_KPPLUS, KEY_KPENTER, KEY_KPEQUAL, KEY_UP, KEY_DOWN,
+ KEY_RIGHT, KEY_LEFT, KEY_INSERT, KEY_HOME, KEY_END,
+
+ /* 280 */
+ KEY_PAGEUP, KEY_PAGEDOWN, KEY_F1, KEY_F2, KEY_F3,
+ KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8,
+ KEY_F9, KEY_F10, KEY_F11, KEY_F12, NONE,
+ NONE, NONE, NONE, NONE, NONE,
+
+ /* 300 */
+ KEY_NUMLOCK, KEY_CAPSLOCK, KEY_SCROLLLOCK, KEY_RIGHTSHIFT,
+ KEY_LEFTSHIFT,
+ KEY_RIGHTCTRL, KEY_LEFTCTRL, KEY_RIGHTALT, KEY_LEFTALT, KEY_RIGHTMETA,
+ KEY_LEFTMETA, NONE, KEY_FN, NONE, KEY_COMPOSE,
+ NONE, KEY_PRINT, KEY_SYSRQ, KEY_PAUSE, NONE,
+
+ /* 320 */
+ NONE, NONE, NONE,
+};
+
+int sandbox_sdl_scan_keys(int key[], int max_keys)
+{
+ Uint8 *keystate;
+ int i, count;
+
+ sandbox_sdl_poll_events();
+ keystate = SDL_GetKeyState(NULL);
+ for (i = count = 0; i < NUM_SDL_CODES; i++) {
+ if (count >= max_keys)
+ break;
+ else if (keystate[i])
+ key[count++] = sdl_to_keycode[i];
+ }
+
+ return count;
+}
+
+int sandbox_sdl_key_pressed(int keycode)
+{
+ int key[8]; /* allow up to 8 keys to be pressed at once */
+ int count;
+ int i;
+
+ count = sandbox_sdl_scan_keys(key, sizeof(key) / sizeof(key[0]));
+ for (i = 0; i < count; i++) {
+ if (key[i] == keycode)
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
+{
+ int avail;
+
+ avail = sdl.audio_size - sdl.audio_pos;
+ if (avail < len)
+ len = avail;
+
+ SDL_MixAudio(stream, sdl.audio_data + sdl.audio_pos, len,
+ SDL_MIX_MAXVOLUME);
+ sdl.audio_pos += len;
+
+ /* Loop if we are at the end */
+ if (sdl.audio_pos == sdl.audio_size)
+ sdl.audio_pos = 0;
+}
+
+int sandbox_sdl_sound_init(void)
+{
+ SDL_AudioSpec wanted;
+
+ if (sandbox_sdl_ensure_init())
+ return -1;
+
+ if (sdl.audio_active)
+ return 0;
+
+ /*
+ * At present all sandbox sounds crash. This is probably due to
+ * symbol name conflicts with U-Boot. We can remove the malloc()
+ * probles with:
+ *
+ * #define USE_DL_PREFIX
+ *
+ * and get this:
+ *
+ * Assertion 'e->pollfd->fd == e->fd' failed at pulse/mainloop.c:676,
+ * function dispatch_pollfds(). Aborting.
+ *
+ * The right solution is probably to make U-Boot's names private or
+ * link os.c and sdl.c against their libraries before liking with
+ * U-Boot. TBD. For now sound is disabled.
+ */
+ printf("(Warning: sandbox sound disabled)\n");
+ return 0;
+
+ /* Set the audio format */
+ wanted.freq = 22050;
+ wanted.format = AUDIO_S16;
+ wanted.channels = 1; /* 1 = mono, 2 = stereo */
+ wanted.samples = 1024; /* Good low-latency value for callback */
+ wanted.callback = sandbox_sdl_fill_audio;
+ wanted.userdata = NULL;
+
+ sdl.audio_size = sizeof(uint16_t) * wanted.freq;
+ sdl.audio_data = malloc(sdl.audio_size);
+ if (!sdl.audio_data) {
+ printf("%s: Out of memory\n", __func__);
+ return -1;
+ }
+ sdl.audio_pos = 0;
+
+ if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
+ printf("Unable to initialize SDL audio: %s\n", SDL_GetError());
+ goto err;
+ }
+
+ /* Open the audio device, forcing the desired format */
+ if (SDL_OpenAudio(&wanted, NULL) < 0) {
+ printf("Couldn't open audio: %s\n", SDL_GetError());
+ goto err;
+ }
+ sdl.audio_active = true;
+
+ return 0;
+
+err:
+ free(sdl.audio_data);
+ return -1;
+}
+
+int sandbox_sdl_sound_start(uint frequency)
+{
+ if (!sdl.audio_active)
+ return -1;
+ sdl.frequency = frequency;
+ sound_create_square_wave((unsigned short *)sdl.audio_data,
+ sdl.audio_size, frequency);
+ sdl.audio_pos = 0;
+ SDL_PauseAudio(0);
+
+ return 0;
+}
+
+int sandbox_sdl_sound_stop(void)
+{
+ if (!sdl.audio_active)
+ return -1;
+ SDL_PauseAudio(1);
+
+ return 0;
+}
diff --git a/arch/sandbox/include/asm/sdl.h b/arch/sandbox/include/asm/sdl.h
new file mode 100644
index 0000000..6edec1a
--- /dev/null
+++ b/arch/sandbox/include/asm/sdl.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __SANDBOX_SDL_H
+#define __SANDBOX_SDL_H
+
+#include <errno.h>
+
+#ifdef CONFIG_SANDBOX_SDL
+
+/**
+ * sandbox_sdl_init_display() - Set up SDL video ready for use
+ *
+ * @width: Window width in pixels
+ * @height Window height in pixels
+ * @log2_bpp: Log to base 2 of the number of bits per pixel. So a 32bpp
+ * display will pass 5, since 2*5 = 32
+ * @return 0 if OK, -ENODEV if no device, -EIO if SDL failed to initialize
+ * and -EPERM if the video failed to come up.
+ */
+int sandbox_sdl_init_display(int width, int height, int log2_bpp);
+
+/**
+ * sandbox_sdl_sync() - Sync current U-Boot LCD frame buffer to SDL
+ *
+ * This must be called periodically to update the screen for SDL so that the
+ * user can see it.
+ *
+ * @lcd_base: Base of frame buffer
+ * @return 0 if screen was updated, -ENODEV is there is no screen.
+ */
+int sandbox_sdl_sync(void *lcd_base);
+
+/**
+ * sandbox_sdl_scan_keys() - scan for pressed keys
+ *
+ * Works out which keys are pressed and returns a list
+ *
+ * @key: Array to receive keycodes
+ * @max_keys: Size of array
+ * @return number of keycodes found, 0 if none, -ENODEV if no keyboard
+ */
+int sandbox_sdl_scan_keys(int key[], int max_keys);
+
+/**
+ * sandbox_sdl_key_pressed() - check if a particular key is pressed
+ *
+ * @keycode: Keycode to check (KEY_... - see include/linux/input.h
+ * @return 0 if pressed, -ENOENT if not pressed. -ENODEV if keybord not
+ * available,
+ */
+int sandbox_sdl_key_pressed(int keycode);
+
+/**
+ * sandbox_sdl_sound_start() - start playing a sound
+ *
+ * @frequency: Frequency of sounds in Hertz
+ * @return 0 if OK, -ENODEV if no sound is available
+ */
+int sandbox_sdl_sound_start(uint frequency);
+
+/**
+ * sandbox_sdl_sound_stop() - stop playing a sound
+ *
+ * @return 0 if OK, -ENODEV if no sound is available
+ */
+int sandbox_sdl_sound_stop(void);
+
+/**
+ * sandbox_sdl_sound_init() - set up the sound system
+ *
+ * @return 0 if OK, -ENODEV if no sound is available
+ */
+int sandbox_sdl_sound_init(void);
+
+#else
+static inline int sandbox_sdl_init_display(int width, int height,
+ int log2_bpp)
+{
+ return -ENODEV;
+}
+
+static inline int sandbox_sdl_sync(void *lcd_base)
+{
+ return -ENODEV;
+}
+
+static inline int sandbox_sdl_scan_keys(int key[], int max_keys)
+{
+ return -ENODEV;
+}
+
+static inline int sandbox_sdl_key_pressed(int keycode)
+{
+ return -ENODEV;
+}
+
+static inline int sandbox_sdl_sound_start(uint frequency)
+{
+ return -ENODEV;
+}
+
+static inline int sandbox_sdl_sound_stop(void)
+{
+ return -ENODEV;
+}
+
+static inline int sandbox_sdl_sound_init(void)
+{
+ return -ENODEV;
+}
+
+#endif
+
+#endif