diff options
author | iwasaki <iwasaki@FreeBSD.org> | 2006-04-15 12:31:34 +0000 |
---|---|---|
committer | iwasaki <iwasaki@FreeBSD.org> | 2006-04-15 12:31:34 +0000 |
commit | 0613b693d0f3abaab631563bf8317bf448193a01 (patch) | |
tree | 57443a0c29eee4bcf962bf261e8f771819778250 | |
parent | e3ccf599d517db9884169bea0bcb19634b43317a (diff) | |
download | FreeBSD-src-0613b693d0f3abaab631563bf8317bf448193a01.zip FreeBSD-src-0613b693d0f3abaab631563bf8317bf448193a01.tar.gz |
Import ACPI Dock Station support. Note that this is still very young.
Additional detach implementaions (or maybe improvement) for other
deivce drivers is required.
Reviewed by: njl, imp
MFC after: 1 week
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/dev/acpica/acpi.c | 14 | ||||
-rw-r--r-- | sys/dev/acpica/acpi_cmbat.c | 5 | ||||
-rw-r--r-- | sys/dev/acpica/acpi_dock.c | 583 | ||||
-rw-r--r-- | sys/dev/ppbus/lpt.c | 16 | ||||
-rw-r--r-- | sys/dev/ppbus/ppbconf.c | 18 | ||||
-rw-r--r-- | sys/dev/ppc/ppc.c | 42 | ||||
-rw-r--r-- | sys/dev/ppc/ppcvar.h | 1 | ||||
-rw-r--r-- | sys/i386/conf/NOTES | 3 | ||||
-rw-r--r-- | sys/modules/acpi/Makefile | 2 | ||||
-rw-r--r-- | sys/modules/acpi/acpi_dock/Makefile | 9 |
11 files changed, 691 insertions, 3 deletions
diff --git a/sys/conf/files b/sys/conf/files index 985d8e6..a48930f 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -407,6 +407,7 @@ dev/acpica/acpi_thermal.c optional acpi dev/acpica/acpi_throttle.c optional acpi dev/acpica/acpi_timer.c optional acpi dev/acpica/acpi_video.c optional acpi_video acpi +dev/acpica/acpi_dock.c optional acpi_dock acpi dev/adlink/adlink.c optional adlink dev/advansys/adv_eisa.c optional adv eisa dev/advansys/adv_pci.c optional adv pci diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index ee7e015..6fb2c75 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -1518,6 +1518,7 @@ static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status) { ACPI_OBJECT_TYPE type; + ACPI_HANDLE h; device_t bus, child; int order, probe_now; char *handle_str, **search; @@ -1577,8 +1578,17 @@ acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status) * "functional" (i.e. if disabled). Go ahead and probe them * anyway since we may enable them later. */ - if (type == ACPI_TYPE_DEVICE && !acpi_DeviceIsPresent(child) && - !acpi_MatchHid(handle, "PNP0C0F")) { + if (type == ACPI_TYPE_DEVICE && !acpi_DeviceIsPresent(child)) { + /* Never disable PCI link devices. */ + if (acpi_MatchHid(handle, "PNP0C0F")) + break; + /* + * Docking stations should remain enabled since the system + * may be undocked at boot. + */ + if (ACPI_SUCCESS(AcpiGetHandle(handle, "_DCK", &h))) + break; + device_disable(child); break; } diff --git a/sys/dev/acpica/acpi_cmbat.c b/sys/dev/acpica/acpi_cmbat.c index e27ffcb..92a8db7 100644 --- a/sys/dev/acpica/acpi_cmbat.c +++ b/sys/dev/acpica/acpi_cmbat.c @@ -159,6 +159,7 @@ acpi_cmbat_detach(device_t dev) { acpi_battery_remove(dev); + AcpiRemoveNotifyHandler(handle, ACPI_ALL_NOTIFY, acpi_cmbat_notify_handler); return (0); } @@ -435,6 +436,10 @@ acpi_cmbat_init_battery(void *arg) * to wait a while. */ for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) { + /* batteries on DOCK can be ejected w/ DOCK during retrying */ + if (!device_is_attached(dev)) + return; + if (!acpi_BatteryIsPresent(dev)) continue; diff --git a/sys/dev/acpica/acpi_dock.c b/sys/dev/acpica/acpi_dock.c new file mode 100644 index 0000000..494c838 --- /dev/null +++ b/sys/dev/acpica/acpi_dock.c @@ -0,0 +1,583 @@ +/*- + * Copyright (c) 2005-2006 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_acpi.h" +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/bus.h> + +#include <sys/kdb.h> + +#include <machine/bus.h> +#include <sys/module.h> + +#include "acpi.h" +#include <dev/acpica/acpivar.h> +#include <dev/acpica/acpiio.h> + +#include <contrib/dev/acpica/acnamesp.h> + +/* Hooks for the ACPI CA debugging infrastructure */ +#define _COMPONENT ACPI_DOCK +ACPI_MODULE_NAME("DOCK") + +/* For Notify handler */ +#define ACPI_DOCK_NOTIFY_BUS_CHECK 0x00 +#define ACPI_DOCK_NOTIFY_DEVICE_CHECK 0x01 +#define ACPI_DOCK_NOTIFY_EJECT_REQUEST 0x03 + +/* For Docking status */ +#define ACPI_DOCK_STATUS_UNKNOWN -1 +#define ACPI_DOCK_STATUS_UNDOCKED 0 +#define ACPI_DOCK_STATUS_DOCKED 1 + +struct acpi_dock_softc { + int _sta; + int _bdn; + int _uid; + int status; + struct sysctl_ctx_list *sysctl_ctx; + struct sysctl_oid *sysctl_tree; +}; + +/* Global docking status, for avoiding duplicated docking */ +static int acpi_dock_status = ACPI_DOCK_STATUS_UNKNOWN; + +ACPI_SERIAL_DECL(dock, "ACPI Dock Station"); + +/* + * Utility + */ + +static void +acpi_dock_get_info(device_t dev) +{ + struct acpi_dock_softc *sc; + ACPI_HANDLE h; + + sc = device_get_softc(dev); + h = acpi_get_handle(dev); + + if (ACPI_FAILURE(acpi_GetInteger(h, "_STA", &sc->_sta))) { + sc->_sta = ACPI_DOCK_STATUS_UNKNOWN; + } + ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), + "_STA = %04x\n", sc->_sta); + + if (ACPI_FAILURE(acpi_GetInteger(h, "_BDN", &sc->_bdn))) { + sc->_bdn = ACPI_DOCK_STATUS_UNKNOWN; + } + ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), + "_BDN = %04x\n", sc->_bdn); + + if (ACPI_FAILURE(acpi_GetInteger(h, "_UID", &sc->_uid))) { + sc->_uid = ACPI_DOCK_STATUS_UNKNOWN; + } + ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), + "_UID = %04x\n", sc->_uid); +} + +static int +acpi_dock_execute_dck(device_t dev, int dock) +{ + ACPI_HANDLE h; + ACPI_OBJECT argobj; + ACPI_OBJECT_LIST args; + ACPI_BUFFER buf; + ACPI_OBJECT retobj; + ACPI_STATUS status; + + h = acpi_get_handle(dev); + + argobj.Type = ACPI_TYPE_INTEGER; + argobj.Integer.Value = dock; + args.Count = 1; + args.Pointer = &argobj; + buf.Pointer = &retobj; + buf.Length = sizeof(retobj); + status = AcpiEvaluateObject(h, "_DCK", &args, &buf); + + if (dock == ACPI_DOCK_STATUS_UNDOCKED) { + /* + * When _DCK is called with 0, OSPM will ignore the return value. + */ + return (0); + } + + if (ACPI_SUCCESS(status)) { + if (retobj.Type == ACPI_TYPE_INTEGER && + retobj.Integer.Value == 1) { + return (0); + } + } + + return (-1); +} + +static void +acpi_dock_execute_lck(device_t dev, int lock) +{ + ACPI_HANDLE h; + + h = acpi_get_handle(dev); + acpi_SetInteger(h, "_LCK", lock); +} + +static int +acpi_dock_execute_ejx(device_t dev, int eject, int state) +{ + ACPI_HANDLE h; + ACPI_STATUS status; + char ejx[5]; + + h = acpi_get_handle(dev); + snprintf(ejx, sizeof(ejx), "_EJ%d", state); + status = acpi_SetInteger(h, ejx, eject); + + if (ACPI_SUCCESS(status)) { + return (0); + } + + return (-1); +} + +static int +acpi_dock_is_ejd_device(ACPI_HANDLE dock_handle, ACPI_HANDLE handle) +{ + int ret; + ACPI_STATUS ret_status; + ACPI_BUFFER ejd_buffer; + ACPI_OBJECT *obj; + + ret = 0; + + ejd_buffer.Pointer = NULL; + ejd_buffer.Length = ACPI_ALLOCATE_BUFFER; + ret_status = AcpiEvaluateObject(handle, "_EJD", NULL, &ejd_buffer); + + if (ACPI_FAILURE(ret_status)) { + goto out; + } + + obj = (ACPI_OBJECT *)ejd_buffer.Pointer; + if (dock_handle != acpi_GetReference(NULL, obj)) { + goto out; + } + + ret = 1; + +out: + if (ejd_buffer.Pointer != NULL) + AcpiOsFree(ejd_buffer.Pointer); + + return (ret); +} + +/* + * Dock + */ + +static void +acpi_dock_attach_later(void *context) +{ + device_t dev; + + dev = (device_t)context; + + if (!device_is_enabled(dev)) { + device_enable(dev); + } + + mtx_lock(&Giant); + device_probe_and_attach(dev); + mtx_unlock(&Giant); +} + +static ACPI_STATUS +acpi_dock_insert_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status) +{ + device_t dock_dev, dev; + ACPI_HANDLE dock_handle; + + dock_dev = (device_t)context; + dock_handle = acpi_get_handle(dock_dev); + + if (!acpi_dock_is_ejd_device(dock_handle, handle)) { + goto out; + } + + ACPI_VPRINT(dock_dev, acpi_device_get_parent_softc(dock_dev), + "inserting device for %s\n", acpi_name(handle)); + +#if 0 + /* + * If the system boot up w/o Docking, the devices under the dock + * still un-initialized, also control methods such as _INI, _STA + * are not executed. + * Normal devices are initialized at booting by calling + * AcpiInitializeObjects(), however the devices under the dock + * need to be initialized here on the scheme of ACPICA. + */ + ACPI_INIT_WALK_INFO Info; + + AcpiNsWalkNamespace(ACPI_TYPE_ANY, handle, + 100, TRUE, AcpiNsInitOneDevice, &Info, NULL); +#endif + + dev = acpi_get_device(handle); + if (dev == NULL) { + ACPI_VPRINT(dock_dev, acpi_device_get_parent_softc(dock_dev), + "%s has no device, something wrong\n", + acpi_name(handle)); + goto out; + } + + AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_dock_attach_later, dev); + +out: + return (AE_OK); +} + +static void +acpi_dock_insert_children(device_t dev) +{ + ACPI_HANDLE sb_handle; + + if (ACPI_SUCCESS(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle))) { + AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle, + 100, acpi_dock_insert_child, dev, NULL); + } +} + +static void +acpi_dock_insert(device_t dev) +{ + struct acpi_dock_softc *sc; + ACPI_HANDLE h; + + ACPI_SERIAL_ASSERT(dock); + + sc = device_get_softc(dev); + h = acpi_get_handle(dev); + + if (acpi_dock_status == ACPI_DOCK_STATUS_UNDOCKED || + acpi_dock_status == ACPI_DOCK_STATUS_UNKNOWN) { + acpi_dock_execute_lck(dev, 1); + if (acpi_dock_execute_dck(dev, 1) != 0) { + device_printf(dev, "_DCK failed\n"); + return; + } + + if (!cold) { + acpi_dock_insert_children(dev); + } + sc->status = acpi_dock_status = ACPI_DOCK_STATUS_DOCKED; + } +} + + +/* + * Undock + */ + +static ACPI_STATUS +acpi_dock_eject_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status) +{ + device_t dock_dev, dev; + ACPI_HANDLE dock_handle; + + dock_dev = *(device_t *)context; + dock_handle = acpi_get_handle(dock_dev); + + if (!acpi_dock_is_ejd_device(dock_handle, handle)) { + goto out; + } + + ACPI_VPRINT(dock_dev, acpi_device_get_parent_softc(dock_dev), + "ejecting device for %s\n", acpi_name(handle)); + + dev = acpi_get_device(handle); + if (dev != NULL && device_is_attached(dev)) { + mtx_lock(&Giant); + device_detach(dev); + mtx_unlock(&Giant); + } + + acpi_SetInteger(handle, "_EJ0", 0); +out: + return (AE_OK); +} + +static void +acpi_dock_eject_children(device_t dev) +{ + ACPI_HANDLE sb_handle; + + if (ACPI_SUCCESS(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle))) { + AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle, + 100, acpi_dock_eject_child, &dev, NULL); + } +} + +static void +acpi_dock_removal(device_t dev) +{ + struct acpi_dock_softc *sc; + + ACPI_SERIAL_ASSERT(dock); + + sc = device_get_softc(dev); + if (acpi_dock_status == ACPI_DOCK_STATUS_DOCKED || + acpi_dock_status == ACPI_DOCK_STATUS_UNKNOWN) { + acpi_dock_eject_children(dev); + if (acpi_dock_execute_dck(dev, 0) != 0) { + return; + } + + acpi_dock_execute_lck(dev, 0); + + if (acpi_dock_execute_ejx(dev, 1, 0) != 0) { + device_printf(dev, "_EJ0 failed\n"); + return; + } + + sc->status = acpi_dock_status = ACPI_DOCK_STATUS_UNDOCKED; + } + + acpi_dock_get_info(dev); + if (sc->_sta != 0) { + device_printf(dev, "mechanical failures (%#x).\n", sc->_sta); + } +} + +/* + * Device/Bus check + */ + +static void +acpi_dock_device_check(device_t dev) +{ + struct acpi_dock_softc *sc; + + ACPI_SERIAL_ASSERT(dock); + + sc = device_get_softc(dev); + acpi_dock_get_info(dev); + + /* + * If the _STA indicates 'present' and 'functioning', + * the system is docked. + */ + if (ACPI_DEVICE_PRESENT(sc->_sta)) { + acpi_dock_insert(dev); + } + if (sc->_sta == 0x0) { + acpi_dock_removal(dev); + } +} + +/* + * Notify Handler + */ + +static void +acpi_dock_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) +{ + device_t dev; + + dev = (device_t) context; + ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), + "got notification %#x\n", notify); + + ACPI_SERIAL_BEGIN(dock); + switch (notify) { + case ACPI_DOCK_NOTIFY_BUS_CHECK: + case ACPI_DOCK_NOTIFY_DEVICE_CHECK: + acpi_dock_device_check(dev); + break; + + case ACPI_DOCK_NOTIFY_EJECT_REQUEST: + acpi_dock_removal(dev); + break; + + default: + device_printf(dev, "unknown notify %#x\n", notify); + break; + } + ACPI_SERIAL_END(dock); +} + +/* + * Sysctl proc + */ + +static int +acpi_dock_status_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct acpi_dock_softc *sc; + device_t dev; + int status, err; + + + err = 0; + dev = (device_t)arg1; + sc = device_get_softc(dev); + status = sc->status; + + ACPI_SERIAL_BEGIN(dock); + err = sysctl_handle_int(oidp, &status, 0, req); + if (err != 0 || req->newptr == NULL) { + goto out; + } + + if (status != ACPI_DOCK_STATUS_UNDOCKED && + status != ACPI_DOCK_STATUS_DOCKED) { + err = EINVAL; + goto out; + } + + if (status == sc->status) { + goto out; + } + + switch (status) { + case ACPI_DOCK_STATUS_UNDOCKED: + acpi_dock_removal(dev); + break; + + case ACPI_DOCK_STATUS_DOCKED: + acpi_dock_device_check(dev); + break; + + default: + err = EINVAL; + break; + } +out: + ACPI_SERIAL_END(dock); + return (err); +} + +/* + * probe/attach + */ + +static int +acpi_dock_probe(device_t dev) +{ + ACPI_HANDLE h, tmp; + + h = acpi_get_handle(dev); + if (acpi_disabled("dock") || + ACPI_FAILURE(AcpiGetHandle(h, "_DCK", &tmp))) + return (ENXIO); + + if (acpi_dock_status == ACPI_DOCK_STATUS_DOCKED) { + return (ENXIO); + } + + device_set_desc(dev, "ACPI Dock Station"); + return (0); +} + +static int +acpi_dock_attach(device_t dev) +{ + struct acpi_dock_softc *sc; + ACPI_HANDLE h; + + sc = device_get_softc(dev); + if (sc == NULL) + return (ENXIO); + + h = acpi_get_handle(dev); + if (h == NULL) + return (ENXIO); + + if (acpi_dock_status == ACPI_DOCK_STATUS_DOCKED) { + return (ENXIO); + } + + sc->status = ACPI_DOCK_STATUS_UNKNOWN; + + AcpiEvaluateObject(h, "_INI", NULL, NULL); + + ACPI_SERIAL_BEGIN(dock); + + acpi_dock_device_check(dev); + + /* Get the sysctl tree */ + sc->sysctl_ctx = device_get_sysctl_ctx(dev); + sc->sysctl_tree = device_get_sysctl_tree(dev); + + SYSCTL_ADD_INT(sc->sysctl_ctx, + SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "_sta", CTLFLAG_RD, + &sc->_sta, 0, "Dock _STA"); + SYSCTL_ADD_INT(sc->sysctl_ctx, + SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "_bdn", CTLFLAG_RD, + &sc->_bdn, 0, "Dock _BDN"); + SYSCTL_ADD_INT(sc->sysctl_ctx, + SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "_uid", CTLFLAG_RD, + &sc->_uid, 0, "Dock _UID"); + SYSCTL_ADD_PROC(sc->sysctl_ctx, + SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "status", + CTLTYPE_INT|CTLFLAG_RW, dev, 0, + acpi_dock_status_sysctl, "I", + "Dock/Undock operation"); + + ACPI_SERIAL_END(dock); + + AcpiInstallNotifyHandler(h, ACPI_ALL_NOTIFY, + acpi_dock_notify_handler, dev); + + return (0); +} + +static device_method_t acpi_dock_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, acpi_dock_probe), + DEVMETHOD(device_attach, acpi_dock_attach), + + {0, 0} +}; + +static driver_t acpi_dock_driver = { + "acpi_dock", + acpi_dock_methods, + sizeof(struct acpi_dock_softc), +}; + +static devclass_t acpi_dock_devclass; + +DRIVER_MODULE(acpi_dock, acpi, acpi_dock_driver, acpi_dock_devclass, 0, 0); +MODULE_DEPEND(acpi_dock, acpi, 1, 1, 1); + diff --git a/sys/dev/ppbus/lpt.c b/sys/dev/ppbus/lpt.c index 6296da5..e968aa5 100644 --- a/sys/dev/ppbus/lpt.c +++ b/sys/dev/ppbus/lpt.c @@ -409,6 +409,21 @@ lpt_attach(device_t dev) return (0); } +static int +lpt_detach(device_t dev) +{ + struct lpt_data *sc = DEVTOSOFTC(dev); + + lpt_release_ppbus(dev); + if (sc->intr_resource != 0) { + BUS_TEARDOWN_INTR(device_get_parent(dev), dev, + sc->intr_resource, sc->intr_cookie); + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->intr_resource); + } + + return (0); +} + static void lptout(void *arg) { @@ -954,6 +969,7 @@ static device_method_t lpt_methods[] = { DEVMETHOD(device_identify, lpt_identify), DEVMETHOD(device_probe, lpt_probe), DEVMETHOD(device_attach, lpt_attach), + DEVMETHOD(device_detach, lpt_detach), { 0, 0 } }; diff --git a/sys/dev/ppbus/ppbconf.c b/sys/dev/ppbus/ppbconf.c index 1ad27f8..53421a2 100644 --- a/sys/dev/ppbus/ppbconf.c +++ b/sys/dev/ppbus/ppbconf.c @@ -399,6 +399,23 @@ ppbus_attach(device_t dev) } static int +ppbus_detach(device_t dev) +{ + device_t *children; + int nchildren, i; + + /* detach & delete all children */ + if (!device_get_children(dev, &children, &nchildren)) { + for (i = 0; i < nchildren; i++) + if (children[i]) + device_delete_child(dev, children[i]); + free(children, M_TEMP); + } + + return (0); +} + +static int ppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags, void (*ihand)(void *), void *arg, void **cookiep) { @@ -539,6 +556,7 @@ static device_method_t ppbus_methods[] = { /* device interface */ DEVMETHOD(device_probe, ppbus_probe), DEVMETHOD(device_attach, ppbus_attach), + DEVMETHOD(device_detach, ppbus_detach), /* bus interface */ DEVMETHOD(bus_add_child, ppbus_add_child), diff --git a/sys/dev/ppc/ppc.c b/sys/dev/ppc/ppc.c index c6bc9cf..7e1ed40 100644 --- a/sys/dev/ppc/ppc.c +++ b/sys/dev/ppc/ppc.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include <sys/module.h> #include <sys/bus.h> #include <sys/malloc.h> +#include <sys/kdb.h> #include <vm/vm.h> #include <vm/pmap.h> @@ -72,6 +73,7 @@ static device_method_t ppc_methods[] = { /* device interface */ DEVMETHOD(device_probe, ppc_isa_probe), DEVMETHOD(device_attach, ppc_attach), + DEVMETHOD(device_detach, ppc_detach), /* bus interface */ DEVMETHOD(bus_read_ivar, ppc_read_ivar), @@ -2007,6 +2009,46 @@ ppc_attach(device_t dev) return (0); } +int +ppc_detach(device_t dev) +{ + struct ppc_data *ppc = DEVTOSOFTC(dev); + device_t *children; + int nchildren, i; + + if (ppc->res_irq == 0) { + return (ENXIO); + } + + /* detach & delete all children */ + if (!device_get_children(dev, &children, &nchildren)) { + for (i = 0; i < nchildren; i++) + if (children[i]) + device_delete_child(dev, children[i]); + free(children, M_TEMP); + } + + if (ppc->res_irq != 0) { + bus_teardown_intr(dev, ppc->res_irq, ppc->intr_cookie); + bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, + ppc->res_irq); + } + if (ppc->res_ioport != 0) { + bus_deactivate_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, + ppc->res_ioport); + bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, + ppc->res_ioport); + } + if (ppc->res_drq != 0) { + bus_deactivate_resource(dev, SYS_RES_DRQ, ppc->rid_drq, + ppc->res_drq); + bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, + ppc->res_drq); + } + + return (0); +} + u_char ppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) { diff --git a/sys/dev/ppc/ppcvar.h b/sys/dev/ppc/ppcvar.h index 9bef908..98bc022 100644 --- a/sys/dev/ppc/ppcvar.h +++ b/sys/dev/ppc/ppcvar.h @@ -30,6 +30,7 @@ int ppc_probe(device_t dev); int ppc_attach(device_t dev); +int ppc_detach(device_t dev); int ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val); int ppc_read(device_t, char *, int, int); diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 6b1aecf..cceff27 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -461,6 +461,9 @@ device acpi_toshiba # ACPI Video Extensions (LCD backlight/brightness, video output, etc.) device acpi_video +# ACPI Docking Station +device acpi_dock + # The cpufreq(4) driver provides support for non-ACPI CPU frequency control device cpufreq diff --git a/sys/modules/acpi/Makefile b/sys/modules/acpi/Makefile index fbe2bdd..f9b4400 100644 --- a/sys/modules/acpi/Makefile +++ b/sys/modules/acpi/Makefile @@ -9,6 +9,6 @@ .endif SUBDIR= acpi acpi_asus acpi_fujitsu acpi_ibm acpi_panasonic acpi_sony \ - acpi_toshiba acpi_video + acpi_toshiba acpi_video acpi_dock .include <bsd.subdir.mk> diff --git a/sys/modules/acpi/acpi_dock/Makefile b/sys/modules/acpi/acpi_dock/Makefile new file mode 100644 index 0000000..f7287a4 --- /dev/null +++ b/sys/modules/acpi/acpi_dock/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/acpica +KMOD= acpi_dock +CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica +SRCS= acpi_dock.c opt_acpi.h device_if.h bus_if.h acpi_if.h +SRCS+= opt_ddb.h + +.include <bsd.kmod.mk> |