2006-07-13 18:01:36 -07:00
/*
2007-05-07 16:16:29 -04:00
* drivers / input / tablet / wacom_sys . c
2006-07-13 18:01:36 -07:00
*
2009-12-15 00:35:24 -08:00
* USB Wacom tablet support - system specific code
2006-07-13 18:01:36 -07: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 "wacom_wac.h"
2010-03-19 22:18:15 -07:00
# include "wacom.h"
2006-07-13 18:01:36 -07:00
2008-11-24 11:44:27 -05:00
/* defines to get HID report descriptor */
# define HID_DEVICET_HID (USB_TYPE_CLASS | 0x01)
# define HID_DEVICET_REPORT (USB_TYPE_CLASS | 0x02)
# define HID_USAGE_UNDEFINED 0x00
# define HID_USAGE_PAGE 0x05
# define HID_USAGE_PAGE_DIGITIZER 0x0d
# define HID_USAGE_PAGE_DESKTOP 0x01
# define HID_USAGE 0x09
# define HID_USAGE_X 0x30
# define HID_USAGE_Y 0x31
# define HID_USAGE_X_TILT 0x3d
# define HID_USAGE_Y_TILT 0x3e
# define HID_USAGE_FINGER 0x22
# define HID_USAGE_STYLUS 0x20
# define HID_COLLECTION 0xc0
enum {
WCM_UNDEFINED = 0 ,
WCM_DESKTOP ,
WCM_DIGITIZER ,
} ;
struct hid_descriptor {
struct usb_descriptor_header header ;
__le16 bcdHID ;
u8 bCountryCode ;
u8 bNumDescriptors ;
u8 bDescriptorType ;
__le16 wDescriptorLength ;
} __attribute__ ( ( packed ) ) ;
/* defines to get/set USB message */
2006-07-13 18:01:36 -07:00
# define USB_REQ_GET_REPORT 0x01
# define USB_REQ_SET_REPORT 0x09
2008-11-24 11:44:27 -05:00
# define WAC_HID_FEATURE_REPORT 0x03
2006-07-13 18:01:36 -07:00
static int usb_get_report ( struct usb_interface * intf , unsigned char type ,
unsigned char id , void * buf , int size )
{
return usb_control_msg ( interface_to_usbdev ( intf ) ,
usb_rcvctrlpipe ( interface_to_usbdev ( intf ) , 0 ) ,
USB_REQ_GET_REPORT , USB_TYPE_CLASS | USB_RECIP_INTERFACE ,
( type < < 8 ) + id , intf - > altsetting [ 0 ] . desc . bInterfaceNumber ,
buf , size , 100 ) ;
}
static int usb_set_report ( struct usb_interface * intf , unsigned char type ,
unsigned char id , void * buf , int size )
{
return usb_control_msg ( interface_to_usbdev ( intf ) ,
usb_sndctrlpipe ( interface_to_usbdev ( intf ) , 0 ) ,
USB_REQ_SET_REPORT , USB_TYPE_CLASS | USB_RECIP_INTERFACE ,
( type < < 8 ) + id , intf - > altsetting [ 0 ] . desc . bInterfaceNumber ,
buf , size , 1000 ) ;
}
2006-11-20 03:23:58 +01:00
static void wacom_sys_irq ( struct urb * urb )
2006-07-13 18:01:36 -07:00
{
struct wacom * wacom = urb - > context ;
int retval ;
switch ( urb - > status ) {
case 0 :
/* success */
break ;
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
/* this urb is terminated, clean up */
2008-05-05 11:36:18 -04:00
dbg ( " %s - urb shutting down with status: %d " , __func__ , urb - > status ) ;
2006-07-13 18:01:36 -07:00
return ;
default :
2008-05-05 11:36:18 -04:00
dbg ( " %s - nonzero urb status received: %d " , __func__ , urb - > status ) ;
2006-07-13 18:01:36 -07:00
goto exit ;
}
2010-03-19 22:18:15 -07:00
wacom_wac_irq ( & wacom - > wacom_wac , urb - > actual_length ) ;
2006-07-13 18:01:36 -07:00
exit :
2008-04-15 01:31:57 -04:00
usb_mark_last_busy ( wacom - > usbdev ) ;
2010-03-19 22:18:15 -07:00
retval = usb_submit_urb ( urb , GFP_ATOMIC ) ;
2006-07-13 18:01:36 -07:00
if ( retval )
err ( " %s - usb_submit_urb failed with result %d " ,
2008-05-05 11:36:18 -04:00
__func__ , retval ) ;
2006-07-13 18:01:36 -07:00
}
static int wacom_open ( struct input_dev * dev )
{
2007-04-12 01:34:39 -04:00
struct wacom * wacom = input_get_drvdata ( dev ) ;
2010-10-04 21:46:11 -07:00
int retval = 0 ;
2006-07-13 18:01:36 -07:00
2010-10-04 21:46:11 -07:00
if ( usb_autopm_get_interface ( wacom - > intf ) < 0 )
2006-07-13 18:01:36 -07:00
return - EIO ;
2010-10-04 21:46:11 -07:00
mutex_lock ( & wacom - > lock ) ;
2008-04-15 01:31:57 -04:00
if ( usb_submit_urb ( wacom - > irq , GFP_KERNEL ) ) {
2010-10-04 21:46:11 -07:00
retval = - EIO ;
goto out ;
2008-04-15 01:31:57 -04:00
}
2010-03-19 22:18:15 -07:00
wacom - > open = true ;
2008-04-15 01:31:57 -04:00
wacom - > intf - > needs_remote_wakeup = 1 ;
2006-07-13 18:01:36 -07:00
2010-10-04 21:46:11 -07:00
out :
2008-04-15 01:31:57 -04:00
mutex_unlock ( & wacom - > lock ) ;
2010-10-10 14:24:16 -07:00
usb_autopm_put_interface ( wacom - > intf ) ;
2010-10-04 21:46:11 -07:00
return retval ;
2006-07-13 18:01:36 -07:00
}
static void wacom_close ( struct input_dev * dev )
{
2007-04-12 01:34:39 -04:00
struct wacom * wacom = input_get_drvdata ( dev ) ;
2010-10-10 14:24:16 -07:00
int autopm_error ;
autopm_error = usb_autopm_get_interface ( wacom - > intf ) ;
2006-07-13 18:01:36 -07:00
2008-04-15 01:31:57 -04:00
mutex_lock ( & wacom - > lock ) ;
2006-07-13 18:01:36 -07:00
usb_kill_urb ( wacom - > irq ) ;
2010-03-19 22:18:15 -07:00
wacom - > open = false ;
2008-04-15 01:31:57 -04:00
wacom - > intf - > needs_remote_wakeup = 0 ;
mutex_unlock ( & wacom - > lock ) ;
2010-10-04 21:46:11 -07:00
2010-10-10 14:24:16 -07:00
if ( ! autopm_error )
usb_autopm_put_interface ( wacom - > intf ) ;
2006-07-13 18:01:36 -07:00
}
2008-11-24 11:44:27 -05:00
static int wacom_parse_hid ( struct usb_interface * intf , struct hid_descriptor * hid_desc ,
2009-12-15 00:35:24 -08:00
struct wacom_features * features )
2008-11-24 11:44:27 -05:00
{
struct usb_device * dev = interface_to_usbdev ( intf ) ;
2009-12-15 00:35:24 -08:00
char limit = 0 ;
/* result has to be defined as int for some devices */
int result = 0 ;
2008-11-24 11:44:27 -05:00
int i = 0 , usage = WCM_UNDEFINED , finger = 0 , pen = 0 ;
unsigned char * report ;
report = kzalloc ( hid_desc - > wDescriptorLength , GFP_KERNEL ) ;
if ( ! report )
return - ENOMEM ;
/* retrive report descriptors */
do {
result = usb_control_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) ,
USB_REQ_GET_DESCRIPTOR ,
USB_RECIP_INTERFACE | USB_DIR_IN ,
HID_DEVICET_REPORT < < 8 ,
intf - > altsetting [ 0 ] . desc . bInterfaceNumber , /* interface */
report ,
hid_desc - > wDescriptorLength ,
5000 ) ; /* 5 secs */
} while ( result < 0 & & limit + + < 5 ) ;
2009-04-28 07:49:54 -07:00
/* No need to parse the Descriptor. It isn't an error though */
2008-11-24 11:44:27 -05:00
if ( result < 0 )
goto out ;
for ( i = 0 ; i < hid_desc - > wDescriptorLength ; i + + ) {
switch ( report [ i ] ) {
case HID_USAGE_PAGE :
switch ( report [ i + 1 ] ) {
case HID_USAGE_PAGE_DIGITIZER :
usage = WCM_DIGITIZER ;
i + + ;
break ;
case HID_USAGE_PAGE_DESKTOP :
usage = WCM_DESKTOP ;
i + + ;
break ;
}
break ;
case HID_USAGE :
switch ( report [ i + 1 ] ) {
case HID_USAGE_X :
if ( usage = = WCM_DESKTOP ) {
if ( finger ) {
2009-12-15 00:35:24 -08:00
features - > device_type = BTN_TOOL_DOUBLETAP ;
if ( features - > type = = TABLETPC2FG ) {
/* need to reset back */
features - > pktlen = WACOM_PKGLEN_TPC2FG ;
features - > device_type = BTN_TOOL_TRIPLETAP ;
}
2010-09-05 12:25:40 -07:00
if ( features - > type = = BAMBOO_PT ) {
/* need to reset back */
features - > pktlen = WACOM_PKGLEN_BBTOUCH ;
features - > device_type = BTN_TOOL_TRIPLETAP ;
features - > x_phy =
get_unaligned_le16 ( & report [ i + 5 ] ) ;
features - > x_max =
get_unaligned_le16 ( & report [ i + 8 ] ) ;
i + = 15 ;
} else {
features - > x_max =
get_unaligned_le16 ( & report [ i + 3 ] ) ;
features - > x_phy =
get_unaligned_le16 ( & report [ i + 6 ] ) ;
features - > unit = report [ i + 9 ] ;
features - > unitExpo = report [ i + 11 ] ;
i + = 12 ;
}
2008-11-24 11:44:27 -05:00
} else if ( pen ) {
2009-12-15 00:35:24 -08:00
/* penabled only accepts exact bytes of data */
if ( features - > type = = TABLETPC2FG )
2010-03-01 23:50:24 -08:00
features - > pktlen = WACOM_PKGLEN_GRAPHIRE ;
2010-09-05 12:25:40 -07:00
if ( features - > type = = BAMBOO_PT )
features - > pktlen = WACOM_PKGLEN_BBFUN ;
2009-12-15 00:35:24 -08:00
features - > device_type = BTN_TOOL_PEN ;
2008-11-24 11:44:27 -05:00
features - > x_max =
2010-03-19 22:33:38 -07:00
get_unaligned_le16 ( & report [ i + 3 ] ) ;
2008-11-24 11:44:27 -05:00
i + = 4 ;
}
} else if ( usage = = WCM_DIGITIZER ) {
/* max pressure isn't reported
features - > pressure_max = ( unsigned short )
( report [ i + 4 ] < < 8 | report [ i + 3 ] ) ;
*/
features - > pressure_max = 255 ;
i + = 4 ;
}
break ;
case HID_USAGE_Y :
2009-12-15 00:35:24 -08:00
if ( usage = = WCM_DESKTOP ) {
if ( finger ) {
features - > device_type = BTN_TOOL_DOUBLETAP ;
if ( features - > type = = TABLETPC2FG ) {
/* need to reset back */
features - > pktlen = WACOM_PKGLEN_TPC2FG ;
features - > device_type = BTN_TOOL_TRIPLETAP ;
features - > y_max =
2010-03-19 22:33:38 -07:00
get_unaligned_le16 ( & report [ i + 3 ] ) ;
2009-12-15 00:35:24 -08:00
features - > y_phy =
2010-03-19 22:33:38 -07:00
get_unaligned_le16 ( & report [ i + 6 ] ) ;
2009-12-15 00:35:24 -08:00
i + = 7 ;
2010-09-05 12:25:40 -07:00
} else if ( features - > type = = BAMBOO_PT ) {
/* need to reset back */
features - > pktlen = WACOM_PKGLEN_BBTOUCH ;
features - > device_type = BTN_TOOL_TRIPLETAP ;
features - > y_phy =
get_unaligned_le16 ( & report [ i + 3 ] ) ;
features - > y_max =
get_unaligned_le16 ( & report [ i + 6 ] ) ;
i + = 12 ;
2009-12-15 00:35:24 -08:00
} else {
features - > y_max =
features - > x_max ;
features - > y_phy =
2010-03-19 22:33:38 -07:00
get_unaligned_le16 ( & report [ i + 3 ] ) ;
2009-12-15 00:35:24 -08:00
i + = 4 ;
}
} else if ( pen ) {
/* penabled only accepts exact bytes of data */
if ( features - > type = = TABLETPC2FG )
2010-03-01 23:50:24 -08:00
features - > pktlen = WACOM_PKGLEN_GRAPHIRE ;
2010-09-05 12:25:40 -07:00
if ( features - > type = = BAMBOO_PT )
features - > pktlen = WACOM_PKGLEN_BBFUN ;
2009-12-15 00:35:24 -08:00
features - > device_type = BTN_TOOL_PEN ;
features - > y_max =
2010-03-19 22:33:38 -07:00
get_unaligned_le16 ( & report [ i + 3 ] ) ;
2009-12-15 00:35:24 -08:00
i + = 4 ;
}
}
2008-11-24 11:44:27 -05:00
break ;
case HID_USAGE_FINGER :
finger = 1 ;
i + + ;
break ;
case HID_USAGE_STYLUS :
pen = 1 ;
i + + ;
break ;
case HID_USAGE_UNDEFINED :
if ( usage = = WCM_DESKTOP & & finger ) /* capacity */
features - > pressure_max =
2010-03-19 22:33:38 -07:00
get_unaligned_le16 ( & report [ i + 3 ] ) ;
2008-11-24 11:44:27 -05:00
i + = 4 ;
break ;
}
break ;
case HID_COLLECTION :
2009-12-15 00:35:24 -08:00
/* reset UsagePage and Finger */
2008-11-24 11:44:27 -05:00
finger = usage = 0 ;
break ;
}
}
out :
2009-04-28 07:49:54 -07:00
result = 0 ;
2008-11-24 11:44:27 -05:00
kfree ( report ) ;
return result ;
}
2009-12-15 00:35:24 -08:00
static int wacom_query_tablet_data ( struct usb_interface * intf , struct wacom_features * features )
2009-08-20 21:41:04 -07:00
{
unsigned char * rep_data ;
2009-12-15 00:35:24 -08:00
int limit = 0 , report_id = 2 ;
int error = - ENOMEM ;
2009-08-20 21:41:04 -07:00
rep_data = kmalloc ( 2 , GFP_KERNEL ) ;
if ( ! rep_data )
2009-12-15 00:35:24 -08:00
return error ;
2010-09-12 00:08:40 -07:00
/* ask to report tablet data if it is 2FGT Tablet PC or
* not a Tablet PC */
if ( features - > type = = TABLETPC2FG ) {
2009-12-15 00:35:24 -08:00
do {
rep_data [ 0 ] = 3 ;
rep_data [ 1 ] = 4 ;
report_id = 3 ;
error = usb_set_report ( intf , WAC_HID_FEATURE_REPORT ,
report_id , rep_data , 2 ) ;
if ( error > = 0 )
error = usb_get_report ( intf ,
WAC_HID_FEATURE_REPORT , report_id ,
rep_data , 3 ) ;
} while ( ( error < 0 | | rep_data [ 1 ] ! = 4 ) & & limit + + < 5 ) ;
2010-09-12 00:08:40 -07:00
} else if ( features - > type ! = TABLETPC ) {
2009-12-15 00:35:24 -08:00
do {
rep_data [ 0 ] = 2 ;
rep_data [ 1 ] = 2 ;
error = usb_set_report ( intf , WAC_HID_FEATURE_REPORT ,
report_id , rep_data , 2 ) ;
if ( error > = 0 )
error = usb_get_report ( intf ,
WAC_HID_FEATURE_REPORT , report_id ,
rep_data , 2 ) ;
} while ( ( error < 0 | | rep_data [ 1 ] ! = 2 ) & & limit + + < 5 ) ;
}
2009-08-20 21:41:04 -07:00
kfree ( rep_data ) ;
return error < 0 ? error : 0 ;
}
2009-12-15 00:35:24 -08:00
static int wacom_retrieve_hid_descriptor ( struct usb_interface * intf ,
struct wacom_features * features )
{
int error = 0 ;
struct usb_host_interface * interface = intf - > cur_altsetting ;
struct hid_descriptor * hid_desc ;
2010-09-05 12:25:11 -07:00
/* default features */
2009-12-15 00:35:24 -08:00
features - > device_type = BTN_TOOL_PEN ;
2010-09-05 12:25:11 -07:00
features - > x_fuzz = 4 ;
features - > y_fuzz = 4 ;
features - > pressure_fuzz = 0 ;
features - > distance_fuzz = 0 ;
2009-12-15 00:35:24 -08:00
2010-09-12 00:08:40 -07:00
/* only Tablet PCs and Bamboo P&T need to retrieve the info */
2010-09-05 12:25:40 -07:00
if ( ( features - > type ! = TABLETPC ) & & ( features - > type ! = TABLETPC2FG ) & &
( features - > type ! = BAMBOO_PT ) )
2009-12-15 00:35:24 -08:00
goto out ;
if ( usb_get_extra_descriptor ( interface , HID_DEVICET_HID , & hid_desc ) ) {
if ( usb_get_extra_descriptor ( & interface - > endpoint [ 0 ] ,
HID_DEVICET_REPORT , & hid_desc ) ) {
printk ( " wacom: can not retrieve extra class descriptor \n " ) ;
error = 1 ;
goto out ;
}
}
error = wacom_parse_hid ( intf , hid_desc , features ) ;
if ( error )
goto out ;
out :
return error ;
}
2010-03-19 22:18:15 -07:00
struct wacom_usbdev_data {
struct list_head list ;
struct kref kref ;
struct usb_device * dev ;
struct wacom_shared shared ;
} ;
static LIST_HEAD ( wacom_udev_list ) ;
static DEFINE_MUTEX ( wacom_udev_list_lock ) ;
static struct wacom_usbdev_data * wacom_get_usbdev_data ( struct usb_device * dev )
{
struct wacom_usbdev_data * data ;
list_for_each_entry ( data , & wacom_udev_list , list ) {
if ( data - > dev = = dev ) {
kref_get ( & data - > kref ) ;
return data ;
}
}
return NULL ;
}
static int wacom_add_shared_data ( struct wacom_wac * wacom ,
struct usb_device * dev )
{
struct wacom_usbdev_data * data ;
int retval = 0 ;
mutex_lock ( & wacom_udev_list_lock ) ;
data = wacom_get_usbdev_data ( dev ) ;
if ( ! data ) {
data = kzalloc ( sizeof ( struct wacom_usbdev_data ) , GFP_KERNEL ) ;
if ( ! data ) {
retval = - ENOMEM ;
goto out ;
}
kref_init ( & data - > kref ) ;
data - > dev = dev ;
list_add_tail ( & data - > list , & wacom_udev_list ) ;
}
wacom - > shared = & data - > shared ;
out :
mutex_unlock ( & wacom_udev_list_lock ) ;
return retval ;
}
static void wacom_release_shared_data ( struct kref * kref )
{
struct wacom_usbdev_data * data =
container_of ( kref , struct wacom_usbdev_data , kref ) ;
mutex_lock ( & wacom_udev_list_lock ) ;
list_del ( & data - > list ) ;
mutex_unlock ( & wacom_udev_list_lock ) ;
kfree ( data ) ;
}
static void wacom_remove_shared_data ( struct wacom_wac * wacom )
{
struct wacom_usbdev_data * data ;
if ( wacom - > shared ) {
data = container_of ( wacom - > shared , struct wacom_usbdev_data , shared ) ;
kref_put ( & data - > kref , wacom_release_shared_data ) ;
wacom - > shared = NULL ;
}
}
2006-07-13 18:01:36 -07:00
static int wacom_probe ( struct usb_interface * intf , const struct usb_device_id * id )
{
struct usb_device * dev = interface_to_usbdev ( intf ) ;
struct usb_endpoint_descriptor * endpoint ;
struct wacom * wacom ;
struct wacom_wac * wacom_wac ;
2010-02-17 22:38:31 -08:00
struct wacom_features * features ;
2006-07-13 18:01:36 -07:00
struct input_dev * input_dev ;
2010-02-17 22:38:31 -08:00
int error ;
2006-07-13 18:01:36 -07:00
2010-02-17 22:38:31 -08:00
if ( ! id - > driver_info )
2010-02-10 23:06:23 -08:00
return - EINVAL ;
2006-07-13 18:01:36 -07:00
wacom = kzalloc ( sizeof ( struct wacom ) , GFP_KERNEL ) ;
input_dev = input_allocate_device ( ) ;
2010-03-19 22:18:15 -07:00
if ( ! wacom | | ! input_dev ) {
2010-02-17 22:38:31 -08:00
error = - ENOMEM ;
goto fail1 ;
}
2010-03-19 22:18:15 -07:00
wacom_wac = & wacom - > wacom_wac ;
2010-02-17 22:38:31 -08:00
wacom_wac - > features = * ( ( struct wacom_features * ) id - > driver_info ) ;
features = & wacom_wac - > features ;
if ( features - > pktlen > WACOM_PKGLEN_MAX ) {
error = - EINVAL ;
2006-07-13 18:01:36 -07:00
goto fail1 ;
2010-02-17 22:38:31 -08:00
}
2006-07-13 18:01:36 -07:00
2010-04-12 13:17:25 +02:00
wacom_wac - > data = usb_alloc_coherent ( dev , WACOM_PKGLEN_MAX ,
GFP_KERNEL , & wacom - > data_dma ) ;
2010-02-17 22:38:31 -08:00
if ( ! wacom_wac - > data ) {
error = - ENOMEM ;
2006-07-13 18:01:36 -07:00
goto fail1 ;
2010-02-17 22:38:31 -08:00
}
2006-07-13 18:01:36 -07:00
wacom - > irq = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2010-02-17 22:38:31 -08:00
if ( ! wacom - > irq ) {
error = - ENOMEM ;
2006-07-13 18:01:36 -07:00
goto fail2 ;
2010-02-17 22:38:31 -08:00
}
2006-07-13 18:01:36 -07:00
wacom - > usbdev = dev ;
2008-04-15 01:31:57 -04:00
wacom - > intf = intf ;
mutex_init ( & wacom - > lock ) ;
2006-07-13 18:01:36 -07:00
usb_make_path ( dev , wacom - > phys , sizeof ( wacom - > phys ) ) ;
strlcat ( wacom - > phys , " /input0 " , sizeof ( wacom - > phys ) ) ;
2010-03-19 22:18:15 -07:00
wacom_wac - > input = input_dev ;
2006-07-13 18:01:36 -07:00
2008-11-24 11:44:27 -05:00
endpoint = & intf - > cur_altsetting - > endpoint [ 0 ] . desc ;
2009-12-15 00:35:24 -08:00
/* Retrieve the physical and logical size for OEM devices */
error = wacom_retrieve_hid_descriptor ( intf , features ) ;
if ( error )
goto fail2 ;
2008-11-24 11:44:27 -05:00
2010-09-05 12:26:16 -07:00
wacom_setup_device_quirks ( features ) ;
2010-02-20 00:53:49 -08:00
strlcpy ( wacom_wac - > name , features - > name , sizeof ( wacom_wac - > name ) ) ;
2010-09-05 12:26:16 -07:00
if ( features - > quirks & WACOM_QUIRK_MULTI_INPUT ) {
2010-02-20 00:53:49 -08:00
/* Append the device type to the name */
strlcat ( wacom_wac - > name ,
features - > device_type = = BTN_TOOL_PEN ?
" Pen " : " Finger " ,
sizeof ( wacom_wac - > name ) ) ;
2010-03-19 22:18:15 -07:00
error = wacom_add_shared_data ( wacom_wac , dev ) ;
if ( error )
goto fail3 ;
2010-02-20 00:53:49 -08:00
}
2010-03-19 22:18:15 -07:00
input_dev - > name = wacom_wac - > name ;
input_dev - > dev . parent = & intf - > dev ;
input_dev - > open = wacom_open ;
input_dev - > close = wacom_close ;
usb_to_input_id ( dev , & input_dev - > id ) ;
input_set_drvdata ( input_dev , wacom ) ;
2010-02-17 22:38:31 -08:00
2010-03-19 22:18:15 -07:00
wacom_setup_input_capabilities ( input_dev , wacom_wac ) ;
2006-07-13 18:01:36 -07:00
usb_fill_int_urb ( wacom - > irq , dev ,
usb_rcvintpipe ( dev , endpoint - > bEndpointAddress ) ,
2009-12-15 00:35:24 -08:00
wacom_wac - > data , features - > pktlen ,
2006-09-26 13:34:47 -07:00
wacom_sys_irq , wacom , endpoint - > bInterval ) ;
2006-07-13 18:01:36 -07:00
wacom - > irq - > transfer_dma = wacom - > data_dma ;
wacom - > irq - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
2010-03-19 22:18:15 -07:00
error = input_register_device ( input_dev ) ;
2007-04-12 01:33:39 -04:00
if ( error )
2010-03-19 22:18:15 -07:00
goto fail4 ;
2006-07-13 18:01:36 -07:00
2009-12-15 00:35:24 -08:00
/* Note that if query fails it is not a hard failure */
wacom_query_tablet_data ( intf , features ) ;
2006-07-13 18:01:36 -07:00
usb_set_intfdata ( intf , wacom ) ;
return 0 ;
2010-03-19 22:18:15 -07:00
fail4 : wacom_remove_shared_data ( wacom_wac ) ;
2007-04-12 01:33:39 -04:00
fail3 : usb_free_urb ( wacom - > irq ) ;
2010-04-12 13:17:25 +02:00
fail2 : usb_free_coherent ( dev , WACOM_PKGLEN_MAX , wacom_wac - > data , wacom - > data_dma ) ;
2007-04-12 01:33:39 -04:00
fail1 : input_free_device ( input_dev ) ;
2006-07-13 18:01:36 -07:00
kfree ( wacom ) ;
2007-04-12 01:33:39 -04:00
return error ;
2006-07-13 18:01:36 -07:00
}
static void wacom_disconnect ( struct usb_interface * intf )
{
2008-04-15 01:31:57 -04:00
struct wacom * wacom = usb_get_intfdata ( intf ) ;
2006-07-13 18:01:36 -07:00
usb_set_intfdata ( intf , NULL ) ;
2008-04-15 01:31:57 -04:00
usb_kill_urb ( wacom - > irq ) ;
2010-03-19 22:18:15 -07:00
input_unregister_device ( wacom - > wacom_wac . input ) ;
2008-04-15 01:31:57 -04:00
usb_free_urb ( wacom - > irq ) ;
2010-04-12 13:17:25 +02:00
usb_free_coherent ( interface_to_usbdev ( intf ) , WACOM_PKGLEN_MAX ,
2010-03-19 22:18:15 -07:00
wacom - > wacom_wac . data , wacom - > data_dma ) ;
wacom_remove_shared_data ( & wacom - > wacom_wac ) ;
2008-04-15 01:31:57 -04:00
kfree ( wacom ) ;
}
static int wacom_suspend ( struct usb_interface * intf , pm_message_t message )
{
struct wacom * wacom = usb_get_intfdata ( intf ) ;
mutex_lock ( & wacom - > lock ) ;
usb_kill_urb ( wacom - > irq ) ;
mutex_unlock ( & wacom - > lock ) ;
return 0 ;
}
static int wacom_resume ( struct usb_interface * intf )
{
struct wacom * wacom = usb_get_intfdata ( intf ) ;
2010-03-19 22:18:15 -07:00
struct wacom_features * features = & wacom - > wacom_wac . features ;
2008-04-15 01:31:57 -04:00
int rv ;
mutex_lock ( & wacom - > lock ) ;
2010-04-13 23:07:52 -07:00
/* switch to wacom mode first */
wacom_query_tablet_data ( intf , features ) ;
if ( wacom - > open )
2008-04-15 01:31:57 -04:00
rv = usb_submit_urb ( wacom - > irq , GFP_NOIO ) ;
2010-04-13 23:07:52 -07:00
else
2008-04-15 01:31:57 -04:00
rv = 0 ;
2010-04-13 23:07:52 -07:00
2008-04-15 01:31:57 -04:00
mutex_unlock ( & wacom - > lock ) ;
return rv ;
}
static int wacom_reset_resume ( struct usb_interface * intf )
{
return wacom_resume ( intf ) ;
2006-07-13 18:01:36 -07:00
}
static struct usb_driver wacom_driver = {
. name = " wacom " ,
2010-02-10 23:06:23 -08:00
. id_table = wacom_ids ,
2006-07-13 18:01:36 -07:00
. probe = wacom_probe ,
. disconnect = wacom_disconnect ,
2008-04-15 01:31:57 -04:00
. suspend = wacom_suspend ,
. resume = wacom_resume ,
. reset_resume = wacom_reset_resume ,
. supports_autosuspend = 1 ,
2006-07-13 18:01:36 -07:00
} ;
static int __init wacom_init ( void )
{
int result ;
2010-02-10 23:06:23 -08:00
2006-07-13 18:01:36 -07:00
result = usb_register ( & wacom_driver ) ;
if ( result = = 0 )
2008-08-18 13:21:04 -07:00
printk ( KERN_INFO KBUILD_MODNAME " : " DRIVER_VERSION " : "
DRIVER_DESC " \n " ) ;
2006-07-13 18:01:36 -07:00
return result ;
}
static void __exit wacom_exit ( void )
{
usb_deregister ( & wacom_driver ) ;
}
module_init ( wacom_init ) ;
module_exit ( wacom_exit ) ;