diff options
-rw-r--r-- | drivers/acpi/proc.c | 305 |
1 files changed, 0 insertions, 305 deletions
diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 04a13784dd20..6a5b152ad4d0 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c | |||
@@ -8,289 +8,17 @@ | |||
8 | #include <acpi/acpi_bus.h> | 8 | #include <acpi/acpi_bus.h> |
9 | #include <acpi/acpi_drivers.h> | 9 | #include <acpi/acpi_drivers.h> |
10 | 10 | ||
11 | #ifdef CONFIG_X86 | ||
12 | #include <linux/mc146818rtc.h> | ||
13 | #endif | ||
14 | |||
15 | #include "sleep.h" | 11 | #include "sleep.h" |
16 | 12 | ||
17 | #define _COMPONENT ACPI_SYSTEM_COMPONENT | 13 | #define _COMPONENT ACPI_SYSTEM_COMPONENT |
18 | 14 | ||
19 | /* | 15 | /* |
20 | * this file provides support for: | 16 | * this file provides support for: |
21 | * /proc/acpi/alarm | ||
22 | * /proc/acpi/wakeup | 17 | * /proc/acpi/wakeup |
23 | */ | 18 | */ |
24 | 19 | ||
25 | ACPI_MODULE_NAME("sleep") | 20 | ACPI_MODULE_NAME("sleep") |
26 | 21 | ||
27 | #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || !defined(CONFIG_X86) | ||
28 | /* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */ | ||
29 | #else | ||
30 | #define HAVE_ACPI_LEGACY_ALARM | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_ACPI_LEGACY_ALARM | ||
34 | |||
35 | static u32 cmos_bcd_read(int offset, int rtc_control); | ||
36 | |||
37 | static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) | ||
38 | { | ||
39 | u32 sec, min, hr; | ||
40 | u32 day, mo, yr, cent = 0; | ||
41 | u32 today = 0; | ||
42 | unsigned char rtc_control = 0; | ||
43 | unsigned long flags; | ||
44 | |||
45 | spin_lock_irqsave(&rtc_lock, flags); | ||
46 | |||
47 | rtc_control = CMOS_READ(RTC_CONTROL); | ||
48 | sec = cmos_bcd_read(RTC_SECONDS_ALARM, rtc_control); | ||
49 | min = cmos_bcd_read(RTC_MINUTES_ALARM, rtc_control); | ||
50 | hr = cmos_bcd_read(RTC_HOURS_ALARM, rtc_control); | ||
51 | |||
52 | /* If we ever get an FACP with proper values... */ | ||
53 | if (acpi_gbl_FADT.day_alarm) { | ||
54 | /* ACPI spec: only low 6 its should be cared */ | ||
55 | day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F; | ||
56 | if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
57 | day = bcd2bin(day); | ||
58 | } else | ||
59 | day = cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control); | ||
60 | if (acpi_gbl_FADT.month_alarm) | ||
61 | mo = cmos_bcd_read(acpi_gbl_FADT.month_alarm, rtc_control); | ||
62 | else { | ||
63 | mo = cmos_bcd_read(RTC_MONTH, rtc_control); | ||
64 | today = cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control); | ||
65 | } | ||
66 | if (acpi_gbl_FADT.century) | ||
67 | cent = cmos_bcd_read(acpi_gbl_FADT.century, rtc_control); | ||
68 | |||
69 | yr = cmos_bcd_read(RTC_YEAR, rtc_control); | ||
70 | |||
71 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
72 | |||
73 | /* we're trusting the FADT (see above) */ | ||
74 | if (!acpi_gbl_FADT.century) | ||
75 | /* If we're not trusting the FADT, we should at least make it | ||
76 | * right for _this_ century... ehm, what is _this_ century? | ||
77 | * | ||
78 | * TBD: | ||
79 | * ASAP: find piece of code in the kernel, e.g. star tracker driver, | ||
80 | * which we can trust to determine the century correctly. Atom | ||
81 | * watch driver would be nice, too... | ||
82 | * | ||
83 | * if that has not happened, change for first release in 2050: | ||
84 | * if (yr<50) | ||
85 | * yr += 2100; | ||
86 | * else | ||
87 | * yr += 2000; // current line of code | ||
88 | * | ||
89 | * if that has not happened either, please do on 2099/12/31:23:59:59 | ||
90 | * s/2000/2100 | ||
91 | * | ||
92 | */ | ||
93 | yr += 2000; | ||
94 | else | ||
95 | yr += cent * 100; | ||
96 | |||
97 | /* | ||
98 | * Show correct dates for alarms up to a month into the future. | ||
99 | * This solves issues for nearly all situations with the common | ||
100 | * 30-day alarm clocks in PC hardware. | ||
101 | */ | ||
102 | if (day < today) { | ||
103 | if (mo < 12) { | ||
104 | mo += 1; | ||
105 | } else { | ||
106 | mo = 1; | ||
107 | yr += 1; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | seq_printf(seq, "%4.4u-", yr); | ||
112 | (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); | ||
113 | (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day); | ||
114 | (hr > 23) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", hr); | ||
115 | (min > 59) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", min); | ||
116 | (sec > 59) ? seq_puts(seq, "**\n") : seq_printf(seq, "%2.2u\n", sec); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static int acpi_system_alarm_open_fs(struct inode *inode, struct file *file) | ||
122 | { | ||
123 | return single_open(file, acpi_system_alarm_seq_show, PDE_DATA(inode)); | ||
124 | } | ||
125 | |||
126 | static int get_date_field(char **p, u32 * value) | ||
127 | { | ||
128 | char *next = NULL; | ||
129 | char *string_end = NULL; | ||
130 | int result = -EINVAL; | ||
131 | |||
132 | /* | ||
133 | * Try to find delimeter, only to insert null. The end of the | ||
134 | * string won't have one, but is still valid. | ||
135 | */ | ||
136 | if (*p == NULL) | ||
137 | return result; | ||
138 | |||
139 | next = strpbrk(*p, "- :"); | ||
140 | if (next) | ||
141 | *next++ = '\0'; | ||
142 | |||
143 | *value = simple_strtoul(*p, &string_end, 10); | ||
144 | |||
145 | /* Signal success if we got a good digit */ | ||
146 | if (string_end != *p) | ||
147 | result = 0; | ||
148 | |||
149 | if (next) | ||
150 | *p = next; | ||
151 | else | ||
152 | *p = NULL; | ||
153 | |||
154 | return result; | ||
155 | } | ||
156 | |||
157 | /* Read a possibly BCD register, always return binary */ | ||
158 | static u32 cmos_bcd_read(int offset, int rtc_control) | ||
159 | { | ||
160 | u32 val = CMOS_READ(offset); | ||
161 | if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
162 | val = bcd2bin(val); | ||
163 | return val; | ||
164 | } | ||
165 | |||
166 | /* Write binary value into possibly BCD register */ | ||
167 | static void cmos_bcd_write(u32 val, int offset, int rtc_control) | ||
168 | { | ||
169 | if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
170 | val = bin2bcd(val); | ||
171 | CMOS_WRITE(val, offset); | ||
172 | } | ||
173 | |||
174 | static ssize_t | ||
175 | acpi_system_write_alarm(struct file *file, | ||
176 | const char __user * buffer, size_t count, loff_t * ppos) | ||
177 | { | ||
178 | int result = 0; | ||
179 | char alarm_string[30] = { '\0' }; | ||
180 | char *p = alarm_string; | ||
181 | u32 sec, min, hr, day, mo, yr; | ||
182 | int adjust = 0; | ||
183 | unsigned char rtc_control = 0; | ||
184 | |||
185 | if (count > sizeof(alarm_string) - 1) | ||
186 | return -EINVAL; | ||
187 | |||
188 | if (copy_from_user(alarm_string, buffer, count)) | ||
189 | return -EFAULT; | ||
190 | |||
191 | alarm_string[count] = '\0'; | ||
192 | |||
193 | /* check for time adjustment */ | ||
194 | if (alarm_string[0] == '+') { | ||
195 | p++; | ||
196 | adjust = 1; | ||
197 | } | ||
198 | |||
199 | if ((result = get_date_field(&p, &yr))) | ||
200 | goto end; | ||
201 | if ((result = get_date_field(&p, &mo))) | ||
202 | goto end; | ||
203 | if ((result = get_date_field(&p, &day))) | ||
204 | goto end; | ||
205 | if ((result = get_date_field(&p, &hr))) | ||
206 | goto end; | ||
207 | if ((result = get_date_field(&p, &min))) | ||
208 | goto end; | ||
209 | if ((result = get_date_field(&p, &sec))) | ||
210 | goto end; | ||
211 | |||
212 | spin_lock_irq(&rtc_lock); | ||
213 | |||
214 | rtc_control = CMOS_READ(RTC_CONTROL); | ||
215 | |||
216 | if (adjust) { | ||
217 | yr += cmos_bcd_read(RTC_YEAR, rtc_control); | ||
218 | mo += cmos_bcd_read(RTC_MONTH, rtc_control); | ||
219 | day += cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control); | ||
220 | hr += cmos_bcd_read(RTC_HOURS, rtc_control); | ||
221 | min += cmos_bcd_read(RTC_MINUTES, rtc_control); | ||
222 | sec += cmos_bcd_read(RTC_SECONDS, rtc_control); | ||
223 | } | ||
224 | |||
225 | spin_unlock_irq(&rtc_lock); | ||
226 | |||
227 | if (sec > 59) { | ||
228 | min += sec/60; | ||
229 | sec = sec%60; | ||
230 | } | ||
231 | if (min > 59) { | ||
232 | hr += min/60; | ||
233 | min = min%60; | ||
234 | } | ||
235 | if (hr > 23) { | ||
236 | day += hr/24; | ||
237 | hr = hr%24; | ||
238 | } | ||
239 | if (day > 31) { | ||
240 | mo += day/32; | ||
241 | day = day%32; | ||
242 | } | ||
243 | if (mo > 12) { | ||
244 | yr += mo/13; | ||
245 | mo = mo%13; | ||
246 | } | ||
247 | |||
248 | spin_lock_irq(&rtc_lock); | ||
249 | /* | ||
250 | * Disable alarm interrupt before setting alarm timer or else | ||
251 | * when ACPI_EVENT_RTC is enabled, a spurious ACPI interrupt occurs | ||
252 | */ | ||
253 | rtc_control &= ~RTC_AIE; | ||
254 | CMOS_WRITE(rtc_control, RTC_CONTROL); | ||
255 | CMOS_READ(RTC_INTR_FLAGS); | ||
256 | |||
257 | /* write the fields the rtc knows about */ | ||
258 | cmos_bcd_write(hr, RTC_HOURS_ALARM, rtc_control); | ||
259 | cmos_bcd_write(min, RTC_MINUTES_ALARM, rtc_control); | ||
260 | cmos_bcd_write(sec, RTC_SECONDS_ALARM, rtc_control); | ||
261 | |||
262 | /* | ||
263 | * If the system supports an enhanced alarm it will have non-zero | ||
264 | * offsets into the CMOS RAM here -- which for some reason are pointing | ||
265 | * to the RTC area of memory. | ||
266 | */ | ||
267 | if (acpi_gbl_FADT.day_alarm) | ||
268 | cmos_bcd_write(day, acpi_gbl_FADT.day_alarm, rtc_control); | ||
269 | if (acpi_gbl_FADT.month_alarm) | ||
270 | cmos_bcd_write(mo, acpi_gbl_FADT.month_alarm, rtc_control); | ||
271 | if (acpi_gbl_FADT.century) { | ||
272 | if (adjust) | ||
273 | yr += cmos_bcd_read(acpi_gbl_FADT.century, rtc_control) * 100; | ||
274 | cmos_bcd_write(yr / 100, acpi_gbl_FADT.century, rtc_control); | ||
275 | } | ||
276 | /* enable the rtc alarm interrupt */ | ||
277 | rtc_control |= RTC_AIE; | ||
278 | CMOS_WRITE(rtc_control, RTC_CONTROL); | ||
279 | CMOS_READ(RTC_INTR_FLAGS); | ||
280 | |||
281 | spin_unlock_irq(&rtc_lock); | ||
282 | |||
283 | acpi_clear_event(ACPI_EVENT_RTC); | ||
284 | acpi_enable_event(ACPI_EVENT_RTC, 0); | ||
285 | |||
286 | *ppos += count; | ||
287 | |||
288 | result = 0; | ||
289 | end: | ||
290 | return result ? result : count; | ||
291 | } | ||
292 | #endif /* HAVE_ACPI_LEGACY_ALARM */ | ||
293 | |||
294 | static int | 22 | static int |
295 | acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) | 23 | acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) |
296 | { | 24 | { |
@@ -417,41 +145,8 @@ static const struct file_operations acpi_system_wakeup_device_fops = { | |||
417 | .release = single_release, | 145 | .release = single_release, |
418 | }; | 146 | }; |
419 | 147 | ||
420 | #ifdef HAVE_ACPI_LEGACY_ALARM | ||
421 | static const struct file_operations acpi_system_alarm_fops = { | ||
422 | .owner = THIS_MODULE, | ||
423 | .open = acpi_system_alarm_open_fs, | ||
424 | .read = seq_read, | ||
425 | .write = acpi_system_write_alarm, | ||
426 | .llseek = seq_lseek, | ||
427 | .release = single_release, | ||
428 | }; | ||
429 | |||
430 | static u32 rtc_handler(void *context) | ||
431 | { | ||
432 | acpi_clear_event(ACPI_EVENT_RTC); | ||
433 | acpi_disable_event(ACPI_EVENT_RTC, 0); | ||
434 | |||
435 | return ACPI_INTERRUPT_HANDLED; | ||
436 | } | ||
437 | #endif /* HAVE_ACPI_LEGACY_ALARM */ | ||
438 | |||
439 | int __init acpi_sleep_proc_init(void) | 148 | int __init acpi_sleep_proc_init(void) |
440 | { | 149 | { |
441 | #ifdef HAVE_ACPI_LEGACY_ALARM | ||
442 | /* 'alarm' [R/W] */ | ||
443 | proc_create("alarm", S_IFREG | S_IRUGO | S_IWUSR, | ||
444 | acpi_root_dir, &acpi_system_alarm_fops); | ||
445 | |||
446 | acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); | ||
447 | /* | ||
448 | * Disable the RTC event after installing RTC handler. | ||
449 | * Only when RTC alarm is set will it be enabled. | ||
450 | */ | ||
451 | acpi_clear_event(ACPI_EVENT_RTC); | ||
452 | acpi_disable_event(ACPI_EVENT_RTC, 0); | ||
453 | #endif /* HAVE_ACPI_LEGACY_ALARM */ | ||
454 | |||
455 | /* 'wakeup device' [R/W] */ | 150 | /* 'wakeup device' [R/W] */ |
456 | proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR, | 151 | proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR, |
457 | acpi_root_dir, &acpi_system_wakeup_device_fops); | 152 | acpi_root_dir, &acpi_system_wakeup_device_fops); |