2005-04-17 02:20:36 +04:00
/*
* USB HID support for Linux
*
* Copyright ( c ) 1999 Andreas Gal
2005-09-05 09:12:01 +04: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 17:38:03 +03:00
* Copyright ( c ) 2007 - 2008 Oliver Neukum
2010-02-02 22:46:34 +03:00
* Copyright ( c ) 2006 - 2010 Jiri Kosina
2005-04-17 02:20: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 <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 14:16:15 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include <linux/spinlock.h>
# include <asm/unaligned.h>
# include <asm/byteorder.h>
# include <linux/input.h>
# include <linux/wait.h>
2008-12-17 17:38:03 +03:00
# include <linux/workqueue.h>
2005-04-17 02:20:36 +04:00
# include <linux/usb.h>
2006-12-08 20:40:44 +03:00
# include <linux/hid.h>
2005-04-17 02:20:36 +04:00
# include <linux/hiddev.h>
2007-01-25 13:43:31 +03:00
# include <linux/hid-debug.h>
2007-05-14 11:57:40 +04:00
# include <linux/hidraw.h>
2006-12-08 20:41:03 +03:00
# include "usbhid.h"
2005-04-17 02:20:36 +04: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 17:38:03 +03:00
static unsigned int ignoreled ;
module_param_named ( ignoreled , ignoreled , uint , 0644 ) ;
MODULE_PARM_DESC ( ignoreled , " Autosuspend with active leds " ) ;
2007-04-19 16:56:12 +04: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-17 02:20:36 +04:00
/*
2007-04-04 01:39:37 +04:00
* Input submission and I / O error handler .
2005-04-17 02:20:36 +04:00
*/
2008-12-17 17:38:03 +03:00
static DEFINE_MUTEX ( hid_open_mut ) ;
static struct workqueue_struct * resumption_waker ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
static void hid_io_error ( struct hid_device * hid ) ;
2008-12-17 17:38:03 +03: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-04 01:39:37 +04:00
/* Start up the input URB */
static int hid_start_in ( struct hid_device * hid )
2005-04-17 02:20:36 +04:00
{
unsigned long flags ;
2007-04-04 01:39:37 +04:00
int rc = 0 ;
struct usbhid_device * usbhid = hid - > driver_data ;
2005-04-17 02:20:36 +04:00
2008-12-17 17:38:03 +03:00
spin_lock_irqsave ( & usbhid - > lock , flags ) ;
if ( hid - > open > 0 & &
2008-03-31 18:27:30 +04:00
! test_bit ( HID_DISCONNECTED , & usbhid - > iofl ) & &
2008-12-17 17:38:03 +03:00
! test_bit ( HID_REPORTED_IDLE , & usbhid - > iofl ) & &
2007-04-04 01:39:37 +04: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-17 02:20:36 +04:00
}
2008-12-17 17:38:03 +03:00
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
2007-04-04 01:39:37 +04:00
return rc ;
2005-04-17 02:20:36 +04:00
}
2007-04-04 01:39:37 +04:00
/* I/O retry timer routine */
static void hid_retry_timeout ( unsigned long _hid )
2005-04-17 02:20:36 +04:00
{
2007-04-04 01:39:37 +04:00
struct hid_device * hid = ( struct hid_device * ) _hid ;
2006-12-08 20:41:03 +03:00
struct usbhid_device * usbhid = hid - > driver_data ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
dev_dbg ( & usbhid - > intf - > dev , " retrying intr urb \n " ) ;
if ( hid_start_in ( hid ) )
hid_io_error ( hid ) ;
2005-04-17 02:20:36 +04:00
}
2007-04-04 01:39:37 +04:00
/* Workqueue routine to reset the device or clear a halt */
static void hid_reset ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2007-04-04 01:39:37 +04:00
struct usbhid_device * usbhid =
container_of ( work , struct usbhid_device , reset_work ) ;
struct hid_device * hid = usbhid - > hid ;
2008-11-04 19:29:27 +03:00
int rc = 0 ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04: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-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
else if ( test_bit ( HID_RESET_PENDING , & usbhid - > iofl ) ) {
dev_dbg ( & usbhid - > intf - > dev , " resetting device \n " ) ;
2008-11-04 19:29:27 +03:00
rc = usb_lock_device_for_reset ( hid_to_usb_dev ( hid ) , usbhid - > intf ) ;
if ( rc = = 0 ) {
2008-06-18 18:00:29 +04:00
rc = usb_reset_device ( hid_to_usb_dev ( hid ) ) ;
2008-11-04 19:29:27 +03:00
usb_unlock_device ( hid_to_usb_dev ( hid ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-04-04 01:39:37 +04:00
clear_bit ( HID_RESET_PENDING , & usbhid - > iofl ) ;
2005-04-17 02:20:36 +04:00
}
2007-04-04 01:39:37 +04:00
switch ( rc ) {
case 0 :
if ( ! test_bit ( HID_IN_RUNNING , & usbhid - > iofl ) )
hid_io_error ( hid ) ;
break ;
default :
2007-05-30 17:07:13 +04:00
err_hid ( " can't reset device, %s-%s/input%d, status %d " ,
2007-04-04 01:39:37 +04:00
hid_to_usb_dev ( hid ) - > bus - > bus_name ,
hid_to_usb_dev ( hid ) - > devpath ,
usbhid - > ifnum , rc ) ;
/* FALLTHROUGH */
case - EHOSTUNREACH :
case - ENODEV :
case - EINTR :
break ;
2005-04-17 02:20:36 +04:00
}
}
2007-04-04 01:39:37 +04:00
/* Main I/O error handler */
static void hid_io_error ( struct hid_device * hid )
2006-12-08 20:40:44 +03:00
{
2007-04-04 01:39:37 +04:00
unsigned long flags ;
struct usbhid_device * usbhid = hid - > driver_data ;
2006-12-08 20:40:44 +03:00
2008-12-17 17:38:03 +03:00
spin_lock_irqsave ( & usbhid - > lock , flags ) ;
2006-12-08 20:40:44 +03:00
2007-04-04 01:39:37 +04:00
/* Stop when disconnected */
2008-03-31 18:27:30 +04:00
if ( test_bit ( HID_DISCONNECTED , & usbhid - > iofl ) )
2007-04-04 01:39:37 +04:00
goto done ;
2006-12-08 20:40:44 +03:00
2007-03-20 21:03:31 +03: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-04 01:39:37 +04: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 20:40:44 +03:00
2007-04-04 01:39:37 +04:00
if ( time_after ( jiffies , usbhid - > stop_retry ) ) {
2006-12-08 20:41:03 +03:00
2007-04-04 01:39:37 +04: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-17 02:20:36 +04:00
}
2007-04-04 01:39:37 +04:00
mod_timer ( & usbhid - > io_retry ,
jiffies + msecs_to_jiffies ( usbhid - > retry_delay ) ) ;
done :
2008-12-17 17:38:03 +03: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-17 02:20:36 +04:00
}
2007-04-04 01:39:37 +04:00
/*
* Input interrupt completion handler .
*/
2005-05-29 11:28:00 +04:00
2007-04-04 01:39:37 +04:00
static void hid_irq_in ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2007-04-04 01:39:37 +04:00
struct hid_device * hid = urb - > context ;
struct usbhid_device * usbhid = hid - > driver_data ;
int status ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
switch ( urb - > status ) {
2008-06-19 01:55:41 +04:00
case 0 : /* success */
2008-12-17 17:38:03 +03:00
usbhid_mark_busy ( usbhid ) ;
2008-06-19 01:55:41 +04:00
usbhid - > retry_delay = 0 ;
hid_input_report ( urb - > context , HID_INPUT_REPORT ,
urb - > transfer_buffer ,
urb - > actual_length , 1 ) ;
2008-12-17 17:38:03 +03: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-19 01:55:41 +04:00
break ;
case - EPIPE : /* stall */
2008-12-17 17:38:03 +03:00
usbhid_mark_busy ( usbhid ) ;
2008-06-19 01:55:41 +04: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 17:38:03 +03:00
usbhid_mark_busy ( usbhid ) ;
2008-06-19 01:55:41 +04:00
clear_bit ( HID_IN_RUNNING , & usbhid - > iofl ) ;
hid_io_error ( hid ) ;
return ;
default : /* error */
2008-10-12 02:25:51 +04:00
dev_warn ( & urb - > dev - > dev , " input irq status %d "
" received \n " , urb - > status ) ;
2007-04-04 01:39:37 +04:00
}
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
status = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( status ) {
clear_bit ( HID_IN_RUNNING , & usbhid - > iofl ) ;
if ( status ! = - EPERM ) {
2007-05-30 17:07:13 +04:00
err_hid ( " can't resubmit intr, %s-%s/input%d, status %d " ,
2007-04-04 01:39:37 +04:00
hid_to_usb_dev ( hid ) - > bus - > bus_name ,
hid_to_usb_dev ( hid ) - > devpath ,
usbhid - > ifnum , status ) ;
hid_io_error ( hid ) ;
}
}
2005-04-17 02:20:36 +04:00
}
2007-04-04 01:39:37 +04:00
static int hid_submit_out ( struct hid_device * hid )
2005-04-17 02:20:36 +04:00
{
2007-04-04 01:39:37 +04:00
struct hid_report * report ;
2008-10-04 16:44:06 +04:00
char * raw_report ;
2006-12-08 20:41:03 +03:00
struct usbhid_device * usbhid = hid - > driver_data ;
2008-10-04 16:44:06 +04:00
report = usbhid - > out [ usbhid - > outtail ] . report ;
raw_report = usbhid - > out [ usbhid - > outtail ] . raw_report ;
2005-04-17 02:20:36 +04:00
2008-12-17 17:38:03 +03: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-30 00:41:07 +04:00
2008-12-17 17:38:03 +03:00
dbg_hid ( " submitting out urb \n " ) ;
2006-10-18 16:47:37 +04:00
2008-12-17 17:38:03 +03:00
if ( usb_submit_urb ( usbhid - > urbout , GFP_ATOMIC ) ) {
err_hid ( " usb_submit_urb(out) failed " ) ;
return - 1 ;
}
2010-02-12 15:02:28 +03:00
usbhid - > last_out = jiffies ;
2008-12-17 17:38:03 +03:00
} else {
/*
* queue work to wake up the device .
* as the work queue is freezeable , this is safe
* with respect to STD and STR
*/
queue_work ( resumption_waker , & usbhid - > restart_work ) ;
2007-04-04 01:39:37 +04:00
}
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
return 0 ;
}
static int hid_submit_ctrl ( struct hid_device * hid )
2005-04-17 02:20:36 +04:00
{
struct hid_report * report ;
2007-04-04 01:39:37 +04:00
unsigned char dir ;
2008-10-04 16:44:06 +04:00
char * raw_report ;
2007-04-04 01:39:37 +04:00
int len ;
2006-12-08 20:41:03 +03:00
struct usbhid_device * usbhid = hid - > driver_data ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
report = usbhid - > ctrl [ usbhid - > ctrltail ] . report ;
2008-10-04 16:44:06 +04:00
raw_report = usbhid - > ctrl [ usbhid - > ctrltail ] . raw_report ;
2007-04-04 01:39:37 +04:00
dir = usbhid - > ctrl [ usbhid - > ctrltail ] . dir ;
2005-04-17 02:20:36 +04:00
2008-12-17 17:38:03 +03: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-17 02:20:36 +04:00
2008-12-17 17:38:03 +03: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-17 02:20:36 +04:00
2008-12-17 17:38:03 +03: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-17 02:20:36 +04:00
2008-12-17 17:38:03 +03:00
if ( usb_submit_urb ( usbhid - > urbctrl , GFP_ATOMIC ) ) {
err_hid ( " usb_submit_urb(ctrl) failed " ) ;
return - 1 ;
}
2010-02-12 15:02:28 +03:00
usbhid - > last_ctrl = jiffies ;
2008-12-17 17:38:03 +03:00
} else {
/*
* queue work to wake up the device .
* as the work queue is freezeable , this is safe
* with respect to STD and STR
*/
queue_work ( resumption_waker , & usbhid - > restart_work ) ;
2007-04-04 01:39:37 +04:00
}
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
/*
* Output interrupt completion handler .
*/
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04: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-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
switch ( urb - > status ) {
2008-06-19 01:55:41 +04: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 */
2008-10-12 02:25:51 +04:00
dev_warn ( & urb - > dev - > dev , " output irq status %d "
" received \n " , urb - > status ) ;
2007-04-04 01:39:37 +04:00
}
2005-04-17 02:20:36 +04:00
2008-12-17 17:38:03 +03:00
spin_lock_irqsave ( & usbhid - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
if ( unplug )
usbhid - > outtail = usbhid - > outhead ;
else
usbhid - > outtail = ( usbhid - > outtail + 1 ) & ( HID_OUTPUT_FIFO_SIZE - 1 ) ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
if ( usbhid - > outhead ! = usbhid - > outtail ) {
if ( hid_submit_out ( hid ) ) {
clear_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ;
2008-03-19 23:55:04 +03:00
wake_up ( & usbhid - > wait ) ;
2007-04-04 01:39:37 +04:00
}
2008-12-17 17:38:03 +03:00
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
2007-04-04 01:39:37 +04:00
return ;
}
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
clear_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ;
2008-12-17 17:38:03 +03:00
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
2008-03-19 23:55:04 +03:00
wake_up ( & usbhid - > wait ) ;
2007-04-04 01:39:37 +04:00
}
2005-07-11 10:08:40 +04:00
2007-04-04 01:39:37 +04:00
/*
* Control pipe completion handler .
*/
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
static void hid_ctrl ( struct urb * urb )
{
struct hid_device * hid = urb - > context ;
struct usbhid_device * usbhid = hid - > driver_data ;
2008-12-17 17:38:03 +03:00
int unplug = 0 , status = urb - > status ;
2005-04-17 02:20:36 +04:00
2008-12-17 17:38:03 +03:00
spin_lock ( & usbhid - > lock ) ;
2005-04-17 02:20:36 +04:00
2008-12-17 17:38:03 +03:00
switch ( status ) {
2008-06-19 01:55:41 +04: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 */
2008-10-12 02:25:51 +04:00
dev_warn ( & urb - > dev - > dev , " ctrl urb status %d "
2008-12-17 17:38:03 +03:00
" received \n " , status ) ;
2007-04-04 01:39:37 +04:00
}
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
if ( unplug )
usbhid - > ctrltail = usbhid - > ctrlhead ;
else
usbhid - > ctrltail = ( usbhid - > ctrltail + 1 ) & ( HID_CONTROL_FIFO_SIZE - 1 ) ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
if ( usbhid - > ctrlhead ! = usbhid - > ctrltail ) {
if ( hid_submit_ctrl ( hid ) ) {
clear_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) ;
2008-03-19 23:55:04 +03:00
wake_up ( & usbhid - > wait ) ;
2007-04-04 01:39:37 +04:00
}
2008-12-17 17:38:03 +03:00
spin_unlock ( & usbhid - > lock ) ;
2007-04-04 01:39:37 +04:00
return ;
}
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
clear_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) ;
2008-12-17 17:38:03 +03:00
spin_unlock ( & usbhid - > lock ) ;
2008-03-19 23:55:04 +03:00
wake_up ( & usbhid - > wait ) ;
2007-04-04 01:39:37 +04:00
}
2005-04-17 02:20:36 +04:00
2009-08-18 02:37:18 +04:00
static void __usbhid_submit_report ( struct hid_device * hid , struct hid_report * report ,
unsigned char dir )
2007-04-04 01:39:37 +04:00
{
int head ;
struct usbhid_device * usbhid = hid - > driver_data ;
2008-10-04 16:44:06 +04:00
int len = ( ( report - > size - 1 ) > > 3 ) + 1 + ( report - > id > 0 ) ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
if ( ( hid - > quirks & HID_QUIRK_NOGET ) & & dir = = USB_DIR_IN )
return ;
2006-06-30 11:44:03 +04:00
2007-04-04 01:39:37 +04: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 ) {
2008-10-12 02:25:51 +04:00
dev_warn ( & hid - > dev , " output queue full \n " ) ;
2007-04-04 01:39:37 +04:00
return ;
}
2005-04-17 02:20:36 +04:00
2008-10-04 16:44:06 +04:00
usbhid - > out [ usbhid - > outhead ] . raw_report = kmalloc ( len , GFP_ATOMIC ) ;
if ( ! usbhid - > out [ usbhid - > outhead ] . raw_report ) {
2008-10-15 22:30:07 +04:00
dev_warn ( & hid - > dev , " output queueing failed \n " ) ;
2008-10-04 16:44:06 +04:00
return ;
}
hid_output_report ( report , usbhid - > out [ usbhid - > outhead ] . raw_report ) ;
usbhid - > out [ usbhid - > outhead ] . report = report ;
2007-04-04 01:39:37 +04:00
usbhid - > outhead = head ;
2005-06-03 09:18:12 +04:00
2010-02-12 15:02:28 +03:00
if ( ! test_and_set_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ) {
2007-04-04 01:39:37 +04:00
if ( hid_submit_out ( hid ) )
clear_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ;
2010-02-12 15:02:28 +03: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-04 01:39:37 +04:00
return ;
}
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
if ( ( head = ( usbhid - > ctrlhead + 1 ) & ( HID_CONTROL_FIFO_SIZE - 1 ) ) = = usbhid - > ctrltail ) {
2008-10-12 02:25:51 +04:00
dev_warn ( & hid - > dev , " control queue full \n " ) ;
2007-04-04 01:39:37 +04:00
return ;
}
2006-09-16 18:17:34 +04:00
2008-10-04 16:44:06 +04:00
if ( dir = = USB_DIR_OUT ) {
usbhid - > ctrl [ usbhid - > ctrlhead ] . raw_report = kmalloc ( len , GFP_ATOMIC ) ;
if ( ! usbhid - > ctrl [ usbhid - > ctrlhead ] . raw_report ) {
2008-10-15 22:30:07 +04:00
dev_warn ( & hid - > dev , " control queueing failed \n " ) ;
2008-10-04 16:44:06 +04:00
return ;
}
hid_output_report ( report , usbhid - > ctrl [ usbhid - > ctrlhead ] . raw_report ) ;
}
2007-04-04 01:39:37 +04:00
usbhid - > ctrl [ usbhid - > ctrlhead ] . report = report ;
usbhid - > ctrl [ usbhid - > ctrlhead ] . dir = dir ;
usbhid - > ctrlhead = head ;
2006-09-16 18:17:34 +04:00
2010-02-12 15:02:28 +03:00
if ( ! test_and_set_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) ) {
2007-04-04 01:39:37 +04:00
if ( hid_submit_ctrl ( hid ) )
clear_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) ;
2010-02-12 15:02:28 +03: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 17:38:03 +03:00
}
2006-09-15 18:23:35 +04:00
2008-12-17 17:38:03 +03: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 18:23:35 +04:00
2008-12-17 17:38:03 +03:00
spin_lock_irqsave ( & usbhid - > lock , flags ) ;
__usbhid_submit_report ( hid , report , dir ) ;
spin_unlock_irqrestore ( & usbhid - > lock , flags ) ;
2007-04-04 01:39:37 +04:00
}
2008-07-05 01:06:45 +04:00
EXPORT_SYMBOL_GPL ( usbhid_submit_report ) ;
2006-10-27 23:08:54 +04:00
2007-04-04 01:39:37 +04:00
static int usb_hidinput_input_event ( struct input_dev * dev , unsigned int type , unsigned int code , int value )
{
2007-05-09 12:17:31 +04:00
struct hid_device * hid = input_get_drvdata ( dev ) ;
2008-12-17 17:38:03 +03:00
struct usbhid_device * usbhid = hid - > driver_data ;
2007-04-04 01:39:37 +04:00
struct hid_field * field ;
2008-12-17 17:38:03 +03:00
unsigned long flags ;
2007-04-04 01:39:37 +04:00
int offset ;
2006-11-05 06:49:53 +03:00
2007-04-04 01:39:37 +04:00
if ( type = = EV_FF )
return input_ff_event ( dev , type , code , value ) ;
2007-01-11 12:14:33 +03:00
2007-04-04 01:39:37 +04:00
if ( type ! = EV_LED )
return - 1 ;
2007-01-11 17:51:17 +03:00
2007-04-04 01:39:37 +04:00
if ( ( offset = hidinput_find_field ( hid , type , code , & field ) ) = = - 1 ) {
2008-10-12 02:25:51 +04:00
dev_warn ( & dev - > dev , " event field not found \n " ) ;
2007-04-04 01:39:37 +04:00
return - 1 ;
}
2007-01-16 07:11:52 +03:00
2007-04-04 01:39:37 +04:00
hid_set_field ( field , offset , value ) ;
2008-12-17 17:38:03 +03: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-04 01:39:37 +04:00
usbhid_submit_report ( hid , field - > report , USB_DIR_OUT ) ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
int usbhid_wait_io ( struct hid_device * hid )
{
struct usbhid_device * usbhid = hid - > driver_data ;
2007-03-01 11:54:44 +03:00
2008-03-19 23:55:04 +03:00
if ( ! wait_event_timeout ( usbhid - > wait ,
( ! test_bit ( HID_CTRL_RUNNING , & usbhid - > iofl ) & &
! test_bit ( HID_OUT_RUNNING , & usbhid - > iofl ) ) ,
2007-04-04 01:39:37 +04:00
10 * HZ ) ) {
2007-05-30 17:07:13 +04:00
dbg_hid ( " timeout waiting for ctrl or out queue to clear \n " ) ;
2007-04-04 01:39:37 +04:00
return - 1 ;
}
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
return 0 ;
}
2005-06-06 11:22:37 +04:00
2007-04-04 01:39:37 +04: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-17 02:20:36 +04:00
2007-04-04 01:39:37 +04: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-17 02:20:36 +04:00
2007-04-04 01:39:37 +04:00
memset ( buf , 0 , size ) ;
2005-04-17 02:20:36 +04:00
2007-04-04 01:39:37 +04: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 08:25:39 +03:00
2007-04-04 01:39:37 +04:00
int usbhid_open ( struct hid_device * hid )
{
2007-07-11 16:48:58 +04:00
struct usbhid_device * usbhid = hid - > driver_data ;
int res ;
2008-12-17 17:38:03 +03:00
mutex_lock ( & hid_open_mut ) ;
2007-07-11 16:48:58 +04:00
if ( ! hid - > open + + ) {
res = usb_autopm_get_interface ( usbhid - > intf ) ;
2008-12-17 17:38:03 +03:00
/* the device must be awake to reliable request remote wakeup */
2007-07-11 16:48:58 +04:00
if ( res < 0 ) {
hid - > open - - ;
2008-12-17 17:38:03 +03:00
mutex_unlock ( & hid_open_mut ) ;
2007-07-11 16:48:58 +04:00
return - EIO ;
}
2008-12-17 17:38:03 +03: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 16:48:58 +04:00
}
2008-12-17 17:38:03 +03:00
mutex_unlock ( & hid_open_mut ) ;
2007-04-04 01:39:37 +04:00
return 0 ;
}
2007-02-05 12:06:01 +03:00
2007-04-04 01:39:37 +04:00
void usbhid_close ( struct hid_device * hid )
{
struct usbhid_device * usbhid = hid - > driver_data ;
2006-01-14 18:08:06 +03:00
2008-12-17 17:38:03 +03: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 16:48:58 +04:00
if ( ! - - hid - > open ) {
2008-12-17 17:38:03 +03:00
spin_unlock_irq ( & usbhid - > lock ) ;
2009-04-29 19:12:12 +04:00
hid_cancel_delayed_stuff ( usbhid ) ;
2007-04-04 01:39:37 +04:00
usb_kill_urb ( usbhid - > urbin ) ;
2008-12-17 17:38:03 +03:00
usbhid - > intf - > needs_remote_wakeup = 0 ;
} else {
spin_unlock_irq ( & usbhid - > lock ) ;
2007-07-11 16:48:58 +04:00
}
2008-12-17 17:38:03 +03:00
mutex_unlock ( & hid_open_mut ) ;
2007-04-04 01:39:37 +04:00
}
2006-03-30 00:41:07 +04:00
2007-04-04 01:39:37 +04:00
/*
* Initialize all reports
*/
2006-11-05 06:49:53 +03:00
2007-04-04 01:39:37 +04: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-05 06:49:53 +03:00
2007-04-04 01:39:37 +04: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 17:51:17 +03:00
2007-04-04 01:39:37 +04: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-16 07:11:52 +03:00
2007-04-04 01:39:37 +04: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-06 03:40:57 +03:00
2007-04-04 01:39:37 +04:00
if ( err )
2008-10-12 02:25:51 +04:00
dev_warn ( & hid - > dev , " timeout initializing reports \n " ) ;
2007-04-04 01:39:37 +04:00
}
2005-04-17 02:20:36 +04:00
2007-04-06 16:33:18 +04: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 22:41:02 +04:00
void usbhid_set_leds ( struct hid_device * hid )
2007-04-06 16:33:18 +04: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 22:41:02 +04:00
EXPORT_SYMBOL_GPL ( usbhid_set_leds ) ;
2007-04-06 16:33:18 +04:00
2005-09-05 09:12:01 +04:00
/*
* Traverse the supplied list of reports and find the longest
*/
2008-03-28 19:06:41 +03:00
static void hid_find_max_report ( struct hid_device * hid , unsigned int type ,
unsigned int * max )
2005-09-05 09:12:01 +04:00
{
struct hid_report * report ;
2008-03-28 19:06:41 +03:00
unsigned int size ;
2005-09-05 09:12:01 +04:00
list_for_each_entry ( report , & hid - > report_enum [ type ] . report_list , list ) {
2008-10-17 17:01:15 +04:00
size = ( ( report - > size - 1 ) > > 3 ) + 1 + hid - > report_enum [ type ] . numbered ;
2005-09-05 09:12:01 +04:00
if ( * max < size )
* max = size ;
}
}
2005-04-17 02:20:36 +04:00
static int hid_alloc_buffers ( struct usb_device * dev , struct hid_device * hid )
{
2006-12-08 20:41:03 +03:00
struct usbhid_device * usbhid = hid - > driver_data ;
2008-11-24 18:20:06 +03:00
usbhid - > inbuf = usb_buffer_alloc ( dev , usbhid - > bufsize , GFP_KERNEL ,
& usbhid - > inbuf_dma ) ;
usbhid - > outbuf = usb_buffer_alloc ( dev , usbhid - > bufsize , GFP_KERNEL ,
& usbhid - > outbuf_dma ) ;
usbhid - > cr = usb_buffer_alloc ( dev , sizeof ( * usbhid - > cr ) , GFP_KERNEL ,
& usbhid - > cr_dma ) ;
usbhid - > ctrlbuf = usb_buffer_alloc ( dev , usbhid - > bufsize , GFP_KERNEL ,
& usbhid - > ctrlbuf_dma ) ;
if ( ! usbhid - > inbuf | | ! usbhid - > outbuf | | ! usbhid - > cr | |
! usbhid - > ctrlbuf )
2005-04-17 02:20:36 +04:00
return - 1 ;
return 0 ;
}
2010-01-29 17:03:36 +03:00
static int usbhid_output_raw_report ( struct hid_device * hid , __u8 * buf , size_t count ,
unsigned char report_type )
2007-05-14 11:54:30 +04: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 ;
ret = usb_control_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
HID_REQ_SET_REPORT ,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE ,
2010-01-29 17:03:36 +03:00
( ( report_type + 1 ) < < 8 ) | * buf ,
2007-05-14 11:54:30 +04:00
interface - > desc . bInterfaceNumber , buf + 1 , count - 1 ,
USB_CTRL_SET_TIMEOUT ) ;
/* count also the report id */
if ( ret > 0 )
ret + + ;
return ret ;
}
2008-12-17 17:38:03 +03:00
static void usbhid_restart_queues ( struct usbhid_device * usbhid )
{
if ( usbhid - > urbout )
usbhid_restart_out_queue ( usbhid ) ;
usbhid_restart_ctrl_queue ( usbhid ) ;
}
static void __usbhid_restart_queues ( struct work_struct * work )
{
struct usbhid_device * usbhid =
container_of ( work , struct usbhid_device , restart_work ) ;
int r ;
r = usb_autopm_get_interface ( usbhid - > intf ) ;
if ( r < 0 )
return ;
usb_autopm_put_interface ( usbhid - > intf ) ;
}
2005-04-17 02:20:36 +04:00
static void hid_free_buffers ( struct usb_device * dev , struct hid_device * hid )
{
2006-12-08 20:41:03 +03:00
struct usbhid_device * usbhid = hid - > driver_data ;
2007-05-03 09:04:52 +04:00
usb_buffer_free ( dev , usbhid - > bufsize , usbhid - > inbuf , usbhid - > inbuf_dma ) ;
usb_buffer_free ( dev , usbhid - > bufsize , usbhid - > outbuf , usbhid - > outbuf_dma ) ;
usb_buffer_free ( dev , sizeof ( * ( usbhid - > cr ) ) , usbhid - > cr , usbhid - > cr_dma ) ;
usb_buffer_free ( dev , usbhid - > bufsize , usbhid - > ctrlbuf , usbhid - > ctrlbuf_dma ) ;
2005-04-17 02:20:36 +04:00
}
2008-05-16 13:49:16 +04:00
static int usbhid_parse ( struct hid_device * hid )
{
struct usb_interface * intf = to_usb_interface ( hid - > dev . parent ) ;
2005-04-17 02:20:36 +04:00
struct usb_host_interface * interface = intf - > cur_altsetting ;
struct usb_device * dev = interface_to_usbdev ( intf ) ;
struct hid_descriptor * hdesc ;
2007-04-19 15:27:04 +04:00
u32 quirks = 0 ;
2008-05-16 13:49:16 +04:00
unsigned int rsize = 0 ;
2005-09-15 11:01:47 +04:00
char * rdesc ;
2008-05-16 13:49:16 +04:00
int ret , n ;
2005-04-17 02:20:36 +04:00
2007-04-19 15:27:04 +04:00
quirks = usbhid_lookup_quirk ( le16_to_cpu ( dev - > descriptor . idVendor ) ,
le16_to_cpu ( dev - > descriptor . idProduct ) ) ;
2005-04-17 02:20:36 +04:00
2009-01-29 02:15:51 +03:00
if ( quirks & HID_QUIRK_IGNORE )
return - ENODEV ;
2006-05-15 22: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 11:01:47 +04: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 17:07:13 +04:00
dbg_hid ( " class descriptor not present \n " ) ;
2008-05-16 13:49:16 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2008-05-16 13:49:16 +04:00
hid - > version = le16_to_cpu ( hdesc - > bcdHID ) ;
hid - > country = hdesc - > bCountryCode ;
2005-04-17 02:20:36 +04: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 17:07:13 +04:00
dbg_hid ( " weird size of report descriptor (%u) \n " , rsize ) ;
2008-05-16 13:49:16 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
if ( ! ( rdesc = kmalloc ( rsize , GFP_KERNEL ) ) ) {
2007-05-30 17:07:13 +04:00
dbg_hid ( " couldn't allocate rdesc memory \n " ) ;
2008-05-16 13:49:16 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
2005-05-29 11:28:00 +04:00
hid_set_idle ( dev , interface - > desc . bInterfaceNumber , 0 , 0 ) ;
2008-05-16 13:49:16 +04:00
ret = hid_get_class_descriptor ( dev , interface - > desc . bInterfaceNumber ,
HID_DT_REPORT , rdesc , rsize ) ;
if ( ret < 0 ) {
2007-05-30 17:07:13 +04:00
dbg_hid ( " reading report descriptor failed \n " ) ;
2005-04-17 02:20:36 +04:00
kfree ( rdesc ) ;
2008-05-16 13:49:16 +04:00
goto err ;
2005-04-17 02:20:36 +04:00
}
2008-05-16 13:49:16 +04:00
ret = hid_parse_report ( hid , rdesc , rsize ) ;
kfree ( rdesc ) ;
if ( ret ) {
2007-05-30 17:07:13 +04:00
dbg_hid ( " parsing report descriptor failed \n " ) ;
2008-05-16 13:49:16 +04:00
goto err ;
2005-04-17 02:20:36 +04:00
}
2009-05-06 18:30:21 +04:00
hid - > quirks | = quirks ;
2005-04-17 02:20:36 +04:00
2008-05-16 13:49:16 +04: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 14:16:15 +03:00
struct usbhid_device * usbhid = hid - > driver_data ;
2008-05-16 13:49:16 +04:00
unsigned int n , insize = 0 ;
int ret ;
2008-11-02 01:41:46 +03:00
clear_bit ( HID_DISCONNECTED , & usbhid - > iofl ) ;
2006-12-08 20:41:03 +03: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 09:12:01 +04:00
2006-12-08 20:41:03 +03:00
if ( usbhid - > bufsize > HID_MAX_BUFFER_SIZE )
usbhid - > bufsize = HID_MAX_BUFFER_SIZE ;
2005-09-05 09:12:01 +04:00
hid_find_max_report ( hid , HID_INPUT_REPORT , & insize ) ;
if ( insize > HID_MAX_BUFFER_SIZE )
insize = HID_MAX_BUFFER_SIZE ;
2008-05-16 13:49:16 +04:00
if ( hid_alloc_buffers ( dev , hid ) ) {
ret = - ENOMEM ;
2005-04-17 02:20:36 +04:00
goto fail ;
2008-03-06 15:23:14 +03:00
}
2005-04-17 02:20:36 +04: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 18:20:08 +03:00
if ( ! usb_endpoint_xfer_int ( endpoint ) )
2005-04-17 02:20:36 +04:00
continue ;
interval = endpoint - > bInterval ;
2008-03-06 15:23:14 +03:00
/* Some vendors give fullspeed interval on highspeed devides */
2008-05-16 13:49:16 +04:00
if ( hid - > quirks & HID_QUIRK_FULLSPEED_INTERVAL & &
2008-03-06 15:23:14 +03: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-17 02:20:36 +04: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 11:29:01 +04:00
2008-05-16 13:49:16 +04:00
ret = - ENOMEM ;
2006-10-26 20:02:51 +04:00
if ( usb_endpoint_dir_in ( endpoint ) ) {
2006-12-08 20:41:03 +03:00
if ( usbhid - > urbin )
2005-04-17 02:20:36 +04:00
continue ;
2006-12-08 20:41:03 +03:00
if ( ! ( usbhid - > urbin = usb_alloc_urb ( 0 , GFP_KERNEL ) ) )
2005-04-17 02:20:36 +04:00
goto fail ;
pipe = usb_rcvintpipe ( dev , endpoint - > bEndpointAddress ) ;
2006-12-08 20:41:03 +03:00
usb_fill_int_urb ( usbhid - > urbin , dev , pipe , usbhid - > inbuf , insize ,
2005-04-17 02:20:36 +04:00
hid_irq_in , hid , interval ) ;
2006-12-08 20:41:03 +03:00
usbhid - > urbin - > transfer_dma = usbhid - > inbuf_dma ;
usbhid - > urbin - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
2005-04-17 02:20:36 +04:00
} else {
2006-12-08 20:41:03 +03:00
if ( usbhid - > urbout )
2005-04-17 02:20:36 +04:00
continue ;
2006-12-08 20:41:03 +03:00
if ( ! ( usbhid - > urbout = usb_alloc_urb ( 0 , GFP_KERNEL ) ) )
2005-04-17 02:20:36 +04:00
goto fail ;
pipe = usb_sndintpipe ( dev , endpoint - > bEndpointAddress ) ;
2006-12-08 20:41:03 +03:00
usb_fill_int_urb ( usbhid - > urbout , dev , pipe , usbhid - > outbuf , 0 ,
2005-04-17 02:20:36 +04:00
hid_irq_out , hid , interval ) ;
2006-12-08 20:41:03 +03:00
usbhid - > urbout - > transfer_dma = usbhid - > outbuf_dma ;
usbhid - > urbout - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
2005-04-17 02:20:36 +04:00
}
}
2008-03-19 23:55:04 +03:00
init_waitqueue_head ( & usbhid - > wait ) ;
2006-12-08 20:41:03 +03:00
INIT_WORK ( & usbhid - > reset_work , hid_reset ) ;
2008-12-17 17:38:03 +03:00
INIT_WORK ( & usbhid - > restart_work , __usbhid_restart_queues ) ;
2006-12-08 20:41:03 +03:00
setup_timer ( & usbhid - > io_retry , hid_retry_timeout , ( unsigned long ) hid ) ;
2006-01-31 20:58:38 +03:00
2008-12-17 17:38:03 +03:00
spin_lock_init ( & usbhid - > lock ) ;
2005-04-17 02:20:36 +04:00
2006-12-08 20:41:03 +03:00
usbhid - > urbctrl = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2008-05-16 13:49:16 +04:00
if ( ! usbhid - > urbctrl ) {
ret = - ENOMEM ;
2005-04-17 02:20:36 +04:00
goto fail ;
2008-05-16 13:49:16 +04:00
}
2005-09-15 11:01:47 +04:00
2006-12-08 20:41:03 +03:00
usb_fill_control_urb ( usbhid - > urbctrl , dev , 0 , ( void * ) usbhid - > cr ,
usbhid - > ctrlbuf , 1 , hid_ctrl , hid ) ;
usbhid - > urbctrl - > setup_dma = usbhid - > cr_dma ;
usbhid - > urbctrl - > transfer_dma = usbhid - > ctrlbuf_dma ;
usbhid - > urbctrl - > transfer_flags | = ( URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP ) ;
2008-05-16 13:49:16 +04:00
2009-11-05 16:08:03 +03:00
if ( ! ( hid - > quirks & HID_QUIRK_NO_INIT_REPORTS ) )
usbhid_init_reports ( hid ) ;
2008-06-27 02:04:24 +04:00
2008-10-27 14:16:15 +03:00
set_bit ( HID_STARTED , & usbhid - > iofl ) ;
2008-10-31 01:58:51 +03: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 .
*/
if ( interface - > desc . bInterfaceSubClass = = USB_INTERFACE_SUBCLASS_BOOT & &
interface - > desc . bInterfaceProtocol = =
USB_INTERFACE_PROTOCOL_KEYBOARD )
usbhid_set_leds ( hid ) ;
2008-05-16 13:49:16 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
fail :
2006-12-08 20:41:03 +03:00
usb_free_urb ( usbhid - > urbin ) ;
usb_free_urb ( usbhid - > urbout ) ;
usb_free_urb ( usbhid - > urbctrl ) ;
2008-11-02 01:41:46 +03:00
usbhid - > urbin = NULL ;
usbhid - > urbout = NULL ;
usbhid - > urbctrl = NULL ;
2007-08-01 14:32:27 +04:00
hid_free_buffers ( dev , hid ) ;
2008-05-16 13:49:16 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2008-05-16 13:49:16 +04:00
static void usbhid_stop ( struct hid_device * hid )
2005-04-17 02:20:36 +04:00
{
2008-05-16 13:49:16 +04:00
struct usbhid_device * usbhid = hid - > driver_data ;
2005-04-17 02:20:36 +04:00
2008-05-16 13:49:16 +04:00
if ( WARN_ON ( ! usbhid ) )
2005-04-17 02:20:36 +04:00
return ;
2008-10-27 14:16:15 +03:00
clear_bit ( HID_STARTED , & usbhid - > iofl ) ;
2008-12-17 17:38:03 +03:00
spin_lock_irq ( & usbhid - > lock ) ; /* Sync with error handler */
2008-03-31 18:27:30 +04:00
set_bit ( HID_DISCONNECTED , & usbhid - > iofl ) ;
2008-12-17 17:38:03 +03:00
spin_unlock_irq ( & usbhid - > lock ) ;
2006-12-08 20:41:03 +03:00
usb_kill_urb ( usbhid - > urbin ) ;
usb_kill_urb ( usbhid - > urbout ) ;
usb_kill_urb ( usbhid - > urbctrl ) ;
2005-04-17 02:20:36 +04:00
2008-12-17 17:38:03 +03:00
hid_cancel_delayed_stuff ( usbhid ) ;
2006-01-31 20:58:38 +03:00
2008-05-16 13:49:16 +04:00
hid - > claimed = 0 ;
2006-12-08 20:41:03 +03:00
usb_free_urb ( usbhid - > urbin ) ;
usb_free_urb ( usbhid - > urbctrl ) ;
usb_free_urb ( usbhid - > urbout ) ;
2008-11-02 01:41:46 +03:00
usbhid - > urbin = NULL ; /* don't mess up next start */
usbhid - > urbctrl = NULL ;
usbhid - > urbout = NULL ;
2005-04-17 02:20:36 +04:00
2007-01-19 20:28:17 +03:00
hid_free_buffers ( hid_to_usb_dev ( hid ) , hid ) ;
2005-04-17 02:20:36 +04:00
}
2008-12-17 17:38:03 +03: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 13:49:16 +04: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 17:38:03 +03:00
. power = usbhid_power ,
2008-05-16 13:49:16 +04:00
. hidinput_input_event = usb_hidinput_input_event ,
} ;
2009-09-15 18:27:45 +04:00
static int usbhid_probe ( struct usb_interface * intf , const struct usb_device_id * id )
2005-04-17 02:20:36 +04:00
{
2008-11-14 14:03:47 +03:00
struct usb_host_interface * interface = intf - > cur_altsetting ;
2008-05-16 13:49:16 +04:00
struct usb_device * dev = interface_to_usbdev ( intf ) ;
2008-10-27 14:16:15 +03:00
struct usbhid_device * usbhid ;
2005-04-17 02:20:36 +04:00
struct hid_device * hid ;
2008-11-14 14:03:47 +03:00
unsigned int n , has_in = 0 ;
2008-05-16 13:49:16 +04:00
size_t len ;
int ret ;
2005-04-17 02:20:36 +04:00
2007-05-30 17:07:13 +04:00
dbg_hid ( " HID probe called for ifnum %d \n " ,
2005-04-17 02:20:36 +04:00
intf - > altsetting - > desc . bInterfaceNumber ) ;
2008-11-14 14:03:47 +03:00
for ( n = 0 ; n < interface - > desc . bNumEndpoints ; n + + )
if ( usb_endpoint_is_int_in ( & interface - > endpoint [ n ] . desc ) )
has_in + + ;
if ( ! has_in ) {
dev_err ( & intf - > dev , " couldn't find an input interrupt "
" endpoint \n " ) ;
return - ENODEV ;
}
2008-05-16 13:49:16 +04:00
hid = hid_allocate_device ( ) ;
if ( IS_ERR ( hid ) )
return PTR_ERR ( hid ) ;
2005-04-17 02:20:36 +04:00
usb_set_intfdata ( intf , hid ) ;
2008-05-16 13:49:16 +04:00
hid - > ll_driver = & usb_hid_driver ;
hid - > hid_output_raw_report = usbhid_output_raw_report ;
2008-09-18 14:23:33 +04:00
hid - > ff_init = hid_pidff_init ;
2008-05-16 13:49:16 +04:00
# ifdef CONFIG_USB_HIDDEV
2008-06-27 02:04:24 +04:00
hid - > hiddev_connect = hiddev_connect ;
2009-09-15 18:27:45 +04:00
hid - > hiddev_disconnect = hiddev_disconnect ;
2008-05-16 13:49:16 +04: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 ;
2008-10-22 16:45:11 +04:00
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol = =
USB_INTERFACE_PROTOCOL_MOUSE )
hid - > type = HID_TYPE_USBMOUSE ;
2005-04-17 02:20:36 +04:00
2008-05-16 13:49:16 +04:00
if ( dev - > manufacturer )
strlcpy ( hid - > name , dev - > manufacturer , sizeof ( hid - > name ) ) ;
2005-04-17 02:20:36 +04:00
2008-05-16 13:49:16 +04:00
if ( dev - > product ) {
if ( dev - > manufacturer )
strlcat ( hid - > name , " " , sizeof ( hid - > name ) ) ;
strlcat ( hid - > name , dev - > product , sizeof ( hid - > name ) ) ;
2005-04-17 02:20:36 +04:00
}
2008-05-16 13:49:16 +04: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-17 02:20:36 +04:00
2008-05-16 13:49:16 +04: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-17 02:20:36 +04:00
2008-10-27 14:16:15 +03:00
usbhid = kzalloc ( sizeof ( * usbhid ) , GFP_KERNEL ) ;
if ( usbhid = = NULL ) {
ret = - ENOMEM ;
goto err ;
}
hid - > driver_data = usbhid ;
usbhid - > hid = hid ;
2010-02-17 16:25:01 +03:00
usbhid - > intf = intf ;
usbhid - > ifnum = interface - > desc . bInterfaceNumber ;
2008-10-27 14:16:15 +03:00
2008-05-16 13:49:15 +04:00
ret = hid_add_device ( hid ) ;
if ( ret ) {
2008-05-16 13:49:20 +04:00
if ( ret ! = - ENODEV )
dev_err ( & intf - > dev , " can't add hid device: %d \n " , ret ) ;
2008-10-27 14:16:15 +03:00
goto err_free ;
2008-05-16 13:49:15 +04:00
}
2008-05-16 13:49:16 +04:00
return 0 ;
2008-10-27 14:16:15 +03:00
err_free :
kfree ( usbhid ) ;
2008-05-16 13:49:16 +04:00
err :
hid_destroy_device ( hid ) ;
2008-05-16 13:49:15 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2009-09-15 18:27:45 +04:00
static void usbhid_disconnect ( struct usb_interface * intf )
2008-05-16 13:49:16 +04:00
{
struct hid_device * hid = usb_get_intfdata ( intf ) ;
2008-10-27 14:16:15 +03:00
struct usbhid_device * usbhid ;
2008-05-16 13:49:16 +04:00
if ( WARN_ON ( ! hid ) )
return ;
2008-10-27 14:16:15 +03:00
usbhid = hid - > driver_data ;
2008-05-16 13:49:16 +04:00
hid_destroy_device ( hid ) ;
2008-10-27 14:16:15 +03:00
kfree ( usbhid ) ;
2008-05-16 13:49:16 +04:00
}
2008-12-17 17:38:03 +03:00
static void hid_cancel_delayed_stuff ( struct usbhid_device * usbhid )
{
del_timer_sync ( & usbhid - > io_retry ) ;
cancel_work_sync ( & usbhid - > restart_work ) ;
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 14:47:08 +03: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 ) ;
2009-03-22 20:01:49 +03:00
cancel_work_sync ( & usbhid - > restart_work ) ;
2009-02-20 14:47:08 +03:00
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 17:48:38 +04:00
2009-02-20 14:47:08 +03: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 17:48:38 +04:00
2009-02-20 14:47:08 +03: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 17:48:38 +04:00
2009-02-20 14:47:08 +03:00
usb_autopm_put_interface ( usbhid - > intf ) ;
}
2009-01-19 11:17:18 +03:00
# ifdef CONFIG_PM
2005-04-19 04:39:22 +04:00
static int hid_suspend ( struct usb_interface * intf , pm_message_t message )
2005-04-17 02:20:36 +04:00
{
2008-12-17 17:38:03 +03:00
struct hid_device * hid = usb_get_intfdata ( intf ) ;
2006-12-08 20:41:03 +03:00
struct usbhid_device * usbhid = hid - > driver_data ;
2008-12-17 17:38:03 +03:00
int status ;
2005-04-17 02:20:36 +04:00
2009-11-13 19:53:59 +03:00
if ( message . event & PM_EVENT_AUTO ) {
2008-12-17 17:38:03 +03: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 ) ;
} else {
usbhid_mark_busy ( usbhid ) ;
spin_unlock_irq ( & usbhid - > lock ) ;
return - EBUSY ;
}
2008-10-27 14:16:15 +03:00
2008-12-17 17:38:03 +03:00
} else {
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 19:53:59 +03:00
if ( ! ignoreled & & ( message . event & PM_EVENT_AUTO ) ) {
2008-12-17 17:38:03 +03: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 19:53:59 +03:00
if ( ( message . event & PM_EVENT_AUTO ) & &
test_bit ( HID_KEYS_PRESSED , & usbhid - > iofl ) ) {
2008-12-17 17:38:03 +03: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-17 02:20:36 +04: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 20:41:03 +03:00
struct usbhid_device * usbhid = hid - > driver_data ;
2005-04-17 02:20:36 +04:00
int status ;
2008-11-23 14:03:20 +03:00
if ( ! test_bit ( HID_STARTED , & usbhid - > iofl ) )
2008-10-27 14:16:15 +03:00
return 0 ;
2008-12-17 17:38:03 +03: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 20:41:03 +03:00
usbhid - > retry_delay = 0 ;
2006-01-31 20:58:38 +03:00
status = hid_start_in ( hid ) ;
2008-12-17 17:38:03 +03:00
if ( status < 0 )
hid_io_error ( hid ) ;
usbhid_restart_queues ( usbhid ) ;
2005-04-17 02:20:36 +04:00
dev_dbg ( & intf - > dev , " resume status %d \n " , status ) ;
2007-05-30 23:38:16 +04:00
return 0 ;
2006-06-01 21:55:28 +04:00
}
2009-02-18 13:46:45 +03:00
static int hid_reset_resume ( struct usb_interface * intf )
2006-06-01 21:55:28 +04:00
{
2009-02-18 13:46:45 +03:00
struct hid_device * hid = usb_get_intfdata ( intf ) ;
struct usbhid_device * usbhid = hid - > driver_data ;
2006-06-01 21:55:28 +04:00
2009-02-18 13:46:45 +03:00
clear_bit ( HID_REPORTED_IDLE , & usbhid - > iofl ) ;
return hid_post_reset ( intf ) ;
2006-06-01 21:55:28 +04:00
}
2009-02-20 14:47:08 +03:00
# endif /* CONFIG_PM */
2006-06-01 21:55:28 +04:00
2010-01-10 19:59:22 +03:00
static const struct usb_device_id hid_usb_ids [ ] = {
2005-04-17 02:20:36 +04: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 18:27:45 +04:00
. probe = usbhid_probe ,
. disconnect = usbhid_disconnect ,
2009-01-19 11:17:18 +03:00
# ifdef CONFIG_PM
2005-04-17 02:20:36 +04:00
. suspend = hid_suspend ,
. resume = hid_resume ,
2009-02-18 13:46:45 +03:00
. reset_resume = hid_reset_resume ,
2009-01-19 11:17:18 +03:00
# endif
2006-06-01 21:55:28 +04:00
. pre_reset = hid_pre_reset ,
. post_reset = hid_post_reset ,
2005-04-17 02:20:36 +04:00
. id_table = hid_usb_ids ,
2007-07-11 16:48:58 +04:00
. supports_autosuspend = 1 ,
2005-04-17 02:20:36 +04:00
} ;
2008-05-16 13:49:15 +04:00
static const struct hid_device_id hid_usb_table [ ] = {
{ HID_USB_DEVICE ( HID_ANY_ID , HID_ANY_ID ) } ,
{ }
} ;
static struct hid_driver hid_usb_driver = {
. name = " generic-usb " ,
. id_table = hid_usb_table ,
} ;
2005-04-17 02:20:36 +04:00
static int __init hid_init ( void )
{
2008-12-17 17:38:03 +03:00
int retval = - ENOMEM ;
resumption_waker = create_freezeable_workqueue ( " usbhid_resumer " ) ;
if ( ! resumption_waker )
goto no_queue ;
2008-05-16 13:49:15 +04:00
retval = hid_register_driver ( & hid_usb_driver ) ;
if ( retval )
goto hid_register_fail ;
2007-04-19 16:56:12 +04:00
retval = usbhid_quirks_init ( quirks_param ) ;
if ( retval )
goto usbhid_quirks_init_fail ;
2005-04-17 02:20:36 +04:00
retval = hiddev_init ( ) ;
if ( retval )
goto hiddev_init_fail ;
retval = usb_register ( & hid_driver ) ;
if ( retval )
goto usb_register_fail ;
2009-10-02 20:31:36 +04:00
printk ( KERN_INFO KBUILD_MODNAME " : " DRIVER_DESC " \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
usb_register_fail :
hiddev_exit ( ) ;
hiddev_init_fail :
2007-04-19 16:56:12 +04:00
usbhid_quirks_exit ( ) ;
usbhid_quirks_init_fail :
2008-05-16 13:49:15 +04:00
hid_unregister_driver ( & hid_usb_driver ) ;
hid_register_fail :
2008-12-17 17:38:03 +03:00
destroy_workqueue ( resumption_waker ) ;
no_queue :
2005-04-17 02:20:36 +04:00
return retval ;
}
static void __exit hid_exit ( void )
{
usb_deregister ( & hid_driver ) ;
hiddev_exit ( ) ;
2007-04-19 16:56:12 +04:00
usbhid_quirks_exit ( ) ;
2008-05-16 13:49:15 +04:00
hid_unregister_driver ( & hid_usb_driver ) ;
2008-12-17 17:38:03 +03:00
destroy_workqueue ( resumption_waker ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( hid_init ) ;
module_exit ( hid_exit ) ;
2009-10-02 20:29:34 +04:00
MODULE_AUTHOR ( " Andreas Gal " ) ;
MODULE_AUTHOR ( " Vojtech Pavlik " ) ;
MODULE_AUTHOR ( " Jiri Kosina " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( DRIVER_LICENSE ) ;