patch-2.3.27 linux/drivers/misc/acpi.c
Next file: linux/drivers/net/3c507.c
Previous file: linux/drivers/misc/Makefile
Back to the patch index
Back to the overall index
- Lines: 303
- Date:
Wed Nov 10 20:01:03 1999
- Orig file:
v2.3.26/linux/drivers/misc/acpi.c
- Orig date:
Mon Nov 1 13:56:26 1999
diff -u --recursive --new-file v2.3.26/linux/drivers/misc/acpi.c linux/drivers/misc/acpi.c
@@ -54,6 +54,7 @@
#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue * x = NULL
#endif
+static int acpi_idle_thread(void *context);
static int acpi_do_ulong(ctl_table *ctl,
int write,
struct file *file,
@@ -69,6 +70,13 @@
struct file *file,
void *buffer,
size_t *len);
+static int acpi_do_sleep_wake(ctl_table *ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t *len);
+
+DECLARE_WAIT_QUEUE_HEAD(acpi_idle_wait);
static struct ctl_table_header *acpi_sysctl = NULL;
@@ -84,6 +92,9 @@
static volatile u32 acpi_gpe_level = 0;
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 L2/L3 until after we've initialized */
static unsigned long acpi_p_lvl2_lat = ~0UL;
static unsigned long acpi_p_lvl3_lat = ~0UL;
@@ -147,6 +158,11 @@
&acpi_slp_typ[5], sizeof(acpi_slp_typ[5]),
0600, NULL, &acpi_do_ulong},
+#if 0
+ {123, "sleep", (void*) 1, 0, 0600, NULL, &acpi_do_sleep_wake},
+ {124, "wake", NULL, 0, 0600, NULL, &acpi_do_sleep_wake},
+#endif
+
{0}
};
@@ -319,15 +335,23 @@
if (addr) {
// map table header to determine size
table = (struct acpi_table *)
- ioremap_nocache((unsigned long) addr,
- sizeof(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_nocache((unsigned long) addr,
- table_size);
+ 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;
@@ -338,6 +362,7 @@
*/
static void acpi_unmap_table(struct acpi_table *table)
{
+ // iounmap ignores addresses within physical memory
if (table)
iounmap(table);
}
@@ -380,8 +405,14 @@
// fetch RSDT from RSDP
rsdt = acpi_map_table(rsdp->rsdt);
- if (!rsdt || rsdt->signature != ACPI_RSDT_SIG) {
- printk(KERN_ERR "ACPI: missing RSDT\n");
+ 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;
}
@@ -396,9 +427,15 @@
acpi_facp_addr = *rsdt_entry;
acpi_dsdt_addr = acpi_facp->dsdt;
+ // map FACS if it exists
if (acpi_facp->facs) {
- acpi_facs = (struct acpi_facs*)
- acpi_map_table(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 {
@@ -624,6 +661,34 @@
}
/*
+ * 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;
+}
+
+/*
* Enter system sleep state
*/
static void acpi_enter_sx(int state)
@@ -903,10 +968,41 @@
}
/*
+ * Sleep or wake system
+ */
+static int acpi_do_sleep_wake(ctl_table *ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t *len)
+{
+ if (!write) {
+ if (file->f_pos) {
+ *len = 0;
+ return 0;
+ }
+ }
+ else
+ {
+ // just shutdown some devices for now
+ if (ctl->data) {
+ acpi_enter_dx(ACPI_D3);
+ }
+ else {
+ acpi_enter_dx(ACPI_D0);
+ }
+ }
+ 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;
@@ -917,7 +1013,7 @@
acpi_irq,
SA_INTERRUPT | SA_SHIRQ,
"acpi",
- NULL)) {
+ acpi_facp)) {
printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n",
acpi_facp->sci_int);
acpi_destroy_tables();
@@ -927,6 +1023,10 @@
acpi_claim_ioports(acpi_facp);
acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
+ pid = kernel_thread(acpi_idle_thread,
+ NULL,
+ CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+
/*
* 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
@@ -956,18 +1056,84 @@
acpi_release_ioports(acpi_facp);
if (acpi_facp->sci_int)
- free_irq(acpi_facp->sci_int, NULL);
+ free_irq(acpi_facp->sci_int, acpi_facp);
acpi_destroy_tables();
}
-#ifdef MODULE
+/*
+ * 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;
+}
-module_init(acpi_init)
-module_exit(acpi_exit)
+/*
+ * Unregister a device with ACPI
+ */
+void acpi_unregister(struct acpi_dev *dev)
+{
+ if (dev) {
+ unsigned long flags;
-#else
+ 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_idle_thread(void *context)
+{
+ exit_mm(current);
+ exit_files(current);
+ strcpy(current->comm, "acpi");
+
+ for(;;) {
+ interruptible_sleep_on(&acpi_idle_wait);
+ if (signal_pending(current))
+ break;
+
+ // find all idle devices and set idle timer based on policy
+ }
+
+ return 0;
+}
__initcall(acpi_init);
-#endif
+/*
+ * Module visible symbols
+ */
+EXPORT_SYMBOL(acpi_idle_wait);
+EXPORT_SYMBOL(acpi_register);
+EXPORT_SYMBOL(acpi_unregister);
+EXPORT_SYMBOL(acpi_wakeup);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)