2005-04-17 02:20:36 +04:00
/*
* acpi_fan . c - ACPI Fan Driver ( $ Revision : 29 $ )
*
* 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>
# include <linux/types.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <asm/uaccess.h>
2008-01-17 10:51:24 +03:00
# include <linux/thermal.h>
2005-04-17 02:20:36 +04:00
# include <acpi/acpi_bus.h>
# include <acpi/acpi_drivers.h>
2009-07-29 00:45:54 +04:00
# define PREFIX "ACPI: "
2005-04-17 02:20:36 +04:00
# define ACPI_FAN_CLASS "fan"
# define ACPI_FAN_FILE_STATE "state"
# define _COMPONENT ACPI_FAN_COMPONENT
2007-02-13 06:42:12 +03:00
ACPI_MODULE_NAME ( " fan " ) ;
2005-04-17 02:20:36 +04:00
2007-02-13 06:42:12 +03:00
MODULE_AUTHOR ( " Paul Diefenbaugh " ) ;
2007-02-13 07:50:02 +03:00
MODULE_DESCRIPTION ( " ACPI Fan Driver " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
2005-08-05 08:44:28 +04:00
static int acpi_fan_add ( struct acpi_device * device ) ;
static int acpi_fan_remove ( struct acpi_device * device , int type ) ;
2008-01-24 06:41:20 +03:00
static int acpi_fan_suspend ( struct acpi_device * device , pm_message_t state ) ;
static int acpi_fan_resume ( struct acpi_device * device ) ;
2005-04-17 02:20:36 +04:00
2007-07-23 16:44:41 +04:00
static const struct acpi_device_id fan_device_ids [ ] = {
{ " PNP0C0B " , 0 } ,
{ " " , 0 } ,
} ;
MODULE_DEVICE_TABLE ( acpi , fan_device_ids ) ;
2005-04-17 02:20:36 +04:00
static struct acpi_driver acpi_fan_driver = {
2007-02-13 07:33:40 +03:00
. name = " fan " ,
2005-08-05 08:44:28 +04:00
. class = ACPI_FAN_CLASS ,
2007-07-23 16:44:41 +04:00
. ids = fan_device_ids ,
2005-08-05 08:44:28 +04:00
. ops = {
. add = acpi_fan_add ,
. remove = acpi_fan_remove ,
2008-01-24 06:41:20 +03:00
. suspend = acpi_fan_suspend ,
. resume = acpi_fan_resume ,
2005-08-05 08:44:28 +04:00
} ,
2005-04-17 02:20:36 +04:00
} ;
2008-01-17 10:51:24 +03:00
/* thermal cooling device callbacks */
2008-11-27 20:48:13 +03:00
static int fan_get_max_state ( struct thermal_cooling_device * cdev , unsigned long
* state )
2008-01-17 10:51:24 +03:00
{
/* ACPI fan device only support two states: ON/OFF */
2008-11-27 20:48:13 +03:00
* state = 1 ;
return 0 ;
2008-01-17 10:51:24 +03:00
}
2008-11-27 20:48:13 +03:00
static int fan_get_cur_state ( struct thermal_cooling_device * cdev , unsigned long
* state )
2008-01-17 10:51:24 +03:00
{
struct acpi_device * device = cdev - > devdata ;
int result ;
2008-11-27 20:48:13 +03:00
int acpi_state ;
2008-01-17 10:51:24 +03:00
if ( ! device )
return - EINVAL ;
2008-11-27 20:48:13 +03:00
result = acpi_bus_get_power ( device - > handle , & acpi_state ) ;
2008-01-17 10:51:24 +03:00
if ( result )
return result ;
2008-11-27 20:48:13 +03:00
* state = ( acpi_state = = ACPI_STATE_D3 ? 0 :
( acpi_state = = ACPI_STATE_D0 ? 1 : - 1 ) ) ;
return 0 ;
2008-01-17 10:51:24 +03:00
}
static int
2008-11-27 20:48:13 +03:00
fan_set_cur_state ( struct thermal_cooling_device * cdev , unsigned long state )
2008-01-17 10:51:24 +03:00
{
struct acpi_device * device = cdev - > devdata ;
int result ;
if ( ! device | | ( state ! = 0 & & state ! = 1 ) )
return - EINVAL ;
result = acpi_bus_set_power ( device - > handle ,
state ? ACPI_STATE_D0 : ACPI_STATE_D3 ) ;
return result ;
}
static struct thermal_cooling_device_ops fan_cooling_ops = {
. get_max_state = fan_get_max_state ,
. get_cur_state = fan_get_cur_state ,
. set_cur_state = fan_set_cur_state ,
} ;
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
FS Interface ( / proc )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2008-01-17 10:51:24 +03:00
# ifdef CONFIG_ACPI_PROCFS
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
static struct proc_dir_entry * acpi_fan_dir ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
static int acpi_fan_read_state ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2007-10-22 14:19:15 +04:00
struct acpi_device * device = seq - > private ;
2005-08-05 08:44:28 +04:00
int state = 0 ;
2005-04-17 02:20:36 +04:00
2007-10-22 14:19:15 +04:00
if ( device ) {
if ( acpi_bus_get_power ( device - > handle , & state ) )
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " status: ERROR \n " ) ;
else
seq_printf ( seq , " status: %s \n " ,
2005-08-05 08:44:28 +04:00
! state ? " on " : " off " ) ;
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
}
static int acpi_fan_state_open_fs ( struct inode * inode , struct file * file )
{
return single_open ( file , acpi_fan_read_state , PDE ( inode ) - > data ) ;
}
static ssize_t
2005-08-05 08:44:28 +04:00
acpi_fan_write_state ( struct file * file , const char __user * buffer ,
size_t count , loff_t * ppos )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
2006-10-01 02:28:50 +04:00
struct seq_file * m = file - > private_data ;
2007-10-22 14:19:15 +04:00
struct acpi_device * device = m - > private ;
ACPI: fix acpi fan state set error
Under /proc/acpi, there is a fan control interface, a user can
set 0 or 3 to /proc/acpi/fan/*/state, 0 denotes D0 state, 3
denotes D3 state, but in current implementation, a user can
set a fan to D1 state by any char excluding '1', '2' and '3'.
For example:
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost acpi]# echo "3" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "xxxxx" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: on
Obviously, such inputs as "" and "xxxxx" are invalid for fan state.
This patch fixes this issue, it strictly limits fan state only to
accept 0, 1, 2 and 3, any other inputs are invalid.
Before applying this patch, the test result is:
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost acpi]# echo "3" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "xxxxx" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost acpi]# echo "3" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "3x" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "-1x" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost acpi]#
After applying this patch, the test result is:
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "" > /proc/acpi/fan/C31B/state
-bash: echo: write error: Invalid argument
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "3" > /proc/acpi/fan/C31B/state
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "xxxxx" > /proc/acpi/fan/C31B/state
-bash: echo: write error: Invalid argument
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "-1x" > /proc/acpi/fan/C31B/state
-bash: echo: write error: Invalid argument
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "0" > //proc/acpi/fan/C31B/state
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost ~]# echo "4" > //proc/acpi/fan/C31B/state
-bash: echo: write error: Invalid argument
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost ~]# echo "3" > //proc/acpi/fan/C31B/state
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "0" > //proc/acpi/fan/C31B/state
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost ~]# echo "3x" > //proc/acpi/fan/C31B/state
-bash: echo: write error: Invalid argument
[root@localhost ~]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2008-06-14 08:52:06 +04:00
char state_string [ 3 ] = { ' \0 ' } ;
2005-04-17 02:20:36 +04:00
2007-10-22 14:19:15 +04:00
if ( count > sizeof ( state_string ) - 1 )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( state_string , buffer , count ) )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
state_string [ count ] = ' \0 ' ;
ACPI: fix acpi fan state set error
Under /proc/acpi, there is a fan control interface, a user can
set 0 or 3 to /proc/acpi/fan/*/state, 0 denotes D0 state, 3
denotes D3 state, but in current implementation, a user can
set a fan to D1 state by any char excluding '1', '2' and '3'.
For example:
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost acpi]# echo "3" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "xxxxx" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: on
Obviously, such inputs as "" and "xxxxx" are invalid for fan state.
This patch fixes this issue, it strictly limits fan state only to
accept 0, 1, 2 and 3, any other inputs are invalid.
Before applying this patch, the test result is:
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost acpi]# echo "3" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "xxxxx" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost acpi]# echo "3" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "3x" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost acpi]# echo "-1x" > /proc/acpi/fan/C31B/state
[root@localhost acpi]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost acpi]#
After applying this patch, the test result is:
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "" > /proc/acpi/fan/C31B/state
-bash: echo: write error: Invalid argument
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "3" > /proc/acpi/fan/C31B/state
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "xxxxx" > /proc/acpi/fan/C31B/state
-bash: echo: write error: Invalid argument
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "-1x" > /proc/acpi/fan/C31B/state
-bash: echo: write error: Invalid argument
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "0" > //proc/acpi/fan/C31B/state
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost ~]# echo "4" > //proc/acpi/fan/C31B/state
-bash: echo: write error: Invalid argument
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost ~]# echo "3" > //proc/acpi/fan/C31B/state
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: off
[root@localhost ~]# echo "0" > //proc/acpi/fan/C31B/state
[root@localhost ~]# cat /proc/acpi/fan/C31B/state
status: on
[root@localhost ~]# echo "3x" > //proc/acpi/fan/C31B/state
-bash: echo: write error: Invalid argument
[root@localhost ~]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2008-06-14 08:52:06 +04:00
if ( ( state_string [ 0 ] < ' 0 ' ) | | ( state_string [ 0 ] > ' 3 ' ) )
return - EINVAL ;
if ( state_string [ 1 ] = = ' \n ' )
state_string [ 1 ] = ' \0 ' ;
if ( state_string [ 1 ] ! = ' \0 ' )
return - EINVAL ;
2005-08-05 08:44:28 +04:00
2007-10-22 14:19:15 +04:00
result = acpi_bus_set_power ( device - > handle ,
2005-08-05 08:44:28 +04:00
simple_strtoul ( state_string , NULL , 0 ) ) ;
2005-04-17 02:20:36 +04:00
if ( result )
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return count ;
2005-04-17 02:20:36 +04:00
}
2006-07-04 21:06:00 +04:00
static const struct file_operations acpi_fan_state_ops = {
2005-08-05 08:44:28 +04:00
. open = acpi_fan_state_open_fs ,
. read = seq_read ,
. write = acpi_fan_write_state ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
} ;
2005-08-05 08:44:28 +04:00
static int acpi_fan_add_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct proc_dir_entry * entry = NULL ;
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
if ( ! acpi_device_dir ( device ) ) {
acpi_device_dir ( device ) = proc_mkdir ( acpi_device_bid ( device ) ,
2005-08-05 08:44:28 +04:00
acpi_fan_dir ) ;
2005-04-17 02:20:36 +04:00
if ( ! acpi_device_dir ( device ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
/* 'status' [R/W] */
2008-04-29 12:02:27 +04:00
entry = proc_create_data ( ACPI_FAN_FILE_STATE ,
S_IFREG | S_IRUGO | S_IWUSR ,
acpi_device_dir ( device ) ,
& acpi_fan_state_ops ,
device ) ;
2005-04-17 02:20:36 +04:00
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_fan_remove_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
if ( acpi_device_dir ( device ) ) {
2005-08-05 08:44:28 +04:00
remove_proc_entry ( ACPI_FAN_FILE_STATE , acpi_device_dir ( device ) ) ;
2005-04-17 02:20:36 +04:00
remove_proc_entry ( acpi_device_bid ( device ) , acpi_fan_dir ) ;
acpi_device_dir ( device ) = NULL ;
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-01-17 10:51:24 +03:00
# else
static int acpi_fan_add_fs ( struct acpi_device * device )
{
return 0 ;
}
2005-04-17 02:20:36 +04:00
2008-01-17 10:51:24 +03:00
static int acpi_fan_remove_fs ( struct acpi_device * device )
{
return 0 ;
}
# endif
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Driver Interface
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-05 08:44:28 +04:00
static int acpi_fan_add ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
int state = 0 ;
2008-01-17 10:51:24 +03:00
struct thermal_cooling_device * cdev ;
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
2005-08-05 08:37:45 +04:00
strcpy ( acpi_device_name ( device ) , " Fan " ) ;
2005-04-17 02:20:36 +04:00
strcpy ( acpi_device_class ( device ) , ACPI_FAN_CLASS ) ;
2006-05-20 00:54:42 +04:00
result = acpi_bus_get_power ( device - > handle , & state ) ;
2005-04-17 02:20:36 +04:00
if ( result ) {
2006-06-27 07:41:38 +04:00
printk ( KERN_ERR PREFIX " Reading power state \n " ) ;
2005-04-17 02:20:36 +04:00
goto end ;
}
2008-01-24 06:41:20 +03:00
device - > flags . force_power_state = 1 ;
acpi_bus_set_power ( device - > handle , state ) ;
device - > flags . force_power_state = 0 ;
2008-01-17 10:51:24 +03:00
cdev = thermal_cooling_device_register ( " Fan " , device ,
& fan_cooling_ops ) ;
2008-02-15 09:01:52 +03:00
if ( IS_ERR ( cdev ) ) {
result = PTR_ERR ( cdev ) ;
goto end ;
}
2008-04-11 06:09:24 +04:00
2009-12-15 00:38:30 +03:00
dev_dbg ( & device - > dev , " registered as cooling_device%d \n " , cdev - > id ) ;
2008-04-11 06:09:24 +04:00
2008-09-23 01:37:34 +04:00
device - > driver_data = cdev ;
2008-04-11 06:09:24 +04:00
result = sysfs_create_link ( & device - > dev . kobj ,
& cdev - > device . kobj ,
" thermal_cooling " ) ;
if ( result )
2008-05-02 08:02:41 +04:00
dev_err ( & device - > dev , " Failed to create sysfs link "
" 'thermal_cooling' \n " ) ;
2008-04-11 06:09:24 +04:00
result = sysfs_create_link ( & cdev - > device . kobj ,
& device - > dev . kobj ,
" device " ) ;
if ( result )
2008-05-02 08:02:41 +04:00
dev_err ( & device - > dev , " Failed to create sysfs link "
" 'device' \n " ) ;
2008-01-17 10:51:24 +03:00
2005-04-17 02:20:36 +04:00
result = acpi_fan_add_fs ( device ) ;
if ( result )
goto end ;
printk ( KERN_INFO PREFIX " %s [%s] (%s) \n " ,
2005-08-05 08:44:28 +04:00
acpi_device_name ( device ) , acpi_device_bid ( device ) ,
! device - > power . state ? " on " : " off " ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
end :
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_fan_remove ( struct acpi_device * device , int type )
2005-04-17 02:20:36 +04:00
{
2008-01-17 10:51:24 +03:00
struct thermal_cooling_device * cdev = acpi_driver_data ( device ) ;
if ( ! device | | ! cdev )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
acpi_fan_remove_fs ( device ) ;
2008-01-17 10:51:24 +03:00
sysfs_remove_link ( & device - > dev . kobj , " thermal_cooling " ) ;
sysfs_remove_link ( & cdev - > device . kobj , " device " ) ;
thermal_cooling_device_unregister ( cdev ) ;
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
}
2008-01-24 06:41:20 +03:00
static int acpi_fan_suspend ( struct acpi_device * device , pm_message_t state )
{
if ( ! device )
return - EINVAL ;
acpi_bus_set_power ( device - > handle , ACPI_STATE_D0 ) ;
return AE_OK ;
}
static int acpi_fan_resume ( struct acpi_device * device )
{
int result = 0 ;
int power_state = 0 ;
if ( ! device )
return - EINVAL ;
result = acpi_bus_get_power ( device - > handle , & power_state ) ;
if ( result ) {
2008-09-28 10:51:56 +04:00
printk ( KERN_ERR PREFIX
" Error reading fan power state \n " ) ;
2008-01-24 06:41:20 +03:00
return result ;
}
device - > flags . force_power_state = 1 ;
acpi_bus_set_power ( device - > handle , power_state ) ;
device - > flags . force_power_state = 0 ;
return result ;
}
2005-08-05 08:44:28 +04:00
static int __init acpi_fan_init ( void )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:37:45 +04:00
int result = 0 ;
2005-04-17 02:20:36 +04:00
2008-02-02 12:05:54 +03:00
# ifdef CONFIG_ACPI_PROCFS
2005-04-17 02:20:36 +04:00
acpi_fan_dir = proc_mkdir ( ACPI_FAN_CLASS , acpi_root_dir ) ;
if ( ! acpi_fan_dir )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2008-02-02 12:05:54 +03:00
# endif
2005-04-17 02:20:36 +04:00
result = acpi_bus_register_driver ( & acpi_fan_driver ) ;
if ( result < 0 ) {
2010-06-10 09:42:49 +04:00
# ifdef CONFIG_ACPI_PROCFS
2005-04-17 02:20:36 +04:00
remove_proc_entry ( ACPI_FAN_CLASS , acpi_root_dir ) ;
2010-06-10 09:42:49 +04:00
# endif
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_fan_exit ( void )
2005-04-17 02:20:36 +04:00
{
acpi_bus_unregister_driver ( & acpi_fan_driver ) ;
2010-07-07 22:30:15 +04:00
# ifdef CONFIG_ACPI_PROCFS
2005-04-17 02:20:36 +04:00
remove_proc_entry ( ACPI_FAN_CLASS , acpi_root_dir ) ;
2010-07-07 22:30:15 +04:00
# endif
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
module_init ( acpi_fan_init ) ;
module_exit ( acpi_fan_exit ) ;