|
Packit Service |
26469c |
/*
|
|
Packit Service |
26469c |
* input_layer - Kernel ACPI Event Input Layer Interface
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* Handles the details of getting kernel ACPI events from the input
|
|
Packit Service |
26469c |
* layer (/dev/input/event*).
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* Inspired by (and in some cases blatantly lifted from) Vojtech Pavlik's
|
|
Packit Service |
26469c |
* evtest.c.
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* Copyright (C) 2008-2009, Ted Felix (www.tedfelix.com)
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
26469c |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
26469c |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit Service |
26469c |
* (at your option) any later version.
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
26469c |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
26469c |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
26469c |
* GNU General Public License for more details.
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
26469c |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
26469c |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* (tabs at 4)
|
|
Packit Service |
26469c |
*/
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* system */
|
|
Packit Service |
26469c |
#include <unistd.h>
|
|
Packit Service |
26469c |
#include <stdio.h>
|
|
Packit Service |
26469c |
#include <stdlib.h>
|
|
Packit Service |
26469c |
#include <fcntl.h>
|
|
Packit Service |
26469c |
#include <linux/input.h>
|
|
Packit Service |
26469c |
#include <string.h>
|
|
Packit Service |
26469c |
#include <errno.h>
|
|
Packit Service |
26469c |
#include <malloc.h>
|
|
Packit Service |
26469c |
#include <glob.h>
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* local */
|
|
Packit Service |
26469c |
#include "acpid.h"
|
|
Packit Service |
26469c |
#include "log.h"
|
|
Packit Service |
26469c |
#include "connection_list.h"
|
|
Packit Service |
26469c |
#include "event.h"
|
|
Packit Service |
26469c |
#include "libc_compat.h"
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
#include "input_layer.h"
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
#define DIM(a) (sizeof(a) / sizeof(a[0]))
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
struct evtab_entry {
|
|
Packit Service |
26469c |
struct input_event event;
|
|
Packit Service |
26469c |
const char *str;
|
|
Packit Service |
26469c |
};
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* Event Table: Events we are interested in and their strings. Use
|
|
Packit Service |
26469c |
evtest.c, acpi_genl, or kacpimon to find new events to add to this
|
|
Packit Service |
26469c |
table. */
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*
|
|
Packit Service |
26469c |
* The two numbers (e.g. "00000080 00000000") in each string is a format
|
|
Packit Service |
26469c |
* that Xorg and maybe others expect.
|
|
Packit Service |
26469c |
*
|
|
Packit Service |
26469c |
* See hw/xfree86/os-support/linux/lnx_acpi.c in xserver and specifically
|
|
Packit Service |
26469c |
* lnxACPIGetEventFromOs().
|
|
Packit Service |
26469c |
*/
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
static struct evtab_entry evtab[] = {
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*** COMMON EVENTS ***/
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_POWER, 1}, "button/power PBTN 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_SUSPEND, 1},
|
|
Packit Service |
26469c |
"button/suspend SUSP 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_SLEEP, 1}, "button/sleep SBTN 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_LID, 1}, "button/lid LID close"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_LID, 0}, "button/lid LID open"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_TABLET_MODE, 0}, "video/tabletmode TBLT 0000008A 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_TABLET_MODE, 1}, "video/tabletmode TBLT 0000008A 00000001"},
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*** VIDEO ***/
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_ZOOM, 1}, "button/zoom ZOOM 00000080 00000000"},
|
|
Packit Service |
26469c |
/* typical events file has "video.* 00000087" */
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_BRIGHTNESSDOWN, 1},
|
|
Packit Service |
26469c |
"video/brightnessdown BRTDN 00000087 00000000"},
|
|
Packit Service |
26469c |
/* typical events file has "video.* 00000086" */
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_BRIGHTNESSUP, 1},
|
|
Packit Service |
26469c |
"video/brightnessup BRTUP 00000086 00000000"},
|
|
Packit Service |
26469c |
/* additional events divined from the kernel's video.c */
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_VIDEO_NEXT, 1},
|
|
Packit Service |
26469c |
"video/next NEXT 00000083 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_VIDEO_PREV, 1},
|
|
Packit Service |
26469c |
"video/prev PREV 00000084 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_BRIGHTNESS_CYCLE, 1},
|
|
Packit Service |
26469c |
"video/brightnesscycle BCYC 00000085 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_BRIGHTNESS_ZERO, 1},
|
|
Packit Service |
26469c |
"video/brightnesszero BZRO 00000088 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_DISPLAY_OFF, 1},
|
|
Packit Service |
26469c |
"video/displayoff DOFF 00000089 00000000"},
|
|
Packit Service |
26469c |
/* procfs on Thinkpad 600X reports "video VID0 00000080 00000000" */
|
|
Packit Service |
26469c |
/* typical events file has "video.* 00000080" */
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_SWITCHVIDEOMODE, 1},
|
|
Packit Service |
26469c |
"video/switchmode VMOD 00000080 00000000"},
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*** AUDIO ***/
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_VOLUMEDOWN, 1},
|
|
Packit Service |
26469c |
"button/volumedown VOLDN 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_VOLUMEDOWN, 2},
|
|
Packit Service |
26469c |
"button/volumedown VOLDN 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_VOLUMEUP, 1},
|
|
Packit Service |
26469c |
"button/volumeup VOLUP 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_VOLUMEUP, 2},
|
|
Packit Service |
26469c |
"button/volumeup VOLUP 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_MUTE, 1},
|
|
Packit Service |
26469c |
"button/mute MUTE 00000080 00000000"},
|
|
Packit Service |
26469c |
/* Kernel 3.1 or later required for KEY_MICMUTE */
|
|
Packit Service |
26469c |
#ifdef KEY_MICMUTE
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_MICMUTE, 1},
|
|
Packit Service |
26469c |
"button/micmute MICMUTE 00000080 00000000"},
|
|
Packit Service |
26469c |
#endif
|
|
Packit Service |
26469c |
/* cd play/pause buttons */
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_NEXTSONG, 1},
|
|
Packit Service |
26469c |
"cd/next CDNEXT 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_PREVIOUSSONG, 1},
|
|
Packit Service |
26469c |
"cd/prev CDPREV 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_PLAYPAUSE, 1},
|
|
Packit Service |
26469c |
"cd/play CDPLAY 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_STOPCD, 1},
|
|
Packit Service |
26469c |
"cd/stop CDSTOP 00000080 00000000"},
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*** JACKS ***/
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* This test probably belongs in configure.ac. */
|
|
Packit Service |
26469c |
#ifdef SW_HEADPHONE_INSERT
|
|
Packit Service |
26469c |
#ifndef SW_LINEIN_INSERT
|
|
Packit Service |
26469c |
#define SW_LINEIN_INSERT 0x0d
|
|
Packit Service |
26469c |
#endif
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_HEADPHONE_INSERT, 0},
|
|
Packit Service |
26469c |
"jack/headphone HEADPHONE unplug"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_HEADPHONE_INSERT, 1},
|
|
Packit Service |
26469c |
"jack/headphone HEADPHONE plug"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_MICROPHONE_INSERT, 0},
|
|
Packit Service |
26469c |
"jack/microphone MICROPHONE unplug"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_MICROPHONE_INSERT, 1},
|
|
Packit Service |
26469c |
"jack/microphone MICROPHONE plug"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_LINEOUT_INSERT, 0},
|
|
Packit Service |
26469c |
"jack/lineout LINEOUT unplug"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_LINEOUT_INSERT, 1},
|
|
Packit Service |
26469c |
"jack/lineout LINEOUT plug"},
|
|
Packit Service |
26469c |
#ifdef SW_VIDEOOUT_INSERT
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_VIDEOOUT_INSERT, 0},
|
|
Packit Service |
26469c |
"jack/videoout VIDEOOUT unplug"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_VIDEOOUT_INSERT, 1},
|
|
Packit Service |
26469c |
"jack/videoout VIDEOOUT plug"},
|
|
Packit Service |
26469c |
#endif
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_LINEIN_INSERT, 0},
|
|
Packit Service |
26469c |
"jack/linein LINEIN unplug"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_SW, SW_LINEIN_INSERT, 1},
|
|
Packit Service |
26469c |
"jack/linein LINEIN plug"},
|
|
Packit Service |
26469c |
#else
|
|
Packit Service |
26469c |
#warning SW_HEADPHONE_INSERT not found in input_layer.h. Support for plug/unplug events will be disabled. Please upgrade your kernel headers to Linux-3.2 or newer.
|
|
Packit Service |
26469c |
#endif
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*** MISCELLANEOUS ***/
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* blue access IBM button on Thinkpad T42p*/
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_PROG1, 1}, "button/prog1 PROG1 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_VENDOR, 1}, "button/vendor VNDR 00000080 00000000"},
|
|
Packit Service |
26469c |
/* Fn-F2 produces KEY_BATTERY on Thinkpad T42p */
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_BATTERY, 1},
|
|
Packit Service |
26469c |
"button/battery BAT 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_SCREENLOCK, 1},
|
|
Packit Service |
26469c |
"button/screenlock SCRNLCK 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_COFFEE, 1}, "button/coffee CFEE 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_WLAN, 1}, "button/wlan WLAN 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_FN_F1, 1}, "button/fnf1 FNF1 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_FN_F2, 1}, "button/fnf2 FNF2 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_FN_F6, 1}, "button/fnf6 FNF6 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_FN_F9, 1}, "button/fnf9 FNF9 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_FN_F10, 1}, "button/fnf10 FF10 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_FN_F11, 1}, "button/fnf11 FF11 00000080 00000000"},
|
|
Packit Service |
26469c |
/* F20 is sometimes used for micmute */
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_F20, 1}, "button/f20 F20 00000080 00000000"},
|
|
Packit Service |
26469c |
/* Fn-F9 produces KEY_F24 on Thinkpad T42p */
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_F24, 1}, "button/f24 F24 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_KBDILLUMTOGGLE, 1},
|
|
Packit Service |
26469c |
"button/kbdillumtoggle KBILLUM 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_COPY, 1}, "button/copy COPY 00000080 00000000"},
|
|
Packit Service |
26469c |
{{{0,0}, EV_KEY, KEY_RESTART, 1}, "button/restart RSTR 00000080 00000000"},
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
#if 0
|
|
Packit Service |
26469c |
/* These "EV_MSC, 4, x" events cause trouble. They are triggered */
|
|
Packit Service |
26469c |
/* by unexpected keys on the keyboard. */
|
|
Packit Service |
26469c |
/* The 4 is MSC_SCAN, so these are actually scan code events. */
|
|
Packit Service |
26469c |
/* Apparently there is no KEY_FN_BS, etc..., defined in input.h. */
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* EV_MSC, MSC_SCAN, KEY_MINUS This is triggered by the minus key. */
|
|
Packit Service |
26469c |
{{{0,0}, EV_MSC, 4, 12}, "button/fnbs FNBS 00000080 00000000"},
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* EV_MSC, MSC_SCAN, KEY_EQUAL Triggered by the equals key. */
|
|
Packit Service |
26469c |
{{{0,0}, EV_MSC, 4, 13}, "button/fnins FNINS 00000080 00000000"},
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* EV_MSC, MSC_SCAN, KEY_BACKSPACE Triggered by the backspace key. */
|
|
Packit Service |
26469c |
{{{0,0}, EV_MSC, 4, 14}, "button/fndel FNDEL 00000080 00000000"},
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* EV_MSC, MSC_SCAN, KEY_E Triggered by the 'E' key. */
|
|
Packit Service |
26469c |
{{{0,0}, EV_MSC, 4, 18}, "button/fnpgdown FNPGDOWN 00000080 00000000"},
|
|
Packit Service |
26469c |
#endif
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
};
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* special support for the MUTE key, as the key toggles we want to
|
|
Packit Service |
26469c |
* consider repeated keys but don't report them all the time. We just
|
|
Packit Service |
26469c |
* ensure that the number of key presses (MOD 2) is correct.
|
|
Packit Service |
26469c |
*/
|
|
Packit Service |
26469c |
static const char *
|
|
Packit Service |
26469c |
mute_string(struct input_event event)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
if (event.type == EV_KEY && event.code == KEY_MUTE) {
|
|
Packit Service |
26469c |
static size_t repeat_count;
|
|
Packit Service |
26469c |
if (event.value == 1) {
|
|
Packit Service |
26469c |
repeat_count = 1;
|
|
Packit Service |
26469c |
return "button/mute MUTE (key pressed)";
|
|
Packit Service |
26469c |
} else if (event.value == 2) {
|
|
Packit Service |
26469c |
repeat_count++;
|
|
Packit Service |
26469c |
return NULL;
|
|
Packit Service |
26469c |
} else if (event.value == 0) {
|
|
Packit Service |
26469c |
if (repeat_count % 2 == 0) {
|
|
Packit Service |
26469c |
return "button/mute MUTE (key released)";
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
return NULL;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*----------------------------------------------------------------------*/
|
|
Packit Service |
26469c |
/* Given an input event, returns the string corresponding to that event.
|
|
Packit Service |
26469c |
If there is no corresponding string, NULL is returned. */
|
|
Packit Service |
26469c |
static const char *
|
|
Packit Service |
26469c |
event_string(struct input_event event)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
unsigned i;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* for each entry in the event table */
|
|
Packit Service |
26469c |
/* ??? Is there a faster way? This is triggered every time the user
|
|
Packit Service |
26469c |
* presses a key. Maybe a simple hash algorithm? Or a simple check
|
|
Packit Service |
26469c |
* for very common keys (alphanumeric) and bail before this? */
|
|
Packit Service |
26469c |
for (i = 0; i < DIM(evtab); ++i)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
/* if this is a matching event, return its string */
|
|
Packit Service |
26469c |
if (event.type == evtab[i].event.type &&
|
|
Packit Service |
26469c |
event.code == evtab[i].event.code &&
|
|
Packit Service |
26469c |
event.value == evtab[i].event.value) {
|
|
Packit Service |
26469c |
return evtab[i].str;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
return NULL;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*-----------------------------------------------------------------*/
|
|
Packit Service |
26469c |
/* returns non-zero if the event type/code is one we need */
|
|
Packit Service |
26469c |
static int
|
|
Packit Service |
26469c |
need_event(int type, int code)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
unsigned i;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* for each entry in the event table */
|
|
Packit Service |
26469c |
for (i = 0; i < DIM(evtab); ++i) {
|
|
Packit Service |
26469c |
/* if we found a matching event */
|
|
Packit Service |
26469c |
if (type == evtab[i].event.type &&
|
|
Packit Service |
26469c |
code == evtab[i].event.code) {
|
|
Packit Service |
26469c |
return 1;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
return 0;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*-----------------------------------------------------------------*/
|
|
Packit Service |
26469c |
/* called when an input layer event is received */
|
|
Packit Service |
26469c |
static void process_input(int fd)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
struct input_event event;
|
|
Packit Service |
26469c |
ssize_t nbytes;
|
|
Packit Service |
26469c |
const char *str;
|
|
Packit Service |
26469c |
static int nerrs;
|
|
Packit Service |
26469c |
struct connection *c;
|
|
Packit Service |
26469c |
char str2[100];
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
nbytes = TEMP_FAILURE_RETRY ( read(fd, &event, sizeof(event)) );
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (nbytes == 0) {
|
|
Packit Service |
26469c |
acpid_log(LOG_WARNING, "input layer connection closed");
|
|
Packit Service |
26469c |
exit(EXIT_FAILURE);
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (nbytes < 0) {
|
|
Packit Service |
26469c |
if (errno == ENODEV) {
|
|
Packit Service |
26469c |
acpid_log(LOG_WARNING, "input device has been disconnected, fd %d",
|
|
Packit Service |
26469c |
fd);
|
|
Packit Service |
26469c |
delete_connection(fd);
|
|
Packit Service |
26469c |
return;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
acpid_log(LOG_ERR, "input layer read error: %s (%d)",
|
|
Packit Service |
26469c |
strerror(errno), errno);
|
|
Packit Service |
26469c |
if (++nerrs >= ACPID_MAX_ERRS) {
|
|
Packit Service |
26469c |
acpid_log(LOG_ERR,
|
|
Packit Service |
26469c |
"too many errors reading "
|
|
Packit Service |
26469c |
"input layer - aborting");
|
|
Packit Service |
26469c |
exit(EXIT_FAILURE);
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
return;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* ??? Is it possible for a partial message to come across? */
|
|
Packit Service |
26469c |
/* If so, we've got more code to write... */
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (nbytes != sizeof(event)) {
|
|
Packit Service |
26469c |
acpid_log(LOG_WARNING, "input layer unexpected length: "
|
|
Packit Service |
26469c |
"%zd expected: %zd", nbytes, sizeof(event));
|
|
Packit Service |
26469c |
return;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
c = find_connection(fd);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* if we're getting scancodes, we probably have a keyboard */
|
|
Packit Service |
26469c |
if (event.type == EV_MSC && event.code == MSC_SCAN) {
|
|
Packit Service |
26469c |
if (c)
|
|
Packit Service |
26469c |
c->kybd = 1; /* appears to be a keyboard device */
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* convert the event into a string */
|
|
Packit Service |
26469c |
if (tpmutefix) {
|
|
Packit Service |
26469c |
str = mute_string(event);
|
|
Packit Service |
26469c |
if (str == NULL)
|
|
Packit Service |
26469c |
str = event_string(event);
|
|
Packit Service |
26469c |
} else
|
|
Packit Service |
26469c |
str = event_string(event);
|
|
Packit Service |
26469c |
/* if this is not an event we care about, bail */
|
|
Packit Service |
26469c |
if (str == NULL)
|
|
Packit Service |
26469c |
return;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* If we suspect this is a keyboard, and we have enough space, tack a
|
|
Packit Service |
26469c |
* "K" on to the end of the event string. */
|
|
Packit Service |
26469c |
if (c && c->kybd && strnlen(str, sizeof(str2)) <= sizeof(str2) - 3) {
|
|
Packit Service |
26469c |
strcpy(str2, str);
|
|
Packit Service |
26469c |
strcat(str2, " K");
|
|
Packit Service |
26469c |
str = str2;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* if we're locked, don't process the event */
|
|
Packit Service |
26469c |
if (locked()) {
|
|
Packit Service |
26469c |
if (logevents) {
|
|
Packit Service |
26469c |
acpid_log(LOG_INFO,
|
|
Packit Service |
26469c |
"lockfile present, not processing "
|
|
Packit Service |
26469c |
"input layer event \"%s\"", str);
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
return;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (logevents)
|
|
Packit Service |
26469c |
acpid_log(LOG_INFO,
|
|
Packit Service |
26469c |
"received input layer event \"%s\"", str);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* send the event off to the handler */
|
|
Packit Service |
26469c |
acpid_handle_event(str);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (logevents)
|
|
Packit Service |
26469c |
acpid_log(LOG_INFO,
|
|
Packit Service |
26469c |
"completed input layer event \"%s\"", str);
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
#define BITS_PER_LONG (sizeof(long) * 8)
|
|
Packit Service |
26469c |
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
|
|
Packit Service |
26469c |
#define OFF(x) ((x)%BITS_PER_LONG)
|
|
Packit Service |
26469c |
#define LONG(x) ((x)/BITS_PER_LONG)
|
|
Packit Service |
26469c |
#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*--------------------------------------------------------------------*/
|
|
Packit Service |
26469c |
/* returns non-zero if the file descriptor supports one of the events */
|
|
Packit Service |
26469c |
/* supported by event_string(). */
|
|
Packit Service |
26469c |
static int
|
|
Packit Service |
26469c |
has_event(int fd)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
int type, code;
|
|
Packit Service |
26469c |
unsigned long bit[EV_MAX][NBITS(KEY_MAX)];
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
memset(bit, 0, sizeof(bit));
|
|
Packit Service |
26469c |
/* get the event type bitmap */
|
|
Packit Service |
26469c |
ioctl(fd, EVIOCGBIT(0, sizeof(bit[0])), bit[0]);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* for each event type */
|
|
Packit Service |
26469c |
for (type = 0; type < EV_MAX; type++) {
|
|
Packit Service |
26469c |
/* if this event type is supported */
|
|
Packit Service |
26469c |
if (test_bit(type, bit[0])) {
|
|
Packit Service |
26469c |
/* skip sync */
|
|
Packit Service |
26469c |
if (type == EV_SYN) continue;
|
|
Packit Service |
26469c |
/* get the event code mask */
|
|
Packit Service |
26469c |
ioctl(fd, EVIOCGBIT(type, sizeof(bit[type])), bit[type]);
|
|
Packit Service |
26469c |
/* for each event code */
|
|
Packit Service |
26469c |
for (code = 0; code < KEY_MAX; code++) {
|
|
Packit Service |
26469c |
/* if this event code is supported */
|
|
Packit Service |
26469c |
if (test_bit(code, bit[type])) {
|
|
Packit Service |
26469c |
/* if we need this event */
|
|
Packit Service |
26469c |
if (need_event(type, code) != 0)
|
|
Packit Service |
26469c |
return 1;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
return 0;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*-----------------------------------------------------------------*
|
|
Packit Service |
26469c |
* open a single input layer file for input */
|
|
Packit Service |
26469c |
int open_inputfile(const char *filename)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
int fd;
|
|
Packit Service |
26469c |
struct connection c;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* O_CLOEXEC: Make sure scripts we exec() (in event.c) don't get our file
|
|
Packit Service |
26469c |
descriptors. */
|
|
Packit Service |
26469c |
fd = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (fd >= 0) {
|
|
Packit Service |
26469c |
char evname[256];
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* if this file doesn't have events we need, indicate failure */
|
|
Packit Service |
26469c |
if (!has_event(fd)) {
|
|
Packit Service |
26469c |
close(fd);
|
|
Packit Service |
26469c |
return -1;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* get this event file's name for debugging */
|
|
Packit Service |
26469c |
strcpy(evname, "Unknown");
|
|
Packit Service |
26469c |
ioctl(fd, EVIOCGNAME(sizeof(evname)), evname);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
acpid_log(LOG_DEBUG, "input layer %s (%s) "
|
|
Packit Service |
26469c |
"opened successfully, fd %d", filename, evname, fd);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* add a connection to the list */
|
|
Packit Service |
26469c |
c.fd = fd;
|
|
Packit Service |
26469c |
c.process = process_input;
|
|
Packit Service |
26469c |
/* delete_connection() will free */
|
|
Packit Service |
26469c |
c.pathname = malloc(strlen(filename) + 1);
|
|
Packit Service |
26469c |
if (c.pathname)
|
|
Packit Service |
26469c |
strcpy(c.pathname, filename);
|
|
Packit Service |
26469c |
/* assume not a keyboard until we see a scancode */
|
|
Packit Service |
26469c |
c.kybd = 0;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (add_connection(&c) < 0) {
|
|
Packit Service |
26469c |
close(fd);
|
|
Packit Service |
26469c |
acpid_log(LOG_ERR,
|
|
Packit Service |
26469c |
"can't add connection for input layer %s (%s)",
|
|
Packit Service |
26469c |
filename, evname);
|
|
Packit Service |
26469c |
return -1;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
return 0; /* success */
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* open unsuccessful */
|
|
Packit Service |
26469c |
return -1;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/*-----------------------------------------------------------------*
|
|
Packit Service |
26469c |
* open each of the appropriate /dev/input/event* files for input */
|
|
Packit Service |
26469c |
void open_input(void)
|
|
Packit Service |
26469c |
{
|
|
Packit Service |
26469c |
char *filename = NULL;
|
|
Packit Service |
26469c |
glob_t globbuf;
|
|
Packit Service |
26469c |
unsigned i;
|
|
Packit Service |
26469c |
int success = 0;
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* get all the matching event filenames */
|
|
Packit Service |
26469c |
glob(ACPID_INPUTLAYERFILES, 0, NULL, &globbuf);
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* for each event file */
|
|
Packit Service |
26469c |
for (i = 0; i < globbuf.gl_pathc; ++i) {
|
|
Packit Service |
26469c |
filename = globbuf.gl_pathv[i];
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
/* open this input layer device file */
|
|
Packit Service |
26469c |
if (open_inputfile(filename) == 0)
|
|
Packit Service |
26469c |
success = 1;
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
if (!success)
|
|
Packit Service |
26469c |
acpid_log(LOG_ERR, "cannot open input layer");
|
|
Packit Service |
26469c |
|
|
Packit Service |
26469c |
globfree(&globbuf);
|
|
Packit Service |
26469c |
}
|
|
Packit Service |
26469c |
|