Logo Search packages:      
Sourcecode: kacpimon version File versions  Download package

input_layer.c

/*
 *  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 <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <string.h>
#include <errno.h>
#include <malloc.h>
#include <glob.h>

/* local */
#include "connection_list.h"
#include "kacpimon.h"

#define DIM(a)  (sizeof(a) / sizeof(a[0]))

#define INPUT_LAYER_FS "/dev/input/event*"

/* set to "1" to see all events come across */
/* ??? make this a command line option */
#define ALL_EVENTS 1

struct evtab_entry {
      struct input_event event;
      const char *str;
};
      
/* event table: events we are interested in and their strings */
static struct evtab_entry evtab[] = {
      {{{0,0}, EV_KEY, KEY_POWER, 1}, "button/power PBTN 00000080 00000000"},
      {{{0,0}, EV_KEY, KEY_SLEEP, 1}, "button/sleep SBTN 00000080 00000000"},
      {{{0,0}, EV_KEY, KEY_SUSPEND, 1}, 
            "button/suspend SUSP 00000080 00000000"},
      {{{0,0}, EV_SW, SW_LID, 1}, "button/lid LID close"},
      {{{0,0}, EV_SW, SW_LID, 0}, "button/lid LID open"}
};
      
/*----------------------------------------------------------------------*/
/* Given an input event, returns the string corresponding to that event.
   If there is no corresponding string, NULL is returned.  */
static const char *
event_string(struct input_event event)
{
      unsigned i;
      
      /* for each entry in the event table */
      for (i = 0; i < DIM(evtab); ++i)
      {
            /* if this is a matching event, return its string */
            if (event.type == evtab[i].event.type  &&
                  event.code == evtab[i].event.code  &&
                  event.value == evtab[i].event.value) {
                  return evtab[i].str;
            }
      }
      
      return NULL;
}

/*-----------------------------------------------------------------*/
/* returns non-zero if the event type/code is one we need */
static int 
need_event(int type, int code)
{
      unsigned i;

      /* for each entry in the event table */
      for (i = 0; i < DIM(evtab); ++i) {
            /* if we found a matching event */
            if (type == evtab[i].event.type  &&
                  code == evtab[i].event.code) {
                  return 1;
            }
      }

      return 0;
}

/*-----------------------------------------------------------------*/
/* called when an input layer event is received */
void process_input(int fd)
{
      struct input_event event;
      ssize_t nbytes;
      const char *str;

      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: %d   Got: %d\n", 
                  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;
      }

      /* convert the event into a string */
      str = event_string(event);
      /* if this is not an event we care about, continue */
      if (str == NULL) {
#if ALL_EVENTS
            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);
#endif

            return;
      }
            
      printf("%s\n", str);
}

#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)

/*--------------------------------------------------------------------*/
/* returns non-zero if the file descriptor supports one of the events */
/* supported by event_string().  */
static int 
has_event(int fd)
{
      int type, code;
      unsigned long bit[EV_MAX][NBITS(KEY_MAX)];

      memset(bit, 0, sizeof(bit));
      /* get the event type bitmap */
      ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]);

      /* for each event type */
      for (type = 0; type < EV_MAX; type++) {
            /* if this event type is supported */
            if (test_bit(type, bit[0])) {
                  /* skip sync */
                  if (type == EV_SYN) continue;
                  /* get the event code mask */
                  ioctl(fd, EVIOCGBIT(type, KEY_MAX), bit[type]);
                  /* for each event code */
                  for (code = 0; code < KEY_MAX; code++) {
                        /* if this event code is supported */
                        if (test_bit(code, bit[type])) {
                              /* if we need this event */
                              if (need_event(type, code) != 0)
                                    return 1;
                        }
                  }
            }
      }
      return 0;
}

/*-----------------------------------------------------------------*
 * 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) {
                  /* if this file doesn't have events we need, try the next */
                  if (!has_event(fd))
                  {
#if !ALL_EVENTS
                        printf("skipping %s as it has no events of interest\n",
                              filename);
                        close(fd);
                        continue;
#endif
                  }

                  /* 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);
}

Generated by  Doxygen 1.6.0   Back to index