2008-11-20 00:58:50 +03:00
/*
* Wacom W8001 penabled serial touchscreen driver
*
* Copyright ( c ) 2008 Jaya Kumar
2010-08-29 09:00:47 +04:00
* Copyright ( c ) 2010 Red Hat , Inc .
2011-01-11 12:06:58 +03:00
* Copyright ( c ) 2010 - 2011 Ping Cheng , Wacom . < pingc @ wacom . com >
2008-11-20 00:58:50 +03:00
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of this archive for
* more details .
*
* Layout based on Elo serial touchscreen driver by Vojtech Pavlik
*/
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/slab.h>
2010-11-27 11:16:48 +03:00
# include <linux/input/mt.h>
2008-11-20 00:58:50 +03:00
# include <linux/serio.h>
# include <linux/init.h>
# include <linux/ctype.h>
2010-12-25 00:16:53 +03:00
# include <linux/delay.h>
2008-11-20 00:58:50 +03:00
# define DRIVER_DESC "Wacom W8001 serial touchscreen driver"
MODULE_AUTHOR ( " Jaya Kumar <jayakumar.lkml@gmail.com> " ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
# define W8001_MAX_LENGTH 11
2009-09-04 04:22:03 +04:00
# define W8001_LEAD_MASK 0x80
# define W8001_LEAD_BYTE 0x80
# define W8001_TAB_MASK 0x40
# define W8001_TAB_BYTE 0x40
2010-08-29 09:00:47 +04:00
/* set in first byte of touch data packets */
# define W8001_TOUCH_MASK (0x10 | W8001_LEAD_MASK)
# define W8001_TOUCH_BYTE (0x10 | W8001_LEAD_BYTE)
2008-11-20 00:58:50 +03:00
2009-09-04 04:22:03 +04:00
# define W8001_QUERY_PACKET 0x20
2010-12-25 00:16:53 +03:00
# define W8001_CMD_STOP '0'
2009-09-04 04:22:03 +04:00
# define W8001_CMD_START '1'
# define W8001_CMD_QUERY '*'
2010-08-29 09:00:47 +04:00
# define W8001_CMD_TOUCHQUERY '%'
/* length of data packets in bytes, depends on device. */
# define W8001_PKTLEN_TOUCH93 5
# define W8001_PKTLEN_TOUCH9A 7
# define W8001_PKTLEN_TPCPEN 9
# define W8001_PKTLEN_TPCCTL 11 /* control packet */
# define W8001_PKTLEN_TOUCH2FG 13
2008-11-20 00:58:50 +03:00
2011-02-01 08:06:38 +03:00
/* resolution in points/mm */
# define W8001_PEN_RESOLUTION 100
# define W8001_TOUCH_RESOLUTION 10
2008-11-20 00:58:50 +03:00
struct w8001_coord {
u8 rdy ;
u8 tsw ;
u8 f1 ;
u8 f2 ;
u16 x ;
u16 y ;
u16 pen_pressure ;
u8 tilt_x ;
u8 tilt_y ;
} ;
2010-08-29 09:00:47 +04:00
/* touch query reply packet */
struct w8001_touch_query {
2011-01-11 12:06:58 +03:00
u16 x ;
u16 y ;
2010-08-29 09:00:47 +04:00
u8 panel_res ;
u8 capacity_res ;
u8 sensor_id ;
} ;
2008-11-20 00:58:50 +03:00
/*
* Per - touchscreen data .
*/
struct w8001 {
struct input_dev * dev ;
struct serio * serio ;
struct completion cmd_done ;
int id ;
int idx ;
2009-09-04 04:22:03 +04:00
unsigned char response_type ;
unsigned char response [ W8001_MAX_LENGTH ] ;
2008-11-20 00:58:50 +03:00
unsigned char data [ W8001_MAX_LENGTH ] ;
char phys [ 32 ] ;
2010-08-29 09:00:05 +04:00
int type ;
2010-08-29 09:00:47 +04:00
unsigned int pktlen ;
2011-01-11 12:06:58 +03:00
u16 max_touch_x ;
u16 max_touch_y ;
u16 max_pen_x ;
u16 max_pen_y ;
char name [ 64 ] ;
2008-11-20 00:58:50 +03:00
} ;
2011-01-11 12:06:58 +03:00
static void parse_pen_data ( u8 * data , struct w8001_coord * coord )
2008-11-20 00:58:50 +03:00
{
2009-09-04 04:22:03 +04:00
memset ( coord , 0 , sizeof ( * coord ) ) ;
2008-11-20 00:58:50 +03:00
coord - > rdy = data [ 0 ] & 0x20 ;
coord - > tsw = data [ 0 ] & 0x01 ;
coord - > f1 = data [ 0 ] & 0x02 ;
coord - > f2 = data [ 0 ] & 0x04 ;
coord - > x = ( data [ 1 ] & 0x7F ) < < 9 ;
coord - > x | = ( data [ 2 ] & 0x7F ) < < 2 ;
coord - > x | = ( data [ 6 ] & 0x60 ) > > 5 ;
coord - > y = ( data [ 3 ] & 0x7F ) < < 9 ;
coord - > y | = ( data [ 4 ] & 0x7F ) < < 2 ;
coord - > y | = ( data [ 6 ] & 0x18 ) > > 3 ;
coord - > pen_pressure = data [ 5 ] & 0x7F ;
coord - > pen_pressure | = ( data [ 6 ] & 0x07 ) < < 7 ;
coord - > tilt_x = data [ 7 ] & 0x7F ;
coord - > tilt_y = data [ 8 ] & 0x7F ;
}
2011-01-11 12:06:58 +03:00
static void parse_single_touch ( u8 * data , struct w8001_coord * coord )
{
coord - > x = ( data [ 1 ] < < 7 ) | data [ 2 ] ;
coord - > y = ( data [ 3 ] < < 7 ) | data [ 4 ] ;
coord - > tsw = data [ 0 ] & 0x01 ;
}
static void scale_touch_coordinates ( struct w8001 * w8001 ,
unsigned int * x , unsigned int * y )
{
if ( w8001 - > max_pen_x & & w8001 - > max_touch_x )
* x = * x * w8001 - > max_pen_x / w8001 - > max_touch_x ;
if ( w8001 - > max_pen_y & & w8001 - > max_touch_y )
* y = * y * w8001 - > max_pen_y / w8001 - > max_touch_y ;
}
static void parse_multi_touch ( struct w8001 * w8001 )
2010-08-29 09:00:47 +04:00
{
struct input_dev * dev = w8001 - > dev ;
unsigned char * data = w8001 - > data ;
2011-01-11 12:06:58 +03:00
unsigned int x , y ;
2010-08-29 09:00:47 +04:00
int i ;
2011-01-11 12:06:58 +03:00
int count = 0 ;
2010-08-29 09:00:47 +04:00
for ( i = 0 ; i < 2 ; i + + ) {
2010-12-15 15:50:34 +03:00
bool touch = data [ 0 ] & ( 1 < < i ) ;
2010-08-29 09:00:47 +04:00
2010-12-15 15:50:34 +03:00
input_mt_slot ( dev , i ) ;
input_mt_report_slot_state ( dev , MT_TOOL_FINGER , touch ) ;
if ( touch ) {
2011-01-11 12:06:58 +03:00
x = ( data [ 6 * i + 1 ] < < 7 ) | data [ 6 * i + 2 ] ;
y = ( data [ 6 * i + 3 ] < < 7 ) | data [ 6 * i + 4 ] ;
2010-08-29 09:00:47 +04:00
/* data[5,6] and [11,12] is finger capacity */
2011-01-11 12:06:58 +03:00
/* scale to pen maximum */
scale_touch_coordinates ( w8001 , & x , & y ) ;
2010-08-29 09:00:47 +04:00
input_report_abs ( dev , ABS_MT_POSITION_X , x ) ;
input_report_abs ( dev , ABS_MT_POSITION_Y , y ) ;
2011-01-11 12:06:58 +03:00
count + + ;
2010-08-29 09:00:47 +04:00
}
}
2011-01-11 12:06:58 +03:00
/* emulate single touch events when stylus is out of proximity.
* This is to make single touch backward support consistent
* across all Wacom single touch devices .
*/
if ( w8001 - > type ! = BTN_TOOL_PEN & &
w8001 - > type ! = BTN_TOOL_RUBBER ) {
w8001 - > type = count = = 1 ? BTN_TOOL_FINGER : KEY_RESERVED ;
input_mt_report_pointer_emulation ( dev , true ) ;
}
2010-08-29 09:00:47 +04:00
input_sync ( dev ) ;
}
2010-08-29 09:00:47 +04:00
static void parse_touchquery ( u8 * data , struct w8001_touch_query * query )
{
memset ( query , 0 , sizeof ( * query ) ) ;
query - > panel_res = data [ 1 ] ;
query - > sensor_id = data [ 2 ] & 0x7 ;
query - > capacity_res = data [ 7 ] ;
query - > x = data [ 3 ] < < 9 ;
query - > x | = data [ 4 ] < < 2 ;
query - > x | = ( data [ 2 ] > > 5 ) & 0x3 ;
query - > y = data [ 5 ] < < 9 ;
query - > y | = data [ 6 ] < < 2 ;
query - > y | = ( data [ 2 ] > > 3 ) & 0x3 ;
2011-01-11 12:06:58 +03:00
/* Early days' single-finger touch models need the following defaults */
if ( ! query - > x & & ! query - > y ) {
query - > x = 1024 ;
query - > y = 1024 ;
if ( query - > panel_res )
query - > x = query - > y = ( 1 < < query - > panel_res ) ;
2011-02-01 08:06:38 +03:00
query - > panel_res = W8001_TOUCH_RESOLUTION ;
2011-01-11 12:06:58 +03:00
}
2010-08-29 09:00:47 +04:00
}
2010-08-29 09:00:05 +04:00
static void report_pen_events ( struct w8001 * w8001 , struct w8001_coord * coord )
{
struct input_dev * dev = w8001 - > dev ;
/*
* We have 1 bit for proximity ( rdy ) and 3 bits for tip , side ,
* side2 / eraser . If rdy & & f2 are set , this can be either pen + side2 ,
2011-01-11 12:06:58 +03:00
* or eraser . Assume :
2010-08-29 09:00:05 +04:00
* - if dev is already in proximity and f2 is toggled → pen + side2
* - if dev comes into proximity with f2 set → eraser
* If f2 disappears after assuming eraser , fake proximity out for
* eraser and in for pen .
*/
2011-01-11 12:06:58 +03:00
switch ( w8001 - > type ) {
case BTN_TOOL_RUBBER :
2010-08-29 09:00:05 +04:00
if ( ! coord - > f2 ) {
input_report_abs ( dev , ABS_PRESSURE , 0 ) ;
input_report_key ( dev , BTN_TOUCH , 0 ) ;
input_report_key ( dev , BTN_STYLUS , 0 ) ;
input_report_key ( dev , BTN_STYLUS2 , 0 ) ;
input_report_key ( dev , BTN_TOOL_RUBBER , 0 ) ;
input_sync ( dev ) ;
w8001 - > type = BTN_TOOL_PEN ;
}
2011-01-11 12:06:58 +03:00
break ;
case BTN_TOOL_FINGER :
input_report_key ( dev , BTN_TOUCH , 0 ) ;
input_report_key ( dev , BTN_TOOL_FINGER , 0 ) ;
input_sync ( dev ) ;
/* fall through */
case KEY_RESERVED :
w8001 - > type = coord - > f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN ;
break ;
default :
2010-08-29 09:00:05 +04:00
input_report_key ( dev , BTN_STYLUS2 , coord - > f2 ) ;
2011-01-11 12:06:58 +03:00
break ;
2010-08-29 09:00:05 +04:00
}
input_report_abs ( dev , ABS_X , coord - > x ) ;
input_report_abs ( dev , ABS_Y , coord - > y ) ;
input_report_abs ( dev , ABS_PRESSURE , coord - > pen_pressure ) ;
input_report_key ( dev , BTN_TOUCH , coord - > tsw ) ;
input_report_key ( dev , BTN_STYLUS , coord - > f1 ) ;
input_report_key ( dev , w8001 - > type , coord - > rdy ) ;
input_sync ( dev ) ;
if ( ! coord - > rdy )
2011-01-11 12:06:58 +03:00
w8001 - > type = KEY_RESERVED ;
}
static void report_single_touch ( struct w8001 * w8001 , struct w8001_coord * coord )
{
struct input_dev * dev = w8001 - > dev ;
unsigned int x = coord - > x ;
unsigned int y = coord - > y ;
/* scale to pen maximum */
scale_touch_coordinates ( w8001 , & x , & y ) ;
input_report_abs ( dev , ABS_X , x ) ;
input_report_abs ( dev , ABS_Y , y ) ;
input_report_key ( dev , BTN_TOUCH , coord - > tsw ) ;
input_report_key ( dev , BTN_TOOL_FINGER , coord - > tsw ) ;
input_sync ( dev ) ;
w8001 - > type = coord - > tsw ? BTN_TOOL_FINGER : KEY_RESERVED ;
2010-08-29 09:00:05 +04:00
}
2009-09-04 04:22:03 +04:00
static irqreturn_t w8001_interrupt ( struct serio * serio ,
unsigned char data , unsigned int flags )
2008-11-20 00:58:50 +03:00
{
2009-09-04 04:22:03 +04:00
struct w8001 * w8001 = serio_get_drvdata ( serio ) ;
2008-11-20 00:58:50 +03:00
struct w8001_coord coord ;
2009-09-04 04:22:03 +04:00
unsigned char tmp ;
2008-11-20 00:58:50 +03:00
w8001 - > data [ w8001 - > idx ] = data ;
switch ( w8001 - > idx + + ) {
case 0 :
if ( ( data & W8001_LEAD_MASK ) ! = W8001_LEAD_BYTE ) {
pr_debug ( " w8001: unsynchronized data: 0x%02x \n " , data ) ;
w8001 - > idx = 0 ;
}
break ;
2009-09-04 04:22:03 +04:00
2010-08-29 09:00:47 +04:00
case W8001_PKTLEN_TOUCH93 - 1 :
case W8001_PKTLEN_TOUCH9A - 1 :
2011-01-11 12:06:58 +03:00
tmp = w8001 - > data [ 0 ] & W8001_TOUCH_BYTE ;
if ( tmp ! = W8001_TOUCH_BYTE )
break ;
if ( w8001 - > pktlen = = w8001 - > idx ) {
2010-08-29 09:00:47 +04:00
w8001 - > idx = 0 ;
2011-01-11 12:06:58 +03:00
if ( w8001 - > type ! = BTN_TOOL_PEN & &
w8001 - > type ! = BTN_TOOL_RUBBER ) {
parse_single_touch ( w8001 - > data , & coord ) ;
report_single_touch ( w8001 , & coord ) ;
}
}
2010-08-29 09:00:47 +04:00
break ;
/* Pen coordinates packet */
case W8001_PKTLEN_TPCPEN - 1 :
2008-11-20 00:58:50 +03:00
tmp = w8001 - > data [ 0 ] & W8001_TAB_MASK ;
if ( unlikely ( tmp = = W8001_TAB_BYTE ) )
break ;
2009-09-04 04:22:03 +04:00
2011-01-11 12:06:58 +03:00
tmp = w8001 - > data [ 0 ] & W8001_TOUCH_BYTE ;
2010-08-29 09:00:47 +04:00
if ( tmp = = W8001_TOUCH_BYTE )
break ;
2008-11-20 00:58:50 +03:00
w8001 - > idx = 0 ;
2011-01-11 12:06:58 +03:00
parse_pen_data ( w8001 - > data , & coord ) ;
2010-08-29 09:00:05 +04:00
report_pen_events ( w8001 , & coord ) ;
2008-11-20 00:58:50 +03:00
break ;
2009-09-04 04:22:03 +04:00
2010-08-29 09:00:47 +04:00
/* control packet */
case W8001_PKTLEN_TPCCTL - 1 :
2011-01-11 12:06:58 +03:00
tmp = w8001 - > data [ 0 ] & W8001_TOUCH_MASK ;
2010-08-29 09:00:47 +04:00
if ( tmp = = W8001_TOUCH_BYTE )
break ;
2008-11-20 00:58:50 +03:00
w8001 - > idx = 0 ;
2009-09-04 04:22:03 +04:00
memcpy ( w8001 - > response , w8001 - > data , W8001_MAX_LENGTH ) ;
w8001 - > response_type = W8001_QUERY_PACKET ;
2008-11-20 00:58:50 +03:00
complete ( & w8001 - > cmd_done ) ;
break ;
2010-08-29 09:00:47 +04:00
2010-08-29 09:00:47 +04:00
/* 2 finger touch packet */
2010-08-29 09:00:47 +04:00
case W8001_PKTLEN_TOUCH2FG - 1 :
2010-08-29 09:00:47 +04:00
w8001 - > idx = 0 ;
2011-01-11 12:06:58 +03:00
parse_multi_touch ( w8001 ) ;
2010-08-29 09:00:47 +04:00
break ;
2008-11-20 00:58:50 +03:00
}
return IRQ_HANDLED ;
}
2009-09-04 04:22:03 +04:00
static int w8001_command ( struct w8001 * w8001 , unsigned char command ,
bool wait_response )
2008-11-20 00:58:50 +03:00
{
2009-09-04 04:22:03 +04:00
int rc ;
2008-11-20 00:58:50 +03:00
2009-09-04 04:22:03 +04:00
w8001 - > response_type = 0 ;
2008-11-20 00:58:50 +03:00
init_completion ( & w8001 - > cmd_done ) ;
2009-09-04 04:22:03 +04:00
rc = serio_write ( w8001 - > serio , command ) ;
if ( rc = = 0 & & wait_response ) {
2008-11-20 00:58:50 +03:00
2009-09-04 04:22:03 +04:00
wait_for_completion_timeout ( & w8001 - > cmd_done , HZ ) ;
if ( w8001 - > response_type ! = W8001_QUERY_PACKET )
rc = - EIO ;
2008-11-20 00:58:50 +03:00
}
return rc ;
}
2011-08-24 09:57:00 +04:00
static int w8001_open ( struct input_dev * dev )
{
struct w8001 * w8001 = input_get_drvdata ( dev ) ;
return w8001_command ( w8001 , W8001_CMD_START , false ) ;
}
static void w8001_close ( struct input_dev * dev )
{
struct w8001 * w8001 = input_get_drvdata ( dev ) ;
w8001_command ( w8001 , W8001_CMD_STOP , false ) ;
}
2008-11-20 00:58:50 +03:00
static int w8001_setup ( struct w8001 * w8001 )
{
struct input_dev * dev = w8001 - > dev ;
2009-09-04 04:22:03 +04:00
struct w8001_coord coord ;
2011-01-11 12:06:58 +03:00
struct w8001_touch_query touch ;
2009-09-04 04:22:03 +04:00
int error ;
2008-11-20 00:58:50 +03:00
2010-12-25 00:16:53 +03:00
error = w8001_command ( w8001 , W8001_CMD_STOP , false ) ;
2009-09-04 04:22:03 +04:00
if ( error )
return error ;
2008-11-20 00:58:50 +03:00
2010-12-25 00:16:53 +03:00
msleep ( 250 ) ; /* wait 250ms before querying the device */
2008-11-20 00:58:50 +03:00
2011-01-11 12:06:58 +03:00
dev - > evbit [ 0 ] = BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_ABS ) ;
strlcat ( w8001 - > name , " Wacom Serial " , sizeof ( w8001 - > name ) ) ;
2011-09-08 20:38:14 +04:00
__set_bit ( INPUT_PROP_DIRECT , dev - > propbit ) ;
2010-12-25 00:16:53 +03:00
/* penabled? */
error = w8001_command ( w8001 , W8001_CMD_QUERY , true ) ;
if ( ! error ) {
2011-01-11 12:06:58 +03:00
__set_bit ( BTN_TOUCH , dev - > keybit ) ;
2010-12-25 00:16:53 +03:00
__set_bit ( BTN_TOOL_PEN , dev - > keybit ) ;
__set_bit ( BTN_TOOL_RUBBER , dev - > keybit ) ;
__set_bit ( BTN_STYLUS , dev - > keybit ) ;
__set_bit ( BTN_STYLUS2 , dev - > keybit ) ;
2011-01-11 12:06:58 +03:00
parse_pen_data ( w8001 - > response , & coord ) ;
w8001 - > max_pen_x = coord . x ;
w8001 - > max_pen_y = coord . y ;
2010-12-25 00:16:53 +03:00
input_set_abs_params ( dev , ABS_X , 0 , coord . x , 0 , 0 ) ;
input_set_abs_params ( dev , ABS_Y , 0 , coord . y , 0 , 0 ) ;
2011-02-01 08:06:38 +03:00
input_abs_set_res ( dev , ABS_X , W8001_PEN_RESOLUTION ) ;
input_abs_set_res ( dev , ABS_Y , W8001_PEN_RESOLUTION ) ;
2010-12-25 00:16:53 +03:00
input_set_abs_params ( dev , ABS_PRESSURE , 0 , coord . pen_pressure , 0 , 0 ) ;
if ( coord . tilt_x & & coord . tilt_y ) {
input_set_abs_params ( dev , ABS_TILT_X , 0 , coord . tilt_x , 0 , 0 ) ;
input_set_abs_params ( dev , ABS_TILT_Y , 0 , coord . tilt_y , 0 , 0 ) ;
}
2011-01-11 12:06:58 +03:00
w8001 - > id = 0x90 ;
strlcat ( w8001 - > name , " Penabled " , sizeof ( w8001 - > name ) ) ;
2010-12-25 00:16:53 +03:00
}
2008-11-20 00:58:50 +03:00
2010-12-25 00:16:53 +03:00
/* Touch enabled? */
2010-08-29 09:00:47 +04:00
error = w8001_command ( w8001 , W8001_CMD_TOUCHQUERY , true ) ;
2010-12-25 00:16:53 +03:00
/*
* Some non - touch devices may reply to the touch query . But their
* second byte is empty , which indicates touch is not supported .
*/
if ( ! error & & w8001 - > response [ 1 ] ) {
2011-01-11 12:06:58 +03:00
__set_bit ( BTN_TOUCH , dev - > keybit ) ;
__set_bit ( BTN_TOOL_FINGER , dev - > keybit ) ;
2010-08-29 09:00:47 +04:00
parse_touchquery ( w8001 - > response , & touch ) ;
2011-01-11 12:06:58 +03:00
w8001 - > max_touch_x = touch . x ;
w8001 - > max_touch_y = touch . y ;
if ( w8001 - > max_pen_x & & w8001 - > max_pen_y ) {
2011-02-01 08:06:38 +03:00
/* if pen is supported scale to pen maximum */
2011-01-11 12:06:58 +03:00
touch . x = w8001 - > max_pen_x ;
touch . y = w8001 - > max_pen_y ;
2011-02-01 08:06:38 +03:00
touch . panel_res = W8001_PEN_RESOLUTION ;
2011-01-11 12:06:58 +03:00
}
2010-08-29 09:00:47 +04:00
2010-12-25 00:16:53 +03:00
input_set_abs_params ( dev , ABS_X , 0 , touch . x , 0 , 0 ) ;
input_set_abs_params ( dev , ABS_Y , 0 , touch . y , 0 , 0 ) ;
2011-02-01 08:06:38 +03:00
input_abs_set_res ( dev , ABS_X , touch . panel_res ) ;
input_abs_set_res ( dev , ABS_Y , touch . panel_res ) ;
2010-12-25 00:16:53 +03:00
2010-08-29 09:00:47 +04:00
switch ( touch . sensor_id ) {
case 0 :
case 2 :
w8001 - > pktlen = W8001_PKTLEN_TOUCH93 ;
2011-01-11 12:06:58 +03:00
w8001 - > id = 0x93 ;
strlcat ( w8001 - > name , " 1FG " , sizeof ( w8001 - > name ) ) ;
2010-08-29 09:00:47 +04:00
break ;
2011-01-11 12:06:58 +03:00
2010-08-29 09:00:47 +04:00
case 1 :
case 3 :
case 4 :
w8001 - > pktlen = W8001_PKTLEN_TOUCH9A ;
2011-01-11 12:06:58 +03:00
strlcat ( w8001 - > name , " 1FG " , sizeof ( w8001 - > name ) ) ;
w8001 - > id = 0x9a ;
2010-08-29 09:00:47 +04:00
break ;
2011-01-11 12:06:58 +03:00
2010-08-29 09:00:47 +04:00
case 5 :
w8001 - > pktlen = W8001_PKTLEN_TOUCH2FG ;
2010-08-29 09:00:47 +04:00
2010-11-27 12:50:54 +03:00
input_mt_init_slots ( dev , 2 ) ;
2010-08-29 09:00:47 +04:00
input_set_abs_params ( dev , ABS_MT_POSITION_X ,
0 , touch . x , 0 , 0 ) ;
input_set_abs_params ( dev , ABS_MT_POSITION_Y ,
0 , touch . y , 0 , 0 ) ;
input_set_abs_params ( dev , ABS_MT_TOOL_TYPE ,
2010-12-15 15:50:34 +03:00
0 , MT_TOOL_MAX , 0 , 0 ) ;
2011-01-11 12:06:58 +03:00
strlcat ( w8001 - > name , " 2FG " , sizeof ( w8001 - > name ) ) ;
if ( w8001 - > max_pen_x & & w8001 - > max_pen_y )
w8001 - > id = 0xE3 ;
else
w8001 - > id = 0xE2 ;
2010-08-29 09:00:47 +04:00
break ;
}
}
2011-01-11 12:06:58 +03:00
strlcat ( w8001 - > name , " Touchscreen " , sizeof ( w8001 - > name ) ) ;
2011-08-24 09:57:00 +04:00
return 0 ;
2008-11-20 00:58:50 +03:00
}
/*
* w8001_disconnect ( ) is the opposite of w8001_connect ( )
*/
static void w8001_disconnect ( struct serio * serio )
{
struct w8001 * w8001 = serio_get_drvdata ( serio ) ;
serio_close ( serio ) ;
2011-08-24 09:57:00 +04:00
input_unregister_device ( w8001 - > dev ) ;
2008-11-20 00:58:50 +03:00
kfree ( w8001 ) ;
2011-08-24 09:57:00 +04:00
serio_set_drvdata ( serio , NULL ) ;
2008-11-20 00:58:50 +03:00
}
/*
* w8001_connect ( ) is the routine that is called when someone adds a
* new serio device that supports the w8001 protocol and registers it as
* an input device .
*/
static int w8001_connect ( struct serio * serio , struct serio_driver * drv )
{
struct w8001 * w8001 ;
struct input_dev * input_dev ;
int err ;
w8001 = kzalloc ( sizeof ( struct w8001 ) , GFP_KERNEL ) ;
input_dev = input_allocate_device ( ) ;
if ( ! w8001 | | ! input_dev ) {
err = - ENOMEM ;
goto fail1 ;
}
w8001 - > serio = serio ;
w8001 - > dev = input_dev ;
init_completion ( & w8001 - > cmd_done ) ;
snprintf ( w8001 - > phys , sizeof ( w8001 - > phys ) , " %s/input0 " , serio - > phys ) ;
serio_set_drvdata ( serio , w8001 ) ;
err = serio_open ( serio , drv ) ;
if ( err )
goto fail2 ;
2009-09-04 04:22:03 +04:00
err = w8001_setup ( w8001 ) ;
if ( err )
2008-11-20 00:58:50 +03:00
goto fail3 ;
2011-01-11 12:06:58 +03:00
input_dev - > name = w8001 - > name ;
input_dev - > phys = w8001 - > phys ;
input_dev - > id . product = w8001 - > id ;
input_dev - > id . bustype = BUS_RS232 ;
input_dev - > id . vendor = 0x056a ;
input_dev - > id . version = 0x0100 ;
input_dev - > dev . parent = & serio - > dev ;
2011-08-24 09:57:00 +04:00
input_dev - > open = w8001_open ;
input_dev - > close = w8001_close ;
input_set_drvdata ( input_dev , w8001 ) ;
2008-11-20 00:58:50 +03:00
err = input_register_device ( w8001 - > dev ) ;
if ( err )
goto fail3 ;
return 0 ;
fail3 :
serio_close ( serio ) ;
fail2 :
serio_set_drvdata ( serio , NULL ) ;
fail1 :
input_free_device ( input_dev ) ;
kfree ( w8001 ) ;
return err ;
}
static struct serio_device_id w8001_serio_ids [ ] = {
{
. type = SERIO_RS232 ,
. proto = SERIO_W8001 ,
. id = SERIO_ANY ,
. extra = SERIO_ANY ,
} ,
{ 0 }
} ;
MODULE_DEVICE_TABLE ( serio , w8001_serio_ids ) ;
static struct serio_driver w8001_drv = {
. driver = {
. name = " w8001 " ,
} ,
. description = DRIVER_DESC ,
. id_table = w8001_serio_ids ,
. interrupt = w8001_interrupt ,
. connect = w8001_connect ,
. disconnect = w8001_disconnect ,
} ;
2012-04-04 10:50:17 +04:00
module_serio_driver ( w8001_drv ) ;