2006-12-12 20:18:30 +03:00
/*
* Apple Motion Sensor driver ( joystick emulation )
*
* Copyright ( C ) 2005 Stelian Pop ( stelian @ popies . net )
* Copyright ( C ) 2006 Michael Hanselmann ( linux - kernel @ hansmi . ch )
*
* 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 <linux/module.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/delay.h>
# include "ams.h"
2012-01-13 03:02:20 +04:00
static bool joystick ;
2008-10-17 19:51:12 +04:00
module_param ( joystick , bool , S_IRUGO ) ;
2006-12-12 20:18:30 +03:00
MODULE_PARM_DESC ( joystick , " Enable the input class device on module load " ) ;
2012-01-13 03:02:20 +04:00
static bool invert ;
2008-10-17 19:51:12 +04:00
module_param ( invert , bool , S_IWUSR | S_IRUGO ) ;
2006-12-12 20:18:30 +03:00
MODULE_PARM_DESC ( invert , " Invert input data on X and Y axis " ) ;
2008-10-17 19:51:12 +04:00
static DEFINE_MUTEX ( ams_input_mutex ) ;
2007-09-26 08:01:41 +04:00
static void ams_idev_poll ( struct input_polled_dev * dev )
2006-12-12 20:18:30 +03:00
{
2007-09-26 08:01:41 +04:00
struct input_dev * idev = dev - > input ;
2006-12-12 20:18:30 +03:00
s8 x , y , z ;
2007-09-26 08:01:41 +04:00
mutex_lock ( & ams_info . lock ) ;
2006-12-12 20:18:30 +03:00
2007-09-26 08:01:41 +04:00
ams_sensors ( & x , & y , & z ) ;
2006-12-12 20:18:30 +03:00
2007-09-26 08:01:41 +04:00
x - = ams_info . xcalib ;
y - = ams_info . ycalib ;
z - = ams_info . zcalib ;
2006-12-12 20:18:30 +03:00
2007-09-26 08:01:41 +04:00
input_report_abs ( idev , ABS_X , invert ? - x : x ) ;
input_report_abs ( idev , ABS_Y , invert ? - y : y ) ;
input_report_abs ( idev , ABS_Z , z ) ;
2006-12-12 20:18:30 +03:00
2007-09-26 08:01:41 +04:00
input_sync ( idev ) ;
2006-12-12 20:18:30 +03:00
2007-09-26 08:01:41 +04:00
mutex_unlock ( & ams_info . lock ) ;
2006-12-12 20:18:30 +03:00
}
/* Call with ams_info.lock held! */
2008-10-17 19:51:12 +04:00
static int ams_input_enable ( void )
2006-12-12 20:18:30 +03:00
{
2007-09-26 08:01:41 +04:00
struct input_dev * input ;
2006-12-12 20:18:30 +03:00
s8 x , y , z ;
2008-10-17 19:51:12 +04:00
int error ;
2006-12-12 20:18:30 +03:00
ams_sensors ( & x , & y , & z ) ;
ams_info . xcalib = x ;
ams_info . ycalib = y ;
ams_info . zcalib = z ;
2007-09-26 08:01:41 +04:00
ams_info . idev = input_allocate_polled_device ( ) ;
2006-12-12 20:18:30 +03:00
if ( ! ams_info . idev )
2008-10-17 19:51:12 +04:00
return - ENOMEM ;
2006-12-12 20:18:30 +03:00
2007-09-26 08:01:41 +04:00
ams_info . idev - > poll = ams_idev_poll ;
ams_info . idev - > poll_interval = 25 ;
input = ams_info . idev - > input ;
input - > name = " Apple Motion Sensor " ;
input - > id . bustype = ams_info . bustype ;
input - > id . vendor = 0 ;
input - > dev . parent = & ams_info . of_dev - > dev ;
2006-12-12 20:18:30 +03:00
2007-09-26 08:01:41 +04:00
input_set_abs_params ( input , ABS_X , - 50 , 50 , 3 , 0 ) ;
input_set_abs_params ( input , ABS_Y , - 50 , 50 , 3 , 0 ) ;
input_set_abs_params ( input , ABS_Z , - 50 , 50 , 3 , 0 ) ;
2006-12-12 20:18:30 +03:00
2007-09-26 08:01:41 +04:00
set_bit ( EV_ABS , input - > evbit ) ;
set_bit ( EV_KEY , input - > evbit ) ;
set_bit ( BTN_TOUCH , input - > keybit ) ;
2006-12-12 20:18:30 +03:00
2008-10-17 19:51:12 +04:00
error = input_register_polled_device ( ams_info . idev ) ;
if ( error ) {
2007-09-26 08:01:41 +04:00
input_free_polled_device ( ams_info . idev ) ;
2006-12-12 20:18:30 +03:00
ams_info . idev = NULL ;
2008-10-17 19:51:12 +04:00
return error ;
2006-12-12 20:18:30 +03:00
}
2008-10-17 19:51:12 +04:00
joystick = 1 ;
return 0 ;
2006-12-12 20:18:30 +03:00
}
static void ams_input_disable ( void )
{
if ( ams_info . idev ) {
2007-09-26 08:01:41 +04:00
input_unregister_polled_device ( ams_info . idev ) ;
input_free_polled_device ( ams_info . idev ) ;
2006-12-12 20:18:30 +03:00
ams_info . idev = NULL ;
}
2008-10-17 19:51:12 +04:00
joystick = 0 ;
2006-12-12 20:18:30 +03:00
}
static ssize_t ams_input_show_joystick ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
return sprintf ( buf , " %d \n " , joystick ) ;
}
static ssize_t ams_input_store_joystick ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
2008-10-17 19:51:12 +04:00
unsigned long enable ;
int error = 0 ;
2013-07-19 11:16:56 +04:00
int ret ;
2008-10-17 19:51:12 +04:00
2013-07-19 11:16:56 +04:00
ret = kstrtoul ( buf , 0 , & enable ) ;
if ( ret )
return ret ;
if ( enable > 1 )
2006-12-12 20:18:30 +03:00
return - EINVAL ;
2008-10-17 19:51:12 +04:00
mutex_lock ( & ams_input_mutex ) ;
2006-12-12 20:18:30 +03:00
2008-10-17 19:51:12 +04:00
if ( enable ! = joystick ) {
if ( enable )
error = ams_input_enable ( ) ;
else
ams_input_disable ( ) ;
}
2006-12-12 20:18:30 +03:00
2008-10-17 19:51:12 +04:00
mutex_unlock ( & ams_input_mutex ) ;
2006-12-12 20:18:30 +03:00
2008-10-17 19:51:12 +04:00
return error ? error : count ;
2006-12-12 20:18:30 +03:00
}
static DEVICE_ATTR ( joystick , S_IRUGO | S_IWUSR ,
ams_input_show_joystick , ams_input_store_joystick ) ;
int ams_input_init ( void )
{
2008-10-17 19:51:12 +04:00
if ( joystick )
2006-12-12 20:18:30 +03:00
ams_input_enable ( ) ;
2008-10-17 19:51:12 +04:00
return device_create_file ( & ams_info . of_dev - > dev , & dev_attr_joystick ) ;
2006-12-12 20:18:30 +03:00
}
2007-02-09 19:38:50 +03:00
void ams_input_exit ( void )
2006-12-12 20:18:30 +03:00
{
device_remove_file ( & ams_info . of_dev - > dev , & dev_attr_joystick ) ;
2008-10-17 19:51:12 +04:00
mutex_lock ( & ams_input_mutex ) ;
ams_input_disable ( ) ;
mutex_unlock ( & ams_input_mutex ) ;
2006-12-12 20:18:30 +03:00
}