vserver 2.0 rc7
[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                 error = 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         unsigned char           rtc_control = 0;
87         unsigned long           flags;
88
89         ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show");
90
91         spin_lock_irqsave(&rtc_lock, flags);
92
93         sec = CMOS_READ(RTC_SECONDS_ALARM);
94         min = CMOS_READ(RTC_MINUTES_ALARM);
95         hr = CMOS_READ(RTC_HOURS_ALARM);
96         rtc_control = CMOS_READ(RTC_CONTROL);
97
98         /* If we ever get an FACP with proper values... */
99         if (acpi_gbl_FADT->day_alrm)
100                 /* ACPI spec: only low 6 its should be cared */
101                 day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F;
102         else
103                 day =  CMOS_READ(RTC_DAY_OF_MONTH);
104         if (acpi_gbl_FADT->mon_alrm)
105                 mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
106         else
107                 mo = CMOS_READ(RTC_MONTH);
108         if (acpi_gbl_FADT->century)
109                 yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR);
110         else
111                 yr = CMOS_READ(RTC_YEAR);
112
113         spin_unlock_irqrestore(&rtc_lock, flags);
114
115         if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
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
124         /* we're trusting the FADT (see above)*/
125         if (!acpi_gbl_FADT->century)
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
146         seq_printf(seq,"%4.4u-", yr);
147         (mo > 12)  ? seq_puts(seq, "**-")  : seq_printf(seq, "%2.2u-", mo);
148         (day > 31) ? seq_puts(seq, "** ")  : seq_printf(seq, "%2.2u ", day);
149         (hr > 23)  ? seq_puts(seq, "**:")  : seq_printf(seq, "%2.2u:", hr);
150         (min > 59) ? seq_puts(seq, "**:")  : seq_printf(seq, "%2.2u:", min);
151         (sec > 59) ? seq_puts(seq, "**\n") : seq_printf(seq, "%2.2u\n", sec);
152
153         return 0;
154 }
155
156 static int acpi_system_alarm_open_fs(struct inode *inode, struct file *file)
157 {
158         return single_open(file, acpi_system_alarm_seq_show, PDE(inode)->data);
159 }
160
161
162 static int
163 get_date_field (
164         char                    **p,
165         u32                     *value)
166 {
167         char                    *next = NULL;
168         char                    *string_end = NULL;
169         int                     result = -EINVAL;
170
171         /*
172          * Try to find delimeter, only to insert null.  The end of the
173          * string won't have one, but is still valid.
174          */
175         next = strpbrk(*p, "- :");
176         if (next)
177                 *next++ = '\0';
178
179         *value = simple_strtoul(*p, &string_end, 10);
180
181         /* Signal success if we got a good digit */
182         if (string_end != *p)
183                 result = 0;
184
185         if (next)
186                 *p = next;
187
188         return result;
189 }
190
191
192 static ssize_t
193 acpi_system_write_alarm (
194         struct file             *file,
195         const char __user       *buffer,
196         size_t                  count,
197         loff_t                  *ppos)
198 {
199         int                     result = 0;
200         char                    alarm_string[30] = {'\0'};
201         char                    *p = alarm_string;
202         u32                     sec, min, hr, day, mo, yr;
203         int                     adjust = 0;
204         unsigned char           rtc_control = 0;
205
206         ACPI_FUNCTION_TRACE("acpi_system_write_alarm");
207
208         if (count > sizeof(alarm_string) - 1)
209                 return_VALUE(-EINVAL);
210         
211         if (copy_from_user(alarm_string, buffer, count))
212                 return_VALUE(-EFAULT);
213
214         alarm_string[count] = '\0';
215
216         /* check for time adjustment */
217         if (alarm_string[0] == '+') {
218                 p++;
219                 adjust = 1;
220         }
221
222         if ((result = get_date_field(&p, &yr)))
223                 goto end;
224         if ((result = get_date_field(&p, &mo)))
225                 goto end;
226         if ((result = get_date_field(&p, &day)))
227                 goto end;
228         if ((result = get_date_field(&p, &hr)))
229                 goto end;
230         if ((result = get_date_field(&p, &min)))
231                 goto end;
232         if ((result = get_date_field(&p, &sec)))
233                 goto end;
234
235         if (sec > 59) {
236                 min += 1;
237                 sec -= 60;
238         }
239         if (min > 59) {
240                 hr += 1;
241                 min -= 60;
242         }
243         if (hr > 23) {
244                 day += 1;
245                 hr -= 24;
246         }
247         if (day > 31) {
248                 mo += 1;
249                 day -= 31;
250         }
251         if (mo > 12) {
252                 yr += 1;
253                 mo -= 12;
254         }
255
256         spin_lock_irq(&rtc_lock);
257
258         rtc_control = CMOS_READ(RTC_CONTROL);
259         if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
260                 BIN_TO_BCD(yr);
261                 BIN_TO_BCD(mo);
262                 BIN_TO_BCD(day);
263                 BIN_TO_BCD(hr);
264                 BIN_TO_BCD(min);
265                 BIN_TO_BCD(sec);
266         }
267
268         if (adjust) {
269                 yr  += CMOS_READ(RTC_YEAR);
270                 mo  += CMOS_READ(RTC_MONTH);
271                 day += CMOS_READ(RTC_DAY_OF_MONTH);
272                 hr  += CMOS_READ(RTC_HOURS);
273                 min += CMOS_READ(RTC_MINUTES);
274                 sec += CMOS_READ(RTC_SECONDS);
275         }
276
277         spin_unlock_irq(&rtc_lock);
278
279         if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
280                 BCD_TO_BIN(yr);
281                 BCD_TO_BIN(mo);
282                 BCD_TO_BIN(day);
283                 BCD_TO_BIN(hr);
284                 BCD_TO_BIN(min);
285                 BCD_TO_BIN(sec);
286         }
287
288         if (sec > 59) {
289                 min++;
290                 sec -= 60;
291         }
292         if (min > 59) {
293                 hr++;
294                 min -= 60;
295         }
296         if (hr > 23) {
297                 day++;
298                 hr -= 24;
299         }
300         if (day > 31) {
301                 mo++;
302                 day -= 31;
303         }
304         if (mo > 12) {
305                 yr++;
306                 mo -= 12;
307         }
308         if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
309                 BIN_TO_BCD(yr);
310                 BIN_TO_BCD(mo);
311                 BIN_TO_BCD(day);
312                 BIN_TO_BCD(hr);
313                 BIN_TO_BCD(min);
314                 BIN_TO_BCD(sec);
315         }
316
317         spin_lock_irq(&rtc_lock);
318         /*
319          * Disable alarm interrupt before setting alarm timer or else
320          * when ACPI_EVENT_RTC is enabled, a spurious ACPI interrupt occurs
321          */
322         rtc_control &= ~RTC_AIE;
323         CMOS_WRITE(rtc_control, RTC_CONTROL);
324         CMOS_READ(RTC_INTR_FLAGS);
325
326         /* write the fields the rtc knows about */
327         CMOS_WRITE(hr, RTC_HOURS_ALARM);
328         CMOS_WRITE(min, RTC_MINUTES_ALARM);
329         CMOS_WRITE(sec, RTC_SECONDS_ALARM);
330
331         /*
332          * If the system supports an enhanced alarm it will have non-zero
333          * offsets into the CMOS RAM here -- which for some reason are pointing
334          * to the RTC area of memory.
335          */
336         if (acpi_gbl_FADT->day_alrm)
337                 CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
338         if (acpi_gbl_FADT->mon_alrm)
339                 CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
340         if (acpi_gbl_FADT->century)
341                 CMOS_WRITE(yr/100, acpi_gbl_FADT->century);
342         /* enable the rtc alarm interrupt */
343         rtc_control |= RTC_AIE;
344         CMOS_WRITE(rtc_control, RTC_CONTROL);
345         CMOS_READ(RTC_INTR_FLAGS);
346
347         spin_unlock_irq(&rtc_lock);
348
349         acpi_clear_event(ACPI_EVENT_RTC);
350         acpi_enable_event(ACPI_EVENT_RTC, 0);
351
352         *ppos += count;
353
354         result = 0;
355 end:
356         return_VALUE(result ? result : count);
357 }
358
359 extern struct list_head acpi_wakeup_device_list;
360 extern spinlock_t acpi_device_lock;
361
362 static int
363 acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
364 {
365         struct list_head * node, * next;
366
367         seq_printf(seq, "Device Sleep state     Status\n");
368
369         spin_lock(&acpi_device_lock);
370         list_for_each_safe(node, next, &acpi_wakeup_device_list) {
371                 struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
372
373                 if (!dev->wakeup.flags.valid)
374                         continue;
375                 spin_unlock(&acpi_device_lock);
376                 if (dev->wakeup.flags.run_wake)
377                         seq_printf(seq, "%4s    %4d             %8s\n",
378                                 dev->pnp.bus_id, (u32) dev->wakeup.sleep_state,
379                                 dev->wakeup.state.enabled ? "*enabled" : "*disabled");
380                 else
381                         seq_printf(seq, "%4s    %4d             %8s\n",
382                                 dev->pnp.bus_id, (u32) dev->wakeup.sleep_state,
383                                 dev->wakeup.state.enabled ? "enabled" : "disabled");
384                 spin_lock(&acpi_device_lock);
385         }
386         spin_unlock(&acpi_device_lock);
387         return 0;
388 }
389
390 static ssize_t
391 acpi_system_write_wakeup_device (
392         struct file             *file,
393         const char __user       *buffer,
394         size_t                  count,
395         loff_t                  *ppos)
396 {
397         struct list_head * node, * next;
398         char            strbuf[5];
399         char            str[5] = "";
400         int             len = count;
401         struct acpi_device *found_dev = NULL;
402
403         if (len > 4) len = 4;
404
405         if (copy_from_user(strbuf, buffer, len))
406                 return -EFAULT;
407         strbuf[len] = '\0';
408         sscanf(strbuf, "%s", str);
409
410         spin_lock(&acpi_device_lock);
411         list_for_each_safe(node, next, &acpi_wakeup_device_list) {
412                 struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
413                 if (!dev->wakeup.flags.valid)
414                         continue;
415
416                 if (!strncmp(dev->pnp.bus_id, str, 4)) {
417                         dev->wakeup.state.enabled = dev->wakeup.state.enabled ? 0:1;
418                         found_dev = dev;
419                         break;
420                 }
421         }
422         if (found_dev) {
423                 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
424                         struct acpi_device * dev = container_of(node,
425                                 struct acpi_device, wakeup_list);
426
427                         if ((dev != found_dev) &&
428                                 (dev->wakeup.gpe_number == found_dev->wakeup.gpe_number) &&
429                                 (dev->wakeup.gpe_device == found_dev->wakeup.gpe_device)) {
430                                 printk(KERN_WARNING "ACPI: '%s' and '%s' have the same GPE, "
431                                         "can't disable/enable one seperately\n",
432                                         dev->pnp.bus_id, found_dev->pnp.bus_id);
433                                 dev->wakeup.state.enabled = found_dev->wakeup.state.enabled;
434                         }
435                 }
436         }
437         spin_unlock(&acpi_device_lock);
438         return count;
439 }
440
441 static int
442 acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
443 {
444         return single_open(file, acpi_system_wakeup_device_seq_show, PDE(inode)->data);
445 }
446
447 static struct file_operations acpi_system_wakeup_device_fops = {
448         .open           = acpi_system_wakeup_device_open_fs,
449         .read           = seq_read,
450         .write          = acpi_system_write_wakeup_device,
451         .llseek         = seq_lseek,
452         .release        = single_release,
453 };
454
455 static struct file_operations acpi_system_sleep_fops = {
456         .open           = acpi_system_sleep_open_fs,
457         .read           = seq_read,
458         .write          = acpi_system_write_sleep,
459         .llseek         = seq_lseek,
460         .release        = single_release,
461 };
462
463 static struct file_operations acpi_system_alarm_fops = {
464         .open           = acpi_system_alarm_open_fs,
465         .read           = seq_read,
466         .write          = acpi_system_write_alarm,
467         .llseek         = seq_lseek,
468         .release        = single_release,
469 };
470
471
472 static u32 rtc_handler(void * context)
473 {
474         acpi_clear_event(ACPI_EVENT_RTC);
475         acpi_disable_event(ACPI_EVENT_RTC, 0);
476
477         return ACPI_INTERRUPT_HANDLED;
478 }
479
480 static int acpi_sleep_proc_init(void)
481 {
482         struct proc_dir_entry   *entry = NULL;
483
484         if (acpi_disabled)
485                 return 0;
486  
487         /* 'sleep' [R/W]*/
488         entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP,
489                                   S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
490         if (entry)
491                 entry->proc_fops = &acpi_system_sleep_fops;
492
493         /* 'alarm' [R/W] */
494         entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM,
495                 S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
496         if (entry)
497                 entry->proc_fops = &acpi_system_alarm_fops;
498
499         /* 'wakeup device' [R/W]*/
500         entry = create_proc_entry(ACPI_SYSTEM_FILE_WAKEUP_DEVICE,
501                                   S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
502         if (entry)
503                 entry->proc_fops = &acpi_system_wakeup_device_fops;
504
505         acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
506         return 0;
507 }
508
509 late_initcall(acpi_sleep_proc_init);