diff --git a/lib/import/import-sdl.mk b/lib/import/import-sdl.mk
new file mode 100644
index 0000000..4c7fce0
--- /dev/null
+++ b/lib/import/import-sdl.mk
@@ -0,0 +1,4 @@
+SDL_PORT_DIR := $(call select_from_ports,sdl)
+
+INC_DIR += $(SDL_PORT_DIR)/include $(SDL_PORT_DIR)/include/SDL
+REP_INC_DIR += include/SDL
diff --git a/lib/import/import-sdl_image.mk b/lib/import/import-sdl_image.mk
new file mode 100644
index 0000000..de52755
--- /dev/null
+++ b/lib/import/import-sdl_image.mk
@@ -0,0 +1,2 @@
+INC_DIR += $(call select_from_ports,sdl_image)/include \
+ $(call select_from_ports,sdl_image)/include/SDL
diff --git a/lib/import/import-sdl_mixer.mk b/lib/import/import-sdl_mixer.mk
new file mode 100644
index 0000000..287e9b9
--- /dev/null
+++ b/lib/import/import-sdl_mixer.mk
@@ -0,0 +1,2 @@
+SDL_MIXER_PORT_DIR := $(call select_from_ports,sdl_mixer)
+INC_DIR += $(SDL_MIXER_PORT_DIR)/include $(SDL_MIXER_PORT_DIR)/include/SDL
diff --git a/lib/import/import-sdl_net.mk b/lib/import/import-sdl_net.mk
new file mode 100644
index 0000000..b73d3f4
--- /dev/null
+++ b/lib/import/import-sdl_net.mk
@@ -0,0 +1,2 @@
+SDL_NET_PORT_DIR := $(call select_from_ports,sdl_net)
+INC_DIR += $(SDL_NET_PORT_DIR)/include $(SDL_NET_PORT_DIR)/include/SDL
diff --git a/lib/import/import-sdl_ttf.mk b/lib/import/import-sdl_ttf.mk
new file mode 100644
index 0000000..697336b
--- /dev/null
+++ b/lib/import/import-sdl_ttf.mk
@@ -0,0 +1 @@
+INC_DIR += $(call select_from_ports,sdl_ttf)/include
diff --git a/lib/mk/sdl.mk b/lib/mk/sdl.mk
new file mode 100644
index 0000000..fce3297
--- /dev/null
+++ b/lib/mk/sdl.mk
@@ -0,0 +1,92 @@
+SDL_PORT_DIR := $(call select_from_ports,sdl)
+SDL_DIR := $(SDL_PORT_DIR)/src/lib/sdl
+
+# build shared object
+SHARED_LIB = yes
+
+# use default warning level for 3rd-party code
+CC_WARN =
+
+INC_DIR += $(SDL_PORT_DIR)/include
+INC_DIR += $(SDL_PORT_DIR)/include/SDL
+
+#
+# In case we use the depot add the location
+# to the global include path.
+#
+ifeq ($(CONTRIB),)
+REP_INC_DIR += include/SDL
+endif
+
+# backends
+SRC_CC = video/SDL_genode_fb_video.cc \
+ video/SDL_genode_fb_events.cc \
+ audio/SDL_genodeaudio.cc \
+ loadso/SDL_loadso.cc
+
+INC_DIR += $(REP_DIR)/include/SDL \
+ $(REP_DIR)/src/lib/sdl \
+ $(REP_DIR)/src/lib/sdl/thread \
+ $(REP_DIR)/src/lib/sdl/video
+
+# main files
+SRC_C = SDL.c \
+ SDL_error.c \
+ SDL_fatal.c
+
+INC_DIR += $(REP_DIR)/src/lib/sdl
+
+# stdlib files
+SRC_C += stdlib/SDL_getenv.c \
+ stdlib/SDL_string.h
+
+# thread subsystem
+SRC_C += thread/SDL_thread.c \
+ thread/pthread/SDL_systhread.c \
+ thread/generic/SDL_syscond.c \
+ thread/generic/SDL_sysmutex.c \
+ thread/pthread/SDL_syssem.c
+INC_DIR += $(SDL_DIR)/src/thread
+
+# cpuinfo subsystem
+SRC_C += cpuinfo/SDL_cpuinfo.c
+
+# timer subsystem
+SRC_C += timer/SDL_timer.c \
+ timer/unix/SDL_systimer.c
+INC_DIR += $(SDL_DIR)/src/timer
+
+# video subsystem
+SRC_C += $(addprefix video/,$(notdir $(wildcard $(SDL_DIR)/src/video/*.c)))
+INC_DIR += $(SDL_DIR)/src/video
+
+# event subsystem
+SRC_C += $(addprefix events/,$(notdir $(wildcard $(SDL_DIR)/src/events/*.c)))
+INC_DIR += $(SDL_DIR)/src/events
+
+# audio subsystem
+SRC_C += $(addprefix audio/,$(notdir $(wildcard $(SDL_DIR)/src/audio/*.c)))
+INC_DIR += $(SDL_DIR)/src/audio
+
+# file I/O subsystem
+SRC_C += file/SDL_rwops.c
+
+# joystick subsystem
+SRC_C += joystick/SDL_joystick.c \
+ joystick/dummy/SDL_sysjoystick.c
+INC_DIR += $(SDL_DIR)/src/joystick
+
+# cdrom subsystem
+SRC_C += cdrom/SDL_cdrom.c \
+ cdrom/dummy/SDL_syscdrom.c
+INC_DIR += $(SDL_DIR)/src/cdrom
+
+# we need libc
+LIBS = libc mesa_api
+
+# backend path
+vpath % $(REP_DIR)/src/lib/sdl
+
+vpath % $(SDL_DIR)/src
+
+CC_CXX_WARN_STRICT =
diff --git a/lib/mk/sdl_image.mk b/lib/mk/sdl_image.mk
new file mode 100644
index 0000000..7dfe04d
--- /dev/null
+++ b/lib/mk/sdl_image.mk
@@ -0,0 +1,15 @@
+SDL_IMAGE_PORT_DIR := $(call select_from_ports,sdl_image)
+
+SRC_C = $(notdir $(wildcard $(SDL_IMAGE_PORT_DIR)/src/lib/sdl_image/IMG*.c))
+
+LIBS += libc libm sdl jpeg libpng zlib
+
+SUPPORTED_FORMATS = PNG JPG TGA PNM XPM
+
+CC_OPT += $(addprefix -DLOAD_,$(SUPPORTED_FORMATS))
+
+vpath %.c $(SDL_IMAGE_PORT_DIR)/src/lib/sdl_image
+
+SHARED_LIB = yes
+
+CC_CXX_WARN_STRICT =
diff --git a/lib/mk/sdl_mixer.mk b/lib/mk/sdl_mixer.mk
new file mode 100644
index 0000000..83e68e9
--- /dev/null
+++ b/lib/mk/sdl_mixer.mk
@@ -0,0 +1,22 @@
+SDL_MIXER_PORT_DIR := $(call select_from_ports,sdl_mixer)
+
+# exclude example programs
+FILTER_OUT = playmus.c playwave.c
+
+ALL_SDL_MIXER_SRC_C = $(notdir $(wildcard $(SDL_MIXER_PORT_DIR)/src/lib/sdl_mixer/*.c))
+
+SRC_C = $(filter-out $(FILTER_OUT), $(ALL_SDL_MIXER_SRC_C))
+
+LIBS += libc libm sdl
+
+# suppress warnings of 3rd-party code
+CC_OPT_music = -Wno-unused-label -Wno-unused-function
+CC_OPT_load_aiff = -Wno-unused-but-set-variable
+CC_OPT_wavestream = -Wno-unused-but-set-variable
+CC_OPT_effect_position = -Wno-misleading-indentation
+
+vpath %.c $(SDL_MIXER_PORT_DIR)/src/lib/sdl_mixer
+
+SHARED_LIB = yes
+
+CC_CXX_WARN_STRICT =
diff --git a/lib/mk/sdl_net.mk b/lib/mk/sdl_net.mk
new file mode 100644
index 0000000..edf98f3
--- /dev/null
+++ b/lib/mk/sdl_net.mk
@@ -0,0 +1,14 @@
+SDL_NET_PORT_DIR := $(call select_from_ports,sdl_net)
+SDL_NET_DIR := $(SDL_NET_PORT_DIR)/src/lib/sdl_net
+
+SRC_C = $(notdir $(wildcard $(SDL_NET_PORT_DIR)/src/lib/sdl_net/SDLnet*.c))
+
+vpath %.c $(SDL_NET_PORT_DIR)/src/lib/sdl_net
+
+INC_DIR += $(SDL_NET_PORT_DIR)/src/lib/sdl_net
+
+LIBS += libc sdl
+
+SHARED_LIB = yes
+
+CC_CXX_WARN_STRICT =
diff --git a/lib/mk/sdl_ttf.mk b/lib/mk/sdl_ttf.mk
new file mode 100644
index 0000000..a2d410c
--- /dev/null
+++ b/lib/mk/sdl_ttf.mk
@@ -0,0 +1,8 @@
+SRC_C = SDL_ttf.c
+LIBS += libc libm freetype sdl
+
+vpath %.c $(call select_from_ports,sdl_ttf)/src/lib/sdl_ttf
+
+SHARED_LIB = yes
+
+CC_CXX_WARN_STRICT =
diff --git a/lib/mk/sdlmain.mk b/lib/mk/sdlmain.mk
new file mode 100644
index 0000000..41bf547
--- /dev/null
+++ b/lib/mk/sdlmain.mk
@@ -0,0 +1,7 @@
+SRC_CC = sdl_main.cc
+
+LIBS += libc
+
+vpath sdl_main.cc $(REP_DIR)/src/lib/sdl
+
+CC_CXX_WARN_STRICT =
diff --git a/lib/symbols/sdl b/lib/symbols/sdl
new file mode 100644
index 0000000..4c29286
--- /dev/null
+++ b/lib/symbols/sdl
@@ -0,0 +1,349 @@
+SDL_AddTimer T
+SDL_AllocBlitMap T
+SDL_AllocFormat T
+SDL_AllocRW T
+SDL_AppActiveInit T
+SDL_AppActiveQuit T
+SDL_ApplyGamma T
+SDL_AudioDriverName T
+SDL_AudioInit T
+SDL_AudioQuit T
+SDL_BuildAudioCVT T
+SDL_CDClose T
+SDL_CDEject T
+SDL_CDName T
+SDL_CDNumDrives T
+SDL_CDOpen T
+SDL_CDPause T
+SDL_CDPlay T
+SDL_CDPlayTracks T
+SDL_CDROMInit T
+SDL_CDROMQuit T
+SDL_CDResume T
+SDL_CDStatus T
+SDL_CDStop T
+SDL_CDcaps B 80
+SDL_CalculateAlphaBlit T
+SDL_CalculateAudioSpec T
+SDL_CalculateBlit T
+SDL_CalculateBlit0 T
+SDL_CalculateBlit1 T
+SDL_CalculateBlitN T
+SDL_CalculatePitch T
+SDL_CheckKeyRepeat T
+SDL_ClearError T
+SDL_CloseAudio T
+SDL_CondBroadcast T
+SDL_CondSignal T
+SDL_CondWait T
+SDL_CondWaitTimeout T
+SDL_Convert16LSB T
+SDL_Convert16MSB T
+SDL_Convert8 T
+SDL_ConvertAudio T
+SDL_ConvertEndian T
+SDL_ConvertMono T
+SDL_ConvertSign T
+SDL_ConvertStereo T
+SDL_ConvertStrip T
+SDL_ConvertStrip_2 T
+SDL_ConvertSurface T
+SDL_ConvertSurround T
+SDL_ConvertSurround_4 T
+SDL_CreateCond T
+SDL_CreateCursor T
+SDL_CreateMutex T
+SDL_CreateRGBSurface T
+SDL_CreateRGBSurfaceFrom T
+SDL_CreateSemaphore T
+SDL_CreateThread T
+SDL_CreateYUVOverlay T
+SDL_CreateYUV_SW T
+SDL_CursorInit T
+SDL_CursorPaletteChanged T
+SDL_CursorQuit T
+SDL_Delay T
+SDL_DestroyCond T
+SDL_DestroyMutex T
+SDL_DestroySemaphore T
+SDL_DisplayFormat T
+SDL_DisplayFormatAlpha T
+SDL_DisplayYUVOverlay T
+SDL_DisplayYUV_SW T
+SDL_DitherColors T
+SDL_DrawCursor T
+SDL_DrawCursorNoLock T
+SDL_EnableKeyRepeat T
+SDL_EnableUNICODE T
+SDL_EraseCursor T
+SDL_EraseCursorNoLock T
+SDL_Error T
+SDL_EventOK B 8
+SDL_EventState T
+SDL_EventThreadID T
+SDL_FillRect T
+SDL_FindColor T
+SDL_FirstAudioFormat T
+SDL_Flip T
+SDL_FormatChanged T
+SDL_FreeBlitMap T
+SDL_FreeCursor T
+SDL_FreeFormat T
+SDL_FreeRW T
+SDL_FreeSurface T
+SDL_FreeWAV T
+SDL_FreeYUVOverlay T
+SDL_FreeYUV_SW T
+SDL_GL_GetAttribute T
+SDL_GL_GetProcAddress T
+SDL_GL_LoadLibrary T
+SDL_GL_Lock T
+SDL_GL_SetAttribute T
+SDL_GL_SwapBuffers T
+SDL_GL_Unlock T
+SDL_GL_UpdateRects T
+SDL_GL_UpdateRectsLock T
+SDL_GetAppState T
+SDL_GetAudioStatus T
+SDL_GetClipRect T
+SDL_GetCursor T
+SDL_GetErrBuf T
+SDL_GetError T
+SDL_GetErrorMsg T
+SDL_GetEventFilter T
+SDL_GetGamma T
+SDL_GetGammaRamp T
+SDL_GetKeyName T
+SDL_GetKeyRepeat T
+SDL_GetKeyState T
+SDL_GetModState T
+SDL_GetMouseState T
+SDL_GetRGB T
+SDL_GetRGBA T
+SDL_GetRelativeMouseState T
+SDL_GetThreadID T
+SDL_GetTicks T
+SDL_GetVideoInfo T
+SDL_GetVideoSurface T
+SDL_GetWMInfo T
+SDL_Has3DNow T
+SDL_Has3DNowExt T
+SDL_HasAltiVec T
+SDL_HasMMX T
+SDL_HasMMXExt T
+SDL_HasRDTSC T
+SDL_HasSSE T
+SDL_HasSSE2 T
+SDL_Init T
+SDL_InitSubSystem T
+SDL_InstallParachute T
+SDL_InvalidateMap T
+SDL_JoystickClose T
+SDL_JoystickEventState T
+SDL_JoystickGetAxis T
+SDL_JoystickGetBall T
+SDL_JoystickGetButton T
+SDL_JoystickGetHat T
+SDL_JoystickIndex T
+SDL_JoystickInit T
+SDL_JoystickName T
+SDL_JoystickNumAxes T
+SDL_JoystickNumBalls T
+SDL_JoystickNumButtons T
+SDL_JoystickNumHats T
+SDL_JoystickOpen T
+SDL_JoystickOpened T
+SDL_JoystickQuit T
+SDL_JoystickUpdate T
+SDL_KeyRepeat B 40
+SDL_KeyboardInit T
+SDL_KeyboardQuit T
+SDL_KillThread T
+SDL_Linked_Version T
+SDL_ListModes T
+SDL_LoadBMP_RW T
+SDL_LoadFunction T
+SDL_LoadObject T
+SDL_LoadWAV_RW T
+SDL_LockAudio T
+SDL_LockSurface T
+SDL_LockYUVOverlay T
+SDL_LockYUV_SW T
+SDL_Lock_EventThread T
+SDL_LowerBlit T
+SDL_MapRGB T
+SDL_MapRGBA T
+SDL_MapSurface T
+SDL_MixAudio T
+SDL_MouseInit T
+SDL_MouseQuit T
+SDL_MouseRect T
+SDL_MoveCursor T
+SDL_NextAudioFormat T
+SDL_NumJoysticks T
+SDL_OpenAudio T
+SDL_PauseAudio T
+SDL_PeepEvents T
+SDL_PollEvent T
+SDL_PrivateAppActive T
+SDL_PrivateExpose T
+SDL_PrivateJoystickAxis T
+SDL_PrivateJoystickBall T
+SDL_PrivateJoystickButton T
+SDL_PrivateJoystickHat T
+SDL_PrivateKeyboard T
+SDL_PrivateMouseButton T
+SDL_PrivateMouseMotion T
+SDL_PrivateQuit T
+SDL_PrivateResize T
+SDL_PrivateSysWMEvent T
+SDL_ProcessEvents B 32
+SDL_PumpEvents T
+SDL_PushEvent T
+SDL_Quit T
+SDL_QuitInit T
+SDL_QuitQuit T
+SDL_QuitSubSystem T
+SDL_RLEAlphaBlit T
+SDL_RLEBlit T
+SDL_RLESurface T
+SDL_RWFromConstMem T
+SDL_RWFromFP T
+SDL_RWFromFile T
+SDL_RWFromMem T
+SDL_RateDIV2 T
+SDL_RateDIV2_c2 T
+SDL_RateDIV2_c4 T
+SDL_RateDIV2_c6 T
+SDL_RateMUL2 T
+SDL_RateMUL2_c2 T
+SDL_RateMUL2_c4 T
+SDL_RateMUL2_c6 T
+SDL_RateSLOW T
+SDL_ReadBE16 T
+SDL_ReadBE32 T
+SDL_ReadBE64 T
+SDL_ReadLE16 T
+SDL_ReadLE32 T
+SDL_ReadLE64 T
+SDL_ReallocFormat T
+SDL_RemoveTimer T
+SDL_ResetCursor T
+SDL_ResetKeyboard T
+SDL_ResetMouse T
+SDL_RunAudio T
+SDL_RunThread T
+SDL_SYS_CDInit T
+SDL_SYS_CDQuit T
+SDL_SYS_CreateThread T
+SDL_SYS_JoystickClose T
+SDL_SYS_JoystickInit T
+SDL_SYS_JoystickName T
+SDL_SYS_JoystickOpen T
+SDL_SYS_JoystickQuit T
+SDL_SYS_JoystickUpdate T
+SDL_SYS_KillThread T
+SDL_SYS_SetupThread T
+SDL_SYS_StartTimer T
+SDL_SYS_StopTimer T
+SDL_SYS_TimerInit T
+SDL_SYS_TimerQuit T
+SDL_SYS_WaitThread T
+SDL_SaveBMP_RW T
+SDL_SemPost T
+SDL_SemTryWait T
+SDL_SemValue T
+SDL_SemWait T
+SDL_SemWaitTimeout T
+SDL_SetAlpha T
+SDL_SetAlphaChannel T
+SDL_SetClipRect T
+SDL_SetColorKey T
+SDL_SetColors T
+SDL_SetCursor T
+SDL_SetError T
+SDL_SetEventFilter T
+SDL_SetGamma T
+SDL_SetGammaRamp T
+SDL_SetModState T
+SDL_SetPalette T
+SDL_SetTimer T
+SDL_SetTimerThreaded T
+SDL_SetVideoMode T
+SDL_ShowCursor T
+SDL_SoftStretch T
+SDL_StartEventLoop T
+SDL_StartTicks T
+SDL_StopEventLoop T
+SDL_ThreadID T
+SDL_ThreadedTimerCheck T
+SDL_ThreadsInit T
+SDL_ThreadsQuit T
+SDL_TimerInit T
+SDL_TimerQuit T
+SDL_TranslateUNICODE B 4
+SDL_UnRLESurface T
+SDL_UninstallParachute T
+SDL_UnloadObject T
+SDL_UnlockAudio T
+SDL_UnlockSurface T
+SDL_UnlockYUVOverlay T
+SDL_UnlockYUV_SW T
+SDL_Unlock_EventThread T
+SDL_UpdateRect T
+SDL_UpdateRects T
+SDL_UpperBlit T
+SDL_VideoDriverName T
+SDL_VideoInit T
+SDL_VideoModeOK T
+SDL_VideoQuit T
+SDL_WM_GetCaption T
+SDL_WM_GrabInput T
+SDL_WM_IconifyWindow T
+SDL_WM_SetCaption T
+SDL_WM_SetIcon T
+SDL_WM_ToggleFullScreen T
+SDL_WaitEvent T
+SDL_WaitThread T
+SDL_WarpMouse T
+SDL_WasInit T
+SDL_WriteBE16 T
+SDL_WriteBE32 T
+SDL_WriteBE64 T
+SDL_WriteLE16 T
+SDL_WriteLE32 T
+SDL_WriteLE64 T
+SDL_alarm_callback B 8
+SDL_alarm_interval B 4
+SDL_copysign T
+SDL_cursor B 8
+SDL_cursorlock B 8
+SDL_cursorstate D 4
+SDL_getenv T
+SDL_joysticks B 8
+SDL_ltoa T
+SDL_memcpy T
+SDL_mutexP T
+SDL_mutexV T
+SDL_numcds B 4
+SDL_numjoysticks B 1
+SDL_putenv T
+SDL_revcpy T
+SDL_scalbn T
+SDL_sscanf T
+SDL_strcasecmp T
+SDL_strchr T
+SDL_strcmp T
+SDL_strdup T
+SDL_strlwr T
+SDL_strrchr T
+SDL_strrev T
+SDL_strstr T
+SDL_strtod T
+SDL_strtol T
+SDL_strtoul T
+SDL_strupr T
+SDL_timer_running B 4
+SDL_timer_started B 4
+SDL_ultoa T
+_Z15sdl_init_genodeRN6Genode3EnvE T
diff --git a/lib/symbols/sdl_image b/lib/symbols/sdl_image
new file mode 100644
index 0000000..0abbd9a
--- /dev/null
+++ b/lib/symbols/sdl_image
@@ -0,0 +1,47 @@
+IMG_Init T
+IMG_InitJPG T
+IMG_InitPNG T
+IMG_InitTIF T
+IMG_InitWEBP T
+IMG_InvertAlpha T
+IMG_Linked_Version T
+IMG_Load T
+IMG_LoadBMP_RW T
+IMG_LoadCUR_RW T
+IMG_LoadGIF_RW T
+IMG_LoadICO_RW T
+IMG_LoadJPG_RW T
+IMG_LoadLBM_RW T
+IMG_LoadPCX_RW T
+IMG_LoadPNG_RW T
+IMG_LoadPNM_RW T
+IMG_LoadTGA_RW T
+IMG_LoadTIF_RW T
+IMG_LoadTyped_RW T
+IMG_LoadWEBP_RW T
+IMG_LoadXCF_RW T
+IMG_LoadXPM_RW T
+IMG_LoadXV_RW T
+IMG_LoadXXX_RW T
+IMG_Load_RW T
+IMG_Quit T
+IMG_QuitJPG T
+IMG_QuitPNG T
+IMG_QuitTIF T
+IMG_QuitWEBP T
+IMG_ReadXPMFromArray T
+IMG_isBMP T
+IMG_isCUR T
+IMG_isGIF T
+IMG_isICO T
+IMG_isJPG T
+IMG_isLBM T
+IMG_isPCX T
+IMG_isPNG T
+IMG_isPNM T
+IMG_isTIF T
+IMG_isWEBP T
+IMG_isXCF T
+IMG_isXPM T
+IMG_isXV T
+IMG_isXXX T
diff --git a/lib/symbols/sdl_mixer b/lib/symbols/sdl_mixer
new file mode 100644
index 0000000..2011522
--- /dev/null
+++ b/lib/symbols/sdl_mixer
@@ -0,0 +1,82 @@
+MIX_string_equals T
+Mix_AllocateChannels T
+Mix_ChannelFinished T
+Mix_CloseAudio T
+Mix_ExpireChannel T
+Mix_FadeInChannelTimed T
+Mix_FadeInMusic T
+Mix_FadeInMusicPos T
+Mix_FadeOutChannel T
+Mix_FadeOutGroup T
+Mix_FadeOutMusic T
+Mix_FadingChannel T
+Mix_FadingMusic T
+Mix_FreeChunk T
+Mix_FreeMusic T
+Mix_GetChunk T
+Mix_GetChunkDecoder T
+Mix_GetMusicDecoder T
+Mix_GetMusicHookData T
+Mix_GetMusicType T
+Mix_GetNumChunkDecoders T
+Mix_GetNumMusicDecoders T
+Mix_GetSynchroValue T
+Mix_GroupAvailable T
+Mix_GroupChannel T
+Mix_GroupChannels T
+Mix_GroupCount T
+Mix_GroupNewer T
+Mix_GroupOldest T
+Mix_HaltChannel T
+Mix_HaltGroup T
+Mix_HaltMusic T
+Mix_HookMusic T
+Mix_HookMusicFinished T
+Mix_Init T
+Mix_Linked_Version T
+Mix_LoadAIFF_RW T
+Mix_LoadMUS T
+Mix_LoadMUSType_RW T
+Mix_LoadMUS_RW T
+Mix_LoadVOC_RW T
+Mix_LoadWAV_RW T
+Mix_OpenAudio T
+Mix_Pause T
+Mix_PauseMusic T
+Mix_Paused T
+Mix_PausedMusic T
+Mix_PlayChannelTimed T
+Mix_PlayMusic T
+Mix_Playing T
+Mix_PlayingMusic T
+Mix_QuerySpec T
+Mix_QuickLoad_RAW T
+Mix_QuickLoad_WAV T
+Mix_Quit T
+Mix_RegisterEffect T
+Mix_ReserveChannels T
+Mix_Resume T
+Mix_ResumeMusic T
+Mix_RewindMusic T
+Mix_SetDistance T
+Mix_SetMusicCMD T
+Mix_SetMusicPosition T
+Mix_SetPanning T
+Mix_SetPosition T
+Mix_SetPostMix T
+Mix_SetReverseStereo T
+Mix_SetSoundFonts T
+Mix_SetSynchroValue T
+Mix_UnregisterAllEffects T
+Mix_UnregisterEffect T
+Mix_Volume T
+Mix_VolumeChunk T
+Mix_VolumeMusic T
+WAVStream_Active T
+WAVStream_FreeSong T
+WAVStream_Init T
+WAVStream_LoadSong_RW T
+WAVStream_PlaySome T
+WAVStream_SetVolume T
+WAVStream_Start T
+WAVStream_Stop T
diff --git a/lib/symbols/sdl_net b/lib/symbols/sdl_net
new file mode 100644
index 0000000..2170873
--- /dev/null
+++ b/lib/symbols/sdl_net
@@ -0,0 +1,38 @@
+SDLNet_AddSocket T
+SDLNet_AllocPacket T
+SDLNet_AllocPacketV T
+SDLNet_AllocSocketSet T
+SDLNet_CheckSockets T
+SDLNet_DelSocket T
+SDLNet_FreePacket T
+SDLNet_FreePacketV T
+SDLNet_FreeSocketSet T
+SDLNet_GetLastError T
+SDLNet_GetLocalAddresses T
+SDLNet_Init T
+SDLNet_Linked_Version T
+SDLNet_Quit T
+SDLNet_Read16 T
+SDLNet_Read32 T
+SDLNet_ResizePacket T
+SDLNet_ResolveHost T
+SDLNet_ResolveIP T
+SDLNet_SetLastError T
+SDLNet_TCP_Accept T
+SDLNet_TCP_Close T
+SDLNet_TCP_GetPeerAddress T
+SDLNet_TCP_Open T
+SDLNet_TCP_Recv T
+SDLNet_TCP_Send T
+SDLNet_UDP_Bind T
+SDLNet_UDP_Close T
+SDLNet_UDP_GetPeerAddress T
+SDLNet_UDP_Open T
+SDLNet_UDP_Recv T
+SDLNet_UDP_RecvV T
+SDLNet_UDP_Send T
+SDLNet_UDP_SendV T
+SDLNet_UDP_SetPacketLoss T
+SDLNet_UDP_Unbind T
+SDLNet_Write16 T
+SDLNet_Write32 T
diff --git a/ports/sdl.hash b/ports/sdl.hash
new file mode 100644
index 0000000..5bf8435
--- /dev/null
+++ b/ports/sdl.hash
@@ -0,0 +1 @@
+8543c5f3448ebea97afa84aee6691e38a78e756e
diff --git a/ports/sdl.port b/ports/sdl.port
new file mode 100644
index 0000000..0007ef5
--- /dev/null
+++ b/ports/sdl.port
@@ -0,0 +1,19 @@
+LICENSE := LGPL
+VERSION := 1.2.13
+DOWNLOADS := sdl.archive
+
+URL(sdl) := http://www.libsdl.org/release/SDL-$(VERSION).tar.gz
+SHA(sdl) := 94f99df1d60f296b57f4740650a71b6425da654044ca30f8f0ce34934429e132
+SIG(sdl) := ${URL(sdl)}.sig
+KEY(sdl) := 1528635D8053A57F77D1E08630A59377A7763BE6
+DIR(sdl) := src/lib/sdl
+
+PATCHES := src/lib/sdl/SDL_video.patch src/lib/sdl/SDL_audio.patch
+
+# wipe original 'SDL_config.h' file because it conflicts with out version
+_dirs: remove_default_config
+remove_default_config: $(DOWNLOADS)
+ $(VERBOSE)rm src/lib/sdl/include/SDL_config.h
+
+DIRS := include/SDL
+DIR_CONTENT(include/SDL) := src/lib/sdl/include/*.h
diff --git a/ports/sdl_image.hash b/ports/sdl_image.hash
new file mode 100644
index 0000000..60062a6
--- /dev/null
+++ b/ports/sdl_image.hash
@@ -0,0 +1 @@
+f030277887e31297069e40ea636528828b60785f
diff --git a/ports/sdl_image.port b/ports/sdl_image.port
new file mode 100644
index 0000000..4d06c99
--- /dev/null
+++ b/ports/sdl_image.port
@@ -0,0 +1,10 @@
+LICENSE := BSD
+VERSION := 1.2.12
+DOWNLOADS := sdl_image.archive
+
+URL(sdl_image) := http://www.libsdl.org/projects/SDL_image/release/SDL_image-$(VERSION).tar.gz
+SHA(sdl_image) := 0b90722984561004de84847744d566809dbb9daf732a9e503b91a1b5a84e5699
+DIR(sdl_image) := src/lib/sdl_image
+
+DIRS := include/SDL
+DIR_CONTENT(include/SDL) := src/lib/sdl_image/SDL_image.h
diff --git a/ports/sdl_mixer.hash b/ports/sdl_mixer.hash
new file mode 100644
index 0000000..5d29db2
--- /dev/null
+++ b/ports/sdl_mixer.hash
@@ -0,0 +1 @@
+992f8f00abd5ae638bb2db56f0b6e0dceb13ebf8
diff --git a/ports/sdl_mixer.port b/ports/sdl_mixer.port
new file mode 100644
index 0000000..8fa4464
--- /dev/null
+++ b/ports/sdl_mixer.port
@@ -0,0 +1,10 @@
+LICENSE := BSD
+VERSION := 1.2.12
+DOWNLOADS := sdl_mixer.archive
+
+URL(sdl_mixer) := http://www.libsdl.org/projects/SDL_mixer/release/SDL_mixer-$(VERSION).tar.gz
+SHA(sdl_mixer) := 1644308279a975799049e4826af2cfc787cad2abb11aa14562e402521f86992a
+DIR(sdl_mixer) := src/lib/sdl_mixer
+
+DIRS := include/SDL
+DIR_CONTENT(include/SDL) := src/lib/sdl_mixer/SDL_mixer.h
diff --git a/ports/sdl_net.hash b/ports/sdl_net.hash
new file mode 100644
index 0000000..957b9b9
--- /dev/null
+++ b/ports/sdl_net.hash
@@ -0,0 +1 @@
+cbe4f323aa29a1334573ea0b58a43a42ee428ad4
diff --git a/ports/sdl_net.port b/ports/sdl_net.port
new file mode 100644
index 0000000..1be6e73
--- /dev/null
+++ b/ports/sdl_net.port
@@ -0,0 +1,12 @@
+LICENSE := BSD
+VERSION := 1.2.8
+DOWNLOADS := sdl_net.archive
+
+URL(sdl_net) := http://www.libsdl.org/projects/SDL_net/release/SDL_net-$(VERSION).tar.gz
+SHA(sdl_net) := 5f4a7a8bb884f793c278ac3f3713be41980c5eedccecff0260411347714facb4
+DIR(sdl_net) := src/lib/sdl_net
+
+PATCHES := src/lib/sdl_net/SDLnet.patch src/lib/sdl_net/SDL_net.h.patch
+
+DIRS := include/SDL
+DIR_CONTENT(include/SDL) := src/lib/sdl_net/SDL_net.h
diff --git a/ports/sdl_ttf.hash b/ports/sdl_ttf.hash
new file mode 100644
index 0000000..a65b573
--- /dev/null
+++ b/ports/sdl_ttf.hash
@@ -0,0 +1 @@
+6adf6a8f99994cefb09043b52df04e5a1d3aca46
diff --git a/ports/sdl_ttf.port b/ports/sdl_ttf.port
new file mode 100644
index 0000000..0d4f244
--- /dev/null
+++ b/ports/sdl_ttf.port
@@ -0,0 +1,10 @@
+LICENSE := BSD
+VERSION := 2.0.11
+DOWNLOADS := sdl_ttf.archive
+
+URL(sdl_ttf) := http://www.libsdl.org/projects/SDL_ttf/release/SDL_ttf-$(VERSION).tar.gz
+SHA(sdl_ttf) := 724cd895ecf4da319a3ef164892b72078bd92632a5d812111261cde248ebcdb7
+DIR(sdl_ttf) := src/lib/sdl_ttf
+
+DIRS := include/SDL
+DIR_CONTENT(include/SDL) := src/lib/sdl_ttf/SDL_ttf.h
diff --git a/recipes/api/sdl/content.mk b/recipes/api/sdl/content.mk
new file mode 100644
index 0000000..1e61fc8
--- /dev/null
+++ b/recipes/api/sdl/content.mk
@@ -0,0 +1,27 @@
+MIRROR_FROM_REP_DIR := lib/symbols/sdl lib/import/import-sdl.mk \
+ lib/mk/mesa_api.mk lib/mk/sdlmain.mk
+
+content: $(MIRROR_FROM_REP_DIR) src/lib/sdl include LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+SDL_PORT_DIR := $(call port_dir,$(REP_DIR)/ports/sdl)
+MESA_PORT_DIR := $(call port_dir,$(REP_DIR)/ports/mesa)
+
+#
+# The Mesa header files needed for SDL_OpenGL are copied as well.
+#
+include:
+ mkdir -p $@
+ cp -r $(SDL_PORT_DIR)/include/SDL $@/
+ cp -r $(REP_DIR)/include/SDL $@/
+ cp -r $(MESA_PORT_DIR)/include/* $@/
+ cp -r $(REP_DIR)/include/EGL $@/
+
+src/lib/sdl:
+ mkdir -p $@
+ cp -r $(REP_DIR)/src/lib/sdl/sdl_main.cc $@/
+
+LICENSE:
+ cp $(SDL_PORT_DIR)/src/lib/sdl/COPYING $@
diff --git a/recipes/api/sdl/hash b/recipes/api/sdl/hash
new file mode 100644
index 0000000..489fc96
--- /dev/null
+++ b/recipes/api/sdl/hash
@@ -0,0 +1 @@
+2018-03-18 2cdaa5c32a93a5acf0ee7159f96e9f01d67ab8d2
diff --git a/recipes/api/sdl_image/content.mk b/recipes/api/sdl_image/content.mk
new file mode 100644
index 0000000..1cafbde
--- /dev/null
+++ b/recipes/api/sdl_image/content.mk
@@ -0,0 +1,15 @@
+MIRROR_FROM_REP_DIR := lib/symbols/sdl_image lib/import/import-sdl_image.mk
+
+content: $(MIRROR_FROM_REP_DIR) include LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/sdl_image)
+
+include:
+ mkdir -p $@
+ cp -r $(PORT_DIR)/include/SDL $@/
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/sdl_image/COPYING $@
diff --git a/recipes/api/sdl_image/hash b/recipes/api/sdl_image/hash
new file mode 100644
index 0000000..d068dfe
--- /dev/null
+++ b/recipes/api/sdl_image/hash
@@ -0,0 +1 @@
+2017-11-29-a 89eb5991a4dfd527e329acf4c8d50db91d6e466a
diff --git a/recipes/api/sdl_mixer/content.mk b/recipes/api/sdl_mixer/content.mk
new file mode 100644
index 0000000..fcf2554
--- /dev/null
+++ b/recipes/api/sdl_mixer/content.mk
@@ -0,0 +1,15 @@
+MIRROR_FROM_REP_DIR := lib/symbols/sdl_mixer lib/import/import-sdl_mixer.mk
+
+content: $(MIRROR_FROM_REP_DIR) include LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/sdl_mixer)
+
+include:
+ mkdir -p $@
+ cp -r $(PORT_DIR)/include/SDL $@/
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/sdl_mixer/COPYING $@
diff --git a/recipes/api/sdl_mixer/hash b/recipes/api/sdl_mixer/hash
new file mode 100644
index 0000000..52bc52b
--- /dev/null
+++ b/recipes/api/sdl_mixer/hash
@@ -0,0 +1 @@
+2017-12-05 745ce078307630a6ad16361998ae76b96d92112c
diff --git a/recipes/api/sdl_net/content.mk b/recipes/api/sdl_net/content.mk
new file mode 100644
index 0000000..fd5018a
--- /dev/null
+++ b/recipes/api/sdl_net/content.mk
@@ -0,0 +1,15 @@
+MIRROR_FROM_REP_DIR := lib/symbols/sdl_net lib/import/import-sdl_net.mk
+
+content: $(MIRROR_FROM_REP_DIR) include LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/sdl_net)
+
+include:
+ mkdir -p $@
+ cp -r $(PORT_DIR)/include/SDL $@/
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/sdl_net/COPYING $@
diff --git a/recipes/api/sdl_net/hash b/recipes/api/sdl_net/hash
new file mode 100644
index 0000000..11664c3
--- /dev/null
+++ b/recipes/api/sdl_net/hash
@@ -0,0 +1 @@
+2017-12-05 8571d52873f4343c456ef43e13db853b0496f1de
diff --git a/recipes/src/sdl/README b/recipes/src/sdl/README
new file mode 100644
index 0000000..9e255ef
--- /dev/null
+++ b/recipes/src/sdl/README
@@ -0,0 +1,3 @@
+SDL itself does not depend on base, os and timer_session APIs. The libc,
+however, does (via its pthread dependency) and therefor we have to include
+it here.
diff --git a/recipes/src/sdl/api b/recipes/src/sdl/api
new file mode 100644
index 0000000..81c362e
--- /dev/null
+++ b/recipes/src/sdl/api
@@ -0,0 +1 @@
+sdl
diff --git a/recipes/src/sdl/content.mk b/recipes/src/sdl/content.mk
new file mode 100644
index 0000000..e7020c4
--- /dev/null
+++ b/recipes/src/sdl/content.mk
@@ -0,0 +1,18 @@
+content: src/lib/sdl/target.mk lib/mk LICENSE
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/sdl)
+
+src/lib/sdl:
+ mkdir -p $@
+ cp -r $(PORT_DIR)/src/lib/sdl/* $@
+ cp -r $(REP_DIR)/src/lib/sdl/* $@
+
+src/lib/sdl/target.mk: src/lib/sdl
+ echo "LIBS += sdl" > $@
+
+lib/mk:
+ mkdir -p $@
+ cp $(REP_DIR)/$@/sdl.mk $@
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/sdl/COPYING $@
diff --git a/recipes/src/sdl/hash b/recipes/src/sdl/hash
new file mode 100644
index 0000000..2a8d6fc
--- /dev/null
+++ b/recipes/src/sdl/hash
@@ -0,0 +1 @@
+2019-01-02 155b546298117fca760a633abcd79080e124df6c
diff --git a/recipes/src/sdl/used_apis b/recipes/src/sdl/used_apis
new file mode 100644
index 0000000..f88cce1
--- /dev/null
+++ b/recipes/src/sdl/used_apis
@@ -0,0 +1,9 @@
+base
+os
+so
+libc
+zlib
+audio_out_session
+framebuffer_session
+input_session
+timer_session
diff --git a/recipes/src/sdl_image/api b/recipes/src/sdl_image/api
new file mode 100644
index 0000000..dc2300d
--- /dev/null
+++ b/recipes/src/sdl_image/api
@@ -0,0 +1 @@
+sdl_image
diff --git a/recipes/src/sdl_image/content.mk b/recipes/src/sdl_image/content.mk
new file mode 100644
index 0000000..ba9117d
--- /dev/null
+++ b/recipes/src/sdl_image/content.mk
@@ -0,0 +1,18 @@
+content: src/lib/sdl_image/target.mk lib/mk LICENSE
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/sdl_image)
+
+src/lib/sdl_image:
+ mkdir -p $@
+ cp $(PORT_DIR)/src/lib/sdl_image/*.c $@
+ cp $(PORT_DIR)/src/lib/sdl_image/*.h $@
+
+src/lib/sdl_image/target.mk: src/lib/sdl_image
+ echo "LIBS += sdl_image" > $@
+
+lib/mk:
+ mkdir -p $@
+ cp $(REP_DIR)/$@/sdl_image.mk $@
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/sdl_image/COPYING $@
diff --git a/recipes/src/sdl_image/hash b/recipes/src/sdl_image/hash
new file mode 100644
index 0000000..b5ccc55
--- /dev/null
+++ b/recipes/src/sdl_image/hash
@@ -0,0 +1 @@
+2019-01-02 dc96a87f0e92557d8d689718c7c574f0d56d1953
diff --git a/recipes/src/sdl_image/used_apis b/recipes/src/sdl_image/used_apis
new file mode 100644
index 0000000..fcc89fc
--- /dev/null
+++ b/recipes/src/sdl_image/used_apis
@@ -0,0 +1,12 @@
+base
+os
+so
+libc
+zlib
+jpeg
+libpng
+sdl
+audio_out_session
+framebuffer_session
+input_session
+timer_session
diff --git a/recipes/src/sdl_mixer/api b/recipes/src/sdl_mixer/api
new file mode 100644
index 0000000..dc4ef74
--- /dev/null
+++ b/recipes/src/sdl_mixer/api
@@ -0,0 +1 @@
+sdl_mixer
diff --git a/recipes/src/sdl_mixer/content.mk b/recipes/src/sdl_mixer/content.mk
new file mode 100644
index 0000000..8477192
--- /dev/null
+++ b/recipes/src/sdl_mixer/content.mk
@@ -0,0 +1,17 @@
+content: src/lib/sdl_mixer/target.mk lib/mk LICENSE
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/sdl_mixer)
+
+src/lib/sdl_mixer:
+ mkdir -p $@
+ cp -r $(PORT_DIR)/src/lib/sdl_mixer/* $@
+
+src/lib/sdl_mixer/target.mk: src/lib/sdl_mixer
+ echo "LIBS += sdl_mixer" > $@
+
+lib/mk:
+ mkdir -p $@
+ cp $(REP_DIR)/$@/sdl_mixer.mk $@
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/sdl_mixer/COPYING $@
diff --git a/recipes/src/sdl_mixer/hash b/recipes/src/sdl_mixer/hash
new file mode 100644
index 0000000..b6b5bd4
--- /dev/null
+++ b/recipes/src/sdl_mixer/hash
@@ -0,0 +1 @@
+2019-01-02 4723897c17c13f732aa41662f7a3e885b633846e
diff --git a/recipes/src/sdl_mixer/used_apis b/recipes/src/sdl_mixer/used_apis
new file mode 100644
index 0000000..46564ed
--- /dev/null
+++ b/recipes/src/sdl_mixer/used_apis
@@ -0,0 +1,10 @@
+base
+os
+so
+libc
+zlib
+sdl
+audio_out_session
+framebuffer_session
+input_session
+timer_session
diff --git a/recipes/src/sdl_net/api b/recipes/src/sdl_net/api
new file mode 100644
index 0000000..f2f9975
--- /dev/null
+++ b/recipes/src/sdl_net/api
@@ -0,0 +1 @@
+sdl_net
diff --git a/recipes/src/sdl_net/content.mk b/recipes/src/sdl_net/content.mk
new file mode 100644
index 0000000..46ce5bc
--- /dev/null
+++ b/recipes/src/sdl_net/content.mk
@@ -0,0 +1,17 @@
+content: src/lib/sdl_net/target.mk lib/mk LICENSE
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/sdl_net)
+
+src/lib/sdl_net:
+ mkdir -p $@
+ cp -r $(PORT_DIR)/src/lib/sdl_net/* $@
+
+src/lib/sdl_net/target.mk: src/lib/sdl_net
+ echo "LIBS += sdl_net" > $@
+
+lib/mk:
+ mkdir -p $@
+ cp $(REP_DIR)/$@/sdl_net.mk $@
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/sdl_net/COPYING $@
diff --git a/recipes/src/sdl_net/hash b/recipes/src/sdl_net/hash
new file mode 100644
index 0000000..c0ef7ed
--- /dev/null
+++ b/recipes/src/sdl_net/hash
@@ -0,0 +1 @@
+2019-01-02 d614d5009c1c55fc21f9c3fe1761a385eadc80ad
diff --git a/recipes/src/sdl_net/used_apis b/recipes/src/sdl_net/used_apis
new file mode 100644
index 0000000..46564ed
--- /dev/null
+++ b/recipes/src/sdl_net/used_apis
@@ -0,0 +1,10 @@
+base
+os
+so
+libc
+zlib
+sdl
+audio_out_session
+framebuffer_session
+input_session
+timer_session
diff --git a/run/sdl.run b/run/sdl.run
new file mode 100644
index 0000000..5329af4
--- /dev/null
+++ b/run/sdl.run
@@ -0,0 +1,101 @@
+#
+# Build
+#
+
+set build_components {
+ core init
+ drivers/timer
+ test/sdl
+ drivers/framebuffer drivers/input
+}
+
+source ${genode_dir}/repos/base/run/platform_drv.inc
+append_platform_drv_build_components
+
+build $build_components
+
+create_boot_directory
+
+#
+# Generate config
+#
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_if [have_spec sdl] config {
+
+
+
+
+
+
+ }
+
+append_platform_drv_config
+
+append_if [have_spec framebuffer] config {
+
+
+
+ }
+
+append_if [have_spec ps2] config {
+
+
+
+ }
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+#
+# Boot modules
+#
+
+# generic modules
+set boot_modules {
+ core init
+ timer
+ test-sdl
+ ld.lib.so libc.lib.so vfs.lib.so libm.lib.so sdl.lib.so
+}
+
+# platform-specific modules
+lappend_if [have_spec linux] boot_modules fb_sdl
+lappend_if [have_spec framebuffer] boot_modules fb_drv
+lappend_if [have_spec ps2] boot_modules ps2_drv
+
+append_platform_drv_boot_modules
+
+build_boot_image $boot_modules
+
+
+run_genode_until forever
diff --git a/src/lib/sdl/SDL_audio.patch b/src/lib/sdl/SDL_audio.patch
new file mode 100644
index 0000000..8f90799
--- /dev/null
+++ b/src/lib/sdl/SDL_audio.patch
@@ -0,0 +1,22 @@
++++ src/lib/sdl/src/audio/SDL_audio.c
+@@ -113,6 +113,9 @@
+ #if SDL_AUDIO_DRIVER_EPOCAUDIO
+ &EPOCAudio_bootstrap,
+ #endif
++#if SDL_AUDIO_DRIVER_GENODE
++ &GENODEAUD_bootstrap,
++#endif
+ NULL
+ };
+ SDL_AudioDevice *current_audio = NULL;
++++ src/lib/sdl/src/audio/SDL_sysaudio.h
+@@ -177,6 +177,9 @@
+ #if SDL_AUDIO_DRIVER_EPOCAUDIO
+ extern AudioBootStrap EPOCAudio_bootstrap;
+ #endif
++#if SDL_AUDIO_DRIVER_GENODE
++extern AudioBootStrap GENODEAUD_bootstrap;
++#endif
+
+ /* This is the current audio device */
+ extern SDL_AudioDevice *current_audio;
diff --git a/src/lib/sdl/SDL_genode_internal.h b/src/lib/sdl/SDL_genode_internal.h
new file mode 100644
index 0000000..bec66bb
--- /dev/null
+++ b/src/lib/sdl/SDL_genode_internal.h
@@ -0,0 +1,24 @@
+/*
+ * \brief Genode-specific data structures
+ * \author Josef Soentgen
+ * \date 2017-11-21
+ */
+
+/*
+ * Copyright (C) 2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _SDL_GENODE_INTERNAL_H_
+#define _SDL_GENODE_INTERNAL_H_
+
+struct Video
+{
+ bool resize_pending;
+ int width;
+ int height;
+};
+
+#endif /* _SDL_GENODE_INTERNAL_H_ */
diff --git a/src/lib/sdl/SDL_video.patch b/src/lib/sdl/SDL_video.patch
new file mode 100644
index 0000000..d96620a
--- /dev/null
+++ b/src/lib/sdl/SDL_video.patch
@@ -0,0 +1,43 @@
++++ src/lib/sdl/src/video/SDL_video.c
+@@ -28,8 +28,8 @@
+ #include "SDL_blit.h"
+ #include "SDL_pixels_c.h"
+ #include "SDL_cursor_c.h"
+-#include "../events/SDL_sysevents.h"
+-#include "../events/SDL_events_c.h"
++#include "SDL_sysevents.h"
++#include "SDL_events_c.h"
+
+ /* Available video drivers */
+ static VideoBootStrap *bootstrap[] = {
+@@ -120,6 +120,9 @@
+ #if SDL_VIDEO_DRIVER_AALIB
+ &AALIB_bootstrap,
+ #endif
++#if SDL_VIDEO_DRIVER_GENODE_FB
++ &Genode_fb_bootstrap,
++#endif
+ #if SDL_VIDEO_DRIVER_DUMMY
+ &DUMMY_bootstrap,
+ #endif
++++ src/lib/sdl/src/video/SDL_sysvideo.h
+@@ -404,6 +404,9 @@
+ #if SDL_VIDEO_DRIVER_AALIB
+ extern VideoBootStrap AALIB_bootstrap;
+ #endif
++#if SDL_VIDEO_DRIVER_GENODE_FB
++extern VideoBootStrap Genode_fb_bootstrap;
++#endif
+ #if SDL_VIDEO_DRIVER_DUMMY
+ extern VideoBootStrap DUMMY_bootstrap;
+ #endif
++++ src/lib/sdl/include/SDL_opengl.h
+@@ -42,7 +42,7 @@
+ #include /* Header File For The GLU Library */
+ #else
+ #include /* Header File For The OpenGL Library */
+-#include /* Header File For The GLU Library */
++//#include /* Header File For The GLU Library */
+ #endif
+ #ifndef NO_SDL_GLEXT
+ #undef __glext_h_
diff --git a/src/lib/sdl/audio/SDL_genodeaudio.cc b/src/lib/sdl/audio/SDL_genodeaudio.cc
new file mode 100644
index 0000000..699668c
--- /dev/null
+++ b/src/lib/sdl/audio/SDL_genodeaudio.cc
@@ -0,0 +1,299 @@
+/*
+ * \brief Genode-specific audio backend
+ * \author Christian Prochaska
+ * \author Sebastian Sumpf
+ * \date 2012-03-13
+ *
+ * based on the dummy SDL audio driver
+ */
+
+/*
+ * Copyright (C) 2012-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* local includes */
+#include
+
+
+extern Genode::Env *global_env();
+extern Genode::Lock event_lock;
+
+
+enum {
+ AUDIO_CHANNELS = 2,
+};
+
+using Genode::Allocator_avl;
+using Genode::Signal_context;
+using Genode::Signal_receiver;
+using Genode::log;
+using Genode::Hex;
+using Genode::Constructible;
+
+static const char *channel_names[] = { "front left", "front right" };
+static Signal_context config_signal_context;
+
+extern "C" {
+
+#include "SDL_config.h"
+
+/* Output audio to Genode audio service. */
+
+#include "SDL_rwops.h"
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "SDL_audiomem.h"
+#include "SDL_audio_c.h"
+#include "SDL_audiodev_c.h"
+#include "SDL_genodeaudio.h"
+
+/* The tag name used by Genode audio */
+#define GENODEAUD_DRIVER_NAME "genode"
+
+struct Volume_config
+{
+ Genode::Env &_env;
+
+ Genode::Attached_rom_dataspace _config_rom { _env, "config" };
+
+ float volume { 1.0f };
+
+ void _handle_config_update()
+ {
+ _config_rom.update();
+
+ if (!_config_rom.valid()) { return; }
+
+ Genode::Lock_guard guard(event_lock);
+
+ Genode::Xml_node config = _config_rom.xml();
+
+ try {
+ unsigned int config_volume;
+ config.sub_node("sdl_audio_volume").attribute("value")
+ .value(&config_volume);
+ volume = (float)config_volume / 100;
+ } catch (...) { }
+
+ Genode::log("Change SDL audio volume to ", volume * 100);
+ }
+
+ Genode::Signal_handler _config_handler {
+ _env.ep(), *this, &Volume_config::_handle_config_update };
+
+ Volume_config(Genode::Env &env) : _env(env)
+ {
+ _config_rom.sigh(_config_handler);
+ _handle_config_update();
+ }
+};
+
+
+
+struct SDL_PrivateAudioData {
+ Uint8 *mixbuf;
+ Uint32 mixlen;
+ Constructible volume_config;
+ Constructible audio[AUDIO_CHANNELS];
+ Audio_out::Packet *packet[AUDIO_CHANNELS];
+};
+
+
+/* Audio driver functions */
+static int GENODEAUD_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void GENODEAUD_WaitAudio(_THIS);
+static void GENODEAUD_PlayAudio(_THIS);
+static Uint8 *GENODEAUD_GetAudioBuf(_THIS);
+static void GENODEAUD_CloseAudio(_THIS);
+
+
+/* Audio driver bootstrap functions */
+static int GENODEAUD_Available(void)
+{
+ return 1;
+}
+
+
+static void GENODEAUD_DeleteDevice(SDL_AudioDevice *device)
+{
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++)
+ device->hidden->audio[channel].destruct();
+
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+
+static SDL_AudioDevice *GENODEAUD_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *_this;
+
+ /* Initialize all variables that we clean on shutdown */
+ _this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( _this ) {
+ SDL_memset(_this, 0, (sizeof *_this));
+ _this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *_this->hidden));
+ }
+ if ( (_this == NULL) || (_this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( _this ) {
+ SDL_free(_this);
+ }
+ return(0);
+ }
+ SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
+
+ /* Set the function pointers */
+ _this->OpenAudio = GENODEAUD_OpenAudio;
+ _this->WaitAudio = GENODEAUD_WaitAudio;
+ _this->PlayAudio = GENODEAUD_PlayAudio;
+ _this->GetAudioBuf = GENODEAUD_GetAudioBuf;
+ _this->CloseAudio = GENODEAUD_CloseAudio;
+
+ _this->free = GENODEAUD_DeleteDevice;
+
+ /* connect to 'Audio_out' service */
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++) {
+ try {
+ _this->hidden->audio[channel].construct(*global_env(),
+ channel_names[channel], false, channel == 0 ? true : false);
+ _this->hidden->audio[channel]->start();
+ }
+ catch(Genode::Service_denied) {
+ Genode::error("could not connect to 'Audio_out' service");
+
+ while(--channel > 0)
+ _this->hidden->audio[channel].destruct();
+
+ return NULL;
+ }
+ }
+
+ _this->hidden->volume_config.construct(*global_env());
+
+ return _this;
+}
+
+
+AudioBootStrap GENODEAUD_bootstrap = {
+ GENODEAUD_DRIVER_NAME, "Genode audio driver",
+ GENODEAUD_Available, GENODEAUD_CreateDevice
+};
+
+
+static void GENODEAUD_WaitAudio(_THIS)
+{
+ Audio_out::Connection &con = *_this->hidden->audio[0];
+ Audio_out::Packet *p = _this->hidden->packet[0];
+
+ unsigned const packet_pos = con.stream()->packet_position(p);
+ unsigned const play_pos = con.stream()->pos();
+ unsigned queued = packet_pos < play_pos
+ ? ((Audio_out::QUEUE_SIZE + packet_pos) - play_pos)
+ : packet_pos - play_pos;
+
+ /* wait until there is only one packet left to play */
+ while (queued > 1) {
+ con.wait_for_progress();
+ queued--;
+ }
+}
+
+
+static void GENODEAUD_PlayAudio(_THIS)
+{
+ Genode::Lock_guard guard(event_lock);
+
+ Audio_out::Connection *c[AUDIO_CHANNELS];
+ Audio_out::Packet *p[AUDIO_CHANNELS];
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++) {
+ c[channel] = &(*_this->hidden->audio[channel]);
+ p[channel] = _this->hidden->packet[channel];
+ }
+
+ /* get the currently played packet initially */
+ static bool init = false;
+ if (!init) {
+ p[0] = c[0]->stream()->next();
+ init = true;
+ }
+
+ float const volume = _this->hidden->volume_config->volume;
+
+ /*
+ * Get new packet for left channel and use it to synchronize
+ * the right channel
+ */
+ p[0] = c[0]->stream()->next(p[0]);
+ unsigned ppos = c[0]->stream()->packet_position(p[0]);
+ p[1] = c[1]->stream()->get(ppos);
+
+ for (int sample = 0; sample < Audio_out::PERIOD; sample++)
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++)
+ p[channel]->content()[sample] =
+ volume * (float)(((int16_t*)_this->hidden->mixbuf)[sample * AUDIO_CHANNELS + channel]) / 32768;
+
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++) {
+ _this->hidden->audio[channel]->submit(p[channel]);
+ /*
+ * Save current packet to query packet position next time and
+ * when in GENODEAUD_WaitAudio
+ */
+ _this->hidden->packet[channel] = p[channel];
+ }
+}
+
+
+static Uint8 *GENODEAUD_GetAudioBuf(_THIS)
+{
+ return(_this->hidden->mixbuf);
+}
+
+
+static void GENODEAUD_CloseAudio(_THIS)
+{
+ if ( _this->hidden->mixbuf != NULL ) {
+ SDL_FreeAudioMem(_this->hidden->mixbuf);
+ _this->hidden->mixbuf = NULL;
+ }
+}
+
+
+static int GENODEAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ log("requested freq=", spec->freq);
+ log(" format=", Hex(spec->format));
+ log(" samples=", spec->samples);
+ log(" size=", spec->size);
+
+ spec->channels = AUDIO_CHANNELS;
+ spec->format = AUDIO_S16LSB;
+ spec->freq = Audio_out::SAMPLE_RATE;
+ spec->samples = Audio_out::PERIOD;
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate mixing buffer */
+ _this->hidden->mixlen = spec->size;
+ _this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(_this->hidden->mixlen);
+ if ( _this->hidden->mixbuf == NULL ) {
+ return(-1);
+ }
+ SDL_memset(_this->hidden->mixbuf, spec->silence, spec->size);
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
+
+}
diff --git a/src/lib/sdl/audio/SDL_genodeaudio.h b/src/lib/sdl/audio/SDL_genodeaudio.h
new file mode 100644
index 0000000..a55b302
--- /dev/null
+++ b/src/lib/sdl/audio/SDL_genodeaudio.h
@@ -0,0 +1,26 @@
+/*
+ * \brief Genode-specific audio backend
+ * \author Christian Prochaska
+ * \date 2012-03-13
+ *
+ * based on the dummy SDL audio driver
+ */
+
+/*
+ * Copyright (C) 2012-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include "SDL_config.h"
+
+#ifndef _SDL_genodeaudio_h
+#define _SDL_genodeaudio_h
+
+#include "SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *_this
+
+#endif /* _SDL_genodeaudio_h */
diff --git a/src/lib/sdl/loadso/SDL_loadso.cc b/src/lib/sdl/loadso/SDL_loadso.cc
new file mode 100644
index 0000000..78371da
--- /dev/null
+++ b/src/lib/sdl/loadso/SDL_loadso.cc
@@ -0,0 +1,38 @@
+/*
+ * \brief Genode-specific shared-object backend
+ * \author Norman Feske
+ * \date 2013-03-29
+ */
+
+/*
+ * Copyright (C) 2013-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+extern "C" {
+
+#include
+
+#include "SDL_config.h"
+#include "SDL_loadso.h"
+
+void *SDL_LoadObject(const char *sofile)
+{
+ return dlopen(sofile, 0);
+}
+
+
+void *SDL_LoadFunction(void *handle, const char *name)
+{
+ return dlsym(handle, name);
+}
+
+
+void SDL_UnloadObject(void* handle)
+{
+ dlclose(handle);
+}
+
+}
diff --git a/src/lib/sdl/sdl_main.cc b/src/lib/sdl/sdl_main.cc
new file mode 100644
index 0000000..53a03cf
--- /dev/null
+++ b/src/lib/sdl/sdl_main.cc
@@ -0,0 +1,132 @@
+/*
+ * \brief Entry point for SDL applications with a main() function
+ * \author Josef Soentgen
+ * \date 2017-11-21
+ */
+
+/*
+ * Copyright (C) 2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* libc includes */
+#include /* 'malloc' and 'exit' */
+#include
+
+extern char **genode_argv;
+extern int genode_argc;
+extern char **genode_envp;
+
+/* initial environment for the FreeBSD libc implementation */
+extern char **environ;
+
+/* provided by the application */
+extern "C" int main(int argc, char *argv[], char *envp[]);
+
+
+/* provided by our SDL backend */
+extern void sdl_init_genode(Genode::Env &env);
+
+
+
+static void* sdl_main(void *)
+{
+ exit(main(genode_argc, genode_argv, genode_envp));
+ return nullptr;
+}
+
+
+void Libc::Component::construct(Libc::Env &env)
+{
+ using Genode::Xml_node;
+ using Genode::Xml_attribute;
+
+ env.config([&] (Xml_node const &node) {
+ int argc = 0;
+ int envc = 0;
+ char **argv;
+ char **envp;
+
+ /* count the number of arguments and environment variables */
+ node.for_each_sub_node([&] (Xml_node const &node) {
+ /* check if the 'value' attribute exists */
+ if (node.has_type("arg") && node.has_attribute("value"))
+ ++argc;
+ else
+ if (node.has_type("env") && node.has_attribute("key") && node.has_attribute("value"))
+ ++envc;
+ });
+
+ if (argc == 0 && envc == 0)
+ return; /* from lambda */
+
+ /* arguments and environment are a contiguous array (but don't count on it) */
+ argv = (char**)malloc((argc + envc + 1) * sizeof(char*));
+ envp = &argv[argc];
+
+ /* read the arguments */
+ int arg_i = 0;
+ int env_i = 0;
+ node.for_each_sub_node([&] (Xml_node const &node) {
+ /* insert an argument */
+ if (node.has_type("arg")) try {
+ Xml_attribute attr = node.attribute("value");
+
+ Genode::size_t const arg_len = attr.value_size()+1;
+ char *arg = argv[arg_i] = (char*)malloc(arg_len);
+
+ attr.value(arg, arg_len);
+ ++arg_i;
+
+ } catch (Xml_node::Nonexistent_sub_node) { }
+
+ else
+
+ /* insert an environment variable */
+ if (node.has_type("env")) try {
+ Xml_attribute key_attr = node.attribute("key");
+ Xml_attribute val_attr = node.attribute("value");
+
+ Genode::size_t const pair_len =
+ key_attr.value_size() +
+ val_attr.value_size() + 1;
+ char *env = envp[env_i] = (char*)malloc(pair_len);
+
+ Genode::size_t off = 0;
+ key_attr.value(&env[off], key_attr.value_size()+1);
+ off = key_attr.value_size();
+ env[off++] = '=';
+ val_attr.value(&env[off], val_attr.value_size()+1);
+ ++env_i;
+
+ } catch (Xml_node::Nonexistent_sub_node) { }
+ });
+
+ envp[env_i] = NULL;
+
+ /* register command-line arguments at Genode's startup code */
+ genode_argc = argc;
+ genode_argv = argv;
+ genode_envp = environ = envp;
+ });
+
+ /* pass env to SDL backend */
+ sdl_init_genode(env);
+
+ pthread_attr_t attr;
+ pthread_t main_thread;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 768 * 1024);
+
+ if (pthread_create(&main_thread, &attr, sdl_main, nullptr)) {
+ Genode::error("failed to create SDL main thread");
+ exit(1);
+ }
+}
diff --git a/src/lib/sdl/video/SDL_genode_fb_events.cc b/src/lib/sdl/video/SDL_genode_fb_events.cc
new file mode 100644
index 0000000..e22d903
--- /dev/null
+++ b/src/lib/sdl/video/SDL_genode_fb_events.cc
@@ -0,0 +1,532 @@
+/*
+ * \brief Genode-specific event backend
+ * \author Stefan Kalkowski
+ * \date 2008-12-12
+ */
+
+/*
+ * Copyright (c) <2008> Stefan Kalkowski
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+/* local includes */
+#include
+
+
+Genode::Lock event_lock;
+Video video_events;
+
+
+static Genode::Env *_global_env = nullptr;
+
+
+Genode::Env *global_env()
+{
+ if (!_global_env) {
+ Genode::error("sdl_init_genode() not called, aborting");
+ throw Genode::Exception();
+ }
+
+ return _global_env;
+}
+
+
+void sdl_init_genode(Genode::Env &env)
+{
+ _global_env = &env;
+}
+
+
+extern "C" {
+
+#include
+#include "SDL_events_c.h"
+#include "SDL_sysevents.h"
+#include "SDL_genode_fb_events.h"
+
+
+ static Genode::Constructible input;
+ static const int KEYNUM_MAX = 512;
+ static SDLKey keymap[KEYNUM_MAX];
+ static int buttonmap[KEYNUM_MAX];
+
+
+ inline SDL_keysym Genode_Fb_TranslateKey(Input::Keycode keycode,
+ Genode::Codepoint codepoint)
+ {
+ return SDL_keysym { .scancode = (uint8_t)keycode,
+ .sym = keymap[keycode],
+ .mod = SDL_GetModState(),
+ .unicode = (uint16_t)codepoint.value };
+ }
+
+
+ void Genode_Fb_PumpEvents(SDL_VideoDevice *t)
+ {
+ Genode::Lock_guard guard(event_lock);
+
+ if (video_events.resize_pending) {
+ video_events.resize_pending = false;
+
+ int const width = video_events.width;
+ int const height = video_events.height;
+
+ bool const quit = width == 0 && height == 0;
+
+ if (!quit)
+ SDL_PrivateResize(width, height);
+ else {
+ /* at least try to quit w/o other event handling */
+ if (SDL_PrivateQuit())
+ return;
+ else
+ Genode::warning("could not deliver requested SDL_QUIT event");
+ }
+ }
+
+ if (!input->pending())
+ return;
+
+ input->for_each_event([&] (Input::Event const &curr) {
+
+ curr.handle_absolute_motion([&] (int x, int y) {
+ SDL_PrivateMouseMotion(0, 0, x, y); });
+
+ curr.handle_relative_motion([&] (int x, int y) {
+ SDL_PrivateMouseMotion(0, 1, x, y); });
+
+ /* return true if keycode refers to a button */
+ auto mouse_button = [] (Input::Keycode key) {
+ return key >= Input::BTN_MISC && key <= Input::BTN_GEAR_UP; };
+
+ curr.handle_press([&] (Input::Keycode key, Genode::Codepoint codepoint) {
+
+ if (mouse_button(key))
+ SDL_PrivateMouseButton(SDL_PRESSED, buttonmap[key], 0, 0);
+
+ else {
+ SDL_keysym ksym = Genode_Fb_TranslateKey(key, codepoint);
+ SDL_PrivateKeyboard(SDL_PRESSED, &ksym);
+ }
+ });
+
+ curr.handle_release([&] (Input::Keycode key) {
+
+ if (mouse_button(key))
+ SDL_PrivateMouseButton(SDL_RELEASED, buttonmap[key], 0, 0);
+
+ else {
+ Genode::Codepoint const invalid { Genode::Codepoint::INVALID };
+ SDL_keysym ksym = Genode_Fb_TranslateKey(key, invalid);
+ SDL_PrivateKeyboard(SDL_RELEASED, &ksym);
+ }
+ });
+ });
+ }
+
+
+ void Genode_Fb_InitOSKeymap(SDL_VideoDevice *t)
+ {
+ try {
+ input.construct(*_global_env);
+ } catch (...) {
+ Genode::error("no input driver available!");
+ return;
+ }
+
+ using namespace Input;
+
+ /* Prepare button mappings */
+ for (int i=0; i Stefan Kalkowski
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef _SDL_genode_fb_events_h
+#define _SDL_genode_fb_events_h
+
+extern void Genode_Fb_InitOSKeymap(SDL_VideoDevice *t);
+extern void Genode_Fb_PumpEvents(SDL_VideoDevice *t);
+
+#endif // _SDL_genode_fb_events_h
diff --git a/src/lib/sdl/video/SDL_genode_fb_video.cc b/src/lib/sdl/video/SDL_genode_fb_video.cc
new file mode 100644
index 0000000..6b0ad25
--- /dev/null
+++ b/src/lib/sdl/video/SDL_genode_fb_video.cc
@@ -0,0 +1,596 @@
+/*
+ * \brief Genode-specific video backend
+ * \author Stefan Kalkowski
+ * \date 2008-12-12
+ */
+
+/*
+ * Copyright (c) <2008> Stefan Kalkowski
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+
+/* local includes */
+#include
+
+
+extern Genode::Env *global_env();
+
+extern Genode::Lock event_lock;
+extern Video video_events;
+
+
+extern "C" {
+
+#include
+
+#include
+#include
+#include
+#include "SDL_sysvideo.h"
+#include "SDL_pixels_c.h"
+#include "SDL_events_c.h"
+#include "SDL_genode_fb_events.h"
+#include "SDL_genode_fb_video.h"
+
+ static SDL_Rect df_mode;
+
+ struct Sdl_framebuffer
+ {
+ Genode::Env &_env;
+
+ Framebuffer::Mode _mode;
+ Framebuffer::Connection _fb { _env, _mode };
+
+ void _handle_mode_change()
+ {
+ Genode::Lock_guard guard(event_lock);
+
+ Framebuffer::Mode mode = _fb.mode();
+ df_mode.w = mode.width();
+ df_mode.h = mode.height();
+
+ video_events.resize_pending = true;
+ video_events.width = mode.width();
+ video_events.height = mode.height();
+ }
+
+ Genode::Signal_handler _mode_handler {
+ _env.ep(), *this, &Sdl_framebuffer::_handle_mode_change };
+
+ Sdl_framebuffer(Genode::Env &env) : _env(env) {
+ _fb.mode_sigh(_mode_handler); }
+
+ bool valid() const { return _fb.cap().valid(); }
+
+
+ /************************************
+ ** Framebuffer::Session Interface **
+ ************************************/
+
+ Genode::Dataspace_capability dataspace() { return _fb.dataspace(); }
+
+ Framebuffer::Mode mode() const { return _fb.mode(); }
+
+ void refresh(int x, int y, int w, int h) {
+ _fb.refresh(x, y, w, h); }
+ };
+
+ static Genode::Constructible framebuffer;
+ static Framebuffer::Mode scr_mode;
+ static SDL_Rect *modes[2];
+
+#if defined(SDL_VIDEO_OPENGL)
+
+#define EGL_EGLEXT_PROTOTYPES
+#include
+#include
+#include
+
+#define MAX_CONFIGS 10
+#define MAX_MODES 100
+
+ /**********************************
+ ** EGL/OpenGL backend functions **
+ **********************************/
+
+ static EGLDisplay display;
+ static EGLSurface screen_surf;
+ static EGLNativeWindowType native_window;
+
+ typedef EGLBoolean (*eglBindAPI_func) (EGLenum);
+ typedef EGLBoolean (*eglChooseConfig_func) (EGLDisplay, const EGLint *, EGLConfig *, EGLint , EGLint *);
+ typedef EGLContext (*eglCreateContext_func) (EGLDisplay, EGLConfig, EGLContext, const EGLint *);
+ typedef EGLSurface (*eglCreatePixmapSurface_func) (EGLDisplay, EGLConfig, EGLNativePixmapType, const EGLint *);
+ typedef EGLDisplay (*eglGetDisplay_func) (EGLNativeDisplayType);
+ typedef EGLBoolean (*eglInitialize_func) (EGLDisplay, EGLint *, EGLint *);
+ typedef EGLBoolean (*eglMakeCurrent_func) (EGLDisplay, EGLSurface, EGLSurface, EGLContext);
+ typedef EGLBoolean (*eglSwapBuffers_func) (EGLDisplay, EGLSurface);
+ typedef EGLBoolean (*eglWaitClient_func) (void);
+ typedef char const* (*eglQueryString_func) (EGLDisplay, EGLint);
+ typedef __eglMustCastToProperFunctionPointerType
+ (*eglGetProcAddress_func) (const char *procname);
+
+
+ static eglBindAPI_func __eglBindAPI;
+ static eglChooseConfig_func __eglChooseConfig;
+ static eglCreateContext_func __eglCreateContext;
+ static eglCreatePixmapSurface_func __eglCreatePixmapSurface;
+ static eglGetDisplay_func __eglGetDisplay;
+ static eglInitialize_func __eglInitialize;
+ static eglMakeCurrent_func __eglMakeCurrent;
+ static eglSwapBuffers_func __eglSwapBuffers;
+ static eglWaitClient_func __eglWaitClient;
+ static eglQueryString_func __eglQueryString;
+ static eglGetProcAddress_func __eglGetProcAddress;
+
+ static bool init_egl()
+ {
+ void *egl = dlopen("egl.lib.so", 0);
+ if (!egl) {
+ Genode::error("could not open EGL library");
+ return false;
+ }
+
+#define LOAD_GL_FUNC(lib, sym) \
+ __ ## sym = (sym ##_func) dlsym(lib, #sym); \
+ if (!__ ## sym) { return false; }
+
+ LOAD_GL_FUNC(egl, eglBindAPI)
+ LOAD_GL_FUNC(egl, eglChooseConfig)
+ LOAD_GL_FUNC(egl, eglCreateContext)
+ LOAD_GL_FUNC(egl, eglCreatePixmapSurface)
+ LOAD_GL_FUNC(egl, eglGetDisplay)
+ LOAD_GL_FUNC(egl, eglInitialize)
+ LOAD_GL_FUNC(egl, eglMakeCurrent)
+ LOAD_GL_FUNC(egl, eglQueryString)
+ LOAD_GL_FUNC(egl, eglSwapBuffers)
+ LOAD_GL_FUNC(egl, eglWaitClient)
+ LOAD_GL_FUNC(egl, eglGetProcAddress)
+
+#undef LOAD_GL_FUNC
+
+ return true;
+ }
+
+ static bool init_opengl(SDL_VideoDevice *t)
+ {
+ if (!init_egl()) { return false; }
+
+ int maj, min;
+ EGLContext ctx;
+ EGLConfig configs[MAX_CONFIGS];
+ GLboolean printInfo = GL_FALSE;
+
+ display = __eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (!display) {
+ Genode::error("eglGetDisplay failed\n");
+ return false;
+ }
+
+ if (!__eglInitialize(display, &maj, &min)) {
+ Genode::error("eglInitialize failed\n");
+ return false;
+ }
+
+ Genode::log("EGL version = ", maj, ".", min);
+ Genode::log("EGL_VENDOR = ", __eglQueryString(display, EGL_VENDOR));
+
+ EGLConfig config;
+ EGLint config_attribs[32];
+ EGLint renderable_type, num_configs, i;
+
+ i = 0;
+ config_attribs[i++] = EGL_RED_SIZE;
+ config_attribs[i++] = 1;
+ config_attribs[i++] = EGL_GREEN_SIZE;
+ config_attribs[i++] = 1;
+ config_attribs[i++] = EGL_BLUE_SIZE;
+ config_attribs[i++] = 1;
+ config_attribs[i++] = EGL_DEPTH_SIZE;
+ config_attribs[i++] = 1;
+
+ config_attribs[i++] = EGL_SURFACE_TYPE;
+ config_attribs[i++] = EGL_WINDOW_BIT;;
+
+ config_attribs[i++] = EGL_RENDERABLE_TYPE;
+ renderable_type = 0x0;
+ renderable_type |= EGL_OPENGL_BIT;
+ config_attribs[i++] = renderable_type;
+
+ config_attribs[i] = EGL_NONE;
+
+ if (!__eglChooseConfig(display, config_attribs, &config, 1, &num_configs)
+ || !num_configs) {
+ Genode::error("eglChooseConfig failed");
+ return false;
+ }
+
+ __eglBindAPI(EGL_OPENGL_API);
+
+ EGLint context_attribs[4]; context_attribs[0] = EGL_NONE;
+ ctx = __eglCreateContext(display, config, EGL_NO_CONTEXT, context_attribs);
+ if (!ctx) {
+ Genode::error("eglCreateContext failed");
+ return false;
+ }
+
+ Genode_egl_window egl_window { scr_mode.width(), scr_mode.height(),
+ (unsigned char*)t->hidden->buffer };
+
+ screen_surf = __eglCreatePixmapSurface(display, config, &egl_window, NULL);
+ if (screen_surf == EGL_NO_SURFACE) {
+ Genode::error("eglCreatePixmapSurface failed");
+ return false;
+ }
+
+ if (!__eglMakeCurrent(display, screen_surf, screen_surf, ctx)) {
+ Genode::error("eglMakeCurrent failed");
+ return false;
+ }
+
+ t->gl_config.driver_loaded = 1;
+ return true;
+ }
+#endif
+
+ /****************************************
+ * Genode_Fb driver bootstrap functions *
+ ****************************************/
+
+ static int Genode_Fb_Available(void)
+ {
+ if (!framebuffer.constructed()) {
+ framebuffer.construct(*global_env());
+ }
+
+ if (!framebuffer->valid()) {
+ Genode::error("could not obtain framebuffer session");
+ return 0;
+ }
+
+ return 1;
+ }
+
+
+ static void Genode_Fb_DeleteDevice(SDL_VideoDevice *device)
+ {
+ if (framebuffer.constructed()) {
+ framebuffer.destruct();
+ }
+ }
+
+
+ static SDL_VideoDevice *Genode_Fb_CreateDevice(int devindex)
+ {
+ SDL_VideoDevice *device;
+
+ /* Initialize all variables that we clean on shutdown */
+ device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
+ if ( device ) {
+ SDL_memset(device, 0, (sizeof *device));
+ device->hidden = (struct SDL_PrivateVideoData *)
+ SDL_malloc((sizeof *device->hidden));
+ }
+ if ( (device == 0) || (device->hidden == 0) ) {
+ SDL_OutOfMemory();
+ if ( device ) {
+ SDL_free(device);
+ }
+ return(0);
+ }
+ SDL_memset(device->hidden, 0, (sizeof *device->hidden));
+
+ /* Set the function pointers */
+ device->VideoInit = Genode_Fb_VideoInit;
+ device->ListModes = Genode_Fb_ListModes;
+ device->SetVideoMode = Genode_Fb_SetVideoMode;
+ device->SetColors = Genode_Fb_SetColors;
+ device->UpdateRects = Genode_Fb_UpdateRects;
+ device->VideoQuit = Genode_Fb_VideoQuit;
+ device->AllocHWSurface = Genode_Fb_AllocHWSurface;
+ device->LockHWSurface = Genode_Fb_LockHWSurface;
+ device->UnlockHWSurface = Genode_Fb_UnlockHWSurface;
+ device->FreeHWSurface = Genode_Fb_FreeHWSurface;
+ device->InitOSKeymap = Genode_Fb_InitOSKeymap;
+ device->PumpEvents = Genode_Fb_PumpEvents;
+ device->free = Genode_Fb_DeleteDevice;
+ device->CreateYUVOverlay = 0;
+ device->CheckHWBlit = 0;
+ device->FillHWRect = 0;
+ device->SetHWColorKey = 0;
+ device->SetHWAlpha = 0;
+ device->FlipHWSurface = 0;
+ device->SetCaption = 0;
+ device->SetIcon = 0;
+ device->IconifyWindow = 0;
+ device->GrabInput = 0;
+ device->GetWMInfo = 0;
+
+ device->GL_MakeCurrent = Genode_Fb_GL_MakeCurrent;
+ device->GL_SwapBuffers = Genode_Fb_GL_SwapBuffers;
+ device->GL_LoadLibrary = Genode_Fb_GL_LoadLibrary;
+ device->GL_GetProcAddress = Genode_Fb_GL_GetProcAddress;
+ return device;
+ }
+
+
+ VideoBootStrap Genode_fb_bootstrap = {
+ "Genode_Fb", "SDL genode_fb video driver",
+ Genode_Fb_Available, Genode_Fb_CreateDevice
+ };
+
+
+ /*****************
+ * Functionality
+ ****************/
+
+ /**
+ * Initialize the native video subsystem, filling 'vformat' with the
+ * "best" display pixel format, returning 0 or -1 if there's an error.
+ */
+ int Genode_Fb_VideoInit(SDL_VideoDevice *t, SDL_PixelFormat *vformat)
+ {
+ if (!framebuffer.constructed()) {
+ Genode::error("framebuffer not initialized");
+ return -1;
+ }
+
+ /* Get the framebuffer size and mode infos */
+ scr_mode = framebuffer->mode();
+ t->info.current_w = scr_mode.width();
+ t->info.current_h = scr_mode.height();
+ Genode::log("Framebuffer has "
+ "width=", t->info.current_w, " "
+ "height=", t->info.current_h);
+
+ /* set mode specific values */
+ switch(scr_mode.format())
+ {
+ case Framebuffer::Mode::RGB565:
+ Genode::log("We use pixelformat rgb565.");
+ vformat->BitsPerPixel = 16;
+ vformat->BytesPerPixel = scr_mode.bytes_per_pixel();
+ vformat->Rmask = 0x0000f800;
+ vformat->Gmask = 0x000007e0;
+ vformat->Bmask = 0x0000001f;
+ break;
+ default:
+ SDL_SetError("Couldn't get console mode info");
+ Genode_Fb_VideoQuit(t);
+ return -1;
+ }
+ modes[0] = &df_mode;
+ df_mode.w = scr_mode.width();
+ df_mode.h = scr_mode.height();
+ modes[1] = 0;
+
+ t->hidden->buffer = 0;
+ return 0;
+ }
+
+
+ /**
+ *Note: If we are terminated, this could be called in the middle of
+ * another SDL video routine -- notably UpdateRects.
+ */
+ void Genode_Fb_VideoQuit(SDL_VideoDevice *t)
+ {
+ Genode::log("Quit video device ...");
+
+ if (t->screen->pixels) {
+ t->screen->pixels = nullptr;
+ }
+
+ if (t->hidden->buffer) {
+ global_env()->rm().detach(t->hidden->buffer);
+ t->hidden->buffer = nullptr;
+ }
+ }
+
+
+ /**
+ * List the available video modes for the given pixel format,
+ * sorted from largest to smallest.
+ */
+ SDL_Rect **Genode_Fb_ListModes(SDL_VideoDevice *t,
+ SDL_PixelFormat *format,
+ Uint32 flags)
+ {
+ if(format->BitsPerPixel != 16) { return (SDL_Rect **) 0; }
+ return modes;
+ }
+
+
+ /**
+ * Set the requested video mode, returning a surface which will be
+ * set to the SDL_VideoSurface. The width and height will already
+ * be verified by ListModes(), and the video subsystem is free to
+ * set the mode to a supported bit depth different from the one
+ * specified -- the desired bpp will be emulated with a shadow
+ * surface if necessary. If a new mode is returned, this function
+ * should take care of cleaning up the current mode.
+ */
+ SDL_Surface *Genode_Fb_SetVideoMode(SDL_VideoDevice *t,
+ SDL_Surface *current,
+ int width, int height,
+ int bpp, Uint32 flags)
+ {
+ /* for now we do not support this */
+ if (t->hidden->buffer && flags & SDL_OPENGL) {
+ Genode::error("resizing a OpenGL window not possible");
+ return nullptr;
+ }
+
+ /*
+ * XXX there is something wrong with how this is used now.
+ * SDL_Flip() is going to call FlipHWSurface which was never
+ * implemented and leads to a nullptr function call.
+ */
+ if (flags & SDL_DOUBLEBUF) {
+ Genode::warning("disable requested double-buffering");
+ flags &= ~SDL_DOUBLEBUF;
+ }
+
+ /* Map the buffer */
+ Genode::Dataspace_capability fb_ds_cap = framebuffer->dataspace();
+ if (!fb_ds_cap.valid()) {
+ Genode::error("could not request dataspace for frame buffer");
+ return nullptr;
+ }
+
+ if (t->hidden->buffer) {
+ global_env()->rm().detach(t->hidden->buffer);
+ }
+
+ t->hidden->buffer = global_env()->rm().attach(fb_ds_cap);
+
+ if (!t->hidden->buffer) {
+ Genode::error("no buffer for requested mode");
+ return nullptr;
+ }
+
+ Genode::log("Set video mode to: ", width, "x", height, "@", bpp);
+
+ SDL_memset(t->hidden->buffer, 0, width * height * (bpp / 8));
+
+ if (!SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) {
+ Genode::error("couldn't allocate new pixel format for requested mode");
+ return nullptr;
+ }
+
+ /* Set up the new mode framebuffer */
+ current->flags = flags | SDL_FULLSCREEN;
+ t->hidden->w = current->w = width;
+ t->hidden->h = current->h = height;
+ current->pitch = current->w * (bpp / 8);
+
+#if defined(SDL_VIDEO_OPENGL)
+ if ((flags & SDL_OPENGL) && !init_opengl(t)) {
+ return nullptr;
+ }
+#endif
+
+ /*
+ * XXX if SDL ever wants to free the pixels pointer,
+ * free() in the libc will trigger a page-fault
+ */
+ current->pixels = t->hidden->buffer;
+ return current;
+ }
+
+
+ /**
+ * We don't actually allow hardware surfaces other than the main one
+ */
+ static int Genode_Fb_AllocHWSurface(SDL_VideoDevice *t,
+ SDL_Surface *surface)
+ {
+ Genode::log(__func__, " not supported yet ...");
+ return -1;
+ }
+
+
+ static void Genode_Fb_FreeHWSurface(SDL_VideoDevice *t,
+ SDL_Surface *surface)
+ {
+ Genode::log(__func__, " not supported yet ...");
+ }
+
+
+ /**
+ * We need to wait for vertical retrace on page flipped displays
+ */
+ static int Genode_Fb_LockHWSurface(SDL_VideoDevice *t,
+ SDL_Surface *surface)
+ {
+ /* Genode::log(__func__, " not supported yet ..."); */
+ return 0;
+ }
+
+
+ static void Genode_Fb_UnlockHWSurface(SDL_VideoDevice *t,
+ SDL_Surface *surface)
+ {
+ /* Genode::log(__func__, " not supported yet ..."); */
+ }
+
+
+ static void Genode_Fb_UpdateRects(SDL_VideoDevice *t, int numrects,
+ SDL_Rect *rects)
+ {
+ int i;
+ for(i=0;irefresh(rects[i].x, rects[i].y, rects[i].w, rects[i].h);
+ }
+ }
+
+
+ /**
+ * Sets the color entries { firstcolor .. (firstcolor+ncolors-1) }
+ * of the physical palette to those in 'colors'. If the device is
+ * using a software palette (SDL_HWPALETTE not set), then the
+ * changes are reflected in the logical palette of the screen
+ * as well.
+ * The return value is 1 if all entries could be set properly
+ * or 0 otherwise.
+ */
+ int Genode_Fb_SetColors(SDL_VideoDevice *t, int firstcolor,
+ int ncolors, SDL_Color *colors)
+ {
+ Genode::warning(__func__, " not yet implemented");
+ return 1;
+ }
+
+
+ int Genode_Fb_GL_MakeCurrent(SDL_VideoDevice *t)
+ {
+ Genode::warning(__func__, ": not yet implemented");
+ return 0;
+ }
+
+
+ void Genode_Fb_GL_SwapBuffers(SDL_VideoDevice *t)
+ {
+#if defined(SDL_VIDEO_OPENGL)
+ __eglWaitClient();
+ __eglSwapBuffers(display, screen_surf);
+ framebuffer->refresh(0, 0, scr_mode.width(), scr_mode.height());
+#endif
+ }
+
+ int Genode_Fb_GL_LoadLibrary(SDL_VideoDevice *t, const char *path)
+ {
+ Genode::warning(__func__, ": not yet implemented");
+ return 0;
+ }
+
+
+ void* Genode_Fb_GL_GetProcAddress(SDL_VideoDevice *t, const char *proc) {
+
+ return (void*)__eglGetProcAddress(proc); }
+} //extern "C"
diff --git a/src/lib/sdl/video/SDL_genode_fb_video.h b/src/lib/sdl/video/SDL_genode_fb_video.h
new file mode 100644
index 0000000..72193d0
--- /dev/null
+++ b/src/lib/sdl/video/SDL_genode_fb_video.h
@@ -0,0 +1,77 @@
+/*
+ * \brief Genode-specific video backend header
+ * \author Stefan Kalkowski
+ * \date 2008-12-12
+ */
+
+/*
+ * Copyright (c) <2008> Stefan Kalkowski
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef _SDL_genode_fb_video_h
+#define _SDL_genode_fb_video_h
+
+/* Private display data */
+struct SDL_PrivateVideoData {
+ int w, h;
+ void *buffer;
+};
+
+/**
+ * Initialization/Query functions
+ */
+static int Genode_Fb_VideoInit(SDL_VideoDevice *t, SDL_PixelFormat *vformat);
+static SDL_Rect **Genode_Fb_ListModes(SDL_VideoDevice *t,
+ SDL_PixelFormat *format,
+ Uint32 flags);
+static SDL_Surface *Genode_Fb_SetVideoMode(SDL_VideoDevice *t,
+ SDL_Surface *current,
+ int width, int height,
+ int bpp, Uint32 flags);
+static int Genode_Fb_SetColors(SDL_VideoDevice *t, int firstcolor,
+ int ncolors, SDL_Color *colors);
+static void Genode_Fb_VideoQuit(SDL_VideoDevice *t);
+
+/**
+ * Hardware surface functions
+ */
+static int Genode_Fb_AllocHWSurface(SDL_VideoDevice *t, SDL_Surface *surface);
+static int Genode_Fb_LockHWSurface(SDL_VideoDevice *t, SDL_Surface *surface);
+static void Genode_Fb_UnlockHWSurface(SDL_VideoDevice *t, SDL_Surface *surface);
+static void Genode_Fb_FreeHWSurface(SDL_VideoDevice *t, SDL_Surface *surface);
+
+/**
+ * etc.
+ */
+static void Genode_Fb_UpdateRects(SDL_VideoDevice *t, int numrects,
+ SDL_Rect *rects);
+
+/**
+ * OpenGL functions
+ */
+static int Genode_Fb_GL_MakeCurrent(SDL_VideoDevice *t);
+static void Genode_Fb_GL_SwapBuffers(SDL_VideoDevice *t);
+static int Genode_Fb_GL_LoadLibrary(SDL_VideoDevice *t, const char *path);
+static void* Genode_Fb_GL_GetProcAddress(SDL_VideoDevice *t, const char *proc);
+
+#endif // _SDL_genode_fb_video_h
diff --git a/src/lib/sdl_net/SDL_net.h.patch b/src/lib/sdl_net/SDL_net.h.patch
new file mode 100644
index 0000000..bdc7407
--- /dev/null
+++ b/src/lib/sdl_net/SDL_net.h.patch
@@ -0,0 +1,15 @@
++++ src/lib/sdl_net/SDL_net.h
+@@ -350,6 +350,13 @@
+ extern no_parse_DECLSPEC char * SDLCALL SDLNet_GetError(void);
+ */
+
++#ifdef __cplusplus
++#define SDL_reinterpret_cast(type, expression) reinterpret_cast(expression)
++#define SDL_static_cast(type, expression) static_cast(expression)
++#else
++#define SDL_reinterpret_cast(type, expression) ((type)(expression))
++#define SDL_static_cast(type, expression) ((type)(expression))
++#endif
+
+ /* Inline macro functions to read/write network data */
+
diff --git a/src/lib/sdl_net/SDLnet.patch b/src/lib/sdl_net/SDLnet.patch
new file mode 100644
index 0000000..e7a4198
--- /dev/null
+++ b/src/lib/sdl_net/SDLnet.patch
@@ -0,0 +1,37 @@
++++ src/lib/sdl_net/SDLnet.c
+@@ -122,11 +122,11 @@
+ } else {
+ address->host = inet_addr(host);
+ if ( address->host == INADDR_NONE ) {
+- struct hostent *hp;
++ struct addrinfo *ai;
+
+- hp = gethostbyname(host);
+- if ( hp ) {
+- memcpy(&address->host,hp->h_addr,hp->h_length);
++ retval = getaddrinfo(host, NULL, NULL, &ai);
++ if ( retval == 0 ) {
++ memcpy(&address->host,ai->ai_addr,ai->ai_addrlen);
+ } else {
+ retval = -1;
+ }
+@@ -149,12 +149,15 @@
+ */
+ const char *SDLNet_ResolveIP(const IPaddress *ip)
+ {
+- struct hostent *hp;
++ static char host[256];
+ struct in_addr in;
++ int err;
+
+- hp = gethostbyaddr((const char *)&ip->host, sizeof(ip->host), AF_INET);
+- if ( hp != NULL ) {
+- return hp->h_name;
++ err = getnameinfo((const struct sockaddr*) &ip->host,
++ sizeof (struct sockaddr), host, sizeof (host),
++ NULL, 0, 0);
++ if ( err == 0 ) {
++ return host;
+ }
+
+ in.s_addr = ip->host;
diff --git a/src/test/sdl/main.cc b/src/test/sdl/main.cc
new file mode 100644
index 0000000..0bbae81
--- /dev/null
+++ b/src/test/sdl/main.cc
@@ -0,0 +1,122 @@
+/*
+ * \brief Simple SDL test program
+ * \author Stefan Kalkowski
+ * \date 2008-12-12
+ */
+
+/*
+ * Copyright (c) <2008> Stefan Kalkowski
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* SDL includes */
+#include
+
+/* Genode includes */
+#include
+#include
+#include
+
+
+static void draw(SDL_Surface * const screen, int w, int h)
+{
+ if (screen == nullptr) { return; }
+
+ /* paint something into pixel buffer */
+ short* const pixels = (short* const) screen->pixels;
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ pixels[i*w+j] = (i/32)*32*64 + (j/32)*32 + i*j/1024;
+ }
+ }
+ SDL_UpdateRect(screen, 0, 0, 0, 0);
+}
+
+
+static SDL_Surface *set_video_mode(int w, int h)
+{
+ SDL_Surface *screen = SDL_SetVideoMode(w, h, 16, SDL_SWSURFACE);
+ if (screen == nullptr) {
+ printf("Error: could not set video mode: %s\n", SDL_GetError());
+ }
+
+ return screen;
+}
+
+
+static SDL_Surface *resize_screen(SDL_Surface * const screen, int w, int h)
+{
+ if (screen == nullptr) { return nullptr; }
+
+ int oldw = screen->w;
+ int oldh = screen->h;
+
+ SDL_Surface *nscreen = set_video_mode(w, h);
+ if (nscreen == nullptr) {
+ printf("Error: could not resize %dx%d -> %dx%d: %s\n",
+ oldw, oldh, w, h, SDL_GetError());
+ return nullptr;
+ }
+
+ return nscreen;
+}
+
+
+int main( int argc, char* args[] )
+{
+
+ /* start SDL */
+ if (SDL_Init(SDL_INIT_VIDEO) == -1) {
+ printf("Error: could not initialize SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ /* set screen to max WxH */
+ SDL_Surface *screen = set_video_mode(0, 0);
+ if (screen == nullptr) { return 1; }
+
+ bool done = false;
+ while (!done) {
+ draw(screen, screen->w, screen->h);
+ SDL_Delay(10);
+
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ switch(event.type) {
+ case SDL_KEYDOWN:
+ printf( "%s\n", SDL_GetKeyName(event.key.keysym.sym));
+ done = true;
+ break;
+ case SDL_VIDEORESIZE:
+ screen = resize_screen(screen, event.resize.w, event.resize.h);
+ if (screen == nullptr) { done = true; }
+
+ break;
+ }
+ }
+ }
+
+ /* quit SDL */
+ SDL_Quit();
+ return 0;
+}
diff --git a/src/test/sdl/target.mk b/src/test/sdl/target.mk
new file mode 100644
index 0000000..1c04b61
--- /dev/null
+++ b/src/test/sdl/target.mk
@@ -0,0 +1,5 @@
+TARGET := test-sdl
+LIBS := libc sdl sdlmain
+SRC_CC := main.cc
+
+CC_CXX_WARN_STRICT =