summaryrefslogtreecommitdiffstats
path: root/drivers/misc/acpi.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-05 06:47:02 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-05 06:47:02 +0000
commit99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch)
tree3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /drivers/misc/acpi.c
parente73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff)
Merge with Linux 2.3.38.
Diffstat (limited to 'drivers/misc/acpi.c')
-rw-r--r--drivers/misc/acpi.c1253
1 files changed, 0 insertions, 1253 deletions
diff --git a/drivers/misc/acpi.c b/drivers/misc/acpi.c
deleted file mode 100644
index ffb05161a..000000000
--- a/drivers/misc/acpi.c
+++ /dev/null
@@ -1,1253 +0,0 @@
-/*
- * acpi.c - Linux ACPI driver
- *
- * Copyright (C) 1999 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
- */
-
-/*
- * See http://www.geocities.com/SiliconValley/Hardware/3165/
- * for the user-level ACPI stuff
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/miscdevice.h>
-#include <linux/sched.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <linux/sysctl.h>
-#include <linux/delay.h>
-#include <linux/acpi.h>
-
-/*
- * Defines for 2.2.x
- */
-#ifndef __exit
-#define __exit
-#endif
-#ifndef module_init
-#define module_init(x) int init_module(void) {return x();}
-#endif
-#ifndef module_exit
-#define module_exit(x) void cleanup_module(void) {x();}
-#endif
-#ifndef DECLARE_WAIT_QUEUE_HEAD
-#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue * x = NULL
-#endif
-
-/*
- * Yes, it's unfortunate that we are relying on get_cmos_time
- * because it is slow (> 1 sec.) and i386 only. It might be better
- * to use some of the code from drivers/char/rtc.c in the near future
- */
-extern unsigned long get_cmos_time(void);
-
-static int acpi_control_thread(void *context);
-static int acpi_do_ulong(ctl_table *ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t *len);
-static int acpi_do_event_reg(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 int acpi_do_sleep(ctl_table *ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t *len);
-
-DECLARE_WAIT_QUEUE_HEAD(acpi_control_wait);
-
-static struct ctl_table_header *acpi_sysctl = NULL;
-
-static struct acpi_facp *acpi_facp = NULL;
-static int acpi_fake_facp = 0;
-static struct acpi_facs *acpi_facs = NULL;
-static unsigned long acpi_facp_addr = 0;
-static unsigned long acpi_dsdt_addr = 0;
-
-// current system sleep state (S0 - S4)
-static acpi_sstate_t acpi_sleep_state = ACPI_S0;
-// time sleep began
-static unsigned long acpi_sleep_start = 0;
-
-static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED;
-static volatile u32 acpi_pm1_status = 0;
-static volatile u32 acpi_gpe_status = 0;
-static volatile u32 acpi_gpe_level = 0;
-static volatile acpi_sstate_t acpi_event_state = ACPI_S0;
-static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait);
-
-static spinlock_t acpi_devs_lock = SPIN_LOCK_UNLOCKED;
-static LIST_HEAD(acpi_devs);
-
-/* Make it impossible to enter C2/C3 until after we've initialized */
-static unsigned long acpi_p_lvl2_lat = ACPI_INFINITE_LAT;
-static unsigned long acpi_p_lvl3_lat = ACPI_INFINITE_LAT;
-
-static unsigned long acpi_p_blk = 0;
-
-static int acpi_p_lvl2_tested = 0;
-static int acpi_p_lvl3_tested = 0;
-
-// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
-static unsigned long acpi_slp_typ[] =
-{
- ACPI_SLP_TYP_DISABLED, /* S0 */
- ACPI_SLP_TYP_DISABLED, /* S1 */
- ACPI_SLP_TYP_DISABLED, /* S2 */
- ACPI_SLP_TYP_DISABLED, /* S3 */
- ACPI_SLP_TYP_DISABLED, /* S4 */
- ACPI_SLP_TYP_DISABLED /* S5 */
-};
-
-static struct ctl_table acpi_table[] =
-{
- {ACPI_FACP, "facp",
- &acpi_facp_addr, sizeof(acpi_facp_addr),
- 0400, NULL, &acpi_do_ulong},
-
- {ACPI_DSDT, "dsdt",
- &acpi_dsdt_addr, sizeof(acpi_dsdt_addr),
- 0400, NULL, &acpi_do_ulong},
-
- {ACPI_PM1_ENABLE, "pm1_enable",
- NULL, 0,
- 0600, NULL, &acpi_do_event_reg},
-
- {ACPI_GPE_ENABLE, "gpe_enable",
- NULL, 0,
- 0600, NULL, &acpi_do_event_reg},
-
- {ACPI_GPE_LEVEL, "gpe_level",
- NULL, 0,
- 0600, NULL, &acpi_do_event_reg},
-
- {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event},
-
- {ACPI_P_BLK, "p_blk",
- &acpi_p_blk, sizeof(acpi_p_blk),
- 0600, NULL, &acpi_do_ulong},
-
- {ACPI_P_LVL2_LAT, "p_lvl2_lat",
- &acpi_p_lvl2_lat, sizeof(acpi_p_lvl2_lat),
- 0644, NULL, &acpi_do_ulong},
-
- {ACPI_P_LVL3_LAT, "p_lvl3_lat",
- &acpi_p_lvl3_lat, sizeof(acpi_p_lvl3_lat),
- 0644, NULL, &acpi_do_ulong},
-
- {ACPI_S0_SLP_TYP, "s0_slp_typ",
- &acpi_slp_typ[ACPI_S0], sizeof(acpi_slp_typ[ACPI_S0]),
- 0600, NULL, &acpi_do_ulong},
-
- {ACPI_S1_SLP_TYP, "s1_slp_typ",
- &acpi_slp_typ[ACPI_S1], sizeof(acpi_slp_typ[ACPI_S1]),
- 0600, NULL, &acpi_do_ulong},
-
- {ACPI_S5_SLP_TYP, "s5_slp_typ",
- &acpi_slp_typ[ACPI_S5], sizeof(acpi_slp_typ[ACPI_S5]),
- 0600, NULL, &acpi_do_ulong},
-
- {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},
-
- {0}
-};
-
-static struct ctl_table acpi_dir_table[] =
-{
- {CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table},
- {0}
-};
-
-
-/*
- * Get the value of the PM1 control register (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 (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);
-}
-
-/*
- * Get the value of the fixed event enable register
- */
-static u32 acpi_read_pm1_enable(struct acpi_facp *facp)
-{
- int offset = facp->pm1_evt_len >> 1;
- u32 value = 0;
- if (facp->pm1a_evt)
- value = inw(facp->pm1a_evt + offset);
- if (facp->pm1b_evt)
- value |= inw(facp->pm1b_evt + offset);
- return value;
-}
-
-/*
- * Set the value of the fixed event enable register (enable events)
- */
-static void acpi_write_pm1_enable(struct acpi_facp *facp, u32 value)
-{
- int offset = facp->pm1_evt_len >> 1;
- if (facp->pm1a_evt)
- outw(value, facp->pm1a_evt + offset);
- if (facp->pm1b_evt)
- outw(value, facp->pm1b_evt + offset);
-}
-
-/*
- * Get the value of the general-purpose event status register
- */
-static u32 acpi_read_gpe_status(struct acpi_facp *facp)
-{
- u32 value = 0;
- int i, size;
-
- if (facp->gpe1) {
- size = facp->gpe1_len >> 1;
- for (i = size - 1; i >= 0; i--)
- value = (value << 8) | inb(facp->gpe1 + i);
- }
- if (facp->gpe0) {
- size = facp->gpe0_len >> 1;
- for (i = size - 1; i >= 0; i--)
- value = (value << 8) | inb(facp->gpe0 + i);
- }
- return value;
-}
-
-/*
- * Set the value of the general-purpose event status register (clear events)
- */
-static void acpi_write_gpe_status(struct acpi_facp *facp, u32 value)
-{
- int i, size;
-
- if (facp->gpe0) {
- size = facp->gpe0_len >> 1;
- for (i = 0; i < size; i++) {
- outb(value & 0xff, facp->gpe0 + i);
- value >>= 8;
- }
- }
- if (facp->gpe1) {
- size = facp->gpe1_len >> 1;
- for (i = 0; i < size; i++) {
- outb(value & 0xff, facp->gpe1 + i);
- value >>= 8;
- }
- }
-}
-
-/*
- * Get the value of the general-purpose event enable register
- */
-static u32 acpi_read_gpe_enable(struct acpi_facp *facp)
-{
- u32 value = 0;
- int i, size, offset;
-
- offset = facp->gpe0_len >> 1;
- if (facp->gpe1) {
- size = facp->gpe1_len >> 1;
- for (i = size - 1; i >= 0; i--) {
- value = (value << 8) | inb(facp->gpe1 + offset + i);
- }
- }
- if (facp->gpe0) {
- size = facp->gpe0_len >> 1;
- for (i = size - 1; i >= 0; i--)
- value = (value << 8) | inb(facp->gpe0 + offset + i);
- }
- return value;
-}
-
-/*
- * Set the value of the general-purpose event enable register (enable events)
- */
-static void acpi_write_gpe_enable(struct acpi_facp *facp, u32 value)
-{
- int i, offset;
-
- offset = facp->gpe0_len >> 1;
- if (facp->gpe0) {
- for (i = 0; i < offset; i++) {
- outb(value & 0xff, facp->gpe0 + offset + i);
- value >>= 8;
- }
- }
- if (facp->gpe1) {
- offset = facp->gpe1_len >> 1;
- for (i = 0; i < offset; i++) {
- outb(value & 0xff, facp->gpe1 + offset + i);
- value >>= 8;
- }
- }
-}
-
-/*
- * Map an ACPI table into virtual memory
- */
-static struct acpi_table *__init acpi_map_table(u32 addr)
-{
- struct acpi_table *table = NULL;
- if (addr) {
- // map table header to determine size
- table = (struct acpi_table *)
- ioremap((unsigned long) addr,
- sizeof(struct acpi_table));
- if (table) {
- unsigned long table_size = table->length;
- iounmap(table);
- // remap entire table
- table = (struct acpi_table *)
- ioremap((unsigned long) addr, table_size);
- }
-
- if (!table) {
- /* ioremap is a pain, it returns NULL if the
- * table starts within mapped physical memory.
- * Hopefully, no table straddles a mapped/unmapped
- * physical memory boundary, ugh
- */
- table = (struct acpi_table*) phys_to_virt(addr);
- }
- }
- return table;
-}
-
-/*
- * Unmap an ACPI table from virtual memory
- */
-static void acpi_unmap_table(struct acpi_table *table)
-{
- // iounmap ignores addresses within physical memory
- if (table)
- iounmap(table);
-}
-
-/*
- * Locate and map ACPI tables
- */
-static int __init acpi_find_tables(void)
-{
- struct acpi_rsdp *rsdp;
- struct acpi_table *rsdt;
- u32 *rsdt_entry;
- int rsdt_entry_count;
- unsigned long i;
-
- // search BIOS memory for RSDP
- for (i = ACPI_BIOS_ROM_BASE; i < ACPI_BIOS_ROM_END; i += 16) {
- rsdp = (struct acpi_rsdp *) phys_to_virt(i);
- if (rsdp->signature[0] == ACPI_RSDP1_SIG
- && rsdp->signature[1] == ACPI_RSDP2_SIG) {
- char oem[7];
- int j;
-
- // strip trailing space and print OEM identifier
- memcpy(oem, rsdp->oem, 6);
- oem[6] = '\0';
- for (j = 5;
- j > 0 && (oem[j] == '\0' || oem[j] == ' ');
- j--) {
- oem[j] = '\0';
- }
- printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n",
- oem, (void *) i);
-
- break;
- }
- }
- if (i >= ACPI_BIOS_ROM_END)
- return -ENODEV;
-
- // fetch RSDT from RSDP
- rsdt = acpi_map_table(rsdp->rsdt);
- if (!rsdt) {
- printk(KERN_ERR "ACPI: missing RSDT at 0x%p\n",
- (void*) rsdp->rsdt);
- return -ENODEV;
- }
- else if (rsdt->signature != ACPI_RSDT_SIG) {
- printk(KERN_ERR "ACPI: bad RSDT at 0x%p (%08x)\n",
- (void*) rsdp->rsdt, (unsigned) rsdt->signature);
- acpi_unmap_table(rsdt);
- return -ENODEV;
- }
- // search RSDT for FACP
- acpi_facp = NULL;
- rsdt_entry = (u32 *) (rsdt + 1);
- rsdt_entry_count = (int) ((rsdt->length - sizeof(*rsdt)) >> 2);
- while (rsdt_entry_count) {
- struct acpi_table *dt = acpi_map_table(*rsdt_entry);
- if (dt && dt->signature == ACPI_FACP_SIG) {
- acpi_facp = (struct acpi_facp*) dt;
- acpi_facp_addr = *rsdt_entry;
- acpi_dsdt_addr = acpi_facp->dsdt;
-
- // map FACS if it exists
- if (acpi_facp->facs) {
- dt = acpi_map_table(acpi_facp->facs);
- if (dt && dt->signature == ACPI_FACS_SIG) {
- acpi_facs = (struct acpi_facs*) dt;
- }
- else {
- acpi_unmap_table(dt);
- }
- }
- }
- else {
- acpi_unmap_table(dt);
- }
- rsdt_entry++;
- rsdt_entry_count--;
- }
-
- acpi_unmap_table(rsdt);
-
- if (!acpi_facp) {
- printk(KERN_ERR "ACPI: missing FACP\n");
- return -ENODEV;
- }
- return 0;
-}
-
-/*
- * Unmap or destroy ACPI tables
- */
-static void acpi_destroy_tables(void)
-{
- if (!acpi_fake_facp)
- acpi_unmap_table((struct acpi_table*) acpi_facp);
- else
- kfree(acpi_facp);
- acpi_unmap_table((struct acpi_table*) acpi_facs);
-}
-
-/*
- * Locate PIIX4 device and create a fake FACP
- */
-static int __init acpi_find_piix4(void)
-{
- struct pci_dev *dev;
- u32 base;
- u16 cmd;
- u8 pmregmisc;
-
- dev = pci_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_3,
- NULL);
- if (!dev)
- return -ENODEV;
-
- 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;
-
- pci_read_config_dword(dev, 0x40, &base);
- if (!(base & PCI_BASE_ADDRESS_SPACE_IO))
- return -ENODEV;
-
- base &= PCI_BASE_ADDRESS_IO_MASK;
- if (!base)
- return -ENODEV;
-
- printk(KERN_INFO "ACPI: found PIIX4 at 0x%04x\n", base);
-
- acpi_facp = kmalloc(sizeof(struct acpi_facp), GFP_KERNEL);
- if (!acpi_facp)
- return -ENOMEM;
-
- acpi_fake_facp = 1;
- memset(acpi_facp, 0, sizeof(struct 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_facp_addr = virt_to_phys(acpi_facp);
- acpi_dsdt_addr = 0;
-
- acpi_p_blk = base + ACPI_PIIX4_P_BLK;
-
- return 0;
-}
-
-/*
- * Handle an ACPI SCI (fixed or general purpose event)
- */
-static void acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- u32 pm1_status, gpe_status, gpe_level, gpe_edge;
- unsigned long flags;
-
- // detect and clear fixed events
- pm1_status = (acpi_read_pm1_status(acpi_facp)
- & acpi_read_pm1_enable(acpi_facp));
- acpi_write_pm1_status(acpi_facp, pm1_status);
-
- // detect and handle general-purpose events
- gpe_status = (acpi_read_gpe_status(acpi_facp)
- & acpi_read_gpe_enable(acpi_facp));
- gpe_level = gpe_status & acpi_gpe_level;
- if (gpe_level) {
- // disable level-triggered events (re-enabled after handling)
- acpi_write_gpe_enable(
- acpi_facp,
- acpi_read_gpe_enable(acpi_facp) & ~gpe_level);
- }
- gpe_edge = gpe_status & ~gpe_level;
- if (gpe_edge) {
- // clear edge-triggered events
- while (acpi_read_gpe_status(acpi_facp) & gpe_edge)
- acpi_write_gpe_status(acpi_facp, gpe_edge);
- }
-
- // notify process waiting on /dev/acpi
- spin_lock_irqsave(&acpi_event_lock, flags);
- acpi_pm1_status |= pm1_status;
- acpi_gpe_status |= gpe_status;
- spin_unlock_irqrestore(&acpi_event_lock, flags);
- acpi_event_state = acpi_sleep_state;
- wake_up_interruptible(&acpi_event_wait);
-}
-
-/*
- * Is ACPI enabled or not?
- */
-static inline int acpi_is_enabled(struct acpi_facp *facp)
-{
- return ((acpi_read_pm1_control(facp) & ACPI_SCI_EN) ? 1:0);
-}
-
-/*
- * Enable SCI
- */
-static int acpi_enable(struct acpi_facp *facp)
-{
- if (facp->smi_cmd)
- outb(facp->acpi_enable, facp->smi_cmd);
- return (acpi_is_enabled(facp) ? 0:-1);
-}
-
-/*
- * Disable SCI
- */
-static int acpi_disable(struct acpi_facp *facp)
-{
- // disable and clear any pending events
- acpi_write_gpe_enable(facp, 0);
- while (acpi_read_gpe_status(facp))
- acpi_write_gpe_status(facp, acpi_read_gpe_status(facp));
- acpi_write_pm1_enable(facp, 0);
- acpi_write_pm1_status(facp, acpi_read_pm1_status(facp));
-
- /* writing acpi_disable to smi_cmd would be appropriate
- * here but this causes a nasty crash on many systems
- */
-
- return 0;
-}
-
-/*
- * Idle loop (uniprocessor only)
- */
-static void acpi_idle_handler(void)
-{
- static int sleep_level = 1;
- u32 pm1_cnt, timer, pm2_cnt, bm_active;
- unsigned long time, usec;
-
- // return to C0 on bus master request (necessary for C3 only)
- pm1_cnt = acpi_read_pm1_control(acpi_facp);
- if (sleep_level == 3) {
- if (!(pm1_cnt & ACPI_BM_RLD)) {
- pm1_cnt |= ACPI_BM_RLD;
- acpi_write_pm1_control(acpi_facp, pm1_cnt);
- }
- }
- else {
- if (pm1_cnt & ACPI_BM_RLD) {
- pm1_cnt &= ~ACPI_BM_RLD;
- acpi_write_pm1_control(acpi_facp, pm1_cnt);
- }
- }
-
- // clear bus master activity flag
- acpi_write_pm1_status(acpi_facp, ACPI_BM);
-
- // get current time (fallback to CPU cycles if no PM timer)
- timer = acpi_facp->pm_tmr;
- if (timer)
- time = inl(timer);
- else
- time = get_cycles();
-
- // sleep
- switch (sleep_level) {
- case 1:
- __asm__ __volatile__("sti ; hlt": : :"memory");
- break;
- case 2:
- inb(acpi_p_blk + ACPI_P_LVL2);
- break;
- case 3:
- pm2_cnt = acpi_facp->pm2_cnt;
- if (pm2_cnt) {
- /* Disable PCI arbitration while sleeping,
- to avoid DMA corruption? */
- outb(inb(pm2_cnt) | ACPI_ARB_DIS, pm2_cnt);
- inb(acpi_p_blk + ACPI_P_LVL3);
- outb(inb(pm2_cnt) & ~ACPI_ARB_DIS, pm2_cnt);
- }
- else {
- inb(acpi_p_blk + ACPI_P_LVL3);
- }
- break;
- }
-
- // calculate time spent sleeping (fallback to CPU cycles)
- if (timer)
- time = (inl(timer) - time) & ACPI_TMR_MASK;
- else
- time = ACPI_CPU_TO_TMR_TICKS(get_cycles() - time);
-
- // check for bus master activity
- bm_active = (acpi_read_pm1_status(acpi_facp) & ACPI_BM);
-
- // record working C2/C3
- if (sleep_level == 2 && !acpi_p_lvl2_tested) {
- acpi_p_lvl2_tested = 1;
- printk(KERN_INFO "ACPI: C2 works\n");
- }
- else if (sleep_level == 3 && !acpi_p_lvl3_tested) {
- acpi_p_lvl3_tested = 1;
- printk(KERN_INFO "ACPI: C3 works\n");
- }
-
- // pick next C-state based on time spent sleeping,
- // C-state latencies, and bus master activity
- sleep_level = 1;
- if (acpi_p_blk) {
- usec = ACPI_TMR_TICKS_TO_uS(time);
- if (usec > acpi_p_lvl3_lat && !bm_active)
- sleep_level = 3;
- else if (usec > acpi_p_lvl2_lat)
- sleep_level = 2;
- }
-}
-
-/*
- * Put all devices into specified D-state
- */
-static int acpi_enter_dx(acpi_dstate_t state)
-{
- int status = 0;
- struct list_head *i = acpi_devs.next;
-
- while (i != &acpi_devs) {
- struct acpi_dev *dev = list_entry(i, struct acpi_dev, entry);
- if (dev->state != state) {
- int dev_status = 0;
- if (dev->info.transition)
- dev_status = dev->info.transition(dev, state);
- if (!dev_status) {
- // put hardware into D-state
- dev->state = state;
- }
- if (dev_status)
- status = dev_status;
- }
-
- i = i->next;
- }
-
- return status;
-}
-
-/*
- * Update system time from real-time clock
- */
-static void acpi_update_clock(void)
-{
- if (acpi_sleep_start) {
- unsigned long delta;
- struct timeval tv;
-
- delta = get_cmos_time() - acpi_sleep_start;
- do_gettimeofday(&tv);
- tv.tv_sec += delta;
- do_settimeofday(&tv);
-
- acpi_sleep_start = 0;
- }
-}
-
-
-/*
- * Enter system sleep state
- */
-static void acpi_enter_sx(acpi_sstate_t state)
-{
- unsigned long slp_typ = acpi_slp_typ[(int) state];
- if (slp_typ != ACPI_SLP_TYP_DISABLED) {
- u16 typa, typb, value;
-
- // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
- typa = (slp_typ >> 8) & 0xff;
- typb = slp_typ & 0xff;
-
- typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
- typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
-
- if (state != ACPI_S0) {
- acpi_sleep_start = get_cmos_time();
- acpi_enter_dx(ACPI_D3);
- acpi_sleep_state = state;
- }
-
- // clear wake status
- acpi_write_pm1_status(acpi_facp, ACPI_WAK);
-
- // set SLP_TYPa/b and SLP_EN
- if (acpi_facp->pm1a_cnt) {
- value = inw(acpi_facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
- outw(value | typa | ACPI_SLP_EN, acpi_facp->pm1a_cnt);
- }
- if (acpi_facp->pm1b_cnt) {
- value = inw(acpi_facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
- outw(value | typb | ACPI_SLP_EN, acpi_facp->pm1b_cnt);
- }
-
- if (state == ACPI_S0) {
- acpi_sleep_state = state;
- acpi_enter_dx(ACPI_D0);
- acpi_sleep_start = 0;
- }
- else if (state == ACPI_S1) {
- // wait until S1 is entered
- while (!(acpi_read_pm1_status(acpi_facp) & ACPI_WAK)) ;
- // finished sleeping, update system time
- acpi_update_clock();
- }
- }
-}
-
-/*
- * Enter soft-off (S5)
- */
-static void acpi_power_off_handler(void)
-{
- acpi_enter_sx(ACPI_S5);
-}
-
-/*
- * Claim ACPI I/O ports
- */
-static int acpi_claim_ioports(struct acpi_facp *facp)
-{
- // we don't get a guarantee of contiguity for any of the ACPI registers
- if (facp->pm1a_evt)
- request_region(facp->pm1a_evt, facp->pm1_evt_len, "acpi");
- if (facp->pm1b_evt)
- request_region(facp->pm1b_evt, facp->pm1_evt_len, "acpi");
- if (facp->pm1a_cnt)
- request_region(facp->pm1a_cnt, facp->pm1_cnt_len, "acpi");
- if (facp->pm1b_cnt)
- request_region(facp->pm1b_cnt, facp->pm1_cnt_len, "acpi");
- if (facp->pm_tmr)
- request_region(facp->pm_tmr, facp->pm_tm_len, "acpi");
- if (facp->gpe0)
- request_region(facp->gpe0, facp->gpe0_len, "acpi");
- if (facp->gpe1)
- request_region(facp->gpe1, facp->gpe1_len, "acpi");
-
- return 0;
-}
-
-/*
- * Free ACPI I/O ports
- */
-static int acpi_release_ioports(struct acpi_facp *facp)
-{
- // we don't get a guarantee of contiguity for any of the ACPI registers
- if (facp->pm1a_evt)
- release_region(facp->pm1a_evt, facp->pm1_evt_len);
- if (facp->pm1b_evt)
- release_region(facp->pm1b_evt, facp->pm1_evt_len);
- if (facp->pm1a_cnt)
- release_region(facp->pm1a_cnt, facp->pm1_cnt_len);
- if (facp->pm1b_cnt)
- release_region(facp->pm1b_cnt, facp->pm1_cnt_len);
- if (facp->pm_tmr)
- release_region(facp->pm_tmr, facp->pm_tm_len);
- if (facp->gpe0)
- release_region(facp->gpe0, facp->gpe0_len);
- if (facp->gpe1)
- release_region(facp->gpe1, facp->gpe1_len);
-
- return 0;
-}
-
-/*
- * 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;
-}
-
-/*
- * Examine/modify event register
- */
-static int acpi_do_event_reg(ctl_table *ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t *len)
-{
- char str[2 * sizeof(u32) + 4], *strend;
- u32 val, enabling;
- int size;
-
- if (!write) {
- if (file->f_pos) {
- *len = 0;
- return 0;
- }
-
- val = 0;
- switch (ctl->ctl_name) {
- case ACPI_PM1_ENABLE:
- val = acpi_read_pm1_enable(acpi_facp);
- break;
- case ACPI_GPE_ENABLE:
- val = acpi_read_gpe_enable(acpi_facp);
- break;
- case ACPI_GPE_LEVEL:
- val = acpi_gpe_level;
- break;
- }
-
- size = sprintf(str, "0x%08x\n", val);
- if (*len >= size) {
- copy_to_user(buffer, str, size);
- *len = size;
- }
- else
- *len = 0;
- }
- else
- {
- // fetch user value
- size = sizeof(str) - 1;
- if (size > *len)
- size = *len;
- copy_from_user(str, buffer, size);
- str[size] = '\0';
- val = (u32) simple_strtoul(str, &strend, 0);
- if (strend == str)
- return -EINVAL;
-
- // store value in register
- switch (ctl->ctl_name) {
- case ACPI_PM1_ENABLE:
- // clear previously disabled events
- enabling = (val
- & ~acpi_read_pm1_enable(acpi_facp));
- acpi_write_pm1_status(acpi_facp, enabling);
-
- if (val) {
- // enable ACPI unless it is already
- if (!acpi_is_enabled(acpi_facp))
- acpi_enable(acpi_facp);
- }
- else if (!acpi_read_gpe_enable(acpi_facp)) {
- // disable ACPI unless it is already
- if (acpi_is_enabled(acpi_facp))
- acpi_disable(acpi_facp);
- }
-
- acpi_write_pm1_enable(acpi_facp, val);
- break;
- case ACPI_GPE_ENABLE:
- // clear previously disabled events
- enabling = (val
- & ~acpi_read_gpe_enable(acpi_facp));
- while (acpi_read_gpe_status(acpi_facp) & enabling)
- acpi_write_gpe_status(acpi_facp, enabling);
-
- if (val) {
- // enable ACPI unless it is already
- if (!acpi_is_enabled(acpi_facp))
- acpi_enable(acpi_facp);
- }
- else if (!acpi_read_pm1_enable(acpi_facp)) {
- // disable ACPI unless it is already
- if (acpi_is_enabled(acpi_facp))
- acpi_disable(acpi_facp);
- }
-
- acpi_write_gpe_enable(acpi_facp, val);
- break;
- case ACPI_GPE_LEVEL:
- acpi_gpe_level = val;
- break;
- }
- }
-
- file->f_pos += *len;
- return 0;
-}
-
-/*
- * Wait for next event
- */
-static int acpi_do_event(ctl_table *ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t *len)
-{
- u32 pm1_status = 0, gpe_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);
- pm1_status = acpi_pm1_status;
- acpi_pm1_status = 0;
- gpe_status = acpi_gpe_status;
- acpi_gpe_status = 0;
- spin_unlock_irqrestore(&acpi_event_lock, flags);
- event_state = acpi_event_state;
-
- if (pm1_status || gpe_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",
- pm1_status,
- gpe_status,
- 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
- {
- acpi_enter_sx(ACPI_S1);
- acpi_enter_sx(ACPI_S0);
- }
- file->f_pos += *len;
- return 0;
-}
-
-/*
- * Initialize and enable ACPI
- */
-static int __init acpi_init(void)
-{
- int pid;
-
- if (acpi_find_tables() && acpi_find_piix4()) {
- // no ACPI tables and not PIIX4
- return -ENODEV;
- }
-
- if (acpi_facp->p_lvl2_lat
- && acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
- acpi_p_lvl2_lat = acpi_facp->p_lvl2_lat;
- }
- if (acpi_facp->p_lvl3_lat
- && acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
- acpi_p_lvl3_lat = acpi_facp->p_lvl3_lat;
- }
-
- if (acpi_facp->sci_int
- && request_irq(acpi_facp->sci_int,
- acpi_irq,
- SA_INTERRUPT | SA_SHIRQ,
- "acpi",
- acpi_facp)) {
- printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n",
- acpi_facp->sci_int);
- acpi_destroy_tables();
- return -ENODEV;
- }
-
- acpi_claim_ioports(acpi_facp);
- acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
-
- pid = kernel_thread(acpi_control_thread,
- NULL,
- CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-
- acpi_power_off = acpi_power_off_handler;
-
- /*
- * Set up the ACPI idle function. Note that we can't really
- * do this with multiple CPU's, we'd need a per-CPU ACPI
- * device..
- */
-#ifdef __SMP__
- if (smp_num_cpus > 1)
- return 0;
-#endif
-
- acpi_idle = acpi_idle_handler;
-
- return 0;
-}
-
-/*
- * Disable and deinitialize ACPI
- */
-static void __exit acpi_exit(void)
-{
- acpi_idle = NULL;
- acpi_power_off = NULL;
-
- unregister_sysctl_table(acpi_sysctl);
- acpi_disable(acpi_facp);
- acpi_release_ioports(acpi_facp);
-
- if (acpi_facp->sci_int)
- free_irq(acpi_facp->sci_int, acpi_facp);
-
- acpi_destroy_tables();
-}
-
-/*
- * Register a device with the ACPI subsystem
- */
-struct acpi_dev* acpi_register(struct acpi_dev_info *info, unsigned long adr)
-{
- struct acpi_dev *dev = NULL;
- if (info) {
- dev = kmalloc(sizeof(struct acpi_dev), GFP_KERNEL);
- if (dev) {
- unsigned long flags;
-
- memset(dev, 0, sizeof(*dev));
- memcpy(&dev->info, info, sizeof(dev->info));
- dev->adr = adr;
-
- spin_lock_irqsave(&acpi_devs_lock, flags);
- list_add(&dev->entry, &acpi_devs);
- spin_unlock_irqrestore(&acpi_devs_lock, flags);
- }
- }
- return dev;
-}
-
-/*
- * Unregister a device with ACPI
- */
-void acpi_unregister(struct acpi_dev *dev)
-{
- if (dev) {
- unsigned long flags;
-
- spin_lock_irqsave(&acpi_devs_lock, flags);
- list_del(&dev->entry);
- spin_unlock_irqrestore(&acpi_devs_lock, flags);
-
- kfree(dev);
- }
-}
-
-/*
- * Wake up a device
- */
-void acpi_wakeup(struct acpi_dev *dev)
-{
- // run _PS0 or tell parent bus to wake device up
-}
-
-/*
- * Manage idle devices
- */
-static int acpi_control_thread(void *context)
-{
- exit_mm(current);
- exit_files(current);
- strcpy(current->comm, "acpi");
-
- for(;;) {
- interruptible_sleep_on(&acpi_control_wait);
- if (signal_pending(current))
- break;
-
- // find all idle devices and set idle timer
- }
-
- return 0;
-}
-
-__initcall(acpi_init);
-
-/*
- * Module visible symbols
- */
-EXPORT_SYMBOL(acpi_control_wait);
-EXPORT_SYMBOL(acpi_register);
-EXPORT_SYMBOL(acpi_unregister);
-EXPORT_SYMBOL(acpi_wakeup);