Index: stable/12/sys/dev/acpi_support/acpi_wmi.c =================================================================== --- stable/12/sys/dev/acpi_support/acpi_wmi.c (revision 367676) +++ stable/12/sys/dev/acpi_support/acpi_wmi.c (revision 367677) @@ -1,1020 +1,1021 @@ /*- * Copyright (c) 2009 Michael Gmelin * 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. */ #include __FBSDID("$FreeBSD$"); /* * Driver for acpi-wmi mapping, provides an interface for vendor specific * implementations (e.g. HP and Acer laptops). * Inspired by the ACPI-WMI mapping driver (c) 2008-2008 Carlos Corbacho which * implements this functionality for Linux. * * WMI and ACPI: http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx * acpi-wmi for Linux: http://www.kernel.org */ #include "opt_acpi.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "acpi_wmi_if.h" static MALLOC_DEFINE(M_ACPIWMI, "acpiwmi", "ACPI-WMI mapping"); #define _COMPONENT ACPI_OEM ACPI_MODULE_NAME("ACPI_WMI"); #define ACPI_WMI_REGFLAG_EXPENSIVE 0x1 /* GUID flag: Expensive operation */ #define ACPI_WMI_REGFLAG_METHOD 0x2 /* GUID flag: Method call */ #define ACPI_WMI_REGFLAG_STRING 0x4 /* GUID flag: String */ #define ACPI_WMI_REGFLAG_EVENT 0x8 /* GUID flag: Event */ /* * acpi_wmi driver private structure */ struct acpi_wmi_softc { device_t wmi_dev; /* wmi device id */ ACPI_HANDLE wmi_handle; /* handle of the PNP0C14 node */ device_t ec_dev; /* acpi_ec0 */ struct cdev *wmistat_dev_t; /* wmistat device handle */ struct sbuf wmistat_sbuf; /* sbuf for /dev/wmistat output */ pid_t wmistat_open_pid; /* pid operating on /dev/wmistat */ int wmistat_bufptr; /* /dev/wmistat ptr to buffer position */ TAILQ_HEAD(wmi_info_list_head, wmi_info) wmi_info_list; }; /* * Struct that holds information about * about a single GUID entry in _WDG */ struct guid_info { char guid[16]; /* 16 byte non human readable GUID */ char oid[2]; /* object id or event notify id (first byte) */ UINT8 max_instance; /* highest instance known for this GUID */ UINT8 flags; /* ACPI_WMI_REGFLAG_%s */ }; /* WExx event generation state (on/off) */ enum event_generation_state { EVENT_GENERATION_ON = 1, EVENT_GENERATION_OFF = 0 }; /* * Information about one entry in _WDG. * List of those is used to lookup information by GUID. */ struct wmi_info { TAILQ_ENTRY(wmi_info) wmi_list; struct guid_info ginfo; /* information on guid */ ACPI_NOTIFY_HANDLER event_handler;/* client provided event handler */ void *event_handler_user_data; /* ev handler cookie */ }; ACPI_SERIAL_DECL(acpi_wmi, "ACPI-WMI Mapping"); /* public interface - declaration */ /* standard device interface*/ static int acpi_wmi_probe(device_t dev); static int acpi_wmi_attach(device_t dev); static int acpi_wmi_detach(device_t dev); /* see acpi_wmi_if.m */ static int acpi_wmi_provides_guid_string_method(device_t dev, const char *guid_string); static ACPI_STATUS acpi_wmi_evaluate_call_method(device_t dev, const char *guid_string, UINT8 instance, UINT32 method_id, const ACPI_BUFFER *in, ACPI_BUFFER *out); static ACPI_STATUS acpi_wmi_install_event_handler_method(device_t dev, const char *guid_string, ACPI_NOTIFY_HANDLER handler, void *data); static ACPI_STATUS acpi_wmi_remove_event_handler_method(device_t dev, const char *guid_string); static ACPI_STATUS acpi_wmi_get_event_data_method(device_t dev, UINT32 event_id, ACPI_BUFFER *out); static ACPI_STATUS acpi_wmi_get_block_method(device_t dev, const char *guid_string, UINT8 instance, ACPI_BUFFER *out); static ACPI_STATUS acpi_wmi_set_block_method(device_t dev, const char *guid_string, UINT8 instance, const ACPI_BUFFER *in); /* private interface - declaration */ /* callbacks */ static void acpi_wmi_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context); static ACPI_STATUS acpi_wmi_ec_handler(UINT32 function, ACPI_PHYSICAL_ADDRESS address, UINT32 width, UINT64 *value, void *context, void *region_context); /* helpers */ static ACPI_STATUS acpi_wmi_read_wdg_blocks(struct acpi_wmi_softc *sc, ACPI_HANDLE h); static ACPI_STATUS acpi_wmi_toggle_we_event_generation(device_t dev, struct wmi_info *winfo, enum event_generation_state state); static int acpi_wmi_guid_string_to_guid(const UINT8 *guid_string, UINT8 *guid); static struct wmi_info* acpi_wmi_lookup_wmi_info_by_guid_string(struct acpi_wmi_softc *sc, const char *guid_string); static d_open_t acpi_wmi_wmistat_open; static d_close_t acpi_wmi_wmistat_close; static d_read_t acpi_wmi_wmistat_read; /* handler /dev/wmistat device */ static struct cdevsw wmistat_cdevsw = { .d_version = D_VERSION, .d_open = acpi_wmi_wmistat_open, .d_close = acpi_wmi_wmistat_close, .d_read = acpi_wmi_wmistat_read, .d_name = "wmistat", }; static device_method_t acpi_wmi_methods[] = { /* Device interface */ DEVMETHOD(device_probe, acpi_wmi_probe), DEVMETHOD(device_attach, acpi_wmi_attach), DEVMETHOD(device_detach, acpi_wmi_detach), /* bus interface */ DEVMETHOD(bus_add_child, bus_generic_add_child), /* acpi_wmi interface */ DEVMETHOD(acpi_wmi_provides_guid_string, acpi_wmi_provides_guid_string_method), DEVMETHOD(acpi_wmi_evaluate_call, acpi_wmi_evaluate_call_method), DEVMETHOD(acpi_wmi_install_event_handler, acpi_wmi_install_event_handler_method), DEVMETHOD(acpi_wmi_remove_event_handler, acpi_wmi_remove_event_handler_method), DEVMETHOD(acpi_wmi_get_event_data, acpi_wmi_get_event_data_method), DEVMETHOD(acpi_wmi_get_block, acpi_wmi_get_block_method), DEVMETHOD(acpi_wmi_set_block, acpi_wmi_set_block_method), DEVMETHOD_END }; static driver_t acpi_wmi_driver = { "acpi_wmi", acpi_wmi_methods, sizeof(struct acpi_wmi_softc), }; static devclass_t acpi_wmi_devclass; DRIVER_MODULE(acpi_wmi, acpi, acpi_wmi_driver, acpi_wmi_devclass, 0, 0); MODULE_VERSION(acpi_wmi, 1); MODULE_DEPEND(acpi_wmi, acpi, 1, 1, 1); static char *wmi_ids[] = {"PNP0C14", NULL}; +ACPI_PNP_INFO(wmi_ids); /* * Probe for the PNP0C14 ACPI node */ static int acpi_wmi_probe(device_t dev) { if (acpi_disabled("wmi") || ACPI_ID_PROBE(device_get_parent(dev), dev, wmi_ids) == NULL) return (ENXIO); device_set_desc(dev, "ACPI-WMI mapping"); return (0); } /* * Attach the device by: * - Looking for the first ACPI EC device * - Install the notify handler * - Install the EC address space handler * - Look for the _WDG node and read GUID information blocks */ static int acpi_wmi_attach(device_t dev) { struct acpi_wmi_softc *sc; int ret; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = device_get_softc(dev); ret = ENXIO; ACPI_SERIAL_BEGIN(acpi_wmi); sc->wmi_dev = dev; sc->wmi_handle = acpi_get_handle(dev); TAILQ_INIT(&sc->wmi_info_list); /* XXX Only works with one EC, but nearly all systems only have one. */ if ((sc->ec_dev = devclass_get_device(devclass_find("acpi_ec"), 0)) == NULL) device_printf(dev, "cannot find EC device\n"); else if (ACPI_FAILURE((status = AcpiInstallNotifyHandler(sc->wmi_handle, ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler, sc)))) device_printf(sc->wmi_dev, "couldn't install notify handler - %s\n", AcpiFormatException(status)); else if (ACPI_FAILURE((status = AcpiInstallAddressSpaceHandler( sc->wmi_handle, ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler, NULL, sc)))) { device_printf(sc->wmi_dev, "couldn't install EC handler - %s\n", AcpiFormatException(status)); AcpiRemoveNotifyHandler(sc->wmi_handle, ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler); } else if (ACPI_FAILURE((status = acpi_wmi_read_wdg_blocks(sc, sc->wmi_handle)))) { device_printf(sc->wmi_dev, "couldn't parse _WDG - %s\n", AcpiFormatException(status)); AcpiRemoveNotifyHandler(sc->wmi_handle, ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler); AcpiRemoveAddressSpaceHandler(sc->wmi_handle, ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler); } else { sc->wmistat_dev_t = make_dev(&wmistat_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644, "wmistat%d", device_get_unit(dev)); sc->wmistat_dev_t->si_drv1 = sc; sc->wmistat_open_pid = 0; sc->wmistat_bufptr = -1; ret = 0; } ACPI_SERIAL_END(acpi_wmi); if (ret == 0) { bus_generic_probe(dev); ret = bus_generic_attach(dev); } return (ret); } /* * Detach the driver by: * - Removing notification handler * - Removing address space handler * - Turning off event generation for all WExx event activated by * child drivers */ static int acpi_wmi_detach(device_t dev) { struct wmi_info *winfo, *tmp; struct acpi_wmi_softc *sc; int ret; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = device_get_softc(dev); ACPI_SERIAL_BEGIN(acpi_wmi); if (sc->wmistat_open_pid != 0) { ret = EBUSY; } else { AcpiRemoveNotifyHandler(sc->wmi_handle, ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler); AcpiRemoveAddressSpaceHandler(sc->wmi_handle, ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler); TAILQ_FOREACH_SAFE(winfo, &sc->wmi_info_list, wmi_list, tmp) { if (winfo->event_handler) acpi_wmi_toggle_we_event_generation(dev, winfo, EVENT_GENERATION_OFF); TAILQ_REMOVE(&sc->wmi_info_list, winfo, wmi_list); free(winfo, M_ACPIWMI); } if (sc->wmistat_bufptr != -1) { sbuf_delete(&sc->wmistat_sbuf); sc->wmistat_bufptr = -1; } sc->wmistat_open_pid = 0; destroy_dev(sc->wmistat_dev_t); ret = 0; } ACPI_SERIAL_END(acpi_wmi); return (ret); } /* * Check if the given GUID string (human readable format * AABBCCDD-EEFF-GGHH-IIJJ-KKLLMMNNOOPP) * exists within _WDG */ static int acpi_wmi_provides_guid_string_method(device_t dev, const char *guid_string) { struct acpi_wmi_softc *sc; struct wmi_info *winfo; int ret; sc = device_get_softc(dev); ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_BEGIN(acpi_wmi); winfo = acpi_wmi_lookup_wmi_info_by_guid_string(sc, guid_string); ret = (winfo == NULL)?0:winfo->ginfo.max_instance+1; ACPI_SERIAL_END(acpi_wmi); return (ret); } /* * Call a method "method_id" on the given GUID block * write result into user provided output buffer */ static ACPI_STATUS acpi_wmi_evaluate_call_method(device_t dev, const char *guid_string, UINT8 instance, UINT32 method_id, const ACPI_BUFFER *in, ACPI_BUFFER *out) { ACPI_OBJECT params[3]; ACPI_OBJECT_LIST input; char method[5] = "WMxx"; struct wmi_info *winfo; struct acpi_wmi_softc *sc; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = device_get_softc(dev); ACPI_SERIAL_BEGIN(acpi_wmi); if ((winfo = acpi_wmi_lookup_wmi_info_by_guid_string(sc, guid_string)) == NULL) status = AE_NOT_FOUND; else if (!(winfo->ginfo.flags & ACPI_WMI_REGFLAG_METHOD)) status = AE_BAD_DATA; else if (instance > winfo->ginfo.max_instance) status = AE_BAD_PARAMETER; else { params[0].Type = ACPI_TYPE_INTEGER; params[0].Integer.Value = instance; params[1].Type = ACPI_TYPE_INTEGER; params[1].Integer.Value = method_id; input.Pointer = params; input.Count = 2; if (in) { params[2].Type = (winfo->ginfo.flags & ACPI_WMI_REGFLAG_STRING) ?ACPI_TYPE_STRING:ACPI_TYPE_BUFFER; params[2].Buffer.Length = in->Length; params[2].Buffer.Pointer = in->Pointer; input.Count = 3; } method[2] = winfo->ginfo.oid[0]; method[3] = winfo->ginfo.oid[1]; status = AcpiEvaluateObject(sc->wmi_handle, method, &input, out); } ACPI_SERIAL_END(acpi_wmi); return (status); } /* * Install a user provided event_handler on the given GUID * provided *data will be passed on callback * If there is already an existing event handler registered it will be silently * discarded */ static ACPI_STATUS acpi_wmi_install_event_handler_method(device_t dev, const char *guid_string, ACPI_NOTIFY_HANDLER event_handler, void *data) { struct acpi_wmi_softc *sc = device_get_softc(dev); struct wmi_info *winfo; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); status = AE_OK; ACPI_SERIAL_BEGIN(acpi_wmi); if (guid_string == NULL || event_handler == NULL) status = AE_BAD_PARAMETER; else if ((winfo = acpi_wmi_lookup_wmi_info_by_guid_string(sc, guid_string)) == NULL) status = AE_NOT_EXIST; else if (winfo->event_handler != NULL || (status = acpi_wmi_toggle_we_event_generation(dev, winfo, EVENT_GENERATION_ON)) == AE_OK) { winfo->event_handler = event_handler; winfo->event_handler_user_data = data; } ACPI_SERIAL_END(acpi_wmi); return (status); } /* * Remove a previously installed event handler from the given GUID * If there was none installed, this call is silently discarded and * reported as AE_OK */ static ACPI_STATUS acpi_wmi_remove_event_handler_method(device_t dev, const char *guid_string) { struct acpi_wmi_softc *sc = device_get_softc(dev); struct wmi_info *winfo; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); status = AE_OK; ACPI_SERIAL_BEGIN(acpi_wmi); if (guid_string && (winfo = acpi_wmi_lookup_wmi_info_by_guid_string(sc, guid_string)) != NULL && winfo->event_handler) { status = acpi_wmi_toggle_we_event_generation(dev, winfo, EVENT_GENERATION_OFF); winfo->event_handler = NULL; winfo->event_handler_user_data = NULL; } ACPI_SERIAL_END(acpi_wmi); return (status); } /* * Get details on an event received through a callback registered * through ACPI_WMI_REMOVE_EVENT_HANDLER into a user provided output buffer. * (event_id equals "notify" passed in the callback) */ static ACPI_STATUS acpi_wmi_get_event_data_method(device_t dev, UINT32 event_id, ACPI_BUFFER *out) { ACPI_OBJECT_LIST input; ACPI_OBJECT params[1]; struct acpi_wmi_softc *sc; struct wmi_info *winfo; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = device_get_softc(dev); status = AE_NOT_FOUND; ACPI_SERIAL_BEGIN(acpi_wmi); params[0].Type = ACPI_TYPE_INTEGER; params[0].Integer.Value = event_id; input.Pointer = params; input.Count = 1; TAILQ_FOREACH(winfo, &sc->wmi_info_list, wmi_list) { if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EVENT) && ((UINT8) winfo->ginfo.oid[0] == event_id)) { status = AcpiEvaluateObject(sc->wmi_handle, "_WED", &input, out); break; } } ACPI_SERIAL_END(acpi_wmi); return (status); } /* * Read a block of data from the given GUID (using WQxx (query)) * Will be returned in a user provided buffer (out). * If the method is marked as expensive (ACPI_WMI_REGFLAG_EXPENSIVE) * we will first call the WCxx control method to lock the node to * lock the node for data collection and release it afterwards. * (Failed WCxx calls are ignored to "support" broken implementations) */ static ACPI_STATUS acpi_wmi_get_block_method(device_t dev, const char *guid_string, UINT8 instance, ACPI_BUFFER *out) { char wc_method[5] = "WCxx"; char wq_method[5] = "WQxx"; ACPI_OBJECT_LIST wc_input; ACPI_OBJECT_LIST wq_input; ACPI_OBJECT wc_params[1]; ACPI_OBJECT wq_params[1]; ACPI_HANDLE wc_handle; struct acpi_wmi_softc *sc; struct wmi_info *winfo; ACPI_STATUS status; ACPI_STATUS wc_status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = device_get_softc(dev); wc_status = AE_ERROR; ACPI_SERIAL_BEGIN(acpi_wmi); if (guid_string == NULL || out == NULL) status = AE_BAD_PARAMETER; else if ((winfo = acpi_wmi_lookup_wmi_info_by_guid_string(sc, guid_string)) == NULL) status = AE_ERROR; else if (instance > winfo->ginfo.max_instance) status = AE_BAD_PARAMETER; else if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EVENT) || (winfo->ginfo.flags & ACPI_WMI_REGFLAG_METHOD)) status = AE_ERROR; else { wq_params[0].Type = ACPI_TYPE_INTEGER; wq_params[0].Integer.Value = instance; wq_input.Pointer = wq_params; wq_input.Count = 1; if (winfo->ginfo.flags & ACPI_WMI_REGFLAG_EXPENSIVE) { wc_params[0].Type = ACPI_TYPE_INTEGER; wc_params[0].Integer.Value = 1; wc_input.Pointer = wc_params; wc_input.Count = 1; wc_method[2] = winfo->ginfo.oid[0]; wc_method[3] = winfo->ginfo.oid[1]; wc_status = AcpiGetHandle(sc->wmi_handle, wc_method, &wc_handle); if (ACPI_SUCCESS(wc_status)) wc_status = AcpiEvaluateObject(wc_handle, wc_method, &wc_input, NULL); } wq_method[2] = winfo->ginfo.oid[0]; wq_method[3] = winfo->ginfo.oid[1]; status = AcpiEvaluateObject(sc->wmi_handle, wq_method, &wq_input, out); if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EXPENSIVE) && ACPI_SUCCESS(wc_status)) { wc_params[0].Integer.Value = 0; status = AcpiEvaluateObject(wc_handle, wc_method, &wc_input, NULL); /* XXX this might be the wrong status to return? */ } } ACPI_SERIAL_END(acpi_wmi); return (status); } /* * Write a block of data to the given GUID (using WSxx) */ static ACPI_STATUS acpi_wmi_set_block_method(device_t dev, const char *guid_string, UINT8 instance, const ACPI_BUFFER *in) { char method[5] = "WSxx"; ACPI_OBJECT_LIST input; ACPI_OBJECT params[2]; struct wmi_info *winfo; struct acpi_wmi_softc *sc; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = device_get_softc(dev); ACPI_SERIAL_BEGIN(acpi_wmi); if (guid_string == NULL || in == NULL) status = AE_BAD_DATA; else if ((winfo = acpi_wmi_lookup_wmi_info_by_guid_string(sc, guid_string)) == NULL) status = AE_ERROR; else if (instance > winfo->ginfo.max_instance) status = AE_BAD_PARAMETER; else if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EVENT) || (winfo->ginfo.flags & ACPI_WMI_REGFLAG_METHOD)) status = AE_ERROR; else { params[0].Type = ACPI_TYPE_INTEGER; params[0].Integer.Value = instance; input.Pointer = params; input.Count = 2; params[1].Type = (winfo->ginfo.flags & ACPI_WMI_REGFLAG_STRING) ?ACPI_TYPE_STRING:ACPI_TYPE_BUFFER; params[1].Buffer.Length = in->Length; params[1].Buffer.Pointer = in->Pointer; method[2] = winfo->ginfo.oid[0]; method[3] = winfo->ginfo.oid[1]; status = AcpiEvaluateObject(sc->wmi_handle, method, &input, NULL); } ACPI_SERIAL_END(acpi_wmi); return (status); } /* * Handle events received and dispatch them to * stakeholders that registered through ACPI_WMI_INSTALL_EVENT_HANDLER */ static void acpi_wmi_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) { struct acpi_wmi_softc *sc = context; ACPI_NOTIFY_HANDLER handler; void *handler_data; struct wmi_info *winfo; ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); handler = NULL; handler_data = NULL; ACPI_SERIAL_BEGIN(acpi_wmi); TAILQ_FOREACH(winfo, &sc->wmi_info_list, wmi_list) { if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EVENT) && ((UINT8) winfo->ginfo.oid[0] == notify)) { if (winfo->event_handler) { handler = winfo->event_handler; handler_data = winfo->event_handler_user_data; break; } } } ACPI_SERIAL_END(acpi_wmi); if (handler) { handler(h, notify, handler_data); } } /* * Handle EC address space notifications reveived on the WDG node * (this mimics EcAddressSpaceHandler in acpi_ec.c) */ static ACPI_STATUS acpi_wmi_ec_handler(UINT32 function, ACPI_PHYSICAL_ADDRESS address, UINT32 width, UINT64 *value, void *context, void *region_context) { struct acpi_wmi_softc *sc; int i; UINT64 ec_data; UINT8 ec_addr; ACPI_STATUS status; ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)address); sc = (struct acpi_wmi_softc *)context; if (width % 8 != 0 || value == NULL || context == NULL) return (AE_BAD_PARAMETER); if (address + (width / 8) - 1 > 0xFF) return (AE_BAD_ADDRESS); if (function == ACPI_READ) *value = 0; ec_addr = address; status = AE_ERROR; for (i = 0; i < width; i += 8, ++ec_addr) { switch (function) { case ACPI_READ: status = ACPI_EC_READ(sc->ec_dev, ec_addr, &ec_data, 1); if (ACPI_SUCCESS(status)) *value |= ((UINT64)ec_data) << i; break; case ACPI_WRITE: ec_data = (UINT8)((*value) >> i); status = ACPI_EC_WRITE(sc->ec_dev, ec_addr, ec_data, 1); break; default: device_printf(sc->wmi_dev, "invalid acpi_wmi_ec_handler function %d\n", function); status = AE_BAD_PARAMETER; break; } if (ACPI_FAILURE(status)) break; } return (status); } /* * Read GUID blocks from the _WDG node * into wmi_info_list. */ static ACPI_STATUS acpi_wmi_read_wdg_blocks(struct acpi_wmi_softc *sc, ACPI_HANDLE h) { ACPI_BUFFER out = {ACPI_ALLOCATE_BUFFER, NULL}; struct guid_info *ginfo; ACPI_OBJECT *obj; struct wmi_info *winfo; UINT32 i; UINT32 wdg_block_count; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(acpi_wmi); if (ACPI_FAILURE(status = AcpiEvaluateObject(h, "_WDG", NULL, &out))) return (status); obj = (ACPI_OBJECT*) out.Pointer; wdg_block_count = obj->Buffer.Length / sizeof(struct guid_info); if ((ginfo = malloc(obj->Buffer.Length, M_ACPIWMI, M_NOWAIT)) == NULL) { AcpiOsFree(out.Pointer); return (AE_NO_MEMORY); } memcpy(ginfo, obj->Buffer.Pointer, obj->Buffer.Length); for (i = 0; i < wdg_block_count; ++i) { if ((winfo = malloc(sizeof(struct wmi_info), M_ACPIWMI, M_NOWAIT | M_ZERO)) == NULL) { AcpiOsFree(out.Pointer); free(ginfo, M_ACPIWMI); return (AE_NO_MEMORY); } winfo->ginfo = ginfo[i]; TAILQ_INSERT_TAIL(&sc->wmi_info_list, winfo, wmi_list); } AcpiOsFree(out.Pointer); free(ginfo, M_ACPIWMI); return (status); } /* * Toggle event generation in for the given GUID (passed by winfo) * Turn on to get notified (through acpi_wmi_notify_handler) if events happen * on the given GUID. */ static ACPI_STATUS acpi_wmi_toggle_we_event_generation(device_t dev, struct wmi_info *winfo, enum event_generation_state state) { char method[5] = "WExx"; ACPI_OBJECT_LIST input; ACPI_OBJECT params[1]; struct acpi_wmi_softc *sc; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = device_get_softc(dev); ACPI_SERIAL_ASSERT(acpi_wmi); params[0].Type = ACPI_TYPE_INTEGER; params[0].Integer.Value = state==EVENT_GENERATION_ON?1:0; input.Pointer = params; input.Count = 1; UINT8 hi = ((UINT8) winfo->ginfo.oid[0]) >> 4; UINT8 lo = ((UINT8) winfo->ginfo.oid[0]) & 0xf; method[2] = (hi > 9 ? hi + 55: hi + 48); method[3] = (lo > 9 ? lo + 55: lo + 48); status = AcpiEvaluateObject(sc->wmi_handle, method, &input, NULL); if (status == AE_NOT_FOUND) status = AE_OK; return (status); } /* * Convert given two digit hex string (hexin) to an UINT8 referenced * by byteout. * Return != 0 if the was a problem (invalid input) */ static __inline int acpi_wmi_hex_to_int(const UINT8 *hexin, UINT8 *byteout) { unsigned int hi; unsigned int lo; hi = hexin[0]; lo = hexin[1]; if ('0' <= hi && hi <= '9') hi -= '0'; else if ('A' <= hi && hi <= 'F') hi -= ('A' - 10); else if ('a' <= hi && hi <= 'f') hi -= ('a' - 10); else return (1); if ('0' <= lo && lo <= '9') lo -= '0'; else if ('A' <= lo && lo <= 'F') lo -= ('A' - 10); else if ('a' <= lo && lo <= 'f') lo -= ('a' - 10); else return (1); *byteout = (hi << 4) + lo; return (0); } /* * Convert a human readable 36 character GUID into a 16byte * machine readable one. * The basic algorithm looks as follows: * Input: AABBCCDD-EEFF-GGHH-IIJJ-KKLLMMNNOOPP * Output: DCBAFEHGIJKLMNOP * (AA BB CC etc. represent two digit hex numbers == bytes) * Return != 0 if passed guid string is invalid */ static int acpi_wmi_guid_string_to_guid(const UINT8 *guid_string, UINT8 *guid) { static const int mapping[20] = {3, 2, 1, 0, -1, 5, 4, -1, 7, 6, -1, 8, 9, -1, 10, 11, 12, 13, 14, 15}; int i; for (i = 0; i < 20; ++i, ++guid_string) { if (mapping[i] >= 0) { if (acpi_wmi_hex_to_int(guid_string, &guid[mapping[i]])) return (-1); ++guid_string; } else if (*guid_string != '-') return (-1); } return (0); } /* * Lookup a wmi_info structure in wmi_list based on a * human readable GUID * Return NULL if the GUID is unknown in the _WDG */ static struct wmi_info* acpi_wmi_lookup_wmi_info_by_guid_string(struct acpi_wmi_softc *sc, const char *guid_string) { char guid[16]; struct wmi_info *winfo; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(acpi_wmi); if (!acpi_wmi_guid_string_to_guid(guid_string, guid)) { TAILQ_FOREACH(winfo, &sc->wmi_info_list, wmi_list) { if (!memcmp(winfo->ginfo.guid, guid, 16)) { return (winfo); } } } return (NULL); } /* * open wmistat device */ static int acpi_wmi_wmistat_open(struct cdev* dev, int flags, int mode, struct thread *td) { struct acpi_wmi_softc *sc; int ret; if (dev == NULL || dev->si_drv1 == NULL) return (EBADF); sc = dev->si_drv1; ACPI_SERIAL_BEGIN(acpi_wmi); if (sc->wmistat_open_pid != 0) { ret = EBUSY; } else { if (sbuf_new(&sc->wmistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) { ret = ENXIO; } else { sc->wmistat_open_pid = td->td_proc->p_pid; sc->wmistat_bufptr = 0; ret = 0; } } ACPI_SERIAL_END(acpi_wmi); return (ret); } /* * close wmistat device */ static int acpi_wmi_wmistat_close(struct cdev* dev, int flags, int mode, struct thread *td) { struct acpi_wmi_softc *sc; int ret; if (dev == NULL || dev->si_drv1 == NULL) return (EBADF); sc = dev->si_drv1; ACPI_SERIAL_BEGIN(acpi_wmi); if (sc->wmistat_open_pid == 0) { ret = EBADF; } else { if (sc->wmistat_bufptr != -1) { sbuf_delete(&sc->wmistat_sbuf); sc->wmistat_bufptr = -1; } sc->wmistat_open_pid = 0; ret = 0; } ACPI_SERIAL_END(acpi_wmi); return (ret); } /* * Read from wmistat guid information */ static int acpi_wmi_wmistat_read(struct cdev *dev, struct uio *buf, int flag) { struct acpi_wmi_softc *sc; struct wmi_info *winfo; int l; int ret; UINT8* guid; if (dev == NULL || dev->si_drv1 == NULL) return (EBADF); sc = dev->si_drv1; ACPI_SERIAL_BEGIN(acpi_wmi); if (sc->wmistat_open_pid != buf->uio_td->td_proc->p_pid || sc->wmistat_bufptr == -1) { ret = EBADF; } else { if (!sbuf_done(&sc->wmistat_sbuf)) { sbuf_printf(&sc->wmistat_sbuf, "GUID " " INST EXPE METH STR " "EVENT OID\n"); TAILQ_FOREACH(winfo, &sc->wmi_info_list, wmi_list) { guid = (UINT8*)winfo->ginfo.guid; sbuf_printf(&sc->wmistat_sbuf, "{%02X%02X%02X%02X-%02X%02X-" "%02X%02X-%02X%02X-%02X%02X" "%02X%02X%02X%02X} %3d %-5s", guid[3], guid[2], guid[1], guid[0], guid[5], guid[4], guid[7], guid[6], guid[8], guid[9], guid[10], guid[11], guid[12], guid[13], guid[14], guid[15], winfo->ginfo.max_instance, (winfo->ginfo.flags& ACPI_WMI_REGFLAG_EXPENSIVE)? "YES":"NO" ); if (winfo->ginfo.flags&ACPI_WMI_REGFLAG_METHOD) sbuf_printf(&sc->wmistat_sbuf, "WM%c%c ", winfo->ginfo.oid[0], winfo->ginfo.oid[1]); else sbuf_printf(&sc->wmistat_sbuf, "NO "); sbuf_printf(&sc->wmistat_sbuf, "%-4s", (winfo->ginfo.flags& ACPI_WMI_REGFLAG_STRING)?"YES":"NO" ); if (winfo->ginfo.flags&ACPI_WMI_REGFLAG_EVENT) sbuf_printf(&sc->wmistat_sbuf, "0x%02X%s -\n", (UINT8)winfo->ginfo.oid[0], winfo->event_handler==NULL? " ":"+"); else sbuf_printf(&sc->wmistat_sbuf, "NO %c%c\n", winfo->ginfo.oid[0], winfo->ginfo.oid[1]); } sbuf_finish(&sc->wmistat_sbuf); } if (sbuf_len(&sc->wmistat_sbuf) <= 0) { sbuf_delete(&sc->wmistat_sbuf); sc->wmistat_bufptr = -1; sc->wmistat_open_pid = 0; ret = ENOMEM; } else { l = min(buf->uio_resid, sbuf_len(&sc->wmistat_sbuf) - sc->wmistat_bufptr); ret = (l > 0)?uiomove(sbuf_data(&sc->wmistat_sbuf) + sc->wmistat_bufptr, l, buf) : 0; sc->wmistat_bufptr += l; } } ACPI_SERIAL_END(acpi_wmi); return (ret); } Index: stable/12/sys/dev/acpica/acpi_dock.c =================================================================== --- stable/12/sys/dev/acpica/acpi_dock.c (revision 367676) +++ stable/12/sys/dev/acpica/acpi_dock.c (revision 367677) @@ -1,547 +1,550 @@ /*- * Copyright (c) 2005-2006 Mitsuru IWASAKI * 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 #include #include #include #include #include #include #include /* Hooks for the ACPI CA debugging infrastructure */ #define _COMPONENT ACPI_DOCK ACPI_MODULE_NAME("DOCK") /* For Docking status */ #define ACPI_DOCK_STATUS_UNKNOWN -1 #define ACPI_DOCK_STATUS_UNDOCKED 0 #define ACPI_DOCK_STATUS_DOCKED 1 #define ACPI_DOCK_UNLOCK 0 /* Allow device to be ejected */ #define ACPI_DOCK_LOCK 1 /* Prevent dev from being removed */ #define ACPI_DOCK_ISOLATE 0 /* Isolate from dock connector */ #define ACPI_DOCK_CONNECT 1 /* Connect to dock */ struct acpi_dock_softc { int _sta; int _bdn; int _uid; int status; struct sysctl_ctx_list *sysctl_ctx; struct sysctl_oid *sysctl_tree; }; ACPI_SERIAL_DECL(dock, "ACPI Docking Station"); +static char *acpi_dock_pnp_ids[] = {"PNP0C15", NULL}; + /* * Utility functions */ 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; if (ACPI_FAILURE(acpi_GetInteger(h, "_BDN", &sc->_bdn))) sc->_bdn = ACPI_DOCK_STATUS_UNKNOWN; if (ACPI_FAILURE(acpi_GetInteger(h, "_UID", &sc->_uid))) sc->_uid = ACPI_DOCK_STATUS_UNKNOWN; ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), "_STA: %04x, _BDN: %04x, _UID: %04x\n", sc->_sta, sc->_bdn, 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); /* * When _DCK is called with 0, OSPM will ignore the return value. */ if (dock == ACPI_DOCK_ISOLATE) return (0); /* If _DCK returned 1, the request succeeded. */ if (ACPI_SUCCESS(status) && retobj.Type == ACPI_TYPE_INTEGER && retobj.Integer.Value == 1) return (0); return (-1); } /* Lock devices while docked to prevent surprise removal. */ static void acpi_dock_execute_lck(device_t dev, int lock) { ACPI_HANDLE h; h = acpi_get_handle(dev); acpi_SetInteger(h, "_LCK", lock); } /* Eject a device (i.e., motorized). */ 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); } /* Find dependent devices. When their parent is removed, so are they. */ 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)) ret = 1; out: if (ejd_buffer.Pointer != NULL) AcpiOsFree(ejd_buffer.Pointer); return (ret); } /* * Docking functions */ 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, NULL, &Info, NULL); #endif dev = acpi_get_device(handle); if (dev == NULL) { device_printf(dock_dev, "error: %s has no associated device\n", acpi_name(handle)); goto out; } AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_dock_attach_later, dev); out: return (AE_OK); } static void acpi_dock_insert_children(device_t dev) { ACPI_STATUS status; ACPI_HANDLE sb_handle; status = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle); if (ACPI_SUCCESS(status)) { AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle, 100, acpi_dock_insert_child, NULL, 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 (sc->status == ACPI_DOCK_STATUS_UNDOCKED || sc->status == ACPI_DOCK_STATUS_UNKNOWN) { acpi_dock_execute_lck(dev, ACPI_DOCK_LOCK); if (acpi_dock_execute_dck(dev, ACPI_DOCK_CONNECT) != 0) { device_printf(dev, "_DCK failed\n"); return; } if (!cold) { acpi_dock_insert_children(dev); acpi_UserNotify("Dock", h, 1); } sc->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; ACPI_STATUS status; status = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle); if (ACPI_SUCCESS(status)) { AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle, 100, acpi_dock_eject_child, NULL, &dev, NULL); } } static void acpi_dock_removal(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 (sc->status == ACPI_DOCK_STATUS_DOCKED || sc->status == ACPI_DOCK_STATUS_UNKNOWN) { acpi_dock_eject_children(dev); if (acpi_dock_execute_dck(dev, ACPI_DOCK_ISOLATE) != 0) return; acpi_dock_execute_lck(dev, ACPI_DOCK_UNLOCK); if (acpi_dock_execute_ejx(dev, 1, 0) != 0) { device_printf(dev, "_EJ0 failed\n"); return; } acpi_UserNotify("Dock", h, 0); sc->status = ACPI_DOCK_STATUS_UNDOCKED; } acpi_dock_get_info(dev); if (sc->_sta != 0) device_printf(dev, "mechanical failure (%#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 method indicates 'present' and 'functioning', the * system is docked. If _STA does not exist for this device, it * is always present. */ if (sc->_sta == ACPI_DOCK_STATUS_UNKNOWN || ACPI_DEVICE_PRESENT(sc->_sta)) acpi_dock_insert(dev); else if (sc->_sta == 0) 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_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: acpi_dock_device_check(dev); break; case ACPI_NOTIFY_EJECT_REQUEST: acpi_dock_removal(dev); break; default: device_printf(dev, "unknown notify %#x\n", notify); break; } ACPI_SERIAL_END(dock); } static int acpi_dock_status_sysctl(SYSCTL_HANDLER_ARGS) { struct acpi_dock_softc *sc; device_t dev; int status, err; 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); } 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); device_set_desc(dev, "ACPI Docking Station"); /* * XXX Somewhere else in the kernel panics on "sysctl kern" if we * return a negative value here (reprobe ok). */ return (0); } static int acpi_dock_attach(device_t dev) { struct acpi_dock_softc *sc; ACPI_HANDLE h; sc = device_get_softc(dev); h = acpi_get_handle(dev); if (sc == NULL || h == NULL) 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), DEVMETHOD_END }; 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); +ACPI_PNP_INFO(acpi_dock_pnp_ids); Index: stable/12/sys/dev/acpica/acpivar.h =================================================================== --- stable/12/sys/dev/acpica/acpivar.h (revision 367676) +++ stable/12/sys/dev/acpica/acpivar.h (revision 367677) @@ -1,558 +1,572 @@ /*- * Copyright (c) 2000 Mitsuru IWASAKI * Copyright (c) 2000 Michael Smith * Copyright (c) 2000 BSDi * 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$ */ #ifndef _ACPIVAR_H_ #define _ACPIVAR_H_ #ifdef _KERNEL #include "acpi_if.h" #include "bus_if.h" #include #ifdef INTRNG #include #endif #include #include #include #include #include #include #include #include struct apm_clone_data; struct acpi_softc { device_t acpi_dev; struct cdev *acpi_dev_t; int acpi_enabled; int acpi_sstate; int acpi_sleep_disabled; int acpi_resources_reserved; struct sysctl_ctx_list acpi_sysctl_ctx; struct sysctl_oid *acpi_sysctl_tree; int acpi_power_button_sx; int acpi_sleep_button_sx; int acpi_lid_switch_sx; int acpi_standby_sx; int acpi_suspend_sx; int acpi_sleep_delay; int acpi_s4bios; int acpi_do_disable; int acpi_verbose; int acpi_handle_reboot; vm_offset_t acpi_wakeaddr; vm_paddr_t acpi_wakephys; int acpi_next_sstate; /* Next suspend Sx state. */ struct apm_clone_data *acpi_clone; /* Pseudo-dev for devd(8). */ STAILQ_HEAD(,apm_clone_data) apm_cdevs; /* All apm/apmctl/acpi cdevs. */ struct callout susp_force_to; /* Force suspend if no acks. */ }; struct acpi_device { /* ACPI ivars */ ACPI_HANDLE ad_handle; void *ad_private; int ad_flags; int ad_cls_class; /* Resources */ struct resource_list ad_rl; }; #ifdef INTRNG struct intr_map_data_acpi { struct intr_map_data hdr; u_int irq; u_int pol; u_int trig; }; #endif /* Track device (/dev/{apm,apmctl} and /dev/acpi) notification status. */ struct apm_clone_data { STAILQ_ENTRY(apm_clone_data) entries; struct cdev *cdev; int flags; #define ACPI_EVF_NONE 0 /* /dev/apm semantics */ #define ACPI_EVF_DEVD 1 /* /dev/acpi is handled via devd(8) */ #define ACPI_EVF_WRITE 2 /* Device instance is opened writable. */ int notify_status; #define APM_EV_NONE 0 /* Device not yet aware of pending sleep. */ #define APM_EV_NOTIFIED 1 /* Device saw next sleep state. */ #define APM_EV_ACKED 2 /* Device agreed sleep can occur. */ struct acpi_softc *acpi_sc; struct selinfo sel_read; }; #define ACPI_PRW_MAX_POWERRES 8 struct acpi_prw_data { ACPI_HANDLE gpe_handle; int gpe_bit; int lowest_wake; ACPI_OBJECT power_res[ACPI_PRW_MAX_POWERRES]; int power_res_count; }; /* Flags for each device defined in the AML namespace. */ #define ACPI_FLAG_WAKE_ENABLED 0x1 /* Macros for extracting parts of a PCI address from an _ADR value. */ #define ACPI_ADR_PCI_SLOT(adr) (((adr) & 0xffff0000) >> 16) #define ACPI_ADR_PCI_FUNC(adr) ((adr) & 0xffff) /* * Entry points to ACPI from above are global functions defined in this * file, sysctls, and I/O on the control device. Entry points from below * are interrupts (the SCI), notifies, task queue threads, and the thermal * zone polling thread. * * ACPI tables and global shared data are protected by a global lock * (acpi_mutex). * * Each ACPI device can have its own driver-specific mutex for protecting * shared access to local data. The ACPI_LOCK macros handle mutexes. * * Drivers that need to serialize access to functions (e.g., to route * interrupts, get/set control paths, etc.) should use the sx lock macros * (ACPI_SERIAL). * * ACPI-CA handles its own locking and should not be called with locks held. * * The most complicated path is: * GPE -> EC runs _Qxx -> _Qxx reads EC space -> GPE */ extern struct mtx acpi_mutex; #define ACPI_LOCK(sys) mtx_lock(&sys##_mutex) #define ACPI_UNLOCK(sys) mtx_unlock(&sys##_mutex) #define ACPI_LOCK_ASSERT(sys) mtx_assert(&sys##_mutex, MA_OWNED); #define ACPI_LOCK_DECL(sys, name) \ static struct mtx sys##_mutex; \ MTX_SYSINIT(sys##_mutex, &sys##_mutex, name, MTX_DEF) #define ACPI_SERIAL_BEGIN(sys) sx_xlock(&sys##_sxlock) #define ACPI_SERIAL_END(sys) sx_xunlock(&sys##_sxlock) #define ACPI_SERIAL_ASSERT(sys) sx_assert(&sys##_sxlock, SX_XLOCKED); #define ACPI_SERIAL_DECL(sys, name) \ static struct sx sys##_sxlock; \ SX_SYSINIT(sys##_sxlock, &sys##_sxlock, name) /* * ACPI CA does not define layers for non-ACPI CA drivers. * We define some here within the range provided. */ #define ACPI_AC_ADAPTER 0x00010000 #define ACPI_BATTERY 0x00020000 #define ACPI_BUS 0x00040000 #define ACPI_BUTTON 0x00080000 #define ACPI_EC 0x00100000 #define ACPI_FAN 0x00200000 #define ACPI_POWERRES 0x00400000 #define ACPI_PROCESSOR 0x00800000 #define ACPI_THERMAL 0x01000000 #define ACPI_TIMER 0x02000000 #define ACPI_OEM 0x04000000 /* * Constants for different interrupt models used with acpi_SetIntrModel(). */ #define ACPI_INTR_PIC 0 #define ACPI_INTR_APIC 1 #define ACPI_INTR_SAPIC 2 /* * Various features and capabilities for the acpi_get_features() method. * In particular, these are used for the ACPI 3.0 _PDC and _OSC methods. * See the Intel document titled "Intel Processor Vendor-Specific ACPI", * number 302223-007. */ #define ACPI_CAP_PERF_MSRS (1 << 0) /* Intel SpeedStep PERF_CTL MSRs */ #define ACPI_CAP_C1_IO_HALT (1 << 1) /* Intel C1 "IO then halt" sequence */ #define ACPI_CAP_THR_MSRS (1 << 2) /* Intel OnDemand throttling MSRs */ #define ACPI_CAP_SMP_SAME (1 << 3) /* MP C1, Px, and Tx (all the same) */ #define ACPI_CAP_SMP_SAME_C3 (1 << 4) /* MP C2 and C3 (all the same) */ #define ACPI_CAP_SMP_DIFF_PX (1 << 5) /* MP Px (different, using _PSD) */ #define ACPI_CAP_SMP_DIFF_CX (1 << 6) /* MP Cx (different, using _CSD) */ #define ACPI_CAP_SMP_DIFF_TX (1 << 7) /* MP Tx (different, using _TSD) */ #define ACPI_CAP_SMP_C1_NATIVE (1 << 8) /* MP C1 support other than halt */ #define ACPI_CAP_SMP_C3_NATIVE (1 << 9) /* MP C2 and C3 support */ #define ACPI_CAP_PX_HW_COORD (1 << 11) /* Intel P-state HW coordination */ #define ACPI_CAP_INTR_CPPC (1 << 12) /* Native Interrupt Handling for Collaborative Processor Performance Control notifications */ #define ACPI_CAP_HW_DUTY_C (1 << 13) /* Hardware Duty Cycling */ /* * Quirk flags. * * ACPI_Q_BROKEN: Disables all ACPI support. * ACPI_Q_TIMER: Disables support for the ACPI timer. * ACPI_Q_MADT_IRQ0: Specifies that ISA IRQ 0 is wired up to pin 0 of the * first APIC and that the MADT should force that by ignoring the PC-AT * compatible flag and ignoring overrides that redirect IRQ 0 to pin 2. */ extern int acpi_quirks; #define ACPI_Q_OK 0 #define ACPI_Q_BROKEN (1 << 0) #define ACPI_Q_TIMER (1 << 1) #define ACPI_Q_MADT_IRQ0 (1 << 2) /* + * Plug and play information for device matching. Matching table format + * is compatible with ids parameter of ACPI_ID_PROBE bus method. + * + * XXX: While ACPI_ID_PROBE matches against _HID and all _CIDs, current + * acpi_pnpinfo_str() exports only _HID and first _CID. That means second + * and further _CIDs should be added to both acpi_pnpinfo_str() and + * ACPICOMPAT_PNP_INFO if device matching against them is required. + */ +#define ACPICOMPAT_PNP_INFO(t, busname) \ + MODULE_PNP_INFO("Z:_HID", busname, t##hid, t, nitems(t)-1); \ + MODULE_PNP_INFO("Z:_CID", busname, t##cid, t, nitems(t)-1); +#define ACPI_PNP_INFO(t) ACPICOMPAT_PNP_INFO(t, acpi) + +/* * Note that the low ivar values are reserved to provide * interface compatibility with ISA drivers which can also * attach to ACPI. */ #define ACPI_IVAR_HANDLE 0x100 #define ACPI_IVAR_UNUSED 0x101 /* Unused/reserved. */ #define ACPI_IVAR_PRIVATE 0x102 #define ACPI_IVAR_FLAGS 0x103 /* * Accessor functions for our ivars. Default value for BUS_READ_IVAR is * (type) 0. The accessor functions don't check return values. */ #define __ACPI_BUS_ACCESSOR(varp, var, ivarp, ivar, type) \ \ static __inline type varp ## _get_ ## var(device_t dev) \ { \ uintptr_t v = 0; \ BUS_READ_IVAR(device_get_parent(dev), dev, \ ivarp ## _IVAR_ ## ivar, &v); \ return ((type) v); \ } \ \ static __inline void varp ## _set_ ## var(device_t dev, type t) \ { \ uintptr_t v = (uintptr_t) t; \ BUS_WRITE_IVAR(device_get_parent(dev), dev, \ ivarp ## _IVAR_ ## ivar, v); \ } __ACPI_BUS_ACCESSOR(acpi, handle, ACPI, HANDLE, ACPI_HANDLE) __ACPI_BUS_ACCESSOR(acpi, private, ACPI, PRIVATE, void *) __ACPI_BUS_ACCESSOR(acpi, flags, ACPI, FLAGS, int) void acpi_fake_objhandler(ACPI_HANDLE h, void *data); static __inline device_t acpi_get_device(ACPI_HANDLE handle) { void *dev = NULL; AcpiGetData(handle, acpi_fake_objhandler, &dev); return ((device_t)dev); } static __inline ACPI_OBJECT_TYPE acpi_get_type(device_t dev) { ACPI_HANDLE h; ACPI_OBJECT_TYPE t; if ((h = acpi_get_handle(dev)) == NULL) return (ACPI_TYPE_NOT_FOUND); if (ACPI_FAILURE(AcpiGetType(h, &t))) return (ACPI_TYPE_NOT_FOUND); return (t); } /* Find the difference between two PM tick counts. */ static __inline uint32_t acpi_TimerDelta(uint32_t end, uint32_t start) { if (end < start && (AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0) end |= 0x01000000; return (end - start); } #ifdef ACPI_DEBUGGER void acpi_EnterDebugger(void); #endif #ifdef ACPI_DEBUG #include #define STEP(x) do {printf x, printf("\n"); cngetc();} while (0) #else #define STEP(x) #endif #define ACPI_VPRINT(dev, acpi_sc, x...) do { \ if (acpi_get_verbose(acpi_sc)) \ device_printf(dev, x); \ } while (0) /* Values for the first status word returned by _OSC. */ #define ACPI_OSC_FAILURE (1 << 1) #define ACPI_OSC_BAD_UUID (1 << 2) #define ACPI_OSC_BAD_REVISION (1 << 3) #define ACPI_OSC_CAPS_MASKED (1 << 4) #define ACPI_DEVINFO_PRESENT(x, flags) \ (((x) & (flags)) == (flags)) #define ACPI_DEVICE_PRESENT(x) \ ACPI_DEVINFO_PRESENT(x, ACPI_STA_DEVICE_PRESENT | \ ACPI_STA_DEVICE_FUNCTIONING) #define ACPI_BATTERY_PRESENT(x) \ ACPI_DEVINFO_PRESENT(x, ACPI_STA_DEVICE_PRESENT | \ ACPI_STA_DEVICE_FUNCTIONING | ACPI_STA_BATTERY_PRESENT) /* Callback function type for walking subtables within a table. */ typedef void acpi_subtable_handler(ACPI_SUBTABLE_HEADER *, void *); BOOLEAN acpi_DeviceIsPresent(device_t dev); BOOLEAN acpi_BatteryIsPresent(device_t dev); ACPI_STATUS acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result); ACPI_BUFFER *acpi_AllocBuffer(int size); ACPI_STATUS acpi_ConvertBufferToInteger(ACPI_BUFFER *bufp, UINT32 *number); ACPI_STATUS acpi_GetInteger(ACPI_HANDLE handle, char *path, UINT32 *number); ACPI_STATUS acpi_SetInteger(ACPI_HANDLE handle, char *path, UINT32 number); ACPI_STATUS acpi_ForeachPackageObject(ACPI_OBJECT *obj, void (*func)(ACPI_OBJECT *comp, void *arg), void *arg); ACPI_STATUS acpi_FindIndexedResource(ACPI_BUFFER *buf, int index, ACPI_RESOURCE **resp); ACPI_STATUS acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res); UINT8 acpi_DSMQuery(ACPI_HANDLE h, uint8_t *uuid, int revision); ACPI_STATUS acpi_EvaluateDSM(ACPI_HANDLE handle, uint8_t *uuid, int revision, uint64_t function, union acpi_object *package, ACPI_BUFFER *out_buf); ACPI_STATUS acpi_EvaluateOSC(ACPI_HANDLE handle, uint8_t *uuid, int revision, int count, uint32_t *caps_in, uint32_t *caps_out, bool query); ACPI_STATUS acpi_OverrideInterruptLevel(UINT32 InterruptNumber); ACPI_STATUS acpi_SetIntrModel(int model); int acpi_ReqSleepState(struct acpi_softc *sc, int state); int acpi_AckSleepState(struct apm_clone_data *clone, int error); ACPI_STATUS acpi_SetSleepState(struct acpi_softc *sc, int state); int acpi_wake_set_enable(device_t dev, int enable); int acpi_parse_prw(ACPI_HANDLE h, struct acpi_prw_data *prw); ACPI_STATUS acpi_Startup(void); void acpi_UserNotify(const char *subsystem, ACPI_HANDLE h, uint8_t notify); int acpi_bus_alloc_gas(device_t dev, int *type, int *rid, ACPI_GENERIC_ADDRESS *gas, struct resource **res, u_int flags); void acpi_walk_subtables(void *first, void *end, acpi_subtable_handler *handler, void *arg); BOOLEAN acpi_has_hid(ACPI_HANDLE handle); BOOLEAN acpi_MatchHid(ACPI_HANDLE h, const char *hid); struct acpi_parse_resource_set { void (*set_init)(device_t dev, void *arg, void **context); void (*set_done)(device_t dev, void *context); void (*set_ioport)(device_t dev, void *context, uint64_t base, uint64_t length); void (*set_iorange)(device_t dev, void *context, uint64_t low, uint64_t high, uint64_t length, uint64_t align); void (*set_memory)(device_t dev, void *context, uint64_t base, uint64_t length); void (*set_memoryrange)(device_t dev, void *context, uint64_t low, uint64_t high, uint64_t length, uint64_t align); void (*set_irq)(device_t dev, void *context, uint8_t *irq, int count, int trig, int pol); void (*set_ext_irq)(device_t dev, void *context, uint32_t *irq, int count, int trig, int pol); void (*set_drq)(device_t dev, void *context, uint8_t *drq, int count); void (*set_start_dependent)(device_t dev, void *context, int preference); void (*set_end_dependent)(device_t dev, void *context); }; extern struct acpi_parse_resource_set acpi_res_parse_set; int acpi_identify(void); void acpi_config_intr(device_t dev, ACPI_RESOURCE *res); #ifdef INTRNG int acpi_map_intr(device_t dev, u_int irq, ACPI_HANDLE handle); #endif ACPI_STATUS acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res, ACPI_RESOURCE *acpi_res); ACPI_STATUS acpi_parse_resources(device_t dev, ACPI_HANDLE handle, struct acpi_parse_resource_set *set, void *arg); struct resource *acpi_alloc_sysres(device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags); /* ACPI event handling */ UINT32 acpi_event_power_button_sleep(void *context); UINT32 acpi_event_power_button_wake(void *context); UINT32 acpi_event_sleep_button_sleep(void *context); UINT32 acpi_event_sleep_button_wake(void *context); #define ACPI_EVENT_PRI_FIRST 0 #define ACPI_EVENT_PRI_DEFAULT 10000 #define ACPI_EVENT_PRI_LAST 20000 typedef void (*acpi_event_handler_t)(void *, int); EVENTHANDLER_DECLARE(acpi_sleep_event, acpi_event_handler_t); EVENTHANDLER_DECLARE(acpi_wakeup_event, acpi_event_handler_t); /* Device power control. */ ACPI_STATUS acpi_pwr_wake_enable(ACPI_HANDLE consumer, int enable); ACPI_STATUS acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state); int acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate); int acpi_set_powerstate(device_t child, int state); /* APM emulation */ void acpi_apm_init(struct acpi_softc *); /* Misc. */ static __inline struct acpi_softc * acpi_device_get_parent_softc(device_t child) { device_t parent; parent = device_get_parent(child); if (parent == NULL) return (NULL); return (device_get_softc(parent)); } static __inline int acpi_get_verbose(struct acpi_softc *sc) { if (sc) return (sc->acpi_verbose); return (0); } char *acpi_name(ACPI_HANDLE handle); int acpi_avoid(ACPI_HANDLE handle); int acpi_disabled(char *subsys); int acpi_machdep_init(device_t dev); void acpi_install_wakeup_handler(struct acpi_softc *sc); int acpi_sleep_machdep(struct acpi_softc *sc, int state); int acpi_wakeup_machdep(struct acpi_softc *sc, int state, int sleep_result, int intr_enabled); int acpi_table_quirks(int *quirks); int acpi_machdep_quirks(int *quirks); int acpi_pnpinfo_str(ACPI_HANDLE handle, char *buf, size_t buflen); uint32_t hpet_get_uid(device_t dev); /* Battery Abstraction. */ struct acpi_battinfo; int acpi_battery_register(device_t dev); int acpi_battery_remove(device_t dev); int acpi_battery_get_units(void); int acpi_battery_get_info_expire(void); int acpi_battery_bst_valid(struct acpi_bst *bst); int acpi_battery_bix_valid(struct acpi_bix *bix); int acpi_battery_get_battinfo(device_t dev, struct acpi_battinfo *info); /* Embedded controller. */ void acpi_ec_ecdt_probe(device_t); /* AC adapter interface. */ int acpi_acad_get_acline(int *); /* Package manipulation convenience functions. */ #define ACPI_PKG_VALID(pkg, size) \ ((pkg) != NULL && (pkg)->Type == ACPI_TYPE_PACKAGE && \ (pkg)->Package.Count >= (size)) #define ACPI_PKG_VALID_EQ(pkg, size) \ ((pkg) != NULL && (pkg)->Type == ACPI_TYPE_PACKAGE && \ (pkg)->Package.Count == (size)) int acpi_PkgInt(ACPI_OBJECT *res, int idx, UINT64 *dst); int acpi_PkgInt32(ACPI_OBJECT *res, int idx, uint32_t *dst); int acpi_PkgInt16(ACPI_OBJECT *res, int idx, uint16_t *dst); int acpi_PkgStr(ACPI_OBJECT *res, int idx, void *dst, size_t size); int acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *type, int *rid, struct resource **dst, u_int flags); int acpi_PkgFFH_IntelCpu(ACPI_OBJECT *res, int idx, int *vendor, int *class, uint64_t *address, int *accsize); ACPI_HANDLE acpi_GetReference(ACPI_HANDLE scope, ACPI_OBJECT *obj); /* * Base level for BUS_ADD_CHILD. Special devices are added at orders less * than this, and normal devices at or above this level. This keeps the * probe order sorted so that things like sysresource are available before * their children need them. */ #define ACPI_DEV_BASE_ORDER 100 /* Default maximum number of tasks to enqueue. */ #ifndef ACPI_MAX_TASKS #define ACPI_MAX_TASKS MAX(32, MAXCPU * 4) #endif /* Default number of task queue threads to start. */ #ifndef ACPI_MAX_THREADS #define ACPI_MAX_THREADS 3 #endif /* Use the device logging level for ktr(4). */ #define KTR_ACPI KTR_DEV SYSCTL_DECL(_debug_acpi); /* * Parse and use proximity information in SRAT and SLIT. */ int acpi_pxm_init(int ncpus, vm_paddr_t maxphys); void acpi_pxm_parse_tables(void); void acpi_pxm_set_mem_locality(void); void acpi_pxm_set_cpu_locality(void); int acpi_pxm_get_cpu_locality(int apic_id); /* * Map a PXM to a VM domain. * * Returns the VM domain ID if found, or -1 if not found / invalid. */ int acpi_map_pxm_to_vm_domainid(int pxm); int acpi_get_cpus(device_t dev, device_t child, enum cpu_sets op, size_t setsize, cpuset_t *cpuset); int acpi_get_domain(device_t dev, device_t child, int *domain); #ifdef __aarch64__ /* * ARM specific ACPI interfaces, relating to IORT table. */ int acpi_iort_map_pci_msi(u_int seg, u_int rid, u_int *xref, u_int *devid); int acpi_iort_its_lookup(u_int its_id, u_int *xref, int *pxm); #endif #endif /* _KERNEL */ #endif /* !_ACPIVAR_H_ */ Index: stable/12/sys/dev/iicbus/iicbus.h =================================================================== --- stable/12/sys/dev/iicbus/iicbus.h (revision 367676) +++ stable/12/sys/dev/iicbus/iicbus.h (revision 367677) @@ -1,103 +1,109 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1998 Nicolas Souchu * 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$ * */ #ifndef __IICBUS_H #define __IICBUS_H #include #include #define IICBUS_IVAR(d) (struct iicbus_ivar *) device_get_ivars(d) #define IICBUS_SOFTC(d) (struct iicbus_softc *) device_get_softc(d) struct iicbus_softc { device_t dev; /* Myself */ device_t owner; /* iicbus owner device structure */ device_t busydev; /* iicbus_release_bus calls unbusy on this */ u_int owncount; /* iicbus ownership nesting count */ u_char started; /* address of the 'started' slave * 0 if no start condition succeeded */ u_char strict; /* deny operations that violate the * I2C protocol */ struct mtx lock; u_int bus_freq; /* Configured bus Hz. */ }; struct iicbus_ivar { uint32_t addr; struct resource_list rl; }; /* Value of 0x100 is reserved for ACPI_IVAR_HANDLE used by acpi_iicbus */ enum { IICBUS_IVAR_ADDR /* Address or base address */ }; #define IICBUS_ACCESSOR(A, B, T) \ __BUS_ACCESSOR(iicbus, A, IICBUS, B, T) IICBUS_ACCESSOR(addr, ADDR, uint32_t) #define IICBUS_LOCK(sc) mtx_lock(&(sc)->lock) #define IICBUS_UNLOCK(sc) mtx_unlock(&(sc)->lock) #define IICBUS_ASSERT_LOCKED(sc) mtx_assert(&(sc)->lock, MA_OWNED) #ifdef FDT #define IICBUS_FDT_PNP_INFO(t) FDTCOMPAT_PNP_INFO(t, iicbus) #else #define IICBUS_FDT_PNP_INFO(t) #endif +#ifdef DEV_ACPI +#define IICBUS_ACPI_PNP_INFO(t) ACPICOMPAT_PNP_INFO(t, iicbus) +#else +#define IICBUS_ACPI_PNP_INFO(t) +#endif + int iicbus_generic_intr(device_t dev, int event, char *buf); void iicbus_init_frequency(device_t dev, u_int bus_freq); int iicbus_attach_common(device_t dev, u_int bus_freq); device_t iicbus_add_child_common(device_t dev, u_int order, const char *name, int unit, size_t ivars_size); int iicbus_detach(device_t dev); void iicbus_probe_nomatch(device_t bus, device_t child); int iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result); int iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t value); int iicbus_child_location_str(device_t bus, device_t child, char *buf, size_t buflen); int iicbus_child_pnpinfo_str(device_t bus, device_t child, char *buf, size_t buflen); extern driver_t iicbus_driver; extern devclass_t iicbus_devclass; extern driver_t ofw_iicbus_driver; extern devclass_t ofw_iicbus_devclass; extern driver_t acpi_iicbus_driver; #endif Index: stable/12 =================================================================== --- stable/12 (revision 367676) +++ stable/12 (revision 367677) Property changes on: stable/12 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r367239-367241