2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
#include <linux/seq_file.h>
|
|
|
|
#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 14:16:50 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* this file provides support for:
|
|
|
|
* /proc/acpi/sleep
|
|
|
|
* /proc/acpi/alarm
|
|
|
|
* /proc/acpi/wakeup
|
|
|
|
*/
|
|
|
|
|
2005-08-05 12:44:28 +08:00
|
|
|
ACPI_MODULE_NAME("sleep")
|
2007-08-29 02:58:56 +08:00
|
|
|
#ifdef CONFIG_ACPI_PROCFS
|
2005-04-17 06:20:36 +08:00
|
|
|
static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
|
|
|
|
{
|
2005-08-05 12:44:28 +08:00
|
|
|
int i;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
for (i = 0; i <= ACPI_STATE_S5; i++) {
|
|
|
|
if (sleep_states[i]) {
|
2005-08-05 12:44:28 +08:00
|
|
|
seq_printf(seq, "S%d ", i);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
seq_puts(seq, "\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int acpi_system_sleep_open_fs(struct inode *inode, struct file *file)
|
|
|
|
{
|
|
|
|
return single_open(file, acpi_system_sleep_seq_show, PDE(inode)->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
2005-08-05 12:44:28 +08:00
|
|
|
acpi_system_write_sleep(struct file *file,
|
|
|
|
const char __user * buffer, size_t count, loff_t * ppos)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-08-05 12:44:28 +08:00
|
|
|
char str[12];
|
|
|
|
u32 state = 0;
|
|
|
|
int error = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (count > sizeof(str) - 1)
|
|
|
|
goto Done;
|
2005-08-05 12:44:28 +08:00
|
|
|
memset(str, 0, sizeof(str));
|
2005-04-17 06:20:36 +08:00
|
|
|
if (copy_from_user(str, buffer, count))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
/* Check for S4 bios request */
|
2005-08-05 12:44:28 +08:00
|
|
|
if (!strcmp(str, "4b")) {
|
2005-04-17 06:20:36 +08:00
|
|
|
error = acpi_suspend(4);
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
state = simple_strtoul(str, NULL, 0);
|
2007-07-30 05:24:36 +08:00
|
|
|
#ifdef CONFIG_HIBERNATION
|
2005-04-17 06:20:36 +08:00
|
|
|
if (state == 4) {
|
2007-05-09 17:33:18 +08:00
|
|
|
error = hibernate();
|
2005-04-17 06:20:36 +08:00
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
error = acpi_suspend(state);
|
2005-08-05 12:44:28 +08:00
|
|
|
Done:
|
2005-04-17 06:20:36 +08:00
|
|
|
return error ? error : count;
|
|
|
|
}
|
2007-08-29 02:58:56 +08:00
|
|
|
#endif /* CONFIG_ACPI_PROCFS */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-07-28 15:33:16 +08:00
|
|
|
#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || !defined(CONFIG_X86)
|
2007-05-08 15:34:02 +08: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 15:10:16 +08:00
|
|
|
static u32 cmos_bcd_read(int offset, int rtc_control);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
|
|
|
|
{
|
2005-08-05 12:44:28 +08:00
|
|
|
u32 sec, min, hr;
|
2007-02-03 00:48:19 +08:00
|
|
|
u32 day, mo, yr, cent = 0;
|
2008-12-09 23:46:30 +08:00
|
|
|
u32 today = 0;
|
2005-08-05 12:44:28 +08:00
|
|
|
unsigned char rtc_control = 0;
|
|
|
|
unsigned long flags;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
spin_lock_irqsave(&rtc_lock, flags);
|
|
|
|
|
|
|
|
rtc_control = CMOS_READ(RTC_CONTROL);
|
2008-12-09 23:46:30 +08: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 06:20:36 +08:00
|
|
|
|
|
|
|
/* If we ever get an FACP with proper values... */
|
2008-12-09 23:46:30 +08:00
|
|
|
if (acpi_gbl_FADT.day_alarm) {
|
2005-04-17 06:20:36 +08:00
|
|
|
/* ACPI spec: only low 6 its should be cared */
|
2007-02-03 00:48:19 +08:00
|
|
|
day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F;
|
2008-12-09 23:46:30 +08: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-03 00:48:19 +08:00
|
|
|
if (acpi_gbl_FADT.month_alarm)
|
2008-12-09 23:46:30 +08: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-03 00:48:19 +08:00
|
|
|
if (acpi_gbl_FADT.century)
|
2008-12-09 23:46:30 +08:00
|
|
|
cent = cmos_bcd_read(acpi_gbl_FADT.century, rtc_control);
|
2007-02-03 00:48:19 +08:00
|
|
|
|
2008-12-09 23:46:30 +08:00
|
|
|
yr = cmos_bcd_read(RTC_YEAR, rtc_control);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
spin_unlock_irqrestore(&rtc_lock, flags);
|
|
|
|
|
2005-08-05 12:44:28 +08:00
|
|
|
/* we're trusting the FADT (see above) */
|
2007-02-03 00:48:19 +08:00
|
|
|
if (!acpi_gbl_FADT.century)
|
2005-08-05 12:44:28 +08: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 06:20:36 +08:00
|
|
|
yr += 2000;
|
2007-02-03 00:48:19 +08:00
|
|
|
else
|
|
|
|
yr += cent * 100;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-12-09 23:46:30 +08: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 12:44:28 +08: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 06:20:36 +08: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)
|
|
|
|
{
|
|
|
|
return single_open(file, acpi_system_alarm_seq_show, PDE(inode)->data);
|
|
|
|
}
|
|
|
|
|
2005-08-05 12:44:28 +08:00
|
|
|
static int get_date_field(char **p, u32 * value)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-08-05 12:44:28 +08:00
|
|
|
char *next = NULL;
|
|
|
|
char *string_end = NULL;
|
|
|
|
int result = -EINVAL;
|
2005-04-17 06:20:36 +08: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 10:50:42 +08:00
|
|
|
if (*p == NULL)
|
|
|
|
return result;
|
|
|
|
|
2005-04-17 06:20:36 +08: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 10:50:42 +08:00
|
|
|
else
|
|
|
|
*p = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2007-10-18 11:18:32 +08: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 11:28:39 +08:00
|
|
|
val = bcd2bin(val);
|
2007-10-18 11:18:32 +08: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 11:28:39 +08:00
|
|
|
val = bin2bcd(val);
|
2007-10-18 11:18:32 +08:00
|
|
|
CMOS_WRITE(val, offset);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static ssize_t
|
2005-08-05 12:44:28 +08:00
|
|
|
acpi_system_write_alarm(struct file *file,
|
|
|
|
const char __user * buffer, size_t count, loff_t * ppos)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-08-05 12:44:28 +08: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 06:20:36 +08:00
|
|
|
|
|
|
|
if (count > sizeof(alarm_string) - 1)
|
2008-12-16 16:49:26 +08:00
|
|
|
return -EINVAL;
|
2005-08-05 12:44:28 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (copy_from_user(alarm_string, buffer, count))
|
2008-12-16 16:49:26 +08:00
|
|
|
return -EFAULT;
|
2005-04-17 06:20:36 +08: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 11:18:32 +08: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 06:20:36 +08: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 11:04:26 +08:00
|
|
|
min += sec/60;
|
|
|
|
sec = sec%60;
|
2005-04-17 06:20:36 +08: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 11:04:26 +08:00
|
|
|
hr += min/60;
|
|
|
|
min = min%60;
|
2005-04-17 06:20:36 +08: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 11:04:26 +08:00
|
|
|
day += hr/24;
|
|
|
|
hr = hr%24;
|
2005-04-17 06:20:36 +08: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 11:04:26 +08:00
|
|
|
mo += day/32;
|
|
|
|
day = day%32;
|
2005-04-17 06:20:36 +08: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 11:04:26 +08:00
|
|
|
yr += mo/13;
|
|
|
|
mo = mo%13;
|
2005-04-17 06:20:36 +08: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 11:18:32 +08: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 06:20:36 +08: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-03 00:48:19 +08:00
|
|
|
if (acpi_gbl_FADT.day_alarm)
|
2007-10-18 11:18:32 +08:00
|
|
|
cmos_bcd_write(day, acpi_gbl_FADT.day_alarm, rtc_control);
|
2007-02-03 00:48:19 +08:00
|
|
|
if (acpi_gbl_FADT.month_alarm)
|
2007-10-18 11:18:32 +08:00
|
|
|
cmos_bcd_write(mo, acpi_gbl_FADT.month_alarm, rtc_control);
|
2008-07-05 00:59:31 +08:00
|
|
|
if (acpi_gbl_FADT.century) {
|
|
|
|
if (adjust)
|
|
|
|
yr += cmos_bcd_read(acpi_gbl_FADT.century, rtc_control) * 100;
|
2007-10-18 11:18:32 +08:00
|
|
|
cmos_bcd_write(yr / 100, acpi_gbl_FADT.century, rtc_control);
|
2008-07-05 00:59:31 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08: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 12:44:28 +08:00
|
|
|
end:
|
2008-12-16 16:49:26 +08:00
|
|
|
return result ? result : count;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2007-05-10 11:34:35 +08:00
|
|
|
#endif /* HAVE_ACPI_LEGACY_ALARM */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-08-05 12:44:28 +08:00
|
|
|
extern struct list_head acpi_wakeup_device_list;
|
2005-04-17 06:20:36 +08:00
|
|
|
extern spinlock_t acpi_device_lock;
|
|
|
|
|
|
|
|
static int
|
|
|
|
acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
|
|
|
|
{
|
2005-08-05 12:44:28 +08:00
|
|
|
struct list_head *node, *next;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-04-26 03:20:10 +08:00
|
|
|
seq_printf(seq, "Device\tS-state\t Status Sysfs node\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
spin_lock(&acpi_device_lock);
|
|
|
|
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
|
2005-08-05 12:44:28 +08:00
|
|
|
struct acpi_device *dev =
|
|
|
|
container_of(node, struct acpi_device, wakeup_list);
|
2007-04-26 03:20:10 +08:00
|
|
|
struct device *ldev;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (!dev->wakeup.flags.valid)
|
|
|
|
continue;
|
|
|
|
spin_unlock(&acpi_device_lock);
|
2007-04-26 03:20:10 +08:00
|
|
|
|
|
|
|
ldev = acpi_get_physical_device(dev->handle);
|
|
|
|
seq_printf(seq, "%s\t S%d\t%c%-8s ",
|
2005-08-05 12:44:28 +08:00
|
|
|
dev->pnp.bus_id,
|
|
|
|
(u32) dev->wakeup.sleep_state,
|
2007-04-26 03:20:10 +08:00
|
|
|
dev->wakeup.flags.run_wake ? '*' : ' ',
|
2005-08-05 12:37:45 +08:00
|
|
|
dev->wakeup.state.enabled ? "enabled" : "disabled");
|
2007-04-26 03:20:10 +08:00
|
|
|
if (ldev)
|
|
|
|
seq_printf(seq, "%s:%s",
|
2008-11-17 02:09:34 +08:00
|
|
|
ldev->bus ? ldev->bus->name : "no-bus",
|
ACPI: struct device - replace bus_id with dev_name(), dev_set_name()
This patch is part of a larger patch series which will remove
the "char bus_id[20]" name string from struct device. The device
name is managed in the kobject anyway, and without any size
limitation, and just needlessly copied into "struct device".
To set and read the device name dev_name(dev) and dev_set_name(dev)
must be used. If your code uses static kobjects, which it shouldn't
do, "const char *init_name" can be used to statically provide the
name the registered device should have. At registration time, the
init_name field is cleared, to enforce the use of dev_name(dev) to
access the device name at a later time.
We need to get rid of all occurrences of bus_id in the entire tree
to be able to enable the new interface. Please apply this patch,
and possibly convert any remaining remaining occurrences of bus_id.
We want to submit a patch to -next, which will remove bus_id from
"struct device", to find the remaining pieces to convert, and finally
switch over to the new api, which will remove the 20 bytes array
and does no longer have a size limitation.
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-Off-By: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Len Brown <len.brown@intel.com>
2008-10-30 08:18:59 +08:00
|
|
|
dev_name(ldev));
|
2007-04-26 03:20:10 +08:00
|
|
|
seq_printf(seq, "\n");
|
|
|
|
put_device(ldev);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
spin_lock(&acpi_device_lock);
|
|
|
|
}
|
|
|
|
spin_unlock(&acpi_device_lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-10-04 06:23:49 +08:00
|
|
|
static void physical_device_enable_wakeup(struct acpi_device *adev)
|
|
|
|
{
|
|
|
|
struct device *dev = acpi_get_physical_device(adev->handle);
|
|
|
|
|
|
|
|
if (dev && device_can_wakeup(dev))
|
|
|
|
device_set_wakeup_enable(dev, adev->wakeup.state.enabled);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static ssize_t
|
2005-08-05 12:44:28 +08:00
|
|
|
acpi_system_write_wakeup_device(struct file *file,
|
|
|
|
const char __user * buffer,
|
|
|
|
size_t count, loff_t * ppos)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-08-05 12:44:28 +08:00
|
|
|
struct list_head *node, *next;
|
|
|
|
char strbuf[5];
|
|
|
|
char str[5] = "";
|
|
|
|
int len = count;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct acpi_device *found_dev = NULL;
|
|
|
|
|
2005-08-05 12:44:28 +08:00
|
|
|
if (len > 4)
|
|
|
|
len = 4;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (copy_from_user(strbuf, buffer, len))
|
|
|
|
return -EFAULT;
|
|
|
|
strbuf[len] = '\0';
|
|
|
|
sscanf(strbuf, "%s", str);
|
|
|
|
|
|
|
|
spin_lock(&acpi_device_lock);
|
|
|
|
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
|
2005-08-05 12:44:28 +08:00
|
|
|
struct acpi_device *dev =
|
|
|
|
container_of(node, struct acpi_device, wakeup_list);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!dev->wakeup.flags.valid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!strncmp(dev->pnp.bus_id, str, 4)) {
|
2005-08-05 12:44:28 +08:00
|
|
|
dev->wakeup.state.enabled =
|
|
|
|
dev->wakeup.state.enabled ? 0 : 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
found_dev = dev;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found_dev) {
|
2008-10-04 06:23:49 +08:00
|
|
|
physical_device_enable_wakeup(found_dev);
|
2005-04-17 06:20:36 +08:00
|
|
|
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
|
2005-08-05 12:44:28 +08:00
|
|
|
struct acpi_device *dev = container_of(node,
|
|
|
|
struct
|
|
|
|
acpi_device,
|
|
|
|
wakeup_list);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if ((dev != found_dev) &&
|
2005-08-05 12:44:28 +08:00
|
|
|
(dev->wakeup.gpe_number ==
|
|
|
|
found_dev->wakeup.gpe_number)
|
|
|
|
&& (dev->wakeup.gpe_device ==
|
|
|
|
found_dev->wakeup.gpe_device)) {
|
|
|
|
printk(KERN_WARNING
|
|
|
|
"ACPI: '%s' and '%s' have the same GPE, "
|
|
|
|
"can't disable/enable one seperately\n",
|
|
|
|
dev->pnp.bus_id, found_dev->pnp.bus_id);
|
|
|
|
dev->wakeup.state.enabled =
|
|
|
|
found_dev->wakeup.state.enabled;
|
2008-10-04 06:23:49 +08:00
|
|
|
physical_device_enable_wakeup(dev);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
spin_unlock(&acpi_device_lock);
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
|
|
|
|
{
|
2005-08-05 12:44:28 +08:00
|
|
|
return single_open(file, acpi_system_wakeup_device_seq_show,
|
|
|
|
PDE(inode)->data);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-07-05 01:06:00 +08:00
|
|
|
static const struct file_operations acpi_system_wakeup_device_fops = {
|
2008-04-29 16:02:27 +08:00
|
|
|
.owner = THIS_MODULE,
|
2005-08-05 12:44:28 +08: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 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2007-08-29 02:58:56 +08:00
|
|
|
#ifdef CONFIG_ACPI_PROCFS
|
2006-07-05 01:06:00 +08:00
|
|
|
static const struct file_operations acpi_system_sleep_fops = {
|
2008-04-29 16:02:27 +08:00
|
|
|
.owner = THIS_MODULE,
|
2005-08-05 12:44:28 +08:00
|
|
|
.open = acpi_system_sleep_open_fs,
|
|
|
|
.read = seq_read,
|
|
|
|
.write = acpi_system_write_sleep,
|
|
|
|
.llseek = seq_lseek,
|
|
|
|
.release = single_release,
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
2007-08-29 02:58:56 +08:00
|
|
|
#endif /* CONFIG_ACPI_PROCFS */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-05-08 15:34:02 +08:00
|
|
|
#ifdef HAVE_ACPI_LEGACY_ALARM
|
2006-07-05 01:06:00 +08:00
|
|
|
static const struct file_operations acpi_system_alarm_fops = {
|
2008-04-29 16:02:27 +08:00
|
|
|
.owner = THIS_MODULE,
|
2005-08-05 12:44:28 +08:00
|
|
|
.open = acpi_system_alarm_open_fs,
|
|
|
|
.read = seq_read,
|
|
|
|
.write = acpi_system_write_alarm,
|
|
|
|
.llseek = seq_lseek,
|
|
|
|
.release = single_release,
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2005-08-05 12:44:28 +08:00
|
|
|
static u32 rtc_handler(void *context)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
acpi_clear_event(ACPI_EVENT_RTC);
|
|
|
|
acpi_disable_event(ACPI_EVENT_RTC, 0);
|
|
|
|
|
|
|
|
return ACPI_INTERRUPT_HANDLED;
|
|
|
|
}
|
2007-05-10 11:34:35 +08:00
|
|
|
#endif /* HAVE_ACPI_LEGACY_ALARM */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-05-08 15:34:02 +08:00
|
|
|
static int __init acpi_sleep_proc_init(void)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
if (acpi_disabled)
|
|
|
|
return 0;
|
2005-08-05 12:44:28 +08:00
|
|
|
|
2007-08-29 02:58:56 +08:00
|
|
|
#ifdef CONFIG_ACPI_PROCFS
|
2005-08-05 12:37:45 +08:00
|
|
|
/* 'sleep' [R/W] */
|
2008-04-29 16:02:27 +08:00
|
|
|
proc_create("sleep", S_IFREG | S_IRUGO | S_IWUSR,
|
|
|
|
acpi_root_dir, &acpi_system_sleep_fops);
|
2007-07-24 14:16:50 +08:00
|
|
|
#endif /* CONFIG_ACPI_PROCFS */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-05-08 15:34:02 +08:00
|
|
|
#ifdef HAVE_ACPI_LEGACY_ALARM
|
2005-04-17 06:20:36 +08:00
|
|
|
/* 'alarm' [R/W] */
|
2008-04-29 16:02:27 +08:00
|
|
|
proc_create("alarm", S_IFREG | S_IRUGO | S_IWUSR,
|
|
|
|
acpi_root_dir, &acpi_system_alarm_fops);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-05-08 15:34:02 +08:00
|
|
|
acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
|
2008-05-14 11:32:59 +08: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 11:34:35 +08:00
|
|
|
#endif /* HAVE_ACPI_LEGACY_ALARM */
|
2007-05-08 15:34:02 +08:00
|
|
|
|
2005-08-05 12:37:45 +08:00
|
|
|
/* 'wakeup device' [R/W] */
|
2008-04-29 16:02:27 +08:00
|
|
|
proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
|
|
|
|
acpi_root_dir, &acpi_system_wakeup_device_fops);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
late_initcall(acpi_sleep_proc_init);
|