2005-04-17 02:20:36 +04:00
/*
* acpi_button . c - ACPI Button Driver ( $ Revision : 30 $ )
*
* Copyright ( C ) 2001 , 2002 Andy Grover < andrew . grover @ intel . com >
* Copyright ( C ) 2001 , 2002 Paul Diefenbaugh < paul . s . diefenbaugh @ intel . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* 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 .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA .
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
2005-08-04 01:55:21 +04:00
# include <linux/types.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
2006-11-09 08:40:13 +03:00
# include <linux/input.h>
2005-04-17 02:20:36 +04:00
# include <acpi/acpi_bus.h>
# include <acpi/acpi_drivers.h>
# define ACPI_BUTTON_CLASS "button"
2005-08-04 01:55:21 +04:00
# define ACPI_BUTTON_FILE_INFO "info"
# define ACPI_BUTTON_FILE_STATE "state"
# define ACPI_BUTTON_TYPE_UNKNOWN 0x00
2005-04-17 02:20:36 +04:00
# define ACPI_BUTTON_NOTIFY_STATUS 0x80
# define ACPI_BUTTON_SUBCLASS_POWER "power"
2005-08-05 08:44:28 +04:00
# define ACPI_BUTTON_HID_POWER "PNP0C0C"
2005-04-17 02:20:36 +04:00
# define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)"
# define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)"
# define ACPI_BUTTON_TYPE_POWER 0x01
# define ACPI_BUTTON_TYPE_POWERF 0x02
# define ACPI_BUTTON_SUBCLASS_SLEEP "sleep"
# define ACPI_BUTTON_HID_SLEEP "PNP0C0E"
# define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)"
# define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)"
# define ACPI_BUTTON_TYPE_SLEEP 0x03
# define ACPI_BUTTON_TYPE_SLEEPF 0x04
# define ACPI_BUTTON_SUBCLASS_LID "lid"
# define ACPI_BUTTON_HID_LID "PNP0C0D"
# define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch"
# define ACPI_BUTTON_TYPE_LID 0x05
# define _COMPONENT ACPI_BUTTON_COMPONENT
2007-02-13 06:42:12 +03:00
ACPI_MODULE_NAME ( " button " ) ;
2005-04-17 02:20:36 +04:00
2006-11-09 08:40:13 +03:00
MODULE_AUTHOR ( " Paul Diefenbaugh " ) ;
2007-02-13 07:50:02 +03:00
MODULE_DESCRIPTION ( " ACPI Button Driver " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
2007-07-23 16:44:41 +04:00
static const struct acpi_device_id button_device_ids [ ] = {
{ ACPI_BUTTON_HID_LID , 0 } ,
{ ACPI_BUTTON_HID_SLEEP , 0 } ,
{ ACPI_BUTTON_HID_SLEEPF , 0 } ,
{ ACPI_BUTTON_HID_POWER , 0 } ,
{ ACPI_BUTTON_HID_POWERF , 0 } ,
{ " " , 0 } ,
} ;
MODULE_DEVICE_TABLE ( acpi , button_device_ids ) ;
2005-08-05 08:44:28 +04:00
static int acpi_button_add ( struct acpi_device * device ) ;
static int acpi_button_remove ( struct acpi_device * device , int type ) ;
2007-10-22 14:18:18 +04:00
static int acpi_button_resume ( struct acpi_device * device ) ;
2005-08-04 01:55:21 +04:00
static int acpi_button_info_open_fs ( struct inode * inode , struct file * file ) ;
static int acpi_button_state_open_fs ( struct inode * inode , struct file * file ) ;
2005-04-17 02:20:36 +04:00
static struct acpi_driver acpi_button_driver = {
2007-02-13 07:33:40 +03:00
. name = " button " ,
2005-08-05 08:44:28 +04:00
. class = ACPI_BUTTON_CLASS ,
2007-07-23 16:44:41 +04:00
. ids = button_device_ids ,
2005-08-05 08:44:28 +04:00
. ops = {
. add = acpi_button_add ,
2007-10-22 14:18:18 +04:00
. resume = acpi_button_resume ,
2005-08-05 08:44:28 +04:00
. remove = acpi_button_remove ,
2006-11-09 08:40:13 +03:00
} ,
2005-04-17 02:20:36 +04:00
} ;
struct acpi_button {
2005-08-05 08:44:28 +04:00
struct acpi_device * device ; /* Fixed button kludge */
2006-11-09 08:40:13 +03:00
unsigned int type ;
struct input_dev * input ;
char phys [ 32 ] ; /* for input device */
2005-08-05 08:44:28 +04:00
unsigned long pushed ;
2005-04-17 02:20:36 +04:00
} ;
2006-07-04 21:06:00 +04:00
static const struct file_operations acpi_button_info_fops = {
2008-04-29 12:02:27 +04:00
. owner = THIS_MODULE ,
2005-08-05 08:44:28 +04:00
. open = acpi_button_info_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-08-04 01:55:21 +04:00
} ;
2006-07-04 21:06:00 +04:00
static const struct file_operations acpi_button_state_fops = {
2008-04-29 12:02:27 +04:00
. owner = THIS_MODULE ,
2005-08-05 08:44:28 +04:00
. open = acpi_button_state_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-08-04 01:55:21 +04:00
} ;
2005-08-05 08:44:28 +04:00
2005-08-04 01:55:21 +04:00
/* --------------------------------------------------------------------------
FS Interface ( / proc )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-05 08:44:28 +04:00
static struct proc_dir_entry * acpi_button_dir ;
2005-08-04 01:55:21 +04:00
static int acpi_button_info_seq_show ( struct seq_file * seq , void * offset )
{
2006-11-09 08:40:13 +03:00
struct acpi_button * button = seq - > private ;
2005-08-04 01:55:21 +04:00
if ( ! button | | ! button - > device )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-08-04 01:55:21 +04:00
2005-08-05 08:44:28 +04:00
seq_printf ( seq , " type: %s \n " ,
acpi_device_name ( button - > device ) ) ;
2005-08-04 01:55:21 +04:00
2006-06-27 08:41:40 +04:00
return 0 ;
2005-08-04 01:55:21 +04:00
}
static int acpi_button_info_open_fs ( struct inode * inode , struct file * file )
{
return single_open ( file , acpi_button_info_seq_show , PDE ( inode ) - > data ) ;
}
2005-08-05 08:44:28 +04:00
2005-08-04 01:55:21 +04:00
static int acpi_button_state_seq_show ( struct seq_file * seq , void * offset )
{
2006-11-09 08:40:13 +03:00
struct acpi_button * button = seq - > private ;
2005-08-05 08:44:28 +04:00
acpi_status status ;
2008-10-10 10:22:59 +04:00
unsigned long long state ;
2005-08-04 01:55:21 +04:00
if ( ! button | | ! button - > device )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-08-04 01:55:21 +04:00
2006-05-20 00:54:42 +04:00
status = acpi_evaluate_integer ( button - > device - > handle , " _LID " , NULL , & state ) ;
2006-11-09 08:40:13 +03:00
seq_printf ( seq , " state: %s \n " ,
ACPI_FAILURE ( status ) ? " unsupported " :
( state ? " open " : " closed " ) ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-08-04 01:55:21 +04:00
}
static int acpi_button_state_open_fs ( struct inode * inode , struct file * file )
{
return single_open ( file , acpi_button_state_seq_show , PDE ( inode ) - > data ) ;
}
static struct proc_dir_entry * acpi_power_dir ;
static struct proc_dir_entry * acpi_sleep_dir ;
static struct proc_dir_entry * acpi_lid_dir ;
2005-08-05 08:44:28 +04:00
static int acpi_button_add_fs ( struct acpi_device * device )
2005-08-04 01:55:21 +04:00
{
2005-08-05 08:44:28 +04:00
struct proc_dir_entry * entry = NULL ;
2006-11-09 08:40:13 +03:00
struct acpi_button * button ;
2005-08-04 01:55:21 +04:00
if ( ! device | | ! acpi_driver_data ( device ) )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-08-04 01:55:21 +04:00
button = acpi_driver_data ( device ) ;
switch ( button - > type ) {
case ACPI_BUTTON_TYPE_POWER :
case ACPI_BUTTON_TYPE_POWERF :
if ( ! acpi_power_dir )
2005-08-05 08:44:28 +04:00
acpi_power_dir = proc_mkdir ( ACPI_BUTTON_SUBCLASS_POWER ,
acpi_button_dir ) ;
2005-08-04 01:55:21 +04:00
entry = acpi_power_dir ;
break ;
case ACPI_BUTTON_TYPE_SLEEP :
case ACPI_BUTTON_TYPE_SLEEPF :
if ( ! acpi_sleep_dir )
2005-08-05 08:44:28 +04:00
acpi_sleep_dir = proc_mkdir ( ACPI_BUTTON_SUBCLASS_SLEEP ,
acpi_button_dir ) ;
2005-08-04 01:55:21 +04:00
entry = acpi_sleep_dir ;
break ;
case ACPI_BUTTON_TYPE_LID :
if ( ! acpi_lid_dir )
2005-08-05 08:44:28 +04:00
acpi_lid_dir = proc_mkdir ( ACPI_BUTTON_SUBCLASS_LID ,
acpi_button_dir ) ;
2005-08-04 01:55:21 +04:00
entry = acpi_lid_dir ;
break ;
}
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-08-04 01:55:21 +04:00
entry - > owner = THIS_MODULE ;
acpi_device_dir ( device ) = proc_mkdir ( acpi_device_bid ( device ) , entry ) ;
if ( ! acpi_device_dir ( device ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-08-04 01:55:21 +04:00
acpi_device_dir ( device ) - > owner = THIS_MODULE ;
/* 'info' [R] */
2008-04-29 12:02:27 +04:00
entry = proc_create_data ( ACPI_BUTTON_FILE_INFO ,
S_IRUGO , acpi_device_dir ( device ) ,
& acpi_button_info_fops ,
acpi_driver_data ( device ) ) ;
2005-08-04 01:55:21 +04:00
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-08-04 01:55:21 +04:00
/* show lid state [R] */
if ( button - > type = = ACPI_BUTTON_TYPE_LID ) {
2008-04-29 12:02:27 +04:00
entry = proc_create_data ( ACPI_BUTTON_FILE_STATE ,
S_IRUGO , acpi_device_dir ( device ) ,
& acpi_button_state_fops ,
acpi_driver_data ( device ) ) ;
2005-08-04 01:55:21 +04:00
if ( ! entry )
2006-06-27 07:58:43 +04:00
return - ENODEV ;
2005-08-04 01:55:21 +04:00
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-08-04 01:55:21 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_button_remove_fs ( struct acpi_device * device )
2005-08-04 01:55:21 +04:00
{
2006-11-09 08:40:13 +03:00
struct acpi_button * button = acpi_driver_data ( device ) ;
2005-08-04 01:55:21 +04:00
if ( acpi_device_dir ( device ) ) {
if ( button - > type = = ACPI_BUTTON_TYPE_LID )
remove_proc_entry ( ACPI_BUTTON_FILE_STATE ,
2005-08-05 08:44:28 +04:00
acpi_device_dir ( device ) ) ;
2005-08-04 01:55:21 +04:00
remove_proc_entry ( ACPI_BUTTON_FILE_INFO ,
2005-08-05 08:44:28 +04:00
acpi_device_dir ( device ) ) ;
2005-08-04 01:55:21 +04:00
remove_proc_entry ( acpi_device_bid ( device ) ,
2005-08-05 08:44:28 +04:00
acpi_device_dir ( device ) - > parent ) ;
2005-08-04 01:55:21 +04:00
acpi_device_dir ( device ) = NULL ;
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-08-04 01:55:21 +04:00
}
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Driver Interface
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-10-22 14:18:18 +04:00
static int acpi_lid_send_state ( struct acpi_button * button )
{
2008-10-10 10:22:59 +04:00
unsigned long long state ;
2007-10-22 14:18:18 +04:00
acpi_status status ;
status = acpi_evaluate_integer ( button - > device - > handle , " _LID " , NULL ,
& state ) ;
if ( ACPI_FAILURE ( status ) )
return - ENODEV ;
/* input layer checks if event is redundant */
input_report_switch ( button - > input , SW_LID , ! state ) ;
2008-10-24 01:28:33 +04:00
input_sync ( button - > input ) ;
2007-10-22 14:18:18 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
static void acpi_button_notify ( acpi_handle handle , u32 event , void * data )
2005-04-17 02:20:36 +04:00
{
2006-11-09 08:40:13 +03:00
struct acpi_button * button = data ;
struct input_dev * input ;
2005-04-17 02:20:36 +04:00
if ( ! button | | ! button - > device )
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
switch ( event ) {
case ACPI_BUTTON_NOTIFY_STATUS :
2006-11-09 08:40:13 +03:00
input = button - > input ;
if ( button - > type = = ACPI_BUTTON_TYPE_LID ) {
2007-10-22 14:18:18 +04:00
acpi_lid_send_state ( button ) ;
2006-11-09 08:40:13 +03:00
} else {
int keycode = test_bit ( KEY_SLEEP , input - > keybit ) ?
KEY_SLEEP : KEY_POWER ;
input_report_key ( input , keycode , 1 ) ;
input_sync ( input ) ;
input_report_key ( input , keycode , 0 ) ;
2008-10-24 01:28:33 +04:00
input_sync ( input ) ;
2006-11-09 08:40:13 +03:00
}
2007-08-23 23:20:26 +04:00
acpi_bus_generate_proc_event ( button - > device , event ,
2005-08-05 08:44:28 +04:00
+ + button - > pushed ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
2005-08-05 08:44:28 +04:00
" Unsupported event [0x%x] \n " , event ) ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static acpi_status acpi_button_notify_fixed ( void * data )
2005-04-17 02:20:36 +04:00
{
2006-11-09 08:40:13 +03:00
struct acpi_button * button = data ;
2005-04-17 02:20:36 +04:00
2005-08-04 01:55:21 +04:00
if ( ! button )
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
2006-05-20 00:54:42 +04:00
acpi_button_notify ( button - > device - > handle , ACPI_BUTTON_NOTIFY_STATUS , button ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return AE_OK ;
2005-04-17 02:20:36 +04:00
}
2006-11-09 08:40:13 +03:00
static int acpi_button_install_notify_handlers ( struct acpi_button * button )
2005-04-17 02:20:36 +04:00
{
2006-11-09 08:40:13 +03:00
acpi_status status ;
2005-04-17 02:20:36 +04:00
2006-11-09 08:40:13 +03:00
switch ( button - > type ) {
case ACPI_BUTTON_TYPE_POWERF :
status =
acpi_install_fixed_event_handler ( ACPI_EVENT_POWER_BUTTON ,
acpi_button_notify_fixed ,
button ) ;
break ;
case ACPI_BUTTON_TYPE_SLEEPF :
status =
acpi_install_fixed_event_handler ( ACPI_EVENT_SLEEP_BUTTON ,
acpi_button_notify_fixed ,
button ) ;
break ;
default :
status = acpi_install_notify_handler ( button - > device - > handle ,
ACPI_DEVICE_NOTIFY ,
acpi_button_notify ,
button ) ;
break ;
}
return ACPI_FAILURE ( status ) ? - ENODEV : 0 ;
}
2007-10-22 14:18:18 +04:00
static int acpi_button_resume ( struct acpi_device * device )
{
struct acpi_button * button ;
if ( ! device )
return - EINVAL ;
button = acpi_driver_data ( device ) ;
if ( button & & button - > type = = ACPI_BUTTON_TYPE_LID )
return acpi_lid_send_state ( button ) ;
return 0 ;
}
2006-11-09 08:40:13 +03:00
static void acpi_button_remove_notify_handlers ( struct acpi_button * button )
{
switch ( button - > type ) {
case ACPI_BUTTON_TYPE_POWERF :
acpi_remove_fixed_event_handler ( ACPI_EVENT_POWER_BUTTON ,
acpi_button_notify_fixed ) ;
break ;
case ACPI_BUTTON_TYPE_SLEEPF :
acpi_remove_fixed_event_handler ( ACPI_EVENT_SLEEP_BUTTON ,
acpi_button_notify_fixed ) ;
break ;
default :
acpi_remove_notify_handler ( button - > device - > handle ,
ACPI_DEVICE_NOTIFY ,
acpi_button_notify ) ;
break ;
}
}
static int acpi_button_add ( struct acpi_device * device )
{
int error ;
struct acpi_button * button ;
struct input_dev * input ;
2005-04-17 02:20:36 +04:00
if ( ! device )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2006-11-09 08:40:13 +03:00
button = kzalloc ( sizeof ( struct acpi_button ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! button )
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
button - > device = device ;
2008-09-23 01:37:34 +04:00
device - > driver_data = button ;
2005-04-17 02:20:36 +04:00
2006-11-09 08:40:13 +03:00
button - > input = input = input_allocate_device ( ) ;
if ( ! input ) {
error = - ENOMEM ;
goto err_free_button ;
}
2005-04-17 02:20:36 +04:00
/*
* Determine the button type ( via hid ) , as fixed - feature buttons
* need to be handled a bit differently than generic - space .
*/
if ( ! strcmp ( acpi_device_hid ( device ) , ACPI_BUTTON_HID_POWER ) ) {
button - > type = ACPI_BUTTON_TYPE_POWER ;
2005-08-05 08:44:28 +04:00
strcpy ( acpi_device_name ( device ) , ACPI_BUTTON_DEVICE_NAME_POWER ) ;
sprintf ( acpi_device_class ( device ) , " %s/%s " ,
2005-04-17 02:20:36 +04:00
ACPI_BUTTON_CLASS , ACPI_BUTTON_SUBCLASS_POWER ) ;
2005-08-05 08:44:28 +04:00
} else if ( ! strcmp ( acpi_device_hid ( device ) , ACPI_BUTTON_HID_POWERF ) ) {
2005-04-17 02:20:36 +04:00
button - > type = ACPI_BUTTON_TYPE_POWERF ;
strcpy ( acpi_device_name ( device ) ,
2005-08-05 08:44:28 +04:00
ACPI_BUTTON_DEVICE_NAME_POWERF ) ;
sprintf ( acpi_device_class ( device ) , " %s/%s " ,
2005-04-17 02:20:36 +04:00
ACPI_BUTTON_CLASS , ACPI_BUTTON_SUBCLASS_POWER ) ;
2005-08-05 08:44:28 +04:00
} else if ( ! strcmp ( acpi_device_hid ( device ) , ACPI_BUTTON_HID_SLEEP ) ) {
2005-04-17 02:20:36 +04:00
button - > type = ACPI_BUTTON_TYPE_SLEEP ;
2005-08-05 08:44:28 +04:00
strcpy ( acpi_device_name ( device ) , ACPI_BUTTON_DEVICE_NAME_SLEEP ) ;
sprintf ( acpi_device_class ( device ) , " %s/%s " ,
2005-04-17 02:20:36 +04:00
ACPI_BUTTON_CLASS , ACPI_BUTTON_SUBCLASS_SLEEP ) ;
2005-08-05 08:44:28 +04:00
} else if ( ! strcmp ( acpi_device_hid ( device ) , ACPI_BUTTON_HID_SLEEPF ) ) {
2005-04-17 02:20:36 +04:00
button - > type = ACPI_BUTTON_TYPE_SLEEPF ;
strcpy ( acpi_device_name ( device ) ,
2005-08-05 08:44:28 +04:00
ACPI_BUTTON_DEVICE_NAME_SLEEPF ) ;
sprintf ( acpi_device_class ( device ) , " %s/%s " ,
2005-04-17 02:20:36 +04:00
ACPI_BUTTON_CLASS , ACPI_BUTTON_SUBCLASS_SLEEP ) ;
2005-08-05 08:44:28 +04:00
} else if ( ! strcmp ( acpi_device_hid ( device ) , ACPI_BUTTON_HID_LID ) ) {
2005-04-17 02:20:36 +04:00
button - > type = ACPI_BUTTON_TYPE_LID ;
2005-08-05 08:44:28 +04:00
strcpy ( acpi_device_name ( device ) , ACPI_BUTTON_DEVICE_NAME_LID ) ;
sprintf ( acpi_device_class ( device ) , " %s/%s " ,
2005-04-17 02:20:36 +04:00
ACPI_BUTTON_CLASS , ACPI_BUTTON_SUBCLASS_LID ) ;
2005-08-05 08:44:28 +04:00
} else {
2006-06-27 07:41:38 +04:00
printk ( KERN_ERR PREFIX " Unsupported hid [%s] \n " ,
acpi_device_hid ( device ) ) ;
2006-11-09 08:40:13 +03:00
error = - ENODEV ;
goto err_free_input ;
2005-04-17 02:20:36 +04:00
}
2006-11-09 08:40:13 +03:00
error = acpi_button_add_fs ( device ) ;
if ( error )
goto err_free_input ;
error = acpi_button_install_notify_handlers ( button ) ;
if ( error )
goto err_remove_fs ;
snprintf ( button - > phys , sizeof ( button - > phys ) ,
" %s/button/input0 " , acpi_device_hid ( device ) ) ;
input - > name = acpi_device_name ( device ) ;
input - > phys = button - > phys ;
input - > id . bustype = BUS_HOST ;
input - > id . product = button - > type ;
2008-03-05 02:06:35 +03:00
input - > dev . parent = & device - > dev ;
2005-08-04 01:55:21 +04:00
2005-04-17 02:20:36 +04:00
switch ( button - > type ) {
2006-11-09 08:40:13 +03:00
case ACPI_BUTTON_TYPE_POWER :
2005-04-17 02:20:36 +04:00
case ACPI_BUTTON_TYPE_POWERF :
2007-10-19 10:40:32 +04:00
input - > evbit [ 0 ] = BIT_MASK ( EV_KEY ) ;
2006-11-09 08:40:13 +03:00
set_bit ( KEY_POWER , input - > keybit ) ;
2005-04-17 02:20:36 +04:00
break ;
2006-11-09 08:40:13 +03:00
case ACPI_BUTTON_TYPE_SLEEP :
2005-04-17 02:20:36 +04:00
case ACPI_BUTTON_TYPE_SLEEPF :
2007-10-19 10:40:32 +04:00
input - > evbit [ 0 ] = BIT_MASK ( EV_KEY ) ;
2006-11-09 08:40:13 +03:00
set_bit ( KEY_SLEEP , input - > keybit ) ;
2005-04-17 02:20:36 +04:00
break ;
2006-11-09 08:40:13 +03:00
case ACPI_BUTTON_TYPE_LID :
2007-10-19 10:40:32 +04:00
input - > evbit [ 0 ] = BIT_MASK ( EV_SW ) ;
2006-11-09 08:40:13 +03:00
set_bit ( SW_LID , input - > swbit ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2006-11-09 08:40:13 +03:00
error = input_register_device ( input ) ;
if ( error )
goto err_remove_handlers ;
2007-10-22 14:18:18 +04:00
if ( button - > type = = ACPI_BUTTON_TYPE_LID )
acpi_lid_send_state ( button ) ;
2005-04-17 02:20:36 +04:00
if ( device - > wakeup . flags . valid ) {
/* Button's GPE is run-wake GPE */
2005-08-05 08:44:28 +04:00
acpi_set_gpe_type ( device - > wakeup . gpe_device ,
device - > wakeup . gpe_number ,
ACPI_GPE_TYPE_WAKE_RUN ) ;
acpi_enable_gpe ( device - > wakeup . gpe_device ,
2008-10-25 21:48:46 +04:00
device - > wakeup . gpe_number ) ;
2005-04-17 02:20:36 +04:00
device - > wakeup . state . enabled = 1 ;
}
2005-08-05 08:44:28 +04:00
printk ( KERN_INFO PREFIX " %s [%s] \n " ,
acpi_device_name ( device ) , acpi_device_bid ( device ) ) ;
2005-04-17 02:20:36 +04:00
2006-11-09 08:40:13 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
2006-11-09 08:40:13 +03:00
err_remove_handlers :
acpi_button_remove_notify_handlers ( button ) ;
err_remove_fs :
acpi_button_remove_fs ( device ) ;
err_free_input :
input_free_device ( input ) ;
err_free_button :
kfree ( button ) ;
return error ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_button_remove ( struct acpi_device * device , int type )
2005-04-17 02:20:36 +04:00
{
2006-11-09 08:40:13 +03:00
struct acpi_button * button ;
2005-04-17 02:20:36 +04:00
if ( ! device | | ! acpi_driver_data ( device ) )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
button = acpi_driver_data ( device ) ;
2006-11-09 08:40:13 +03:00
acpi_button_remove_notify_handlers ( button ) ;
2005-08-05 08:44:28 +04:00
acpi_button_remove_fs ( device ) ;
2006-11-09 08:40:13 +03:00
input_unregister_device ( button - > input ) ;
2005-04-17 02:20:36 +04:00
kfree ( button ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int __init acpi_button_init ( void )
2005-04-17 02:20:36 +04:00
{
2006-11-09 08:40:13 +03:00
int result ;
2005-04-17 02:20:36 +04:00
2005-08-04 01:55:21 +04:00
acpi_button_dir = proc_mkdir ( ACPI_BUTTON_CLASS , acpi_root_dir ) ;
if ( ! acpi_button_dir )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-08-04 01:55:21 +04:00
acpi_button_dir - > owner = THIS_MODULE ;
2005-04-17 02:20:36 +04:00
result = acpi_bus_register_driver ( & acpi_button_driver ) ;
if ( result < 0 ) {
2005-08-04 01:55:21 +04:00
remove_proc_entry ( ACPI_BUTTON_CLASS , acpi_root_dir ) ;
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static void __exit acpi_button_exit ( void )
2005-04-17 02:20:36 +04:00
{
acpi_bus_unregister_driver ( & acpi_button_driver ) ;
2005-08-05 08:44:28 +04:00
if ( acpi_power_dir )
2005-08-04 01:55:21 +04:00
remove_proc_entry ( ACPI_BUTTON_SUBCLASS_POWER , acpi_button_dir ) ;
if ( acpi_sleep_dir )
remove_proc_entry ( ACPI_BUTTON_SUBCLASS_SLEEP , acpi_button_dir ) ;
if ( acpi_lid_dir )
remove_proc_entry ( ACPI_BUTTON_SUBCLASS_LID , acpi_button_dir ) ;
remove_proc_entry ( ACPI_BUTTON_CLASS , acpi_root_dir ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( acpi_button_init ) ;
module_exit ( acpi_button_exit ) ;