From owner-acpi-jp@jp.freebsd.org  Sat Oct  7 16:02:38 2000
Received: (from daemon@localhost)
	by castle.jp.freebsd.org (8.9.3+3.2W/8.7.3) id QAA00551;
	Sat, 7 Oct 2000 16:02:38 +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 QAA00546
	for <acpi-jp@jp.freebsd.org>; Sat, 7 Oct 2000 16:02:37 +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 e9772Yr75921
	for <acpi-jp@jp.freebsd.org>; Sat, 7 Oct 2000 16:02:34 +0900 (JST)
	(envelope-from iwasaki@jp.FreeBSD.org)
To: acpi-jp@jp.freebsd.org
In-Reply-To: <20001007042124G.iwasaki@jp.FreeBSD.org>
References: <20001006235205R.iwasaki@jp.FreeBSD.org>
	<200010061900.e96J0Uh06929@mass.osd.bsdi.com>
	<20001007042124G.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=us-ascii
Content-Transfer-Encoding: 7bit
Message-Id: <20001007160232T.iwasaki@jp.FreeBSD.org>
Date: Sat, 07 Oct 2000 16:02:32 +0900
From: Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
X-Dispatcher: imput version 20000228(IM140)
Lines: 457
Reply-To: acpi-jp@jp.freebsd.org
Precedence: list
X-Distribute: distribute version 2.1 (Alpha) patchlevel 24e+000315
X-Sequence: acpi-jp 813
Subject: [acpi-jp 813] Re: acpi_lid patch 
Errors-To: owner-acpi-jp@jp.freebsd.org
Sender: owner-acpi-jp@jp.freebsd.org
X-Originator: iwasaki@jp.freebsd.org

Hi,

> > > BTW, does anybody woking on Power/Sleep button driver?  If no, I'm
> > > going to try it.
> > 
> > Nobody has said anything to me about it, so I assume not.
> 
> OK, I'll try it tomorrow.

Here is the my latest patch for Sx transition by Power/Sleep button
and lid switch.  Some event handlers are shared by fixed-event and
device notification.  I did test Sx transition by both fixed-event and
device notification and it seems work very well for me :-)

Character device code also is included.  Mike, I think we should
support the compatible interface to the older driver if we really
intend to migrate to ACPICA.  Also I believe that making effort on
BSDs portability doesn't hurt anything in the most cases where we can.
I'm sure there are some advantages of BSDs portabbility in terms of
sharing the code and developer-base.
# but I think we don't need to consider it too much for now.
# Implementation for FreeBSD comes first rather than consideration of
# portability :-)

Calling acpi_Disable() from acpi_shutdown_pre_sync() is mandatory for
some machines.  We know that GPE events prevent the system from power off,
I have one machine which have this problem.  Without this code, the
system is immediately turned on again and start booting :-(  The older
driver has this work around.  Also we probably need event handler cleanup
around here.

For acpi_Enable/Disable, I think we should support them unless we can
replace APM with ACPI providing the full power management features
including S2-4.  Many laptop users will use APM for suspending the
system untill full ACPI support (at least power management portion).
I agree with mike, acpi driver have to remember which events are
enabled by the driver and disable the events and re-enable them.  We
should write this up in near future...

Thanks

Index: acpi.c
===================================================================
RCS file: /home/iwasaki/cvs/acpica-bsd/dev/acpica/acpi.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 acpi.c
--- acpi.c	2000/10/05 12:30:37	1.1.1.3
+++ acpi.c	2000/10/07 05:36:00
@@ -48,9 +48,37 @@
 #include "acpi.h"	/* cheat and get them all */
 
 #include <dev/acpica/acpivar.h>
+#include <dev/acpica/acpiio.h>
+#include <dev/acpica/acpieventhandler.h>
 
 MALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices");
 
+/*
+ * Character device 
+ */
+
+static d_open_t		acpiopen;
+static d_close_t	acpiclose;
+static d_ioctl_t	acpiioctl;
+
+#define CDEV_MAJOR 152
+static struct cdevsw acpi_cdevsw = {
+	acpiopen,
+	acpiclose,
+	noread,
+	nowrite,
+	acpiioctl,
+	nopoll,
+	nommap,
+	nostrategy,
+	"acpi",
+	CDEV_MAJOR,
+	nodump,
+	nopsize,
+	0,
+	-1
+};
+
 static void	acpi_identify(driver_t *driver, device_t parent);
 static int	acpi_probe(device_t dev);
 static int	acpi_attach(device_t dev);
@@ -74,6 +102,8 @@
 static void	acpi_set_debugging(void);
 #endif
 
+static void	acpi_system_eventhandler_sleep(void *arg, int state);
+static void	acpi_system_eventhandler_wakeup(void *arg, int state);
 
 static device_method_t acpi_methods[] = {
     /* Device interface */
@@ -220,6 +250,30 @@
 	return(ENXIO);
     }
 
+    /* enable and clear fixed events. */
+    AcpiEnableEvent(ACPI_EVENT_PMTIMER, ACPI_EVENT_FIXED);
+    AcpiEnableEvent(ACPI_EVENT_GLOBAL, ACPI_EVENT_FIXED);
+    AcpiEnableEvent(ACPI_EVENT_POWER_BUTTON, ACPI_EVENT_FIXED);
+    AcpiEnableEvent(ACPI_EVENT_SLEEP_BUTTON, ACPI_EVENT_FIXED);
+    AcpiEnableEvent(ACPI_EVENT_RTC, ACPI_EVENT_FIXED);
+    AcpiClearEvent(ACPI_EVENT_PMTIMER, ACPI_EVENT_FIXED);
+    AcpiClearEvent(ACPI_EVENT_GLOBAL, ACPI_EVENT_FIXED);
+    AcpiClearEvent(ACPI_EVENT_POWER_BUTTON, ACPI_EVENT_FIXED);
+    AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON, ACPI_EVENT_FIXED);
+    AcpiClearEvent(ACPI_EVENT_RTC, ACPI_EVENT_FIXED);
+
+    /*
+     * Dispatch the default sleep state to devices.
+     * TBD: should be configured from userland policy manager.
+     */
+    sc->acpi_power_button_sx = ACPI_POWER_BUTTON_DEFAULT_SX;
+    sc->acpi_sleep_button_sx = ACPI_SLEEP_BUTTON_DEFAULT_SX;
+    sc->acpi_lid_switch_sx = ACPI_LID_SWITCH_DEFAULT_SX;
+
+    /* Install fixed-event handlers */
+    AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, acpi_eventhandler_power_button_for_sleep, sc);
+    AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON, acpi_eventhandler_sleep_button_for_sleep, sc);
+
     /*
      * Scan the namespace and attach/initialise children.
      */
@@ -232,11 +286,20 @@
     EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc, SHUTDOWN_PRI_LAST);
 
     /*
+     * Register our acpi event handlers
+     * TBD: should be configured from userland policy manager.
+     */
+    EVENTHANDLER_REGISTER(acpi_sleep_event, acpi_system_eventhandler_sleep, sc, ACPI_EVENT_PRI_LAST);
+    EVENTHANDLER_REGISTER(acpi_wakeup_event, acpi_system_eventhandler_wakeup, sc, ACPI_EVENT_PRI_LAST);
+
+    /*
      * Flag our initial states.
      */
     sc->acpi_enabled = 1;
     sc->acpi_sstate = ACPI_STATE_S0;
 
+    (make_dev(&acpi_cdevsw, 0, 0, 5, 0660, "acpi"))->si_drv1 = sc;
+
     return(0);
 }
 
@@ -517,8 +580,11 @@
 static void
 acpi_shutdown_pre_sync(void *arg, int howto)
 {
-    /* XXX is this the right thing to do? */
-/*    acpi_Disable((struct acpi_softc *)arg);*/
+    /*
+     * disable all of ACPI events before soft off, otherwise the system
+     * will be turned on again on some laptops.
+     */
+    acpi_Disable((struct acpi_softc *)arg);
 }
 
 static void
@@ -594,8 +660,11 @@
     ACPI_STATUS	status = AE_OK;
 
     switch (state) {
-    case ACPI_STATE_S0:
-	DEVICE_RESUME(root_bus);
+    case ACPI_STATE_S0:	/* XXX only for testing */
+	status = AcpiSetSystemSleepState((UINT8)state);
+	if (status != AE_OK) {
+	    device_printf(sc->acpi_dev, "AcpiSetSystemSleepState failed - %s\n", acpi_strerror(status));
+	}
 	break;
 
     case ACPI_STATE_S1:
@@ -614,10 +683,12 @@
 	    return(AE_ERROR);
 	}
 	sc->acpi_sstate = state;
-	status = AcpiSetSystemSleepState(state);
+	status = AcpiSetSystemSleepState((UINT8)state);
 	if (status != AE_OK) {
 	    device_printf(sc->acpi_dev, "AcpiSetSystemSleepState failed - %s\n", acpi_strerror(status));
 	}
+	DEVICE_RESUME(root_bus);
+	sc->acpi_sstate = ACPI_STATE_S0;
 	break;
 
     case ACPI_STATE_S5:
@@ -642,9 +713,12 @@
 acpi_Enable(struct acpi_softc *sc)
 {
     ACPI_STATUS	status;
+    u_int32_t	flags;
 
+    flags = ACPI_NO_ADDRESS_SPACE_INIT | ACPI_NO_HARDWARE_INIT |
+            ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT;
     if (!sc->acpi_enabled) {
-	status = AcpiEnable();
+	status = AcpiEnableSubsystem(flags);
     } else {
 	status = AE_OK;
     }
@@ -689,6 +763,63 @@
     return("(error formatting exception)");
 }
 
+
+static int
+acpiopen(dev_t dev, int flag, int fmt, struct proc * p)
+{
+    return (0);
+}
+
+static int
+acpiclose(dev_t dev, int flag, int fmt, struct proc * p)
+{
+    return (0);
+}
+
+static int
+acpiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc * p)
+{
+    int		error, state;
+    struct acpi_softc	*sc;
+
+    error = state = 0;
+    sc = dev->si_drv1;
+
+    switch (cmd) {
+    case ACPIIO_ENABLE:
+	if (ACPI_FAILURE(acpi_Enable(sc))) {
+	    error = ENXIO;
+	}
+	break;
+
+    case ACPIIO_DISABLE:
+	if (ACPI_FAILURE(acpi_Disable(sc))) {
+	    error = ENXIO;
+	}
+	break;
+
+    case ACPIIO_SETSLPSTATE:
+	if (!sc->acpi_enabled) {
+	    error = ENXIO;
+	    break;
+	}
+	state = *(int *)addr;
+	if (state >= ACPI_STATE_S0  && state <= ACPI_STATE_S5) {
+	    acpi_SetSleepState(sc, state);
+	} else {
+	    error = EINVAL;
+	}
+
+	break;
+
+    default:
+	error = EINVAL;
+	break;
+    }
+
+    return(error);
+}
+
 #ifdef ACPI_DEBUG
 struct debugtag
 {
@@ -794,4 +925,65 @@
     
 }
 #endif
+
+/*
+ * ACPI Event Handlers
+ */
+
+/* System Event Handlers (registered by EVENTHANDLER_REGISTER) */
+
+static void
+acpi_system_eventhandler_sleep(void *arg, int state)
+{
+    if (state < ACPI_STATE_S0 || state > ACPI_STATE_S5) {
+	return;
+    }
+
+    acpi_SetSleepState((struct acpi_softc *)arg, state);
+}
+
+
+static void
+acpi_system_eventhandler_wakeup(void *arg, int state)
+{
+    /* Well, what to do? :-) */
+}
+
+/* ACPICA Event Handlers (FixedEvent, also called from button notify handler) */
+
+UINT32
+acpi_eventhandler_power_button_for_sleep(void *context)
+{
+    struct acpi_softc	*sc = (struct acpi_softc *)context;
+
+    EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_power_button_sx);
+    return (INTERRUPT_HANDLED);
+}
+
+UINT32
+acpi_eventhandler_power_button_for_wakeup(void *context)
+{
+    struct acpi_softc	*sc = (struct acpi_softc *)context;
+
+    EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_power_button_sx);
+    return (INTERRUPT_HANDLED);
+}
+
+UINT32
+acpi_eventhandler_sleep_button_for_sleep(void *context)
+{
+    struct acpi_softc	*sc = (struct acpi_softc *)context;
+
+    EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_sleep_button_sx);
+    return (INTERRUPT_HANDLED);
+}
+
+UINT32
+acpi_eventhandler_sleep_button_for_wakeup(void *context)
+{
+    struct acpi_softc	*sc = (struct acpi_softc *)context;
+
+    EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_sleep_button_sx);
+    return (INTERRUPT_HANDLED);
+}
 
Index: acpivar.h
===================================================================
RCS file: /home/iwasaki/cvs/acpica-bsd/dev/acpica/acpivar.h,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 acpivar.h
--- acpivar.h	2000/10/05 12:30:37	1.1.1.3
+++ acpivar.h	2000/10/07 05:28:44
@@ -40,6 +40,13 @@
 
     int			acpi_enabled;
     int			acpi_sstate;
+
+#define ACPI_POWER_BUTTON_DEFAULT_SX	ACPI_STATE_S5;
+#define ACPI_SLEEP_BUTTON_DEFAULT_SX	ACPI_STATE_S1;
+#define ACPI_LID_SWITCH_DEFAULT_SX	ACPI_STATE_S1;
+    int			acpi_power_button_sx;
+    int			acpi_sleep_button_sx;
+    int			acpi_lid_switch_sx;
 };
 
 struct acpi_device {
@@ -133,4 +140,24 @@
 
 /* XXX this is ugly */
 extern char		*acpi_strerror(ACPI_STATUS excep);
+
+/* ACPICA event handlers */
+extern UINT32		acpi_eventhandler_power_button_for_sleep(void *context);
+extern UINT32		acpi_eventhandler_power_button_for_wakeup(void *context);
+extern UINT32		acpi_eventhandler_sleep_button_for_sleep(void *context);
+extern UINT32		acpi_eventhandler_sleep_button_for_wakeup(void *context);
+
+/* Misc. */
+
+static __inline struct acpi_softc *
+acpi_device_get_parent_softc(device_t child)
+{
+    device_t	parent;
+
+    parent = device_get_parent(child);
+    if (parent == NULL) {
+	return(NULL);
+    }
+    return(device_get_softc(parent));
+}
 
--- /dev/null	Sat Oct  7 10:23:21 2000
+++ acpieventhandler.h	Sat Oct  7 15:07:36 2000
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	$FreeBSD$
+ */
+
+/* ACPI events */
+
+#define ACPI_EVENT_PRI_FIRST      0
+#define ACPI_EVENT_PRI_DEFAULT    10000
+#define ACPI_EVENT_PRI_LAST       20000
+
+typedef void (*acpi_event_handler_t) __P((void *, int));
+
+EVENTHANDLER_DECLARE(acpi_sleep_event, acpi_event_handler_t);
+EVENTHANDLER_DECLARE(acpi_wakeup_event, acpi_event_handler_t);
+
--- acpi_lid.c-	Sat Oct  7 13:06:08 2000
+++ acpi_lid.c	Sat Oct  7 14:53:09 2000
@@ -47,6 +47,7 @@
 #include "acpi.h"	/* cheat and get them all */
 
 #include <dev/acpica/acpivar.h>
+#include <dev/acpica/acpieventhandler.h>
 
 struct acpi_lid_softc {
     device_t	lid_dev;
@@ -109,6 +110,7 @@
 acpi_lid_notify_status_changed(void *arg)
 {
     struct acpi_lid_softc	*sc;
+    struct acpi_softc		*acpi_sc;
     ACPI_BUFFER			Buffer;
     ACPI_OBJECT			Object;
 
@@ -133,8 +135,15 @@
 
     device_printf(sc->lid_dev, "status changed: %d\n", sc->lid_status);
 
+    acpi_sc = acpi_device_get_parent_softc(sc->lid_dev);
+    if (acpi_sc == NULL) {
+        return;
+    }
+
     if (sc->lid_status == 0) {
-	/* TODO: generate Sleep event. */
+	EVENTHANDLER_INVOKE(acpi_sleep_event, acpi_sc->acpi_lid_switch_sx);
+    } else {
+	EVENTHANDLER_INVOKE(acpi_wakeup_event, acpi_sc->acpi_lid_switch_sx);
     }
 }
 
