implement input to avoid PD common dependency
authornotaz <notasas@gmail.com>
Sat, 13 Nov 2010 18:34:23 +0000 (20:34 +0200)
committernotaz <notasas@gmail.com>
Sat, 13 Nov 2010 18:48:19 +0000 (20:48 +0200)
Also commit fbdev/oshide.

src/video/omapdss/Makefile
src/video/omapdss/config.c
src/video/omapdss/linux/fbdev.c [new file with mode: 0644]
src/video/omapdss/linux/fbdev.h [new file with mode: 0644]
src/video/omapdss/linux/oshide.c [new file with mode: 0644]
src/video/omapdss/linux/oshide.h [new file with mode: 0644]
src/video/omapdss/omapsdl.h
src/video/omapdss/osdl_input.c
src/video/omapdss/standalone.c

index 523d82f..8fea694 100644 (file)
@@ -9,13 +9,13 @@ ARCH ?= arm
 
 TARGET = libSDL-1.2.so.0
 OBJS += standalone.o osdl_input.o config.o \
-       common/input.o linux/fbdev.o linux/in_evdev.o linux/oshide.o linux/plat.o
+       linux/fbdev.o linux/oshide.o
 ifeq ($(ARCH),arm)
 OBJS += arm_utils.o
 else
 CFLAGS += -fPIC
 endif
-CFLAGS += -DIN_EVDEV -DSTANDALONE
+CFLAGS += -DSTANDALONE
 
 all: $(TARGET)
 
index 865b80a..52809d6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) notaz, 2010
+ * (C) Gražvydas "notaz" Ignotas, 2010
  *
  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  * See the COPYING file in the top-level directory.
diff --git a/src/video/omapdss/linux/fbdev.c b/src/video/omapdss/linux/fbdev.c
new file mode 100644 (file)
index 0000000..6ae0c77
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * (C) Gražvydas "notaz" Ignotas, 2009-2010
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <linux/fb.h>
+#include <linux/matroxfb.h>
+
+#include "fbdev.h"
+
+#define FBDEV_MAX_BUFFERS 3
+
+struct vout_fbdev {
+       int     fd;
+       void    *mem;
+       size_t  mem_size;
+       struct  fb_var_screeninfo fbvar_old;
+       struct  fb_var_screeninfo fbvar_new;
+       int     buffer_write;
+       int     fb_size;
+       int     buffer_count;
+       int     top_border, bottom_border;
+};
+
+void *vout_fbdev_flip(struct vout_fbdev *fbdev)
+{
+       int draw_buf;
+
+       if (fbdev->buffer_count < 2)
+               return fbdev->mem;
+
+       draw_buf = fbdev->buffer_write;
+       fbdev->buffer_write++;
+       if (fbdev->buffer_write >= fbdev->buffer_count)
+               fbdev->buffer_write = 0;
+
+       fbdev->fbvar_new.yoffset = 
+               (fbdev->top_border + fbdev->fbvar_new.yres + fbdev->bottom_border) * draw_buf +
+               fbdev->top_border;
+
+       ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new);
+
+       return (char *)fbdev->mem + fbdev->fb_size * fbdev->buffer_write;
+}
+
+void vout_fbdev_wait_vsync(struct vout_fbdev *fbdev)
+{
+       int arg = 0;
+       ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &arg);
+}
+
+int vout_fbdev_resize(struct vout_fbdev *fbdev, int w, int h,
+                     int left_border, int right_border, int top_border, int bottom_border, int no_dblbuf)
+{
+       int w_total = left_border + w + right_border;
+       int h_total = top_border + h + bottom_border;
+       size_t mem_size;
+       int ret;
+
+       // unblank to be sure the mode is really accepted
+       ioctl(fbdev->fd, FBIOBLANK, FB_BLANK_UNBLANK);
+
+       if (fbdev->fbvar_new.bits_per_pixel != 16 ||
+                       w != fbdev->fbvar_new.xres ||
+                       h != fbdev->fbvar_new.yres ||
+                       w_total != fbdev->fbvar_new.xres_virtual ||
+                       h_total > fbdev->fbvar_new.yres_virtual ||
+                       left_border != fbdev->fbvar_new.xoffset) {
+               fbdev->fbvar_new.xres = w;
+               fbdev->fbvar_new.yres = h;
+               fbdev->fbvar_new.xres_virtual = w_total;
+               fbdev->fbvar_new.yres_virtual = h_total;
+               fbdev->fbvar_new.xoffset = left_border;
+               fbdev->fbvar_new.bits_per_pixel = 16;
+               printf(" switching to %dx%d@16\n", w, h);
+               ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
+               if (ret == -1) {
+                       perror("FBIOPUT_VSCREENINFO ioctl");
+                       return -1;
+               }
+       }
+
+       fbdev->buffer_count = FBDEV_MAX_BUFFERS; // be optimistic
+       if (no_dblbuf)
+               fbdev->buffer_count = 1;
+
+       if (fbdev->fbvar_new.yres_virtual < h_total * fbdev->buffer_count) {
+               fbdev->fbvar_new.yres_virtual = h_total * fbdev->buffer_count;
+               ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
+               if (ret == -1) {
+                       fbdev->buffer_count = 1;
+                       fprintf(stderr, "Warning: failed to increase virtual resolution, "
+                                       "doublebuffering disabled\n");
+               }
+       }
+
+       fbdev->fb_size = w_total * h_total * 2;
+       fbdev->top_border = top_border;
+       fbdev->bottom_border = bottom_border;
+
+       mem_size = fbdev->fb_size * fbdev->buffer_count;
+       if (fbdev->mem_size >= mem_size)
+               return 0;
+
+       if (fbdev->mem != NULL)
+               munmap(fbdev->mem, fbdev->mem_size);
+
+       fbdev->mem = mmap(0, mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
+       if (fbdev->mem == MAP_FAILED && fbdev->buffer_count > 1) {
+               fprintf(stderr, "Warning: can't map %zd bytes, doublebuffering disabled\n", fbdev->mem_size);
+               fbdev->buffer_count = 1;
+               mem_size = fbdev->fb_size;
+               fbdev->mem = mmap(0, mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
+       }
+       if (fbdev->mem == MAP_FAILED) {
+               fbdev->mem = NULL;
+               fbdev->mem_size = 0;
+               perror("mmap framebuffer");
+               return -1;
+       }
+
+       fbdev->mem_size = mem_size;
+       return 0;
+}
+
+void vout_fbdev_clear(struct vout_fbdev *fbdev)
+{
+       memset(fbdev->mem, 0, fbdev->mem_size);
+}
+
+void vout_fbdev_clear_lines(struct vout_fbdev *fbdev, int y, int count)
+{
+       int stride = fbdev->fbvar_new.xres_virtual * fbdev->fbvar_new.bits_per_pixel / 8;
+       int i;
+
+       if (y + count > fbdev->top_border + fbdev->fbvar_new.yres)
+               count = fbdev->top_border + fbdev->fbvar_new.yres - y;
+
+       if (y >= 0 && count > 0)
+               for (i = 0; i < fbdev->buffer_count; i++)
+                       memset((char *)fbdev->mem + fbdev->fb_size * i + y * stride, 0, stride * count);
+}
+
+int vout_fbdev_get_fd(struct vout_fbdev *fbdev)
+{
+       return fbdev->fd;
+}
+
+struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int no_dblbuf)
+{
+       struct vout_fbdev *fbdev;
+       int req_w, req_h;
+       int ret;
+
+       fbdev = calloc(1, sizeof(*fbdev));
+       if (fbdev == NULL)
+               return NULL;
+
+       fbdev->fd = open(fbdev_name, O_RDWR);
+       if (fbdev->fd == -1) {
+               fprintf(stderr, "%s: ", fbdev_name);
+               perror("open");
+               goto fail_open;
+       }
+
+       ret = ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->fbvar_old);
+       if (ret == -1) {
+               perror("FBIOGET_VSCREENINFO ioctl");
+               goto fail;
+       }
+
+       fbdev->fbvar_new = fbdev->fbvar_old;
+
+       req_w = fbdev->fbvar_new.xres;
+       if (*w != 0)
+               req_w = *w;
+       req_h = fbdev->fbvar_new.yres;
+       if (*h != 0)
+               req_h = *h;
+
+       ret = vout_fbdev_resize(fbdev, req_w, req_h, 0, 0, 0, 0, no_dblbuf);
+       if (ret != 0)
+               goto fail;
+
+       printf("%s: %ix%i@%d\n", fbdev_name, fbdev->fbvar_new.xres, fbdev->fbvar_new.yres,
+               fbdev->fbvar_new.bits_per_pixel);
+       *w = fbdev->fbvar_new.xres;
+       *h = fbdev->fbvar_new.yres;
+
+       memset(fbdev->mem, 0, fbdev->mem_size);
+
+       // some checks
+       ret = 0;
+       ret = ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &ret);
+       if (ret != 0)
+               fprintf(stderr, "Warning: vsync doesn't seem to be supported\n");
+
+       if (fbdev->buffer_count > 1) {
+               fbdev->buffer_write = 0;
+               fbdev->fbvar_new.yoffset = fbdev->fbvar_new.yres * (fbdev->buffer_count - 1);
+               ret = ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new);
+               if (ret != 0) {
+                       fbdev->buffer_count = 1;
+                       fprintf(stderr, "Warning: can't pan display, doublebuffering disabled\n");
+               }
+       }
+
+       printf("fbdev initialized.\n");
+       return fbdev;
+
+fail:
+       close(fbdev->fd);
+fail_open:
+       free(fbdev);
+       return NULL;
+}
+
+void vout_fbdev_finish(struct vout_fbdev *fbdev)
+{
+       ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_old);
+       if (fbdev->mem != MAP_FAILED)
+               munmap(fbdev->mem, fbdev->mem_size);
+       if (fbdev->fd >= 0)
+               close(fbdev->fd);
+       fbdev->mem = NULL;
+       fbdev->fd = -1;
+       free(fbdev);
+}
+
diff --git a/src/video/omapdss/linux/fbdev.h b/src/video/omapdss/linux/fbdev.h
new file mode 100644 (file)
index 0000000..fa163aa
--- /dev/null
@@ -0,0 +1,12 @@
+struct vout_fbdev;
+
+struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int no_dblbuf);
+void *vout_fbdev_flip(struct vout_fbdev *fbdev);
+void  vout_fbdev_wait_vsync(struct vout_fbdev *fbdev);
+int   vout_fbdev_resize(struct vout_fbdev *fbdev, int w, int h,
+                       int left_border, int right_border, int top_border, int bottom_border,
+                       int no_dblbuf);
+void  vout_fbdev_clear(struct vout_fbdev *fbdev);
+void  vout_fbdev_clear_lines(struct vout_fbdev *fbdev, int y, int count);
+int   vout_fbdev_get_fd(struct vout_fbdev *fbdev);
+void  vout_fbdev_finish(struct vout_fbdev *fbdev);
diff --git a/src/video/omapdss/linux/oshide.c b/src/video/omapdss/linux/oshide.c
new file mode 100644 (file)
index 0000000..484618d
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * (C) Gražvydas "notaz" Ignotas, 2009-2010
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <dlfcn.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <linux/kd.h>
+
+#define PFX "oshide: "
+
+#define FPTR(f) typeof(f) * p##f
+#define FPTR_LINK(xf, dl, f) { \
+       xf.p##f = dlsym(dl, #f); \
+       if (xf.p##f == NULL) { \
+               fprintf(stderr, "missing symbol: %s\n", #f); \
+               goto fail; \
+       } \
+}
+
+struct xfuncs {
+FPTR(XCreateBitmapFromData);
+FPTR(XCreatePixmapCursor);
+FPTR(XFreePixmap);
+FPTR(XOpenDisplay);
+FPTR(XDisplayName);
+FPTR(XCloseDisplay);
+FPTR(XCreateSimpleWindow);
+FPTR(XChangeWindowAttributes);
+FPTR(XSelectInput);
+FPTR(XMapWindow);
+FPTR(XNextEvent);
+FPTR(XCheckTypedEvent);
+FPTR(XUnmapWindow);
+FPTR(XGrabKeyboard);
+};
+
+
+static Cursor transparent_cursor(struct xfuncs *xf, Display *display, Window win)
+{
+       Cursor cursor;
+       Pixmap pix;
+       XColor dummy;
+       char d = 0;
+
+       memset(&dummy, 0, sizeof(dummy));
+       pix = xf->pXCreateBitmapFromData(display, win, &d, 1, 1);
+       cursor = xf->pXCreatePixmapCursor(display, pix, pix,
+                       &dummy, &dummy, 0, 0);
+       xf->pXFreePixmap(display, pix);
+       return cursor;
+}
+
+static void *x11h_handler(void *arg)
+{
+       struct xfuncs xf;
+       unsigned int display_width, display_height;
+       XSetWindowAttributes attributes;
+       Window win;
+       XEvent report;
+       Display *display;
+       Visual *visual;
+       void *x11lib;
+       int screen;
+
+       memset(&xf, 0, sizeof(xf));
+       x11lib = dlopen("libX11.so.6", RTLD_LAZY);
+       if (x11lib == NULL) {
+               fprintf(stderr, "libX11.so load failed:\n%s\n", dlerror());
+               goto fail;
+       }
+       FPTR_LINK(xf, x11lib, XCreateBitmapFromData);
+       FPTR_LINK(xf, x11lib, XCreatePixmapCursor);
+       FPTR_LINK(xf, x11lib, XFreePixmap);
+       FPTR_LINK(xf, x11lib, XOpenDisplay);
+       FPTR_LINK(xf, x11lib, XDisplayName);
+       FPTR_LINK(xf, x11lib, XCloseDisplay);
+       FPTR_LINK(xf, x11lib, XCreateSimpleWindow);
+       FPTR_LINK(xf, x11lib, XChangeWindowAttributes);
+       FPTR_LINK(xf, x11lib, XSelectInput);
+       FPTR_LINK(xf, x11lib, XMapWindow);
+       FPTR_LINK(xf, x11lib, XNextEvent);
+       FPTR_LINK(xf, x11lib, XCheckTypedEvent);
+       FPTR_LINK(xf, x11lib, XUnmapWindow);
+       FPTR_LINK(xf, x11lib, XGrabKeyboard);
+
+       //XInitThreads();
+
+       display = xf.pXOpenDisplay(NULL);
+       if (display == NULL)
+       {
+               fprintf(stderr, "cannot connect to X server %s, X handling disabled.\n",
+                               xf.pXDisplayName(NULL));
+               goto fail2;
+       }
+
+       visual = DefaultVisual(display, 0);
+       if (visual->class != TrueColor)
+               fprintf(stderr, PFX "warning: non true color visual\n");
+
+       printf(PFX "X vendor: %s, rel: %d, display: %s, protocol ver: %d.%d\n", ServerVendor(display),
+               VendorRelease(display), DisplayString(display), ProtocolVersion(display),
+               ProtocolRevision(display));
+
+       screen = DefaultScreen(display);
+
+       display_width = DisplayWidth(display, screen);
+       display_height = DisplayHeight(display, screen);
+       printf(PFX "display is %dx%d\n", display_width, display_height);
+
+       win = xf.pXCreateSimpleWindow(display,
+                       RootWindow(display, screen),
+                       0, 0, display_width, display_height, 0,
+                       BlackPixel(display, screen),
+                       BlackPixel(display, screen));
+
+       attributes.override_redirect = True;
+       attributes.cursor = transparent_cursor(&xf, display, win);
+       xf.pXChangeWindowAttributes(display, win, CWOverrideRedirect | CWCursor, &attributes);
+
+       xf.pXSelectInput(display, win, ExposureMask | FocusChangeMask | KeyPressMask | KeyReleaseMask);
+       xf.pXMapWindow(display, win);
+       xf.pXGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
+       // XSetIOErrorHandler
+
+       while (1)
+       {
+               xf.pXNextEvent(display, &report);
+               switch (report.type)
+               {
+                       case Expose:
+                               while (xf.pXCheckTypedEvent(display, Expose, &report))
+                                       ;
+                               break;
+
+                       case FocusOut:
+                               // XFocusChangeEvent
+                               // printf("focus out\n");
+                               // xf.pXUnmapWindow(display, win);
+                               break;
+
+                       case KeyPress:
+                               // printf("press %d\n", report.xkey.keycode);
+                               break;
+
+                       default:
+                               break;
+               }
+       }
+
+fail2:
+       dlclose(x11lib);
+fail:
+       fprintf(stderr, "x11 handling disabled.\n");
+       return NULL;
+}
+
+static struct termios g_kbd_termios_saved;
+static int g_kbdfd;
+
+static void hidecon_start(void)
+{
+       struct termios kbd_termios;
+       int mode;
+
+       g_kbdfd = open("/dev/tty", O_RDWR);
+       if (g_kbdfd == -1) {
+               perror(PFX "open /dev/tty");
+               return;
+       }
+
+       if (ioctl(g_kbdfd, KDGETMODE, &mode) == -1) {
+               perror(PFX "(not hiding FB): KDGETMODE");
+               goto fail;
+       }
+
+       if (tcgetattr(g_kbdfd, &kbd_termios) == -1) {
+               perror(PFX "tcgetattr");
+               goto fail;
+       }
+
+       g_kbd_termios_saved = kbd_termios;
+       kbd_termios.c_lflag &= ~(ICANON | ECHO); // | ISIG);
+       kbd_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
+       kbd_termios.c_cc[VMIN] = 0;
+       kbd_termios.c_cc[VTIME] = 0;
+
+       if (tcsetattr(g_kbdfd, TCSAFLUSH, &kbd_termios) == -1) {
+               perror(PFX "tcsetattr");
+               goto fail;
+       }
+
+       if (ioctl(g_kbdfd, KDSETMODE, KD_GRAPHICS) == -1) {
+               perror(PFX "KDSETMODE KD_GRAPHICS");
+               tcsetattr(g_kbdfd, TCSAFLUSH, &g_kbd_termios_saved);
+               goto fail;
+       }
+
+       return;
+
+fail:
+       close(g_kbdfd);
+       g_kbdfd = -1;
+}
+
+static void hidecon_end(void)
+{
+       if (g_kbdfd < 0)
+               return;
+
+       if (ioctl(g_kbdfd, KDSETMODE, KD_TEXT) == -1)
+               perror(PFX "KDSETMODE KD_TEXT");
+
+       if (tcsetattr(g_kbdfd, TCSAFLUSH, &g_kbd_termios_saved) == -1)
+               perror(PFX "tcsetattr");
+
+       close(g_kbdfd);
+       g_kbdfd = -1;
+}
+
+int oshide_init(void)
+{
+       pthread_t tid;
+       int ret;
+
+       ret = pthread_create(&tid, NULL, x11h_handler, NULL);
+       if (ret != 0) {
+               fprintf(stderr, PFX "failed to create thread: %d\n", ret);
+               return ret;
+       }
+       pthread_detach(tid);
+
+       hidecon_start();
+
+       return 0;
+}
+
+void oshide_finish(void)
+{
+       /* XXX: the X thread.. */
+
+       hidecon_end();
+}
+
+#if 0
+int main()
+{
+       x11h_init();
+       sleep(5);
+}
+#endif
diff --git a/src/video/omapdss/linux/oshide.h b/src/video/omapdss/linux/oshide.h
new file mode 100644 (file)
index 0000000..f661305
--- /dev/null
@@ -0,0 +1,3 @@
+int  oshide_init(void);
+void oshide_finish(void);
+
index 4e842bc..ab94f3f 100644 (file)
@@ -13,7 +13,8 @@
 
 void omapsdl_input_init(void);
 void omapsdl_input_bind(const char *kname, const char *sdlname);
-int  omapsdl_input_get_event(int *is_down, int timeout);
+int  omapsdl_input_get_events(int timeout,
+               int (*cb)(void *cb_arg, int sdl_kc, int is_pressed), void *cb_arg);
 
 void omapsdl_config(void);
 
index 86a510d..68c58e4 100644 (file)
@@ -1,18 +1,27 @@
 /*
- * (C) notaz, 2010
+ * (C) Gražvydas "notaz" Ignotas, 2010
  *
  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  * See the COPYING file in the top-level directory.
  */
 
 #include <strings.h>
-#include <SDL/SDL.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
 #include <linux/input.h>
+#include <SDL/SDL.h>
 
 #include "omapsdl.h"
-#include "common/input.h"
 
-static short pmsdl_map[KEY_CNT] = {
+static int osdl_evdev_devs[32];
+static int osdl_evdev_dev_count;
+
+static short osdl_evdev_map[KEY_CNT] = {
        [KEY_0]         = SDLK_0,
        [KEY_1]         = SDLK_1,
        [KEY_2]         = SDLK_2,
@@ -113,8 +122,93 @@ static short pmsdl_map[KEY_CNT] = {
        [KEY_RIGHTCTRL] = SDLK_RCTRL,
 };
 
+static const char * const osdl_evdev_keys[KEY_CNT] = {
+       [KEY_RESERVED] = "Reserved",            [KEY_ESC] = "Esc",
+       [KEY_1] = "1",                          [KEY_2] = "2",
+       [KEY_3] = "3",                          [KEY_4] = "4",
+       [KEY_5] = "5",                          [KEY_6] = "6",
+       [KEY_7] = "7",                          [KEY_8] = "8",
+       [KEY_9] = "9",                          [KEY_0] = "0",
+       [KEY_MINUS] = "Minus",                  [KEY_EQUAL] = "Equal",
+       [KEY_BACKSPACE] = "Backspace",          [KEY_TAB] = "Tab",
+       [KEY_Q] = "Q",                          [KEY_W] = "W",
+       [KEY_E] = "E",                          [KEY_R] = "R",
+       [KEY_T] = "T",                          [KEY_Y] = "Y",
+       [KEY_U] = "U",                          [KEY_I] = "I",
+       [KEY_O] = "O",                          [KEY_P] = "P",
+       [KEY_LEFTBRACE] = "LeftBrace",          [KEY_RIGHTBRACE] = "RightBrace",
+       [KEY_ENTER] = "Enter",                  [KEY_LEFTCTRL] = "LeftControl",
+       [KEY_A] = "A",                          [KEY_S] = "S",
+       [KEY_D] = "D",                          [KEY_F] = "F",
+       [KEY_G] = "G",                          [KEY_H] = "H",
+       [KEY_J] = "J",                          [KEY_K] = "K",
+       [KEY_L] = "L",                          [KEY_SEMICOLON] = "Semicolon",
+       [KEY_APOSTROPHE] = "Apostrophe",        [KEY_GRAVE] = "Grave",
+       [KEY_LEFTSHIFT] = "LeftShift",          [KEY_BACKSLASH] = "BackSlash",
+       [KEY_Z] = "Z",                          [KEY_X] = "X",
+       [KEY_C] = "C",                          [KEY_V] = "V",
+       [KEY_B] = "B",                          [KEY_N] = "N",
+       [KEY_M] = "M",                          [KEY_COMMA] = "Comma",
+       [KEY_DOT] = "Dot",                      [KEY_SLASH] = "Slash",
+       [KEY_RIGHTSHIFT] = "RightShift",        [KEY_KPASTERISK] = "KPAsterisk",
+       [KEY_LEFTALT] = "LeftAlt",              [KEY_SPACE] = "Space",
+       [KEY_CAPSLOCK] = "CapsLock",            [KEY_F1] = "F1",
+       [KEY_F2] = "F2",                        [KEY_F3] = "F3",
+       [KEY_F4] = "F4",                        [KEY_F5] = "F5",
+       [KEY_F6] = "F6",                        [KEY_F7] = "F7",
+       [KEY_F8] = "F8",                        [KEY_F9] = "F9",
+       [KEY_F10] = "F10",                      [KEY_NUMLOCK] = "NumLock",
+       [KEY_SCROLLLOCK] = "ScrollLock",        [KEY_KP7] = "KP7",
+       [KEY_KP8] = "KP8",                      [KEY_KP9] = "KP9",
+       [KEY_KPMINUS] = "KPMinus",              [KEY_KP4] = "KP4",
+       [KEY_KP5] = "KP5",                      [KEY_KP6] = "KP6",
+       [KEY_KPPLUS] = "KPPlus",                [KEY_KP1] = "KP1",
+       [KEY_KP2] = "KP2",                      [KEY_KP3] = "KP3",
+       [KEY_KP0] = "KP0",                      [KEY_KPDOT] = "KPDot",
+       [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
+       [KEY_F11] = "F11",                      [KEY_F12] = "F12",
+       [KEY_KPJPCOMMA] = "KPJpComma",          [KEY_KPENTER] = "KPEnter",
+       [KEY_RIGHTCTRL] = "RightCtrl",          [KEY_KPSLASH] = "KPSlash",
+       [KEY_SYSRQ] = "SysRq",                  [KEY_RIGHTALT] = "RightAlt",
+       [KEY_LINEFEED] = "LineFeed",            [KEY_HOME] = "Home",
+       [KEY_UP] = "Up",                        [KEY_PAGEUP] = "PageUp",
+       [KEY_LEFT] = "Left",                    [KEY_RIGHT] = "Right",
+       [KEY_END] = "End",                      [KEY_DOWN] = "Down",
+       [KEY_PAGEDOWN] = "PageDown",            [KEY_INSERT] = "Insert",
+       [KEY_DELETE] = "Delete",                [KEY_MACRO] = "Macro",
+       [KEY_HELP] = "Help",                    [KEY_MENU] = "Menu",
+       [KEY_COFFEE] = "Coffee",                [KEY_DIRECTION] = "Direction",
+       [BTN_0] = "Btn0",                       [BTN_1] = "Btn1",
+       [BTN_2] = "Btn2",                       [BTN_3] = "Btn3",
+       [BTN_4] = "Btn4",                       [BTN_5] = "Btn5",
+       [BTN_6] = "Btn6",                       [BTN_7] = "Btn7",
+       [BTN_8] = "Btn8",                       [BTN_9] = "Btn9",
+       [BTN_LEFT] = "LeftBtn",                 [BTN_RIGHT] = "RightBtn",
+       [BTN_MIDDLE] = "MiddleBtn",             [BTN_SIDE] = "SideBtn",
+       [BTN_EXTRA] = "ExtraBtn",               [BTN_FORWARD] = "ForwardBtn",
+       [BTN_BACK] = "BackBtn",                 [BTN_TASK] = "TaskBtn",
+       [BTN_TRIGGER] = "Trigger",              [BTN_THUMB] = "ThumbBtn",
+       [BTN_THUMB2] = "ThumbBtn2",             [BTN_TOP] = "TopBtn",
+       [BTN_TOP2] = "TopBtn2",                 [BTN_PINKIE] = "PinkieBtn",
+       [BTN_BASE] = "BaseBtn",                 [BTN_BASE2] = "BaseBtn2",
+       [BTN_BASE3] = "BaseBtn3",               [BTN_BASE4] = "BaseBtn4",
+       [BTN_BASE5] = "BaseBtn5",               [BTN_BASE6] = "BaseBtn6",
+       [BTN_DEAD] = "BtnDead",                 [BTN_A] = "BtnA",
+       [BTN_B] = "BtnB",                       [BTN_C] = "BtnC",
+       [BTN_X] = "BtnX",                       [BTN_Y] = "BtnY",
+       [BTN_Z] = "BtnZ",                       [BTN_TL] = "BtnTL",
+       [BTN_TR] = "BtnTR",                     [BTN_TL2] = "BtnTL2",
+       [BTN_TR2] = "BtnTR2",                   [BTN_SELECT] = "BtnSelect",
+       [BTN_START] = "BtnStart",               [BTN_MODE] = "BtnMode",
+       [BTN_THUMBL] = "BtnThumbL",             [BTN_THUMBR] = "BtnThumbR",
+       [BTN_TOUCH] = "Touch",                  [BTN_STYLUS] = "Stylus",
+       [BTN_STYLUS2] = "Stylus2",              [BTN_TOOL_DOUBLETAP] = "Tool Doubletap",
+       [BTN_TOOL_TRIPLETAP] = "Tool Tripletap", [BTN_GEAR_DOWN] = "WheelBtn",
+       [BTN_GEAR_UP] = "Gear up",              [KEY_OK] = "Ok",
+};
+
 #define DNKEY(x) [SDLK_##x] = #x
-static const char *sdl_keynames[SDLK_LAST] = {
+static const char * const sdl_keynames[SDLK_LAST] = {
        DNKEY(BACKSPACE),
        DNKEY(TAB),
        DNKEY(RETURN),
@@ -342,56 +436,174 @@ void omapsdl_input_bind(const char *kname, const char *sdlname)
 {
        int i, kc;
 
-       kc = in_get_key_code(-1, kname);
-       if (kc < 0) {
-               err("can't resolve key '%s'", kname);
-               return;
+       if (kname == NULL || strncasecmp(kname, "ev_", 3) != 0)
+               goto bad_ev_key;
+
+       for (i = 0; i < ARRAY_SIZE(osdl_evdev_keys); i++) {
+               if (osdl_evdev_keys[i] == NULL)
+                       continue;
+               if (strcasecmp(osdl_evdev_keys[i], kname + 3) == 0)
+                       break;
        }
 
+       if (i >= ARRAY_SIZE(osdl_evdev_keys))
+               goto bad_ev_key;
+       kc = i;
+
        if (sdlname == NULL || strncasecmp(sdlname, "SDLK_", 5) != 0)
                goto bad_sdlkey;
 
-       for (i = 0; i < SDLK_LAST; i++) {
+       for (i = 0; i < ARRAY_SIZE(sdl_keynames); i++) {
                if (sdl_keynames[i] == NULL)
                        continue;
                if (strcasecmp(sdl_keynames[i], sdlname + 5) == 0)
                        break;
        }
 
-       if (i >= SDLK_LAST)
+       if (i >= ARRAY_SIZE(sdl_keynames))
                goto bad_sdlkey;
 
-       pmsdl_map[kc] = i;
+       osdl_evdev_map[kc] = i;
+       return;
+
+bad_ev_key:
+       err("can't resolve evdev key '%s'", kname);
        return;
 
 bad_sdlkey:
        err("can't resolve SDL key '%s'", sdlname);
 }
 
+#define KEYBITS_BIT(keybits, x) (keybits[(x)/sizeof(keybits[0])/8] & \
+       (1 << ((x) & (sizeof(keybits[0])*8-1))))
+
 void omapsdl_input_init(void)
 {
-       in_init();
-       in_probe();
+       long keybits[KEY_CNT / sizeof(long) / 8];
+       int i;
+
+       // the kernel might support and return less keys then we know about,
+       // so make sure the buffer is clear.
+       memset(keybits, 0, sizeof(keybits));
+
+       for (i = 0;; i++)
+       {
+               int support = 0, count = 0;
+               int u, ret, fd;
+               char name[64];
+
+               snprintf(name, sizeof(name), "/dev/input/event%d", i);
+               fd = open(name, O_RDONLY|O_NONBLOCK);
+               if (fd == -1) {
+                       if (errno == EACCES)
+                               continue;       /* maybe we can access next one */
+                       break;
+               }
+
+               /* check supported events */
+               ret = ioctl(fd, EVIOCGBIT(0, sizeof(support)), &support);
+               if (ret == -1) {
+                       printf("in_evdev: ioctl failed on %s\n", name);
+                       goto skip;
+               }
+
+               if (!(support & (1 << EV_KEY)))
+                       goto skip;
+
+               ret = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits);
+               if (ret == -1) {
+                       printf("in_evdev: ioctl failed on %s\n", name);
+                       goto skip;
+               }
+
+               /* check for interesting keys */
+               for (u = 0; u < KEY_CNT; u++) {
+                       if (KEYBITS_BIT(keybits, u)) {
+                               if (u != KEY_POWER && u != KEY_SLEEP && u != BTN_TOUCH)
+                                       count++;
+                       }
+               }
+
+               if (count == 0)
+                       goto skip;
+
+               osdl_evdev_devs[osdl_evdev_dev_count++] = fd;
+               ioctl(fd, EVIOCGNAME(sizeof(name)), name);
+               printf("in_evdev: found \"%s\" with %d events (type %08x)\n",
+                       name, count, support);
+               continue;
+
+skip:
+               close(fd);
+       }
+
+       printf("found %d evdev devices.\n", osdl_evdev_dev_count);
 }
 
-int omapsdl_input_get_event(int *is_down, int timeout)
+int omapsdl_input_get_events(int timeout_ms,
+               int (*cb)(void *cb_arg, int sdl_kc, int is_pressed), void *cb_arg)
 {
-       int key;
+       struct timeval tv, *timeout = NULL;
+       struct input_event ev;
+       int i, fdmax = -1;
+       fd_set fdset;
+
+       if (timeout_ms >= 0) {
+               tv.tv_sec = timeout_ms / 1000;
+               tv.tv_usec = (timeout_ms % 1000) * 1000;
+               timeout = &tv;
+       }
 
-       while (1) {
-               int kc;
+       FD_ZERO(&fdset);
+       for (i = 0; i < osdl_evdev_dev_count; i++) {
+               if (osdl_evdev_devs[i] > fdmax)
+                       fdmax = osdl_evdev_devs[i];
+               FD_SET(osdl_evdev_devs[i], &fdset);
+       }
 
-               *is_down = 0;
-               kc = in_update_keycode(NULL, is_down, timeout);
-               if (kc < 0 || kc > KEY_MAX)
-                       return -1;
+       while (1)
+       {
+               int fd, ret, sdl_kc;
 
-               key = pmsdl_map[kc];
-               if (key != 0)
-                       break;
+               ret = select(fdmax + 1, &fdset, NULL, NULL, timeout);
+               if (ret == -1)
+               {
+                       perror("in_evdev: select failed");
+                       return -1;
+               }
+               else if (ret == 0)
+                       return -1; /* timeout */
+
+               for (i = 0; i < osdl_evdev_dev_count; i++) {
+                       if (!FD_ISSET(osdl_evdev_devs[i], &fdset))
+                               continue;
+
+                       fd = osdl_evdev_devs[i];
+                       while (1) {
+                               ret = read(fd, &ev, sizeof(ev));
+                               if (ret < (int)sizeof(ev)) {
+                                       if (errno != EAGAIN) {
+                                               perror("in_evdev: read failed");
+                                               return -1;
+                                       }
+                                       break;
+                               }
+
+                               if (ev.type != EV_KEY)
+                                       continue; /* not key event */
+                               if ((unsigned int)ev.value > 1)
+                                       continue; /* not key up/down */
+                               if ((unsigned int)ev.code >= ARRAY_SIZE(osdl_evdev_map))
+                                       continue; /* keycode from future */
+                               sdl_kc = osdl_evdev_map[ev.code];
+                               if (sdl_kc == 0)
+                                       continue; /* not mapped */
+                               ret = cb(cb_arg, sdl_kc, ev.value);
+                               if (ret != 0)
+                                       return ret;
+                       }
+               }
        }
-
-       return key;
 }
 
 /* SDL */
@@ -399,24 +611,39 @@ int omapsdl_input_get_event(int *is_down, int timeout)
 
 static unsigned char g_keystate[SDLK_LAST];
 
+struct key_event {
+       int sdl_kc;
+       int is_pressed;
+};
+
+static int do_key_cb(void *cb_arg, int sdl_kc, int is_pressed)
+{
+       struct key_event *ev = cb_arg;
+       ev->sdl_kc = sdl_kc;
+       ev->is_pressed = is_pressed;
+
+       return 1; /* done */
+}
+
 static int do_event(SDL_Event *event, int timeout)
 {
-       int key, is_down;
+       struct key_event ev;
+       int ret;
 
-       key = omapsdl_input_get_event(&is_down, timeout);
-       if (key < 0)
+       ret = omapsdl_input_get_events(timeout, do_key_cb, &ev);
+       if (ret < 0)
                return 0;
 
-       g_keystate[key] = is_down;
+       g_keystate[ev.sdl_kc] = ev.is_pressed;
 
        if (event == NULL)
                return 1; // FIXME: ..but the event is lost
 
        memset(event, 0, sizeof(event->key));
-       event->type = is_down ? SDL_KEYDOWN : SDL_KEYUP;
+       event->type = ev.is_pressed ? SDL_KEYDOWN : SDL_KEYUP;
        // event->key.which =
-       event->key.state = is_down ? SDL_PRESSED : SDL_RELEASED;
-       event->key.keysym.sym = key;
+       event->key.state = ev.is_pressed ? SDL_PRESSED : SDL_RELEASED;
+       event->key.keysym.sym = ev.sdl_kc;
        // event->key.keysym.mod
 
        return 1;
index 8c0e6bc..de238e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) notaz, 2010
+ * (C) Gražvydas "notaz" Ignotas, 2010
  *
  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  * See the COPYING file in the top-level directory.
@@ -12,7 +12,6 @@
 #include <SDL/SDL.h>
 
 #include "omapsdl.h"
-#include "common/input.h"
 #include "linux/fbdev.h"
 #include "linux/oshide.h"