2009-10-25 12:13:58 -07:00
/*
* Dynapro serial touchscreen driver
*
* Copyright ( c ) 2009 Tias Guns
* Based on the inexio driver ( c ) Vojtech Pavlik and Dan Streetman and
* Richard Lemon
*
*/
/*
* 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 .
*/
/*
* 2009 / 09 / 19 Tias Guns < tias @ ulyssis . org >
* Copied inexio . c and edited for Dynapro protocol ( from retired Xorg module )
*/
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/input.h>
# include <linux/serio.h>
# define DRIVER_DESC "Dynapro serial touchscreen driver"
MODULE_AUTHOR ( " Tias Guns <tias@ulyssis.org> " ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
/*
* Definitions & global arrays .
*/
# define DYNAPRO_FORMAT_TOUCH_BIT 0x40
# define DYNAPRO_FORMAT_LENGTH 3
# define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80
# define DYNAPRO_MIN_XC 0
# define DYNAPRO_MAX_XC 0x3ff
# define DYNAPRO_MIN_YC 0
# define DYNAPRO_MAX_YC 0x3ff
# define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4))
# define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7))
# define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0])
/*
* Per - touchscreen data .
*/
struct dynapro {
struct input_dev * dev ;
struct serio * serio ;
int idx ;
unsigned char data [ DYNAPRO_FORMAT_LENGTH ] ;
char phys [ 32 ] ;
} ;
static void dynapro_process_data ( struct dynapro * pdynapro )
{
struct input_dev * dev = pdynapro - > dev ;
if ( DYNAPRO_FORMAT_LENGTH = = + + pdynapro - > idx ) {
input_report_abs ( dev , ABS_X , DYNAPRO_GET_XC ( pdynapro - > data ) ) ;
input_report_abs ( dev , ABS_Y , DYNAPRO_GET_YC ( pdynapro - > data ) ) ;
input_report_key ( dev , BTN_TOUCH ,
DYNAPRO_GET_TOUCHED ( pdynapro - > data ) ) ;
input_sync ( dev ) ;
pdynapro - > idx = 0 ;
}
}
static irqreturn_t dynapro_interrupt ( struct serio * serio ,
unsigned char data , unsigned int flags )
{
struct dynapro * pdynapro = serio_get_drvdata ( serio ) ;
pdynapro - > data [ pdynapro - > idx ] = data ;
if ( DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro - > data [ 0 ] )
dynapro_process_data ( pdynapro ) ;
else
dev_dbg ( & serio - > dev , " unknown/unsynchronized data: %x \n " ,
pdynapro - > data [ 0 ] ) ;
return IRQ_HANDLED ;
}
static void dynapro_disconnect ( struct serio * serio )
{
struct dynapro * pdynapro = serio_get_drvdata ( serio ) ;
input_get_device ( pdynapro - > dev ) ;
input_unregister_device ( pdynapro - > dev ) ;
serio_close ( serio ) ;
serio_set_drvdata ( serio , NULL ) ;
input_put_device ( pdynapro - > dev ) ;
kfree ( pdynapro ) ;
}
/*
* dynapro_connect ( ) is the routine that is called when someone adds a
* new serio device that supports dynapro protocol and registers it as
* an input device . This is usually accomplished using inputattach .
*/
static int dynapro_connect ( struct serio * serio , struct serio_driver * drv )
{
struct dynapro * pdynapro ;
struct input_dev * input_dev ;
int err ;
pdynapro = kzalloc ( sizeof ( struct dynapro ) , GFP_KERNEL ) ;
input_dev = input_allocate_device ( ) ;
if ( ! pdynapro | | ! input_dev ) {
err = - ENOMEM ;
goto fail1 ;
}
pdynapro - > serio = serio ;
pdynapro - > dev = input_dev ;
snprintf ( pdynapro - > phys , sizeof ( pdynapro - > phys ) ,
" %s/input0 " , serio - > phys ) ;
input_dev - > name = " Dynapro Serial TouchScreen " ;
input_dev - > phys = pdynapro - > phys ;
input_dev - > id . bustype = BUS_RS232 ;
input_dev - > id . vendor = SERIO_DYNAPRO ;
input_dev - > id . product = 0 ;
input_dev - > id . version = 0x0001 ;
input_dev - > dev . parent = & serio - > dev ;
input_dev - > evbit [ 0 ] = BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_ABS ) ;
input_dev - > keybit [ BIT_WORD ( BTN_TOUCH ) ] = BIT_MASK ( BTN_TOUCH ) ;
input_set_abs_params ( pdynapro - > dev , ABS_X ,
DYNAPRO_MIN_XC , DYNAPRO_MAX_XC , 0 , 0 ) ;
input_set_abs_params ( pdynapro - > dev , ABS_Y ,
DYNAPRO_MIN_YC , DYNAPRO_MAX_YC , 0 , 0 ) ;
serio_set_drvdata ( serio , pdynapro ) ;
err = serio_open ( serio , drv ) ;
if ( err )
goto fail2 ;
err = input_register_device ( pdynapro - > dev ) ;
if ( err )
goto fail3 ;
return 0 ;
fail3 : serio_close ( serio ) ;
fail2 : serio_set_drvdata ( serio , NULL ) ;
fail1 : input_free_device ( input_dev ) ;
kfree ( pdynapro ) ;
return err ;
}
/*
* The serio driver structure .
*/
2017-08-18 17:10:41 -07:00
static const struct serio_device_id dynapro_serio_ids [ ] = {
2009-10-25 12:13:58 -07:00
{
. type = SERIO_RS232 ,
. proto = SERIO_DYNAPRO ,
. id = SERIO_ANY ,
. extra = SERIO_ANY ,
} ,
{ 0 }
} ;
MODULE_DEVICE_TABLE ( serio , dynapro_serio_ids ) ;
static struct serio_driver dynapro_drv = {
. driver = {
. name = " dynapro " ,
} ,
. description = DRIVER_DESC ,
. id_table = dynapro_serio_ids ,
. interrupt = dynapro_interrupt ,
. connect = dynapro_connect ,
. disconnect = dynapro_disconnect ,
} ;
2012-04-03 23:50:17 -07:00
module_serio_driver ( dynapro_drv ) ;