1*1899b7d2Sriastradh /* $NetBSD: wmi_acpi.c,v 1.23 2023/08/11 08:36:59 riastradh Exp $ */
2a913ee75Sjruoho
3a913ee75Sjruoho /*-
4a913ee75Sjruoho * Copyright (c) 2009, 2010 Jukka Ruohonen <jruohonen@iki.fi>
5a913ee75Sjruoho * All rights reserved.
6a913ee75Sjruoho *
7a913ee75Sjruoho * Redistribution and use in source and binary forms, with or without
8a913ee75Sjruoho * modification, are permitted provided that the following conditions
9a913ee75Sjruoho * are met:
10a913ee75Sjruoho *
11a913ee75Sjruoho * 1. Redistributions of source code must retain the above copyright
12a913ee75Sjruoho * notice, this list of conditions and the following disclaimer.
13a913ee75Sjruoho * 2. Redistributions in binary form must reproduce the above copyright
14a913ee75Sjruoho * notice, this list of conditions and the following disclaimer in the
15a913ee75Sjruoho * documentation and/or other materials provided with the distribution.
16a913ee75Sjruoho *
17a913ee75Sjruoho * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18a913ee75Sjruoho * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19a913ee75Sjruoho * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20a913ee75Sjruoho * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21a913ee75Sjruoho * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22a913ee75Sjruoho * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23a913ee75Sjruoho * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24a913ee75Sjruoho * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25a913ee75Sjruoho * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26a913ee75Sjruoho * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27a913ee75Sjruoho * SUCH DAMAGE.
28a913ee75Sjruoho */
29a913ee75Sjruoho #include <sys/cdefs.h>
30*1899b7d2Sriastradh __KERNEL_RCSID(0, "$NetBSD: wmi_acpi.c,v 1.23 2023/08/11 08:36:59 riastradh Exp $");
31a913ee75Sjruoho
32a913ee75Sjruoho #include <sys/param.h>
33a913ee75Sjruoho #include <sys/device.h>
34a913ee75Sjruoho #include <sys/endian.h>
35a913ee75Sjruoho #include <sys/kmem.h>
36a913ee75Sjruoho #include <sys/systm.h>
379750ca2fSjmcneill #include <sys/module.h>
38a913ee75Sjruoho
39a913ee75Sjruoho #include <dev/acpi/acpireg.h>
40a913ee75Sjruoho #include <dev/acpi/acpivar.h>
41639d1b97Sjruoho #include <dev/acpi/acpi_ecvar.h>
42a913ee75Sjruoho #include <dev/acpi/wmi/wmi_acpivar.h>
43a913ee75Sjruoho
44a913ee75Sjruoho #define _COMPONENT ACPI_RESOURCE_COMPONENT
45a913ee75Sjruoho ACPI_MODULE_NAME ("wmi_acpi")
46a913ee75Sjruoho
47a913ee75Sjruoho /*
48a913ee75Sjruoho * This implements something called "Microsoft Windows Management
491cb7819fSandvar * Instrumentation" (WMI). This subset of ACPI is described in:
50a913ee75Sjruoho *
51a913ee75Sjruoho * http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx
52a913ee75Sjruoho *
53a913ee75Sjruoho * (Obtained on Thu Feb 12 18:21:44 EET 2009.)
54a913ee75Sjruoho */
55a913ee75Sjruoho
56a913ee75Sjruoho static int acpi_wmi_match(device_t, cfdata_t, void *);
57a913ee75Sjruoho static void acpi_wmi_attach(device_t, device_t, void *);
58a913ee75Sjruoho static int acpi_wmi_detach(device_t, int);
595991cdfeSjmcneill static int acpi_wmi_rescan(device_t, const char *, const int *);
605991cdfeSjmcneill static void acpi_wmi_childdet(device_t, device_t);
61a913ee75Sjruoho static int acpi_wmi_print(void *, const char *);
62a913ee75Sjruoho static bool acpi_wmi_init(struct acpi_wmi_softc *);
63639d1b97Sjruoho static void acpi_wmi_init_ec(struct acpi_wmi_softc *);
64fd34ea77Schs static void acpi_wmi_add(struct acpi_wmi_softc *, ACPI_OBJECT *);
65a913ee75Sjruoho static void acpi_wmi_del(struct acpi_wmi_softc *);
66460de0d6Sjruoho static void acpi_wmi_dump(struct acpi_wmi_softc *);
67a913ee75Sjruoho static ACPI_STATUS acpi_wmi_guid_get(struct acpi_wmi_softc *,
68a913ee75Sjruoho const char *, struct wmi_t **);
6955052ecaSjruoho static void acpi_wmi_event_add(struct acpi_wmi_softc *);
7055052ecaSjruoho static void acpi_wmi_event_del(struct acpi_wmi_softc *);
71a913ee75Sjruoho static void acpi_wmi_event_handler(ACPI_HANDLE, uint32_t, void *);
72639d1b97Sjruoho static ACPI_STATUS acpi_wmi_ec_handler(uint32_t, ACPI_PHYSICAL_ADDRESS,
73639d1b97Sjruoho uint32_t, ACPI_INTEGER *, void *, void *);
74a913ee75Sjruoho static bool acpi_wmi_suspend(device_t, const pmf_qual_t *);
75a913ee75Sjruoho static bool acpi_wmi_resume(device_t, const pmf_qual_t *);
76ff198a0bSjakllsch static ACPI_STATUS acpi_wmi_enable_event(ACPI_HANDLE, uint8_t, bool);
77ff198a0bSjakllsch static ACPI_STATUS acpi_wmi_enable_collection(ACPI_HANDLE, const char *, bool);
78a913ee75Sjruoho static bool acpi_wmi_input(struct wmi_t *, uint8_t, uint8_t);
79a913ee75Sjruoho
8037725553Sthorpej static const struct device_compatible_entry compat_data[] = {
8137725553Sthorpej { .compat = "PNP0C14" },
8237725553Sthorpej { .compat = "pnp0c14" },
8337725553Sthorpej DEVICE_COMPAT_EOL
84a913ee75Sjruoho };
85a913ee75Sjruoho
865991cdfeSjmcneill CFATTACH_DECL2_NEW(acpiwmi, sizeof(struct acpi_wmi_softc),
875991cdfeSjmcneill acpi_wmi_match, acpi_wmi_attach, acpi_wmi_detach, NULL,
885991cdfeSjmcneill acpi_wmi_rescan, acpi_wmi_childdet);
89a913ee75Sjruoho
90a913ee75Sjruoho static int
acpi_wmi_match(device_t parent,cfdata_t match,void * aux)91a913ee75Sjruoho acpi_wmi_match(device_t parent, cfdata_t match, void *aux)
92a913ee75Sjruoho {
93a913ee75Sjruoho struct acpi_attach_args *aa = aux;
94a913ee75Sjruoho
9537725553Sthorpej return acpi_compatible_match(aa, compat_data);
96a913ee75Sjruoho }
97a913ee75Sjruoho
98a913ee75Sjruoho static void
acpi_wmi_attach(device_t parent,device_t self,void * aux)99a913ee75Sjruoho acpi_wmi_attach(device_t parent, device_t self, void *aux)
100a913ee75Sjruoho {
101a913ee75Sjruoho struct acpi_wmi_softc *sc = device_private(self);
102a913ee75Sjruoho struct acpi_attach_args *aa = aux;
103a913ee75Sjruoho
104a913ee75Sjruoho sc->sc_dev = self;
105a913ee75Sjruoho sc->sc_node = aa->aa_node;
106a913ee75Sjruoho
107a913ee75Sjruoho sc->sc_child = NULL;
108639d1b97Sjruoho sc->sc_ecdev = NULL;
109a913ee75Sjruoho sc->sc_handler = NULL;
110a913ee75Sjruoho
111a913ee75Sjruoho aprint_naive("\n");
112a913ee75Sjruoho aprint_normal(": ACPI WMI Interface\n");
113a913ee75Sjruoho
114a913ee75Sjruoho if (acpi_wmi_init(sc) != true)
115a913ee75Sjruoho return;
116a913ee75Sjruoho
117460de0d6Sjruoho acpi_wmi_dump(sc);
118639d1b97Sjruoho acpi_wmi_init_ec(sc);
11955052ecaSjruoho acpi_wmi_event_add(sc);
1205991cdfeSjmcneill acpi_wmi_rescan(self, NULL, NULL);
12155052ecaSjruoho
12255052ecaSjruoho (void)pmf_device_register(self, acpi_wmi_suspend, acpi_wmi_resume);
123a913ee75Sjruoho }
124a913ee75Sjruoho
125a913ee75Sjruoho static int
acpi_wmi_detach(device_t self,int flags)126a913ee75Sjruoho acpi_wmi_detach(device_t self, int flags)
127a913ee75Sjruoho {
128a913ee75Sjruoho struct acpi_wmi_softc *sc = device_private(self);
1297baff382Sriastradh int error;
1307baff382Sriastradh
1317baff382Sriastradh error = config_detach_children(self, flags);
1327baff382Sriastradh if (error)
1337baff382Sriastradh return error;
134a913ee75Sjruoho
13555052ecaSjruoho acpi_wmi_event_del(sc);
136a913ee75Sjruoho
137639d1b97Sjruoho if (sc->sc_ecdev != NULL) {
138639d1b97Sjruoho (void)AcpiRemoveAddressSpaceHandler(sc->sc_node->ad_handle,
139639d1b97Sjruoho ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler);
140639d1b97Sjruoho }
141639d1b97Sjruoho
142a913ee75Sjruoho acpi_wmi_del(sc);
143a913ee75Sjruoho pmf_device_deregister(self);
144a913ee75Sjruoho
145a913ee75Sjruoho return 0;
146a913ee75Sjruoho }
147a913ee75Sjruoho
148a913ee75Sjruoho static int
acpi_wmi_rescan(device_t self,const char * ifattr,const int * locators)1495991cdfeSjmcneill acpi_wmi_rescan(device_t self, const char *ifattr, const int *locators)
1505991cdfeSjmcneill {
1515991cdfeSjmcneill struct acpi_wmi_softc *sc = device_private(self);
1525991cdfeSjmcneill
1532685996bSthorpej if (sc->sc_child == NULL) {
1542685996bSthorpej sc->sc_child =
155c7fb772bSthorpej config_found(self, NULL, acpi_wmi_print, CFARGS_NONE);
1562685996bSthorpej }
1575991cdfeSjmcneill
1585991cdfeSjmcneill return 0;
1595991cdfeSjmcneill }
1605991cdfeSjmcneill
1615991cdfeSjmcneill static void
acpi_wmi_childdet(device_t self,device_t child)1625991cdfeSjmcneill acpi_wmi_childdet(device_t self, device_t child)
1635991cdfeSjmcneill {
1645991cdfeSjmcneill struct acpi_wmi_softc *sc = device_private(self);
1655991cdfeSjmcneill
1665991cdfeSjmcneill if (sc->sc_child == child)
1675991cdfeSjmcneill sc->sc_child = NULL;
1685991cdfeSjmcneill }
1695991cdfeSjmcneill
1705991cdfeSjmcneill static int
acpi_wmi_print(void * aux,const char * pnp)171a913ee75Sjruoho acpi_wmi_print(void *aux, const char *pnp)
172a913ee75Sjruoho {
173a913ee75Sjruoho
174a913ee75Sjruoho if (pnp != NULL)
175a913ee75Sjruoho aprint_normal("acpiwmibus at %s", pnp);
176a913ee75Sjruoho
177a913ee75Sjruoho return UNCONF;
178a913ee75Sjruoho }
179a913ee75Sjruoho
180a913ee75Sjruoho static bool
acpi_wmi_init(struct acpi_wmi_softc * sc)181a913ee75Sjruoho acpi_wmi_init(struct acpi_wmi_softc *sc)
182a913ee75Sjruoho {
183a913ee75Sjruoho ACPI_OBJECT *obj;
184a913ee75Sjruoho ACPI_BUFFER buf;
185a913ee75Sjruoho ACPI_STATUS rv;
186a913ee75Sjruoho uint32_t len;
187a913ee75Sjruoho
188a913ee75Sjruoho rv = acpi_eval_struct(sc->sc_node->ad_handle, "_WDG", &buf);
189a913ee75Sjruoho
190a913ee75Sjruoho if (ACPI_FAILURE(rv))
191a913ee75Sjruoho goto fail;
192a913ee75Sjruoho
193a913ee75Sjruoho obj = buf.Pointer;
194a913ee75Sjruoho
195a913ee75Sjruoho if (obj->Type != ACPI_TYPE_BUFFER) {
196a913ee75Sjruoho rv = AE_TYPE;
197a913ee75Sjruoho goto fail;
198a913ee75Sjruoho }
199a913ee75Sjruoho
200a913ee75Sjruoho len = obj->Buffer.Length;
201a913ee75Sjruoho
202a913ee75Sjruoho if (len != obj->Package.Count) {
203a913ee75Sjruoho rv = AE_BAD_VALUE;
204a913ee75Sjruoho goto fail;
205a913ee75Sjruoho }
206a913ee75Sjruoho
207a913ee75Sjruoho CTASSERT(sizeof(struct guid_t) == 20);
208a913ee75Sjruoho
209a913ee75Sjruoho if (len < sizeof(struct guid_t) ||
210a913ee75Sjruoho len % sizeof(struct guid_t) != 0) {
211a913ee75Sjruoho rv = AE_BAD_DATA;
212a913ee75Sjruoho goto fail;
213a913ee75Sjruoho }
214a913ee75Sjruoho
215fd34ea77Schs acpi_wmi_add(sc, obj);
216fd34ea77Schs return true;
217a913ee75Sjruoho
218a913ee75Sjruoho fail:
219a913ee75Sjruoho aprint_error_dev(sc->sc_dev, "failed to evaluate _WDG: %s\n",
220a913ee75Sjruoho AcpiFormatException(rv));
221a913ee75Sjruoho
222a913ee75Sjruoho if (buf.Pointer != NULL)
223a913ee75Sjruoho ACPI_FREE(buf.Pointer);
224a913ee75Sjruoho
225a913ee75Sjruoho return false;
226a913ee75Sjruoho }
227a913ee75Sjruoho
228fd34ea77Schs static void
acpi_wmi_add(struct acpi_wmi_softc * sc,ACPI_OBJECT * obj)229a913ee75Sjruoho acpi_wmi_add(struct acpi_wmi_softc *sc, ACPI_OBJECT *obj)
230a913ee75Sjruoho {
231a913ee75Sjruoho struct wmi_t *wmi;
232a913ee75Sjruoho size_t i, n, offset, siz;
233a913ee75Sjruoho
234a913ee75Sjruoho siz = sizeof(struct guid_t);
235a913ee75Sjruoho n = obj->Buffer.Length / siz;
236a913ee75Sjruoho
237a913ee75Sjruoho SIMPLEQ_INIT(&sc->wmi_head);
238a913ee75Sjruoho
239a913ee75Sjruoho for (i = offset = 0; i < n; ++i) {
240a913ee75Sjruoho
241fd34ea77Schs wmi = kmem_zalloc(sizeof(*wmi), KM_SLEEP);
242a913ee75Sjruoho (void)memcpy(&wmi->guid, obj->Buffer.Pointer + offset, siz);
243a913ee75Sjruoho
244a913ee75Sjruoho wmi->eevent = false;
245a913ee75Sjruoho offset = offset + siz;
246a913ee75Sjruoho
247a913ee75Sjruoho SIMPLEQ_INSERT_TAIL(&sc->wmi_head, wmi, wmi_link);
248a913ee75Sjruoho }
249a913ee75Sjruoho
250a913ee75Sjruoho ACPI_FREE(obj);
251a913ee75Sjruoho }
252a913ee75Sjruoho
253a913ee75Sjruoho static void
acpi_wmi_del(struct acpi_wmi_softc * sc)254a913ee75Sjruoho acpi_wmi_del(struct acpi_wmi_softc *sc)
255a913ee75Sjruoho {
256a913ee75Sjruoho struct wmi_t *wmi;
257a913ee75Sjruoho
258a913ee75Sjruoho while (SIMPLEQ_FIRST(&sc->wmi_head) != NULL) {
259a913ee75Sjruoho wmi = SIMPLEQ_FIRST(&sc->wmi_head);
260a913ee75Sjruoho SIMPLEQ_REMOVE_HEAD(&sc->wmi_head, wmi_link);
261a913ee75Sjruoho kmem_free(wmi, sizeof(*wmi));
262a913ee75Sjruoho }
263a913ee75Sjruoho }
264a913ee75Sjruoho
265460de0d6Sjruoho static void
acpi_wmi_dump(struct acpi_wmi_softc * sc)266460de0d6Sjruoho acpi_wmi_dump(struct acpi_wmi_softc *sc)
267460de0d6Sjruoho {
268460de0d6Sjruoho struct wmi_t *wmi;
269460de0d6Sjruoho
270460de0d6Sjruoho KASSERT(SIMPLEQ_EMPTY(&sc->wmi_head) == 0);
271460de0d6Sjruoho
272460de0d6Sjruoho SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
273460de0d6Sjruoho
274460de0d6Sjruoho aprint_debug_dev(sc->sc_dev, "{%08X-%04X-%04X-",
275460de0d6Sjruoho wmi->guid.data1, wmi->guid.data2, wmi->guid.data3);
276460de0d6Sjruoho
277460de0d6Sjruoho aprint_debug("%02X%02X-%02X%02X%02X%02X%02X%02X} ",
278460de0d6Sjruoho wmi->guid.data4[0], wmi->guid.data4[1],
279460de0d6Sjruoho wmi->guid.data4[2], wmi->guid.data4[3],
280460de0d6Sjruoho wmi->guid.data4[4], wmi->guid.data4[5],
281460de0d6Sjruoho wmi->guid.data4[6], wmi->guid.data4[7]);
282460de0d6Sjruoho
283460de0d6Sjruoho aprint_debug("oid %04X count %02X flags %02X\n",
284460de0d6Sjruoho UGET16(wmi->guid.oid), wmi->guid.count, wmi->guid.flags);
285460de0d6Sjruoho }
286460de0d6Sjruoho }
287460de0d6Sjruoho
288639d1b97Sjruoho static void
acpi_wmi_init_ec(struct acpi_wmi_softc * sc)289639d1b97Sjruoho acpi_wmi_init_ec(struct acpi_wmi_softc *sc)
290639d1b97Sjruoho {
291639d1b97Sjruoho ACPI_STATUS rv;
292639d1b97Sjruoho deviter_t i;
293639d1b97Sjruoho device_t d;
294639d1b97Sjruoho
295639d1b97Sjruoho d = deviter_first(&i, DEVITER_F_ROOT_FIRST);
296639d1b97Sjruoho
297639d1b97Sjruoho for (; d != NULL; d = deviter_next(&i)) {
298639d1b97Sjruoho
299639d1b97Sjruoho if (device_is_a(d, "acpiec") != false ||
300639d1b97Sjruoho device_is_a(d, "acpiecdt") != false) {
301639d1b97Sjruoho sc->sc_ecdev = d;
302639d1b97Sjruoho break;
303639d1b97Sjruoho }
304639d1b97Sjruoho }
305639d1b97Sjruoho
306639d1b97Sjruoho deviter_release(&i);
307639d1b97Sjruoho
308639d1b97Sjruoho if (sc->sc_ecdev == NULL)
309639d1b97Sjruoho return;
310639d1b97Sjruoho
311639d1b97Sjruoho rv = AcpiInstallAddressSpaceHandler(sc->sc_node->ad_handle,
312639d1b97Sjruoho ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler, NULL, sc);
313639d1b97Sjruoho
314639d1b97Sjruoho if (ACPI_FAILURE(rv))
315639d1b97Sjruoho sc->sc_ecdev = NULL;
316639d1b97Sjruoho }
317639d1b97Sjruoho
318a913ee75Sjruoho static ACPI_STATUS
acpi_wmi_guid_get(struct acpi_wmi_softc * sc,const char * src,struct wmi_t ** out)319a913ee75Sjruoho acpi_wmi_guid_get(struct acpi_wmi_softc *sc,
320a913ee75Sjruoho const char *src, struct wmi_t **out)
321a913ee75Sjruoho {
322a913ee75Sjruoho struct wmi_t *wmi;
323*1899b7d2Sriastradh struct guid_t guid;
324*1899b7d2Sriastradh char bin[16];
32587dcc5d7Sbouyer char hex[3];
326a913ee75Sjruoho const char *ptr;
327a913ee75Sjruoho uint8_t i;
328a913ee75Sjruoho
329a913ee75Sjruoho if (sc == NULL || src == NULL || strlen(src) != 36)
330a913ee75Sjruoho return AE_BAD_PARAMETER;
331a913ee75Sjruoho
332a913ee75Sjruoho for (ptr = src, i = 0; i < 16; i++) {
333a913ee75Sjruoho
334a913ee75Sjruoho if (*ptr == '-')
335a913ee75Sjruoho ptr++;
336a913ee75Sjruoho
337a913ee75Sjruoho (void)memcpy(hex, ptr, 2);
33887dcc5d7Sbouyer hex[2] = '\0';
339a913ee75Sjruoho
3407a8e9522Sjruoho if (HEXCHAR(hex[0]) == 0 || HEXCHAR(hex[1]) == 0)
341a913ee75Sjruoho return AE_BAD_HEX_CONSTANT;
342a913ee75Sjruoho
343a913ee75Sjruoho bin[i] = strtoul(hex, NULL, 16) & 0xFF;
344a913ee75Sjruoho
345a913ee75Sjruoho ptr++;
346a913ee75Sjruoho ptr++;
347a913ee75Sjruoho }
348a913ee75Sjruoho
349*1899b7d2Sriastradh guid.data1 = be32dec(&bin[0]);
350*1899b7d2Sriastradh guid.data2 = be16dec(&bin[4]);
351*1899b7d2Sriastradh guid.data3 = be16dec(&bin[6]);
352*1899b7d2Sriastradh memcpy(guid.data4, &bin[8], 8);
353a913ee75Sjruoho
354a913ee75Sjruoho SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
355a913ee75Sjruoho
356*1899b7d2Sriastradh if (GUIDCMP(&guid, &wmi->guid) != 0) {
357a913ee75Sjruoho
358a913ee75Sjruoho if (out != NULL)
359a913ee75Sjruoho *out = wmi;
360a913ee75Sjruoho
361a913ee75Sjruoho return AE_OK;
362a913ee75Sjruoho }
363a913ee75Sjruoho }
364a913ee75Sjruoho
365a913ee75Sjruoho return AE_NOT_FOUND;
366a913ee75Sjruoho }
367a913ee75Sjruoho
368a913ee75Sjruoho /*
369a913ee75Sjruoho * Checks if a GUID is present. Child devices
370a913ee75Sjruoho * can use this in their autoconf(9) routines.
371a913ee75Sjruoho */
372a913ee75Sjruoho int
acpi_wmi_guid_match(device_t self,const char * guid)373a913ee75Sjruoho acpi_wmi_guid_match(device_t self, const char *guid)
374a913ee75Sjruoho {
375a913ee75Sjruoho struct acpi_wmi_softc *sc = device_private(self);
376a913ee75Sjruoho ACPI_STATUS rv;
377a913ee75Sjruoho
378a913ee75Sjruoho rv = acpi_wmi_guid_get(sc, guid, NULL);
379a913ee75Sjruoho
380a913ee75Sjruoho if (ACPI_SUCCESS(rv))
381a913ee75Sjruoho return 1;
382a913ee75Sjruoho
383a913ee75Sjruoho return 0;
384a913ee75Sjruoho }
385a913ee75Sjruoho
386a913ee75Sjruoho /*
387a913ee75Sjruoho * Adds internal event handler.
388a913ee75Sjruoho */
38955052ecaSjruoho static void
acpi_wmi_event_add(struct acpi_wmi_softc * sc)390a913ee75Sjruoho acpi_wmi_event_add(struct acpi_wmi_softc *sc)
391a913ee75Sjruoho {
392a913ee75Sjruoho struct wmi_t *wmi;
393a913ee75Sjruoho ACPI_STATUS rv;
394a913ee75Sjruoho
39555052ecaSjruoho if (acpi_register_notify(sc->sc_node, acpi_wmi_event_handler) != true)
39655052ecaSjruoho return;
397a913ee75Sjruoho
398a240caeaSjruoho /*
399ff198a0bSjakllsch * Enable possible events, expensive or otherwise.
400a240caeaSjruoho */
401a913ee75Sjruoho SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
402a913ee75Sjruoho
403ff198a0bSjakllsch if ((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) != 0) {
404a913ee75Sjruoho
405ff198a0bSjakllsch rv = acpi_wmi_enable_event(sc->sc_node->ad_handle,
406ff198a0bSjakllsch wmi->guid.nid, true);
407a913ee75Sjruoho
408a913ee75Sjruoho if (ACPI_SUCCESS(rv)) {
409a913ee75Sjruoho wmi->eevent = true;
410a913ee75Sjruoho continue;
411a913ee75Sjruoho }
412a913ee75Sjruoho
413a240caeaSjruoho aprint_debug_dev(sc->sc_dev, "failed to enable "
414a913ee75Sjruoho "expensive WExx: %s\n", AcpiFormatException(rv));
415a913ee75Sjruoho }
416a913ee75Sjruoho }
417a913ee75Sjruoho }
418a913ee75Sjruoho
419a913ee75Sjruoho /*
420a913ee75Sjruoho * Removes the internal event handler.
421a913ee75Sjruoho */
42255052ecaSjruoho static void
acpi_wmi_event_del(struct acpi_wmi_softc * sc)423a913ee75Sjruoho acpi_wmi_event_del(struct acpi_wmi_softc *sc)
424a913ee75Sjruoho {
425a913ee75Sjruoho struct wmi_t *wmi;
426a913ee75Sjruoho ACPI_STATUS rv;
427a913ee75Sjruoho
42855052ecaSjruoho acpi_deregister_notify(sc->sc_node);
429a913ee75Sjruoho
430a913ee75Sjruoho SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
431a913ee75Sjruoho
432a913ee75Sjruoho if (wmi->eevent != true)
433a913ee75Sjruoho continue;
434a913ee75Sjruoho
435a913ee75Sjruoho KASSERT((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) != 0);
436a913ee75Sjruoho
437ff198a0bSjakllsch rv = acpi_wmi_enable_event(sc->sc_node->ad_handle,
438ff198a0bSjakllsch wmi->guid.nid, false);
439a913ee75Sjruoho
440a913ee75Sjruoho if (ACPI_SUCCESS(rv)) {
441a913ee75Sjruoho wmi->eevent = false;
442a913ee75Sjruoho continue;
443a913ee75Sjruoho }
444a913ee75Sjruoho
445a240caeaSjruoho aprint_debug_dev(sc->sc_dev, "failed to disable "
446a913ee75Sjruoho "expensive WExx: %s\n", AcpiFormatException(rv));
447a913ee75Sjruoho }
448a913ee75Sjruoho }
449a913ee75Sjruoho
450a913ee75Sjruoho /*
451a913ee75Sjruoho * Returns extra information possibly associated with an event.
452a913ee75Sjruoho */
453a913ee75Sjruoho ACPI_STATUS
acpi_wmi_event_get(device_t self,uint32_t event,ACPI_BUFFER * obuf)454a913ee75Sjruoho acpi_wmi_event_get(device_t self, uint32_t event, ACPI_BUFFER *obuf)
455a913ee75Sjruoho {
456a913ee75Sjruoho struct acpi_wmi_softc *sc = device_private(self);
457a913ee75Sjruoho struct wmi_t *wmi;
458a913ee75Sjruoho ACPI_OBJECT_LIST arg;
459a913ee75Sjruoho ACPI_OBJECT obj;
4607a8e9522Sjruoho ACPI_HANDLE hdl;
4617a8e9522Sjruoho
462a913ee75Sjruoho if (sc == NULL || obuf == NULL)
463a913ee75Sjruoho return AE_BAD_PARAMETER;
464a913ee75Sjruoho
465a913ee75Sjruoho if (sc->sc_handler == NULL)
466a913ee75Sjruoho return AE_ABORT_METHOD;
467a913ee75Sjruoho
468a57241d4Sjruoho hdl = sc->sc_node->ad_handle;
469a57241d4Sjruoho
470a913ee75Sjruoho obj.Type = ACPI_TYPE_INTEGER;
471a913ee75Sjruoho obj.Integer.Value = event;
472a913ee75Sjruoho
473a913ee75Sjruoho arg.Count = 0x01;
474a913ee75Sjruoho arg.Pointer = &obj;
475a913ee75Sjruoho
476a913ee75Sjruoho obuf->Pointer = NULL;
477a913ee75Sjruoho obuf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
478a913ee75Sjruoho
479a913ee75Sjruoho SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
480a913ee75Sjruoho
481a913ee75Sjruoho if ((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) == 0)
482a913ee75Sjruoho continue;
483a913ee75Sjruoho
484a913ee75Sjruoho if (wmi->guid.nid != event)
485a913ee75Sjruoho continue;
486a913ee75Sjruoho
4877a8e9522Sjruoho return AcpiEvaluateObject(hdl, "_WED", &arg, obuf);
488a913ee75Sjruoho }
489a913ee75Sjruoho
490a913ee75Sjruoho return AE_NOT_FOUND;
491a913ee75Sjruoho }
492a913ee75Sjruoho
493a913ee75Sjruoho /*
494a913ee75Sjruoho * Forwards events to the external handler through the internal one.
495a913ee75Sjruoho */
496a913ee75Sjruoho static void
acpi_wmi_event_handler(ACPI_HANDLE hdl,uint32_t evt,void * aux)497a913ee75Sjruoho acpi_wmi_event_handler(ACPI_HANDLE hdl, uint32_t evt, void *aux)
498a913ee75Sjruoho {
49955052ecaSjruoho struct acpi_wmi_softc *sc;
50055052ecaSjruoho device_t self = aux;
50155052ecaSjruoho
50255052ecaSjruoho sc = device_private(self);
503a913ee75Sjruoho
504a913ee75Sjruoho if (sc->sc_child == NULL)
505a913ee75Sjruoho return;
506a913ee75Sjruoho
507a913ee75Sjruoho if (sc->sc_handler == NULL)
508a913ee75Sjruoho return;
509a913ee75Sjruoho
510a913ee75Sjruoho (*sc->sc_handler)(NULL, evt, sc->sc_child);
511a913ee75Sjruoho }
512a913ee75Sjruoho
513a913ee75Sjruoho ACPI_STATUS
acpi_wmi_event_register(device_t self,ACPI_NOTIFY_HANDLER handler)514a913ee75Sjruoho acpi_wmi_event_register(device_t self, ACPI_NOTIFY_HANDLER handler)
515a913ee75Sjruoho {
516a913ee75Sjruoho struct acpi_wmi_softc *sc = device_private(self);
517a913ee75Sjruoho
518a913ee75Sjruoho if (sc == NULL)
519a913ee75Sjruoho return AE_BAD_PARAMETER;
520a913ee75Sjruoho
521a913ee75Sjruoho if (handler != NULL && sc->sc_handler != NULL)
522a913ee75Sjruoho return AE_ALREADY_EXISTS;
523a913ee75Sjruoho
524a913ee75Sjruoho sc->sc_handler = handler;
525a913ee75Sjruoho
526a913ee75Sjruoho return AE_OK;
527a913ee75Sjruoho }
528a913ee75Sjruoho
529a913ee75Sjruoho ACPI_STATUS
acpi_wmi_event_deregister(device_t self)530a913ee75Sjruoho acpi_wmi_event_deregister(device_t self)
531a913ee75Sjruoho {
532a913ee75Sjruoho return acpi_wmi_event_register(self, NULL);
533a913ee75Sjruoho }
534a913ee75Sjruoho
535a913ee75Sjruoho /*
536639d1b97Sjruoho * Handler for EC regions, which may be embedded in WMI.
537639d1b97Sjruoho */
538639d1b97Sjruoho static ACPI_STATUS
acpi_wmi_ec_handler(uint32_t func,ACPI_PHYSICAL_ADDRESS addr,uint32_t width,ACPI_INTEGER * val,void * setup,void * aux)539639d1b97Sjruoho acpi_wmi_ec_handler(uint32_t func, ACPI_PHYSICAL_ADDRESS addr,
540639d1b97Sjruoho uint32_t width, ACPI_INTEGER *val, void *setup, void *aux)
541639d1b97Sjruoho {
542639d1b97Sjruoho struct acpi_wmi_softc *sc = aux;
543639d1b97Sjruoho
544639d1b97Sjruoho if (aux == NULL || val == NULL)
545639d1b97Sjruoho return AE_BAD_PARAMETER;
546639d1b97Sjruoho
547639d1b97Sjruoho if (addr > 0xFF || width % 8 != 0)
548639d1b97Sjruoho return AE_BAD_ADDRESS;
549639d1b97Sjruoho
550639d1b97Sjruoho switch (func) {
551639d1b97Sjruoho
552639d1b97Sjruoho case ACPI_READ:
553639d1b97Sjruoho (void)acpiec_bus_read(sc->sc_ecdev, addr, val, width);
554639d1b97Sjruoho break;
555639d1b97Sjruoho
556639d1b97Sjruoho case ACPI_WRITE:
557639d1b97Sjruoho (void)acpiec_bus_write(sc->sc_ecdev, addr, *val, width);
558639d1b97Sjruoho break;
559639d1b97Sjruoho
560639d1b97Sjruoho default:
561639d1b97Sjruoho return AE_BAD_PARAMETER;
562639d1b97Sjruoho }
563639d1b97Sjruoho
564639d1b97Sjruoho return AE_OK;
565639d1b97Sjruoho }
566639d1b97Sjruoho
567639d1b97Sjruoho /*
568a913ee75Sjruoho * As there is no prior knowledge about the expensive
569a913ee75Sjruoho * events that cause "significant overhead", try to
570a913ee75Sjruoho * disable (enable) these before suspending (resuming).
571a913ee75Sjruoho */
572a913ee75Sjruoho static bool
acpi_wmi_suspend(device_t self,const pmf_qual_t * qual)573a913ee75Sjruoho acpi_wmi_suspend(device_t self, const pmf_qual_t *qual)
574a913ee75Sjruoho {
575a913ee75Sjruoho struct acpi_wmi_softc *sc = device_private(self);
576a913ee75Sjruoho
577a913ee75Sjruoho acpi_wmi_event_del(sc);
578a913ee75Sjruoho
579a913ee75Sjruoho return true;
580a913ee75Sjruoho }
581a913ee75Sjruoho
582a913ee75Sjruoho static bool
acpi_wmi_resume(device_t self,const pmf_qual_t * qual)583a913ee75Sjruoho acpi_wmi_resume(device_t self, const pmf_qual_t *qual)
584a913ee75Sjruoho {
585a913ee75Sjruoho struct acpi_wmi_softc *sc = device_private(self);
586a913ee75Sjruoho
587a913ee75Sjruoho acpi_wmi_event_add(sc);
588a913ee75Sjruoho
589a913ee75Sjruoho return true;
590a913ee75Sjruoho }
591a913ee75Sjruoho
592a913ee75Sjruoho static ACPI_STATUS
acpi_wmi_enable_event(ACPI_HANDLE hdl,uint8_t nid,bool flag)593ff198a0bSjakllsch acpi_wmi_enable_event(ACPI_HANDLE hdl, uint8_t nid, bool flag)
594a913ee75Sjruoho {
595a913ee75Sjruoho char path[5];
596a913ee75Sjruoho
597ff198a0bSjakllsch snprintf(path, sizeof(path), "WE%02X", nid);
598a913ee75Sjruoho
599ff198a0bSjakllsch return acpi_eval_set_integer(hdl, path, (flag != false) ? 0x01 : 0x00);
600ff198a0bSjakllsch }
601ff198a0bSjakllsch
602ff198a0bSjakllsch static ACPI_STATUS
acpi_wmi_enable_collection(ACPI_HANDLE hdl,const char * oid,bool flag)603ff198a0bSjakllsch acpi_wmi_enable_collection(ACPI_HANDLE hdl, const char *oid, bool flag)
604ff198a0bSjakllsch {
605ff198a0bSjakllsch char path[5];
606ff198a0bSjakllsch
607ff198a0bSjakllsch strlcpy(path, "WC", sizeof(path));
608ff198a0bSjakllsch strlcat(path, oid, sizeof(path));
609a913ee75Sjruoho
610a913ee75Sjruoho return acpi_eval_set_integer(hdl, path, (flag != false) ? 0x01 : 0x00);
611a913ee75Sjruoho }
612a913ee75Sjruoho
613a913ee75Sjruoho static bool
acpi_wmi_input(struct wmi_t * wmi,uint8_t flag,uint8_t idx)614a913ee75Sjruoho acpi_wmi_input(struct wmi_t *wmi, uint8_t flag, uint8_t idx)
615a913ee75Sjruoho {
61687dcc5d7Sbouyer /* A data block may have no flags at all */
61787dcc5d7Sbouyer if ((wmi->guid.flags & flag) == 0 &&
61887dcc5d7Sbouyer (flag == ACPI_WMI_FLAG_DATA &&
61987dcc5d7Sbouyer (wmi->guid.flags & ~ACPI_WMI_FLAG_EXPENSIVE) != 0))
620a913ee75Sjruoho return false;
621a913ee75Sjruoho
622a913ee75Sjruoho if (wmi->guid.count == 0x00)
623a913ee75Sjruoho return false;
624a913ee75Sjruoho
625a913ee75Sjruoho if (wmi->guid.count < idx)
626a913ee75Sjruoho return false;
627a913ee75Sjruoho
628a913ee75Sjruoho return true;
629a913ee75Sjruoho }
630a913ee75Sjruoho
631a913ee75Sjruoho /*
632a913ee75Sjruoho * Makes a WMI data block query (WQxx). The corresponding control
633a913ee75Sjruoho * method for data collection will be invoked if it is available.
634a913ee75Sjruoho */
635a913ee75Sjruoho ACPI_STATUS
acpi_wmi_data_query(device_t self,const char * guid,uint8_t idx,ACPI_BUFFER * obuf)636a913ee75Sjruoho acpi_wmi_data_query(device_t self, const char *guid,
637a913ee75Sjruoho uint8_t idx, ACPI_BUFFER *obuf)
638a913ee75Sjruoho {
639a913ee75Sjruoho struct acpi_wmi_softc *sc = device_private(self);
640a913ee75Sjruoho struct wmi_t *wmi;
641a913ee75Sjruoho char path[5] = "WQ";
642a913ee75Sjruoho ACPI_OBJECT_LIST arg;
643a913ee75Sjruoho ACPI_STATUS rv, rvxx;
644a913ee75Sjruoho ACPI_OBJECT obj;
645a913ee75Sjruoho
646a913ee75Sjruoho rvxx = AE_SUPPORT;
647a913ee75Sjruoho
648a913ee75Sjruoho if (obuf == NULL)
649a913ee75Sjruoho return AE_BAD_PARAMETER;
650a913ee75Sjruoho
651a913ee75Sjruoho rv = acpi_wmi_guid_get(sc, guid, &wmi);
652a913ee75Sjruoho
653a913ee75Sjruoho if (ACPI_FAILURE(rv))
654a913ee75Sjruoho return rv;
655a913ee75Sjruoho
656a913ee75Sjruoho if (acpi_wmi_input(wmi, ACPI_WMI_FLAG_DATA, idx) != true)
657a913ee75Sjruoho return AE_BAD_DATA;
658a913ee75Sjruoho
659a913ee75Sjruoho (void)strlcat(path, wmi->guid.oid, sizeof(path));
660a913ee75Sjruoho
661a913ee75Sjruoho obj.Type = ACPI_TYPE_INTEGER;
662a913ee75Sjruoho obj.Integer.Value = idx;
663a913ee75Sjruoho
664a913ee75Sjruoho arg.Count = 0x01;
665a913ee75Sjruoho arg.Pointer = &obj;
666a913ee75Sjruoho
667a913ee75Sjruoho obuf->Pointer = NULL;
668a913ee75Sjruoho obuf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
669a913ee75Sjruoho
670a913ee75Sjruoho /*
671a913ee75Sjruoho * If the expensive flag is set, we should enable
672a913ee75Sjruoho * data collection before evaluating the WQxx buffer.
673a913ee75Sjruoho */
674a913ee75Sjruoho if ((wmi->guid.flags & ACPI_WMI_FLAG_EXPENSIVE) != 0) {
675a913ee75Sjruoho
676ff198a0bSjakllsch rvxx = acpi_wmi_enable_collection(sc->sc_node->ad_handle,
677ff198a0bSjakllsch wmi->guid.oid, true);
678a913ee75Sjruoho }
679a913ee75Sjruoho
680a913ee75Sjruoho rv = AcpiEvaluateObject(sc->sc_node->ad_handle, path, &arg, obuf);
681a913ee75Sjruoho
682a913ee75Sjruoho /* No longer needed. */
683a913ee75Sjruoho if (ACPI_SUCCESS(rvxx)) {
684a913ee75Sjruoho
685ff198a0bSjakllsch (void)acpi_wmi_enable_collection(sc->sc_node->ad_handle,
686ff198a0bSjakllsch wmi->guid.oid, false);
687a913ee75Sjruoho }
688a913ee75Sjruoho
689a913ee75Sjruoho #ifdef DIAGNOSTIC
690a913ee75Sjruoho /*
691a913ee75Sjruoho * XXX: It appears that quite a few laptops have WQxx
692a913ee75Sjruoho * methods that are declared as expensive, but lack the
693a913ee75Sjruoho * corresponding WCxx control method.
694a913ee75Sjruoho *
695a913ee75Sjruoho * -- Acer Aspire One is one example <jruohonen@iki.fi>.
696a913ee75Sjruoho */
697a913ee75Sjruoho if (ACPI_FAILURE(rvxx) && rvxx != AE_SUPPORT)
698a913ee75Sjruoho aprint_error_dev(sc->sc_dev, "failed to evaluate WCxx "
699a913ee75Sjruoho "for %s: %s\n", path, AcpiFormatException(rvxx));
700a913ee75Sjruoho #endif
701a913ee75Sjruoho return rv;
702a913ee75Sjruoho }
703a913ee75Sjruoho
704a913ee75Sjruoho /*
705a913ee75Sjruoho * Writes to a data block (WSxx).
706a913ee75Sjruoho */
707a913ee75Sjruoho ACPI_STATUS
acpi_wmi_data_write(device_t self,const char * guid,uint8_t idx,ACPI_BUFFER * ibuf)708a913ee75Sjruoho acpi_wmi_data_write(device_t self, const char *guid,
709a913ee75Sjruoho uint8_t idx, ACPI_BUFFER *ibuf)
710a913ee75Sjruoho {
711a913ee75Sjruoho struct acpi_wmi_softc *sc = device_private(self);
712a913ee75Sjruoho struct wmi_t *wmi;
713a913ee75Sjruoho ACPI_OBJECT_LIST arg;
714a913ee75Sjruoho ACPI_OBJECT obj[2];
715a913ee75Sjruoho char path[5] = "WS";
716a913ee75Sjruoho ACPI_STATUS rv;
717a913ee75Sjruoho
718a913ee75Sjruoho if (ibuf == NULL)
719a913ee75Sjruoho return AE_BAD_PARAMETER;
720a913ee75Sjruoho
721a913ee75Sjruoho rv = acpi_wmi_guid_get(sc, guid, &wmi);
722a913ee75Sjruoho
723a913ee75Sjruoho if (ACPI_FAILURE(rv))
724a913ee75Sjruoho return rv;
725a913ee75Sjruoho
726a913ee75Sjruoho if (acpi_wmi_input(wmi, ACPI_WMI_FLAG_DATA, idx) != true)
727a913ee75Sjruoho return AE_BAD_DATA;
728a913ee75Sjruoho
729a913ee75Sjruoho (void)strlcat(path, wmi->guid.oid, sizeof(path));
730a913ee75Sjruoho
731a913ee75Sjruoho obj[0].Integer.Value = idx;
732a913ee75Sjruoho obj[0].Type = ACPI_TYPE_INTEGER;
733a913ee75Sjruoho
734a913ee75Sjruoho obj[1].Buffer.Length = ibuf->Length;
735a913ee75Sjruoho obj[1].Buffer.Pointer = ibuf->Pointer;
736a913ee75Sjruoho
737a913ee75Sjruoho obj[1].Type = ((wmi->guid.flags & ACPI_WMI_FLAG_STRING) != 0) ?
738a913ee75Sjruoho ACPI_TYPE_STRING : ACPI_TYPE_BUFFER;
739a913ee75Sjruoho
740a913ee75Sjruoho arg.Count = 0x02;
741a913ee75Sjruoho arg.Pointer = obj;
742a913ee75Sjruoho
743a913ee75Sjruoho return AcpiEvaluateObject(sc->sc_node->ad_handle, path, &arg, NULL);
744a913ee75Sjruoho }
745a913ee75Sjruoho
746a913ee75Sjruoho /*
747a913ee75Sjruoho * Executes a method (WMxx).
748a913ee75Sjruoho */
749a913ee75Sjruoho ACPI_STATUS
acpi_wmi_method(device_t self,const char * guid,uint8_t idx,uint32_t mid,ACPI_BUFFER * ibuf,ACPI_BUFFER * obuf)750a913ee75Sjruoho acpi_wmi_method(device_t self, const char *guid, uint8_t idx,
751a913ee75Sjruoho uint32_t mid, ACPI_BUFFER *ibuf, ACPI_BUFFER *obuf)
752a913ee75Sjruoho {
753a913ee75Sjruoho struct acpi_wmi_softc *sc = device_private(self);
754a913ee75Sjruoho struct wmi_t *wmi;
755a913ee75Sjruoho ACPI_OBJECT_LIST arg;
756a913ee75Sjruoho ACPI_OBJECT obj[3];
757a913ee75Sjruoho char path[5] = "WM";
758a913ee75Sjruoho ACPI_STATUS rv;
759a913ee75Sjruoho
760a913ee75Sjruoho if (ibuf == NULL || obuf == NULL)
761a913ee75Sjruoho return AE_BAD_PARAMETER;
762a913ee75Sjruoho
763a913ee75Sjruoho rv = acpi_wmi_guid_get(sc, guid, &wmi);
764a913ee75Sjruoho
765a913ee75Sjruoho if (ACPI_FAILURE(rv))
766a913ee75Sjruoho return rv;
767a913ee75Sjruoho
768a913ee75Sjruoho if (acpi_wmi_input(wmi, ACPI_WMI_FLAG_METHOD, idx) != true)
769a913ee75Sjruoho return AE_BAD_DATA;
770a913ee75Sjruoho
771a913ee75Sjruoho (void)strlcat(path, wmi->guid.oid, sizeof(path));
772a913ee75Sjruoho
773a913ee75Sjruoho obj[0].Integer.Value = idx;
774a913ee75Sjruoho obj[1].Integer.Value = mid;
775a913ee75Sjruoho obj[0].Type = obj[1].Type = ACPI_TYPE_INTEGER;
776a913ee75Sjruoho
777a913ee75Sjruoho obj[2].Buffer.Length = ibuf->Length;
778a913ee75Sjruoho obj[2].Buffer.Pointer = ibuf->Pointer;
779a913ee75Sjruoho
780a913ee75Sjruoho obj[2].Type = ((wmi->guid.flags & ACPI_WMI_FLAG_STRING) != 0) ?
781a913ee75Sjruoho ACPI_TYPE_STRING : ACPI_TYPE_BUFFER;
782a913ee75Sjruoho
783a913ee75Sjruoho arg.Count = 0x03;
784a913ee75Sjruoho arg.Pointer = obj;
785a913ee75Sjruoho
786a913ee75Sjruoho obuf->Pointer = NULL;
787a913ee75Sjruoho obuf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
788a913ee75Sjruoho
789a913ee75Sjruoho return AcpiEvaluateObject(sc->sc_node->ad_handle, path, &arg, obuf);
790a913ee75Sjruoho }
7919750ca2fSjmcneill
7929750ca2fSjmcneill MODULE(MODULE_CLASS_DRIVER, acpiwmi, NULL);
7939750ca2fSjmcneill
794b9f301d5Sjruoho #ifdef _MODULE
795b9f301d5Sjruoho #include "ioconf.c"
796b9f301d5Sjruoho #endif
7979750ca2fSjmcneill
7989750ca2fSjmcneill static int
acpiwmi_modcmd(modcmd_t cmd,void * aux)799b9f301d5Sjruoho acpiwmi_modcmd(modcmd_t cmd, void *aux)
8009750ca2fSjmcneill {
801b9f301d5Sjruoho int rv = 0;
8029750ca2fSjmcneill
8039750ca2fSjmcneill switch (cmd) {
8049750ca2fSjmcneill
8059750ca2fSjmcneill case MODULE_CMD_INIT:
8069750ca2fSjmcneill
807b9f301d5Sjruoho #ifdef _MODULE
808b9f301d5Sjruoho rv = config_init_component(cfdriver_ioconf_acpiwmi,
809b9f301d5Sjruoho cfattach_ioconf_acpiwmi, cfdata_ioconf_acpiwmi);
810b9f301d5Sjruoho #endif
811b9f301d5Sjruoho break;
8129750ca2fSjmcneill
8139750ca2fSjmcneill case MODULE_CMD_FINI:
8149750ca2fSjmcneill
815b9f301d5Sjruoho #ifdef _MODULE
816b9f301d5Sjruoho rv = config_fini_component(cfdriver_ioconf_acpiwmi,
817b9f301d5Sjruoho cfattach_ioconf_acpiwmi, cfdata_ioconf_acpiwmi);
818b9f301d5Sjruoho #endif
819b9f301d5Sjruoho break;
8209750ca2fSjmcneill
8219750ca2fSjmcneill default:
822b9f301d5Sjruoho rv = ENOTTY;
8239750ca2fSjmcneill }
8249750ca2fSjmcneill
825b9f301d5Sjruoho return rv;
826b9f301d5Sjruoho }
827