2005-04-17 02:20:36 +04:00
/*
* Joystick device driver for the input driver suite .
*
* Copyright ( c ) 1999 - 2002 Vojtech Pavlik
* Copyright ( c ) 1999 Colin Van Dyke
*
* 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 .
*/
# include <asm/io.h>
# include <asm/system.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/joystick.h>
# include <linux/input.h>
# include <linux/kernel.h>
# include <linux/major.h>
# include <linux/slab.h>
# include <linux/mm.h>
# include <linux/miscdevice.h>
# include <linux/module.h>
# include <linux/poll.h>
# include <linux/init.h>
# include <linux/smp_lock.h>
# include <linux/device.h>
MODULE_AUTHOR ( " Vojtech Pavlik <vojtech@ucw.cz> " ) ;
MODULE_DESCRIPTION ( " Joystick device interfaces " ) ;
MODULE_SUPPORTED_DEVICE ( " input/js " ) ;
MODULE_LICENSE ( " GPL " ) ;
# define JOYDEV_MINOR_BASE 0
# define JOYDEV_MINORS 16
# define JOYDEV_BUFFER_SIZE 64
struct joydev {
int exist ;
int open ;
int minor ;
char name [ 16 ] ;
struct input_handle handle ;
wait_queue_head_t wait ;
struct list_head list ;
struct js_corr corr [ ABS_MAX + 1 ] ;
struct JS_DATA_SAVE_TYPE glue ;
int nabs ;
int nkey ;
__u16 keymap [ KEY_MAX - BTN_MISC + 1 ] ;
__u16 keypam [ KEY_MAX - BTN_MISC + 1 ] ;
__u8 absmap [ ABS_MAX + 1 ] ;
__u8 abspam [ ABS_MAX + 1 ] ;
__s16 abs [ ABS_MAX + 1 ] ;
} ;
struct joydev_list {
struct js_event buffer [ JOYDEV_BUFFER_SIZE ] ;
int head ;
int tail ;
int startup ;
struct fasync_struct * fasync ;
struct joydev * joydev ;
struct list_head node ;
} ;
static struct joydev * joydev_table [ JOYDEV_MINORS ] ;
static int joydev_correct ( int value , struct js_corr * corr )
{
switch ( corr - > type ) {
case JS_CORR_NONE :
break ;
case JS_CORR_BROKEN :
value = value > corr - > coef [ 0 ] ? ( value < corr - > coef [ 1 ] ? 0 :
( ( corr - > coef [ 3 ] * ( value - corr - > coef [ 1 ] ) ) > > 14 ) ) :
( ( corr - > coef [ 2 ] * ( value - corr - > coef [ 0 ] ) ) > > 14 ) ;
break ;
default :
return 0 ;
}
2006-06-26 09:48:47 +04:00
return value < - 32767 ? - 32767 : ( value > 32767 ? 32767 : value ) ;
2005-04-17 02:20:36 +04:00
}
static void joydev_event ( struct input_handle * handle , unsigned int type , unsigned int code , int value )
{
struct joydev * joydev = handle - > private ;
struct joydev_list * list ;
struct js_event event ;
switch ( type ) {
case EV_KEY :
2006-06-26 09:48:47 +04:00
if ( code < BTN_MISC | | value = = 2 )
return ;
2005-04-17 02:20:36 +04:00
event . type = JS_EVENT_BUTTON ;
event . number = joydev - > keymap [ code - BTN_MISC ] ;
event . value = value ;
break ;
case EV_ABS :
event . type = JS_EVENT_AXIS ;
event . number = joydev - > absmap [ code ] ;
event . value = joydev_correct ( value , joydev - > corr + event . number ) ;
2006-06-26 09:48:47 +04:00
if ( event . value = = joydev - > abs [ event . number ] )
return ;
2005-04-17 02:20:36 +04:00
joydev - > abs [ event . number ] = event . value ;
break ;
default :
return ;
}
2005-07-11 10:08:56 +04:00
event . time = jiffies_to_msecs ( jiffies ) ;
2005-04-17 02:20:36 +04:00
list_for_each_entry ( list , & joydev - > list , node ) {
memcpy ( list - > buffer + list - > head , & event , sizeof ( struct js_event ) ) ;
if ( list - > startup = = joydev - > nabs + joydev - > nkey )
if ( list - > tail = = ( list - > head = ( list - > head + 1 ) & ( JOYDEV_BUFFER_SIZE - 1 ) ) )
list - > startup = 0 ;
kill_fasync ( & list - > fasync , SIGIO , POLL_IN ) ;
}
wake_up_interruptible ( & joydev - > wait ) ;
}
static int joydev_fasync ( int fd , struct file * file , int on )
{
int retval ;
struct joydev_list * list = file - > private_data ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
retval = fasync_helper ( fd , file , on , & list - > fasync ) ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
return retval < 0 ? retval : 0 ;
}
static void joydev_free ( struct joydev * joydev )
{
joydev_table [ joydev - > minor ] = NULL ;
kfree ( joydev ) ;
}
static int joydev_release ( struct inode * inode , struct file * file )
{
struct joydev_list * list = file - > private_data ;
joydev_fasync ( - 1 , file , 0 ) ;
list_del ( & list - > node ) ;
if ( ! - - list - > joydev - > open ) {
if ( list - > joydev - > exist )
input_close_device ( & list - > joydev - > handle ) ;
else
joydev_free ( list - > joydev ) ;
}
kfree ( list ) ;
return 0 ;
}
static int joydev_open ( struct inode * inode , struct file * file )
{
struct joydev_list * list ;
int i = iminor ( inode ) - JOYDEV_MINOR_BASE ;
if ( i > = JOYDEV_MINORS | | ! joydev_table [ i ] )
return - ENODEV ;
2006-03-14 08:09:16 +03:00
if ( ! ( list = kzalloc ( sizeof ( struct joydev_list ) , GFP_KERNEL ) ) )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
list - > joydev = joydev_table [ i ] ;
list_add_tail ( & list - > node , & joydev_table [ i ] - > list ) ;
file - > private_data = list ;
if ( ! list - > joydev - > open + + )
if ( list - > joydev - > exist )
input_open_device ( & list - > joydev - > handle ) ;
return 0 ;
}
static ssize_t joydev_write ( struct file * file , const char __user * buffer , size_t count , loff_t * ppos )
{
return - EINVAL ;
}
static ssize_t joydev_read ( struct file * file , char __user * buf , size_t count , loff_t * ppos )
{
struct joydev_list * list = file - > private_data ;
struct joydev * joydev = list - > joydev ;
struct input_dev * input = joydev - > handle . dev ;
int retval = 0 ;
if ( ! list - > joydev - > exist )
return - ENODEV ;
if ( count < sizeof ( struct js_event ) )
return - EINVAL ;
if ( count = = sizeof ( struct JS_DATA_TYPE ) ) {
struct JS_DATA_TYPE data ;
int i ;
for ( data . buttons = i = 0 ; i < 32 & & i < joydev - > nkey ; i + + )
data . buttons | = test_bit ( joydev - > keypam [ i ] , input - > key ) ? ( 1 < < i ) : 0 ;
data . x = ( joydev - > abs [ 0 ] / 256 + 128 ) > > joydev - > glue . JS_CORR . x ;
data . y = ( joydev - > abs [ 1 ] / 256 + 128 ) > > joydev - > glue . JS_CORR . y ;
if ( copy_to_user ( buf , & data , sizeof ( struct JS_DATA_TYPE ) ) )
return - EFAULT ;
list - > startup = 0 ;
list - > tail = list - > head ;
return sizeof ( struct JS_DATA_TYPE ) ;
}
2006-06-26 09:48:47 +04:00
if ( list - > startup = = joydev - > nabs + joydev - > nkey & &
list - > head = = list - > tail & & ( file - > f_flags & O_NONBLOCK ) )
return - EAGAIN ;
2005-04-17 02:20:36 +04:00
retval = wait_event_interruptible ( list - > joydev - > wait ,
2006-06-26 09:48:47 +04:00
! list - > joydev - > exist | |
2005-04-17 02:20:36 +04:00
list - > startup < joydev - > nabs + joydev - > nkey | |
list - > head ! = list - > tail ) ;
if ( retval )
return retval ;
if ( ! list - > joydev - > exist )
return - ENODEV ;
while ( list - > startup < joydev - > nabs + joydev - > nkey & & retval + sizeof ( struct js_event ) < = count ) {
struct js_event event ;
2005-07-11 10:08:56 +04:00
event . time = jiffies_to_msecs ( jiffies ) ;
2005-04-17 02:20:36 +04:00
if ( list - > startup < joydev - > nkey ) {
event . type = JS_EVENT_BUTTON | JS_EVENT_INIT ;
event . number = list - > startup ;
event . value = ! ! test_bit ( joydev - > keypam [ event . number ] , input - > key ) ;
} else {
event . type = JS_EVENT_AXIS | JS_EVENT_INIT ;
event . number = list - > startup - joydev - > nkey ;
event . value = joydev - > abs [ event . number ] ;
}
if ( copy_to_user ( buf + retval , & event , sizeof ( struct js_event ) ) )
return - EFAULT ;
list - > startup + + ;
retval + = sizeof ( struct js_event ) ;
}
while ( list - > head ! = list - > tail & & retval + sizeof ( struct js_event ) < = count ) {
if ( copy_to_user ( buf + retval , list - > buffer + list - > tail , sizeof ( struct js_event ) ) )
return - EFAULT ;
list - > tail = ( list - > tail + 1 ) & ( JOYDEV_BUFFER_SIZE - 1 ) ;
retval + = sizeof ( struct js_event ) ;
}
return retval ;
}
/* No kernel lock - fine */
static unsigned int joydev_poll ( struct file * file , poll_table * wait )
{
struct joydev_list * list = file - > private_data ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
poll_wait ( file , & list - > joydev - > wait , wait ) ;
2006-06-26 09:48:47 +04:00
return ( ( list - > head ! = list - > tail | | list - > startup < list - > joydev - > nabs + list - > joydev - > nkey ) ?
2005-04-17 02:20:36 +04:00
( POLLIN | POLLRDNORM ) : 0 ) | ( list - > joydev - > exist ? 0 : ( POLLHUP | POLLERR ) ) ;
}
2005-05-29 11:26:31 +04:00
static int joydev_ioctl_common ( struct joydev * joydev , unsigned int cmd , void __user * argp )
2005-04-17 02:20:36 +04:00
{
struct input_dev * dev = joydev - > handle . dev ;
int i , j ;
switch ( cmd ) {
case JS_SET_CAL :
return copy_from_user ( & joydev - > glue . JS_CORR , argp ,
2005-05-29 11:26:31 +04:00
sizeof ( joydev - > glue . JS_CORR ) ) ? - EFAULT : 0 ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JS_GET_CAL :
return copy_to_user ( argp , & joydev - > glue . JS_CORR ,
2005-05-29 11:26:31 +04:00
sizeof ( joydev - > glue . JS_CORR ) ) ? - EFAULT : 0 ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JS_SET_TIMEOUT :
2005-05-29 11:26:31 +04:00
return get_user ( joydev - > glue . JS_TIMEOUT , ( s32 __user * ) argp ) ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JS_GET_TIMEOUT :
2005-05-29 11:26:31 +04:00
return put_user ( joydev - > glue . JS_TIMEOUT , ( s32 __user * ) argp ) ;
2005-04-17 02:20:36 +04:00
case JSIOCGVERSION :
2005-05-29 11:26:31 +04:00
return put_user ( JS_VERSION , ( __u32 __user * ) argp ) ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JSIOCGAXES :
2005-05-29 11:26:31 +04:00
return put_user ( joydev - > nabs , ( __u8 __user * ) argp ) ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JSIOCGBUTTONS :
2005-05-29 11:26:31 +04:00
return put_user ( joydev - > nkey , ( __u8 __user * ) argp ) ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JSIOCSCORR :
if ( copy_from_user ( joydev - > corr , argp ,
2005-05-29 11:26:31 +04:00
sizeof ( joydev - > corr [ 0 ] ) * joydev - > nabs ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
for ( i = 0 ; i < joydev - > nabs ; i + + ) {
j = joydev - > abspam [ i ] ;
joydev - > abs [ i ] = joydev_correct ( dev - > abs [ j ] , joydev - > corr + i ) ;
}
return 0 ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JSIOCGCORR :
return copy_to_user ( argp , joydev - > corr ,
2005-05-29 11:26:31 +04:00
sizeof ( joydev - > corr [ 0 ] ) * joydev - > nabs ) ? - EFAULT : 0 ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JSIOCSAXMAP :
if ( copy_from_user ( joydev - > abspam , argp , sizeof ( __u8 ) * ( ABS_MAX + 1 ) ) )
return - EFAULT ;
for ( i = 0 ; i < joydev - > nabs ; i + + ) {
2006-06-26 09:48:47 +04:00
if ( joydev - > abspam [ i ] > ABS_MAX )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
joydev - > absmap [ joydev - > abspam [ i ] ] = i ;
}
return 0 ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JSIOCGAXMAP :
return copy_to_user ( argp , joydev - > abspam ,
sizeof ( __u8 ) * ( ABS_MAX + 1 ) ) ? - EFAULT : 0 ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JSIOCSBTNMAP :
if ( copy_from_user ( joydev - > keypam , argp , sizeof ( __u16 ) * ( KEY_MAX - BTN_MISC + 1 ) ) )
return - EFAULT ;
for ( i = 0 ; i < joydev - > nkey ; i + + ) {
2006-06-26 09:48:47 +04:00
if ( joydev - > keypam [ i ] > KEY_MAX | | joydev - > keypam [ i ] < BTN_MISC )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
joydev - > keymap [ joydev - > keypam [ i ] - BTN_MISC ] = i ;
}
return 0 ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
case JSIOCGBTNMAP :
return copy_to_user ( argp , joydev - > keypam ,
sizeof ( __u16 ) * ( KEY_MAX - BTN_MISC + 1 ) ) ? - EFAULT : 0 ;
2006-06-26 09:48:47 +04:00
2005-04-17 02:20:36 +04:00
default :
if ( ( cmd & ~ ( _IOC_SIZEMASK < < _IOC_SIZESHIFT ) ) = = JSIOCGNAME ( 0 ) ) {
int len ;
2006-06-26 09:48:47 +04:00
if ( ! dev - > name )
return 0 ;
2005-04-17 02:20:36 +04:00
len = strlen ( dev - > name ) + 1 ;
2006-06-26 09:48:47 +04:00
if ( len > _IOC_SIZE ( cmd ) )
len = _IOC_SIZE ( cmd ) ;
if ( copy_to_user ( argp , dev - > name , len ) )
return - EFAULT ;
2005-04-17 02:20:36 +04:00
return len ;
}
}
return - EINVAL ;
}
2005-05-29 11:26:31 +04:00
# ifdef CONFIG_COMPAT
static long joydev_compat_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
{
struct joydev_list * list = file - > private_data ;
struct joydev * joydev = list - > joydev ;
void __user * argp = ( void __user * ) arg ;
s32 tmp32 ;
struct JS_DATA_SAVE_TYPE_32 ds32 ;
int err ;
2006-06-26 09:48:47 +04:00
if ( ! joydev - > exist )
return - ENODEV ;
2005-05-29 11:26:31 +04:00
switch ( cmd ) {
case JS_SET_TIMELIMIT :
err = get_user ( tmp32 , ( s32 __user * ) arg ) ;
if ( err = = 0 )
joydev - > glue . JS_TIMELIMIT = tmp32 ;
break ;
case JS_GET_TIMELIMIT :
tmp32 = joydev - > glue . JS_TIMELIMIT ;
err = put_user ( tmp32 , ( s32 __user * ) arg ) ;
break ;
case JS_SET_ALL :
err = copy_from_user ( & ds32 , argp ,
sizeof ( ds32 ) ) ? - EFAULT : 0 ;
if ( err = = 0 ) {
joydev - > glue . JS_TIMEOUT = ds32 . JS_TIMEOUT ;
joydev - > glue . BUSY = ds32 . BUSY ;
joydev - > glue . JS_EXPIRETIME = ds32 . JS_EXPIRETIME ;
joydev - > glue . JS_TIMELIMIT = ds32 . JS_TIMELIMIT ;
joydev - > glue . JS_SAVE = ds32 . JS_SAVE ;
joydev - > glue . JS_CORR = ds32 . JS_CORR ;
}
break ;
case JS_GET_ALL :
ds32 . JS_TIMEOUT = joydev - > glue . JS_TIMEOUT ;
ds32 . BUSY = joydev - > glue . BUSY ;
ds32 . JS_EXPIRETIME = joydev - > glue . JS_EXPIRETIME ;
ds32 . JS_TIMELIMIT = joydev - > glue . JS_TIMELIMIT ;
ds32 . JS_SAVE = joydev - > glue . JS_SAVE ;
ds32 . JS_CORR = joydev - > glue . JS_CORR ;
2006-06-26 09:48:47 +04:00
err = copy_to_user ( argp , & ds32 , sizeof ( ds32 ) ) ? - EFAULT : 0 ;
2005-05-29 11:26:31 +04:00
break ;
default :
err = joydev_ioctl_common ( joydev , cmd , argp ) ;
}
return err ;
}
# endif /* CONFIG_COMPAT */
static int joydev_ioctl ( struct inode * inode , struct file * file , unsigned int cmd , unsigned long arg )
{
struct joydev_list * list = file - > private_data ;
struct joydev * joydev = list - > joydev ;
void __user * argp = ( void __user * ) arg ;
2006-06-26 09:48:47 +04:00
if ( ! joydev - > exist )
return - ENODEV ;
2005-05-29 11:26:31 +04:00
switch ( cmd ) {
case JS_SET_TIMELIMIT :
return get_user ( joydev - > glue . JS_TIMELIMIT , ( long __user * ) arg ) ;
case JS_GET_TIMELIMIT :
return put_user ( joydev - > glue . JS_TIMELIMIT , ( long __user * ) arg ) ;
case JS_SET_ALL :
return copy_from_user ( & joydev - > glue , argp ,
sizeof ( joydev - > glue ) ) ? - EFAULT : 0 ;
case JS_GET_ALL :
return copy_to_user ( argp , & joydev - > glue ,
sizeof ( joydev - > glue ) ) ? - EFAULT : 0 ;
default :
return joydev_ioctl_common ( joydev , cmd , argp ) ;
}
}
2005-04-17 02:20:36 +04:00
static struct file_operations joydev_fops = {
. owner = THIS_MODULE ,
. read = joydev_read ,
. write = joydev_write ,
. poll = joydev_poll ,
. open = joydev_open ,
. release = joydev_release ,
. ioctl = joydev_ioctl ,
2005-05-29 11:26:31 +04:00
# ifdef CONFIG_COMPAT
. compat_ioctl = joydev_compat_ioctl ,
# endif
2005-04-17 02:20:36 +04:00
. fasync = joydev_fasync ,
} ;
static struct input_handle * joydev_connect ( struct input_handler * handler , struct input_dev * dev , struct input_device_id * id )
{
struct joydev * joydev ;
2005-10-28 09:25:43 +04:00
struct class_device * cdev ;
2005-04-17 02:20:36 +04:00
int i , j , t , minor ;
for ( minor = 0 ; minor < JOYDEV_MINORS & & joydev_table [ minor ] ; minor + + ) ;
if ( minor = = JOYDEV_MINORS ) {
printk ( KERN_ERR " joydev: no more free joydev devices \n " ) ;
return NULL ;
}
2006-03-14 08:09:16 +03:00
if ( ! ( joydev = kzalloc ( sizeof ( struct joydev ) , GFP_KERNEL ) ) )
2005-04-17 02:20:36 +04:00
return NULL ;
INIT_LIST_HEAD ( & joydev - > list ) ;
init_waitqueue_head ( & joydev - > wait ) ;
joydev - > minor = minor ;
joydev - > exist = 1 ;
joydev - > handle . dev = dev ;
joydev - > handle . name = joydev - > name ;
joydev - > handle . handler = handler ;
joydev - > handle . private = joydev ;
sprintf ( joydev - > name , " js%d " , minor ) ;
for ( i = 0 ; i < ABS_MAX + 1 ; i + + )
if ( test_bit ( i , dev - > absbit ) ) {
joydev - > absmap [ i ] = joydev - > nabs ;
joydev - > abspam [ joydev - > nabs ] = i ;
joydev - > nabs + + ;
}
for ( i = BTN_JOYSTICK - BTN_MISC ; i < KEY_MAX - BTN_MISC + 1 ; i + + )
if ( test_bit ( i + BTN_MISC , dev - > keybit ) ) {
joydev - > keymap [ i ] = joydev - > nkey ;
joydev - > keypam [ joydev - > nkey ] = i + BTN_MISC ;
joydev - > nkey + + ;
}
2005-05-28 11:11:49 +04:00
for ( i = 0 ; i < BTN_JOYSTICK - BTN_MISC ; i + + )
2005-04-17 02:20:36 +04:00
if ( test_bit ( i + BTN_MISC , dev - > keybit ) ) {
joydev - > keymap [ i ] = joydev - > nkey ;
joydev - > keypam [ joydev - > nkey ] = i + BTN_MISC ;
joydev - > nkey + + ;
}
for ( i = 0 ; i < joydev - > nabs ; i + + ) {
j = joydev - > abspam [ i ] ;
if ( dev - > absmax [ j ] = = dev - > absmin [ j ] ) {
joydev - > corr [ i ] . type = JS_CORR_NONE ;
joydev - > abs [ i ] = dev - > abs [ j ] ;
continue ;
}
joydev - > corr [ i ] . type = JS_CORR_BROKEN ;
joydev - > corr [ i ] . prec = dev - > absfuzz [ j ] ;
joydev - > corr [ i ] . coef [ 0 ] = ( dev - > absmax [ j ] + dev - > absmin [ j ] ) / 2 - dev - > absflat [ j ] ;
joydev - > corr [ i ] . coef [ 1 ] = ( dev - > absmax [ j ] + dev - > absmin [ j ] ) / 2 + dev - > absflat [ j ] ;
if ( ! ( t = ( ( dev - > absmax [ j ] - dev - > absmin [ j ] ) / 2 - 2 * dev - > absflat [ j ] ) ) )
continue ;
joydev - > corr [ i ] . coef [ 2 ] = ( 1 < < 29 ) / t ;
joydev - > corr [ i ] . coef [ 3 ] = ( 1 < < 29 ) / t ;
joydev - > abs [ i ] = joydev_correct ( dev - > abs [ j ] , joydev - > corr + i ) ;
}
joydev_table [ minor ] = joydev ;
2005-10-28 09:25:43 +04:00
cdev = class_device_create ( & input_class , & dev - > cdev ,
2005-03-16 01:26:30 +03:00
MKDEV ( INPUT_MAJOR , JOYDEV_MINOR_BASE + minor ) ,
2005-10-28 09:25:43 +04:00
dev - > cdev . dev , joydev - > name ) ;
/* temporary symlink to keep userspace happy */
sysfs_create_link ( & input_class . subsys . kset . kobj , & cdev - > kobj ,
joydev - > name ) ;
2005-04-17 02:20:36 +04:00
return & joydev - > handle ;
}
static void joydev_disconnect ( struct input_handle * handle )
{
struct joydev * joydev = handle - > private ;
struct joydev_list * list ;
2005-10-28 09:25:43 +04:00
sysfs_remove_link ( & input_class . subsys . kset . kobj , joydev - > name ) ;
2005-10-28 09:25:43 +04:00
class_device_destroy ( & input_class , MKDEV ( INPUT_MAJOR , JOYDEV_MINOR_BASE + joydev - > minor ) ) ;
2005-04-17 02:20:36 +04:00
joydev - > exist = 0 ;
if ( joydev - > open ) {
input_close_device ( handle ) ;
wake_up_interruptible ( & joydev - > wait ) ;
list_for_each_entry ( list , & joydev - > list , node )
kill_fasync ( & list - > fasync , SIGIO , POLL_HUP ) ;
} else
joydev_free ( joydev ) ;
}
static struct input_device_id joydev_blacklist [ ] = {
{
. flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT ,
. evbit = { BIT ( EV_KEY ) } ,
. keybit = { [ LONG ( BTN_TOUCH ) ] = BIT ( BTN_TOUCH ) } ,
2006-06-26 09:48:47 +04:00
} , /* Avoid itouchpads, touchscreens and tablets */
{ } /* Terminating entry */
2005-04-17 02:20:36 +04:00
} ;
static struct input_device_id joydev_ids [ ] = {
{
. flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT ,
. evbit = { BIT ( EV_ABS ) } ,
. absbit = { BIT ( ABS_X ) } ,
} ,
{
. flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT ,
. evbit = { BIT ( EV_ABS ) } ,
. absbit = { BIT ( ABS_WHEEL ) } ,
} ,
{
. flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT ,
. evbit = { BIT ( EV_ABS ) } ,
. absbit = { BIT ( ABS_THROTTLE ) } ,
} ,
2006-06-26 09:48:47 +04:00
{ } /* Terminating entry */
2005-04-17 02:20:36 +04:00
} ;
MODULE_DEVICE_TABLE ( input , joydev_ids ) ;
static struct input_handler joydev_handler = {
. event = joydev_event ,
. connect = joydev_connect ,
. disconnect = joydev_disconnect ,
. fops = & joydev_fops ,
. minor = JOYDEV_MINOR_BASE ,
. name = " joydev " ,
. id_table = joydev_ids ,
2006-06-26 09:48:47 +04:00
. blacklist = joydev_blacklist ,
2005-04-17 02:20:36 +04:00
} ;
static int __init joydev_init ( void )
{
input_register_handler ( & joydev_handler ) ;
return 0 ;
}
static void __exit joydev_exit ( void )
{
input_unregister_handler ( & joydev_handler ) ;
}
module_init ( joydev_init ) ;
module_exit ( joydev_exit ) ;