patch-2.3.24 linux/drivers/misc/acpi.c
Next file: linux/drivers/net/Config.in
Previous file: linux/drivers/macintosh/macserial.c
Back to the patch index
Back to the overall index
- Lines: 945
- Date:
Wed Oct 27 16:06:52 1999
- Orig file:
v2.3.23/linux/drivers/misc/acpi.c
- Orig date:
Fri Oct 22 13:21:49 1999
diff -u --recursive --new-file v2.3.23/linux/drivers/misc/acpi.c linux/drivers/misc/acpi.c
@@ -29,8 +29,13 @@
#include <linux/sched.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>
/*
@@ -49,7 +54,26 @@
#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue * x = NULL
#endif
+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 struct ctl_table_header *acpi_sysctl = NULL;
+
static struct acpi_facp *acpi_facp = NULL;
+static int acpi_fake_facp = 0;
static unsigned long acpi_facp_addr = 0;
static unsigned long acpi_dsdt_addr = 0;
@@ -57,15 +81,64 @@
static volatile u32 acpi_pm1_status = 0;
static volatile u32 acpi_gpe_status = 0;
static volatile u32 acpi_gpe_level = 0;
-static DECLARE_WAIT_QUEUE_HEAD(acpi_wait_event);
+static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait);
/* Make it impossible to enter L2/L3 until after we've initialized */
static unsigned long acpi_p_lvl2_lat = ~0UL;
static unsigned long acpi_p_lvl3_lat = ~0UL;
/* Initialize to guaranteed harmless port read */
-static u16 acpi_p_lvl2 = 0x80;
-static u16 acpi_p_lvl3 = 0x80;
+static unsigned long acpi_p_lvl2 = 0x80;
+static unsigned long acpi_p_lvl3 = 0x80;
+
+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_LVL2, "p_lvl2",
+ &acpi_p_lvl2, sizeof(acpi_p_lvl2),
+ 0600, NULL, &acpi_do_ulong},
+
+ {ACPI_P_LVL3, "p_lvl3",
+ &acpi_p_lvl3, sizeof(acpi_p_lvl3),
+ 0600, NULL, &acpi_do_ulong},
+
+ {ACPI_P_LVL2_LAT, "p_lvl2_lat",
+ &acpi_p_lvl2_lat, sizeof(acpi_p_lvl2_lat),
+ 0600, NULL, &acpi_do_ulong},
+
+ {ACPI_P_LVL3_LAT, "p_lvl3_lat",
+ &acpi_p_lvl3_lat, sizeof(acpi_p_lvl3_lat),
+ 0600, NULL, &acpi_do_ulong},
+
+ {0}
+};
+
+static struct ctl_table acpi_dir_table[] =
+{
+ {CTL_ACPI, "acpi", NULL, 0, 0500, acpi_table},
+ {0}
+};
/*
@@ -73,7 +146,9 @@
*/
static u32 acpi_read_pm1_control(struct acpi_facp *facp)
{
- u32 value = inw(facp->pm1a_cnt);
+ u32 value = 0;
+ if (facp->pm1a_cnt)
+ value = inw(facp->pm1a_cnt);
if (facp->pm1b_cnt)
value |= inw(facp->pm1b_cnt);
return value;
@@ -84,7 +159,9 @@
*/
static u32 acpi_read_pm1_status(struct acpi_facp *facp)
{
- u32 value = inw(facp->pm1a_evt);
+ u32 value = 0;
+ if (facp->pm1a_evt)
+ value = inw(facp->pm1a_evt);
if (facp->pm1b_evt)
value |= inw(facp->pm1b_evt);
return value;
@@ -95,7 +172,8 @@
*/
static void acpi_write_pm1_status(struct acpi_facp *facp, u32 value)
{
- outw(value, facp->pm1a_evt);
+ if (facp->pm1a_evt)
+ outw(value, facp->pm1a_evt);
if (facp->pm1b_evt)
outw(value, facp->pm1b_evt);
}
@@ -106,7 +184,9 @@
static u32 acpi_read_pm1_enable(struct acpi_facp *facp)
{
int offset = facp->pm1_evt_len >> 1;
- u32 value = inw(facp->pm1a_evt + offset);
+ 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;
@@ -118,7 +198,8 @@
static void acpi_write_pm1_enable(struct acpi_facp *facp, u32 value)
{
int offset = facp->pm1_evt_len >> 1;
- outw(value, facp->pm1a_evt + offset);
+ if (facp->pm1a_evt)
+ outw(value, facp->pm1a_evt + offset);
if (facp->pm1b_evt)
outw(value, facp->pm1b_evt + offset);
}
@@ -136,9 +217,11 @@
for (i = size - 1; i >= 0; i--)
value = (value << 8) | inb(facp->gpe1 + i);
}
- size = facp->gpe0_len >> 1;
- for (i = size - 1; i >= 0; i--)
- value = (value << 8) | inb(facp->gpe0 + 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;
}
@@ -149,10 +232,12 @@
{
int i, size;
- size = facp->gpe0_len >> 1;
- for (i = 0; i < size; i++) {
- outb(value & 0xff, facp->gpe0 + i);
- value >>= 8;
+ 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;
@@ -178,9 +263,11 @@
value = (value << 8) | inb(facp->gpe1 + offset + i);
}
}
- size = facp->gpe0_len >> 1;
- for (i = size - 1; i >= 0; i--)
- value = (value << 8) | inb(facp->gpe0 + 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;
}
@@ -192,9 +279,11 @@
int i, offset;
offset = facp->gpe0_len >> 1;
- for (i = 0; i < offset; i++) {
- outb(value & 0xff, facp->gpe0 + offset + i);
- value >>= 8;
+ 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;
@@ -238,9 +327,9 @@
}
/*
- * Locate and map ACPI tables (FACP, DSDT, ...)
+ * Locate and map ACPI tables
*/
-static int __init acpi_map_tables(void)
+static int __init acpi_find_tables(void)
{
struct acpi_rsdp *rsdp;
struct acpi_table *rsdt;
@@ -251,8 +340,8 @@
// 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) {
+ if (rsdp->signature[0] == ACPI_RSDP1_SIG
+ && rsdp->signature[1] == ACPI_RSDP2_SIG) {
char oem[7];
int j;
@@ -270,14 +359,13 @@
break;
}
}
- if (i >= ACPI_BIOS_ROM_END) {
- printk(KERN_ERR "ACPI: no RSDP found\n");
+ if (i >= ACPI_BIOS_ROM_END)
return -ENODEV;
- }
+
// fetch RSDT from RSDP
rsdt = acpi_map_table(rsdp->rsdt);
if (!rsdt || rsdt->signature != ACPI_RSDT_SIG) {
- printk(KERN_ERR "ACPI: no RSDT found\n");
+ printk(KERN_ERR "ACPI: missing RSDT\n");
acpi_unmap_table(rsdt);
return -ENODEV;
}
@@ -288,11 +376,11 @@
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 = (struct acpi_facp*) dt;
acpi_facp_addr = *rsdt_entry;
acpi_dsdt_addr = acpi_facp->dsdt;
- break;
- } else {
+ }
+ else {
acpi_unmap_table(dt);
}
rsdt_entry++;
@@ -302,22 +390,89 @@
acpi_unmap_table(rsdt);
if (!acpi_facp) {
- printk(KERN_ERR "ACPI: no FACP found\n");
+ printk(KERN_ERR "ACPI: missing FACP\n");
return -ENODEV;
}
return 0;
}
/*
- * Unmap ACPI tables (FACP, DSDT, ...)
+ * Unmap or destroy ACPI tables
*/
-static void acpi_unmap_tables(void)
+static void acpi_destroy_tables(void)
{
- acpi_idle = NULL;
+ if (!acpi_fake_facp)
+ acpi_unmap_table((struct acpi_table*) acpi_facp);
+ else
+ kfree(acpi_facp);
+}
+
+/*
+ * 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 = ~0;
+ acpi_facp->p_lvl3_lat = ~0;
+
+ acpi_facp_addr = virt_to_phys(acpi_facp);
acpi_dsdt_addr = 0;
- acpi_facp_addr = 0;
- acpi_unmap_table((struct acpi_table *) acpi_facp);
- acpi_facp = NULL;
+
+ acpi_p_lvl2 = base + ACPI_PIIX4_P_LVL2;
+ acpi_p_lvl3 = base + ACPI_PIIX4_P_LVL3;
+
+ return 0;
}
/*
@@ -355,25 +510,7 @@
acpi_pm1_status |= pm1_status;
acpi_gpe_status |= gpe_status;
spin_unlock_irqrestore(&acpi_event_lock, flags);
- wake_up_interruptible(&acpi_wait_event);
-}
-
-/*
- * Handle open of /dev/acpi
- */
-static int acpi_open(struct inode *inode, struct file *file)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * Handle close of /dev/acpi
- */
-static int acpi_release(struct inode *inode, struct file *file)
-{
- MOD_DEC_USE_COUNT;
- return 0;
+ wake_up_interruptible(&acpi_event_wait);
}
/*
@@ -389,7 +526,8 @@
*/
static int acpi_enable(struct acpi_facp *facp)
{
- outb(facp->acpi_enable, facp->smi_cmd);
+ if (facp->smi_cmd)
+ outb(facp->acpi_enable, facp->smi_cmd);
return (acpi_is_enabled(facp) ? 0:-1);
}
@@ -404,132 +542,29 @@
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));
-
- outb(facp->acpi_disable, facp->smi_cmd);
+
+ if (facp->smi_cmd)
+ outb(facp->acpi_disable, facp->smi_cmd);
return (acpi_is_enabled(facp) ? -1:0);
}
/*
- * Handle command to /dev/acpi
+ * Idle loop
*/
-static int acpi_ioctl(struct inode *inode,
- struct file *file,
- unsigned cmd,
- unsigned long arg)
-{
- int status = -EINVAL;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- switch (cmd) {
- case ACPI_FIND_TABLES:
- status = verify_area(VERIFY_WRITE,
- (void *) arg,
- sizeof(struct acpi_find_tables));
- if (!status) {
- struct acpi_find_tables *rqst
- = (struct acpi_find_tables *) arg;
- put_user(acpi_facp_addr, &rqst->facp);
- put_user(acpi_dsdt_addr, &rqst->dsdt);
- status = 0;
- }
- break;
- case ACPI_ENABLE_EVENT:
- status = verify_area(VERIFY_READ,
- (void *) arg,
- sizeof(struct acpi_enable_event));
- if (!status) {
- struct acpi_enable_event *rqst
- = (struct acpi_enable_event *) arg;
- u32 pm1_enable, gpe_enable, gpe_level;
- u32 pm1_enabling, gpe_enabling;
-
- get_user(pm1_enable, &rqst->pm1_enable);
- get_user(gpe_enable, &rqst->gpe_enable);
- get_user(gpe_level, &rqst->gpe_level);
- gpe_level &= gpe_enable;
-
- // clear previously disabled events before enabling
- pm1_enabling = (pm1_enable
- & ~acpi_read_pm1_enable(acpi_facp));
- acpi_write_pm1_status(acpi_facp, pm1_enabling);
- gpe_enabling = (gpe_enable &
- ~acpi_read_gpe_enable(acpi_facp));
- while (acpi_read_gpe_status(acpi_facp) & gpe_enabling)
- acpi_write_gpe_status(acpi_facp, gpe_enabling);
-
- status = 0;
-
- if (pm1_enable || gpe_enable) {
- // enable ACPI unless it is already
- if (!acpi_is_enabled(acpi_facp)
- && acpi_enable(acpi_facp)) {
- status = -EBUSY;
- }
- }
- else {
- // disable ACPI unless it is already
- if (acpi_is_enabled(acpi_facp)
- && acpi_disable(acpi_facp)) {
- status = -EBUSY;
- }
- }
-
- if (!status)
- {
- acpi_write_pm1_enable(acpi_facp, pm1_enable);
- acpi_write_gpe_enable(acpi_facp, gpe_enable);
- acpi_gpe_level = gpe_level;
- }
- }
- break;
- case ACPI_WAIT_EVENT:
- status = verify_area(VERIFY_WRITE,
- (void *) arg,
- sizeof(struct acpi_wait_event));
- if (!status) {
- struct acpi_wait_event *rqst
- = (struct acpi_wait_event *) arg;
- u32 pm1_status = 0;
- u32 gpe_status = 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);
-
- if (pm1_status || gpe_status)
- break;
-
- // wait for an event to arrive
- interruptible_sleep_on(&acpi_wait_event);
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
-
- put_user(pm1_status, &rqst->pm1_status);
- put_user(gpe_status, &rqst->gpe_status);
- status = 0;
- }
- break;
- }
- return status;
-}
-
static void acpi_idle_handler(void)
{
- unsigned long time;
static int sleep_level = 1;
+ u32 timer, pm2_cnt;
+ unsigned long time;
+
+ // 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();
- time = inl(acpi_facp->pm_tmr);
+ // sleep
switch (sleep_level) {
case 1:
__asm__ __volatile__("sti ; hlt": : :"memory");
@@ -538,18 +573,25 @@
inb(acpi_p_lvl2);
break;
case 3:
- /* Disable PCI arbitration while sleeping,
- to avoid DMA corruption? */
- if (acpi_facp->pm2_cnt) {
- unsigned int port = acpi_facp->pm2_cnt;
- outb(inb(port) | ACPI_ARB_DIS, port);
+ 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_lvl3);
+ outb(inb(pm2_cnt) & ~ACPI_ARB_DIS, pm2_cnt);
+ }
+ else {
inb(acpi_p_lvl3);
- outb(inb(port) & ~ACPI_ARB_DIS, port);
- break;
}
- inb(acpi_p_lvl3);
+ break;
}
- time = (inl(acpi_facp->pm_tmr) - time) & ACPI_TMR_MASK;
+
+ // 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);
if (time > acpi_p_lvl3_lat)
sleep_level = 3;
@@ -559,50 +601,24 @@
sleep_level = 1;
}
-static struct file_operations acpi_fops =
-{
- NULL, /* llseek */
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- acpi_ioctl, /* ioctl */
- NULL, /* mmap */
- acpi_open, /* open */
- NULL, /* flush */
- acpi_release, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* check_media_change */
- NULL, /* revalidate */
- NULL, /* lock */
-};
-
-static struct miscdevice acpi_device =
-{
- ACPI_MINOR_DEV,
- "acpi",
- &acpi_fops,
- NULL,
- NULL
-};
-
/*
* 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
- request_region(facp->pm1a_evt, facp->pm1_evt_len, "acpi");
+ 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");
- request_region(facp->pm1a_cnt, facp->pm1_cnt_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->pm2_cnt)
- request_region(facp->pm2_cnt, facp->pm2_cnt_len, "acpi");
- request_region(facp->pm_tmr, facp->pm_tm_len, "acpi");
- request_region(facp->gpe0, facp->gpe0_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");
@@ -615,16 +631,18 @@
static int acpi_release_ioports(struct acpi_facp *facp)
{
// we don't get a guarantee of contiguity for any of the ACPI registers
- release_region(facp->pm1a_evt, facp->pm1_evt_len);
+ 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);
- release_region(facp->pm1a_cnt, facp->pm1_cnt_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->pm2_cnt)
- release_region(facp->pm2_cnt, facp->pm2_cnt_len);
- release_region(facp->pm_tmr, facp->pm_tm_len);
- release_region(facp->gpe0, facp->gpe0_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);
@@ -632,28 +650,224 @@
}
/*
+ * 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;
+ char str[4 * sizeof(u32) + 6];
+ 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);
+
+ 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\n", pm1_status, gpe_status);
+ copy_to_user(buffer, str, size);
+ *len = size;
+ file->f_pos += size;
+
+ return 0;
+}
+
+/*
* Initialize and enable ACPI
*/
static int __init acpi_init(void)
{
- if (acpi_map_tables())
+ if (acpi_find_tables() && acpi_find_piix4()) {
+ // no ACPI tables and not PIIX4
return -ENODEV;
+ }
- if (request_irq(acpi_facp->sci_int,
- acpi_irq,
- SA_INTERRUPT | SA_SHIRQ,
- "acpi",
- NULL)) {
+ if (acpi_facp->sci_int
+ && request_irq(acpi_facp->sci_int,
+ acpi_irq,
+ SA_INTERRUPT | SA_SHIRQ,
+ "acpi",
+ NULL)) {
printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n",
acpi_facp->sci_int);
- acpi_unmap_tables();
+ acpi_destroy_tables();
return -ENODEV;
}
acpi_claim_ioports(acpi_facp);
-
- if (misc_register(&acpi_device))
- printk(KERN_ERR "ACPI: misc. register failed\n");
+ acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
/*
* Set up the ACPI idle function. Note that we can't really
@@ -664,7 +878,9 @@
if (smp_num_cpus > 1)
return 0;
#endif
+
acpi_idle = acpi_idle_handler;
+
return 0;
}
@@ -673,11 +889,16 @@
*/
static void __exit acpi_exit(void)
{
- misc_deregister(&acpi_device);
+ acpi_idle = NULL;
+
+ unregister_sysctl_table(acpi_sysctl);
acpi_disable(acpi_facp);
acpi_release_ioports(acpi_facp);
- free_irq(acpi_facp->sci_int, NULL);
- acpi_unmap_tables();
+
+ if (acpi_facp->sci_int)
+ free_irq(acpi_facp->sci_int, NULL);
+
+ acpi_destroy_tables();
}
#ifdef MODULE
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)