Home | History | Annotate | Line # | Download | only in wmi
wmi_acpi.c revision 1.14.16.1
      1  1.14.16.1     skrll /*	$NetBSD: wmi_acpi.c,v 1.14.16.1 2017/08/28 17:52:01 skrll 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.14.16.1     skrll __KERNEL_RCSID(0, "$NetBSD: wmi_acpi.c,v 1.14.16.1 2017/08/28 17:52:01 skrll 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.14.16.1     skrll 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.1    jruoho const char * const acpi_wmi_ids[] = {
     81        1.1    jruoho 	"PNP0C14",
     82        1.6    jruoho 	"pnp0c14",
     83        1.1    jruoho 	NULL
     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.1    jruoho 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
     96        1.1    jruoho 		return 0;
     97        1.1    jruoho 
     98        1.1    jruoho 	return acpi_match_hid(aa->aa_node->ad_devinfo, acpi_wmi_ids);
     99        1.1    jruoho }
    100        1.1    jruoho 
    101        1.1    jruoho static void
    102        1.1    jruoho acpi_wmi_attach(device_t parent, device_t self, void *aux)
    103        1.1    jruoho {
    104        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    105        1.1    jruoho 	struct acpi_attach_args *aa = aux;
    106        1.1    jruoho 
    107        1.1    jruoho 	sc->sc_dev = self;
    108        1.1    jruoho 	sc->sc_node = aa->aa_node;
    109        1.1    jruoho 
    110        1.1    jruoho 	sc->sc_child = NULL;
    111       1.11    jruoho 	sc->sc_ecdev = NULL;
    112        1.1    jruoho 	sc->sc_handler = NULL;
    113        1.1    jruoho 
    114        1.1    jruoho 	aprint_naive("\n");
    115        1.1    jruoho 	aprint_normal(": ACPI WMI Interface\n");
    116        1.1    jruoho 
    117        1.1    jruoho 	if (acpi_wmi_init(sc) != true)
    118        1.1    jruoho 		return;
    119        1.1    jruoho 
    120        1.7    jruoho 	acpi_wmi_dump(sc);
    121       1.11    jruoho 	acpi_wmi_init_ec(sc);
    122        1.4    jruoho 	acpi_wmi_event_add(sc);
    123        1.8  jmcneill 	acpi_wmi_rescan(self, NULL, NULL);
    124        1.4    jruoho 
    125        1.4    jruoho 	(void)pmf_device_register(self, acpi_wmi_suspend, acpi_wmi_resume);
    126        1.1    jruoho }
    127        1.1    jruoho 
    128        1.1    jruoho static int
    129        1.1    jruoho acpi_wmi_detach(device_t self, int flags)
    130        1.1    jruoho {
    131        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    132        1.1    jruoho 
    133        1.4    jruoho 	acpi_wmi_event_del(sc);
    134        1.1    jruoho 
    135       1.11    jruoho 	if (sc->sc_ecdev != NULL) {
    136       1.11    jruoho 
    137       1.11    jruoho 		(void)AcpiRemoveAddressSpaceHandler(sc->sc_node->ad_handle,
    138       1.11    jruoho 		    ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler);
    139       1.11    jruoho 	}
    140       1.11    jruoho 
    141        1.1    jruoho 	if (sc->sc_child != NULL)
    142        1.1    jruoho 		(void)config_detach(sc->sc_child, flags);
    143        1.1    jruoho 
    144        1.1    jruoho 	acpi_wmi_del(sc);
    145        1.1    jruoho 	pmf_device_deregister(self);
    146        1.1    jruoho 
    147        1.1    jruoho 	return 0;
    148        1.1    jruoho }
    149        1.1    jruoho 
    150        1.1    jruoho static int
    151        1.8  jmcneill acpi_wmi_rescan(device_t self, const char *ifattr, const int *locators)
    152        1.8  jmcneill {
    153        1.8  jmcneill 	struct acpi_wmi_softc *sc = device_private(self);
    154        1.8  jmcneill 
    155        1.8  jmcneill 	if (ifattr_match(ifattr, "acpiwmibus") && sc->sc_child == NULL)
    156        1.8  jmcneill 		sc->sc_child = config_found_ia(self, "acpiwmibus",
    157        1.8  jmcneill 		    NULL, acpi_wmi_print);
    158        1.8  jmcneill 
    159        1.8  jmcneill 	return 0;
    160        1.8  jmcneill }
    161        1.8  jmcneill 
    162        1.8  jmcneill static void
    163        1.8  jmcneill acpi_wmi_childdet(device_t self, device_t child)
    164        1.8  jmcneill {
    165        1.8  jmcneill 	struct acpi_wmi_softc *sc = device_private(self);
    166        1.8  jmcneill 
    167        1.8  jmcneill 	if (sc->sc_child == child)
    168        1.8  jmcneill 		sc->sc_child = NULL;
    169        1.8  jmcneill }
    170        1.8  jmcneill 
    171        1.8  jmcneill static int
    172        1.1    jruoho acpi_wmi_print(void *aux, const char *pnp)
    173        1.1    jruoho {
    174        1.1    jruoho 
    175        1.1    jruoho 	if (pnp != NULL)
    176        1.1    jruoho 		aprint_normal("acpiwmibus at %s", pnp);
    177        1.1    jruoho 
    178        1.1    jruoho 	return UNCONF;
    179        1.1    jruoho }
    180        1.1    jruoho 
    181        1.1    jruoho static bool
    182        1.1    jruoho acpi_wmi_init(struct acpi_wmi_softc *sc)
    183        1.1    jruoho {
    184        1.1    jruoho 	ACPI_OBJECT *obj;
    185        1.1    jruoho 	ACPI_BUFFER buf;
    186        1.1    jruoho 	ACPI_STATUS rv;
    187        1.1    jruoho 	uint32_t len;
    188        1.1    jruoho 
    189        1.1    jruoho 	rv = acpi_eval_struct(sc->sc_node->ad_handle, "_WDG", &buf);
    190        1.1    jruoho 
    191        1.1    jruoho 	if (ACPI_FAILURE(rv))
    192        1.1    jruoho 		goto fail;
    193        1.1    jruoho 
    194        1.1    jruoho 	obj = buf.Pointer;
    195        1.1    jruoho 
    196        1.1    jruoho 	if (obj->Type != ACPI_TYPE_BUFFER) {
    197        1.1    jruoho 		rv = AE_TYPE;
    198        1.1    jruoho 		goto fail;
    199        1.1    jruoho 	}
    200        1.1    jruoho 
    201        1.1    jruoho 	len = obj->Buffer.Length;
    202        1.1    jruoho 
    203        1.1    jruoho 	if (len != obj->Package.Count) {
    204        1.1    jruoho 		rv = AE_BAD_VALUE;
    205        1.1    jruoho 		goto fail;
    206        1.1    jruoho 	}
    207        1.1    jruoho 
    208        1.1    jruoho 	CTASSERT(sizeof(struct guid_t) == 20);
    209        1.1    jruoho 
    210        1.1    jruoho 	if (len < sizeof(struct guid_t) ||
    211        1.1    jruoho 	    len % sizeof(struct guid_t) != 0) {
    212        1.1    jruoho 		rv = AE_BAD_DATA;
    213        1.1    jruoho 		goto fail;
    214        1.1    jruoho 	}
    215        1.1    jruoho 
    216  1.14.16.1     skrll 	acpi_wmi_add(sc, obj);
    217  1.14.16.1     skrll 	return true;
    218        1.1    jruoho 
    219        1.1    jruoho fail:
    220        1.1    jruoho 	aprint_error_dev(sc->sc_dev, "failed to evaluate _WDG: %s\n",
    221        1.1    jruoho 	    AcpiFormatException(rv));
    222        1.1    jruoho 
    223        1.1    jruoho 	if (buf.Pointer != NULL)
    224        1.1    jruoho 		ACPI_FREE(buf.Pointer);
    225        1.1    jruoho 
    226        1.1    jruoho 	return false;
    227        1.1    jruoho }
    228        1.1    jruoho 
    229  1.14.16.1     skrll static void
    230        1.1    jruoho acpi_wmi_add(struct acpi_wmi_softc *sc, ACPI_OBJECT *obj)
    231        1.1    jruoho {
    232        1.1    jruoho 	struct wmi_t *wmi;
    233        1.1    jruoho 	size_t i, n, offset, siz;
    234        1.1    jruoho 
    235        1.1    jruoho 	siz = sizeof(struct guid_t);
    236        1.1    jruoho 	n = obj->Buffer.Length / siz;
    237        1.1    jruoho 
    238        1.1    jruoho 	SIMPLEQ_INIT(&sc->wmi_head);
    239        1.1    jruoho 
    240        1.1    jruoho 	for (i = offset = 0; i < n; ++i) {
    241        1.1    jruoho 
    242  1.14.16.1     skrll 		wmi = kmem_zalloc(sizeof(*wmi), KM_SLEEP);
    243        1.1    jruoho 		(void)memcpy(&wmi->guid, obj->Buffer.Pointer + offset, siz);
    244        1.1    jruoho 
    245        1.1    jruoho 		wmi->eevent = false;
    246        1.1    jruoho 		offset = offset + siz;
    247        1.1    jruoho 
    248        1.1    jruoho 		SIMPLEQ_INSERT_TAIL(&sc->wmi_head, wmi, wmi_link);
    249        1.1    jruoho 	}
    250        1.1    jruoho 
    251        1.1    jruoho 	ACPI_FREE(obj);
    252        1.1    jruoho }
    253        1.1    jruoho 
    254        1.1    jruoho static void
    255        1.1    jruoho acpi_wmi_del(struct acpi_wmi_softc *sc)
    256        1.1    jruoho {
    257        1.1    jruoho 	struct wmi_t *wmi;
    258        1.1    jruoho 
    259        1.1    jruoho 	while (SIMPLEQ_FIRST(&sc->wmi_head) != NULL) {
    260        1.1    jruoho 		wmi = SIMPLEQ_FIRST(&sc->wmi_head);
    261        1.1    jruoho 		SIMPLEQ_REMOVE_HEAD(&sc->wmi_head, wmi_link);
    262        1.1    jruoho 		kmem_free(wmi, sizeof(*wmi));
    263        1.1    jruoho 	}
    264        1.1    jruoho }
    265        1.1    jruoho 
    266        1.7    jruoho static void
    267        1.7    jruoho acpi_wmi_dump(struct acpi_wmi_softc *sc)
    268        1.7    jruoho {
    269        1.7    jruoho 	struct wmi_t *wmi;
    270        1.7    jruoho 
    271        1.7    jruoho 	KASSERT(SIMPLEQ_EMPTY(&sc->wmi_head) == 0);
    272        1.7    jruoho 
    273        1.7    jruoho 	SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
    274        1.7    jruoho 
    275        1.7    jruoho 		aprint_debug_dev(sc->sc_dev, "{%08X-%04X-%04X-",
    276        1.7    jruoho 		    wmi->guid.data1, wmi->guid.data2, wmi->guid.data3);
    277        1.7    jruoho 
    278        1.7    jruoho 		aprint_debug("%02X%02X-%02X%02X%02X%02X%02X%02X} ",
    279        1.7    jruoho 		    wmi->guid.data4[0], wmi->guid.data4[1],
    280        1.7    jruoho 		    wmi->guid.data4[2], wmi->guid.data4[3],
    281        1.7    jruoho 		    wmi->guid.data4[4], wmi->guid.data4[5],
    282        1.7    jruoho 		    wmi->guid.data4[6], wmi->guid.data4[7]);
    283        1.7    jruoho 
    284        1.7    jruoho 		aprint_debug("oid %04X count %02X flags %02X\n",
    285        1.7    jruoho 		    UGET16(wmi->guid.oid), wmi->guid.count, wmi->guid.flags);
    286        1.7    jruoho 	}
    287        1.7    jruoho }
    288        1.7    jruoho 
    289       1.11    jruoho static void
    290       1.11    jruoho acpi_wmi_init_ec(struct acpi_wmi_softc *sc)
    291       1.11    jruoho {
    292       1.11    jruoho 	ACPI_STATUS rv;
    293       1.11    jruoho 	deviter_t i;
    294       1.11    jruoho 	device_t d;
    295       1.11    jruoho 
    296       1.11    jruoho 	d = deviter_first(&i, DEVITER_F_ROOT_FIRST);
    297       1.11    jruoho 
    298       1.11    jruoho 	for (; d != NULL; d = deviter_next(&i)) {
    299       1.11    jruoho 
    300       1.11    jruoho 		if (device_is_a(d, "acpiec") != false ||
    301       1.11    jruoho 		    device_is_a(d, "acpiecdt") != false) {
    302       1.11    jruoho 			sc->sc_ecdev = d;
    303       1.11    jruoho 			break;
    304       1.11    jruoho 		}
    305       1.11    jruoho 	}
    306       1.11    jruoho 
    307       1.11    jruoho 	deviter_release(&i);
    308       1.11    jruoho 
    309       1.11    jruoho 	if (sc->sc_ecdev == NULL)
    310       1.11    jruoho 		return;
    311       1.11    jruoho 
    312       1.11    jruoho 	rv = AcpiInstallAddressSpaceHandler(sc->sc_node->ad_handle,
    313       1.11    jruoho 	    ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler, NULL, sc);
    314       1.11    jruoho 
    315       1.11    jruoho 	if (ACPI_FAILURE(rv))
    316       1.11    jruoho 		sc->sc_ecdev = NULL;
    317       1.11    jruoho }
    318       1.11    jruoho 
    319        1.1    jruoho static ACPI_STATUS
    320        1.1    jruoho acpi_wmi_guid_get(struct acpi_wmi_softc *sc,
    321        1.1    jruoho     const char *src, struct wmi_t **out)
    322        1.1    jruoho {
    323        1.1    jruoho 	struct wmi_t *wmi;
    324        1.1    jruoho 	struct guid_t *guid;
    325        1.1    jruoho 	char bin[16];
    326        1.1    jruoho 	char hex[2];
    327        1.1    jruoho 	const char *ptr;
    328        1.1    jruoho 	uint8_t i;
    329        1.1    jruoho 
    330        1.1    jruoho 	if (sc == NULL || src == NULL || strlen(src) != 36)
    331        1.1    jruoho 		return AE_BAD_PARAMETER;
    332        1.1    jruoho 
    333        1.1    jruoho 	for (ptr = src, i = 0; i < 16; i++) {
    334        1.1    jruoho 
    335        1.1    jruoho 		if (*ptr == '-')
    336        1.1    jruoho 			ptr++;
    337        1.1    jruoho 
    338        1.1    jruoho 		(void)memcpy(hex, ptr, 2);
    339        1.1    jruoho 
    340        1.2    jruoho 		if (HEXCHAR(hex[0]) == 0 || HEXCHAR(hex[1]) == 0)
    341        1.1    jruoho 			return AE_BAD_HEX_CONSTANT;
    342        1.1    jruoho 
    343        1.1    jruoho 		bin[i] = strtoul(hex, NULL, 16) & 0xFF;
    344        1.1    jruoho 
    345        1.1    jruoho 		ptr++;
    346        1.1    jruoho 		ptr++;
    347        1.1    jruoho 	}
    348        1.1    jruoho 
    349        1.1    jruoho 	guid = (struct guid_t *)bin;
    350        1.1    jruoho 	guid->data1 = be32toh(guid->data1);
    351        1.1    jruoho 	guid->data2 = be16toh(guid->data2);
    352        1.1    jruoho 	guid->data3 = be16toh(guid->data3);
    353        1.1    jruoho 
    354        1.1    jruoho 	SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
    355        1.1    jruoho 
    356        1.1    jruoho 		if (GUIDCMP(guid, &wmi->guid) != 0) {
    357        1.1    jruoho 
    358        1.1    jruoho 			if (out != NULL)
    359        1.1    jruoho 				*out = wmi;
    360        1.1    jruoho 
    361        1.1    jruoho 			return AE_OK;
    362        1.1    jruoho 		}
    363        1.1    jruoho 	}
    364        1.1    jruoho 
    365        1.1    jruoho 	return AE_NOT_FOUND;
    366        1.1    jruoho }
    367        1.1    jruoho 
    368        1.1    jruoho /*
    369        1.1    jruoho  * Checks if a GUID is present. Child devices
    370        1.1    jruoho  * can use this in their autoconf(9) routines.
    371        1.1    jruoho  */
    372        1.1    jruoho int
    373        1.1    jruoho acpi_wmi_guid_match(device_t self, const char *guid)
    374        1.1    jruoho {
    375        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    376        1.1    jruoho 	ACPI_STATUS rv;
    377        1.1    jruoho 
    378        1.1    jruoho 	rv = acpi_wmi_guid_get(sc, guid, NULL);
    379        1.1    jruoho 
    380        1.1    jruoho 	if (ACPI_SUCCESS(rv))
    381        1.1    jruoho 		return 1;
    382        1.1    jruoho 
    383        1.1    jruoho 	return 0;
    384        1.1    jruoho }
    385        1.1    jruoho 
    386        1.1    jruoho /*
    387        1.1    jruoho  * Adds internal event handler.
    388        1.1    jruoho  */
    389        1.4    jruoho static void
    390        1.1    jruoho acpi_wmi_event_add(struct acpi_wmi_softc *sc)
    391        1.1    jruoho {
    392        1.1    jruoho 	struct wmi_t *wmi;
    393        1.1    jruoho 	ACPI_STATUS rv;
    394        1.1    jruoho 
    395        1.4    jruoho 	if (acpi_register_notify(sc->sc_node, acpi_wmi_event_handler) != true)
    396        1.4    jruoho 		return;
    397        1.1    jruoho 
    398        1.6    jruoho 	/*
    399       1.13  jakllsch 	 * Enable possible events, expensive or otherwise.
    400        1.6    jruoho 	 */
    401        1.1    jruoho 	SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
    402        1.1    jruoho 
    403       1.13  jakllsch 		if ((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) != 0) {
    404        1.1    jruoho 
    405       1.13  jakllsch 			rv = acpi_wmi_enable_event(sc->sc_node->ad_handle,
    406       1.13  jakllsch 			    wmi->guid.nid, true);
    407        1.1    jruoho 
    408        1.1    jruoho 			if (ACPI_SUCCESS(rv)) {
    409        1.1    jruoho 				wmi->eevent = true;
    410        1.1    jruoho 				continue;
    411        1.1    jruoho 			}
    412        1.1    jruoho 
    413        1.6    jruoho 			aprint_debug_dev(sc->sc_dev, "failed to enable "
    414        1.1    jruoho 			    "expensive WExx: %s\n", AcpiFormatException(rv));
    415        1.1    jruoho 		}
    416        1.1    jruoho 	}
    417        1.1    jruoho }
    418        1.1    jruoho 
    419        1.1    jruoho /*
    420        1.1    jruoho  * Removes the internal event handler.
    421        1.1    jruoho  */
    422        1.4    jruoho static void
    423        1.1    jruoho acpi_wmi_event_del(struct acpi_wmi_softc *sc)
    424        1.1    jruoho {
    425        1.1    jruoho 	struct wmi_t *wmi;
    426        1.1    jruoho 	ACPI_STATUS rv;
    427        1.1    jruoho 
    428        1.4    jruoho 	acpi_deregister_notify(sc->sc_node);
    429        1.1    jruoho 
    430        1.1    jruoho 	SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
    431        1.1    jruoho 
    432        1.1    jruoho 		if (wmi->eevent != true)
    433        1.1    jruoho 			continue;
    434        1.1    jruoho 
    435        1.1    jruoho 		KASSERT((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) != 0);
    436        1.1    jruoho 
    437       1.13  jakllsch 		rv = acpi_wmi_enable_event(sc->sc_node->ad_handle,
    438       1.13  jakllsch 		    wmi->guid.nid, false);
    439        1.1    jruoho 
    440        1.1    jruoho 		if (ACPI_SUCCESS(rv)) {
    441        1.1    jruoho 			wmi->eevent = false;
    442        1.1    jruoho 			continue;
    443        1.1    jruoho 		}
    444        1.1    jruoho 
    445        1.6    jruoho 		aprint_debug_dev(sc->sc_dev, "failed to disable "
    446        1.1    jruoho 		    "expensive WExx: %s\n", AcpiFormatException(rv));
    447        1.1    jruoho 	}
    448        1.1    jruoho }
    449        1.1    jruoho 
    450        1.1    jruoho /*
    451        1.1    jruoho  * Returns extra information possibly associated with an event.
    452        1.1    jruoho  */
    453        1.1    jruoho ACPI_STATUS
    454        1.1    jruoho acpi_wmi_event_get(device_t self, uint32_t event, ACPI_BUFFER *obuf)
    455        1.1    jruoho {
    456        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    457        1.1    jruoho 	struct wmi_t *wmi;
    458        1.1    jruoho 	ACPI_OBJECT_LIST arg;
    459        1.1    jruoho 	ACPI_OBJECT obj;
    460        1.2    jruoho 	ACPI_HANDLE hdl;
    461        1.2    jruoho 
    462        1.1    jruoho 	if (sc == NULL || obuf == NULL)
    463        1.1    jruoho 		return AE_BAD_PARAMETER;
    464        1.1    jruoho 
    465        1.1    jruoho 	if (sc->sc_handler == NULL)
    466        1.1    jruoho 		return AE_ABORT_METHOD;
    467        1.1    jruoho 
    468        1.3    jruoho 	hdl = sc->sc_node->ad_handle;
    469        1.3    jruoho 
    470        1.1    jruoho 	obj.Type = ACPI_TYPE_INTEGER;
    471        1.1    jruoho 	obj.Integer.Value = event;
    472        1.1    jruoho 
    473        1.1    jruoho 	arg.Count = 0x01;
    474        1.1    jruoho 	arg.Pointer = &obj;
    475        1.1    jruoho 
    476        1.1    jruoho 	obuf->Pointer = NULL;
    477        1.1    jruoho 	obuf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    478        1.1    jruoho 
    479        1.1    jruoho 	SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
    480        1.1    jruoho 
    481        1.1    jruoho 		if ((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) == 0)
    482        1.1    jruoho 			continue;
    483        1.1    jruoho 
    484        1.1    jruoho 		if (wmi->guid.nid != event)
    485        1.1    jruoho 			continue;
    486        1.1    jruoho 
    487        1.2    jruoho 		return AcpiEvaluateObject(hdl, "_WED", &arg, obuf);
    488        1.1    jruoho 	}
    489        1.1    jruoho 
    490        1.1    jruoho 	return AE_NOT_FOUND;
    491        1.1    jruoho }
    492        1.1    jruoho 
    493        1.1    jruoho /*
    494        1.1    jruoho  * Forwards events to the external handler through the internal one.
    495        1.1    jruoho  */
    496        1.1    jruoho static void
    497        1.1    jruoho acpi_wmi_event_handler(ACPI_HANDLE hdl, uint32_t evt, void *aux)
    498        1.1    jruoho {
    499        1.4    jruoho 	struct acpi_wmi_softc *sc;
    500        1.4    jruoho 	device_t self = aux;
    501        1.4    jruoho 
    502        1.4    jruoho 	sc = device_private(self);
    503        1.1    jruoho 
    504        1.1    jruoho 	if (sc->sc_child == NULL)
    505        1.1    jruoho 		return;
    506        1.1    jruoho 
    507        1.1    jruoho 	if (sc->sc_handler == NULL)
    508        1.1    jruoho 		return;
    509        1.1    jruoho 
    510        1.1    jruoho 	(*sc->sc_handler)(NULL, evt, sc->sc_child);
    511        1.1    jruoho }
    512        1.1    jruoho 
    513        1.1    jruoho ACPI_STATUS
    514        1.1    jruoho acpi_wmi_event_register(device_t self, ACPI_NOTIFY_HANDLER handler)
    515        1.1    jruoho {
    516        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    517        1.1    jruoho 
    518        1.1    jruoho 	if (sc == NULL)
    519        1.1    jruoho 		return AE_BAD_PARAMETER;
    520        1.1    jruoho 
    521        1.1    jruoho 	if (handler != NULL && sc->sc_handler != NULL)
    522        1.1    jruoho 		return AE_ALREADY_EXISTS;
    523        1.1    jruoho 
    524        1.1    jruoho 	sc->sc_handler = handler;
    525        1.1    jruoho 
    526        1.1    jruoho 	return AE_OK;
    527        1.1    jruoho }
    528        1.1    jruoho 
    529        1.1    jruoho ACPI_STATUS
    530        1.1    jruoho acpi_wmi_event_deregister(device_t self)
    531        1.1    jruoho {
    532        1.1    jruoho 	return acpi_wmi_event_register(self, NULL);
    533        1.1    jruoho }
    534        1.1    jruoho 
    535        1.1    jruoho /*
    536       1.11    jruoho  * Handler for EC regions, which may be embedded in WMI.
    537       1.11    jruoho  */
    538       1.11    jruoho static ACPI_STATUS
    539       1.11    jruoho acpi_wmi_ec_handler(uint32_t func, ACPI_PHYSICAL_ADDRESS addr,
    540       1.11    jruoho     uint32_t width, ACPI_INTEGER *val, void *setup, void *aux)
    541       1.11    jruoho {
    542       1.11    jruoho 	struct acpi_wmi_softc *sc = aux;
    543       1.11    jruoho 
    544       1.11    jruoho 	if (aux == NULL || val == NULL)
    545       1.11    jruoho 		return AE_BAD_PARAMETER;
    546       1.11    jruoho 
    547       1.11    jruoho 	if (addr > 0xFF || width % 8 != 0)
    548       1.11    jruoho 		return AE_BAD_ADDRESS;
    549       1.11    jruoho 
    550       1.11    jruoho 	switch (func) {
    551       1.11    jruoho 
    552       1.11    jruoho 	case ACPI_READ:
    553       1.11    jruoho 		(void)acpiec_bus_read(sc->sc_ecdev, addr, val, width);
    554       1.11    jruoho 		break;
    555       1.11    jruoho 
    556       1.11    jruoho 	case ACPI_WRITE:
    557       1.11    jruoho 		(void)acpiec_bus_write(sc->sc_ecdev, addr, *val, width);
    558       1.11    jruoho 		break;
    559       1.11    jruoho 
    560       1.11    jruoho 	default:
    561       1.11    jruoho 		return AE_BAD_PARAMETER;
    562       1.11    jruoho 	}
    563       1.11    jruoho 
    564       1.11    jruoho 	return AE_OK;
    565       1.11    jruoho }
    566       1.11    jruoho 
    567       1.11    jruoho /*
    568        1.1    jruoho  * As there is no prior knowledge about the expensive
    569        1.1    jruoho  * events that cause "significant overhead", try to
    570        1.1    jruoho  * disable (enable) these before suspending (resuming).
    571        1.1    jruoho  */
    572        1.1    jruoho static bool
    573        1.1    jruoho acpi_wmi_suspend(device_t self, const pmf_qual_t *qual)
    574        1.1    jruoho {
    575        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    576        1.1    jruoho 
    577        1.1    jruoho 	acpi_wmi_event_del(sc);
    578        1.1    jruoho 
    579        1.1    jruoho 	return true;
    580        1.1    jruoho }
    581        1.1    jruoho 
    582        1.1    jruoho static bool
    583        1.1    jruoho acpi_wmi_resume(device_t self, const pmf_qual_t *qual)
    584        1.1    jruoho {
    585        1.1    jruoho 	struct acpi_wmi_softc *sc = device_private(self);
    586        1.1    jruoho 
    587        1.1    jruoho 	acpi_wmi_event_add(sc);
    588        1.1    jruoho 
    589        1.1    jruoho 	return true;
    590        1.1    jruoho }
    591        1.1    jruoho 
    592        1.1    jruoho static ACPI_STATUS
    593       1.13  jakllsch acpi_wmi_enable_event(ACPI_HANDLE hdl, uint8_t nid, bool flag)
    594        1.1    jruoho {
    595        1.1    jruoho 	char path[5];
    596        1.1    jruoho 
    597       1.13  jakllsch 	snprintf(path, sizeof(path), "WE%02X", nid);
    598       1.13  jakllsch 
    599       1.13  jakllsch 	return acpi_eval_set_integer(hdl, path, (flag != false) ? 0x01 : 0x00);
    600       1.13  jakllsch }
    601       1.13  jakllsch 
    602       1.13  jakllsch static ACPI_STATUS
    603       1.13  jakllsch acpi_wmi_enable_collection(ACPI_HANDLE hdl, const char *oid, bool flag)
    604       1.13  jakllsch {
    605       1.13  jakllsch 	char path[5];
    606        1.1    jruoho 
    607       1.13  jakllsch 	strlcpy(path, "WC", sizeof(path));
    608       1.13  jakllsch 	strlcat(path, oid, sizeof(path));
    609        1.1    jruoho 
    610        1.1    jruoho 	return acpi_eval_set_integer(hdl, path, (flag != false) ? 0x01 : 0x00);
    611        1.1    jruoho }
    612        1.1    jruoho 
    613        1.1    jruoho static bool
    614        1.1    jruoho acpi_wmi_input(struct wmi_t *wmi, uint8_t flag, uint8_t idx)
    615        1.1    jruoho {
    616        1.1    jruoho 
    617        1.2    jruoho 	if ((wmi->guid.flags & flag) == 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