@ -74,6 +74,7 @@
# define EVDEV_RELATIVE_EVENTS (1 << 2)
# define EVDEV_ABSOLUTE_EVENTS (1 << 3)
# define EVDEV_TOUCHPAD (1 << 4)
# define EVDEV_INITIALIZED (1 << 5) /* WheelInit etc. called already? */
# define MIN_KEYCODE 8
# define GLYPHS_PER_KEY 2
@ -112,6 +113,9 @@ static PropHandler evdevPropHandlers[] =
# endif
static int EvdevOn ( DeviceIntPtr ) ;
static int EvdevCacheCompare ( InputInfoPtr pInfo , Bool compare ) ;
static void
SetXkbOption ( InputInfoPtr pInfo , char * name , char * * option )
{
@ -195,6 +199,55 @@ static Bool EvdevGetProperty(DeviceIntPtr dev,
}
# endif
/**
* Coming back from resume may leave us with a file descriptor that can be
* opened but fails on the first read ( ENODEV ) .
* In this case , try to open the device until it becomes available or until
* the predefined count expires .
*/
static CARD32
EvdevReopenTimer ( OsTimerPtr timer , CARD32 time , pointer arg )
{
InputInfoPtr pInfo = ( InputInfoPtr ) arg ;
EvdevPtr pEvdev = pInfo - > private ;
do {
pInfo - > fd = open ( pEvdev - > device , O_RDWR , 0 ) ;
} while ( pInfo - > fd < 0 & & errno = = EINTR ) ;
if ( pInfo - > fd ! = - 1 )
{
pEvdev - > reopen_left = 0 ;
if ( EvdevCacheCompare ( pInfo , TRUE ) = = Success )
{
xf86Msg ( X_INFO , " %s: Device reopened after %d attempts. \n " , pInfo - > name ,
pEvdev - > reopen_attempts - pEvdev - > reopen_left ) ;
EvdevOn ( pInfo - > dev ) ;
} else
{
xf86Msg ( X_ERROR , " %s: Device has changed - disabling. \n " ,
pInfo - > name ) ;
DisableDevice ( pInfo - > dev ) ;
close ( pInfo - > fd ) ;
pInfo - > fd = - 1 ;
}
return 0 ;
}
pEvdev - > reopen_left - - ;
if ( ! pEvdev - > reopen_left )
{
xf86Msg ( X_ERROR , " %s: Failed to reopen device after %d attempts. \n " ,
pInfo - > name , pEvdev - > reopen_attempts ) ;
DisableDevice ( pInfo - > dev ) ;
return 0 ;
}
return 100 ; /* come back in 100 ms */
}
static void
EvdevReadInput ( InputInfoPtr pInfo )
{
@ -215,6 +268,15 @@ EvdevReadInput(InputInfoPtr pInfo)
/* The kernel promises that we always only read a complete
* event , so len ! = sizeof ev is an error . */
xf86Msg ( X_ERROR , " %s: Read error: %s \n " , pInfo - > name , strerror ( errno ) ) ;
if ( errno = = ENODEV ) /* May happen after resume */
{
xf86RemoveEnabledDevice ( pInfo ) ;
close ( pInfo - > fd ) ;
pInfo - > fd = - 1 ;
pEvdev - > reopen_left = pEvdev - > reopen_attempts ;
pEvdev - > reopen_timer = TimerSet ( NULL , 0 , 100 , EvdevReopenTimer , pInfo ) ;
}
break ;
}
@ -345,8 +407,6 @@ EvdevReadInput(InputInfoPtr pInfo)
}
}
# define LONG_BITS (sizeof(long) * 8)
# define NBITS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
# define TestBit(bit, array) (array[(bit) / LONG_BITS]) & (1 << ((bit) % LONG_BITS))
static void
@ -933,6 +993,58 @@ EvdevInit(DeviceIntPtr device)
return Success ;
}
/**
* Init all extras ( wheel emulation , etc . ) and grab the device .
*
* Coming from a resume , the grab may fail with ENODEV . In this case , we set a
* timer to wake up and try to reopen the device later .
*/
static int
EvdevOn ( DeviceIntPtr device )
{
InputInfoPtr pInfo ;
EvdevPtr pEvdev ;
int rc = 0 ;
pInfo = device - > public . devicePrivate ;
pEvdev = pInfo - > private ;
if ( pInfo - > fd ! = - 1 & & ! pEvdev - > kernel24 & &
( rc = ioctl ( pInfo - > fd , EVIOCGRAB , ( void * ) 1 ) ) )
{
xf86Msg ( X_WARNING , " %s: Grab failed (%s) \n " , pInfo - > name ,
strerror ( errno ) ) ;
/* ENODEV - device has disappeared after resume */
if ( rc & & errno = = ENODEV )
{
close ( pInfo - > fd ) ;
pInfo - > fd = - 1 ;
}
}
if ( pInfo - > fd = = - 1 )
{
pEvdev - > reopen_left = pEvdev - > reopen_attempts ;
pEvdev - > reopen_timer = TimerSet ( NULL , 0 , 100 , EvdevReopenTimer , pInfo ) ;
} else
{
xf86AddEnabledDevice ( pInfo ) ;
if ( ( pEvdev - > flags & EVDEV_BUTTON_EVENTS ) & &
! ( pEvdev - > flags & EVDEV_INITIALIZED ) )
{
EvdevMBEmuPreInit ( pInfo ) ;
EvdevWheelEmuPreInit ( pInfo ) ;
EvdevDragLockInit ( pInfo ) ;
}
pEvdev - > flags | = EVDEV_INITIALIZED ;
device - > public . on = TRUE ;
}
return Success ;
}
static int
EvdevProc ( DeviceIntPtr device , int what )
{
@ -948,40 +1060,149 @@ EvdevProc(DeviceIntPtr device, int what)
return EvdevInit ( device ) ;
case DEVICE_ON :
if ( ! pEvdev - > kernel24 & & ioctl ( pInfo - > fd , EVIOCGRAB , ( void * ) 1 ) )
xf86Msg ( X_WARNING , " %s: Grab failed (%s) \n " , pInfo - > name ,
strerror ( errno ) ) ;
if ( errno ! = ENODEV )
{
xf86AddEnabledDevice ( pInfo ) ;
if ( pEvdev - > flags & EVDEV_BUTTON_EVENTS )
{
EvdevMBEmuPreInit ( pInfo ) ;
EvdevWheelEmuPreInit ( pInfo ) ;
EvdevDragLockInit ( pInfo ) ;
}
device - > public . on = TRUE ;
}
break ;
return EvdevOn ( device ) ;
case DEVICE_OFF :
if ( ! pEvdev - > kernel24 & & ioctl ( pInfo - > fd , EVIOCGRAB , ( void * ) 0 ) )
xf86Msg ( X_WARNING , " %s: Release failed (%s) \n " , pInfo - > name ,
strerror ( errno ) ) ;
xf86RemoveEnabledDevice ( pInfo ) ;
EvdevMBEmuFinalize ( pInfo ) ;
if ( pInfo - > fd ! = - 1 )
{
if ( ! pEvdev - > kernel24 & & ioctl ( pInfo - > fd , EVIOCGRAB , ( void * ) 0 ) )
xf86Msg ( X_WARNING , " %s: Release failed (%s) \n " , pInfo - > name ,
strerror ( errno ) ) ;
xf86RemoveEnabledDevice ( pInfo ) ;
}
if ( pEvdev - > flags & EVDEV_INITIALIZED )
EvdevMBEmuFinalize ( pInfo ) ;
pEvdev - > flags & = ~ EVDEV_INITIALIZED ;
device - > public . on = FALSE ;
if ( pEvdev - > reopen_timer )
{
TimerFree ( pEvdev - > reopen_timer ) ;
pEvdev - > reopen_timer = NULL ;
}
break ;
case DEVICE_CLOSE :
xf86Msg ( X_INFO , " %s: Close \n " , pInfo - > name ) ;
close ( pInfo - > fd ) ;
if ( pInfo - > fd ! = - 1 )
close ( pInfo - > fd ) ;
break ;
}
return Success ;
}
/**
* Get as much information as we can from the fd and cache it .
* If compare is True , then the information retrieved will be compared to the
* one already cached . If the information does not match , then this function
* returns an error .
*
* @ return Success if the information was cached , or ! Success otherwise .
*/
static int
EvdevCacheCompare ( InputInfoPtr pInfo , Bool compare )
{
EvdevPtr pEvdev = pInfo - > private ;
int i ;
char name [ 1024 ] = { 0 } ;
long bitmask [ NBITS ( EV_MAX ) ] = { 0 } ;
long key_bitmask [ NBITS ( KEY_MAX ) ] = { 0 } ;
long rel_bitmask [ NBITS ( REL_MAX ) ] = { 0 } ;
long abs_bitmask [ NBITS ( ABS_MAX ) ] = { 0 } ;
long led_bitmask [ NBITS ( LED_MAX ) ] = { 0 } ;
struct input_absinfo absinfo [ ABS_MAX ] ;
if ( ioctl ( pInfo - > fd ,
EVIOCGNAME ( sizeof ( name ) - 1 ) , name ) < 0 ) {
xf86Msg ( X_ERROR , " ioctl EVIOCGNAME failed: %s \n " , strerror ( errno ) ) ;
goto error ;
}
if ( compare & & strcmp ( pEvdev - > name , name ) )
goto error ;
if ( ioctl ( pInfo - > fd ,
EVIOCGBIT ( 0 , sizeof ( bitmask ) ) , bitmask ) < 0 ) {
xf86Msg ( X_ERROR , " ioctl EVIOCGNAME failed: %s \n " , strerror ( errno ) ) ;
goto error ;
}
if ( compare & & memcmp ( pEvdev - > bitmask , bitmask , sizeof ( bitmask ) ) )
goto error ;
if ( ioctl ( pInfo - > fd ,
EVIOCGBIT ( EV_REL , sizeof ( rel_bitmask ) ) , rel_bitmask ) < 0 ) {
xf86Msg ( X_ERROR , " ioctl EVIOCGBIT failed: %s \n " , strerror ( errno ) ) ;
goto error ;
}
if ( compare & & memcmp ( pEvdev - > rel_bitmask , rel_bitmask , sizeof ( rel_bitmask ) ) )
goto error ;
if ( ioctl ( pInfo - > fd ,
EVIOCGBIT ( EV_ABS , sizeof ( abs_bitmask ) ) , abs_bitmask ) < 0 ) {
xf86Msg ( X_ERROR , " ioctl EVIOCGBIT failed: %s \n " , strerror ( errno ) ) ;
goto error ;
}
if ( compare & & memcmp ( pEvdev - > abs_bitmask , abs_bitmask , sizeof ( abs_bitmask ) ) )
goto error ;
if ( ioctl ( pInfo - > fd ,
EVIOCGBIT ( EV_KEY , sizeof ( key_bitmask ) ) , key_bitmask ) < 0 ) {
xf86Msg ( X_ERROR , " ioctl EVIOCGBIT failed: %s \n " , strerror ( errno ) ) ;
goto error ;
}
if ( compare & & memcmp ( pEvdev - > key_bitmask , key_bitmask , sizeof ( key_bitmask ) ) )
goto error ;
if ( ioctl ( pInfo - > fd ,
EVIOCGBIT ( EV_LED , sizeof ( led_bitmask ) ) , led_bitmask ) < 0 ) {
xf86Msg ( X_ERROR , " ioctl EVIOCGBIT failed: %s \n " , strerror ( errno ) ) ;
goto error ;
}
if ( compare & & memcmp ( pEvdev - > led_bitmask , led_bitmask , sizeof ( led_bitmask ) ) )
goto error ;
memset ( absinfo , 0 , sizeof ( absinfo ) ) ;
for ( i = 0 ; i < ABS_MAX ; i + + )
{
if ( TestBit ( i , abs_bitmask ) )
{
if ( ioctl ( pInfo - > fd , EVIOCGABS ( i ) , & absinfo [ i ] ) < 0 ) {
xf86Msg ( X_ERROR , " ioctl EVIOCGABS failed: %s \n " , strerror ( errno ) ) ;
goto error ;
}
}
}
if ( compare & & memcmp ( pEvdev - > absinfo , absinfo , sizeof ( absinfo ) ) )
goto error ;
/* cache info */
if ( ! compare )
{
strcpy ( pEvdev - > name , name ) ;
memcpy ( pEvdev - > bitmask , bitmask , sizeof ( bitmask ) ) ;
memcpy ( pEvdev - > key_bitmask , key_bitmask , sizeof ( key_bitmask ) ) ;
memcpy ( pEvdev - > rel_bitmask , rel_bitmask , sizeof ( rel_bitmask ) ) ;
memcpy ( pEvdev - > abs_bitmask , abs_bitmask , sizeof ( abs_bitmask ) ) ;
memcpy ( pEvdev - > led_bitmask , led_bitmask , sizeof ( led_bitmask ) ) ;
memcpy ( pEvdev - > absinfo , absinfo , sizeof ( absinfo ) ) ;
}
return Success ;
error :
return ! Success ;
}
static int
EvdevProbe ( InputInfoPtr pInfo )
{
@ -1147,11 +1368,12 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
return NULL ;
}
pEvdev - > device = device ;
xf86Msg ( deviceFrom , " %s: Device: \" %s \" \n " , pInfo - > name , device ) ;
do {
pInfo - > fd = open ( device , O_RDWR , 0 ) ;
}
while ( pInfo - > fd < 0 & & errno = = EINTR ) ;
} while ( pInfo - > fd < 0 & & errno = = EINTR ) ;
if ( pInfo - > fd < 0 ) {
xf86Msg ( X_ERROR , " Unable to open evdev device \" %s \" . \n " , device ) ;
@ -1159,6 +1381,8 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
return NULL ;
}
pEvdev - > reopen_attempts = xf86SetIntOption ( pInfo - > options , " ReopenAttempts " , 10 ) ;
EvdevInitButtonMapping ( pInfo ) ;
pEvdev - > noXkb = noXkbExtension ;
@ -1170,6 +1394,8 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
return NULL ;
}
EvdevCacheCompare ( pInfo , FALSE ) ; /* cache device data */
return pInfo ;
}