2005-04-17 02:20:36 +04:00
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
2011-10-27 00:22:14 +04:00
# include <linux/export.h>
2005-04-17 02:20:36 +04:00
# include <linux/suspend.h>
# include <linux/bcd.h>
# include <asm/uaccess.h>
# include <acpi/acpi_bus.h>
# include <acpi/acpi_drivers.h>
# ifdef CONFIG_X86
# include <linux/mc146818rtc.h>
# endif
# include "sleep.h"
# define _COMPONENT ACPI_SYSTEM_COMPONENT
2007-07-24 10:16:50 +04:00
/*
* this file provides support for :
* / proc / acpi / alarm
* / proc / acpi / wakeup
*/
2005-08-05 08:44:28 +04:00
ACPI_MODULE_NAME ( " sleep " )
2005-04-17 02:20:36 +04:00
2007-07-28 11:33:16 +04:00
# if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || !defined(CONFIG_X86)
2007-05-08 11:34:02 +04:00
/* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */
# else
# define HAVE_ACPI_LEGACY_ALARM
# endif
# ifdef HAVE_ACPI_LEGACY_ALARM
2009-01-09 10:10:16 +03:00
static u32 cmos_bcd_read ( int offset , int rtc_control ) ;
2005-04-17 02:20:36 +04:00
static int acpi_system_alarm_seq_show ( struct seq_file * seq , void * offset )
{
2005-08-05 08:44:28 +04:00
u32 sec , min , hr ;
2007-02-02 19:48:19 +03:00
u32 day , mo , yr , cent = 0 ;
2008-12-09 18:46:30 +03:00
u32 today = 0 ;
2005-08-05 08:44:28 +04:00
unsigned char rtc_control = 0 ;
unsigned long flags ;
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & rtc_lock , flags ) ;
rtc_control = CMOS_READ ( RTC_CONTROL ) ;
2008-12-09 18:46:30 +03:00
sec = cmos_bcd_read ( RTC_SECONDS_ALARM , rtc_control ) ;
min = cmos_bcd_read ( RTC_MINUTES_ALARM , rtc_control ) ;
hr = cmos_bcd_read ( RTC_HOURS_ALARM , rtc_control ) ;
2005-04-17 02:20:36 +04:00
/* If we ever get an FACP with proper values... */
2008-12-09 18:46:30 +03:00
if ( acpi_gbl_FADT . day_alarm ) {
2005-04-17 02:20:36 +04:00
/* ACPI spec: only low 6 its should be cared */
2007-02-02 19:48:19 +03:00
day = CMOS_READ ( acpi_gbl_FADT . day_alarm ) & 0x3F ;
2008-12-09 18:46:30 +03:00
if ( ! ( rtc_control & RTC_DM_BINARY ) | | RTC_ALWAYS_BCD )
day = bcd2bin ( day ) ;
} else
day = cmos_bcd_read ( RTC_DAY_OF_MONTH , rtc_control ) ;
2007-02-02 19:48:19 +03:00
if ( acpi_gbl_FADT . month_alarm )
2008-12-09 18:46:30 +03:00
mo = cmos_bcd_read ( acpi_gbl_FADT . month_alarm , rtc_control ) ;
else {
mo = cmos_bcd_read ( RTC_MONTH , rtc_control ) ;
today = cmos_bcd_read ( RTC_DAY_OF_MONTH , rtc_control ) ;
}
2007-02-02 19:48:19 +03:00
if ( acpi_gbl_FADT . century )
2008-12-09 18:46:30 +03:00
cent = cmos_bcd_read ( acpi_gbl_FADT . century , rtc_control ) ;
2007-02-02 19:48:19 +03:00
2008-12-09 18:46:30 +03:00
yr = cmos_bcd_read ( RTC_YEAR , rtc_control ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & rtc_lock , flags ) ;
2005-08-05 08:44:28 +04:00
/* we're trusting the FADT (see above) */
2007-02-02 19:48:19 +03:00
if ( ! acpi_gbl_FADT . century )
2005-08-05 08:44:28 +04:00
/* If we're not trusting the FADT, we should at least make it
* right for _this_ century . . . ehm , what is _this_ century ?
*
* TBD :
* ASAP : find piece of code in the kernel , e . g . star tracker driver ,
* which we can trust to determine the century correctly . Atom
* watch driver would be nice , too . . .
*
* if that has not happened , change for first release in 2050 :
* if ( yr < 50 )
* yr + = 2100 ;
* else
* yr + = 2000 ; // current line of code
*
* if that has not happened either , please do on 2099 / 12 / 31 : 23 : 59 : 59
* s / 2000 / 2100
*
*/
2005-04-17 02:20:36 +04:00
yr + = 2000 ;
2007-02-02 19:48:19 +03:00
else
yr + = cent * 100 ;
2005-04-17 02:20:36 +04:00
2008-12-09 18:46:30 +03:00
/*
* Show correct dates for alarms up to a month into the future .
* This solves issues for nearly all situations with the common
* 30 - day alarm clocks in PC hardware .
*/
if ( day < today ) {
if ( mo < 12 ) {
mo + = 1 ;
} else {
mo = 1 ;
yr + = 1 ;
}
}
2005-08-05 08:44:28 +04:00
seq_printf ( seq , " %4.4u- " , yr ) ;
( mo > 12 ) ? seq_puts ( seq , " **- " ) : seq_printf ( seq , " %2.2u- " , mo ) ;
( day > 31 ) ? seq_puts ( seq , " ** " ) : seq_printf ( seq , " %2.2u " , day ) ;
( hr > 23 ) ? seq_puts ( seq , " **: " ) : seq_printf ( seq , " %2.2u: " , hr ) ;
( min > 59 ) ? seq_puts ( seq , " **: " ) : seq_printf ( seq , " %2.2u: " , min ) ;
2005-04-17 02:20:36 +04:00
( sec > 59 ) ? seq_puts ( seq , " ** \n " ) : seq_printf ( seq , " %2.2u \n " , sec ) ;
return 0 ;
}
static int acpi_system_alarm_open_fs ( struct inode * inode , struct file * file )
{
2013-04-01 02:16:14 +04:00
return single_open ( file , acpi_system_alarm_seq_show , PDE_DATA ( inode ) ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int get_date_field ( char * * p , u32 * value )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
char * next = NULL ;
char * string_end = NULL ;
int result = - EINVAL ;
2005-04-17 02:20:36 +04:00
/*
* Try to find delimeter , only to insert null . The end of the
* string won ' t have one , but is still valid .
*/
2007-12-28 05:50:42 +03:00
if ( * p = = NULL )
return result ;
2005-04-17 02:20:36 +04:00
next = strpbrk ( * p , " - : " ) ;
if ( next )
* next + + = ' \0 ' ;
* value = simple_strtoul ( * p , & string_end , 10 ) ;
/* Signal success if we got a good digit */
if ( string_end ! = * p )
result = 0 ;
if ( next )
* p = next ;
2007-12-28 05:50:42 +03:00
else
* p = NULL ;
2005-04-17 02:20:36 +04:00
return result ;
}
2007-10-18 07:18:32 +04:00
/* Read a possibly BCD register, always return binary */
static u32 cmos_bcd_read ( int offset , int rtc_control )
{
u32 val = CMOS_READ ( offset ) ;
if ( ! ( rtc_control & RTC_DM_BINARY ) | | RTC_ALWAYS_BCD )
2008-10-19 07:28:39 +04:00
val = bcd2bin ( val ) ;
2007-10-18 07:18:32 +04:00
return val ;
}
/* Write binary value into possibly BCD register */
static void cmos_bcd_write ( u32 val , int offset , int rtc_control )
{
if ( ! ( rtc_control & RTC_DM_BINARY ) | | RTC_ALWAYS_BCD )
2008-10-19 07:28:39 +04:00
val = bin2bcd ( val ) ;
2007-10-18 07:18:32 +04:00
CMOS_WRITE ( val , offset ) ;
}
2005-04-17 02:20:36 +04:00
static ssize_t
2005-08-05 08:44:28 +04:00
acpi_system_write_alarm ( 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 ;
char alarm_string [ 30 ] = { ' \0 ' } ;
char * p = alarm_string ;
u32 sec , min , hr , day , mo , yr ;
int adjust = 0 ;
unsigned char rtc_control = 0 ;
2005-04-17 02:20:36 +04:00
if ( count > sizeof ( alarm_string ) - 1 )
2008-12-16 11:49:26 +03:00
return - EINVAL ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( alarm_string , buffer , count ) )
2008-12-16 11:49:26 +03:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
alarm_string [ count ] = ' \0 ' ;
/* check for time adjustment */
if ( alarm_string [ 0 ] = = ' + ' ) {
p + + ;
adjust = 1 ;
}
if ( ( result = get_date_field ( & p , & yr ) ) )
goto end ;
if ( ( result = get_date_field ( & p , & mo ) ) )
goto end ;
if ( ( result = get_date_field ( & p , & day ) ) )
goto end ;
if ( ( result = get_date_field ( & p , & hr ) ) )
goto end ;
if ( ( result = get_date_field ( & p , & min ) ) )
goto end ;
if ( ( result = get_date_field ( & p , & sec ) ) )
goto end ;
spin_lock_irq ( & rtc_lock ) ;
rtc_control = CMOS_READ ( RTC_CONTROL ) ;
if ( adjust ) {
2007-10-18 07:18:32 +04:00
yr + = cmos_bcd_read ( RTC_YEAR , rtc_control ) ;
mo + = cmos_bcd_read ( RTC_MONTH , rtc_control ) ;
day + = cmos_bcd_read ( RTC_DAY_OF_MONTH , rtc_control ) ;
hr + = cmos_bcd_read ( RTC_HOURS , rtc_control ) ;
min + = cmos_bcd_read ( RTC_MINUTES , rtc_control ) ;
sec + = cmos_bcd_read ( RTC_SECONDS , rtc_control ) ;
2005-04-17 02:20:36 +04:00
}
spin_unlock_irq ( & rtc_lock ) ;
if ( sec > 59 ) {
ACPI: /proc/acpi/alarm parsing: handle large numbers properly
In function acpi_system_write_alarm in file drivers/acpi/sleep/proc.c,
big sec, min, hr, mo, day and yr are counted twice to get reasonable
values, that is very superfluous, we can do that only once.
In additon, /proc/acpi/alarm can set a related value which can be
specified as YYYY years MM months DD days HH hours MM minutes SS
senconds, it isn't a date, so you can specify as +0000-00-00 96:00:00
, that means 3 days later, current code can't handle such a case.
This patch removes unnecessary code and does with the aforementioned
situation.
Before applying this patch:
[root@localhost /]# cat /proc/acpi/alarm
2007-12-00 00:00:00
[root@localhost /]# echo "0000-00-00 96:180:180" > /proc/acpi/alarm
[root@localhost /]# cat /proc/acpi/alarm
0007-12-02 **:**:**
[root@localhost /]#
After applying this patch:
[root@localhost ~]# echo "2007-12-00 00:00:00" > /proc/acpi/alarm
[root@localhost ~]# cat /proc/acpi/alarm
2007-12-00 00:00:00
[root@localhost ~]# echo "0000-00-00 96:180:180" > /proc/acpi/alarm
[root@localhost ~]# cat /proc/acpi/alarm
0007-12-04 03:03:00
[root@localhost ~]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2007-12-28 06:04:26 +03:00
min + = sec / 60 ;
sec = sec % 60 ;
2005-04-17 02:20:36 +04:00
}
if ( min > 59 ) {
ACPI: /proc/acpi/alarm parsing: handle large numbers properly
In function acpi_system_write_alarm in file drivers/acpi/sleep/proc.c,
big sec, min, hr, mo, day and yr are counted twice to get reasonable
values, that is very superfluous, we can do that only once.
In additon, /proc/acpi/alarm can set a related value which can be
specified as YYYY years MM months DD days HH hours MM minutes SS
senconds, it isn't a date, so you can specify as +0000-00-00 96:00:00
, that means 3 days later, current code can't handle such a case.
This patch removes unnecessary code and does with the aforementioned
situation.
Before applying this patch:
[root@localhost /]# cat /proc/acpi/alarm
2007-12-00 00:00:00
[root@localhost /]# echo "0000-00-00 96:180:180" > /proc/acpi/alarm
[root@localhost /]# cat /proc/acpi/alarm
0007-12-02 **:**:**
[root@localhost /]#
After applying this patch:
[root@localhost ~]# echo "2007-12-00 00:00:00" > /proc/acpi/alarm
[root@localhost ~]# cat /proc/acpi/alarm
2007-12-00 00:00:00
[root@localhost ~]# echo "0000-00-00 96:180:180" > /proc/acpi/alarm
[root@localhost ~]# cat /proc/acpi/alarm
0007-12-04 03:03:00
[root@localhost ~]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2007-12-28 06:04:26 +03:00
hr + = min / 60 ;
min = min % 60 ;
2005-04-17 02:20:36 +04:00
}
if ( hr > 23 ) {
ACPI: /proc/acpi/alarm parsing: handle large numbers properly
In function acpi_system_write_alarm in file drivers/acpi/sleep/proc.c,
big sec, min, hr, mo, day and yr are counted twice to get reasonable
values, that is very superfluous, we can do that only once.
In additon, /proc/acpi/alarm can set a related value which can be
specified as YYYY years MM months DD days HH hours MM minutes SS
senconds, it isn't a date, so you can specify as +0000-00-00 96:00:00
, that means 3 days later, current code can't handle such a case.
This patch removes unnecessary code and does with the aforementioned
situation.
Before applying this patch:
[root@localhost /]# cat /proc/acpi/alarm
2007-12-00 00:00:00
[root@localhost /]# echo "0000-00-00 96:180:180" > /proc/acpi/alarm
[root@localhost /]# cat /proc/acpi/alarm
0007-12-02 **:**:**
[root@localhost /]#
After applying this patch:
[root@localhost ~]# echo "2007-12-00 00:00:00" > /proc/acpi/alarm
[root@localhost ~]# cat /proc/acpi/alarm
2007-12-00 00:00:00
[root@localhost ~]# echo "0000-00-00 96:180:180" > /proc/acpi/alarm
[root@localhost ~]# cat /proc/acpi/alarm
0007-12-04 03:03:00
[root@localhost ~]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2007-12-28 06:04:26 +03:00
day + = hr / 24 ;
hr = hr % 24 ;
2005-04-17 02:20:36 +04:00
}
if ( day > 31 ) {
ACPI: /proc/acpi/alarm parsing: handle large numbers properly
In function acpi_system_write_alarm in file drivers/acpi/sleep/proc.c,
big sec, min, hr, mo, day and yr are counted twice to get reasonable
values, that is very superfluous, we can do that only once.
In additon, /proc/acpi/alarm can set a related value which can be
specified as YYYY years MM months DD days HH hours MM minutes SS
senconds, it isn't a date, so you can specify as +0000-00-00 96:00:00
, that means 3 days later, current code can't handle such a case.
This patch removes unnecessary code and does with the aforementioned
situation.
Before applying this patch:
[root@localhost /]# cat /proc/acpi/alarm
2007-12-00 00:00:00
[root@localhost /]# echo "0000-00-00 96:180:180" > /proc/acpi/alarm
[root@localhost /]# cat /proc/acpi/alarm
0007-12-02 **:**:**
[root@localhost /]#
After applying this patch:
[root@localhost ~]# echo "2007-12-00 00:00:00" > /proc/acpi/alarm
[root@localhost ~]# cat /proc/acpi/alarm
2007-12-00 00:00:00
[root@localhost ~]# echo "0000-00-00 96:180:180" > /proc/acpi/alarm
[root@localhost ~]# cat /proc/acpi/alarm
0007-12-04 03:03:00
[root@localhost ~]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2007-12-28 06:04:26 +03:00
mo + = day / 32 ;
day = day % 32 ;
2005-04-17 02:20:36 +04:00
}
if ( mo > 12 ) {
ACPI: /proc/acpi/alarm parsing: handle large numbers properly
In function acpi_system_write_alarm in file drivers/acpi/sleep/proc.c,
big sec, min, hr, mo, day and yr are counted twice to get reasonable
values, that is very superfluous, we can do that only once.
In additon, /proc/acpi/alarm can set a related value which can be
specified as YYYY years MM months DD days HH hours MM minutes SS
senconds, it isn't a date, so you can specify as +0000-00-00 96:00:00
, that means 3 days later, current code can't handle such a case.
This patch removes unnecessary code and does with the aforementioned
situation.
Before applying this patch:
[root@localhost /]# cat /proc/acpi/alarm
2007-12-00 00:00:00
[root@localhost /]# echo "0000-00-00 96:180:180" > /proc/acpi/alarm
[root@localhost /]# cat /proc/acpi/alarm
0007-12-02 **:**:**
[root@localhost /]#
After applying this patch:
[root@localhost ~]# echo "2007-12-00 00:00:00" > /proc/acpi/alarm
[root@localhost ~]# cat /proc/acpi/alarm
2007-12-00 00:00:00
[root@localhost ~]# echo "0000-00-00 96:180:180" > /proc/acpi/alarm
[root@localhost ~]# cat /proc/acpi/alarm
0007-12-04 03:03:00
[root@localhost ~]#
Signed-off-by: Yi Yang <yi.y.yang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2007-12-28 06:04:26 +03:00
yr + = mo / 13 ;
mo = mo % 13 ;
2005-04-17 02:20:36 +04:00
}
spin_lock_irq ( & rtc_lock ) ;
/*
* Disable alarm interrupt before setting alarm timer or else
* when ACPI_EVENT_RTC is enabled , a spurious ACPI interrupt occurs
*/
rtc_control & = ~ RTC_AIE ;
CMOS_WRITE ( rtc_control , RTC_CONTROL ) ;
CMOS_READ ( RTC_INTR_FLAGS ) ;
/* write the fields the rtc knows about */
2007-10-18 07:18:32 +04:00
cmos_bcd_write ( hr , RTC_HOURS_ALARM , rtc_control ) ;
cmos_bcd_write ( min , RTC_MINUTES_ALARM , rtc_control ) ;
cmos_bcd_write ( sec , RTC_SECONDS_ALARM , rtc_control ) ;
2005-04-17 02:20:36 +04:00
/*
* If the system supports an enhanced alarm it will have non - zero
* offsets into the CMOS RAM here - - which for some reason are pointing
* to the RTC area of memory .
*/
2007-02-02 19:48:19 +03:00
if ( acpi_gbl_FADT . day_alarm )
2007-10-18 07:18:32 +04:00
cmos_bcd_write ( day , acpi_gbl_FADT . day_alarm , rtc_control ) ;
2007-02-02 19:48:19 +03:00
if ( acpi_gbl_FADT . month_alarm )
2007-10-18 07:18:32 +04:00
cmos_bcd_write ( mo , acpi_gbl_FADT . month_alarm , rtc_control ) ;
2008-07-04 20:59:31 +04:00
if ( acpi_gbl_FADT . century ) {
if ( adjust )
yr + = cmos_bcd_read ( acpi_gbl_FADT . century , rtc_control ) * 100 ;
2007-10-18 07:18:32 +04:00
cmos_bcd_write ( yr / 100 , acpi_gbl_FADT . century , rtc_control ) ;
2008-07-04 20:59:31 +04:00
}
2005-04-17 02:20:36 +04:00
/* enable the rtc alarm interrupt */
rtc_control | = RTC_AIE ;
CMOS_WRITE ( rtc_control , RTC_CONTROL ) ;
CMOS_READ ( RTC_INTR_FLAGS ) ;
spin_unlock_irq ( & rtc_lock ) ;
acpi_clear_event ( ACPI_EVENT_RTC ) ;
acpi_enable_event ( ACPI_EVENT_RTC , 0 ) ;
* ppos + = count ;
result = 0 ;
2005-08-05 08:44:28 +04:00
end :
2008-12-16 11:49:26 +03:00
return result ? result : count ;
2005-04-17 02:20:36 +04:00
}
2007-05-10 07:34:35 +04:00
# endif /* HAVE_ACPI_LEGACY_ALARM */
2005-04-17 02:20:36 +04:00
static int
acpi_system_wakeup_device_seq_show ( struct seq_file * seq , void * offset )
{
2005-08-05 08:44:28 +04:00
struct list_head * node , * next ;
2005-04-17 02:20:36 +04:00
2007-04-25 23:20:10 +04:00
seq_printf ( seq , " Device \t S-state \t Status Sysfs node \n " ) ;
2005-04-17 02:20:36 +04:00
2009-04-07 06:24:29 +04:00
mutex_lock ( & acpi_device_lock ) ;
2005-04-17 02:20:36 +04:00
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2005-08-05 08:44:28 +04:00
struct acpi_device * dev =
container_of ( node , struct acpi_device , wakeup_list ) ;
2012-08-17 10:44:09 +04:00
struct acpi_device_physical_node * entry ;
2005-04-17 02:20:36 +04:00
if ( ! dev - > wakeup . flags . valid )
continue ;
2007-04-25 23:20:10 +04:00
2012-08-17 10:44:09 +04:00
seq_printf ( seq , " %s \t S%d \t " ,
2005-08-05 08:44:28 +04:00
dev - > pnp . bus_id ,
2012-08-17 10:44:09 +04:00
( u32 ) dev - > wakeup . sleep_state ) ;
2013-01-27 18:17:55 +04:00
if ( ! dev - > physical_node_count ) {
2012-08-17 10:44:09 +04:00
seq_printf ( seq , " %c%-8s \n " ,
2013-01-27 18:17:55 +04:00
dev - > wakeup . flags . run_wake ? ' * ' : ' ' ,
device_may_wakeup ( & dev - > dev ) ?
" enabled " : " disabled " ) ;
} else {
2012-08-17 10:44:09 +04:00
struct device * ldev ;
list_for_each_entry ( entry , & dev - > physical_node_list ,
node ) {
ldev = get_device ( entry - > dev ) ;
if ( ! ldev )
continue ;
if ( & entry - > node ! =
dev - > physical_node_list . next )
seq_printf ( seq , " \t \t " ) ;
seq_printf ( seq , " %c%-8s %s:%s \n " ,
dev - > wakeup . flags . run_wake ? ' * ' : ' ' ,
( device_may_wakeup ( & dev - > dev ) | |
( ldev & & device_may_wakeup ( ldev ) ) ) ?
" enabled " : " disabled " ,
ldev - > bus ? ldev - > bus - > name :
" no-bus " , dev_name ( ldev ) ) ;
put_device ( ldev ) ;
}
}
2005-04-17 02:20:36 +04:00
}
2009-04-07 06:24:29 +04:00
mutex_unlock ( & acpi_device_lock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-10-04 02:23:49 +04:00
static void physical_device_enable_wakeup ( struct acpi_device * adev )
{
2012-08-17 10:44:09 +04:00
struct acpi_device_physical_node * entry ;
2008-10-04 02:23:49 +04:00
2012-08-17 10:44:09 +04:00
list_for_each_entry ( entry ,
& adev - > physical_node_list , node )
if ( entry - > dev & & device_can_wakeup ( entry - > dev ) ) {
bool enable = ! device_may_wakeup ( entry - > dev ) ;
device_set_wakeup_enable ( entry - > dev , enable ) ;
}
2008-10-04 02:23:49 +04:00
}
2005-04-17 02:20:36 +04:00
static ssize_t
2005-08-05 08:44:28 +04:00
acpi_system_write_wakeup_device ( 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
struct list_head * node , * next ;
char strbuf [ 5 ] ;
char str [ 5 ] = " " ;
2005-04-17 02:20:36 +04:00
2012-11-23 02:20:31 +04:00
if ( count > 4 )
count = 4 ;
2005-04-17 02:20:36 +04:00
2012-11-23 02:20:31 +04:00
if ( copy_from_user ( strbuf , buffer , count ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
2012-11-23 02:20:31 +04:00
strbuf [ count ] = ' \0 ' ;
2005-04-17 02:20:36 +04:00
sscanf ( strbuf , " %s " , str ) ;
2009-04-07 06:24:29 +04:00
mutex_lock ( & acpi_device_lock ) ;
2005-04-17 02:20:36 +04:00
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2005-08-05 08:44:28 +04:00
struct acpi_device * dev =
container_of ( node , struct acpi_device , wakeup_list ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev - > wakeup . flags . valid )
continue ;
if ( ! strncmp ( dev - > pnp . bus_id , str , 4 ) ) {
2011-01-07 01:34:22 +03:00
if ( device_can_wakeup ( & dev - > dev ) ) {
bool enable = ! device_may_wakeup ( & dev - > dev ) ;
device_set_wakeup_enable ( & dev - > dev , enable ) ;
} else {
physical_device_enable_wakeup ( dev ) ;
}
2005-04-17 02:20:36 +04:00
break ;
}
}
2009-04-07 06:24:29 +04:00
mutex_unlock ( & acpi_device_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
static int
acpi_system_wakeup_device_open_fs ( struct inode * inode , struct file * file )
{
2005-08-05 08:44:28 +04:00
return single_open ( file , acpi_system_wakeup_device_seq_show ,
2013-04-01 02:16:14 +04:00
PDE_DATA ( inode ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-07-04 21:06:00 +04:00
static const struct file_operations acpi_system_wakeup_device_fops = {
2008-04-29 12:02:27 +04:00
. owner = THIS_MODULE ,
2005-08-05 08:44:28 +04:00
. open = acpi_system_wakeup_device_open_fs ,
. read = seq_read ,
. write = acpi_system_write_wakeup_device ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
2007-05-08 11:34:02 +04:00
# ifdef HAVE_ACPI_LEGACY_ALARM
2006-07-04 21:06:00 +04:00
static const struct file_operations acpi_system_alarm_fops = {
2008-04-29 12:02:27 +04:00
. owner = THIS_MODULE ,
2005-08-05 08:44:28 +04:00
. open = acpi_system_alarm_open_fs ,
. read = seq_read ,
. write = acpi_system_write_alarm ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
2005-08-05 08:44:28 +04:00
static u32 rtc_handler ( void * context )
2005-04-17 02:20:36 +04:00
{
acpi_clear_event ( ACPI_EVENT_RTC ) ;
acpi_disable_event ( ACPI_EVENT_RTC , 0 ) ;
return ACPI_INTERRUPT_HANDLED ;
}
2007-05-10 07:34:35 +04:00
# endif /* HAVE_ACPI_LEGACY_ALARM */
2005-04-17 02:20:36 +04:00
2009-03-25 01:50:14 +03:00
int __init acpi_sleep_proc_init ( void )
2005-04-17 02:20:36 +04:00
{
2007-05-08 11:34:02 +04:00
# ifdef HAVE_ACPI_LEGACY_ALARM
2005-04-17 02:20:36 +04:00
/* 'alarm' [R/W] */
2008-04-29 12:02:27 +04:00
proc_create ( " alarm " , S_IFREG | S_IRUGO | S_IWUSR ,
acpi_root_dir , & acpi_system_alarm_fops ) ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:34:02 +04:00
acpi_install_fixed_event_handler ( ACPI_EVENT_RTC , rtc_handler , NULL ) ;
2008-05-14 07:32:59 +04:00
/*
* Disable the RTC event after installing RTC handler .
* Only when RTC alarm is set will it be enabled .
*/
acpi_clear_event ( ACPI_EVENT_RTC ) ;
acpi_disable_event ( ACPI_EVENT_RTC , 0 ) ;
2007-05-10 07:34:35 +04:00
# endif /* HAVE_ACPI_LEGACY_ALARM */
2007-05-08 11:34:02 +04:00
2005-08-05 08:37:45 +04:00
/* 'wakeup device' [R/W] */
2008-04-29 12:02:27 +04:00
proc_create ( " wakeup " , S_IFREG | S_IRUGO | S_IWUSR ,
acpi_root_dir , & acpi_system_wakeup_device_fops ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}