1*96f1dfc1SKristof Provost /*- 2*96f1dfc1SKristof Provost * Copyright (c) 2024 Rubicon Communications, LLC (Netgate) 3*96f1dfc1SKristof Provost * 4*96f1dfc1SKristof Provost * Redistribution and use in source and binary forms, with or without 5*96f1dfc1SKristof Provost * modification, are permitted provided that the following conditions 6*96f1dfc1SKristof Provost * are met: 7*96f1dfc1SKristof Provost * 1. Redistributions of source code must retain the above copyright 8*96f1dfc1SKristof Provost * notice, this list of conditions and the following disclaimer. 9*96f1dfc1SKristof Provost * 2. Redistributions in binary form must reproduce the above copyright 10*96f1dfc1SKristof Provost * notice, this list of conditions and the following disclaimer in the 11*96f1dfc1SKristof Provost * documentation and/or other materials provided with the distribution. 12*96f1dfc1SKristof Provost * 13*96f1dfc1SKristof Provost * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*96f1dfc1SKristof Provost * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*96f1dfc1SKristof Provost * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*96f1dfc1SKristof Provost * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17*96f1dfc1SKristof Provost * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*96f1dfc1SKristof Provost * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*96f1dfc1SKristof Provost * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*96f1dfc1SKristof Provost * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*96f1dfc1SKristof Provost * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*96f1dfc1SKristof Provost * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*96f1dfc1SKristof Provost * SUCH DAMAGE. 24*96f1dfc1SKristof Provost */ 25*96f1dfc1SKristof Provost 26*96f1dfc1SKristof Provost #include <sys/cdefs.h> 27*96f1dfc1SKristof Provost #include "opt_acpi.h" 28*96f1dfc1SKristof Provost #include <sys/param.h> 29*96f1dfc1SKristof Provost #include <sys/conf.h> 30*96f1dfc1SKristof Provost #include <sys/uio.h> 31*96f1dfc1SKristof Provost #include <sys/proc.h> 32*96f1dfc1SKristof Provost #include <sys/kernel.h> 33*96f1dfc1SKristof Provost #include <sys/bus.h> 34*96f1dfc1SKristof Provost #include <sys/sbuf.h> 35*96f1dfc1SKristof Provost #include <sys/module.h> 36*96f1dfc1SKristof Provost #include <sys/sysctl.h> 37*96f1dfc1SKristof Provost 38*96f1dfc1SKristof Provost #include <contrib/dev/acpica/include/acpi.h> 39*96f1dfc1SKristof Provost #include <contrib/dev/acpica/include/accommon.h> 40*96f1dfc1SKristof Provost #include <dev/acpica/acpivar.h> 41*96f1dfc1SKristof Provost #include "acpi_wmi_if.h" 42*96f1dfc1SKristof Provost 43*96f1dfc1SKristof Provost #define _COMPONENT ACPI_OEM 44*96f1dfc1SKristof Provost ACPI_MODULE_NAME("SBL-FW-UPDATE-WMI") 45*96f1dfc1SKristof Provost ACPI_SERIAL_DECL(sbl_wmi, "SBL WMI device"); 46*96f1dfc1SKristof Provost 47*96f1dfc1SKristof Provost #define ACPI_SBL_FW_UPDATE_WMI_GUID "44FADEB1-B204-40F2-8581-394BBDC1B651" 48*96f1dfc1SKristof Provost 49*96f1dfc1SKristof Provost struct acpi_sbl_wmi_softc { 50*96f1dfc1SKristof Provost device_t dev; 51*96f1dfc1SKristof Provost device_t wmi_dev; 52*96f1dfc1SKristof Provost }; 53*96f1dfc1SKristof Provost 54*96f1dfc1SKristof Provost static void 55*96f1dfc1SKristof Provost acpi_sbl_wmi_identify(driver_t *driver, device_t parent) 56*96f1dfc1SKristof Provost { 57*96f1dfc1SKristof Provost /* Don't do anything if driver is disabled. */ 58*96f1dfc1SKristof Provost if (acpi_disabled("sbl_wmi")) 59*96f1dfc1SKristof Provost return; 60*96f1dfc1SKristof Provost 61*96f1dfc1SKristof Provost /* Add only a single device instance. */ 62*96f1dfc1SKristof Provost if (device_find_child(parent, "acpi_sbl_wmi", -1) != NULL) 63*96f1dfc1SKristof Provost return; 64*96f1dfc1SKristof Provost 65*96f1dfc1SKristof Provost /* Check management GUID to see whether system is compatible. */ 66*96f1dfc1SKristof Provost if (!ACPI_WMI_PROVIDES_GUID_STRING(parent, 67*96f1dfc1SKristof Provost ACPI_SBL_FW_UPDATE_WMI_GUID)) 68*96f1dfc1SKristof Provost return; 69*96f1dfc1SKristof Provost 70*96f1dfc1SKristof Provost if (BUS_ADD_CHILD(parent, 0, "acpi_sbl_wmi", -1) == NULL) 71*96f1dfc1SKristof Provost device_printf(parent, "add acpi_sbl_wmi child failed\n"); 72*96f1dfc1SKristof Provost } 73*96f1dfc1SKristof Provost 74*96f1dfc1SKristof Provost static int 75*96f1dfc1SKristof Provost acpi_sbl_wmi_probe(device_t dev) 76*96f1dfc1SKristof Provost { 77*96f1dfc1SKristof Provost if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev), 78*96f1dfc1SKristof Provost ACPI_SBL_FW_UPDATE_WMI_GUID)) 79*96f1dfc1SKristof Provost return (EINVAL); 80*96f1dfc1SKristof Provost device_set_desc(dev, "SBL Firmware Update WMI device"); 81*96f1dfc1SKristof Provost return (0); 82*96f1dfc1SKristof Provost } 83*96f1dfc1SKristof Provost 84*96f1dfc1SKristof Provost static int 85*96f1dfc1SKristof Provost acpi_sbl_wmi_sysctl_get(struct acpi_sbl_wmi_softc *sc, int *val) 86*96f1dfc1SKristof Provost { 87*96f1dfc1SKristof Provost ACPI_OBJECT *obj; 88*96f1dfc1SKristof Provost ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL }; 89*96f1dfc1SKristof Provost int error = 0; 90*96f1dfc1SKristof Provost 91*96f1dfc1SKristof Provost if (ACPI_FAILURE(ACPI_WMI_GET_BLOCK(sc->wmi_dev, 92*96f1dfc1SKristof Provost ACPI_SBL_FW_UPDATE_WMI_GUID, 0, &out))) { 93*96f1dfc1SKristof Provost error = EINVAL; 94*96f1dfc1SKristof Provost goto out; 95*96f1dfc1SKristof Provost } 96*96f1dfc1SKristof Provost 97*96f1dfc1SKristof Provost obj = out.Pointer; 98*96f1dfc1SKristof Provost if (obj->Type != ACPI_TYPE_INTEGER) { 99*96f1dfc1SKristof Provost error = EINVAL; 100*96f1dfc1SKristof Provost goto out; 101*96f1dfc1SKristof Provost } 102*96f1dfc1SKristof Provost 103*96f1dfc1SKristof Provost *val = obj->Integer.Value; 104*96f1dfc1SKristof Provost 105*96f1dfc1SKristof Provost out: 106*96f1dfc1SKristof Provost if (out.Pointer) 107*96f1dfc1SKristof Provost AcpiOsFree(out.Pointer); 108*96f1dfc1SKristof Provost 109*96f1dfc1SKristof Provost return (error); 110*96f1dfc1SKristof Provost } 111*96f1dfc1SKristof Provost 112*96f1dfc1SKristof Provost static int 113*96f1dfc1SKristof Provost acpi_sbl_wmi_sysctl_set(struct acpi_sbl_wmi_softc *sc, int in) 114*96f1dfc1SKristof Provost { 115*96f1dfc1SKristof Provost ACPI_BUFFER input = { ACPI_ALLOCATE_BUFFER, NULL }; 116*96f1dfc1SKristof Provost uint32_t val; 117*96f1dfc1SKristof Provost 118*96f1dfc1SKristof Provost val = in; 119*96f1dfc1SKristof Provost input.Length = sizeof(val); 120*96f1dfc1SKristof Provost input.Pointer = &val; 121*96f1dfc1SKristof Provost 122*96f1dfc1SKristof Provost if (ACPI_FAILURE(ACPI_WMI_SET_BLOCK(sc->wmi_dev, 123*96f1dfc1SKristof Provost ACPI_SBL_FW_UPDATE_WMI_GUID, 0, &input))) 124*96f1dfc1SKristof Provost return (ENODEV); 125*96f1dfc1SKristof Provost 126*96f1dfc1SKristof Provost return (0); 127*96f1dfc1SKristof Provost } 128*96f1dfc1SKristof Provost 129*96f1dfc1SKristof Provost static int 130*96f1dfc1SKristof Provost acpi_sbl_wmi_fw_upgrade_sysctl(SYSCTL_HANDLER_ARGS) 131*96f1dfc1SKristof Provost { 132*96f1dfc1SKristof Provost struct acpi_sbl_wmi_softc *sc; 133*96f1dfc1SKristof Provost int arg; 134*96f1dfc1SKristof Provost int error = 0; 135*96f1dfc1SKristof Provost 136*96f1dfc1SKristof Provost ACPI_SERIAL_BEGIN(sbl_wmi); 137*96f1dfc1SKristof Provost 138*96f1dfc1SKristof Provost sc = (struct acpi_sbl_wmi_softc *)oidp->oid_arg1; 139*96f1dfc1SKristof Provost error = acpi_sbl_wmi_sysctl_get(sc, &arg); 140*96f1dfc1SKristof Provost if (error != 0) 141*96f1dfc1SKristof Provost goto out; 142*96f1dfc1SKristof Provost 143*96f1dfc1SKristof Provost error = sysctl_handle_int(oidp, &arg, 0, req); 144*96f1dfc1SKristof Provost if (! error && req->newptr != NULL) 145*96f1dfc1SKristof Provost error = acpi_sbl_wmi_sysctl_set(sc, arg); 146*96f1dfc1SKristof Provost 147*96f1dfc1SKristof Provost out: 148*96f1dfc1SKristof Provost ACPI_SERIAL_END(sbl_wmi); 149*96f1dfc1SKristof Provost 150*96f1dfc1SKristof Provost return (error); 151*96f1dfc1SKristof Provost } 152*96f1dfc1SKristof Provost 153*96f1dfc1SKristof Provost static int 154*96f1dfc1SKristof Provost acpi_sbl_wmi_attach(device_t dev) 155*96f1dfc1SKristof Provost { 156*96f1dfc1SKristof Provost struct acpi_sbl_wmi_softc *sc; 157*96f1dfc1SKristof Provost struct sysctl_ctx_list *sysctl_ctx; 158*96f1dfc1SKristof Provost struct sysctl_oid *sysctl_tree; 159*96f1dfc1SKristof Provost 160*96f1dfc1SKristof Provost sc = device_get_softc(dev); 161*96f1dfc1SKristof Provost sc->dev = dev; 162*96f1dfc1SKristof Provost sc->wmi_dev = device_get_parent(dev); 163*96f1dfc1SKristof Provost 164*96f1dfc1SKristof Provost sysctl_ctx = device_get_sysctl_ctx(dev); 165*96f1dfc1SKristof Provost sysctl_tree = device_get_sysctl_tree(dev); 166*96f1dfc1SKristof Provost 167*96f1dfc1SKristof Provost SYSCTL_ADD_PROC(sysctl_ctx, 168*96f1dfc1SKristof Provost SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, 169*96f1dfc1SKristof Provost "firmware_update_request", 170*96f1dfc1SKristof Provost CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 171*96f1dfc1SKristof Provost sc, 0, acpi_sbl_wmi_fw_upgrade_sysctl, "I", 172*96f1dfc1SKristof Provost "Signal SBL that a firmware update is available"); 173*96f1dfc1SKristof Provost 174*96f1dfc1SKristof Provost return (0); 175*96f1dfc1SKristof Provost } 176*96f1dfc1SKristof Provost 177*96f1dfc1SKristof Provost static device_method_t acpi_sbl_wmi_methods[] = { 178*96f1dfc1SKristof Provost DEVMETHOD(device_identify, acpi_sbl_wmi_identify), 179*96f1dfc1SKristof Provost DEVMETHOD(device_probe, acpi_sbl_wmi_probe), 180*96f1dfc1SKristof Provost DEVMETHOD(device_attach, acpi_sbl_wmi_attach), 181*96f1dfc1SKristof Provost 182*96f1dfc1SKristof Provost DEVMETHOD_END 183*96f1dfc1SKristof Provost }; 184*96f1dfc1SKristof Provost 185*96f1dfc1SKristof Provost static driver_t acpi_sbl_wmi_driver = { 186*96f1dfc1SKristof Provost "acpi_sbl_wmi", 187*96f1dfc1SKristof Provost acpi_sbl_wmi_methods, 188*96f1dfc1SKristof Provost sizeof(struct acpi_sbl_wmi_softc), 189*96f1dfc1SKristof Provost }; 190*96f1dfc1SKristof Provost 191*96f1dfc1SKristof Provost DRIVER_MODULE(acpi_sbl_wmi, acpi_wmi, acpi_sbl_wmi_driver, 0, 0); 192*96f1dfc1SKristof Provost MODULE_DEPEND(acpi_sbl_wmi, acpi_wmi, 1, 1, 1); 193*96f1dfc1SKristof Provost MODULE_DEPEND(acpi_sbl_wmi, acpi, 1, 1, 1); 194