You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lirc/lirc-0.8.6-devinput-pass-mo...

263 lines
5.5 KiB

diff -Naurp lirc-0.8.6/daemons/hw_devinput.c~ lirc-0.8.6/daemons/hw_devinput.c
--- lirc-0.8.6/daemons/hw_devinput.c~ 2009/09/07 18:08:00 5.20
+++ lirc-0.8.6/daemons/hw_devinput.c 2009/10/31 09:37:30 5.21
@@ -31,8 +31,10 @@
#include <sys/types.h>
#include <dirent.h>
#include <fnmatch.h>
+#include <limits.h>
#include <linux/input.h>
+#include <linux/uinput.h>
#ifndef EV_SYN
/* previous name */
@@ -44,8 +46,18 @@
#include "lircd.h"
#include "receive.h"
+/* from evtest.c - Copyright (c) 1999-2000 Vojtech Pavlik */
+#define BITS_PER_LONG (sizeof(long) * CHAR_BIT)
+/* NBITS was defined in linux/uinput.h */
+#undef NBITS
+#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
+#define OFF(x) ((x)%BITS_PER_LONG)
+#define BIT(x) (1UL<<OFF(x))
+#define LONG(x) ((x)/BITS_PER_LONG)
+#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
static int devinput_init();
+static int devinput_init_fwd();
static int devinput_deinit(void);
static int devinput_decode(struct ir_remote *remote,
ir_code *prep, ir_code *codep, ir_code *postp,
@@ -67,7 +76,7 @@
0, /* send_mode */
LIRC_MODE_LIRCCODE, /* rec_mode */
32, /* code_length */
- devinput_init, /* init_func */
+ devinput_init_fwd, /* init_func */
NULL, /* config_func */
devinput_deinit, /* deinit_func */
NULL, /* send_func */
@@ -80,6 +89,141 @@
static ir_code code;
static int repeat_flag=0;
+static int exclusive = 0;
+static int uinputfd = -1;
+
+static int setup_uinputfd(const char *name, int source)
+{
+ int fd;
+ int key;
+ struct uinput_user_dev dev;
+ long events[NBITS(EV_MAX)];
+ long bits[NBITS(KEY_MAX)];
+
+ if(ioctl(source, EVIOCGBIT(0, EV_MAX), events) == -1)
+ {
+ return -1;
+ }
+ if(!test_bit(EV_REL, events) && !test_bit(EV_ABS, events))
+ {
+ /* no move events, don't forward anything */
+ return -1;
+ }
+ fd = open("/dev/input/uinput", O_RDWR);
+ if(fd == -1)
+ {
+ fd = open("/dev/uinput", O_RDWR);
+ if(fd == -1)
+ {
+ fd = open("/dev/misc/uinput", O_RDWR);
+ if(fd == -1)
+ {
+ logprintf(LOG_WARNING, "could not open %s\n",
+ "uinput");
+ logperror(LOG_WARNING, NULL);
+ return -1;
+ }
+ }
+ }
+ memset(&dev, 0, sizeof(dev));
+ if(ioctl(source, EVIOCGNAME(sizeof(dev.name)), dev.name) >= 0)
+ {
+ dev.name[sizeof(dev.name)-1] = 0;
+ if(strlen(dev.name) > 0)
+ {
+ strncat(dev.name, " ", sizeof(dev.name) -
+ strlen(dev.name));
+ dev.name[sizeof(dev.name)-1] = 0;
+ }
+ }
+ strncat(dev.name, name, sizeof(dev.name) - strlen(dev.name));
+ dev.name[sizeof(dev.name)-1] = 0;
+
+ if(write(fd, &dev, sizeof(dev)) != sizeof(dev))
+ {
+ goto setup_error;
+ }
+
+ if(test_bit(EV_KEY, events))
+ {
+ if(ioctl(source, EVIOCGBIT(EV_KEY, KEY_MAX), bits) == -1)
+ {
+ goto setup_error;
+ }
+
+ if(ioctl(fd, UI_SET_EVBIT, EV_KEY) == -1)
+ {
+ goto setup_error;
+ }
+
+ /* only forward mouse button events */
+ for(key = BTN_MISC; key <= BTN_GEAR_UP; key++)
+ {
+ if(test_bit(key, bits))
+ {
+ if(ioctl(fd, UI_SET_KEYBIT, key) == -1)
+ {
+ goto setup_error;
+ }
+ }
+ }
+ }
+ if(test_bit(EV_REL, events))
+ {
+ if(ioctl(source, EVIOCGBIT(EV_REL, REL_MAX), bits) == -1)
+ {
+ goto setup_error;
+ }
+ if(ioctl(fd, UI_SET_EVBIT, EV_REL) == -1)
+ {
+ goto setup_error;
+ }
+ for(key = 0; key <= REL_MAX; key++)
+ {
+ if(test_bit(key, bits))
+ {
+ if(ioctl(fd, UI_SET_RELBIT, key) == -1)
+ {
+ goto setup_error;
+ }
+ }
+ }
+ }
+ if(test_bit(EV_ABS, events))
+ {
+ if(ioctl(source, EVIOCGBIT(EV_ABS, ABS_MAX), bits) == -1)
+ {
+ goto setup_error;
+ }
+ if(ioctl(fd, UI_SET_EVBIT, EV_ABS) == -1)
+ {
+ goto setup_error;
+ }
+ for(key = 0; key <= ABS_MAX; key++)
+ {
+ if(test_bit(key, bits))
+ {
+ if(ioctl(fd, UI_SET_ABSBIT, key) == -1)
+ {
+ goto setup_error;
+ }
+ }
+ }
+ }
+
+
+ if(ioctl(fd, UI_DEV_CREATE) == -1)
+ {
+ goto setup_error;
+ }
+ return fd;
+
+ setup_error:
+ logprintf(LOG_ERR, "could not setup %s\n", "uinput");
+ logperror(LOG_ERR, NULL);
+ close(fd);
+ return -1;
+}
#if 0
/* using fnmatch */
@@ -217,13 +361,26 @@
}
#ifdef EVIOCGRAB
+ exclusive = 1;
if (ioctl(hw.fd, EVIOCGRAB, 1) == -1)
{
+ exclusive = 0;
logprintf(LOG_WARNING, "can't get exclusive access to events "
"coming from `%s' interface",
hw.device);
}
#endif
+ return 1;
+}
+
+int devinput_init_fwd()
+{
+ if(!devinput_init()) return 0;
+
+ if(exclusive)
+ {
+ uinputfd = setup_uinputfd("(lircd bypass)", hw.fd);
+ }
return 1;
}
@@ -232,6 +389,12 @@
int devinput_deinit(void)
{
logprintf(LOG_INFO, "closing '%s'", hw.device);
+ if(uinputfd != -1)
+ {
+ ioctl(uinputfd, UI_DEV_DESTROY);
+ close(uinputfd);
+ uinputfd = -1;
+ }
close(hw.fd);
hw.fd=-1;
return 1;
@@ -271,7 +434,10 @@
rd = read(hw.fd, &event, sizeof event);
if (rd != sizeof event) {
logprintf(LOG_ERR, "error reading '%s'", hw.device);
- if(rd <= 0 && errno != EINTR) raise(SIGTERM);
+ if(rd <= 0 && errno != EINTR)
+ {
+ devinput_deinit();
+ }
return 0;
}
@@ -292,6 +458,25 @@
LOGPRINTF(1, "code %.8llx", code);
+ if(uinputfd != -1)
+ {
+ if(event.type == EV_REL ||
+ event.type == EV_ABS ||
+ (event.type == EV_KEY &&
+ event.code >= BTN_MISC &&
+ event.code <= BTN_GEAR_UP) ||
+ event.type == EV_SYN)
+ {
+ LOGPRINTF(1, "forwarding: %04x %04x", event.type, event.code);
+ if(write(uinputfd, &event, sizeof(event)) != sizeof(event))
+ {
+ logprintf(LOG_ERR, "writing to uinput failed");
+ logperror(LOG_ERR, NULL);
+ }
+ return NULL;
+ }
+ }
+
/* ignore EV_SYN */
if(event.type == EV_SYN) return NULL;