summaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-07-15 03:32:22 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-07-15 03:32:22 +0000
commitf1da2c3860e301527d56a1ef0b56c649ee7c4b1b (patch)
tree562b5d2e8b9cb62eb983d78ff6bcf9789e08fcf6 /drivers/acpi
parent00f11569ac8ca73cbcdef8822de1583e79aee571 (diff)
Merge with Linux 2.4.0-test5-pre1. This works again on Origin UP.
The IP22 cache bugs which are plaguing some machines are still unfixed.
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Makefile2
-rw-r--r--drivers/acpi/cpu.c307
-rw-r--r--drivers/acpi/driver.c388
-rw-r--r--drivers/acpi/driver.h115
-rw-r--r--drivers/acpi/ec.c191
-rw-r--r--drivers/acpi/os.c379
-rw-r--r--drivers/acpi/osd.c1319
-rw-r--r--drivers/acpi/sys.c182
-rw-r--r--drivers/acpi/tables.c303
9 files changed, 1866 insertions, 1320 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index c8b888ff1..2c9606663 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -11,7 +11,7 @@ O_TARGET := acpi.o
O_OBJS :=
M_OBJS :=
-ACPI_OBJS := osd.o
+ACPI_OBJS := driver.o ec.o cpu.o os.o sys.o tables.o
ACPI_OBJS += $(patsubst %.c,%.o,$(wildcard */*.c))
EXTRA_CFLAGS += -I./include -D_LINUX
diff --git a/drivers/acpi/cpu.c b/drivers/acpi/cpu.c
new file mode 100644
index 000000000..f1feeb12b
--- /dev/null
+++ b/drivers/acpi/cpu.c
@@ -0,0 +1,307 @@
+/*
+ * cpu.c - Processor handling
+ *
+ * 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/config.h>
+#include <linux/kernel.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
+#include "acpi.h"
+#include "driver.h"
+
+unsigned long acpi_c2_exit_latency = ACPI_INFINITE;
+unsigned long acpi_c3_exit_latency = ACPI_INFINITE;
+unsigned long acpi_c2_enter_latency = ACPI_INFINITE;
+unsigned long acpi_c3_enter_latency = ACPI_INFINITE;
+
+static unsigned long acpi_pblk = ACPI_INVALID;
+static int acpi_c2_tested = 0;
+static int acpi_c3_tested = 0;
+
+/*
+ * Clear busmaster activity flag
+ */
+static inline void
+acpi_clear_bm_activity(struct acpi_facp *facp)
+{
+ acpi_write_pm1_status(facp, ACPI_BM);
+}
+
+/*
+ * Returns 1 if there has been busmaster activity
+ */
+static inline int
+acpi_bm_activity(struct acpi_facp *facp)
+{
+ return acpi_read_pm1_status(facp) & ACPI_BM;
+}
+
+/*
+ * Set system to sleep through busmaster requests
+ */
+static void
+acpi_sleep_on_busmaster(struct acpi_facp *facp)
+{
+ u32 pm1_cntr = acpi_read_pm1_control(facp);
+ if (pm1_cntr & ACPI_BM_RLD) {
+ pm1_cntr &= ~ACPI_BM_RLD;
+ acpi_write_pm1_control(facp, pm1_cntr);
+ }
+}
+
+/*
+ * Set system to wake on busmaster requests
+ */
+static void
+acpi_wake_on_busmaster(struct acpi_facp *facp)
+{
+ u32 pm1_cntr = acpi_read_pm1_control(facp);
+ if (!(pm1_cntr & ACPI_BM_RLD)) {
+ pm1_cntr |= ACPI_BM_RLD;
+ acpi_write_pm1_control(facp, pm1_cntr);
+ }
+ acpi_clear_bm_activity(facp);
+}
+
+/* The ACPI timer is just the low 24 bits */
+#define TIME_BEGIN(tmr) inl(tmr)
+#define TIME_END(tmr, begin) ((inl(tmr) - (begin)) & 0x00ffffff)
+
+/*
+ * Idle loop (uniprocessor only)
+ */
+static void
+acpi_idle(void)
+{
+ static int sleep_level = 1;
+ struct acpi_facp *facp = &acpi_facp;
+
+ if (!facp
+ || facp->hdr.signature != ACPI_FACP_SIG
+ || !facp->pm_tmr
+ || !acpi_pblk)
+ goto not_initialized;
+
+ /*
+ * start from the previous sleep level..
+ */
+ if (sleep_level == 1)
+ goto sleep1;
+ if (sleep_level == 2)
+ goto sleep2;
+ sleep3:
+ sleep_level = 3;
+ if (!acpi_c3_tested) {
+ printk(KERN_DEBUG "ACPI C3 works\n");
+ acpi_c3_tested = 1;
+ }
+ acpi_wake_on_busmaster(facp);
+ if (facp->pm2_cnt)
+ goto sleep3_with_arbiter;
+
+ for (;;) {
+ unsigned long time;
+ unsigned int pm_tmr = facp->pm_tmr;
+
+ __cli();
+ if (current->need_resched)
+ goto out;
+ if (acpi_bm_activity(facp))
+ goto sleep2;
+
+ time = TIME_BEGIN(pm_tmr);
+ inb(acpi_pblk + ACPI_P_LVL3);
+ /* Dummy read, force synchronization with the PMU */
+ inl(pm_tmr);
+ time = TIME_END(pm_tmr, time);
+
+ __sti();
+ if (time < acpi_c3_exit_latency)
+ goto sleep2;
+ }
+
+ sleep3_with_arbiter:
+ for (;;) {
+ unsigned long time;
+ u8 arbiter;
+ unsigned int pm2_cntr = facp->pm2_cnt;
+ unsigned int pm_tmr = facp->pm_tmr;
+
+ __cli();
+ if (current->need_resched)
+ goto out;
+ if (acpi_bm_activity(facp))
+ goto sleep2;
+
+ time = TIME_BEGIN(pm_tmr);
+ arbiter = inb(pm2_cntr) & ~ACPI_ARB_DIS;
+ /* Disable arbiter, park on CPU */
+ outb(arbiter | ACPI_ARB_DIS, pm2_cntr);
+ inb(acpi_pblk + ACPI_P_LVL3);
+ /* Dummy read, force synchronization with the PMU */
+ inl(pm_tmr);
+ time = TIME_END(pm_tmr, time);
+ /* Enable arbiter again.. */
+ outb(arbiter, pm2_cntr);
+
+ __sti();
+ if (time < acpi_c3_exit_latency)
+ goto sleep2;
+ }
+
+ sleep2:
+ sleep_level = 2;
+ if (!acpi_c2_tested) {
+ printk(KERN_DEBUG "ACPI C2 works\n");
+ acpi_c2_tested = 1;
+ }
+ acpi_wake_on_busmaster(facp); /* Required to track BM activity.. */
+ for (;;) {
+ unsigned long time;
+ unsigned int pm_tmr = facp->pm_tmr;
+
+ __cli();
+ if (current->need_resched)
+ goto out;
+
+ time = TIME_BEGIN(pm_tmr);
+ inb(acpi_pblk + ACPI_P_LVL2);
+ /* Dummy read, force synchronization with the PMU */
+ inl(pm_tmr);
+ time = TIME_END(pm_tmr, time);
+
+ __sti();
+ if (time < acpi_c2_exit_latency)
+ goto sleep1;
+ if (acpi_bm_activity(facp)) {
+ acpi_clear_bm_activity(facp);
+ continue;
+ }
+ if (time > acpi_c3_enter_latency)
+ goto sleep3;
+ }
+
+ sleep1:
+ sleep_level = 1;
+ acpi_sleep_on_busmaster(facp);
+ for (;;) {
+ unsigned long time;
+ unsigned int pm_tmr = facp->pm_tmr;
+
+ __cli();
+ if (current->need_resched)
+ goto out;
+ time = TIME_BEGIN(pm_tmr);
+ safe_halt();
+ time = TIME_END(pm_tmr, time);
+ if (time > acpi_c2_enter_latency)
+ goto sleep2;
+ }
+
+ not_initialized:
+ for (;;) {
+ __cli();
+ if (current->need_resched)
+ goto out;
+ safe_halt();
+ }
+
+ out:
+ __sti();
+}
+
+/*
+ * Get processor information
+ */
+static ACPI_STATUS
+acpi_find_cpu(ACPI_HANDLE handle, u32 level, void *ctx, void **value)
+{
+ ACPI_OBJECT obj;
+ ACPI_CX_STATE lat[4];
+ ACPI_CPU_THROTTLING_STATE throttle[ACPI_MAX_THROTTLE];
+ ACPI_BUFFER buf;
+ int i, count;
+
+ buf.length = sizeof(obj);
+ buf.pointer = &obj;
+ if (!ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buf)))
+ return AE_OK;
+
+ printk(KERN_INFO "ACPI: PBLK %d @ 0x%04x:%d\n",
+ obj.processor.proc_id,
+ obj.processor.pblk_address,
+ obj.processor.pblk_length);
+ if (acpi_pblk != ACPI_INVALID
+ || !obj.processor.pblk_address
+ || obj.processor.pblk_length != 6)
+ return AE_OK;
+
+ acpi_pblk = obj.processor.pblk_address;
+
+ buf.length = sizeof(lat);
+ buf.pointer = lat;
+ if (!ACPI_SUCCESS(acpi_get_processor_cx_info(handle, &buf)))
+ return AE_OK;
+
+ if (lat[2].latency < MAX_CX_STATE_LATENCY) {
+ printk(KERN_INFO "ACPI: C2 supported\n");
+ acpi_c2_exit_latency = lat[2].latency;
+ }
+ if (lat[3].latency < MAX_CX_STATE_LATENCY) {
+ printk(KERN_INFO "ACPI: C3 supported\n");
+ acpi_c3_exit_latency = lat[3].latency;
+ }
+
+ memset(throttle, 0, sizeof(throttle));
+ buf.length = sizeof(throttle);
+ buf.pointer = throttle;
+
+ if (!ACPI_SUCCESS(acpi_get_processor_throttling_info(handle, &buf)))
+ return AE_OK;
+
+ for (i = 0, count = 0; i < ACPI_MAX_THROTTLE; i++) {
+ if (throttle[i].percent_of_clock)
+ count++;
+ }
+ count--;
+ if (count > 0)
+ printk(KERN_INFO "ACPI: %d throttling states\n", count);
+
+ return AE_OK;
+}
+
+int
+acpi_cpu_init(void)
+{
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_INT32_MAX,
+ acpi_find_cpu,
+ NULL,
+ NULL);
+
+#ifdef CONFIG_SMP
+ if (smp_num_cpus == 1)
+ pm_idle = acpi_idle;
+#else
+ pm_idle = acpi_idle;
+#endif
+
+ return 0;
+}
diff --git a/drivers/acpi/driver.c b/drivers/acpi/driver.c
new file mode 100644
index 000000000..0c668f59b
--- /dev/null
+++ b/drivers/acpi/driver.c
@@ -0,0 +1,388 @@
+/*
+ * driver.c - ACPI driver
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
+#include <asm/uaccess.h>
+#include "acpi.h"
+#include "driver.h"
+
+struct acpi_run_entry
+{
+ void (*callback)(void*);
+ void *context;
+ struct tq_struct task;
+};
+
+static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED;
+static volatile u32 acpi_event_status = 0;
+static volatile acpi_sstate_t acpi_event_state = ACPI_S0;
+static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait);
+
+static volatile int acpi_thread_pid = -1;
+static DECLARE_TASK_QUEUE(acpi_thread_run);
+static DECLARE_WAIT_QUEUE_HEAD(acpi_thread_wait);
+
+static struct ctl_table_header *acpi_sysctl = NULL;
+
+/*
+ * Examine/modify value
+ */
+static int
+acpi_do_ulong(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len)
+{
+ char str[2 * sizeof(unsigned long) + 4], *strend;
+ unsigned long val;
+ int size;
+
+ if (!write) {
+ if (file->f_pos) {
+ *len = 0;
+ return 0;
+ }
+
+ val = *(unsigned long *) ctl->data;
+ size = sprintf(str, "0x%08lx\n", val);
+ if (*len >= size) {
+ copy_to_user(buffer, str, size);
+ *len = size;
+ }
+ else
+ *len = 0;
+ }
+ else {
+ size = sizeof(str) - 1;
+ if (size > *len)
+ size = *len;
+ copy_from_user(str, buffer, size);
+ str[size] = '\0';
+ val = simple_strtoul(str, &strend, 0);
+ if (strend == str)
+ return -EINVAL;
+ *(unsigned long *) ctl->data = val;
+ }
+
+ file->f_pos += *len;
+ return 0;
+}
+
+/*
+ * Handle ACPI event
+ */
+static u32
+acpi_event(void *context)
+{
+ unsigned long flags;
+ int event = (int) context;
+ int mask = 0;
+
+ switch (event) {
+ case ACPI_EVENT_POWER_BUTTON: mask = ACPI_PWRBTN; break;
+ case ACPI_EVENT_SLEEP_BUTTON: mask = ACPI_SLPBTN; break;
+ default: return AE_ERROR;
+ }
+
+ if (mask) {
+ // notify process waiting on /dev/acpi
+ spin_lock_irqsave(&acpi_event_lock, flags);
+ acpi_event_status |= mask;
+ spin_unlock_irqrestore(&acpi_event_lock, flags);
+ acpi_event_state = acpi_sleep_state;
+ wake_up_interruptible(&acpi_event_wait);
+ }
+
+ return AE_OK;
+}
+
+/*
+ * Wait for next event
+ */
+static int
+acpi_do_event(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len)
+{
+ u32 event_status = 0;
+ acpi_sstate_t event_state = 0;
+ char str[27];
+ int size;
+
+ if (write)
+ return -EPERM;
+ if (*len < sizeof(str)) {
+ *len = 0;
+ return 0;
+ }
+
+ for (;;) {
+ unsigned long flags;
+
+ // we need an atomic exchange here
+ spin_lock_irqsave(&acpi_event_lock, flags);
+ event_status = acpi_event_status;
+ acpi_event_status = 0;
+ spin_unlock_irqrestore(&acpi_event_lock, flags);
+ event_state = acpi_event_state;
+
+ if (event_status)
+ break;
+
+ // wait for an event to arrive
+ interruptible_sleep_on(&acpi_event_wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ }
+
+ size = sprintf(str,
+ "0x%08x 0x%08x 0x%01x\n",
+ event_status,
+ 0,
+ event_state);
+ copy_to_user(buffer, str, size);
+ *len = size;
+ file->f_pos += size;
+
+ return 0;
+}
+
+/*
+ * Enter system sleep state
+ */
+static int
+acpi_do_sleep(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len)
+{
+ if (!write) {
+ if (file->f_pos) {
+ *len = 0;
+ return 0;
+ }
+ }
+ else {
+#ifdef CONFIG_ACPI_S1_SLEEP
+ int status = acpi_enter_sx(ACPI_S1);
+ if (status)
+ return status;
+#endif
+ }
+ file->f_pos += *len;
+ return 0;
+}
+
+/*
+ * Run queued callback
+ */
+static void
+acpi_run_exec(void *context)
+{
+ struct acpi_run_entry *entry
+ = (struct acpi_run_entry*) context;
+ (*entry->callback)(entry->context);
+ kfree(entry);
+}
+
+/*
+ * Queue for execution by the ACPI thread
+ */
+int
+acpi_run(void (*callback)(void*), void *context)
+{
+ struct acpi_run_entry *entry;
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry)
+ return -1;
+
+ memset(entry, 0, sizeof(entry));
+ entry->callback = callback;
+ entry->context = context;
+ entry->task.routine = acpi_run_exec;
+ entry->task.data = entry;
+
+ queue_task(&entry->task, &acpi_thread_run);
+
+ if (waitqueue_active(&acpi_thread_wait))
+ wake_up(&acpi_thread_wait);
+
+ return 0;
+}
+
+static struct ctl_table acpi_table[] =
+{
+ {ACPI_P_LVL2_LAT, "c2_exit_latency",
+ &acpi_c2_exit_latency, sizeof(acpi_c2_exit_latency),
+ 0644, NULL, &acpi_do_ulong},
+
+ {ACPI_ENTER_LVL2_LAT, "c2_enter_latency",
+ &acpi_c2_enter_latency, sizeof(acpi_c2_enter_latency),
+ 0644, NULL, &acpi_do_ulong},
+
+ {ACPI_P_LVL3_LAT, "c3_exit_latency",
+ &acpi_c3_exit_latency, sizeof(acpi_c3_exit_latency),
+ 0644, NULL, &acpi_do_ulong},
+
+ {ACPI_ENTER_LVL3_LAT, "c3_enter_latency",
+ &acpi_c3_enter_latency, sizeof(acpi_c3_enter_latency),
+ 0644, NULL, &acpi_do_ulong},
+
+ {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},
+
+ {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event},
+
+ {0}
+};
+
+static struct ctl_table acpi_dir_table[] =
+{
+ {CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table},
+ {0}
+};
+
+/*
+ * Initialize and run interpreter within a kernel thread
+ */
+static int
+acpi_thread(void *context)
+{
+ /*
+ * initialize
+ */
+ exit_files(current);
+ daemonize();
+ strcpy(current->comm, "acpi");
+
+ if (!ACPI_SUCCESS(acpi_initialize(NULL))) {
+ printk(KERN_ERR "ACPI: initialize failed\n");
+ return -ENODEV;
+ }
+
+ if (acpi_load_tables())
+ return -ENODEV;
+
+ if (PM_IS_ACTIVE()) {
+ printk(KERN_NOTICE "ACPI: APM is already active.\n");
+ acpi_terminate();
+ return -ENODEV;
+ }
+
+ pm_active = 1;
+
+ if (!ACPI_SUCCESS(acpi_enable())) {
+ printk(KERN_ERR "ACPI: enable failed\n");
+ acpi_terminate();
+ return -ENODEV;
+ }
+
+ acpi_cpu_init();
+ acpi_sys_init();
+ acpi_ec_init();
+
+ if (!ACPI_SUCCESS(acpi_install_fixed_event_handler(
+ ACPI_EVENT_POWER_BUTTON,
+ acpi_event,
+ (void *) ACPI_EVENT_POWER_BUTTON))) {
+ printk(KERN_ERR "ACPI: power button enable failed\n");
+ }
+ if (!ACPI_SUCCESS(acpi_install_fixed_event_handler(
+ ACPI_EVENT_SLEEP_BUTTON,
+ acpi_event,
+ (void *) ACPI_EVENT_SLEEP_BUTTON))) {
+ printk(KERN_ERR "ACPI: sleep button enable failed\n");
+ }
+
+ acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
+
+ /*
+ * run
+ */
+ for (;;) {
+ interruptible_sleep_on(&acpi_thread_wait);
+ if (signal_pending(current))
+ break;
+ do {
+ run_task_queue(&acpi_thread_run);
+ } while (acpi_thread_run);
+ }
+
+ /*
+ * terminate
+ */
+ unregister_sysctl_table(acpi_sysctl);
+ acpi_terminate();
+
+ acpi_thread_pid = -1;
+
+ return 0;
+}
+
+/*
+ * Start the interpreter
+ */
+int __init
+acpi_init(void)
+{
+ acpi_thread_pid = kernel_thread(acpi_thread,
+ NULL,
+ (CLONE_FS | CLONE_FILES
+ | CLONE_SIGHAND | SIGCHLD));
+ return ((acpi_thread_pid >= 0) ? 0:-ENODEV);
+}
+
+/*
+ * Terminate the interpreter
+ */
+void __exit
+acpi_exit(void)
+{
+ int count;
+
+ if (!kill_proc(acpi_thread_pid, SIGTERM, 1)) {
+ // wait until thread terminates (at most 5 seconds)
+ count = 5 * HZ;
+ while (acpi_thread_pid >= 0 && --count) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ }
+
+ pm_idle = NULL;
+ pm_power_off = NULL;
+ pm_active = 0;
+}
+
+module_init(acpi_init);
+module_exit(acpi_exit);
diff --git a/drivers/acpi/driver.h b/drivers/acpi/driver.h
new file mode 100644
index 000000000..a26402b40
--- /dev/null
+++ b/drivers/acpi/driver.h
@@ -0,0 +1,115 @@
+/*
+ * driver.h - ACPI driver
+ *
+ * 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
+ */
+
+#ifndef __DRIVER_H
+#define __DRIVER_H
+
+#include <linux/tqueue.h>
+#include <linux/wait.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
+#include <asm/io.h>
+
+#define ACPI_MAX_THROTTLE 10
+#define ACPI_INVALID ~0UL
+#define ACPI_INFINITE ~0UL
+
+/*
+ * cpu.c
+ */
+int acpi_cpu_init(void);
+
+extern unsigned long acpi_c2_exit_latency;
+extern unsigned long acpi_c3_exit_latency;
+extern unsigned long acpi_c2_enter_latency;
+extern unsigned long acpi_c3_enter_latency;
+
+/*
+ * driver.c
+ */
+int acpi_run(void (*callback)(void*), void *context);
+
+/*
+ * ec.c
+ */
+int acpi_ec_init(void);
+int acpi_ec_read(int addr, int *value);
+int acpi_ec_write(int addr, int value);
+
+/*
+ * sys.c
+ */
+int acpi_sys_init(void);
+int acpi_enter_sx(acpi_sstate_t state);
+
+extern volatile acpi_sstate_t acpi_sleep_state;
+
+/*
+ * tables.c
+ */
+extern struct acpi_facp acpi_facp;
+
+int acpi_load_tables(void);
+
+/*
+ * access ACPI registers
+ */
+
+extern inline u32
+acpi_read_pm1_control(struct acpi_facp *facp)
+{
+ u32 value = 0;
+ if (facp->pm1a_cnt)
+ value = inw(facp->pm1a_cnt);
+ if (facp->pm1b_cnt)
+ value |= inw(facp->pm1b_cnt);
+ return value;
+}
+
+extern inline void
+acpi_write_pm1_control(struct acpi_facp *facp, u32 value)
+{
+ if (facp->pm1a_cnt)
+ outw(value, facp->pm1a_cnt);
+ if (facp->pm1b_cnt)
+ outw(value, facp->pm1b_cnt);
+}
+
+extern inline u32
+acpi_read_pm1_status(struct acpi_facp *facp)
+{
+ u32 value = 0;
+ if (facp->pm1a_evt)
+ value = inw(facp->pm1a_evt);
+ if (facp->pm1b_evt)
+ value |= inw(facp->pm1b_evt);
+ return value;
+}
+
+extern inline void
+acpi_write_pm1_status(struct acpi_facp *facp, u32 value)
+{
+ if (facp->pm1a_evt)
+ outw(value, facp->pm1a_evt);
+ if (facp->pm1b_evt)
+ outw(value, facp->pm1b_evt);
+}
+
+#endif /* __DRIVER_H */
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
new file mode 100644
index 000000000..3e5fe753f
--- /dev/null
+++ b/drivers/acpi/ec.c
@@ -0,0 +1,191 @@
+/*
+ * ec.c - Embedded controller support
+ *
+ * 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/types.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include "acpi.h"
+#include "driver.h"
+
+enum
+{
+ ACPI_EC_HID = 0x090cd041,
+};
+
+enum
+{
+ ACPI_EC_SMI = 0x40,
+ ACPI_EC_SCI = 0x20,
+ ACPI_EC_BURST = 0x10,
+ ACPI_EC_CMD = 0x08,
+ ACPI_EC_IBF = 0x02,
+ ACPI_EC_OBF = 0x01
+};
+
+enum
+{
+ ACPI_EC_READ = 0x80,
+ ACPI_EC_WRITE = 0x81,
+ ACPI_EC_BURST_ENABLE = 0x82,
+ ACPI_EC_BURST_DISABLE = 0x83,
+ ACPI_EC_QUERY = 0x84,
+};
+
+
+static int acpi_ec_data = 0;
+static int acpi_ec_status = 0;
+static DECLARE_WAIT_QUEUE_HEAD(acpi_ec_wait);
+
+/*
+ * handle GPE
+ */
+static void
+acpi_ec_gpe(void *context)
+{
+ printk(KERN_INFO "ACPI: EC GPE\n");
+ if (waitqueue_active(&acpi_ec_wait))
+ wake_up_interruptible(&acpi_ec_wait);
+}
+
+/*
+ * wait for read/write status to clear
+ */
+static void
+acpi_ec_wait_control(void)
+{
+ udelay(1);
+ while(inb(acpi_ec_status) & ACPI_EC_IBF)
+ udelay(10);
+}
+
+/*
+ * read a byte from the EC
+ */
+int
+acpi_ec_read(int addr, int *value)
+{
+ if (!acpi_ec_data || !acpi_ec_status)
+ return -1;
+
+ outb(ACPI_EC_READ, acpi_ec_status);
+ acpi_ec_wait_control();
+ outb(addr, acpi_ec_data);
+ acpi_ec_wait_control();
+ interruptible_sleep_on(&acpi_ec_wait);
+ *value = inb(acpi_ec_data);
+
+ return 0;
+}
+
+/*
+ * write a byte to the EC
+ */
+int
+acpi_ec_write(int addr, int value)
+{
+ if (!acpi_ec_data || !acpi_ec_status)
+ return -1;
+
+ outb(ACPI_EC_WRITE, acpi_ec_status);
+ acpi_ec_wait_control();
+ outb(addr, acpi_ec_data);
+ acpi_ec_wait_control();
+ outb(value, acpi_ec_data);
+ acpi_ec_wait_control();
+ interruptible_sleep_on(&acpi_ec_wait);
+
+ return 0;
+}
+
+/*
+ * Get processor information
+ */
+static ACPI_STATUS
+acpi_find_ec(ACPI_HANDLE handle, u32 level, void *ctx, void **value)
+{
+ ACPI_BUFFER buf;
+ ACPI_OBJECT obj;
+ RESOURCE *res;
+ int gpe;
+
+ buf.length = sizeof(obj);
+ buf.pointer = &obj;
+ if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_HID", NULL, &buf))
+ || obj.type != ACPI_TYPE_NUMBER
+ || obj.number.value != ACPI_EC_HID)
+ return AE_OK;
+
+ buf.length = 0;
+ buf.pointer = NULL;
+ if (acpi_get_current_resources(handle, &buf) != AE_BUFFER_OVERFLOW)
+ return AE_OK;
+
+ buf.pointer = kmalloc(buf.length, GFP_KERNEL);
+ if (!buf.pointer)
+ return AE_OK;
+
+ if (!ACPI_SUCCESS(acpi_get_current_resources(handle, &buf))) {
+ kfree(buf.pointer);
+ return AE_OK;
+ }
+
+ res = (RESOURCE*) buf.pointer;
+ acpi_ec_data = (int) res->data.io.min_base_address;
+ res = (RESOURCE*)((u8*) buf.pointer + res->length);
+ acpi_ec_status = (int) res->data.io.min_base_address;
+
+ kfree(buf.pointer);
+
+ buf.length = sizeof(obj);
+ buf.pointer = &obj;
+ if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_GPE", NULL, &buf))
+ || obj.type != ACPI_TYPE_NUMBER)
+ return AE_OK;
+ gpe = (int) obj.number.value;
+
+ printk(KERN_INFO "ACPI: found EC @ (0x%02x,0x%02x,%d)\n",
+ acpi_ec_data, acpi_ec_status, gpe);
+
+ if (!ACPI_SUCCESS(acpi_install_gpe_handler(
+ gpe,
+ (ACPI_EVENT_LEVEL_TRIGGERED
+ | ACPI_EVENT_EDGE_TRIGGERED),
+ acpi_ec_gpe,
+ NULL)))
+ return AE_OK;
+
+ return AE_OK;
+}
+
+int
+acpi_ec_init(void)
+{
+ acpi_walk_namespace(ACPI_TYPE_DEVICE,
+ ACPI_ROOT_OBJECT,
+ ACPI_INT32_MAX,
+ acpi_find_ec,
+ NULL,
+ NULL);
+ return 0;
+}
diff --git a/drivers/acpi/os.c b/drivers/acpi/os.c
new file mode 100644
index 000000000..7398534ad
--- /dev/null
+++ b/drivers/acpi/os.c
@@ -0,0 +1,379 @@
+/*
+ * os.c - OS-dependent functions
+ *
+ * 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/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include "acpi.h"
+#include "driver.h"
+
+static int acpi_irq_irq = 0;
+static OSD_HANDLER acpi_irq_handler = NULL;
+static void *acpi_irq_context = NULL;
+
+char *
+strupr(char *str)
+{
+ char *s = str;
+ while (*s) {
+ *s = TOUPPER(*s);
+ s++;
+ }
+ return str;
+}
+
+ACPI_STATUS
+acpi_os_initialize(void)
+{
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_terminate(void)
+{
+ if (acpi_irq_handler) {
+ acpi_os_remove_interrupt_handler(acpi_irq_irq,
+ acpi_irq_handler);
+ }
+ return AE_OK;
+}
+
+s32
+acpi_os_printf(const char *fmt,...)
+{
+ s32 size;
+ va_list args;
+ va_start(args, fmt);
+ size = acpi_os_vprintf(fmt, args);
+ va_end(args);
+ return size;
+}
+
+s32
+acpi_os_vprintf(const char *fmt, va_list args)
+{
+ static char buffer[512];
+ int size = vsprintf(buffer, fmt, args);
+ printk(KERN_DEBUG "ACPI: %s", buffer);
+ return size;
+}
+
+void *
+acpi_os_allocate(u32 size)
+{
+ return kmalloc(size, GFP_KERNEL);
+}
+
+void *
+acpi_os_callocate(u32 size)
+{
+ void *ptr = acpi_os_allocate(size);
+ if (ptr)
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+void
+acpi_os_free(void *ptr)
+{
+ kfree(ptr);
+}
+
+ACPI_STATUS
+acpi_os_map_memory(void *phys, u32 size, void **virt)
+{
+ if ((unsigned long) phys < virt_to_phys(high_memory)) {
+ *virt = phys_to_virt((unsigned long) phys);
+ return AE_OK;
+ }
+
+ *virt = ioremap((unsigned long) phys, size);
+ if (!*virt)
+ return AE_ERROR;
+
+ return AE_OK;
+}
+
+void
+acpi_os_unmap_memory(void *virt, u32 size)
+{
+ if (virt >= high_memory)
+ iounmap(virt);
+}
+
+static void
+acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ (*acpi_irq_handler)(acpi_irq_context);
+}
+
+ACPI_STATUS
+acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context)
+{
+ acpi_irq_irq = irq;
+ acpi_irq_handler = handler;
+ acpi_irq_context = context;
+ if (request_irq(irq,
+ acpi_irq,
+ SA_INTERRUPT | SA_SHIRQ,
+ "acpi",
+ acpi_irq)) {
+ printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", irq);
+ return AE_ERROR;
+ }
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler)
+{
+ if (acpi_irq_handler) {
+ free_irq(irq, acpi_irq);
+ acpi_irq_handler = NULL;
+ }
+ return AE_OK;
+}
+
+/*
+ * Running in interpreter thread context, safe to sleep
+ */
+
+void
+acpi_os_sleep(u32 sec, u32 ms)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ * sec + (ms * HZ) / 1000);
+}
+
+void
+acpi_os_sleep_usec(u32 us)
+{
+ udelay(us);
+}
+
+u8
+acpi_os_in8(ACPI_IO_ADDRESS port)
+{
+ return inb(port);
+}
+
+u16
+acpi_os_in16(ACPI_IO_ADDRESS port)
+{
+ return inw(port);
+}
+
+u32
+acpi_os_in32(ACPI_IO_ADDRESS port)
+{
+ return inl(port);
+}
+
+void
+acpi_os_out8(ACPI_IO_ADDRESS port, u8 val)
+{
+ outb(val, port);
+}
+
+void
+acpi_os_out16(ACPI_IO_ADDRESS port, u16 val)
+{
+ outw(val, port);
+}
+
+void
+acpi_os_out32(ACPI_IO_ADDRESS port, u32 val)
+{
+ outl(val, port);
+}
+
+ACPI_STATUS
+acpi_os_read_pci_cfg_byte(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u8 * val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!val || !dev || pci_read_config_byte(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_read_pci_cfg_word(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u16 * val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!val || !dev || pci_read_config_word(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_read_pci_cfg_dword(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u32 * val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!val || !dev || pci_read_config_dword(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_write_pci_cfg_byte(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u8 val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!dev || pci_write_config_byte(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_write_pci_cfg_word(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u16 val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!dev || pci_write_config_word(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_write_pci_cfg_dword(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u32 val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!dev || pci_write_config_dword(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+/*
+ * Queue for interpreter thread
+ */
+
+ACPI_STATUS
+acpi_os_queue_for_execution(
+ u32 priority,
+ OSD_EXECUTION_CALLBACK callback,
+ void *context)
+{
+ if (acpi_run(callback, context))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+/*
+ * Semaphores are unused, interpreter access is single threaded
+ */
+
+ACPI_STATUS
+acpi_os_create_semaphore(u32 max_units, u32 init, ACPI_HANDLE * handle)
+{
+ *handle = (ACPI_HANDLE) 0;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_delete_semaphore(ACPI_HANDLE handle)
+{
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_wait_semaphore(ACPI_HANDLE handle, u32 units, u32 timeout)
+{
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_signal_semaphore(ACPI_HANDLE handle, u32 units)
+{
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_breakpoint(char *msg)
+{
+ acpi_os_printf("breakpoint: %s", msg);
+ return AE_OK;
+}
+
+void
+acpi_os_dbg_trap(char *msg)
+{
+ acpi_os_printf("trap: %s", msg);
+}
+
+void
+acpi_os_dbg_assert(void *failure, void *file, u32 line, char *msg)
+{
+ acpi_os_printf("assert: %s", msg);
+}
+
+u32
+acpi_os_get_line(char *buffer)
+{
+ return 0;
+}
+
+/*
+ * We just have to assume we're dealing with valid memory
+ */
+
+BOOLEAN
+acpi_os_readable(void *ptr, u32 len)
+{
+ return 1;
+}
+
+BOOLEAN
+acpi_os_writable(void *ptr, u32 len)
+{
+ return 1;
+}
diff --git a/drivers/acpi/osd.c b/drivers/acpi/osd.c
deleted file mode 100644
index 402df75d7..000000000
--- a/drivers/acpi/osd.c
+++ /dev/null
@@ -1,1319 +0,0 @@
-/*
- * osd.c - Linux specific code
- *
- * 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/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/sysctl.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/pm.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/acpi.h>
-#include <asm/io.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
-#include "acpi.h"
-
-#define ACPI_MAX_THROTTLE 10
-#define ACPI_INVALID ~0UL
-#define ACPI_INFINITE ~0UL
-
-static struct acpi_facp *acpi_facp = NULL;
-
-static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED;
-static volatile u32 acpi_event_status = 0;
-static volatile acpi_sstate_t acpi_event_state = ACPI_S0;
-static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait);
-static int acpi_irq_irq = 0;
-static OSD_HANDLER acpi_irq_handler = NULL;
-static void *acpi_irq_context = NULL;
-
-static unsigned long acpi_pblk = ACPI_INVALID;
-static unsigned long acpi_c2_exit_latency = ACPI_INFINITE;
-static unsigned long acpi_c3_exit_latency = ACPI_INFINITE;
-static unsigned long acpi_c2_enter_latency = ACPI_INFINITE;
-static unsigned long acpi_c3_enter_latency = ACPI_INFINITE;
-static int acpi_c2_tested = 0;
-static int acpi_c3_tested = 0;
-
-struct acpi_intrp_entry
-{
- int priority;
- OSD_EXECUTION_CALLBACK callback;
- void *context;
- struct list_head list;
-};
-
-struct acpi_enter_sx_ctx
-{
- wait_queue_head_t wait;
- int state;
-};
-
-static volatile int acpi_intrp_pid = -1;
-static DECLARE_WAIT_QUEUE_HEAD(acpi_intrp_wait);
-static LIST_HEAD(acpi_intrp_exec);
-static spinlock_t acpi_intrp_exec_lock = SPIN_LOCK_UNLOCKED;
-
-#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)
-
-static volatile acpi_sstate_t acpi_sleep_state = ACPI_S0;
-static unsigned long acpi_slptyp[ACPI_S5 + 1] = {ACPI_INVALID,};
-
-static struct ctl_table_header *acpi_sysctl = NULL;
-
-static int acpi_do_ulong(ctl_table * ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t * len);
-static int acpi_do_sleep(ctl_table * ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t * len);
-static int acpi_do_event(ctl_table * ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t * len);
-
-static struct ctl_table acpi_table[] =
-{
- {ACPI_P_LVL2_LAT, "c2_exit_latency",
- &acpi_c2_exit_latency, sizeof(acpi_c2_exit_latency),
- 0644, NULL, &acpi_do_ulong},
-
- {ACPI_ENTER_LVL2_LAT, "c2_enter_latency",
- &acpi_c2_enter_latency, sizeof(acpi_c2_enter_latency),
- 0644, NULL, &acpi_do_ulong},
-
- {ACPI_P_LVL3_LAT, "c3_exit_latency",
- &acpi_c3_exit_latency, sizeof(acpi_c3_exit_latency),
- 0644, NULL, &acpi_do_ulong},
-
- {ACPI_ENTER_LVL3_LAT, "c3_enter_latency",
- &acpi_c3_enter_latency, sizeof(acpi_c3_enter_latency),
- 0644, NULL, &acpi_do_ulong},
-
- {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},
-
- {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event},
-
- {0}
-};
-
-static struct ctl_table acpi_dir_table[] =
-{
- {CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table},
- {0}
-};
-
-static u32 FASTCALL(acpi_read_pm1_control(struct acpi_facp *));
-static u32 FASTCALL(acpi_read_pm1_status(struct acpi_facp *));
-static void FASTCALL(acpi_write_pm1_control(struct acpi_facp *, u32));
-static void FASTCALL(acpi_write_pm1_status(struct acpi_facp *, u32));
-
-/*
- * Get the value of the PM1 control register (ACPI_SCI_EN, ...)
- */
-static u32
-acpi_read_pm1_control(struct acpi_facp *facp)
-{
- u32 value = 0;
- if (facp->pm1a_cnt)
- value = inw(facp->pm1a_cnt);
- if (facp->pm1b_cnt)
- value |= inw(facp->pm1b_cnt);
- return value;
-}
-
-/*
- * Set the value of the PM1 control register (ACPI_BM_RLD, ...)
- */
-static void
-acpi_write_pm1_control(struct acpi_facp *facp, u32 value)
-{
- if (facp->pm1a_cnt)
- outw(value, facp->pm1a_cnt);
- if (facp->pm1b_cnt)
- outw(value, facp->pm1b_cnt);
-}
-
-/*
- * Get the value of the fixed event status register
- */
-static u32
-acpi_read_pm1_status(struct acpi_facp *facp)
-{
- u32 value = 0;
- if (facp->pm1a_evt)
- value = inw(facp->pm1a_evt);
- if (facp->pm1b_evt)
- value |= inw(facp->pm1b_evt);
- return value;
-}
-
-/*
- * Set the value of the fixed event status register (clear events)
- */
-static void
-acpi_write_pm1_status(struct acpi_facp *facp, u32 value)
-{
- if (facp->pm1a_evt)
- outw(value, facp->pm1a_evt);
- if (facp->pm1b_evt)
- outw(value, facp->pm1b_evt);
-}
-
-/*
- * Examine/modify value
- */
-static int
-acpi_do_ulong(ctl_table * ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t * len)
-{
- char str[2 * sizeof(unsigned long) + 4], *strend;
- unsigned long val;
- int size;
-
- if (!write) {
- if (file->f_pos) {
- *len = 0;
- return 0;
- }
-
- val = *(unsigned long *) ctl->data;
- size = sprintf(str, "0x%08lx\n", val);
- if (*len >= size) {
- copy_to_user(buffer, str, size);
- *len = size;
- }
- else
- *len = 0;
- }
- else {
- size = sizeof(str) - 1;
- if (size > *len)
- size = *len;
- copy_from_user(str, buffer, size);
- str[size] = '\0';
- val = simple_strtoul(str, &strend, 0);
- if (strend == str)
- return -EINVAL;
- *(unsigned long *) ctl->data = val;
- }
-
- file->f_pos += *len;
- return 0;
-}
-
-/*
- * Handle ACPI event
- */
-u32
-acpi_event(void *context)
-{
- unsigned long flags;
- int event = (int) context;
- int mask = 0;
-
- switch (event) {
- case ACPI_EVENT_POWER_BUTTON:
- mask = ACPI_PWRBTN;
- break;
- case ACPI_EVENT_SLEEP_BUTTON:
- mask = ACPI_SLPBTN;
- break;
- }
-
- if (mask) {
- // notify process waiting on /dev/acpi
- spin_lock_irqsave(&acpi_event_lock, flags);
- acpi_event_status |= mask;
- spin_unlock_irqrestore(&acpi_event_lock, flags);
- acpi_event_state = acpi_sleep_state;
- wake_up_interruptible(&acpi_event_wait);
- }
-
- return AE_OK;
-}
-
-/*
- * Wait for next event
- */
-int
-acpi_do_event(ctl_table * ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t * len)
-{
- u32 event_status = 0;
- acpi_sstate_t event_state = 0;
- char str[27];
- int size;
-
- if (write)
- return -EPERM;
- if (*len < sizeof(str)) {
- *len = 0;
- return 0;
- }
-
- for (;;) {
- unsigned long flags;
-
- // we need an atomic exchange here
- spin_lock_irqsave(&acpi_event_lock, flags);
- event_status = acpi_event_status;
- acpi_event_status = 0;
- spin_unlock_irqrestore(&acpi_event_lock, flags);
- event_state = acpi_event_state;
-
- if (event_status)
- break;
-
- // wait for an event to arrive
- interruptible_sleep_on(&acpi_event_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
-
- size = sprintf(str,
- "0x%08x 0x%08x 0x%01x\n",
- event_status,
- 0,
- event_state);
- copy_to_user(buffer, str, size);
- *len = size;
- file->f_pos += size;
-
- return 0;
-}
-
-/*
- * Enter system sleep state
- */
-static void
-acpi_enter_sx(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 system sleep state and wait for completion
- */
-static int
-acpi_enter_sx_and_wait(acpi_sstate_t state)
-{
- struct acpi_enter_sx_ctx ctx;
-
- if (!acpi_facp
- || 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, &ctx))
- return -1;
-
- interruptible_sleep_on(&ctx.wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- return 0;
-}
-
-/*
- * Enter system sleep state
- */
-static int
-acpi_do_sleep(ctl_table * ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t * len)
-{
- if (!write) {
- if (file->f_pos) {
- *len = 0;
- return 0;
- }
- }
- else {
-#ifdef CONFIG_ACPI_S1_SLEEP
- int status = acpi_enter_sx_and_wait(ACPI_S1);
- if (status)
- return status;
-#endif
- }
- file->f_pos += *len;
- return 0;
-}
-
-/*
- * Clear busmaster activity flag
- */
-static inline void
-acpi_clear_bm_activity(struct acpi_facp *facp)
-{
- acpi_write_pm1_status(facp, ACPI_BM);
-}
-
-/*
- * Returns 1 if there has been busmaster activity
- */
-static inline int
-acpi_bm_activity(struct acpi_facp *facp)
-{
- return acpi_read_pm1_status(facp) & ACPI_BM;
-}
-
-/*
- * Set system to sleep through busmaster requests
- */
-static void
-acpi_sleep_on_busmaster(struct acpi_facp *facp)
-{
- u32 pm1_cntr = acpi_read_pm1_control(facp);
- if (pm1_cntr & ACPI_BM_RLD) {
- pm1_cntr &= ~ACPI_BM_RLD;
- acpi_write_pm1_control(facp, pm1_cntr);
- }
-}
-
-/*
- * Set system to wake on busmaster requests
- */
-static void
-acpi_wake_on_busmaster(struct acpi_facp *facp)
-{
- u32 pm1_cntr = acpi_read_pm1_control(facp);
- if (!(pm1_cntr & ACPI_BM_RLD)) {
- pm1_cntr |= ACPI_BM_RLD;
- acpi_write_pm1_control(facp, pm1_cntr);
- }
- acpi_clear_bm_activity(facp);
-}
-
-/* The ACPI timer is just the low 24 bits */
-#define TIME_BEGIN(tmr) inl(tmr)
-#define TIME_END(tmr, begin) ((inl(tmr) - (begin)) & 0x00ffffff)
-
-/*
- * Idle loop (uniprocessor only)
- */
-void
-acpi_idle(void)
-{
- static int sleep_level = 1;
- struct acpi_facp *facp = acpi_facp;
-
- if (!facp
- || facp->hdr.signature != ACPI_FACP_SIG
- || !facp->pm_tmr
- || !acpi_pblk)
- goto not_initialized;
-
- /*
- * start from the previous sleep level..
- */
- if (sleep_level == 1)
- goto sleep1;
- if (sleep_level == 2)
- goto sleep2;
- sleep3:
- sleep_level = 3;
- if (!acpi_c3_tested) {
- printk(KERN_DEBUG "ACPI C3 works\n");
- acpi_c3_tested = 1;
- }
- acpi_wake_on_busmaster(facp);
- if (facp->pm2_cnt)
- goto sleep3_with_arbiter;
-
- for (;;) {
- unsigned long time;
- unsigned int pm_tmr = facp->pm_tmr;
-
- __cli();
- if (current->need_resched)
- goto out;
- if (acpi_bm_activity(facp))
- goto sleep2;
-
- time = TIME_BEGIN(pm_tmr);
- inb(acpi_pblk + ACPI_P_LVL3);
- /* Dummy read, force synchronization with the PMU */
- inl(pm_tmr);
- time = TIME_END(pm_tmr, time);
-
- __sti();
- if (time < acpi_c3_exit_latency)
- goto sleep2;
- }
-
- sleep3_with_arbiter:
- for (;;) {
- unsigned long time;
- u8 arbiter;
- unsigned int pm2_cntr = facp->pm2_cnt;
- unsigned int pm_tmr = facp->pm_tmr;
-
- __cli();
- if (current->need_resched)
- goto out;
- if (acpi_bm_activity(facp))
- goto sleep2;
-
- time = TIME_BEGIN(pm_tmr);
- arbiter = inb(pm2_cntr) & ~ACPI_ARB_DIS;
- /* Disable arbiter, park on CPU */
- outb(arbiter | ACPI_ARB_DIS, pm2_cntr);
- inb(acpi_pblk + ACPI_P_LVL3);
- /* Dummy read, force synchronization with the PMU */
- inl(pm_tmr);
- time = TIME_END(pm_tmr, time);
- /* Enable arbiter again.. */
- outb(arbiter, pm2_cntr);
-
- __sti();
- if (time < acpi_c3_exit_latency)
- goto sleep2;
- }
-
- sleep2:
- sleep_level = 2;
- if (!acpi_c2_tested) {
- printk(KERN_DEBUG "ACPI C2 works\n");
- acpi_c2_tested = 1;
- }
- acpi_wake_on_busmaster(facp); /* Required to track BM activity.. */
- for (;;) {
- unsigned long time;
- unsigned int pm_tmr = facp->pm_tmr;
-
- __cli();
- if (current->need_resched)
- goto out;
-
- time = TIME_BEGIN(pm_tmr);
- inb(acpi_pblk + ACPI_P_LVL2);
- /* Dummy read, force synchronization with the PMU */
- inl(pm_tmr);
- time = TIME_END(pm_tmr, time);
-
- __sti();
- if (time < acpi_c2_exit_latency)
- goto sleep1;
- if (acpi_bm_activity(facp)) {
- acpi_clear_bm_activity(facp);
- continue;
- }
- if (time > acpi_c3_enter_latency)
- goto sleep3;
- }
-
- sleep1:
- sleep_level = 1;
- acpi_sleep_on_busmaster(facp);
- for (;;) {
- unsigned long time;
- unsigned int pm_tmr = facp->pm_tmr;
-
- __cli();
- if (current->need_resched)
- goto out;
- time = TIME_BEGIN(pm_tmr);
- safe_halt();
- time = TIME_END(pm_tmr, time);
- if (time > acpi_c2_enter_latency)
- goto sleep2;
- }
-
- not_initialized:
- for (;;) {
- __cli();
- if (current->need_resched)
- goto out;
- safe_halt();
- }
-
- out:
- __sti();
-}
-
-/*
- * Enter soft-off (S5)
- */
-static void
-acpi_power_off(void)
-{
- struct acpi_enter_sx_ctx ctx;
-
- if (!acpi_facp
- || 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(&ctx);
-}
-
-/*
- * Get processor information
- */
-static ACPI_STATUS
-acpi_get_cpu_info(ACPI_HANDLE handle, u32 level, void *ctx, void **value)
-{
- ACPI_OBJECT obj;
- ACPI_CX_STATE lat[4];
- ACPI_CPU_THROTTLING_STATE throttle[ACPI_MAX_THROTTLE];
- ACPI_BUFFER buf;
- int i, count;
-
- buf.length = sizeof(obj);
- buf.pointer = &obj;
- if (!ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buf)))
- return AE_OK;
-
- printk(KERN_INFO "ACPI: PBLK %d @ 0x%04x:%d\n",
- obj.processor.proc_id,
- obj.processor.pblk_address,
- obj.processor.pblk_length);
- if (acpi_pblk != ACPI_INVALID
- || !obj.processor.pblk_address
- || obj.processor.pblk_length != 6)
- return AE_OK;
-
- acpi_pblk = obj.processor.pblk_address;
-
- buf.length = sizeof(lat);
- buf.pointer = lat;
- if (!ACPI_SUCCESS(acpi_get_processor_cx_info(handle, &buf)))
- return AE_OK;
-
- if (lat[2].latency < MAX_CX_STATE_LATENCY) {
- printk(KERN_INFO "ACPI: C2 supported\n");
- acpi_c2_exit_latency = lat[2].latency;
- }
- if (lat[3].latency < MAX_CX_STATE_LATENCY) {
- printk(KERN_INFO "ACPI: C3 supported\n");
- acpi_c3_exit_latency = lat[3].latency;
- }
-
- memset(throttle, 0, sizeof(throttle));
- buf.length = sizeof(throttle);
- buf.pointer = throttle;
-
- if (!ACPI_SUCCESS(acpi_get_processor_throttling_info(handle, &buf)))
- return AE_OK;
-
- for (i = 0, count = 0; i < ACPI_MAX_THROTTLE; i++) {
- if (throttle[i].percent_of_clock)
- count++;
- }
- count--;
- if (count > 0)
- printk(KERN_INFO "ACPI: %d throttling states\n", count);
-
- return AE_OK;
-}
-
-/*
- * Fetch the FACP information
- */
-static int
-acpi_fetch_facp(void)
-{
- ACPI_BUFFER buffer;
-
- buffer.pointer = acpi_facp;
- buffer.length = sizeof(*acpi_facp);
- if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FACP, 1, &buffer))) {
- printk(KERN_ERR "ACPI: no FACP\n");
- kfree(acpi_facp);
- return -ENODEV;
- }
-
- if (acpi_facp->p_lvl2_lat
- && acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
- acpi_c2_exit_latency
- = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl2_lat);
- acpi_c2_enter_latency
- = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000);
- }
- if (acpi_facp->p_lvl3_lat
- && acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
- acpi_c3_exit_latency
- = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat);
- acpi_c3_enter_latency
- = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat * 5);
- }
-
- return 0;
-}
-
-/*
- * Execute callbacks (interpret methods)
- */
-static void
-acpi_intrp_run(void)
-{
- for (;;) {
- struct acpi_intrp_entry *entry;
- unsigned long flags;
-
- interruptible_sleep_on(&acpi_intrp_wait);
- if (signal_pending(current))
- return;
-
- for (;;) {
- entry = NULL;
-
- spin_lock_irqsave(&acpi_intrp_exec_lock, flags);
- if (!list_empty(&acpi_intrp_exec)) {
- entry = list_entry(acpi_intrp_exec.next,
- struct acpi_intrp_entry,
- list);
- list_del(&entry->list);
- }
- spin_unlock_irqrestore(&acpi_intrp_exec_lock, flags);
-
- if (!entry)
- break;
-
- (*entry->callback)(entry->context);
-
- kfree(entry);
- }
- }
-}
-
-/*
- * Initialize and run interpreter within a kernel thread
- */
-static int
-acpi_intrp_thread(void *context)
-{
- ACPI_STATUS status;
- u8 sx, typa, typb;
-
- /*
- * initialize interpreter
- */
- exit_files(current);
- daemonize();
- strcpy(current->comm, "acpi");
-
- if (!ACPI_SUCCESS(acpi_initialize(NULL))) {
- printk(KERN_ERR "ACPI: initialize failed\n");
- return -ENODEV;
- }
-
- if (!ACPI_SUCCESS(acpi_load_firmware_tables())) {
- printk(KERN_ERR "ACPI: table load failed\n");
- acpi_terminate();
- return -ENODEV;
- }
-
- if (acpi_fetch_facp()) {
- acpi_terminate();
- return -ENODEV;
- }
-
- status = acpi_load_namespace();
- if (!ACPI_SUCCESS(status) && status != AE_CTRL_PENDING) {
- printk(KERN_ERR "ACPI: namespace load failed\n");
- acpi_terminate();
- return -ENODEV;
- }
-
- printk(KERN_INFO "ACPI: ACPI support found\n");
-
- acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
- ACPI_ROOT_OBJECT,
- ACPI_INT32_MAX,
- acpi_get_cpu_info,
- NULL,
- NULL);
-
- 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");
-
- if (!ACPI_SUCCESS(acpi_enable())) {
- printk(KERN_ERR "ACPI: enable failed\n");
- acpi_terminate();
- return -ENODEV;
- }
-
- if (!ACPI_SUCCESS(acpi_install_fixed_event_handler(
- ACPI_EVENT_POWER_BUTTON,
- acpi_event,
- (void *) ACPI_EVENT_POWER_BUTTON))) {
- printk(KERN_ERR "ACPI: power button enable failed\n");
- }
- if (!ACPI_SUCCESS(acpi_install_fixed_event_handler(
- ACPI_EVENT_SLEEP_BUTTON,
- acpi_event,
- (void *) ACPI_EVENT_SLEEP_BUTTON))) {
- printk(KERN_ERR "ACPI: sleep button enable failed\n");
- }
-
-#ifdef CONFIG_SMP
- if (smp_num_cpus == 1)
- pm_idle = acpi_idle;
-#else
- pm_idle = acpi_idle;
-#endif
- pm_power_off = acpi_power_off;
-
- acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
-
- /*
- * run interpreter
- */
- acpi_intrp_run();
-
- /*
- * terminate interpreter
- */
- unregister_sysctl_table(acpi_sysctl);
- acpi_terminate();
-
- acpi_intrp_pid = -1;
-
- return 0;
-}
-
-/*
- * Start the interpreter
- */
-int __init
-acpi_init(void)
-{
- acpi_facp = kmalloc(sizeof(*acpi_facp), GFP_KERNEL);
- if (!acpi_facp)
- return -ENOMEM;
- memset(acpi_facp, 0, sizeof(*acpi_facp));
-
- acpi_intrp_pid = kernel_thread(acpi_intrp_thread,
- NULL,
- (CLONE_FS | CLONE_FILES
- | CLONE_SIGHAND | SIGCHLD));
- return ((acpi_intrp_pid >= 0) ? 0:-ENODEV);
-}
-
-/*
- * Terminate the interpreter
- */
-void __exit
-acpi_exit(void)
-{
- int count;
-
- if (!kill_proc(acpi_intrp_pid, SIGTERM, 1)) {
- // wait until interpreter thread terminates (at most 5 seconds)
- count = 5 * HZ;
- while (acpi_intrp_pid >= 0 && --count) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
- }
- }
-
- // clean up after the interpreter
-
- if (acpi_irq_handler) {
- acpi_os_remove_interrupt_handler(acpi_irq_irq,
- acpi_irq_handler);
- }
-
- if (pm_power_off == acpi_power_off)
- pm_power_off = NULL;
- if (pm_idle == acpi_idle)
- pm_idle = NULL;
-
- kfree(acpi_facp);
-}
-
-module_init(acpi_init);
-module_exit(acpi_exit);
-
-/*
- * OS-dependent functions
- *
- */
-
-char *
-strupr(char *str)
-{
- char *s = str;
- while (*s) {
- *s = TOUPPER(*s);
- s++;
- }
- return str;
-}
-
-ACPI_STATUS
-acpi_os_initialize(void)
-{
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_terminate(void)
-{
- return AE_OK;
-}
-
-s32
-acpi_os_printf(const char *fmt,...)
-{
- s32 size;
- va_list args;
- va_start(args, fmt);
- size = acpi_os_vprintf(fmt, args);
- va_end(args);
- return size;
-}
-
-s32
-acpi_os_vprintf(const char *fmt, va_list args)
-{
- static char buffer[512];
- int size = vsprintf(buffer, fmt, args);
- printk(KERN_DEBUG "%s", buffer);
- return size;
-}
-
-void *
-acpi_os_allocate(u32 size)
-{
- return kmalloc(size, GFP_KERNEL);
-}
-
-void *
-acpi_os_callocate(u32 size)
-{
- void *ptr = acpi_os_allocate(size);
- if (ptr)
- memset(ptr, 0, size);
- return ptr;
-}
-
-void
-acpi_os_free(void *ptr)
-{
- kfree(ptr);
-}
-
-ACPI_STATUS
-acpi_os_map_memory(void *phys, u32 size, void **virt)
-{
- if ((unsigned long) phys < virt_to_phys(high_memory)) {
- *virt = phys_to_virt((unsigned long) phys);
- return AE_OK;
- }
-
- *virt = ioremap((unsigned long) phys, size);
- if (!*virt)
- return AE_ERROR;
-
- return AE_OK;
-}
-
-void
-acpi_os_unmap_memory(void *virt, u32 size)
-{
- if (virt >= high_memory)
- iounmap(virt);
-}
-
-static void
-acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- (*acpi_irq_handler)(acpi_irq_context);
-}
-
-ACPI_STATUS
-acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context)
-{
- acpi_irq_irq = irq;
- acpi_irq_handler = handler;
- acpi_irq_context = context;
- if (request_irq(irq,
- acpi_irq,
- SA_INTERRUPT | SA_SHIRQ,
- "acpi",
- acpi_irq)) {
- printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", irq);
- return AE_ERROR;
- }
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler)
-{
- if (acpi_irq_handler) {
- free_irq(irq, acpi_irq);
- acpi_irq_handler = NULL;
- }
- return AE_OK;
-}
-
-/*
- * Running in interpreter thread context, safe to sleep
- */
-
-void
-acpi_os_sleep(u32 sec, u32 ms)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ * sec + (ms * HZ) / 1000);
-}
-
-void
-acpi_os_sleep_usec(u32 us)
-{
- udelay(us);
-}
-
-u8
-acpi_os_in8(ACPI_IO_ADDRESS port)
-{
- return inb(port);
-}
-
-u16
-acpi_os_in16(ACPI_IO_ADDRESS port)
-{
- return inw(port);
-}
-
-u32
-acpi_os_in32(ACPI_IO_ADDRESS port)
-{
- return inl(port);
-}
-
-void
-acpi_os_out8(ACPI_IO_ADDRESS port, u8 val)
-{
- outb(val, port);
-}
-
-void
-acpi_os_out16(ACPI_IO_ADDRESS port, u16 val)
-{
- outw(val, port);
-}
-
-void
-acpi_os_out32(ACPI_IO_ADDRESS port, u32 val)
-{
- outl(val, port);
-}
-
-ACPI_STATUS
-acpi_os_read_pci_cfg_byte(
- u32 bus,
- u32 func,
- u32 addr,
- u8 * val)
-{
- int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
- struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
- if (!val || !dev || pci_read_config_byte(dev, addr, val))
- return AE_ERROR;
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_read_pci_cfg_word(
- u32 bus,
- u32 func,
- u32 addr,
- u16 * val)
-{
- int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
- struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
- if (!val || !dev || pci_read_config_word(dev, addr, val))
- return AE_ERROR;
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_read_pci_cfg_dword(
- u32 bus,
- u32 func,
- u32 addr,
- u32 * val)
-{
- int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
- struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
- if (!val || !dev || pci_read_config_dword(dev, addr, val))
- return AE_ERROR;
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_write_pci_cfg_byte(
- u32 bus,
- u32 func,
- u32 addr,
- u8 val)
-{
- int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
- struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
- if (!dev || pci_write_config_byte(dev, addr, val))
- return AE_ERROR;
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_write_pci_cfg_word(
- u32 bus,
- u32 func,
- u32 addr,
- u16 val)
-{
- int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
- struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
- if (!dev || pci_write_config_word(dev, addr, val))
- return AE_ERROR;
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_write_pci_cfg_dword(
- u32 bus,
- u32 func,
- u32 addr,
- u32 val)
-{
- int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
- struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
- if (!dev || pci_write_config_dword(dev, addr, val))
- return AE_ERROR;
- return AE_OK;
-}
-
-/*
- * Queue for interpreter thread
- */
-
-ACPI_STATUS
-acpi_os_queue_for_execution(
- u32 priority,
- OSD_EXECUTION_CALLBACK callback,
- void *context)
-{
- struct acpi_intrp_entry *entry;
- unsigned long flags;
-
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry)
- return AE_ERROR;
-
- memset(entry, 0, sizeof(entry));
- entry->priority = priority;
- entry->callback = callback;
- entry->context = context;
- INIT_LIST_HEAD(&entry->list);
-
- if (!waitqueue_active(&acpi_intrp_wait)) {
- kfree(entry);
- return AE_ERROR;
- }
-
- spin_lock_irqsave(&acpi_intrp_exec_lock, flags);
- list_add(&entry->list, &acpi_intrp_exec);
- wake_up(&acpi_intrp_wait);
- spin_unlock_irqrestore(&acpi_intrp_exec_lock, flags);
-
- return AE_OK;
-}
-
-/*
- * Semaphores are unused, interpreter access is single threaded
- */
-
-ACPI_STATUS
-acpi_os_create_semaphore(u32 max_units, u32 init, ACPI_HANDLE * handle)
-{
- *handle = (ACPI_HANDLE) 0;
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_delete_semaphore(ACPI_HANDLE handle)
-{
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_wait_semaphore(ACPI_HANDLE handle, u32 units, u32 timeout)
-{
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_signal_semaphore(ACPI_HANDLE handle, u32 units)
-{
- return AE_OK;
-}
-
-ACPI_STATUS
-acpi_os_breakpoint(char *msg)
-{
- acpi_os_printf("breakpoint: %s", msg);
- return AE_OK;
-}
-
-void
-acpi_os_dbg_trap(char *msg)
-{
- acpi_os_printf("trap: %s", msg);
-}
-
-void
-acpi_os_dbg_assert(void *failure, void *file, u32 line, char *msg)
-{
- acpi_os_printf("assert: %s", msg);
-}
-
-u32
-acpi_os_get_line(char *buffer)
-{
- return 0;
-}
-
-/*
- * We just have to assume we're dealing with valid memory
- */
-
-BOOLEAN
-acpi_os_readable(void *ptr, u32 len)
-{
- return 1;
-}
-
-BOOLEAN
-acpi_os_writable(void *ptr, u32 len)
-{
- return 1;
-}
diff --git a/drivers/acpi/sys.c b/drivers/acpi/sys.c
new file mode 100644
index 000000000..1a403f86f
--- /dev/null
+++ b/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;
+}
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
new file mode 100644
index 000000000..9ec6c58f4
--- /dev/null
+++ b/drivers/acpi/tables.c
@@ -0,0 +1,303 @@
+/*
+ * tables.c - ACPI tables, chipset, and errata handling
+ *
+ * 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/types.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
+#include "acpi.h"
+#include "driver.h"
+
+struct acpi_facp acpi_facp;
+
+#define ACPI_DUMMY_CHECKSUM 9
+#define ACPI_DUMMY_PBLK 51
+
+static u8 acpi_dummy_dsdt[] =
+{
+ 0x44, 0x53, 0x44, 0x54, // "DSDT"
+ 0x38, 0x00, 0x00, 0x00, // length
+ 0x01, // revision
+ 0x00, // checksum
+ 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x00, // "LINUX"
+ 0x44, 0x55, 0x4d, 0x4d, 0x59, 0x00, 0x00, 0x00, // "DUMMY"
+ 0x01, 0x00, 0x00, 0x00, // OEM rev
+ 0x4c, 0x4e, 0x55, 0x58, // "LNUX"
+ 0x01, 0x00, 0x00, 0x00, // creator rev
+ 0x10, // Scope
+ 0x13, // PkgLength
+ 0x5c, 0x5f, 0x50, 0x52, 0x5f, // \_PR_
+ 0x5b, 0x83, // Processor
+ 0x0b, // PkgLength
+ 0x43, 0x50, 0x55, 0x30, // CPU0
+ 0x00, // ID
+ 0x00, 0x00, 0x00, 0x00, // PBLK
+ 0x06 // PBLK size
+};
+
+/*
+ * Calculate and set ACPI table checksum
+ */
+static void
+acpi_set_checksum(u8 *table, int size)
+{
+ int i, sum = 0;
+ for (i = 0; i < size; i++)
+ sum += (int) table[i];
+ sum = (0x100 - ((sum - table[ACPI_DUMMY_CHECKSUM]) & 0xff));
+ table[ACPI_DUMMY_CHECKSUM] = sum;
+}
+
+/*
+ * Init PIIX4 device, create a fake FACP
+ */
+static int
+acpi_init_piix4(struct pci_dev *dev)
+{
+ u32 base, pblk;
+ u16 cmd;
+ u8 pmregmisc;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (!(cmd & PCI_COMMAND_IO))
+ return -ENODEV;
+
+ pci_read_config_byte(dev, ACPI_PIIX4_PMREGMISC, &pmregmisc);
+ if (!(pmregmisc & ACPI_PIIX4_PMIOSE))
+ return -ENODEV;
+
+ base = pci_resource_start (dev, PCI_BRIDGE_RESOURCES);
+ if (!base)
+ return -ENODEV;
+
+ printk(KERN_INFO "ACPI: found \"%s\" at 0x%04x\n", dev->name, base);
+
+ memset(&acpi_facp, 0, sizeof(acpi_facp));
+ acpi_facp.hdr.signature = ACPI_FACP_SIG;
+ acpi_facp.hdr.length = sizeof(acpi_facp);
+ acpi_facp.int_model = ACPI_PIIX4_INT_MODEL;
+ acpi_facp.sci_int = ACPI_PIIX4_SCI_INT;
+ acpi_facp.smi_cmd = ACPI_PIIX4_SMI_CMD;
+ acpi_facp.acpi_enable = ACPI_PIIX4_ACPI_ENABLE;
+ acpi_facp.acpi_disable = ACPI_PIIX4_ACPI_DISABLE;
+ acpi_facp.s4bios_req = ACPI_PIIX4_S4BIOS_REQ;
+ acpi_facp.pm1a_evt = base + ACPI_PIIX4_PM1_EVT;
+ acpi_facp.pm1a_cnt = base + ACPI_PIIX4_PM1_CNT;
+ acpi_facp.pm2_cnt = ACPI_PIIX4_PM2_CNT;
+ acpi_facp.pm_tmr = base + ACPI_PIIX4_PM_TMR;
+ acpi_facp.gpe0 = base + ACPI_PIIX4_GPE0;
+ acpi_facp.pm1_evt_len = ACPI_PIIX4_PM1_EVT_LEN;
+ acpi_facp.pm1_cnt_len = ACPI_PIIX4_PM1_CNT_LEN;
+ acpi_facp.pm2_cnt_len = ACPI_PIIX4_PM2_CNT_LEN;
+ acpi_facp.pm_tm_len = ACPI_PIIX4_PM_TM_LEN;
+ acpi_facp.gpe0_len = ACPI_PIIX4_GPE0_LEN;
+ acpi_facp.p_lvl2_lat = (__u16) ACPI_INFINITE_LAT;
+ acpi_facp.p_lvl3_lat = (__u16) ACPI_INFINITE_LAT;
+
+ acpi_set_checksum((u8*) &acpi_facp, sizeof(acpi_facp));
+ acpi_load_table((ACPI_TABLE_HEADER*) &acpi_facp);
+
+ pblk = base + ACPI_PIIX4_P_BLK;
+ memcpy(acpi_dummy_dsdt + ACPI_DUMMY_PBLK, &pblk, sizeof(pblk));
+ acpi_set_checksum(acpi_dummy_dsdt, sizeof(acpi_dummy_dsdt));
+ acpi_load_table((ACPI_TABLE_HEADER*) acpi_dummy_dsdt);
+
+ return 0;
+}
+
+/*
+ * Init VIA ACPI device and create a fake FACP
+ */
+static int
+acpi_init_via(struct pci_dev *dev)
+{
+ u32 base, pblk;
+ u8 tmp, irq;
+
+ pci_read_config_byte(dev, 0x41, &tmp);
+ if (!(tmp & 0x80))
+ return -ENODEV;
+
+ base = pci_resource_start(dev, PCI_BRIDGE_RESOURCES);
+ if (!base) {
+ base = pci_resource_start(dev, PCI_BASE_ADDRESS_4);
+ if (!base)
+ return -ENODEV;
+ }
+
+ pci_read_config_byte(dev, 0x42, &irq);
+
+ printk(KERN_INFO "ACPI: found \"%s\" at 0x%04x\n", dev->name, base);
+
+ memset(&acpi_facp, 0, sizeof(acpi_facp));
+ acpi_facp.hdr.signature = ACPI_FACP_SIG;
+ acpi_facp.hdr.length = sizeof(acpi_facp);
+ acpi_facp.int_model = ACPI_VIA_INT_MODEL;
+ acpi_facp.sci_int = irq;
+ acpi_facp.smi_cmd = base + ACPI_VIA_SMI_CMD;
+ acpi_facp.acpi_enable = ACPI_VIA_ACPI_ENABLE;
+ acpi_facp.acpi_disable = ACPI_VIA_ACPI_DISABLE;
+ acpi_facp.pm1a_evt = base + ACPI_VIA_PM1_EVT;
+ acpi_facp.pm1a_cnt = base + ACPI_VIA_PM1_CNT;
+ acpi_facp.pm_tmr = base + ACPI_VIA_PM_TMR;
+ acpi_facp.gpe0 = base + ACPI_VIA_GPE0;
+
+ acpi_facp.pm1_evt_len = ACPI_VIA_PM1_EVT_LEN;
+ acpi_facp.pm1_cnt_len = ACPI_VIA_PM1_CNT_LEN;
+ acpi_facp.pm_tm_len = ACPI_VIA_PM_TM_LEN;
+ acpi_facp.gpe0_len = ACPI_VIA_GPE0_LEN;
+ acpi_facp.p_lvl2_lat = (__u16) ACPI_INFINITE_LAT;
+ acpi_facp.p_lvl3_lat = (__u16) ACPI_INFINITE_LAT;
+
+ acpi_facp.duty_offset = ACPI_VIA_DUTY_OFFSET;
+ acpi_facp.duty_width = ACPI_VIA_DUTY_WIDTH;
+
+ acpi_facp.day_alarm = ACPI_VIA_DAY_ALARM;
+ acpi_facp.mon_alarm = ACPI_VIA_MON_ALARM;
+ acpi_facp.century = ACPI_VIA_CENTURY;
+
+ acpi_set_checksum((u8*) &acpi_facp, sizeof(acpi_facp));
+ acpi_load_table((ACPI_TABLE_HEADER*) &acpi_facp);
+
+ pblk = base + ACPI_VIA_P_BLK;
+ memcpy(acpi_dummy_dsdt + ACPI_DUMMY_PBLK, &pblk, sizeof(pblk));
+ acpi_set_checksum(acpi_dummy_dsdt, sizeof(acpi_dummy_dsdt));
+ acpi_load_table((ACPI_TABLE_HEADER*) acpi_dummy_dsdt);
+
+ return 0;
+}
+
+typedef enum
+{
+ CH_UNKNOWN = 0,
+ CH_INTEL_PIIX4,
+ CH_VIA_586,
+ CH_VIA_686A,
+} acpi_chip_t;
+
+/* indexed by value of each enum in acpi_chip_t */
+const static struct
+{
+ int (*chip_init)(struct pci_dev *dev);
+} acpi_chip_info[] =
+{
+ {NULL,},
+ {acpi_init_piix4},
+ {acpi_init_via},
+ {acpi_init_via},
+};
+
+static struct pci_device_id acpi_pci_tbl[] =
+{
+ {0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4},
+ {0x1106, 0x3040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_586},
+ {0x1106, 0x3057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_686A},
+ {0,} /* terminate list */
+};
+
+static int
+acpi_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return acpi_chip_info[id->driver_data].chip_init(dev);
+}
+
+static struct pci_driver acpi_driver =
+{
+ name: "acpi",
+ id_table: acpi_pci_tbl,
+ probe: acpi_probe,
+};
+static int acpi_driver_registered = 0;
+
+/*
+ * Locate a known ACPI chipset
+ */
+static int
+acpi_find_chipset(void)
+{
+ if (pci_register_driver(&acpi_driver) < 1)
+ return -ENODEV;
+ acpi_driver_registered = 1;
+ return 0;
+}
+
+/*
+ * Fetch the FACP information
+ */
+static int
+acpi_fetch_facp(void)
+{
+ ACPI_BUFFER buffer;
+
+ memset(&acpi_facp, 0, sizeof(acpi_facp));
+ buffer.pointer = &acpi_facp;
+ buffer.length = sizeof(acpi_facp);
+ if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FACP, 1, &buffer))) {
+ printk(KERN_ERR "ACPI: missing FACP\n");
+ return -ENODEV;
+ }
+
+ if (acpi_facp.p_lvl2_lat
+ && acpi_facp.p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
+ acpi_c2_exit_latency
+ = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl2_lat);
+ acpi_c2_enter_latency
+ = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000);
+ }
+ if (acpi_facp.p_lvl3_lat
+ && acpi_facp.p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
+ acpi_c3_exit_latency
+ = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl3_lat);
+ acpi_c3_enter_latency
+ = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl3_lat * 5);
+ }
+
+ return 0;
+}
+
+/*
+ * Find and load ACPI tables
+ */
+int
+acpi_load_tables(void)
+{
+ if (ACPI_SUCCESS(acpi_load_firmware_tables()))
+ {
+ printk(KERN_INFO "ACPI: support found\n");
+ }
+ else if (acpi_find_chipset()) {
+ acpi_terminate();
+ return -1;
+ }
+
+ if (acpi_fetch_facp()) {
+ acpi_terminate();
+ return -1;
+ }
+
+ if (!ACPI_SUCCESS(acpi_load_namespace())) {
+ printk(KERN_ERR "ACPI: namespace load failed\n");
+ acpi_terminate();
+ return -1;
+ }
+
+ return 0;
+}