xref: /freebsd/sys/dev/acpica/acpi_button.c (revision 9b937d48)
115e32d5dSMike Smith /*-
215e32d5dSMike Smith  * Copyright (c) 2000 Mitsaru IWASAKI <iwasaki@jp.freebsd.org>
315e32d5dSMike Smith  * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
415e32d5dSMike Smith  * Copyright (c) 2000 BSDi
515e32d5dSMike Smith  * All rights reserved.
615e32d5dSMike Smith  *
715e32d5dSMike Smith  * Redistribution and use in source and binary forms, with or without
815e32d5dSMike Smith  * modification, are permitted provided that the following conditions
915e32d5dSMike Smith  * are met:
1015e32d5dSMike Smith  * 1. Redistributions of source code must retain the above copyright
1115e32d5dSMike Smith  *    notice, this list of conditions and the following disclaimer.
1215e32d5dSMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
1315e32d5dSMike Smith  *    notice, this list of conditions and the following disclaimer in the
1415e32d5dSMike Smith  *    documentation and/or other materials provided with the distribution.
1515e32d5dSMike Smith  *
1615e32d5dSMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1715e32d5dSMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1815e32d5dSMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1915e32d5dSMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2015e32d5dSMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2115e32d5dSMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2215e32d5dSMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2315e32d5dSMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2415e32d5dSMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2515e32d5dSMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2615e32d5dSMike Smith  * SUCH DAMAGE.
2715e32d5dSMike Smith  *
2815e32d5dSMike Smith  *	$FreeBSD$
2915e32d5dSMike Smith  */
3015e32d5dSMike Smith 
3115e32d5dSMike Smith #include "opt_acpi.h"
3215e32d5dSMike Smith #include <sys/param.h>
3315e32d5dSMike Smith #include <sys/kernel.h>
3415e32d5dSMike Smith #include <sys/bus.h>
3515e32d5dSMike Smith 
3615e32d5dSMike Smith #include "acpi.h"
3715e32d5dSMike Smith #include <dev/acpica/acpivar.h>
3815e32d5dSMike Smith 
39798fb860SNate Lawson /* Hooks for the ACPI CA debugging infrastructure */
402a4ac806SMike Smith #define _COMPONENT	ACPI_BUTTON
419127281cSMike Smith ACPI_MODULE_NAME("BUTTON")
420ae55423SMike Smith 
4315e32d5dSMike Smith struct acpi_button_softc {
4415e32d5dSMike Smith     device_t	button_dev;
4515e32d5dSMike Smith     ACPI_HANDLE	button_handle;
46be8dca59SNate Lawson     boolean_t	button_type;
4715e32d5dSMike Smith #define		ACPI_POWER_BUTTON	0
4815e32d5dSMike Smith #define		ACPI_SLEEP_BUTTON	1
49be8dca59SNate Lawson     boolean_t	fixed;
5015e32d5dSMike Smith };
5115e32d5dSMike Smith 
52798fb860SNate Lawson #define		ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP	0x80
53798fb860SNate Lawson #define		ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP	0x02
54798fb860SNate Lawson 
5515e32d5dSMike Smith static int	acpi_button_probe(device_t dev);
5615e32d5dSMike Smith static int	acpi_button_attach(device_t dev);
57a1fccb47SMitsuru IWASAKI static int	acpi_button_suspend(device_t dev);
58a1fccb47SMitsuru IWASAKI static int	acpi_button_resume(device_t dev);
59798fb860SNate Lawson static void 	acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify,
60798fb860SNate Lawson 					   void *context);
61be8dca59SNate Lawson static ACPI_STATUS
62be8dca59SNate Lawson 		acpi_button_fixed_handler(void *context);
6315e32d5dSMike Smith static void	acpi_button_notify_pressed_for_sleep(void *arg);
6415e32d5dSMike Smith static void	acpi_button_notify_pressed_for_wakeup(void *arg);
6515e32d5dSMike Smith 
6615e32d5dSMike Smith static device_method_t acpi_button_methods[] = {
6715e32d5dSMike Smith     /* Device interface */
6815e32d5dSMike Smith     DEVMETHOD(device_probe,	acpi_button_probe),
6915e32d5dSMike Smith     DEVMETHOD(device_attach,	acpi_button_attach),
70a1fccb47SMitsuru IWASAKI     DEVMETHOD(device_suspend,	acpi_button_suspend),
7162d4c42bSTakanori Watanabe     DEVMETHOD(device_shutdown,	acpi_button_suspend),
72a1fccb47SMitsuru IWASAKI     DEVMETHOD(device_resume,	acpi_button_resume),
7315e32d5dSMike Smith 
7415e32d5dSMike Smith     {0, 0}
7515e32d5dSMike Smith };
7615e32d5dSMike Smith 
7715e32d5dSMike Smith static driver_t acpi_button_driver = {
7815e32d5dSMike Smith     "acpi_button",
7915e32d5dSMike Smith     acpi_button_methods,
8015e32d5dSMike Smith     sizeof(struct acpi_button_softc),
8115e32d5dSMike Smith };
8215e32d5dSMike Smith 
833273b005SMike Smith static devclass_t acpi_button_devclass;
84798fb860SNate Lawson DRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass,
85798fb860SNate Lawson 	      0, 0);
8615e32d5dSMike Smith 
8715e32d5dSMike Smith static int
8815e32d5dSMike Smith acpi_button_probe(device_t dev)
8915e32d5dSMike Smith {
9015e32d5dSMike Smith     struct acpi_button_softc	*sc;
91be8dca59SNate Lawson     int ret = ENXIO;
9215e32d5dSMike Smith 
9315e32d5dSMike Smith     sc = device_get_softc(dev);
94be8dca59SNate Lawson     if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("button")) {
9515e32d5dSMike Smith 	if (acpi_MatchHid(dev, "PNP0C0C")) {
9667ce1673SMike Smith 	    device_set_desc(dev, "Power Button");
9715e32d5dSMike Smith 	    sc->button_type = ACPI_POWER_BUTTON;
98be8dca59SNate Lawson 	    ret = 0;
99be8dca59SNate Lawson 	} else if (acpi_MatchHid(dev, "ACPI_FPB")) {
100be8dca59SNate Lawson 	    device_set_desc(dev, "Power Button (fixed)");
101be8dca59SNate Lawson 	    sc->button_type = ACPI_POWER_BUTTON;
102be8dca59SNate Lawson 	    sc->fixed = 1;
103be8dca59SNate Lawson 	    ret = 0;
104be8dca59SNate Lawson 	} else if (acpi_MatchHid(dev, "PNP0C0E")) {
10567ce1673SMike Smith 	    device_set_desc(dev, "Sleep Button");
10615e32d5dSMike Smith 	    sc->button_type = ACPI_SLEEP_BUTTON;
107be8dca59SNate Lawson 	    ret = 0;
108be8dca59SNate Lawson 	} else if (acpi_MatchHid(dev, "ACPI_FSB")) {
109be8dca59SNate Lawson 	    device_set_desc(dev, "Sleep Button (fixed)");
110be8dca59SNate Lawson 	    sc->button_type = ACPI_SLEEP_BUTTON;
111be8dca59SNate Lawson 	    sc->fixed = 1;
112be8dca59SNate Lawson 	    ret = 0;
11315e32d5dSMike Smith 	}
1140ae55423SMike Smith     }
115be8dca59SNate Lawson     return (ret);
11615e32d5dSMike Smith }
11715e32d5dSMike Smith 
11815e32d5dSMike Smith static int
11915e32d5dSMike Smith acpi_button_attach(device_t dev)
12015e32d5dSMike Smith {
12115e32d5dSMike Smith     struct acpi_button_softc	*sc;
12215e32d5dSMike Smith     ACPI_STATUS			status;
123be8dca59SNate Lawson     int event;
12415e32d5dSMike Smith 
125b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1260ae55423SMike Smith 
12715e32d5dSMike Smith     sc = device_get_softc(dev);
12815e32d5dSMike Smith     sc->button_dev = dev;
12915e32d5dSMike Smith     sc->button_handle = acpi_get_handle(dev);
13015e32d5dSMike Smith 
131be8dca59SNate Lawson     if (sc->fixed) {
132be8dca59SNate Lawson 	event = (sc->button_type == ACPI_SLEEP_BUTTON) ?
133be8dca59SNate Lawson 		ACPI_EVENT_SLEEP_BUTTON : ACPI_EVENT_POWER_BUTTON;
134be8dca59SNate Lawson 	status = AcpiInstallFixedEventHandler(event,
135be8dca59SNate Lawson 			acpi_button_fixed_handler, sc);
136be8dca59SNate Lawson     } else {
137be8dca59SNate Lawson 	status = AcpiInstallNotifyHandler(sc->button_handle,
138be8dca59SNate Lawson 			ACPI_DEVICE_NOTIFY, acpi_button_notify_handler, sc);
139be8dca59SNate Lawson     }
140798fb860SNate Lawson     if (ACPI_FAILURE(status)) {
141be8dca59SNate Lawson 	device_printf(sc->button_dev, "couldn't install notify handler - %s\n",
142798fb860SNate Lawson 		      AcpiFormatException(status));
1430ae55423SMike Smith 	return_VALUE (ENXIO);
14415e32d5dSMike Smith     }
145a1fccb47SMitsuru IWASAKI     acpi_device_enable_wake_capability(sc->button_handle, 1);
1460ae55423SMike Smith     return_VALUE (0);
14715e32d5dSMike Smith }
14815e32d5dSMike Smith 
149a1fccb47SMitsuru IWASAKI static int
150a1fccb47SMitsuru IWASAKI acpi_button_suspend(device_t dev)
151a1fccb47SMitsuru IWASAKI {
152a1fccb47SMitsuru IWASAKI     struct acpi_button_softc	*sc;
153a1fccb47SMitsuru IWASAKI 
154a1fccb47SMitsuru IWASAKI     sc = device_get_softc(dev);
155a1fccb47SMitsuru IWASAKI     acpi_device_enable_wake_event(sc->button_handle);
156a1fccb47SMitsuru IWASAKI     return (0);
157a1fccb47SMitsuru IWASAKI }
158a1fccb47SMitsuru IWASAKI 
159a1fccb47SMitsuru IWASAKI static int
160a1fccb47SMitsuru IWASAKI acpi_button_resume(device_t dev)
161a1fccb47SMitsuru IWASAKI {
162a1fccb47SMitsuru IWASAKI     return (0);
163a1fccb47SMitsuru IWASAKI }
164a1fccb47SMitsuru IWASAKI 
16515e32d5dSMike Smith static void
16615e32d5dSMike Smith acpi_button_notify_pressed_for_sleep(void *arg)
16715e32d5dSMike Smith {
16815e32d5dSMike Smith     struct acpi_button_softc	*sc;
16915e32d5dSMike Smith     struct acpi_softc		*acpi_sc;
17015e32d5dSMike Smith 
171b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1720ae55423SMike Smith 
17315e32d5dSMike Smith     sc = (struct acpi_button_softc *)arg;
17415e32d5dSMike Smith     acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
175798fb860SNate Lawson     if (acpi_sc == NULL)
1760ae55423SMike Smith 	return_VOID;
17715e32d5dSMike Smith 
1789b937d48SNate Lawson     acpi_UserNotify("Button", sc->button_handle, sc->button_type);
1799b937d48SNate Lawson 
18015e32d5dSMike Smith     switch (sc->button_type) {
18115e32d5dSMike Smith     case ACPI_POWER_BUTTON:
182e788f796SBruce Evans 	ACPI_VPRINT(sc->button_dev, acpi_sc, "power button pressed\n");
18315e32d5dSMike Smith 	acpi_eventhandler_power_button_for_sleep((void *)acpi_sc);
18415e32d5dSMike Smith 	break;
18515e32d5dSMike Smith     case ACPI_SLEEP_BUTTON:
186e788f796SBruce Evans 	ACPI_VPRINT(sc->button_dev, acpi_sc, "sleep button pressed\n");
18715e32d5dSMike Smith 	acpi_eventhandler_sleep_button_for_sleep((void *)acpi_sc);
18815e32d5dSMike Smith 	break;
18915e32d5dSMike Smith     default:
1900ae55423SMike Smith 	break;		/* unknown button type */
19115e32d5dSMike Smith     }
19215e32d5dSMike Smith }
19315e32d5dSMike Smith 
19415e32d5dSMike Smith static void
19515e32d5dSMike Smith acpi_button_notify_pressed_for_wakeup(void *arg)
19615e32d5dSMike Smith {
19715e32d5dSMike Smith     struct acpi_button_softc	*sc;
19815e32d5dSMike Smith     struct acpi_softc		*acpi_sc;
19915e32d5dSMike Smith 
200b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
2010ae55423SMike Smith 
20215e32d5dSMike Smith     sc = (struct acpi_button_softc *)arg;
20315e32d5dSMike Smith     acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
204798fb860SNate Lawson     if (acpi_sc == NULL)
2050ae55423SMike Smith 	return_VOID;
20615e32d5dSMike Smith 
2079b937d48SNate Lawson     acpi_UserNotify("Button", sc->button_handle, sc->button_type);
2089b937d48SNate Lawson 
20915e32d5dSMike Smith     switch (sc->button_type) {
21015e32d5dSMike Smith     case ACPI_POWER_BUTTON:
211e788f796SBruce Evans 	ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by power button\n");
21215e32d5dSMike Smith 	acpi_eventhandler_power_button_for_wakeup((void *)acpi_sc);
21315e32d5dSMike Smith 	break;
21415e32d5dSMike Smith     case ACPI_SLEEP_BUTTON:
215e788f796SBruce Evans 	ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by sleep button\n");
21615e32d5dSMike Smith 	acpi_eventhandler_sleep_button_for_wakeup((void *)acpi_sc);
21715e32d5dSMike Smith 	break;
21815e32d5dSMike Smith     default:
2190ae55423SMike Smith 	break;		/* unknown button type */
22015e32d5dSMike Smith     }
22115e32d5dSMike Smith }
22215e32d5dSMike Smith 
22315e32d5dSMike Smith static void
22415e32d5dSMike Smith acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
22515e32d5dSMike Smith {
22615e32d5dSMike Smith     struct acpi_button_softc	*sc = (struct acpi_button_softc *)context;
22715e32d5dSMike Smith 
228b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
2290ae55423SMike Smith 
23015e32d5dSMike Smith     switch (notify) {
23115e32d5dSMike Smith     case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP:
232798fb860SNate Lawson 	AcpiOsQueueForExecution(OSD_PRIORITY_LO,
233798fb860SNate Lawson 				acpi_button_notify_pressed_for_sleep, sc);
23415e32d5dSMike Smith 	break;
23515e32d5dSMike Smith     case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP:
236798fb860SNate Lawson 	AcpiOsQueueForExecution(OSD_PRIORITY_LO,
237798fb860SNate Lawson 				acpi_button_notify_pressed_for_wakeup, sc);
23815e32d5dSMike Smith 	break;
23915e32d5dSMike Smith     default:
2400ae55423SMike Smith 	break;		/* unknown notification value */
24115e32d5dSMike Smith     }
24215e32d5dSMike Smith }
243be8dca59SNate Lawson 
244be8dca59SNate Lawson static ACPI_STATUS
245be8dca59SNate Lawson acpi_button_fixed_handler(void *context)
246be8dca59SNate Lawson {
247be8dca59SNate Lawson     struct acpi_button_softc	*sc = (struct acpi_button_softc *)context;
248be8dca59SNate Lawson 
249a6a1d015SNate Lawson     ACPI_FUNCTION_TRACE_PTR((char *)(uintptr_t)__func__, context);
250d2f243d0SPoul-Henning Kamp 
251be8dca59SNate Lawson     if (context == NULL)
252be8dca59SNate Lawson 	return_ACPI_STATUS (AE_BAD_PARAMETER);
253be8dca59SNate Lawson 
254be8dca59SNate Lawson     acpi_button_notify_handler(sc->button_handle,
255be8dca59SNate Lawson 			       ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP, sc);
256a6a1d015SNate Lawson     return_ACPI_STATUS (AE_OK);
257be8dca59SNate Lawson }
258