1 /* $NetBSD: acpi_wakedev.c,v 1.1 2009/08/04 14:20:40 jmcneill Exp $ */
4 * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: acpi_wakedev.c,v 1.1 2009/08/04 14:20:40 jmcneill Exp $");
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/kernel.h>
36 #include <sys/device.h>
37 #include <sys/queue.h>
38 #include <sys/sysctl.h>
40 #include <dev/acpi/acpivar.h>
41 #include <dev/acpi/acpireg.h>
42 #include <dev/acpi/acpi_wakedev.h>
46 static TAILQ_HEAD(, acpi_wakedev
) acpi_wakedevlist
=
47 TAILQ_HEAD_INITIALIZER(acpi_wakedevlist
);
48 static int acpi_wakedev_node
= -1;
51 struct acpi_devnode
*aw_node
;
53 struct sysctllog
*aw_sysctllog
;
54 TAILQ_ENTRY(acpi_wakedev
) aw_list
;
57 static const char * const acpi_wakedev_default
[] = {
58 "PNP0C0C", /* power button */
59 "PNP0C0E", /* sleep button */
60 "PNP0C0D", /* lid switch */
61 "PNP03??", /* PC KBD port */
65 SYSCTL_SETUP(sysctl_acpi_wakedev_setup
, "sysctl hw.wake subtree setup")
67 const struct sysctlnode
*rnode
;
70 err
= sysctl_createv(NULL
, 0, NULL
, NULL
,
72 CTLTYPE_NODE
, "hw", NULL
,
73 NULL
, 0, NULL
, 0, CTL_HW
, CTL_EOL
);
76 err
= sysctl_createv(NULL
, 0, NULL
, &rnode
,
78 CTLTYPE_NODE
, "wake", NULL
,
80 CTL_HW
, CTL_CREATE
, CTL_EOL
);
83 acpi_wakedev_node
= rnode
->sysctl_num
;
87 acpi_wakedev_sysctl_add(struct acpi_wakedev
*aw
)
91 if (acpi_wakedev_node
== -1)
94 err
= sysctl_createv(&aw
->aw_sysctllog
, 0, NULL
, NULL
,
95 CTLFLAG_READWRITE
, CTLTYPE_INT
, aw
->aw_node
->ad_name
,
96 NULL
, NULL
, 0, &aw
->aw_enabled
, 0,
97 CTL_HW
, acpi_wakedev_node
, CTL_CREATE
, CTL_EOL
);
99 printf("acpi_wakedev_sysctl_add: "
100 "sysctl_createv(hw.wake.%s) failed. (%d)\n",
101 aw
->aw_node
->ad_name
, err
);
105 acpi_wakedev_add(struct acpi_softc
*sc
, struct acpi_devnode
*ad
)
107 struct acpi_wakedev
*aw
;
110 if (ACPI_FAILURE(AcpiGetHandle(ad
->ad_handle
, "_PRW", &hdl
)))
113 aw
= kmem_alloc(sizeof(*aw
), KM_SLEEP
);
115 aprint_error("acpi_wakedev_add: kmem_alloc failed\n");
119 aw
->aw_sysctllog
= NULL
;
120 if (acpi_match_hid(ad
->ad_devinfo
, acpi_wakedev_default
))
125 TAILQ_INSERT_TAIL(&acpi_wakedevlist
, aw
, aw_list
);
127 acpi_wakedev_sysctl_add(aw
);
133 acpi_wakedev_print(struct acpi_wakedev
*aw
)
135 aprint_debug(" %s", aw
->aw_node
->ad_name
);
139 acpi_wakedev_scan(struct acpi_softc
*sc
)
141 struct acpi_scope
*as
;
142 struct acpi_devnode
*ad
;
143 struct acpi_wakedev
*aw
;
144 ACPI_DEVICE_INFO
*di
;
147 #define ACPI_STA_DEV_VALID \
148 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED|ACPI_STA_DEV_OK)
150 TAILQ_FOREACH(as
, &sc
->sc_scopes
, as_list
)
151 TAILQ_FOREACH(ad
, &as
->as_devnodes
, ad_list
) {
153 if (di
->Type
!= ACPI_TYPE_DEVICE
)
155 if ((di
->Valid
& ACPI_VALID_STA
) != 0 &&
156 (di
->CurrentStatus
& ACPI_STA_DEV_VALID
) !=
159 if (acpi_wakedev_add(sc
, ad
) == true)
163 #undef ACPI_STA_DEV_VALID
168 aprint_debug_dev(sc
->sc_dev
, "wakeup devices:");
169 TAILQ_FOREACH(aw
, &acpi_wakedevlist
, aw_list
)
170 acpi_wakedev_print(aw
);
177 acpi_wakedev_commit(struct acpi_softc
*sc
)
179 struct acpi_wakedev
*aw
;
181 TAILQ_FOREACH(aw
, &acpi_wakedevlist
, aw_list
) {
182 if (aw
->aw_enabled
) {
183 aprint_debug_dev(sc
->sc_dev
, "set wake GPE (%s)\n",
184 aw
->aw_node
->ad_name
);
185 acpi_set_wake_gpe(aw
->aw_node
->ad_handle
);
187 acpi_clear_wake_gpe(aw
->aw_node
->ad_handle
);