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/