2011-01-08 01:45:50 +03:00
/*
* HID driver for multitouch panels
*
* Copyright ( c ) 2010 - 2011 Stephane Chatty < chatty @ enac . fr >
* Copyright ( c ) 2010 - 2011 Benjamin Tissoires < benjamin . tissoires @ gmail . com >
* Copyright ( c ) 2010 - 2011 Ecole Nationale de l ' Aviation Civile , France
*
2011-03-09 08:20:57 +03:00
* This code is partly based on hid - egalax . c :
*
* Copyright ( c ) 2010 Stephane Chatty < chatty @ enac . fr >
* Copyright ( c ) 2010 Henrik Rydberg < rydberg @ euromail . se >
* Copyright ( c ) 2010 Canonical , Ltd .
*
2011-03-22 19:34:01 +03:00
* This code is partly based on hid - 3 m - pct . c :
*
* Copyright ( c ) 2009 - 2010 Stephane Chatty < chatty @ enac . fr >
* Copyright ( c ) 2010 Henrik Rydberg < rydberg @ euromail . se >
* Copyright ( c ) 2010 Canonical , Ltd .
*
2011-01-08 01:45:50 +03:00
*/
/*
* 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/device.h>
# include <linux/hid.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/usb.h>
# include <linux/input/mt.h>
# include "usbhid/usbhid.h"
MODULE_AUTHOR ( " Stephane Chatty <chatty@enac.fr> " ) ;
2011-01-31 13:28:21 +03:00
MODULE_AUTHOR ( " Benjamin Tissoires <benjamin.tissoires@gmail.com> " ) ;
2011-01-08 01:45:50 +03:00
MODULE_DESCRIPTION ( " HID multitouch panels " ) ;
MODULE_LICENSE ( " GPL " ) ;
# include "hid-ids.h"
/* quirks to control the device */
# define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0)
# define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1)
2011-01-11 18:45:54 +03:00
# define MT_QUIRK_CYPRESS (1 << 2)
2011-01-08 01:47:27 +03:00
# define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
2011-01-11 18:45:54 +03:00
# define MT_QUIRK_VALID_IS_INRANGE (1 << 4)
# define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5)
2011-03-09 08:20:57 +03:00
# define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 6)
2011-04-22 13:51:48 +04:00
# define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 7)
2011-01-08 01:45:50 +03:00
struct mt_slot {
__s32 x , y , p , w , h ;
__s32 contactid ; /* the device ContactID assigned to this slot */
bool touch_state ; /* is the touch valid? */
bool seen_in_this_frame ; /* has this slot been updated */
} ;
struct mt_device {
struct mt_slot curdata ; /* placeholder of incoming data */
struct mt_class * mtclass ; /* our mt device class */
unsigned last_field_index ; /* last field index of the report */
unsigned last_slot_field ; /* the last field of a slot */
2011-06-12 10:22:08 +04:00
int last_mt_collection ; /* last known mt-related collection */
2011-01-08 01:45:50 +03:00
__s8 inputmode ; /* InputMode HID feature, -1 if non-existent */
__u8 num_received ; /* how many contacts we received */
__u8 num_expected ; /* expected last contact index */
2011-03-18 16:27:52 +03:00
__u8 maxcontacts ;
2011-01-08 01:45:50 +03:00
bool curvalid ; /* is the current contact valid? */
2011-03-18 16:27:52 +03:00
struct mt_slot * slots ;
2011-01-08 01:45:50 +03:00
} ;
struct mt_class {
2011-01-11 18:45:54 +03:00
__s32 name ; /* MT_CLS */
2011-01-08 01:45:50 +03:00
__s32 quirks ;
__s32 sn_move ; /* Signal/noise ratio for move events */
2011-03-22 19:34:01 +03:00
__s32 sn_width ; /* Signal/noise ratio for width events */
__s32 sn_height ; /* Signal/noise ratio for height events */
2011-01-08 01:45:50 +03:00
__s32 sn_pressure ; /* Signal/noise ratio for pressure events */
__u8 maxcontacts ;
} ;
/* classes of device behavior */
2011-05-20 17:59:34 +04:00
# define MT_CLS_DEFAULT 0x0001
# define MT_CLS_CONFIDENCE 0x0002
# define MT_CLS_CONFIDENCE_MINUS_ONE 0x0003
# define MT_CLS_DUAL_INRANGE_CONTACTID 0x0004
# define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0005
# define MT_CLS_DUAL_NSMU_CONTACTID 0x0006
/* vendor specific classes */
# define MT_CLS_3M 0x0101
# define MT_CLS_CYPRESS 0x0102
# define MT_CLS_EGALAX 0x0103
2011-01-08 01:45:50 +03:00
2011-03-18 16:27:52 +03:00
# define MT_DEFAULT_MAXCONTACT 10
2011-01-08 01:45:50 +03:00
/*
* these device - dependent functions determine what slot corresponds
* to a valid contact that was just read .
*/
2011-01-08 01:46:30 +03:00
static int cypress_compute_slot ( struct mt_device * td )
{
if ( td - > curdata . contactid ! = 0 | | td - > num_received = = 0 )
return td - > curdata . contactid ;
else
return - 1 ;
}
2011-01-08 01:45:50 +03:00
static int find_slot_from_contactid ( struct mt_device * td )
{
int i ;
2011-03-18 16:27:52 +03:00
for ( i = 0 ; i < td - > maxcontacts ; + + i ) {
2011-01-08 01:45:50 +03:00
if ( td - > slots [ i ] . contactid = = td - > curdata . contactid & &
td - > slots [ i ] . touch_state )
return i ;
}
2011-03-18 16:27:52 +03:00
for ( i = 0 ; i < td - > maxcontacts ; + + i ) {
2011-01-08 01:45:50 +03:00
if ( ! td - > slots [ i ] . seen_in_this_frame & &
! td - > slots [ i ] . touch_state )
return i ;
}
/* should not occurs. If this happens that means
* that the device sent more touches that it says
* in the report descriptor . It is ignored then . */
2011-01-11 18:45:54 +03:00
return - 1 ;
2011-01-08 01:45:50 +03:00
}
struct mt_class mt_classes [ ] = {
2011-01-11 18:45:54 +03:00
{ . name = MT_CLS_DEFAULT ,
2011-03-18 16:27:52 +03:00
. quirks = MT_QUIRK_NOT_SEEN_MEANS_UP } ,
2011-05-20 17:59:34 +04:00
{ . name = MT_CLS_CONFIDENCE ,
. quirks = MT_QUIRK_VALID_IS_CONFIDENCE } ,
{ . name = MT_CLS_CONFIDENCE_MINUS_ONE ,
. quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE } ,
2011-01-31 13:28:20 +03:00
{ . name = MT_CLS_DUAL_INRANGE_CONTACTID ,
2011-01-11 18:45:54 +03:00
. quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTID ,
. maxcontacts = 2 } ,
2011-01-31 13:28:20 +03:00
{ . name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER ,
2011-01-11 18:45:54 +03:00
. quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTNUMBER ,
. maxcontacts = 2 } ,
2011-05-20 17:59:34 +04:00
{ . name = MT_CLS_DUAL_NSMU_CONTACTID ,
. quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
MT_QUIRK_SLOT_IS_CONTACTID ,
. maxcontacts = 2 } ,
/*
* vendor specific classes
*/
{ . name = MT_CLS_3M ,
. quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
MT_QUIRK_SLOT_IS_CONTACTID ,
. sn_move = 2048 ,
. sn_width = 128 ,
. sn_height = 128 } ,
2011-01-11 18:45:54 +03:00
{ . name = MT_CLS_CYPRESS ,
. quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
MT_QUIRK_CYPRESS ,
. maxcontacts = 10 } ,
2011-03-09 08:20:57 +03:00
{ . name = MT_CLS_EGALAX ,
. quirks = MT_QUIRK_SLOT_IS_CONTACTID |
MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_EGALAX_XYZ_FIXUP ,
. maxcontacts = 2 ,
. sn_move = 4096 ,
. sn_pressure = 32 ,
} ,
2011-03-18 16:27:53 +03:00
2011-01-11 18:45:54 +03:00
{ }
2011-01-08 01:45:50 +03:00
} ;
2011-02-24 21:30:59 +03:00
static void mt_feature_mapping ( struct hid_device * hdev ,
2011-01-08 01:45:50 +03:00
struct hid_field * field , struct hid_usage * usage )
{
2011-03-18 16:27:52 +03:00
struct mt_device * td = hid_get_drvdata ( hdev ) ;
switch ( usage - > hid ) {
case HID_DG_INPUTMODE :
2011-01-08 01:45:50 +03:00
td - > inputmode = field - > report - > id ;
2011-03-18 16:27:52 +03:00
break ;
case HID_DG_CONTACTMAX :
td - > maxcontacts = field - > value [ 0 ] ;
if ( td - > mtclass - > maxcontacts )
/* check if the maxcontacts is given by the class */
td - > maxcontacts = td - > mtclass - > maxcontacts ;
break ;
2011-01-08 01:45:50 +03:00
}
}
static void set_abs ( struct input_dev * input , unsigned int code ,
struct hid_field * field , int snratio )
{
int fmin = field - > logical_minimum ;
int fmax = field - > logical_maximum ;
int fuzz = snratio ? ( fmax - fmin ) / snratio : 0 ;
input_set_abs_params ( input , code , fmin , fmax , fuzz , 0 ) ;
}
static int mt_input_mapping ( struct hid_device * hdev , struct hid_input * hi ,
struct hid_field * field , struct hid_usage * usage ,
unsigned long * * bit , int * max )
{
struct mt_device * td = hid_get_drvdata ( hdev ) ;
struct mt_class * cls = td - > mtclass ;
2011-03-09 08:20:57 +03:00
__s32 quirks = cls - > quirks ;
2011-01-08 01:45:50 +03:00
switch ( usage - > hid & HID_USAGE_PAGE ) {
case HID_UP_GENDESK :
switch ( usage - > hid ) {
case HID_GD_X :
2011-03-09 08:20:57 +03:00
if ( quirks & MT_QUIRK_EGALAX_XYZ_FIXUP )
field - > logical_maximum = 32760 ;
2011-01-08 01:45:50 +03:00
hid_map_usage ( hi , usage , bit , max ,
EV_ABS , ABS_MT_POSITION_X ) ;
set_abs ( hi - > input , ABS_MT_POSITION_X , field ,
cls - > sn_move ) ;
/* touchscreen emulation */
set_abs ( hi - > input , ABS_X , field , cls - > sn_move ) ;
2011-06-12 10:22:08 +04:00
if ( td - > last_mt_collection = = usage - > collection_index ) {
td - > last_slot_field = usage - > hid ;
td - > last_field_index = field - > index ;
}
2011-01-08 01:45:50 +03:00
return 1 ;
case HID_GD_Y :
2011-03-09 08:20:57 +03:00
if ( quirks & MT_QUIRK_EGALAX_XYZ_FIXUP )
field - > logical_maximum = 32760 ;
2011-01-08 01:45:50 +03:00
hid_map_usage ( hi , usage , bit , max ,
EV_ABS , ABS_MT_POSITION_Y ) ;
set_abs ( hi - > input , ABS_MT_POSITION_Y , field ,
cls - > sn_move ) ;
/* touchscreen emulation */
set_abs ( hi - > input , ABS_Y , field , cls - > sn_move ) ;
2011-06-12 10:22:08 +04:00
if ( td - > last_mt_collection = = usage - > collection_index ) {
td - > last_slot_field = usage - > hid ;
td - > last_field_index = field - > index ;
}
2011-01-08 01:45:50 +03:00
return 1 ;
}
return 0 ;
case HID_UP_DIGITIZER :
switch ( usage - > hid ) {
case HID_DG_INRANGE :
2011-06-12 10:22:08 +04:00
if ( td - > last_mt_collection = = usage - > collection_index ) {
td - > last_slot_field = usage - > hid ;
td - > last_field_index = field - > index ;
}
2011-01-08 01:45:50 +03:00
return 1 ;
case HID_DG_CONFIDENCE :
2011-06-12 10:22:08 +04:00
if ( td - > last_mt_collection = = usage - > collection_index ) {
td - > last_slot_field = usage - > hid ;
td - > last_field_index = field - > index ;
}
2011-01-08 01:45:50 +03:00
return 1 ;
case HID_DG_TIPSWITCH :
hid_map_usage ( hi , usage , bit , max , EV_KEY , BTN_TOUCH ) ;
input_set_capability ( hi - > input , EV_KEY , BTN_TOUCH ) ;
2011-06-12 10:22:08 +04:00
if ( td - > last_mt_collection = = usage - > collection_index ) {
td - > last_slot_field = usage - > hid ;
td - > last_field_index = field - > index ;
}
2011-01-08 01:45:50 +03:00
return 1 ;
case HID_DG_CONTACTID :
2011-06-21 17:01:53 +04:00
if ( ! td - > maxcontacts )
td - > maxcontacts = MT_DEFAULT_MAXCONTACT ;
2011-03-18 16:27:52 +03:00
input_mt_init_slots ( hi - > input , td - > maxcontacts ) ;
2011-01-08 01:45:50 +03:00
td - > last_slot_field = usage - > hid ;
2011-04-21 16:15:59 +04:00
td - > last_field_index = field - > index ;
2011-06-12 10:22:08 +04:00
td - > last_mt_collection = usage - > collection_index ;
2011-01-08 01:45:50 +03:00
return 1 ;
case HID_DG_WIDTH :
hid_map_usage ( hi , usage , bit , max ,
EV_ABS , ABS_MT_TOUCH_MAJOR ) ;
2011-03-22 19:34:01 +03:00
set_abs ( hi - > input , ABS_MT_TOUCH_MAJOR , field ,
cls - > sn_width ) ;
2011-06-12 10:22:08 +04:00
if ( td - > last_mt_collection = = usage - > collection_index ) {
td - > last_slot_field = usage - > hid ;
td - > last_field_index = field - > index ;
}
2011-01-08 01:45:50 +03:00
return 1 ;
case HID_DG_HEIGHT :
hid_map_usage ( hi , usage , bit , max ,
EV_ABS , ABS_MT_TOUCH_MINOR ) ;
2011-03-22 19:34:01 +03:00
set_abs ( hi - > input , ABS_MT_TOUCH_MINOR , field ,
cls - > sn_height ) ;
2011-03-18 16:27:55 +03:00
input_set_abs_params ( hi - > input ,
ABS_MT_ORIENTATION , 0 , 1 , 0 , 0 ) ;
2011-06-12 10:22:08 +04:00
if ( td - > last_mt_collection = = usage - > collection_index ) {
td - > last_slot_field = usage - > hid ;
td - > last_field_index = field - > index ;
}
2011-01-08 01:45:50 +03:00
return 1 ;
case HID_DG_TIPPRESSURE :
2011-03-09 08:20:57 +03:00
if ( quirks & MT_QUIRK_EGALAX_XYZ_FIXUP )
field - > logical_minimum = 0 ;
2011-01-08 01:45:50 +03:00
hid_map_usage ( hi , usage , bit , max ,
EV_ABS , ABS_MT_PRESSURE ) ;
set_abs ( hi - > input , ABS_MT_PRESSURE , field ,
cls - > sn_pressure ) ;
/* touchscreen emulation */
set_abs ( hi - > input , ABS_PRESSURE , field ,
cls - > sn_pressure ) ;
2011-06-12 10:22:08 +04:00
if ( td - > last_mt_collection = = usage - > collection_index ) {
td - > last_slot_field = usage - > hid ;
td - > last_field_index = field - > index ;
}
2011-01-08 01:45:50 +03:00
return 1 ;
case HID_DG_CONTACTCOUNT :
2011-06-12 10:22:08 +04:00
if ( td - > last_mt_collection = = usage - > collection_index )
td - > last_field_index = field - > index ;
2011-01-08 01:45:50 +03:00
return 1 ;
case HID_DG_CONTACTMAX :
/* we don't set td->last_slot_field as contactcount and
* contact max are global to the report */
2011-06-12 10:22:08 +04:00
if ( td - > last_mt_collection = = usage - > collection_index )
td - > last_field_index = field - > index ;
2011-01-08 01:45:50 +03:00
return - 1 ;
}
/* let hid-input decide for the others */
return 0 ;
case 0xff000000 :
/* we do not want to map these: no input-oriented meaning */
return - 1 ;
}
return 0 ;
}
static int mt_input_mapped ( struct hid_device * hdev , struct hid_input * hi ,
struct hid_field * field , struct hid_usage * usage ,
unsigned long * * bit , int * max )
{
if ( usage - > type = = EV_KEY | | usage - > type = = EV_ABS )
set_bit ( usage - > type , hi - > input - > evbit ) ;
return - 1 ;
}
static int mt_compute_slot ( struct mt_device * td )
{
2011-01-11 18:45:54 +03:00
__s32 quirks = td - > mtclass - > quirks ;
2011-01-08 01:45:50 +03:00
2011-01-11 18:45:54 +03:00
if ( quirks & MT_QUIRK_SLOT_IS_CONTACTID )
return td - > curdata . contactid ;
2011-01-08 01:45:50 +03:00
2011-01-11 18:45:54 +03:00
if ( quirks & MT_QUIRK_CYPRESS )
2011-01-08 01:46:30 +03:00
return cypress_compute_slot ( td ) ;
2011-01-11 18:45:54 +03:00
if ( quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER )
return td - > num_received ;
2011-01-08 01:47:27 +03:00
2011-04-22 13:51:48 +04:00
if ( quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE )
return td - > curdata . contactid - 1 ;
2011-01-08 01:45:50 +03:00
return find_slot_from_contactid ( td ) ;
}
/*
* this function is called when a whole contact has been processed ,
* so that it can assign it to a slot and store the data there
*/
static void mt_complete_slot ( struct mt_device * td )
{
2011-01-11 18:45:54 +03:00
td - > curdata . seen_in_this_frame = true ;
2011-01-08 01:45:50 +03:00
if ( td - > curvalid ) {
int slotnum = mt_compute_slot ( td ) ;
2011-03-18 16:27:52 +03:00
if ( slotnum > = 0 & & slotnum < td - > maxcontacts )
2011-01-11 18:45:54 +03:00
td - > slots [ slotnum ] = td - > curdata ;
2011-01-08 01:45:50 +03:00
}
td - > num_received + + ;
}
/*
* this function is called when a whole packet has been received and processed ,
* so that it can decide what to send to the input layer .
*/
static void mt_emit_event ( struct mt_device * td , struct input_dev * input )
{
int i ;
2011-03-18 16:27:52 +03:00
for ( i = 0 ; i < td - > maxcontacts ; + + i ) {
2011-01-08 01:45:50 +03:00
struct mt_slot * s = & ( td - > slots [ i ] ) ;
if ( ( td - > mtclass - > quirks & MT_QUIRK_NOT_SEEN_MEANS_UP ) & &
! s - > seen_in_this_frame ) {
s - > touch_state = false ;
}
input_mt_slot ( input , i ) ;
input_mt_report_slot_state ( input , MT_TOOL_FINGER ,
s - > touch_state ) ;
2011-01-11 18:45:54 +03:00
if ( s - > touch_state ) {
2011-03-22 19:34:01 +03:00
/* this finger is on the screen */
int wide = ( s - > w > s - > h ) ;
/* divided by two to match visual scale of touch */
int major = max ( s - > w , s - > h ) > > 1 ;
int minor = min ( s - > w , s - > h ) > > 1 ;
2011-01-11 18:45:54 +03:00
input_event ( input , EV_ABS , ABS_MT_POSITION_X , s - > x ) ;
input_event ( input , EV_ABS , ABS_MT_POSITION_Y , s - > y ) ;
2011-03-22 19:34:01 +03:00
input_event ( input , EV_ABS , ABS_MT_ORIENTATION , wide ) ;
2011-01-11 18:45:54 +03:00
input_event ( input , EV_ABS , ABS_MT_PRESSURE , s - > p ) ;
2011-03-22 19:34:01 +03:00
input_event ( input , EV_ABS , ABS_MT_TOUCH_MAJOR , major ) ;
input_event ( input , EV_ABS , ABS_MT_TOUCH_MINOR , minor ) ;
2011-01-11 18:45:54 +03:00
}
2011-01-08 01:45:50 +03:00
s - > seen_in_this_frame = false ;
}
input_mt_report_pointer_emulation ( input , true ) ;
input_sync ( input ) ;
td - > num_received = 0 ;
}
static int mt_event ( struct hid_device * hid , struct hid_field * field ,
struct hid_usage * usage , __s32 value )
{
struct mt_device * td = hid_get_drvdata ( hid ) ;
2011-01-11 18:45:54 +03:00
__s32 quirks = td - > mtclass - > quirks ;
2011-01-08 01:45:50 +03:00
2011-03-18 16:27:52 +03:00
if ( hid - > claimed & HID_CLAIMED_INPUT & & td - > slots ) {
2011-01-08 01:45:50 +03:00
switch ( usage - > hid ) {
case HID_DG_INRANGE :
2011-01-11 18:45:54 +03:00
if ( quirks & MT_QUIRK_VALID_IS_INRANGE )
td - > curvalid = value ;
2011-01-08 01:45:50 +03:00
break ;
case HID_DG_TIPSWITCH :
2011-01-11 18:45:54 +03:00
if ( quirks & MT_QUIRK_NOT_SEEN_MEANS_UP )
td - > curvalid = value ;
2011-01-08 01:45:50 +03:00
td - > curdata . touch_state = value ;
break ;
case HID_DG_CONFIDENCE :
2011-01-11 18:45:54 +03:00
if ( quirks & MT_QUIRK_VALID_IS_CONFIDENCE )
td - > curvalid = value ;
2011-01-08 01:45:50 +03:00
break ;
case HID_DG_CONTACTID :
td - > curdata . contactid = value ;
break ;
case HID_DG_TIPPRESSURE :
td - > curdata . p = value ;
break ;
case HID_GD_X :
td - > curdata . x = value ;
break ;
case HID_GD_Y :
td - > curdata . y = value ;
break ;
case HID_DG_WIDTH :
td - > curdata . w = value ;
break ;
case HID_DG_HEIGHT :
td - > curdata . h = value ;
break ;
case HID_DG_CONTACTCOUNT :
/*
2011-01-11 18:45:54 +03:00
* Includes multi - packet support where subsequent
* packets are sent with zero contactcount .
2011-01-08 01:45:50 +03:00
*/
if ( value )
2011-01-11 18:45:54 +03:00
td - > num_expected = value ;
2011-01-08 01:45:50 +03:00
break ;
default :
/* fallback to the generic hidinput handling */
return 0 ;
}
2011-03-09 08:35:25 +03:00
if ( usage - > hid = = td - > last_slot_field ) {
2011-01-11 18:45:54 +03:00
mt_complete_slot ( td ) ;
2011-03-09 08:35:25 +03:00
}
2011-01-11 18:45:54 +03:00
if ( field - > index = = td - > last_field_index
& & td - > num_received > = td - > num_expected )
mt_emit_event ( td , field - > hidinput - > input ) ;
2011-01-08 01:45:50 +03:00
2011-01-11 18:45:54 +03:00
}
2011-01-08 01:45:50 +03:00
/* we have handled the hidinput part, now remains hiddev */
if ( hid - > claimed & HID_CLAIMED_HIDDEV & & hid - > hiddev_hid_event )
hid - > hiddev_hid_event ( hid , field , usage , value ) ;
return 1 ;
}
static void mt_set_input_mode ( struct hid_device * hdev )
{
struct mt_device * td = hid_get_drvdata ( hdev ) ;
struct hid_report * r ;
struct hid_report_enum * re ;
if ( td - > inputmode < 0 )
return ;
re = & ( hdev - > report_enum [ HID_FEATURE_REPORT ] ) ;
r = re - > report_id_hash [ td - > inputmode ] ;
if ( r ) {
r - > field [ 0 ] - > value [ 0 ] = 0x02 ;
usbhid_submit_report ( hdev , r , USB_DIR_OUT ) ;
}
}
static int mt_probe ( struct hid_device * hdev , const struct hid_device_id * id )
{
2011-01-11 18:45:54 +03:00
int ret , i ;
2011-01-08 01:45:50 +03:00
struct mt_device * td ;
2011-01-11 18:45:54 +03:00
struct mt_class * mtclass = mt_classes ; /* MT_CLS_DEFAULT */
for ( i = 0 ; mt_classes [ i ] . name ; i + + ) {
if ( id - > driver_data = = mt_classes [ i ] . name ) {
mtclass = & ( mt_classes [ i ] ) ;
break ;
}
}
2011-01-08 01:45:50 +03:00
/* This allows the driver to correctly support devices
* that emit events over several HID messages .
*/
hdev - > quirks | = HID_QUIRK_NO_INPUT_SYNC ;
2011-03-18 16:27:52 +03:00
td = kzalloc ( sizeof ( struct mt_device ) , GFP_KERNEL ) ;
2011-01-08 01:45:50 +03:00
if ( ! td ) {
dev_err ( & hdev - > dev , " cannot allocate multitouch data \n " ) ;
return - ENOMEM ;
}
td - > mtclass = mtclass ;
td - > inputmode = - 1 ;
2011-06-12 10:22:08 +04:00
td - > last_mt_collection = - 1 ;
2011-01-08 01:45:50 +03:00
hid_set_drvdata ( hdev , td ) ;
ret = hid_parse ( hdev ) ;
if ( ret ! = 0 )
goto fail ;
ret = hid_hw_start ( hdev , HID_CONNECT_DEFAULT ) ;
2011-01-11 18:45:54 +03:00
if ( ret )
2011-01-08 01:45:50 +03:00
goto fail ;
2011-03-18 16:27:52 +03:00
td - > slots = kzalloc ( td - > maxcontacts * sizeof ( struct mt_slot ) ,
GFP_KERNEL ) ;
if ( ! td - > slots ) {
dev_err ( & hdev - > dev , " cannot allocate multitouch slots \n " ) ;
hid_hw_stop ( hdev ) ;
ret = - ENOMEM ;
goto fail ;
}
2011-01-08 01:45:50 +03:00
mt_set_input_mode ( hdev ) ;
return 0 ;
fail :
kfree ( td ) ;
return ret ;
}
# ifdef CONFIG_PM
static int mt_reset_resume ( struct hid_device * hdev )
{
mt_set_input_mode ( hdev ) ;
return 0 ;
}
# endif
static void mt_remove ( struct hid_device * hdev )
{
struct mt_device * td = hid_get_drvdata ( hdev ) ;
hid_hw_stop ( hdev ) ;
2011-03-18 16:27:52 +03:00
kfree ( td - > slots ) ;
2011-01-08 01:45:50 +03:00
kfree ( td ) ;
hid_set_drvdata ( hdev , NULL ) ;
}
static const struct hid_device_id mt_devices [ ] = {
2011-03-22 19:34:01 +03:00
/* 3M panels */
{ . driver_data = MT_CLS_3M ,
HID_USB_DEVICE ( USB_VENDOR_ID_3M ,
USB_DEVICE_ID_3M1968 ) } ,
{ . driver_data = MT_CLS_3M ,
HID_USB_DEVICE ( USB_VENDOR_ID_3M ,
USB_DEVICE_ID_3M2256 ) } ,
2011-05-19 16:18:13 +04:00
/* ActionStar panels */
{ . driver_data = MT_CLS_DEFAULT ,
HID_USB_DEVICE ( USB_VENDOR_ID_ACTIONSTAR ,
USB_DEVICE_ID_ACTIONSTAR_1011 ) } ,
2011-03-18 16:27:54 +03:00
/* Cando panels */
{ . driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER ,
HID_USB_DEVICE ( USB_VENDOR_ID_CANDO ,
USB_DEVICE_ID_CANDO_MULTI_TOUCH ) } ,
{ . driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER ,
HID_USB_DEVICE ( USB_VENDOR_ID_CANDO ,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1 ) } ,
{ . driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER ,
HID_USB_DEVICE ( USB_VENDOR_ID_CANDO ,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 ) } ,
{ . driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER ,
HID_USB_DEVICE ( USB_VENDOR_ID_CANDO ,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6 ) } ,
2011-05-27 22:03:47 +04:00
/* Chunghwa Telecom touch panels */
{ . driver_data = MT_CLS_DEFAULT ,
HID_USB_DEVICE ( USB_VENDOR_ID_CHUNGHWAT ,
USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH ) } ,
2011-05-19 16:18:14 +04:00
/* CVTouch panels */
{ . driver_data = MT_CLS_DEFAULT ,
HID_USB_DEVICE ( USB_VENDOR_ID_CVTOUCH ,
USB_DEVICE_ID_CVTOUCH_SCREEN ) } ,
2011-01-08 01:46:30 +03:00
/* Cypress panel */
{ . driver_data = MT_CLS_CYPRESS ,
HID_USB_DEVICE ( USB_VENDOR_ID_CYPRESS ,
USB_DEVICE_ID_CYPRESS_TRUETOUCH ) } ,
2011-05-20 17:59:34 +04:00
/* eGalax devices (resistive) */
{ . driver_data = MT_CLS_EGALAX ,
HID_USB_DEVICE ( USB_VENDOR_ID_DWAV ,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH ) } ,
{ . driver_data = MT_CLS_EGALAX ,
HID_USB_DEVICE ( USB_VENDOR_ID_DWAV ,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3 ) } ,
/* eGalax devices (capacitive) */
{ . driver_data = MT_CLS_EGALAX ,
HID_USB_DEVICE ( USB_VENDOR_ID_DWAV ,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1 ) } ,
{ . driver_data = MT_CLS_EGALAX ,
HID_USB_DEVICE ( USB_VENDOR_ID_DWAV ,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2 ) } ,
{ . driver_data = MT_CLS_EGALAX ,
HID_USB_DEVICE ( USB_VENDOR_ID_DWAV ,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4 ) } ,
2011-05-19 13:37:29 +04:00
/* Elo TouchSystems IntelliTouch Plus panel */
{ . driver_data = MT_CLS_DUAL_NSMU_CONTACTID ,
HID_USB_DEVICE ( USB_VENDOR_ID_ELO ,
USB_DEVICE_ID_ELO_TS2515 ) } ,
2011-01-08 01:47:27 +03:00
/* GeneralTouch panel */
2011-01-31 13:28:20 +03:00
{ . driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER ,
2011-01-08 01:47:27 +03:00
HID_USB_DEVICE ( USB_VENDOR_ID_GENERAL_TOUCH ,
USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS ) } ,
2011-05-19 16:18:15 +04:00
/* GoodTouch panels */
{ . driver_data = MT_CLS_DEFAULT ,
HID_USB_DEVICE ( USB_VENDOR_ID_GOODTOUCH ,
USB_DEVICE_ID_GOODTOUCH_000f ) } ,
2011-05-09 19:54:14 +04:00
/* Ilitek dual touch panel */
{ . driver_data = MT_CLS_DEFAULT ,
HID_USB_DEVICE ( USB_VENDOR_ID_ILITEK ,
USB_DEVICE_ID_ILITEK_MULTITOUCH ) } ,
2011-01-31 13:28:22 +03:00
/* IRTOUCH panels */
{ . driver_data = MT_CLS_DUAL_INRANGE_CONTACTID ,
HID_USB_DEVICE ( USB_VENDOR_ID_IRTOUCHSYSTEMS ,
USB_DEVICE_ID_IRTOUCH_INFRARED_USB ) } ,
2011-05-18 17:27:24 +04:00
/* Lumio panels */
{ . driver_data = MT_CLS_CONFIDENCE_MINUS_ONE ,
HID_USB_DEVICE ( USB_VENDOR_ID_LUMIO ,
USB_DEVICE_ID_CRYSTALTOUCH ) } ,
2011-04-22 13:51:48 +04:00
/* MosArt panels */
{ . driver_data = MT_CLS_CONFIDENCE_MINUS_ONE ,
HID_USB_DEVICE ( USB_VENDOR_ID_ASUS ,
USB_DEVICE_ID_ASUS_T91MT ) } ,
{ . driver_data = MT_CLS_CONFIDENCE_MINUS_ONE ,
HID_USB_DEVICE ( USB_VENDOR_ID_ASUS ,
USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO ) } ,
{ . driver_data = MT_CLS_CONFIDENCE_MINUS_ONE ,
HID_USB_DEVICE ( USB_VENDOR_ID_TURBOX ,
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART ) } ,
2011-04-21 18:21:52 +04:00
/* PenMount panels */
{ . driver_data = MT_CLS_CONFIDENCE ,
HID_USB_DEVICE ( USB_VENDOR_ID_PENMOUNT ,
USB_DEVICE_ID_PENMOUNT_PCI ) } ,
2011-01-08 01:45:50 +03:00
/* PixCir-based panels */
2011-01-31 13:28:20 +03:00
{ . driver_data = MT_CLS_DUAL_INRANGE_CONTACTID ,
2011-01-08 01:45:50 +03:00
HID_USB_DEVICE ( USB_VENDOR_ID_HANVON ,
USB_DEVICE_ID_HANVON_MULTITOUCH ) } ,
2011-01-31 13:28:20 +03:00
{ . driver_data = MT_CLS_DUAL_INRANGE_CONTACTID ,
2011-01-08 01:45:50 +03:00
HID_USB_DEVICE ( USB_VENDOR_ID_CANDO ,
USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH ) } ,
2011-03-18 16:27:53 +03:00
/* Stantum panels */
2011-05-19 16:18:18 +04:00
{ . driver_data = MT_CLS_CONFIDENCE ,
2011-03-18 16:27:53 +03:00
HID_USB_DEVICE ( USB_VENDOR_ID_STANTUM ,
USB_DEVICE_ID_MTP ) } ,
2011-05-19 16:18:18 +04:00
{ . driver_data = MT_CLS_CONFIDENCE ,
2011-06-21 17:01:54 +04:00
HID_USB_DEVICE ( USB_VENDOR_ID_STANTUM_STM ,
2011-03-18 16:27:53 +03:00
USB_DEVICE_ID_MTP_STM ) } ,
2011-05-19 16:18:18 +04:00
{ . driver_data = MT_CLS_CONFIDENCE ,
2011-06-21 17:01:54 +04:00
HID_USB_DEVICE ( USB_VENDOR_ID_STANTUM_SITRONIX ,
2011-03-18 16:27:53 +03:00
USB_DEVICE_ID_MTP_SITRONIX ) } ,
2011-05-19 16:18:16 +04:00
/* Touch International panels */
{ . driver_data = MT_CLS_DEFAULT ,
HID_USB_DEVICE ( USB_VENDOR_ID_TOUCH_INTL ,
USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH ) } ,
2011-05-19 16:18:17 +04:00
/* Unitec panels */
{ . driver_data = MT_CLS_DEFAULT ,
HID_USB_DEVICE ( USB_VENDOR_ID_UNITEC ,
USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 ) } ,
{ . driver_data = MT_CLS_DEFAULT ,
HID_USB_DEVICE ( USB_VENDOR_ID_UNITEC ,
USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19 ) } ,
2011-01-08 01:45:50 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( hid , mt_devices ) ;
static const struct hid_usage_id mt_grabbed_usages [ ] = {
{ HID_ANY_ID , HID_ANY_ID , HID_ANY_ID } ,
{ HID_ANY_ID - 1 , HID_ANY_ID - 1 , HID_ANY_ID - 1 }
} ;
static struct hid_driver mt_driver = {
. name = " hid-multitouch " ,
. id_table = mt_devices ,
. probe = mt_probe ,
. remove = mt_remove ,
. input_mapping = mt_input_mapping ,
. input_mapped = mt_input_mapped ,
. feature_mapping = mt_feature_mapping ,
. usage_table = mt_grabbed_usages ,
. event = mt_event ,
# ifdef CONFIG_PM
. reset_resume = mt_reset_resume ,
# endif
} ;
static int __init mt_init ( void )
{
return hid_register_driver ( & mt_driver ) ;
}
static void __exit mt_exit ( void )
{
hid_unregister_driver ( & mt_driver ) ;
}
module_init ( mt_init ) ;
module_exit ( mt_exit ) ;