1 /*
2 * sys.c - System management (suspend, ...)
3 *
4 * Copyright (C) 2000 Andrew Henroid
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <linux/kernel.h>
22 #include <linux/pm.h>
23 #include <linux/acpi.h>
24 #include "acpi.h"
25 #include "driver.h"
26
27 #define _COMPONENT OS_DEPENDENT
28 MODULE_NAME ("sys")
29
30 #define ACPI_SLP_TYP(typa, typb) (((int)(typa) << 8) | (int)(typb))
31 #define ACPI_SLP_TYPA(value) ((value) >> 8)
32 #define ACPI_SLP_TYPB(value) ((value) & 0xff)
33
34 struct acpi_enter_sx_ctx
35 {
36 wait_queue_head_t wait;
37 unsigned int state;
38 };
39
40 volatile acpi_sstate_t acpi_sleep_state = ACPI_S0;
41 static unsigned long acpi_slptyp[ACPI_S5 + 1] = {ACPI_INVALID,};
42
43 /*
44 * Enter system sleep state
45 */
46 static void
47 acpi_enter_sx_async(void *context)
48 {
49 struct acpi_enter_sx_ctx *ctx = (struct acpi_enter_sx_ctx*) context;
50 ACPI_OBJECT_LIST arg_list;
51 ACPI_OBJECT arg;
52
53 /*
54 * _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
55 */
56
57 // run the _PTS method
58 memset(&arg_list, 0, sizeof(arg_list));
59 arg_list.count = 1;
60 arg_list.pointer = &arg;
61
62 memset(&arg, 0, sizeof(arg));
63 arg.type = ACPI_TYPE_NUMBER;
64 arg.number.value = ctx->state;
65
66 acpi_evaluate_object(NULL, "\\_PTS", &arg_list, NULL);
67
68 // clear wake status by writing a 1
69 acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, WAK_STS, 1);
70
71 acpi_sleep_state = ctx->state;
72
73 // set ACPI_SLP_TYPA/b and ACPI_SLP_EN
74 acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, SLP_TYPE_A,
75 ACPI_SLP_TYPA(acpi_slptyp[ctx->state]));
76 acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, SLP_TYPE_B,
77 ACPI_SLP_TYPB(acpi_slptyp[ctx->state]));
78 acpi_hw_register_bit_access(ACPI_WRITE, ACPI_MTX_LOCK, SLP_EN, 1);
79
80 if (ctx->state != ACPI_S1) {
81 /* we should have just shut off - what are we doing here? */
82 printk(KERN_ERR "ACPI: S%d failed\n", ctx->state);
83 goto out;
84 }
85
86 // wait until S1 is entered
87 while (!(acpi_hw_register_bit_access(ACPI_READ, ACPI_MTX_LOCK, WAK_STS)))
88 safe_halt();
89
90 // run the _WAK method
91 memset(&arg_list, 0, sizeof(arg_list));
92 arg_list.count = 1;
93 arg_list.pointer = &arg;
94
95 memset(&arg, 0, sizeof(arg));
96 arg.type = ACPI_TYPE_NUMBER;
97 arg.number.value = ctx->state;
98
99 acpi_evaluate_object(NULL, "\\_WAK", &arg_list, NULL);
100
101 out:
102 acpi_sleep_state = ACPI_S0;
103
104 if (waitqueue_active(&ctx->wait))
105 wake_up_interruptible(&ctx->wait);
106 }
107
108 /*
109 * Enter soft-off (S5)
110 */
111 static void
112 acpi_power_off(void)
113 {
114 struct acpi_enter_sx_ctx ctx;
115
116 if ((STRNCMP(acpi_fadt.header.signature, ACPI_FADT_SIGNATURE, ACPI_SIG_LEN) != 0)
117 || acpi_slptyp[ACPI_S5] == ACPI_INVALID)
118 return;
119
120 init_waitqueue_head(&ctx.wait);
121 ctx.state = ACPI_S5;
122 acpi_enter_sx_async(&ctx);
123 }
124
125 /*
126 * Enter system sleep state and wait for completion
127 */
128 int
129 acpi_enter_sx(acpi_sstate_t state)
130 {
131 struct acpi_enter_sx_ctx ctx;
132 DECLARE_WAITQUEUE(wait, current);
133 int ret = 0;
134
135 if ((STRNCMP(acpi_fadt.header.signature, ACPI_FADT_SIGNATURE, ACPI_SIG_LEN) != 0)
136 || acpi_slptyp[state] == ACPI_INVALID)
137 return -EINVAL;
138
139 init_waitqueue_head(&ctx.wait);
140 ctx.state = state;
141
142 set_current_state(TASK_INTERRUPTIBLE);
143 add_wait_queue(&ctx.wait, &wait);
144
145 if (acpi_os_queue_for_execution(0, acpi_enter_sx_async, &ctx))
146 ret = -1;
147
148 if (!ret)
149 schedule();
150
151 set_current_state(TASK_RUNNING);
152 remove_wait_queue(&ctx.wait, &wait);
153
154 if (!ret && signal_pending(current))
155 ret = -ERESTARTSYS;
156
157 return ret;
158 }
159
160 int
161 acpi_sys_init(void)
162 {
163 u8 sx;
164 u8 type_a;
165 u8 type_b;
166
167 printk(KERN_INFO "ACPI: System firmware supports:");
168
169 for (sx = ACPI_S0; sx <= ACPI_S5; sx++) {
170 int ca_sx = (sx <= ACPI_S4) ? sx : (sx + 1);
171 if (ACPI_SUCCESS(
172 acpi_hw_obtain_sleep_type_register_data(ca_sx,
173 &type_a,
174 &type_b))) {
175
176 acpi_slptyp[sx] = ACPI_SLP_TYP(type_a, type_b);
177 printk(" S%d", sx);
178 }
179 else {
180 acpi_slptyp[sx] = ACPI_INVALID;
181 }
182 }
183 printk("\n");
184
185 pm_power_off = acpi_power_off;
186
187 return 0;
188 }
189
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.