--- a/sys/dev/acpica/acpi_acad.c +++ b/sys/dev/acpica/acpi_acad.c @@ -62,10 +62,11 @@ struct acpi_acad_softc { int status; + struct sysctl_oid *acline_oid; }; static void acpi_acad_get_status(void *); static void acpi_acad_notify_handler(ACPI_HANDLE, UINT32, void *); +static int acpi_acad_detach(device_t); static int acpi_acad_probe(device_t); static int acpi_acad_ioctl(u_long, caddr_t, void *); static int acpi_acad_sysctl(SYSCTL_HANDLER_ARGS); @@ -74,6 +75,7 @@ static device_method_t acpi_acad_methods[] = { /* Device interface */ DEVMETHOD(device_probe, acpi_acad_probe), DEVMETHOD(device_attach, acpi_acad_attach), + DEVMETHOD(device_detach, acpi_acad_detach), DEVMETHOD_END }; @@ -176,8 +178,10 @@ acpi_acad_attach(device_t dev) ACPI_SERIAL_INIT(acad); if (device_get_unit(dev) == 0) { acpi_sc = acpi_device_get_parent_softc(dev); - SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx, + sc->acline_oid = SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, "acline", CTLTYPE_INT | CTLFLAG_RD, &sc->status, 0, acpi_acad_sysctl, "I", ""); @@ -205,6 +209,28 @@ acpi_acad_attach(device_t dev) return (0); } +static int +acpi_acad_detach(device_t dev) +{ + struct acpi_acad_softc *sc; + + sc = device_get_softc(dev); + + /* Remove both the system and device notify handlers installed at + * attach (context = dev); ACPICA's AcpiRemoveNotifyHandler drains + * deferred notify work itself (evxface.c calls AcpiOsWaitEventsComplete + * while holding the handler removal lock, so an in-flight + * acpi_acad_notify_handler cannot queue new acpi_acad_get_status work + * behind our back). + */ + AcpiRemoveNotifyHandler(acpi_get_handle(dev), ACPI_ALL_NOTIFY, + acpi_acad_notify_handler); + + acpi_deregister_ioctl(ACPIIO_ACAD_GET_STATUS, acpi_acad_ioctl); + + if (sc->acline_oid != NULL) + sysctl_remove_oid(sc->acline_oid, 1, 0); + + return (0); +} + static int acpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg) {