OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [acpi/] [sleep/] [proc.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
#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 _COMPONENT              ACPI_SYSTEM_COMPONENT
17
 
18
/*
19
 * this file provides support for:
20
 * /proc/acpi/sleep
21
 * /proc/acpi/alarm
22
 * /proc/acpi/wakeup
23
 */
24
 
25
ACPI_MODULE_NAME("sleep")
26
#ifdef  CONFIG_ACPI_PROCFS
27
static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
28
{
29
        int i;
30
 
31
        ACPI_FUNCTION_TRACE("acpi_system_sleep_seq_show");
32
 
33
        for (i = 0; i <= ACPI_STATE_S5; i++) {
34
                if (sleep_states[i]) {
35
                        seq_printf(seq, "S%d ", i);
36
                }
37
        }
38
 
39
        seq_puts(seq, "\n");
40
 
41
        return 0;
42
}
43
 
44
static int acpi_system_sleep_open_fs(struct inode *inode, struct file *file)
45
{
46
        return single_open(file, acpi_system_sleep_seq_show, PDE(inode)->data);
47
}
48
 
49
static ssize_t
50
acpi_system_write_sleep(struct file *file,
51
                        const char __user * buffer, size_t count, loff_t * ppos)
52
{
53
        char str[12];
54
        u32 state = 0;
55
        int error = 0;
56
 
57
        if (count > sizeof(str) - 1)
58
                goto Done;
59
        memset(str, 0, sizeof(str));
60
        if (copy_from_user(str, buffer, count))
61
                return -EFAULT;
62
 
63
        /* Check for S4 bios request */
64
        if (!strcmp(str, "4b")) {
65
                error = acpi_suspend(4);
66
                goto Done;
67
        }
68
        state = simple_strtoul(str, NULL, 0);
69
#ifdef CONFIG_HIBERNATION
70
        if (state == 4) {
71
                error = hibernate();
72
                goto Done;
73
        }
74
#endif
75
        error = acpi_suspend(state);
76
      Done:
77
        return error ? error : count;
78
}
79
#endif                          /* CONFIG_ACPI_PROCFS */
80
 
81
#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || !defined(CONFIG_X86)
82
/* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */
83
#else
84
#define HAVE_ACPI_LEGACY_ALARM
85
#endif
86
 
87
#ifdef  HAVE_ACPI_LEGACY_ALARM
88
 
89
static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
90
{
91
        u32 sec, min, hr;
92
        u32 day, mo, yr, cent = 0;
93
        unsigned char rtc_control = 0;
94
        unsigned long flags;
95
 
96
        ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show");
97
 
98
        spin_lock_irqsave(&rtc_lock, flags);
99
 
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);
104
 
105
        /* If we ever get an FACP with proper values... */
106
        if (acpi_gbl_FADT.day_alarm)
107
                /* ACPI spec: only low 6 its should be cared */
108
                day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F;
109
        else
110
                day = CMOS_READ(RTC_DAY_OF_MONTH);
111
        if (acpi_gbl_FADT.month_alarm)
112
                mo = CMOS_READ(acpi_gbl_FADT.month_alarm);
113
        else
114
                mo = CMOS_READ(RTC_MONTH);
115
        if (acpi_gbl_FADT.century)
116
                cent = CMOS_READ(acpi_gbl_FADT.century);
117
 
118
        yr = CMOS_READ(RTC_YEAR);
119
 
120
        spin_unlock_irqrestore(&rtc_lock, flags);
121
 
122
        if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
123
                BCD_TO_BIN(sec);
124
                BCD_TO_BIN(min);
125
                BCD_TO_BIN(hr);
126
                BCD_TO_BIN(day);
127
                BCD_TO_BIN(mo);
128
                BCD_TO_BIN(yr);
129
                BCD_TO_BIN(cent);
130
        }
131
 
132
        /* we're trusting the FADT (see above) */
133
        if (!acpi_gbl_FADT.century)
134
                /* If we're not trusting the FADT, we should at least make it
135
                 * right for _this_ century... ehm, what is _this_ century?
136
                 *
137
                 * TBD:
138
                 *  ASAP: find piece of code in the kernel, e.g. star tracker driver,
139
                 *        which we can trust to determine the century correctly. Atom
140
                 *        watch driver would be nice, too...
141
                 *
142
                 *  if that has not happened, change for first release in 2050:
143
                 *        if (yr<50)
144
                 *                yr += 2100;
145
                 *        else
146
                 *                yr += 2000;   // current line of code
147
                 *
148
                 *  if that has not happened either, please do on 2099/12/31:23:59:59
149
                 *        s/2000/2100
150
                 *
151
                 */
152
                yr += 2000;
153
        else
154
                yr += cent * 100;
155
 
156
        seq_printf(seq, "%4.4u-", yr);
157
        (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo);
158
        (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day);
159
        (hr > 23) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", hr);
160
        (min > 59) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", min);
161
        (sec > 59) ? seq_puts(seq, "**\n") : seq_printf(seq, "%2.2u\n", sec);
162
 
163
        return 0;
164
}
165
 
166
static int acpi_system_alarm_open_fs(struct inode *inode, struct file *file)
167
{
168
        return single_open(file, acpi_system_alarm_seq_show, PDE(inode)->data);
169
}
170
 
171
static int get_date_field(char **p, u32 * value)
172
{
173
        char *next = NULL;
174
        char *string_end = NULL;
175
        int result = -EINVAL;
176
 
177
        /*
178
         * Try to find delimeter, only to insert null.  The end of the
179
         * string won't have one, but is still valid.
180
         */
181
        next = strpbrk(*p, "- :");
182
        if (next)
183
                *next++ = '\0';
184
 
185
        *value = simple_strtoul(*p, &string_end, 10);
186
 
187
        /* Signal success if we got a good digit */
188
        if (string_end != *p)
189
                result = 0;
190
 
191
        if (next)
192
                *p = next;
193
 
194
        return result;
195
}
196
 
197
/* Read a possibly BCD register, always return binary */
198
static u32 cmos_bcd_read(int offset, int rtc_control)
199
{
200
        u32 val = CMOS_READ(offset);
201
        if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
202
                BCD_TO_BIN(val);
203
        return val;
204
}
205
 
206
/* Write binary value into possibly BCD register */
207
static void cmos_bcd_write(u32 val, int offset, int rtc_control)
208
{
209
        if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
210
                BIN_TO_BCD(val);
211
        CMOS_WRITE(val, offset);
212
}
213
 
214
static ssize_t
215
acpi_system_write_alarm(struct file *file,
216
                        const char __user * buffer, size_t count, loff_t * ppos)
217
{
218
        int result = 0;
219
        char alarm_string[30] = { '\0' };
220
        char *p = alarm_string;
221
        u32 sec, min, hr, day, mo, yr;
222
        int adjust = 0;
223
        unsigned char rtc_control = 0;
224
 
225
        ACPI_FUNCTION_TRACE("acpi_system_write_alarm");
226
 
227
        if (count > sizeof(alarm_string) - 1)
228
                return_VALUE(-EINVAL);
229
 
230
        if (copy_from_user(alarm_string, buffer, count))
231
                return_VALUE(-EFAULT);
232
 
233
        alarm_string[count] = '\0';
234
 
235
        /* check for time adjustment */
236
        if (alarm_string[0] == '+') {
237
                p++;
238
                adjust = 1;
239
        }
240
 
241
        if ((result = get_date_field(&p, &yr)))
242
                goto end;
243
        if ((result = get_date_field(&p, &mo)))
244
                goto end;
245
        if ((result = get_date_field(&p, &day)))
246
                goto end;
247
        if ((result = get_date_field(&p, &hr)))
248
                goto end;
249
        if ((result = get_date_field(&p, &min)))
250
                goto end;
251
        if ((result = get_date_field(&p, &sec)))
252
                goto end;
253
 
254
        if (sec > 59) {
255
                min += 1;
256
                sec -= 60;
257
        }
258
        if (min > 59) {
259
                hr += 1;
260
                min -= 60;
261
        }
262
        if (hr > 23) {
263
                day += 1;
264
                hr -= 24;
265
        }
266
        if (day > 31) {
267
                mo += 1;
268
                day -= 31;
269
        }
270
        if (mo > 12) {
271
                yr += 1;
272
                mo -= 12;
273
        }
274
 
275
        spin_lock_irq(&rtc_lock);
276
 
277
        rtc_control = CMOS_READ(RTC_CONTROL);
278
 
279
        if (adjust) {
280
                yr += cmos_bcd_read(RTC_YEAR, rtc_control);
281
                mo += cmos_bcd_read(RTC_MONTH, rtc_control);
282
                day += cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control);
283
                hr += cmos_bcd_read(RTC_HOURS, rtc_control);
284
                min += cmos_bcd_read(RTC_MINUTES, rtc_control);
285
                sec += cmos_bcd_read(RTC_SECONDS, rtc_control);
286
        }
287
 
288
        spin_unlock_irq(&rtc_lock);
289
 
290
        if (sec > 59) {
291
                min++;
292
                sec -= 60;
293
        }
294
        if (min > 59) {
295
                hr++;
296
                min -= 60;
297
        }
298
        if (hr > 23) {
299
                day++;
300
                hr -= 24;
301
        }
302
        if (day > 31) {
303
                mo++;
304
                day -= 31;
305
        }
306
        if (mo > 12) {
307
                yr++;
308
                mo -= 12;
309
        }
310
 
311
        spin_lock_irq(&rtc_lock);
312
        /*
313
         * Disable alarm interrupt before setting alarm timer or else
314
         * when ACPI_EVENT_RTC is enabled, a spurious ACPI interrupt occurs
315
         */
316
        rtc_control &= ~RTC_AIE;
317
        CMOS_WRITE(rtc_control, RTC_CONTROL);
318
        CMOS_READ(RTC_INTR_FLAGS);
319
 
320
        /* write the fields the rtc knows about */
321
        cmos_bcd_write(hr, RTC_HOURS_ALARM, rtc_control);
322
        cmos_bcd_write(min, RTC_MINUTES_ALARM, rtc_control);
323
        cmos_bcd_write(sec, RTC_SECONDS_ALARM, rtc_control);
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 (acpi_gbl_FADT.day_alarm)
331
                cmos_bcd_write(day, acpi_gbl_FADT.day_alarm, rtc_control);
332
        if (acpi_gbl_FADT.month_alarm)
333
                cmos_bcd_write(mo, acpi_gbl_FADT.month_alarm, rtc_control);
334
        if (acpi_gbl_FADT.century)
335
                cmos_bcd_write(yr / 100, acpi_gbl_FADT.century, rtc_control);
336
        /* enable the rtc alarm interrupt */
337
        rtc_control |= RTC_AIE;
338
        CMOS_WRITE(rtc_control, RTC_CONTROL);
339
        CMOS_READ(RTC_INTR_FLAGS);
340
 
341
        spin_unlock_irq(&rtc_lock);
342
 
343
        acpi_clear_event(ACPI_EVENT_RTC);
344
        acpi_enable_event(ACPI_EVENT_RTC, 0);
345
 
346
        *ppos += count;
347
 
348
        result = 0;
349
      end:
350
        return_VALUE(result ? result : count);
351
}
352
#endif                          /* HAVE_ACPI_LEGACY_ALARM */
353
 
354
extern struct list_head acpi_wakeup_device_list;
355
extern spinlock_t acpi_device_lock;
356
 
357
static int
358
acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
359
{
360
        struct list_head *node, *next;
361
 
362
        seq_printf(seq, "Device\tS-state\t  Status   Sysfs node\n");
363
 
364
        spin_lock(&acpi_device_lock);
365
        list_for_each_safe(node, next, &acpi_wakeup_device_list) {
366
                struct acpi_device *dev =
367
                    container_of(node, struct acpi_device, wakeup_list);
368
                struct device *ldev;
369
 
370
                if (!dev->wakeup.flags.valid)
371
                        continue;
372
                spin_unlock(&acpi_device_lock);
373
 
374
                ldev = acpi_get_physical_device(dev->handle);
375
                seq_printf(seq, "%s\t  S%d\t%c%-8s  ",
376
                           dev->pnp.bus_id,
377
                           (u32) dev->wakeup.sleep_state,
378
                           dev->wakeup.flags.run_wake ? '*' : ' ',
379
                           dev->wakeup.state.enabled ? "enabled" : "disabled");
380
                if (ldev)
381
                        seq_printf(seq, "%s:%s",
382
                                   ldev->bus ? ldev->bus->name : "no-bus",
383
                                   ldev->bus_id);
384
                seq_printf(seq, "\n");
385
                put_device(ldev);
386
 
387
                spin_lock(&acpi_device_lock);
388
        }
389
        spin_unlock(&acpi_device_lock);
390
        return 0;
391
}
392
 
393
static ssize_t
394
acpi_system_write_wakeup_device(struct file *file,
395
                                const char __user * buffer,
396
                                size_t count, loff_t * ppos)
397
{
398
        struct list_head *node, *next;
399
        char strbuf[5];
400
        char str[5] = "";
401
        int len = count;
402
        struct acpi_device *found_dev = NULL;
403
 
404
        if (len > 4)
405
                len = 4;
406
 
407
        if (copy_from_user(strbuf, buffer, len))
408
                return -EFAULT;
409
        strbuf[len] = '\0';
410
        sscanf(strbuf, "%s", str);
411
 
412
        spin_lock(&acpi_device_lock);
413
        list_for_each_safe(node, next, &acpi_wakeup_device_list) {
414
                struct acpi_device *dev =
415
                    container_of(node, struct acpi_device, wakeup_list);
416
                if (!dev->wakeup.flags.valid)
417
                        continue;
418
 
419
                if (!strncmp(dev->pnp.bus_id, str, 4)) {
420
                        dev->wakeup.state.enabled =
421
                            dev->wakeup.state.enabled ? 0 : 1;
422
                        found_dev = dev;
423
                        break;
424
                }
425
        }
426
        if (found_dev) {
427
                list_for_each_safe(node, next, &acpi_wakeup_device_list) {
428
                        struct acpi_device *dev = container_of(node,
429
                                                               struct
430
                                                               acpi_device,
431
                                                               wakeup_list);
432
 
433
                        if ((dev != found_dev) &&
434
                            (dev->wakeup.gpe_number ==
435
                             found_dev->wakeup.gpe_number)
436
                            && (dev->wakeup.gpe_device ==
437
                                found_dev->wakeup.gpe_device)) {
438
                                printk(KERN_WARNING
439
                                       "ACPI: '%s' and '%s' have the same GPE, "
440
                                       "can't disable/enable one seperately\n",
441
                                       dev->pnp.bus_id, found_dev->pnp.bus_id);
442
                                dev->wakeup.state.enabled =
443
                                    found_dev->wakeup.state.enabled;
444
                        }
445
                }
446
        }
447
        spin_unlock(&acpi_device_lock);
448
        return count;
449
}
450
 
451
static int
452
acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
453
{
454
        return single_open(file, acpi_system_wakeup_device_seq_show,
455
                           PDE(inode)->data);
456
}
457
 
458
static const struct file_operations acpi_system_wakeup_device_fops = {
459
        .open = acpi_system_wakeup_device_open_fs,
460
        .read = seq_read,
461
        .write = acpi_system_write_wakeup_device,
462
        .llseek = seq_lseek,
463
        .release = single_release,
464
};
465
 
466
#ifdef  CONFIG_ACPI_PROCFS
467
static const struct file_operations acpi_system_sleep_fops = {
468
        .open = acpi_system_sleep_open_fs,
469
        .read = seq_read,
470
        .write = acpi_system_write_sleep,
471
        .llseek = seq_lseek,
472
        .release = single_release,
473
};
474
#endif                          /* CONFIG_ACPI_PROCFS */
475
 
476
#ifdef  HAVE_ACPI_LEGACY_ALARM
477
static const struct file_operations acpi_system_alarm_fops = {
478
        .open = acpi_system_alarm_open_fs,
479
        .read = seq_read,
480
        .write = acpi_system_write_alarm,
481
        .llseek = seq_lseek,
482
        .release = single_release,
483
};
484
 
485
static u32 rtc_handler(void *context)
486
{
487
        acpi_clear_event(ACPI_EVENT_RTC);
488
        acpi_disable_event(ACPI_EVENT_RTC, 0);
489
 
490
        return ACPI_INTERRUPT_HANDLED;
491
}
492
#endif                          /* HAVE_ACPI_LEGACY_ALARM */
493
 
494
static int __init acpi_sleep_proc_init(void)
495
{
496
        struct proc_dir_entry *entry = NULL;
497
 
498
        if (acpi_disabled)
499
                return 0;
500
 
501
#ifdef  CONFIG_ACPI_PROCFS
502
        /* 'sleep' [R/W] */
503
        entry =
504
            create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR,
505
                              acpi_root_dir);
506
        if (entry)
507
                entry->proc_fops = &acpi_system_sleep_fops;
508
#endif                          /* CONFIG_ACPI_PROCFS */
509
 
510
#ifdef  HAVE_ACPI_LEGACY_ALARM
511
        /* 'alarm' [R/W] */
512
        entry =
513
            create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR,
514
                              acpi_root_dir);
515
        if (entry)
516
                entry->proc_fops = &acpi_system_alarm_fops;
517
 
518
        acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
519
#endif                          /* HAVE_ACPI_LEGACY_ALARM */
520
 
521
        /* 'wakeup device' [R/W] */
522
        entry =
523
            create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
524
                              acpi_root_dir);
525
        if (entry)
526
                entry->proc_fops = &acpi_system_wakeup_device_fops;
527
 
528
        return 0;
529
}
530
 
531
late_initcall(acpi_sleep_proc_init);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.