Mon Mar 8 10:53:03 2010 UTC ()
Add a detachment routine.


(jruoho)
diff -r1.15 -r1.16 src/sys/dev/acpi/wmi_acpi.c

cvs diff -r1.15 -r1.16 src/sys/dev/acpi/Attic/wmi_acpi.c (expand / switch to unified diff)

--- src/sys/dev/acpi/Attic/wmi_acpi.c 2010/03/05 14:00:17 1.15
+++ src/sys/dev/acpi/Attic/wmi_acpi.c 2010/03/08 10:53:03 1.16
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: wmi_acpi.c,v 1.15 2010/03/05 14:00:17 jruoho Exp $ */ 1/* $NetBSD: wmi_acpi.c,v 1.16 2010/03/08 10:53:03 jruoho Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2009, 2010 Jukka Ruohonen <jruohonen@iki.fi> 4 * Copyright (c) 2009, 2010 Jukka Ruohonen <jruohonen@iki.fi>
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 10 *
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
@@ -17,27 +17,27 @@ @@ -17,27 +17,27 @@
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE. 27 * SUCH DAMAGE.
28 */ 28 */
29#include <sys/cdefs.h> 29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: wmi_acpi.c,v 1.15 2010/03/05 14:00:17 jruoho Exp $"); 30__KERNEL_RCSID(0, "$NetBSD: wmi_acpi.c,v 1.16 2010/03/08 10:53:03 jruoho Exp $");
31 31
32#include <sys/param.h> 32#include <sys/param.h>
33#include <sys/device.h> 33#include <sys/device.h>
34#include <sys/endian.h> 34#include <sys/endian.h>
35#include <sys/kmem.h> 35#include <sys/kmem.h>
36#include <sys/systm.h> 36#include <sys/systm.h>
37 37
38#include <dev/acpi/acpireg.h> 38#include <dev/acpi/acpireg.h>
39#include <dev/acpi/acpivar.h> 39#include <dev/acpi/acpivar.h>
40#include <dev/acpi/wmi_acpivar.h> 40#include <dev/acpi/wmi_acpivar.h>
41 41
42#define _COMPONENT ACPI_RESOURCE_COMPONENT 42#define _COMPONENT ACPI_RESOURCE_COMPONENT
43ACPI_MODULE_NAME ("wmi_acpi") 43ACPI_MODULE_NAME ("wmi_acpi")
@@ -107,96 +107,115 @@ struct acpi_wmi_softc { @@ -107,96 +107,115 @@ struct acpi_wmi_softc {
107 107
108#define HEXCHAR(x) (((x) >= '0' && (x) <= '9') || \ 108#define HEXCHAR(x) (((x) >= '0' && (x) <= '9') || \
109 ((x) >= 'a' && (x) <= 'f') || \ 109 ((x) >= 'a' && (x) <= 'f') || \
110 ((x) >= 'A' && (x) <= 'F')) 110 ((x) >= 'A' && (x) <= 'F'))
111 111
112#define GUIDCMP(a, b) \ 112#define GUIDCMP(a, b) \
113 ((a)->data1 == (b)->data1 && \ 113 ((a)->data1 == (b)->data1 && \
114 (a)->data2 == (b)->data2 && \ 114 (a)->data2 == (b)->data2 && \
115 (a)->data3 == (b)->data3 && \ 115 (a)->data3 == (b)->data3 && \
116 UGET64((a)->data4) == UGET64((b)->data4)) 116 UGET64((a)->data4) == UGET64((b)->data4))
117 117
118static int acpi_wmi_match(device_t, cfdata_t, void *); 118static int acpi_wmi_match(device_t, cfdata_t, void *);
119static void acpi_wmi_attach(device_t, device_t, void *); 119static void acpi_wmi_attach(device_t, device_t, void *);
 120static int acpi_wmi_detach(device_t, int);
120static int acpi_wmi_print(void *, const char *); 121static int acpi_wmi_print(void *, const char *);
121static bool acpi_wmi_init(struct acpi_wmi_softc *); 122static bool acpi_wmi_init(struct acpi_wmi_softc *);
122static bool acpi_wmi_add(struct acpi_wmi_softc *, ACPI_OBJECT *); 123static bool acpi_wmi_add(struct acpi_wmi_softc *, ACPI_OBJECT *);
123static void acpi_wmi_del(struct acpi_wmi_softc *); 124static void acpi_wmi_del(struct acpi_wmi_softc *);
124 125
125#ifdef ACPIVERBOSE 126#ifdef ACPIVERBOSE
126static void acpi_wmi_dump(struct acpi_wmi_softc *); 127static void acpi_wmi_dump(struct acpi_wmi_softc *);
127#endif 128#endif
128 129
129static ACPI_STATUS acpi_wmi_guid_get(struct acpi_wmi_softc *, 130static ACPI_STATUS acpi_wmi_guid_get(struct acpi_wmi_softc *,
130 const char *, struct wmi_t **); 131 const char *, struct wmi_t **);
131static void acpi_wmi_event_add(struct acpi_wmi_softc *); 132static ACPI_STATUS acpi_wmi_event_add(struct acpi_wmi_softc *);
132static void acpi_wmi_event_del(struct acpi_wmi_softc *); 133static ACPI_STATUS acpi_wmi_event_del(struct acpi_wmi_softc *);
133static void acpi_wmi_event_handler(ACPI_HANDLE, uint32_t, void *); 134static void acpi_wmi_event_handler(ACPI_HANDLE, uint32_t, void *);
134static bool acpi_wmi_suspend(device_t, const pmf_qual_t *); 135static bool acpi_wmi_suspend(device_t, const pmf_qual_t *);
135static bool acpi_wmi_resume(device_t, const pmf_qual_t *); 136static bool acpi_wmi_resume(device_t, const pmf_qual_t *);
136static ACPI_STATUS acpi_wmi_enable(ACPI_HANDLE, const char *, bool, bool); 137static ACPI_STATUS acpi_wmi_enable(ACPI_HANDLE, const char *, bool, bool);
137static bool acpi_wmi_input(struct wmi_t *, uint8_t, uint8_t); 138static bool acpi_wmi_input(struct wmi_t *, uint8_t, uint8_t);
138 139
139const char * const acpi_wmi_ids[] = { 140const char * const acpi_wmi_ids[] = {
140 "PNP0C14", 141 "PNP0C14",
141 NULL 142 NULL
142}; 143};
143 144
144CFATTACH_DECL_NEW(acpiwmi, sizeof(struct acpi_wmi_softc), 145CFATTACH_DECL_NEW(acpiwmi, sizeof(struct acpi_wmi_softc),
145 acpi_wmi_match, acpi_wmi_attach, NULL, NULL); 146 acpi_wmi_match, acpi_wmi_attach, acpi_wmi_detach, NULL);
146 147
147static int 148static int
148acpi_wmi_match(device_t parent, cfdata_t match, void *aux) 149acpi_wmi_match(device_t parent, cfdata_t match, void *aux)
149{ 150{
150 struct acpi_attach_args *aa = aux; 151 struct acpi_attach_args *aa = aux;
151 152
152 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) 153 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
153 return 0; 154 return 0;
154 155
155 return acpi_match_hid(aa->aa_node->ad_devinfo, acpi_wmi_ids); 156 return acpi_match_hid(aa->aa_node->ad_devinfo, acpi_wmi_ids);
156} 157}
157 158
158static void 159static void
159acpi_wmi_attach(device_t parent, device_t self, void *aux) 160acpi_wmi_attach(device_t parent, device_t self, void *aux)
160{ 161{
161 struct acpi_wmi_softc *sc = device_private(self); 162 struct acpi_wmi_softc *sc = device_private(self);
162 struct acpi_attach_args *aa = aux; 163 struct acpi_attach_args *aa = aux;
163 164
164 sc->sc_dev = self; 165 sc->sc_dev = self;
165 sc->sc_node = aa->aa_node; 166 sc->sc_node = aa->aa_node;
 167
 168 sc->sc_child = NULL;
166 sc->sc_handler = NULL; 169 sc->sc_handler = NULL;
167 170
168 aprint_naive("\n"); 171 aprint_naive("\n");
169 aprint_normal(": ACPI WMI Interface\n"); 172 aprint_normal(": ACPI WMI Interface\n");
170 173
171 if (acpi_wmi_init(sc) != true) 174 if (acpi_wmi_init(sc) != true)
172 return; 175 return;
173 176
174#ifdef ACPIVERBOSE 177#ifdef ACPIVERBOSE
175 acpi_wmi_dump(sc); 178 acpi_wmi_dump(sc);
176#endif 179#endif
177 180
178 acpi_wmi_event_add(sc); 181 (void)acpi_wmi_event_add(sc);
179 182 (void)pmf_device_register(self, acpi_wmi_suspend, acpi_wmi_resume);
180 if (pmf_device_register(sc->sc_dev, 
181 acpi_wmi_suspend, acpi_wmi_resume) != true) 
182 aprint_error_dev(self, "failed to register power handler\n"); 
183 183
184 /* Attach a child device to the pseudo-bus. */ 
185 sc->sc_child = config_found_ia(self, "acpiwmibus", 184 sc->sc_child = config_found_ia(self, "acpiwmibus",
186 NULL, acpi_wmi_print); 185 NULL, acpi_wmi_print);
187} 186}
188 187
189static int 188static int
 189acpi_wmi_detach(device_t self, int flags)
 190{
 191 struct acpi_wmi_softc *sc = device_private(self);
 192 ACPI_STATUS rv;
 193
 194 rv = acpi_wmi_event_del(sc);
 195
 196 if (ACPI_FAILURE(rv))
 197 return EBUSY;
 198
 199 if (sc->sc_child != NULL)
 200 (void)config_detach(sc->sc_child, flags);
 201
 202 acpi_wmi_del(sc);
 203 pmf_device_deregister(self);
 204
 205 return 0;
 206}
 207
 208static int
190acpi_wmi_print(void *aux, const char *pnp) 209acpi_wmi_print(void *aux, const char *pnp)
191{ 210{
192 211
193 if (pnp != NULL) 212 if (pnp != NULL)
194 aprint_normal("acpiwmibus at %s", pnp); 213 aprint_normal("acpiwmibus at %s", pnp);
195 214
196 return UNCONF; 215 return UNCONF;
197} 216}
198 217
199static bool 218static bool
200acpi_wmi_init(struct acpi_wmi_softc *sc) 219acpi_wmi_init(struct acpi_wmi_softc *sc)
201{ 220{
202 ACPI_OBJECT *obj; 221 ACPI_OBJECT *obj;
@@ -379,98 +398,102 @@ int @@ -379,98 +398,102 @@ int
379acpi_wmi_guid_match(device_t self, const char *guid) 398acpi_wmi_guid_match(device_t self, const char *guid)
380{ 399{
381 struct acpi_wmi_softc *sc = device_private(self); 400 struct acpi_wmi_softc *sc = device_private(self);
382 401
383 if (ACPI_SUCCESS(acpi_wmi_guid_get(sc, guid, NULL))) 402 if (ACPI_SUCCESS(acpi_wmi_guid_get(sc, guid, NULL)))
384 return 1; 403 return 1;
385 404
386 return 0; 405 return 0;
387} 406}
388 407
389/* 408/*
390 * Adds internal event handler. 409 * Adds internal event handler.
391 */ 410 */
392static void 411static ACPI_STATUS
393acpi_wmi_event_add(struct acpi_wmi_softc *sc) 412acpi_wmi_event_add(struct acpi_wmi_softc *sc)
394{ 413{
395 struct wmi_t *wmi; 414 struct wmi_t *wmi;
396 ACPI_STATUS rv; 415 ACPI_STATUS rv;
397 416
398 rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, 417 rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle,
399 ACPI_ALL_NOTIFY, acpi_wmi_event_handler, sc); 418 ACPI_ALL_NOTIFY, acpi_wmi_event_handler, sc);
400 419
401 if (ACPI_FAILURE(rv)) { 420 if (ACPI_FAILURE(rv)) {
402 aprint_error_dev(sc->sc_dev, "failed to install notify " 421 aprint_error_dev(sc->sc_dev, "failed to install notify "
403 "handler: %s\n", AcpiFormatException(rv)); 422 "handler: %s\n", AcpiFormatException(rv));
404 return; 423 return rv;
405 } 424 }
406 425
407 /* Enable possible expensive events. */ 426 /* Enable possible expensive events. */
408 SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) { 427 SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
409 428
410 if ((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) && 429 if ((wmi->guid.flags & ACPI_WMI_FLAG_EVENT) &&
411 (wmi->guid.flags & ACPI_WMI_FLAG_EXPENSIVE)) { 430 (wmi->guid.flags & ACPI_WMI_FLAG_EXPENSIVE)) {
412 431
413 rv = acpi_wmi_enable(sc->sc_node->ad_handle, 432 rv = acpi_wmi_enable(sc->sc_node->ad_handle,
414 wmi->guid.oid, false, true); 433 wmi->guid.oid, false, true);
415 434
416 if (ACPI_SUCCESS(rv)) { 435 if (ACPI_SUCCESS(rv)) {
417 wmi->eevent = true; 436 wmi->eevent = true;
418 continue; 437 continue;
419 } 438 }
420 439
421 aprint_error_dev(sc->sc_dev, "failed to enable " 440 aprint_error_dev(sc->sc_dev, "failed to enable "
422 "expensive WExx: %s\n", AcpiFormatException(rv)); 441 "expensive WExx: %s\n", AcpiFormatException(rv));
423 } 442 }
424 } 443 }
 444
 445 return AE_OK;
425} 446}
426 447
427/* 448/*
428 * Removes the internal event handler. 449 * Removes the internal event handler.
429 */ 450 */
430static void 451static ACPI_STATUS
431acpi_wmi_event_del(struct acpi_wmi_softc *sc) 452acpi_wmi_event_del(struct acpi_wmi_softc *sc)
432{ 453{
433 struct wmi_t *wmi; 454 struct wmi_t *wmi;
434 ACPI_STATUS rv; 455 ACPI_STATUS rv;
435 456
436 rv = AcpiRemoveNotifyHandler(sc->sc_node->ad_handle, 457 rv = AcpiRemoveNotifyHandler(sc->sc_node->ad_handle,
437 ACPI_ALL_NOTIFY, acpi_wmi_event_handler); 458 ACPI_ALL_NOTIFY, acpi_wmi_event_handler);
438 459
439 if (ACPI_FAILURE(rv)) { 460 if (ACPI_FAILURE(rv)) {
440 aprint_debug_dev(sc->sc_dev, "failed to remove notify " 461 aprint_debug_dev(sc->sc_dev, "failed to remove notify "
441 "handler: %s\n", AcpiFormatException(rv)); 462 "handler: %s\n", AcpiFormatException(rv));
442 return; 463 return rv;
443 } 464 }
444 465
445 SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) { 466 SIMPLEQ_FOREACH(wmi, &sc->wmi_head, wmi_link) {
446 467
447 if (wmi->eevent != true) 468 if (wmi->eevent != true)
448 continue; 469 continue;
449 470
450 KASSERT(wmi->guid.flags & ACPI_WMI_FLAG_EVENT); 471 KASSERT(wmi->guid.flags & ACPI_WMI_FLAG_EVENT);
451 KASSERT(wmi->guid.flags & ACPI_WMI_FLAG_EXPENSIVE); 472 KASSERT(wmi->guid.flags & ACPI_WMI_FLAG_EXPENSIVE);
452 473
453 rv = acpi_wmi_enable(sc->sc_node->ad_handle, 474 rv = acpi_wmi_enable(sc->sc_node->ad_handle,
454 wmi->guid.oid, false, false); 475 wmi->guid.oid, false, false);
455 476
456 if (ACPI_SUCCESS(rv)) { 477 if (ACPI_SUCCESS(rv)) {
457 wmi->eevent = false; 478 wmi->eevent = false;
458 continue; 479 continue;
459 } 480 }
460 481
461 aprint_error_dev(sc->sc_dev, "failed to disable " 482 aprint_error_dev(sc->sc_dev, "failed to disable "
462 "expensive WExx: %s\n", AcpiFormatException(rv)); 483 "expensive WExx: %s\n", AcpiFormatException(rv));
463 } 484 }
 485
 486 return AE_OK;
464} 487}
465 488
466/* 489/*
467 * Returns extra information possibly associated with an event. 490 * Returns extra information possibly associated with an event.
468 */ 491 */
469ACPI_STATUS 492ACPI_STATUS
470acpi_wmi_event_get(device_t self, uint32_t event, ACPI_BUFFER *obuf) 493acpi_wmi_event_get(device_t self, uint32_t event, ACPI_BUFFER *obuf)
471{ 494{
472 struct acpi_wmi_softc *sc = device_private(self); 495 struct acpi_wmi_softc *sc = device_private(self);
473 struct wmi_t *wmi; 496 struct wmi_t *wmi;
474 ACPI_OBJECT_LIST arg; 497 ACPI_OBJECT_LIST arg;
475 ACPI_OBJECT obj; 498 ACPI_OBJECT obj;
476 499
@@ -502,26 +525,29 @@ acpi_wmi_event_get(device_t self, uint32 @@ -502,26 +525,29 @@ acpi_wmi_event_get(device_t self, uint32
502 } 525 }
503 526
504 return AE_NOT_FOUND; 527 return AE_NOT_FOUND;
505} 528}
506 529
507/* 530/*
508 * Forwards events to the external handler through the internal one. 531 * Forwards events to the external handler through the internal one.
509 */ 532 */
510static void 533static void
511acpi_wmi_event_handler(ACPI_HANDLE hdl, uint32_t evt, void *aux) 534acpi_wmi_event_handler(ACPI_HANDLE hdl, uint32_t evt, void *aux)
512{ 535{
513 struct acpi_wmi_softc *sc = aux; 536 struct acpi_wmi_softc *sc = aux;
514 537
 538 if (sc->sc_child == NULL)
 539 return;
 540
515 if (sc->sc_handler == NULL) 541 if (sc->sc_handler == NULL)
516 return; 542 return;
517 543
518 (*sc->sc_handler)(NULL, evt, sc->sc_child); 544 (*sc->sc_handler)(NULL, evt, sc->sc_child);
519} 545}
520 546
521/* 547/*
522 * Adds or removes (NULL) the external event handler. 548 * Adds or removes (NULL) the external event handler.
523 */ 549 */
524ACPI_STATUS 550ACPI_STATUS
525acpi_wmi_event_register(device_t self, ACPI_NOTIFY_HANDLER handler) 551acpi_wmi_event_register(device_t self, ACPI_NOTIFY_HANDLER handler)
526{ 552{
527 struct acpi_wmi_softc *sc = device_private(self); 553 struct acpi_wmi_softc *sc = device_private(self);