167761Smsmith/*-
267761Smsmith * Copyright (c) 2000 Takanori Watanabe <takawata@jp.freebsd.org>
367761Smsmith * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
467761Smsmith * Copyright (c) 2000 Michael Smith <msmith@freebd.org>
567761Smsmith * Copyright (c) 2000 BSDi
667761Smsmith * All rights reserved.
767761Smsmith *
867761Smsmith * Redistribution and use in source and binary forms, with or without
967761Smsmith * modification, are permitted provided that the following conditions
1067761Smsmith * are met:
1167761Smsmith * 1. Redistributions of source code must retain the above copyright
1267761Smsmith *    notice, this list of conditions and the following disclaimer.
1367761Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1467761Smsmith *    notice, this list of conditions and the following disclaimer in the
1567761Smsmith *    documentation and/or other materials provided with the distribution.
1667761Smsmith *
1767761Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1867761Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1967761Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2067761Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2167761Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2267761Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2367761Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2467761Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2567761Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2667761Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2767761Smsmith * SUCH DAMAGE.
2867761Smsmith */
2967761Smsmith
30119418Sobrien#include <sys/cdefs.h>
31119418Sobrien__FBSDID("$FreeBSD$");
32119418Sobrien
3367761Smsmith#include "opt_acpi.h"
3467761Smsmith#include <sys/param.h>
3567761Smsmith#include <sys/kernel.h>
36129879Sphk#include <sys/module.h>
3767761Smsmith#include <sys/bus.h>
3874914Sjhb#include <sys/proc.h>
3967761Smsmith
40193530Sjkim#include <contrib/dev/acpica/include/acpi.h>
41193530Sjkim#include <contrib/dev/acpica/include/accommon.h>
42193530Sjkim
4367761Smsmith#include <dev/acpica/acpivar.h>
4467761Smsmith
45119529Snjl/* Hooks for the ACPI CA debugging infrastructure */
4677432Smsmith#define _COMPONENT	ACPI_BUTTON
4791123SmsmithACPI_MODULE_NAME("LID")
4869744Smsmith
4967761Smsmithstruct acpi_lid_softc {
5067761Smsmith    device_t	lid_dev;
5167761Smsmith    ACPI_HANDLE	lid_handle;
5267761Smsmith    int		lid_status;	/* open or closed */
5367761Smsmith};
5467761Smsmith
55133618SnjlACPI_SERIAL_DECL(lid, "ACPI lid");
56133618Snjl
5767761Smsmithstatic int	acpi_lid_probe(device_t dev);
5867761Smsmithstatic int	acpi_lid_attach(device_t dev);
59100497Siwasakistatic int	acpi_lid_suspend(device_t dev);
60100497Siwasakistatic int	acpi_lid_resume(device_t dev);
6167761Smsmithstatic void	acpi_lid_notify_status_changed(void *arg);
62121493Snjlstatic void 	acpi_lid_notify_handler(ACPI_HANDLE h, UINT32 notify,
63121493Snjl					void *context);
6467761Smsmith
6567761Smsmithstatic device_method_t acpi_lid_methods[] = {
6667761Smsmith    /* Device interface */
6767761Smsmith    DEVMETHOD(device_probe,	acpi_lid_probe),
6867761Smsmith    DEVMETHOD(device_attach,	acpi_lid_attach),
69100497Siwasaki    DEVMETHOD(device_suspend,	acpi_lid_suspend),
70100497Siwasaki    DEVMETHOD(device_resume,	acpi_lid_resume),
7167761Smsmith
72246128Ssbz    DEVMETHOD_END
7367761Smsmith};
7467761Smsmith
7567761Smsmithstatic driver_t acpi_lid_driver = {
7667761Smsmith    "acpi_lid",
7767761Smsmith    acpi_lid_methods,
7867761Smsmith    sizeof(struct acpi_lid_softc),
7967761Smsmith};
8067761Smsmith
8189054Smsmithstatic devclass_t acpi_lid_devclass;
8267761SmsmithDRIVER_MODULE(acpi_lid, acpi, acpi_lid_driver, acpi_lid_devclass, 0, 0);
83128071SnjlMODULE_DEPEND(acpi_lid, acpi, 1, 1, 1);
8467761Smsmith
8567761Smsmithstatic int
8667761Smsmithacpi_lid_probe(device_t dev)
8767761Smsmith{
88131282Snjl    static char *lid_ids[] = { "PNP0C0D", NULL };
89119529Snjl
90131282Snjl    if (acpi_disabled("lid") ||
91131282Snjl	ACPI_ID_PROBE(device_get_parent(dev), dev, lid_ids) == NULL)
92131282Snjl	return (ENXIO);
93131282Snjl
94131282Snjl    device_set_desc(dev, "Control Method Lid Switch");
95131282Snjl    return (0);
9667761Smsmith}
9767761Smsmith
9867761Smsmithstatic int
9967761Smsmithacpi_lid_attach(device_t dev)
10067761Smsmith{
101209746Sjkim    struct acpi_prw_data	prw;
10267761Smsmith    struct acpi_lid_softc	*sc;
10367761Smsmith
10496926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
10569744Smsmith
10667761Smsmith    sc = device_get_softc(dev);
10767761Smsmith    sc->lid_dev = dev;
10867761Smsmith    sc->lid_handle = acpi_get_handle(dev);
10967761Smsmith
110129692Snjl    /*
111129692Snjl     * If a system does not get lid events, it may make sense to change
112129692Snjl     * the type to ACPI_ALL_NOTIFY.  Some systems generate both a wake and
113129692Snjl     * runtime notify in that case though.
114129692Snjl     */
115119529Snjl    AcpiInstallNotifyHandler(sc->lid_handle, ACPI_DEVICE_NOTIFY,
116119529Snjl			     acpi_lid_notify_handler, sc);
117119529Snjl
118129783Snjl    /* Enable the GPE for wake/runtime. */
119129783Snjl    acpi_wake_set_enable(dev, 1);
120209746Sjkim    if (acpi_parse_prw(sc->lid_handle, &prw) == 0)
121209746Sjkim	AcpiEnableGpe(prw.gpe_handle, prw.gpe_bit);
122129783Snjl
123133618Snjl    return (0);
12467761Smsmith}
12567761Smsmith
126100497Siwasakistatic int
127100497Siwasakiacpi_lid_suspend(device_t dev)
128100497Siwasaki{
129100497Siwasaki    return (0);
130100497Siwasaki}
131100497Siwasaki
132100497Siwasakistatic int
133100497Siwasakiacpi_lid_resume(device_t dev)
134100497Siwasaki{
135100497Siwasaki    return (0);
136100497Siwasaki}
137100497Siwasaki
13867761Smsmithstatic void
13967761Smsmithacpi_lid_notify_status_changed(void *arg)
14067761Smsmith{
14167761Smsmith    struct acpi_lid_softc	*sc;
14267761Smsmith    struct acpi_softc		*acpi_sc;
143119529Snjl    ACPI_STATUS			status;
14467761Smsmith
14596926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
14669744Smsmith
14767761Smsmith    sc = (struct acpi_lid_softc *)arg;
148134305Snjl    ACPI_SERIAL_BEGIN(lid);
14967761Smsmith
15067761Smsmith    /*
15171872Smsmith     * Evaluate _LID and check the return value, update lid status.
15267761Smsmith     *	Zero:		The lid is closed
15367761Smsmith     *	Non-zero:	The lid is open
15467761Smsmith     */
155134305Snjl    status = acpi_GetInteger(sc->lid_handle, "_LID", &sc->lid_status);
156119529Snjl    if (ACPI_FAILURE(status))
157134305Snjl	goto out;
15867761Smsmith
159134305Snjl    acpi_sc = acpi_device_get_parent_softc(sc->lid_dev);
160134305Snjl    if (acpi_sc == NULL)
161134305Snjl	goto out;
16267761Smsmith
163134305Snjl    ACPI_VPRINT(sc->lid_dev, acpi_sc, "Lid %s\n",
164134305Snjl		sc->lid_status ? "opened" : "closed");
16586552Siwasaki
166134305Snjl    acpi_UserNotify("Lid", sc->lid_handle, sc->lid_status);
167121493Snjl
168134305Snjl    if (sc->lid_status == 0)
169134305Snjl	EVENTHANDLER_INVOKE(acpi_sleep_event, acpi_sc->acpi_lid_switch_sx);
170134305Snjl    else
171134305Snjl	EVENTHANDLER_INVOKE(acpi_wakeup_event, acpi_sc->acpi_lid_switch_sx);
172134305Snjl
173133618Snjlout:
174133618Snjl    ACPI_SERIAL_END(lid);
17569744Smsmith    return_VOID;
17667761Smsmith}
17767761Smsmith
17867761Smsmith/* XXX maybe not here */
17967761Smsmith#define	ACPI_NOTIFY_STATUS_CHANGED	0x80
18067761Smsmith
18167761Smsmithstatic void
18267761Smsmithacpi_lid_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
18367761Smsmith{
184129692Snjl    struct acpi_lid_softc	*sc;
18567761Smsmith
18696926Speter    ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
18769744Smsmith
188129692Snjl    sc = (struct acpi_lid_softc *)context;
18967761Smsmith    switch (notify) {
19067761Smsmith    case ACPI_NOTIFY_STATUS_CHANGED:
191167814Sjkim	AcpiOsExecute(OSL_NOTIFY_HANDLER,
192167814Sjkim		      acpi_lid_notify_status_changed, sc);
19367761Smsmith	break;
19467761Smsmith    default:
195129692Snjl	device_printf(sc->lid_dev, "unknown notify %#x\n", notify);
196119529Snjl	break;
19767761Smsmith    }
198119529Snjl
19969744Smsmith    return_VOID;
20067761Smsmith}
201