2015-02-20 19:14:10 +03:00
/*
* Copyright ( c ) 2015 Etienne Gemsa < etienne . gemsa @ lse . epita . fr >
* Copyright ( c ) 2015 Dmitry V . Levin < ldv @ altlinux . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "defs.h"
# ifdef HAVE_LINUX_INPUT_H
2016-05-27 03:39:33 +03:00
# include <linux / ioctl.h>
# include <linux / input.h>
# include "xlat / evdev_abs.h"
# include "xlat / evdev_autorepeat.h"
# include "xlat / evdev_ff_status.h"
# include "xlat / evdev_ff_types.h"
# include "xlat / evdev_keycode.h"
# include "xlat / evdev_leds.h"
# include "xlat / evdev_misc.h"
# include "xlat / evdev_mtslots.h"
# include "xlat / evdev_prop.h"
# include "xlat / evdev_relative_axes.h"
# include "xlat / evdev_snd.h"
# include "xlat / evdev_switch.h"
# include "xlat / evdev_sync.h"
# ifndef SYN_MAX
# define SYN_MAX 0xf
# endif
evdev: fix build with old kernel headers
* configure.ac: Check whether struct input_absinfo.resolution is defined
in <linux/input.h>.
* evdev.c (SYN_MAX): Add fallback definition.
(abs_ioctl): Wrap use of struct input_absinfo.resolution in #ifdef check.
(keycode_V2_ioctl, mtslots_ioctl, repeat_ioctl): Wrap in #ifdef checks.
(evdev_read_ioctl): Wrap in #ifdef checks the code that uses EV_SW,
EVIOCGREP, EVIOCGKEYCODE_V2, EVIOCGMTSLOTS, EVIOCGPROP, and EVIOCGSW.
(evdev_write_ioctl): Wrap in #ifdef checks the code that uses EVIOCSREP,
EVIOCSKEYCODE_V2, EVIOCSCLOCKID, and EVIOCREVOKE.
2015-02-22 02:50:33 +03:00
2015-02-20 19:14:10 +03:00
static void
2016-05-27 03:40:53 +03:00
decode_envelope ( const struct ff_envelope * envelope )
2015-02-20 19:14:10 +03:00
{
2016-05-27 03:40:53 +03:00
tprintf ( " , envelope={attack_length=% " PRIu16
" , attack_level=% " PRIu16
" , fade_length=% " PRIu16
" , fade_level=%#x} " ,
2015-02-20 19:14:10 +03:00
envelope - > attack_length ,
envelope - > attack_level ,
envelope - > fade_length ,
envelope - > fade_level ) ;
}
static int
ff_effect_ioctl ( struct tcb * tcp , long arg )
{
2016-05-27 03:41:02 +03:00
tprints ( " , " ) ;
2015-02-20 19:14:10 +03:00
struct ff_effect ffe ;
2016-05-27 03:41:02 +03:00
if ( umove_or_printaddr ( tcp , arg , & ffe ) )
return 1 ;
2015-02-20 19:14:10 +03:00
2016-05-27 03:41:02 +03:00
tprints ( " {type= " ) ;
2015-02-20 19:14:10 +03:00
printxval ( evdev_ff_types , ffe . type , " FF_??? " ) ;
2016-05-27 03:41:02 +03:00
tprintf ( " , id=% " PRIu16
" , direction=% " PRIu16 " , " ,
ffe . id ,
ffe . direction ) ;
2015-02-20 19:14:10 +03:00
2016-05-27 03:41:02 +03:00
if ( abbrev ( tcp ) ) {
tprints ( " ...} " ) ;
return 1 ;
2015-02-20 19:14:10 +03:00
}
2016-05-27 03:41:02 +03:00
tprintf ( " trigger={button=% " PRIu16
" , interval=% " PRIu16 " } "
" , replay={length=% " PRIu16
" , delay=% " PRIu16 " } " ,
ffe . trigger . button ,
ffe . trigger . interval ,
ffe . replay . length ,
ffe . replay . delay ) ;
switch ( ffe . type ) {
case FF_CONSTANT :
tprintf ( " , constant={level=% " PRId16 ,
ffe . u . constant . level ) ;
decode_envelope ( & ffe . u . constant . envelope ) ;
tprints ( " } " ) ;
break ;
case FF_RAMP :
tprintf ( " , ramp={start_level=% " PRId16
" , end_level=% " PRId16 ,
ffe . u . ramp . start_level ,
ffe . u . ramp . end_level ) ;
decode_envelope ( & ffe . u . ramp . envelope ) ;
tprints ( " } " ) ;
break ;
case FF_PERIODIC :
tprintf ( " , periodic={waveform=% " PRIu16
" , period=% " PRIu16
" , magnitude=% " PRId16
" , offset=% " PRId16
" , phase=% " PRIu16 ,
ffe . u . periodic . waveform ,
ffe . u . periodic . period ,
ffe . u . periodic . magnitude ,
ffe . u . periodic . offset ,
ffe . u . periodic . phase ) ;
decode_envelope ( & ffe . u . periodic . envelope ) ;
tprintf ( " , custom_len=%u "
" , custom_data=%#lx} " ,
ffe . u . periodic . custom_len ,
( unsigned long ) ffe . u . periodic . custom_data ) ;
break ;
case FF_RUMBLE :
tprintf ( " , rumble={strong_magnitude=% " PRIu16
" , weak_magnitude=% " PRIu16 " } " ,
ffe . u . rumble . strong_magnitude ,
ffe . u . rumble . weak_magnitude ) ;
break ;
default :
break ;
}
tprints ( " } " ) ;
2015-02-20 19:14:10 +03:00
return 1 ;
}
static int
abs_ioctl ( struct tcb * tcp , long arg )
{
2016-05-27 03:41:14 +03:00
tprints ( " , " ) ;
2015-02-20 19:14:10 +03:00
2016-05-27 03:41:14 +03:00
struct input_absinfo absinfo ;
2015-02-20 19:14:10 +03:00
2016-05-27 03:41:14 +03:00
if ( ! umove_or_printaddr ( tcp , arg , & absinfo ) ) {
tprintf ( " {value=%u "
" , minimum=%u, " ,
absinfo . value ,
absinfo . minimum ) ;
if ( ! abbrev ( tcp ) ) {
tprintf ( " maximum=%u "
" , fuzz=%u "
" , flat=%u " ,
absinfo . maximum ,
absinfo . fuzz ,
absinfo . flat ) ;
2016-05-27 03:39:33 +03:00
# ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION
2016-05-27 03:41:14 +03:00
tprintf ( " , resolution=%u " ,
absinfo . resolution ) ;
2016-05-27 03:39:33 +03:00
# endif
2016-05-27 03:41:14 +03:00
} else {
tprints ( " ... " ) ;
}
2015-02-20 19:14:10 +03:00
tprints ( " } " ) ;
}
2016-05-27 03:41:14 +03:00
2015-02-20 19:14:10 +03:00
return 1 ;
}
static int
keycode_ioctl ( struct tcb * tcp , long arg )
{
2016-05-27 03:41:25 +03:00
tprints ( " , " ) ;
2015-02-20 19:14:10 +03:00
unsigned int keycode [ 2 ] ;
2016-05-27 03:41:25 +03:00
if ( ! umove_or_printaddr ( tcp , arg , & keycode ) ) {
tprintf ( " [%u, " , keycode [ 0 ] ) ;
printxval ( evdev_keycode , keycode [ 1 ] , " KEY_??? " ) ;
tprints ( " ] " ) ;
2015-02-20 19:14:10 +03:00
}
return 1 ;
}
2016-05-27 03:39:33 +03:00
# ifdef EVIOCGKEYCODE_V2
2015-02-20 19:14:10 +03:00
static int
keycode_V2_ioctl ( struct tcb * tcp , long arg )
{
2016-05-27 03:41:34 +03:00
tprints ( " , " ) ;
2015-02-20 19:14:10 +03:00
struct input_keymap_entry ike ;
2016-05-27 03:41:34 +03:00
if ( umove_or_printaddr ( tcp , arg , & ike ) )
2015-02-20 19:14:10 +03:00
return 1 ;
2016-05-27 03:41:34 +03:00
tprintf ( " {flags=% " PRIu8
" , len=% " PRIu8 " , " ,
ike . flags ,
ike . len ) ;
2015-02-20 19:14:10 +03:00
if ( ! abbrev ( tcp ) ) {
2015-02-22 02:05:26 +03:00
unsigned int i ;
2016-05-27 03:41:34 +03:00
tprintf ( " index=% " PRIu16 " , keycode= " , ike . index ) ;
2015-02-22 02:05:26 +03:00
printxval ( evdev_keycode , ike . keycode , " KEY_??? " ) ;
tprints ( " , scancode=[ " ) ;
for ( i = 0 ; i < ARRAY_SIZE ( ike . scancode ) ; i + + ) {
if ( i > 0 )
tprints ( " , " ) ;
tprintf ( " % " PRIx8 , ike . scancode [ i ] ) ;
}
2016-05-27 03:41:34 +03:00
tprints ( " ] " ) ;
2015-02-20 19:14:10 +03:00
} else {
2016-05-27 03:41:34 +03:00
tprints ( " ... " ) ;
2015-02-20 19:14:10 +03:00
}
2016-05-27 03:41:34 +03:00
tprints ( " } " ) ;
2015-02-20 19:14:10 +03:00
return 1 ;
}
2016-05-27 03:39:33 +03:00
# endif /* EVIOCGKEYCODE_V2 */
2015-02-20 19:14:10 +03:00
static int
getid_ioctl ( struct tcb * tcp , long arg )
{
2016-05-27 03:41:43 +03:00
tprints ( " , " ) ;
2015-02-20 19:14:10 +03:00
struct input_id id ;
2016-05-27 03:41:43 +03:00
if ( ! umove_or_printaddr ( tcp , arg , & id ) )
tprintf ( " {ID_BUS=% " PRIu16
" , ID_VENDOR=% " PRIu16
" , ID_PRODUCT=% " PRIu16
" , ID_VERSION=% " PRIu16 " } " ,
id . bustype ,
id . vendor ,
id . product ,
id . version ) ;
2015-02-20 19:14:10 +03:00
return 1 ;
}
static int
decode_bitset ( struct tcb * tcp , long arg , const struct xlat decode_nr [ ] ,
const unsigned int max_nr , const char * dflt )
{
2016-05-27 03:41:51 +03:00
tprints ( " , " ) ;
2015-02-20 19:14:10 +03:00
unsigned int size ;
if ( ( unsigned long ) tcp - > u_rval > max_nr )
size = max_nr ;
else
size = tcp - > u_rval ;
char decoded_arg [ size ] ;
2016-05-27 03:41:51 +03:00
if ( umove_or_printaddr ( tcp , arg , & decoded_arg ) )
return 1 ;
2015-02-20 19:14:10 +03:00
2016-05-27 03:41:51 +03:00
tprints ( " [ " ) ;
2015-02-20 19:14:10 +03:00
int bit_displayed = 0 ;
int i = next_set_bit ( decoded_arg , 0 , size ) ;
if ( i < 0 ) {
tprints ( " 0 " ) ;
} else {
printxval ( decode_nr , i , dflt ) ;
while ( ( i = next_set_bit ( decoded_arg , i + 1 , size ) ) > 0 ) {
if ( abbrev ( tcp ) & & bit_displayed > = 3 ) {
tprints ( " , ... " ) ;
break ;
}
tprints ( " , " ) ;
printxval ( decode_nr , i , dflt ) ;
bit_displayed + + ;
}
}
tprints ( " ] " ) ;
return 1 ;
}
2016-05-27 03:39:33 +03:00
# ifdef EVIOCGMTSLOTS
2015-02-20 19:14:10 +03:00
static int
mtslots_ioctl ( struct tcb * tcp , const unsigned int code , long arg )
{
2016-05-27 03:41:59 +03:00
tprints ( " , " ) ;
const size_t size = _IOC_SIZE ( code ) / sizeof ( int ) ;
if ( ! size ) {
printaddr ( arg ) ;
return 1 ;
}
2015-02-20 19:14:10 +03:00
2016-05-27 03:41:59 +03:00
int buffer [ size ] ;
2015-02-20 19:14:10 +03:00
2016-05-27 03:41:59 +03:00
if ( umove_or_printaddr ( tcp , arg , & buffer ) )
return 1 ;
2015-02-20 19:14:10 +03:00
2016-05-27 03:41:59 +03:00
tprints ( " {code= " ) ;
2015-02-20 19:14:10 +03:00
printxval ( evdev_mtslots , buffer [ 0 ] , " ABS_MT_??? " ) ;
tprints ( " , values=[ " ) ;
2016-05-27 03:41:59 +03:00
unsigned int i ;
2015-02-20 19:14:10 +03:00
for ( i = 1 ; i < ARRAY_SIZE ( buffer ) ; i + + )
tprintf ( " %s%d " , i > 1 ? " , " : " " , buffer [ i ] ) ;
tprints ( " ]} " ) ;
2016-05-27 03:41:59 +03:00
2015-02-20 19:14:10 +03:00
return 1 ;
}
2016-05-27 03:39:33 +03:00
# endif /* EVIOCGMTSLOTS */
2015-02-20 19:14:10 +03:00
2016-05-27 03:39:33 +03:00
# if defined EVIOCGREP || defined EVIOCSREP
2015-02-20 19:14:10 +03:00
static int
repeat_ioctl ( struct tcb * tcp , long arg )
{
2015-07-07 01:33:39 +03:00
tprints ( " , " ) ;
printpair_int ( tcp , arg , " %u " ) ;
2015-02-20 19:14:10 +03:00
return 1 ;
}
2016-05-27 03:39:33 +03:00
# endif /* EVIOCGREP || EVIOCSREP */
2015-02-20 19:14:10 +03:00
2016-05-27 03:40:18 +03:00
static int
bit_ioctl ( struct tcb * tcp , const unsigned int ev_nr , const long arg )
{
switch ( ev_nr ) {
case EV_SYN :
return decode_bitset ( tcp , arg , evdev_sync ,
SYN_MAX , " SYN_??? " ) ;
case EV_KEY :
return decode_bitset ( tcp , arg , evdev_keycode ,
KEY_MAX , " KEY_??? " ) ;
case EV_REL :
return decode_bitset ( tcp , arg , evdev_relative_axes ,
REL_MAX , " REL_??? " ) ;
case EV_ABS :
return decode_bitset ( tcp , arg ,
evdev_abs , ABS_MAX , " ABS_??? " ) ;
case EV_MSC :
return decode_bitset ( tcp , arg ,
evdev_misc , MSC_MAX , " MSC_??? " ) ;
# ifdef EV_SW
case EV_SW :
return decode_bitset ( tcp , arg ,
evdev_switch , SW_MAX , " SW_??? " ) ;
# endif
case EV_LED :
return decode_bitset ( tcp , arg ,
evdev_leds , LED_MAX , " LED_??? " ) ;
case EV_SND :
return decode_bitset ( tcp , arg ,
evdev_snd , SND_MAX , " SND_??? " ) ;
case EV_REP :
return decode_bitset ( tcp , arg , evdev_autorepeat ,
REP_MAX , " REP_??? " ) ;
case EV_FF :
return decode_bitset ( tcp , arg , evdev_ff_types ,
FF_MAX , " FF_??? " ) ;
case EV_PWR :
printnum_int ( tcp , arg , " %d " ) ;
return 1 ;
case EV_FF_STATUS :
return decode_bitset ( tcp , arg , evdev_ff_status ,
FF_STATUS_MAX , " FF_STATUS_??? " ) ;
default :
return 0 ;
}
}
2015-02-20 19:14:10 +03:00
static int
2016-05-27 03:40:10 +03:00
evdev_read_ioctl ( struct tcb * tcp , const unsigned int code , const long arg )
2015-02-20 19:14:10 +03:00
{
if ( syserror ( tcp ) )
return 0 ;
2016-05-27 03:40:10 +03:00
/* fixed-number fixed-length commands */
2015-02-20 19:14:10 +03:00
switch ( code ) {
case EVIOCGVERSION :
tprints ( " , " ) ;
2016-05-27 03:42:07 +03:00
printnum_int ( tcp , arg , " %#x " ) ;
2015-02-20 19:14:10 +03:00
return 1 ;
case EVIOCGEFFECTS :
tprints ( " , " ) ;
printnum_int ( tcp , arg , " % " PRIu32 ) ;
return 1 ;
case EVIOCGID :
return getid_ioctl ( tcp , arg ) ;
2016-05-27 03:39:33 +03:00
# ifdef EVIOCGREP
2015-02-20 19:14:10 +03:00
case EVIOCGREP :
return repeat_ioctl ( tcp , arg ) ; ;
2016-05-27 03:39:33 +03:00
# endif
2015-02-20 19:14:10 +03:00
case EVIOCGKEYCODE :
return keycode_ioctl ( tcp , arg ) ;
2016-05-27 03:39:33 +03:00
# ifdef EVIOCGKEYCODE_V2
2015-02-20 19:14:10 +03:00
case EVIOCGKEYCODE_V2 :
return keycode_V2_ioctl ( tcp , arg ) ;
2016-05-27 03:39:33 +03:00
# endif
2015-02-20 19:14:10 +03:00
}
2016-05-27 03:40:10 +03:00
/* fixed-number variable-length commands */
2015-02-20 19:14:10 +03:00
switch ( _IOC_NR ( code ) ) {
2016-05-27 03:39:33 +03:00
# ifdef EVIOCGMTSLOTS
2015-02-20 19:14:10 +03:00
case _IOC_NR ( EVIOCGMTSLOTS ( 0 ) ) :
return mtslots_ioctl ( tcp , code , arg ) ;
2016-05-27 03:39:33 +03:00
# endif
2015-02-20 19:14:10 +03:00
case _IOC_NR ( EVIOCGNAME ( 0 ) ) :
case _IOC_NR ( EVIOCGPHYS ( 0 ) ) :
case _IOC_NR ( EVIOCGUNIQ ( 0 ) ) :
tprints ( " , " ) ;
printstr ( tcp , arg , tcp - > u_rval - 1 ) ;
return 1 ;
2016-05-27 03:39:33 +03:00
# ifdef EVIOCGPROP
2015-02-20 19:14:10 +03:00
case _IOC_NR ( EVIOCGPROP ( 0 ) ) :
return decode_bitset ( tcp , arg ,
evdev_prop , INPUT_PROP_MAX , " PROP_??? " ) ;
2016-05-27 03:39:33 +03:00
# endif
2015-02-20 19:14:10 +03:00
case _IOC_NR ( EVIOCGSND ( 0 ) ) :
return decode_bitset ( tcp , arg ,
evdev_snd , SND_MAX , " SND_??? " ) ;
2016-05-27 03:39:33 +03:00
# ifdef EVIOCGSW
2015-02-20 19:14:10 +03:00
case _IOC_NR ( EVIOCGSW ( 0 ) ) :
return decode_bitset ( tcp , arg ,
evdev_switch , SW_MAX , " SW_??? " ) ;
2016-05-27 03:39:33 +03:00
# endif
2015-02-20 19:14:10 +03:00
case _IOC_NR ( EVIOCGKEY ( 0 ) ) :
return decode_bitset ( tcp , arg ,
evdev_keycode , KEY_MAX , " KEY_??? " ) ;
case _IOC_NR ( EVIOCGLED ( 0 ) ) :
return decode_bitset ( tcp , arg ,
evdev_leds , LED_MAX , " LED_??? " ) ;
}
2016-05-27 03:40:10 +03:00
/* multi-number fixed-length commands */
if ( ( _IOC_NR ( code ) & ~ ABS_MAX ) = = _IOC_NR ( EVIOCGABS ( 0 ) ) )
return abs_ioctl ( tcp , arg ) ;
/* multi-number variable-length commands */
2016-05-27 03:40:18 +03:00
if ( ( _IOC_NR ( code ) & ~ EV_MAX ) = = _IOC_NR ( EVIOCGBIT ( 0 , 0 ) ) )
return bit_ioctl ( tcp , _IOC_NR ( code ) & EV_MAX , arg ) ;
2016-05-27 03:40:10 +03:00
return 0 ;
2015-02-20 19:14:10 +03:00
}
static int
2016-05-27 03:40:10 +03:00
evdev_write_ioctl ( struct tcb * tcp , const unsigned int code , const long arg )
2015-02-20 19:14:10 +03:00
{
2016-05-27 03:40:10 +03:00
/* fixed-number fixed-length commands */
2015-02-20 19:14:10 +03:00
switch ( code ) {
2016-05-27 03:39:33 +03:00
# ifdef EVIOCSREP
2015-02-20 19:14:10 +03:00
case EVIOCSREP :
return repeat_ioctl ( tcp , arg ) ;
2016-05-27 03:39:33 +03:00
# endif
2015-02-20 19:14:10 +03:00
case EVIOCSKEYCODE :
return keycode_ioctl ( tcp , arg ) ;
2016-05-27 03:39:33 +03:00
# ifdef EVIOCSKEYCODE_V2
2015-02-20 19:14:10 +03:00
case EVIOCSKEYCODE_V2 :
return keycode_V2_ioctl ( tcp , arg ) ;
2016-05-27 03:39:33 +03:00
# endif
2015-02-20 19:14:10 +03:00
case EVIOCSFF :
return ff_effect_ioctl ( tcp , arg ) ;
case EVIOCRMFF :
2016-05-27 03:40:27 +03:00
tprintf ( " , %d " , ( int ) arg ) ;
return 1 ;
2015-02-20 19:14:10 +03:00
case EVIOCGRAB :
2016-05-27 03:39:33 +03:00
# ifdef EVIOCREVOKE
2015-02-20 19:14:10 +03:00
case EVIOCREVOKE :
2016-05-27 03:39:33 +03:00
# endif
2016-05-27 03:40:45 +03:00
tprintf ( " , %lu " , arg ) ;
return 1 ;
# ifdef EVIOCSCLOCKID
case EVIOCSCLOCKID :
2015-02-20 19:14:10 +03:00
tprints ( " , " ) ;
printnum_int ( tcp , arg , " %u " ) ;
return 1 ;
2016-05-27 03:40:45 +03:00
# endif
2015-02-20 19:14:10 +03:00
}
2016-05-27 03:40:10 +03:00
/* multi-number fixed-length commands */
if ( ( _IOC_NR ( code ) & ~ ABS_MAX ) = = _IOC_NR ( EVIOCSABS ( 0 ) ) )
return abs_ioctl ( tcp , arg ) ;
return 0 ;
2015-02-20 19:14:10 +03:00
}
int
evdev_ioctl ( struct tcb * tcp , const unsigned int code , long arg )
{
switch ( _IOC_DIR ( code ) ) {
case _IOC_READ :
2016-05-27 03:40:02 +03:00
if ( entering ( tcp ) )
return 0 ;
2015-02-20 19:14:10 +03:00
return evdev_read_ioctl ( tcp , code , arg ) ;
case _IOC_WRITE :
2016-05-27 03:40:02 +03:00
return evdev_write_ioctl ( tcp , code , arg ) | RVAL_DECODED ;
2015-02-20 19:14:10 +03:00
default :
2016-05-27 03:40:02 +03:00
return RVAL_DECODED ;
2015-02-20 19:14:10 +03:00
}
}
# endif /* HAVE_LINUX_INPUT_H */