2005-09-08 12:19:48 +04:00
/*
2006-04-20 01:36:40 +04:00
* Apple USB Touchpad ( for post - February 2005 PowerBooks and MacBooks ) driver
2005-09-08 12:19:48 +04:00
*
* Copyright ( C ) 2001 - 2004 Greg Kroah - Hartman ( greg @ kroah . com )
2008-05-06 07:56:55 +04:00
* Copyright ( C ) 2005 - 2008 Johannes Berg ( johannes @ sipsolutions . net )
2008-10-29 06:20:46 +03:00
* Copyright ( C ) 2005 - 2008 Stelian Pop ( stelian @ popies . net )
2005-09-08 12:19:48 +04:00
* Copyright ( C ) 2005 Frank Arnold ( frank @ scirocco - 5 v - turbo . de )
* Copyright ( C ) 2005 Peter Osterlund ( petero2 @ telia . com )
2005-12-21 08:50:23 +03:00
* Copyright ( C ) 2005 Michael Hanselmann ( linux - kernel @ hansmi . ch )
2006-04-20 01:36:40 +04:00
* Copyright ( C ) 2006 Nicolas Boichat ( nicolas @ boichat . ch )
2008-05-06 07:56:55 +04:00
* Copyright ( C ) 2007 - 2008 Sven Anders ( anders @ anduras . de )
2005-09-08 12:19:48 +04:00
*
* Thanks to Alex Harper < basilisk @ foobox . net > for his inputs .
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
*/
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/module.h>
2006-06-13 21:04:34 +04:00
# include <linux/usb/input.h>
2005-09-08 12:19:48 +04:00
2008-10-29 06:20:46 +03:00
/*
* Note : We try to keep the touchpad aspect ratio while still doing only
* simple arithmetics :
* 0 < = x < = ( xsensors - 1 ) * xfact
* 0 < = y < = ( ysensors - 1 ) * yfact
*/
struct atp_info {
int xsensors ; /* number of X sensors */
int xsensors_17 ; /* 17" models have more sensors */
int ysensors ; /* number of Y sensors */
int xfact ; /* X multiplication factor */
int yfact ; /* Y multiplication factor */
int datalen ; /* size of USB transfers */
void ( * callback ) ( struct urb * ) ; /* callback function */
2014-03-27 01:10:43 +04:00
int fuzz ; /* fuzz touchpad generates */
2008-10-29 06:20:46 +03:00
} ;
static void atp_complete_geyser_1_2 ( struct urb * urb ) ;
static void atp_complete_geyser_3_4 ( struct urb * urb ) ;
static const struct atp_info fountain_info = {
. xsensors = 16 ,
. xsensors_17 = 26 ,
. ysensors = 16 ,
. xfact = 64 ,
. yfact = 43 ,
. datalen = 81 ,
. callback = atp_complete_geyser_1_2 ,
2014-03-27 01:10:43 +04:00
. fuzz = 16 ,
2008-10-29 06:20:46 +03:00
} ;
static const struct atp_info geyser1_info = {
. xsensors = 16 ,
. xsensors_17 = 26 ,
. ysensors = 16 ,
. xfact = 64 ,
. yfact = 43 ,
. datalen = 81 ,
. callback = atp_complete_geyser_1_2 ,
2014-03-27 01:10:43 +04:00
. fuzz = 16 ,
2008-10-29 06:20:46 +03:00
} ;
static const struct atp_info geyser2_info = {
. xsensors = 15 ,
. xsensors_17 = 20 ,
. ysensors = 9 ,
. xfact = 64 ,
. yfact = 43 ,
. datalen = 64 ,
. callback = atp_complete_geyser_1_2 ,
2014-03-27 01:10:43 +04:00
. fuzz = 0 ,
2008-10-29 06:20:46 +03:00
} ;
static const struct atp_info geyser3_info = {
. xsensors = 20 ,
. ysensors = 10 ,
. xfact = 64 ,
. yfact = 64 ,
. datalen = 64 ,
. callback = atp_complete_geyser_3_4 ,
2014-03-27 01:10:43 +04:00
. fuzz = 0 ,
2008-05-06 07:57:10 +04:00
} ;
2008-04-02 18:02:06 +04:00
2008-10-29 06:20:46 +03:00
static const struct atp_info geyser4_info = {
. xsensors = 20 ,
. ysensors = 10 ,
. xfact = 64 ,
. yfact = 64 ,
. datalen = 64 ,
. callback = atp_complete_geyser_3_4 ,
2014-03-27 01:10:43 +04:00
. fuzz = 0 ,
2008-10-29 06:20:46 +03:00
} ;
# define ATP_DEVICE(prod, info) \
2008-05-06 07:57:10 +04:00
{ \
2005-09-15 11:01:47 +04:00
. match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
2005-09-08 12:19:48 +04:00
USB_DEVICE_ID_MATCH_INT_CLASS | \
USB_DEVICE_ID_MATCH_INT_PROTOCOL , \
2008-05-06 07:57:10 +04:00
. idVendor = 0x05ac , /* Apple */ \
2005-09-08 12:19:48 +04:00
. idProduct = ( prod ) , \
. bInterfaceClass = 0x03 , \
2008-05-06 07:57:10 +04:00
. bInterfaceProtocol = 0x02 , \
2008-10-29 06:20:46 +03:00
. driver_info = ( unsigned long ) & info , \
2008-05-06 07:57:10 +04:00
}
/*
* Table of devices ( Product IDs ) that work with this driver .
* ( The names come from Info . plist in AppleUSBTrackpad . kext ,
* According to Info . plist Geyser IV is the same as Geyser III . )
*/
2005-09-08 12:19:48 +04:00
2008-10-29 06:20:46 +03:00
static struct usb_device_id atp_table [ ] = {
2008-05-06 07:56:55 +04:00
/* PowerBooks Feb 2005, iBooks G4 */
2008-10-29 06:20:46 +03:00
ATP_DEVICE ( 0x020e , fountain_info ) , /* FOUNTAIN ANSI */
ATP_DEVICE ( 0x020f , fountain_info ) , /* FOUNTAIN ISO */
ATP_DEVICE ( 0x030a , fountain_info ) , /* FOUNTAIN TP ONLY */
ATP_DEVICE ( 0x030b , geyser1_info ) , /* GEYSER 1 TP ONLY */
2005-12-21 08:50:23 +03:00
/* PowerBooks Oct 2005 */
2008-10-29 06:20:46 +03:00
ATP_DEVICE ( 0x0214 , geyser2_info ) , /* GEYSER 2 ANSI */
ATP_DEVICE ( 0x0215 , geyser2_info ) , /* GEYSER 2 ISO */
ATP_DEVICE ( 0x0216 , geyser2_info ) , /* GEYSER 2 JIS */
2005-12-21 08:50:23 +03:00
2006-11-17 09:06:13 +03:00
/* Core Duo MacBook & MacBook Pro */
2008-10-29 06:20:46 +03:00
ATP_DEVICE ( 0x0217 , geyser3_info ) , /* GEYSER 3 ANSI */
ATP_DEVICE ( 0x0218 , geyser3_info ) , /* GEYSER 3 ISO */
ATP_DEVICE ( 0x0219 , geyser3_info ) , /* GEYSER 3 JIS */
2006-04-20 01:36:40 +04:00
2006-11-17 09:06:13 +03:00
/* Core2 Duo MacBook & MacBook Pro */
2008-10-29 06:20:46 +03:00
ATP_DEVICE ( 0x021a , geyser4_info ) , /* GEYSER 4 ANSI */
ATP_DEVICE ( 0x021b , geyser4_info ) , /* GEYSER 4 ISO */
ATP_DEVICE ( 0x021c , geyser4_info ) , /* GEYSER 4 JIS */
2006-11-17 09:06:13 +03:00
2008-05-06 07:56:55 +04:00
/* Core2 Duo MacBook3,1 */
2008-10-29 06:20:46 +03:00
ATP_DEVICE ( 0x0229 , geyser4_info ) , /* GEYSER 4 HF ANSI */
ATP_DEVICE ( 0x022a , geyser4_info ) , /* GEYSER 4 HF ISO */
ATP_DEVICE ( 0x022b , geyser4_info ) , /* GEYSER 4 HF JIS */
2008-04-02 18:02:06 +04:00
2005-12-21 08:50:23 +03:00
/* Terminating entry */
{ }
2005-09-08 12:19:48 +04:00
} ;
2008-05-06 07:56:55 +04:00
MODULE_DEVICE_TABLE ( usb , atp_table ) ;
2005-09-08 12:19:48 +04:00
2008-10-29 06:20:46 +03:00
/* maximum number of sensors */
2005-09-08 12:19:48 +04:00
# define ATP_XSENSORS 26
# define ATP_YSENSORS 16
2014-03-31 10:21:21 +04:00
/*
* The largest possible bank of sensors with additional buffer of 4 extra values
* on either side , for an array of smoothed sensor values .
*/
# define ATP_SMOOTHSIZE 34
2005-09-08 12:19:48 +04:00
/* maximum pressure this driver will report */
# define ATP_PRESSURE 300
/*
* Threshold for the touchpad sensors . Any change less than ATP_THRESHOLD is
* ignored .
*/
2014-03-31 10:21:21 +04:00
# define ATP_THRESHOLD 5
/*
* How far we ' ll bitshift our sensor values before averaging them . Mitigates
* rounding errors .
*/
# define ATP_SCALE 12
2005-09-08 12:19:48 +04:00
2007-11-02 05:13:32 +03:00
/* Geyser initialization constants */
# define ATP_GEYSER_MODE_READ_REQUEST_ID 1
# define ATP_GEYSER_MODE_WRITE_REQUEST_ID 9
# define ATP_GEYSER_MODE_REQUEST_VALUE 0x300
# define ATP_GEYSER_MODE_REQUEST_INDEX 0
# define ATP_GEYSER_MODE_VENDOR_VALUE 0x04
2006-04-20 01:36:40 +04:00
2008-08-09 00:31:33 +04:00
/**
* enum atp_status_bits - status bit meanings
*
* These constants represent the meaning of the status bits .
* ( only Geyser 3 / 4 )
*
* @ ATP_STATUS_BUTTON : The button was pressed
* @ ATP_STATUS_BASE_UPDATE : Update of the base values ( untouched pad )
* @ ATP_STATUS_FROM_RESET : Reset previously performed
*/
enum atp_status_bits {
ATP_STATUS_BUTTON = BIT ( 0 ) ,
ATP_STATUS_BASE_UPDATE = BIT ( 2 ) ,
ATP_STATUS_FROM_RESET = BIT ( 4 ) ,
} ;
2005-09-08 12:19:48 +04:00
/* Structure to hold all of our device specific stuff */
struct atp {
2005-09-15 11:01:47 +04:00
char phys [ 64 ] ;
2008-05-06 07:56:55 +04:00
struct usb_device * udev ; /* usb device */
2012-05-05 02:33:01 +04:00
struct usb_interface * intf ; /* usb interface */
2008-05-06 07:56:55 +04:00
struct urb * urb ; /* usb request block */
2008-08-09 00:31:33 +04:00
u8 * data ; /* transferred data */
2008-05-06 07:56:55 +04:00
struct input_dev * input ; /* input dev */
2008-10-29 06:20:46 +03:00
const struct atp_info * info ; /* touchpad model */
2008-05-06 07:56:55 +04:00
bool open ;
bool valid ; /* are the samples valid? */
bool size_detect_done ;
bool overflow_warned ;
2014-03-31 10:37:05 +04:00
int fingers_old ; /* last reported finger count */
2005-09-08 12:19:48 +04:00
int x_old ; /* last reported x/y, */
int y_old ; /* used for smoothing */
2010-08-09 07:48:08 +04:00
signed char xy_cur [ ATP_XSENSORS + ATP_YSENSORS ] ;
signed char xy_old [ ATP_XSENSORS + ATP_YSENSORS ] ;
2005-09-08 12:19:48 +04:00
int xy_acc [ ATP_XSENSORS + ATP_YSENSORS ] ;
2014-03-31 10:21:21 +04:00
int smooth [ ATP_SMOOTHSIZE ] ;
int smooth_tmp [ ATP_SMOOTHSIZE ] ;
2008-05-06 07:56:55 +04:00
int idlecount ; /* number of empty packets */
struct work_struct work ;
2005-09-08 12:19:48 +04:00
} ;
# define dbg_dump(msg, tab) \
if ( debug > 1 ) { \
2008-05-06 07:56:55 +04:00
int __i ; \
printk ( KERN_DEBUG " appletouch: %s " , msg ) ; \
for ( __i = 0 ; __i < ATP_XSENSORS + ATP_YSENSORS ; __i + + ) \
printk ( " %02x " , tab [ __i ] ) ; \
2005-09-15 11:01:47 +04:00
printk ( " \n " ) ; \
2005-09-08 12:19:48 +04:00
}
2005-09-15 11:01:47 +04:00
# define dprintk(format, a...) \
2005-09-08 12:19:48 +04:00
do { \
2008-05-06 07:56:55 +04:00
if ( debug ) \
printk ( KERN_DEBUG format , # # a ) ; \
2005-09-08 12:19:48 +04:00
} while ( 0 )
2008-05-06 07:56:55 +04:00
MODULE_AUTHOR ( " Johannes Berg " ) ;
MODULE_AUTHOR ( " Stelian Pop " ) ;
MODULE_AUTHOR ( " Frank Arnold " ) ;
MODULE_AUTHOR ( " Michael Hanselmann " ) ;
MODULE_AUTHOR ( " Sven Anders " ) ;
MODULE_DESCRIPTION ( " Apple PowerBook and MacBook USB touchpad driver " ) ;
2005-09-08 12:19:48 +04:00
MODULE_LICENSE ( " GPL " ) ;
2006-11-17 09:05:58 +03:00
/*
* Make the threshold a module parameter
*/
static int threshold = ATP_THRESHOLD ;
module_param ( threshold , int , 0644 ) ;
2008-05-06 07:56:55 +04:00
MODULE_PARM_DESC ( threshold , " Discard any change in data from a sensor "
" (the trackpad has many of these sensors) "
" less than this value. " ) ;
2006-11-17 09:05:58 +03:00
2008-05-06 07:56:55 +04:00
static int debug ;
2005-09-08 12:19:48 +04:00
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " Activate debugging output " ) ;
2007-07-20 08:29:32 +04:00
/*
2007-11-02 05:13:32 +03:00
* By default newer Geyser devices send standard USB HID mouse
2007-07-20 08:29:32 +04:00
* packets ( Report ID 2 ) . This code changes device mode , so it
* sends raw sensor reports ( Report ID 5 ) .
*/
2012-05-02 04:56:47 +04:00
static int atp_geyser_init ( struct atp * dev )
2007-07-20 08:29:32 +04:00
{
2012-05-02 04:56:47 +04:00
struct usb_device * udev = dev - > udev ;
2009-04-28 18:49:53 +04:00
char * data ;
2007-07-20 08:29:32 +04:00
int size ;
2008-05-06 07:56:55 +04:00
int i ;
2009-04-28 18:49:53 +04:00
int ret ;
data = kmalloc ( 8 , GFP_KERNEL ) ;
if ( ! data ) {
2012-05-05 02:33:01 +04:00
dev_err ( & dev - > intf - > dev , " Out of memory \n " ) ;
2009-04-28 18:49:53 +04:00
return - ENOMEM ;
}
2007-07-20 08:29:32 +04:00
size = usb_control_msg ( udev , usb_rcvctrlpipe ( udev , 0 ) ,
2007-11-02 05:13:32 +03:00
ATP_GEYSER_MODE_READ_REQUEST_ID ,
2007-07-20 08:29:32 +04:00
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE ,
2007-11-02 05:13:32 +03:00
ATP_GEYSER_MODE_REQUEST_VALUE ,
2009-04-28 18:49:53 +04:00
ATP_GEYSER_MODE_REQUEST_INDEX , data , 8 , 5000 ) ;
2007-07-20 08:29:32 +04:00
if ( size ! = 8 ) {
2008-05-06 07:56:55 +04:00
dprintk ( " atp_geyser_init: read error \n " ) ;
for ( i = 0 ; i < 8 ; i + + )
dprintk ( " appletouch[%d]: %d \n " , i , data [ i ] ) ;
2012-05-05 02:33:01 +04:00
dev_err ( & dev - > intf - > dev , " Failed to read mode from device. \n " ) ;
2009-04-28 18:49:53 +04:00
ret = - EIO ;
goto out_free ;
2007-07-20 08:29:32 +04:00
}
/* Apply the mode switch */
2007-11-02 05:13:32 +03:00
data [ 0 ] = ATP_GEYSER_MODE_VENDOR_VALUE ;
2007-07-20 08:29:32 +04:00
size = usb_control_msg ( udev , usb_sndctrlpipe ( udev , 0 ) ,
2007-11-02 05:13:32 +03:00
ATP_GEYSER_MODE_WRITE_REQUEST_ID ,
2007-07-20 08:29:32 +04:00
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE ,
2007-11-02 05:13:32 +03:00
ATP_GEYSER_MODE_REQUEST_VALUE ,
2009-04-28 18:49:53 +04:00
ATP_GEYSER_MODE_REQUEST_INDEX , data , 8 , 5000 ) ;
2007-07-20 08:29:32 +04:00
if ( size ! = 8 ) {
2008-05-06 07:56:55 +04:00
dprintk ( " atp_geyser_init: write error \n " ) ;
for ( i = 0 ; i < 8 ; i + + )
dprintk ( " appletouch[%d]: %d \n " , i , data [ i ] ) ;
2012-05-05 02:33:01 +04:00
dev_err ( & dev - > intf - > dev , " Failed to request geyser raw mode \n " ) ;
2009-04-28 18:49:53 +04:00
ret = - EIO ;
goto out_free ;
2007-07-20 08:29:32 +04:00
}
2009-04-28 18:49:53 +04:00
ret = 0 ;
out_free :
kfree ( data ) ;
return ret ;
2007-07-20 08:29:32 +04:00
}
2007-11-02 05:13:32 +03:00
/*
* Reinitialise the device . This usually stops stream of empty packets
* coming from it .
*/
2007-07-20 08:29:32 +04:00
static void atp_reinit ( struct work_struct * work )
{
struct atp * dev = container_of ( work , struct atp , work ) ;
2007-11-02 05:13:32 +03:00
int retval ;
2007-07-20 08:29:32 +04:00
2008-05-06 07:56:55 +04:00
dprintk ( " appletouch: putting appletouch to sleep (reinit) \n " ) ;
2012-05-02 04:56:47 +04:00
atp_geyser_init ( dev ) ;
2007-11-02 05:13:32 +03:00
retval = usb_submit_urb ( dev - > urb , GFP_ATOMIC ) ;
2008-05-06 07:56:55 +04:00
if ( retval )
2012-05-05 02:33:01 +04:00
dev_err ( & dev - > intf - > dev ,
2012-04-26 01:48:31 +04:00
" atp_reinit: usb_submit_urb failed with error %d \n " ,
retval ) ;
2007-07-20 08:29:32 +04:00
}
2014-03-31 10:21:21 +04:00
static int atp_calculate_abs ( struct atp * dev , int offset , int nb_sensors ,
int fact , int * z , int * fingers )
2005-09-08 12:19:48 +04:00
{
2014-03-31 10:21:21 +04:00
int i , pass ;
/*
* Use offset to point xy_sensors at the first value in dev - > xy_acc
* for whichever dimension we ' re looking at this particular go - round .
*/
int * xy_sensors = dev - > xy_acc + offset ;
2005-09-08 12:19:48 +04:00
/* values to calculate mean */
int pcum = 0 , psum = 0 ;
2006-11-17 09:05:58 +03:00
int is_increasing = 0 ;
2005-09-08 12:19:48 +04:00
* fingers = 0 ;
for ( i = 0 ; i < nb_sensors ; i + + ) {
2006-11-17 09:05:58 +03:00
if ( xy_sensors [ i ] < threshold ) {
if ( is_increasing )
is_increasing = 0 ;
/*
* Makes the finger detection more versatile . For example ,
* two fingers with no gap will be detected . Also , my
* tests show it less likely to have intermittent loss
* of multiple finger readings while moving around ( scrolling ) .
*
* Changes the multiple finger detection to counting humps on
* sensors ( transitions from nonincreasing to increasing )
* instead of counting transitions from low sensors ( no
* finger reading ) to high sensors ( finger above
* sensor )
*
* - Jason Parekh < jasonparekh @ gmail . com >
*/
2014-03-31 10:21:21 +04:00
} else if ( i < 1 | |
2008-05-06 07:56:55 +04:00
( ! is_increasing & & xy_sensors [ i - 1 ] < xy_sensors [ i ] ) ) {
2005-09-08 12:19:48 +04:00
( * fingers ) + + ;
2006-11-17 09:05:58 +03:00
is_increasing = 1 ;
2009-06-03 18:29:39 +04:00
} else if ( i > 0 & & ( xy_sensors [ i - 1 ] - xy_sensors [ i ] > threshold ) ) {
2006-11-17 09:05:58 +03:00
is_increasing = 0 ;
}
2014-03-31 10:21:21 +04:00
}
if ( * fingers < 1 ) /* No need to continue if no fingers are found. */
return 0 ;
/*
* Use a smoothed version of sensor data for movement calculations , to
* combat noise without needing to rely so heavily on a threshold .
* This improves tracking .
*
* The smoothed array is bigger than the original so that the smoothing
* doesn ' t result in edge values being truncated .
*/
memset ( dev - > smooth , 0 , 4 * sizeof ( dev - > smooth [ 0 ] ) ) ;
/* Pull base values, scaled up to help avoid truncation errors. */
for ( i = 0 ; i < nb_sensors ; i + + )
dev - > smooth [ i + 4 ] = xy_sensors [ i ] < < ATP_SCALE ;
memset ( & dev - > smooth [ nb_sensors + 4 ] , 0 , 4 * sizeof ( dev - > smooth [ 0 ] ) ) ;
for ( pass = 0 ; pass < 4 ; pass + + ) {
/* Handle edge. */
dev - > smooth_tmp [ 0 ] = ( dev - > smooth [ 0 ] + dev - > smooth [ 1 ] ) / 2 ;
2006-11-17 09:05:58 +03:00
2014-03-31 10:21:21 +04:00
/* Average values with neighbors. */
for ( i = 1 ; i < nb_sensors + 7 ; i + + )
dev - > smooth_tmp [ i ] = ( dev - > smooth [ i - 1 ] +
dev - > smooth [ i ] * 2 +
dev - > smooth [ i + 1 ] ) / 4 ;
/* Handle other edge. */
dev - > smooth_tmp [ i ] = ( dev - > smooth [ i - 1 ] + dev - > smooth [ i ] ) / 2 ;
memcpy ( dev - > smooth , dev - > smooth_tmp , sizeof ( dev - > smooth ) ) ;
}
for ( i = 0 ; i < nb_sensors + 8 ; i + + ) {
2006-11-17 09:05:58 +03:00
/*
2014-03-31 10:21:21 +04:00
* Skip values if they ' re small enough to be truncated to 0
* by scale . Mostly noise .
2006-11-17 09:05:58 +03:00
*/
2014-03-31 10:21:21 +04:00
if ( ( dev - > smooth [ i ] > > ATP_SCALE ) > 0 ) {
pcum + = dev - > smooth [ i ] * i ;
psum + = dev - > smooth [ i ] ;
}
2005-09-08 12:19:48 +04:00
}
if ( psum > 0 ) {
2014-03-31 10:21:21 +04:00
* z = psum > > ATP_SCALE ; /* Scale down pressure output. */
2005-09-08 12:19:48 +04:00
return pcum * fact / psum ;
}
return 0 ;
}
static inline void atp_report_fingers ( struct input_dev * input , int fingers )
{
input_report_key ( input , BTN_TOOL_FINGER , fingers = = 1 ) ;
input_report_key ( input , BTN_TOOL_DOUBLETAP , fingers = = 2 ) ;
input_report_key ( input , BTN_TOOL_TRIPLETAP , fingers > 2 ) ;
}
2008-08-09 00:31:31 +04:00
/* Check URB status and for correct length of data package */
# define ATP_URB_STATUS_SUCCESS 0
# define ATP_URB_STATUS_ERROR 1
# define ATP_URB_STATUS_ERROR_FATAL 2
static int atp_status_check ( struct urb * urb )
2005-09-08 12:19:48 +04:00
{
struct atp * dev = urb - > context ;
2012-05-05 02:33:01 +04:00
struct usb_interface * intf = dev - > intf ;
2005-09-08 12:19:48 +04:00
switch ( urb - > status ) {
case 0 :
/* success */
break ;
2005-12-21 08:50:23 +03:00
case - EOVERFLOW :
2008-05-06 07:56:55 +04:00
if ( ! dev - > overflow_warned ) {
2012-05-05 02:33:01 +04:00
dev_warn ( & intf - > dev ,
2012-05-02 08:33:04 +04:00
" appletouch: OVERFLOW with data length %d, actual length is %d \n " ,
2008-10-29 06:20:46 +03:00
dev - > info - > datalen , dev - > urb - > actual_length ) ;
2008-05-06 07:56:55 +04:00
dev - > overflow_warned = true ;
2005-12-21 08:50:23 +03:00
}
2005-09-08 12:19:48 +04:00
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
/* This urb is terminated, clean up */
2012-05-05 02:33:01 +04:00
dev_dbg ( & intf - > dev ,
2012-05-02 08:33:04 +04:00
" atp_complete: urb shutting down with status: %d \n " ,
urb - > status ) ;
2008-08-09 00:31:31 +04:00
return ATP_URB_STATUS_ERROR_FATAL ;
2005-09-08 12:19:48 +04:00
default :
2012-05-05 02:33:01 +04:00
dev_dbg ( & intf - > dev ,
2012-05-02 08:33:04 +04:00
" atp_complete: nonzero urb status received: %d \n " ,
urb - > status ) ;
2008-08-09 00:31:31 +04:00
return ATP_URB_STATUS_ERROR ;
2005-09-08 12:19:48 +04:00
}
/* drop incomplete datasets */
2008-10-29 06:20:46 +03:00
if ( dev - > urb - > actual_length ! = dev - > info - > datalen ) {
2006-04-20 01:36:40 +04:00
dprintk ( " appletouch: incomplete data package "
" (first byte: %d, length: %d). \n " ,
dev - > data [ 0 ] , dev - > urb - > actual_length ) ;
2008-08-09 00:31:31 +04:00
return ATP_URB_STATUS_ERROR ;
2005-09-08 12:19:48 +04:00
}
2008-08-09 00:31:31 +04:00
return ATP_URB_STATUS_SUCCESS ;
}
2006-04-20 01:36:40 +04:00
2008-10-29 06:20:46 +03:00
static void atp_detect_size ( struct atp * dev )
{
int i ;
/* 17" Powerbooks have extra X sensors */
for ( i = dev - > info - > xsensors ; i < ATP_XSENSORS ; i + + ) {
if ( dev - > xy_cur [ i ] ) {
2012-05-05 02:33:01 +04:00
dev_info ( & dev - > intf - > dev ,
2012-05-02 08:33:04 +04:00
" appletouch: 17 \" model detected. \n " ) ;
2008-10-29 06:20:46 +03:00
input_set_abs_params ( dev - > input , ABS_X , 0 ,
( dev - > info - > xsensors_17 - 1 ) *
dev - > info - > xfact - 1 ,
2014-03-27 01:10:43 +04:00
dev - > info - > fuzz , 0 ) ;
2008-10-29 06:20:46 +03:00
break ;
}
}
}
2008-08-09 00:31:31 +04:00
/*
* USB interrupt callback functions
*/
2006-04-20 01:36:40 +04:00
2008-08-09 00:31:31 +04:00
/* Interrupt function for older touchpads: FOUNTAIN/GEYSER1/GEYSER2 */
static void atp_complete_geyser_1_2 ( struct urb * urb )
{
int x , y , x_z , y_z , x_f , y_f ;
int retval , i , j ;
2014-03-31 10:37:05 +04:00
int key , fingers ;
2008-08-09 00:31:31 +04:00
struct atp * dev = urb - > context ;
int status = atp_status_check ( urb ) ;
if ( status = = ATP_URB_STATUS_ERROR_FATAL )
return ;
else if ( status = = ATP_URB_STATUS_ERROR )
goto exit ;
/* reorder the sensors values */
2008-10-29 06:20:46 +03:00
if ( dev - > info = = & geyser2_info ) {
2005-12-21 08:50:23 +03:00
memset ( dev - > xy_cur , 0 , sizeof ( dev - > xy_cur ) ) ;
/*
* The values are laid out like this :
* Y1 , Y2 , - , Y3 , Y4 , - , . . . , X1 , X2 , - , X3 , X4 , - , . . .
* ' - ' is an unused value .
*/
/* read X values */
for ( i = 0 , j = 19 ; i < 20 ; i + = 2 , j + = 3 ) {
dev - > xy_cur [ i ] = dev - > data [ j ] ;
dev - > xy_cur [ i + 1 ] = dev - > data [ j + 1 ] ;
}
/* read Y values */
for ( i = 0 , j = 1 ; i < 9 ; i + = 2 , j + = 3 ) {
dev - > xy_cur [ ATP_XSENSORS + i ] = dev - > data [ j ] ;
dev - > xy_cur [ ATP_XSENSORS + i + 1 ] = dev - > data [ j + 1 ] ;
}
} else {
for ( i = 0 ; i < 8 ; i + + ) {
/* X values */
2008-05-06 07:56:55 +04:00
dev - > xy_cur [ i + 0 ] = dev - > data [ 5 * i + 2 ] ;
2005-12-21 08:50:23 +03:00
dev - > xy_cur [ i + 8 ] = dev - > data [ 5 * i + 4 ] ;
dev - > xy_cur [ i + 16 ] = dev - > data [ 5 * i + 42 ] ;
if ( i < 2 )
dev - > xy_cur [ i + 24 ] = dev - > data [ 5 * i + 44 ] ;
/* Y values */
2008-10-29 06:20:46 +03:00
dev - > xy_cur [ ATP_XSENSORS + i ] = dev - > data [ 5 * i + 1 ] ;
dev - > xy_cur [ ATP_XSENSORS + i + 8 ] = dev - > data [ 5 * i + 3 ] ;
2005-12-21 08:50:23 +03:00
}
2005-09-08 12:19:48 +04:00
}
dbg_dump ( " sample " , dev - > xy_cur ) ;
if ( ! dev - > valid ) {
/* first sample */
2008-05-06 07:56:55 +04:00
dev - > valid = true ;
2005-09-08 12:19:48 +04:00
dev - > x_old = dev - > y_old = - 1 ;
2008-08-09 00:31:31 +04:00
/* Store first sample */
2005-09-08 12:19:48 +04:00
memcpy ( dev - > xy_old , dev - > xy_cur , sizeof ( dev - > xy_old ) ) ;
2008-08-09 00:31:31 +04:00
/* Perform size detection, if not done already */
2008-10-29 06:20:46 +03:00
if ( unlikely ( ! dev - > size_detect_done ) ) {
atp_detect_size ( dev ) ;
2008-08-09 00:31:31 +04:00
dev - > size_detect_done = 1 ;
2006-04-20 01:36:40 +04:00
goto exit ;
2008-08-09 00:31:31 +04:00
}
}
2006-04-20 01:36:40 +04:00
2008-08-09 00:31:31 +04:00
for ( i = 0 ; i < ATP_XSENSORS + ATP_YSENSORS ; i + + ) {
/* accumulate the change */
2010-08-09 07:48:08 +04:00
signed char change = dev - > xy_old [ i ] - dev - > xy_cur [ i ] ;
2008-08-09 00:31:31 +04:00
dev - > xy_acc [ i ] - = change ;
/* prevent down drifting */
if ( dev - > xy_acc [ i ] < 0 )
dev - > xy_acc [ i ] = 0 ;
}
memcpy ( dev - > xy_old , dev - > xy_cur , sizeof ( dev - > xy_old ) ) ;
dbg_dump ( " accumulator " , dev - > xy_acc ) ;
2014-03-31 10:21:21 +04:00
x = atp_calculate_abs ( dev , 0 , ATP_XSENSORS ,
2008-10-29 06:20:46 +03:00
dev - > info - > xfact , & x_z , & x_f ) ;
2014-03-31 10:21:21 +04:00
y = atp_calculate_abs ( dev , ATP_XSENSORS , ATP_YSENSORS ,
2008-10-29 06:20:46 +03:00
dev - > info - > yfact , & y_z , & y_f ) ;
key = dev - > data [ dev - > info - > datalen - 1 ] & ATP_STATUS_BUTTON ;
2008-08-09 00:31:31 +04:00
2014-03-31 10:37:05 +04:00
fingers = max ( x_f , y_f ) ;
if ( x & & y & & fingers = = dev - > fingers_old ) {
2008-08-09 00:31:31 +04:00
if ( dev - > x_old ! = - 1 ) {
2014-03-31 10:21:21 +04:00
x = ( dev - > x_old * 7 + x ) > > 3 ;
y = ( dev - > y_old * 7 + y ) > > 3 ;
2008-08-09 00:31:31 +04:00
dev - > x_old = x ;
dev - > y_old = y ;
if ( debug > 1 )
printk ( KERN_DEBUG " appletouch: "
" X: %3d Y: %3d Xz: %3d Yz: %3d \n " ,
x , y , x_z , y_z ) ;
input_report_key ( dev - > input , BTN_TOUCH , 1 ) ;
input_report_abs ( dev - > input , ABS_X , x ) ;
input_report_abs ( dev - > input , ABS_Y , y ) ;
input_report_abs ( dev - > input , ABS_PRESSURE ,
min ( ATP_PRESSURE , x_z + y_z ) ) ;
2014-03-31 10:37:05 +04:00
atp_report_fingers ( dev - > input , fingers ) ;
2005-12-21 08:50:23 +03:00
}
2008-08-09 00:31:31 +04:00
dev - > x_old = x ;
dev - > y_old = y ;
} else if ( ! x & & ! y ) {
dev - > x_old = dev - > y_old = - 1 ;
2014-03-31 10:37:05 +04:00
dev - > fingers_old = 0 ;
2008-08-09 00:31:31 +04:00
input_report_key ( dev - > input , BTN_TOUCH , 0 ) ;
input_report_abs ( dev - > input , ABS_PRESSURE , 0 ) ;
atp_report_fingers ( dev - > input , 0 ) ;
/* reset the accumulator on release */
memset ( dev - > xy_acc , 0 , sizeof ( dev - > xy_acc ) ) ;
}
2014-03-31 10:37:05 +04:00
if ( fingers ! = dev - > fingers_old )
dev - > x_old = dev - > y_old = - 1 ;
dev - > fingers_old = fingers ;
2008-08-09 00:31:31 +04:00
input_report_key ( dev - > input , BTN_LEFT , key ) ;
input_sync ( dev - > input ) ;
exit :
retval = usb_submit_urb ( dev - > urb , GFP_ATOMIC ) ;
if ( retval )
2012-05-05 02:33:01 +04:00
dev_err ( & dev - > intf - > dev ,
2012-04-26 01:48:31 +04:00
" atp_complete: usb_submit_urb failed with result %d \n " ,
retval ) ;
2008-08-09 00:31:31 +04:00
}
/* Interrupt function for older touchpads: GEYSER3/GEYSER4 */
static void atp_complete_geyser_3_4 ( struct urb * urb )
{
int x , y , x_z , y_z , x_f , y_f ;
int retval , i , j ;
2014-03-31 10:37:05 +04:00
int key , fingers ;
2008-08-09 00:31:31 +04:00
struct atp * dev = urb - > context ;
int status = atp_status_check ( urb ) ;
if ( status = = ATP_URB_STATUS_ERROR_FATAL )
return ;
else if ( status = = ATP_URB_STATUS_ERROR )
goto exit ;
/* Reorder the sensors values:
*
* The values are laid out like this :
* - , Y1 , Y2 , - , Y3 , Y4 , - , . . . , - , X1 , X2 , - , X3 , X4 , . . .
* ' - ' is an unused value .
*/
/* read X values */
for ( i = 0 , j = 19 ; i < 20 ; i + = 2 , j + = 3 ) {
dev - > xy_cur [ i ] = dev - > data [ j + 1 ] ;
dev - > xy_cur [ i + 1 ] = dev - > data [ j + 2 ] ;
}
/* read Y values */
for ( i = 0 , j = 1 ; i < 9 ; i + = 2 , j + = 3 ) {
dev - > xy_cur [ ATP_XSENSORS + i ] = dev - > data [ j + 1 ] ;
dev - > xy_cur [ ATP_XSENSORS + i + 1 ] = dev - > data [ j + 2 ] ;
}
dbg_dump ( " sample " , dev - > xy_cur ) ;
2008-08-09 00:31:33 +04:00
/* Just update the base values (i.e. touchpad in untouched state) */
2008-10-29 06:20:46 +03:00
if ( dev - > data [ dev - > info - > datalen - 1 ] & ATP_STATUS_BASE_UPDATE ) {
2005-09-08 12:19:48 +04:00
2010-10-31 03:19:49 +03:00
dprintk ( " appletouch: updated base values \n " ) ;
2008-08-09 00:31:33 +04:00
memcpy ( dev - > xy_old , dev - > xy_cur , sizeof ( dev - > xy_old ) ) ;
2005-09-08 12:19:48 +04:00
goto exit ;
}
for ( i = 0 ; i < ATP_XSENSORS + ATP_YSENSORS ; i + + ) {
2008-08-09 00:31:33 +04:00
/* calculate the change */
dev - > xy_acc [ i ] = dev - > xy_cur [ i ] - dev - > xy_old [ i ] ;
/* this is a round-robin value, so couple with that */
if ( dev - > xy_acc [ i ] > 127 )
dev - > xy_acc [ i ] - = 256 ;
if ( dev - > xy_acc [ i ] < - 127 )
dev - > xy_acc [ i ] + = 256 ;
2005-09-08 12:19:48 +04:00
/* prevent down drifting */
if ( dev - > xy_acc [ i ] < 0 )
dev - > xy_acc [ i ] = 0 ;
}
dbg_dump ( " accumulator " , dev - > xy_acc ) ;
2014-03-31 10:21:21 +04:00
x = atp_calculate_abs ( dev , 0 , ATP_XSENSORS ,
2008-10-29 06:20:46 +03:00
dev - > info - > xfact , & x_z , & x_f ) ;
2014-03-31 10:21:21 +04:00
y = atp_calculate_abs ( dev , ATP_XSENSORS , ATP_YSENSORS ,
2008-10-29 06:20:46 +03:00
dev - > info - > yfact , & y_z , & y_f ) ;
2014-03-31 10:21:21 +04:00
2008-10-29 06:20:46 +03:00
key = dev - > data [ dev - > info - > datalen - 1 ] & ATP_STATUS_BUTTON ;
2005-09-08 12:19:48 +04:00
2014-03-31 10:37:05 +04:00
fingers = max ( x_f , y_f ) ;
if ( x & & y & & fingers = = dev - > fingers_old ) {
2005-09-08 12:19:48 +04:00
if ( dev - > x_old ! = - 1 ) {
2014-03-31 10:21:21 +04:00
x = ( dev - > x_old * 7 + x ) > > 3 ;
y = ( dev - > y_old * 7 + y ) > > 3 ;
2005-09-08 12:19:48 +04:00
dev - > x_old = x ;
dev - > y_old = y ;
if ( debug > 1 )
2007-11-02 05:13:32 +03:00
printk ( KERN_DEBUG " appletouch: X: %3d Y: %3d "
2005-09-08 12:19:48 +04:00
" Xz: %3d Yz: %3d \n " ,
x , y , x_z , y_z ) ;
2005-09-15 11:01:47 +04:00
input_report_key ( dev - > input , BTN_TOUCH , 1 ) ;
input_report_abs ( dev - > input , ABS_X , x ) ;
input_report_abs ( dev - > input , ABS_Y , y ) ;
input_report_abs ( dev - > input , ABS_PRESSURE ,
2005-09-08 12:19:48 +04:00
min ( ATP_PRESSURE , x_z + y_z ) ) ;
2014-03-31 10:37:05 +04:00
atp_report_fingers ( dev - > input , fingers ) ;
2005-09-08 12:19:48 +04:00
}
dev - > x_old = x ;
dev - > y_old = y ;
2007-07-20 08:29:32 +04:00
} else if ( ! x & & ! y ) {
2005-09-08 12:19:48 +04:00
dev - > x_old = dev - > y_old = - 1 ;
2014-03-31 10:37:05 +04:00
dev - > fingers_old = 0 ;
2005-09-15 11:01:47 +04:00
input_report_key ( dev - > input , BTN_TOUCH , 0 ) ;
input_report_abs ( dev - > input , ABS_PRESSURE , 0 ) ;
atp_report_fingers ( dev - > input , 0 ) ;
2005-09-08 12:19:48 +04:00
/* reset the accumulator on release */
memset ( dev - > xy_acc , 0 , sizeof ( dev - > xy_acc ) ) ;
2007-10-13 08:31:15 +04:00
}
2014-03-31 10:37:05 +04:00
if ( fingers ! = dev - > fingers_old )
dev - > x_old = dev - > y_old = - 1 ;
dev - > fingers_old = fingers ;
2007-10-22 08:59:59 +04:00
input_report_key ( dev - > input , BTN_LEFT , key ) ;
input_sync ( dev - > input ) ;
2007-11-02 05:13:32 +03:00
/*
2008-08-09 00:31:31 +04:00
* Geysers 3 / 4 will continue to send packets continually after
2007-11-02 05:13:32 +03:00
* the first touch unless reinitialised . Do so if it ' s been
* idle for a while in order to avoid waking the kernel up
2008-08-09 00:31:31 +04:00
* several hundred times a second .
2007-11-02 05:13:32 +03:00
*/
2008-08-09 00:31:31 +04:00
/*
* Button must not be pressed when entering suspend ,
* otherwise we will never release the button .
*/
if ( ! x & & ! y & & ! key ) {
dev - > idlecount + + ;
if ( dev - > idlecount = = 10 ) {
2008-08-09 00:31:33 +04:00
dev - > x_old = dev - > y_old = - 1 ;
dev - > idlecount = 0 ;
2008-08-09 00:31:31 +04:00
schedule_work ( & dev - > work ) ;
/* Don't resubmit urb here, wait for reinit */
return ;
}
} else
dev - > idlecount = 0 ;
2005-09-08 12:19:48 +04:00
2008-05-06 07:56:55 +04:00
exit :
2005-09-08 12:19:48 +04:00
retval = usb_submit_urb ( dev - > urb , GFP_ATOMIC ) ;
2008-05-06 07:56:55 +04:00
if ( retval )
2012-05-05 02:33:01 +04:00
dev_err ( & dev - > intf - > dev ,
2012-04-26 01:48:31 +04:00
" atp_complete: usb_submit_urb failed with result %d \n " ,
retval ) ;
2005-09-08 12:19:48 +04:00
}
static int atp_open ( struct input_dev * input )
{
2007-04-12 09:34:39 +04:00
struct atp * dev = input_get_drvdata ( input ) ;
2005-09-08 12:19:48 +04:00
if ( usb_submit_urb ( dev - > urb , GFP_ATOMIC ) )
return - EIO ;
dev - > open = 1 ;
return 0 ;
}
static void atp_close ( struct input_dev * input )
{
2007-04-12 09:34:39 +04:00
struct atp * dev = input_get_drvdata ( input ) ;
2005-09-08 12:19:48 +04:00
usb_kill_urb ( dev - > urb ) ;
2007-07-20 08:29:32 +04:00
cancel_work_sync ( & dev - > work ) ;
2005-09-08 12:19:48 +04:00
dev - > open = 0 ;
}
2008-06-17 19:56:55 +04:00
static int atp_handle_geyser ( struct atp * dev )
{
2008-10-29 06:20:46 +03:00
if ( dev - > info ! = & fountain_info ) {
2008-06-17 19:56:55 +04:00
/* switch to raw sensor mode */
2012-05-02 04:56:47 +04:00
if ( atp_geyser_init ( dev ) )
2008-06-17 19:56:55 +04:00
return - EIO ;
2012-05-05 02:33:01 +04:00
dev_info ( & dev - > intf - > dev , " Geyser mode initialized. \n " ) ;
2008-06-17 19:56:55 +04:00
}
return 0 ;
}
2008-05-06 07:56:55 +04:00
static int atp_probe ( struct usb_interface * iface ,
const struct usb_device_id * id )
2005-09-08 12:19:48 +04:00
{
2005-09-15 11:01:47 +04:00
struct atp * dev ;
struct input_dev * input_dev ;
struct usb_device * udev = interface_to_usbdev ( iface ) ;
2005-09-08 12:19:48 +04:00
struct usb_host_interface * iface_desc ;
struct usb_endpoint_descriptor * endpoint ;
int int_in_endpointAddr = 0 ;
2007-04-12 09:33:39 +04:00
int i , error = - ENOMEM ;
2008-10-29 06:20:46 +03:00
const struct atp_info * info = ( const struct atp_info * ) id - > driver_info ;
2005-09-08 12:19:48 +04:00
/* set up the endpoint information */
/* use only the first interrupt-in endpoint */
iface_desc = iface - > cur_altsetting ;
for ( i = 0 ; i < iface_desc - > desc . bNumEndpoints ; i + + ) {
endpoint = & iface_desc - > endpoint [ i ] . desc ;
2006-09-27 22:58:53 +04:00
if ( ! int_in_endpointAddr & & usb_endpoint_is_int_in ( endpoint ) ) {
2005-09-08 12:19:48 +04:00
/* we found an interrupt in endpoint */
int_in_endpointAddr = endpoint - > bEndpointAddress ;
break ;
}
}
if ( ! int_in_endpointAddr ) {
2012-04-26 01:48:31 +04:00
dev_err ( & iface - > dev , " Could not find int-in endpoint \n " ) ;
2005-09-15 11:01:47 +04:00
return - EIO ;
2005-09-08 12:19:48 +04:00
}
2005-09-15 11:01:47 +04:00
/* allocate memory for our device state and initialize it */
dev = kzalloc ( sizeof ( struct atp ) , GFP_KERNEL ) ;
input_dev = input_allocate_device ( ) ;
if ( ! dev | | ! input_dev ) {
2012-04-26 01:48:31 +04:00
dev_err ( & iface - > dev , " Out of memory \n " ) ;
2005-09-15 11:01:47 +04:00
goto err_free_devs ;
}
dev - > udev = udev ;
2012-05-05 02:33:01 +04:00
dev - > intf = iface ;
2005-09-15 11:01:47 +04:00
dev - > input = input_dev ;
2008-10-29 06:20:46 +03:00
dev - > info = info ;
2008-05-06 07:56:55 +04:00
dev - > overflow_warned = false ;
2006-04-20 01:36:40 +04:00
2005-09-08 12:19:48 +04:00
dev - > urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2007-04-12 09:33:39 +04:00
if ( ! dev - > urb )
2005-09-15 11:01:47 +04:00
goto err_free_devs ;
2010-04-12 15:17:25 +04:00
dev - > data = usb_alloc_coherent ( dev - > udev , dev - > info - > datalen , GFP_KERNEL ,
& dev - > urb - > transfer_dma ) ;
2007-04-12 09:33:39 +04:00
if ( ! dev - > data )
2005-09-15 11:01:47 +04:00
goto err_free_urb ;
2008-10-29 06:20:46 +03:00
usb_fill_int_urb ( dev - > urb , udev ,
usb_rcvintpipe ( udev , int_in_endpointAddr ) ,
dev - > data , dev - > info - > datalen ,
dev - > info - > callback , dev , 1 ) ;
2005-09-08 12:19:48 +04:00
2008-06-17 19:56:55 +04:00
error = atp_handle_geyser ( dev ) ;
if ( error )
goto err_free_buffer ;
2005-09-15 11:01:47 +04:00
usb_make_path ( udev , dev - > phys , sizeof ( dev - > phys ) ) ;
strlcat ( dev - > phys , " /input0 " , sizeof ( dev - > phys ) ) ;
input_dev - > name = " appletouch " ;
input_dev - > phys = dev - > phys ;
usb_to_input_id ( dev - > udev , & input_dev - > id ) ;
2007-04-12 09:35:03 +04:00
input_dev - > dev . parent = & iface - > dev ;
2005-09-08 12:19:48 +04:00
2007-04-12 09:34:39 +04:00
input_set_drvdata ( input_dev , dev ) ;
2005-09-15 11:01:47 +04:00
input_dev - > open = atp_open ;
input_dev - > close = atp_close ;
2005-09-08 12:19:48 +04:00
2005-09-15 11:01:47 +04:00
set_bit ( EV_ABS , input_dev - > evbit ) ;
2005-09-08 12:19:48 +04:00
2008-10-29 06:20:46 +03:00
input_set_abs_params ( input_dev , ABS_X , 0 ,
( dev - > info - > xsensors - 1 ) * dev - > info - > xfact - 1 ,
2014-03-27 01:10:43 +04:00
dev - > info - > fuzz , 0 ) ;
2008-10-29 06:20:46 +03:00
input_set_abs_params ( input_dev , ABS_Y , 0 ,
( dev - > info - > ysensors - 1 ) * dev - > info - > yfact - 1 ,
2014-03-27 01:10:43 +04:00
dev - > info - > fuzz , 0 ) ;
2005-09-15 11:01:47 +04:00
input_set_abs_params ( input_dev , ABS_PRESSURE , 0 , ATP_PRESSURE , 0 , 0 ) ;
2005-09-08 12:19:48 +04:00
2005-09-15 11:01:47 +04:00
set_bit ( EV_KEY , input_dev - > evbit ) ;
set_bit ( BTN_TOUCH , input_dev - > keybit ) ;
set_bit ( BTN_TOOL_FINGER , input_dev - > keybit ) ;
set_bit ( BTN_TOOL_DOUBLETAP , input_dev - > keybit ) ;
set_bit ( BTN_TOOL_TRIPLETAP , input_dev - > keybit ) ;
set_bit ( BTN_LEFT , input_dev - > keybit ) ;
2005-09-08 12:19:48 +04:00
2007-04-12 09:33:39 +04:00
error = input_register_device ( dev - > input ) ;
if ( error )
goto err_free_buffer ;
2005-09-08 12:19:48 +04:00
2005-09-15 11:01:47 +04:00
/* save our data pointer in this interface device */
usb_set_intfdata ( iface , dev ) ;
2005-09-08 12:19:48 +04:00
2007-07-20 08:29:32 +04:00
INIT_WORK ( & dev - > work , atp_reinit ) ;
2005-09-08 12:19:48 +04:00
return 0 ;
2007-04-12 09:33:39 +04:00
err_free_buffer :
2010-04-12 15:17:25 +04:00
usb_free_coherent ( dev - > udev , dev - > info - > datalen ,
dev - > data , dev - > urb - > transfer_dma ) ;
2005-09-15 11:01:47 +04:00
err_free_urb :
2005-09-08 12:19:48 +04:00
usb_free_urb ( dev - > urb ) ;
2005-09-15 11:01:47 +04:00
err_free_devs :
2005-09-08 12:19:48 +04:00
usb_set_intfdata ( iface , NULL ) ;
kfree ( dev ) ;
2005-09-15 11:01:47 +04:00
input_free_device ( input_dev ) ;
2007-04-12 09:33:39 +04:00
return error ;
2005-09-08 12:19:48 +04:00
}
static void atp_disconnect ( struct usb_interface * iface )
{
struct atp * dev = usb_get_intfdata ( iface ) ;
usb_set_intfdata ( iface , NULL ) ;
if ( dev ) {
usb_kill_urb ( dev - > urb ) ;
2005-09-15 11:01:47 +04:00
input_unregister_device ( dev - > input ) ;
2010-04-12 15:17:25 +04:00
usb_free_coherent ( dev - > udev , dev - > info - > datalen ,
dev - > data , dev - > urb - > transfer_dma ) ;
2006-07-19 17:39:46 +04:00
usb_free_urb ( dev - > urb ) ;
2005-09-08 12:19:48 +04:00
kfree ( dev ) ;
}
2012-05-05 02:33:01 +04:00
dev_info ( & iface - > dev , " input: appletouch disconnected \n " ) ;
2005-09-08 12:19:48 +04:00
}
2008-06-17 19:56:55 +04:00
static int atp_recover ( struct atp * dev )
{
int error ;
error = atp_handle_geyser ( dev ) ;
if ( error )
return error ;
if ( dev - > open & & usb_submit_urb ( dev - > urb , GFP_ATOMIC ) )
return - EIO ;
return 0 ;
}
2005-09-08 12:19:48 +04:00
static int atp_suspend ( struct usb_interface * iface , pm_message_t message )
{
struct atp * dev = usb_get_intfdata ( iface ) ;
2007-07-20 08:29:32 +04:00
2005-09-08 12:19:48 +04:00
usb_kill_urb ( dev - > urb ) ;
return 0 ;
}
static int atp_resume ( struct usb_interface * iface )
{
struct atp * dev = usb_get_intfdata ( iface ) ;
2007-07-20 08:29:32 +04:00
2005-09-08 12:19:48 +04:00
if ( dev - > open & & usb_submit_urb ( dev - > urb , GFP_ATOMIC ) )
return - EIO ;
return 0 ;
}
2008-06-17 19:56:55 +04:00
static int atp_reset_resume ( struct usb_interface * iface )
{
struct atp * dev = usb_get_intfdata ( iface ) ;
return atp_recover ( dev ) ;
}
2005-09-08 12:19:48 +04:00
static struct usb_driver atp_driver = {
. name = " appletouch " ,
. probe = atp_probe ,
. disconnect = atp_disconnect ,
. suspend = atp_suspend ,
. resume = atp_resume ,
2008-06-17 19:56:55 +04:00
. reset_resume = atp_reset_resume ,
2005-09-08 12:19:48 +04:00
. id_table = atp_table ,
} ;
2011-11-18 21:48:31 +04:00
module_usb_driver ( atp_driver ) ;