2005-04-16 15:20:36 -07:00
/*
* USB HID support for Linux
*
* Copyright ( c ) 1999 Andreas Gal
2005-09-05 00:12:01 -05:00
* Copyright ( c ) 2000 - 2005 Vojtech Pavlik < vojtech @ suse . cz >
* Copyright ( c ) 2005 Michael Haboustak < mike - @ cinci . rr . com > for Concept2 , Inc
2008-12-17 15:38:03 +01:00
* Copyright ( c ) 2007 - 2008 Oliver Neukum
2010-02-02 20:46:34 +01:00
* Copyright ( c ) 2006 - 2010 Jiri Kosina
2005-04-16 15:20: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 <linux/module.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/mm.h>
2008-10-27 12:16:15 +01:00
# include <linux/mutex.h>
2005-04-16 15:20:36 -07:00
# include <linux/spinlock.h>
# include <asm/unaligned.h>
# include <asm/byteorder.h>
# include <linux/input.h>
# include <linux/wait.h>
2008-12-17 15:38:03 +01:00
# include <linux/workqueue.h>
2005-04-16 15:20:36 -07:00
# include <linux/usb.h>
2006-12-08 18:40:44 +01:00
# include <linux/hid.h>
2005-04-16 15:20:36 -07:00
# include <linux/hiddev.h>
2007-01-25 11:43:31 +01:00
# include <linux/hid-debug.h>
2007-05-14 09:57:40 +02:00
# include <linux/hidraw.h>
2006-12-08 18:41:03 +01:00
# include "usbhid.h"
2005-04-16 15:20:36 -07:00
/*
* Version Information
*/
# define DRIVER_DESC "USB HID core driver"
# define DRIVER_LICENSE "GPL"
/*
* Module parameters .
*/
static unsigned int hid_mousepoll_interval ;
module_param_named ( mousepoll , hid_mousepoll_interval , uint , 0644 ) ;
MODULE_PARM_DESC ( mousepoll , " Polling interval of mice " ) ;
2008-12-17 15:38:03 +01:00
static unsigned int ignoreled ;
module_param_named ( ignoreled , ignoreled , uint , 0644 ) ;
MODULE_PARM_DESC ( ignoreled , " Autosuspend with active leds " ) ;
2007-04-19 14:56:12 +02:00
/* Quirks specified at module load time */
static char * quirks_param [ MAX_USBHID_BOOT_QUIRKS ] = { [ 0 . . . ( MAX_USBHID_BOOT_QUIRKS - 1 ) ] = NULL } ;
module_param_array_named ( quirks , quirks_param , charp , NULL , 0444 ) ;
MODULE_PARM_DESC ( quirks , " Add/modify USB HID quirks by specifying "
" quirks=vendorID:productID:quirks "
" where vendorID, productID, and quirks are all in "
" 0x-prefixed hex " ) ;
2005-04-16 15:20:36 -07:00
/*
2007-04-03 23:39:37 +02:00
* Input submission and I / O error handler .
2005-04-16 15:20:36 -07:00
*/
2008-12-17 15:38:03 +01:00
static DEFINE_MUTEX ( hid_open_mut ) ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
static void hid_io_error ( struct hid_device * hid ) ;
2008-12-17 15:38:03 +01:00
static int hid_submit_out ( struct hid_device * hid ) ;
static int hid_submit_ctrl ( struct hid_device * hid ) ;
static void hid_cancel_delayed_stuff ( struct usbhid_device * usbhid ) ;
2007-04-03 23:39:37 +02:00
/* Start up the input URB */
static int hid_start_in ( struct hid_device * hid )
2005-04-16 15:20:36 -07:00
{
unsigned long flags ;
2007-04-03 23:39:37 +02:00
int rc = 0 ;
struct usbhid_device * usbhid = hid - > driver_data ;
2005-04-16 15:20:36 -07:00
2008-12-17 15:38:03 +01:00
spin_lock_irqsave ( & usbhid - > lock , flags ) ;
if ( hid - > open > 0 & &
2008-03-31 16:27:30 +02:00
! test_bit ( HID_DISCONNECTED , & usbhid - > iofl ) & &
2008-12-17 15:38:03 +01:00
! test_bit ( HID_REPORTED_IDLE , & usbhid - > iofl ) & &
2007-04-03 23:39:37 +02:00
! test_and_set_bit ( HID_IN_RUNNING , & usbhid - > iofl ) ) {
rc = usb_submit_urb ( usbhid - > urbin , GFP_ATOMIC ) ;
if ( rc ! = 0 )
clear_bit ( HID_IN_RUNNING , & usbhid - > iofl ) ;
2005-04-16 15:20:36 -07:00
}
2008-12-17 15:38:03 +01:00
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
2007-04-03 23:39:37 +02:00
return rc ;
2005-04-16 15:20:36 -07:00
}
2007-04-03 23:39:37 +02:00
/* I/O retry timer routine */
static void hid_retry_timeout ( unsigned long _hid )
2005-04-16 15:20:36 -07:00
{
2007-04-03 23:39:37 +02:00
struct hid_device * hid = ( struct hid_device * ) _hid ;
2006-12-08 18:41:03 +01:00
struct usbhid_device * usbhid = hid - > driver_data ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
dev_dbg ( & usbhid - > intf - > dev , " retrying intr urb \n " ) ;
if ( hid_start_in ( hid ) )
hid_io_error ( hid ) ;
2005-04-16 15:20:36 -07:00
}
2007-04-03 23:39:37 +02:00
/* Workqueue routine to reset the device or clear a halt */
static void hid_reset ( struct work_struct * work )
2005-04-16 15:20:36 -07:00
{
2007-04-03 23:39:37 +02:00
struct usbhid_device * usbhid =
container_of ( work , struct usbhid_device , reset_work ) ;
struct hid_device * hid = usbhid - > hid ;
2008-11-04 11:29:27 -05:00
int rc = 0 ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
if ( test_bit ( HID_CLEAR_HALT , & usbhid - > iofl ) ) {
dev_dbg ( & usbhid - > intf - > dev , " clear halt \n " ) ;
rc = usb_clear_halt ( hid_to_usb_dev ( hid ) , usbhid - > urbin - > pipe ) ;
clear_bit ( HID_CLEAR_HALT , & usbhid - > iofl ) ;
hid_start_in ( hid ) ;
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
else if ( test_bit ( HID_RESET_PENDING , & usbhid - > iofl ) ) {
dev_dbg ( & usbhid - > intf - > dev , " resetting device \n " ) ;
2008-11-04 11:29:27 -05:00
rc = usb_lock_device_for_reset ( hid_to_usb_dev ( hid ) , usbhid - > intf ) ;
if ( rc = = 0 ) {
2008-06-18 22:00:29 +08:00
rc = usb_reset_device ( hid_to_usb_dev ( hid ) ) ;
2008-11-04 11:29:27 -05:00
usb_unlock_device ( hid_to_usb_dev ( hid ) ) ;
2005-04-16 15:20:36 -07:00
}
2007-04-03 23:39:37 +02:00
clear_bit ( HID_RESET_PENDING , & usbhid - > iofl ) ;
2005-04-16 15:20:36 -07:00
}
2007-04-03 23:39:37 +02:00
switch ( rc ) {
case 0 :
if ( ! test_bit ( HID_IN_RUNNING , & usbhid - > iofl ) )
hid_io_error ( hid ) ;
break ;
default :
2010-12-09 19:29:03 -08:00
hid_err ( hid , " can't reset device, %s-%s/input%d, status %d \n " ,
hid_to_usb_dev ( hid ) - > bus - > bus_name ,
hid_to_usb_dev ( hid ) - > devpath ,
usbhid - > ifnum , rc ) ;
2007-04-03 23:39:37 +02:00
/* FALLTHROUGH */
case - EHOSTUNREACH :
case - ENODEV :
case - EINTR :
break ;
2005-04-16 15:20:36 -07:00
}
}
2007-04-03 23:39:37 +02:00
/* Main I/O error handler */
static void hid_io_error ( struct hid_device * hid )
2006-12-08 18:40:44 +01:00
{
2007-04-03 23:39:37 +02:00
unsigned long flags ;
struct usbhid_device * usbhid = hid - > driver_data ;
2006-12-08 18:40:44 +01:00
2008-12-17 15:38:03 +01:00
spin_lock_irqsave ( & usbhid - > lock , flags ) ;
2006-12-08 18:40:44 +01:00
2007-04-03 23:39:37 +02:00
/* Stop when disconnected */
2008-03-31 16:27:30 +02:00
if ( test_bit ( HID_DISCONNECTED , & usbhid - > iofl ) )
2007-04-03 23:39:37 +02:00
goto done ;
2006-12-08 18:40:44 +01:00
2007-03-20 19:03:31 +01:00
/* If it has been a while since the last error, we'll assume
* this a brand new error and reset the retry timeout . */
if ( time_after ( jiffies , usbhid - > stop_retry + HZ / 2 ) )
usbhid - > retry_delay = 0 ;
2007-04-03 23:39:37 +02:00
/* When an error occurs, retry at increasing intervals */
if ( usbhid - > retry_delay = = 0 ) {
usbhid - > retry_delay = 13 ; /* Then 26, 52, 104, 104, ... */
usbhid - > stop_retry = jiffies + msecs_to_jiffies ( 1000 ) ;
} else if ( usbhid - > retry_delay < 100 )
usbhid - > retry_delay * = 2 ;
2006-12-08 18:40:44 +01:00
2007-04-03 23:39:37 +02:00
if ( time_after ( jiffies , usbhid - > stop_retry ) ) {
2006-12-08 18:41:03 +01:00
2007-04-03 23:39:37 +02:00
/* Retries failed, so do a port reset */
if ( ! test_and_set_bit ( HID_RESET_PENDING , & usbhid - > iofl ) ) {
schedule_work ( & usbhid - > reset_work ) ;
goto done ;
}
2005-04-16 15:20:36 -07:00
}
2007-04-03 23:39:37 +02:00
mod_timer ( & usbhid - > io_retry ,
jiffies + msecs_to_jiffies ( usbhid - > retry_delay ) ) ;
done :
2008-12-17 15:38:03 +01:00
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
}
static void usbhid_mark_busy ( struct usbhid_device * usbhid )
{
struct usb_interface * intf = usbhid - > intf ;
usb_mark_last_busy ( interface_to_usbdev ( intf ) ) ;
}
static int usbhid_restart_out_queue ( struct usbhid_device * usbhid )
{
struct hid_device * hid = usb_get_intfdata ( usbhid - > intf ) ;
int kicked ;
if ( ! hid )
return 0 ;
if ( ( kicked = ( usbhid - > outhead ! = usbhid - > outtail ) ) ) {
dbg ( " Kicking head %d tail %d " , usbhid - > outhead , usbhid - > outtail ) ;
if ( hid_submit_out ( hid ) ) {
clear_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ;
wake_up ( & usbhid - > wait ) ;
}
}
return kicked ;
}
static int usbhid_restart_ctrl_queue ( struct usbhid_device * usbhid )
{
struct hid_device * hid = usb_get_intfdata ( usbhid - > intf ) ;
int kicked ;
WARN_ON ( hid = = NULL ) ;
if ( ! hid )
return 0 ;
if ( ( kicked = ( usbhid - > ctrlhead ! = usbhid - > ctrltail ) ) ) {
dbg ( " Kicking head %d tail %d " , usbhid - > ctrlhead , usbhid - > ctrltail ) ;
if ( hid_submit_ctrl ( hid ) ) {
clear_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) ;
wake_up ( & usbhid - > wait ) ;
}
}
return kicked ;
2005-04-16 15:20:36 -07:00
}
2007-04-03 23:39:37 +02:00
/*
* Input interrupt completion handler .
*/
2005-05-29 02:28:00 -05:00
2007-04-03 23:39:37 +02:00
static void hid_irq_in ( struct urb * urb )
2005-04-16 15:20:36 -07:00
{
2007-04-03 23:39:37 +02:00
struct hid_device * hid = urb - > context ;
struct usbhid_device * usbhid = hid - > driver_data ;
int status ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
switch ( urb - > status ) {
2008-06-18 23:55:41 +02:00
case 0 : /* success */
2008-12-17 15:38:03 +01:00
usbhid_mark_busy ( usbhid ) ;
2008-06-18 23:55:41 +02:00
usbhid - > retry_delay = 0 ;
hid_input_report ( urb - > context , HID_INPUT_REPORT ,
urb - > transfer_buffer ,
urb - > actual_length , 1 ) ;
2008-12-17 15:38:03 +01:00
/*
* autosuspend refused while keys are pressed
* because most keyboards don ' t wake up when
* a key is released
*/
if ( hid_check_keys_pressed ( hid ) )
set_bit ( HID_KEYS_PRESSED , & usbhid - > iofl ) ;
else
clear_bit ( HID_KEYS_PRESSED , & usbhid - > iofl ) ;
2008-06-18 23:55:41 +02:00
break ;
case - EPIPE : /* stall */
2008-12-17 15:38:03 +01:00
usbhid_mark_busy ( usbhid ) ;
2008-06-18 23:55:41 +02:00
clear_bit ( HID_IN_RUNNING , & usbhid - > iofl ) ;
set_bit ( HID_CLEAR_HALT , & usbhid - > iofl ) ;
schedule_work ( & usbhid - > reset_work ) ;
return ;
case - ECONNRESET : /* unlink */
case - ENOENT :
case - ESHUTDOWN : /* unplug */
clear_bit ( HID_IN_RUNNING , & usbhid - > iofl ) ;
return ;
case - EILSEQ : /* protocol error or unplug */
case - EPROTO : /* protocol error or unplug */
case - ETIME : /* protocol error or unplug */
case - ETIMEDOUT : /* Should never happen, but... */
2008-12-17 15:38:03 +01:00
usbhid_mark_busy ( usbhid ) ;
2008-06-18 23:55:41 +02:00
clear_bit ( HID_IN_RUNNING , & usbhid - > iofl ) ;
hid_io_error ( hid ) ;
return ;
default : /* error */
2010-12-09 19:29:03 -08:00
hid_warn ( urb - > dev , " input irq status %d received \n " ,
urb - > status ) ;
2007-04-03 23:39:37 +02:00
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
status = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( status ) {
clear_bit ( HID_IN_RUNNING , & usbhid - > iofl ) ;
if ( status ! = - EPERM ) {
2010-12-09 19:29:03 -08:00
hid_err ( hid , " can't resubmit intr, %s-%s/input%d, status %d \n " ,
hid_to_usb_dev ( hid ) - > bus - > bus_name ,
hid_to_usb_dev ( hid ) - > devpath ,
usbhid - > ifnum , status ) ;
2007-04-03 23:39:37 +02:00
hid_io_error ( hid ) ;
}
}
2005-04-16 15:20:36 -07:00
}
2007-04-03 23:39:37 +02:00
static int hid_submit_out ( struct hid_device * hid )
2005-04-16 15:20:36 -07:00
{
2007-04-03 23:39:37 +02:00
struct hid_report * report ;
2008-10-04 14:44:06 +02:00
char * raw_report ;
2006-12-08 18:41:03 +01:00
struct usbhid_device * usbhid = hid - > driver_data ;
2010-12-22 15:33:40 +01:00
int r ;
2006-12-08 18:41:03 +01:00
2008-10-04 14:44:06 +02:00
report = usbhid - > out [ usbhid - > outtail ] . report ;
raw_report = usbhid - > out [ usbhid - > outtail ] . raw_report ;
2005-04-16 15:20:36 -07:00
2010-12-22 15:33:40 +01:00
r = usb_autopm_get_interface_async ( usbhid - > intf ) ;
if ( r < 0 )
return - 1 ;
/*
* if the device hasn ' t been woken , we leave the output
* to resume ( )
*/
2008-12-17 15:38:03 +01:00
if ( ! test_bit ( HID_REPORTED_IDLE , & usbhid - > iofl ) ) {
usbhid - > urbout - > transfer_buffer_length = ( ( report - > size - 1 ) > > 3 ) + 1 + ( report - > id > 0 ) ;
usbhid - > urbout - > dev = hid_to_usb_dev ( hid ) ;
memcpy ( usbhid - > outbuf , raw_report , usbhid - > urbout - > transfer_buffer_length ) ;
kfree ( raw_report ) ;
2006-03-29 22:41:07 +02:00
2008-12-17 15:38:03 +01:00
dbg_hid ( " submitting out urb \n " ) ;
2006-10-18 08:47:37 -04:00
2008-12-17 15:38:03 +01:00
if ( usb_submit_urb ( usbhid - > urbout , GFP_ATOMIC ) ) {
2010-12-09 19:29:03 -08:00
hid_err ( hid , " usb_submit_urb(out) failed \n " ) ;
2010-12-22 15:33:40 +01:00
usb_autopm_put_interface_async ( usbhid - > intf ) ;
2008-12-17 15:38:03 +01:00
return - 1 ;
}
2010-02-12 13:02:28 +01:00
usbhid - > last_out = jiffies ;
2007-04-03 23:39:37 +02:00
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
return 0 ;
}
static int hid_submit_ctrl ( struct hid_device * hid )
2005-04-16 15:20:36 -07:00
{
struct hid_report * report ;
2007-04-03 23:39:37 +02:00
unsigned char dir ;
2008-10-04 14:44:06 +02:00
char * raw_report ;
2010-12-22 15:33:40 +01:00
int len , r ;
2006-12-08 18:41:03 +01:00
struct usbhid_device * usbhid = hid - > driver_data ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
report = usbhid - > ctrl [ usbhid - > ctrltail ] . report ;
2008-10-04 14:44:06 +02:00
raw_report = usbhid - > ctrl [ usbhid - > ctrltail ] . raw_report ;
2007-04-03 23:39:37 +02:00
dir = usbhid - > ctrl [ usbhid - > ctrltail ] . dir ;
2005-04-16 15:20:36 -07:00
2010-12-22 15:33:40 +01:00
r = usb_autopm_get_interface_async ( usbhid - > intf ) ;
if ( r < 0 )
return - 1 ;
2008-12-17 15:38:03 +01:00
if ( ! test_bit ( HID_REPORTED_IDLE , & usbhid - > iofl ) ) {
len = ( ( report - > size - 1 ) > > 3 ) + 1 + ( report - > id > 0 ) ;
if ( dir = = USB_DIR_OUT ) {
usbhid - > urbctrl - > pipe = usb_sndctrlpipe ( hid_to_usb_dev ( hid ) , 0 ) ;
usbhid - > urbctrl - > transfer_buffer_length = len ;
memcpy ( usbhid - > ctrlbuf , raw_report , len ) ;
kfree ( raw_report ) ;
} else {
int maxpacket , padlen ;
usbhid - > urbctrl - > pipe = usb_rcvctrlpipe ( hid_to_usb_dev ( hid ) , 0 ) ;
maxpacket = usb_maxpacket ( hid_to_usb_dev ( hid ) , usbhid - > urbctrl - > pipe , 0 ) ;
if ( maxpacket > 0 ) {
padlen = DIV_ROUND_UP ( len , maxpacket ) ;
padlen * = maxpacket ;
if ( padlen > usbhid - > bufsize )
padlen = usbhid - > bufsize ;
} else
padlen = 0 ;
usbhid - > urbctrl - > transfer_buffer_length = padlen ;
}
usbhid - > urbctrl - > dev = hid_to_usb_dev ( hid ) ;
2005-04-16 15:20:36 -07:00
2008-12-17 15:38:03 +01:00
usbhid - > cr - > bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir ;
usbhid - > cr - > bRequest = ( dir = = USB_DIR_OUT ) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT ;
usbhid - > cr - > wValue = cpu_to_le16 ( ( ( report - > type + 1 ) < < 8 ) | report - > id ) ;
usbhid - > cr - > wIndex = cpu_to_le16 ( usbhid - > ifnum ) ;
usbhid - > cr - > wLength = cpu_to_le16 ( len ) ;
2005-04-16 15:20:36 -07:00
2008-12-17 15:38:03 +01:00
dbg_hid ( " submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u \n " ,
usbhid - > cr - > bRequest = = HID_REQ_SET_REPORT ? " Set_Report " : " Get_Report " ,
usbhid - > cr - > wValue , usbhid - > cr - > wIndex , usbhid - > cr - > wLength ) ;
2005-04-16 15:20:36 -07:00
2008-12-17 15:38:03 +01:00
if ( usb_submit_urb ( usbhid - > urbctrl , GFP_ATOMIC ) ) {
2010-12-22 15:33:40 +01:00
usb_autopm_put_interface_async ( usbhid - > intf ) ;
2010-12-09 19:29:03 -08:00
hid_err ( hid , " usb_submit_urb(ctrl) failed \n " ) ;
2008-12-17 15:38:03 +01:00
return - 1 ;
}
2010-02-12 13:02:28 +01:00
usbhid - > last_ctrl = jiffies ;
2007-04-03 23:39:37 +02:00
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
return 0 ;
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
/*
* Output interrupt completion handler .
*/
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
static void hid_irq_out ( struct urb * urb )
{
struct hid_device * hid = urb - > context ;
struct usbhid_device * usbhid = hid - > driver_data ;
unsigned long flags ;
int unplug = 0 ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
switch ( urb - > status ) {
2008-06-18 23:55:41 +02:00
case 0 : /* success */
break ;
case - ESHUTDOWN : /* unplug */
unplug = 1 ;
case - EILSEQ : /* protocol error or unplug */
case - EPROTO : /* protocol error or unplug */
case - ECONNRESET : /* unlink */
case - ENOENT :
break ;
default : /* error */
2010-12-09 19:29:03 -08:00
hid_warn ( urb - > dev , " output irq status %d received \n " ,
urb - > status ) ;
2007-04-03 23:39:37 +02:00
}
2005-04-16 15:20:36 -07:00
2008-12-17 15:38:03 +01:00
spin_lock_irqsave ( & usbhid - > lock , flags ) ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
if ( unplug )
usbhid - > outtail = usbhid - > outhead ;
else
usbhid - > outtail = ( usbhid - > outtail + 1 ) & ( HID_OUTPUT_FIFO_SIZE - 1 ) ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
if ( usbhid - > outhead ! = usbhid - > outtail ) {
if ( hid_submit_out ( hid ) ) {
clear_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ;
2008-03-19 21:55:04 +01:00
wake_up ( & usbhid - > wait ) ;
2007-04-03 23:39:37 +02:00
}
2008-12-17 15:38:03 +01:00
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
2007-04-03 23:39:37 +02:00
return ;
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
clear_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ;
2008-12-17 15:38:03 +01:00
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
2010-12-22 15:33:40 +01:00
usb_autopm_put_interface_async ( usbhid - > intf ) ;
2008-03-19 21:55:04 +01:00
wake_up ( & usbhid - > wait ) ;
2007-04-03 23:39:37 +02:00
}
2005-07-11 01:08:40 -05:00
2007-04-03 23:39:37 +02:00
/*
* Control pipe completion handler .
*/
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
static void hid_ctrl ( struct urb * urb )
{
struct hid_device * hid = urb - > context ;
struct usbhid_device * usbhid = hid - > driver_data ;
2008-12-17 15:38:03 +01:00
int unplug = 0 , status = urb - > status ;
2005-04-16 15:20:36 -07:00
2008-12-17 15:38:03 +01:00
spin_lock ( & usbhid - > lock ) ;
2005-04-16 15:20:36 -07:00
2008-12-17 15:38:03 +01:00
switch ( status ) {
2008-06-18 23:55:41 +02:00
case 0 : /* success */
if ( usbhid - > ctrl [ usbhid - > ctrltail ] . dir = = USB_DIR_IN )
hid_input_report ( urb - > context ,
usbhid - > ctrl [ usbhid - > ctrltail ] . report - > type ,
urb - > transfer_buffer , urb - > actual_length , 0 ) ;
break ;
case - ESHUTDOWN : /* unplug */
unplug = 1 ;
case - EILSEQ : /* protocol error or unplug */
case - EPROTO : /* protocol error or unplug */
case - ECONNRESET : /* unlink */
case - ENOENT :
case - EPIPE : /* report not available */
break ;
default : /* error */
2010-12-09 19:29:03 -08:00
hid_warn ( urb - > dev , " ctrl urb status %d received \n " , status ) ;
2007-04-03 23:39:37 +02:00
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
if ( unplug )
usbhid - > ctrltail = usbhid - > ctrlhead ;
else
usbhid - > ctrltail = ( usbhid - > ctrltail + 1 ) & ( HID_CONTROL_FIFO_SIZE - 1 ) ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
if ( usbhid - > ctrlhead ! = usbhid - > ctrltail ) {
if ( hid_submit_ctrl ( hid ) ) {
clear_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) ;
2008-03-19 21:55:04 +01:00
wake_up ( & usbhid - > wait ) ;
2007-04-03 23:39:37 +02:00
}
2008-12-17 15:38:03 +01:00
spin_unlock ( & usbhid - > lock ) ;
2010-12-22 15:33:40 +01:00
usb_autopm_put_interface_async ( usbhid - > intf ) ;
2007-04-03 23:39:37 +02:00
return ;
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
clear_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) ;
2008-12-17 15:38:03 +01:00
spin_unlock ( & usbhid - > lock ) ;
2010-12-22 15:33:40 +01:00
usb_autopm_put_interface_async ( usbhid - > intf ) ;
2008-03-19 21:55:04 +01:00
wake_up ( & usbhid - > wait ) ;
2007-04-03 23:39:37 +02:00
}
2005-04-16 15:20:36 -07:00
2009-08-17 15:37:18 -07:00
static void __usbhid_submit_report ( struct hid_device * hid , struct hid_report * report ,
unsigned char dir )
2007-04-03 23:39:37 +02:00
{
int head ;
struct usbhid_device * usbhid = hid - > driver_data ;
2008-10-04 14:44:06 +02:00
int len = ( ( report - > size - 1 ) > > 3 ) + 1 + ( report - > id > 0 ) ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
if ( ( hid - > quirks & HID_QUIRK_NOGET ) & & dir = = USB_DIR_IN )
return ;
2006-06-30 09:44:03 +02:00
2007-04-03 23:39:37 +02:00
if ( usbhid - > urbout & & dir = = USB_DIR_OUT & & report - > type = = HID_OUTPUT_REPORT ) {
if ( ( head = ( usbhid - > outhead + 1 ) & ( HID_OUTPUT_FIFO_SIZE - 1 ) ) = = usbhid - > outtail ) {
2010-12-09 19:29:03 -08:00
hid_warn ( hid , " output queue full \n " ) ;
2007-04-03 23:39:37 +02:00
return ;
}
2005-04-16 15:20:36 -07:00
2008-10-04 14:44:06 +02:00
usbhid - > out [ usbhid - > outhead ] . raw_report = kmalloc ( len , GFP_ATOMIC ) ;
if ( ! usbhid - > out [ usbhid - > outhead ] . raw_report ) {
2010-12-09 19:29:03 -08:00
hid_warn ( hid , " output queueing failed \n " ) ;
2008-10-04 14:44:06 +02:00
return ;
}
hid_output_report ( report , usbhid - > out [ usbhid - > outhead ] . raw_report ) ;
usbhid - > out [ usbhid - > outhead ] . report = report ;
2007-04-03 23:39:37 +02:00
usbhid - > outhead = head ;
2005-06-02 22:18:12 -07:00
2010-02-12 13:02:28 +01:00
if ( ! test_and_set_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ) {
2007-04-03 23:39:37 +02:00
if ( hid_submit_out ( hid ) )
clear_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ;
2010-02-12 13:02:28 +01:00
} else {
/*
* the queue is known to run
* but an earlier request may be stuck
* we may need to time out
* no race because this is called under
* spinlock
*/
if ( time_after ( jiffies , usbhid - > last_out + HZ * 5 ) )
usb_unlink_urb ( usbhid - > urbout ) ;
}
2007-04-03 23:39:37 +02:00
return ;
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
if ( ( head = ( usbhid - > ctrlhead + 1 ) & ( HID_CONTROL_FIFO_SIZE - 1 ) ) = = usbhid - > ctrltail ) {
2010-12-09 19:29:03 -08:00
hid_warn ( hid , " control queue full \n " ) ;
2007-04-03 23:39:37 +02:00
return ;
}
2006-09-16 16:17:34 +02:00
2008-10-04 14:44:06 +02:00
if ( dir = = USB_DIR_OUT ) {
usbhid - > ctrl [ usbhid - > ctrlhead ] . raw_report = kmalloc ( len , GFP_ATOMIC ) ;
if ( ! usbhid - > ctrl [ usbhid - > ctrlhead ] . raw_report ) {
2010-12-09 19:29:03 -08:00
hid_warn ( hid , " control queueing failed \n " ) ;
2008-10-04 14:44:06 +02:00
return ;
}
hid_output_report ( report , usbhid - > ctrl [ usbhid - > ctrlhead ] . raw_report ) ;
}
2007-04-03 23:39:37 +02:00
usbhid - > ctrl [ usbhid - > ctrlhead ] . report = report ;
usbhid - > ctrl [ usbhid - > ctrlhead ] . dir = dir ;
usbhid - > ctrlhead = head ;
2006-09-16 16:17:34 +02:00
2010-02-12 13:02:28 +01:00
if ( ! test_and_set_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) ) {
2007-04-03 23:39:37 +02:00
if ( hid_submit_ctrl ( hid ) )
clear_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) ;
2010-02-12 13:02:28 +01:00
} else {
/*
* the queue is known to run
* but an earlier request may be stuck
* we may need to time out
* no race because this is called under
* spinlock
*/
if ( time_after ( jiffies , usbhid - > last_ctrl + HZ * 5 ) )
usb_unlink_urb ( usbhid - > urbctrl ) ;
}
2008-12-17 15:38:03 +01:00
}
2006-09-15 19:53:35 +05:30
2008-12-17 15:38:03 +01:00
void usbhid_submit_report ( struct hid_device * hid , struct hid_report * report , unsigned char dir )
{
struct usbhid_device * usbhid = hid - > driver_data ;
unsigned long flags ;
2006-09-15 19:53:35 +05:30
2008-12-17 15:38:03 +01:00
spin_lock_irqsave ( & usbhid - > lock , flags ) ;
__usbhid_submit_report ( hid , report , dir ) ;
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
2007-04-03 23:39:37 +02:00
}
2008-07-04 23:06:45 +02:00
EXPORT_SYMBOL_GPL ( usbhid_submit_report ) ;
2006-10-27 16:08:54 -03:00
2007-04-03 23:39:37 +02:00
static int usb_hidinput_input_event ( struct input_dev * dev , unsigned int type , unsigned int code , int value )
{
2007-05-09 10:17:31 +02:00
struct hid_device * hid = input_get_drvdata ( dev ) ;
2008-12-17 15:38:03 +01:00
struct usbhid_device * usbhid = hid - > driver_data ;
2007-04-03 23:39:37 +02:00
struct hid_field * field ;
2008-12-17 15:38:03 +01:00
unsigned long flags ;
2007-04-03 23:39:37 +02:00
int offset ;
2006-11-04 22:49:53 -05:00
2007-04-03 23:39:37 +02:00
if ( type = = EV_FF )
return input_ff_event ( dev , type , code , value ) ;
2007-01-11 10:14:33 +01:00
2007-04-03 23:39:37 +02:00
if ( type ! = EV_LED )
return - 1 ;
2007-01-11 16:51:17 +02:00
2007-04-03 23:39:37 +02:00
if ( ( offset = hidinput_find_field ( hid , type , code , & field ) ) = = - 1 ) {
2010-12-09 19:29:03 -08:00
hid_warn ( dev , " event field not found \n " ) ;
2007-04-03 23:39:37 +02:00
return - 1 ;
}
2007-01-15 20:11:52 -08:00
2007-04-03 23:39:37 +02:00
hid_set_field ( field , offset , value ) ;
2008-12-17 15:38:03 +01:00
if ( value ) {
spin_lock_irqsave ( & usbhid - > lock , flags ) ;
usbhid - > ledcount + + ;
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
} else {
spin_lock_irqsave ( & usbhid - > lock , flags ) ;
usbhid - > ledcount - - ;
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
}
2007-04-03 23:39:37 +02:00
usbhid_submit_report ( hid , field - > report , USB_DIR_OUT ) ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
return 0 ;
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
int usbhid_wait_io ( struct hid_device * hid )
{
struct usbhid_device * usbhid = hid - > driver_data ;
2007-03-01 09:54:44 +01:00
2008-03-19 21:55:04 +01:00
if ( ! wait_event_timeout ( usbhid - > wait ,
( ! test_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) & &
! test_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ) ,
2007-04-03 23:39:37 +02:00
10 * HZ ) ) {
2007-05-30 15:07:13 +02:00
dbg_hid ( " timeout waiting for ctrl or out queue to clear \n " ) ;
2007-04-03 23:39:37 +02:00
return - 1 ;
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
return 0 ;
}
2010-03-30 22:34:30 +02:00
EXPORT_SYMBOL_GPL ( usbhid_wait_io ) ;
2005-06-06 02:22:37 -05:00
2007-04-03 23:39:37 +02:00
static int hid_set_idle ( struct usb_device * dev , int ifnum , int report , int idle )
{
return usb_control_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
HID_REQ_SET_IDLE , USB_TYPE_CLASS | USB_RECIP_INTERFACE , ( idle < < 8 ) | report ,
ifnum , NULL , 0 , USB_CTRL_SET_TIMEOUT ) ;
}
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
static int hid_get_class_descriptor ( struct usb_device * dev , int ifnum ,
unsigned char type , void * buf , int size )
{
int result , retries = 4 ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
memset ( buf , 0 , size ) ;
2005-04-16 15:20:36 -07:00
2007-04-03 23:39:37 +02:00
do {
result = usb_control_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) ,
USB_REQ_GET_DESCRIPTOR , USB_RECIP_INTERFACE | USB_DIR_IN ,
( type < < 8 ) , ifnum , buf , size , USB_CTRL_GET_TIMEOUT ) ;
retries - - ;
} while ( result < size & & retries ) ;
return result ;
}
2006-01-14 00:25:39 -05:00
2007-04-03 23:39:37 +02:00
int usbhid_open ( struct hid_device * hid )
{
2007-07-11 14:48:58 +02:00
struct usbhid_device * usbhid = hid - > driver_data ;
int res ;
2008-12-17 15:38:03 +01:00
mutex_lock ( & hid_open_mut ) ;
2007-07-11 14:48:58 +02:00
if ( ! hid - > open + + ) {
res = usb_autopm_get_interface ( usbhid - > intf ) ;
2010-12-22 15:33:40 +01:00
/* the device must be awake to reliably request remote wakeup */
2007-07-11 14:48:58 +02:00
if ( res < 0 ) {
hid - > open - - ;
2008-12-17 15:38:03 +01:00
mutex_unlock ( & hid_open_mut ) ;
2007-07-11 14:48:58 +02:00
return - EIO ;
}
2008-12-17 15:38:03 +01:00
usbhid - > intf - > needs_remote_wakeup = 1 ;
if ( hid_start_in ( hid ) )
hid_io_error ( hid ) ;
usb_autopm_put_interface ( usbhid - > intf ) ;
2007-07-11 14:48:58 +02:00
}
2008-12-17 15:38:03 +01:00
mutex_unlock ( & hid_open_mut ) ;
2007-04-03 23:39:37 +02:00
return 0 ;
}
2007-02-05 10:06:01 +01:00
2007-04-03 23:39:37 +02:00
void usbhid_close ( struct hid_device * hid )
{
struct usbhid_device * usbhid = hid - > driver_data ;
2006-01-14 10:08:06 -05:00
2008-12-17 15:38:03 +01:00
mutex_lock ( & hid_open_mut ) ;
/* protecting hid->open to make sure we don't restart
* data acquistion due to a resumption we no longer
* care about
*/
spin_lock_irq ( & usbhid - > lock ) ;
2007-07-11 14:48:58 +02:00
if ( ! - - hid - > open ) {
2008-12-17 15:38:03 +01:00
spin_unlock_irq ( & usbhid - > lock ) ;
2009-04-29 17:12:12 +02:00
hid_cancel_delayed_stuff ( usbhid ) ;
2007-04-03 23:39:37 +02:00
usb_kill_urb ( usbhid - > urbin ) ;
2008-12-17 15:38:03 +01:00
usbhid - > intf - > needs_remote_wakeup = 0 ;
} else {
spin_unlock_irq ( & usbhid - > lock ) ;
2007-07-11 14:48:58 +02:00
}
2008-12-17 15:38:03 +01:00
mutex_unlock ( & hid_open_mut ) ;
2007-04-03 23:39:37 +02:00
}
2006-03-29 22:41:07 +02:00
2007-04-03 23:39:37 +02:00
/*
* Initialize all reports
*/
2006-11-04 22:49:53 -05:00
2007-04-03 23:39:37 +02:00
void usbhid_init_reports ( struct hid_device * hid )
{
struct hid_report * report ;
struct usbhid_device * usbhid = hid - > driver_data ;
int err , ret ;
2006-11-04 22:49:53 -05:00
2007-04-03 23:39:37 +02:00
list_for_each_entry ( report , & hid - > report_enum [ HID_INPUT_REPORT ] . report_list , list )
usbhid_submit_report ( hid , report , USB_DIR_IN ) ;
2007-01-11 16:51:17 +02:00
2007-04-03 23:39:37 +02:00
list_for_each_entry ( report , & hid - > report_enum [ HID_FEATURE_REPORT ] . report_list , list )
usbhid_submit_report ( hid , report , USB_DIR_IN ) ;
2007-01-15 20:11:52 -08:00
2007-04-03 23:39:37 +02:00
err = 0 ;
ret = usbhid_wait_io ( hid ) ;
while ( ret ) {
err | = ret ;
if ( test_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) )
usb_kill_urb ( usbhid - > urbctrl ) ;
if ( test_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) )
usb_kill_urb ( usbhid - > urbout ) ;
ret = usbhid_wait_io ( hid ) ;
}
2007-02-05 16:40:57 -08:00
2007-04-03 23:39:37 +02:00
if ( err )
2010-12-09 19:29:03 -08:00
hid_warn ( hid , " timeout initializing reports \n " ) ;
2007-04-03 23:39:37 +02:00
}
2005-04-16 15:20:36 -07:00
2007-04-06 14:33:18 +02:00
/*
* Reset LEDs which BIOS might have left on . For now , just NumLock ( 0x01 ) .
*/
static int hid_find_field_early ( struct hid_device * hid , unsigned int page ,
unsigned int hid_code , struct hid_field * * pfield )
{
struct hid_report * report ;
struct hid_field * field ;
struct hid_usage * usage ;
int i , j ;
list_for_each_entry ( report , & hid - > report_enum [ HID_OUTPUT_REPORT ] . report_list , list ) {
for ( i = 0 ; i < report - > maxfield ; i + + ) {
field = report - > field [ i ] ;
for ( j = 0 ; j < field - > maxusage ; j + + ) {
usage = & field - > usage [ j ] ;
if ( ( usage - > hid & HID_USAGE_PAGE ) = = page & &
( usage - > hid & 0xFFFF ) = = hid_code ) {
* pfield = field ;
return j ;
}
}
}
}
return - 1 ;
}
2008-06-27 20:41:02 +02:00
void usbhid_set_leds ( struct hid_device * hid )
2007-04-06 14:33:18 +02:00
{
struct hid_field * field ;
int offset ;
if ( ( offset = hid_find_field_early ( hid , HID_UP_LED , 0x01 , & field ) ) ! = - 1 ) {
hid_set_field ( field , offset , 0 ) ;
usbhid_submit_report ( hid , field - > report , USB_DIR_OUT ) ;
}
}
2008-06-27 20:41:02 +02:00
EXPORT_SYMBOL_GPL ( usbhid_set_leds ) ;
2007-04-06 14:33:18 +02:00
2005-09-05 00:12:01 -05:00
/*
* Traverse the supplied list of reports and find the longest
*/
2008-03-28 17:06:41 +01:00
static void hid_find_max_report ( struct hid_device * hid , unsigned int type ,
unsigned int * max )
2005-09-05 00:12:01 -05:00
{
struct hid_report * report ;
2008-03-28 17:06:41 +01:00
unsigned int size ;
2005-09-05 00:12:01 -05:00
list_for_each_entry ( report , & hid - > report_enum [ type ] . report_list , list ) {
2008-10-17 15:01:15 +02:00
size = ( ( report - > size - 1 ) > > 3 ) + 1 + hid - > report_enum [ type ] . numbered ;
2005-09-05 00:12:01 -05:00
if ( * max < size )
* max = size ;
}
}
2005-04-16 15:20:36 -07:00
static int hid_alloc_buffers ( struct usb_device * dev , struct hid_device * hid )
{
2006-12-08 18:41:03 +01:00
struct usbhid_device * usbhid = hid - > driver_data ;
2010-04-12 13:17:25 +02:00
usbhid - > inbuf = usb_alloc_coherent ( dev , usbhid - > bufsize , GFP_KERNEL ,
2008-11-24 16:20:06 +01:00
& usbhid - > inbuf_dma ) ;
2010-04-12 13:17:25 +02:00
usbhid - > outbuf = usb_alloc_coherent ( dev , usbhid - > bufsize , GFP_KERNEL ,
2008-11-24 16:20:06 +01:00
& usbhid - > outbuf_dma ) ;
2010-03-05 15:10:17 -05:00
usbhid - > cr = kmalloc ( sizeof ( * usbhid - > cr ) , GFP_KERNEL ) ;
2010-04-12 13:17:25 +02:00
usbhid - > ctrlbuf = usb_alloc_coherent ( dev , usbhid - > bufsize , GFP_KERNEL ,
2008-11-24 16:20:06 +01:00
& usbhid - > ctrlbuf_dma ) ;
if ( ! usbhid - > inbuf | | ! usbhid - > outbuf | | ! usbhid - > cr | |
! usbhid - > ctrlbuf )
2005-04-16 15:20:36 -07:00
return - 1 ;
return 0 ;
}
2010-01-29 15:03:36 +01:00
static int usbhid_output_raw_report ( struct hid_device * hid , __u8 * buf , size_t count ,
unsigned char report_type )
2007-05-14 09:54:30 +02:00
{
struct usbhid_device * usbhid = hid - > driver_data ;
struct usb_device * dev = hid_to_usb_dev ( hid ) ;
struct usb_interface * intf = usbhid - > intf ;
struct usb_host_interface * interface = intf - > cur_altsetting ;
int ret ;
2010-09-22 13:19:42 +02:00
if ( usbhid - > urbout & & report_type ! = HID_FEATURE_REPORT ) {
2010-05-16 18:07:09 -04:00
int actual_length ;
int skipped_report_id = 0 ;
2010-09-22 13:33:20 +02:00
2010-05-16 18:07:09 -04:00
if ( buf [ 0 ] = = 0x0 ) {
/* Don't send the Report ID */
buf + + ;
count - - ;
skipped_report_id = 1 ;
}
ret = usb_interrupt_msg ( dev , usbhid - > urbout - > pipe ,
buf , count , & actual_length ,
USB_CTRL_SET_TIMEOUT ) ;
/* return the number of bytes transferred */
if ( ret = = 0 ) {
ret = actual_length ;
/* count also the report id */
if ( skipped_report_id )
ret + + ;
}
} else {
2010-06-30 09:50:36 -04:00
int skipped_report_id = 0 ;
2010-08-17 00:44:04 -04:00
int report_id = buf [ 0 ] ;
2010-06-30 09:50:36 -04:00
if ( buf [ 0 ] = = 0x0 ) {
/* Don't send the Report ID */
buf + + ;
count - - ;
skipped_report_id = 1 ;
}
2010-05-16 18:07:09 -04:00
ret = usb_control_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
HID_REQ_SET_REPORT ,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE ,
2010-08-17 00:44:04 -04:00
( ( report_type + 1 ) < < 8 ) | report_id ,
2010-06-30 09:50:36 -04:00
interface - > desc . bInterfaceNumber , buf , count ,
2010-05-16 18:07:09 -04:00
USB_CTRL_SET_TIMEOUT ) ;
2010-06-30 09:50:36 -04:00
/* count also the report id, if this was a numbered report. */
if ( ret > 0 & & skipped_report_id )
2010-05-16 18:07:09 -04:00
ret + + ;
}
2007-05-14 09:54:30 +02:00
return ret ;
}
2008-12-17 15:38:03 +01:00
static void usbhid_restart_queues ( struct usbhid_device * usbhid )
{
if ( usbhid - > urbout )
usbhid_restart_out_queue ( usbhid ) ;
usbhid_restart_ctrl_queue ( usbhid ) ;
}
2005-04-16 15:20:36 -07:00
static void hid_free_buffers ( struct usb_device * dev , struct hid_device * hid )
{
2006-12-08 18:41:03 +01:00
struct usbhid_device * usbhid = hid - > driver_data ;
2010-04-12 13:17:25 +02:00
usb_free_coherent ( dev , usbhid - > bufsize , usbhid - > inbuf , usbhid - > inbuf_dma ) ;
usb_free_coherent ( dev , usbhid - > bufsize , usbhid - > outbuf , usbhid - > outbuf_dma ) ;
2010-03-05 15:10:17 -05:00
kfree ( usbhid - > cr ) ;
2010-04-12 13:17:25 +02:00
usb_free_coherent ( dev , usbhid - > bufsize , usbhid - > ctrlbuf , usbhid - > ctrlbuf_dma ) ;
2005-04-16 15:20:36 -07:00
}
2008-05-16 11:49:16 +02:00
static int usbhid_parse ( struct hid_device * hid )
{
struct usb_interface * intf = to_usb_interface ( hid - > dev . parent ) ;
2005-04-16 15:20:36 -07:00
struct usb_host_interface * interface = intf - > cur_altsetting ;
struct usb_device * dev = interface_to_usbdev ( intf ) ;
struct hid_descriptor * hdesc ;
2007-04-19 13:27:04 +02:00
u32 quirks = 0 ;
2008-05-16 11:49:16 +02:00
unsigned int rsize = 0 ;
2005-09-15 02:01:47 -05:00
char * rdesc ;
2008-05-16 11:49:16 +02:00
int ret , n ;
2005-04-16 15:20:36 -07:00
2007-04-19 13:27:04 +02:00
quirks = usbhid_lookup_quirk ( le16_to_cpu ( dev - > descriptor . idVendor ) ,
le16_to_cpu ( dev - > descriptor . idProduct ) ) ;
2005-04-16 15:20:36 -07:00
2009-01-29 00:15:51 +01:00
if ( quirks & HID_QUIRK_IGNORE )
return - ENODEV ;
2006-05-15 14:49:04 -04:00
/* Many keyboards and mice don't like to be polled for reports,
* so we will always set the HID_QUIRK_NOGET flag for them . */
if ( interface - > desc . bInterfaceSubClass = = USB_INTERFACE_SUBCLASS_BOOT ) {
if ( interface - > desc . bInterfaceProtocol = = USB_INTERFACE_PROTOCOL_KEYBOARD | |
interface - > desc . bInterfaceProtocol = = USB_INTERFACE_PROTOCOL_MOUSE )
quirks | = HID_QUIRK_NOGET ;
}
2005-09-15 02:01:47 -05:00
if ( usb_get_extra_descriptor ( interface , HID_DT_HID , & hdesc ) & &
( ! interface - > desc . bNumEndpoints | |
usb_get_extra_descriptor ( & interface - > endpoint [ 0 ] , HID_DT_HID , & hdesc ) ) ) {
2007-05-30 15:07:13 +02:00
dbg_hid ( " class descriptor not present \n " ) ;
2008-05-16 11:49:16 +02:00
return - ENODEV ;
2005-04-16 15:20:36 -07:00
}
2008-05-16 11:49:16 +02:00
hid - > version = le16_to_cpu ( hdesc - > bcdHID ) ;
hid - > country = hdesc - > bCountryCode ;
2005-04-16 15:20:36 -07:00
for ( n = 0 ; n < hdesc - > bNumDescriptors ; n + + )
if ( hdesc - > desc [ n ] . bDescriptorType = = HID_DT_REPORT )
rsize = le16_to_cpu ( hdesc - > desc [ n ] . wDescriptorLength ) ;
if ( ! rsize | | rsize > HID_MAX_DESCRIPTOR_SIZE ) {
2007-05-30 15:07:13 +02:00
dbg_hid ( " weird size of report descriptor (%u) \n " , rsize ) ;
2008-05-16 11:49:16 +02:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
}
if ( ! ( rdesc = kmalloc ( rsize , GFP_KERNEL ) ) ) {
2007-05-30 15:07:13 +02:00
dbg_hid ( " couldn't allocate rdesc memory \n " ) ;
2008-05-16 11:49:16 +02:00
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
}
2005-05-29 02:28:00 -05:00
hid_set_idle ( dev , interface - > desc . bInterfaceNumber , 0 , 0 ) ;
2008-05-16 11:49:16 +02:00
ret = hid_get_class_descriptor ( dev , interface - > desc . bInterfaceNumber ,
HID_DT_REPORT , rdesc , rsize ) ;
if ( ret < 0 ) {
2007-05-30 15:07:13 +02:00
dbg_hid ( " reading report descriptor failed \n " ) ;
2005-04-16 15:20:36 -07:00
kfree ( rdesc ) ;
2008-05-16 11:49:16 +02:00
goto err ;
2005-04-16 15:20:36 -07:00
}
2008-05-16 11:49:16 +02:00
ret = hid_parse_report ( hid , rdesc , rsize ) ;
kfree ( rdesc ) ;
if ( ret ) {
2007-05-30 15:07:13 +02:00
dbg_hid ( " parsing report descriptor failed \n " ) ;
2008-05-16 11:49:16 +02:00
goto err ;
2005-04-16 15:20:36 -07:00
}
2009-05-06 16:30:21 +02:00
hid - > quirks | = quirks ;
2005-04-16 15:20:36 -07:00
2008-05-16 11:49:16 +02:00
return 0 ;
err :
return ret ;
}
static int usbhid_start ( struct hid_device * hid )
{
struct usb_interface * intf = to_usb_interface ( hid - > dev . parent ) ;
struct usb_host_interface * interface = intf - > cur_altsetting ;
struct usb_device * dev = interface_to_usbdev ( intf ) ;
2008-10-27 12:16:15 +01:00
struct usbhid_device * usbhid = hid - > driver_data ;
2008-05-16 11:49:16 +02:00
unsigned int n , insize = 0 ;
int ret ;
2008-11-01 23:41:46 +01:00
clear_bit ( HID_DISCONNECTED , & usbhid - > iofl ) ;
2006-12-08 18:41:03 +01:00
usbhid - > bufsize = HID_MIN_BUFFER_SIZE ;
hid_find_max_report ( hid , HID_INPUT_REPORT , & usbhid - > bufsize ) ;
hid_find_max_report ( hid , HID_OUTPUT_REPORT , & usbhid - > bufsize ) ;
hid_find_max_report ( hid , HID_FEATURE_REPORT , & usbhid - > bufsize ) ;
2005-09-05 00:12:01 -05:00
2006-12-08 18:41:03 +01:00
if ( usbhid - > bufsize > HID_MAX_BUFFER_SIZE )
usbhid - > bufsize = HID_MAX_BUFFER_SIZE ;
2005-09-05 00:12:01 -05:00
hid_find_max_report ( hid , HID_INPUT_REPORT , & insize ) ;
if ( insize > HID_MAX_BUFFER_SIZE )
insize = HID_MAX_BUFFER_SIZE ;
2008-05-16 11:49:16 +02:00
if ( hid_alloc_buffers ( dev , hid ) ) {
ret = - ENOMEM ;
2005-04-16 15:20:36 -07:00
goto fail ;
2008-03-06 13:23:14 +01:00
}
2005-04-16 15:20:36 -07:00
for ( n = 0 ; n < interface - > desc . bNumEndpoints ; n + + ) {
struct usb_endpoint_descriptor * endpoint ;
int pipe ;
int interval ;
endpoint = & interface - > endpoint [ n ] . desc ;
2008-11-24 16:20:08 +01:00
if ( ! usb_endpoint_xfer_int ( endpoint ) )
2005-04-16 15:20:36 -07:00
continue ;
interval = endpoint - > bInterval ;
2008-03-06 13:23:14 +01:00
/* Some vendors give fullspeed interval on highspeed devides */
2008-05-16 11:49:16 +02:00
if ( hid - > quirks & HID_QUIRK_FULLSPEED_INTERVAL & &
2008-03-06 13:23:14 +01:00
dev - > speed = = USB_SPEED_HIGH ) {
interval = fls ( endpoint - > bInterval * 8 ) ;
printk ( KERN_INFO " %s: Fixing fullspeed to highspeed interval: %d -> %d \n " ,
hid - > name , endpoint - > bInterval , interval ) ;
}
2005-04-16 15:20:36 -07:00
/* Change the polling interval of mice. */
if ( hid - > collection - > usage = = HID_GD_MOUSE & & hid_mousepoll_interval > 0 )
interval = hid_mousepoll_interval ;
2005-05-29 02:29:01 -05:00
2008-05-16 11:49:16 +02:00
ret = - ENOMEM ;
2006-10-26 13:02:51 -03:00
if ( usb_endpoint_dir_in ( endpoint ) ) {
2006-12-08 18:41:03 +01:00
if ( usbhid - > urbin )
2005-04-16 15:20:36 -07:00
continue ;
2006-12-08 18:41:03 +01:00
if ( ! ( usbhid - > urbin = usb_alloc_urb ( 0 , GFP_KERNEL ) ) )
2005-04-16 15:20:36 -07:00
goto fail ;
pipe = usb_rcvintpipe ( dev , endpoint - > bEndpointAddress ) ;
2006-12-08 18:41:03 +01:00
usb_fill_int_urb ( usbhid - > urbin , dev , pipe , usbhid - > inbuf , insize ,
2005-04-16 15:20:36 -07:00
hid_irq_in , hid , interval ) ;
2006-12-08 18:41:03 +01:00
usbhid - > urbin - > transfer_dma = usbhid - > inbuf_dma ;
usbhid - > urbin - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
2005-04-16 15:20:36 -07:00
} else {
2006-12-08 18:41:03 +01:00
if ( usbhid - > urbout )
2005-04-16 15:20:36 -07:00
continue ;
2006-12-08 18:41:03 +01:00
if ( ! ( usbhid - > urbout = usb_alloc_urb ( 0 , GFP_KERNEL ) ) )
2005-04-16 15:20:36 -07:00
goto fail ;
pipe = usb_sndintpipe ( dev , endpoint - > bEndpointAddress ) ;
2006-12-08 18:41:03 +01:00
usb_fill_int_urb ( usbhid - > urbout , dev , pipe , usbhid - > outbuf , 0 ,
2005-04-16 15:20:36 -07:00
hid_irq_out , hid , interval ) ;
2006-12-08 18:41:03 +01:00
usbhid - > urbout - > transfer_dma = usbhid - > outbuf_dma ;
usbhid - > urbout - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
2005-04-16 15:20:36 -07:00
}
}
2006-12-08 18:41:03 +01:00
usbhid - > urbctrl = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2008-05-16 11:49:16 +02:00
if ( ! usbhid - > urbctrl ) {
ret = - ENOMEM ;
2005-04-16 15:20:36 -07:00
goto fail ;
2008-05-16 11:49:16 +02:00
}
2005-09-15 02:01:47 -05:00
2006-12-08 18:41:03 +01:00
usb_fill_control_urb ( usbhid - > urbctrl , dev , 0 , ( void * ) usbhid - > cr ,
usbhid - > ctrlbuf , 1 , hid_ctrl , hid ) ;
usbhid - > urbctrl - > transfer_dma = usbhid - > ctrlbuf_dma ;
2010-03-05 15:10:17 -05:00
usbhid - > urbctrl - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
2008-05-16 11:49:16 +02:00
2009-11-05 14:08:03 +01:00
if ( ! ( hid - > quirks & HID_QUIRK_NO_INIT_REPORTS ) )
usbhid_init_reports ( hid ) ;
2008-06-27 00:04:24 +02:00
2008-10-27 12:16:15 +01:00
set_bit ( HID_STARTED , & usbhid - > iofl ) ;
2008-10-30 23:58:51 +01:00
/* Some keyboards don't work until their LEDs have been set.
* Since BIOSes do set the LEDs , it must be safe for any device
* that supports the keyboard boot protocol .
2010-04-02 13:21:58 -04:00
* In addition , enable remote wakeup by default for all keyboard
* devices supporting the boot protocol .
2008-10-30 23:58:51 +01:00
*/
if ( interface - > desc . bInterfaceSubClass = = USB_INTERFACE_SUBCLASS_BOOT & &
interface - > desc . bInterfaceProtocol = =
2010-04-02 13:21:58 -04:00
USB_INTERFACE_PROTOCOL_KEYBOARD ) {
2008-10-30 23:58:51 +01:00
usbhid_set_leds ( hid ) ;
2010-04-02 13:21:58 -04:00
device_set_wakeup_enable ( & dev - > dev , 1 ) ;
}
2008-05-16 11:49:16 +02:00
return 0 ;
2005-04-16 15:20:36 -07:00
fail :
2006-12-08 18:41:03 +01:00
usb_free_urb ( usbhid - > urbin ) ;
usb_free_urb ( usbhid - > urbout ) ;
usb_free_urb ( usbhid - > urbctrl ) ;
2008-11-01 23:41:46 +01:00
usbhid - > urbin = NULL ;
usbhid - > urbout = NULL ;
usbhid - > urbctrl = NULL ;
2007-08-01 12:32:27 +02:00
hid_free_buffers ( dev , hid ) ;
2008-05-16 11:49:16 +02:00
return ret ;
2005-04-16 15:20:36 -07:00
}
2008-05-16 11:49:16 +02:00
static void usbhid_stop ( struct hid_device * hid )
2005-04-16 15:20:36 -07:00
{
2008-05-16 11:49:16 +02:00
struct usbhid_device * usbhid = hid - > driver_data ;
2005-04-16 15:20:36 -07:00
2008-05-16 11:49:16 +02:00
if ( WARN_ON ( ! usbhid ) )
2005-04-16 15:20:36 -07:00
return ;
2008-10-27 12:16:15 +01:00
clear_bit ( HID_STARTED , & usbhid - > iofl ) ;
2008-12-17 15:38:03 +01:00
spin_lock_irq ( & usbhid - > lock ) ; /* Sync with error handler */
2008-03-31 16:27:30 +02:00
set_bit ( HID_DISCONNECTED , & usbhid - > iofl ) ;
2008-12-17 15:38:03 +01:00
spin_unlock_irq ( & usbhid - > lock ) ;
2006-12-08 18:41:03 +01:00
usb_kill_urb ( usbhid - > urbin ) ;
usb_kill_urb ( usbhid - > urbout ) ;
usb_kill_urb ( usbhid - > urbctrl ) ;
2005-04-16 15:20:36 -07:00
2008-12-17 15:38:03 +01:00
hid_cancel_delayed_stuff ( usbhid ) ;
2006-01-31 12:58:38 -05:00
2008-05-16 11:49:16 +02:00
hid - > claimed = 0 ;
2006-12-08 18:41:03 +01:00
usb_free_urb ( usbhid - > urbin ) ;
usb_free_urb ( usbhid - > urbctrl ) ;
usb_free_urb ( usbhid - > urbout ) ;
2008-11-01 23:41:46 +01:00
usbhid - > urbin = NULL ; /* don't mess up next start */
usbhid - > urbctrl = NULL ;
usbhid - > urbout = NULL ;
2005-04-16 15:20:36 -07:00
2007-01-19 19:28:17 +02:00
hid_free_buffers ( hid_to_usb_dev ( hid ) , hid ) ;
2005-04-16 15:20:36 -07:00
}
2008-12-17 15:38:03 +01:00
static int usbhid_power ( struct hid_device * hid , int lvl )
{
int r = 0 ;
switch ( lvl ) {
case PM_HINT_FULLON :
r = usbhid_get_power ( hid ) ;
break ;
case PM_HINT_NORMAL :
usbhid_put_power ( hid ) ;
break ;
}
return r ;
}
2008-05-16 11:49:16 +02:00
static struct hid_ll_driver usb_hid_driver = {
. parse = usbhid_parse ,
. start = usbhid_start ,
. stop = usbhid_stop ,
. open = usbhid_open ,
. close = usbhid_close ,
2008-12-17 15:38:03 +01:00
. power = usbhid_power ,
2008-05-16 11:49:16 +02:00
. hidinput_input_event = usb_hidinput_input_event ,
} ;
2009-09-15 16:27:45 +02:00
static int usbhid_probe ( struct usb_interface * intf , const struct usb_device_id * id )
2005-04-16 15:20:36 -07:00
{
2008-11-14 12:03:47 +01:00
struct usb_host_interface * interface = intf - > cur_altsetting ;
2008-05-16 11:49:16 +02:00
struct usb_device * dev = interface_to_usbdev ( intf ) ;
2008-10-27 12:16:15 +01:00
struct usbhid_device * usbhid ;
2005-04-16 15:20:36 -07:00
struct hid_device * hid ;
2008-11-14 12:03:47 +01:00
unsigned int n , has_in = 0 ;
2008-05-16 11:49:16 +02:00
size_t len ;
int ret ;
2005-04-16 15:20:36 -07:00
2007-05-30 15:07:13 +02:00
dbg_hid ( " HID probe called for ifnum %d \n " ,
2005-04-16 15:20:36 -07:00
intf - > altsetting - > desc . bInterfaceNumber ) ;
2008-11-14 12:03:47 +01:00
for ( n = 0 ; n < interface - > desc . bNumEndpoints ; n + + )
if ( usb_endpoint_is_int_in ( & interface - > endpoint [ n ] . desc ) )
has_in + + ;
if ( ! has_in ) {
2010-12-09 19:29:03 -08:00
hid_err ( intf , " couldn't find an input interrupt endpoint \n " ) ;
2008-11-14 12:03:47 +01:00
return - ENODEV ;
}
2008-05-16 11:49:16 +02:00
hid = hid_allocate_device ( ) ;
if ( IS_ERR ( hid ) )
return PTR_ERR ( hid ) ;
2005-04-16 15:20:36 -07:00
usb_set_intfdata ( intf , hid ) ;
2008-05-16 11:49:16 +02:00
hid - > ll_driver = & usb_hid_driver ;
hid - > hid_output_raw_report = usbhid_output_raw_report ;
2008-09-18 12:23:33 +02:00
hid - > ff_init = hid_pidff_init ;
2008-05-16 11:49:16 +02:00
# ifdef CONFIG_USB_HIDDEV
2008-06-27 00:04:24 +02:00
hid - > hiddev_connect = hiddev_connect ;
2009-09-15 16:27:45 +02:00
hid - > hiddev_disconnect = hiddev_disconnect ;
2008-05-16 11:49:16 +02:00
hid - > hiddev_hid_event = hiddev_hid_event ;
hid - > hiddev_report_event = hiddev_report_event ;
# endif
hid - > dev . parent = & intf - > dev ;
hid - > bus = BUS_USB ;
hid - > vendor = le16_to_cpu ( dev - > descriptor . idVendor ) ;
hid - > product = le16_to_cpu ( dev - > descriptor . idProduct ) ;
hid - > name [ 0 ] = 0 ;
2010-04-16 17:19:50 +01:00
hid - > quirks = usbhid_lookup_quirk ( hid - > vendor , hid - > product ) ;
2008-10-22 14:45:11 +02:00
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol = =
USB_INTERFACE_PROTOCOL_MOUSE )
hid - > type = HID_TYPE_USBMOUSE ;
2005-04-16 15:20:36 -07:00
2008-05-16 11:49:16 +02:00
if ( dev - > manufacturer )
strlcpy ( hid - > name , dev - > manufacturer , sizeof ( hid - > name ) ) ;
2005-04-16 15:20:36 -07:00
2008-05-16 11:49:16 +02:00
if ( dev - > product ) {
if ( dev - > manufacturer )
strlcat ( hid - > name , " " , sizeof ( hid - > name ) ) ;
strlcat ( hid - > name , dev - > product , sizeof ( hid - > name ) ) ;
2005-04-16 15:20:36 -07:00
}
2008-05-16 11:49:16 +02:00
if ( ! strlen ( hid - > name ) )
snprintf ( hid - > name , sizeof ( hid - > name ) , " HID %04x:%04x " ,
le16_to_cpu ( dev - > descriptor . idVendor ) ,
le16_to_cpu ( dev - > descriptor . idProduct ) ) ;
2005-04-16 15:20:36 -07:00
2008-05-16 11:49:16 +02:00
usb_make_path ( dev , hid - > phys , sizeof ( hid - > phys ) ) ;
strlcat ( hid - > phys , " /input " , sizeof ( hid - > phys ) ) ;
len = strlen ( hid - > phys ) ;
if ( len < sizeof ( hid - > phys ) - 1 )
snprintf ( hid - > phys + len , sizeof ( hid - > phys ) - len ,
" %d " , intf - > altsetting [ 0 ] . desc . bInterfaceNumber ) ;
if ( usb_string ( dev , dev - > descriptor . iSerialNumber , hid - > uniq , 64 ) < = 0 )
hid - > uniq [ 0 ] = 0 ;
2005-04-16 15:20:36 -07:00
2008-10-27 12:16:15 +01:00
usbhid = kzalloc ( sizeof ( * usbhid ) , GFP_KERNEL ) ;
if ( usbhid = = NULL ) {
ret = - ENOMEM ;
goto err ;
}
hid - > driver_data = usbhid ;
usbhid - > hid = hid ;
2010-02-17 14:25:01 +01:00
usbhid - > intf = intf ;
usbhid - > ifnum = interface - > desc . bInterfaceNumber ;
2008-10-27 12:16:15 +01:00
2010-05-07 10:41:10 -04:00
init_waitqueue_head ( & usbhid - > wait ) ;
INIT_WORK ( & usbhid - > reset_work , hid_reset ) ;
setup_timer ( & usbhid - > io_retry , hid_retry_timeout , ( unsigned long ) hid ) ;
spin_lock_init ( & usbhid - > lock ) ;
2008-05-16 11:49:15 +02:00
ret = hid_add_device ( hid ) ;
if ( ret ) {
2008-05-16 11:49:20 +02:00
if ( ret ! = - ENODEV )
2010-12-09 19:29:03 -08:00
hid_err ( intf , " can't add hid device: %d \n " , ret ) ;
2008-10-27 12:16:15 +01:00
goto err_free ;
2008-05-16 11:49:15 +02:00
}
2008-05-16 11:49:16 +02:00
return 0 ;
2008-10-27 12:16:15 +01:00
err_free :
kfree ( usbhid ) ;
2008-05-16 11:49:16 +02:00
err :
hid_destroy_device ( hid ) ;
2008-05-16 11:49:15 +02:00
return ret ;
2005-04-16 15:20:36 -07:00
}
2009-09-15 16:27:45 +02:00
static void usbhid_disconnect ( struct usb_interface * intf )
2008-05-16 11:49:16 +02:00
{
struct hid_device * hid = usb_get_intfdata ( intf ) ;
2008-10-27 12:16:15 +01:00
struct usbhid_device * usbhid ;
2008-05-16 11:49:16 +02:00
if ( WARN_ON ( ! hid ) )
return ;
2008-10-27 12:16:15 +01:00
usbhid = hid - > driver_data ;
2008-05-16 11:49:16 +02:00
hid_destroy_device ( hid ) ;
2008-10-27 12:16:15 +01:00
kfree ( usbhid ) ;
2008-05-16 11:49:16 +02:00
}
2008-12-17 15:38:03 +01:00
static void hid_cancel_delayed_stuff ( struct usbhid_device * usbhid )
{
del_timer_sync ( & usbhid - > io_retry ) ;
cancel_work_sync ( & usbhid - > reset_work ) ;
}
static void hid_cease_io ( struct usbhid_device * usbhid )
{
del_timer ( & usbhid - > io_retry ) ;
usb_kill_urb ( usbhid - > urbin ) ;
usb_kill_urb ( usbhid - > urbctrl ) ;
usb_kill_urb ( usbhid - > urbout ) ;
}
2009-02-20 12:47:08 +01:00
/* Treat USB reset pretty much the same as suspend/resume */
static int hid_pre_reset ( struct usb_interface * intf )
{
struct hid_device * hid = usb_get_intfdata ( intf ) ;
struct usbhid_device * usbhid = hid - > driver_data ;
spin_lock_irq ( & usbhid - > lock ) ;
set_bit ( HID_RESET_PENDING , & usbhid - > iofl ) ;
spin_unlock_irq ( & usbhid - > lock ) ;
hid_cease_io ( usbhid ) ;
return 0 ;
}
/* Same routine used for post_reset and reset_resume */
static int hid_post_reset ( struct usb_interface * intf )
{
struct usb_device * dev = interface_to_usbdev ( intf ) ;
struct hid_device * hid = usb_get_intfdata ( intf ) ;
struct usbhid_device * usbhid = hid - > driver_data ;
int status ;
2009-06-04 15:48:38 +02:00
2009-02-20 12:47:08 +01:00
spin_lock_irq ( & usbhid - > lock ) ;
clear_bit ( HID_RESET_PENDING , & usbhid - > iofl ) ;
spin_unlock_irq ( & usbhid - > lock ) ;
hid_set_idle ( dev , intf - > cur_altsetting - > desc . bInterfaceNumber , 0 , 0 ) ;
status = hid_start_in ( hid ) ;
if ( status < 0 )
hid_io_error ( hid ) ;
usbhid_restart_queues ( usbhid ) ;
return 0 ;
}
int usbhid_get_power ( struct hid_device * hid )
{
struct usbhid_device * usbhid = hid - > driver_data ;
2009-06-04 15:48:38 +02:00
2009-02-20 12:47:08 +01:00
return usb_autopm_get_interface ( usbhid - > intf ) ;
}
void usbhid_put_power ( struct hid_device * hid )
{
struct usbhid_device * usbhid = hid - > driver_data ;
2009-06-04 15:48:38 +02:00
2009-02-20 12:47:08 +01:00
usb_autopm_put_interface ( usbhid - > intf ) ;
}
2009-01-19 09:17:18 +01:00
# ifdef CONFIG_PM
2005-04-18 17:39:22 -07:00
static int hid_suspend ( struct usb_interface * intf , pm_message_t message )
2005-04-16 15:20:36 -07:00
{
2008-12-17 15:38:03 +01:00
struct hid_device * hid = usb_get_intfdata ( intf ) ;
2006-12-08 18:41:03 +01:00
struct usbhid_device * usbhid = hid - > driver_data ;
2008-12-17 15:38:03 +01:00
int status ;
2005-04-16 15:20:36 -07:00
2009-11-13 11:53:59 -05:00
if ( message . event & PM_EVENT_AUTO ) {
2008-12-17 15:38:03 +01:00
spin_lock_irq ( & usbhid - > lock ) ; /* Sync with error handler */
if ( ! test_bit ( HID_RESET_PENDING , & usbhid - > iofl )
& & ! test_bit ( HID_CLEAR_HALT , & usbhid - > iofl )
& & ! test_bit ( HID_OUT_RUNNING , & usbhid - > iofl )
& & ! test_bit ( HID_CTRL_RUNNING , & usbhid - > iofl )
& & ! test_bit ( HID_KEYS_PRESSED , & usbhid - > iofl )
& & ( ! usbhid - > ledcount | | ignoreled ) )
{
set_bit ( HID_REPORTED_IDLE , & usbhid - > iofl ) ;
spin_unlock_irq ( & usbhid - > lock ) ;
2010-04-25 21:40:03 +02:00
if ( hid - > driver & & hid - > driver - > suspend ) {
status = hid - > driver - > suspend ( hid , message ) ;
if ( status < 0 )
return status ;
}
2008-12-17 15:38:03 +01:00
} else {
usbhid_mark_busy ( usbhid ) ;
spin_unlock_irq ( & usbhid - > lock ) ;
return - EBUSY ;
}
2008-10-27 12:16:15 +01:00
2008-12-17 15:38:03 +01:00
} else {
2010-04-25 21:40:03 +02:00
if ( hid - > driver & & hid - > driver - > suspend ) {
status = hid - > driver - > suspend ( hid , message ) ;
if ( status < 0 )
return status ;
}
2008-12-17 15:38:03 +01:00
spin_lock_irq ( & usbhid - > lock ) ;
set_bit ( HID_REPORTED_IDLE , & usbhid - > iofl ) ;
spin_unlock_irq ( & usbhid - > lock ) ;
if ( usbhid_wait_io ( hid ) < 0 )
return - EIO ;
}
2009-11-13 11:53:59 -05:00
if ( ! ignoreled & & ( message . event & PM_EVENT_AUTO ) ) {
2008-12-17 15:38:03 +01:00
spin_lock_irq ( & usbhid - > lock ) ;
if ( test_bit ( HID_LED_ON , & usbhid - > iofl ) ) {
spin_unlock_irq ( & usbhid - > lock ) ;
usbhid_mark_busy ( usbhid ) ;
return - EBUSY ;
}
spin_unlock_irq ( & usbhid - > lock ) ;
}
hid_cancel_delayed_stuff ( usbhid ) ;
hid_cease_io ( usbhid ) ;
2009-11-13 11:53:59 -05:00
if ( ( message . event & PM_EVENT_AUTO ) & &
test_bit ( HID_KEYS_PRESSED , & usbhid - > iofl ) ) {
2008-12-17 15:38:03 +01:00
/* lost race against keypresses */
status = hid_start_in ( hid ) ;
if ( status < 0 )
hid_io_error ( hid ) ;
usbhid_mark_busy ( usbhid ) ;
return - EBUSY ;
}
2005-04-16 15:20:36 -07:00
dev_dbg ( & intf - > dev , " suspend \n " ) ;
return 0 ;
}
static int hid_resume ( struct usb_interface * intf )
{
struct hid_device * hid = usb_get_intfdata ( intf ) ;
2006-12-08 18:41:03 +01:00
struct usbhid_device * usbhid = hid - > driver_data ;
2005-04-16 15:20:36 -07:00
int status ;
2008-11-23 12:03:20 +01:00
if ( ! test_bit ( HID_STARTED , & usbhid - > iofl ) )
2008-10-27 12:16:15 +01:00
return 0 ;
2008-12-17 15:38:03 +01:00
clear_bit ( HID_REPORTED_IDLE , & usbhid - > iofl ) ;
usbhid_mark_busy ( usbhid ) ;
if ( test_bit ( HID_CLEAR_HALT , & usbhid - > iofl ) | |
test_bit ( HID_RESET_PENDING , & usbhid - > iofl ) )
schedule_work ( & usbhid - > reset_work ) ;
2006-12-08 18:41:03 +01:00
usbhid - > retry_delay = 0 ;
2006-01-31 12:58:38 -05:00
status = hid_start_in ( hid ) ;
2008-12-17 15:38:03 +01:00
if ( status < 0 )
hid_io_error ( hid ) ;
usbhid_restart_queues ( usbhid ) ;
2005-04-16 15:20:36 -07:00
2010-04-25 21:40:03 +02:00
if ( status > = 0 & & hid - > driver & & hid - > driver - > resume ) {
int ret = hid - > driver - > resume ( hid ) ;
if ( ret < 0 )
status = ret ;
}
2005-04-16 15:20:36 -07:00
dev_dbg ( & intf - > dev , " resume status %d \n " , status ) ;
2007-05-30 15:38:16 -04:00
return 0 ;
2006-06-01 13:55:28 -04:00
}
2009-02-18 11:46:45 +01:00
static int hid_reset_resume ( struct usb_interface * intf )
2006-06-01 13:55:28 -04:00
{
2009-02-18 11:46:45 +01:00
struct hid_device * hid = usb_get_intfdata ( intf ) ;
struct usbhid_device * usbhid = hid - > driver_data ;
2010-04-25 21:40:03 +02:00
int status ;
2006-06-01 13:55:28 -04:00
2009-02-18 11:46:45 +01:00
clear_bit ( HID_REPORTED_IDLE , & usbhid - > iofl ) ;
2010-04-25 21:40:03 +02:00
status = hid_post_reset ( intf ) ;
if ( status > = 0 & & hid - > driver & & hid - > driver - > reset_resume ) {
int ret = hid - > driver - > reset_resume ( hid ) ;
if ( ret < 0 )
status = ret ;
}
return status ;
2006-06-01 13:55:28 -04:00
}
2009-02-20 12:47:08 +01:00
# endif /* CONFIG_PM */
2006-06-01 13:55:28 -04:00
2010-01-10 17:59:22 +01:00
static const struct usb_device_id hid_usb_ids [ ] = {
2005-04-16 15:20:36 -07:00
{ . match_flags = USB_DEVICE_ID_MATCH_INT_CLASS ,
. bInterfaceClass = USB_INTERFACE_CLASS_HID } ,
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , hid_usb_ids ) ;
static struct usb_driver hid_driver = {
. name = " usbhid " ,
2009-09-15 16:27:45 +02:00
. probe = usbhid_probe ,
. disconnect = usbhid_disconnect ,
2009-01-19 09:17:18 +01:00
# ifdef CONFIG_PM
2005-04-16 15:20:36 -07:00
. suspend = hid_suspend ,
. resume = hid_resume ,
2009-02-18 11:46:45 +01:00
. reset_resume = hid_reset_resume ,
2009-01-19 09:17:18 +01:00
# endif
2006-06-01 13:55:28 -04:00
. pre_reset = hid_pre_reset ,
. post_reset = hid_post_reset ,
2005-04-16 15:20:36 -07:00
. id_table = hid_usb_ids ,
2007-07-11 14:48:58 +02:00
. supports_autosuspend = 1 ,
2005-04-16 15:20:36 -07:00
} ;
2008-05-16 11:49:15 +02:00
static const struct hid_device_id hid_usb_table [ ] = {
{ HID_USB_DEVICE ( HID_ANY_ID , HID_ANY_ID ) } ,
{ }
} ;
2010-09-12 21:32:35 +02:00
struct usb_interface * usbhid_find_interface ( int minor )
{
return usb_find_interface ( & hid_driver , minor ) ;
}
2008-05-16 11:49:15 +02:00
static struct hid_driver hid_usb_driver = {
. name = " generic-usb " ,
. id_table = hid_usb_table ,
} ;
2005-04-16 15:20:36 -07:00
static int __init hid_init ( void )
{
2008-12-17 15:38:03 +01:00
int retval = - ENOMEM ;
2008-05-16 11:49:15 +02:00
retval = hid_register_driver ( & hid_usb_driver ) ;
if ( retval )
goto hid_register_fail ;
2007-04-19 14:56:12 +02:00
retval = usbhid_quirks_init ( quirks_param ) ;
if ( retval )
goto usbhid_quirks_init_fail ;
2005-04-16 15:20:36 -07:00
retval = usb_register ( & hid_driver ) ;
if ( retval )
goto usb_register_fail ;
2009-10-02 18:31:36 +02:00
printk ( KERN_INFO KBUILD_MODNAME " : " DRIVER_DESC " \n " ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
usb_register_fail :
2007-04-19 14:56:12 +02:00
usbhid_quirks_exit ( ) ;
usbhid_quirks_init_fail :
2008-05-16 11:49:15 +02:00
hid_unregister_driver ( & hid_usb_driver ) ;
hid_register_fail :
2005-04-16 15:20:36 -07:00
return retval ;
}
static void __exit hid_exit ( void )
{
usb_deregister ( & hid_driver ) ;
2007-04-19 14:56:12 +02:00
usbhid_quirks_exit ( ) ;
2008-05-16 11:49:15 +02:00
hid_unregister_driver ( & hid_usb_driver ) ;
2005-04-16 15:20:36 -07:00
}
module_init ( hid_init ) ;
module_exit ( hid_exit ) ;
2009-10-02 18:29:34 +02:00
MODULE_AUTHOR ( " Andreas Gal " ) ;
MODULE_AUTHOR ( " Vojtech Pavlik " ) ;
MODULE_AUTHOR ( " Jiri Kosina " ) ;
2005-04-16 15:20:36 -07:00
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( DRIVER_LICENSE ) ;