> > > I would think that it would make sense to keep shutdown 
> > with all the other
> > > power management events. Perhaps it will makes more sense 
> > to handle UPS's
> > > through the power management code.
> > 
> > Yes, that would be another acceptable solution. Situation where half
> > of power managment (UPS) is done with init and half with acpid is not
> > acceptable. [I doubt UPS users will want to switch. Why invent new
> > daemon when init is doing perfect job?]
> 
> I think init is doing a perfect job WRT UPSs because this is a trivial
> application of power management. init wasn't really meant for this.
> According to its man page:
> 
> "init...it's primary role is to create processes from a script in the file
> /etc/inittab...It also controls autonomous processes required by any
> particular system"
> 
> We are going to need some software that handles button events, as well as
> thermal events, battery events, polling the battery, AC adapter status
> changes, sleeping the system, and more.
I do not want to put battery/thermal/AC adapter status through
init. On *many* machines, button is only usefull device from ACPI (for
example all desktop machines). On desktop machine, you probably will
not want to configure/run acpid. Init should be able to do its job.
I agree that for notebooks where you want to handle thermal events
etc., acpid will be neccessary. I just do not want desktop people to
be forced to run acpid.
> We need WAY more flexibility than init provides. I find the argument that
> init is already handling one minor power-related thing an unconvincing
> reason why we should cram all power management through it.
It is doing UPS and c-a-d handling, which is *very* similar to what
you want to do on power button press 99% of time.
								Pavel
PS: About thermal events -- do I need to do something special in order
for temperature to be measured?
I can send _TMP, and get temperature reading, but it does not change
with time -- I get the same value from boot on.
BTW here are hacks I use for easy control of ACPI. That way, I can
just for A in device_*; do echo -n '_TMP' > $A; done and get
temperature reading in syslog ;-).
Do you think some way to reflect acpi structure in proc would be good
idea?
diff -ur -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkeymap.c -x uni_hash.tbl -x zImage -x vmlinu?* -x TAGS -x bootsect -x *RCS* -x conmakehash -x map -x build -x build -x configure -x *target* -x *.flags -x *.bak clean/drivers/acpi/common/cmeval.c linux/drivers/acpi/common/cmeval.c
--- clean/drivers/acpi/common/cmeval.c	Wed Jan 31 16:14:27 2001
+++ linux/drivers/acpi/common/cmeval.c	Fri Apr  6 08:45:21 2001
@@ -262,9 +262,10 @@
  ***************************************************************************/
 
 ACPI_STATUS
-acpi_cm_execute_STA (
+acpi_cm_execute_rint (
 	ACPI_NAMESPACE_NODE     *device_node,
-	u32                     *flags)
+	u32                     *flags,
+	char			*name)
 {
 	ACPI_OPERAND_OBJECT     *obj_desc;
 	ACPI_STATUS             status;
@@ -273,14 +274,12 @@
 	/* Execute the method */
 
 	status = acpi_ns_evaluate_relative (device_node,
-			 METHOD_NAME__STA, NULL, &obj_desc);
-	if (AE_NOT_FOUND == status) {
-		*flags = 0x0F;
-		status = AE_OK;
-	}
-
+			 name, NULL, &obj_desc);
+	if (ACPI_FAILURE (status))
+		return (status);
 
-	else /* success */ {
+	/* I guess it used to be subtle bug here, on AE_NOT_FOUND, it did cm_remove_reference, anyway */
+	{
 		/* Did we get a return object? */
 
 		if (!obj_desc) {
@@ -306,3 +305,71 @@
 
 	return (status);
 }
+
+
+ACPI_STATUS
+acpi_cm_execute_STA (
+	ACPI_NAMESPACE_NODE     *device_node,
+	u32                     *flags)
+{
+	ACPI_STATUS             status;
+
+	status = acpi_cm_execute_rint(device_node, flags, "_STA");
+	if (status == AE_NOT_FOUND) {
+		*flags = 0x0F;
+		return AE_OK;
+	}
+	return status;
+}
+
+
+ACPI_STATUS
+acpi_cm_execute_any (
+	ACPI_NAMESPACE_NODE     *device_node,
+	char                    *res,
+	char			*name)
+{
+	ACPI_OPERAND_OBJECT     *obj_desc;
+	ACPI_STATUS             status;
+
+
+	/* Execute the method */
+
+	status = acpi_ns_evaluate_relative (device_node,
+			 name, NULL, &obj_desc);
+	sprintf(res, "error");
+	if (ACPI_FAILURE (status))
+		return (status);
+
+	/* I guess it used to be subtle bug here, on AE_NOT_FOUND, it did cm_remove_reference, anyway */
+	{
+		/* Did we get a return object? */
+
+		if (!obj_desc) {
+			sprintf(res, "no return");
+			return (AE_OK);
+		}
+
+		/* Is the return object of the correct type? */
+
+		switch (obj_desc->common.type) {
+		case ACPI_TYPE_INTEGER:
+			sprintf(res, "int: %d", obj_desc->integer.value);
+			break;
+		case ACPI_TYPE_STRING:
+			sprintf(res, "string: %20s", obj_desc->string.pointer);
+			break;
+		deafult:
+			sprintf(res, "unknown", obj_desc->string.pointer);
+			break;
+		}
+
+		/* On exit, we must delete the return object */
+
+		acpi_cm_remove_reference (obj_desc);
+	}
+
+	return (status);
+}
+
+
diff -ur -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkeymap.c -x uni_hash.tbl -x zImage -x vmlinu?* -x TAGS -x bootsect -x *RCS* -x conmakehash -x map -x build -x build -x configure -x *target* -x *.flags -x *.bak clean/drivers/acpi/events/evevent.c linux/drivers/acpi/events/evevent.c
--- clean/drivers/acpi/events/evevent.c	Sun Apr  1 00:22:57 2001
+++ linux/drivers/acpi/events/evevent.c	Wed Apr  4 01:08:11 2001
@@ -30,6 +30,8 @@
 #include "acnamesp.h"
 #include "accommon.h"
 
+#include <linux/signal.h>
+
 #define _COMPONENT          EVENT_HANDLING
 	 MODULE_NAME         ("evevent")
 
@@ -49,25 +51,15 @@
  *************************************************************************/
 
 ACPI_STATUS
-acpi_ev_initialize (
-	void)
+acpi_ev_initialize (void)
 {
 	ACPI_STATUS             status;
 
-
-	/* Make sure we have ACPI tables */
-
-	if (!acpi_gbl_DSDT) {
+	if (!acpi_gbl_DSDT)		 	/* Make sure we have ACPI tables */
 		return (AE_NO_ACPI_TABLES);
-	}
-
-
-	/* Make sure the BIOS supports ACPI mode */
 
-	if (SYS_MODE_LEGACY == acpi_hw_get_mode_capabilities()) {
+	if (SYS_MODE_LEGACY == acpi_hw_get_mode_capabilities())	/* Make sure the BIOS supports ACPI mode */
 		return (AE_ERROR);
-	}
-
 
 	acpi_gbl_original_mode = acpi_hw_get_mode();
 
@@ -77,38 +69,18 @@
 	 * before handers are installed.
 	 */
 
-	status = acpi_ev_fixed_event_initialize ();
-	if (ACPI_FAILURE (status)) {
+	if (ACPI_FAILURE (status = acpi_ev_fixed_event_initialize ()))
 		return (status);
-	}
-
-	status = acpi_ev_gpe_initialize ();
-	if (ACPI_FAILURE (status)) {
+	if (ACPI_FAILURE (status = acpi_ev_gpe_initialize ()))
 		return (status);
-	}
-
-	/* Install the SCI handler */
-
-	status = acpi_ev_install_sci_handler ();
-	if (ACPI_FAILURE (status)) {
+	if (ACPI_FAILURE (status = acpi_ev_install_sci_handler ()))
 		return (status);
-	}
-
-
 	/* Install handlers for control method GPE handlers (_Lxx, _Exx) */
-
-	status = acpi_ev_init_gpe_control_methods ();
-	if (ACPI_FAILURE (status)) {
+	if (ACPI_FAILURE (status = acpi_ev_init_gpe_control_methods ()))
 		return (status);
-	}
-
 	/* Install the handler for the Global Lock */
-
-	status = acpi_ev_init_global_lock_handler ();
-	if (ACPI_FAILURE (status)) {
+	if (ACPI_FAILURE (status = acpi_ev_init_global_lock_handler ()))
 		return (status);
-	}
-
 
 	return (status);
 }
@@ -131,6 +103,7 @@
 {
 	int                     i = 0;
 
+	printk("acpi: Initializing fixed events\n");
 	/* Initialize the structure that keeps track of fixed event handlers */
 
 	for (i = 0; i < NUM_FIXED_EVENTS; i++) {
@@ -181,6 +154,7 @@
 	if ((status_register & ACPI_STATUS_PMTIMER) &&
 		(enable_register & ACPI_ENABLE_PMTIMER))
 	{
+		printk ("acpi: PM timer!\n");
 		int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_PMTIMER);
 	}
 
@@ -189,22 +163,27 @@
 	if ((status_register & ACPI_STATUS_GLOBAL) &&
 		(enable_register & ACPI_ENABLE_GLOBAL))
 	{
+		printk ("acpi: BIOS wants to play!\n");
 		int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_GLOBAL);
 	}
 
 	/* power button event */
 
 	if ((status_register & ACPI_STATUS_POWER_BUTTON) &&
-		(enable_register & ACPI_ENABLE_POWER_BUTTON))
+	    (enable_register & ACPI_ENABLE_POWER_BUTTON))
 	{
+		printk ("acpi: Power button pressed!\n");
+		kill_proc (1, SIGTERM, 1);
 		int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_POWER_BUTTON);
 	}
 
+
 	/* sleep button event */
 
 	if ((status_register & ACPI_STATUS_SLEEP_BUTTON) &&
 		(enable_register & ACPI_ENABLE_SLEEP_BUTTON))
 	{
+		printk("acpi: Sleep button pressed!\n");
 		int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_SLEEP_BUTTON);
 	}
 
diff -ur -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkeymap.c -x uni_hash.tbl -x zImage -x vmlinu?* -x TAGS -x bootsect -x *RCS* -x conmakehash -x map -x build -x build -x configure -x *target* -x *.flags -x *.bak clean/drivers/acpi/hardware/hwsleep.c linux/drivers/acpi/hardware/hwsleep.c
--- clean/drivers/acpi/hardware/hwsleep.c	Sun Apr  1 00:22:57 2001
+++ linux/drivers/acpi/hardware/hwsleep.c	Wed Apr  4 00:11:19 2001
@@ -27,6 +27,7 @@
 #include "acpi.h"
 #include "acnamesp.h"
 #include "achware.h"
+#include <linux/delay.h>
 
 #define _COMPONENT          HARDWARE
 	 MODULE_NAME         ("hwsleep")
@@ -50,7 +51,6 @@
 	ACPI_PHYSICAL_ADDRESS physical_address)
 {
 
-
 	/* Make sure that we have an FACS */
 
 	if (!acpi_gbl_FACS) {
@@ -59,6 +59,8 @@
 
 	/* Set the vector */
 
+	printk("Setting waking_vector to %lx\n", physical_address);
+
 	if (acpi_gbl_FACS->vector_width == 32) {
 		* (u32 *) acpi_gbl_FACS->firmware_waking_vector = (u32) physical_address;
 	}
@@ -112,6 +114,12 @@
 	return (AE_OK);
 }
 
+void
+while1(void)
+{
+	while(1);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    Acpi_enter_sleep_state
@@ -136,6 +144,13 @@
 	u16 PM1_acontrol;
 	u16 PM1_bcontrol;
 
+/*
+	acpi_set_firmware_waking_vector(0xffff0);
+*/
+	acpi_set_firmware_waking_vector(&while1 - 0xc0000000);
+
+	printk("Entering power state %d\n", sleep_state);
+
 	/*
 	 * _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
 	 */
@@ -175,14 +190,23 @@
 	PM1_acontrol |= (type_a << acpi_hw_get_bit_shift (SLP_TYPE_X_MASK));
 	PM1_bcontrol |= (type_b << acpi_hw_get_bit_shift (SLP_TYPE_X_MASK));
 
-	disable();
+	/*disable();*/
 
+	printk("hwsleep: Writing registers\n");
 	acpi_hw_register_write(ACPI_MTX_LOCK, PM1_a_CONTROL, PM1_acontrol);
 	acpi_hw_register_write(ACPI_MTX_LOCK, PM1_b_CONTROL, PM1_bcontrol);
+	printk("hwsleep: enabling sleep!\n");
 	acpi_hw_register_write(ACPI_MTX_LOCK, PM1_CONTROL,
 		(1 << acpi_hw_get_bit_shift (SLP_EN_MASK)));
+	printk("hwsleep: before enable\n");
 
-	enable();
+	/*enable();*/
+	printk("hwsleep: after enable\n");
 
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	acpi_evaluate_object(NULL, "\\_WAK", &arg_list, NULL);
+	printk("hwsleep: Waked up?\n");
+	mdelay(1000);
 	return (AE_OK);
 }
diff -ur -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkeymap.c -x uni_hash.tbl -x zImage -x vmlinu?* -x TAGS -x bootsect -x *RCS* -x conmakehash -x map -x build -x build -x configure -x *target* -x *.flags -x *.bak clean/drivers/acpi/namespace/nsxfobj.c linux/drivers/acpi/namespace/nsxfobj.c
--- clean/drivers/acpi/namespace/nsxfobj.c	Sun Apr  1 00:23:00 2001
+++ linux/drivers/acpi/namespace/nsxfobj.c	Tue Apr 10 00:19:01 2001
@@ -30,6 +30,10 @@
 #include "acnamesp.h"
 #include "acdispat.h"
 
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
 
 #define _COMPONENT          NAMESPACE
 	 MODULE_NAME         ("nsxfobj")
@@ -592,7 +596,7 @@
 
 	status = acpi_cm_execute_STA (node, &flags);
 	if (ACPI_FAILURE (status)) {
-		return (status);
+		return AE_OK;
 	}
 
 	if (!(flags & 0x01)) {
@@ -694,3 +698,203 @@
 
 	return (status);
 }
+
+static int
+proc_read_device_info(char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	ACPI_HANDLE             obj_handle = (u32) data;
+	ACPI_NAMESPACE_NODE     *node;
+	ACPI_STATUS		status;
+	char *p = page;
+	int len;
+	u32 flags;
+	DEVICE_ID               device_id;
+
+	/* don't get info more than once for a single proc read */
+	if (off != 0)
+		goto end;
+
+	acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+	node = acpi_ns_convert_handle_to_entry (obj_handle);
+
+	acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+	status = acpi_cm_execute_STA (node, &flags);
+	if (ACPI_FAILURE (status))
+		p += sprintf(p, "Present:	No (%lx)\n", status);
+	else	p += sprintf(p, "Present:	Yes (flags %lx)\n", flags);
+
+	status = acpi_cm_execute_HID (node, &device_id);
+	if (!ACPI_FAILURE (status))
+		p += sprintf(p, "HID ident:	%s\n", &device_id.buffer );
+
+	status = acpi_cm_execute_UID (node, &device_id);
+	if (!ACPI_FAILURE (status))
+		p += sprintf(p, "UID ident:	%s\n", &device_id.buffer );
+
+	flags = 0xdeadbeef;
+	status = acpi_cm_execute_rint (node, &flags, "_PSC");
+	if (!ACPI_FAILURE (status))
+		p += sprintf(p, "Power status:	%d\n", flags);
+
+	p += sprintf(p, "This is some random information\n");
+end:
+	len = (p - page);
+	if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+int
+proc_write_device_info(struct file *file, const char *buffer,
+		       unsigned long count, void *data)
+{
+	ACPI_HANDLE             obj_handle = (u32) data;
+	ACPI_NAMESPACE_NODE     *node;
+	ACPI_STATUS		status;
+	int len;
+	u32 flags;
+	char buf[256], buf2[256];
+	DEVICE_ID               device_id;
+
+	acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+	node = acpi_ns_convert_handle_to_entry (obj_handle);
+
+	acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+	if (count > 250)
+		return -EPERM;
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+	buf[count] = 0;
+	printk("acpi_write_device_info: %s...", buf);
+	flags = 0xdeadbeef;
+	status = acpi_cm_execute_any (node, buf2, buf);
+	if (ACPI_FAILURE (status))
+		printk("error: %lx (%s)\n", status, buf2);
+	else 
+		printk("okay: %lx (%s)\n", status, buf2);
+
+	return -EL3RST;
+}
+
+
+static ACPI_STATUS
+acpi_ns_add_proc_callback (
+	ACPI_HANDLE             obj_handle,
+	u32                     nesting_level,
+	void                    *context,
+	void                    **return_value)
+{
+	ACPI_STATUS             status;
+	ACPI_NAMESPACE_NODE     *node;
+	u32                     flags;
+	DEVICE_ID               device_id;
+	ACPI_GET_DEVICES_INFO   *info;
+
+
+	info = context;
+
+	acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+	printk("acpi_add_proc_callback: %lx\n", obj_handle);
+	node = acpi_ns_convert_handle_to_entry (obj_handle);
+
+	acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+	if (!node) {
+		printk("No node?!\n");
+		return (AE_BAD_PARAMETER);
+	}
+
+	/*
+	 * Run _STA to determine if device is present
+	 */
+
+#if 0
+	status = acpi_cm_execute_STA (node, &flags);
+	if (ACPI_FAILURE (status)) {
+		return (AE_OK);
+	}
+
+	if (!(flags & 0x01)) {
+		/* don't return at the device or children of the device if not there */
+
+		return (AE_CTRL_DEPTH);
+	}
+#endif
+
+	{
+		char proc_name[120];
+		struct proc_dir_entry *proc;
+
+		status = acpi_cm_execute_HID (node, &device_id);
+
+		if ((status == AE_NOT_FOUND) || (ACPI_FAILURE (status)))
+			sprintf(proc_name, "power/device_unknown_%lx", obj_handle);
+		else	sprintf(proc_name, "power/device_%s", device_id.buffer );
+		printk("ACPI: creating %s\n", proc_name);
+		proc = create_proc_read_entry(proc_name, 0, NULL,
+			proc_read_device_info, (void *) obj_handle);
+		if (!proc) printk(KERN_ERR "ACPI: Error creating %s\n", proc_name);
+		else {
+			proc->write_proc = proc_write_device_info;
+		}
+	}
+
+	return (AE_OK);
+}
+
+
+void
+acpi_namespace_init(
+	void)
+{
+	ACPI_STATUS             status;
+	void ** return_value;
+
+	printk("ACPI: initializing namespace\n");
+
+	acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+	status = acpi_ns_walk_namespace (ACPI_TYPE_ANY,
+			   ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+			   NS_WALK_UNLOCK,
+			   acpi_ns_add_proc_callback, NULL,
+			   return_value);
+
+	acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+	return (status);
+}
+
+/*
+   _PSW -> lid does something interesting (unknown status).
+   _PSC -> PNP0303  (type error)
+   _LID -> lid does get lid status.
+   _ADR -> succeeds on many things
+   _CRS -> sometimes okay
+   _DIS -> 3 times okay
+   _EJ0 -> 1 time okay
+   _HID -> mostly returns integers
+   _PCL -> 2 times okay
+   _PRS -> 2 times okay
+   _PR[W0] -> 4 times okay
+   _PR1 -> okay once
+   _PSC -> 8 times okay
+   _PS3 -> 8 times okay, and seems to work
+   _PS2 -> okay once
+   _PS0 -> 8 times okay
+   _STA -> many times okay
+   _SRS -> error 3008
+   _UID -> many times okay.
+   _BST -> PNP0C0A battery status
+   _STM -> error 3008, sometimes (IDE set transfer timings)
+
+   
+*/
diff -ur -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkeymap.c -x uni_hash.tbl -x zImage -x vmlinu?* -x TAGS -x bootsect -x *RCS* -x conmakehash -x map -x build -x build -x configure -x *target* -x *.flags -x *.bak clean/drivers/acpi/power.c linux/drivers/acpi/power.c
--- clean/drivers/acpi/power.c	Wed Jan 31 16:14:33 2001
+++ linux/drivers/acpi/power.c	Thu Apr  5 00:51:28 2001
@@ -118,6 +118,7 @@
 	}
 
 	acpi_cmbatt_init();
+	acpi_namespace_init();
 
 	return 0;
 }
diff -ur -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm -x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkeymap.c -x uni_hash.tbl -x zImage -x vmlinu?* -x TAGS -x bootsect -x *RCS* -x conmakehash -x map -x build -x build -x configure -x *target* -x *.flags -x *.bak clean/drivers/acpi/sys.c linux/drivers/acpi/sys.c
--- clean/drivers/acpi/sys.c	Wed Jan 31 16:14:33 2001
+++ linux/drivers/acpi/sys.c	Thu Apr  5 00:51:17 2001
@@ -79,11 +79,12 @@
 /*
  * Enter soft-off (S5)
  */
-static void
+void
 acpi_power_off(void)
 {
 	struct acpi_enter_sx_ctx ctx;
 	
+	printk("Entering power off\n");
 	init_waitqueue_head(&ctx.wait);
 	ctx.state = ACPI_STATE_S5;
 	acpi_enter_sx_async(&ctx);
-- I'm pavel@ucw.cz. "In my country we have almost anarchy and I don't care." Panos Katsaloulis describing me w.r.t. patents at discuss@linmodems.org - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/