Module Name:    src
Committed By:   jruoho
Date:           Sat Jun  5 15:31:22 UTC 2010

Modified Files:
        src/sys/dev/acpi: acpi_wakedev.c

Log Message:
Complete the support for wakeup devices. As imposed by the standard, all
power resources should be turned on for wakeup devices. This follows common
sense: a device cannot wake if the power of it is turned off.

ok jmcneill@


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/acpi/acpi_wakedev.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/acpi/acpi_wakedev.c
diff -u src/sys/dev/acpi/acpi_wakedev.c:1.12 src/sys/dev/acpi/acpi_wakedev.c:1.13
--- src/sys/dev/acpi/acpi_wakedev.c:1.12	Sun Apr 18 14:05:26 2010
+++ src/sys/dev/acpi/acpi_wakedev.c	Sat Jun  5 15:31:21 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_wakedev.c,v 1.12 2010/04/18 14:05:26 jruoho Exp $ */
+/* $NetBSD: acpi_wakedev.c,v 1.13 2010/06/05 15:31:21 jruoho Exp $ */
 
 /*-
  * Copyright (c) 2009, 2010 Jared D. McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_wakedev.c,v 1.12 2010/04/18 14:05:26 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_wakedev.c,v 1.13 2010/06/05 15:31:21 jruoho Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -36,10 +36,11 @@
 
 #include <dev/acpi/acpireg.h>
 #include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpi_power.h>
 #include <dev/acpi/acpi_wakedev.h>
 
-#define _COMPONENT		   ACPI_BUS_COMPONENT
-ACPI_MODULE_NAME		   ("acpi_wakedev")
+#define _COMPONENT		ACPI_BUS_COMPONENT
+ACPI_MODULE_NAME		("acpi_wakedev")
 
 static const char * const acpi_wakedev_default[] = {
 	"PNP0C0C",	/* power button */
@@ -51,8 +52,9 @@
 
 static const struct sysctlnode *rnode = NULL;
 
-static void	acpi_wakedev_prepare(struct acpi_devnode *, int, int);
-static void	acpi_wakedev_gpe(struct acpi_devnode *, int);
+static void	acpi_wakedev_method(struct acpi_devnode *, int, int);
+static void	acpi_wakedev_gpe(struct acpi_devnode *, int, int);
+static void	acpi_wakedev_power(ACPI_OBJECT *);
 
 SYSCTL_SETUP(sysctl_acpi_wakedev_setup, "sysctl hw.acpi.wake subtree setup")
 {
@@ -121,27 +123,26 @@
 	struct acpi_devnode *ad;
 
 	/*
-	 * As noted in ACPI 3.0 (p. 243), preparing
-	 * a device for wakeup is a two-step process:
+	 * To prepare a device for wakeup:
 	 *
-	 *  1.	Enable all power resources in _PRW.
+	 *  1.	Set appropriate GPEs.
 	 *
-	 *  2.	If present, execute _DSW/_PSW method.
+	 *  2.	Enable all power resources in _PRW.
 	 *
-	 * XXX: The first one is yet to be implemented.
+	 *  3.	If present, execute _DSW/_PSW method.
 	 */
 	SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) {
 
 		if ((ad->ad_flags & ACPI_DEVICE_WAKEUP) == 0)
 			continue;
 
-		acpi_wakedev_gpe(ad, ad->ad_wake);
-		acpi_wakedev_prepare(ad, ad->ad_wake, state);
+		acpi_wakedev_gpe(ad, ad->ad_wake, state);
+		acpi_wakedev_method(ad, ad->ad_wake, state);
 	}
 }
 
 static void
-acpi_wakedev_prepare(struct acpi_devnode *ad, int enable, int state)
+acpi_wakedev_method(struct acpi_devnode *ad, int enable, int state)
 {
 	ACPI_OBJECT_LIST arg;
 	ACPI_OBJECT obj[3];
@@ -194,9 +195,10 @@
 }
 
 static void
-acpi_wakedev_gpe(struct acpi_devnode *ad, int enable)
+acpi_wakedev_gpe(struct acpi_devnode *ad, int enable, int state)
 {
 	ACPI_OBJECT *elm, *obj;
+	ACPI_HANDLE hdl = NULL;
 	ACPI_INTEGER val;
 	ACPI_BUFFER buf;
 	ACPI_STATUS rv;
@@ -237,6 +239,7 @@
 		if (elm->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
 			goto out;
 
+		hdl = elm->Package.Elements[0].Reference.Handle;
 		val = elm->Package.Elements[1].Integer.Value;
 		break;
 
@@ -244,14 +247,35 @@
 		goto out;
 	}
 
+ 	/*
+	 * The second element is an integer that contains the
+	 * lowest sleep state that can be entered while still
+	 * providing wake-up functionality. The rest of the
+	 * elements are references to power resources.
+	 */
+	elm = &obj->Package.Elements[1];
+
+	if (elm->Type != ACPI_TYPE_INTEGER)
+		goto out;
+
+	if (state > elm->Integer.Value)
+		aprint_error_dev(ad->ad_root, "sleep state S%d "
+		    "loses wake for %s\n", state, ad->ad_name);
+
+	/*
+	 * Turn on power resources.
+	 */
+	if (enable != 0)
+		acpi_wakedev_power(obj);
+
 	/*
 	 * Set or unset a GPE as both runtime and wake.
 	 */
 	if (enable == 0)
-		(void)AcpiDisableGpe(NULL, val, ACPI_NOT_ISR);
+		(void)AcpiDisableGpe(hdl, val, ACPI_NOT_ISR);
 	else {
-		(void)AcpiSetGpeType(NULL, val, ACPI_GPE_TYPE_WAKE_RUN);
-		(void)AcpiEnableGpe(NULL, val, ACPI_NOT_ISR);
+		(void)AcpiSetGpeType(hdl, val, ACPI_GPE_TYPE_WAKE_RUN);
+		(void)AcpiEnableGpe(hdl, val, ACPI_NOT_ISR);
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "wake GPE %s for %s\n",
@@ -260,3 +284,28 @@
 out:
 	ACPI_FREE(buf.Pointer);
 }
+
+static void
+acpi_wakedev_power(ACPI_OBJECT *obj)
+{
+	ACPI_OBJECT *elm;
+	ACPI_HANDLE hdl;
+	ACPI_STATUS rv;
+	uint32_t i, n;
+
+	n = obj->Package.Count;
+
+	if (n < 3)
+		return;
+
+	for (i = 2; i < n; i++) {
+
+		elm = &obj->Package.Elements[i];
+		rv = acpi_eval_reference_handle(elm, &hdl);
+
+		if (ACPI_FAILURE(rv))
+			continue;
+
+		(void)acpi_power_set_from_handle(hdl, ACPI_STATE_D0);
+	}
+}

Reply via email to