Home | History | Annotate | Line # | Download | only in wmi
wmi_acpi.c revision 1.16.18.1
      1  1.16.18.1   thorpej /*	$NetBSD: wmi_acpi.c,v 1.16.18.1 2021/04/03 22:28:43 thorpej Exp $	*/
      2        1.1    jruoho 
      3        1.1    jruoho /*-
      4        1.1    jruoho  * Copyright (c) 2009, 2010 Jukka Ruohonen <jruohonen (at) iki.fi>
      5        1.1    jruoho  * All rights reserved.
      6        1.1    jruoho  *
      7        1.1    jruoho  * Redistribution and use in source and binary forms, with or without
      8        1.1    jruoho  * modification, are permitted provided that the following conditions
      9        1.1    jruoho  * are met:
     10        1.1    jruoho  *
     11        1.1    jruoho  * 1. Redistributions of source code must retain the above copyright
     12        1.1    jruoho  *    notice, this list of conditions and the following disclaimer.
     13        1.1    jruoho  * 2. Redistributions in binary form must reproduce the above copyright
     14        1.1    jruoho  *    notice, this list of conditions and the following disclaimer in the
     15        1.1    jruoho  *    documentation and/or other materials provided with the distribution.
     16        1.1    jruoho  *
     17        1.1    jruoho  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     18        1.1    jruoho  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19        1.1    jruoho  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20        1.1    jruoho  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     21        1.1    jruoho  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22        1.1    jruoho  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23        1.1    jruoho  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24        1.1    jruoho  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25        1.1    jruoho  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26        1.1    jruoho  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27        1.1    jruoho  * SUCH DAMAGE.
     28        1.1    jruoho  */
     29        1.1    jruoho #include <sys/cdefs.h>
     30  1.16.18.1   thorpej __KERNEL_RCSID(0, "$NetBSD: wmi_acpi.c,v 1.16.18.1 2021/04/03 22:28:43 thorpej Exp $");
     31        1.1    jruoho 
     32        1.1    jruoho #include <sys/param.h>
     33        1.1    jruoho #include <sys/device.h>
     34        1.1    jruoho #include <sys/endian.h>
     35        1.1    jruoho #include <sys/kmem.h>
     36        1.1    jruoho #include <sys/systm.h>
     37        1.9  jmcneill #include <sys/module.h>
     38        1.1    jruoho 
     39        1.1    jruoho #include <dev/acpi/acpireg.h>
     40        1.1    jruoho #include <dev/acpi/acpivar.h>
     41       1.11    jruoho #include <dev/acpi/acpi_ecvar.h>
     42        1.1    jruoho #include <dev/acpi/wmi/wmi_acpivar.h>
     43        1.1    jruoho 
     44        1.1    jruoho #define _COMPONENT          ACPI_RESOURCE_COMPONENT
     45        1.1    jruoho ACPI_MODULE_NAME            ("wmi_acpi")
     46        1.1    jruoho 
     47        1.1    jruoho /*
     48        1.1    jruoho  * This implements something called "Microsoft Windows Management
     49        1.1    jruoho  * Instrumentation" (WMI). This subset of ACPI is desribed in:
     50        1.1    jruoho  *
     51        1.1    jruoho  * http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx
     52        1.1    jruoho  *
     53        1.1    jruoho  * (Obtained on Thu Feb 12 18:21:44 EET 2009.)
     54        1.1    jruoho  */
     55        1.1    jruoho 
     56       1.11    jruoho static int		acpi_wmi_match(device_t, cfdata_t, void *);
     57       1.11    jruoho static void		acpi_wmi_attach(device_t, device_t, void *);
     58       1.11    jruoho static int		acpi_wmi_detach(device_t, int);
     59       1.11    jruoho static int		acpi_wmi_rescan(device_t, const char *, const int *);
     60       1.11    jruoho static void		acpi_wmi_childdet(device_t, device_t);
     61       1.11    jruoho static int		acpi_wmi_print(void *, const char *);
     62       1.11    jruoho static bool		acpi_wmi_init(struct acpi_wmi_softc *);
     63       1.11    jruoho static void		acpi_wmi_init_ec(struct acpi_wmi_softc *);
     64       1.15       chs static void		acpi_wmi_add(struct acpi_wmi_softc *, ACPI_OBJECT *);
     65       1.11    jruoho static void		acpi_wmi_del(struct acpi_wmi_softc *);
     66       1.11    jruoho static void		acpi_wmi_dump(struct acpi_wmi_softc *);
     67       1.11    jruoho static ACPI_STATUS	acpi_wmi_guid_get(struct acpi_wmi_softc *,
     68       1.11    jruoho 				const char *, struct wmi_t **);
     69       1.11    jruoho static void		acpi_wmi_event_add(struct acpi_wmi_softc *);
     70       1.11    jruoho static void		acpi_wmi_event_del(struct acpi_wmi_softc *);
     71       1.11    jruoho static void		acpi_wmi_event_handler(ACPI_HANDLE, uint32_t, void *);
     72       1.11    jruoho static ACPI_STATUS	acpi_wmi_ec_handler(uint32_t, ACPI_PHYSICAL_ADDRESS,
     73       1.11    jruoho 				uint32_t, ACPI_INTEGER *, void *, void *);
     74       1.11    jruoho static bool		acpi_wmi_suspend(device_t, const pmf_qual_t *);
     75       1.11    jruoho static bool		acpi_wmi_resume(device_t, const pmf_qual_t *);
     76       1.13  jakllsch static ACPI_STATUS	acpi_wmi_enable_event(ACPI_HANDLE, uint8_t, bool);
     77       1.13  jakllsch static ACPI_STATUS	acpi_wmi_enable_collection(ACPI_HANDLE, const char *, bool);
     78       1.11    jruoho static bool		acpi_wmi_input(struct wmi_t *, uint8_t, uint8_t);
     79        1.1    jruoho 
     80  1.16.18.1   thorpej static const struct device_compatible_entry compat_data[] = {
     81  1.16.18.1   thorpej 	{ .compat = "PNP0C14" },
     82  1.16.18.1   thorpej 	{ .compat = "pnp0c14" },
     83  1.16.18.1   thorpej 	DEVICE_COMPAT_EOL
     84        1.1    jruoho };
     85        1.1    jruoho 
     86        1.8  jmcneill CFATTACH_DECL2_NEW(acpiwmi, sizeof(struct acpi_wmi_softc),
     87        1.8  jmcneill     acpi_wmi_match, acpi_wmi_attach, acpi_wmi_detach, NULL,
     88        1.8  jmcneill     acpi_wmi_rescan, acpi_wmi_childdet);
     89        1.1    jruoho 
     90        1.1    jruoho static int
     91        1.1    jruoho acpi_wmi_match(device_t parent, cfdata_t match, void *aux)
     92        1.1    jruoho {
     93        1.1    jruoho 	struct acpi_attach_args *aa = aux;
     94        1.1    jruoho 
     95  1.16.18.1   thorpej 	return acpi_compatible_match(aa, compat_data);
     96        1.1    jruoho }
     97        1.1    jruoho 
     98        1.1    jruoho static void
     99        1.1    jruoho acpi_wmi_attach(device_t parent, device_t self, void *aux)
    100        1.1    jruoho {
    101        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    102        1.1    jruoho 	struct acpi_attach_args *aa = aux;
    103        1.1    jruoho 
    104        1.1    jruoho 	sc->sc_dev = self;
    105        1.1    jruoho 	sc->sc_node = aa->aa_node;
    106        1.1    jruoho 
    107        1.1    jruoho 	sc->sc_child = NULL;
    108       1.11    jruoho 	sc->sc_ecdev = NULL;
    109        1.1    jruoho 	sc->sc_handler = NULL;
    110        1.1    jruoho 
    111        1.1    jruoho 	aprint_naive("\n");
    112        1.1    jruoho 	aprint_normal(": ACPI WMI Interface\n");
    113        1.1    jruoho 
    114        1.1    jruoho 	if (acpi_wmi_init(sc) != true)
    115        1.1    jruoho 		return;
    116        1.1    jruoho 
    117        1.7    jruoho 	acpi_wmi_dump(sc);
    118       1.11    jruoho 	acpi_wmi_init_ec(sc);
    119        1.4    jruoho 	acpi_wmi_event_add(sc);
    120        1.8  jmcneill 	acpi_wmi_rescan(self, NULL, NULL);
    121        1.4    jruoho 
    122        1.4    jruoho 	(void)pmf_device_register(self, acpi_wmi_suspend, acpi_wmi_resume);
    123        1.1    jruoho }
    124        1.1    jruoho 
    125        1.1    jruoho static int
    126        1.1    jruoho acpi_wmi_detach(device_t self, int flags)
    127        1.1    jruoho {
    128        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    129        1.1    jruoho 
    130        1.4    jruoho 	acpi_wmi_event_del(sc);
    131        1.1    jruoho 
    132       1.11    jruoho 	if (sc->sc_ecdev != NULL) {
    133       1.11    jruoho 
    134       1.11    jruoho 		(void)AcpiRemoveAddressSpaceHandler(sc->sc_node->ad_handle,
    135       1.11    jruoho 		    ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler);
    136       1.11    jruoho 	}
    137       1.11    jruoho 
    138        1.1    jruoho 	if (sc->sc_child != NULL)
    139        1.1    jruoho 		(void)config_detach(sc->sc_child, flags);
    140        1.1    jruoho 
    141        1.1    jruoho 	acpi_wmi_del(sc);
    142        1.1    jruoho 	pmf_device_deregister(self);
    143        1.1    jruoho 
    144        1.1    jruoho 	return 0;
    145        1.1    jruoho }
    146        1.1    jruoho 
    147        1.1    jruoho static int
    148        1.8  jmcneill acpi_wmi_rescan(device_t self, const char *ifattr, const int *locators)
    149        1.8  jmcneill {
    150        1.8  jmcneill 	struct acpi_wmi_softc *sc = device_private(self);
    151        1.8  jmcneill 
    152        1.8  jmcneill 	if (ifattr_match(ifattr, "acpiwmibus") && sc->sc_child == NULL)
    153        1.8  jmcneill 		sc->sc_child = config_found_ia(self, "acpiwmibus",
    154        1.8  jmcneill 		    NULL, acpi_wmi_print);
    155        1.8  jmcneill 
    156        1.8  jmcneill 	return 0;
    157        1.8  jmcneill }
    158        1.8  jmcneill 
    159        1.8  jmcneill static void
    160        1.8  jmcneill acpi_wmi_childdet(device_t self, device_t child)
    161        1.8  jmcneill {
    162        1.8  jmcneill 	struct acpi_wmi_softc *sc = device_private(self);
    163        1.8  jmcneill 
    164        1.8  jmcneill 	if (sc->sc_child == child)
    165        1.8  jmcneill 		sc->sc_child = NULL;
    166        1.8  jmcneill }
    167        1.8  jmcneill 
    168        1.8  jmcneill static int
    169        1.1    jruoho acpi_wmi_print(void *aux, const char *pnp)
    170        1.1    jruoho {
    171        1.1    jruoho 
    172        1.1    jruoho 	if (pnp != NULL)
    173        1.1    jruoho 		aprint_normal("acpiwmibus at %s", pnp);
    174        1.1    jruoho 
    175        1.1    jruoho 	return UNCONF;
    176        1.1    jruoho }
    177        1.1    jruoho 
    178        1.1    jruoho static bool
    179        1.1    jruoho acpi_wmi_init(struct acpi_wmi_softc *sc)
    180        1.1    jruoho {
    181        1.1    jruoho 	ACPI_OBJECT *obj;
    182        1.1    jruoho 	ACPI_BUFFER buf;
    183        1.1    jruoho 	ACPI_STATUS rv;
    184        1.1    jruoho 	uint32_t len;
    185        1.1    jruoho 
    186        1.1    jruoho 	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_WDG", &buf);
    187        1.1    jruoho 
    188        1.1    jruoho 	if (ACPI_FAILURE(rv))
    189        1.1    jruoho 		goto fail;
    190        1.1    jruoho 
    191        1.1    jruoho 	obj = buf.Pointer;
    192        1.1    jruoho 
    193        1.1    jruoho 	if (obj->Type != ACPI_TYPE_BUFFER) {
    194        1.1    jruoho 		rv = AE_TYPE;
    195        1.1    jruoho 		goto fail;
    196        1.1    jruoho 	}
    197        1.1    jruoho 
    198        1.1    jruoho 	len = obj->Buffer.Length;
    199        1.1    jruoho 
    200        1.1    jruoho 	if (len != obj->Package.Count) {
    201        1.1    jruoho 		rv = AE_BAD_VALUE;
    202        1.1    jruoho 		goto fail;
    203        1.1    jruoho 	}
    204        1.1    jruoho 
    205        1.1    jruoho 	CTASSERT(sizeof(struct guid_t) == 20);
    206        1.1    jruoho 
    207        1.1    jruoho 	if (len < sizeof(struct guid_t) ||
    208        1.1    jruoho 	    len % sizeof(struct guid_t) != 0) {
    209        1.1    jruoho 		rv = AE_BAD_DATA;
    210        1.1    jruoho 		goto fail;
    211        1.1    jruoho 	}
    212        1.1    jruoho 
    213       1.15       chs 	acpi_wmi_add(sc, obj);
    214       1.15       chs 	return true;
    215        1.1    jruoho 
    216        1.1    jruoho fail:
    217        1.1    jruoho 	aprint_error_dev(sc->sc_dev, "failed to evaluate _WDG: %s\n",
    218        1.1    jruoho 	    AcpiFormatException(rv));
    219        1.1    jruoho 
    220        1.1    jruoho 	if (buf.Pointer != NULL)
    221        1.1    jruoho 		ACPI_FREE(buf.Pointer);
    222        1.1    jruoho 
    223        1.1    jruoho 	return false;
    224        1.1    jruoho }
    225        1.1    jruoho 
    226       1.15       chs static void
    227        1.1    jruoho acpi_wmi_add(struct acpi_wmi_softc *sc, ACPI_OBJECT *obj)
    228        1.1    jruoho {
    229        1.1    jruoho 	struct wmi_t *wmi;
    230        1.1    jruoho 	size_t i, n, offset, siz;
    231        1.1    jruoho 
    232        1.1    jruoho 	siz = sizeof(struct guid_t);
    233        1.1    jruoho 	n = obj->Buffer.Length / siz;
    234        1.1    jruoho 
    235        1.1    jruoho 	SIMPLEQ_INIT(&sc->wmi_head);
    236        1.1    jruoho 
    237        1.1    jruoho 	for (i = offset = 0; i < n; ++i) {
    238        1.1    jruoho 
    239       1.15       chs 		wmi = kmem_zalloc(sizeof(*wmi), KM_SLEEP);
    240        1.1    jruoho 		(void)memcpy(&wmi->guid, obj->Buffer.Pointer + offset, siz);
    241        1.1    jruoho 
    242        1.1    jruoho 		wmi->eevent = false;
    243        1.1    jruoho 		offset = offset + siz;
    244        1.1    jruoho 
    245        1.1    jruoho 		SIMPLEQ_INSERT_TAIL(&sc->wmi_head, wmi, wmi_link);
    246        1.1    jruoho 	}
    247        1.1    jruoho 
    248        1.1    jruoho 	ACPI_FREE(obj);
    249        1.1    jruoho }
    250        1.1    jruoho 
    251        1.1    jruoho static void
    252        1.1    jruoho acpi_wmi_del(struct acpi_wmi_softc *sc)
    253        1.1    jruoho {
    254        1.1    jruoho 	struct wmi_t *wmi;
    255        1.1    jruoho 
    256        1.1    jruoho 	while (SIMPLEQ_FIRST(&sc->wmi_head) != NULL) {
    257        1.1    jruoho 		wmi = SIMPLEQ_FIRST(&sc->wmi_head);
    258        1.1    jruoho 		SIMPLEQ_REMOVE_HEAD(&sc->wmi_head, wmi_link);
    259        1.1    jruoho 		kmem_free(wmi, sizeof(*wmi));
    260        1.1    jruoho 	}
    261        1.1    jruoho }
    262        1.1    jruoho 
    263        1.7    jruoho static void
    264        1.7    jruoho acpi_wmi_dump(struct acpi_wmi_softc *sc)
    265        1.7    jruoho {
    266        1.7    jruoho 	struct wmi_t *wmi;
    267        1.7    jruoho 
    268        1.7    jruoho 	KASSERT(SIMPLEQ_EMPTY(&sc->wmi_head) == 0);
    269        1.7    jruoho 
    270        1.7    jruoho 	SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
    271        1.7    jruoho 
    272        1.7    jruoho 		aprint_debug_dev(sc->sc_dev, "{%08X-%04X-%04X-",
    273        1.7    jruoho 		    wmi->guid.data1, wmi->guid.data2, wmi->guid.data3);
    274        1.7    jruoho 
    275        1.7    jruoho 		aprint_debug("%02X%02X-%02X%02X%02X%02X%02X%02X} ",
    276        1.7    jruoho 		    wmi->guid.data4[0], wmi->guid.data4[1],
    277        1.7    jruoho 		    wmi->guid.data4[2], wmi->guid.data4[3],
    278        1.7    jruoho 		    wmi->guid.data4[4], wmi->guid.data4[5],
    279        1.7    jruoho 		    wmi->guid.data4[6], wmi->guid.data4[7]);
    280        1.7    jruoho 
    281        1.7    jruoho 		aprint_debug("oid %04X count %02X flags %02X\n",
    282        1.7    jruoho 		    UGET16(wmi->guid.oid), wmi->guid.count, wmi->guid.flags);
    283        1.7    jruoho 	}
    284        1.7    jruoho }
    285        1.7    jruoho 
    286       1.11    jruoho static void
    287       1.11    jruoho acpi_wmi_init_ec(struct acpi_wmi_softc *sc)
    288       1.11    jruoho {
    289       1.11    jruoho 	ACPI_STATUS rv;
    290       1.11    jruoho 	deviter_t i;
    291       1.11    jruoho 	device_t d;
    292       1.11    jruoho 
    293       1.11    jruoho 	d = deviter_first(&i, DEVITER_F_ROOT_FIRST);
    294       1.11    jruoho 
    295       1.11    jruoho 	for (; d != NULL; d = deviter_next(&i)) {
    296       1.11    jruoho 
    297       1.11    jruoho 		if (device_is_a(d, "acpiec") != false ||
    298       1.11    jruoho 		    device_is_a(d, "acpiecdt") != false) {
    299       1.11    jruoho 			sc->sc_ecdev = d;
    300       1.11    jruoho 			break;
    301       1.11    jruoho 		}
    302       1.11    jruoho 	}
    303       1.11    jruoho 
    304       1.11    jruoho 	deviter_release(&i);
    305       1.11    jruoho 
    306       1.11    jruoho 	if (sc->sc_ecdev == NULL)
    307       1.11    jruoho 		return;
    308       1.11    jruoho 
    309       1.11    jruoho 	rv = AcpiInstallAddressSpaceHandler(sc->sc_node->ad_handle,
    310       1.11    jruoho 	    ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler, NULL, sc);
    311       1.11    jruoho 
    312       1.11    jruoho 	if (ACPI_FAILURE(rv))
    313       1.11    jruoho 		sc->sc_ecdev = NULL;
    314       1.11    jruoho }
    315       1.11    jruoho 
    316        1.1    jruoho static ACPI_STATUS
    317        1.1    jruoho acpi_wmi_guid_get(struct acpi_wmi_softc *sc,
    318        1.1    jruoho     const char *src, struct wmi_t **out)
    319        1.1    jruoho {
    320        1.1    jruoho 	struct wmi_t *wmi;
    321        1.1    jruoho 	struct guid_t *guid;
    322        1.1    jruoho 	char bin[16];
    323       1.16    bouyer 	char hex[3];
    324        1.1    jruoho 	const char *ptr;
    325        1.1    jruoho 	uint8_t i;
    326        1.1    jruoho 
    327        1.1    jruoho 	if (sc == NULL || src == NULL || strlen(src) != 36)
    328        1.1    jruoho 		return AE_BAD_PARAMETER;
    329        1.1    jruoho 
    330        1.1    jruoho 	for (ptr = src, i = 0; i < 16; i++) {
    331        1.1    jruoho 
    332        1.1    jruoho 		if (*ptr == '-')
    333        1.1    jruoho 			ptr++;
    334        1.1    jruoho 
    335        1.1    jruoho 		(void)memcpy(hex, ptr, 2);
    336       1.16    bouyer 		hex[2] = '\0';
    337        1.1    jruoho 
    338        1.2    jruoho 		if (HEXCHAR(hex[0]) == 0 || HEXCHAR(hex[1]) == 0)
    339        1.1    jruoho 			return AE_BAD_HEX_CONSTANT;
    340        1.1    jruoho 
    341        1.1    jruoho 		bin[i] = strtoul(hex, NULL, 16) & 0xFF;
    342        1.1    jruoho 
    343        1.1    jruoho 		ptr++;
    344        1.1    jruoho 		ptr++;
    345        1.1    jruoho 	}
    346        1.1    jruoho 
    347        1.1    jruoho 	guid = (struct guid_t *)bin;
    348        1.1    jruoho 	guid->data1 = be32toh(guid->data1);
    349        1.1    jruoho 	guid->data2 = be16toh(guid->data2);
    350        1.1    jruoho 	guid->data3 = be16toh(guid->data3);
    351        1.1    jruoho 
    352        1.1    jruoho 	SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
    353        1.1    jruoho 
    354        1.1    jruoho 		if (GUIDCMP(guid, &wmi->guid) != 0) {
    355        1.1    jruoho 
    356        1.1    jruoho 			if (out != NULL)
    357        1.1    jruoho 				*out = wmi;
    358        1.1    jruoho 
    359        1.1    jruoho 			return AE_OK;
    360        1.1    jruoho 		}
    361        1.1    jruoho 	}
    362        1.1    jruoho 
    363        1.1    jruoho 	return AE_NOT_FOUND;
    364        1.1    jruoho }
    365        1.1    jruoho 
    366        1.1    jruoho /*
    367        1.1    jruoho  * Checks if a GUID is present. Child devices
    368        1.1    jruoho  * can use this in their autoconf(9) routines.
    369        1.1    jruoho  */
    370        1.1    jruoho int
    371        1.1    jruoho acpi_wmi_guid_match(device_t self, const char *guid)
    372        1.1    jruoho {
    373        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    374        1.1    jruoho 	ACPI_STATUS rv;
    375        1.1    jruoho 
    376        1.1    jruoho 	rv = acpi_wmi_guid_get(sc, guid, NULL);
    377        1.1    jruoho 
    378        1.1    jruoho 	if (ACPI_SUCCESS(rv))
    379        1.1    jruoho 		return 1;
    380        1.1    jruoho 
    381        1.1    jruoho 	return 0;
    382        1.1    jruoho }
    383        1.1    jruoho 
    384        1.1    jruoho /*
    385        1.1    jruoho  * Adds internal event handler.
    386        1.1    jruoho  */
    387        1.4    jruoho static void
    388        1.1    jruoho acpi_wmi_event_add(struct acpi_wmi_softc *sc)
    389        1.1    jruoho {
    390        1.1    jruoho 	struct wmi_t *wmi;
    391        1.1    jruoho 	ACPI_STATUS rv;
    392        1.1    jruoho 
    393        1.4    jruoho 	if (acpi_register_notify(sc->sc_node, acpi_wmi_event_handler) != true)
    394        1.4    jruoho 		return;
    395        1.1    jruoho 
    396        1.6    jruoho 	/*
    397       1.13  jakllsch 	 * Enable possible events, expensive or otherwise.
    398        1.6    jruoho 	 */
    399        1.1    jruoho 	SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
    400        1.1    jruoho 
    401       1.13  jakllsch 		if ((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) != 0) {
    402        1.1    jruoho 
    403       1.13  jakllsch 			rv = acpi_wmi_enable_event(sc->sc_node->ad_handle,
    404       1.13  jakllsch 			    wmi->guid.nid, true);
    405        1.1    jruoho 
    406        1.1    jruoho 			if (ACPI_SUCCESS(rv)) {
    407        1.1    jruoho 				wmi->eevent = true;
    408        1.1    jruoho 				continue;
    409        1.1    jruoho 			}
    410        1.1    jruoho 
    411        1.6    jruoho 			aprint_debug_dev(sc->sc_dev, "failed to enable "
    412        1.1    jruoho 			    "expensive WExx: %s\n", AcpiFormatException(rv));
    413        1.1    jruoho 		}
    414        1.1    jruoho 	}
    415        1.1    jruoho }
    416        1.1    jruoho 
    417        1.1    jruoho /*
    418        1.1    jruoho  * Removes the internal event handler.
    419        1.1    jruoho  */
    420        1.4    jruoho static void
    421        1.1    jruoho acpi_wmi_event_del(struct acpi_wmi_softc *sc)
    422        1.1    jruoho {
    423        1.1    jruoho 	struct wmi_t *wmi;
    424        1.1    jruoho 	ACPI_STATUS rv;
    425        1.1    jruoho 
    426        1.4    jruoho 	acpi_deregister_notify(sc->sc_node);
    427        1.1    jruoho 
    428        1.1    jruoho 	SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
    429        1.1    jruoho 
    430        1.1    jruoho 		if (wmi->eevent != true)
    431        1.1    jruoho 			continue;
    432        1.1    jruoho 
    433        1.1    jruoho 		KASSERT((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) != 0);
    434        1.1    jruoho 
    435       1.13  jakllsch 		rv = acpi_wmi_enable_event(sc->sc_node->ad_handle,
    436       1.13  jakllsch 		    wmi->guid.nid, false);
    437        1.1    jruoho 
    438        1.1    jruoho 		if (ACPI_SUCCESS(rv)) {
    439        1.1    jruoho 			wmi->eevent = false;
    440        1.1    jruoho 			continue;
    441        1.1    jruoho 		}
    442        1.1    jruoho 
    443        1.6    jruoho 		aprint_debug_dev(sc->sc_dev, "failed to disable "
    444        1.1    jruoho 		    "expensive WExx: %s\n", AcpiFormatException(rv));
    445        1.1    jruoho 	}
    446        1.1    jruoho }
    447        1.1    jruoho 
    448        1.1    jruoho /*
    449        1.1    jruoho  * Returns extra information possibly associated with an event.
    450        1.1    jruoho  */
    451        1.1    jruoho ACPI_STATUS
    452        1.1    jruoho acpi_wmi_event_get(device_t self, uint32_t event, ACPI_BUFFER *obuf)
    453        1.1    jruoho {
    454        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    455        1.1    jruoho 	struct wmi_t *wmi;
    456        1.1    jruoho 	ACPI_OBJECT_LIST arg;
    457        1.1    jruoho 	ACPI_OBJECT obj;
    458        1.2    jruoho 	ACPI_HANDLE hdl;
    459        1.2    jruoho 
    460        1.1    jruoho 	if (sc == NULL || obuf == NULL)
    461        1.1    jruoho 		return AE_BAD_PARAMETER;
    462        1.1    jruoho 
    463        1.1    jruoho 	if (sc->sc_handler == NULL)
    464        1.1    jruoho 		return AE_ABORT_METHOD;
    465        1.1    jruoho 
    466        1.3    jruoho 	hdl = sc->sc_node->ad_handle;
    467        1.3    jruoho 
    468        1.1    jruoho 	obj.Type = ACPI_TYPE_INTEGER;
    469        1.1    jruoho 	obj.Integer.Value = event;
    470        1.1    jruoho 
    471        1.1    jruoho 	arg.Count = 0x01;
    472        1.1    jruoho 	arg.Pointer = &obj;
    473        1.1    jruoho 
    474        1.1    jruoho 	obuf->Pointer = NULL;
    475        1.1    jruoho 	obuf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    476        1.1    jruoho 
    477        1.1    jruoho 	SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
    478        1.1    jruoho 
    479        1.1    jruoho 		if ((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) == 0)
    480        1.1    jruoho 			continue;
    481        1.1    jruoho 
    482        1.1    jruoho 		if (wmi->guid.nid != event)
    483        1.1    jruoho 			continue;
    484        1.1    jruoho 
    485        1.2    jruoho 		return AcpiEvaluateObject(hdl, "_WED", &arg, obuf);
    486        1.1    jruoho 	}
    487        1.1    jruoho 
    488        1.1    jruoho 	return AE_NOT_FOUND;
    489        1.1    jruoho }
    490        1.1    jruoho 
    491        1.1    jruoho /*
    492        1.1    jruoho  * Forwards events to the external handler through the internal one.
    493        1.1    jruoho  */
    494        1.1    jruoho static void
    495        1.1    jruoho acpi_wmi_event_handler(ACPI_HANDLE hdl, uint32_t evt, void *aux)
    496        1.1    jruoho {
    497        1.4    jruoho 	struct acpi_wmi_softc *sc;
    498        1.4    jruoho 	device_t self = aux;
    499        1.4    jruoho 
    500        1.4    jruoho 	sc = device_private(self);
    501        1.1    jruoho 
    502        1.1    jruoho 	if (sc->sc_child == NULL)
    503        1.1    jruoho 		return;
    504        1.1    jruoho 
    505        1.1    jruoho 	if (sc->sc_handler == NULL)
    506        1.1    jruoho 		return;
    507        1.1    jruoho 
    508        1.1    jruoho 	(*sc->sc_handler)(NULL, evt, sc->sc_child);
    509        1.1    jruoho }
    510        1.1    jruoho 
    511        1.1    jruoho ACPI_STATUS
    512        1.1    jruoho acpi_wmi_event_register(device_t self, ACPI_NOTIFY_HANDLER handler)
    513        1.1    jruoho {
    514        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    515        1.1    jruoho 
    516        1.1    jruoho 	if (sc == NULL)
    517        1.1    jruoho 		return AE_BAD_PARAMETER;
    518        1.1    jruoho 
    519        1.1    jruoho 	if (handler != NULL && sc->sc_handler != NULL)
    520        1.1    jruoho 		return AE_ALREADY_EXISTS;
    521        1.1    jruoho 
    522        1.1    jruoho 	sc->sc_handler = handler;
    523        1.1    jruoho 
    524        1.1    jruoho 	return AE_OK;
    525        1.1    jruoho }
    526        1.1    jruoho 
    527        1.1    jruoho ACPI_STATUS
    528        1.1    jruoho acpi_wmi_event_deregister(device_t self)
    529        1.1    jruoho {
    530        1.1    jruoho 	return acpi_wmi_event_register(self, NULL);
    531        1.1    jruoho }
    532        1.1    jruoho 
    533        1.1    jruoho /*
    534       1.11    jruoho  * Handler for EC regions, which may be embedded in WMI.
    535       1.11    jruoho  */
    536       1.11    jruoho static ACPI_STATUS
    537       1.11    jruoho acpi_wmi_ec_handler(uint32_t func, ACPI_PHYSICAL_ADDRESS addr,
    538       1.11    jruoho     uint32_t width, ACPI_INTEGER *val, void *setup, void *aux)
    539       1.11    jruoho {
    540       1.11    jruoho 	struct acpi_wmi_softc *sc = aux;
    541       1.11    jruoho 
    542       1.11    jruoho 	if (aux == NULL || val == NULL)
    543       1.11    jruoho 		return AE_BAD_PARAMETER;
    544       1.11    jruoho 
    545       1.11    jruoho 	if (addr > 0xFF || width % 8 != 0)
    546       1.11    jruoho 		return AE_BAD_ADDRESS;
    547       1.11    jruoho 
    548       1.11    jruoho 	switch (func) {
    549       1.11    jruoho 
    550       1.11    jruoho 	case ACPI_READ:
    551       1.11    jruoho 		(void)acpiec_bus_read(sc->sc_ecdev, addr, val, width);
    552       1.11    jruoho 		break;
    553       1.11    jruoho 
    554       1.11    jruoho 	case ACPI_WRITE:
    555       1.11    jruoho 		(void)acpiec_bus_write(sc->sc_ecdev, addr, *val, width);
    556       1.11    jruoho 		break;
    557       1.11    jruoho 
    558       1.11    jruoho 	default:
    559       1.11    jruoho 		return AE_BAD_PARAMETER;
    560       1.11    jruoho 	}
    561       1.11    jruoho 
    562       1.11    jruoho 	return AE_OK;
    563       1.11    jruoho }
    564       1.11    jruoho 
    565       1.11    jruoho /*
    566        1.1    jruoho  * As there is no prior knowledge about the expensive
    567        1.1    jruoho  * events that cause "significant overhead", try to
    568        1.1    jruoho  * disable (enable) these before suspending (resuming).
    569        1.1    jruoho  */
    570        1.1    jruoho static bool
    571        1.1    jruoho acpi_wmi_suspend(device_t self, const pmf_qual_t *qual)
    572        1.1    jruoho {
    573        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    574        1.1    jruoho 
    575        1.1    jruoho 	acpi_wmi_event_del(sc);
    576        1.1    jruoho 
    577        1.1    jruoho 	return true;
    578        1.1    jruoho }
    579        1.1    jruoho 
    580        1.1    jruoho static bool
    581        1.1    jruoho acpi_wmi_resume(device_t self, const pmf_qual_t *qual)
    582        1.1    jruoho {
    583        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    584        1.1    jruoho 
    585        1.1    jruoho 	acpi_wmi_event_add(sc);
    586        1.1    jruoho 
    587        1.1    jruoho 	return true;
    588        1.1    jruoho }
    589        1.1    jruoho 
    590        1.1    jruoho static ACPI_STATUS
    591       1.13  jakllsch acpi_wmi_enable_event(ACPI_HANDLE hdl, uint8_t nid, bool flag)
    592        1.1    jruoho {
    593        1.1    jruoho 	char path[5];
    594        1.1    jruoho 
    595       1.13  jakllsch 	snprintf(path, sizeof(path), "WE%02X", nid);
    596       1.13  jakllsch 
    597       1.13  jakllsch 	return acpi_eval_set_integer(hdl, path, (flag != false) ? 0x01 : 0x00);
    598       1.13  jakllsch }
    599       1.13  jakllsch 
    600       1.13  jakllsch static ACPI_STATUS
    601       1.13  jakllsch acpi_wmi_enable_collection(ACPI_HANDLE hdl, const char *oid, bool flag)
    602       1.13  jakllsch {
    603       1.13  jakllsch 	char path[5];
    604        1.1    jruoho 
    605       1.13  jakllsch 	strlcpy(path, "WC", sizeof(path));
    606       1.13  jakllsch 	strlcat(path, oid, sizeof(path));
    607        1.1    jruoho 
    608        1.1    jruoho 	return acpi_eval_set_integer(hdl, path, (flag != false) ? 0x01 : 0x00);
    609        1.1    jruoho }
    610        1.1    jruoho 
    611        1.1    jruoho static bool
    612        1.1    jruoho acpi_wmi_input(struct wmi_t *wmi, uint8_t flag, uint8_t idx)
    613        1.1    jruoho {
    614       1.16    bouyer 	/* A data block may have no flags at all */
    615       1.16    bouyer 	if ((wmi->guid.flags & flag) == 0 &&
    616       1.16    bouyer 	    (flag == ACPI_WMI_FLAG_DATA  &&
    617       1.16    bouyer 	     (wmi->guid.flags & ~ACPI_WMI_FLAG_EXPENSIVE) != 0))
    618        1.1    jruoho 		return false;
    619        1.1    jruoho 
    620        1.1    jruoho 	if (wmi->guid.count == 0x00)
    621        1.1    jruoho 		return false;
    622        1.1    jruoho 
    623        1.1    jruoho 	if (wmi->guid.count < idx)
    624        1.1    jruoho 		return false;
    625        1.1    jruoho 
    626        1.1    jruoho 	return true;
    627        1.1    jruoho }
    628        1.1    jruoho 
    629        1.1    jruoho /*
    630        1.1    jruoho  * Makes a WMI data block query (WQxx). The corresponding control
    631        1.1    jruoho  * method for data collection will be invoked if it is available.
    632        1.1    jruoho  */
    633        1.1    jruoho ACPI_STATUS
    634        1.1    jruoho acpi_wmi_data_query(device_t self, const char *guid,
    635        1.1    jruoho     uint8_t idx, ACPI_BUFFER *obuf)
    636        1.1    jruoho {
    637        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    638        1.1    jruoho 	struct wmi_t *wmi;
    639        1.1    jruoho 	char path[5] = "WQ";
    640        1.1    jruoho 	ACPI_OBJECT_LIST arg;
    641        1.1    jruoho 	ACPI_STATUS rv, rvxx;
    642        1.1    jruoho 	ACPI_OBJECT obj;
    643        1.1    jruoho 
    644        1.1    jruoho 	rvxx = AE_SUPPORT;
    645        1.1    jruoho 
    646        1.1    jruoho 	if (obuf == NULL)
    647        1.1    jruoho 		return AE_BAD_PARAMETER;
    648        1.1    jruoho 
    649        1.1    jruoho 	rv = acpi_wmi_guid_get(sc, guid, &wmi);
    650        1.1    jruoho 
    651        1.1    jruoho 	if (ACPI_FAILURE(rv))
    652        1.1    jruoho 		return rv;
    653        1.1    jruoho 
    654        1.1    jruoho 	if (acpi_wmi_input(wmi, ACPI_WMI_FLAG_DATA, idx) != true)
    655        1.1    jruoho 		return AE_BAD_DATA;
    656        1.1    jruoho 
    657        1.1    jruoho 	(void)strlcat(path, wmi->guid.oid, sizeof(path));
    658        1.1    jruoho 
    659        1.1    jruoho 	obj.Type = ACPI_TYPE_INTEGER;
    660        1.1    jruoho 	obj.Integer.Value = idx;
    661        1.1    jruoho 
    662        1.1    jruoho 	arg.Count = 0x01;
    663        1.1    jruoho 	arg.Pointer = &obj;
    664        1.1    jruoho 
    665        1.1    jruoho 	obuf->Pointer = NULL;
    666        1.1    jruoho 	obuf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    667        1.1    jruoho 
    668        1.1    jruoho 	/*
    669        1.1    jruoho 	 * If the expensive flag is set, we should enable
    670        1.1    jruoho 	 * data collection before evaluating the WQxx buffer.
    671        1.1    jruoho 	 */
    672        1.1    jruoho 	if ((wmi->guid.flags & ACPI_WMI_FLAG_EXPENSIVE) != 0) {
    673        1.1    jruoho 
    674       1.13  jakllsch 		rvxx = acpi_wmi_enable_collection(sc->sc_node->ad_handle,
    675       1.13  jakllsch 		    wmi->guid.oid, true);
    676        1.1    jruoho 	}
    677        1.1    jruoho 
    678        1.1    jruoho 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle, path, &arg, obuf);
    679        1.1    jruoho 
    680        1.1    jruoho 	/* No longer needed. */
    681        1.1    jruoho 	if (ACPI_SUCCESS(rvxx)) {
    682        1.1    jruoho 
    683       1.13  jakllsch 		(void)acpi_wmi_enable_collection(sc->sc_node->ad_handle,
    684       1.13  jakllsch 		    wmi->guid.oid, false);
    685        1.1    jruoho 	}
    686        1.1    jruoho 
    687        1.1    jruoho #ifdef DIAGNOSTIC
    688        1.1    jruoho 	/*
    689        1.1    jruoho 	 * XXX: It appears that quite a few laptops have WQxx
    690        1.1    jruoho 	 * methods that are declared as expensive, but lack the
    691        1.1    jruoho 	 * corresponding WCxx control method.
    692        1.1    jruoho 	 *
    693        1.1    jruoho 	 * -- Acer Aspire One is one example <jruohonen (at) iki.fi>.
    694        1.1    jruoho 	 */
    695        1.1    jruoho 	if (ACPI_FAILURE(rvxx) && rvxx != AE_SUPPORT)
    696        1.1    jruoho 		aprint_error_dev(sc->sc_dev, "failed to evaluate WCxx "
    697        1.1    jruoho 		    "for %s: %s\n", path, AcpiFormatException(rvxx));
    698        1.1    jruoho #endif
    699        1.1    jruoho 	return rv;
    700        1.1    jruoho }
    701        1.1    jruoho 
    702        1.1    jruoho /*
    703        1.1    jruoho  * Writes to a data block (WSxx).
    704        1.1    jruoho  */
    705        1.1    jruoho ACPI_STATUS
    706        1.1    jruoho acpi_wmi_data_write(device_t self, const char *guid,
    707        1.1    jruoho     uint8_t idx, ACPI_BUFFER *ibuf)
    708        1.1    jruoho {
    709        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    710        1.1    jruoho 	struct wmi_t *wmi;
    711        1.1    jruoho 	ACPI_OBJECT_LIST arg;
    712        1.1    jruoho 	ACPI_OBJECT obj[2];
    713        1.1    jruoho 	char path[5] = "WS";
    714        1.1    jruoho 	ACPI_STATUS rv;
    715        1.1    jruoho 
    716        1.1    jruoho 	if (ibuf == NULL)
    717        1.1    jruoho 		return AE_BAD_PARAMETER;
    718        1.1    jruoho 
    719        1.1    jruoho 	rv = acpi_wmi_guid_get(sc, guid, &wmi);
    720        1.1    jruoho 
    721        1.1    jruoho 	if (ACPI_FAILURE(rv))
    722        1.1    jruoho 		return rv;
    723        1.1    jruoho 
    724        1.1    jruoho 	if (acpi_wmi_input(wmi, ACPI_WMI_FLAG_DATA, idx) != true)
    725        1.1    jruoho 		return AE_BAD_DATA;
    726        1.1    jruoho 
    727        1.1    jruoho 	(void)strlcat(path, wmi->guid.oid, sizeof(path));
    728        1.1    jruoho 
    729        1.1    jruoho 	obj[0].Integer.Value = idx;
    730        1.1    jruoho 	obj[0].Type = ACPI_TYPE_INTEGER;
    731        1.1    jruoho 
    732        1.1    jruoho 	obj[1].Buffer.Length = ibuf->Length;
    733        1.1    jruoho 	obj[1].Buffer.Pointer = ibuf->Pointer;
    734        1.1    jruoho 
    735        1.1    jruoho 	obj[1].Type = ((wmi->guid.flags & ACPI_WMI_FLAG_STRING) != 0) ?
    736        1.1    jruoho 	    ACPI_TYPE_STRING : ACPI_TYPE_BUFFER;
    737        1.1    jruoho 
    738        1.1    jruoho 	arg.Count = 0x02;
    739        1.1    jruoho 	arg.Pointer = obj;
    740        1.1    jruoho 
    741        1.1    jruoho 	return AcpiEvaluateObject(sc->sc_node->ad_handle, path, &arg, NULL);
    742        1.1    jruoho }
    743        1.1    jruoho 
    744        1.1    jruoho /*
    745        1.1    jruoho  * Executes a method (WMxx).
    746        1.1    jruoho  */
    747        1.1    jruoho ACPI_STATUS
    748        1.1    jruoho acpi_wmi_method(device_t self, const char *guid, uint8_t idx,
    749        1.1    jruoho     uint32_t mid, ACPI_BUFFER *ibuf, ACPI_BUFFER *obuf)
    750        1.1    jruoho {
    751        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    752        1.1    jruoho 	struct wmi_t *wmi;
    753        1.1    jruoho 	ACPI_OBJECT_LIST arg;
    754        1.1    jruoho 	ACPI_OBJECT obj[3];
    755        1.1    jruoho 	char path[5] = "WM";
    756        1.1    jruoho 	ACPI_STATUS rv;
    757        1.1    jruoho 
    758        1.1    jruoho 	if (ibuf == NULL || obuf == NULL)
    759        1.1    jruoho 		return AE_BAD_PARAMETER;
    760        1.1    jruoho 
    761        1.1    jruoho 	rv = acpi_wmi_guid_get(sc, guid, &wmi);
    762        1.1    jruoho 
    763        1.1    jruoho 	if (ACPI_FAILURE(rv))
    764        1.1    jruoho 		return rv;
    765        1.1    jruoho 
    766        1.1    jruoho 	if (acpi_wmi_input(wmi, ACPI_WMI_FLAG_METHOD, idx) != true)
    767        1.1    jruoho 		return AE_BAD_DATA;
    768        1.1    jruoho 
    769        1.1    jruoho 	(void)strlcat(path, wmi->guid.oid, sizeof(path));
    770        1.1    jruoho 
    771        1.1    jruoho 	obj[0].Integer.Value = idx;
    772        1.1    jruoho 	obj[1].Integer.Value = mid;
    773        1.1    jruoho 	obj[0].Type = obj[1].Type = ACPI_TYPE_INTEGER;
    774        1.1    jruoho 
    775        1.1    jruoho 	obj[2].Buffer.Length = ibuf->Length;
    776        1.1    jruoho 	obj[2].Buffer.Pointer = ibuf->Pointer;
    777        1.1    jruoho 
    778        1.1    jruoho 	obj[2].Type = ((wmi->guid.flags & ACPI_WMI_FLAG_STRING) != 0) ?
    779        1.1    jruoho 	    ACPI_TYPE_STRING : ACPI_TYPE_BUFFER;
    780        1.1    jruoho 
    781        1.1    jruoho 	arg.Count = 0x03;
    782        1.1    jruoho 	arg.Pointer = obj;
    783        1.1    jruoho 
    784        1.1    jruoho 	obuf->Pointer = NULL;
    785        1.1    jruoho 	obuf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    786        1.1    jruoho 
    787        1.1    jruoho 	return AcpiEvaluateObject(sc->sc_node->ad_handle, path, &arg, obuf);
    788        1.1    jruoho }
    789        1.9  jmcneill 
    790        1.9  jmcneill MODULE(MODULE_CLASS_DRIVER, acpiwmi, NULL);
    791        1.9  jmcneill 
    792       1.12    jruoho #ifdef _MODULE
    793       1.12    jruoho #include "ioconf.c"
    794       1.12    jruoho #endif
    795        1.9  jmcneill 
    796        1.9  jmcneill static int
    797       1.12    jruoho acpiwmi_modcmd(modcmd_t cmd, void *aux)
    798        1.9  jmcneill {
    799       1.12    jruoho 	int rv = 0;
    800        1.9  jmcneill 
    801        1.9  jmcneill 	switch (cmd) {
    802        1.9  jmcneill 
    803        1.9  jmcneill 	case MODULE_CMD_INIT:
    804        1.9  jmcneill 
    805       1.12    jruoho #ifdef _MODULE
    806       1.12    jruoho 		rv = config_init_component(cfdriver_ioconf_acpiwmi,
    807       1.12    jruoho 		    cfattach_ioconf_acpiwmi, cfdata_ioconf_acpiwmi);
    808       1.12    jruoho #endif
    809       1.12    jruoho 		break;
    810        1.9  jmcneill 
    811        1.9  jmcneill 	case MODULE_CMD_FINI:
    812        1.9  jmcneill 
    813       1.12    jruoho #ifdef _MODULE
    814       1.12    jruoho 		rv = config_fini_component(cfdriver_ioconf_acpiwmi,
    815       1.12    jruoho 		    cfattach_ioconf_acpiwmi, cfdata_ioconf_acpiwmi);
    816       1.12    jruoho #endif
    817       1.12    jruoho 		break;
    818        1.9  jmcneill 
    819        1.9  jmcneill 	default:
    820       1.12    jruoho 		rv = ENOTTY;
    821        1.9  jmcneill 	}
    822       1.12    jruoho 
    823       1.12    jruoho 	return rv;
    824        1.9  jmcneill }
    825