patch-2.4.0-prerelease linux/drivers/acpi/driver.c
Next file: linux/drivers/acpi/driver.h
Previous file: linux/drivers/acpi/dispatcher/dswstate.c
Back to the patch index
Back to the overall index
- Lines: 367
- Date:
Fri Dec 29 14:07:21 2000
- Orig file:
v2.4.0-test12/linux/drivers/acpi/driver.c
- Orig date:
Mon Dec 11 17:59:43 2000
diff -u --recursive --new-file v2.4.0-test12/linux/drivers/acpi/driver.c linux/drivers/acpi/driver.c
@@ -17,6 +17,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/*
+ * Changes
+ * David Woodhouse <dwmw2@redhat.com> 2000-12-6
+ * - Fix interruptible_sleep_on() races
+ */
#include <linux/config.h>
#include <linux/module.h>
@@ -32,6 +37,12 @@
#include "acpi.h"
#include "driver.h"
+#ifdef CONFIG_ACPI_KERNEL_CONFIG
+#include <asm/efi.h>
+#define ACPI_CAN_USE_EFI_STRUCT
+#endif
+
+
#define _COMPONENT OS_DEPENDENT
MODULE_NAME ("driver")
@@ -48,7 +59,15 @@
static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait);
static volatile int acpi_thread_pid = -1;
+
+/************************************************/
+/* DECLARE_TASK_QUEUE is defined in */
+/* /usr/src/linux/include/linux/tqueue.h */
+/* So, acpi_thread_run is a pointer to a */
+/* tq_struct structure,defined in the same file.*/
+/************************************************/
static DECLARE_TASK_QUEUE(acpi_thread_run);
+
static DECLARE_WAIT_QUEUE_HEAD(acpi_thread_wait);
static struct ctl_table_header *acpi_sysctl = NULL;
@@ -98,6 +117,38 @@
return 0;
}
+static int
+acpi_do_pm_timer(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len)
+{
+ int size;
+ u32 val = 0;
+
+ char str[12];
+
+ if (file->f_pos) {
+ *len = 0;
+ return 0;
+ }
+
+ val = acpi_read_pm_timer();
+
+ size = sprintf(str, "0x%08x\n", val);
+ if (*len >= size) {
+ copy_to_user(buffer, str, size);
+ *len = size;
+ }
+ else
+ *len = 0;
+
+ file->f_pos += *len;
+
+ return 0;
+}
+
/*
* Handle ACPI event
*/
@@ -105,13 +156,18 @@
acpi_event(void *context)
{
unsigned long flags;
- int event = (int) context;
+ int event = (int)(long)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;
+ case ACPI_EVENT_POWER_BUTTON:
+ mask = ACPI_PWRBTN;
+ break;
+ case ACPI_EVENT_SLEEP_BUTTON:
+ mask = ACPI_SLPBTN;
+ break;
+ default:
+ return AE_ERROR;
}
if (mask) {
@@ -148,8 +204,12 @@
return 0;
}
- for (;;) {
+ while (!event_status) {
unsigned long flags;
+ DECLARE_WAITQUEUE(wait, current);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&acpi_event_wait, &wait);
// we need an atomic exchange here
spin_lock_irqsave(&acpi_event_lock, flags);
@@ -158,11 +218,12 @@
spin_unlock_irqrestore(&acpi_event_lock, flags);
event_state = acpi_event_state;
- if (event_status)
- break;
+ if (!event_status)
+ schedule();
+
+ remove_wait_queue(&acpi_event_wait, &wait);
+ set_current_state(TASK_RUNNING);
- // wait for an event to arrive
- interruptible_sleep_on(&acpi_event_wait);
if (signal_pending(current))
return -ERESTARTSYS;
}
@@ -196,19 +257,78 @@
}
}
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
+ * Output important ACPI tables to proc
*/
+static int
+acpi_do_table(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len)
+{
+ u32 table_type;
+ size_t size;
+ ACPI_BUFFER buf;
+ u8* data;
+
+ table_type = (u32) ctl->data;
+ size = 0;
+ buf.length = 0;
+ buf.pointer = NULL;
+
+ /* determine what buffer size we will need */
+ if (acpi_get_table(table_type, 1, &buf) != AE_BUFFER_OVERFLOW) {
+ *len = 0;
+ return 0;
+ }
+
+ buf.pointer = kmalloc(buf.length, GFP_KERNEL);
+ if (!buf.pointer) {
+ return -ENOMEM;
+ }
+
+ /* get the table for real */
+ if (!ACPI_SUCCESS(acpi_get_table(table_type, 1, &buf))) {
+ kfree(buf.pointer);
+ *len = 0;
+ return 0;
+ }
+
+ if (file->f_pos < buf.length) {
+ data = buf.pointer + file->f_pos;
+ size = buf.length - file->f_pos;
+ if (size > *len)
+ size = *len;
+ if (copy_to_user(buffer, data, size))
+ return -EFAULT;
+ }
+
+ kfree(buf.pointer);
+
+ *len = size;
+ file->f_pos += size;
+ return 0;
+}
+
+/********************************************************************/
+/* R U N Q U E U E D C A L L B A C K */
+/* */
+/* The "callback" function address that was tramped through via */
+/* "acpi_run" below is finally called and executed. If we trace all */
+/* this down, the function is acpi_ev_asynch_execute_gpe_method, in */
+/* evevent.c The only other function that is ever queued is */
+/* acpi_ev_global_lock_thread in evmisc.c. */
+/********************************************************************/
static void
acpi_run_exec(void *context)
{
@@ -266,6 +386,20 @@
{ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event},
+ {ACPI_FADT, "fadt", (void *) ACPI_TABLE_FADT, sizeof(int),
+ 0444, NULL, &acpi_do_table},
+
+ {ACPI_DSDT, "dsdt", (void *) ACPI_TABLE_DSDT, sizeof(int),
+ 0444, NULL, &acpi_do_table},
+
+ {ACPI_FACS, "facs", (void *) ACPI_TABLE_FACS, sizeof(int),
+ 0444, NULL, &acpi_do_table},
+
+ {ACPI_XSDT, "xsdt", (void *) ACPI_TABLE_XSDT, sizeof(int),
+ 0444, NULL, &acpi_do_table},
+
+ {ACPI_PMTIMER, "pm_timer", NULL, 0, 0444, NULL, &acpi_do_pm_timer},
+
{0}
};
@@ -281,50 +415,75 @@
static int
acpi_thread(void *context)
{
+ ACPI_PHYSICAL_ADDRESS rsdp_phys;
+
/*
* initialize
*/
-
daemonize();
- strcpy(current->comm, "acpi");
+ strcpy(current->comm, "kacpid");
+
+ if (!ACPI_SUCCESS(acpi_initialize_subsystem())) {
+ printk(KERN_ERR "ACPI: Driver initialization failed\n");
+ return -ENODEV;
+ }
- if (!ACPI_SUCCESS(acpi_initialize(NULL))) {
- printk(KERN_ERR "ACPI: initialize failed\n");
+#ifndef ACPI_CAN_USE_EFI_STRUCT
+ if (!ACPI_SUCCESS(acpi_find_root_pointer(&rsdp_phys))) {
+ printk(KERN_ERR "ACPI: System description tables not found\n");
return -ENODEV;
}
+#else
+ rsdp_phys = efi.acpi;
+#endif
+
+ printk(KERN_ERR "ACPI: System description tables found\n");
- if (acpi_load_tables())
+ if (!ACPI_SUCCESS(acpi_find_and_load_tables(rsdp_phys)))
return -ENODEV;
if (PM_IS_ACTIVE()) {
- printk(KERN_NOTICE "ACPI: APM is already active.\n");
+ printk(KERN_NOTICE "ACPI: APM is already active, exiting\n");
acpi_terminate();
return -ENODEV;
}
- pm_active = 1;
-
- if (!ACPI_SUCCESS(acpi_enable())) {
- printk(KERN_ERR "ACPI: enable failed\n");
+ if (!ACPI_SUCCESS(acpi_enable_subsystem(ACPI_FULL_INITIALIZATION))) {
+ printk(KERN_ERR "ACPI: Subsystem enable failed\n");
acpi_terminate();
return -ENODEV;
}
+ printk(KERN_ERR "ACPI: Subsystem enabled\n");
+
+ pm_active = 1;
+
acpi_cpu_init();
acpi_sys_init();
acpi_ec_init();
+ acpi_power_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");
+ /*
+ * Non-intuitive: 0 means pwr and sleep are implemented using the fixed
+ * feature model, so we install handlers. 1 means a control method
+ * implementation, or none at all, so do nothing. See ACPI spec.
+ */
+ if (acpi_fadt.pwr_button == 0) {
+ 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_fadt.sleep_button == 0) {
+ 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);
@@ -333,9 +492,20 @@
* run
*/
for (;;) {
- interruptible_sleep_on(&acpi_thread_wait);
+ DECLARE_WAITQUEUE(wait, current);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&acpi_thread_wait, &wait);
+
+ if (list_empty(&acpi_thread_run))
+ schedule();
+
+ remove_wait_queue(&acpi_thread_wait, &wait);
+ set_current_state(TASK_RUNNING);
+
if (signal_pending(current))
break;
+
run_task_queue(&acpi_thread_run);
}
@@ -343,7 +513,9 @@
* terminate
*/
unregister_sysctl_table(acpi_sysctl);
- acpi_terminate();
+
+ /* do not terminate, because we need acpi in order to shut down */
+ /*acpi_terminate();*/
acpi_thread_pid = -1;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)