2005-04-17 02:20:36 +04:00
/*
* Input driver to ExplorerPS / 2 device driver module .
*
* Copyright ( c ) 1999 - 2002 Vojtech Pavlik
* Copyright ( c ) 2004 Dmitry Torokhov
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*/
2010-11-30 10:33:07 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-09-15 11:01:38 +04:00
# define MOUSEDEV_MINOR_BASE 32
2012-11-16 21:14:12 +04:00
# define MOUSEDEV_MINORS 31
# define MOUSEDEV_MIX 63
2005-04-17 02:20:36 +04:00
2017-06-25 08:50:12 +03:00
# include <linux/bitops.h>
2009-10-04 16:11:37 +04:00
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
# include <linux/slab.h>
# include <linux/poll.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/input.h>
# include <linux/random.h>
# include <linux/major.h>
# include <linux/device.h>
2012-10-08 20:07:24 +04:00
# include <linux/cdev.h>
2010-08-03 07:15:17 +04:00
# include <linux/kernel.h>
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " Vojtech Pavlik <vojtech@ucw.cz> " ) ;
MODULE_DESCRIPTION ( " Mouse (ExplorerPS/2) device interfaces " ) ;
MODULE_LICENSE ( " GPL " ) ;
# ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
# define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
# endif
# ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
# define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
# endif
static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X ;
2005-12-11 20:41:03 +03:00
module_param ( xres , uint , 0644 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( xres , " Horizontal screen resolution " ) ;
static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y ;
2005-12-11 20:41:03 +03:00
module_param ( yres , uint , 0644 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( yres , " Vertical screen resolution " ) ;
static unsigned tap_time = 200 ;
2005-12-11 20:41:03 +03:00
module_param ( tap_time , uint , 0644 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( tap_time , " Tap time for touchpads in absolute mode (msecs) " ) ;
struct mousedev_hw_data {
int dx , dy , dz ;
int x , y ;
int abs_event ;
unsigned long buttons ;
} ;
struct mousedev {
int open ;
2007-08-30 08:22:24 +04:00
struct input_handle handle ;
2005-04-17 02:20:36 +04:00
wait_queue_head_t wait ;
2007-04-12 09:30:00 +04:00
struct list_head client_list ;
2007-08-30 08:22:24 +04:00
spinlock_t client_lock ; /* protects client_list */
struct mutex mutex ;
2007-06-15 07:32:24 +04:00
struct device dev ;
2012-10-08 20:07:24 +04:00
struct cdev cdev ;
2010-07-16 10:27:36 +04:00
bool exist ;
2005-04-17 02:20:36 +04:00
2007-04-12 09:30:15 +04:00
struct list_head mixdev_node ;
2012-10-08 20:07:24 +04:00
bool opened_by_mixdev ;
2007-04-12 09:30:15 +04:00
2005-04-17 02:20:36 +04:00
struct mousedev_hw_data packet ;
unsigned int pkt_count ;
int old_x [ 4 ] , old_y [ 4 ] ;
int frac_dx , frac_dy ;
unsigned long touch ;
2014-03-07 00:57:24 +04:00
int ( * open_device ) ( struct mousedev * mousedev ) ;
void ( * close_device ) ( struct mousedev * mousedev ) ;
2005-04-17 02:20:36 +04:00
} ;
enum mousedev_emul {
MOUSEDEV_EMUL_PS2 ,
MOUSEDEV_EMUL_IMPS ,
MOUSEDEV_EMUL_EXPS
} ;
struct mousedev_motion {
int dx , dy , dz ;
unsigned long buttons ;
} ;
# define PACKET_QUEUE_LEN 16
2007-04-12 09:30:00 +04:00
struct mousedev_client {
2005-04-17 02:20:36 +04:00
struct fasync_struct * fasync ;
struct mousedev * mousedev ;
struct list_head node ;
struct mousedev_motion packets [ PACKET_QUEUE_LEN ] ;
unsigned int head , tail ;
spinlock_t packet_lock ;
int pos_x , pos_y ;
2017-06-25 08:50:12 +03:00
u8 ps2 [ 6 ] ;
2005-04-17 02:20:36 +04:00
unsigned char ready , buffer , bufsiz ;
unsigned char imexseq , impsseq ;
enum mousedev_emul mode ;
2005-05-27 23:53:03 +04:00
unsigned long last_buttons ;
2005-04-17 02:20:36 +04:00
} ;
# define MOUSEDEV_SEQ_LEN 6
static unsigned char mousedev_imps_seq [ ] = { 0xf3 , 200 , 0xf3 , 100 , 0xf3 , 80 } ;
static unsigned char mousedev_imex_seq [ ] = { 0xf3 , 200 , 0xf3 , 200 , 0xf3 , 80 } ;
2007-06-15 07:32:24 +04:00
static struct mousedev * mousedev_mix ;
2007-04-12 09:30:15 +04:00
static LIST_HEAD ( mousedev_mix_list ) ;
2005-04-17 02:20:36 +04:00
# define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
# define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
2007-08-30 08:22:24 +04:00
static void mousedev_touchpad_event ( struct input_dev * dev ,
struct mousedev * mousedev ,
unsigned int code , int value )
2005-04-17 02:20:36 +04:00
{
int size , tmp ;
enum { FRACTION_DENOM = 128 } ;
2007-04-12 09:31:55 +04:00
switch ( code ) {
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
case ABS_X :
2010-08-03 07:15:17 +04:00
2007-08-30 08:22:24 +04:00
fx ( 0 ) = value ;
if ( mousedev - > touch & & mousedev - > pkt_count > = 2 ) {
2010-08-24 11:33:37 +04:00
size = input_abs_get_max ( dev , ABS_X ) -
input_abs_get_min ( dev , ABS_X ) ;
2007-08-30 08:22:24 +04:00
if ( size = = 0 )
size = 256 * 2 ;
2010-08-03 07:15:17 +04:00
2007-08-30 08:22:24 +04:00
tmp = ( ( value - fx ( 2 ) ) * 256 * FRACTION_DENOM ) / size ;
tmp + = mousedev - > frac_dx ;
mousedev - > packet . dx = tmp / FRACTION_DENOM ;
mousedev - > frac_dx =
tmp - mousedev - > packet . dx * FRACTION_DENOM ;
}
break ;
case ABS_Y :
fy ( 0 ) = value ;
if ( mousedev - > touch & & mousedev - > pkt_count > = 2 ) {
2010-08-03 07:15:17 +04:00
/* use X size for ABS_Y to keep the same scale */
2010-08-24 11:33:37 +04:00
size = input_abs_get_max ( dev , ABS_X ) -
input_abs_get_min ( dev , ABS_X ) ;
2007-08-30 08:22:24 +04:00
if ( size = = 0 )
size = 256 * 2 ;
2010-08-03 07:15:17 +04:00
2007-08-30 08:22:24 +04:00
tmp = - ( ( value - fy ( 2 ) ) * 256 * FRACTION_DENOM ) / size ;
tmp + = mousedev - > frac_dy ;
mousedev - > packet . dy = tmp / FRACTION_DENOM ;
mousedev - > frac_dy = tmp -
mousedev - > packet . dy * FRACTION_DENOM ;
}
break ;
2005-04-17 02:20:36 +04:00
}
}
2007-08-30 08:22:24 +04:00
static void mousedev_abs_event ( struct input_dev * dev , struct mousedev * mousedev ,
unsigned int code , int value )
2005-04-17 02:20:36 +04:00
{
2010-08-03 07:15:17 +04:00
int min , max , size ;
2005-04-17 02:20:36 +04:00
switch ( code ) {
2007-08-30 08:22:24 +04:00
case ABS_X :
2010-08-03 07:15:17 +04:00
min = input_abs_get_min ( dev , ABS_X ) ;
max = input_abs_get_max ( dev , ABS_X ) ;
size = max - min ;
2007-08-30 08:22:24 +04:00
if ( size = = 0 )
size = xres ? : 1 ;
2010-08-03 07:15:17 +04:00
2011-05-25 20:24:32 +04:00
value = clamp ( value , min , max ) ;
2010-08-03 07:15:17 +04:00
mousedev - > packet . x = ( ( value - min ) * xres ) / size ;
2007-08-30 08:22:24 +04:00
mousedev - > packet . abs_event = 1 ;
break ;
case ABS_Y :
2010-08-03 07:15:17 +04:00
min = input_abs_get_min ( dev , ABS_Y ) ;
max = input_abs_get_max ( dev , ABS_Y ) ;
size = max - min ;
2007-08-30 08:22:24 +04:00
if ( size = = 0 )
size = yres ? : 1 ;
2010-08-03 07:15:17 +04:00
2011-05-25 20:24:32 +04:00
value = clamp ( value , min , max ) ;
2010-08-03 07:15:17 +04:00
mousedev - > packet . y = yres - ( ( value - min ) * yres ) / size ;
2007-08-30 08:22:24 +04:00
mousedev - > packet . abs_event = 1 ;
break ;
2005-04-17 02:20:36 +04:00
}
}
2007-08-30 08:22:24 +04:00
static void mousedev_rel_event ( struct mousedev * mousedev ,
unsigned int code , int value )
2005-04-17 02:20:36 +04:00
{
switch ( code ) {
2007-08-30 08:22:24 +04:00
case REL_X :
mousedev - > packet . dx + = value ;
break ;
case REL_Y :
mousedev - > packet . dy - = value ;
break ;
case REL_WHEEL :
mousedev - > packet . dz - = value ;
break ;
2005-04-17 02:20:36 +04:00
}
}
2007-08-30 08:22:24 +04:00
static void mousedev_key_event ( struct mousedev * mousedev ,
unsigned int code , int value )
2005-04-17 02:20:36 +04:00
{
int index ;
switch ( code ) {
2007-08-30 08:22:24 +04:00
case BTN_TOUCH :
case BTN_0 :
case BTN_LEFT : index = 0 ; break ;
case BTN_STYLUS :
case BTN_1 :
case BTN_RIGHT : index = 1 ; break ;
case BTN_2 :
case BTN_FORWARD :
case BTN_STYLUS2 :
case BTN_MIDDLE : index = 2 ; break ;
case BTN_3 :
case BTN_BACK :
case BTN_SIDE : index = 3 ; break ;
case BTN_4 :
case BTN_EXTRA : index = 4 ; break ;
default : return ;
2005-04-17 02:20:36 +04:00
}
if ( value ) {
set_bit ( index , & mousedev - > packet . buttons ) ;
2007-06-15 07:32:24 +04:00
set_bit ( index , & mousedev_mix - > packet . buttons ) ;
2005-04-17 02:20:36 +04:00
} else {
clear_bit ( index , & mousedev - > packet . buttons ) ;
2007-06-15 07:32:24 +04:00
clear_bit ( index , & mousedev_mix - > packet . buttons ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-08-30 08:22:24 +04:00
static void mousedev_notify_readers ( struct mousedev * mousedev ,
struct mousedev_hw_data * packet )
2005-04-17 02:20:36 +04:00
{
2007-04-12 09:30:00 +04:00
struct mousedev_client * client ;
2005-04-17 02:20:36 +04:00
struct mousedev_motion * p ;
2007-08-30 08:22:24 +04:00
unsigned int new_head ;
2005-06-01 11:39:36 +04:00
int wake_readers = 0 ;
2005-04-17 02:20:36 +04:00
2007-10-13 23:46:55 +04:00
rcu_read_lock ( ) ;
2007-08-30 08:22:24 +04:00
list_for_each_entry_rcu ( client , & mousedev - > client_list , node ) {
/* Just acquire the lock, interrupts already disabled */
spin_lock ( & client - > packet_lock ) ;
2005-04-17 02:20:36 +04:00
2007-04-12 09:30:00 +04:00
p = & client - > packets [ client - > head ] ;
if ( client - > ready & & p - > buttons ! = mousedev - > packet . buttons ) {
2007-08-30 08:22:24 +04:00
new_head = ( client - > head + 1 ) % PACKET_QUEUE_LEN ;
2007-04-12 09:30:00 +04:00
if ( new_head ! = client - > tail ) {
p = & client - > packets [ client - > head = new_head ] ;
2005-04-17 02:20:36 +04:00
memset ( p , 0 , sizeof ( struct mousedev_motion ) ) ;
}
}
if ( packet - > abs_event ) {
2007-04-12 09:30:00 +04:00
p - > dx + = packet - > x - client - > pos_x ;
p - > dy + = packet - > y - client - > pos_y ;
client - > pos_x = packet - > x ;
client - > pos_y = packet - > y ;
2005-04-17 02:20:36 +04:00
}
2007-04-12 09:30:00 +04:00
client - > pos_x + = packet - > dx ;
2017-06-25 08:50:12 +03:00
client - > pos_x = clamp_val ( client - > pos_x , 0 , xres ) ;
2007-04-12 09:30:00 +04:00
client - > pos_y + = packet - > dy ;
2017-06-25 08:50:12 +03:00
client - > pos_y = clamp_val ( client - > pos_y , 0 , yres ) ;
2005-04-17 02:20:36 +04:00
p - > dx + = packet - > dx ;
p - > dy + = packet - > dy ;
p - > dz + = packet - > dz ;
p - > buttons = mousedev - > packet . buttons ;
2007-08-30 08:22:24 +04:00
if ( p - > dx | | p - > dy | | p - > dz | |
p - > buttons ! = client - > last_buttons )
2007-04-12 09:30:00 +04:00
client - > ready = 1 ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
spin_unlock ( & client - > packet_lock ) ;
2005-05-27 23:53:03 +04:00
2007-04-12 09:30:00 +04:00
if ( client - > ready ) {
kill_fasync ( & client - > fasync , SIGIO , POLL_IN ) ;
2005-06-01 11:39:36 +04:00
wake_readers = 1 ;
}
2005-04-17 02:20:36 +04:00
}
2007-10-13 23:46:55 +04:00
rcu_read_unlock ( ) ;
2005-04-17 02:20:36 +04:00
2005-06-01 11:39:36 +04:00
if ( wake_readers )
wake_up_interruptible ( & mousedev - > wait ) ;
2005-04-17 02:20:36 +04:00
}
static void mousedev_touchpad_touch ( struct mousedev * mousedev , int value )
{
if ( ! value ) {
if ( mousedev - > touch & &
2007-08-30 08:22:24 +04:00
time_before ( jiffies ,
mousedev - > touch + msecs_to_jiffies ( tap_time ) ) ) {
2005-04-17 02:20:36 +04:00
/*
* Toggle left button to emulate tap .
* We rely on the fact that mousedev_mix always has 0
* motion packet so we won ' t mess current position .
*/
set_bit ( 0 , & mousedev - > packet . buttons ) ;
2007-06-15 07:32:24 +04:00
set_bit ( 0 , & mousedev_mix - > packet . buttons ) ;
mousedev_notify_readers ( mousedev , & mousedev_mix - > packet ) ;
2007-08-30 08:22:24 +04:00
mousedev_notify_readers ( mousedev_mix ,
& mousedev_mix - > packet ) ;
2005-04-17 02:20:36 +04:00
clear_bit ( 0 , & mousedev - > packet . buttons ) ;
2007-06-15 07:32:24 +04:00
clear_bit ( 0 , & mousedev_mix - > packet . buttons ) ;
2005-04-17 02:20:36 +04:00
}
mousedev - > touch = mousedev - > pkt_count = 0 ;
mousedev - > frac_dx = 0 ;
mousedev - > frac_dy = 0 ;
2006-06-26 09:48:47 +04:00
} else if ( ! mousedev - > touch )
mousedev - > touch = jiffies ;
2005-04-17 02:20:36 +04:00
}
2007-08-30 08:22:24 +04:00
static void mousedev_event ( struct input_handle * handle ,
unsigned int type , unsigned int code , int value )
2005-04-17 02:20:36 +04:00
{
struct mousedev * mousedev = handle - > private ;
switch ( type ) {
2007-08-30 08:22:24 +04:00
case EV_ABS :
/* Ignore joysticks */
if ( test_bit ( BTN_TRIGGER , handle - > dev - > keybit ) )
return ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
if ( test_bit ( BTN_TOOL_FINGER , handle - > dev - > keybit ) )
mousedev_touchpad_event ( handle - > dev ,
mousedev , code , value ) ;
else
mousedev_abs_event ( handle - > dev , mousedev , code , value ) ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
break ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
case EV_REL :
mousedev_rel_event ( mousedev , code , value ) ;
break ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
case EV_KEY :
if ( value ! = 2 ) {
if ( code = = BTN_TOUCH & &
test_bit ( BTN_TOOL_FINGER , handle - > dev - > keybit ) )
mousedev_touchpad_touch ( mousedev , value ) ;
else
mousedev_key_event ( mousedev , code , value ) ;
}
break ;
case EV_SYN :
if ( code = = SYN_REPORT ) {
if ( mousedev - > touch ) {
mousedev - > pkt_count + + ;
/*
* Input system eats duplicate events ,
* but we need all of them to do correct
* averaging so apply present one forward
*/
fx ( 0 ) = fx ( 1 ) ;
fy ( 0 ) = fy ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
2007-08-30 08:22:24 +04:00
mousedev_notify_readers ( mousedev , & mousedev - > packet ) ;
mousedev_notify_readers ( mousedev_mix , & mousedev - > packet ) ;
mousedev - > packet . dx = mousedev - > packet . dy =
mousedev - > packet . dz = 0 ;
mousedev - > packet . abs_event = 0 ;
}
break ;
2005-04-17 02:20:36 +04:00
}
}
static int mousedev_fasync ( int fd , struct file * file , int on )
{
2007-04-12 09:30:00 +04:00
struct mousedev_client * client = file - > private_data ;
2006-06-26 09:48:47 +04:00
2009-02-02 00:52:56 +03:00
return fasync_helper ( fd , file , on , & client - > fasync ) ;
2005-04-17 02:20:36 +04:00
}
2007-06-15 07:32:24 +04:00
static void mousedev_free ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2007-06-15 07:32:24 +04:00
struct mousedev * mousedev = container_of ( dev , struct mousedev , dev ) ;
2008-04-01 08:22:53 +04:00
input_put_device ( mousedev - > handle . dev ) ;
2005-04-17 02:20:36 +04:00
kfree ( mousedev ) ;
}
2007-08-30 08:22:24 +04:00
static int mousedev_open_device ( struct mousedev * mousedev )
2005-04-17 02:20:36 +04:00
{
2007-08-30 08:22:24 +04:00
int retval ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
retval = mutex_lock_interruptible ( & mousedev - > mutex ) ;
if ( retval )
return retval ;
2007-04-12 09:30:15 +04:00
2014-03-07 00:57:24 +04:00
if ( ! mousedev - > exist )
2007-08-30 08:22:24 +04:00
retval = - ENODEV ;
2007-10-12 22:18:40 +04:00
else if ( ! mousedev - > open + + ) {
2007-08-30 08:22:24 +04:00
retval = input_open_device ( & mousedev - > handle ) ;
2007-10-12 22:18:40 +04:00
if ( retval )
mousedev - > open - - ;
}
2007-04-12 09:30:15 +04:00
2007-08-30 08:22:24 +04:00
mutex_unlock ( & mousedev - > mutex ) ;
return retval ;
2007-04-12 09:30:15 +04:00
}
2007-08-30 08:22:24 +04:00
static void mousedev_close_device ( struct mousedev * mousedev )
2007-04-12 09:30:15 +04:00
{
2007-08-30 08:22:24 +04:00
mutex_lock ( & mousedev - > mutex ) ;
2007-04-12 09:30:15 +04:00
2014-03-07 00:57:24 +04:00
if ( mousedev - > exist & & ! - - mousedev - > open )
2007-08-30 08:22:24 +04:00
input_close_device ( & mousedev - > handle ) ;
mutex_unlock ( & mousedev - > mutex ) ;
2007-04-12 09:30:15 +04:00
}
2007-08-30 08:22:24 +04:00
/*
* Open all available devices so they can all be multiplexed in one .
* stream . Note that this function is called with mousedev_mix - > mutex
* held .
*/
2014-03-07 00:57:24 +04:00
static int mixdev_open_devices ( struct mousedev * mixdev )
2007-04-12 09:30:15 +04:00
{
2014-03-07 00:57:24 +04:00
int error ;
error = mutex_lock_interruptible ( & mixdev - > mutex ) ;
if ( error )
return error ;
2007-04-12 09:30:15 +04:00
2014-03-07 00:57:24 +04:00
if ( ! mixdev - > open + + ) {
struct mousedev * mousedev ;
2007-06-15 07:32:24 +04:00
2014-03-07 00:57:24 +04:00
list_for_each_entry ( mousedev , & mousedev_mix_list , mixdev_node ) {
if ( ! mousedev - > opened_by_mixdev ) {
if ( mousedev_open_device ( mousedev ) )
continue ;
2007-04-12 09:30:15 +04:00
2014-03-07 00:57:24 +04:00
mousedev - > opened_by_mixdev = true ;
}
2005-04-17 02:20:36 +04:00
}
}
2014-03-07 00:57:24 +04:00
mutex_unlock ( & mixdev - > mutex ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-08-30 08:22:24 +04:00
/*
* Close all devices that were opened as part of multiplexed
* device . Note that this function is called with mousedev_mix - > mutex
* held .
*/
2014-03-07 00:57:24 +04:00
static void mixdev_close_devices ( struct mousedev * mixdev )
2005-04-17 02:20:36 +04:00
{
2014-03-07 00:57:24 +04:00
mutex_lock ( & mixdev - > mutex ) ;
2007-04-12 09:30:15 +04:00
2014-03-07 00:57:24 +04:00
if ( ! - - mixdev - > open ) {
struct mousedev * mousedev ;
2007-06-15 07:32:24 +04:00
2014-03-07 00:57:24 +04:00
list_for_each_entry ( mousedev , & mousedev_mix_list , mixdev_node ) {
if ( mousedev - > opened_by_mixdev ) {
mousedev - > opened_by_mixdev = false ;
mousedev_close_device ( mousedev ) ;
}
2005-04-17 02:20:36 +04:00
}
}
2014-03-07 00:57:24 +04:00
mutex_unlock ( & mixdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
}
2007-08-30 08:22:24 +04:00
static void mousedev_attach_client ( struct mousedev * mousedev ,
struct mousedev_client * client )
{
spin_lock ( & mousedev - > client_lock ) ;
list_add_tail_rcu ( & client - > node , & mousedev - > client_list ) ;
spin_unlock ( & mousedev - > client_lock ) ;
}
static void mousedev_detach_client ( struct mousedev * mousedev ,
struct mousedev_client * client )
{
spin_lock ( & mousedev - > client_lock ) ;
list_del_rcu ( & client - > node ) ;
spin_unlock ( & mousedev - > client_lock ) ;
2007-10-13 23:46:55 +04:00
synchronize_rcu ( ) ;
2007-08-30 08:22:24 +04:00
}
2007-04-12 09:30:00 +04:00
static int mousedev_release ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
2007-04-12 09:30:00 +04:00
struct mousedev_client * client = file - > private_data ;
struct mousedev * mousedev = client - > mousedev ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
mousedev_detach_client ( mousedev , client ) ;
2007-04-12 09:30:00 +04:00
kfree ( client ) ;
2005-04-17 02:20:36 +04:00
2014-03-07 00:57:24 +04:00
mousedev - > close_device ( mousedev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-04-12 09:30:00 +04:00
static int mousedev_open ( struct inode * inode , struct file * file )
2005-04-17 02:20:36 +04:00
{
2007-04-12 09:30:00 +04:00
struct mousedev_client * client ;
2005-04-17 02:20:36 +04:00
struct mousedev * mousedev ;
2007-04-12 09:30:15 +04:00
int error ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if ( imajor ( inode ) = = MISC_MAJOR )
2012-10-08 20:07:24 +04:00
mousedev = mousedev_mix ;
2005-04-17 02:20:36 +04:00
else
# endif
2012-10-08 20:07:24 +04:00
mousedev = container_of ( inode - > i_cdev , struct mousedev , cdev ) ;
2005-04-17 02:20:36 +04:00
2007-04-12 09:30:00 +04:00
client = kzalloc ( sizeof ( struct mousedev_client ) , GFP_KERNEL ) ;
2012-10-08 20:07:24 +04:00
if ( ! client )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2007-04-12 09:30:00 +04:00
spin_lock_init ( & client - > packet_lock ) ;
client - > pos_x = xres / 2 ;
client - > pos_y = yres / 2 ;
client - > mousedev = mousedev ;
2007-08-30 08:22:24 +04:00
mousedev_attach_client ( mousedev , client ) ;
2005-04-17 02:20:36 +04:00
2014-03-07 00:57:24 +04:00
error = mousedev - > open_device ( mousedev ) ;
2007-08-30 08:22:24 +04:00
if ( error )
goto err_free_client ;
2005-04-17 02:20:36 +04:00
2007-04-12 09:30:00 +04:00
file - > private_data = client ;
2012-10-08 20:07:24 +04:00
nonseekable_open ( inode , file ) ;
2012-10-08 20:07:24 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
2007-06-15 07:32:24 +04:00
err_free_client :
2007-08-30 08:22:24 +04:00
mousedev_detach_client ( mousedev , client ) ;
2007-06-15 07:32:24 +04:00
kfree ( client ) ;
return error ;
2005-04-17 02:20:36 +04:00
}
2017-06-25 08:50:12 +03:00
static void mousedev_packet ( struct mousedev_client * client , u8 * ps2_data )
2005-04-17 02:20:36 +04:00
{
2007-08-30 08:22:24 +04:00
struct mousedev_motion * p = & client - > packets [ client - > tail ] ;
2017-06-25 08:50:12 +03:00
s8 dx , dy , dz ;
dx = clamp_val ( p - > dx , - 127 , 127 ) ;
p - > dx - = dx ;
dy = clamp_val ( p - > dy , - 127 , 127 ) ;
p - > dy - = dy ;
2005-04-17 02:20:36 +04:00
2017-06-25 08:50:12 +03:00
ps2_data [ 0 ] = BIT ( 3 ) ;
ps2_data [ 0 ] | = ( ( dx & BIT ( 7 ) ) > > 3 ) | ( ( dy & BIT ( 7 ) ) > > 2 ) ;
ps2_data [ 0 ] | = p - > buttons & 0x07 ;
ps2_data [ 1 ] = dx ;
ps2_data [ 2 ] = dy ;
2005-04-17 02:20:36 +04:00
2007-04-12 09:30:00 +04:00
switch ( client - > mode ) {
2007-08-30 08:22:24 +04:00
case MOUSEDEV_EMUL_EXPS :
2017-06-25 08:50:12 +03:00
dz = clamp_val ( p - > dz , - 7 , 7 ) ;
p - > dz - = dz ;
ps2_data [ 3 ] = ( dz & 0x0f ) | ( ( p - > buttons & 0x18 ) < < 1 ) ;
2007-08-30 08:22:24 +04:00
client - > bufsiz = 4 ;
break ;
case MOUSEDEV_EMUL_IMPS :
2017-06-25 08:50:12 +03:00
dz = clamp_val ( p - > dz , - 127 , 127 ) ;
p - > dz - = dz ;
ps2_data [ 0 ] | = ( ( p - > buttons & 0x10 ) > > 3 ) |
( ( p - > buttons & 0x08 ) > > 1 ) ;
ps2_data [ 3 ] = dz ;
2007-08-30 08:22:24 +04:00
client - > bufsiz = 4 ;
break ;
case MOUSEDEV_EMUL_PS2 :
default :
p - > dz = 0 ;
2017-06-25 08:50:12 +03:00
ps2_data [ 0 ] | = ( ( p - > buttons & 0x10 ) > > 3 ) |
( ( p - > buttons & 0x08 ) > > 1 ) ;
2007-08-30 08:22:24 +04:00
client - > bufsiz = 3 ;
break ;
2005-04-17 02:20:36 +04:00
}
if ( ! p - > dx & & ! p - > dy & & ! p - > dz ) {
2007-04-12 09:30:00 +04:00
if ( client - > tail = = client - > head ) {
client - > ready = 0 ;
client - > last_buttons = p - > buttons ;
2005-05-27 23:53:03 +04:00
} else
2007-04-12 09:30:00 +04:00
client - > tail = ( client - > tail + 1 ) % PACKET_QUEUE_LEN ;
2005-04-17 02:20:36 +04:00
}
}
2007-08-30 08:22:24 +04:00
static void mousedev_generate_response ( struct mousedev_client * client ,
int command )
{
client - > ps2 [ 0 ] = 0xfa ; /* ACK */
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
switch ( command ) {
case 0xeb : /* Poll */
mousedev_packet ( client , & client - > ps2 [ 1 ] ) ;
client - > bufsiz + + ; /* account for leading ACK */
break ;
case 0xf2 : /* Get ID */
switch ( client - > mode ) {
case MOUSEDEV_EMUL_PS2 :
client - > ps2 [ 1 ] = 0 ;
break ;
case MOUSEDEV_EMUL_IMPS :
client - > ps2 [ 1 ] = 3 ;
break ;
case MOUSEDEV_EMUL_EXPS :
client - > ps2 [ 1 ] = 4 ;
break ;
}
client - > bufsiz = 2 ;
break ;
case 0xe9 : /* Get info */
client - > ps2 [ 1 ] = 0x60 ; client - > ps2 [ 2 ] = 3 ; client - > ps2 [ 3 ] = 200 ;
client - > bufsiz = 4 ;
break ;
case 0xff : /* Reset */
client - > impsseq = client - > imexseq = 0 ;
client - > mode = MOUSEDEV_EMUL_PS2 ;
client - > ps2 [ 1 ] = 0xaa ; client - > ps2 [ 2 ] = 0x00 ;
client - > bufsiz = 3 ;
break ;
default :
client - > bufsiz = 1 ;
break ;
}
client - > buffer = client - > bufsiz ;
}
static ssize_t mousedev_write ( struct file * file , const char __user * buffer ,
size_t count , loff_t * ppos )
2005-04-17 02:20:36 +04:00
{
2007-04-12 09:30:00 +04:00
struct mousedev_client * client = file - > private_data ;
2005-04-17 02:20:36 +04:00
unsigned char c ;
unsigned int i ;
for ( i = 0 ; i < count ; i + + ) {
if ( get_user ( c , buffer + i ) )
return - EFAULT ;
2007-08-30 08:22:24 +04:00
spin_lock_irq ( & client - > packet_lock ) ;
2007-04-12 09:30:00 +04:00
if ( c = = mousedev_imex_seq [ client - > imexseq ] ) {
if ( + + client - > imexseq = = MOUSEDEV_SEQ_LEN ) {
client - > imexseq = 0 ;
client - > mode = MOUSEDEV_EMUL_EXPS ;
2005-04-17 02:20:36 +04:00
}
2006-06-26 09:48:47 +04:00
} else
2007-04-12 09:30:00 +04:00
client - > imexseq = 0 ;
2005-04-17 02:20:36 +04:00
2007-04-12 09:30:00 +04:00
if ( c = = mousedev_imps_seq [ client - > impsseq ] ) {
if ( + + client - > impsseq = = MOUSEDEV_SEQ_LEN ) {
client - > impsseq = 0 ;
client - > mode = MOUSEDEV_EMUL_IMPS ;
2005-04-17 02:20:36 +04:00
}
2006-06-26 09:48:47 +04:00
} else
2007-04-12 09:30:00 +04:00
client - > impsseq = 0 ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
mousedev_generate_response ( client , c ) ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
spin_unlock_irq ( & client - > packet_lock ) ;
2005-04-17 02:20:36 +04:00
}
2007-04-12 09:30:00 +04:00
kill_fasync ( & client - > fasync , SIGIO , POLL_IN ) ;
wake_up_interruptible ( & client - > mousedev - > wait ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-08-30 08:22:24 +04:00
static ssize_t mousedev_read ( struct file * file , char __user * buffer ,
size_t count , loff_t * ppos )
2005-04-17 02:20:36 +04:00
{
2007-04-12 09:30:00 +04:00
struct mousedev_client * client = file - > private_data ;
2007-08-30 08:22:24 +04:00
struct mousedev * mousedev = client - > mousedev ;
2017-06-25 08:50:12 +03:00
u8 data [ sizeof ( client - > ps2 ) ] ;
2005-04-17 02:20:36 +04:00
int retval = 0 ;
2007-08-30 08:22:24 +04:00
if ( ! client - > ready & & ! client - > buffer & & mousedev - > exist & &
( file - > f_flags & O_NONBLOCK ) )
2005-04-17 02:20:36 +04:00
return - EAGAIN ;
2007-08-30 08:22:24 +04:00
retval = wait_event_interruptible ( mousedev - > wait ,
! mousedev - > exist | | client - > ready | | client - > buffer ) ;
2005-04-17 02:20:36 +04:00
if ( retval )
return retval ;
2007-08-30 08:22:24 +04:00
if ( ! mousedev - > exist )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
2007-08-30 08:22:24 +04:00
spin_lock_irq ( & client - > packet_lock ) ;
2007-04-12 09:30:00 +04:00
if ( ! client - > buffer & & client - > ready ) {
mousedev_packet ( client , client - > ps2 ) ;
client - > buffer = client - > bufsiz ;
2005-04-17 02:20:36 +04:00
}
2007-04-12 09:30:00 +04:00
if ( count > client - > buffer )
count = client - > buffer ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
memcpy ( data , client - > ps2 + client - > bufsiz - client - > buffer , count ) ;
2007-04-12 09:30:00 +04:00
client - > buffer - = count ;
2005-04-17 02:20:36 +04:00
2007-08-30 08:22:24 +04:00
spin_unlock_irq ( & client - > packet_lock ) ;
if ( copy_to_user ( buffer , data , count ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
return count ;
}
/* No kernel lock - fine */
2017-07-03 13:39:46 +03:00
static __poll_t mousedev_poll ( struct file * file , poll_table * wait )
2005-04-17 02:20:36 +04:00
{
2007-04-12 09:30:00 +04:00
struct mousedev_client * client = file - > private_data ;
struct mousedev * mousedev = client - > mousedev ;
2017-07-03 13:39:46 +03:00
__poll_t mask ;
2006-06-26 09:48:47 +04:00
2007-04-12 09:30:00 +04:00
poll_wait ( file , & mousedev - > wait , wait ) ;
2010-07-16 10:27:56 +04:00
2018-02-12 01:34:03 +03:00
mask = mousedev - > exist ? EPOLLOUT | EPOLLWRNORM : EPOLLHUP | EPOLLERR ;
2010-07-16 10:27:56 +04:00
if ( client - > ready | | client - > buffer )
2018-02-12 01:34:03 +03:00
mask | = EPOLLIN | EPOLLRDNORM ;
2010-07-16 10:27:56 +04:00
return mask ;
2005-04-17 02:20:36 +04:00
}
2006-09-14 09:31:59 +04:00
static const struct file_operations mousedev_fops = {
2012-10-08 20:07:24 +04:00
. owner = THIS_MODULE ,
. read = mousedev_read ,
. write = mousedev_write ,
. poll = mousedev_poll ,
. open = mousedev_open ,
. release = mousedev_release ,
. fasync = mousedev_fasync ,
. llseek = noop_llseek ,
2005-04-17 02:20:36 +04:00
} ;
2007-08-30 08:22:24 +04:00
/*
* Mark device non - existent . This disables writes , ioctls and
* prevents new users from opening the device . Already posted
* blocking reads will stay , however new ones will fail .
*/
static void mousedev_mark_dead ( struct mousedev * mousedev )
{
mutex_lock ( & mousedev - > mutex ) ;
2010-07-16 10:27:36 +04:00
mousedev - > exist = false ;
2007-08-30 08:22:24 +04:00
mutex_unlock ( & mousedev - > mutex ) ;
}
/*
* Wake up users waiting for IO so they can disconnect from
* dead device .
*/
static void mousedev_hangup ( struct mousedev * mousedev )
{
struct mousedev_client * client ;
spin_lock ( & mousedev - > client_lock ) ;
list_for_each_entry ( client , & mousedev - > client_list , node )
kill_fasync ( & client - > fasync , SIGIO , POLL_HUP ) ;
spin_unlock ( & mousedev - > client_lock ) ;
wake_up_interruptible ( & mousedev - > wait ) ;
}
static void mousedev_cleanup ( struct mousedev * mousedev )
{
struct input_handle * handle = & mousedev - > handle ;
mousedev_mark_dead ( mousedev ) ;
mousedev_hangup ( mousedev ) ;
2012-10-08 20:07:24 +04:00
2007-08-30 08:22:24 +04:00
/* mousedev is marked dead so no one else accesses mousedev->open */
if ( mousedev - > open )
input_close_device ( handle ) ;
}
2012-10-08 20:07:24 +04:00
static int mousedev_reserve_minor ( bool mixdev )
{
int minor ;
if ( mixdev ) {
minor = input_get_new_minor ( MOUSEDEV_MIX , 1 , false ) ;
if ( minor < 0 )
pr_err ( " failed to reserve mixdev minor: %d \n " , minor ) ;
} else {
minor = input_get_new_minor ( MOUSEDEV_MINOR_BASE ,
MOUSEDEV_MINORS , true ) ;
if ( minor < 0 )
pr_err ( " failed to reserve new minor: %d \n " , minor ) ;
}
return minor ;
}
2007-06-15 07:32:24 +04:00
static struct mousedev * mousedev_create ( struct input_dev * dev ,
struct input_handler * handler ,
2012-10-08 20:07:24 +04:00
bool mixdev )
2005-04-17 02:20:36 +04:00
{
struct mousedev * mousedev ;
2012-10-08 20:07:24 +04:00
int minor ;
2007-04-12 09:29:46 +04:00
int error ;
2005-04-17 02:20:36 +04:00
2012-10-08 20:07:24 +04:00
minor = mousedev_reserve_minor ( mixdev ) ;
if ( minor < 0 ) {
error = minor ;
goto err_out ;
}
2007-04-12 09:29:46 +04:00
mousedev = kzalloc ( sizeof ( struct mousedev ) , GFP_KERNEL ) ;
2007-06-15 07:32:24 +04:00
if ( ! mousedev ) {
error = - ENOMEM ;
2012-10-08 20:07:24 +04:00
goto err_free_minor ;
2007-06-15 07:32:24 +04:00
}
2005-04-17 02:20:36 +04:00
2007-04-12 09:30:00 +04:00
INIT_LIST_HEAD ( & mousedev - > client_list ) ;
2007-04-12 09:29:46 +04:00
INIT_LIST_HEAD ( & mousedev - > mixdev_node ) ;
2007-08-30 08:22:24 +04:00
spin_lock_init ( & mousedev - > client_lock ) ;
mutex_init ( & mousedev - > mutex ) ;
lockdep_set_subclass ( & mousedev - > mutex ,
2012-10-08 20:07:24 +04:00
mixdev ? SINGLE_DEPTH_NESTING : 0 ) ;
2005-04-17 02:20:36 +04:00
init_waitqueue_head ( & mousedev - > wait ) ;
2012-10-08 20:07:24 +04:00
if ( mixdev ) {
2009-05-10 03:08:04 +04:00
dev_set_name ( & mousedev - > dev , " mice " ) ;
2014-03-07 00:57:24 +04:00
mousedev - > open_device = mixdev_open_devices ;
mousedev - > close_device = mixdev_close_devices ;
2012-10-08 20:07:24 +04:00
} else {
int dev_no = minor ;
/* Normalize device number if it falls into legacy range */
if ( dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS )
dev_no - = MOUSEDEV_MINOR_BASE ;
dev_set_name ( & mousedev - > dev , " mouse%d " , dev_no ) ;
2014-03-07 00:57:24 +04:00
mousedev - > open_device = mousedev_open_device ;
mousedev - > close_device = mousedev_close_device ;
2012-10-08 20:07:24 +04:00
}
2007-06-15 07:32:24 +04:00
2010-07-16 10:27:36 +04:00
mousedev - > exist = true ;
2008-04-01 08:22:53 +04:00
mousedev - > handle . dev = input_get_device ( dev ) ;
2009-05-10 03:08:04 +04:00
mousedev - > handle . name = dev_name ( & mousedev - > dev ) ;
2005-04-17 02:20:36 +04:00
mousedev - > handle . handler = handler ;
mousedev - > handle . private = mousedev ;
2007-06-15 07:32:24 +04:00
mousedev - > dev . class = & input_class ;
if ( dev )
mousedev - > dev . parent = & dev - > dev ;
2012-10-08 20:07:24 +04:00
mousedev - > dev . devt = MKDEV ( INPUT_MAJOR , minor ) ;
2007-06-15 07:32:24 +04:00
mousedev - > dev . release = mousedev_free ;
device_initialize ( & mousedev - > dev ) ;
2005-04-17 02:20:36 +04:00
2012-10-08 20:07:24 +04:00
if ( ! mixdev ) {
2007-08-30 08:22:24 +04:00
error = input_register_handle ( & mousedev - > handle ) ;
if ( error )
goto err_free_mousedev ;
}
2012-10-08 20:07:24 +04:00
cdev_init ( & mousedev - > cdev , & mousedev_fops ) ;
2007-04-12 09:29:46 +04:00
2017-03-17 21:48:11 +03:00
error = cdev_device_add ( & mousedev - > cdev , & mousedev - > dev ) ;
2007-06-15 07:32:24 +04:00
if ( error )
2007-08-30 08:22:24 +04:00
goto err_cleanup_mousedev ;
2007-06-15 07:32:24 +04:00
return mousedev ;
2007-08-30 08:22:24 +04:00
err_cleanup_mousedev :
mousedev_cleanup ( mousedev ) ;
2012-10-08 20:07:24 +04:00
if ( ! mixdev )
2007-08-30 08:22:24 +04:00
input_unregister_handle ( & mousedev - > handle ) ;
2007-06-15 07:32:24 +04:00
err_free_mousedev :
put_device ( & mousedev - > dev ) ;
2012-10-08 20:07:24 +04:00
err_free_minor :
input_free_minor ( minor ) ;
2007-06-15 07:32:24 +04:00
err_out :
return ERR_PTR ( error ) ;
}
static void mousedev_destroy ( struct mousedev * mousedev )
{
2017-03-17 21:48:11 +03:00
cdev_device_del ( & mousedev - > cdev , & mousedev - > dev ) ;
2007-08-30 08:22:24 +04:00
mousedev_cleanup ( mousedev ) ;
2012-10-08 20:07:24 +04:00
input_free_minor ( MINOR ( mousedev - > dev . devt ) ) ;
2014-03-07 00:57:24 +04:00
if ( mousedev ! = mousedev_mix )
2007-08-30 08:22:24 +04:00
input_unregister_handle ( & mousedev - > handle ) ;
put_device ( & mousedev - > dev ) ;
}
2007-06-15 07:32:24 +04:00
2007-08-30 08:22:24 +04:00
static int mixdev_add_device ( struct mousedev * mousedev )
{
int retval ;
retval = mutex_lock_interruptible ( & mousedev_mix - > mutex ) ;
if ( retval )
return retval ;
if ( mousedev_mix - > open ) {
retval = mousedev_open_device ( mousedev ) ;
if ( retval )
goto out ;
2012-10-08 20:07:24 +04:00
mousedev - > opened_by_mixdev = true ;
2007-04-12 09:29:46 +04:00
}
2005-10-28 09:25:43 +04:00
2007-08-30 08:22:24 +04:00
get_device ( & mousedev - > dev ) ;
list_add_tail ( & mousedev - > mixdev_node , & mousedev_mix_list ) ;
out :
mutex_unlock ( & mousedev_mix - > mutex ) ;
return retval ;
}
static void mixdev_remove_device ( struct mousedev * mousedev )
{
mutex_lock ( & mousedev_mix - > mutex ) ;
2012-10-08 20:07:24 +04:00
if ( mousedev - > opened_by_mixdev ) {
mousedev - > opened_by_mixdev = false ;
2007-08-30 08:22:24 +04:00
mousedev_close_device ( mousedev ) ;
}
list_del_init ( & mousedev - > mixdev_node ) ;
mutex_unlock ( & mousedev_mix - > mutex ) ;
2007-06-15 07:32:24 +04:00
put_device ( & mousedev - > dev ) ;
}
2007-08-30 08:22:24 +04:00
static int mousedev_connect ( struct input_handler * handler ,
struct input_dev * dev ,
2007-06-15 07:32:24 +04:00
const struct input_device_id * id )
{
struct mousedev * mousedev ;
int error ;
2012-10-08 20:07:24 +04:00
mousedev = mousedev_create ( dev , handler , false ) ;
2007-06-15 07:32:24 +04:00
if ( IS_ERR ( mousedev ) )
return PTR_ERR ( mousedev ) ;
2007-04-12 09:29:46 +04:00
2007-04-12 09:30:15 +04:00
error = mixdev_add_device ( mousedev ) ;
2007-08-30 08:22:24 +04:00
if ( error ) {
mousedev_destroy ( mousedev ) ;
return error ;
}
2005-04-17 02:20:36 +04:00
2007-04-12 09:29:46 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static void mousedev_disconnect ( struct input_handle * handle )
{
struct mousedev * mousedev = handle - > private ;
2007-04-12 09:30:15 +04:00
mixdev_remove_device ( mousedev ) ;
2007-06-15 07:32:24 +04:00
mousedev_destroy ( mousedev ) ;
2005-04-17 02:20:36 +04:00
}
2006-09-14 09:31:59 +04:00
static const struct input_device_id mousedev_ids [ ] = {
2005-04-17 02:20:36 +04:00
{
2007-08-30 08:22:24 +04:00
. flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_RELBIT ,
2007-10-19 10:40:32 +04:00
. evbit = { BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_REL ) } ,
. keybit = { [ BIT_WORD ( BTN_LEFT ) ] = BIT_MASK ( BTN_LEFT ) } ,
. relbit = { BIT_MASK ( REL_X ) | BIT_MASK ( REL_Y ) } ,
2007-08-30 08:22:24 +04:00
} , /* A mouse like device, at least one button,
two relative axes */
2005-04-17 02:20:36 +04:00
{
2007-08-30 08:22:24 +04:00
. flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_RELBIT ,
2007-10-19 10:40:32 +04:00
. evbit = { BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_REL ) } ,
. relbit = { BIT_MASK ( REL_WHEEL ) } ,
2005-04-17 02:20:36 +04:00
} , /* A separate scrollwheel */
{
2007-08-30 08:22:24 +04:00
. flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT ,
2007-10-19 10:40:32 +04:00
. evbit = { BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_ABS ) } ,
. keybit = { [ BIT_WORD ( BTN_TOUCH ) ] = BIT_MASK ( BTN_TOUCH ) } ,
. absbit = { BIT_MASK ( ABS_X ) | BIT_MASK ( ABS_Y ) } ,
2007-08-30 08:22:24 +04:00
} , /* A tablet like device, at least touch detection,
two absolute axes */
2005-04-17 02:20:36 +04:00
{
2007-08-30 08:22:24 +04:00
. flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT ,
2007-10-19 10:40:32 +04:00
. evbit = { BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_ABS ) } ,
. keybit = { [ BIT_WORD ( BTN_TOOL_FINGER ) ] =
BIT_MASK ( BTN_TOOL_FINGER ) } ,
. absbit = { BIT_MASK ( ABS_X ) | BIT_MASK ( ABS_Y ) |
BIT_MASK ( ABS_PRESSURE ) |
BIT_MASK ( ABS_TOOL_WIDTH ) } ,
2005-04-17 02:20:36 +04:00
} , /* A touchpad */
2008-01-17 20:01:04 +03:00
{
. flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT ,
2008-01-31 00:33:40 +03:00
. evbit = { BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_ABS ) } ,
2008-01-17 20:01:04 +03:00
. keybit = { [ BIT_WORD ( BTN_LEFT ) ] = BIT_MASK ( BTN_LEFT ) } ,
. absbit = { BIT_MASK ( ABS_X ) | BIT_MASK ( ABS_Y ) } ,
} , /* Mouse-like device with absolute X and Y but ordinary
clicks , like hp ILO2 High Performance mouse */
2005-04-17 02:20:36 +04:00
2007-04-12 09:30:00 +04:00
{ } , /* Terminating entry */
2005-04-17 02:20:36 +04:00
} ;
MODULE_DEVICE_TABLE ( input , mousedev_ids ) ;
static struct input_handler mousedev_handler = {
2012-10-08 20:07:24 +04:00
. event = mousedev_event ,
. connect = mousedev_connect ,
. disconnect = mousedev_disconnect ,
2012-10-08 20:07:24 +04:00
. legacy_minors = true ,
2012-10-08 20:07:24 +04:00
. minor = MOUSEDEV_MINOR_BASE ,
. name = " mousedev " ,
. id_table = mousedev_ids ,
2005-04-17 02:20:36 +04:00
} ;
# ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
2012-10-08 20:07:23 +04:00
# include <linux/miscdevice.h>
2005-04-17 02:20:36 +04:00
static struct miscdevice psaux_mouse = {
2012-10-08 20:07:23 +04:00
. minor = PSMOUSE_MINOR ,
. name = " psaux " ,
. fops = & mousedev_fops ,
2005-04-17 02:20:36 +04:00
} ;
2012-10-08 20:07:23 +04:00
static bool psaux_registered ;
static void __init mousedev_psaux_register ( void )
{
int error ;
error = misc_register ( & psaux_mouse ) ;
if ( error )
pr_warn ( " could not register psaux device, error: %d \n " ,
error ) ;
else
psaux_registered = true ;
}
static void __exit mousedev_psaux_unregister ( void )
{
if ( psaux_registered )
misc_deregister ( & psaux_mouse ) ;
}
# else
static inline void mousedev_psaux_register ( void ) { }
static inline void mousedev_psaux_unregister ( void ) { }
2005-04-17 02:20:36 +04:00
# endif
static int __init mousedev_init ( void )
{
2006-09-14 09:32:39 +04:00
int error ;
2012-10-08 20:07:24 +04:00
mousedev_mix = mousedev_create ( NULL , & mousedev_handler , true ) ;
2007-06-15 07:32:24 +04:00
if ( IS_ERR ( mousedev_mix ) )
return PTR_ERR ( mousedev_mix ) ;
2006-09-14 09:32:39 +04:00
error = input_register_handler ( & mousedev_handler ) ;
2007-06-15 07:32:24 +04:00
if ( error ) {
mousedev_destroy ( mousedev_mix ) ;
2006-09-14 09:32:39 +04:00
return error ;
}
2005-04-17 02:20:36 +04:00
2012-10-08 20:07:23 +04:00
mousedev_psaux_register ( ) ;
2005-04-17 02:20:36 +04:00
2010-11-30 10:33:07 +03:00
pr_info ( " PS/2 mouse device common for all mice \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void __exit mousedev_exit ( void )
{
2012-10-08 20:07:23 +04:00
mousedev_psaux_unregister ( ) ;
2005-04-17 02:20:36 +04:00
input_unregister_handler ( & mousedev_handler ) ;
2007-06-15 07:32:24 +04:00
mousedev_destroy ( mousedev_mix ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( mousedev_init ) ;
module_exit ( mousedev_exit ) ;