|
Packit |
a94d48 |
/*
|
|
Packit |
a94d48 |
* input_layer - Kernel ACPI Event Input Layer Interface
|
|
Packit |
a94d48 |
*
|
|
Packit |
a94d48 |
* Handles the details of getting kernel ACPI events from the input
|
|
Packit |
a94d48 |
* layer (/dev/input/event*).
|
|
Packit |
a94d48 |
*
|
|
Packit |
a94d48 |
* Inspired by (and in some cases blatantly lifted from) Vojtech Pavlik's
|
|
Packit |
a94d48 |
* evtest.c.
|
|
Packit |
a94d48 |
*
|
|
Packit |
a94d48 |
* Copyright (C) 2008, Ted Felix (www.tedfelix.com)
|
|
Packit |
a94d48 |
*
|
|
Packit |
a94d48 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
a94d48 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
a94d48 |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
a94d48 |
* (at your option) any later version.
|
|
Packit |
a94d48 |
*
|
|
Packit |
a94d48 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
a94d48 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a94d48 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
a94d48 |
* GNU General Public License for more details.
|
|
Packit |
a94d48 |
*
|
|
Packit |
a94d48 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
a94d48 |
* along with this program; if not, write to the Free Software
|
|
Packit |
a94d48 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
a94d48 |
*
|
|
Packit |
a94d48 |
* (tabs at 4)
|
|
Packit |
a94d48 |
*/
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
/* system */
|
|
Packit |
a94d48 |
#include <stdio.h>
|
|
Packit |
a94d48 |
#include <unistd.h>
|
|
Packit |
a94d48 |
#include <fcntl.h>
|
|
Packit |
a94d48 |
#include <linux/input.h>
|
|
Packit |
a94d48 |
#include <string.h>
|
|
Packit |
a94d48 |
#include <errno.h>
|
|
Packit |
a94d48 |
#include <malloc.h>
|
|
Packit |
a94d48 |
#include <glob.h>
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
/* local */
|
|
Packit |
a94d48 |
#include "connection_list.h"
|
|
Packit |
a94d48 |
#include "kacpimon.h"
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
#include "input_layer.h"
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
#define DIM(a) (sizeof(a) / sizeof(a[0]))
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
#define INPUT_LAYER_FS "/dev/input/event*"
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
/*-----------------------------------------------------------------*/
|
|
Packit |
a94d48 |
/* called when an input layer event is received */
|
|
Packit |
a94d48 |
static void process_input(int fd)
|
|
Packit |
a94d48 |
{
|
|
Packit |
a94d48 |
struct input_event event;
|
|
Packit |
a94d48 |
ssize_t nbytes;
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
nbytes = read(fd, &event, sizeof(event));
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
if (nbytes == 0) {
|
|
Packit |
a94d48 |
printf("Input layer connection closed.\n");
|
|
Packit |
a94d48 |
return;
|
|
Packit |
a94d48 |
}
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
if (nbytes < 0) {
|
|
Packit |
a94d48 |
/* if it's a signal, bail */
|
|
Packit |
a94d48 |
if (errno == EINTR)
|
|
Packit |
a94d48 |
return;
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
printf("Input layer read error: %s (%d)\n",
|
|
Packit |
a94d48 |
strerror(errno), errno);
|
|
Packit |
a94d48 |
return;
|
|
Packit |
a94d48 |
}
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
/* ??? Is it possible for a partial message to come across? */
|
|
Packit |
a94d48 |
/* If so, we've got more code to write... */
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
if (nbytes != sizeof(event)) {
|
|
Packit |
a94d48 |
printf("Input Layer unexpected Length\n");
|
|
Packit |
a94d48 |
printf(" Expected: %lu Got: %zd\n",
|
|
Packit |
a94d48 |
(unsigned long) sizeof(event), nbytes);
|
|
Packit |
a94d48 |
return;
|
|
Packit |
a94d48 |
}
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
/* If the Escape key was pressed, set the exitflag to exit. */
|
|
Packit |
a94d48 |
if (event.type == EV_KEY &&
|
|
Packit |
a94d48 |
event.code == KEY_ESC &&
|
|
Packit |
a94d48 |
event.value == 1) {
|
|
Packit |
a94d48 |
printf("Escape key pressed\n");
|
|
Packit |
a94d48 |
exitflag = 1;
|
|
Packit |
a94d48 |
}
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
if (event.type == EV_SYN)
|
|
Packit |
a94d48 |
printf("Input Layer: Sync\n");
|
|
Packit |
a94d48 |
else
|
|
Packit |
a94d48 |
/* format and display the event struct in decimal */
|
|
Packit |
a94d48 |
printf("Input Layer: "
|
|
Packit |
a94d48 |
"Type: %hu Code: %hu Value: %d\n",
|
|
Packit |
a94d48 |
event.type, event.code, event.value);
|
|
Packit |
a94d48 |
}
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
#define BITS_PER_LONG (sizeof(long) * 8)
|
|
Packit |
a94d48 |
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
|
|
Packit |
a94d48 |
#define OFF(x) ((x)%BITS_PER_LONG)
|
|
Packit |
a94d48 |
#define LONG(x) ((x)/BITS_PER_LONG)
|
|
Packit |
a94d48 |
#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
/*-----------------------------------------------------------------*
|
|
Packit |
a94d48 |
* open each of the appropriate /dev/input/event* files for input */
|
|
Packit |
a94d48 |
void open_input(void)
|
|
Packit |
a94d48 |
{
|
|
Packit |
a94d48 |
char *filename = NULL;
|
|
Packit |
a94d48 |
glob_t globbuf;
|
|
Packit |
a94d48 |
unsigned i;
|
|
Packit |
a94d48 |
int fd;
|
|
Packit |
a94d48 |
struct connection c;
|
|
Packit |
a94d48 |
int had_some_success = 0;
|
|
Packit |
a94d48 |
char evname[256];
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
/* get all the matching event filenames */
|
|
Packit |
a94d48 |
glob(INPUT_LAYER_FS, 0, NULL, &globbuf);
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
/* for each event file */
|
|
Packit |
a94d48 |
for (i = 0; i < globbuf.gl_pathc; ++i)
|
|
Packit |
a94d48 |
{
|
|
Packit |
a94d48 |
filename = globbuf.gl_pathv[i];
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
fd = open(filename, O_RDONLY | O_NONBLOCK);
|
|
Packit |
a94d48 |
if (fd >= 0) {
|
|
Packit |
a94d48 |
/* get this event file's name */
|
|
Packit |
a94d48 |
strcpy(evname, "Unknown");
|
|
Packit |
a94d48 |
ioctl(fd, EVIOCGNAME(sizeof(evname)), evname);
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
printf("%s (%s) opened successfully\n", filename, evname);
|
|
Packit |
a94d48 |
had_some_success = 1;
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
/* add a connection to the list */
|
|
Packit |
a94d48 |
c.fd = fd;
|
|
Packit |
a94d48 |
c.process = process_input;
|
|
Packit |
a94d48 |
add_connection(&c);
|
|
Packit |
a94d48 |
}
|
|
Packit |
a94d48 |
else
|
|
Packit |
a94d48 |
{
|
|
Packit |
a94d48 |
if (had_some_success == 1)
|
|
Packit |
a94d48 |
continue;
|
|
Packit |
a94d48 |
int errno2 = errno;
|
|
Packit |
a94d48 |
printf("open for %s failed: %s (%d)\n",
|
|
Packit |
a94d48 |
filename, strerror(errno2), errno2);
|
|
Packit |
a94d48 |
if (errno2 == EACCES)
|
|
Packit |
a94d48 |
printf(" (try running as root)\n");
|
|
Packit |
a94d48 |
if (errno2 == ENOENT)
|
|
Packit |
a94d48 |
printf(" (input layer driver may not be present)\n");
|
|
Packit |
a94d48 |
}
|
|
Packit |
a94d48 |
}
|
|
Packit |
a94d48 |
|
|
Packit |
a94d48 |
globfree(&globbuf);
|
|
Packit |
a94d48 |
}
|
|
Packit |
a94d48 |
|