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