From owner-acpi-jp@jp.freebsd.org  Mon Aug 21 22:16:50 2000
Received: (from daemon@localhost)
	by castle.jp.freebsd.org (8.9.3+3.2W/8.7.3) id WAA16733;
	Mon, 21 Aug 2000 22:16:50 +0900 (JST)
	(envelope-from owner-acpi-jp@jp.FreeBSD.org)
Received: from shidahara1.planet.sci.kobe-u.ac.jp (shidahara1.planet.sci.kobe-u.ac.jp [133.30.50.200])
	by castle.jp.freebsd.org (8.9.3+3.2W/8.7.3) with ESMTP id WAA16728
	for <acpi-jp@jp.freebsd.org>; Mon, 21 Aug 2000 22:16:49 +0900 (JST)
	(envelope-from takawata@shidahara1.planet.sci.kobe-u.ac.jp)
Received: from shidahara1.planet.sci.kobe-u.ac.jp (localhost [127.0.0.1])
	by shidahara1.planet.sci.kobe-u.ac.jp (8.9.3/8.9.3) with ESMTP id WAA78063
	for <acpi-jp@jp.freebsd.org>; Mon, 21 Aug 2000 22:15:46 +0900 (JST)
	(envelope-from takawata@shidahara1.planet.sci.kobe-u.ac.jp)
Message-Id: <200008211315.WAA78063@shidahara1.planet.sci.kobe-u.ac.jp>
To: acpi-jp@jp.freebsd.org
Date: Mon, 21 Aug 2000 22:15:46 +0900
From: Takanori Watanabe <takawata@shidahara1.planet.sci.kobe-u.ac.jp>
Reply-To: acpi-jp@jp.freebsd.org
Precedence: list
X-Distribute: distribute version 2.1 (Alpha) patchlevel 24e+000315
X-Sequence: acpi-jp 576
Subject: [acpi-jp 576] Catching GPE in Kernel thread.
Errors-To: owner-acpi-jp@jp.freebsd.org
Sender: owner-acpi-jp@jp.freebsd.org
X-Originator: takawata@shidahara1.planet.sci.kobe-u.ac.jp


ACPI$B%+!<%M%k%9%l%C%I$r@8@.$7$F(BGPE$B$r<u$1;_$a$k;v$,=PMh$k$h$&$K$7$F$_$^$7$?!#(B
$B$D$$$G$K!"(BEVENTHANDLER$B$X$NEPO?$r(Battach$B$G$9$k$h$&$K$7$F$_$F$$$^$9$,!"(B
shutdown -p $B$O$&$^$/F0$+$J$$$_$?$$$G$9!#(B

$BEOJUB:5*(B
$B?@8MBg3XBg3X1!<+A32J3X8&5f2J(BD3$B>pJs%a%G%#%"2J3X@l96(B
<a href="http://www.planet.sci.kobe-u.ac.jp/~takawata/key.html">
Public Key</a>
Key fingerprint =  2C 51 E2 78 2C E1 C5 2D  0F F1 20 A3 11 3A 62 2A 

Index: acpi.c
===================================================================
RCS file: /home/cvs/ACPI/sys/dev/acpi/acpi.c,v
retrieving revision 1.26
diff -u -r1.26 acpi.c
--- acpi.c	2000/08/15 14:43:43	1.26
+++ acpi.c	2000/08/21 12:30:58
@@ -35,13 +35,16 @@
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/sysctl.h>
-
+#include <sys/malloc.h>
 #include <sys/eventhandler.h>		/* for EVENTHANDLER_REGISTER */
 #include <machine/clock.h>		/* for DELAY */
+#include <sys/kthread.h>
+#include <sys/ctype.h>
 
 #include <machine/bus.h>
 #include <machine/resource.h>
 #include <sys/rman.h>
+#include <sys/reboot.h>
 
 #include <sys/acpi.h>
 
@@ -84,6 +87,15 @@
 
 static struct	ACPIaddr acpi_addr;
 struct		ACPIrsdp *acpi_rsdp;
+/*Event Structure */
+struct acpi_event {
+	STAILQ_ENTRY (acpi_event) ae_q;
+#define ACPI_EVENT_TYPE_FIXEDREG 0
+#define ACPI_EVENT_TYPE_GPEREG 1
+#define ACPI_EVENT_TYPE_EC 2
+	int ae_type;
+	int ae_arg;
+};
 
 /* softc */
 typedef struct acpi_softc {
@@ -94,7 +106,10 @@
 	struct	FACS *facs;
 	int	system_state_initialized;
 	int	broken_wakeuplogic;
+	u_int32_t gpe0_mask;
+	u_int32_t gpe1_mask;
 	struct	acpi_system_state_package system_state_package;
+	STAILQ_HEAD(, acpi_event) event;
 } acpi_softc_t;
 
 /* Character device stuff */
@@ -147,6 +162,7 @@
 static void acpi_handle_dsdt(acpi_softc_t *sc);
 static void acpi_handle_facp(acpi_softc_t *sc);
 static int  acpi_handle_rsdt(acpi_softc_t *sc);
+void acpi_queue_event(int type, int arg);
 
 /* System sleeping state stuff */
 static void acpi_trans_sleeping_state(acpi_softc_t *sc, u_int8_t state);
@@ -879,6 +895,8 @@
 	acpi_softc_t	*sc;
 
 	sc = (acpi_softc_t *) data;
+	if(!(howto & RB_POWEROFF))
+		return;
 	/* wait 1sec before turning off the system power */
 	DELAY(1000*1000);
 	acpi_trans_sleeping_state(sc, 5);
@@ -915,8 +933,6 @@
 		break;
 	case 5:
 		/* Power the system off using ACPI */
-		EVENTHANDLER_REGISTER(shutdown_final, acpi_soft_off, sc,
-		    SHUTDOWN_PRI_LAST);
 		shutdown_nice();	/* XXX */
 		break;
 	default:
@@ -970,13 +986,33 @@
     u_int32_t status_0, u_int32_t status_1)
 {
 
+	int i;
 	if (status_a & ACPI_PM1_PWRBTN_EN || status_b & ACPI_PM1_PWRBTN_EN) {
+#if 0
 		acpi_set_sleeping_state(sc, 5);
+#else
+		/*If there is ACPI userland daemon, this event should be
+		  passed to it,so that user can determine power policy
+		  and process some on userland (Not yet)*/
+		acpi_queue_event(ACPI_EVENT_TYPE_FIXEDREG,0);
+#endif
+
 	}
 
 	if (status_a & ACPI_PM1_SLPBTN_EN || status_b & ACPI_PM1_SLPBTN_EN) {
+#if 0
 		acpi_set_sleeping_state(sc, 1);
+#else
+		acpi_queue_event(ACPI_EVENT_TYPE_FIXEDREG,1);
+#endif
 	}
+	for(i=0;i<sc->facp_body->gpe0_len*4;i++)
+		if((status_0&(1<<i))&&(sc->gpe0_mask&(1<<i)))
+			acpi_queue_event(ACPI_EVENT_TYPE_GPEREG,i);
+	for(i=0;i<sc->facp_body->gpe1_len*4;i++)
+		if((status_1&(1<<i))&&(sc->gpe1_mask&(1<<i)))
+				acpi_queue_event(ACPI_EVENT_TYPE_GPEREG,
+				    i+sc->facp_body->gpe1_base);
 }
 
 static void
@@ -1023,7 +1059,7 @@
 	}
 
 	/* General-Purpose Events 0 Status Registers */
-	status_0 = enable_0 = 0;
+	status_0=enable_0=0;
 	acpi_io_gpe0_status(sc, ACPI_REGISTERS_INPUT, &status_0);
 
 	/* Get Current Interrupt Mask */
@@ -1037,20 +1073,16 @@
 
 		/* Disable all interrupt generation */
 		val_a = enable_0 & ~status_0;
-#if 0
-		/* or should we disable all? */
-		val_a = 0x0;
-#endif
 		acpi_io_gpe0_enable(sc, ACPI_REGISTERS_OUTPUT, &val_a);
-
+#if 0	       
 		/* Clear interrupt status */
-		val_a = enable_0;	/* XXX */
+		val_a = 0xffff;	/* XXX */
 		acpi_io_gpe0_status(sc, ACPI_REGISTERS_OUTPUT, &val_a);
 
 		/* Re-enable interrupt */
 		acpi_io_gpe0_enable(sc, ACPI_REGISTERS_OUTPUT, &enable_0);
-
 		acpi_debug = 0;		/* Shut up again */
+#endif
 	}
 
 	/* General-Purpose Events 1 Status Registers */
@@ -1073,14 +1105,14 @@
 		val_a = 0x0;
 #endif
 		acpi_io_gpe1_enable(sc, ACPI_REGISTERS_OUTPUT, &val_a);
-
+#if 0
 		/* Clear interrupt status */
 		val_a = enable_1;	/* XXX */
 		acpi_io_gpe1_status(sc, ACPI_REGISTERS_OUTPUT, &val_a);
 
 		/* Re-enable interrupt */
 		acpi_io_gpe1_enable(sc, ACPI_REGISTERS_OUTPUT, &enable_1);
-
+#endif
 		acpi_debug = 0;		/* Shut up again */
 	}
 
@@ -1089,7 +1121,25 @@
 
 	acpi_debug = debug;	/* Restore debug level */
 }
-
+static int set_gpe_bits(struct aml_name *name,va_list ap)
+{
+	struct acpi_softc *sc=va_arg(ap,struct acpi_softc *);
+	int *gpemask0=va_arg(ap,int *);
+	int *gpemask1=va_arg(ap,int *);
+	int gpenum;
+#define XDIGITTONUM(c) ((isdigit(c))?((c)-'0'):('A'<=(c)&&(c)<='F')?((c)-'A'+10):0)
+	if(isxdigit(name->name[2]) && isxdigit(name->name[3])){
+		gpenum=XDIGITTONUM(name->name[2])*16+XDIGITTONUM(name->name[3]);
+		printf("GPENUM %d %d \n",gpenum,sc->facp_body->gpe0_len*4);
+		if(gpenum<(sc->facp_body->gpe0_len*4)){
+			*gpemask0|=(1<<gpenum);
+		}else{
+			*gpemask1|=(1<<(gpenum-sc->facp_body->gpe1_base));
+		}
+	}
+	printf("GPEMASK %x %x\n",*gpemask0,*gpemask1);
+	return 0;
+}
 static void
 acpi_enable_events(acpi_softc_t *sc)
 {
@@ -1111,17 +1161,21 @@
 		status_b |= ACPI_PM1_SLPBTN_EN;
 	}
 	acpi_io_pm1_enable(sc, ACPI_REGISTERS_OUTPUT, &status_a, &status_b);
-
-#if 0
+#if 1
+	status_a=status_b=0;
+	aml_apply_foreach_found_objects(NULL,"\\_GPE._L",set_gpe_bits,sc
+	    ,&status_a,&status_b);
+	sc->gpe0_mask=status_a;
+	sc->gpe1_mask=status_b;
 	/*
 	 * XXX
 	 * This should be done based on level event handlers in
 	 * \_GPE scope (4.7.2.2.1.2).
 	 */
-
+	
 	/* try to enable all bits */
-	status_a = 0xffff;
 	acpi_io_gpe0_enable(sc, ACPI_REGISTERS_OUTPUT, &status_a);
+	acpi_io_gpe1_enable(sc, ACPI_REGISTERS_OUTPUT, &status_b);
 #endif
 
 	/* print all event status for debugging */
@@ -1277,6 +1331,7 @@
 		return (ENXIO);
 	}
 
+	STAILQ_INIT(&sc->event);
 	/* Allocate the port range and interrupt */
 	port = sc->facp_body->smi_cmd;
 	rid_port = 0;
@@ -1315,6 +1370,11 @@
 	acpi_enable_disable(sc, 1);
 	acpi_enable_events(sc);
 #endif
+
+	EVENTHANDLER_REGISTER(shutdown_final, acpi_soft_off, sc,
+			      SHUTDOWN_PRI_LAST);
+
+
 	acpi_pmap_release();
 
 	make_dev(&acpi_cdevsw, 0, 0, 5, 0660, "acpi");
@@ -1337,3 +1397,94 @@
 };
 
 DRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, 0, 0);
+/*
+ *KTHREAD 
+ *This part is mostly stolen from NEWCARD pcic code.
+ */
+
+void acpi_queue_event(int type,int arg)
+{
+	struct acpi_event *ae;
+	int s;
+	acpi_softc_t *sc=devclass_get_softc(acpi_devclass,0);
+	ae = malloc(sizeof(*ae),M_TEMP,M_NOWAIT);
+	if(ae == NULL)
+		panic("acpi_queue_event; can't allocate event");
+	
+	ae->ae_type=type;
+	ae->ae_arg=arg;
+	s=splhigh();
+	STAILQ_INSERT_TAIL(&sc->event,ae,ae_q);
+	splx(s);
+	wakeup(&sc->event);
+}
+
+void acpi_event_thread(void *arg)
+{
+	acpi_softc_t *sc=arg;
+	int s,gpe1_base=sc->facp_body->gpe1_base;
+	u_int32_t status,bit;
+	struct acpi_event *ae;
+	const char numconv[]={'0','1','2','3','4','5','6','7','8','9',
+			     'A','B','C','D','E','F',-1};
+	char gpemethod[]="\\_GPE._LXX";
+	union aml_object argv;/* Dummy*/
+	while(1){
+		s = splhigh();
+		if((ae = STAILQ_FIRST(&sc->event))==NULL){
+			splx(s);
+			tsleep(&sc->event,PWAIT,"acpiev",0);
+			continue;
+		} else {
+			splx(s);
+		}
+		s = splhigh();
+		STAILQ_REMOVE_HEAD_UNTIL(&sc->event,ae,ae_q);
+		splx(s);
+		switch(ae->ae_type){
+		case ACPI_EVENT_TYPE_GPEREG:
+			sprintf(gpemethod,"\\_GPE._L%c%c",
+			    numconv[(ae->ae_arg/0x10)&0xf],
+			    numconv[ae->ae_arg&0xf]);
+			aml_invoke_method_by_name(gpemethod,0,&argv);
+			sprintf(gpemethod,"\\_GPE._E%c%c",
+			    numconv[(ae->ae_arg/0x10)&0xf],
+			    numconv[ae->ae_arg&0xf]);
+			aml_invoke_method_by_name(gpemethod,0,&argv);
+			s=splhigh();
+			if((ae->ae_arg < gpe1_base)||(gpe1_base==0)){
+				bit=1<<ae->ae_arg;
+				printf("GPE0%x\n",bit);
+				acpi_io_gpe0_status(sc, ACPI_REGISTERS_OUTPUT,
+				    &bit);
+				acpi_io_gpe0_enable(sc,ACPI_REGISTERS_INPUT,
+				    &status);
+				printf("GPE0%x\n",status);
+				status|=bit;
+				acpi_io_gpe0_enable(sc,ACPI_REGISTERS_OUTPUT,
+				    &status);
+			}else{
+				bit=1<<(ae->ae_arg-sc->facp_body->gpe1_base);
+				acpi_io_gpe1_status(sc, ACPI_REGISTERS_OUTPUT,
+				    &bit);
+				acpi_io_gpe1_enable(sc,ACPI_REGISTERS_INPUT,
+				    &status);
+				status|=bit;
+				acpi_io_gpe1_enable(sc,ACPI_REGISTERS_OUTPUT,
+				    &status);
+			}
+			splx(s);
+			break;
+		}
+		free(ae,M_TEMP);
+	}
+}
+void acpi_start_threads(void *arg)
+{
+	acpi_softc_t *sc=devclass_get_softc(acpi_devclass,0);
+	device_t dev= devclass_get_device(acpi_devclass,0);
+	if(kthread_create(acpi_event_thread,sc,NULL,"acpi")){
+		ACPI_DEVPRINTF("CANNOT CREATE THREAD\n");
+	}
+}
+SYSINIT(acpi,SI_SUB_KTHREAD_IDLE,SI_ORDER_ANY,acpi_start_threads,0);



