2 * sys.c - System management (suspend, ...)
4 * Copyright (C) 2000 Andrew Henroid
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.
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.
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
21 #include <linux/kernel.h>
23 #include <linux/acpi.h>
27 #define _COMPONENT OS_DEPENDENT
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)
34 struct acpi_enter_sx_ctx
36 wait_queue_head_t wait
;
40 volatile acpi_sstate_t acpi_sleep_state
= ACPI_S0
;
41 static unsigned long acpi_slptyp
[ACPI_S5
+ 1] = {ACPI_INVALID
,};
44 * Enter system sleep state
47 acpi_enter_sx_async(void *context
)
49 struct acpi_enter_sx_ctx
*ctx
= (struct acpi_enter_sx_ctx
*) context
;
50 ACPI_OBJECT_LIST arg_list
;
54 * _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
57 // run the _PTS method
58 memset(&arg_list
, 0, sizeof(arg_list
));
60 arg_list
.pointer
= &arg
;
62 memset(&arg
, 0, sizeof(arg
));
63 arg
.type
= ACPI_TYPE_NUMBER
;
64 arg
.number
.value
= ctx
->state
;
66 acpi_evaluate_object(NULL
, "\\_PTS", &arg_list
, NULL
);
68 // clear wake status by writing a 1
69 acpi_hw_register_bit_access(ACPI_WRITE
, ACPI_MTX_LOCK
, WAK_STS
, 1);
71 acpi_sleep_state
= ctx
->state
;
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);
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
);
86 // wait until S1 is entered
87 while (!(acpi_hw_register_bit_access(ACPI_READ
, ACPI_MTX_LOCK
, WAK_STS
)))
90 // run the _WAK method
91 memset(&arg_list
, 0, sizeof(arg_list
));
93 arg_list
.pointer
= &arg
;
95 memset(&arg
, 0, sizeof(arg
));
96 arg
.type
= ACPI_TYPE_NUMBER
;
97 arg
.number
.value
= ctx
->state
;
99 acpi_evaluate_object(NULL
, "\\_WAK", &arg_list
, NULL
);
102 acpi_sleep_state
= ACPI_S0
;
104 if (waitqueue_active(&ctx
->wait
))
105 wake_up_interruptible(&ctx
->wait
);
109 * Enter soft-off (S5)
114 struct acpi_enter_sx_ctx ctx
;
116 if ((STRNCMP(acpi_fadt
.header
.signature
, ACPI_FADT_SIGNATURE
, ACPI_SIG_LEN
) != 0)
117 || acpi_slptyp
[ACPI_S5
] == ACPI_INVALID
)
120 init_waitqueue_head(&ctx
.wait
);
122 acpi_enter_sx_async(&ctx
);
126 * Enter system sleep state and wait for completion
129 acpi_enter_sx(acpi_sstate_t state
)
131 struct acpi_enter_sx_ctx ctx
;
132 DECLARE_WAITQUEUE(wait
, current
);
135 if ((STRNCMP(acpi_fadt
.header
.signature
, ACPI_FADT_SIGNATURE
, ACPI_SIG_LEN
) != 0)
136 || acpi_slptyp
[state
] == ACPI_INVALID
)
139 init_waitqueue_head(&ctx
.wait
);
142 set_current_state(TASK_INTERRUPTIBLE
);
143 add_wait_queue(&ctx
.wait
, &wait
);
145 if (acpi_os_queue_for_execution(0, acpi_enter_sx_async
, &ctx
))
151 set_current_state(TASK_RUNNING
);
152 remove_wait_queue(&ctx
.wait
, &wait
);
154 if (!ret
&& signal_pending(current
))
167 printk(KERN_INFO
"ACPI: System firmware supports:");
169 for (sx
= ACPI_S0
; sx
<= ACPI_S5
; sx
++) {
170 int ca_sx
= (sx
<= ACPI_S4
) ? sx
: (sx
+ 1);
172 acpi_hw_obtain_sleep_type_register_data(ca_sx
,
176 acpi_slptyp
[sx
] = ACPI_SLP_TYP(type_a
, type_b
);
180 acpi_slptyp
[sx
] = ACPI_INVALID
;
185 pm_power_off
= acpi_power_off
;