diff options
author | Mark Lord <lkml@rtr.ca> | 2008-12-09 10:46:30 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-12-10 00:29:35 -0500 |
commit | 48452e5f99ab35d643df0463b6ad11aea8ea7bdc (patch) | |
tree | 9d5418951b0064f231d1df81f96b1ba624e46f99 /drivers/acpi/sleep/proc.c | |
parent | 437f2f91d6597c67662f847d9ed4c99cb3c440cd (diff) |
/proc/acpi/alarm: handle day-of-month wraparound on readback
Fix month wrap issue with readback from /proc/acpi/alarm
This bug has been around *forever*.
$ echo '2008-12-01 10:36:20' > /proc/acpi/alarm
$ cat /proc/acpi/alarm
2008-11-01 10:36:20
Note how the readback above shows the month incorrectly
when the alarm is set in the *next* calendar month.
But with this patch applied, it shows the correct month (12).
Signed-off-by: Mark Lord <mlord@pobox.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/sleep/proc.c')
-rw-r--r-- | drivers/acpi/sleep/proc.c | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 4dbc2271acf5..232d4b64140b 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c | |||
@@ -84,12 +84,15 @@ acpi_system_write_sleep(struct file *file, | |||
84 | #define HAVE_ACPI_LEGACY_ALARM | 84 | #define HAVE_ACPI_LEGACY_ALARM |
85 | #endif | 85 | #endif |
86 | 86 | ||
87 | static u32 cmos_bcd_read(int offset, int rtc_control); | ||
88 | |||
87 | #ifdef HAVE_ACPI_LEGACY_ALARM | 89 | #ifdef HAVE_ACPI_LEGACY_ALARM |
88 | 90 | ||
89 | static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) | 91 | static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) |
90 | { | 92 | { |
91 | u32 sec, min, hr; | 93 | u32 sec, min, hr; |
92 | u32 day, mo, yr, cent = 0; | 94 | u32 day, mo, yr, cent = 0; |
95 | u32 today = 0; | ||
93 | unsigned char rtc_control = 0; | 96 | unsigned char rtc_control = 0; |
94 | unsigned long flags; | 97 | unsigned long flags; |
95 | 98 | ||
@@ -97,38 +100,32 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) | |||
97 | 100 | ||
98 | spin_lock_irqsave(&rtc_lock, flags); | 101 | spin_lock_irqsave(&rtc_lock, flags); |
99 | 102 | ||
100 | sec = CMOS_READ(RTC_SECONDS_ALARM); | ||
101 | min = CMOS_READ(RTC_MINUTES_ALARM); | ||
102 | hr = CMOS_READ(RTC_HOURS_ALARM); | ||
103 | rtc_control = CMOS_READ(RTC_CONTROL); | 103 | rtc_control = CMOS_READ(RTC_CONTROL); |
104 | sec = cmos_bcd_read(RTC_SECONDS_ALARM, rtc_control); | ||
105 | min = cmos_bcd_read(RTC_MINUTES_ALARM, rtc_control); | ||
106 | hr = cmos_bcd_read(RTC_HOURS_ALARM, rtc_control); | ||
104 | 107 | ||
105 | /* If we ever get an FACP with proper values... */ | 108 | /* If we ever get an FACP with proper values... */ |
106 | if (acpi_gbl_FADT.day_alarm) | 109 | if (acpi_gbl_FADT.day_alarm) { |
107 | /* ACPI spec: only low 6 its should be cared */ | 110 | /* ACPI spec: only low 6 its should be cared */ |
108 | day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F; | 111 | day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F; |
109 | else | 112 | if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) |
110 | day = CMOS_READ(RTC_DAY_OF_MONTH); | 113 | day = bcd2bin(day); |
114 | } else | ||
115 | day = cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control); | ||
111 | if (acpi_gbl_FADT.month_alarm) | 116 | if (acpi_gbl_FADT.month_alarm) |
112 | mo = CMOS_READ(acpi_gbl_FADT.month_alarm); | 117 | mo = cmos_bcd_read(acpi_gbl_FADT.month_alarm, rtc_control); |
113 | else | 118 | else { |
114 | mo = CMOS_READ(RTC_MONTH); | 119 | mo = cmos_bcd_read(RTC_MONTH, rtc_control); |
120 | today = cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control); | ||
121 | } | ||
115 | if (acpi_gbl_FADT.century) | 122 | if (acpi_gbl_FADT.century) |
116 | cent = CMOS_READ(acpi_gbl_FADT.century); | 123 | cent = cmos_bcd_read(acpi_gbl_FADT.century, rtc_control); |
117 | 124 | ||
118 | yr = CMOS_READ(RTC_YEAR); | 125 | yr = cmos_bcd_read(RTC_YEAR, rtc_control); |
119 | 126 | ||
120 | spin_unlock_irqrestore(&rtc_lock, flags); | 127 | spin_unlock_irqrestore(&rtc_lock, flags); |
121 | 128 | ||
122 | if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
123 | sec = bcd2bin(sec); | ||
124 | min = bcd2bin(min); | ||
125 | hr = bcd2bin(hr); | ||
126 | day = bcd2bin(day); | ||
127 | mo = bcd2bin(mo); | ||
128 | yr = bcd2bin(yr); | ||
129 | cent = bcd2bin(cent); | ||
130 | } | ||
131 | |||
132 | /* we're trusting the FADT (see above) */ | 129 | /* we're trusting the FADT (see above) */ |
133 | if (!acpi_gbl_FADT.century) | 130 | if (!acpi_gbl_FADT.century) |
134 | /* If we're not trusting the FADT, we should at least make it | 131 | /* If we're not trusting the FADT, we should at least make it |
@@ -153,6 +150,20 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) | |||
153 | else | 150 | else |
154 | yr += cent * 100; | 151 | yr += cent * 100; |
155 | 152 | ||
153 | /* | ||
154 | * Show correct dates for alarms up to a month into the future. | ||
155 | * This solves issues for nearly all situations with the common | ||
156 | * 30-day alarm clocks in PC hardware. | ||
157 | */ | ||
158 | if (day < today) { | ||
159 | if (mo < 12) { | ||
160 | mo += 1; | ||
161 | } else { | ||
162 | mo = 1; | ||
163 | yr += 1; | ||
164 | } | ||
165 | } | ||
166 | |||
156 | seq_printf(seq, "%4.4u-", yr); | 167 | seq_printf(seq, "%4.4u-", yr); |
157 | (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); | 168 | (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); |
158 | (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day); | 169 | (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day); |