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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [acpi/] [system.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  acpi_system.c - ACPI System Driver ($Revision: 1.1.1.1 $)
3
 *
4
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6
 *
7
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or (at
12
 *  your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful, but
15
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 *  General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License along
20
 *  with this program; if not, write to the Free Software Foundation, Inc.,
21
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22
 *
23
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24
 */
25
 
26
#include <linux/config.h>
27
#include <linux/kernel.h>
28
#include <linux/module.h>
29
#include <linux/init.h>
30
#include <linux/types.h>
31
#include <linux/spinlock.h>
32
#include <linux/poll.h>
33
#include <linux/delay.h>
34
#include <linux/interrupt.h>
35
#include <linux/sysrq.h>
36
#include <linux/compatmac.h>
37
#include <linux/proc_fs.h>
38
#include <linux/pm.h>
39
#include <asm/uaccess.h>
40
#include <asm/acpi.h>
41
#include <acpi/acpi_bus.h>
42
#include <acpi/acpi_drivers.h>
43
#include <linux/sched.h>
44
 
45
#ifdef CONFIG_ACPI_SLEEP
46
#include <linux/mc146818rtc.h>
47
#include <linux/irq.h>
48
#include <asm/hw_irq.h>
49
 
50
acpi_status acpi_system_save_state(u32);
51
#else
52
static inline acpi_status acpi_system_save_state(u32 state)
53
{
54
        return AE_OK;
55
}
56
#endif /* !CONFIG_ACPI_SLEEP */
57
 
58
#define _COMPONENT              ACPI_SYSTEM_COMPONENT
59
ACPI_MODULE_NAME                ("acpi_system")
60
 
61
#define PREFIX                  "ACPI: "
62
 
63
extern FADT_DESCRIPTOR          acpi_fadt;
64
 
65
static int acpi_system_add (struct acpi_device *device);
66
static int acpi_system_remove (struct acpi_device *device, int type);
67
 
68
acpi_status acpi_suspend (u32 state);
69
 
70
static struct acpi_driver acpi_system_driver = {
71
        .name =         ACPI_SYSTEM_DRIVER_NAME,
72
        .class =        ACPI_SYSTEM_CLASS,
73
        .ids =          ACPI_SYSTEM_HID,
74
        .ops =          {
75
                                .add =          acpi_system_add,
76
                                .remove =       acpi_system_remove
77
                        },
78
};
79
 
80
struct acpi_system
81
{
82
        acpi_handle             handle;
83
        u8                      states[ACPI_S_STATE_COUNT];
84
};
85
 
86
/* Global vars for handling event proc entry */
87
static spinlock_t               acpi_system_event_lock = SPIN_LOCK_UNLOCKED;
88
int                             event_is_open = 0;
89
extern struct list_head         acpi_bus_event_list;
90
extern wait_queue_head_t        acpi_bus_event_queue;
91
 
92
/* --------------------------------------------------------------------------
93
                                  System Sleep
94
   -------------------------------------------------------------------------- */
95
 
96
#ifdef CONFIG_PM
97
 
98
static void
99
acpi_power_off (void)
100
{
101
        if (unlikely(in_interrupt()))
102
                BUG();
103
        /* Some SMP machines only can poweroff in boot CPU */
104
        set_cpus_allowed(current, 1UL << cpu_logical_map(0));
105
        acpi_system_save_state(ACPI_STATE_S5);
106
        acpi_enter_sleep_state_prep(ACPI_STATE_S5);
107
        ACPI_DISABLE_IRQS();
108
        acpi_enter_sleep_state(ACPI_STATE_S5);
109
 
110
        printk(KERN_EMERG "ACPI: can not power off machine\n");
111
}
112
 
113
#endif /*CONFIG_PM*/
114
 
115
 
116
#ifdef CONFIG_ACPI_SLEEP
117
 
118
/**
119
 * acpi_system_restore_state - OS-specific restoration of state
120
 * @state:      sleep state we're exiting
121
 *
122
 * Note that if we're coming back from S4, the memory image should have
123
 * already been loaded from the disk and is already in place.  (Otherwise how
124
 * else would we be here?).
125
 */
126
acpi_status
127
acpi_system_restore_state(
128
        u32                     state)
129
{
130
        /*
131
         * We should only be here if we're coming back from STR or STD.
132
         * And, in the case of the latter, the memory image should have already
133
         * been loaded from disk.
134
         */
135
        if (state > ACPI_STATE_S1) {
136
                acpi_restore_state_mem();
137
 
138
                /* Do _early_ resume for irqs.  Required by
139
                 * ACPI specs.
140
                 */
141
                /* TBD: call arch dependant reinitialization of the
142
                 * interrupts.
143
                 */
144
#ifdef CONFIG_X86
145
                init_8259A(0);
146
#endif
147
                /* wait for power to come back */
148
                mdelay(1000);
149
 
150
        }
151
 
152
        /* Be really sure that irqs are disabled. */
153
        ACPI_DISABLE_IRQS();
154
 
155
        /* Wait a little again, just in case... */
156
        mdelay(1000);
157
 
158
        /* enable interrupts once again */
159
        ACPI_ENABLE_IRQS();
160
 
161
        /* turn all the devices back on */
162
        if (state > ACPI_STATE_S1)
163
                pm_send_all(PM_RESUME, (void *)0);
164
 
165
        return AE_OK;
166
}
167
 
168
 
169
/**
170
 * acpi_system_save_state - save OS specific state and power down devices
171
 * @state:      sleep state we're entering.
172
 *
173
 * This handles saving all context to memory, and possibly disk.
174
 * First, we call to the device driver layer to save device state.
175
 * Once we have that, we save whatevery processor and kernel state we
176
 * need to memory.
177
 * If we're entering S4, we then write the memory image to disk.
178
 *
179
 * Only then it is safe for us to power down devices, since we may need
180
 * the disks and upstream buses to write to.
181
 */
182
acpi_status
183
acpi_system_save_state(
184
        u32                     state)
185
{
186
        int                     error = 0;
187
 
188
        /* Send notification to devices that they will be suspended.
189
         * If any device or driver cannot make the transition, either up
190
         * or down, we'll get an error back.
191
         */
192
        if (state > ACPI_STATE_S1) {
193
                error = pm_send_all(PM_SAVE_STATE, (void *)3);
194
                if (error)
195
                        return AE_ERROR;
196
        }
197
 
198
        if (state <= ACPI_STATE_S5) {
199
                /* Tell devices to stop I/O and actually save their state.
200
                 * It is theoretically possible that something could fail,
201
                 * so handle that gracefully..
202
                 */
203
                if (state > ACPI_STATE_S1 && state != ACPI_STATE_S5) {
204
                        error = pm_send_all(PM_SUSPEND, (void *)3);
205
                        if (error) {
206
                                /* Tell devices to restore state if they have
207
                                 * it saved and to start taking I/O requests.
208
                                 */
209
                                pm_send_all(PM_RESUME, (void *)0);
210
                                return error;
211
                        }
212
                }
213
 
214
                /* flush caches */
215
                ACPI_FLUSH_CPU_CACHE();
216
 
217
                /* Do arch specific saving of state. */
218
                if (state > ACPI_STATE_S1) {
219
                        error = acpi_save_state_mem();
220
 
221
                        /* TBD: if no s4bios, write codes for
222
                         * acpi_save_state_disk()...
223
                         */
224
#if 0
225
                        if (!error && (state == ACPI_STATE_S4))
226
                                error = acpi_save_state_disk();
227
#endif
228
                        if (error) {
229
                                pm_send_all(PM_RESUME, (void *)0);
230
                                return error;
231
                        }
232
                }
233
        }
234
        /* disable interrupts
235
         * Note that acpi_suspend -- our caller -- will do this once we return.
236
         * But, we want it done early, so we don't get any suprises during
237
         * the device suspend sequence.
238
         */
239
        ACPI_DISABLE_IRQS();
240
 
241
        /* Unconditionally turn off devices.
242
         * Obvious if we enter a sleep state.
243
         * If entering S5 (soft off), this should put devices in a
244
         * quiescent state.
245
         */
246
 
247
        if (state > ACPI_STATE_S1) {
248
                error = pm_send_all(PM_SUSPEND, (void *)3);
249
 
250
                /* We're pretty screwed if we got an error from this.
251
                 * We try to recover by simply calling our own restore_state
252
                 * function; see above for definition.
253
                 *
254
                 * If it's S5 though, go through with it anyway..
255
                 */
256
                if (error && state != ACPI_STATE_S5)
257
                        acpi_system_restore_state(state);
258
        }
259
        return error ? AE_ERROR : AE_OK;
260
}
261
 
262
 
263
/****************************************************************************
264
 *
265
 * FUNCTION:    acpi_system_suspend
266
 *
267
 * PARAMETERS:  %state: Sleep state to enter.
268
 *
269
 * RETURN:      acpi_status, whether or not we successfully entered and
270
 *              exited sleep.
271
 *
272
 * DESCRIPTION: Perform OS-specific action to enter sleep state.
273
 *              This is the final step in going to sleep, per spec.  If we
274
 *              know we're coming back (i.e. not entering S5), we save the
275
 *              processor flags. [ We'll have to save and restore them anyway,
276
 *              so we use the arch-agnostic save_flags and restore_flags
277
 *              here.]  We then set the place to return to in arch-specific
278
 *              globals using arch_set_return_point. Finally, we call the
279
 *              ACPI function to write the proper values to I/O ports.
280
 *
281
 ****************************************************************************/
282
 
283
acpi_status
284
acpi_system_suspend(
285
        u32             state)
286
{
287
        acpi_status             status = AE_ERROR;
288
        unsigned long           flags = 0;
289
 
290
        local_irq_save(flags);
291
        /* kernel_fpu_begin(); */
292
 
293
        switch (state) {
294
        case ACPI_STATE_S1:
295
        case ACPI_STATE_S5:
296
                barrier();
297
                status = acpi_enter_sleep_state(state);
298
                break;
299
        case ACPI_STATE_S4:
300
                do_suspend_lowlevel_s4bios(0);
301
                break;
302
        }
303
 
304
        /* kernel_fpu_end(); */
305
        local_irq_restore(flags);
306
 
307
        return status;
308
}
309
 
310
 
311
 
312
/**
313
 * acpi_suspend - OS-agnostic system suspend/resume support (S? states)
314
 * @state:      state we're entering
315
 *
316
 */
317
acpi_status
318
acpi_suspend (
319
        u32                     state)
320
{
321
        acpi_status status;
322
 
323
        /* only support S1 and S5 on kernel 2.4 */
324
        if (state != ACPI_STATE_S1 && state != ACPI_STATE_S4
325
            && state != ACPI_STATE_S5)
326
                return AE_ERROR;
327
 
328
 
329
        if (ACPI_STATE_S4 == state) {
330
                /* For s4bios, we need a wakeup address. */
331
                if (1 == acpi_gbl_FACS->S4bios_f &&
332
 
333
                        if (!acpi_wakeup_address)
334
                                return AE_ERROR;
335
                        acpi_set_firmware_waking_vector((acpi_physical_address) acpi_wakeup_address);
336
                } else
337
                        /* We don't support S4 under 2.4.  Give up */
338
                        return AE_ERROR;
339
        }
340
 
341
        status = acpi_system_save_state(state);
342
        if (!ACPI_SUCCESS(status) && state != ACPI_STATE_S5)
343
                return status;
344
 
345
        acpi_enter_sleep_state_prep(state);
346
 
347
        /* disable interrupts and flush caches */
348
        ACPI_DISABLE_IRQS();
349
        ACPI_FLUSH_CPU_CACHE();
350
 
351
        /* perform OS-specific sleep actions */
352
        status = acpi_system_suspend(state);
353
 
354
        /* Even if we failed to go to sleep, all of the devices are in an suspended
355
         * mode. So, we run these unconditionaly to make sure we have a usable system
356
         * no matter what.
357
         */
358
        acpi_leave_sleep_state(state);
359
        acpi_system_restore_state(state);
360
 
361
        /* make sure interrupts are enabled */
362
        ACPI_ENABLE_IRQS();
363
 
364
        /* reset firmware waking vector */
365
        acpi_set_firmware_waking_vector((acpi_physical_address) 0);
366
 
367
        return status;
368
}
369
 
370
#endif /* CONFIG_ACPI_SLEEP */
371
 
372
 
373
/* --------------------------------------------------------------------------
374
                              FS Interface (/proc)
375
   -------------------------------------------------------------------------- */
376
 
377
static int
378
acpi_system_read_info (
379
        char                    *page,
380
        char                    **start,
381
        off_t                   off,
382
        int                     count,
383
        int                     *eof,
384
        void                    *data)
385
{
386
        struct acpi_system      *system = (struct acpi_system *) data;
387
        char                    *p = page;
388
        int                     size = 0;
389
        u32                     i = 0;
390
 
391
        ACPI_FUNCTION_TRACE("acpi_system_read_info");
392
 
393
        if (!system || (off != 0))
394
                goto end;
395
 
396
        p += sprintf(p, "version:                 %x\n", ACPI_CA_VERSION);
397
 
398
        p += sprintf(p, "states:                  ");
399
        for (i=0; i<ACPI_S_STATE_COUNT; i++) {
400
                if (system->states[i]) {
401
                        p += sprintf(p, "S%d ", i);
402
                        if (i == ACPI_STATE_S4 &&
403
                            acpi_gbl_FACS->S4bios_f &&
404
 
405
                                p += sprintf(p, "S4Bios ");
406
                }
407
        }
408
        p += sprintf(p, "\n");
409
 
410
end:
411
        size = (p - page);
412
        if (size <= off+count) *eof = 1;
413
        *start = page + off;
414
        size -= off;
415
        if (size>count) size = count;
416
        if (size<0) size = 0;
417
 
418
        return_VALUE(size);
419
}
420
 
421
static int acpi_system_open_event(struct inode *inode, struct file *file);
422
static ssize_t acpi_system_read_event (struct file*, char*, size_t, loff_t*);
423
static int acpi_system_close_event(struct inode *inode, struct file *file);
424
static unsigned int acpi_system_poll_event(struct file *file, poll_table *wait);
425
 
426
 
427
static struct file_operations acpi_system_event_ops = {
428
        .open =         acpi_system_open_event,
429
        .read =         acpi_system_read_event,
430
        .release =      acpi_system_close_event,
431
        .poll =         acpi_system_poll_event,
432
};
433
 
434
static int
435
acpi_system_open_event(struct inode *inode, struct file *file)
436
{
437
        spin_lock_irq (&acpi_system_event_lock);
438
 
439
        if(event_is_open)
440
                goto out_busy;
441
 
442
        event_is_open = 1;
443
 
444
        spin_unlock_irq (&acpi_system_event_lock);
445
        return 0;
446
 
447
out_busy:
448
        spin_unlock_irq (&acpi_system_event_lock);
449
        return -EBUSY;
450
}
451
 
452
static ssize_t
453
acpi_system_read_event (
454
        struct file             *file,
455
        char                    *buffer,
456
        size_t                  count,
457
        loff_t                  *ppos)
458
{
459
        int                     result = 0;
460
        struct acpi_bus_event   event;
461
        static char             str[ACPI_MAX_STRING];
462
        static int              chars_remaining = 0;
463
        static char             *ptr;
464
 
465
 
466
        ACPI_FUNCTION_TRACE("acpi_system_read_event");
467
 
468
        if (!chars_remaining) {
469
                memset(&event, 0, sizeof(struct acpi_bus_event));
470
 
471
                if ((file->f_flags & O_NONBLOCK)
472
                    && (list_empty(&acpi_bus_event_list)))
473
                        return_VALUE(-EAGAIN);
474
 
475
                result = acpi_bus_receive_event(&event);
476
                if (result) {
477
                        return_VALUE(-EIO);
478
                }
479
 
480
                chars_remaining = sprintf(str, "%s %s %08x %08x\n",
481
                        event.device_class?event.device_class:"<unknown>",
482
                        event.bus_id?event.bus_id:"<unknown>",
483
                        event.type, event.data);
484
                ptr = str;
485
        }
486
 
487
        if (chars_remaining < count) {
488
                count = chars_remaining;
489
        }
490
 
491
        if (copy_to_user(buffer, ptr, count))
492
                return_VALUE(-EFAULT);
493
 
494
        *ppos += count;
495
        chars_remaining -= count;
496
        ptr += count;
497
 
498
        return_VALUE(count);
499
}
500
 
501
static int
502
acpi_system_close_event(struct inode *inode, struct file *file)
503
{
504
        spin_lock_irq (&acpi_system_event_lock);
505
        event_is_open = 0;
506
        spin_unlock_irq (&acpi_system_event_lock);
507
        return 0;
508
}
509
 
510
static unsigned int
511
acpi_system_poll_event(
512
        struct file             *file,
513
        poll_table              *wait)
514
{
515
        poll_wait(file, &acpi_bus_event_queue, wait);
516
        if (!list_empty(&acpi_bus_event_list))
517
                return POLLIN | POLLRDNORM;
518
        return 0;
519
}
520
 
521
static ssize_t acpi_system_read_dsdt (struct file*, char*, size_t, loff_t*);
522
 
523
static struct file_operations acpi_system_dsdt_ops = {
524
        .read =                 acpi_system_read_dsdt,
525
};
526
 
527
static ssize_t
528
acpi_system_read_dsdt (
529
        struct file             *file,
530
        char                    *buffer,
531
        size_t                  count,
532
        loff_t                  *ppos)
533
{
534
        acpi_status             status = AE_OK;
535
        struct acpi_buffer      dsdt = {ACPI_ALLOCATE_BUFFER, NULL};
536
        void                    *data = 0;
537
        size_t                  size = 0;
538
 
539
        ACPI_FUNCTION_TRACE("acpi_system_read_dsdt");
540
 
541
        status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt);
542
        if (ACPI_FAILURE(status))
543
                return_VALUE(-ENODEV);
544
 
545
        if (*ppos < dsdt.length) {
546
                data = dsdt.pointer + file->f_pos;
547
                size = dsdt.length - file->f_pos;
548
                if (size > count)
549
                        size = count;
550
                if (copy_to_user(buffer, data, size)) {
551
                        acpi_os_free(dsdt.pointer);
552
                        return_VALUE(-EFAULT);
553
                }
554
        }
555
 
556
        acpi_os_free(dsdt.pointer);
557
 
558
        *ppos += size;
559
 
560
        return_VALUE(size);
561
}
562
 
563
 
564
static ssize_t acpi_system_read_fadt (struct file*, char*, size_t, loff_t*);
565
 
566
static struct file_operations acpi_system_fadt_ops = {
567
        .read =                 acpi_system_read_fadt,
568
};
569
 
570
static ssize_t
571
acpi_system_read_fadt (
572
        struct file             *file,
573
        char                    *buffer,
574
        size_t                  count,
575
        loff_t                  *ppos)
576
{
577
        acpi_status             status = AE_OK;
578
        struct acpi_buffer      fadt = {ACPI_ALLOCATE_BUFFER, NULL};
579
        void                    *data = 0;
580
        size_t                  size = 0;
581
 
582
        ACPI_FUNCTION_TRACE("acpi_system_read_fadt");
583
 
584
        status = acpi_get_table(ACPI_TABLE_FADT, 1, &fadt);
585
        if (ACPI_FAILURE(status))
586
                return_VALUE(-ENODEV);
587
 
588
        if (*ppos < fadt.length) {
589
                data = fadt.pointer + file->f_pos;
590
                size = fadt.length - file->f_pos;
591
                if (size > count)
592
                        size = count;
593
                if (copy_to_user(buffer, data, size)) {
594
                        acpi_os_free(fadt.pointer);
595
                        return_VALUE(-EFAULT);
596
                }
597
        }
598
 
599
        acpi_os_free(fadt.pointer);
600
 
601
        *ppos += size;
602
 
603
        return_VALUE(size);
604
}
605
 
606
 
607
#ifdef ACPI_DEBUG_OUTPUT
608
 
609
static int
610
acpi_system_read_debug (
611
        char                    *page,
612
        char                    **start,
613
        off_t                   off,
614
        int                     count,
615
        int                     *eof,
616
        void                    *data)
617
{
618
        char                    *p = page;
619
        int                     size = 0;
620
 
621
        if (off != 0)
622
                goto end;
623
 
624
        switch ((unsigned long) data) {
625
        case 0:
626
                p += sprintf(p, "0x%08x\n", acpi_dbg_layer);
627
                break;
628
        case 1:
629
                p += sprintf(p, "0x%08x\n", acpi_dbg_level);
630
                break;
631
        default:
632
                p += sprintf(p, "Invalid debug option\n");
633
                break;
634
        }
635
 
636
end:
637
        size = (p - page);
638
        if (size <= off+count) *eof = 1;
639
        *start = page + off;
640
        size -= off;
641
        if (size>count) size = count;
642
        if (size<0) size = 0;
643
 
644
        return size;
645
}
646
 
647
 
648
static int
649
acpi_system_write_debug (
650
        struct file             *file,
651
        const char              *buffer,
652
        unsigned long           count,
653
        void                    *data)
654
{
655
        char                    debug_string[12] = {'\0'};
656
 
657
        ACPI_FUNCTION_TRACE("acpi_system_write_debug");
658
 
659
        if (count > sizeof(debug_string) - 1)
660
                return_VALUE(-EINVAL);
661
 
662
        if (copy_from_user(debug_string, buffer, count))
663
                return_VALUE(-EFAULT);
664
 
665
        debug_string[count] = '\0';
666
 
667
        switch ((unsigned long) data) {
668
        case 0:
669
                acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0);
670
                break;
671
        case 1:
672
                acpi_dbg_level = simple_strtoul(debug_string, NULL, 0);
673
                break;
674
        default:
675
                return_VALUE(-EINVAL);
676
        }
677
 
678
        return_VALUE(count);
679
}
680
 
681
#endif /* ACPI_DEBUG_OUTPUT */
682
 
683
 
684
#ifdef CONFIG_ACPI_SLEEP
685
 
686
static int
687
acpi_system_read_sleep (
688
        char                    *page,
689
        char                    **start,
690
        off_t                   off,
691
        int                     count,
692
        int                     *eof,
693
        void                    *data)
694
{
695
        struct acpi_system      *system = (struct acpi_system *) data;
696
        char                    *p = page;
697
        int                     size;
698
        int                     i;
699
 
700
        ACPI_FUNCTION_TRACE("acpi_system_read_sleep");
701
 
702
        if (!system || (off != 0))
703
                goto end;
704
 
705
        for (i = 0; i <= ACPI_STATE_S5; i++) {
706
                if (system->states[i]) {
707
                        p += sprintf(p,"S%d ", i);
708
                        if (i == ACPI_STATE_S4 && acpi_gbl_FACS->S4bios_f &&
709
                            acpi_gbl_FADT->smi_cmd != 0)
710
                                p += sprintf(p, "S4Bios ");
711
                }
712
        }
713
 
714
        p += sprintf(p, "\n");
715
 
716
end:
717
        size = (p - page);
718
        if (size <= off+count) *eof = 1;
719
        *start = page + off;
720
        size -= off;
721
        if (size>count) size = count;
722
        if (size<0) size = 0;
723
 
724
        return_VALUE(size);
725
}
726
 
727
 
728
static int
729
acpi_system_write_sleep (
730
        struct file             *file,
731
        const char              *buffer,
732
        unsigned long           count,
733
        void                    *data)
734
{
735
        acpi_status             status = AE_OK;
736
        struct acpi_system      *system = (struct acpi_system *) data;
737
        char                    state_string[12] = {'\0'};
738
        u32                     state = 0;
739
 
740
        ACPI_FUNCTION_TRACE("acpi_system_write_sleep");
741
 
742
        if (!system || (count > sizeof(state_string) - 1))
743
                return_VALUE(-EINVAL);
744
 
745
        if (copy_from_user(state_string, buffer, count))
746
                return_VALUE(-EFAULT);
747
 
748
        state_string[count] = '\0';
749
 
750
        state = simple_strtoul(state_string, NULL, 0);
751
 
752
        if (!system->states[state])
753
                return_VALUE(-ENODEV);
754
 
755
        /*
756
         * If S4 is supported by the OS, then we should assume that
757
         * echo 4b > /proc/acpi/sleep is for s4bios.
758
         * Since we have only s4bios, we assume that acpi_suspend failed
759
         * if no s4bios support.
760
         */
761
        status = acpi_suspend(state);
762
        if (ACPI_FAILURE(status))
763
                return_VALUE(-ENODEV);
764
 
765
        return_VALUE(count);
766
}
767
 
768
 
769
static int
770
acpi_system_read_alarm (
771
        char                    *page,
772
        char                    **start,
773
        off_t                   off,
774
        int                     count,
775
        int                     *eof,
776
        void                    *context)
777
{
778
        char                    *p = page;
779
        int                     size = 0;
780
        u32                     sec, min, hr;
781
        u32                     day, mo, yr;
782
 
783
        ACPI_FUNCTION_TRACE("acpi_system_read_alarm");
784
 
785
        if (off != 0)
786
                goto end;
787
 
788
        spin_lock(&rtc_lock);
789
 
790
        sec = CMOS_READ(RTC_SECONDS_ALARM);
791
        min = CMOS_READ(RTC_MINUTES_ALARM);
792
        hr = CMOS_READ(RTC_HOURS_ALARM);
793
 
794
#if 0   /* If we ever get an FACP with proper values... */
795
        if (acpi_gbl_FADT->day_alrm)
796
                day = CMOS_READ(acpi_gbl_FADT->day_alrm);
797
        else
798
                day =  CMOS_READ(RTC_DAY_OF_MONTH);
799
        if (acpi_gbl_FADT->mon_alrm)
800
                mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
801
        else
802
                mo = CMOS_READ(RTC_MONTH);;
803
        if (acpi_gbl_FADT->century)
804
                yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR);
805
        else
806
                yr = CMOS_READ(RTC_YEAR);
807
#else
808
        day = CMOS_READ(RTC_DAY_OF_MONTH);
809
        mo = CMOS_READ(RTC_MONTH);
810
        yr = CMOS_READ(RTC_YEAR);
811
#endif
812
 
813
        spin_unlock(&rtc_lock);
814
 
815
        BCD_TO_BIN(sec);
816
        BCD_TO_BIN(min);
817
        BCD_TO_BIN(hr);
818
        BCD_TO_BIN(day);
819
        BCD_TO_BIN(mo);
820
        BCD_TO_BIN(yr);
821
 
822
#if 0
823
        /* we're trusting the FADT (see above)*/
824
#else
825
        /* If we're not trusting the FADT, we should at least make it
826
         * right for _this_ century... ehm, what is _this_ century?
827
         *
828
         * TBD:
829
         *  ASAP: find piece of code in the kernel, e.g. star tracker driver,
830
         *        which we can trust to determine the century correctly. Atom
831
         *        watch driver would be nice, too...
832
         *
833
         *  if that has not happened, change for first release in 2050:
834
         *        if (yr<50)
835
         *                yr += 2100;
836
         *        else
837
         *                yr += 2000;   // current line of code
838
         *
839
         *  if that has not happened either, please do on 2099/12/31:23:59:59
840
         *        s/2000/2100
841
         *
842
         */
843
        yr += 2000;
844
#endif
845
 
846
        p += sprintf(p,"%4.4u-", yr);
847
        p += (mo > 12)  ? sprintf(p, "**-")  : sprintf(p, "%2.2u-", mo);
848
        p += (day > 31) ? sprintf(p, "** ")  : sprintf(p, "%2.2u ", day);
849
        p += (hr > 23)  ? sprintf(p, "**:")  : sprintf(p, "%2.2u:", hr);
850
        p += (min > 59) ? sprintf(p, "**:")  : sprintf(p, "%2.2u:", min);
851
        p += (sec > 59) ? sprintf(p, "**\n") : sprintf(p, "%2.2u\n", sec);
852
 
853
 end:
854
        size = p - page;
855
        if (size < count) *eof = 1;
856
        else if (size > count) size = count;
857
        if (size < 0) size = 0;
858
        *start = page;
859
 
860
        return_VALUE(size);
861
}
862
 
863
 
864
static int
865
get_date_field (
866
        char                    **p,
867
        u32                     *value)
868
{
869
        char                    *next = NULL;
870
        char                    *string_end = NULL;
871
        int                     result = -EINVAL;
872
 
873
        /*
874
         * Try to find delimeter, only to insert null.  The end of the
875
         * string won't have one, but is still valid.
876
         */
877
        next = strpbrk(*p, "- :");
878
        if (next)
879
                *next++ = '\0';
880
 
881
        *value = simple_strtoul(*p, &string_end, 10);
882
 
883
        /* Signal success if we got a good digit */
884
        if (string_end != *p)
885
                result = 0;
886
 
887
        if (next)
888
                *p = next;
889
 
890
        return result;
891
}
892
 
893
 
894
static int
895
acpi_system_write_alarm (
896
        struct file             *file,
897
        const char              *buffer,
898
        unsigned long           count,
899
        void                    *data)
900
{
901
        int                     result = 0;
902
        char                    alarm_string[30] = {'\0'};
903
        char                    *p = alarm_string;
904
        u32                     sec, min, hr, day, mo, yr;
905
        int                     adjust = 0;
906
        unsigned char           rtc_control = 0;
907
 
908
        ACPI_FUNCTION_TRACE("acpi_system_write_alarm");
909
 
910
        if (count > sizeof(alarm_string) - 1)
911
                return_VALUE(-EINVAL);
912
 
913
        if (copy_from_user(alarm_string, buffer, count))
914
                return_VALUE(-EFAULT);
915
 
916
        alarm_string[count] = '\0';
917
 
918
        /* check for time adjustment */
919
        if (alarm_string[0] == '+') {
920
                p++;
921
                adjust = 1;
922
        }
923
 
924
        if ((result = get_date_field(&p, &yr)))
925
                goto end;
926
        if ((result = get_date_field(&p, &mo)))
927
                goto end;
928
        if ((result = get_date_field(&p, &day)))
929
                goto end;
930
        if ((result = get_date_field(&p, &hr)))
931
                goto end;
932
        if ((result = get_date_field(&p, &min)))
933
                goto end;
934
        if ((result = get_date_field(&p, &sec)))
935
                goto end;
936
 
937
        if (sec > 59) {
938
                min += 1;
939
                sec -= 60;
940
        }
941
        if (min > 59) {
942
                hr += 1;
943
                min -= 60;
944
        }
945
        if (hr > 23) {
946
                day += 1;
947
                hr -= 24;
948
        }
949
        if (day > 31) {
950
                mo += 1;
951
                day -= 31;
952
        }
953
        if (mo > 12) {
954
                yr += 1;
955
                mo -= 12;
956
        }
957
 
958
        spin_lock_irq(&rtc_lock);
959
 
960
        rtc_control = CMOS_READ(RTC_CONTROL);
961
        if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
962
                BIN_TO_BCD(yr);
963
                BIN_TO_BCD(mo);
964
                BIN_TO_BCD(day);
965
                BIN_TO_BCD(hr);
966
                BIN_TO_BCD(min);
967
                BIN_TO_BCD(sec);
968
        }
969
 
970
        if (adjust) {
971
                yr  += CMOS_READ(RTC_YEAR);
972
                mo  += CMOS_READ(RTC_MONTH);
973
                day += CMOS_READ(RTC_DAY_OF_MONTH);
974
                hr  += CMOS_READ(RTC_HOURS);
975
                min += CMOS_READ(RTC_MINUTES);
976
                sec += CMOS_READ(RTC_SECONDS);
977
        }
978
 
979
        spin_unlock_irq(&rtc_lock);
980
 
981
        if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
982
                BCD_TO_BIN(yr);
983
                BCD_TO_BIN(mo);
984
                BCD_TO_BIN(day);
985
                BCD_TO_BIN(hr);
986
                BCD_TO_BIN(min);
987
                BCD_TO_BIN(sec);
988
        }
989
 
990
        if (sec > 59) {
991
                min++;
992
                sec -= 60;
993
        }
994
        if (min > 59) {
995
                hr++;
996
                min -= 60;
997
        }
998
        if (hr > 23) {
999
                day++;
1000
                hr -= 24;
1001
        }
1002
        if (day > 31) {
1003
                mo++;
1004
                day -= 31;
1005
        }
1006
        if (mo > 12) {
1007
                yr++;
1008
                mo -= 12;
1009
        }
1010
        if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
1011
                BIN_TO_BCD(yr);
1012
                BIN_TO_BCD(mo);
1013
                BIN_TO_BCD(day);
1014
                BIN_TO_BCD(hr);
1015
                BIN_TO_BCD(min);
1016
                BIN_TO_BCD(sec);
1017
        }
1018
 
1019
        spin_lock_irq(&rtc_lock);
1020
 
1021
        /* write the fields the rtc knows about */
1022
        CMOS_WRITE(hr, RTC_HOURS_ALARM);
1023
        CMOS_WRITE(min, RTC_MINUTES_ALARM);
1024
        CMOS_WRITE(sec, RTC_SECONDS_ALARM);
1025
 
1026
        /*
1027
         * If the system supports an enhanced alarm it will have non-zero
1028
         * offsets into the CMOS RAM here -- which for some reason are pointing
1029
         * to the RTC area of memory.
1030
         */
1031
#if 0
1032
        if (acpi_gbl_FADT->day_alrm)
1033
                CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
1034
        if (acpi_gbl_FADT->mon_alrm)
1035
                CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
1036
        if (acpi_gbl_FADT->century)
1037
                CMOS_WRITE(yr/100, acpi_gbl_FADT->century);
1038
#endif
1039
        /* enable the rtc alarm interrupt */
1040
        if (!(rtc_control & RTC_AIE)) {
1041
                rtc_control |= RTC_AIE;
1042
                CMOS_WRITE(rtc_control,RTC_CONTROL);
1043
                CMOS_READ(RTC_INTR_FLAGS);
1044
        }
1045
 
1046
        spin_unlock_irq(&rtc_lock);
1047
 
1048
        acpi_set_register(ACPI_BITREG_RT_CLOCK_ENABLE, 1, ACPI_MTX_LOCK);
1049
 
1050
        file->f_pos += count;
1051
 
1052
        result = 0;
1053
end:
1054
        return_VALUE(result ? result : count);
1055
}
1056
 
1057
#endif /*CONFIG_ACPI_SLEEP*/
1058
 
1059
 
1060
static int
1061
acpi_system_add_fs (
1062
        struct acpi_device      *device)
1063
{
1064
        struct proc_dir_entry   *entry = NULL;
1065
 
1066
        ACPI_FUNCTION_TRACE("acpi_system_add_fs");
1067
 
1068
        if (!device)
1069
                return_VALUE(-EINVAL);
1070
 
1071
        /* 'info' [R] */
1072
        entry = create_proc_entry(ACPI_SYSTEM_FILE_INFO,
1073
                S_IRUGO, acpi_device_dir(device));
1074
        if (!entry)
1075
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1076
                        "Unable to create '%s' fs entry\n",
1077
                        ACPI_SYSTEM_FILE_INFO));
1078
        else {
1079
                entry->read_proc = acpi_system_read_info;
1080
                entry->data = acpi_driver_data(device);
1081
        }
1082
 
1083
        /* 'dsdt' [R] */
1084
        entry = create_proc_entry(ACPI_SYSTEM_FILE_DSDT,
1085
                S_IRUSR, acpi_device_dir(device));
1086
        if (!entry)
1087
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1088
                        "Unable to create '%s' fs entry\n",
1089
                        ACPI_SYSTEM_FILE_DSDT));
1090
        else
1091
                entry->proc_fops = &acpi_system_dsdt_ops;
1092
 
1093
        /* 'fadt' [R] */
1094
        entry = create_proc_entry(ACPI_SYSTEM_FILE_FADT,
1095
                S_IRUSR, acpi_device_dir(device));
1096
        if (!entry)
1097
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1098
                        "Unable to create '%s' fs entry\n",
1099
                        ACPI_SYSTEM_FILE_FADT));
1100
        else
1101
                entry->proc_fops = &acpi_system_fadt_ops;
1102
 
1103
        /* 'event' [R] */
1104
        entry = create_proc_entry(ACPI_SYSTEM_FILE_EVENT,
1105
                S_IRUSR, acpi_device_dir(device));
1106
        if (!entry)
1107
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1108
                        "Unable to create '%s' fs entry\n",
1109
                        ACPI_SYSTEM_FILE_EVENT));
1110
        else
1111
                entry->proc_fops = &acpi_system_event_ops;
1112
 
1113
#ifdef CONFIG_ACPI_SLEEP
1114
 
1115
        /* 'sleep' [R/W]*/
1116
        entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP,
1117
                S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
1118
        if (!entry)
1119
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1120
                        "Unable to create '%s' fs entry\n",
1121
                        ACPI_SYSTEM_FILE_SLEEP));
1122
        else {
1123
                entry->read_proc = acpi_system_read_sleep;
1124
                entry->write_proc = acpi_system_write_sleep;
1125
                entry->data = acpi_driver_data(device);
1126
        }
1127
 
1128
        /* 'alarm' [R/W] */
1129
        entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM,
1130
                S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
1131
        if (!entry)
1132
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1133
                        "Unable to create '%s' fs entry\n",
1134
                        ACPI_SYSTEM_FILE_ALARM));
1135
        else {
1136
                entry->read_proc = acpi_system_read_alarm;
1137
                entry->write_proc = acpi_system_write_alarm;
1138
                entry->data = acpi_driver_data(device);
1139
        }
1140
 
1141
#endif /*CONFIG_ACPI_SLEEP*/
1142
 
1143
#ifdef ACPI_DEBUG_OUTPUT
1144
 
1145
        /* 'debug_layer' [R/W] */
1146
        entry = create_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER,
1147
                S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
1148
        if (!entry)
1149
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1150
                        "Unable to create '%s' fs entry\n",
1151
                        ACPI_SYSTEM_FILE_DEBUG_LAYER));
1152
        else {
1153
                entry->read_proc  = acpi_system_read_debug;
1154
                entry->write_proc = acpi_system_write_debug;
1155
                entry->data = (void *) 0;
1156
        }
1157
 
1158
        /* 'debug_level' [R/W] */
1159
        entry = create_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL,
1160
                S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
1161
        if (!entry)
1162
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1163
                        "Unable to create '%s' fs entry\n",
1164
                        ACPI_SYSTEM_FILE_DEBUG_LEVEL));
1165
        else {
1166
                entry->read_proc  = acpi_system_read_debug;
1167
                entry->write_proc = acpi_system_write_debug;
1168
                entry->data = (void *) 1;
1169
        }
1170
 
1171
#endif /*ACPI_DEBUG_OUTPUT */
1172
 
1173
        return_VALUE(0);
1174
}
1175
 
1176
 
1177
static int
1178
acpi_system_remove_fs (
1179
        struct acpi_device      *device)
1180
{
1181
        ACPI_FUNCTION_TRACE("acpi_system_remove_fs");
1182
 
1183
        if (!device)
1184
                return_VALUE(-EINVAL);
1185
 
1186
        remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_device_dir(device));
1187
        remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_device_dir(device));
1188
        remove_proc_entry(ACPI_SYSTEM_FILE_EVENT, acpi_device_dir(device));
1189
#ifdef CONFIG_ACPI_SLEEP
1190
        remove_proc_entry(ACPI_SYSTEM_FILE_SLEEP, acpi_device_dir(device));
1191
        remove_proc_entry(ACPI_SYSTEM_FILE_ALARM, acpi_device_dir(device));
1192
#endif
1193
#ifdef ACPI_DEBUG_OUTPUT
1194
        remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER,
1195
                acpi_device_dir(device));
1196
        remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL,
1197
                acpi_device_dir(device));
1198
#endif
1199
 
1200
        return_VALUE(0);
1201
}
1202
 
1203
 
1204
/* --------------------------------------------------------------------------
1205
                                 Driver Interface
1206
   -------------------------------------------------------------------------- */
1207
 
1208
#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_PM)
1209
 
1210
static int po_cb_active;
1211
 
1212
static void acpi_po_tramp(void *x)
1213
{
1214
        acpi_power_off();
1215
}
1216
 
1217
/* Simple wrapper calling power down function. */
1218
static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs,
1219
        struct kbd_struct *kbd, struct tty_struct *tty)
1220
{
1221
        static struct tq_struct tq = { .routine = acpi_po_tramp };
1222
        if (po_cb_active++)
1223
                return;
1224
        schedule_task(&tq);
1225
}
1226
 
1227
struct sysrq_key_op sysrq_acpi_poweroff_op = {
1228
        .handler =      &acpi_sysrq_power_off,
1229
        .help_msg =     "Off",
1230
        .action_msg =   "Power Off\n"
1231
};
1232
 
1233
#endif  /* CONFIG_MAGIC_SYSRQ */
1234
 
1235
static int
1236
acpi_system_add (
1237
        struct acpi_device      *device)
1238
{
1239
        int                     result = 0;
1240
        acpi_status             status = AE_OK;
1241
        struct acpi_system      *system = NULL;
1242
        u8                      i = 0;
1243
 
1244
        ACPI_FUNCTION_TRACE("acpi_system_add");
1245
 
1246
        if (!device)
1247
                return_VALUE(-EINVAL);
1248
 
1249
        system = kmalloc(sizeof(struct acpi_system), GFP_KERNEL);
1250
        if (!system)
1251
                return_VALUE(-ENOMEM);
1252
        memset(system, 0, sizeof(struct acpi_system));
1253
 
1254
        system->handle = device->handle;
1255
        sprintf(acpi_device_name(device), "%s", ACPI_SYSTEM_DEVICE_NAME);
1256
        sprintf(acpi_device_class(device), "%s", ACPI_SYSTEM_CLASS);
1257
        acpi_driver_data(device) = system;
1258
 
1259
        result = acpi_system_add_fs(device);
1260
        if (result)
1261
                goto end;
1262
 
1263
        printk(KERN_INFO PREFIX "%s [%s] (supports",
1264
                acpi_device_name(device), acpi_device_bid(device));
1265
        for (i=0; i<ACPI_S_STATE_COUNT; i++) {
1266
                u8 type_a, type_b;
1267
                status = acpi_get_sleep_type_data(i, &type_a, &type_b);
1268
                switch (i) {
1269
                case ACPI_STATE_S4:
1270
                        if (acpi_gbl_FACS->S4bios_f &&
1271
 
1272
                                printk(" S4bios");
1273
                                system->states[i] = 1;
1274
                        }
1275
                        /* no break */
1276
                default:
1277
                        if (ACPI_SUCCESS(status)) {
1278
                                system->states[i] = 1;
1279
                                printk(" S%d", i);
1280
                        }
1281
                }
1282
        }
1283
        printk(")\n");
1284
 
1285
#ifdef CONFIG_PM
1286
        /* Install the soft-off (S5) handler. */
1287
        if (system->states[ACPI_STATE_S5]) {
1288
                pm_power_off = acpi_power_off;
1289
                register_sysrq_key('o', &sysrq_acpi_poweroff_op);
1290
        }
1291
#endif
1292
 
1293
end:
1294
        if (result)
1295
                kfree(system);
1296
 
1297
        return_VALUE(result);
1298
}
1299
 
1300
 
1301
static int
1302
acpi_system_remove (
1303
        struct acpi_device      *device,
1304
        int                     type)
1305
{
1306
        struct acpi_system      *system = NULL;
1307
 
1308
        ACPI_FUNCTION_TRACE("acpi_system_remove");
1309
 
1310
        if (!device || !acpi_driver_data(device))
1311
                return_VALUE(-EINVAL);
1312
 
1313
        system = (struct acpi_system *) acpi_driver_data(device);
1314
 
1315
#ifdef CONFIG_PM
1316
        /* Remove the soft-off (S5) handler. */
1317
        if (system->states[ACPI_STATE_S5]) {
1318
                unregister_sysrq_key('o', &sysrq_acpi_poweroff_op);
1319
                pm_power_off = NULL;
1320
        }
1321
#endif
1322
 
1323
        acpi_system_remove_fs(device);
1324
 
1325
        kfree(system);
1326
 
1327
        return 0;
1328
}
1329
 
1330
 
1331
int __init
1332
acpi_system_init (void)
1333
{
1334
        int                     result = 0;
1335
 
1336
        ACPI_FUNCTION_TRACE("acpi_system_init");
1337
 
1338
        result = acpi_bus_register_driver(&acpi_system_driver);
1339
        if (result < 0)
1340
                return_VALUE(-ENODEV);
1341
 
1342
        return_VALUE(0);
1343
}
1344
 
1345
 
1346
void __exit
1347
acpi_system_exit (void)
1348
{
1349
        ACPI_FUNCTION_TRACE("acpi_system_exit");
1350
        acpi_bus_unregister_driver(&acpi_system_driver);
1351
        return_VOID;
1352
}

powered by: WebSVN 2.1.0

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