[U-Boot] [PATCH 30/32] sandbox: Add SDL library for LCD, keyboard, audio

Simon Glass sjg at chromium.org
Sun Nov 10 18:27:16 CET 2013


SDL (Simple DirectMedia Layer - see www.libsdl.org) is a library which
provides simple graphics and sound features. It works under X11 and also
with a simple frame buffer interface. It is ideally suited to sandbox
U-Boot since it fits nicely with the low-level feature set required by
U-Boot. For example, U-Boot has its own font drawing routines, its own
keyboard processing and just needs raw sound output.

We can use SDL to provide emulation of these basic functions for sandbox.
This significantly expands the testing that is possible with sandbox.

Add a basic SDL library which we will use in future commits.

Signed-off-by: Simon Glass <sjg at chromium.org>
Tested-by: Che-Liang Chiou <clchiou at chromium.org>
---
 arch/sandbox/config.mk         |   5 +
 arch/sandbox/cpu/Makefile      |   6 +
 arch/sandbox/cpu/sdl.c         | 332 +++++++++++++++++++++++++++++++++++++++++
 arch/sandbox/include/asm/sdl.h |  20 +++
 4 files changed, 363 insertions(+)
 create mode 100644 arch/sandbox/cpu/sdl.c
 create mode 100644 arch/sandbox/include/asm/sdl.h

diff --git a/arch/sandbox/config.mk b/arch/sandbox/config.mk
index 60b7262..01fe1fe 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 58c2537..f8b4345 100644
--- a/arch/sandbox/cpu/Makefile
+++ b/arch/sandbox/cpu/Makefile
@@ -8,9 +8,15 @@
 #
 
 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
 $(obj)os.o: ALL_CFLAGS := $(BASE_CPPFLAGS) \
 	$(patsubst %, -idirafter %, $(BASE_INCLUDE_DIRS))
 $(obj).depend.os: CPPFLAGS := $(BASE_CPPFLAGS) \
 	$(patsubst %, -idirafter %, $(BASE_INCLUDE_DIRS))
+
+$(obj)sdl.o: ALL_CFLAGS := $(BASE_CPPFLAGS) \
+	$(patsubst %, -idirafter %, $(BASE_INCLUDE_DIRS))
+$(obj).depend.sdl: CPPFLAGS := $(BASE_CPPFLAGS) \
+	$(patsubst %, -idirafter %, $(BASE_INCLUDE_DIRS))
diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c
new file mode 100644
index 0000000..909e835
--- /dev/null
+++ b/arch/sandbox/cpu/sdl.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#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)
+{
+	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 -1;
+		}
+
+		atexit(SDL_Quit);
+
+		sdl.inited = true;
+	}
+	return 0;
+}
+
+int sandbox_sdl_init_display(int width, int height, int log2_bpp)
+{
+	if (!width)
+		return 0;
+	if (sandbox_sdl_ensure_init())
+		return -1;
+	if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
+		printf("Unable to initialize SDL LCD: %s\n", SDL_GetError());
+		return -1;
+	}
+	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;
+	SDL_Event event;
+
+	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 1;
+	}
+
+	return 0;
+}
+
+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..b9cdb0b
--- /dev/null
+++ b/arch/sandbox/include/asm/sdl.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __SANDBOX_SDL_H
+#define __SANDBOX_SDL_H
+
+int sandbox_sdl_init_display(int width, int height, int log2_bpp);
+int sandbox_sdl_sync(void *lcd_base);
+
+int sandbox_sdl_scan_keys(int key[], int max_keys);
+int sandbox_sdl_key_pressed(int keycode);
+
+int sandbox_sdl_sound_start(uint frequency);
+int sandbox_sdl_sound_stop(void);
+int sandbox_sdl_sound_init(void);
+
+#endif
-- 
1.8.4.1



More information about the U-Boot mailing list