mirror of
https://github.com/tuxbox-fork-migrations/recycled-ni-neutrino.git
synced 2025-08-28 16:01:10 +02:00
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:
committed by
Michael Liebmann
parent
3c7aca7949
commit
b5ec2b42df
@@ -4,7 +4,7 @@
|
||||
Copyright (C) 2001 Steffen Hehn 'McClean'
|
||||
2003 thegoodguy
|
||||
|
||||
Copyright (C) 2008-2014,2016 Stefan Seyfried
|
||||
Copyright (C) 2008-2014,2016-2017 Stefan Seyfried
|
||||
Copyright (C) 2013-2014 martii
|
||||
|
||||
License: GPL
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <system/helpers.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <asm/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
@@ -50,6 +49,8 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <eventserver.h>
|
||||
|
||||
#include <global.h>
|
||||
@@ -65,17 +66,6 @@
|
||||
|
||||
#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;
|
||||
|
||||
#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL
|
||||
@@ -83,6 +73,13 @@ static struct termio orig_termio;
|
||||
static bool saved_orig_termio = false;
|
||||
#endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */
|
||||
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
|
||||
@@ -146,13 +143,9 @@ CRCInput::CRCInput()
|
||||
perror("[neutrino] listen failed...\n");
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++)
|
||||
{
|
||||
fd_rc[i] = -1;
|
||||
}
|
||||
clickfd = -1;
|
||||
repeat_block = repeat_block_generic = 0;
|
||||
checkdev();
|
||||
open();
|
||||
rc_last_key = KEY_MAX;
|
||||
firstKey = true;
|
||||
@@ -162,21 +155,93 @@ CRCInput::CRCInput()
|
||||
set_rc_hw();
|
||||
}
|
||||
|
||||
/* if dev is given, open device with index <dev>, if not (re)open all */
|
||||
void CRCInput::open(int dev)
|
||||
bool CRCInput::checkdev()
|
||||
{
|
||||
if (dev == -1)
|
||||
close();
|
||||
/* stat()ing the directory is fast and cheap. If a device gets added or
|
||||
* removed, the mtime of /dev/input/ will change, which in turn
|
||||
* warrants a more thorough investigation */
|
||||
struct stat st;
|
||||
if (stat("/dev/input/", &st) == 0) {
|
||||
if (st.st_mtim.tv_sec != devinput_mtime.tv_sec ||
|
||||
st.st_mtim.tv_nsec != devinput_mtime.tv_nsec) {
|
||||
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... */
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++)
|
||||
bool CRCInput::checkpath(in_dev id)
|
||||
{
|
||||
if (dev != -1) {
|
||||
if (i != dev || fd_rc[i] != -1)
|
||||
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;
|
||||
}
|
||||
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]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//+++++++++++++++++++++++++++++++++++++++
|
||||
@@ -224,12 +289,10 @@ void CRCInput::open(int dev)
|
||||
|
||||
void CRCInput::close()
|
||||
{
|
||||
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) {
|
||||
if (fd_rc[i] != -1) {
|
||||
::close(fd_rc[i]);
|
||||
fd_rc[i] = -1;
|
||||
}
|
||||
}
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
||||
for (unsigned int i = 0; i < indev.size(); i++)
|
||||
::close(indev[i].fd);
|
||||
indev.clear();
|
||||
#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL
|
||||
if (saved_orig_termio)
|
||||
{
|
||||
@@ -251,9 +314,9 @@ void CRCInput::calculateMaxFd()
|
||||
{
|
||||
fd_max = fd_event;
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++)
|
||||
if (fd_rc[i] > fd_max)
|
||||
fd_max = fd_rc[i];
|
||||
for (unsigned int i = 0; i < indev.size(); i++)
|
||||
if (indev[i].fd > fd_max)
|
||||
fd_max = indev[i].fd;
|
||||
|
||||
if(fd_pipe_high_priority[0] > fd_max)
|
||||
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...
|
||||
* right now it is only run if some event is happening "by accident" */
|
||||
if (!input_stopped) {
|
||||
for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) {
|
||||
if (fd_rc[i] == -1)
|
||||
open(i);
|
||||
}
|
||||
if (checkdev())
|
||||
open(true);
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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)
|
||||
FD_SET(fd_rc[i], &rfds);
|
||||
if (indev[i].fd != -1)
|
||||
FD_SET(indev[i].fd, &rfds);
|
||||
}
|
||||
#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL
|
||||
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++) {
|
||||
if ((fd_rc[i] != -1) && (FD_ISSET(fd_rc[i], &rfds))) {
|
||||
for (std::vector<in_dev>::iterator i = indev.begin(); i != indev.end(); ++i) {
|
||||
if (((*i).fd != -1) && (FD_ISSET((*i).fd, &rfds))) {
|
||||
uint64_t now_pressed = 0;
|
||||
t_input_event ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
/* we later check for ev.type = EV_SYN = 0x00, so set something invalid here... */
|
||||
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 (errno == ENODEV) {
|
||||
/* hot-unplugged? */
|
||||
::close(fd_rc[i]);
|
||||
fd_rc[i] = -1;
|
||||
::close((*i).fd);
|
||||
indev.erase(i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -1436,11 +1497,11 @@ void CRCInput::clearRCMsg()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
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)
|
||||
perror("IOC_IR_SET_PRI_PROTOCOL");
|
||||
else
|
||||
@@ -1706,7 +1770,7 @@ void CRCInput::set_rc_hw(ir_protocol_t ir_protocol, unsigned int ir_address)
|
||||
if(ir_address > 0)
|
||||
{
|
||||
//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)
|
||||
perror("IOC_IR_SET_PRI_ADDRESS");
|
||||
else
|
||||
|
@@ -39,6 +39,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <OpenThreads/Mutex>
|
||||
#include <OpenThreads/ScopedLock>
|
||||
|
||||
#ifdef BOXMODEL_CS_HD2
|
||||
#ifdef HAVE_COOLSTREAM_CS_IR_GENERIC_H
|
||||
#include <cs_ir_generic.h>
|
||||
@@ -138,6 +141,12 @@ class CRCInput
|
||||
bool correct_time;
|
||||
};
|
||||
|
||||
struct in_dev
|
||||
{
|
||||
int fd;
|
||||
std::string path;
|
||||
};
|
||||
|
||||
uint32_t timerid;
|
||||
std::vector<timer> timers;
|
||||
|
||||
@@ -147,21 +156,19 @@ class CRCInput
|
||||
int fd_pipe_high_priority[2];
|
||||
int fd_pipe_low_priority[2];
|
||||
int fd_gamerc;
|
||||
#ifdef HAVE_SPARK_HARDWARE
|
||||
#define NUMBER_OF_EVENT_DEVICES 2
|
||||
#else
|
||||
#define NUMBER_OF_EVENT_DEVICES 1
|
||||
#endif
|
||||
int fd_rc[NUMBER_OF_EVENT_DEVICES];
|
||||
std::vector<in_dev> indev;
|
||||
int fd_keyb;
|
||||
int fd_event;
|
||||
|
||||
int fd_max;
|
||||
int clickfd;
|
||||
__u16 rc_last_key;
|
||||
OpenThreads::Mutex mutex;
|
||||
void set_dsp();
|
||||
|
||||
void open(int dev = -1);
|
||||
void open(bool recheck = false);
|
||||
bool checkpath(in_dev id);
|
||||
bool checkdev();
|
||||
void close();
|
||||
int translate(int code);
|
||||
void calculateMaxFd(void);
|
||||
@@ -280,7 +287,9 @@ class CRCInput
|
||||
|
||||
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 restartInput(const bool ext = false);
|
||||
|
Reference in New Issue
Block a user