2006-07-14 05:01:36 +04:00
/*
2007-05-08 00:16:29 +04:00
* drivers / input / tablet / wacom_sys . c
2006-07-14 05:01:36 +04:00
*
2009-12-15 11:35:24 +03:00
* USB Wacom tablet support - system specific code
2006-07-14 05:01:36 +04: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-20 08:18:15 +03:00
# include "wacom.h"
2006-07-14 05:01:36 +04:00
2008-11-24 19:44:27 +03: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
2011-10-27 09:32:52 +04:00
# define HID_COLLECTION 0xa1
# define HID_COLLECTION_LOGICAL 0x02
# define HID_COLLECTION_END 0xc0
2008-11-24 19:44:27 +03:00
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-14 05:01:36 +04:00
# define USB_REQ_GET_REPORT 0x01
# define USB_REQ_SET_REPORT 0x09
2011-09-08 01:08:54 +04:00
2008-11-24 19:44:27 +03:00
# define WAC_HID_FEATURE_REPORT 0x03
2011-08-16 11:17:56 +04:00
# define WAC_MSG_RETRIES 5
2006-07-14 05:01:36 +04:00
2011-09-08 01:08:54 +04:00
# define WAC_CMD_LED_CONTROL 0x20
# define WAC_CMD_ICON_START 0x21
# define WAC_CMD_ICON_XFER 0x23
# define WAC_CMD_RETRIES 10
static int wacom_get_report ( struct usb_interface * intf , u8 type , u8 id ,
void * buf , size_t size , unsigned int retries )
2006-07-14 05:01:36 +04:00
{
2011-09-08 01:08:54 +04:00
struct usb_device * dev = interface_to_usbdev ( intf ) ;
int retval ;
do {
retval = usb_control_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) ,
USB_REQ_GET_REPORT ,
2011-10-27 09:24:22 +04:00
USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE ,
2011-09-08 01:08:54 +04:00
( type < < 8 ) + id ,
intf - > altsetting [ 0 ] . desc . bInterfaceNumber ,
buf , size , 100 ) ;
} while ( ( retval = = - ETIMEDOUT | | retval = = - EPIPE ) & & - - retries ) ;
return retval ;
2006-07-14 05:01:36 +04:00
}
2011-09-08 01:08:54 +04:00
static int wacom_set_report ( struct usb_interface * intf , u8 type , u8 id ,
void * buf , size_t size , unsigned int retries )
2006-07-14 05:01:36 +04:00
{
2011-09-08 01:08:54 +04:00
struct usb_device * dev = interface_to_usbdev ( intf ) ;
int retval ;
do {
retval = usb_control_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
USB_REQ_SET_REPORT ,
USB_TYPE_CLASS | USB_RECIP_INTERFACE ,
( type < < 8 ) + id ,
intf - > altsetting [ 0 ] . desc . bInterfaceNumber ,
buf , size , 1000 ) ;
} while ( ( retval = = - ETIMEDOUT | | retval = = - EPIPE ) & & - - retries ) ;
return retval ;
2006-07-14 05:01:36 +04:00
}
2006-11-20 05:23:58 +03:00
static void wacom_sys_irq ( struct urb * urb )
2006-07-14 05:01:36 +04: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 19:36:18 +04:00
dbg ( " %s - urb shutting down with status: %d " , __func__ , urb - > status ) ;
2006-07-14 05:01:36 +04:00
return ;
default :
2008-05-05 19:36:18 +04:00
dbg ( " %s - nonzero urb status received: %d " , __func__ , urb - > status ) ;
2006-07-14 05:01:36 +04:00
goto exit ;
}
2010-03-20 08:18:15 +03:00
wacom_wac_irq ( & wacom - > wacom_wac , urb - > actual_length ) ;
2006-07-14 05:01:36 +04:00
exit :
2008-04-15 09:31:57 +04:00
usb_mark_last_busy ( wacom - > usbdev ) ;
2010-03-20 08:18:15 +03:00
retval = usb_submit_urb ( urb , GFP_ATOMIC ) ;
2006-07-14 05:01:36 +04:00
if ( retval )
err ( " %s - usb_submit_urb failed with result %d " ,
2008-05-05 19:36:18 +04:00
__func__ , retval ) ;
2006-07-14 05:01:36 +04:00
}
static int wacom_open ( struct input_dev * dev )
{
2007-04-12 09:34:39 +04:00
struct wacom * wacom = input_get_drvdata ( dev ) ;
2010-10-05 08:46:11 +04:00
int retval = 0 ;
2006-07-14 05:01:36 +04:00
2010-10-05 08:46:11 +04:00
if ( usb_autopm_get_interface ( wacom - > intf ) < 0 )
2006-07-14 05:01:36 +04:00
return - EIO ;
2010-10-05 08:46:11 +04:00
mutex_lock ( & wacom - > lock ) ;
2008-04-15 09:31:57 +04:00
if ( usb_submit_urb ( wacom - > irq , GFP_KERNEL ) ) {
2010-10-05 08:46:11 +04:00
retval = - EIO ;
goto out ;
2008-04-15 09:31:57 +04:00
}
2010-03-20 08:18:15 +03:00
wacom - > open = true ;
2008-04-15 09:31:57 +04:00
wacom - > intf - > needs_remote_wakeup = 1 ;
2006-07-14 05:01:36 +04:00
2010-10-05 08:46:11 +04:00
out :
2008-04-15 09:31:57 +04:00
mutex_unlock ( & wacom - > lock ) ;
2010-10-11 01:24:16 +04:00
usb_autopm_put_interface ( wacom - > intf ) ;
2010-10-05 08:46:11 +04:00
return retval ;
2006-07-14 05:01:36 +04:00
}
static void wacom_close ( struct input_dev * dev )
{
2007-04-12 09:34:39 +04:00
struct wacom * wacom = input_get_drvdata ( dev ) ;
2010-10-11 01:24:16 +04:00
int autopm_error ;
autopm_error = usb_autopm_get_interface ( wacom - > intf ) ;
2006-07-14 05:01:36 +04:00
2008-04-15 09:31:57 +04:00
mutex_lock ( & wacom - > lock ) ;
2006-07-14 05:01:36 +04:00
usb_kill_urb ( wacom - > irq ) ;
2010-03-20 08:18:15 +03:00
wacom - > open = false ;
2008-04-15 09:31:57 +04:00
wacom - > intf - > needs_remote_wakeup = 0 ;
mutex_unlock ( & wacom - > lock ) ;
2010-10-05 08:46:11 +04:00
2010-10-11 01:24:16 +04:00
if ( ! autopm_error )
usb_autopm_put_interface ( wacom - > intf ) ;
2006-07-14 05:01:36 +04:00
}
2012-03-26 10:26:20 +04:00
/*
* Static values for max X / Y and resolution of Pen interface is stored in
* features . This mean physical size of active area can be computed .
* This is useful to do when Pen and Touch have same active area of tablet .
* This means for Touch device , we only need to find max X / Y value and we
* have enough information to compute resolution of touch .
*/
static void wacom_set_phy_from_res ( struct wacom_features * features )
{
features - > x_phy = ( features - > x_max * 100 ) / features - > x_resolution ;
features - > y_phy = ( features - > y_max * 100 ) / features - > y_resolution ;
}
2011-10-27 09:32:52 +04:00
static int wacom_parse_logical_collection ( unsigned char * report ,
struct wacom_features * features )
{
int length = 0 ;
if ( features - > type = = BAMBOO_PT ) {
/* Logical collection is only used by 3rd gen Bamboo Touch */
features - > pktlen = WACOM_PKGLEN_BBTOUCH3 ;
2012-01-31 12:07:33 +04:00
features - > device_type = BTN_TOOL_FINGER ;
2011-10-27 09:32:52 +04:00
2012-03-26 10:26:20 +04:00
wacom_set_phy_from_res ( features ) ;
2011-10-27 09:32:52 +04:00
features - > x_max = features - > y_max =
get_unaligned_le16 ( & report [ 10 ] ) ;
length = 11 ;
}
return length ;
}
2011-10-27 09:26:59 +04:00
/*
* Interface Descriptor of wacom devices can be incomplete and
* inconsistent so wacom_features table is used to store stylus
* device ' s packet lengths , various maximum values , and tablet
* resolution based on product ID ' s .
*
* For devices that contain 2 interfaces , wacom_features table is
* inaccurate for the touch interface . Since the Interface Descriptor
* for touch interfaces has pretty complete data , this function exists
* to query tablet for this missing information instead of hard coding in
* an additional table .
*
* A typical Interface Descriptor for a stylus will contain a
* boot mouse application collection that is not of interest and this
* function will ignore it .
*
* It also contains a digitizer application collection that also is not
* of interest since any information it contains would be duplicate
* of what is in wacom_features . Usually it defines a report of an array
* of bytes that could be used as max length of the stylus packet returned .
* If it happens to define a Digitizer - Stylus Physical Collection then
* the X and Y logical values contain valid data but it is ignored .
*
* A typical Interface Descriptor for a touch interface will contain a
* Digitizer - Finger Physical Collection which will define both logical
* X / Y maximum as well as the physical size of tablet . Since touch
* interfaces haven ' t supported pressure or distance , this is enough
* information to override invalid values in the wacom_features table .
2011-10-27 09:32:52 +04:00
*
* 3 rd gen Bamboo Touch no longer define a Digitizer - Finger Pysical
* Collection . Instead they define a Logical Collection with a single
* Logical Maximum for both X and Y .
2012-04-04 02:50:40 +04:00
*
* Intuos5 touch interface does not contain useful data . We deal with
* this after returning from this function .
2011-10-27 09:26:59 +04:00
*/
static int wacom_parse_hid ( struct usb_interface * intf ,
struct hid_descriptor * hid_desc ,
2009-12-15 11:35:24 +03:00
struct wacom_features * features )
2008-11-24 19:44:27 +03:00
{
struct usb_device * dev = interface_to_usbdev ( intf ) ;
2009-12-15 11:35:24 +03:00
char limit = 0 ;
/* result has to be defined as int for some devices */
int result = 0 ;
2008-11-24 19:44:27 +03: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 */
2011-08-16 11:17:56 +04:00
} while ( result < 0 & & limit + + < WAC_MSG_RETRIES ) ;
2008-11-24 19:44:27 +03:00
2009-04-28 18:49:54 +04:00
/* No need to parse the Descriptor. It isn't an error though */
2008-11-24 19:44:27 +03: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 ) {
2011-03-13 07:35:18 +03:00
features - > device_type = BTN_TOOL_FINGER ;
2009-12-15 11:35:24 +03:00
if ( features - > type = = TABLETPC2FG ) {
/* need to reset back */
features - > pktlen = WACOM_PKGLEN_TPC2FG ;
}
2010-09-05 23:25:40 +04:00
if ( features - > type = = BAMBOO_PT ) {
/* need to reset back */
features - > pktlen = WACOM_PKGLEN_BBTOUCH ;
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 19:44:27 +03:00
} else if ( pen ) {
2009-12-15 11:35:24 +03:00
/* penabled only accepts exact bytes of data */
if ( features - > type = = TABLETPC2FG )
2010-03-02 10:50:24 +03:00
features - > pktlen = WACOM_PKGLEN_GRAPHIRE ;
2009-12-15 11:35:24 +03:00
features - > device_type = BTN_TOOL_PEN ;
2008-11-24 19:44:27 +03:00
features - > x_max =
2010-03-20 08:33:38 +03:00
get_unaligned_le16 ( & report [ i + 3 ] ) ;
2008-11-24 19:44:27 +03:00
i + = 4 ;
}
}
break ;
case HID_USAGE_Y :
2009-12-15 11:35:24 +03:00
if ( usage = = WCM_DESKTOP ) {
if ( finger ) {
2011-03-13 07:35:18 +03:00
features - > device_type = BTN_TOOL_FINGER ;
2009-12-15 11:35:24 +03:00
if ( features - > type = = TABLETPC2FG ) {
/* need to reset back */
features - > pktlen = WACOM_PKGLEN_TPC2FG ;
features - > y_max =
2010-03-20 08:33:38 +03:00
get_unaligned_le16 ( & report [ i + 3 ] ) ;
2009-12-15 11:35:24 +03:00
features - > y_phy =
2010-03-20 08:33:38 +03:00
get_unaligned_le16 ( & report [ i + 6 ] ) ;
2009-12-15 11:35:24 +03:00
i + = 7 ;
2010-09-05 23:25:40 +04:00
} else if ( features - > type = = BAMBOO_PT ) {
/* need to reset back */
features - > pktlen = WACOM_PKGLEN_BBTOUCH ;
features - > y_phy =
get_unaligned_le16 ( & report [ i + 3 ] ) ;
features - > y_max =
get_unaligned_le16 ( & report [ i + 6 ] ) ;
i + = 12 ;
2009-12-15 11:35:24 +03:00
} else {
features - > y_max =
features - > x_max ;
features - > y_phy =
2010-03-20 08:33:38 +03:00
get_unaligned_le16 ( & report [ i + 3 ] ) ;
2009-12-15 11:35:24 +03:00
i + = 4 ;
}
} else if ( pen ) {
/* penabled only accepts exact bytes of data */
if ( features - > type = = TABLETPC2FG )
2010-03-02 10:50:24 +03:00
features - > pktlen = WACOM_PKGLEN_GRAPHIRE ;
2009-12-15 11:35:24 +03:00
features - > device_type = BTN_TOOL_PEN ;
features - > y_max =
2010-03-20 08:33:38 +03:00
get_unaligned_le16 ( & report [ i + 3 ] ) ;
2009-12-15 11:35:24 +03:00
i + = 4 ;
}
}
2008-11-24 19:44:27 +03:00
break ;
case HID_USAGE_FINGER :
finger = 1 ;
i + + ;
break ;
2011-10-27 09:26:59 +04:00
/*
* Requiring Stylus Usage will ignore boot mouse
* X / Y values and some cases of invalid Digitizer X / Y
* values commonly reported .
*/
2008-11-24 19:44:27 +03:00
case HID_USAGE_STYLUS :
pen = 1 ;
i + + ;
break ;
}
break ;
2011-10-27 09:32:52 +04:00
case HID_COLLECTION_END :
2009-12-15 11:35:24 +03:00
/* reset UsagePage and Finger */
2008-11-24 19:44:27 +03:00
finger = usage = 0 ;
break ;
2011-10-27 09:32:52 +04:00
case HID_COLLECTION :
i + + ;
switch ( report [ i ] ) {
case HID_COLLECTION_LOGICAL :
i + = wacom_parse_logical_collection ( & report [ i ] ,
features ) ;
break ;
}
break ;
2008-11-24 19:44:27 +03:00
}
}
out :
2009-04-28 18:49:54 +04:00
result = 0 ;
2008-11-24 19:44:27 +03:00
kfree ( report ) ;
return result ;
}
2009-12-15 11:35:24 +03:00
static int wacom_query_tablet_data ( struct usb_interface * intf , struct wacom_features * features )
2009-08-21 08:41:04 +04:00
{
unsigned char * rep_data ;
2009-12-15 11:35:24 +03:00
int limit = 0 , report_id = 2 ;
int error = - ENOMEM ;
2009-08-21 08:41:04 +04:00
2011-08-16 11:17:57 +04:00
rep_data = kmalloc ( 4 , GFP_KERNEL ) ;
2009-08-21 08:41:04 +04:00
if ( ! rep_data )
2009-12-15 11:35:24 +03:00
return error ;
2011-08-16 11:17:57 +04:00
/* ask to report tablet data if it is MT Tablet PC or
2010-09-12 11:08:40 +04:00
* not a Tablet PC */
if ( features - > type = = TABLETPC2FG ) {
2009-12-15 11:35:24 +03:00
do {
rep_data [ 0 ] = 3 ;
rep_data [ 1 ] = 4 ;
2011-08-16 11:17:57 +04:00
rep_data [ 2 ] = 0 ;
rep_data [ 3 ] = 0 ;
2009-12-15 11:35:24 +03:00
report_id = 3 ;
2011-09-08 01:08:54 +04:00
error = wacom_set_report ( intf , WAC_HID_FEATURE_REPORT ,
report_id , rep_data , 4 , 1 ) ;
2009-12-15 11:35:24 +03:00
if ( error > = 0 )
2011-09-08 01:08:54 +04:00
error = wacom_get_report ( intf ,
WAC_HID_FEATURE_REPORT ,
report_id , rep_data , 4 , 1 ) ;
2011-08-16 11:17:56 +04:00
} while ( ( error < 0 | | rep_data [ 1 ] ! = 4 ) & & limit + + < WAC_MSG_RETRIES ) ;
2011-10-27 09:24:22 +04:00
} else if ( features - > type ! = TABLETPC & &
2012-03-26 10:26:11 +04:00
features - > type ! = WIRELESS & &
2011-10-27 09:24:22 +04:00
features - > device_type = = BTN_TOOL_PEN ) {
2009-12-15 11:35:24 +03:00
do {
rep_data [ 0 ] = 2 ;
rep_data [ 1 ] = 2 ;
2011-09-08 01:08:54 +04:00
error = wacom_set_report ( intf , WAC_HID_FEATURE_REPORT ,
report_id , rep_data , 2 , 1 ) ;
2009-12-15 11:35:24 +03:00
if ( error > = 0 )
2011-09-08 01:08:54 +04:00
error = wacom_get_report ( intf ,
WAC_HID_FEATURE_REPORT ,
report_id , rep_data , 2 , 1 ) ;
2011-08-16 11:17:56 +04:00
} while ( ( error < 0 | | rep_data [ 1 ] ! = 2 ) & & limit + + < WAC_MSG_RETRIES ) ;
2009-12-15 11:35:24 +03:00
}
2009-08-21 08:41:04 +04:00
kfree ( rep_data ) ;
return error < 0 ? error : 0 ;
}
2009-12-15 11:35:24 +03: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 23:25:11 +04:00
/* default features */
2009-12-15 11:35:24 +03:00
features - > device_type = BTN_TOOL_PEN ;
2010-09-05 23:25:11 +04:00
features - > x_fuzz = 4 ;
features - > y_fuzz = 4 ;
features - > pressure_fuzz = 0 ;
features - > distance_fuzz = 0 ;
2009-12-15 11:35:24 +03:00
2012-03-26 10:26:11 +04:00
/*
* The wireless device HID is basic and layout conflicts with
* other tablets ( monitor and touch interface can look like pen ) .
* Skip the query for this type and modify defaults based on
* interface number .
*/
if ( features - > type = = WIRELESS ) {
if ( intf - > cur_altsetting - > desc . bInterfaceNumber = = 0 ) {
features - > device_type = 0 ;
} else if ( intf - > cur_altsetting - > desc . bInterfaceNumber = = 2 ) {
features - > device_type = BTN_TOOL_DOUBLETAP ;
features - > pktlen = WACOM_PKGLEN_BBTOUCH3 ;
}
}
2010-09-12 11:08:40 +04:00
/* only Tablet PCs and Bamboo P&T need to retrieve the info */
2010-09-05 23:25:40 +04:00
if ( ( features - > type ! = TABLETPC ) & & ( features - > type ! = TABLETPC2FG ) & &
( features - > type ! = BAMBOO_PT ) )
2009-12-15 11:35:24 +03: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-20 08:18:15 +03: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 ;
}
}
2011-09-08 01:08:54 +04:00
static int wacom_led_control ( struct wacom * wacom )
{
unsigned char * buf ;
2012-04-04 02:50:37 +04:00
int retval ;
2011-09-08 01:08:54 +04:00
buf = kzalloc ( 9 , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
2012-04-04 02:50:37 +04:00
if ( wacom - > wacom_wac . features . type > = INTUOS5S & &
wacom - > wacom_wac . features . type < = INTUOS5L ) {
/*
* Touch Ring and crop mark LED luminance may take on
* one of four values :
* 0 = Low ; 1 = Medium ; 2 = High ; 3 = Off
*/
int ring_led = wacom - > led . select [ 0 ] & 0x03 ;
int ring_lum = ( ( ( wacom - > led . llv & 0x60 ) > > 5 ) - 1 ) & 0x03 ;
int crop_lum = 0 ;
buf [ 0 ] = WAC_CMD_LED_CONTROL ;
buf [ 1 ] = ( crop_lum < < 4 ) | ( ring_lum < < 2 ) | ( ring_led ) ;
}
else {
int led = wacom - > led . select [ 0 ] | 0x4 ;
if ( wacom - > wacom_wac . features . type = = WACOM_21UX2 | |
wacom - > wacom_wac . features . type = = WACOM_24HD )
led | = ( wacom - > led . select [ 1 ] < < 4 ) | 0x40 ;
buf [ 0 ] = WAC_CMD_LED_CONTROL ;
buf [ 1 ] = led ;
buf [ 2 ] = wacom - > led . llv ;
buf [ 3 ] = wacom - > led . hlv ;
buf [ 4 ] = wacom - > led . img_lum ;
}
2011-09-08 01:08:54 +04:00
retval = wacom_set_report ( wacom - > intf , 0x03 , WAC_CMD_LED_CONTROL ,
buf , 9 , WAC_CMD_RETRIES ) ;
kfree ( buf ) ;
return retval ;
}
static int wacom_led_putimage ( struct wacom * wacom , int button_id , const void * img )
{
unsigned char * buf ;
int i , retval ;
buf = kzalloc ( 259 , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
/* Send 'start' command */
buf [ 0 ] = WAC_CMD_ICON_START ;
buf [ 1 ] = 1 ;
retval = wacom_set_report ( wacom - > intf , 0x03 , WAC_CMD_ICON_START ,
buf , 2 , WAC_CMD_RETRIES ) ;
if ( retval < 0 )
goto out ;
buf [ 0 ] = WAC_CMD_ICON_XFER ;
buf [ 1 ] = button_id & 0x07 ;
for ( i = 0 ; i < 4 ; i + + ) {
buf [ 2 ] = i ;
memcpy ( buf + 3 , img + i * 256 , 256 ) ;
retval = wacom_set_report ( wacom - > intf , 0x03 , WAC_CMD_ICON_XFER ,
buf , 259 , WAC_CMD_RETRIES ) ;
if ( retval < 0 )
break ;
}
/* Send 'stop' */
buf [ 0 ] = WAC_CMD_ICON_START ;
buf [ 1 ] = 0 ;
wacom_set_report ( wacom - > intf , 0x03 , WAC_CMD_ICON_START ,
buf , 2 , WAC_CMD_RETRIES ) ;
out :
kfree ( buf ) ;
return retval ;
}
2011-10-05 10:51:14 +04:00
static ssize_t wacom_led_select_store ( struct device * dev , int set_id ,
2011-09-08 01:08:54 +04:00
const char * buf , size_t count )
{
struct wacom * wacom = dev_get_drvdata ( dev ) ;
unsigned int id ;
int err ;
err = kstrtouint ( buf , 10 , & id ) ;
if ( err )
return err ;
mutex_lock ( & wacom - > lock ) ;
2011-10-05 10:51:14 +04:00
wacom - > led . select [ set_id ] = id & 0x3 ;
2011-09-08 01:08:54 +04:00
err = wacom_led_control ( wacom ) ;
mutex_unlock ( & wacom - > lock ) ;
return err < 0 ? err : count ;
}
2011-10-05 10:51:14 +04:00
# define DEVICE_LED_SELECT_ATTR(SET_ID) \
static ssize_t wacom_led # # SET_ID # # _select_store ( struct device * dev , \
struct device_attribute * attr , const char * buf , size_t count ) \
{ \
return wacom_led_select_store ( dev , SET_ID , buf , count ) ; \
} \
2011-10-05 10:51:49 +04:00
static ssize_t wacom_led # # SET_ID # # _select_show ( struct device * dev , \
struct device_attribute * attr , char * buf ) \
{ \
struct wacom * wacom = dev_get_drvdata ( dev ) ; \
return snprintf ( buf , 2 , " %d \n " , wacom - > led . select [ SET_ID ] ) ; \
} \
static DEVICE_ATTR ( status_led # # SET_ID # # _select , S_IWUSR | S_IRUSR , \
wacom_led # # SET_ID # # _select_show , \
2011-10-05 10:51:14 +04:00
wacom_led # # SET_ID # # _select_store )
DEVICE_LED_SELECT_ATTR ( 0 ) ;
DEVICE_LED_SELECT_ATTR ( 1 ) ;
2011-09-08 01:08:54 +04:00
static ssize_t wacom_luminance_store ( struct wacom * wacom , u8 * dest ,
const char * buf , size_t count )
{
unsigned int value ;
int err ;
err = kstrtouint ( buf , 10 , & value ) ;
if ( err )
return err ;
mutex_lock ( & wacom - > lock ) ;
* dest = value & 0x7f ;
err = wacom_led_control ( wacom ) ;
mutex_unlock ( & wacom - > lock ) ;
return err < 0 ? err : count ;
}
# define DEVICE_LUMINANCE_ATTR(name, field) \
static ssize_t wacom_ # # name # # _luminance_store ( struct device * dev , \
struct device_attribute * attr , const char * buf , size_t count ) \
{ \
struct wacom * wacom = dev_get_drvdata ( dev ) ; \
\
return wacom_luminance_store ( wacom , & wacom - > led . field , \
buf , count ) ; \
} \
static DEVICE_ATTR ( name # # _luminance , S_IWUSR , \
NULL , wacom_ # # name # # _luminance_store )
DEVICE_LUMINANCE_ATTR ( status0 , llv ) ;
DEVICE_LUMINANCE_ATTR ( status1 , hlv ) ;
DEVICE_LUMINANCE_ATTR ( buttons , img_lum ) ;
static ssize_t wacom_button_image_store ( struct device * dev , int button_id ,
const char * buf , size_t count )
{
struct wacom * wacom = dev_get_drvdata ( dev ) ;
int err ;
if ( count ! = 1024 )
return - EINVAL ;
mutex_lock ( & wacom - > lock ) ;
err = wacom_led_putimage ( wacom , button_id , buf ) ;
mutex_unlock ( & wacom - > lock ) ;
return err < 0 ? err : count ;
}
# define DEVICE_BTNIMG_ATTR(BUTTON_ID) \
static ssize_t wacom_btnimg # # BUTTON_ID # # _store ( struct device * dev , \
struct device_attribute * attr , const char * buf , size_t count ) \
{ \
return wacom_button_image_store ( dev , BUTTON_ID , buf , count ) ; \
} \
static DEVICE_ATTR ( button # # BUTTON_ID # # _rawimg , S_IWUSR , \
NULL , wacom_btnimg # # BUTTON_ID # # _store )
DEVICE_BTNIMG_ATTR ( 0 ) ;
DEVICE_BTNIMG_ATTR ( 1 ) ;
DEVICE_BTNIMG_ATTR ( 2 ) ;
DEVICE_BTNIMG_ATTR ( 3 ) ;
DEVICE_BTNIMG_ATTR ( 4 ) ;
DEVICE_BTNIMG_ATTR ( 5 ) ;
DEVICE_BTNIMG_ATTR ( 6 ) ;
DEVICE_BTNIMG_ATTR ( 7 ) ;
2011-10-05 10:51:14 +04:00
static struct attribute * cintiq_led_attrs [ ] = {
& dev_attr_status_led0_select . attr ,
& dev_attr_status_led1_select . attr ,
NULL
} ;
static struct attribute_group cintiq_led_attr_group = {
. name = " wacom_led " ,
. attrs = cintiq_led_attrs ,
} ;
static struct attribute * intuos4_led_attrs [ ] = {
2011-09-08 01:08:54 +04:00
& dev_attr_status0_luminance . attr ,
& dev_attr_status1_luminance . attr ,
2011-10-05 10:51:14 +04:00
& dev_attr_status_led0_select . attr ,
2011-09-08 01:08:54 +04:00
& dev_attr_buttons_luminance . attr ,
& dev_attr_button0_rawimg . attr ,
& dev_attr_button1_rawimg . attr ,
& dev_attr_button2_rawimg . attr ,
& dev_attr_button3_rawimg . attr ,
& dev_attr_button4_rawimg . attr ,
& dev_attr_button5_rawimg . attr ,
& dev_attr_button6_rawimg . attr ,
& dev_attr_button7_rawimg . attr ,
NULL
} ;
2011-10-05 10:51:14 +04:00
static struct attribute_group intuos4_led_attr_group = {
2011-09-08 01:08:54 +04:00
. name = " wacom_led " ,
2011-10-05 10:51:14 +04:00
. attrs = intuos4_led_attrs ,
2011-09-08 01:08:54 +04:00
} ;
2012-04-04 02:50:37 +04:00
static struct attribute * intuos5_led_attrs [ ] = {
& dev_attr_status0_luminance . attr ,
& dev_attr_status_led0_select . attr ,
NULL
} ;
static struct attribute_group intuos5_led_attr_group = {
. name = " wacom_led " ,
. attrs = intuos5_led_attrs ,
} ;
2011-09-08 01:08:54 +04:00
static int wacom_initialize_leds ( struct wacom * wacom )
{
int error ;
2011-10-05 10:51:14 +04:00
/* Initialize default values */
switch ( wacom - > wacom_wac . features . type ) {
case INTUOS4 :
case INTUOS4L :
wacom - > led . select [ 0 ] = 0 ;
wacom - > led . select [ 1 ] = 0 ;
2011-10-05 10:49:42 +04:00
wacom - > led . llv = 10 ;
2011-09-08 01:08:54 +04:00
wacom - > led . hlv = 20 ;
wacom - > led . img_lum = 10 ;
2011-10-05 10:51:14 +04:00
error = sysfs_create_group ( & wacom - > intf - > dev . kobj ,
& intuos4_led_attr_group ) ;
break ;
2011-12-12 12:12:04 +04:00
case WACOM_24HD :
2011-10-05 10:51:14 +04:00
case WACOM_21UX2 :
wacom - > led . select [ 0 ] = 0 ;
wacom - > led . select [ 1 ] = 0 ;
wacom - > led . llv = 0 ;
wacom - > led . hlv = 0 ;
wacom - > led . img_lum = 0 ;
2011-09-08 01:08:54 +04:00
error = sysfs_create_group ( & wacom - > intf - > dev . kobj ,
2011-10-05 10:51:14 +04:00
& cintiq_led_attr_group ) ;
break ;
2012-04-04 02:50:37 +04:00
case INTUOS5S :
case INTUOS5 :
case INTUOS5L :
wacom - > led . select [ 0 ] = 0 ;
wacom - > led . select [ 1 ] = 0 ;
wacom - > led . llv = 32 ;
wacom - > led . hlv = 0 ;
wacom - > led . img_lum = 0 ;
error = sysfs_create_group ( & wacom - > intf - > dev . kobj ,
& intuos5_led_attr_group ) ;
break ;
2011-10-05 10:51:14 +04:00
default :
return 0 ;
2011-09-08 01:08:54 +04:00
}
2011-10-05 10:51:14 +04:00
if ( error ) {
dev_err ( & wacom - > intf - > dev ,
" cannot create sysfs group err: %d \n " , error ) ;
return error ;
}
wacom_led_control ( wacom ) ;
2011-09-08 01:08:54 +04:00
return 0 ;
}
static void wacom_destroy_leds ( struct wacom * wacom )
{
2011-10-05 10:51:14 +04:00
switch ( wacom - > wacom_wac . features . type ) {
case INTUOS4 :
case INTUOS4L :
2011-09-08 01:08:54 +04:00
sysfs_remove_group ( & wacom - > intf - > dev . kobj ,
2011-10-05 10:51:14 +04:00
& intuos4_led_attr_group ) ;
break ;
2011-12-12 12:12:04 +04:00
case WACOM_24HD :
2011-10-05 10:51:14 +04:00
case WACOM_21UX2 :
sysfs_remove_group ( & wacom - > intf - > dev . kobj ,
& cintiq_led_attr_group ) ;
break ;
2012-04-04 02:50:37 +04:00
case INTUOS5S :
case INTUOS5 :
case INTUOS5L :
sysfs_remove_group ( & wacom - > intf - > dev . kobj ,
& intuos5_led_attr_group ) ;
break ;
2011-09-08 01:08:54 +04:00
}
}
2012-03-26 10:26:30 +04:00
static enum power_supply_property wacom_battery_props [ ] = {
POWER_SUPPLY_PROP_CAPACITY
} ;
static int wacom_battery_get_property ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
struct wacom * wacom = container_of ( psy , struct wacom , battery ) ;
int ret = 0 ;
switch ( psp ) {
case POWER_SUPPLY_PROP_CAPACITY :
val - > intval =
wacom - > wacom_wac . battery_capacity * 100 / 31 ;
break ;
default :
ret = - EINVAL ;
break ;
}
return ret ;
}
static int wacom_initialize_battery ( struct wacom * wacom )
{
int error = 0 ;
if ( wacom - > wacom_wac . features . quirks & WACOM_QUIRK_MONITOR ) {
wacom - > battery . properties = wacom_battery_props ;
wacom - > battery . num_properties = ARRAY_SIZE ( wacom_battery_props ) ;
wacom - > battery . get_property = wacom_battery_get_property ;
wacom - > battery . name = " wacom_battery " ;
wacom - > battery . type = POWER_SUPPLY_TYPE_BATTERY ;
wacom - > battery . use_for_apm = 0 ;
error = power_supply_register ( & wacom - > usbdev - > dev ,
& wacom - > battery ) ;
}
return error ;
}
static void wacom_destroy_battery ( struct wacom * wacom )
{
if ( wacom - > wacom_wac . features . quirks & WACOM_QUIRK_MONITOR )
power_supply_unregister ( & wacom - > battery ) ;
}
2012-03-26 10:25:45 +04:00
static int wacom_register_input ( struct wacom * wacom )
{
struct input_dev * input_dev ;
struct usb_interface * intf = wacom - > intf ;
struct usb_device * dev = interface_to_usbdev ( intf ) ;
struct wacom_wac * wacom_wac = & ( wacom - > wacom_wac ) ;
int error ;
input_dev = input_allocate_device ( ) ;
if ( ! input_dev )
return - ENOMEM ;
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 ) ;
wacom_wac - > input = input_dev ;
wacom_setup_input_capabilities ( input_dev , wacom_wac ) ;
error = input_register_device ( input_dev ) ;
if ( error ) {
input_free_device ( input_dev ) ;
wacom_wac - > input = NULL ;
}
return error ;
}
2012-03-26 10:26:20 +04:00
static void wacom_wireless_work ( struct work_struct * work )
{
struct wacom * wacom = container_of ( work , struct wacom , work ) ;
struct usb_device * usbdev = wacom - > usbdev ;
struct wacom_wac * wacom_wac = & wacom - > wacom_wac ;
/*
* Regardless if this is a disconnect or a new tablet ,
* remove any existing input devices .
*/
/* Stylus interface */
wacom = usb_get_intfdata ( usbdev - > config - > interface [ 1 ] ) ;
if ( wacom - > wacom_wac . input )
input_unregister_device ( wacom - > wacom_wac . input ) ;
wacom - > wacom_wac . input = 0 ;
/* Touch interface */
wacom = usb_get_intfdata ( usbdev - > config - > interface [ 2 ] ) ;
if ( wacom - > wacom_wac . input )
input_unregister_device ( wacom - > wacom_wac . input ) ;
wacom - > wacom_wac . input = 0 ;
if ( wacom_wac - > pid = = 0 ) {
printk ( KERN_INFO " wacom: wireless tablet disconnected \n " ) ;
} else {
const struct usb_device_id * id = wacom_ids ;
printk ( KERN_INFO
" wacom: wireless tablet connected with PID %x \n " ,
wacom_wac - > pid ) ;
while ( id - > match_flags ) {
if ( id - > idVendor = = USB_VENDOR_ID_WACOM & &
id - > idProduct = = wacom_wac - > pid )
break ;
id + + ;
}
if ( ! id - > match_flags ) {
printk ( KERN_INFO
" wacom: ignorning unknown PID. \n " ) ;
return ;
}
/* Stylus interface */
wacom = usb_get_intfdata ( usbdev - > config - > interface [ 1 ] ) ;
wacom_wac = & wacom - > wacom_wac ;
wacom_wac - > features =
* ( ( struct wacom_features * ) id - > driver_info ) ;
wacom_wac - > features . device_type = BTN_TOOL_PEN ;
wacom_register_input ( wacom ) ;
/* Touch interface */
wacom = usb_get_intfdata ( usbdev - > config - > interface [ 2 ] ) ;
wacom_wac = & wacom - > wacom_wac ;
wacom_wac - > features =
* ( ( struct wacom_features * ) id - > driver_info ) ;
wacom_wac - > features . pktlen = WACOM_PKGLEN_BBTOUCH3 ;
wacom_wac - > features . device_type = BTN_TOOL_FINGER ;
wacom_set_phy_from_res ( & wacom_wac - > features ) ;
wacom_wac - > features . x_max = wacom_wac - > features . y_max = 4096 ;
wacom_register_input ( wacom ) ;
}
}
2006-07-14 05:01:36 +04: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-18 09:38:31 +03:00
struct wacom_features * features ;
int error ;
2006-07-14 05:01:36 +04:00
2010-02-18 09:38:31 +03:00
if ( ! id - > driver_info )
2010-02-11 10:06:23 +03:00
return - EINVAL ;
2006-07-14 05:01:36 +04:00
wacom = kzalloc ( sizeof ( struct wacom ) , GFP_KERNEL ) ;
2012-03-30 09:38:11 +04:00
if ( ! wacom )
return - ENOMEM ;
2010-02-18 09:38:31 +03:00
2010-03-20 08:18:15 +03:00
wacom_wac = & wacom - > wacom_wac ;
2010-02-18 09:38:31 +03:00
wacom_wac - > features = * ( ( struct wacom_features * ) id - > driver_info ) ;
features = & wacom_wac - > features ;
if ( features - > pktlen > WACOM_PKGLEN_MAX ) {
error = - EINVAL ;
2006-07-14 05:01:36 +04:00
goto fail1 ;
2010-02-18 09:38:31 +03:00
}
2006-07-14 05:01:36 +04:00
2010-04-12 15:17:25 +04:00
wacom_wac - > data = usb_alloc_coherent ( dev , WACOM_PKGLEN_MAX ,
GFP_KERNEL , & wacom - > data_dma ) ;
2010-02-18 09:38:31 +03:00
if ( ! wacom_wac - > data ) {
error = - ENOMEM ;
2006-07-14 05:01:36 +04:00
goto fail1 ;
2010-02-18 09:38:31 +03:00
}
2006-07-14 05:01:36 +04:00
wacom - > irq = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2010-02-18 09:38:31 +03:00
if ( ! wacom - > irq ) {
error = - ENOMEM ;
2006-07-14 05:01:36 +04:00
goto fail2 ;
2010-02-18 09:38:31 +03:00
}
2006-07-14 05:01:36 +04:00
wacom - > usbdev = dev ;
2008-04-15 09:31:57 +04:00
wacom - > intf = intf ;
mutex_init ( & wacom - > lock ) ;
2012-03-26 10:26:20 +04:00
INIT_WORK ( & wacom - > work , wacom_wireless_work ) ;
2006-07-14 05:01:36 +04:00
usb_make_path ( dev , wacom - > phys , sizeof ( wacom - > phys ) ) ;
strlcat ( wacom - > phys , " /input0 " , sizeof ( wacom - > phys ) ) ;
2008-11-24 19:44:27 +03:00
endpoint = & intf - > cur_altsetting - > endpoint [ 0 ] . desc ;
2009-12-15 11:35:24 +03:00
/* Retrieve the physical and logical size for OEM devices */
error = wacom_retrieve_hid_descriptor ( intf , features ) ;
if ( error )
2011-02-11 11:44:41 +03:00
goto fail3 ;
2008-11-24 19:44:27 +03:00
2012-04-04 02:50:40 +04:00
/*
* Intuos5 has no useful data about its touch interface in its
* HID descriptor . If this is the touch interface ( wMaxPacketSize
* of WACOM_PKGLEN_BBTOUCH3 ) , override the table values .
*/
if ( features - > type > = INTUOS5S & & features - > type < = INTUOS5L ) {
if ( endpoint - > wMaxPacketSize = = WACOM_PKGLEN_BBTOUCH3 ) {
features - > device_type = BTN_TOOL_FINGER ;
features - > pktlen = WACOM_PKGLEN_BBTOUCH3 ;
features - > x_phy =
( features - > x_max * 100 ) / features - > x_resolution ;
features - > y_phy =
( features - > y_max * 100 ) / features - > y_resolution ;
features - > x_max = 4096 ;
features - > y_max = 4096 ;
} else {
features - > device_type = BTN_TOOL_PEN ;
}
}
2010-09-05 23:26:16 +04:00
wacom_setup_device_quirks ( features ) ;
2010-02-20 11:53:49 +03:00
strlcpy ( wacom_wac - > name , features - > name , sizeof ( wacom_wac - > name ) ) ;
2010-09-05 23:26:16 +04:00
if ( features - > quirks & WACOM_QUIRK_MULTI_INPUT ) {
2010-02-20 11:53:49 +03: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-20 08:18:15 +03:00
error = wacom_add_shared_data ( wacom_wac , dev ) ;
if ( error )
goto fail3 ;
2010-02-20 11:53:49 +03:00
}
2006-07-14 05:01:36 +04:00
usb_fill_int_urb ( wacom - > irq , dev ,
usb_rcvintpipe ( dev , endpoint - > bEndpointAddress ) ,
2009-12-15 11:35:24 +03:00
wacom_wac - > data , features - > pktlen ,
2006-09-27 00:34:47 +04:00
wacom_sys_irq , wacom , endpoint - > bInterval ) ;
2006-07-14 05:01:36 +04:00
wacom - > irq - > transfer_dma = wacom - > data_dma ;
wacom - > irq - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
2011-09-08 01:08:54 +04:00
error = wacom_initialize_leds ( wacom ) ;
2007-04-12 09:33:39 +04:00
if ( error )
2010-03-20 08:18:15 +03:00
goto fail4 ;
2006-07-14 05:01:36 +04:00
2012-03-26 10:26:30 +04:00
error = wacom_initialize_battery ( wacom ) ;
if ( error )
goto fail5 ;
2012-03-26 10:26:11 +04:00
if ( ! ( features - > quirks & WACOM_QUIRK_NO_INPUT ) ) {
error = wacom_register_input ( wacom ) ;
if ( error )
2012-03-26 10:26:30 +04:00
goto fail6 ;
2012-03-26 10:26:11 +04:00
}
2011-09-08 01:08:54 +04:00
2009-12-15 11:35:24 +03:00
/* Note that if query fails it is not a hard failure */
wacom_query_tablet_data ( intf , features ) ;
2006-07-14 05:01:36 +04:00
usb_set_intfdata ( intf , wacom ) ;
2012-03-26 10:26:11 +04:00
if ( features - > quirks & WACOM_QUIRK_MONITOR ) {
if ( usb_submit_urb ( wacom - > irq , GFP_KERNEL ) )
goto fail5 ;
}
2006-07-14 05:01:36 +04:00
return 0 ;
2012-03-26 10:26:30 +04:00
fail6 : wacom_destroy_battery ( wacom ) ;
2011-09-08 01:08:54 +04:00
fail5 : wacom_destroy_leds ( wacom ) ;
2010-03-20 08:18:15 +03:00
fail4 : wacom_remove_shared_data ( wacom_wac ) ;
2007-04-12 09:33:39 +04:00
fail3 : usb_free_urb ( wacom - > irq ) ;
2010-04-12 15:17:25 +04:00
fail2 : usb_free_coherent ( dev , WACOM_PKGLEN_MAX , wacom_wac - > data , wacom - > data_dma ) ;
2012-03-26 10:25:45 +04:00
fail1 : kfree ( wacom ) ;
2007-04-12 09:33:39 +04:00
return error ;
2006-07-14 05:01:36 +04:00
}
static void wacom_disconnect ( struct usb_interface * intf )
{
2008-04-15 09:31:57 +04:00
struct wacom * wacom = usb_get_intfdata ( intf ) ;
2006-07-14 05:01:36 +04:00
usb_set_intfdata ( intf , NULL ) ;
2008-04-15 09:31:57 +04:00
usb_kill_urb ( wacom - > irq ) ;
2012-03-26 10:26:20 +04:00
cancel_work_sync ( & wacom - > work ) ;
2012-03-26 10:26:11 +04:00
if ( wacom - > wacom_wac . input )
input_unregister_device ( wacom - > wacom_wac . input ) ;
2012-03-26 10:26:30 +04:00
wacom_destroy_battery ( wacom ) ;
2011-09-08 01:08:54 +04:00
wacom_destroy_leds ( wacom ) ;
2008-04-15 09:31:57 +04:00
usb_free_urb ( wacom - > irq ) ;
2010-04-12 15:17:25 +04:00
usb_free_coherent ( interface_to_usbdev ( intf ) , WACOM_PKGLEN_MAX ,
2010-03-20 08:18:15 +03:00
wacom - > wacom_wac . data , wacom - > data_dma ) ;
wacom_remove_shared_data ( & wacom - > wacom_wac ) ;
2008-04-15 09: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-20 08:18:15 +03:00
struct wacom_features * features = & wacom - > wacom_wac . features ;
2011-09-08 01:08:54 +04:00
int rv = 0 ;
2008-04-15 09:31:57 +04:00
mutex_lock ( & wacom - > lock ) ;
2010-04-14 10:07:52 +04:00
/* switch to wacom mode first */
wacom_query_tablet_data ( intf , features ) ;
2011-09-08 01:08:54 +04:00
wacom_led_control ( wacom ) ;
2010-04-14 10:07:52 +04:00
2012-03-26 10:26:11 +04:00
if ( ( wacom - > open | | features - > quirks & WACOM_QUIRK_MONITOR )
& & usb_submit_urb ( wacom - > irq , GFP_NOIO ) < 0 )
2011-09-08 01:08:54 +04:00
rv = - EIO ;
2010-04-14 10:07:52 +04:00
2008-04-15 09: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-14 05:01:36 +04:00
}
static struct usb_driver wacom_driver = {
. name = " wacom " ,
2010-02-11 10:06:23 +03:00
. id_table = wacom_ids ,
2006-07-14 05:01:36 +04:00
. probe = wacom_probe ,
. disconnect = wacom_disconnect ,
2008-04-15 09:31:57 +04:00
. suspend = wacom_suspend ,
. resume = wacom_resume ,
. reset_resume = wacom_reset_resume ,
. supports_autosuspend = 1 ,
2006-07-14 05:01:36 +04:00
} ;
2011-11-18 21:48:31 +04:00
module_usb_driver ( wacom_driver ) ;