vserver 1.9.3
[linux-2.6.git] / drivers / acpi / sleep / proc.c
1 #include <linux/proc_fs.h>
2 #include <linux/seq_file.h>
3 #include <linux/suspend.h>
4 #include <linux/bcd.h>
5 #include <asm/uaccess.h>
6
7 #include <acpi/acpi_bus.h>
8 #include <acpi/acpi_drivers.h>
9
10 #ifdef CONFIG_X86
11 #include <linux/mc146818rtc.h>
12 #endif
13
14 #include "sleep.h"
15
16 #define ACPI_SYSTEM_FILE_SLEEP          "sleep"
17 #define ACPI_SYSTEM_FILE_ALARM          "alarm"
18 #define ACPI_SYSTEM_FILE_WAKEUP_DEVICE   "wakeup"
19
20 #define _COMPONENT              ACPI_SYSTEM_COMPONENT
21 ACPI_MODULE_NAME                ("sleep")
22
23
24 static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
25 {
26         int                     i;
27
28         ACPI_FUNCTION_TRACE("acpi_system_sleep_seq_show");
29
30         for (i = 0; i <= ACPI_STATE_S5; i++) {
31                 if (sleep_states[i]) {
32                         seq_printf(seq,"S%d ", i);
33                         if (i == ACPI_STATE_S4 && acpi_gbl_FACS->S4bios_f)
34                                 seq_printf(seq, "S4bios ");
35                 }
36         }
37
38         seq_puts(seq, "\n");
39
40         return 0;
41 }
42
43 static int acpi_system_sleep_open_fs(struct inode *inode, struct file *file)
44 {
45         return single_open(file, acpi_system_sleep_seq_show, PDE(inode)->data);
46 }
47
48 static ssize_t
49 acpi_system_write_sleep (
50         struct file             *file,
51         const char __user       *buffer,
52         size_t                  count,
53         loff_t                  *ppos)
54 {
55         char    str[12];
56         u32     state = 0;
57         int     error = 0;
58
59         if (count > sizeof(str) - 1)
60                 goto Done;
61         memset(str,0,sizeof(str));
62         if (copy_from_user(str, buffer, count))
63                 return -EFAULT;
64
65         /* Check for S4 bios request */
66         if (!strcmp(str,"4b")) {
67                 error = acpi_suspend(4);
68                 goto Done;
69         }
70         state = simple_strtoul(str, NULL, 0);
71 #ifdef CONFIG_SOFTWARE_SUSPEND
72         if (state == 4) {
73                 software_suspend();
74                 goto Done;
75         }
76 #endif
77         error = acpi_suspend(state);
78  Done:
79         return error ? error : count;
80 }
81
82 static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
83 {
84         u32                     sec, min, hr;
85         u32                     day, mo, yr;
86
87         ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show");
88
89         spin_lock(&rtc_lock);
90
91         sec = CMOS_READ(RTC_SECONDS_ALARM);
92         min = CMOS_READ(RTC_MINUTES_ALARM);
93         hr = CMOS_READ(RTC_HOURS_ALARM);
94
95 #if 0   /* If we ever get an FACP with proper values... */
96         if (acpi_gbl_FADT->day_alrm)
97                 day = CMOS_READ(acpi_gbl_FADT->day_alrm);
98         else
99                 day =  CMOS_READ(RTC_DAY_OF_MONTH);
100         if (acpi_gbl_FADT->mon_alrm)
101                 mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
102         else
103                 mo = CMOS_READ(RTC_MONTH);
104         if (acpi_gbl_FADT->century)
105                 yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR);
106         else
107                 yr = CMOS_READ(RTC_YEAR);
108 #else
109         day = CMOS_READ(RTC_DAY_OF_MONTH);
110         mo = CMOS_READ(RTC_MONTH);
111         yr = CMOS_READ(RTC_YEAR);
112 #endif
113
114         spin_unlock(&rtc_lock);
115
116         BCD_TO_BIN(sec);
117         BCD_TO_BIN(min);
118         BCD_TO_BIN(hr);
119         BCD_TO_BIN(day);
120         BCD_TO_BIN(mo);
121         BCD_TO_BIN(yr);
122
123 #if 0
124         /* we're trusting the FADT (see above)*/
125 #else
126         /* If we're not trusting the FADT, we should at least make it
127          * right for _this_ century... ehm, what is _this_ century?
128          *
129          * TBD:
130          *  ASAP: find piece of code in the kernel, e.g. star tracker driver,
131          *        which we can trust to determine the century correctly. Atom
132          *        watch driver would be nice, too...
133          *
134          *  if that has not happened, change for first release in 2050:
135          *        if (yr<50)
136          *                yr += 2100;
137          *        else
138          *                yr += 2000;   // current line of code
139          *
140          *  if that has not happened either, please do on 2099/12/31:23:59:59
141          *        s/2000/2100
142          *
143          */
144         yr += 2000;
145 #endif
146
147         seq_printf(seq,"%4.4u-", yr);
148         (mo > 12)  ? seq_puts(seq, "**-")  : seq_printf(seq, "%2.2u-", mo);
149         (day > 31) ? seq_puts(seq, "** ")  : seq_printf(seq, "%2.2u ", day);
150         (hr > 23)  ? seq_puts(seq, "**:")  : seq_printf(seq, "%2.2u:", hr);
151         (min > 59) ? seq_puts(seq, "**:")  : seq_printf(seq, "%2.2u:", min);
152         (sec > 59) ? seq_puts(seq, "**\n") : seq_printf(seq, "%2.2u\n", sec);
153
154         return 0;
155 }
156
157 static int acpi_system_alarm_open_fs(struct inode *inode, struct file *file)
158 {
159         return single_open(file, acpi_system_alarm_seq_show, PDE(inode)->data);
160 }
161
162
163 static int
164 get_date_field (
165         char                    **p,
166         u32                     *value)
167 {
168         char                    *next = NULL;
169         char                    *string_end = NULL;
170         int                     result = -EINVAL;
171
172         /*
173          * Try to find delimeter, only to insert null.  The end of the
174          * string won't have one, but is still valid.
175          */
176         next = strpbrk(*p, "- :");
177         if (next)
178                 *next++ = '\0';
179
180         *value = simple_strtoul(*p, &string_end, 10);
181
182         /* Signal success if we got a good digit */
183         if (string_end != *p)
184                 result = 0;
185
186         if (next)
187                 *p = next;
188
189         return result;
190 }
191
192
193 static ssize_t
194 acpi_system_write_alarm (
195         struct file             *file,
196         const char __user       *buffer,
197         size_t                  count,
198         loff_t                  *ppos)
199 {
200         int                     result = 0;
201         char                    alarm_string[30] = {'\0'};
202         char                    *p = alarm_string;
203         u32                     sec, min, hr, day, mo, yr;
204         int                     adjust = 0;
205         unsigned char           rtc_control = 0;
206
207         ACPI_FUNCTION_TRACE("acpi_system_write_alarm");
208
209         if (count > sizeof(alarm_string) - 1)
210                 return_VALUE(-EINVAL);
211         
212         if (copy_from_user(alarm_string, buffer, count))
213                 return_VALUE(-EFAULT);
214
215         alarm_string[count] = '\0';
216
217         /* check for time adjustment */
218         if (alarm_string[0] == '+') {
219                 p++;
220                 adjust = 1;
221         }
222
223         if ((result = get_date_field(&p, &yr)))
224                 goto end;
225         if ((result = get_date_field(&p, &mo)))
226                 goto end;
227         if ((result = get_date_field(&p, &day)))
228                 goto end;
229         if ((result = get_date_field(&p, &hr)))
230                 goto end;
231         if ((result = get_date_field(&p, &min)))
232                 goto end;
233         if ((result = get_date_field(&p, &sec)))
234                 goto end;
235
236         if (sec > 59) {
237                 min += 1;
238                 sec -= 60;
239         }
240         if (min > 59) {
241                 hr += 1;
242                 min -= 60;
243         }
244         if (hr > 23) {
245                 day += 1;
246                 hr -= 24;
247         }
248         if (day > 31) {
249                 mo += 1;
250                 day -= 31;
251         }
252         if (mo > 12) {
253                 yr += 1;
254                 mo -= 12;
255         }
256
257         spin_lock_irq(&rtc_lock);
258
259         rtc_control = CMOS_READ(RTC_CONTROL);
260         if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
261                 BIN_TO_BCD(yr);
262                 BIN_TO_BCD(mo);
263                 BIN_TO_BCD(day);
264                 BIN_TO_BCD(hr);
265                 BIN_TO_BCD(min);
266                 BIN_TO_BCD(sec);
267         }
268
269         if (adjust) {
270                 yr  += CMOS_READ(RTC_YEAR);
271                 mo  += CMOS_READ(RTC_MONTH);
272                 day += CMOS_READ(RTC_DAY_OF_MONTH);
273                 hr  += CMOS_READ(RTC_HOURS);
274                 min += CMOS_READ(RTC_MINUTES);
275                 sec += CMOS_READ(RTC_SECONDS);
276         }
277
278         spin_unlock_irq(&rtc_lock);
279
280         if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
281                 BCD_TO_BIN(yr);
282                 BCD_TO_BIN(mo);
283                 BCD_TO_BIN(day);
284                 BCD_TO_BIN(hr);
285                 BCD_TO_BIN(min);
286                 BCD_TO_BIN(sec);
287         }
288
289         if (sec > 59) {
290                 min++;
291                 sec -= 60;
292         }
293         if (min > 59) {
294                 hr++;
295                 min -= 60;
296         }
297         if (hr > 23) {
298                 day++;
299                 hr -= 24;
300         }
301         if (day > 31) {
302                 mo++;
303                 day -= 31;
304         }
305         if (mo > 12) {
306                 yr++;
307                 mo -= 12;
308         }
309         if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
310                 BIN_TO_BCD(yr);
311                 BIN_TO_BCD(mo);
312                 BIN_TO_BCD(day);
313                 BIN_TO_BCD(hr);
314                 BIN_TO_BCD(min);
315                 BIN_TO_BCD(sec);
316         }
317
318         spin_lock_irq(&rtc_lock);
319
320         /* write the fields the rtc knows about */
321         CMOS_WRITE(hr, RTC_HOURS_ALARM);
322         CMOS_WRITE(min, RTC_MINUTES_ALARM);
323         CMOS_WRITE(sec, RTC_SECONDS_ALARM);
324
325         /*
326          * If the system supports an enhanced alarm it will have non-zero
327          * offsets into the CMOS RAM here -- which for some reason are pointing
328          * to the RTC area of memory.
329          */
330 #if 0
331         if (acpi_gbl_FADT->day_alrm)
332                 CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
333         if (acpi_gbl_FADT->mon_alrm)
334                 CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
335         if (acpi_gbl_FADT->century)
336                 CMOS_WRITE(yr/100, acpi_gbl_FADT->century);
337 #endif
338         /* enable the rtc alarm interrupt */
339         if (!(rtc_control & RTC_AIE)) {
340                 rtc_control |= RTC_AIE;
341                 CMOS_WRITE(rtc_control,RTC_CONTROL);
342                 CMOS_READ(RTC_INTR_FLAGS);
343         }
344
345         spin_unlock_irq(&rtc_lock);
346
347         acpi_set_register(ACPI_BITREG_RT_CLOCK_ENABLE, 1, ACPI_MTX_LOCK);
348
349         *ppos += count;
350
351         result = 0;
352 end:
353         return_VALUE(result ? result : count);
354 }
355
356 extern struct list_head acpi_wakeup_device_list;
357 extern spinlock_t acpi_device_lock;
358
359 static int
360 acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
361 {
362         struct list_head * node, * next;
363
364         seq_printf(seq, "Device Sleep state     Status\n");
365
366         spin_lock(&acpi_device_lock);
367         list_for_each_safe(node, next, &acpi_wakeup_device_list) {
368                 struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
369
370                 if (!dev->wakeup.flags.valid)
371                         continue;
372                 spin_unlock(&acpi_device_lock);
373                 if (dev->wakeup.flags.run_wake)
374                         seq_printf(seq, "%4s    %4d             %8s\n",
375                                 dev->pnp.bus_id, (u32) dev->wakeup.sleep_state,
376                                 dev->wakeup.state.enabled ? "*enabled" : "*disabled");
377                 else
378                         seq_printf(seq, "%4s    %4d             %8s\n",
379                                 dev->pnp.bus_id, (u32) dev->wakeup.sleep_state,
380                                 dev->wakeup.state.enabled ? "enabled" : "disabled");
381                 spin_lock(&acpi_device_lock);
382         }
383         spin_unlock(&acpi_device_lock);
384         return 0;
385 }
386
387 static ssize_t
388 acpi_system_write_wakeup_device (
389         struct file             *file,
390         const char __user       *buffer,
391         size_t                  count,
392         loff_t                  *ppos)
393 {
394         struct list_head * node, * next;
395         char            strbuf[5];
396         char            str[5] = "";
397         int             len = count;
398
399         if (len > 4) len = 4;
400
401         if (copy_from_user(strbuf, buffer, len))
402                 return -EFAULT;
403         strbuf[len] = '\0';
404         sscanf(strbuf, "%s", str);
405
406         spin_lock(&acpi_device_lock);
407         list_for_each_safe(node, next, &acpi_wakeup_device_list) {
408                 struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
409                 if (!dev->wakeup.flags.valid)
410                         continue;
411
412                 if (!strncmp(dev->pnp.bus_id, str, 4)) {
413                         dev->wakeup.state.enabled = dev->wakeup.state.enabled ? 0:1;
414                         break;
415                 }
416         }
417         spin_unlock(&acpi_device_lock);
418         return count;
419 }
420
421 static int
422 acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
423 {
424         return single_open(file, acpi_system_wakeup_device_seq_show, PDE(inode)->data);
425 }
426
427 static struct file_operations acpi_system_wakeup_device_fops = {
428         .open           = acpi_system_wakeup_device_open_fs,
429         .read           = seq_read,
430         .write          = acpi_system_write_wakeup_device,
431         .llseek         = seq_lseek,
432         .release        = single_release,
433 };
434
435 static struct file_operations acpi_system_sleep_fops = {
436         .open           = acpi_system_sleep_open_fs,
437         .read           = seq_read,
438         .write          = acpi_system_write_sleep,
439         .llseek         = seq_lseek,
440         .release        = single_release,
441 };
442
443 static struct file_operations acpi_system_alarm_fops = {
444         .open           = acpi_system_alarm_open_fs,
445         .read           = seq_read,
446         .write          = acpi_system_write_alarm,
447         .llseek         = seq_lseek,
448         .release        = single_release,
449 };
450
451
452 static int acpi_sleep_proc_init(void)
453 {
454         struct proc_dir_entry   *entry = NULL;
455
456         if (acpi_disabled)
457                 return 0;
458  
459         /* 'sleep' [R/W]*/
460         entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP,
461                                   S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
462         if (entry)
463                 entry->proc_fops = &acpi_system_sleep_fops;
464
465         /* 'alarm' [R/W] */
466         entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM,
467                 S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
468         if (entry)
469                 entry->proc_fops = &acpi_system_alarm_fops;
470
471         /* 'wakeup device' [R/W]*/
472         entry = create_proc_entry(ACPI_SYSTEM_FILE_WAKEUP_DEVICE,
473                                   S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
474         if (entry)
475                 entry->proc_fops = &acpi_system_wakeup_device_fops;
476
477         return 0;
478 }
479
480 late_initcall(acpi_sleep_proc_init);