فهرست منبع

Raspberry Pi support (also unified UDEV and EVDEV support)

Gabriel Jacobo 11 سال پیش
والد
کامیت
9ceed73db4

+ 48 - 0
README-raspberrypi.txt

@@ -0,0 +1,48 @@
+================================================================================
+SDL2 for Raspberry Pi
+================================================================================
+
+Requirements:
+
+Raspbian (other Linux distros may work as well).
+
+================================================================================
+ Features
+================================================================================
+
+* Works without X11
+* Hardware accelerated OpenGL ES 2.x
+* Sound via ALSA
+* Input (mouse/keyboard/joystick) via EVDEV
+* Hotplugging of input devices via UDEV
+
+================================================================================
+ Raspbian Build Dependencies
+================================================================================
+
+sudo apt-get install libudev-dev libasound2-dev
+
+You also need the VideoCore binary stuff that ships in /opt/vc for EGL and 
+OpenGL ES 2.x, it usually comes pre installed, but in any case:
+    
+sudo apt-get install libraspberrypi0 libraspberrypi-bin libraspberrypi-dev
+
+================================================================================
+ No HDMI Audio
+================================================================================
+
+If you notice that ALSA works but there's no audio over HDMI, try adding:
+    
+    hdmi_drive=2
+    
+to your config.txt file and reboot.
+
+Reference: http://www.raspberrypi.org/phpBB3/viewtopic.php?t=5062
+
+================================================================================
+ Notes
+================================================================================
+
+* Building has only been tested natively (i.e. not cross compiled). Cross
+  compilation might work though, feedback is welcome!
+* No Text Input yet.

+ 6 - 2
build-scripts/config.guess

@@ -896,12 +896,16 @@ EOF
 	then
 	    echo ${UNAME_MACHINE}-unknown-linux-gnu
 	else
+        case `sed -n '/^Hardware/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+        BCM2708) MANUFACTURER=raspberry;;
+        *) MANUFACTURER=unknown;;
+        esac
 	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
 		| grep -q __ARM_PCS_VFP
 	    then
-		echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+		echo ${UNAME_MACHINE}-${MANUFACTURER}-linux-gnueabi
 	    else
-		echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
+		echo ${UNAME_MACHINE}-${MANUFACTURER}-linux-gnueabihf
 	    fi
 	fi
 	exit ;;

+ 23 - 0
configure

@@ -22028,6 +22028,21 @@ fi
 case "$host" in
     *-*-linux*|*-*-uclinux*|*-*-gnu*|*-*-k*bsd*-gnu|*-*-bsdi*|*-*-freebsd*|*-*-dragonfly*|*-*-netbsd*|*-*-openbsd*|*-*-sysv5*|*-*-solaris*|*-*-hpux*|*-*-aix*|*-*-minix*)
         case "$host" in
+            *-raspberry-linux*)
+                # Raspberry Pi
+                ARCH=linux
+                RPI_CFLAGS="-I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux"
+                RPI_LDFLAGS="-L/opt/vc/lib -lbcm_host"
+                CFLAGS="$CFLAGS $RPI_CFLAGS"
+                SDL_CFLAGS="$SDL_CFLAGS $RPI_CFLAGS"
+                EXTRA_CFLAGS="$EXTRA_CFLAGS $RPI_CFLAGS"
+                SDL_LIBS="$SDL_LIBS $RPI_LDFLAGS"
+
+                if test x$enable_video = xyes; then
+                    SOURCES="$SOURCES $srcdir/src/video/raspberry/*.c"
+                    $as_echo "#define SDL_VIDEO_DRIVER_RPI 1" >>confdefs.h
+                fi
+                ;;
             *-*-linux*)         ARCH=linux ;;
             *-*-uclinux*)       ARCH=linux ;;
             *-*-kfreebsd*-gnu)  ARCH=kfreebsd-gnu ;;
@@ -22151,6 +22166,14 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h
             SOURCES="$SOURCES $srcdir/src/timer/unix/*.c"
             have_timers=yes
         fi
+        # Set up files for udev hotplugging support
+        if test x$enable_libudev = xyes && test x$have_libudev_h_hdr = xyes; then
+            SOURCES="$SOURCES $srcdir/src/core/linux/SDL_udev.c"
+        fi
+        # Set up files for evdev input
+        if test x$use_input_events = xyes; then
+            SOURCES="$SOURCES $srcdir/src/input/evdev/*.c"
+        fi
         ;;
     *-*-cygwin* | *-*-mingw32*)
         ARCH=win32

+ 23 - 0
configure.in

@@ -2343,6 +2343,21 @@ dnl Set up the configuration based on the host platform!
 case "$host" in
     *-*-linux*|*-*-uclinux*|*-*-gnu*|*-*-k*bsd*-gnu|*-*-bsdi*|*-*-freebsd*|*-*-dragonfly*|*-*-netbsd*|*-*-openbsd*|*-*-sysv5*|*-*-solaris*|*-*-hpux*|*-*-aix*|*-*-minix*)
         case "$host" in
+            *-raspberry-linux*)
+                # Raspberry Pi
+                ARCH=linux
+                RPI_CFLAGS="-I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux"
+                RPI_LDFLAGS="-L/opt/vc/lib -lbcm_host"
+                CFLAGS="$CFLAGS $RPI_CFLAGS"
+                SDL_CFLAGS="$SDL_CFLAGS $RPI_CFLAGS"
+                EXTRA_CFLAGS="$EXTRA_CFLAGS $RPI_CFLAGS"
+                SDL_LIBS="$SDL_LIBS $RPI_LDFLAGS"
+
+                if test x$enable_video = xyes; then
+                    SOURCES="$SOURCES $srcdir/src/video/raspberry/*.c"
+                    $as_echo "#define SDL_VIDEO_DRIVER_RPI 1" >>confdefs.h
+                fi
+                ;;
             *-*-linux*)         ARCH=linux ;;
             *-*-uclinux*)       ARCH=linux ;;
             *-*-kfreebsd*-gnu)  ARCH=kfreebsd-gnu ;;
@@ -2450,6 +2465,14 @@ case "$host" in
             SOURCES="$SOURCES $srcdir/src/timer/unix/*.c"
             have_timers=yes
         fi
+        # Set up files for udev hotplugging support
+        if test x$enable_libudev = xyes && test x$have_libudev_h_hdr = xyes; then
+            SOURCES="$SOURCES $srcdir/src/core/linux/SDL_udev.c"               
+        fi
+        # Set up files for evdev input
+        if test x$use_input_events = xyes; then
+            SOURCES="$SOURCES $srcdir/src/input/evdev/*.c"               
+        fi
         ;;
     *-*-cygwin* | *-*-mingw32*)
         ARCH=win32

+ 1 - 0
include/SDL_config.h.in

@@ -259,6 +259,7 @@
 #undef SDL_VIDEO_DRIVER_DUMMY
 #undef SDL_VIDEO_DRIVER_WINDOWS
 #undef SDL_VIDEO_DRIVER_X11
+#undef SDL_VIDEO_DRIVER_RPI
 #undef SDL_VIDEO_DRIVER_X11_DYNAMIC
 #undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT
 #undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR

+ 404 - 0
src/core/linux/SDL_udev.c

@@ -0,0 +1,404 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* 
+ * To list the properties of a device, try something like:
+ * udevadm info -a -n snd/hwC0D0 (for a sound card)
+ * udevadm info --query=all -n input/event3 (for a keyboard, mouse, etc)
+ * udevadm info --query=property -n input/event2
+ */
+
+#include "SDL_udev.h"
+
+#ifdef SDL_USE_LIBUDEV
+
+static char* SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
+
+#define _THIS SDL_UDEV_PrivateData *_this
+static _THIS = NULL;
+
+#include "SDL.h"
+
+static SDL_bool SDL_UDEV_load_sym(const char *fn, void **addr);
+static int SDL_UDEV_load_syms(void);
+static SDL_bool SDL_UDEV_hotplug_update_available(void);
+static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev);
+
+static SDL_bool
+SDL_UDEV_load_sym(const char *fn, void **addr)
+{
+    *addr = SDL_LoadFunction(_this->udev_handle, fn);
+    if (*addr == NULL) {
+        /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
+        return SDL_FALSE;
+    }
+
+    return SDL_TRUE;
+}
+
+static int
+SDL_UDEV_load_syms(void)
+{
+    /* cast funcs to char* first, to please GCC's strict aliasing rules. */
+    #define SDL_UDEV_SYM(x) \
+        if (!SDL_UDEV_load_sym(#x, (void **) (char *) & _this->x)) return -1
+
+    SDL_UDEV_SYM(udev_device_get_action);
+    SDL_UDEV_SYM(udev_device_get_devnode);
+    SDL_UDEV_SYM(udev_device_get_subsystem);
+    SDL_UDEV_SYM(udev_device_get_property_value);
+    SDL_UDEV_SYM(udev_device_new_from_syspath);
+    SDL_UDEV_SYM(udev_device_unref);
+    SDL_UDEV_SYM(udev_enumerate_add_match_property);
+    SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
+    SDL_UDEV_SYM(udev_enumerate_get_list_entry);
+    SDL_UDEV_SYM(udev_enumerate_new);
+    SDL_UDEV_SYM(udev_enumerate_scan_devices);
+    SDL_UDEV_SYM(udev_enumerate_unref);
+    SDL_UDEV_SYM(udev_list_entry_get_name);
+    SDL_UDEV_SYM(udev_list_entry_get_next);
+    SDL_UDEV_SYM(udev_monitor_enable_receiving);
+    SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
+    SDL_UDEV_SYM(udev_monitor_get_fd);
+    SDL_UDEV_SYM(udev_monitor_new_from_netlink);
+    SDL_UDEV_SYM(udev_monitor_receive_device);
+    SDL_UDEV_SYM(udev_monitor_unref);
+    SDL_UDEV_SYM(udev_new);
+    SDL_UDEV_SYM(udev_unref);
+    SDL_UDEV_SYM(udev_device_new_from_devnum);
+    SDL_UDEV_SYM(udev_device_get_devnum);
+    #undef SDL_UDEV_SYM
+
+    return 0;
+}
+
+static SDL_bool
+SDL_UDEV_hotplug_update_available(void)
+{
+    if (_this->udev_mon != NULL) {
+        const int fd = _this->udev_monitor_get_fd(_this->udev_mon);
+        fd_set fds;
+        struct timeval tv;
+
+        FD_ZERO(&fds);
+        FD_SET(fd, &fds);
+        tv.tv_sec = 0;
+        tv.tv_usec = 0;
+        if ((select(fd+1, &fds, NULL, NULL, &tv) > 0) && (FD_ISSET(fd, &fds))) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}
+
+
+int
+SDL_UDEV_Init(void)
+{
+    int retval = 0;
+    
+    if (_this == NULL) {
+        _this = (SDL_UDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
+        if(_this == NULL) {
+            return SDL_OutOfMemory();
+        }
+        
+        retval = SDL_UDEV_LoadLibrary();
+        if (retval < 0) {
+            SDL_UDEV_Quit();
+            return retval;
+        }
+        
+        /* Set up udev monitoring 
+         * Listen for input devices (mouse, keyboard, joystick, etc) and sound devices
+         */
+        
+        _this->udev = _this->udev_new();
+        if (_this->udev == NULL) {
+            SDL_UDEV_Quit();
+            return SDL_SetError("udev_new() failed");
+        }
+
+        _this->udev_mon = _this->udev_monitor_new_from_netlink(_this->udev, "udev");
+        if (_this->udev_mon == NULL) {
+            SDL_UDEV_Quit();
+            return SDL_SetError("udev_monitor_new_from_netlink() failed");
+        }
+        
+        _this->udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL);
+        _this->udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL);
+        _this->udev_monitor_enable_receiving(_this->udev_mon);
+        
+        /* Do an initial scan of existing devices */
+        SDL_UDEV_Scan();
+
+    }
+    
+    _this->ref_count += 1;
+    
+    return retval;
+}
+
+void
+SDL_UDEV_Quit(void)
+{
+    SDL_UDEV_CallbackList *item;
+    
+    if (_this == NULL) {
+        return;
+    }
+    
+    _this->ref_count -= 1;
+    
+    if (_this->ref_count < 1) {
+        
+        if (_this->udev_mon != NULL) {
+            _this->udev_monitor_unref(_this->udev_mon);
+            _this->udev_mon = NULL;
+        }
+        if (_this->udev != NULL) {
+            _this->udev_unref(_this->udev);
+            _this->udev = NULL;
+        }
+        
+        /* Remove existing devices */
+        while (_this->first != NULL) {
+            item = _this->first;
+            _this->first = _this->first->next;
+            SDL_free(item);
+        }
+        
+        SDL_UDEV_UnloadLibrary();
+        SDL_free(_this);
+        _this = NULL;
+    }
+}
+
+void
+SDL_UDEV_Scan(void)
+{
+    struct udev_enumerate *enumerate = NULL;
+    struct udev_list_entry *devs = NULL;
+    struct udev_list_entry *item = NULL;  
+    
+    if (_this == NULL) {
+        return;
+    }
+   
+    enumerate = _this->udev_enumerate_new(_this->udev);
+    if (enumerate == NULL) {
+        SDL_UDEV_Quit();
+        SDL_SetError("udev_monitor_new_from_netlink() failed");
+        return;
+    }
+    
+    _this->udev_enumerate_add_match_subsystem(enumerate, "input");
+    _this->udev_enumerate_add_match_subsystem(enumerate, "sound");
+    
+    _this->udev_enumerate_scan_devices(enumerate);
+    devs = _this->udev_enumerate_get_list_entry(enumerate);
+    for (item = devs; item; item = _this->udev_list_entry_get_next(item)) {
+        const char *path = _this->udev_list_entry_get_name(item);
+        struct udev_device *dev = _this->udev_device_new_from_syspath(_this->udev, path);
+        if (dev != NULL) {
+            device_event(SDL_UDEV_DEVICEADDED, dev);
+            _this->udev_device_unref(dev);
+        }
+    }
+
+    _this->udev_enumerate_unref(enumerate);
+}
+
+
+void
+SDL_UDEV_UnloadLibrary(void)
+{
+    if (_this == NULL) {
+        return;
+    }
+    
+    if (_this->udev_handle != NULL) {
+        SDL_UnloadObject(_this->udev_handle);
+        _this->udev_handle = NULL;
+    }
+}
+
+int
+SDL_UDEV_LoadLibrary(void)
+{
+    int retval = 0, i;
+    
+    if (_this == NULL) {
+        return SDL_SetError("UDEV not initialized");
+    }
+    
+   
+    if (_this->udev_handle == NULL) {
+        for( i = 0 ; i < SDL_arraysize(SDL_UDEV_LIBS); i++) {
+            _this->udev_handle = SDL_LoadObject(SDL_UDEV_LIBS[i]);
+            if (_this->udev_handle != NULL) {
+                retval = SDL_UDEV_load_syms();
+                if (retval < 0) {
+                    SDL_UDEV_UnloadLibrary();
+                }
+                else {
+                    break;
+                }
+            }
+        }
+        
+        if (_this->udev_handle == NULL) {
+            retval = -1;
+            /* Don't call SDL_SetError(): SDL_LoadObject already did. */
+        }
+    }
+
+    return retval;
+}
+
+static void 
+device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) 
+{
+    const char *subsystem;
+    const char *val = NULL;
+    SDL_UDEV_deviceclass devclass = 0;
+    const char *path;
+    SDL_UDEV_CallbackList *item;
+    
+    path = _this->udev_device_get_devnode(dev);
+    if (path == NULL) {
+        return;
+    }
+    
+    subsystem = _this->udev_device_get_subsystem(dev);
+    if (SDL_strcmp(subsystem, "sound") == 0) {
+        devclass = SDL_UDEV_DEVICE_SOUND;
+    }
+    else if (SDL_strcmp(subsystem, "input") == 0) {
+        val = _this->udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
+        if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
+            devclass = SDL_UDEV_DEVICE_JOYSTICK;
+        }
+        
+        if (devclass == 0) {
+            val = _this->udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
+            if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
+                devclass = SDL_UDEV_DEVICE_MOUSE;
+            }
+        }
+        
+        if (devclass == 0) {
+            val = _this->udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD");
+            if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
+                devclass = SDL_UDEV_DEVICE_KEYBOARD;
+            }
+        }
+        
+        if (devclass == 0) {
+            return;
+        }
+    }
+    else {
+        return;
+    }
+    
+    /* Process callbacks */
+    for (item = _this->first; item != NULL; item = item->next) {
+        item->callback(type, devclass, path);
+    }
+}
+
+void 
+SDL_UDEV_Poll(void)
+{
+    struct udev_device *dev = NULL;
+    const char *action = NULL;
+
+    if (_this == NULL) {
+        return;
+    }
+
+    while (SDL_UDEV_hotplug_update_available()) {
+        dev = _this->udev_monitor_receive_device(_this->udev_mon);
+        if (dev == NULL) {
+            break;
+        }
+        action = _this->udev_device_get_action(dev);
+
+        if (SDL_strcmp(action, "add") == 0) {
+            device_event(SDL_UDEV_DEVICEADDED, dev);
+        } else if (SDL_strcmp(action, "remove") == 0) {
+            device_event(SDL_UDEV_DEVICEREMOVED, dev);
+        }
+        
+        _this->udev_device_unref(dev);
+    }
+}
+
+int 
+SDL_UDEV_AddCallback(SDL_UDEV_Callback cb)
+{
+    SDL_UDEV_CallbackList *item;
+    item = (SDL_UDEV_CallbackList *) SDL_calloc(1, sizeof (SDL_UDEV_CallbackList));
+    if (item == NULL) {
+        return SDL_OutOfMemory();
+    }
+    
+    item->callback = cb;
+
+    if (_this->last == NULL) {
+        _this->first = _this->last = item;
+    } else {
+        _this->last->next = item;
+        _this->last = item;
+    }
+    
+    return 1;
+}
+
+void 
+SDL_UDEV_DelCallback(SDL_UDEV_Callback cb)
+{
+    SDL_UDEV_CallbackList *item;
+    SDL_UDEV_CallbackList *prev = NULL;
+
+    for (item = _this->first; item != NULL; item = item->next) {
+        /* found it, remove it. */
+        if (item->callback == cb) {
+            if (prev != NULL) {
+                prev->next = item->next;
+            } else {
+                SDL_assert(_this->first == item);
+                _this->first = item->next;
+            }
+            if (item == _this->last) {
+                _this->last = prev;
+            }
+            SDL_free(item);
+            return;
+        }
+        prev = item;
+    }
+    
+}
+
+
+#endif /* SDL_USE_LIBUDEV */

+ 114 - 0
src/core/linux/SDL_udev.h

@@ -0,0 +1,114 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+
+#ifndef _SDL_udev_h
+#define _SDL_udev_h
+
+#if HAVE_LIBUDEV_H
+
+#ifndef SDL_USE_LIBUDEV
+#define SDL_USE_LIBUDEV 1
+#endif
+
+#include "SDL_loadso.h"
+#include "SDL_events.h"
+#include <libudev.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+/**
+ *  \brief Device type
+ */
+
+typedef enum
+{
+    SDL_UDEV_DEVICEADDED = 0x0001,
+    SDL_UDEV_DEVICEREMOVED
+} SDL_UDEV_deviceevent;
+
+typedef enum
+{
+    SDL_UDEV_DEVICE_MOUSE = 0x0001,
+    SDL_UDEV_DEVICE_KEYBOARD,
+    SDL_UDEV_DEVICE_JOYSTICK,
+    SDL_UDEV_DEVICE_SOUND
+} SDL_UDEV_deviceclass;
+
+typedef void (*SDL_UDEV_Callback)(SDL_UDEV_deviceevent udev_type, SDL_UDEV_deviceclass udev_class, const char *devpath);
+
+typedef struct SDL_UDEV_CallbackList {
+    SDL_UDEV_Callback callback;
+    struct SDL_UDEV_CallbackList *next;
+} SDL_UDEV_CallbackList;
+
+typedef struct SDL_UDEV_PrivateData
+{
+    const char *udev_library;
+    void *udev_handle;
+    struct udev *udev;
+    struct udev_monitor *udev_mon;
+    int ref_count;
+    SDL_UDEV_CallbackList *first, *last;
+    
+    /* Function pointers */
+    const char *(*udev_device_get_action)(struct udev_device *);
+    const char *(*udev_device_get_devnode)(struct udev_device *);
+    const char *(*udev_device_get_subsystem)(struct udev_device *);
+    const char *(*udev_device_get_property_value)(struct udev_device *, const char *);
+    struct udev_device *(*udev_device_new_from_syspath)(struct udev *, const char *);
+    void (*udev_device_unref)(struct udev_device *);
+    int (*udev_enumerate_add_match_property)(struct udev_enumerate *, const char *, const char *);
+    int (*udev_enumerate_add_match_subsystem)(struct udev_enumerate *, const char *);
+    struct udev_list_entry *(*udev_enumerate_get_list_entry)(struct udev_enumerate *);
+    struct udev_enumerate *(*udev_enumerate_new)(struct udev *);
+    int (*udev_enumerate_scan_devices)(struct udev_enumerate *);
+    void (*udev_enumerate_unref)(struct udev_enumerate *);
+    const char *(*udev_list_entry_get_name)(struct udev_list_entry *);
+    struct udev_list_entry *(*udev_list_entry_get_next)(struct udev_list_entry *);
+    int (*udev_monitor_enable_receiving)(struct udev_monitor *);
+    int (*udev_monitor_filter_add_match_subsystem_devtype)(struct udev_monitor *, const char *, const char *);
+    int (*udev_monitor_get_fd)(struct udev_monitor *);
+    struct udev_monitor *(*udev_monitor_new_from_netlink)(struct udev *, const char *);
+    struct udev_device *(*udev_monitor_receive_device)(struct udev_monitor *);
+    void (*udev_monitor_unref)(struct udev_monitor *);
+    struct udev *(*udev_new)(void);
+    void (*udev_unref)(struct udev *);
+    struct udev_device * (*udev_device_new_from_devnum)(struct udev *udev, char type, dev_t devnum);
+    dev_t (*udev_device_get_devnum) (struct udev_device *udev_device);
+} SDL_UDEV_PrivateData;
+
+extern int SDL_UDEV_Init(void);
+extern void SDL_UDEV_Quit(void);
+extern void SDL_UDEV_UnloadLibrary(void);
+extern int SDL_UDEV_LoadLibrary(void);
+extern void SDL_UDEV_Poll(void);
+extern void SDL_UDEV_Scan(void);
+extern int SDL_UDEV_AddCallback(SDL_UDEV_Callback cb);
+extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb);
+
+
+
+
+#endif /* HAVE_LIBUDEV_H */
+
+#endif /* _SDL_udev_h */

+ 0 - 2
src/events/SDL_mouse.c

@@ -246,13 +246,11 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
     mouse->xdelta += xrel;
     mouse->ydelta += yrel;
 
-#if 0 /* FIXME */
     /* Move the mouse cursor, if needed */
     if (mouse->cursor_shown && !mouse->relative_mode &&
         mouse->MoveCursor && mouse->cur_cursor) {
         mouse->MoveCursor(mouse->cur_cursor);
     }
-#endif
 
     /* Post the event, if desired */
     posted = 0;

+ 646 - 0
src/input/evdev/SDL_evdev.c

@@ -0,0 +1,646 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#ifdef SDL_INPUT_LINUXEV
+
+/* This is based on the linux joystick driver */
+/* References: https://www.kernel.org/doc/Documentation/input/input.txt 
+ *             https://www.kernel.org/doc/Documentation/input/event-codes.txt
+ *             /usr/include/linux/input.h
+ *             The evtest application is also useful to debug the protocol
+ */
+
+
+#include "SDL_evdev.h"
+#define _THIS SDL_EVDEV_PrivateData *_this
+static _THIS = NULL;
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <limits.h>             /* For the definition of PATH_MAX */
+
+
+#include "SDL.h"
+#include "SDL_assert.h"
+#include "SDL_endian.h"
+#include "../../core/linux/SDL_udev.h"
+#include "SDL_scancode.h"
+#include "../../events/SDL_events_c.h"
+
+/* This isn't defined in older Linux kernel headers */
+#ifndef SYN_DROPPED
+#define SYN_DROPPED 3
+#endif
+
+
+static int SDL_EVDEV_device_removed(const char *devpath);
+static int SDL_EVDEV_device_added(const SDL_UDEV_deviceclass devclass, const char *devpath);
+static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
+static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
+void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, SDL_UDEV_deviceclass udev_class, const char *devpath);
+
+static SDL_Scancode EVDEV_Keycodes[] = {
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_RESERVED        0 */
+    SDL_SCANCODE_ESCAPE,        /*  KEY_ESC         1 */
+    SDL_SCANCODE_1,             /*  KEY_1           2 */
+    SDL_SCANCODE_2,             /*  KEY_2           3 */
+    SDL_SCANCODE_3,             /*  KEY_3           4 */
+    SDL_SCANCODE_4,             /*  KEY_4           5 */
+    SDL_SCANCODE_5,             /*  KEY_5           6 */
+    SDL_SCANCODE_6,             /*  KEY_6           7 */
+    SDL_SCANCODE_7,             /*  KEY_7           8 */
+    SDL_SCANCODE_8,             /*  KEY_8           9 */
+    SDL_SCANCODE_9,             /*  KEY_9           10 */
+    SDL_SCANCODE_0,             /*  KEY_0           11 */
+    SDL_SCANCODE_MINUS,         /*  KEY_MINUS       12 */
+    SDL_SCANCODE_EQUALS,        /*  KEY_EQUAL       13 */
+    SDL_SCANCODE_BACKSPACE,     /*  KEY_BACKSPACE       14 */
+    SDL_SCANCODE_TAB,           /*  KEY_TAB         15 */
+    SDL_SCANCODE_Q,             /*  KEY_Q           16 */
+    SDL_SCANCODE_W,             /*  KEY_W           17 */
+    SDL_SCANCODE_E,             /*  KEY_E           18 */
+    SDL_SCANCODE_R,             /*  KEY_R           19 */
+    SDL_SCANCODE_T,             /*  KEY_T           20 */
+    SDL_SCANCODE_Y,             /*  KEY_Y           21 */
+    SDL_SCANCODE_U,             /*  KEY_U           22 */
+    SDL_SCANCODE_I,             /*  KEY_I           23 */
+    SDL_SCANCODE_O,             /*  KEY_O           24 */
+    SDL_SCANCODE_P,             /*  KEY_P           25 */
+    SDL_SCANCODE_LEFTBRACKET,   /*  KEY_LEFTBRACE       26 */
+    SDL_SCANCODE_RIGHTBRACKET,  /*  KEY_RIGHTBRACE      27 */
+    SDL_SCANCODE_RETURN,        /*  KEY_ENTER       28 */
+    SDL_SCANCODE_LCTRL,         /*  KEY_LEFTCTRL        29 */
+    SDL_SCANCODE_A,             /*  KEY_A           30 */
+    SDL_SCANCODE_S,             /*  KEY_S           31 */
+    SDL_SCANCODE_D,             /*  KEY_D           32 */
+    SDL_SCANCODE_F,             /*  KEY_F           33 */
+    SDL_SCANCODE_G,             /*  KEY_G           34 */
+    SDL_SCANCODE_H,             /*  KEY_H           35 */
+    SDL_SCANCODE_J,             /*  KEY_J           36 */
+    SDL_SCANCODE_K,             /*  KEY_K           37 */
+    SDL_SCANCODE_L,             /*  KEY_L           38 */
+    SDL_SCANCODE_SEMICOLON,     /*  KEY_SEMICOLON       39 */
+    SDL_SCANCODE_APOSTROPHE,    /*  KEY_APOSTROPHE      40 */
+    SDL_SCANCODE_GRAVE,         /*  KEY_GRAVE       41 */
+    SDL_SCANCODE_LSHIFT,        /*  KEY_LEFTSHIFT       42 */
+    SDL_SCANCODE_BACKSLASH,     /*  KEY_BACKSLASH       43 */
+    SDL_SCANCODE_Z,             /*  KEY_Z           44 */
+    SDL_SCANCODE_X,             /*  KEY_X           45 */
+    SDL_SCANCODE_C,             /*  KEY_C           46 */
+    SDL_SCANCODE_V,             /*  KEY_V           47 */
+    SDL_SCANCODE_B,             /*  KEY_B           48 */
+    SDL_SCANCODE_N,             /*  KEY_N           49 */
+    SDL_SCANCODE_M,             /*  KEY_M           50 */
+    SDL_SCANCODE_COMMA,         /*  KEY_COMMA       51 */
+    SDL_SCANCODE_PERIOD,        /*  KEY_DOT         52 */
+    SDL_SCANCODE_SLASH,         /*  KEY_SLASH       53 */
+    SDL_SCANCODE_RSHIFT,        /*  KEY_RIGHTSHIFT      54 */
+    SDL_SCANCODE_KP_MULTIPLY,   /*  KEY_KPASTERISK      55 */
+    SDL_SCANCODE_LALT,          /*  KEY_LEFTALT     56 */
+    SDL_SCANCODE_SPACE,         /*  KEY_SPACE       57 */
+    SDL_SCANCODE_CAPSLOCK,      /*  KEY_CAPSLOCK        58 */
+    SDL_SCANCODE_F1,            /*  KEY_F1          59 */
+    SDL_SCANCODE_F2,            /*  KEY_F2          60 */
+    SDL_SCANCODE_F3,            /*  KEY_F3          61 */
+    SDL_SCANCODE_F4,            /*  KEY_F4          62 */
+    SDL_SCANCODE_F5,            /*  KEY_F5          63 */
+    SDL_SCANCODE_F6,            /*  KEY_F6          64 */
+    SDL_SCANCODE_F7,            /*  KEY_F7          65 */
+    SDL_SCANCODE_F8,            /*  KEY_F8          66 */
+    SDL_SCANCODE_F9,            /*  KEY_F9          67 */
+    SDL_SCANCODE_F10,           /*  KEY_F10         68 */
+    SDL_SCANCODE_NUMLOCKCLEAR,  /*  KEY_NUMLOCK     69 */
+    SDL_SCANCODE_SCROLLLOCK,    /*  KEY_SCROLLLOCK      70 */
+    SDL_SCANCODE_KP_7,          /*  KEY_KP7         71 */
+    SDL_SCANCODE_KP_8,          /*  KEY_KP8         72 */
+    SDL_SCANCODE_KP_9,          /*  KEY_KP9         73 */
+    SDL_SCANCODE_KP_MINUS,      /*  KEY_KPMINUS     74 */
+    SDL_SCANCODE_KP_4,          /*  KEY_KP4         75 */
+    SDL_SCANCODE_KP_5,          /*  KEY_KP5         76 */
+    SDL_SCANCODE_KP_6,          /*  KEY_KP6         77 */
+    SDL_SCANCODE_KP_PLUS,       /*  KEY_KPPLUS      78 */
+    SDL_SCANCODE_KP_1,          /*  KEY_KP1         79 */
+    SDL_SCANCODE_KP_2,          /*  KEY_KP2         80 */
+    SDL_SCANCODE_KP_3,          /*  KEY_KP3         81 */
+    SDL_SCANCODE_KP_0,          /*  KEY_KP0         82 */
+    SDL_SCANCODE_KP_PERIOD,     /*  KEY_KPDOT       83 */
+    SDL_SCANCODE_UNKNOWN,       /*  84 */
+    SDL_SCANCODE_LANG5,         /*  KEY_ZENKAKUHANKAKU  85 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_102ND       86 */
+    SDL_SCANCODE_F11,           /*  KEY_F11         87 */
+    SDL_SCANCODE_F12,           /*  KEY_F12         88 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_RO          89 */
+    SDL_SCANCODE_LANG3,         /*  KEY_KATAKANA        90 */
+    SDL_SCANCODE_LANG4,         /*  KEY_HIRAGANA        91 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_HENKAN      92 */
+    SDL_SCANCODE_LANG3,         /*  KEY_KATAKANAHIRAGANA    93 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_MUHENKAN        94 */
+    SDL_SCANCODE_KP_COMMA,      /*  KEY_KPJPCOMMA       95 */
+    SDL_SCANCODE_KP_ENTER,      /*  KEY_KPENTER     96 */
+    SDL_SCANCODE_RCTRL,         /*  KEY_RIGHTCTRL       97 */
+    SDL_SCANCODE_KP_DIVIDE,     /*  KEY_KPSLASH     98 */
+    SDL_SCANCODE_SYSREQ,        /*  KEY_SYSRQ       99 */
+    SDL_SCANCODE_RALT,          /*  KEY_RIGHTALT        100 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_LINEFEED        101 */
+    SDL_SCANCODE_HOME,          /*  KEY_HOME        102 */
+    SDL_SCANCODE_UP,            /*  KEY_UP          103 */
+    SDL_SCANCODE_PAGEUP,        /*  KEY_PAGEUP      104 */
+    SDL_SCANCODE_LEFT,          /*  KEY_LEFT        105 */
+    SDL_SCANCODE_RIGHT,         /*  KEY_RIGHT       106 */
+    SDL_SCANCODE_END,           /*  KEY_END         107 */
+    SDL_SCANCODE_DOWN,          /*  KEY_DOWN        108 */
+    SDL_SCANCODE_PAGEDOWN,      /*  KEY_PAGEDOWN        109 */
+    SDL_SCANCODE_INSERT,        /*  KEY_INSERT      110 */
+    SDL_SCANCODE_DELETE,        /*  KEY_DELETE      111 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_MACRO       112 */
+    SDL_SCANCODE_MUTE,          /*  KEY_MUTE        113 */
+    SDL_SCANCODE_VOLUMEDOWN,    /*  KEY_VOLUMEDOWN      114 */
+    SDL_SCANCODE_VOLUMEUP,      /*  KEY_VOLUMEUP        115 */
+    SDL_SCANCODE_POWER,         /*  KEY_POWER       116 SC System Power Down */
+    SDL_SCANCODE_KP_EQUALS,     /*  KEY_KPEQUAL     117 */
+    SDL_SCANCODE_KP_MINUS,      /*  KEY_KPPLUSMINUS     118 */
+    SDL_SCANCODE_PAUSE,         /*  KEY_PAUSE       119 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SCALE       120 AL Compiz Scale (Expose) */
+    SDL_SCANCODE_KP_COMMA,      /*  KEY_KPCOMMA     121 */
+    SDL_SCANCODE_LANG1,         /*  KEY_HANGEUL,KEY_HANGUEL 122 */
+    SDL_SCANCODE_LANG2,         /*  KEY_HANJA       123 */
+    SDL_SCANCODE_INTERNATIONAL3,/*  KEY_YEN         124 */
+    SDL_SCANCODE_LGUI,          /*  KEY_LEFTMETA        125 */
+    SDL_SCANCODE_RGUI,          /*  KEY_RIGHTMETA       126 */
+    SDL_SCANCODE_APPLICATION,   /*  KEY_COMPOSE     127 */
+    SDL_SCANCODE_STOP,          /*  KEY_STOP        128 AC Stop */
+    SDL_SCANCODE_AGAIN,         /*  KEY_AGAIN       129 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_PROPS       130 AC Properties */
+    SDL_SCANCODE_UNDO,          /*  KEY_UNDO        131 AC Undo */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_FRONT       132 */
+    SDL_SCANCODE_COPY,          /*  KEY_COPY        133 AC Copy */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_OPEN        134 AC Open */
+    SDL_SCANCODE_PASTE,         /*  KEY_PASTE       135 AC Paste */
+    SDL_SCANCODE_FIND,          /*  KEY_FIND        136 AC Search */
+    SDL_SCANCODE_CUT,           /*  KEY_CUT         137 AC Cut */
+    SDL_SCANCODE_HELP,          /*  KEY_HELP        138 AL Integrated Help Center */
+    SDL_SCANCODE_MENU,          /*  KEY_MENU        139 Menu (show menu) */
+    SDL_SCANCODE_CALCULATOR,    /*  KEY_CALC        140 AL Calculator */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SETUP       141 */
+    SDL_SCANCODE_SLEEP,         /*  KEY_SLEEP       142 SC System Sleep */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_WAKEUP      143 System Wake Up */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_FILE        144 AL Local Machine Browser */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SENDFILE        145 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_DELETEFILE      146 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_XFER        147 */
+    SDL_SCANCODE_APP1,          /*  KEY_PROG1       148 */
+    SDL_SCANCODE_APP1,          /*  KEY_PROG2       149 */
+    SDL_SCANCODE_WWW,           /*  KEY_WWW         150 AL Internet Browser */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_MSDOS       151 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_COFFEE,KEY_SCREENLOCK      152 AL Terminal Lock/Screensaver */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_DIRECTION       153 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_CYCLEWINDOWS    154 */
+    SDL_SCANCODE_MAIL,          /*  KEY_MAIL        155 */
+    SDL_SCANCODE_AC_BOOKMARKS,  /*  KEY_BOOKMARKS       156 AC Bookmarks */
+    SDL_SCANCODE_COMPUTER,      /*  KEY_COMPUTER        157 */
+    SDL_SCANCODE_AC_BACK,       /*  KEY_BACK        158 AC Back */
+    SDL_SCANCODE_AC_FORWARD,    /*  KEY_FORWARD     159 AC Forward */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_CLOSECD     160 */
+    SDL_SCANCODE_EJECT,         /*  KEY_EJECTCD     161 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_EJECTCLOSECD    162 */
+    SDL_SCANCODE_AUDIONEXT,     /*  KEY_NEXTSONG        163 */
+    SDL_SCANCODE_AUDIOPLAY,     /*  KEY_PLAYPAUSE       164 */
+    SDL_SCANCODE_AUDIOPREV,     /*  KEY_PREVIOUSSONG    165 */
+    SDL_SCANCODE_AUDIOSTOP,     /*  KEY_STOPCD      166 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_RECORD      167 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_REWIND      168 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_PHONE       169 Media Select Telephone */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_ISO         170 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_CONFIG      171 AL Consumer Control Configuration */
+    SDL_SCANCODE_AC_HOME,       /*  KEY_HOMEPAGE        172 AC Home */
+    SDL_SCANCODE_AC_REFRESH,    /*  KEY_REFRESH     173 AC Refresh */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_EXIT        174 AC Exit */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_MOVE        175 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_EDIT        176 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SCROLLUP        177 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SCROLLDOWN      178 */
+    SDL_SCANCODE_KP_LEFTPAREN,  /*  KEY_KPLEFTPAREN     179 */
+    SDL_SCANCODE_KP_RIGHTPAREN, /*  KEY_KPRIGHTPAREN    180 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_NEW         181 AC New */
+    SDL_SCANCODE_AGAIN,         /*  KEY_REDO        182 AC Redo/Repeat */
+    SDL_SCANCODE_F13,           /*  KEY_F13         183 */
+    SDL_SCANCODE_F14,           /*  KEY_F14         184 */
+    SDL_SCANCODE_F15,           /*  KEY_F15         185 */
+    SDL_SCANCODE_F16,           /*  KEY_F16         186 */
+    SDL_SCANCODE_F17,           /*  KEY_F17         187 */
+    SDL_SCANCODE_F18,           /*  KEY_F18         188 */
+    SDL_SCANCODE_F19,           /*  KEY_F19         189 */
+    SDL_SCANCODE_F20,           /*  KEY_F20         190 */
+    SDL_SCANCODE_F21,           /*  KEY_F21         191 */
+    SDL_SCANCODE_F22,           /*  KEY_F22         192 */
+    SDL_SCANCODE_F23,           /*  KEY_F23         193 */
+    SDL_SCANCODE_F24,           /*  KEY_F24         194 */
+    SDL_SCANCODE_UNKNOWN,       /*  195 */
+    SDL_SCANCODE_UNKNOWN,       /*  196 */
+    SDL_SCANCODE_UNKNOWN,       /*  197 */
+    SDL_SCANCODE_UNKNOWN,       /*  198 */
+    SDL_SCANCODE_UNKNOWN,       /*  199 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_PLAYCD      200 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_PAUSECD     201 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_PROG3       202 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_PROG4       203 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_DASHBOARD       204 AL Dashboard */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SUSPEND     205 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_CLOSE       206 AC Close */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_PLAY        207 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_FASTFORWARD     208 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_BASSBOOST       209 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_PRINT       210 AC Print */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_HP          211 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_CAMERA      212 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SOUND       213 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_QUESTION        214 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_EMAIL       215 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_CHAT        216 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SEARCH      217 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_CONNECT     218 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_FINANCE     219 AL Checkbook/Finance */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SPORT       220 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SHOP        221 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_ALTERASE        222 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_CANCEL      223 AC Cancel */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_BRIGHTNESSDOWN  224 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_BRIGHTNESSUP    225 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_MEDIA       226 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SWITCHVIDEOMODE 227 Cycle between available video outputs (Monitor/LCD/TV-out/etc) */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_KBDILLUMTOGGLE  228 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_KBDILLUMDOWN    229 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_KBDILLUMUP      230 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SEND        231 AC Send */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_REPLY       232 AC Reply */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_FORWARDMAIL     233 AC Forward Msg */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_SAVE        234 AC Save */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_DOCUMENTS       235 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_BATTERY     236  */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_BLUETOOTH       237 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_WLAN        238 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_UWB         239 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_UNKNOWN     240 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_VIDEO_NEXT      241 drive next video source */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_VIDEO_PREV      242 drive previous video source */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_BRIGHTNESS_CYCLE    243 brightness up, after max is min */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_BRIGHTNESS_ZERO 244 brightness off, use ambient */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_DISPLAY_OFF     245 display device to off state */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_WIMAX       246 */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_RFKILL      247 Key that controls all radios */
+    SDL_SCANCODE_UNKNOWN,       /*  KEY_MICMUTE     248 Mute / unmute the microphone */
+};
+
+static Uint8 EVDEV_MouseButtons[] = {
+    SDL_BUTTON_LEFT,            /*  BTN_LEFT        0x110 */
+    SDL_BUTTON_RIGHT,           /*  BTN_RIGHT       0x111 */
+    SDL_BUTTON_MIDDLE,          /*  BTN_MIDDLE      0x112 */
+    SDL_BUTTON_X1,              /*  BTN_SIDE        0x113 */
+    SDL_BUTTON_X2,              /*  BTN_EXTRA       0x114 */
+    SDL_BUTTON_X2 + 1,          /*  BTN_FORWARD     0x115 */
+    SDL_BUTTON_X2 + 2,          /*  BTN_BACK        0x116 */
+    SDL_BUTTON_X2 + 3           /*  BTN_TASK        0x117 */
+};
+
+int
+SDL_EVDEV_Init(void)
+{
+    int retval = 0;
+    
+    if (_this == NULL) {
+        _this = (SDL_EVDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
+        if(_this == NULL) {
+            return SDL_OutOfMemory();
+        }
+
+#if SDL_USE_LIBUDEV
+        if (SDL_UDEV_Init() < 0) {
+            SDL_free(_this);
+            _this = NULL;
+            return -1;
+        }
+
+        /* Set up the udev callback */
+        if ( SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
+            SDL_EVDEV_Quit();
+            return -1;
+        }
+        
+        /* Force a scan to build the initial device list */
+        SDL_UDEV_Scan();
+#else
+        /* TODO: Scan the devices manually, like a caveman */
+#endif /* SDL_USE_LIBUDEV */
+
+    }
+    
+    _this->ref_count += 1;
+    
+    return retval;
+}
+
+void
+SDL_EVDEV_Quit(void)
+{
+    if (_this == NULL) {
+        return;
+    }
+    
+    _this->ref_count -= 1;
+    
+    if (_this->ref_count < 1) {
+        
+#if SDL_USE_LIBUDEV
+        SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
+        SDL_UDEV_Quit();
+#endif /* SDL_USE_LIBUDEV */
+       
+        /* Remove existing devices */
+        while(_this->first != NULL) {
+            SDL_EVDEV_device_removed(_this->first->path);
+        }
+        
+        SDL_assert(_this->first == NULL);
+        SDL_assert(_this->last == NULL);
+        SDL_assert(_this->numdevices == 0);
+        
+        SDL_free(_this);
+        _this = NULL;
+    }
+}
+
+void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, SDL_UDEV_deviceclass udev_class, const char *devpath)
+{
+    SDL_EVDEV_deviceclass devclass;
+    
+    if (devpath == NULL) {
+        return;
+    }
+    
+    switch( udev_class )
+    {
+        case SDL_UDEV_DEVICE_MOUSE:
+            devclass = SDL_EVDEV_DEVICE_MOUSE;
+            break;
+            
+        case SDL_UDEV_DEVICE_KEYBOARD:
+            devclass = SDL_EVDEV_DEVICE_KEYBOARD;
+            break;
+            
+        default:
+            return;
+    }
+    
+    switch( udev_type )
+    {
+        case SDL_UDEV_DEVICEADDED:
+            SDL_EVDEV_device_added(devclass, devpath);
+            break;
+            
+        case SDL_UDEV_DEVICEREMOVED:
+            SDL_EVDEV_device_removed(devpath);
+            break;
+            
+        default:
+            break;
+            
+    }
+    
+}
+
+void 
+SDL_EVDEV_Poll(void)
+{
+    struct input_event events[32];
+    int i, len;
+    SDL_evdevlist_item *item;
+    SDL_Scancode scan_code;
+    int mouse_button;
+    SDL_Mouse *mouse;
+    
+#if SDL_USE_LIBUDEV
+    SDL_UDEV_Poll();
+#endif
+    
+    for (item = _this->first; item != NULL; item = item->next) {
+        while ((len = read(item->fd, events, (sizeof events))) > 0) {
+            len /= sizeof(events[0]);
+            for (i = 0; i < len; ++i) {
+                switch(item->devclass) {
+                    case SDL_EVDEV_DEVICE_KEYBOARD:
+                        switch (events[i].type) {
+                            case EV_KEY:
+                                scan_code = SDL_EVDEV_translate_keycode(events[i].code);
+                                if (scan_code != SDL_SCANCODE_UNKNOWN) {
+                                    if (events[i].value == 0) {
+                                        SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
+                                    }
+                                    else if (events[i].value == 1) {
+                                        SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
+                                    }
+                                    else if (events[i].value == 2) {
+                                        /* Key repeated */
+                                        SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
+                                    }
+                                }
+                                break;
+
+                            default:
+                                break;
+                        }
+                        break; /* SDL_EVDEV_DEVICE_KEYBOARD */
+                        
+                    case SDL_EVDEV_DEVICE_MOUSE:
+                        mouse = SDL_GetMouse();
+                        switch (events[i].type) {
+                            case EV_KEY:
+                                mouse_button = events[i].code - BTN_MOUSE;
+                                if (mouse_button >= 0 && mouse_button < SDL_arraysize(EVDEV_MouseButtons)) {
+                                    if (events[i].value == 0) {
+                                        SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
+                                    }
+                                    else if (events[i].value == 1) {
+                                        SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
+                                    } 
+                                }
+                                break;
+                            case EV_ABS:
+                                 switch(events[i].code) {
+                                    case ABS_X:
+                                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
+                                        break;
+                                    case ABS_Y:
+                                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
+                                        break;
+                                    default:
+                                        break;
+                                 }
+                                break;
+                            case EV_REL:
+                                switch(events[i].code) {
+                                    case REL_X:
+                                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
+                                        break;
+                                    case REL_Y:
+                                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
+                                        break;
+                                    case REL_WHEEL:
+                                        SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value);
+                                        break;
+                                    case REL_HWHEEL:
+                                        SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0);
+                                        break;
+                                    default:
+                                        break;
+                                }
+                                break;
+                            default:
+                                break;
+                        }
+                        break; /* SDL_EVDEV_DEVICE_MOUSE */                    
+
+                    default:
+                        break;
+                }
+                
+                
+                /* Handle events not specific to any type of device */
+                switch (events[i].type) {
+                    case EV_SYN:
+                        switch (events[i].code) {
+                        case SYN_DROPPED :
+                            SDL_EVDEV_sync_device(item);
+                            break;
+                        default:
+                            break;
+                        }
+                }
+            
+            }
+        }    
+    }
+}
+
+static SDL_Scancode
+SDL_EVDEV_translate_keycode(int keycode)
+{
+    SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
+
+    if (keycode < SDL_arraysize(EVDEV_Keycodes)) {
+        scancode = EVDEV_Keycodes[keycode];
+    }
+    if (scancode == SDL_SCANCODE_UNKNOWN) {
+        SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL mailing list <sdl@libsdl.org> EVDEV KeyCode %d \n", keycode);
+    }
+    return scancode;
+}
+
+static void
+SDL_EVDEV_sync_device(SDL_evdevlist_item *item) 
+{
+    /* TODO: get full state of device and report whatever is required */
+}
+
+static int
+SDL_EVDEV_device_added(const SDL_UDEV_deviceclass devclass, const char *devpath)
+{
+    SDL_evdevlist_item *item;
+
+    /* Check to make sure it's not already in list. */
+    for (item = _this->first; item != NULL; item = item->next) {
+        if (strcmp(devpath, item->path) == 0) {
+            return -1;  /* already have this one */
+        }
+    }
+    
+    item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
+    if (item == NULL) {
+        return SDL_OutOfMemory();
+    }
+
+    item->devclass = devclass;
+    
+   
+    item->fd = open(devpath, O_RDONLY, 0);
+    if (item->fd < 0) {
+        SDL_free(item);
+        return SDL_SetError("Unable to open %s", devpath);
+    }
+    
+    item->path = SDL_strdup(devpath);
+    if (item->path == NULL) {
+        close(item->fd);
+        SDL_free(item);
+        return SDL_OutOfMemory();
+    }
+    
+    /* Non blocking read mode */
+    fcntl(item->fd, F_SETFL, O_NONBLOCK);
+    
+    if (_this->last == NULL) {
+        _this->first = _this->last = item;
+    } else {
+        _this->last->next = item;
+        _this->last = item;
+    }
+    
+    SDL_EVDEV_sync_device(item);
+    
+    return _this->numdevices++;
+}
+
+
+static int
+SDL_EVDEV_device_removed(const char *devpath)
+{
+    SDL_evdevlist_item *item;
+    SDL_evdevlist_item *prev = NULL;
+
+    for (item = _this->first; item != NULL; item = item->next) {
+        /* found it, remove it. */
+        if ( strcmp(devpath, item->path) ==0 ) {
+            if (prev != NULL) {
+                prev->next = item->next;
+            } else {
+                SDL_assert(_this->first == item);
+                _this->first = item->next;
+            }
+            if (item == _this->last) {
+                _this->last = prev;
+            }
+            close(item->fd);
+            SDL_free(item->path);
+            SDL_free(item);
+            _this->numdevices--;
+            return 0;
+        }
+        prev = item;
+    }
+
+    return -1;
+}
+
+#endif /* SDL_INPUT_LINUXEV */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 65 - 0
src/input/evdev/SDL_evdev.h

@@ -0,0 +1,65 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <linux/input.h>
+
+#include "SDL_config.h"
+
+#ifndef _SDL_evdev_h
+#define _SDL_evdev_h
+
+#ifdef SDL_INPUT_LINUXEV
+
+#include "SDL_events.h"
+#include <sys/stat.h>
+
+typedef enum
+{
+    SDL_EVDEV_DEVICE_MOUSE = 0x0001,
+    SDL_EVDEV_DEVICE_KEYBOARD
+} SDL_EVDEV_deviceclass;
+
+typedef struct SDL_evdevlist_item
+{
+    char *path;
+    int fd;
+    SDL_EVDEV_deviceclass devclass;
+    struct SDL_evdevlist_item *next;   
+} SDL_evdevlist_item;
+
+typedef struct SDL_EVDEV_PrivateData
+{
+    SDL_evdevlist_item *first;
+    SDL_evdevlist_item *last;
+    int numdevices;
+    int ref_count;
+} SDL_EVDEV_PrivateData;
+
+extern int SDL_EVDEV_Init(void);
+extern void SDL_EVDEV_Quit(void);
+extern void SDL_EVDEV_Poll(void);
+
+
+#endif /* SDL_INPUT_LINUXEV */
+
+#endif /* _SDL_evdev_h */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 50 - 42
src/video/SDL_egl.c

@@ -25,13 +25,20 @@
 #include "SDL_sysvideo.h"
 #include "SDL_egl.h"
 
-#define DEFAULT_EGL "libEGL.so"
-#define DEFAULT_OGL_ES2 "libGLESv2.so"
-#define DEFAULT_OGL_ES_PVR "libGLES_CM.so"
-#define DEFAULT_OGL_ES "libGLESv1_CM.so"
+#if SDL_VIDEO_DRIVER_RPI
+#define DEFAULT_EGL "/opt/vc/lib/libEGL.so"
+#define DEFAULT_OGL_ES2 "/opt/vc/lib/libGLESv2.so"
+#define DEFAULT_OGL_ES_PVR "/opt/vc/lib/libGLES_CM.so"
+#define DEFAULT_OGL_ES "/opt/vc/lib/libGLESv1_CM.so"
+#else
+#define DEFAULT_EGL "libEGL.so.1"
+#define DEFAULT_OGL_ES2 "libGLESv2.so.2"
+#define DEFAULT_OGL_ES_PVR "libGLES_CM.so.1"
+#define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
+#endif /* SDL_VIDEO_DRIVER_RPI */
 
 #define LOAD_FUNC(NAME) \
-*((void**)&_this->egl_data->NAME) = dlsym(handle, #NAME); \
+*((void**)&_this->egl_data->NAME) = dlsym(dll_handle, #NAME); \
 if (!_this->egl_data->NAME) \
 { \
     return SDL_SetError("Could not retrieve EGL function " #NAME); \
@@ -88,9 +95,10 @@ SDL_EGL_UnloadLibrary(_THIS)
 }
 
 int
-SDL_EGL_LoadLibrary(_THIS, const char *path, NativeDisplayType native_display)
+SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display)
 {
-    void *handle;
+    void *dll_handle, *egl_dll_handle; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */
+    char *path;
     int dlopen_flags;
     
     if (_this->egl_data) {
@@ -105,22 +113,44 @@ SDL_EGL_LoadLibrary(_THIS, const char *path, NativeDisplayType native_display)
     #else
     dlopen_flags = RTLD_LAZY;
     #endif
-    handle = dlopen(path, dlopen_flags);
+    
+    /* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */
+    path = getenv("SDL_VIDEO_GL_DRIVER");
+    egl_dll_handle = dlopen(path, dlopen_flags);
+    if ((path == NULL) | (egl_dll_handle == NULL)) {
+        if (_this->gl_config.major_version > 1) {
+            path = DEFAULT_OGL_ES2;
+            egl_dll_handle = dlopen(path, dlopen_flags);
+        } else {
+            path = DEFAULT_OGL_ES;
+            egl_dll_handle = dlopen(path, dlopen_flags);
+            if (egl_dll_handle == NULL) {
+                path = DEFAULT_OGL_ES_PVR;
+                egl_dll_handle = dlopen(path, dlopen_flags);
+            }
+        }
+    }
+
+    if (egl_dll_handle == NULL) {
+        return SDL_SetError("Could not initialize OpenGL ES library: %s", dlerror());
+    }
+    
+    /* Loading libGL* in the previous step took care of loading libEGL.so, but we future proof by double checking */
+    dll_handle = dlopen(egl_path, dlopen_flags);
     /* Catch the case where the application isn't linked with EGL */
-    if ((dlsym(handle, "eglChooseConfig") == NULL) && (path == NULL)) {
-        
-        dlclose(handle);
+    if ((dlsym(dll_handle, "eglChooseConfig") == NULL) && (egl_path == NULL)) {
+        dlclose(dll_handle);
         path = getenv("SDL_VIDEO_EGL_DRIVER");
         if (path == NULL) {
             path = DEFAULT_EGL;
         }
-        handle = dlopen(path, dlopen_flags);
-    }
-
-    if (handle == NULL) {
-        return SDL_SetError("Could not load OpenGL ES/EGL library");
+        dll_handle = dlopen(path, dlopen_flags);
     }
     
+    if (dll_handle == NULL) {
+        return SDL_SetError("Could not load EGL library: %s", dlerror());
+    }
+
     _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData));
     if (!_this->egl_data) {
         return SDL_OutOfMemory();
@@ -153,36 +183,14 @@ SDL_EGL_LoadLibrary(_THIS, const char *path, NativeDisplayType native_display)
         return SDL_SetError("Could not initialize EGL");
     }
 
-    _this->egl_data->egl_dll_handle = handle;
-
-    path = getenv("SDL_VIDEO_GL_DRIVER");
-    handle = dlopen(path, dlopen_flags);
-    if ((path == NULL) | (handle == NULL)) {
-      if (_this->gl_config.major_version > 1) {
-          path = DEFAULT_OGL_ES2;
-          handle = dlopen(path, dlopen_flags);
-      } else {
-          path = DEFAULT_OGL_ES;
-          handle = dlopen(path, dlopen_flags);
-          if (handle == NULL) {
-              path = DEFAULT_OGL_ES_PVR;
-              handle = dlopen(path, dlopen_flags);
-          }
-      }
-    }
-
-    if (handle == NULL) {
-      return SDL_SetError("Could not initialize OpenGL ES library");
-    }
-
-    _this->gl_config.dll_handle = handle;
+    _this->gl_config.dll_handle = dll_handle;
+    _this->egl_data->egl_dll_handle = egl_dll_handle;
     _this->gl_config.driver_loaded = 1;
 
     if (path) {
-      strncpy(_this->gl_config.driver_path, path,
-              sizeof(_this->gl_config.driver_path) - 1);
+        strncpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
     } else {
-      strcpy(_this->gl_config.driver_path, "");
+        strcpy(_this->gl_config.driver_path, "");
     }
     
     /* We need to select a config here to satisfy some video backends such as X11 */

+ 3 - 0
src/video/SDL_sysvideo.h

@@ -363,6 +363,9 @@ extern VideoBootStrap Android_bootstrap;
 #if SDL_VIDEO_DRIVER_PSP
 extern VideoBootStrap PSP_bootstrap;
 #endif
+#if SDL_VIDEO_DRIVER_RPI
+extern VideoBootStrap RPI_bootstrap;
+#endif
 #if SDL_VIDEO_DRIVER_DUMMY
 extern VideoBootStrap DUMMY_bootstrap;
 #endif

+ 3 - 0
src/video/SDL_video.c

@@ -80,6 +80,9 @@ static VideoBootStrap *bootstrap[] = {
 #if SDL_VIDEO_DRIVER_PSP
     &PSP_bootstrap,
 #endif
+#if SDL_VIDEO_DRIVER_RPI
+    &RPI_bootstrap,
+#endif 
 #if SDL_VIDEO_DRIVER_DUMMY
     &DUMMY_bootstrap,
 #endif

+ 45 - 0
src/video/raspberry/SDL_rpievents.c

@@ -0,0 +1,45 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+
+#if SDL_VIDEO_DRIVER_RPI
+
+#include "../../events/SDL_sysevents.h"
+#include "../../events/SDL_events_c.h"
+#include "../../events/SDL_keyboard_c.h"
+#include "SDL_rpivideo.h"
+#include "SDL_rpievents_c.h"
+
+#ifdef SDL_INPUT_LINUXEV
+#include "../../input/evdev/SDL_evdev.h"
+#endif
+
+void RPI_PumpEvents(_THIS)
+{
+#ifdef SDL_INPUT_LINUXEV
+    SDL_EVDEV_Poll();
+#endif
+    
+}
+
+#endif /* SDL_VIDEO_DRIVER_RPI */
+

+ 31 - 0
src/video/raspberry/SDL_rpievents_c.h

@@ -0,0 +1,31 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef _SDL_rpievents_c_h
+#define _SDL_rpievents_c_h
+
+#include "SDL_rpivideo.h"
+
+void RPI_PumpEvents(_THIS);
+void RPI_EventInit(_THIS);
+void RPI_EventQuit(_THIS);
+
+#endif /* _SDL_rpievents_c_h */

+ 277 - 0
src/video/raspberry/SDL_rpimouse.c

@@ -0,0 +1,277 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#if SDL_VIDEO_DRIVER_RPI
+
+#include "SDL_assert.h"
+#include "SDL_surface.h"
+
+#include "SDL_rpivideo.h"
+#include "SDL_rpimouse.h"
+
+#include "../SDL_sysvideo.h"
+#include "../../events/SDL_mouse_c.h"
+#include "../../events/default_cursor.h"
+
+/* Copied from vc_vchi_dispmanx.h which is bugged and tries to include a non existing file */
+/* Attributes changes flag mask */
+#define ELEMENT_CHANGE_LAYER          (1<<0)
+#define ELEMENT_CHANGE_OPACITY        (1<<1)
+#define ELEMENT_CHANGE_DEST_RECT      (1<<2)
+#define ELEMENT_CHANGE_SRC_RECT       (1<<3)
+#define ELEMENT_CHANGE_MASK_RESOURCE  (1<<4)
+#define ELEMENT_CHANGE_TRANSFORM      (1<<5)
+/* End copied from vc_vchi_dispmanx.h */
+
+static SDL_Cursor *RPI_CreateDefaultCursor(void);
+static SDL_Cursor *RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y);
+static int RPI_ShowCursor(SDL_Cursor * cursor);
+static void RPI_MoveCursor(SDL_Cursor * cursor);
+static void RPI_FreeCursor(SDL_Cursor * cursor);
+static void RPI_WarpMouse(SDL_Window * window, int x, int y);
+
+static SDL_Cursor *
+RPI_CreateDefaultCursor(void)
+{
+    return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
+}
+
+/* Create a cursor from a surface */
+static SDL_Cursor *
+RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
+{
+    RPI_CursorData *curdata;
+    SDL_Cursor *cursor;
+    int ret;
+    VC_RECT_T dst_rect;
+    Uint32 dummy;
+        
+    SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
+    SDL_assert(surface->pitch == surface->w * 4);
+    
+    cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
+    curdata = (RPI_CursorData *) SDL_calloc(1, sizeof(*curdata));
+
+    curdata->hot_x = hot_x;
+    curdata->hot_y = hot_y;
+    curdata->w = surface->w;
+    curdata->h = surface->h;
+    
+    /* This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess */
+    curdata->resource = vc_dispmanx_resource_create( VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy );
+    SDL_assert(curdata->resource);
+    vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
+    /* A note from Weston: 
+     * vc_dispmanx_resource_write_data() ignores ifmt,
+     * rect.x, rect.width, and uses stride only for computing
+     * the size of the transfer as rect.height * stride.
+     * Therefore we can only write rows starting at x=0.
+     */
+    ret = vc_dispmanx_resource_write_data( curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect );
+    SDL_assert ( ret == DISPMANX_SUCCESS );
+    
+    cursor->driverdata = curdata;
+    
+    return cursor;
+
+}
+
+/* Show the specified cursor, or hide if cursor is NULL */
+static int
+RPI_ShowCursor(SDL_Cursor * cursor)
+{
+    int ret;
+    DISPMANX_UPDATE_HANDLE_T update;
+    RPI_CursorData *curdata;
+    VC_RECT_T src_rect, dst_rect;
+    SDL_Mouse *mouse;
+    SDL_VideoDisplay *display;
+    SDL_DisplayData *data;
+    VC_DISPMANX_ALPHA_T alpha = {  DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */ , 255 /*opacity 0->255*/,  0 /* mask */ };
+    
+    mouse = SDL_GetMouse();
+    if (mouse == NULL) {
+        return -1;
+    }
+    
+    if (cursor == NULL) {
+        /* FIXME: We hide the current mouse's cursor, what we actually need is *_HideCursor */
+
+        if ( mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
+            curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
+            if (curdata->element > DISPMANX_NO_HANDLE) {
+                update = vc_dispmanx_update_start( 10 );
+                SDL_assert( update );
+                ret = vc_dispmanx_element_remove( update, curdata->element );
+                SDL_assert( ret == DISPMANX_SUCCESS );
+                ret = vc_dispmanx_update_submit_sync( update );
+                SDL_assert( ret == DISPMANX_SUCCESS );
+                curdata->element = DISPMANX_NO_HANDLE;
+            }
+        }
+        return 0;
+    }
+    
+    curdata = (RPI_CursorData *) cursor->driverdata;
+    if (curdata == NULL) {
+        return -1;
+    }
+    
+    if (mouse->focus == NULL) {
+        return -1;
+    }
+    
+    display = SDL_GetDisplayForWindow(mouse->focus);
+    if (display == NULL) {
+        return -1;
+    }
+    
+    data = (SDL_DisplayData*) display->driverdata;
+    if (data == NULL) {
+        return -1;
+    }
+    
+    if (curdata->element == DISPMANX_NO_HANDLE) {
+        vc_dispmanx_rect_set( &src_rect, 0, 0, curdata->w << 16, curdata->h << 16 );
+        vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
+        
+        update = vc_dispmanx_update_start( 10 );
+        SDL_assert( update );
+
+        curdata->element = vc_dispmanx_element_add( update,
+                                                    data->dispman_display,
+                                                    SDL_RPI_MOUSELAYER, // layer
+                                                    &dst_rect,
+                                                    curdata->resource,
+                                                    &src_rect,
+                                                    DISPMANX_PROTECTION_NONE,
+                                                    &alpha,
+                                                    DISPMANX_NO_HANDLE, // clamp
+                                                    VC_IMAGE_ROT0 );
+        SDL_assert( curdata->element > DISPMANX_NO_HANDLE);
+        ret = vc_dispmanx_update_submit_sync( update );
+        SDL_assert( ret == DISPMANX_SUCCESS );
+    }
+    
+    return 0;
+}
+
+/* Free a window manager cursor */
+static void
+RPI_FreeCursor(SDL_Cursor * cursor)
+{
+    int ret;
+    DISPMANX_UPDATE_HANDLE_T update;
+    RPI_CursorData *curdata;
+    
+    if (cursor != NULL) {
+        curdata = (RPI_CursorData *) cursor->driverdata;
+        
+        if (curdata != NULL) {
+            if (curdata->element != DISPMANX_NO_HANDLE) {
+                update = vc_dispmanx_update_start( 10 );
+                SDL_assert( update );
+                ret = vc_dispmanx_element_remove( update, curdata->element );
+                SDL_assert( ret == DISPMANX_SUCCESS );
+                ret = vc_dispmanx_update_submit_sync( update );
+                SDL_assert( ret == DISPMANX_SUCCESS );
+            }
+            
+            if (curdata->resource != DISPMANX_NO_HANDLE) {
+                ret = vc_dispmanx_resource_delete( curdata->resource );
+                SDL_assert( ret == DISPMANX_SUCCESS );
+            }
+        
+            SDL_free(cursor->driverdata);
+        }
+        SDL_free(cursor);
+    }
+}
+
+/* Warp the mouse to (x,y) */
+static void
+RPI_WarpMouse(SDL_Window * window, int x, int y)
+{
+    RPI_CursorData *curdata;
+    DISPMANX_UPDATE_HANDLE_T update;
+    int ret;
+    VC_RECT_T dst_rect;
+    SDL_Mouse *mouse = SDL_GetMouse();
+    
+    if (mouse != NULL && mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
+        curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
+        if (curdata->element != DISPMANX_NO_HANDLE) {
+            update = vc_dispmanx_update_start( 10 );
+            SDL_assert( update );
+            vc_dispmanx_rect_set( &dst_rect, x, y, curdata->w, curdata->h);
+            ret = vc_dispmanx_element_change_attributes(
+                update,
+                curdata->element,
+                ELEMENT_CHANGE_DEST_RECT,
+                0,
+                0,
+                &dst_rect,
+                NULL,
+                DISPMANX_NO_HANDLE,
+                DISPMANX_NO_ROTATE);
+            SDL_assert( ret == DISPMANX_SUCCESS );
+            /* Submit asynchronously, otherwise the peformance suffers a lot */
+            ret = vc_dispmanx_update_submit( update, 0, NULL );
+            SDL_assert( ret == DISPMANX_SUCCESS );
+        }
+    }    
+}
+
+void
+RPI_InitMouse(_THIS)
+{
+    /* FIXME: Using UDEV it should be possible to scan all mice 
+     * but there's no point in doing so as there's no multimice support...yet!
+     */
+    SDL_Mouse *mouse = SDL_GetMouse();
+
+    mouse->CreateCursor = RPI_CreateCursor;
+    mouse->ShowCursor = RPI_ShowCursor;
+    mouse->MoveCursor = RPI_MoveCursor;
+    mouse->FreeCursor = RPI_FreeCursor;
+    mouse->WarpMouse = RPI_WarpMouse;
+
+    SDL_SetDefaultCursor(RPI_CreateDefaultCursor());
+}
+
+void
+RPI_QuitMouse(_THIS)
+{
+    
+}
+
+/* This is called when a mouse motion event occurs */
+static void
+RPI_MoveCursor(SDL_Cursor * cursor)
+{
+    SDL_Mouse *mouse = SDL_GetMouse();
+    RPI_WarpMouse(mouse->focus, mouse->x, mouse->y);
+}
+
+#endif /* SDL_VIDEO_DRIVER_RPI */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 43 - 0
src/video/raspberry/SDL_rpimouse.h

@@ -0,0 +1,43 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef _SDL_RPI_mouse_h
+#define _SDL_RPI_mouse_h
+
+#include "../SDL_sysvideo.h"
+
+typedef struct _RPI_CursorData RPI_CursorData;
+struct _RPI_CursorData
+{
+    DISPMANX_RESOURCE_HANDLE_T  resource;
+    DISPMANX_ELEMENT_HANDLE_T   element;
+    int                         hot_x, hot_y;
+    int                         w, h;
+};
+
+#define SDL_RPI_CURSORDATA(curs)  RPI_CursorData *curdata = (RPI_CursorData *) ((curs) ? (curs)->driverdata : NULL)
+
+extern void RPI_InitMouse(_THIS);
+extern void RPI_QuitMouse(_THIS);
+
+#endif /* _SDL_RPI_mouse_h */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 42 - 0
src/video/raspberry/SDL_rpiopengles.c

@@ -0,0 +1,42 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#if SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL
+
+#include "SDL_rpivideo.h"
+#include "SDL_rpiopengles.h"
+
+/* EGL implementation of SDL OpenGL support */
+
+int
+RPI_GLES_LoadLibrary(_THIS, const char *path) {
+    return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY);
+}
+
+SDL_EGL_CreateContext_impl(RPI)
+SDL_EGL_SwapWindow_impl(RPI)
+SDL_EGL_MakeCurrent_impl(RPI)
+
+#endif /* SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL */
+
+/* vi: set ts=4 sw=4 expandtab: */
+

+ 48 - 0
src/video/raspberry/SDL_rpiopengles.h

@@ -0,0 +1,48 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_rpiopengles_h
+#define _SDL_rpiopengles_h
+
+#if SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL
+
+#include "../SDL_sysvideo.h"
+#include "../SDL_egl.h"
+
+/* OpenGLES functions */
+#define RPI_GLES_GetAttribute SDL_EGL_GetAttribute
+#define RPI_GLES_GetProcAddress SDL_EGL_GetProcAddress
+#define RPI_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
+#define RPI_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
+#define RPI_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
+#define RPI_GLES_DeleteContext SDL_EGL_DeleteContext
+
+extern int RPI_GLES_LoadLibrary(_THIS, const char *path);
+extern SDL_GLContext RPI_GLES_CreateContext(_THIS, SDL_Window * window);
+extern void RPI_GLES_SwapWindow(_THIS, SDL_Window * window);
+extern int RPI_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
+
+#endif /* SDL_VIDEO_DRIVER_RPI && SDL_VIDEO_OPENGL_EGL */
+
+#endif /* _SDL_rpiopengles_h */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 361 - 0
src/video/raspberry/SDL_rpivideo.c

@@ -0,0 +1,361 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+
+#if SDL_VIDEO_DRIVER_RPI
+
+/* References
+ * http://elinux.org/RPi_VideoCore_APIs
+ * https://github.com/raspberrypi/firmware/blob/master/opt/vc/src/hello_pi/hello_triangle/triangle.c
+ * http://cgit.freedesktop.org/wayland/weston/tree/src/rpi-renderer.c
+ * http://cgit.freedesktop.org/wayland/weston/tree/src/compositor-rpi.c
+ */
+
+/* SDL internals */
+#include "../SDL_sysvideo.h"
+#include "SDL_version.h"
+#include "SDL_syswm.h"
+#include "SDL_loadso.h"
+#include "SDL_events.h"
+#include "../../events/SDL_mouse_c.h"
+#include "../../events/SDL_keyboard_c.h"
+
+#ifdef SDL_INPUT_LINUXEV
+#include "../../input/evdev/SDL_evdev.h"
+#endif
+
+/* RPI declarations */
+#include "SDL_rpivideo.h"
+#include "SDL_rpievents_c.h"
+#include "SDL_rpiopengles.h"
+#include "SDL_rpimouse.h"
+
+static int
+RPI_Available(void)
+{
+    return 1;
+}
+
+static void
+RPI_Destroy(SDL_VideoDevice * device)
+{
+    /*    SDL_VideoData *phdata = (SDL_VideoData *) device->driverdata; */
+
+    if (device->driverdata != NULL) {
+        device->driverdata = NULL;
+    }
+}
+
+static SDL_VideoDevice *
+RPI_Create()
+{
+    SDL_VideoDevice *device;
+    SDL_VideoData *phdata;
+
+    /* Initialize SDL_VideoDevice structure */
+    device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
+    if (device == NULL) {
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    /* Initialize internal data */
+    phdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
+    if (phdata == NULL) {
+        SDL_OutOfMemory();
+        SDL_free(device);
+        return NULL;
+    }
+
+    device->driverdata = phdata;
+
+    /* Setup amount of available displays and current display */
+    device->num_displays = 0;
+
+    /* Set device free function */
+    device->free = RPI_Destroy;
+
+    /* Setup all functions which we can handle */
+    device->VideoInit = RPI_VideoInit;
+    device->VideoQuit = RPI_VideoQuit;
+    device->GetDisplayModes = RPI_GetDisplayModes;
+    device->SetDisplayMode = RPI_SetDisplayMode;
+    device->CreateWindow = RPI_CreateWindow;
+    device->CreateWindowFrom = RPI_CreateWindowFrom;
+    device->SetWindowTitle = RPI_SetWindowTitle;
+    device->SetWindowIcon = RPI_SetWindowIcon;
+    device->SetWindowPosition = RPI_SetWindowPosition;
+    device->SetWindowSize = RPI_SetWindowSize;
+    device->ShowWindow = RPI_ShowWindow;
+    device->HideWindow = RPI_HideWindow;
+    device->RaiseWindow = RPI_RaiseWindow;
+    device->MaximizeWindow = RPI_MaximizeWindow;
+    device->MinimizeWindow = RPI_MinimizeWindow;
+    device->RestoreWindow = RPI_RestoreWindow;
+    device->SetWindowGrab = RPI_SetWindowGrab;
+    device->DestroyWindow = RPI_DestroyWindow;
+    device->GetWindowWMInfo = RPI_GetWindowWMInfo;
+    device->GL_LoadLibrary = RPI_GLES_LoadLibrary;
+    device->GL_GetProcAddress = RPI_GLES_GetProcAddress;
+    device->GL_UnloadLibrary = RPI_GLES_UnloadLibrary;
+    device->GL_CreateContext = RPI_GLES_CreateContext;
+    device->GL_MakeCurrent = RPI_GLES_MakeCurrent;
+    device->GL_SetSwapInterval = RPI_GLES_SetSwapInterval;
+    device->GL_GetSwapInterval = RPI_GLES_GetSwapInterval;
+    device->GL_SwapWindow = RPI_GLES_SwapWindow;
+    device->GL_DeleteContext = RPI_GLES_DeleteContext;
+
+    device->PumpEvents = RPI_PumpEvents;
+
+    return device;
+}
+
+VideoBootStrap RPI_bootstrap = {
+    "RPI",
+    "RPI Video Driver",
+    RPI_Available,
+    RPI_Create
+};
+
+/*****************************************************************************/
+/* SDL Video and Display initialization/handling functions                   */
+/*****************************************************************************/
+int
+RPI_VideoInit(_THIS)
+{
+    SDL_VideoDisplay display;
+    SDL_DisplayMode current_mode;
+    uint32_t w,h;
+
+    /* Initialize BCM Host */
+    bcm_host_init();
+
+    SDL_zero(current_mode);
+
+    if (graphics_get_display_size( 0, &w, &h) < 0) {
+        return -1;
+    }
+
+    current_mode.w = w;
+    current_mode.h = h;
+    /* FIXME: Is there a way to tell the actual refresh rate? */
+    current_mode.refresh_rate = 60;
+    /* 32 bpp for default */
+    current_mode.format = SDL_PIXELFORMAT_ABGR8888;
+
+    current_mode.driverdata = NULL;
+
+    SDL_zero(display);
+    display.desktop_mode = current_mode;
+    display.current_mode = current_mode;
+
+    SDL_DisplayData *data;
+
+    /* Allocate display internal data */
+    data = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
+    if (data == NULL) {
+        return SDL_OutOfMemory();
+    }
+
+    data->dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
+
+    display.driverdata = data;
+
+    SDL_AddVideoDisplay(&display);
+
+#ifdef SDL_INPUT_LINUXEV    
+    SDL_EVDEV_Init();
+#endif    
+    
+    RPI_InitMouse(_this);
+
+    return 1;
+}
+
+void
+RPI_VideoQuit(_THIS)
+{
+#ifdef SDL_INPUT_LINUXEV    
+    SDL_EVDEV_Quit();
+#endif    
+}
+
+void
+RPI_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
+{
+    /* Only one display mode available, the current one */
+    SDL_AddDisplayMode(display, &display->current_mode);
+}
+
+int
+RPI_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
+{
+    return 0;
+}
+
+int
+RPI_CreateWindow(_THIS, SDL_Window * window)
+{
+    SDL_WindowData *wdata;
+    SDL_VideoDisplay *display;
+    SDL_DisplayData *displaydata;
+    VC_RECT_T dst_rect;
+    VC_RECT_T src_rect;
+    VC_DISPMANX_ALPHA_T         dispman_alpha;
+    DISPMANX_UPDATE_HANDLE_T dispman_update;
+
+    /* Disable alpha, otherwise the app looks composed with whatever dispman is showing (X11, console,etc) */
+    dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; 
+    dispman_alpha.opacity = 0xFF; 
+    dispman_alpha.mask = 0;
+
+    /* Allocate window internal data */
+    wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
+    if (wdata == NULL) {
+        return SDL_OutOfMemory();
+    }
+    display = SDL_GetDisplayForWindow(window);
+    displaydata = (SDL_DisplayData *) display->driverdata;
+
+    /* Windows have one size for now */
+    window->w = display->desktop_mode.w;
+    window->h = display->desktop_mode.h;
+
+    /* OpenGL ES is the law here, buddy */
+    window->flags |= SDL_WINDOW_OPENGL;
+
+    /* Create a dispman element and associate a window to it */
+    dst_rect.x = 0;
+    dst_rect.y = 0;
+    dst_rect.width = window->w;
+    dst_rect.height = window->h;
+
+    src_rect.x = 0;
+    src_rect.y = 0;
+    src_rect.width = window->w << 16;
+    src_rect.height = window->h << 16;
+
+    dispman_update = vc_dispmanx_update_start( 0 );
+    wdata->dispman_window.element = vc_dispmanx_element_add ( dispman_update, displaydata->dispman_display, SDL_RPI_VIDEOLAYER /* layer */, &dst_rect, 0/*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &dispman_alpha /*alpha*/, 0/*clamp*/, 0/*transform*/);
+    wdata->dispman_window.width = window->w;
+    wdata->dispman_window.height = window->h;
+    vc_dispmanx_update_submit_sync( dispman_update );
+    
+    if (!_this->egl_data) {
+        if (SDL_GL_LoadLibrary(NULL) < 0) {
+            return -1;
+        }
+    }
+    wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) &wdata->dispman_window);
+
+    if (wdata->egl_surface == EGL_NO_SURFACE) {
+        return SDL_SetError("Could not create GLES window surface");
+    }
+
+    /* Setup driver data for this window */
+    window->driverdata = wdata;
+    
+    /* One window, it always has focus */
+    SDL_SetMouseFocus(window);
+    SDL_SetKeyboardFocus(window);
+
+    /* Window has been successfully created */
+    return 0;
+}
+
+int
+RPI_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
+{
+    return -1;
+}
+
+void
+RPI_SetWindowTitle(_THIS, SDL_Window * window)
+{
+}
+void
+RPI_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
+{
+}
+void
+RPI_SetWindowPosition(_THIS, SDL_Window * window)
+{
+}
+void
+RPI_SetWindowSize(_THIS, SDL_Window * window)
+{
+}
+void
+RPI_ShowWindow(_THIS, SDL_Window * window)
+{
+}
+void
+RPI_HideWindow(_THIS, SDL_Window * window)
+{
+}
+void
+RPI_RaiseWindow(_THIS, SDL_Window * window)
+{
+}
+void
+RPI_MaximizeWindow(_THIS, SDL_Window * window)
+{
+}
+void
+RPI_MinimizeWindow(_THIS, SDL_Window * window)
+{
+}
+void
+RPI_RestoreWindow(_THIS, SDL_Window * window)
+{
+}
+void
+RPI_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
+{
+
+}
+void
+RPI_DestroyWindow(_THIS, SDL_Window * window)
+{
+}
+
+/*****************************************************************************/
+/* SDL Window Manager function                                               */
+/*****************************************************************************/
+SDL_bool
+RPI_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
+{
+    if (info->version.major <= SDL_MAJOR_VERSION) {
+        return SDL_TRUE;
+    } else {
+        SDL_SetError("application not compiled with SDL %d.%d\n",
+                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
+        return SDL_FALSE;
+    }
+
+    /* Failed to get window manager information */
+    return SDL_FALSE;
+}
+
+#endif /* SDL_VIDEO_DRIVER_RPI */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 98 - 0
src/video/raspberry/SDL_rpivideo.h

@@ -0,0 +1,98 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef __SDL_RPIVIDEO_H__
+#define __SDL_RPIVIDEO_H__
+
+#include "SDL_config.h"
+#include "../SDL_sysvideo.h"
+
+#include "bcm_host.h"
+#include "GLES/gl.h"
+#include "EGL/egl.h"
+#include "EGL/eglext.h"
+
+typedef struct SDL_VideoData
+{
+    uint32_t egl_refcount;      /* OpenGL ES reference count              */
+} SDL_VideoData;
+
+
+typedef struct SDL_DisplayData
+{
+    DISPMANX_DISPLAY_HANDLE_T dispman_display;
+} SDL_DisplayData;
+
+
+typedef struct SDL_WindowData
+{
+    EGL_DISPMANX_WINDOW_T dispman_window;
+#if SDL_VIDEO_OPENGL_EGL  
+    EGLSurface egl_surface;
+#endif    
+} SDL_WindowData;
+
+#define SDL_RPI_VIDEOLAYER 10000 /* High enough so to occlude everything */
+#define SDL_RPI_MOUSELAYER SDL_RPI_VIDEOLAYER + 1
+
+
+/****************************************************************************/
+/* SDL_VideoDevice functions declaration                                    */
+/****************************************************************************/
+
+/* Display and window functions */
+int RPI_VideoInit(_THIS);
+void RPI_VideoQuit(_THIS);
+void RPI_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
+int RPI_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
+int RPI_CreateWindow(_THIS, SDL_Window * window);
+int RPI_CreateWindowFrom(_THIS, SDL_Window * window, const void *data);
+void RPI_SetWindowTitle(_THIS, SDL_Window * window);
+void RPI_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon);
+void RPI_SetWindowPosition(_THIS, SDL_Window * window);
+void RPI_SetWindowSize(_THIS, SDL_Window * window);
+void RPI_ShowWindow(_THIS, SDL_Window * window);
+void RPI_HideWindow(_THIS, SDL_Window * window);
+void RPI_RaiseWindow(_THIS, SDL_Window * window);
+void RPI_MaximizeWindow(_THIS, SDL_Window * window);
+void RPI_MinimizeWindow(_THIS, SDL_Window * window);
+void RPI_RestoreWindow(_THIS, SDL_Window * window);
+void RPI_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
+void RPI_DestroyWindow(_THIS, SDL_Window * window);
+
+/* Window manager function */
+SDL_bool RPI_GetWindowWMInfo(_THIS, SDL_Window * window,
+                             struct SDL_SysWMinfo *info);
+
+/* OpenGL/OpenGL ES functions */
+int RPI_GLES_LoadLibrary(_THIS, const char *path);
+void *RPI_GLES_GetProcAddress(_THIS, const char *proc);
+void RPI_GLES_UnloadLibrary(_THIS);
+SDL_GLContext RPI_GLES_CreateContext(_THIS, SDL_Window * window);
+int RPI_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
+int RPI_GLES_SetSwapInterval(_THIS, int interval);
+int RPI_GLES_GetSwapInterval(_THIS);
+void RPI_GLES_SwapWindow(_THIS, SDL_Window * window);
+void RPI_GLES_DeleteContext(_THIS, SDL_GLContext context);
+
+#endif /* __SDL_RPIVIDEO_H__ */
+
+/* vi: set ts=4 sw=4 expandtab: */