2005-04-17 02:20:36 +04:00
/*
* Elo serial touchscreen driver
*
* Copyright ( c ) 2004 Vojtech Pavlik
*/
/*
* 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 .
*/
/*
* This driver can handle serial Elo touchscreens using either the Elo standard
* ' E271 - 2210 ' 10 - byte protocol , Elo legacy ' E281A - 4002 ' 6 - byte protocol , Elo
* legacy ' E271 - 140 ' 4 - byte protocol and Elo legacy ' E261 - 280 ' 3 - byte protocol .
*/
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/input.h>
# include <linux/serio.h>
# include <linux/init.h>
# define DRIVER_DESC "Elo serial touchscreen driver"
MODULE_AUTHOR ( " Vojtech Pavlik <vojtech@ucw.cz> " ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
/*
* Definitions & global arrays .
*/
# define ELO_MAX_LENGTH 10
/*
* Per - touchscreen data .
*/
struct elo {
2005-09-15 11:01:46 +04:00
struct input_dev * dev ;
2005-04-17 02:20:36 +04:00
struct serio * serio ;
int id ;
int idx ;
unsigned char csum ;
unsigned char data [ ELO_MAX_LENGTH ] ;
char phys [ 32 ] ;
} ;
static void elo_process_data_10 ( struct elo * elo , unsigned char data , struct pt_regs * regs )
{
2005-09-15 11:01:46 +04:00
struct input_dev * dev = elo - > dev ;
2005-04-17 02:20:36 +04:00
elo - > csum + = elo - > data [ elo - > idx ] = data ;
switch ( elo - > idx + + ) {
case 0 :
if ( data ! = ' U ' ) {
elo - > idx = 0 ;
elo - > csum = 0 ;
}
break ;
case 1 :
if ( data ! = ' T ' ) {
elo - > idx = 0 ;
elo - > csum = 0 ;
}
break ;
case 9 :
if ( elo - > csum ) {
input_regs ( dev , regs ) ;
input_report_abs ( dev , ABS_X , ( elo - > data [ 4 ] < < 8 ) | elo - > data [ 3 ] ) ;
input_report_abs ( dev , ABS_Y , ( elo - > data [ 6 ] < < 8 ) | elo - > data [ 5 ] ) ;
input_report_abs ( dev , ABS_PRESSURE , ( elo - > data [ 8 ] < < 8 ) | elo - > data [ 7 ] ) ;
2005-09-15 11:01:46 +04:00
input_report_key ( dev , BTN_TOUCH , elo - > data [ 8 ] | | elo - > data [ 7 ] ) ;
2005-04-17 02:20:36 +04:00
input_sync ( dev ) ;
}
elo - > idx = 0 ;
elo - > csum = 0 ;
break ;
}
}
static void elo_process_data_6 ( struct elo * elo , unsigned char data , struct pt_regs * regs )
{
2005-09-15 11:01:46 +04:00
struct input_dev * dev = elo - > dev ;
2005-04-17 02:20:36 +04:00
elo - > data [ elo - > idx ] = data ;
switch ( elo - > idx + + ) {
case 0 : if ( ( data & 0xc0 ) ! = 0xc0 ) elo - > idx = 0 ; break ;
case 1 : if ( ( data & 0xc0 ) ! = 0x80 ) elo - > idx = 0 ; break ;
case 2 : if ( ( data & 0xc0 ) ! = 0x40 ) elo - > idx = 0 ; break ;
case 3 :
if ( data & 0xc0 ) {
elo - > idx = 0 ;
break ;
}
input_regs ( dev , regs ) ;
input_report_abs ( dev , ABS_X , ( ( elo - > data [ 0 ] & 0x3f ) < < 6 ) | ( elo - > data [ 1 ] & 0x3f ) ) ;
input_report_abs ( dev , ABS_Y , ( ( elo - > data [ 2 ] & 0x3f ) < < 6 ) | ( elo - > data [ 3 ] & 0x3f ) ) ;
if ( elo - > id = = 2 ) {
input_report_key ( dev , BTN_TOUCH , 1 ) ;
input_sync ( dev ) ;
elo - > idx = 0 ;
}
break ;
case 4 :
if ( data ) {
input_sync ( dev ) ;
elo - > idx = 0 ;
}
break ;
case 5 :
if ( ( data & 0xf0 ) = = 0 ) {
input_report_abs ( dev , ABS_PRESSURE , elo - > data [ 5 ] ) ;
2005-09-15 11:01:46 +04:00
input_report_key ( dev , BTN_TOUCH , ! ! elo - > data [ 5 ] ) ;
2005-04-17 02:20:36 +04:00
}
input_sync ( dev ) ;
elo - > idx = 0 ;
break ;
}
}
static void elo_process_data_3 ( struct elo * elo , unsigned char data , struct pt_regs * regs )
{
2005-09-15 11:01:46 +04:00
struct input_dev * dev = elo - > dev ;
2005-04-17 02:20:36 +04:00
elo - > data [ elo - > idx ] = data ;
switch ( elo - > idx + + ) {
case 0 :
if ( ( data & 0x7f ) ! = 0x01 )
elo - > idx = 0 ;
break ;
case 2 :
input_regs ( dev , regs ) ;
input_report_key ( dev , BTN_TOUCH , ! ( elo - > data [ 1 ] & 0x80 ) ) ;
input_report_abs ( dev , ABS_X , elo - > data [ 1 ] ) ;
input_report_abs ( dev , ABS_Y , elo - > data [ 2 ] ) ;
input_sync ( dev ) ;
elo - > idx = 0 ;
break ;
}
}
static irqreturn_t elo_interrupt ( struct serio * serio ,
unsigned char data , unsigned int flags , struct pt_regs * regs )
{
struct elo * elo = serio_get_drvdata ( serio ) ;
switch ( elo - > id ) {
case 0 :
elo_process_data_10 ( elo , data , regs ) ;
break ;
case 1 :
case 2 :
elo_process_data_6 ( elo , data , regs ) ;
break ;
case 3 :
elo_process_data_3 ( elo , data , regs ) ;
break ;
}
return IRQ_HANDLED ;
}
/*
* elo_disconnect ( ) is the opposite of elo_connect ( )
*/
static void elo_disconnect ( struct serio * serio )
{
struct elo * elo = serio_get_drvdata ( serio ) ;
2005-09-15 11:01:46 +04:00
input_unregister_device ( elo - > dev ) ;
2005-04-17 02:20:36 +04:00
serio_close ( serio ) ;
serio_set_drvdata ( serio , NULL ) ;
kfree ( elo ) ;
}
/*
* elo_connect ( ) is the routine that is called when someone adds a
* new serio device that supports Gunze protocol and registers it as
* an input device .
*/
static int elo_connect ( struct serio * serio , struct serio_driver * drv )
{
struct elo * elo ;
2005-09-15 11:01:46 +04:00
struct input_dev * input_dev ;
2005-04-17 02:20:36 +04:00
int err ;
2005-09-15 11:01:46 +04:00
elo = kzalloc ( sizeof ( struct elo ) , GFP_KERNEL ) ;
input_dev = input_allocate_device ( ) ;
if ( ! elo | | ! input_dev ) {
err = - ENOMEM ;
goto fail ;
}
2005-04-17 02:20:36 +04:00
2005-09-15 11:01:46 +04:00
elo - > serio = serio ;
elo - > id = serio - > id . id ;
elo - > dev = input_dev ;
snprintf ( elo - > phys , sizeof ( elo - > phys ) , " %s/input0 " , serio - > phys ) ;
2005-04-17 02:20:36 +04:00
2005-09-15 11:01:46 +04:00
input_dev - > private = elo ;
input_dev - > name = " Elo Serial TouchScreen " ;
input_dev - > phys = elo - > phys ;
input_dev - > id . bustype = BUS_RS232 ;
input_dev - > id . vendor = SERIO_ELO ;
input_dev - > id . product = elo - > id ;
input_dev - > id . version = 0x0100 ;
input_dev - > cdev . dev = & serio - > dev ;
2005-04-17 02:20:36 +04:00
2005-09-15 11:01:46 +04:00
input_dev - > evbit [ 0 ] = BIT ( EV_KEY ) | BIT ( EV_ABS ) ;
input_dev - > keybit [ LONG ( BTN_TOUCH ) ] = BIT ( BTN_TOUCH ) ;
2005-04-17 02:20:36 +04:00
switch ( elo - > id ) {
case 0 : /* 10-byte protocol */
2005-09-15 11:01:46 +04:00
input_set_abs_params ( input_dev , ABS_X , 96 , 4000 , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_Y , 96 , 4000 , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_PRESSURE , 0 , 255 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
break ;
2005-05-29 11:28:50 +04:00
2005-04-17 02:20:36 +04:00
case 1 : /* 6-byte protocol */
2005-09-15 11:01:46 +04:00
input_set_abs_params ( input_dev , ABS_PRESSURE , 0 , 15 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
case 2 : /* 4-byte protocol */
2005-09-15 11:01:46 +04:00
input_set_abs_params ( input_dev , ABS_X , 96 , 4000 , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_Y , 96 , 4000 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
break ;
case 3 : /* 3-byte protocol */
2005-09-15 11:01:46 +04:00
input_set_abs_params ( input_dev , ABS_X , 0 , 255 , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_Y , 0 , 255 , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
break ;
}
serio_set_drvdata ( serio , elo ) ;
err = serio_open ( serio , drv ) ;
2005-09-15 11:01:46 +04:00
if ( err )
goto fail ;
2005-04-17 02:20:36 +04:00
2005-09-15 11:01:46 +04:00
input_register_device ( elo - > dev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2005-09-15 11:01:46 +04:00
fail : serio_set_drvdata ( serio , NULL ) ;
input_free_device ( input_dev ) ;
kfree ( elo ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
/*
* The serio driver structure .
*/
static struct serio_device_id elo_serio_ids [ ] = {
{
. type = SERIO_RS232 ,
. proto = SERIO_ELO ,
. id = SERIO_ANY ,
. extra = SERIO_ANY ,
} ,
{ 0 }
} ;
MODULE_DEVICE_TABLE ( serio , elo_serio_ids ) ;
static struct serio_driver elo_drv = {
. driver = {
. name = " elo " ,
} ,
. description = DRIVER_DESC ,
. id_table = elo_serio_ids ,
. interrupt = elo_interrupt ,
. connect = elo_connect ,
. disconnect = elo_disconnect ,
} ;
/*
* The functions for inserting / removing us as a module .
*/
static int __init elo_init ( void )
{
serio_register_driver ( & elo_drv ) ;
return 0 ;
}
static void __exit elo_exit ( void )
{
serio_unregister_driver ( & elo_drv ) ;
}
module_init ( elo_init ) ;
module_exit ( elo_exit ) ;