From ad169fb488d48df5dd4e2a72aceee64a5c57c729 Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Fri, 11 Dec 2015 12:23:40 +0100 Subject: [PATCH] New driver linux_input This driver receives input from event devices of the linux input subsystem. Tested on Linux 3.16/i386. Signed-off-by: Harald Geyer --- LCDd.conf | 17 +- acinclude.m4 | 12 +- docs/LCDd.8.in | 3 + docs/lcdproc-user/drivers.docbook | 1 + docs/lcdproc-user/drivers/linux_input.docbook | 57 +++++ docs/lcdproc-user/lcdproc-user.docbook | 1 + server/drivers/Makefile.am | 3 +- server/drivers/linux_input.c | 230 ++++++++++++++++++ server/drivers/linux_input.h | 11 + 9 files changed, 331 insertions(+), 4 deletions(-) create mode 100644 docs/lcdproc-user/drivers/linux_input.docbook create mode 100644 server/drivers/linux_input.c create mode 100644 server/drivers/linux_input.h diff --git a/LCDd.conf b/LCDd.conf index f0ac69b..41aa8dd 100644 --- a/LCDd.conf +++ b/LCDd.conf @@ -46,7 +46,7 @@ DriverPath=server/drivers/ # The following drivers are supported: # bayrad, CFontz, CFontzPacket, curses, CwLnx, ea65, EyeboxOne, g15, glcd, # glcdlib, glk, hd44780, icp_a106, imon, imonlcd,, IOWarrior, irman, joy, -# lb216, lcdm001, lcterm, lirc, lis, MD8800,, mdm166a, ms6931, mtc_s16209x, +# lb216, lcdm001, lcterm, linux_input, lirc, lis, MD8800, mdm166a, ms6931, mtc_s16209x, # MtxOrb, mx5000, NoritakeVFD, picolcd,, pyramid, rawserial, sdeclcd, # sed1330, sed1520, serialPOS, serialVFD, shuttleVFD, sli,, stv5730, svga, # t6963, text, tyan, ula200, vlsys_m428, xosd @@ -797,6 +797,21 @@ Device=/dev/ttyS1 Size=16x2 +## Linux event device input driver ## +[linux_input] + +# Select the input device to use [default: /dev/input/event0] +Device=/dev/input/event0 + +# specify a non-default key map +#key=1,Escape +#key=28,Enter +#key=96,Enter +#key=105,Left +#key=106,Right +#key=103,Up +#key=108,Down + ## LIRC input driver ## [lirc] diff --git a/acinclude.m4 b/acinclude.m4 index 0a7e423..fe7ab78 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -11,7 +11,7 @@ AC_ARG_ENABLE(drivers, [ bayrad,CFontz,CFontzPacket,curses,CwLnx,ea65,] [ EyeboxOne,g15,glcd,glcdlib,glk,hd44780,i2500vfd,] [ icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,] - [ joy,lb216,lcdm001,lcterm,lirc,lis,MD8800,mdm166a,] + [ joy,lb216,lcdm001,lcterm,linux_input,lirc,lis,MD8800,mdm166a,] [ ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,] [ picolcd,pyramid,rawserial,sdeclcd,sed1330,sed1520,] [ serialPOS,serialVFD,shuttleVFD,sli,stv5730,SureElec,] @@ -22,7 +22,7 @@ AC_ARG_ENABLE(drivers, drivers="$enableval", drivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,glk,lb216,lcdm001,MtxOrb,pyramid,text]) -allDrivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcd,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,lirc,lis,MD8800,mdm166a,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,picolcd,pyramid,sdeclcd,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,stv5730,SureElec,svga,t6963,text,tyan,ula200,vlsys_m428,xosd,rawserial] +allDrivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcd,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,linux_input,lirc,lis,MD8800,mdm166a,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,picolcd,pyramid,sdeclcd,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,stv5730,SureElec,svga,t6963,text,tyan,ula200,vlsys_m428,xosd,rawserial] if test "$debug" = yes; then allDrivers=["${allDrivers},debug"] fi @@ -310,6 +310,14 @@ dnl else DRIVERS="$DRIVERS lcterm${SO}" actdrivers=["$actdrivers lcterm"] ;; + linux_input) + case $host in + *-*-linux*) + DRIVERS="$DRIVERS linux_input${SO}" + actdrivers=["$actdrivers linux_input"] + ;; + esac + ;; lirc) AC_CHECK_LIB(lirc_client, main,[ LIBLIRC_CLIENT="-llirc_client" diff --git a/docs/LCDd.8.in b/docs/LCDd.8.in index 977e22d..6028b91 100644 --- a/docs/LCDd.8.in +++ b/docs/LCDd.8.in @@ -247,6 +247,9 @@ kernelconcepts.de 20x4 serial LCD displays .B lcterm serial LCD terminal from Helmut Neumark Elektronik (http://www.neumark.de) .TP +.B linux_input +Linux event devices (input) +.TP .B lirc Infrared (input) .TP diff --git a/docs/lcdproc-user/drivers.docbook b/docs/lcdproc-user/drivers.docbook index 72a4244..e9a83f7 100644 --- a/docs/lcdproc-user/drivers.docbook +++ b/docs/lcdproc-user/drivers.docbook @@ -30,6 +30,7 @@ well as the configuration of LCDd. &lb216; &lcdm001; &lcterm; +&linux_input; &lirc; &lis; &MD8800; diff --git a/docs/lcdproc-user/drivers/linux_input.docbook b/docs/lcdproc-user/drivers/linux_input.docbook new file mode 100644 index 0000000..394d361 --- /dev/null +++ b/docs/lcdproc-user/drivers/linux_input.docbook @@ -0,0 +1,57 @@ + +The Linux Event Device Input Driver + + +This section covers the linux event device input driver for LCDd. + + + + +Configuration in LCDd.conf + + +[linux_input] + + + + + Device = + DEVICE + + + Select the input device to use [default: /dev/input/event0] + + + + + + key = + KEYCODE,KEY + + + + Set an alternate key map, e.g. to use custom buttons instead of the + standard codes for Escape, Enter, Left, Right, Up and Down. This entry + typically repeaded for any non-standard key code. + + + + KEYCODE is an integer like the ones defined in + /usr/include/linux/input.h. + + + + KEY can be one of the keys that LCDd recognizes + (Left, Right, Up, + Down, Enter or Escape) + or any other string that a client can parse. + + + + + + + + + + diff --git a/docs/lcdproc-user/lcdproc-user.docbook b/docs/lcdproc-user/lcdproc-user.docbook index 1c73ed6..b3ec38d 100644 --- a/docs/lcdproc-user/lcdproc-user.docbook +++ b/docs/lcdproc-user/lcdproc-user.docbook @@ -37,6 +37,7 @@ + diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am index d0127db..378a55f 100644 --- a/server/drivers/Makefile.am +++ b/server/drivers/Makefile.am @@ -23,7 +23,7 @@ AM_LDFLAGS = @LDSHARED@ lcdexecbindir = $(pkglibdir) lcdexecbin_PROGRAMS = @DRIVERS@ -EXTRA_PROGRAMS = bayrad CFontz CFontzPacket curses CwLnx debug ea65 EyeboxOne g15 glcd glcdlib glk hd44780 i2500vfd icp_a106 imon imonlcd IOWarrior irman irtrans joy lb216 lcdm001 lcterm lirc lis MD8800 mdm166a ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD picolcd pyramid rawserial sdeclcd sed1330 sed1520 serialPOS serialVFD shuttleVFD sli stv5730 SureElec svga t6963 text tyan ula200 vlsys_m428 xosd +EXTRA_PROGRAMS = bayrad CFontz CFontzPacket curses CwLnx debug ea65 EyeboxOne g15 glcd glcdlib glk hd44780 i2500vfd icp_a106 imon imonlcd IOWarrior irman irtrans joy lb216 lcdm001 lcterm linux_input lirc lis MD8800 mdm166a ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD picolcd pyramid rawserial sdeclcd sed1330 sed1520 serialPOS serialVFD shuttleVFD sli stv5730 SureElec svga t6963 text tyan ula200 vlsys_m428 xosd noinst_LIBRARIES = libLCD.a libbignum.a g15_CFLAGS = @LIBUSB_CFLAGS@ $(AM_CFLAGS) @@ -107,6 +107,7 @@ joy_SOURCES = lcd.h joy.c joy.h port.h report.h lb216_SOURCES = lcd.h lcd_lib.h lb216.c lb216.h report.h lcdm001_SOURCES = lcd.h lcdm001.c lcdm001.h report.h lcterm_SOURCES = lcd.h lcd_lib.h lcterm.c lcterm.h report.h +linux_input_SOURCES = lcd.h linux_input.h linux_input.c report.h lirc_SOURCES = lcd.h lircin.c lircin.h report.h lis_SOURCES = lcd.h lcd_lib.h lis.h lis.c report.h MD8800_SOURCES = lcd.h lcd_lib.h MD8800.c MD8800.h report.h diff --git a/server/drivers/linux_input.c b/server/drivers/linux_input.c new file mode 100644 index 0000000..86a3855 --- /dev/null +++ b/server/drivers/linux_input.c @@ -0,0 +1,230 @@ +/** \file server/drivers/linux_input.c + * LCDd \c linux event device driver for inputting data from the input + * subsystem of the linux kernel.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "lcd.h" +#include "linux_input.h" +#include "report.h" +#include "shared/LL.h" + +#define LINUXINPUT_DEFAULT_DEVICE "/dev/input/event0" + +/** describe the button of a keycode */ +struct keycode { + unsigned short code; + char *button; +}; + +/** + * Parse key definition from config file + * \param configvalue value part of the config file entry + * \retval NULL Error. + * \retval else Pointer to newly allocated struct keycode. + */ +static struct keycode * +keycode_create(const char *configvalue) +{ + int code; + char *button; + struct keycode *ret; + + code = atoi(configvalue); + if (code < 0 || code > UINT16_MAX) + return NULL; + + button = strchr(configvalue,','); + if (!button) + return NULL; + button = strdup(&button[1]); + if (!button) + return NULL; + + ret = malloc(sizeof(*ret)); + if (ret) { + ret->code = code; + ret->button = button; + } + + return ret; +} + +/** private data for the linux event device driver */ +typedef struct linuxInput_private_data { + int fd; + LinkedList *buttonmap; +} PrivateData; + + +// Vars for the server core +MODULE_EXPORT char *api_version = API_VERSION; +MODULE_EXPORT int stay_in_foreground = 0; +MODULE_EXPORT int supports_multiple = 1; +MODULE_EXPORT char *symbol_prefix = "linuxInput_"; + + +/** + * Initialize the driver. + * \param drvthis Pointer to driver structure. + * \retval 0 Success. + * \retval <0 Error. + */ +MODULE_EXPORT int +linuxInput_init (Driver *drvthis) +{ + PrivateData *p; + const char *s; + struct keycode *key; + int i; + + /* Allocate and store private data */ + p = (PrivateData *) calloc(1, sizeof(PrivateData)); + if (p == NULL) + return -1; + if (drvthis->store_private_ptr(drvthis, p)) + return -1; + + /* initialize private data */ + p->fd = -1; + if ((p->buttonmap = LL_new()) == NULL) { + report(RPT_ERR, "%s: cannot allocate memory for buttons", drvthis->name); + return -1; + } + + /* Read config file */ + + /* What device should be used */ + s = drvthis->config_get_string(drvthis->name, "Device", 0, + LINUXINPUT_DEFAULT_DEVICE); + report(RPT_INFO, "%s: using Device %s", drvthis->name, s); + + + if ((p->fd = open(s, O_RDONLY | O_NONBLOCK)) < 0) { + report(RPT_ERR, "%s: open(%s) failed (%s)", + drvthis->name, s, strerror(errno)); + return -1; + } + + for (i = 0; (s = drvthis->config_get_string(drvthis->name, "key", i, NULL)) != NULL; i++) { + if ((key = keycode_create(s)) == NULL) { + report(RPT_ERR, "%s: parsing configvalue '%s' failed", + drvthis->name, s); + continue; + } + LL_AddNode(p->buttonmap, key); + } + + report(RPT_DEBUG, "%s: init() done", drvthis->name); + + return 0; +} + + +/** + * Close the driver (do necessary clean-up). + * \param drvthis Pointer to driver structure. + */ +MODULE_EXPORT void +linuxInput_close (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + struct keycode *k; + + if (p != NULL) { + if (p->fd >= 0) + close(p->fd); + + if (p->buttonmap != NULL) { + while ((k = LL_Pop(p->buttonmap)) != NULL) { + free(k->button); + free(k); + } + LL_Destroy(p->buttonmap); + } + + free(p); + } + drvthis->store_private_ptr(drvthis, NULL); +} + + +/** + * Helper function to check LL items against a given key code. + * \param data Pointer to data of list item + * \param codep Pointer to value holding the received key code + * \retval 0 We found the right item. + * \retval else We need to continue searching. + */ +static int +compare_with_keycode (void *data, void *codep) +{ + uint16_t code = *(uint16_t *)codep; + struct keycode *k = data; + + return k->code != code; +} + +/** + * Read the next input event. + * \param drvthis Pointer to driver structure. + * \retval String representation of the key; + * \c NULL for nothing available / error. + */ +MODULE_EXPORT const char * +linuxInput_get_key (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + struct input_event event; + struct keycode *k; + + if (read(p->fd, &event, sizeof(event)) != sizeof(event)) + return NULL; + + /* Ignore release events and not-key events */ + if (event.type != EV_KEY || event.value == 0) + return NULL; + + switch (event.code) { + case KEY_ESC: + return "Escape"; + + case KEY_UP: + return "Up"; + + case KEY_LEFT: + return "Left"; + + case KEY_RIGHT: + return "Right"; + + case KEY_DOWN: + return "Down"; + + case KEY_ENTER: + case KEY_KPENTER: + return "Enter"; + + default: + LL_Rewind(p->buttonmap); + k = LL_Find(p->buttonmap, compare_with_keycode, &event.code); + if (k) + return k->button; + + return NULL; + } +} diff --git a/server/drivers/linux_input.h b/server/drivers/linux_input.h new file mode 100644 index 0000000..8477f58 --- /dev/null +++ b/server/drivers/linux_input.h @@ -0,0 +1,11 @@ +#ifndef LINUX_INPUT_H +#define LINUX_INPUT_H + +#include "lcd.h" + +MODULE_EXPORT int linuxInput_init (Driver *drvthis); +MODULE_EXPORT void linuxInput_close (Driver *drvthis); + +MODULE_EXPORT const char *linuxInput_get_key (Driver *drvthis); + +#endif