Re: [ACPI-sppt] Compaq Armada m300 resume problem #1

Yotzo <[email protected]> Sun, 26 Oct 2003 21:40:34 +0100
Newsgroups gmane.linux.acpi.support
Message-ID <[email protected]>
--vGgW1X5XWziG23Ko
Content-Type: text/plain; charset=iso-8859-2
Content-Disposition: inline

Some addition, that might be help some others too:

As [email protected] wrote on acpi-bugzilla mailing list

---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<-

this patch will create a proc entry called "/proc/acpi/wakeup_devices"

cat /proc/acpi/wakeup_devices will show all possible wake capable devices

echo devicename > /proc/acpi/wakeup_devices  will enable the device to
wakeup machine from sleeping state

call echo devicename > /proc/acpi/wakeup_devices again will disable 
the device's wakeup capablility.

---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<-

With this patch, I saw that my sleep buton would only wake up from sleep 
state 4.

---8<---8<---8<---8<---8<---8<---8<--
Device  Speep state     Status
C005       3            disabled
C0AF       3            disabled
C14A       1            disabled
C056       4            disabled
C169       4            disabled
---8<---8<---8<---8<---8<---8<---8<--

 I know nothing about dsdt programming, but made a try with iasl to
decompile dsdt, and found a 0x04 string near the C056 string, that is
my sleep button. I changed it to 0x03, do the same with the lid switch,
compiled the source, patched the kernel, and included the hex file,
rebooted, and now I can wake up the system wih only opening the lid, 
which is beutiful.

After resume, tThe NIC finds itself...
1. The keyboard and the mouse doesn't work.
    I can ssh to the machine, make a /etc/init.d/gdm restart, and the
    keyboard works again. Mouse still unusable, even in console and X.
    I ried tpconfig -x and removing, inserting psmouse and eventd, but 
    nothing happened.

2. If I understand, the clock doesn't updated. There were about 3 
    minutes between suspend and resume...

---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<-

Oct 26 16:25:04 m300 kernel: PM: Preparing system for suspend
Oct 26 16:25:04 m300 kernel: Stopping tasks: 
============================================|
Oct 26 16:25:04 m300 kernel: [ACPI Debug] String: Enable Sleep button to wake up the system
Oct 26 16:25:04 m300 kernel: [ACPI Debug] String: _PTS:  Enter
Oct 26 16:25:04 m300 kernel: [ACPI Debug] Integer: 0000000000000003
Oct 26 16:25:04 m300 kernel: [ACPI Debug] String: Going into Suspend to RAM State
Oct 26 16:25:04 m300 kernel: [ACPI Debug] String: _PTS:  Exit
Oct 26 16:25:04 m300 kernel: hdc: start_power_step(step: 0)
Oct 26 16:25:04 m300 kernel: hdc: completing PM request, suspend
Oct 26 16:25:04 m300 kernel: hda: start_power_step(step: 0)
Oct 26 16:25:04 m300 kernel: hda: start_power_step(step: 1)
Oct 26 16:25:04 m300 kernel: hda: complete_power_step(step: 1, stat: 50, err: 0)
Oct 26 16:25:04 m300 kernel: hda: completing PM request, suspend
Oct 26 16:25:04 m300 kernel: PM: Entering state.
Oct 26 16:25:04 m300 kernel:  hwsleep-0257 [46] acpi_enter_sleep_state: Entering sleep state [S3]
Oct 26 16:25:04 m300 kernel: Back to C!
Oct 26 16:25:04 m300 kernel: PM: Finishing up.
Oct 26 16:25:04 m300 kernel: hda: Wakeup request inited, waiting for !BSY...
Oct 26 16:25:04 m300 kernel: hda: start_power_step(step: 1000)
Oct 26 16:25:04 m300 kernel: blk: queue cbc78600, I/O limit 4095Mb (mask 0xffffffff)
Oct 26 16:25:04 m300 kernel: hda: completing PM request, resume
Oct 26 16:25:04 m300 kernel: hdc: Wakeup request inited, waiting for !BSY...
Oct 26 16:25:04 m300 kernel: hdc: start_power_step(step: 1000)
Oct 26 16:25:04 m300 kernel: hdc: completing PM request, resume
Oct 26 16:25:04 m300 kernel: [ACPI Debug] String: _WAK:  Enter
Oct 26 16:25:04 m300 kernel: [ACPI Debug] Integer: 0000000000000003
Oct 26 16:25:04 m300 kernel: [ACPI Debug] String: _WAK:  Exit
Oct 26 16:25:04 m300 kernel: Restarting tasks... done
Oct 26 16:25:06 m300 kernel: e100: eth0 NIC Link is Up 10 Mbps Half duplex

---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<-

3. Poweroff, sleep and lid switch buttons stops working
    While works with just a simple boot, after suspend/resume they stops.

If someone could help me, or give any tip how to go on, please do.

Thanks, Yotzo

--vGgW1X5XWziG23Ko
Content-Type: text/plain; charset=iso-8859-2
Content-Disposition: attachment; filename="wakeup-devices.diff"

diff -Nur linux-2.6.0-test7/drivers/acpi/power.c linux-2.6.0-test7.new/drivers/acpi/power.c
--- linux-2.6.0-test7/drivers/acpi/power.c	2003-10-09 03:24:06.000000000 +0800
+++ linux-2.6.0-test7.new/drivers/acpi/power.c	2003-10-24 23:39:40.800350720 +0800
@@ -176,7 +176,7 @@
 }
 
 
-static int
+int
 acpi_power_on (
 	acpi_handle		handle)
 {
@@ -193,7 +193,7 @@
 
 	resource->references++;
 
-	if ((resource->references > 1) 
+	if ((resource->references > 1)
 		|| (resource->state == ACPI_POWER_RESOURCE_STATE_ON)) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already on\n",
 			resource->name));
@@ -223,7 +223,7 @@
 }
 
 
-static int
+int
 acpi_power_off_device (
 	acpi_handle		handle)
 {
diff -Nur linux-2.6.0-test7/drivers/acpi/scan.c linux-2.6.0-test7.new/drivers/acpi/scan.c
--- linux-2.6.0-test7/drivers/acpi/scan.c	2003-10-09 03:24:04.000000000 +0800
+++ linux-2.6.0-test7.new/drivers/acpi/scan.c	2003-10-24 23:39:40.803350264 +0800
@@ -23,6 +23,7 @@
 #define ACPI_BUS_DEVICE_NAME		"System Bus"
 
 static LIST_HEAD(acpi_device_list);
+LIST_HEAD(acpi_wakeup_device_list);
 static spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED;
 
 static void acpi_device_release(struct kobject * kobj)
@@ -45,7 +46,6 @@
 	.ktype	= &ktype_acpi_ns,
 };
 
-
 static void acpi_device_register(struct acpi_device * device, struct acpi_device * parent)
 {
 	/*
@@ -115,9 +115,6 @@
 	status = acpi_get_handle(device->handle, "_IRC", &handle);
 	if (ACPI_SUCCESS(status))
 		device->power.flags.inrush_current = 1;
-	status = acpi_get_handle(device->handle, "_PRW", &handle);
-	if (ACPI_SUCCESS(status))
-		device->power.flags.wake_capable = 1;
 
 	/*
 	 * Enumerate supported power management states
@@ -163,7 +160,83 @@
 	return 0;
 }
 
+static acpi_status
+acpi_bus_extract_wakeup_device_power_package (
+	struct acpi_device	*device,
+	union acpi_object	*package)
+{
+	int 	 i = 0;
+	union acpi_object	*element = NULL;
+
+	if (!device || !package || (package->package.count < 2))
+		return AE_BAD_PARAMETER;
+
+	element = &(package->package.elements[0]);
+	if (element->type != ACPI_TYPE_INTEGER) {
+		/* TBD: support this feature*/
+		return AE_BAD_DATA;
+	}
+	device->wakeup_power.gpe = element->integer.value;
+
+	element = &(package->package.elements[1]);
+	if (element->type != ACPI_TYPE_INTEGER) {
+		return AE_BAD_DATA;
+	}
+	device->wakeup_power.sleep_state = element->integer.value;
+
+	if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
+		return AE_NO_MEMORY;
+	}
+	device->wakeup_power.resources.count = package->package.count - 2;
+	for (i=0; i < device->wakeup_power.resources.count; i++) {
+		element = &(package->package.elements[i + 2]);
+		if (element->type != ACPI_TYPE_ANY ) {
+			return AE_BAD_DATA;
+		}
+
+		device->wakeup_power.resources.handles[i] = element->reference.handle;
+	}
+
+	return AE_OK;
+}
+
+static int
+acpi_bus_get_wakeup_device_flags (
+	struct acpi_device	*device)
+{
+	acpi_status	status = 0;
+	struct acpi_buffer	buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	union acpi_object	*package = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_get_wakeup_flags");
 
+	/* _PRW */
+	status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRW\n"));
+		goto end;
+	}
+
+	package = (union acpi_object *) buffer.pointer;
+	status = acpi_bus_extract_wakeup_device_power_package(device, package);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _PRW package\n"));
+		goto end;
+	}
+
+	acpi_os_free(buffer.pointer);
+
+	/*TBD: if exist PSW*/
+
+	/* TBD: lock */
+	INIT_LIST_HEAD(&device->wakeup_list);
+	list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
+
+end:
+	if (ACPI_FAILURE(status))
+		device->flags.wake_capable = 0;
+	return 0;
+}
 /* --------------------------------------------------------------------------
                               Performance Management
    -------------------------------------------------------------------------- */
@@ -464,6 +537,11 @@
 	if (ACPI_SUCCESS(status))
 		device->flags.power_manageable = 1;
 
+	/* Presence of _PRW indicates wake capable */
+	status = acpi_get_handle(device->handle, "_PRW", &temp);
+	if (ACPI_SUCCESS(status))
+		device->flags.wake_capable = 1;
+
 	/* TBD: Peformance management */
 
 	return_VALUE(0);
@@ -736,6 +814,16 @@
 	}
 
 	/*
+	*Wakeup device management
+	*-----------------------
+	*/
+	if (device->flags.wake_capable) {
+		result = acpi_bus_get_wakeup_device_flags(device);
+		if (result)
+			goto end;
+	}
+
+	/*
 	 * Performance Management
 	 * ----------------------
 	 */
diff -Nur linux-2.6.0-test7/drivers/acpi/sleep/main.c linux-2.6.0-test7.new/drivers/acpi/sleep/main.c
--- linux-2.6.0-test7/drivers/acpi/sleep/main.c	2003-10-09 03:24:00.000000000 +0800
+++ linux-2.6.0-test7.new/drivers/acpi/sleep/main.c	2003-10-24 23:39:40.804350112 +0800
@@ -56,6 +56,9 @@
 			(acpi_physical_address) acpi_wakeup_address);
 	}
 	ACPI_FLUSH_CPU_CACHE();
+	
+	/* change a position for the function? */
+	acpi_enable_wakeup_device_prep(acpi_state);
 	acpi_enter_sleep_state_prep(acpi_state);
 	return 0;
 }
@@ -87,6 +90,9 @@
 
 
 	local_irq_save(flags);
+	/* change a position for the function? */
+	acpi_enable_wakeup_device(acpi_state);
+
 	switch (state)
 	{
 	case PM_SUSPEND_STANDBY:
@@ -133,7 +139,10 @@
 
 static int acpi_pm_finish(u32 state)
 {
-	acpi_leave_sleep_state(state);
+	u32 acpi_state = acpi_suspend_states[state];
+
+	acpi_leave_sleep_state(acpi_state);
+	acpi_disable_wakeup_device_power(acpi_state);
 
 	/* reset firmware waking vector */
 	acpi_set_firmware_waking_vector((acpi_physical_address) 0);
diff -Nur linux-2.6.0-test7/drivers/acpi/sleep/Makefile linux-2.6.0-test7.new/drivers/acpi/sleep/Makefile
--- linux-2.6.0-test7/drivers/acpi/sleep/Makefile	2003-10-09 03:24:27.000000000 +0800
+++ linux-2.6.0-test7.new/drivers/acpi/sleep/Makefile	2003-10-24 23:39:40.805349960 +0800
@@ -1,5 +1,5 @@
 obj-y					:= poweroff.o
-obj-$(CONFIG_ACPI_SLEEP)		+= main.o
+obj-$(CONFIG_ACPI_SLEEP)		+= main.o wakeup.o
 obj-$(CONFIG_ACPI_SLEEP_PROC_FS)	+= proc.o
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff -Nur linux-2.6.0-test7/drivers/acpi/sleep/proc.c linux-2.6.0-test7.new/drivers/acpi/sleep/proc.c
--- linux-2.6.0-test7/drivers/acpi/sleep/proc.c	2003-10-09 03:24:17.000000000 +0800
+++ linux-2.6.0-test7.new/drivers/acpi/sleep/proc.c	2003-10-24 23:39:40.806349808 +0800
@@ -15,6 +15,7 @@
 
 #define ACPI_SYSTEM_FILE_SLEEP		"sleep"
 #define ACPI_SYSTEM_FILE_ALARM		"alarm"
+#define ACPI_SYSTEM_FILE_WAKEUP_DEVICE	"wakeup_devices"
 
 #define _COMPONENT		ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME		("sleep")
@@ -352,6 +353,65 @@
 	return_VALUE(result ? result : count);
 }
 
+extern struct list_head	acpi_wakeup_device_list;
+static int
+acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
+{
+	struct list_head * node, * next;
+
+	seq_printf(seq, "Device	Speep state	Status\n");
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
+
+		seq_printf(seq, "%4s	%4d		%8s\n",
+			dev->pnp.bus_id, (u32) dev->wakeup_power.sleep_state,
+			dev->wakeup_power.state ? "enabled" : "disabled");
+	}
+	return 0;
+}
+
+static int
+acpi_system_write_wakeup_device (
+	struct file		*file,
+	const char		*buffer,
+	size_t			count,
+	loff_t			*ppos)
+{
+	struct list_head * node, * next;
+	char		strbuf[5];
+	char		str[5] = "";
+	int 		len = count;
+
+	if (len > 4) len = 4;
+
+	if (copy_from_user(strbuf, buffer, len))
+		return -EFAULT;
+	strbuf[len] = '\0';
+	sscanf(strbuf, "%s", str);
+
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
+
+		if (!strncmp(dev->pnp.bus_id, str, 4)) {
+			dev->wakeup_power.state = dev->wakeup_power.state ? 0 : 1;
+		}
+	}
+	return count;
+}
+
+static int
+acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_system_wakeup_device_seq_show, PDE(inode)->data);
+}
+
+static struct file_operations acpi_system_wakeup_device_fops = {
+	.open		= acpi_system_wakeup_device_open_fs,
+	.read		= seq_read,
+	.write		= acpi_system_write_wakeup_device,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
 
 static struct file_operations acpi_system_sleep_fops = {
 	.open		= acpi_system_sleep_open_fs,
@@ -385,6 +445,13 @@
 		S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
 	if (entry)
 		entry->proc_fops = &acpi_system_alarm_fops;
+
+	/* 'wakeup device' [R/W]*/
+	entry = create_proc_entry(ACPI_SYSTEM_FILE_WAKEUP_DEVICE,
+				  S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
+	if (entry)
+		entry->proc_fops = &acpi_system_wakeup_device_fops;
+
 	return 0;
 }
 
diff -Nur linux-2.6.0-test7/drivers/acpi/sleep/sleep.h linux-2.6.0-test7.new/drivers/acpi/sleep/sleep.h
--- linux-2.6.0-test7/drivers/acpi/sleep/sleep.h	2003-10-09 03:24:26.000000000 +0800
+++ linux-2.6.0-test7.new/drivers/acpi/sleep/sleep.h	2003-10-24 23:39:40.807349656 +0800
@@ -1,4 +1,7 @@
 
 extern u8 sleep_states[];
 extern int acpi_suspend (u32 state);
+void acpi_enable_wakeup_device_prep(u8 sleep_state);
+void acpi_enable_wakeup_device(u8 sleep_state);
+void acpi_disable_wakeup_device_power (u8 sleep_state);
 
diff -Nur linux-2.6.0-test7/drivers/acpi/sleep/wakeup.c linux-2.6.0-test7.new/drivers/acpi/sleep/wakeup.c
--- linux-2.6.0-test7/drivers/acpi/sleep/wakeup.c	1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.0-test7.new/drivers/acpi/sleep/wakeup.c	2003-10-24 23:42:13.590123144 +0800
@@ -0,0 +1,113 @@
+/*
+* wakeup.c - support wakeup devices
+*/
+
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <acpi/acevents.h>
+
+#define _COMPONENT		ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME		("wakeup_devices")
+
+/*
+* acpi_enable_wakeup_device_prep
+*/
+extern struct list_head	acpi_wakeup_device_list;
+extern int acpi_power_on (acpi_handle	handle);
+extern int acpi_power_off_device (acpi_handle	handle);
+
+void
+acpi_enable_wakeup_device_prep(
+	u8		sleep_state)
+{
+	struct list_head * node, * next;
+	union acpi_object 		arg = {ACPI_TYPE_INTEGER};
+	struct acpi_object_list	arg_list = {1, &arg};
+	acpi_status			status = AE_OK;
+	int					i;
+	int 					ret = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_prep");
+	arg.integer.value = 1;
+
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
+
+		if (dev->wakeup_power.state && (sleep_state >= dev->wakeup_power.sleep_state)) {
+			/* Open power resource */
+			for (i = 0; i < dev->wakeup_power.resources.count; i++) {
+				ret = acpi_power_on(dev->wakeup_power.resources.handles[i]);
+				if (ret) {
+					/* TBD: reverse changes */
+					ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error transition power state\n"));
+					dev->wakeup_power.state = 0;
+					continue;
+				}
+			}
+
+			/* Execute PSW */
+			status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
+			if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
+				/* TBD; reverse changes */
+				ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n"));
+				dev->wakeup_power.state = 0;
+				continue;
+			}
+		}
+	}
+}
+
+/*
+* acpi_enable_wakeup_device
+*/
+void
+acpi_enable_wakeup_device(
+	u8		sleep_state)
+{
+	struct list_head * node, * next;
+	struct acpi_gpe_event_info * gpe_info = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device");
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
+
+		if (dev->wakeup_power.state && (sleep_state >= dev->wakeup_power.sleep_state)) {
+			/* TBD: support GPE block device */
+			gpe_info = acpi_ev_get_gpe_event_info(NULL, (u32) dev->wakeup_power.gpe);
+			if (!gpe_info) {
+				ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error GPE info\n"));
+				continue;
+			}
+			acpi_hw_enable_gpe_for_wakeup(gpe_info);
+		}
+	}
+}
+
+/*
+* acpi_disable_wakeup_device_power
+*/
+void
+acpi_disable_wakeup_device_power (
+	u8		sleep_state)
+{
+	/* need we change power state? */
+}
+
+static int __init acpi_wakeup_device_init()
+{
+	struct list_head * node, * next;
+
+	printk("Wake capable device:");
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
+
+		printk(" %4s", dev->pnp.bus_id);
+	}
+	printk("\n");
+
+	return 0;
+}
+
+late_initcall(acpi_wakeup_device_init);
diff -Nur linux-2.6.0-test7/include/acpi/acpi_bus.h linux-2.6.0-test7.new/include/acpi/acpi_bus.h
--- linux-2.6.0-test7/include/acpi/acpi_bus.h	2003-10-09 03:24:04.000000000 +0800
+++ linux-2.6.0-test7.new/include/acpi/acpi_bus.h	2003-10-24 23:39:40.810349200 +0800
@@ -159,7 +159,8 @@
 	u32			suprise_removal_ok:1;
 	u32			power_manageable:1;
 	u32			performance_manageable:1;
-	u32			reserved:21;
+	u32			wake_capable:1;	
+	u32			reserved:20;
 };
 
 
@@ -205,10 +206,8 @@
 	u32			explicit_get:1;		     /* _PSC present? */
 	u32			power_resources:1;	   /* Power resources */
 	u32			inrush_current:1;	  /* Serialize Dx->D0 */
-	u32			wake_capable:1;		 /* Wakeup supported? */
-	u32			wake_enabled:1;		/* Enabled for wakeup */
 	u32			power_removed:1;	   /* Optimize Dx->D0 */
-	u32			reserved:26;
+	u32			reserved:28;
 };
 
 struct acpi_device_power_state {
@@ -228,6 +227,14 @@
 	struct acpi_device_power_state states[4];     /* Power states (D0-D3) */
 };
 
+/* Wakeup Management */
+
+struct acpi_wakeup_power {
+	acpi_integer		gpe;
+	int			state;
+	acpi_integer		sleep_state;
+	struct acpi_handle_list	resources;
+};
 
 /* Performance Management */
 
@@ -261,10 +268,12 @@
 	struct list_head	children;
 	struct list_head	node;
 	struct list_head	g_list;
+	struct list_head	wakeup_list;
 	struct acpi_device_status status;
 	struct acpi_device_flags flags;
 	struct acpi_device_pnp	pnp;
 	struct acpi_device_power power;
+	struct acpi_wakeup_power wakeup_power;
 	struct acpi_device_perf	performance;
 	struct acpi_device_dir	dir;
 	struct acpi_device_ops	ops;

--vGgW1X5XWziG23Ko--


-------------------------------------------------------
This SF.net email is sponsored by: The SF.net Donation Program.
Do you like what SourceForge.net is doing for the Open
Source Community?  Make a contribution, and help us add new
features and functionality. Click here: http://sourceforge.net/donate/