patch-2.4.0-test4 linux/drivers/acpi/sys.c
Next file: linux/drivers/acpi/tables.c
Previous file: linux/drivers/acpi/osd.c
Back to the patch index
Back to the overall index
- Lines: 183
- Date:
Thu Jul 13 09:39:49 2000
- Orig file:
v2.4.0-test3/linux/drivers/acpi/sys.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.4.0-test3/linux/drivers/acpi/sys.c linux/drivers/acpi/sys.c
@@ -0,0 +1,182 @@
+/*
+ * sys.c - System management (suspend, ...)
+ *
+ * Copyright (C) 2000 Andrew Henroid
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
+#include "acpi.h"
+#include "driver.h"
+
+#define ACPI_SLP_TYP(typa, typb) (((int)(typa) << 8) | (int)(typb))
+#define ACPI_SLP_TYPA(value) \
+ ((((value) >> 8) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK)
+#define ACPI_SLP_TYPB(value) \
+ ((((value) & 0xff) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK)
+
+struct acpi_enter_sx_ctx
+{
+ wait_queue_head_t wait;
+ int state;
+};
+
+volatile acpi_sstate_t acpi_sleep_state = ACPI_S0;
+static unsigned long acpi_slptyp[ACPI_S5 + 1] = {ACPI_INVALID,};
+
+/*
+ * Enter system sleep state
+ */
+static void
+acpi_enter_sx_async(void *context)
+{
+ struct acpi_enter_sx_ctx *ctx = (struct acpi_enter_sx_ctx*) context;
+ struct acpi_facp *facp = &acpi_facp;
+ ACPI_OBJECT_LIST arg_list;
+ ACPI_OBJECT arg;
+ u16 value;
+
+ /*
+ * _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
+ */
+
+ // run the _PTS method
+ memset(&arg_list, 0, sizeof(arg_list));
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = ACPI_TYPE_NUMBER;
+ arg.number.value = ctx->state;
+
+ acpi_evaluate_object(NULL, "\\_PTS", &arg_list, NULL);
+
+ // clear wake status
+ acpi_write_pm1_status(facp, ACPI_WAK);
+
+ acpi_sleep_state = ctx->state;
+
+ // set ACPI_SLP_TYPA/b and ACPI_SLP_EN
+ __cli();
+ if (facp->pm1a_cnt) {
+ value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
+ value |= (ACPI_SLP_TYPA(acpi_slptyp[ctx->state])
+ | ACPI_SLP_EN);
+ outw(value, facp->pm1a_cnt);
+ }
+ if (facp->pm1b_cnt) {
+ value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
+ value |= (ACPI_SLP_TYPB(acpi_slptyp[ctx->state])
+ | ACPI_SLP_EN);
+ outw(value, facp->pm1b_cnt);
+ }
+ __sti();
+
+ if (ctx->state != ACPI_S1) {
+ printk(KERN_ERR "ACPI: S%d failed\n", ctx->state);
+ goto out;
+ }
+
+ // wait until S1 is entered
+ while (!(acpi_read_pm1_status(facp) & ACPI_WAK))
+ safe_halt();
+
+ // run the _WAK method
+ memset(&arg_list, 0, sizeof(arg_list));
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = ACPI_TYPE_NUMBER;
+ arg.number.value = ctx->state;
+
+ acpi_evaluate_object(NULL, "\\_WAK", &arg_list, NULL);
+
+ out:
+ acpi_sleep_state = ACPI_S0;
+
+ if (waitqueue_active(&ctx->wait))
+ wake_up_interruptible(&ctx->wait);
+}
+
+/*
+ * Enter soft-off (S5)
+ */
+static void
+acpi_power_off(void)
+{
+ struct acpi_enter_sx_ctx ctx;
+
+ if (acpi_facp.hdr.signature != ACPI_FACP_SIG
+ || acpi_slptyp[ACPI_S5] == ACPI_INVALID)
+ return;
+
+ init_waitqueue_head(&ctx.wait);
+ ctx.state = ACPI_S5;
+ acpi_enter_sx_async(&ctx);
+}
+
+/*
+ * Enter system sleep state and wait for completion
+ */
+int
+acpi_enter_sx(acpi_sstate_t state)
+{
+ struct acpi_enter_sx_ctx ctx;
+
+ if (acpi_facp.hdr.signature != ACPI_FACP_SIG
+ || acpi_slptyp[state] == ACPI_INVALID)
+ return -EINVAL;
+
+ init_waitqueue_head(&ctx.wait);
+ ctx.state = state;
+
+ if (acpi_os_queue_for_execution(0, acpi_enter_sx_async, &ctx))
+ return -1;
+
+ interruptible_sleep_on(&ctx.wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ return 0;
+}
+
+int
+acpi_sys_init(void)
+{
+ u8 sx, typa, typb;
+
+ for (sx = ACPI_S0; sx <= ACPI_S5; sx++) {
+ int ca_sx = (sx <= ACPI_S4) ? sx : (sx + 1);
+ if (ACPI_SUCCESS(
+ acpi_hw_obtain_sleep_type_register_data(ca_sx,
+ &typa,
+ &typb)))
+ acpi_slptyp[sx] = ACPI_SLP_TYP(typa, typb);
+ else
+ acpi_slptyp[sx] = ACPI_INVALID;
+ }
+ if (acpi_slptyp[ACPI_S1] != ACPI_INVALID)
+ printk(KERN_INFO "ACPI: S1 supported\n");
+ if (acpi_slptyp[ACPI_S5] != ACPI_INVALID)
+ printk(KERN_INFO "ACPI: S5 supported\n");
+
+ pm_power_off = acpi_power_off;
+
+ return 0;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)