rcinput: use a dynamic list of input devices

Instead of the fixed, static list of input devices, scan /dev/input/ for
proper event devices. A "good" input device is one that supports the
EVIOCGBIT ioctl and at least the EV_KEY event type.
This probably needs further fixes, e.g. in repeat rate setting code.


Origin commit data
------------------
Branch: ni/coolstream
Commit: 7b3aa2b181
Author: Stefan Seyfried <seife@tuxbox-git.slipkontur.de>
Date: 2017-02-19 (Sun, 19 Feb 2017)



------------------
This commit was generated by Migit
This commit is contained in:
Stefan Seyfried
2017-02-19 23:16:09 +01:00
committed by Michael Liebmann
parent 3c7aca7949
commit b5ec2b42df
2 changed files with 139 additions and 66 deletions

View File

@@ -4,7 +4,7 @@
Copyright (C) 2001 Steffen Hehn 'McClean' Copyright (C) 2001 Steffen Hehn 'McClean'
2003 thegoodguy 2003 thegoodguy
Copyright (C) 2008-2014,2016 Stefan Seyfried Copyright (C) 2008-2014,2016-2017 Stefan Seyfried
Copyright (C) 2013-2014 martii Copyright (C) 2013-2014 martii
License: GPL License: GPL
@@ -33,7 +33,6 @@
#include <system/helpers.h> #include <system/helpers.h>
#include <stdio.h> #include <stdio.h>
#include <asm/types.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
@@ -50,6 +49,8 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <dirent.h>
#include <eventserver.h> #include <eventserver.h>
#include <global.h> #include <global.h>
@@ -65,17 +66,6 @@
#define ENABLE_REPEAT_CHECK #define ENABLE_REPEAT_CHECK
#if HAVE_SPARK_HARDWARE
/* this relies on event0 being the AOTOM frontpanel driver device
* TODO: what if another input device is present? */
const char * const RC_EVENT_DEVICE[NUMBER_OF_EVENT_DEVICES] = {"/dev/input/nevis_ir", "/dev/input/event0"};
#elif HAVE_GENERIC_HARDWARE
/* the FIFO created by libstb-hal */
const char * const RC_EVENT_DEVICE[NUMBER_OF_EVENT_DEVICES] = {"/tmp/neutrino.input"};
#else
//const char * const RC_EVENT_DEVICE[NUMBER_OF_EVENT_DEVICES] = {"/dev/input/nevis_ir", "/dev/input/event0"};
const char * const RC_EVENT_DEVICE[NUMBER_OF_EVENT_DEVICES] = {"/dev/input/nevis_ir"};
#endif
typedef struct input_event t_input_event; typedef struct input_event t_input_event;
#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL #ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL
@@ -83,6 +73,13 @@ static struct termio orig_termio;
static bool saved_orig_termio = false; static bool saved_orig_termio = false;
#endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ #endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */
static bool input_stopped = false; static bool input_stopped = false;
static struct timespec devinput_mtime = { 0, 0 };
#ifdef RCDEBUG
#define d_printf printf
#else
#define d_printf(...)
#endif
/********************************************************************************* /*********************************************************************************
* Constructor - opens rc-input device, selects rc-hardware and starts threads * Constructor - opens rc-input device, selects rc-hardware and starts threads
@@ -146,13 +143,9 @@ CRCInput::CRCInput()
perror("[neutrino] listen failed...\n"); perror("[neutrino] listen failed...\n");
exit( -1 ); exit( -1 );
} }
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++)
{
fd_rc[i] = -1;
}
clickfd = -1; clickfd = -1;
repeat_block = repeat_block_generic = 0; repeat_block = repeat_block_generic = 0;
checkdev();
open(); open();
rc_last_key = KEY_MAX; rc_last_key = KEY_MAX;
firstKey = true; firstKey = true;
@@ -162,21 +155,93 @@ CRCInput::CRCInput()
set_rc_hw(); set_rc_hw();
} }
/* if dev is given, open device with index <dev>, if not (re)open all */ bool CRCInput::checkdev()
void CRCInput::open(int dev)
{ {
if (dev == -1) /* stat()ing the directory is fast and cheap. If a device gets added or
close(); * removed, the mtime of /dev/input/ will change, which in turn
* warrants a more thorough investigation */
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) struct stat st;
{ if (stat("/dev/input/", &st) == 0) {
if (dev != -1) { if (st.st_mtim.tv_sec != devinput_mtime.tv_sec ||
if (i != dev || fd_rc[i] != -1) st.st_mtim.tv_nsec != devinput_mtime.tv_nsec) {
continue; devinput_mtime.tv_sec = st.st_mtim.tv_sec;
devinput_mtime.tv_nsec = st.st_mtim.tv_nsec;
printf("[rcinput:%s] /dev/input mtime changed\n", __func__);
return true;
}
return false; /* still the same... */
}
printf("[rcinput:%s] stat /dev/input failed: %m\n", __func__);
return true; /* need to check anyway... */
}
bool CRCInput::checkpath(in_dev id)
{
for (std::vector<in_dev>::iterator it = indev.begin(); it != indev.end(); ++it) {
if ((*it).path == id.path) {
printf("[rcinput:%s] skipping already opened %s\n", __func__, id.path.c_str());
return true;
}
}
return false;
}
/* if recheck == true, only not already opened devices are opened, if not, close then (re)open all */
void CRCInput::open(bool recheck)
{
if (recheck == false)
close();
/* close() takes the lock, too... */
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
unsigned long evbit;
struct in_dev id;
DIR *dir;
struct dirent *dentry;
dir = opendir("/dev/input");
if (! dir) {
printf("[rcinput:%s] opendir failed: %m\n", __func__);
return;
}
while ((dentry = readdir(dir)) != NULL)
{
if (dentry->d_type != DT_CHR) {
d_printf("[rcinput:%s] skipping '%s'\n", __func__, dentry->d_name);
continue;
}
d_printf("[rcinput:%s] considering '%s'\n", __func__, dentry->d_name);
id.path = "/dev/input/" + std::string(dentry->d_name);
if (checkpath(id))
continue;
id.fd = ::open(id.path.c_str(), O_RDWR|O_NONBLOCK|O_CLOEXEC);
if (id.fd == -1) {
printf("[rcinput:%s] open %s failed: %m\n", __func__, id.path.c_str());
continue;
}
if (ioctl(id.fd, EVIOCGBIT(0, EV_MAX), &evbit) < 0) {
::close(id.fd); /* not a proper input device, e.g. /dev/input/mice */
continue;
}
if ((evbit & (1 << EV_KEY)) == 0) {
printf("[rcinput:%s] %s is bad; no EV_KEY support (0x%lx)\n", __func__, id.path.c_str(), evbit);
::close(id.fd);
continue;
}
printf("[rcinput:%s] opened %s (fd %d) ev 0x%lx\n", __func__, id.path.c_str(), id.fd, evbit);
indev.push_back(id);
}
closedir(dir);
id.path = "/tmp/neutrino.input";
if (! checkpath(id)) {
id.fd = ::open(id.path.c_str(), O_RDWR|O_NONBLOCK|O_CLOEXEC);
if (id.fd == -1) {
/* debug, because it only matters for HAVE_GENERIC_HARDWARE */
d_printf("[rcinput:%s] open %s failed: %m\n", __func__, id.path.c_str());
} else {
printf("[rcinput:%s] opened %s (fd %d)\n", __func__, id.path.c_str(), id.fd);
indev.push_back(id);
} }
if ((fd_rc[i] = ::open(RC_EVENT_DEVICE[i], O_RDWR|O_NONBLOCK|O_CLOEXEC)) == -1)
perror(RC_EVENT_DEVICE[i]);
printf("CRCInput::open: %s fd %d\n", RC_EVENT_DEVICE[i], fd_rc[i]);
} }
//+++++++++++++++++++++++++++++++++++++++ //+++++++++++++++++++++++++++++++++++++++
@@ -224,12 +289,10 @@ void CRCInput::open(int dev)
void CRCInput::close() void CRCInput::close()
{ {
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) { OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
if (fd_rc[i] != -1) { for (unsigned int i = 0; i < indev.size(); i++)
::close(fd_rc[i]); ::close(indev[i].fd);
fd_rc[i] = -1; indev.clear();
}
}
#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL #ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL
if (saved_orig_termio) if (saved_orig_termio)
{ {
@@ -251,9 +314,9 @@ void CRCInput::calculateMaxFd()
{ {
fd_max = fd_event; fd_max = fd_event;
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) for (unsigned int i = 0; i < indev.size(); i++)
if (fd_rc[i] > fd_max) if (indev[i].fd > fd_max)
fd_max = fd_rc[i]; fd_max = indev[i].fd;
if(fd_pipe_high_priority[0] > fd_max) if(fd_pipe_high_priority[0] > fd_max)
fd_max = fd_pipe_high_priority[0]; fd_max = fd_pipe_high_priority[0];
@@ -558,10 +621,8 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6
* TODO: real hot-plugging, e.g. of keyboards and triggering this loop... * TODO: real hot-plugging, e.g. of keyboards and triggering this loop...
* right now it is only run if some event is happening "by accident" */ * right now it is only run if some event is happening "by accident" */
if (!input_stopped) { if (!input_stopped) {
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) { if (checkdev())
if (fd_rc[i] == -1) open(true);
open(i);
}
} }
// wiederholung reinmachen - dass wirklich die ganze zeit bis timeout gewartet wird! // wiederholung reinmachen - dass wirklich die ganze zeit bis timeout gewartet wird!
@@ -595,10 +656,10 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6
tvselect.tv_usec = targetTimeout%1000000; tvselect.tv_usec = targetTimeout%1000000;
FD_ZERO(&rfds); FD_ZERO(&rfds);
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) for (unsigned int i = 0; i < indev.size(); i++)
{ {
if (fd_rc[i] != -1) if (indev[i].fd != -1)
FD_SET(fd_rc[i], &rfds); FD_SET(indev[i].fd, &rfds);
} }
#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL #ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL
if (true) if (true)
@@ -1234,19 +1295,19 @@ void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, uint6
} }
} }
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) { for (std::vector<in_dev>::iterator i = indev.begin(); i != indev.end(); ++i) {
if ((fd_rc[i] != -1) && (FD_ISSET(fd_rc[i], &rfds))) { if (((*i).fd != -1) && (FD_ISSET((*i).fd, &rfds))) {
uint64_t now_pressed = 0; uint64_t now_pressed = 0;
t_input_event ev; t_input_event ev;
memset(&ev, 0, sizeof(ev)); memset(&ev, 0, sizeof(ev));
/* we later check for ev.type = EV_SYN = 0x00, so set something invalid here... */ /* we later check for ev.type = EV_SYN = 0x00, so set something invalid here... */
ev.type = EV_MAX; ev.type = EV_MAX;
int ret = read(fd_rc[i], &ev, sizeof(t_input_event)); int ret = read((*i).fd, &ev, sizeof(t_input_event));
if (ret != sizeof(t_input_event)) { if (ret != sizeof(t_input_event)) {
if (errno == ENODEV) { if (errno == ENODEV) {
/* hot-unplugged? */ /* hot-unplugged? */
::close(fd_rc[i]); ::close((*i).fd);
fd_rc[i] = -1; indev.erase(i);
} }
continue; continue;
} }
@@ -1436,11 +1497,11 @@ void CRCInput::clearRCMsg()
{ {
t_input_event ev; t_input_event ev;
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) for (unsigned int i = 0; i < indev.size(); i++)
{ {
if (fd_rc[i] != -1) if (indev[i].fd != -1)
{ {
while (read(fd_rc[i], &ev, sizeof(t_input_event)) == sizeof(t_input_event)) while (read(indev[i].fd, &ev, sizeof(t_input_event)) == sizeof(t_input_event))
; ;
} }
} }
@@ -1694,9 +1755,12 @@ void CRCInput::play_click()
void CRCInput::set_rc_hw(ir_protocol_t ir_protocol, unsigned int ir_address) void CRCInput::set_rc_hw(ir_protocol_t ir_protocol, unsigned int ir_address)
{ {
int ioctl_ret = -1; int ioctl_ret = -1;
if (indev.empty()) {
printf("[rcinput:%s] indev is empty!\n", __func__);
return;
}
//fixme?: for now fd_rc[] is hardcoded to 0 since only fd_rc[0] is used at the moment //fixme?: for now fd_rc[] is hardcoded to 0 since only fd_rc[0] is used at the moment
ioctl_ret = ::ioctl(fd_rc[0], IOC_IR_SET_PRI_PROTOCOL, ir_protocol); ioctl_ret = ::ioctl(indev[0].fd, IOC_IR_SET_PRI_PROTOCOL, ir_protocol);
if(ioctl_ret < 0) if(ioctl_ret < 0)
perror("IOC_IR_SET_PRI_PROTOCOL"); perror("IOC_IR_SET_PRI_PROTOCOL");
else else
@@ -1706,7 +1770,7 @@ void CRCInput::set_rc_hw(ir_protocol_t ir_protocol, unsigned int ir_address)
if(ir_address > 0) if(ir_address > 0)
{ {
//fixme?: for now fd_rc[] is hardcoded to 0 since only fd_rc[0] is used at the moment //fixme?: for now fd_rc[] is hardcoded to 0 since only fd_rc[0] is used at the moment
ioctl_ret = ::ioctl(fd_rc[0], IOC_IR_SET_PRI_ADDRESS, ir_address); ioctl_ret = ::ioctl(indev[0].fd, IOC_IR_SET_PRI_ADDRESS, ir_address);
if(ioctl_ret < 0) if(ioctl_ret < 0)
perror("IOC_IR_SET_PRI_ADDRESS"); perror("IOC_IR_SET_PRI_ADDRESS");
else else

View File

@@ -39,6 +39,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <OpenThreads/Mutex>
#include <OpenThreads/ScopedLock>
#ifdef BOXMODEL_CS_HD2 #ifdef BOXMODEL_CS_HD2
#ifdef HAVE_COOLSTREAM_CS_IR_GENERIC_H #ifdef HAVE_COOLSTREAM_CS_IR_GENERIC_H
#include <cs_ir_generic.h> #include <cs_ir_generic.h>
@@ -138,6 +141,12 @@ class CRCInput
bool correct_time; bool correct_time;
}; };
struct in_dev
{
int fd;
std::string path;
};
uint32_t timerid; uint32_t timerid;
std::vector<timer> timers; std::vector<timer> timers;
@@ -147,21 +156,19 @@ class CRCInput
int fd_pipe_high_priority[2]; int fd_pipe_high_priority[2];
int fd_pipe_low_priority[2]; int fd_pipe_low_priority[2];
int fd_gamerc; int fd_gamerc;
#ifdef HAVE_SPARK_HARDWARE std::vector<in_dev> indev;
#define NUMBER_OF_EVENT_DEVICES 2
#else
#define NUMBER_OF_EVENT_DEVICES 1
#endif
int fd_rc[NUMBER_OF_EVENT_DEVICES];
int fd_keyb; int fd_keyb;
int fd_event; int fd_event;
int fd_max; int fd_max;
int clickfd; int clickfd;
__u16 rc_last_key; __u16 rc_last_key;
OpenThreads::Mutex mutex;
void set_dsp(); void set_dsp();
void open(int dev = -1); void open(bool recheck = false);
bool checkpath(in_dev id);
bool checkdev();
void close(); void close();
int translate(int code); int translate(int code);
void calculateMaxFd(void); void calculateMaxFd(void);
@@ -280,7 +287,9 @@ class CRCInput
inline int getFileHandle(void) /* used for plugins (i.e. games) only */ inline int getFileHandle(void) /* used for plugins (i.e. games) only */
{ {
return fd_rc[0]; if (indev.empty())
return -1;
return indev[0].fd;
} }
void stopInput(const bool ext = false); void stopInput(const bool ext = false);
void restartInput(const bool ext = false); void restartInput(const bool ext = false);