2005-08-03 18:07:59 -04:00
/*
* hotkey . c - ACPI Hotkey Driver ( $ Revision : 0.2 $ )
2005-03-18 18:03:45 -05:00
*
* Copyright ( C ) 2004 Luming Yu < luming . yu @ 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>
# include <linux/types.h>
# include <linux/proc_fs.h>
# include <linux/sched.h>
# include <linux/kmod.h>
# include <linux/seq_file.h>
# include <acpi/acpi_drivers.h>
# include <acpi/acpi_bus.h>
# include <asm/uaccess.h>
# define HOTKEY_ACPI_VERSION "0.1"
# define HOTKEY_PROC "hotkey"
# define HOTKEY_EV_CONFIG "event_config"
# define HOTKEY_PL_CONFIG "poll_config"
# define HOTKEY_ACTION "action"
# define HOTKEY_INFO "info"
# define ACPI_HOTK_NAME "Generic Hotkey Driver"
# define ACPI_HOTK_CLASS "Hotkey"
# define ACPI_HOTK_DEVICE_NAME "Hotkey"
# define ACPI_HOTK_HID "Unknown?"
# define ACPI_HOTKEY_COMPONENT 0x20000000
# define ACPI_HOTKEY_EVENT 0x1
# define ACPI_HOTKEY_POLLING 0x2
# define ACPI_UNDEFINED_EVENT 0xf
2005-08-03 18:07:59 -04:00
# define RESULT_STR_LEN 80
2005-03-18 18:03:45 -05:00
2005-08-03 18:07:59 -04:00
# define ACTION_METHOD 0
# define POLL_METHOD 1
2005-03-18 18:03:45 -05:00
2005-08-03 18:07:59 -04:00
# define IS_EVENT(e) ((e) <= 10000 && (e) >0)
# define IS_POLL(e) ((e) > 10000)
# define IS_OTHERS(e) ((e)<=0 || (e)>=20000)
2005-03-18 18:03:45 -05:00
# define _COMPONENT ACPI_HOTKEY_COMPONENT
ACPI_MODULE_NAME ( " acpi_hotkey " )
2005-08-05 00:44:28 -04:00
MODULE_AUTHOR ( " luming.yu@intel.com " ) ;
2005-03-18 18:03:45 -05:00
MODULE_DESCRIPTION ( ACPI_HOTK_NAME ) ;
MODULE_LICENSE ( " GPL " ) ;
/* standardized internal hotkey number/event */
enum {
/* Video Extension event */
HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80 ,
HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE ,
HK_EVENT_CYCLE_DISPLAY_OUTPUT ,
HK_EVENT_NEXT_DISPLAY_OUTPUT ,
HK_EVENT_PREVIOUS_DISPLAY_OUTPUT ,
HK_EVENT_CYCLE_BRIGHTNESS ,
HK_EVENT_INCREASE_BRIGHTNESS ,
HK_EVENT_DECREASE_BRIGHTNESS ,
HK_EVENT_ZERO_BRIGHTNESS ,
HK_EVENT_DISPLAY_DEVICE_OFF ,
/* Snd Card event */
HK_EVENT_VOLUME_MUTE ,
HK_EVENT_VOLUME_INCLREASE ,
HK_EVENT_VOLUME_DECREASE ,
/* running state control */
HK_EVENT_ENTERRING_S3 ,
HK_EVENT_ENTERRING_S4 ,
HK_EVENT_ENTERRING_S5 ,
} ;
/* procdir we use */
static struct proc_dir_entry * hotkey_proc_dir ;
static struct proc_dir_entry * hotkey_config ;
static struct proc_dir_entry * hotkey_poll_config ;
static struct proc_dir_entry * hotkey_action ;
static struct proc_dir_entry * hotkey_info ;
/* linkage for all type of hotkey */
struct acpi_hotkey_link {
struct list_head entries ;
int hotkey_type ; /* event or polling based hotkey */
int hotkey_standard_num ; /* standardized hotkey(event) number */
} ;
/* event based hotkey */
struct acpi_event_hotkey {
struct acpi_hotkey_link hotkey_link ;
int flag ;
acpi_handle bus_handle ; /* bus to install notify handler */
int external_hotkey_num ; /* external hotkey/event number */
acpi_handle action_handle ; /* acpi handle attached aml action method */
char * action_method ; /* action method */
} ;
2005-08-03 18:07:59 -04:00
/*
2005-03-18 18:03:45 -05:00
* There are two ways to poll status
* 1. directy call read_xxx method , without any arguments passed in
* 2. call write_xxx method , with arguments passed in , you need
* the result is saved in acpi_polling_hotkey . poll_result .
* anthoer read command through polling interface .
*
*/
/* polling based hotkey */
struct acpi_polling_hotkey {
struct acpi_hotkey_link hotkey_link ;
int flag ;
acpi_handle poll_handle ; /* acpi handle attached polling method */
char * poll_method ; /* poll method */
acpi_handle action_handle ; /* acpi handle attached action method */
char * action_method ; /* action method */
2005-08-03 18:07:59 -04:00
union acpi_object * poll_result ; /* polling_result */
2005-03-18 18:03:45 -05:00
struct proc_dir_entry * proc ;
} ;
/* hotkey object union */
union acpi_hotkey {
struct list_head entries ;
struct acpi_hotkey_link link ;
struct acpi_event_hotkey event_hotkey ;
struct acpi_polling_hotkey poll_hotkey ;
} ;
/* hotkey object list */
struct acpi_hotkey_list {
struct list_head * entries ;
int count ;
} ;
static int auto_hotkey_add ( struct acpi_device * device ) ;
static int auto_hotkey_remove ( struct acpi_device * device , int type ) ;
static struct acpi_driver hotkey_driver = {
. name = ACPI_HOTK_NAME ,
. class = ACPI_HOTK_CLASS ,
. ids = ACPI_HOTK_HID ,
. ops = {
. add = auto_hotkey_add ,
. remove = auto_hotkey_remove ,
} ,
} ;
2005-08-03 18:07:59 -04:00
static void free_hotkey_device ( union acpi_hotkey * key ) ;
static void free_hotkey_buffer ( union acpi_hotkey * key ) ;
static void free_poll_hotkey_buffer ( union acpi_hotkey * key ) ;
2005-03-18 18:03:45 -05:00
static int hotkey_open_config ( struct inode * inode , struct file * file ) ;
2005-08-03 18:07:59 -04:00
static int hotkey_poll_open_config ( struct inode * inode , struct file * file ) ;
2005-03-18 18:03:45 -05:00
static ssize_t hotkey_write_config ( struct file * file ,
const char __user * buffer ,
size_t count , loff_t * data ) ;
static int hotkey_info_open_fs ( struct inode * inode , struct file * file ) ;
static int hotkey_action_open_fs ( struct inode * inode , struct file * file ) ;
static ssize_t hotkey_execute_aml_method ( struct file * file ,
const char __user * buffer ,
size_t count , loff_t * data ) ;
static int hotkey_config_seq_show ( struct seq_file * seq , void * offset ) ;
2005-08-03 18:07:59 -04:00
static int hotkey_poll_config_seq_show ( struct seq_file * seq , void * offset ) ;
2005-03-18 18:03:45 -05:00
static int hotkey_polling_open_fs ( struct inode * inode , struct file * file ) ;
2005-08-03 18:07:59 -04:00
static union acpi_hotkey * get_hotkey_by_event ( struct
2005-08-05 00:44:28 -04:00
acpi_hotkey_list
* hotkey_list , int event ) ;
2005-03-18 18:03:45 -05:00
/* event based config */
static struct file_operations hotkey_config_fops = {
. open = hotkey_open_config ,
. read = seq_read ,
. write = hotkey_write_config ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
/* polling based config */
static struct file_operations hotkey_poll_config_fops = {
2005-08-03 18:07:59 -04:00
. open = hotkey_poll_open_config ,
2005-03-18 18:03:45 -05:00
. read = seq_read ,
2005-08-03 18:07:59 -04:00
. write = hotkey_write_config ,
2005-03-18 18:03:45 -05:00
. llseek = seq_lseek ,
. release = single_release ,
} ;
/* hotkey driver info */
static struct file_operations hotkey_info_fops = {
. open = hotkey_info_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
/* action */
static struct file_operations hotkey_action_fops = {
. open = hotkey_action_open_fs ,
. read = seq_read ,
. write = hotkey_execute_aml_method ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
/* polling results */
static struct file_operations hotkey_polling_fops = {
. open = hotkey_polling_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
struct acpi_hotkey_list global_hotkey_list ; /* link all ev or pl hotkey */
struct list_head hotkey_entries ; /* head of the list of hotkey_list */
static int hotkey_info_seq_show ( struct seq_file * seq , void * offset )
{
ACPI_FUNCTION_TRACE ( " hotkey_info_seq_show " ) ;
2005-08-03 18:07:59 -04:00
seq_printf ( seq , " Hotkey generic driver ver: %s \n " , HOTKEY_ACPI_VERSION ) ;
2005-03-18 18:03:45 -05:00
return_VALUE ( 0 ) ;
}
static int hotkey_info_open_fs ( struct inode * inode , struct file * file )
{
return single_open ( file , hotkey_info_seq_show , PDE ( inode ) - > data ) ;
}
static char * format_result ( union acpi_object * object )
{
2005-08-03 18:07:59 -04:00
char * buf = NULL ;
2005-08-05 00:44:28 -04:00
2005-08-03 18:07:59 -04:00
buf = ( char * ) kmalloc ( RESULT_STR_LEN , GFP_KERNEL ) ;
if ( buf )
memset ( buf , 0 , RESULT_STR_LEN ) ;
else
goto do_fail ;
2005-03-18 18:03:45 -05:00
/* Now, just support integer type */
if ( object - > type = = ACPI_TYPE_INTEGER )
2005-08-03 18:07:59 -04:00
sprintf ( buf , " %d \n " , ( u32 ) object - > integer . value ) ;
2005-08-05 00:44:28 -04:00
do_fail :
2005-08-03 18:07:59 -04:00
return ( buf ) ;
2005-03-18 18:03:45 -05:00
}
static int hotkey_polling_seq_show ( struct seq_file * seq , void * offset )
{
struct acpi_polling_hotkey * poll_hotkey =
( struct acpi_polling_hotkey * ) seq - > private ;
2005-08-03 18:07:59 -04:00
char * buf ;
2005-03-18 18:03:45 -05:00
ACPI_FUNCTION_TRACE ( " hotkey_polling_seq_show " ) ;
2005-08-05 00:44:28 -04:00
if ( poll_hotkey - > poll_result ) {
2005-08-03 18:07:59 -04:00
buf = format_result ( poll_hotkey - > poll_result ) ;
2005-08-05 00:44:28 -04:00
if ( buf )
2005-08-03 18:07:59 -04:00
seq_printf ( seq , " %s " , buf ) ;
kfree ( buf ) ;
}
2005-03-18 18:03:45 -05:00
return_VALUE ( 0 ) ;
}
static int hotkey_polling_open_fs ( struct inode * inode , struct file * file )
{
return single_open ( file , hotkey_polling_seq_show , PDE ( inode ) - > data ) ;
}
static int hotkey_action_open_fs ( struct inode * inode , struct file * file )
{
return single_open ( file , hotkey_info_seq_show , PDE ( inode ) - > data ) ;
}
/* Mapping external hotkey number to standardized hotkey event num */
static int hotkey_get_internal_event ( int event , struct acpi_hotkey_list * list )
{
2005-08-03 18:07:59 -04:00
struct list_head * entries ;
int val = - 1 ;
2005-03-18 18:03:45 -05:00
ACPI_FUNCTION_TRACE ( " hotkey_get_internal_event " ) ;
2005-08-03 18:07:59 -04:00
list_for_each ( entries , list - > entries ) {
2005-03-18 18:03:45 -05:00
union acpi_hotkey * key =
container_of ( entries , union acpi_hotkey , entries ) ;
if ( key - > link . hotkey_type = = ACPI_HOTKEY_EVENT
2005-08-05 00:44:28 -04:00
& & key - > event_hotkey . external_hotkey_num = = event ) {
2005-03-18 18:03:45 -05:00
val = key - > link . hotkey_standard_num ;
2005-08-03 18:07:59 -04:00
break ;
}
2005-03-18 18:03:45 -05:00
}
return_VALUE ( val ) ;
}
static void
acpi_hotkey_notify_handler ( acpi_handle handle , u32 event , void * data )
{
struct acpi_device * device = NULL ;
u32 internal_event ;
ACPI_FUNCTION_TRACE ( " acpi_hotkey_notify_handler " ) ;
if ( acpi_bus_get_device ( handle , & device ) )
return_VOID ;
internal_event = hotkey_get_internal_event ( event , & global_hotkey_list ) ;
2005-08-03 18:07:59 -04:00
acpi_bus_generate_event ( device , internal_event , 0 ) ;
2005-03-18 18:03:45 -05:00
return_VOID ;
}
/* Need to invent automatically hotkey add method */
static int auto_hotkey_add ( struct acpi_device * device )
{
/* Implement me */
return 0 ;
}
/* Need to invent automatically hotkey remove method */
static int auto_hotkey_remove ( struct acpi_device * device , int type )
{
/* Implement me */
return 0 ;
}
/* Create a proc file for each polling method */
static int create_polling_proc ( union acpi_hotkey * device )
{
struct proc_dir_entry * proc ;
2005-08-05 00:44:28 -04:00
char proc_name [ 80 ] ;
2005-03-30 22:53:30 -05:00
mode_t mode ;
2005-03-18 18:03:45 -05:00
ACPI_FUNCTION_TRACE ( " create_polling_proc " ) ;
2005-03-30 22:53:30 -05:00
mode = S_IFREG | S_IRUGO | S_IWUGO ;
2005-03-18 18:03:45 -05:00
2005-08-03 18:07:59 -04:00
sprintf ( proc_name , " %d " , device - > link . hotkey_standard_num ) ;
/*
2005-08-05 00:44:28 -04:00
strcat ( proc_name , device - > poll_hotkey . poll_method ) ;
*/
2005-08-03 18:07:59 -04:00
proc = create_proc_entry ( proc_name , mode , hotkey_proc_dir ) ;
2005-03-18 18:03:45 -05:00
if ( ! proc ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Hotkey: Unable to create %s entry \n " ,
device - > poll_hotkey . poll_method ) ) ;
return_VALUE ( - ENODEV ) ;
} else {
proc - > proc_fops = & hotkey_polling_fops ;
proc - > owner = THIS_MODULE ;
proc - > data = device ;
proc - > uid = 0 ;
proc - > gid = 0 ;
device - > poll_hotkey . proc = proc ;
}
return_VALUE ( 0 ) ;
}
static int hotkey_add ( union acpi_hotkey * device )
{
int status = 0 ;
struct acpi_device * dev = NULL ;
ACPI_FUNCTION_TRACE ( " hotkey_add " ) ;
if ( device - > link . hotkey_type = = ACPI_HOTKEY_EVENT ) {
2005-08-03 18:07:59 -04:00
acpi_bus_get_device ( device - > event_hotkey . bus_handle , & dev ) ;
2005-03-18 18:03:45 -05:00
status = acpi_install_notify_handler ( dev - > handle ,
2005-08-03 18:07:59 -04:00
ACPI_DEVICE_NOTIFY ,
2005-03-18 18:03:45 -05:00
acpi_hotkey_notify_handler ,
2005-08-03 18:07:59 -04:00
dev ) ;
2005-03-18 18:03:45 -05:00
} else /* Add polling hotkey */
create_polling_proc ( device ) ;
global_hotkey_list . count + + ;
list_add_tail ( & device - > link . entries , global_hotkey_list . entries ) ;
return_VALUE ( status ) ;
}
static int hotkey_remove ( union acpi_hotkey * device )
{
struct list_head * entries , * next ;
ACPI_FUNCTION_TRACE ( " hotkey_remove " ) ;
list_for_each_safe ( entries , next , global_hotkey_list . entries ) {
union acpi_hotkey * key =
container_of ( entries , union acpi_hotkey , entries ) ;
if ( key - > link . hotkey_standard_num = =
device - > link . hotkey_standard_num ) {
list_del ( & key - > link . entries ) ;
2005-08-03 18:07:59 -04:00
free_hotkey_device ( key ) ;
2005-03-18 18:03:45 -05:00
global_hotkey_list . count - - ;
break ;
}
}
2005-08-03 18:07:59 -04:00
kfree ( device ) ;
2005-03-18 18:03:45 -05:00
return_VALUE ( 0 ) ;
}
2005-08-05 00:44:28 -04:00
static int hotkey_update ( union acpi_hotkey * key )
2005-03-18 18:03:45 -05:00
{
2005-08-03 18:07:59 -04:00
struct list_head * entries ;
2005-03-18 18:03:45 -05:00
ACPI_FUNCTION_TRACE ( " hotkey_update " ) ;
2005-08-03 18:07:59 -04:00
list_for_each ( entries , global_hotkey_list . entries ) {
2005-08-05 00:44:28 -04:00
union acpi_hotkey * tmp =
2005-03-18 18:03:45 -05:00
container_of ( entries , union acpi_hotkey , entries ) ;
2005-08-03 18:07:59 -04:00
if ( tmp - > link . hotkey_standard_num = =
2005-03-18 18:03:45 -05:00
key - > link . hotkey_standard_num ) {
2005-08-03 18:07:59 -04:00
if ( key - > link . hotkey_type = = ACPI_HOTKEY_EVENT ) {
free_hotkey_buffer ( tmp ) ;
tmp - > event_hotkey . bus_handle =
2005-08-05 00:44:28 -04:00
key - > event_hotkey . bus_handle ;
2005-08-03 18:07:59 -04:00
tmp - > event_hotkey . external_hotkey_num =
2005-08-05 00:44:28 -04:00
key - > event_hotkey . external_hotkey_num ;
2005-08-03 18:07:59 -04:00
tmp - > event_hotkey . action_handle =
2005-08-05 00:44:28 -04:00
key - > event_hotkey . action_handle ;
2005-08-03 18:07:59 -04:00
tmp - > event_hotkey . action_method =
2005-08-05 00:44:28 -04:00
key - > event_hotkey . action_method ;
2005-08-03 18:07:59 -04:00
kfree ( key ) ;
} else {
/*
2005-08-05 00:44:28 -04:00
char proc_name [ 80 ] ;
2005-08-03 18:07:59 -04:00
2005-08-05 00:44:28 -04:00
sprintf ( proc_name , " %d " , tmp - > link . hotkey_standard_num ) ;
strcat ( proc_name , tmp - > poll_hotkey . poll_method ) ;
remove_proc_entry ( proc_name , hotkey_proc_dir ) ;
*/
2005-08-03 18:07:59 -04:00
free_poll_hotkey_buffer ( tmp ) ;
tmp - > poll_hotkey . poll_handle =
2005-08-05 00:44:28 -04:00
key - > poll_hotkey . poll_handle ;
2005-08-03 18:07:59 -04:00
tmp - > poll_hotkey . poll_method =
2005-08-05 00:44:28 -04:00
key - > poll_hotkey . poll_method ;
2005-08-03 18:07:59 -04:00
tmp - > poll_hotkey . action_handle =
2005-08-05 00:44:28 -04:00
key - > poll_hotkey . action_handle ;
2005-08-03 18:07:59 -04:00
tmp - > poll_hotkey . action_method =
2005-08-05 00:44:28 -04:00
key - > poll_hotkey . action_method ;
2005-08-03 18:07:59 -04:00
tmp - > poll_hotkey . poll_result =
2005-08-05 00:44:28 -04:00
key - > poll_hotkey . poll_result ;
2005-08-03 18:07:59 -04:00
/*
2005-08-05 00:44:28 -04:00
create_polling_proc ( tmp ) ;
*/
2005-08-03 18:07:59 -04:00
kfree ( key ) ;
}
return_VALUE ( 0 ) ;
2005-03-18 18:03:45 -05:00
break ;
}
}
2005-08-03 18:07:59 -04:00
return_VALUE ( - ENODEV ) ;
2005-03-18 18:03:45 -05:00
}
static void free_hotkey_device ( union acpi_hotkey * key )
{
struct acpi_device * dev ;
ACPI_FUNCTION_TRACE ( " free_hotkey_device " ) ;
if ( key - > link . hotkey_type = = ACPI_HOTKEY_EVENT ) {
2005-08-03 18:07:59 -04:00
acpi_bus_get_device ( key - > event_hotkey . bus_handle , & dev ) ;
2005-03-18 18:03:45 -05:00
if ( dev - > handle )
acpi_remove_notify_handler ( dev - > handle ,
2005-08-03 18:07:59 -04:00
ACPI_DEVICE_NOTIFY ,
2005-03-18 18:03:45 -05:00
acpi_hotkey_notify_handler ) ;
2005-08-03 18:07:59 -04:00
free_hotkey_buffer ( key ) ;
} else {
2005-08-05 00:44:28 -04:00
char proc_name [ 80 ] ;
2005-08-03 18:07:59 -04:00
sprintf ( proc_name , " %d " , key - > link . hotkey_standard_num ) ;
/*
2005-08-05 00:44:28 -04:00
strcat ( proc_name , key - > poll_hotkey . poll_method ) ;
*/
remove_proc_entry ( proc_name , hotkey_proc_dir ) ;
2005-08-03 18:07:59 -04:00
free_poll_hotkey_buffer ( key ) ;
}
2005-03-18 18:03:45 -05:00
kfree ( key ) ;
return_VOID ;
}
2005-08-05 00:44:28 -04:00
static void free_hotkey_buffer ( union acpi_hotkey * key )
2005-08-03 18:07:59 -04:00
{
kfree ( key - > event_hotkey . action_method ) ;
}
2005-08-05 00:44:28 -04:00
static void free_poll_hotkey_buffer ( union acpi_hotkey * key )
2005-08-03 18:07:59 -04:00
{
kfree ( key - > poll_hotkey . action_method ) ;
kfree ( key - > poll_hotkey . poll_method ) ;
kfree ( key - > poll_hotkey . poll_result ) ;
}
2005-03-18 18:03:45 -05:00
static int
init_hotkey_device ( union acpi_hotkey * key , char * bus_str , char * action_str ,
char * method , int std_num , int external_num )
{
2005-08-05 00:44:28 -04:00
acpi_handle tmp_handle ;
2005-08-03 18:07:59 -04:00
acpi_status status = AE_OK ;
2005-03-18 18:03:45 -05:00
ACPI_FUNCTION_TRACE ( " init_hotkey_device " ) ;
2005-08-05 00:44:28 -04:00
if ( std_num < 0 | | IS_POLL ( std_num ) | | ! key )
2005-08-03 18:07:59 -04:00
goto do_fail ;
2005-08-05 00:44:28 -04:00
if ( ! bus_str | | ! action_str | | ! method )
2005-08-03 18:07:59 -04:00
goto do_fail ;
2005-03-18 18:03:45 -05:00
key - > link . hotkey_type = ACPI_HOTKEY_EVENT ;
key - > link . hotkey_standard_num = std_num ;
key - > event_hotkey . flag = 0 ;
2005-08-03 18:07:59 -04:00
key - > event_hotkey . action_method = method ;
2005-03-18 18:03:45 -05:00
2005-08-05 00:44:28 -04:00
status =
acpi_get_handle ( NULL , bus_str , & ( key - > event_hotkey . bus_handle ) ) ;
if ( ACPI_FAILURE ( status ) )
2005-08-03 18:07:59 -04:00
goto do_fail ;
key - > event_hotkey . external_hotkey_num = external_num ;
2005-08-05 00:44:28 -04:00
status =
acpi_get_handle ( NULL , action_str ,
& ( key - > event_hotkey . action_handle ) ) ;
if ( ACPI_FAILURE ( status ) )
2005-08-03 18:07:59 -04:00
goto do_fail ;
status = acpi_get_handle ( key - > event_hotkey . action_handle ,
2005-08-05 00:44:28 -04:00
method , & tmp_handle ) ;
2005-08-03 18:07:59 -04:00
if ( ACPI_FAILURE ( status ) )
goto do_fail ;
return_VALUE ( AE_OK ) ;
2005-08-05 00:44:28 -04:00
do_fail :
2005-08-03 18:07:59 -04:00
return_VALUE ( - ENODEV ) ;
2005-03-18 18:03:45 -05:00
}
static int
init_poll_hotkey_device ( union acpi_hotkey * key ,
char * poll_str ,
char * poll_method ,
char * action_str , char * action_method , int std_num )
{
2005-08-03 18:07:59 -04:00
acpi_status status = AE_OK ;
2005-08-05 00:44:28 -04:00
acpi_handle tmp_handle ;
2005-08-03 18:07:59 -04:00
2005-03-18 18:03:45 -05:00
ACPI_FUNCTION_TRACE ( " init_poll_hotkey_device " ) ;
2005-08-05 00:44:28 -04:00
if ( std_num < 0 | | IS_EVENT ( std_num ) | | ! key )
2005-08-03 18:07:59 -04:00
goto do_fail ;
2005-08-05 00:44:28 -04:00
if ( ! poll_str | | ! poll_method | | ! action_str | | ! action_method )
2005-08-03 18:07:59 -04:00
goto do_fail ;
2005-03-18 18:03:45 -05:00
key - > link . hotkey_type = ACPI_HOTKEY_POLLING ;
key - > link . hotkey_standard_num = std_num ;
key - > poll_hotkey . flag = 0 ;
key - > poll_hotkey . poll_method = poll_method ;
2005-08-03 18:07:59 -04:00
key - > poll_hotkey . action_method = action_method ;
2005-08-05 00:44:28 -04:00
status =
acpi_get_handle ( NULL , poll_str , & ( key - > poll_hotkey . poll_handle ) ) ;
if ( ACPI_FAILURE ( status ) )
2005-08-03 18:07:59 -04:00
goto do_fail ;
status = acpi_get_handle ( key - > poll_hotkey . poll_handle ,
2005-08-05 00:44:28 -04:00
poll_method , & tmp_handle ) ;
if ( ACPI_FAILURE ( status ) )
goto do_fail ;
status =
acpi_get_handle ( NULL , action_str ,
& ( key - > poll_hotkey . action_handle ) ) ;
2005-08-03 18:07:59 -04:00
if ( ACPI_FAILURE ( status ) )
goto do_fail ;
status = acpi_get_handle ( key - > poll_hotkey . action_handle ,
2005-08-05 00:44:28 -04:00
action_method , & tmp_handle ) ;
2005-08-03 18:07:59 -04:00
if ( ACPI_FAILURE ( status ) )
goto do_fail ;
2005-03-18 18:03:45 -05:00
key - > poll_hotkey . poll_result =
( union acpi_object * ) kmalloc ( sizeof ( union acpi_object ) , GFP_KERNEL ) ;
2005-08-05 00:44:28 -04:00
if ( ! key - > poll_hotkey . poll_result )
2005-08-03 18:07:59 -04:00
goto do_fail ;
return_VALUE ( AE_OK ) ;
2005-08-05 00:44:28 -04:00
do_fail :
2005-08-03 18:07:59 -04:00
return_VALUE ( - ENODEV ) ;
2005-03-18 18:03:45 -05:00
}
static int hotkey_open_config ( struct inode * inode , struct file * file )
{
ACPI_FUNCTION_TRACE ( " hotkey_open_config " ) ;
return_VALUE ( single_open
( file , hotkey_config_seq_show , PDE ( inode ) - > data ) ) ;
}
2005-08-03 18:07:59 -04:00
static int hotkey_poll_open_config ( struct inode * inode , struct file * file )
{
ACPI_FUNCTION_TRACE ( " hotkey_poll_open_config " ) ;
return_VALUE ( single_open
( file , hotkey_poll_config_seq_show , PDE ( inode ) - > data ) ) ;
}
2005-03-18 18:03:45 -05:00
static int hotkey_config_seq_show ( struct seq_file * seq , void * offset )
{
struct acpi_hotkey_list * hotkey_list = & global_hotkey_list ;
2005-08-03 18:07:59 -04:00
struct list_head * entries ;
2005-03-18 18:03:45 -05:00
char bus_name [ ACPI_PATHNAME_MAX ] = { 0 } ;
char action_name [ ACPI_PATHNAME_MAX ] = { 0 } ;
struct acpi_buffer bus = { ACPI_PATHNAME_MAX , bus_name } ;
struct acpi_buffer act = { ACPI_PATHNAME_MAX , action_name } ;
ACPI_FUNCTION_TRACE ( ( " hotkey_config_seq_show " ) ) ;
2005-08-03 18:07:59 -04:00
list_for_each ( entries , hotkey_list - > entries ) {
2005-03-18 18:03:45 -05:00
union acpi_hotkey * key =
container_of ( entries , union acpi_hotkey , entries ) ;
if ( key - > link . hotkey_type = = ACPI_HOTKEY_EVENT ) {
acpi_get_name ( key - > event_hotkey . bus_handle ,
ACPI_NAME_TYPE_MAX , & bus ) ;
acpi_get_name ( key - > event_hotkey . action_handle ,
ACPI_NAME_TYPE_MAX , & act ) ;
2005-08-03 18:07:59 -04:00
seq_printf ( seq , " %s:%s:%s:%d:%d \n " , bus_name ,
2005-03-18 18:03:45 -05:00
action_name ,
key - > event_hotkey . action_method ,
key - > link . hotkey_standard_num ,
key - > event_hotkey . external_hotkey_num ) ;
2005-08-03 18:07:59 -04:00
}
}
seq_puts ( seq , " \n " ) ;
return_VALUE ( 0 ) ;
}
static int hotkey_poll_config_seq_show ( struct seq_file * seq , void * offset )
{
struct acpi_hotkey_list * hotkey_list = & global_hotkey_list ;
struct list_head * entries ;
char bus_name [ ACPI_PATHNAME_MAX ] = { 0 } ;
char action_name [ ACPI_PATHNAME_MAX ] = { 0 } ;
struct acpi_buffer bus = { ACPI_PATHNAME_MAX , bus_name } ;
struct acpi_buffer act = { ACPI_PATHNAME_MAX , action_name } ;
ACPI_FUNCTION_TRACE ( ( " hotkey_config_seq_show " ) ) ;
list_for_each ( entries , hotkey_list - > entries ) {
union acpi_hotkey * key =
container_of ( entries , union acpi_hotkey , entries ) ;
if ( key - > link . hotkey_type = = ACPI_HOTKEY_POLLING ) {
2005-03-18 18:03:45 -05:00
acpi_get_name ( key - > poll_hotkey . poll_handle ,
ACPI_NAME_TYPE_MAX , & bus ) ;
acpi_get_name ( key - > poll_hotkey . action_handle ,
ACPI_NAME_TYPE_MAX , & act ) ;
2005-08-03 18:07:59 -04:00
seq_printf ( seq , " %s:%s:%s:%s:%d \n " , bus_name ,
2005-03-18 18:03:45 -05:00
key - > poll_hotkey . poll_method ,
action_name ,
key - > poll_hotkey . action_method ,
key - > link . hotkey_standard_num ) ;
}
}
seq_puts ( seq , " \n " ) ;
return_VALUE ( 0 ) ;
}
static int
get_parms ( char * config_record ,
int * cmd ,
2005-08-03 18:07:59 -04:00
char * * bus_handle ,
char * * bus_method ,
char * * action_handle ,
char * * method , int * internal_event_num , int * external_event_num )
2005-03-18 18:03:45 -05:00
{
2005-08-03 18:07:59 -04:00
char * tmp , * tmp1 , count ;
2005-03-18 18:03:45 -05:00
ACPI_FUNCTION_TRACE ( ( " get_parms " ) ) ;
sscanf ( config_record , " %d " , cmd ) ;
2005-08-05 00:44:28 -04:00
if ( * cmd = = 1 ) {
if ( sscanf ( config_record , " %d:%d " , cmd , internal_event_num ) ! =
2 )
2005-08-03 18:07:59 -04:00
goto do_fail ;
else
return ( 6 ) ;
}
2005-03-18 18:03:45 -05:00
tmp = strchr ( config_record , ' : ' ) ;
2005-08-03 18:07:59 -04:00
if ( ! tmp )
goto do_fail ;
2005-03-18 18:03:45 -05:00
tmp + + ;
tmp1 = strchr ( tmp , ' : ' ) ;
2005-08-03 18:07:59 -04:00
if ( ! tmp1 )
goto do_fail ;
count = tmp1 - tmp ;
2005-08-05 00:44:28 -04:00
* bus_handle = ( char * ) kmalloc ( count + 1 , GFP_KERNEL ) ;
if ( ! * bus_handle )
2005-08-03 18:07:59 -04:00
goto do_fail ;
strncpy ( * bus_handle , tmp , count ) ;
* ( * bus_handle + count ) = 0 ;
2005-03-18 18:03:45 -05:00
tmp = tmp1 ;
tmp + + ;
tmp1 = strchr ( tmp , ' : ' ) ;
2005-08-03 18:07:59 -04:00
if ( ! tmp1 )
goto do_fail ;
count = tmp1 - tmp ;
2005-08-05 00:44:28 -04:00
* bus_method = ( char * ) kmalloc ( count + 1 , GFP_KERNEL ) ;
if ( ! * bus_method )
2005-08-03 18:07:59 -04:00
goto do_fail ;
strncpy ( * bus_method , tmp , count ) ;
* ( * bus_method + count ) = 0 ;
2005-03-18 18:03:45 -05:00
tmp = tmp1 ;
tmp + + ;
tmp1 = strchr ( tmp , ' : ' ) ;
2005-08-03 18:07:59 -04:00
if ( ! tmp1 )
goto do_fail ;
count = tmp1 - tmp ;
2005-08-05 00:44:28 -04:00
* action_handle = ( char * ) kmalloc ( count + 1 , GFP_KERNEL ) ;
2005-08-03 18:07:59 -04:00
strncpy ( * action_handle , tmp , count ) ;
* ( * action_handle + count ) = 0 ;
2005-03-18 18:03:45 -05:00
tmp = tmp1 ;
tmp + + ;
tmp1 = strchr ( tmp , ' : ' ) ;
2005-08-03 18:07:59 -04:00
if ( ! tmp1 )
goto do_fail ;
count = tmp1 - tmp ;
2005-08-05 00:44:28 -04:00
* method = ( char * ) kmalloc ( count + 1 , GFP_KERNEL ) ;
if ( ! * method )
2005-08-03 18:07:59 -04:00
goto do_fail ;
strncpy ( * method , tmp , count ) ;
* ( * method + count ) = 0 ;
2005-08-05 00:44:28 -04:00
if ( sscanf ( tmp1 + 1 , " %d:%d " , internal_event_num , external_event_num ) < =
0 )
2005-08-03 18:07:59 -04:00
goto do_fail ;
2005-03-18 18:03:45 -05:00
return_VALUE ( 6 ) ;
2005-08-05 00:44:28 -04:00
do_fail :
2005-08-03 18:07:59 -04:00
return_VALUE ( - 1 ) ;
2005-03-18 18:03:45 -05:00
}
/* count is length for one input record */
static ssize_t hotkey_write_config ( struct file * file ,
const char __user * buffer ,
size_t count , loff_t * data )
{
2005-08-03 18:07:59 -04:00
char * config_record = NULL ;
char * bus_handle = NULL ;
char * bus_method = NULL ;
char * action_handle = NULL ;
char * method = NULL ;
2005-03-18 18:03:45 -05:00
int cmd , internal_event_num , external_event_num ;
int ret = 0 ;
union acpi_hotkey * key = NULL ;
ACPI_FUNCTION_TRACE ( ( " hotkey_write_config " ) ) ;
2005-08-05 00:44:28 -04:00
config_record = ( char * ) kmalloc ( count + 1 , GFP_KERNEL ) ;
if ( ! config_record )
2005-08-03 18:07:59 -04:00
return_VALUE ( - ENOMEM ) ;
2005-03-18 18:03:45 -05:00
if ( copy_from_user ( config_record , buffer , count ) ) {
2005-08-03 18:07:59 -04:00
kfree ( config_record ) ;
2005-03-18 18:03:45 -05:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR , " Invalid data \n " ) ) ;
return_VALUE ( - EINVAL ) ;
}
2005-08-03 18:07:59 -04:00
config_record [ count ] = 0 ;
2005-03-18 18:03:45 -05:00
ret = get_parms ( config_record ,
& cmd ,
2005-08-03 18:07:59 -04:00
& bus_handle ,
& bus_method ,
& action_handle ,
& method , & internal_event_num , & external_event_num ) ;
kfree ( config_record ) ;
2005-08-05 00:44:28 -04:00
if ( IS_OTHERS ( internal_event_num ) )
2005-08-03 18:07:59 -04:00
goto do_fail ;
2005-03-18 18:03:45 -05:00
if ( ret ! = 6 ) {
2005-08-05 00:44:28 -04:00
do_fail :
2005-08-03 18:07:59 -04:00
kfree ( bus_handle ) ;
kfree ( bus_method ) ;
kfree ( action_handle ) ;
kfree ( method ) ;
2005-03-18 18:03:45 -05:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Invalid data format ret=%d \n " , ret ) ) ;
return_VALUE ( - EINVAL ) ;
}
key = kmalloc ( sizeof ( union acpi_hotkey ) , GFP_KERNEL ) ;
2005-08-05 00:44:28 -04:00
if ( ! key )
2005-08-03 18:07:59 -04:00
goto do_fail ;
memset ( key , 0 , sizeof ( union acpi_hotkey ) ) ;
2005-08-05 00:44:28 -04:00
if ( cmd = = 1 ) {
2005-08-03 18:07:59 -04:00
union acpi_hotkey * tmp = NULL ;
tmp = get_hotkey_by_event ( & global_hotkey_list ,
2005-08-05 00:44:28 -04:00
internal_event_num ) ;
if ( ! tmp )
2005-08-03 18:07:59 -04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR , " Invalid key " ) ) ;
else
memcpy ( key , tmp , sizeof ( union acpi_hotkey ) ) ;
goto cont_cmd ;
}
if ( IS_EVENT ( internal_event_num ) ) {
kfree ( bus_method ) ;
ret = init_hotkey_device ( key , bus_handle , action_handle , method ,
2005-08-05 00:44:28 -04:00
internal_event_num ,
external_event_num ) ;
2005-08-03 18:07:59 -04:00
} else
ret = init_poll_hotkey_device ( key , bus_handle , bus_method ,
2005-08-05 00:44:28 -04:00
action_handle , method ,
internal_event_num ) ;
2005-08-03 18:07:59 -04:00
if ( ret ) {
kfree ( bus_handle ) ;
kfree ( action_handle ) ;
2005-08-05 00:44:28 -04:00
if ( IS_EVENT ( internal_event_num ) )
2005-08-03 18:07:59 -04:00
free_hotkey_buffer ( key ) ;
else
free_poll_hotkey_buffer ( key ) ;
2005-03-18 18:03:45 -05:00
kfree ( key ) ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR , " Invalid hotkey \n " ) ) ;
return_VALUE ( - EINVAL ) ;
}
2005-08-05 00:44:28 -04:00
cont_cmd :
2005-08-03 18:07:59 -04:00
kfree ( bus_handle ) ;
kfree ( action_handle ) ;
2005-03-18 18:03:45 -05:00
switch ( cmd ) {
case 0 :
2005-08-05 00:44:28 -04:00
if ( get_hotkey_by_event
( & global_hotkey_list , key - > link . hotkey_standard_num ) )
2005-08-03 18:07:59 -04:00
goto fail_out ;
else
hotkey_add ( key ) ;
2005-03-18 18:03:45 -05:00
break ;
case 1 :
hotkey_remove ( key ) ;
break ;
case 2 :
2005-08-05 00:44:28 -04:00
if ( hotkey_update ( key ) )
2005-08-03 18:07:59 -04:00
goto fail_out ;
2005-03-18 18:03:45 -05:00
break ;
default :
2005-08-03 18:07:59 -04:00
goto fail_out ;
2005-03-18 18:03:45 -05:00
break ;
}
return_VALUE ( count ) ;
2005-08-05 00:44:28 -04:00
fail_out :
if ( IS_EVENT ( internal_event_num ) )
2005-08-03 18:07:59 -04:00
free_hotkey_buffer ( key ) ;
else
free_poll_hotkey_buffer ( key ) ;
kfree ( key ) ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR , " invalid key \n " ) ) ;
return_VALUE ( - EINVAL ) ;
2005-03-18 18:03:45 -05:00
}
2005-08-03 18:07:59 -04:00
/*
2005-03-18 18:03:45 -05:00
* This function evaluates an ACPI method , given an int as parameter , the
* method is searched within the scope of the handle , can be NULL . The output
* of the method is written is output , which can also be NULL
*
* returns 1 if write is successful , 0 else .
*/
static int write_acpi_int ( acpi_handle handle , const char * method , int val ,
struct acpi_buffer * output )
{
struct acpi_object_list params ; /* list of input parameters (an int here) */
union acpi_object in_obj ; /* the only param we use */
acpi_status status ;
ACPI_FUNCTION_TRACE ( " write_acpi_int " ) ;
params . count = 1 ;
params . pointer = & in_obj ;
in_obj . type = ACPI_TYPE_INTEGER ;
in_obj . integer . value = val ;
status = acpi_evaluate_object ( handle , ( char * ) method , & params , output ) ;
return_VALUE ( status = = AE_OK ) ;
}
2005-08-05 00:44:28 -04:00
static int read_acpi_int ( acpi_handle handle , const char * method ,
union acpi_object * val )
2005-03-18 18:03:45 -05:00
{
struct acpi_buffer output ;
union acpi_object out_obj ;
acpi_status status ;
ACPI_FUNCTION_TRACE ( " read_acpi_int " ) ;
output . length = sizeof ( out_obj ) ;
output . pointer = & out_obj ;
status = acpi_evaluate_object ( handle , ( char * ) method , NULL , & output ) ;
2005-08-05 00:44:28 -04:00
if ( val ) {
2005-08-03 18:07:59 -04:00
val - > integer . value = out_obj . integer . value ;
val - > type = out_obj . type ;
} else
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR , " null val pointer " ) ) ;
2005-03-18 18:03:45 -05:00
return_VALUE ( ( status = = AE_OK )
& & ( out_obj . type = = ACPI_TYPE_INTEGER ) ) ;
}
2005-08-03 18:07:59 -04:00
static union acpi_hotkey * get_hotkey_by_event ( struct
2005-08-05 00:44:28 -04:00
acpi_hotkey_list
* hotkey_list , int event )
2005-03-18 18:03:45 -05:00
{
2005-08-03 18:07:59 -04:00
struct list_head * entries ;
2005-03-18 18:03:45 -05:00
2005-08-03 18:07:59 -04:00
list_for_each ( entries , hotkey_list - > entries ) {
2005-03-18 18:03:45 -05:00
union acpi_hotkey * key =
container_of ( entries , union acpi_hotkey , entries ) ;
2005-08-03 18:07:59 -04:00
if ( key - > link . hotkey_standard_num = = event ) {
2005-08-05 00:44:28 -04:00
return ( key ) ;
2005-03-18 18:03:45 -05:00
}
}
2005-08-05 00:44:28 -04:00
return ( NULL ) ;
2005-03-18 18:03:45 -05:00
}
2005-08-03 18:07:59 -04:00
/*
2005-03-18 18:03:45 -05:00
* user call AML method interface :
* Call convention :
* echo " event_num: arg type : value "
* example : echo " 1:1:30 " > / proc / acpi / action
* Just support 1 integer arg passing to AML method
*/
static ssize_t hotkey_execute_aml_method ( struct file * file ,
const char __user * buffer ,
size_t count , loff_t * data )
{
struct acpi_hotkey_list * hotkey_list = & global_hotkey_list ;
2005-08-03 18:07:59 -04:00
char * arg ;
2005-08-05 00:44:28 -04:00
int event , method_type , type , value ;
2005-08-03 18:07:59 -04:00
union acpi_hotkey * key ;
2005-03-18 18:03:45 -05:00
ACPI_FUNCTION_TRACE ( " hotkey_execte_aml_method " ) ;
2005-08-05 00:44:28 -04:00
arg = ( char * ) kmalloc ( count + 1 , GFP_KERNEL ) ;
if ( ! arg )
2005-08-03 18:07:59 -04:00
return_VALUE ( - ENOMEM ) ;
2005-08-05 00:44:28 -04:00
arg [ count ] = 0 ;
2005-03-18 18:03:45 -05:00
if ( copy_from_user ( arg , buffer , count ) ) {
2005-08-03 18:07:59 -04:00
kfree ( arg ) ;
2005-03-18 18:03:45 -05:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR , " Invalid argument 2 " ) ) ;
return_VALUE ( - EINVAL ) ;
}
2005-08-05 00:44:28 -04:00
if ( sscanf ( arg , " %d:%d:%d:%d " , & event , & method_type , & type , & value ) ! =
4 ) {
2005-08-03 18:07:59 -04:00
kfree ( arg ) ;
2005-03-18 18:03:45 -05:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR , " Invalid argument 3 " ) ) ;
return_VALUE ( - EINVAL ) ;
}
2005-08-03 18:07:59 -04:00
kfree ( arg ) ;
2005-03-18 18:03:45 -05:00
if ( type = = ACPI_TYPE_INTEGER ) {
2005-08-03 18:07:59 -04:00
key = get_hotkey_by_event ( hotkey_list , event ) ;
2005-08-05 00:44:28 -04:00
if ( ! key )
2005-08-03 18:07:59 -04:00
goto do_fail ;
2005-03-18 18:03:45 -05:00
if ( IS_EVENT ( event ) )
2005-08-03 18:07:59 -04:00
write_acpi_int ( key - > event_hotkey . action_handle ,
2005-08-05 00:44:28 -04:00
key - > event_hotkey . action_method , value ,
NULL ) ;
2005-03-18 18:03:45 -05:00
else if ( IS_POLL ( event ) ) {
2005-08-05 00:44:28 -04:00
if ( method_type = = POLL_METHOD )
2005-08-03 18:07:59 -04:00
read_acpi_int ( key - > poll_hotkey . poll_handle ,
2005-08-05 00:44:28 -04:00
key - > poll_hotkey . poll_method ,
key - > poll_hotkey . poll_result ) ;
else if ( method_type = = ACTION_METHOD )
2005-08-03 18:07:59 -04:00
write_acpi_int ( key - > poll_hotkey . action_handle ,
2005-08-05 00:44:28 -04:00
key - > poll_hotkey . action_method ,
value , NULL ) ;
2005-08-03 18:07:59 -04:00
else
goto do_fail ;
2005-03-18 18:03:45 -05:00
}
} else {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR , " Not supported " ) ) ;
return_VALUE ( - EINVAL ) ;
}
return_VALUE ( count ) ;
2005-08-05 00:44:28 -04:00
do_fail :
2005-08-03 18:07:59 -04:00
return_VALUE ( - EINVAL ) ;
2005-03-18 18:03:45 -05:00
}
static int __init hotkey_init ( void )
{
int result ;
mode_t mode = S_IFREG | S_IRUGO | S_IWUGO ;
ACPI_FUNCTION_TRACE ( " hotkey_init " ) ;
if ( acpi_disabled )
return - ENODEV ;
if ( acpi_specific_hotkey_enabled ) {
printk ( " Using specific hotkey driver \n " ) ;
return - ENODEV ;
}
hotkey_proc_dir = proc_mkdir ( HOTKEY_PROC , acpi_root_dir ) ;
if ( ! hotkey_proc_dir ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Hotkey: Unable to create %s entry \n " ,
HOTKEY_PROC ) ) ;
return ( - ENODEV ) ;
}
hotkey_proc_dir - > owner = THIS_MODULE ;
hotkey_config =
create_proc_entry ( HOTKEY_EV_CONFIG , mode , hotkey_proc_dir ) ;
if ( ! hotkey_config ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Hotkey: Unable to create %s entry \n " ,
HOTKEY_EV_CONFIG ) ) ;
2005-08-03 18:07:59 -04:00
goto do_fail1 ;
2005-03-18 18:03:45 -05:00
} else {
hotkey_config - > proc_fops = & hotkey_config_fops ;
hotkey_config - > data = & global_hotkey_list ;
hotkey_config - > owner = THIS_MODULE ;
hotkey_config - > uid = 0 ;
hotkey_config - > gid = 0 ;
}
hotkey_poll_config =
create_proc_entry ( HOTKEY_PL_CONFIG , mode , hotkey_proc_dir ) ;
if ( ! hotkey_poll_config ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Hotkey: Unable to create %s entry \n " ,
HOTKEY_EV_CONFIG ) ) ;
2005-08-03 18:07:59 -04:00
goto do_fail2 ;
2005-03-18 18:03:45 -05:00
} else {
hotkey_poll_config - > proc_fops = & hotkey_poll_config_fops ;
hotkey_poll_config - > data = & global_hotkey_list ;
hotkey_poll_config - > owner = THIS_MODULE ;
hotkey_poll_config - > uid = 0 ;
hotkey_poll_config - > gid = 0 ;
}
hotkey_action = create_proc_entry ( HOTKEY_ACTION , mode , hotkey_proc_dir ) ;
if ( ! hotkey_action ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Hotkey: Unable to create %s entry \n " ,
HOTKEY_ACTION ) ) ;
2005-08-03 18:07:59 -04:00
goto do_fail3 ;
2005-03-18 18:03:45 -05:00
} else {
hotkey_action - > proc_fops = & hotkey_action_fops ;
hotkey_action - > owner = THIS_MODULE ;
hotkey_action - > uid = 0 ;
hotkey_action - > gid = 0 ;
}
hotkey_info = create_proc_entry ( HOTKEY_INFO , mode , hotkey_proc_dir ) ;
if ( ! hotkey_info ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Hotkey: Unable to create %s entry \n " ,
HOTKEY_INFO ) ) ;
2005-08-03 18:07:59 -04:00
goto do_fail4 ;
2005-03-18 18:03:45 -05:00
} else {
hotkey_info - > proc_fops = & hotkey_info_fops ;
hotkey_info - > owner = THIS_MODULE ;
hotkey_info - > uid = 0 ;
hotkey_info - > gid = 0 ;
}
result = acpi_bus_register_driver ( & hotkey_driver ) ;
2005-08-03 18:07:59 -04:00
if ( result < 0 )
goto do_fail5 ;
2005-03-18 18:03:45 -05:00
global_hotkey_list . count = 0 ;
global_hotkey_list . entries = & hotkey_entries ;
INIT_LIST_HEAD ( & hotkey_entries ) ;
return ( 0 ) ;
2005-08-03 18:07:59 -04:00
2005-08-05 00:44:28 -04:00
do_fail5 :
2005-08-03 18:07:59 -04:00
remove_proc_entry ( HOTKEY_INFO , hotkey_proc_dir ) ;
2005-08-05 00:44:28 -04:00
do_fail4 :
2005-08-03 18:07:59 -04:00
remove_proc_entry ( HOTKEY_ACTION , hotkey_proc_dir ) ;
2005-08-05 00:44:28 -04:00
do_fail3 :
2005-08-03 18:07:59 -04:00
remove_proc_entry ( HOTKEY_PL_CONFIG , hotkey_proc_dir ) ;
2005-08-05 00:44:28 -04:00
do_fail2 :
2005-08-03 18:07:59 -04:00
remove_proc_entry ( HOTKEY_EV_CONFIG , hotkey_proc_dir ) ;
2005-08-05 00:44:28 -04:00
do_fail1 :
2005-08-03 18:07:59 -04:00
remove_proc_entry ( HOTKEY_PROC , acpi_root_dir ) ;
return ( - ENODEV ) ;
2005-03-18 18:03:45 -05:00
}
static void __exit hotkey_exit ( void )
{
struct list_head * entries , * next ;
2005-08-03 18:07:59 -04:00
ACPI_FUNCTION_TRACE ( " hotkey_exit " ) ;
2005-03-18 18:03:45 -05:00
list_for_each_safe ( entries , next , global_hotkey_list . entries ) {
union acpi_hotkey * key =
container_of ( entries , union acpi_hotkey , entries ) ;
acpi_os_wait_events_complete ( NULL ) ;
list_del ( & key - > link . entries ) ;
global_hotkey_list . count - - ;
free_hotkey_device ( key ) ;
}
acpi_bus_unregister_driver ( & hotkey_driver ) ;
remove_proc_entry ( HOTKEY_EV_CONFIG , hotkey_proc_dir ) ;
remove_proc_entry ( HOTKEY_PL_CONFIG , hotkey_proc_dir ) ;
remove_proc_entry ( HOTKEY_ACTION , hotkey_proc_dir ) ;
remove_proc_entry ( HOTKEY_INFO , hotkey_proc_dir ) ;
remove_proc_entry ( HOTKEY_PROC , acpi_root_dir ) ;
return ;
}
module_init ( hotkey_init ) ;
module_exit ( hotkey_exit ) ;