From owner-acpi-jp@jp.freebsd.org  Mon Sep 18 13:32:31 2000
Received: (from daemon@localhost)
	by castle.jp.freebsd.org (8.9.3+3.2W/8.7.3) id NAA38220;
	Mon, 18 Sep 2000 13:32:31 +0900 (JST)
	(envelope-from owner-acpi-jp@jp.FreeBSD.org)
Received: from tasogare.imasy.or.jp (daemon@tasogare.imasy.or.jp [202.227.24.5])
	by castle.jp.freebsd.org (8.9.3+3.2W/8.7.3) with ESMTP id NAA38215
	for <acpi-jp@jp.freebsd.org>; Mon, 18 Sep 2000 13:32:30 +0900 (JST)
	(envelope-from iwasaki@jp.FreeBSD.org)
Received: from localhost (iwasaki.imasy.or.jp [202.227.24.92])
	by tasogare.imasy.or.jp (8.10.2+3.3W/3.7W-tasogare/smtpfeed 1.07) with ESMTP id e8I4WQr31268
	for <acpi-jp@jp.freebsd.org>; Mon, 18 Sep 2000 13:32:26 +0900 (JST)
	(envelope-from iwasaki@jp.FreeBSD.org)
To: acpi-jp@jp.freebsd.org
In-Reply-To: <20000917003359R.iwasaki@jp.FreeBSD.org>
References: <200009161000.TAA08374@libr.scitec.kobe-u.ac.jp>
	<20000814181553D.iwasaki@jp.FreeBSD.org>
	<20000917003359R.iwasaki@jp.FreeBSD.org>
X-Mailer: Mew version 1.94.1 on Emacs 19.34 / Mule 2.3 (SUETSUMUHANA)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=iso-2022-jp
Content-Transfer-Encoding: 7bit
Message-Id: <20000918133211O.iwasaki@jp.FreeBSD.org>
Date: Mon, 18 Sep 2000 13:32:11 +0900
From: Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
X-Dispatcher: imput version 20000228(IM140)
Lines: 790
Reply-To: acpi-jp@jp.freebsd.org
Precedence: list
X-Distribute: distribute version 2.1 (Alpha) patchlevel 24e+000315
X-Sequence: acpi-jp 645
Subject: [acpi-jp 645] Re: zzz and ACPI (was: Re: acpi_send_pm_event()) 
Errors-To: owner-acpi-jp@jp.freebsd.org
Sender: owner-acpi-jp@jp.freebsd.org
X-Originator: iwasaki@jp.freebsd.org

> > S1 $BA+0\$H(B PowerResource $B$K4X$9$k$H$3$m$r(B pickup $B$7$^$7$?!#(B
> > # system $B$r(B wakeup $B$5$;$k(B device (MODEM $B$H$+(B) $B$O:#2s9M$($^$;$s!#(B
> $B$3$l$r=q$$$?$H$-!"(BGPEx_EN $B$,Mm$`$N$G8e2s$7$K$7$?5-21$,$"$j$^$9!#(B
> $B$=$m$=$mCe<j$7$F(B PowerResource $B4X78$O40@.$5$;$h$&$+$J$!$H$$$&5$J,$G$9!#(B

$B$J$s$H$J$/$=$l$C$]$$$N$,=PMh$^$7$?!#0J2<$O(B Chandra2 $B$G$N7k2L$G$9$,!"(B
_PRW $B$K$h$k$H(B CardBus x 3 $B$H(B USB $B$,(B S1 $B$G(B wake capability $B$,$"$j!"(B
sleep $BA0$K(B GPEx_EN $B$N@_Dj$,$A$c$s$H@_Dj$5$l$F$$$^$9!#(B
# $BHa$7$$$3$H$K$^$@(B wakeup $B$5$;$k$H$3$m$^$G$O%F%9%H$G$-$^$;$s$,(B...

Mounting root from ufs:/dev/ad0s2a
acpi0: acpi_io_gpe0_enable(0) = (0)
acpi0: acpi_io_gpe0_enable(1) = (80)
acpi0: acpi_io_gpe0_enable(0) = (80)
acpi0: acpi_io_gpe0_enable(1) = (80)
acpi0: acpi_io_gpe0_enable(0) = (80)
acpi0: acpi_io_gpe0_enable(1) = (80)
acpi0: acpi_io_gpe0_enable(0) = (80)
acpi0: acpi_io_gpe0_enable(1) = (280)
acpi_powerres_debug[device]:[D0] [PRW:1:0xa:3] 
acpi_powerres_debug[device]:[D0] [PRW:1:0x7:0] 
acpi_powerres_debug[device]:[D0] [PRW:1:0x7:0] 
acpi_powerres_debug[device]:[D0] [PRW:1:0x7:0] 
acpi_powerres_debug[device]:[D0] [PRW:1:0x9:1] 
acpi0: acpi_io_pm1_status(0) = (411, 0)
acpi0: wake-up logic seems broken, this may cause troubles on wakeup
acpi0: acpi_io_pm1_status(1) = (8000, 8000)
acpi0: acpi_io_pm1_control(0) = (1, 0)
acpi0: acpi_io_pm1_control(1) = (2401, 2400)
acpi0: acpi_io_gpe0_enable(0) = (280)
acpi0: acpi_io_gpe0_enable(1) = (200)
acpi0: acpi_io_gpe0_enable(0) = (200)
acpi0: acpi_io_gpe0_enable(1) = (200)
acpi0: acpi_io_gpe0_enable(0) = (200)
acpi0: acpi_io_gpe0_enable(1) = (200)
acpi0: acpi_io_gpe0_enable(0) = (200)
acpi0: acpi_io_gpe0_enable(1) = (0)
acpi_powerres_debug[device]:[D0] [PRW:1:0xa:3] 
acpi_powerres_debug[device]:[D0] [PRW:1:0x7:0] 
acpi_powerres_debug[device]:[D0] [PRW:1:0x7:0] 
acpi_powerres_debug[device]:[D0] [PRW:1:0x7:0] 
acpi_powerres_debug[device]:[D0] [PRW:1:0x9:1] 
wakeup from sleeping state (slept 00:00:21)
ata0: resetting devices .. done

$B$H$j$"$($:(B S1 $B$+$i$NI|5"8e$K(B GPEx_EN $B$N2r=|$r$d$C$F$$$k$N$G$9$,!"(B
$B$I$&$9$k$N$,@5$7$$$s$G$7$g$&$+$M(B?

$B0J2<!"%Q%C%A$G$9!#<c43$N(B fix $B$b4^$s$G$$$^$9!#(B
# $B<j85$N%Q%C%A$,KD$i$_$9$.$F4IM}$G$-$J$/$J$C$F$-$?$N$G(B (^^;
# $B$-$j$N$$$$$H$3$m$G(B commit $B$7$^$9!#(B

Index: acpi.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/acpi/acpi.c,v
retrieving revision 1.8
diff -u -r1.8 acpi.c
--- acpi.c	2000/09/14 23:29:37	1.8
+++ acpi.c	2000/09/18 03:22:00
@@ -289,6 +290,34 @@
  * ACPI Registers I/O
  */
 
+void
+acpi_gpe_enable_bit(acpi_softc_t *sc, u_int32_t bit, boolean_t on_off)
+{
+	int		x;
+	u_int32_t	pos, value;
+	void		(*GPEx_EN[])(acpi_softc_t *, boolean_t, u_int32_t *) = {
+				acpi_io_gpe0_enable, acpi_io_gpe0_enable
+			};
+
+	x = -1;
+	pos = bit;
+	if (bit < sc->facp_body->gpe0_len * 4) {
+		x = 0;
+	} else {
+		/* should we check gpe1_len too? */
+		pos = bit - sc->facp_body->gpe1_base;
+		x = 1;
+	}
+
+	if (x == -1 || (on_off != 0 && on_off != 1)) {
+		return;
+	}
+
+	GPEx_EN[x](sc, ACPI_REGISTERS_INPUT, &value);
+	value = (value & (~(1 << pos))) | (on_off << pos);
+	GPEx_EN[x](sc, ACPI_REGISTERS_OUTPUT, &value);
+}
+
 static __inline void
 acpi_register_input(u_int32_t ioaddr, u_int32_t *value, u_int32_t size)
 {
Index: acpi.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/acpi/acpi.h,v
retrieving revision 1.3
diff -u -r1.3 acpi.h
--- acpi.h	2000/09/14 23:29:37	1.3
+++ acpi.h	2000/09/18 04:04:57
@@ -34,14 +34,31 @@
 struct acpi_powerres_device {
 	LIST_ENTRY(acpi_powerres_device) links;
 	struct	aml_name *name;
+
+/* _PR[0-2] */
 #define ACPI_D_STATE_D0		0
 #define ACPI_D_STATE_D1		1
 #define ACPI_D_STATE_D2		2
 #define ACPI_D_STATE_D3		3
+#define ACPI_D_STATE_UNKNOWN	255
 	u_int8_t	state;		/* D0 to D3 */
 	u_int8_t	next_state;	/* initialized with D0 */
+/* _PRW */
+#define ACPI_D_WAKECAP_DISABLE	0
+#define ACPI_D_WAKECAP_ENABLE	1
+#define ACPI_D_WAKECAP_UNKNOWN	255
+#define ACPI_D_WAKECAP_DEFAULT	1 	/* XXX default enable for testing */
+	u_int8_t	wake_cap;	/* wake capability */
+	boolean_t	gpe_enabled;	/* GEPx_EN enabled/disabled */
+	union aml_object *prw_val[2];	/* elements of _PRW package */
 };
 
+/* Device Power Management Chind Object Type */
+#define ACPI_D_PM_TYPE_IRC	0	/* _IRC */
+#define ACPI_D_PM_TYPE_PRW	1	/* _PRW */
+#define ACPI_D_PM_TYPE_PRX	2	/* _PR0 - _PR2 */
+/* and more... */
+
 struct acpi_powerres_device_ref {
 	LIST_ENTRY(acpi_powerres_device_ref) links;
 	struct	acpi_powerres_device *device;
@@ -55,6 +72,7 @@
 	u_int8_t	state;		/* OFF or ON */
 #define ACPI_PR_MAX		3	/* _PR[0-2] */
 	LIST_HEAD(, acpi_powerres_device_ref) reflist[ACPI_PR_MAX];
+	LIST_HEAD(, acpi_powerres_device_ref) prwlist;
 };
 
 /* softc */
@@ -77,6 +96,8 @@
 u_int8_t	 acpi_get_current_device_state(struct aml_name *);
 void		 acpi_set_device_state(acpi_softc_t *, struct aml_name *,
 				       u_int8_t);
+void		 acpi_set_device_wakecap(acpi_softc_t *, struct aml_name *,
+					 u_int8_t);
 
 /* PowerResource State */
 void		 acpi_powerres_init(acpi_softc_t *);
@@ -85,5 +106,8 @@
 void		 acpi_set_powerres_state(acpi_softc_t *, struct aml_name *,
 				         u_int8_t);
 void		 acpi_powerres_set_sleeping_state(acpi_softc_t *, u_int8_t);
+
+/* GPE enable bit manuplation */
+void		 acpi_gpe_enable_bit(acpi_softc_t *, u_int32_t, boolean_t);
 
 #endif	/* !_DEV_ACPI_ACPI_H_ */
Index: acpi_powerres.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/acpi/acpi_powerres.c,v
retrieving revision 1.3
diff -u -r1.3 acpi_powerres.c
--- acpi_powerres.c	2000/09/14 23:29:37	1.3
+++ acpi_powerres.c	2000/09/18 04:07:16
@@ -47,6 +47,11 @@
 static int	 acpi_powerres_register(struct aml_name *name, va_list ap);
 static int	 acpi_powerres_add_device(struct aml_name *name, va_list ap);
 
+static void	 acpi_set_device_next_state(acpi_softc_t *sc,
+					    struct acpi_powerres_device *device,
+					    u_int8_t sleeping_state,
+					    u_int8_t def_dstate);
+
 static char	*powerres_statestr[2] = {"_OFF", "_ON"};
 
 /*
@@ -74,6 +79,20 @@
 	return (dstate);
 }
 
+static __inline struct acpi_powerres_device *
+acpi_powerres_get_powerres_device(acpi_softc_t *sc, struct aml_name *name)
+{
+	struct	acpi_powerres_device *device;
+
+	LIST_FOREACH(device, &sc->acpi_powerres_devlist, links) {
+		if (device->name == name) {
+			return (device);
+		}
+	}
+
+	return (NULL);
+}
+
 /*
  * 7.2.2-4: For the OS to put the device in the Dx device state.
  */
@@ -83,6 +102,7 @@
 	char	psx[5];	/* "_PSx" */
 	struct	acpi_powerres_info *powerres;
 	struct	acpi_powerres_device_ref *device_ref;
+	struct	acpi_powerres_device *device;
 	struct	aml_name *method;
 	struct	aml_environ env;
 
@@ -90,27 +110,40 @@
 		return;
 	}
 
+	device = acpi_powerres_get_powerres_device(sc, name);
+	if (device == NULL) {
+		return;
+	}
+	device->state = dstate;
+
 	/*
+	 * D3 state transition.  We don't need to check PowerResource,
+	 * just execute _PS3 control method of the device.
+	 */
+	if (dstate == ACPI_D_STATE_D3) {
+		goto method_execution;
+	}
+
+	/*
+	 * D0 - D2 state transition.
 	 * All Power Resources referenced by elements 1 through N 
 	 * in _PRx of the device must be in the ON state.
 	 * 
 	 */
-	if (dstate < ACPI_PR_MAX) {
-		LIST_FOREACH(powerres, &sc->acpi_powerres_inflist, links) {
-			LIST_FOREACH(device_ref, &powerres->reflist[dstate], links) {
-				if (device_ref->device->name != name) {
-					continue;
-				}
-				if (powerres->state == ACPI_POWER_RESOURCE_ON) {
-					continue;
-				}
+	LIST_FOREACH(powerres, &sc->acpi_powerres_inflist, links) {
+		LIST_FOREACH(device_ref, &powerres->reflist[dstate], links) {
+			if (device_ref->device->name != name) {
+				continue;
+			}
+			if (powerres->state != ACPI_POWER_RESOURCE_ON) {
 				acpi_set_powerres_state(sc, powerres->name,
 				    ACPI_POWER_RESOURCE_ON);
-				powerres->state = ACPI_POWER_RESOURCE_ON;
 			}
+			break;	/* already found, goto next PowerResource */
 		}
 	}
 
+method_execution:
 	/*
 	 * If present, the _PSx control method is executed to set the
 	 * device into the Dx device state.
@@ -128,6 +161,75 @@
 }
 
 /*
+ * 7.2.1: For the OS to have the defined wake capability properly enabled
+ *        for the device.
+ */
+void
+acpi_set_device_wakecap(acpi_softc_t *sc, struct aml_name *name, u_int8_t cap)
+{
+	struct	acpi_powerres_info *powerres;
+	struct	acpi_powerres_device_ref *device_ref;
+	struct	acpi_powerres_device *device;
+	struct	aml_name *method;
+	union	aml_object argv[1], *retval;
+
+	if (cap != ACPI_D_WAKECAP_ENABLE && cap != ACPI_D_WAKECAP_DISABLE ) {
+		return;
+	}
+
+	device = acpi_powerres_get_powerres_device(sc, name);
+	if (device == NULL) {
+		return;
+	}
+	device->wake_cap = cap;
+
+	/*
+	 * Disable wake capability.  We don't need to check PowerResource,
+	 * just execute _PSW control method of the device.
+	 */
+	if (cap == ACPI_D_WAKECAP_DISABLE ) {
+		goto method_execution;
+	}
+
+	/*
+	 * Enable wake capability.
+	 * All Power Resources referenced by elements 2 through N 
+	 * are put into the ON state.
+	 * 
+	 */
+	LIST_FOREACH(powerres, &sc->acpi_powerres_inflist, links) {
+		LIST_FOREACH(device_ref, &powerres->prwlist, links) {
+			if (device_ref->device->name != name) {
+				continue;
+			}
+			if (powerres->state != ACPI_POWER_RESOURCE_ON) {
+				acpi_set_powerres_state(sc, powerres->name,
+				    ACPI_POWER_RESOURCE_ON);
+			}
+			break;	/* already found, goto next PowerResource */
+		}
+	}
+
+method_execution:
+	/*
+	 * If present, the _PSW control method is executed to set the
+	 * device-specific registers to enable the wake functionality
+	 * of the device.
+	 */
+	method = aml_find_from_namespace(name, "_PSW");
+	if (method == NULL) {
+		return;
+	}
+
+
+	argv[0].type = aml_t_num;
+	argv[0].num.number = cap;
+	aml_local_stack_push(aml_local_stack_create());
+	retval = aml_invoke_method(method, 1, argv);
+	aml_local_stack_delete(aml_local_stack_pop());
+}
+
+/*
  * 7.4.1 Returns the current ON or OFF status for the power resource.
  */
 u_int8_t
@@ -152,6 +254,20 @@
 	return (pstate);
 }
 
+static __inline struct acpi_powerres_info *
+acpi_powerres_get_powerres(acpi_softc_t *sc, struct aml_name *name)
+{
+	struct	acpi_powerres_info *powerres;
+
+	LIST_FOREACH(powerres, &sc->acpi_powerres_inflist, links) {
+		if (powerres->name == name) {
+			return (powerres);
+		}
+	}
+
+	return (NULL);
+}
+
 /*
  * 7.4.2,3 Puts the power resource into the ON/OFF state.
  */
@@ -159,6 +275,7 @@
 acpi_set_powerres_state(acpi_softc_t *sc, struct aml_name *name,
     u_int8_t pstate)
 {
+	struct	acpi_powerres_info *powerres;
 	struct	aml_name *method;
 	struct	aml_environ env;
 
@@ -167,6 +284,12 @@
 		return;
 	}
 
+	powerres = acpi_powerres_get_powerres(sc, name);
+	if (powerres == NULL) {
+		return;
+	}
+	powerres->state = pstate;
+
 	method = aml_find_from_namespace(name, powerres_statestr[pstate]);
 	if (method == NULL) {
 		return;			/* just in case */
@@ -197,6 +320,7 @@
 			}
 			LIST_INIT(&powerres->reflist[i]);
 		}
+		LIST_INIT(&powerres->prwlist);
 		LIST_REMOVE(powerres, links);
 		FREE(powerres, M_TEMP);
 	}
@@ -214,6 +338,25 @@
 	    acpi_powerres_add_device, sc);
 }
 
+static __inline void
+acpi_powerres_device_prw_print(struct acpi_powerres_device *device)
+{
+
+	printf("[PRW:%d:", device->wake_cap);
+	switch (device->prw_val[0]->type) {
+	case aml_t_num:
+		/* bit index in GPEx_EN of the enable bit */
+		printf("0x%x", device->prw_val[0]->num.number);
+		break;
+	default:
+		/* XXX in ACPI 2.0, we can have additional GPE blocks */
+		printf("GPE block");
+		break;
+	}
+	/* the lowest sleeping state */
+	printf(":%d] ", device->prw_val[1]->num.number);
+}
+
 void
 acpi_powerres_debug(acpi_softc_t *sc)
 {
@@ -223,11 +366,13 @@
 	int	i;
 
 	LIST_FOREACH(powerres, &sc->acpi_powerres_inflist, links) {
-		printf("acpi_powerres_debug:");
+		printf("acpi_powerres_debug[powerres]:");
 		aml_print_curname(powerres->name);
 		printf("[%d:%d:%s]\n", powerres->name->property->pres.level, 
 		    powerres->name->property->pres.order, 
 		    powerres_statestr[powerres->state]);
+
+		/* for _PR[0-2] */
 		for (i = 0; i < ACPI_PR_MAX; i++) {
 			if (LIST_EMPTY(&powerres->reflist[i])) {
 				continue;
@@ -240,6 +385,30 @@
 			}
 			printf("\n");
 		}
+
+		/* for _PRW */
+		if (LIST_EMPTY(&powerres->prwlist)) {
+			continue;
+		}
+		printf("\t_PRW:");
+		LIST_FOREACH(device_ref, &powerres->prwlist, links) {
+			device = device_ref->device;
+			aml_print_curname(device->name);
+			acpi_powerres_device_prw_print(device);
+		}
+		printf("\n");
+	}
+
+	LIST_FOREACH(device, &sc->acpi_powerres_devlist, links) {
+		printf("acpi_powerres_debug[device]:");
+		aml_print_curname(device->name);
+		if (device->state != ACPI_D_STATE_UNKNOWN) {
+			printf("[D%d] ", device->state);
+		}
+		if (device->wake_cap != ACPI_D_WAKECAP_UNKNOWN) {
+			acpi_powerres_device_prw_print(device);
+		}
+		printf("\n");
 	}
 }
 
@@ -290,6 +459,7 @@
 	for (i = 0; i < ACPI_PR_MAX; i++) {
 		LIST_INIT(&powerres->reflist[i]);
 	}
+	LIST_INIT(&powerres->prwlist);
 
 	return (0);
 }
@@ -297,7 +467,7 @@
 static int
 acpi_powerres_add_device(struct aml_name *name, va_list ap)
 {
-	int	i;
+	int	i, offset, objtype;
 	int	prnum;
 	int	dev_found;
 	acpi_softc_t *sc;
@@ -306,12 +476,23 @@
 	struct	acpi_powerres_info *powerres;
 	struct	aml_name *powerres_name;
 	struct	aml_environ env;
+	union	aml_object **objects;
 
 	sc = va_arg(ap, acpi_softc_t *);
-
-	/* should be _PR[0-2] */
-	prnum =  name->name[3] - '0';
-	if (!(prnum >= 0 && prnum < ACPI_PR_MAX)) {
+	objtype = prnum = 0;
+	/* should be _PR[0-2] or _PRW */
+	switch (name->name[3]) {
+	case '0' ... '2':
+		objtype = ACPI_D_PM_TYPE_PRX;
+		prnum =  name->name[3] - '0';
+		offset = 0;
+		break;
+	case 'W':
+		objtype = ACPI_D_PM_TYPE_PRW;
+		/* for _PRW, PowerResource reference starts from elements 2 */ 
+		offset = 2;
+		break;
+	default:
 		return (0);
 	}
 
@@ -327,7 +508,7 @@
 	/* make the list of devices */
 	dev_found = 0;
 	LIST_FOREACH(device, &sc->acpi_powerres_devlist, links) {
-		if (device->name == name) {
+		if (device->name == name->parent) {
 			dev_found = 1;
 			break;
 		}
@@ -338,51 +519,150 @@
 		if (device == NULL) {
 			return (1);
 		}
+
+		/* set default values */
+		device->state = ACPI_D_STATE_UNKNOWN;
+		device->wake_cap = ACPI_D_WAKECAP_UNKNOWN;
 
-		/* this is a _PR[0-2] object, we need get a parent of this. */
+		/* this is a _PR[0-2|W] object, we need get a parent of this. */
 		device->name = name->parent;
 
-		/* get the current device state.  */
-		device->state = acpi_get_current_device_state(device->name);
 
 		LIST_INSERT_HEAD(&sc->acpi_powerres_devlist, device, links);
 	}
 
+	objects = name->property->package.objects;
+
+	switch (objtype) {
+	case ACPI_D_PM_TYPE_PRX:
+		/* get the current device state.  */
+		if (device->state == ACPI_D_STATE_UNKNOWN) {
+			device->state = acpi_get_current_device_state(device->name);
+		}
+		break;
+	case ACPI_D_PM_TYPE_PRW:
+		device->wake_cap = ACPI_D_WAKECAP_DEFAULT;
+		for (i = 0; i < 2; i++) {
+			device->prw_val[i] = objects[i];
+		}
+		break;
+	default:
+		break;
+	}
+
 	/* find PowerResource which the device reference to */
 	MALLOC(device_ref, struct acpi_powerres_device_ref *,
 	   sizeof(*device_ref), M_TEMP, M_NOWAIT);
 	if (device_ref == NULL) {
 		return (1);
 	}
+
 	device_ref->device = device;
 	env.curname = device->name;
-	for (i = 0; i < name->property->package.elements; i++) {
-		if (name->property->package.objects[i]->type != aml_t_namestr) {
+	for (i = offset; i < name->property->package.elements; i++) {
+		if (objects[i]->type != aml_t_namestr) {
 			printf("acpi_powerres_add_device: not name string\n");
 			continue;
 		}
-		powerres_name = aml_search_name(&env,
-		    name->property->package.objects[i]->nstr.dp);
+		powerres_name = aml_search_name(&env, objects[i]->nstr.dp);
 		if (powerres_name == NULL) {
 			printf("acpi_powerres_add_device: not found\n");
 			continue;
 		}
 
 		LIST_FOREACH(powerres, &sc->acpi_powerres_inflist, links) {
-			if (powerres->name == powerres_name) {
+			if (powerres->name != powerres_name) {
+				continue;
+			}
+
+			switch (objtype) {
+			case ACPI_D_PM_TYPE_PRX:
 				LIST_INSERT_HEAD(&powerres->reflist[prnum],
 				    device_ref, links);
 				break;
+			case ACPI_D_PM_TYPE_PRW:
+				LIST_INSERT_HEAD(&powerres->prwlist,
+				    device_ref, links);
+				break;
+			default:
+				break;
 			}
+			/* already found, go to next element... */
+			break;
 		}
 	}
 
+	switch (objtype) {
+	case ACPI_D_PM_TYPE_PRX:
+		/* XXX
+		 * force to set the current device state to make
+		 * PowerResource compatible with the device state.
+		 */
+		acpi_set_device_state(sc, device->name, device->state);
+		break;
+	case ACPI_D_PM_TYPE_PRW:
+		acpi_set_device_wakecap(sc, device->name, device->wake_cap);
+		break;
+	default:
+		break;
+	}
+
+	return (0);
+}
+
+static __inline void
+acpi_set_device_prw_gpe(acpi_softc_t *sc, struct acpi_powerres_device *device,
+    boolean_t on_off)
+{
+	u_long		ef;
+
+	device->gpe_enabled = on_off;
+
+	/* The proper general-purpose register bits are enabled. */
+	switch (device->prw_val[0]->type) {
+	case aml_t_num:
+		/* bit index in GPEx_EN of the enable bit */
+		ef = read_eflags();	/* XXX should MI */
+		acpi_gpe_enable_bit(sc, device->prw_val[0]->num.number, on_off);
+		write_eflags(ef);
+		break;
+	default:
+		/* XXX in ACPI 2.0, we can have additional GPE blocks */
+		printf("ACPI 2.0 style _PRW/GPE handling is not suppoerted\n");
+		break;
+	}
+}
+
+static void
+acpi_set_device_next_state(acpi_softc_t *sc,
+    struct acpi_powerres_device *device, u_int8_t sleeping_state,
+    u_int8_t def_dstate)
+{
+
+	/* set given default device state */
+	device->next_state = def_dstate;
+
+	if (device->wake_cap != ACPI_D_WAKECAP_ENABLE) {
+		goto out;
+	}
+
 	/*
-	 * force to set the current device state to make
-	 * PowerResource compatible with the device state.
+	 * 7.2.1 _PRW
+	 * The sleeping state being enterted must be greater or equal to the
+	 * power state declared in element 1 of the _PRW object.
 	 */
-	acpi_set_device_state(sc, device->name, device->state);
-	return (0);
+	if (sleeping_state < device->prw_val[1]->num.number) {
+		goto out;
+	}
+
+	if (sleeping_state > ACPI_S_STATE_S0) {
+		acpi_set_device_prw_gpe(sc, device, 1);
+	}
+
+	device->next_state = ACPI_D_STATE_D0;	/* XXX need to refer _SxD ? */
+
+out:
+	return;
 }
 
 /*
@@ -405,7 +685,7 @@
 	 *  based on PowerResource state change.
 	 */
 	LIST_FOREACH(device, &sc->acpi_powerres_devlist, links) {
-		device->next_state = ACPI_D_STATE_D0;
+		acpi_set_device_next_state(sc, device, state, ACPI_D_STATE_D0);
 	}
 
 	/*
@@ -420,7 +700,6 @@
 			if (powerres->state == ACPI_POWER_RESOURCE_ON) {
 				acpi_set_powerres_state(sc, powerres->name,
 				    ACPI_POWER_RESOURCE_OFF);
-				powerres->state = ACPI_POWER_RESOURCE_OFF;
 			}
 			/*
 			 * Device states are compatible with the current
@@ -429,8 +708,8 @@
 			for (i = 0; i < ACPI_PR_MAX; i++) {
 				LIST_FOREACH(device_ref, &powerres->reflist[i], links) {
 					device = device_ref->device;
-					/* D3 state */
-					device->next_state = ACPI_D_STATE_D3;
+					acpi_set_device_next_state(sc, device,
+					    state, ACPI_D_STATE_D3);
 				}
 			}
 		} else {
@@ -438,7 +717,6 @@
 			if (powerres->state == ACPI_POWER_RESOURCE_OFF) {
 				acpi_set_powerres_state(sc, powerres->name,
 				    ACPI_POWER_RESOURCE_ON);
-				powerres->state = ACPI_POWER_RESOURCE_ON;
 			}
 		}
 	}
@@ -460,12 +738,16 @@
 		if (device->next_state == ACPI_D_STATE_D3 &&
 		    device->state != ACPI_D_STATE_D3) {
 			acpi_set_device_state(sc, device->name, ACPI_D_STATE_D3);
-			device->state = ACPI_D_STATE_D3;
 		}
 		if (device->next_state == ACPI_D_STATE_D0 &&
 		    device->state != ACPI_D_STATE_D0) {
 			acpi_set_device_state(sc, device->name, ACPI_D_STATE_D0);
-			device->state = ACPI_D_STATE_D0;
+		}
+
+		/* XXX reset GEPx_EN enabled bit on S0 state */
+		if (state == ACPI_S_STATE_S0 && device->gpe_enabled &&
+		    device->wake_cap == ACPI_D_WAKECAP_ENABLE) {
+			acpi_set_device_prw_gpe(sc, device, 0);
 		}
 	}
 }
Index: aml/aml_evalobj.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/acpi/aml/aml_evalobj.c,v
retrieving revision 1.1
diff -u -r1.1 aml_evalobj.c
--- aml/aml_evalobj.c	2000/08/24 09:33:08	1.1
+++ aml/aml_evalobj.c	2000/09/17 16:38:03
@@ -373,10 +378,9 @@
 }
 
 union aml_object *
-aml_invoke_method_by_name(char *method, int argc, union aml_object *argv)
+aml_invoke_method(struct aml_name *name, int argc, union aml_object *argv)
 {
 	int	i;
-	struct	aml_name *name;
 	struct	aml_name *tmp;
 	struct	aml_environ *env;
 	struct	aml_local_stack *stack;
@@ -389,7 +393,6 @@
 		return (NULL);
 	}
 	bzero(env, sizeof(struct aml_environ));
-	name = aml_find_from_namespace(aml_get_rootname(), method);
 
 	if (name != NULL && name->property != NULL &&
 	    name->property->type == aml_t_method) {
@@ -418,4 +421,17 @@
 	}
 	memman_free(aml_memman, memid_aml_environ, env);
 	return (retval);
+}
+
+union aml_object *
+aml_invoke_method_by_name(char *method, int argc, union aml_object *argv)
+{
+	struct	aml_name *name;
+
+	name = aml_find_from_namespace(aml_get_rootname(), method);
+	if (name == NULL) {
+		return (NULL);
+	}
+
+	return (aml_invoke_method(name, argc, argv));
 }
Index: aml/aml_evalobj.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/acpi/aml/aml_evalobj.h,v
retrieving revision 1.1
diff -u -r1.1 aml_evalobj.h
--- aml/aml_evalobj.h	2000/08/24 09:33:08	1.1
+++ aml/aml_evalobj.h	2000/09/17 16:39:08
@@ -40,6 +40,8 @@
 int			 aml_objtonum(struct aml_environ *,
 				      union aml_object *);
 struct aml_name		*aml_execute_method(struct aml_environ *);
+union aml_object	*aml_invoke_method(struct aml_name *,
+					   int, union aml_object *);
 union aml_object	*aml_invoke_method_by_name(char *,
 						   int, union aml_object *);
 

