1 1.11 maya /* $NetBSD: wmi_hp.c,v 1.11 2018/06/06 01:49:08 maya Exp $ */ 2 1.1 jruoho 3 1.1 jruoho /*- 4 1.1 jruoho * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc. 5 1.1 jruoho * All rights reserved. 6 1.1 jruoho * 7 1.1 jruoho * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jruoho * by Jukka Ruohonen. 9 1.1 jruoho * 10 1.1 jruoho * Redistribution and use in source and binary forms, with or without 11 1.1 jruoho * modification, are permitted provided that the following conditions 12 1.1 jruoho * are met: 13 1.1 jruoho * 14 1.1 jruoho * 1. Redistributions of source code must retain the above copyright 15 1.1 jruoho * notice, this list of conditions and the following disclaimer. 16 1.1 jruoho * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 jruoho * notice, this list of conditions and the following disclaimer in the 18 1.1 jruoho * documentation and/or other materials provided with the distribution. 19 1.1 jruoho * 20 1.1 jruoho * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 1.1 jruoho * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.1 jruoho * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.1 jruoho * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 1.1 jruoho * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.1 jruoho * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.1 jruoho * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.1 jruoho * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.1 jruoho * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.1 jruoho * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.1 jruoho * SUCH DAMAGE. 31 1.1 jruoho */ 32 1.1 jruoho 33 1.1 jruoho /*- 34 1.1 jruoho * Copyright (c) 2009 Michael Gmelin <freebsd (at) grem.de> 35 1.1 jruoho * All rights reserved. 36 1.1 jruoho * 37 1.1 jruoho * Redistribution and use in source and binary forms, with or without 38 1.1 jruoho * modification, are permitted provided that the following conditions 39 1.1 jruoho * are met: 40 1.1 jruoho * 1. Redistributions of source code must retain the above copyright 41 1.1 jruoho * notice, this list of conditions and the following disclaimer. 42 1.1 jruoho * 2. Redistributions in binary form must reproduce the above copyright 43 1.1 jruoho * notice, this list of conditions and the following disclaimer in the 44 1.1 jruoho * documentation and/or other materials provided with the distribution. 45 1.1 jruoho * 46 1.1 jruoho * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 47 1.1 jruoho * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 1.1 jruoho * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 1.1 jruoho * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 50 1.1 jruoho * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 1.1 jruoho * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 1.1 jruoho * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 1.1 jruoho * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 1.1 jruoho * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 1.1 jruoho * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 1.1 jruoho * SUCH DAMAGE. 57 1.1 jruoho */ 58 1.1 jruoho 59 1.1 jruoho #include <sys/cdefs.h> 60 1.11 maya __KERNEL_RCSID(0, "$NetBSD: wmi_hp.c,v 1.11 2018/06/06 01:49:08 maya Exp $"); 61 1.1 jruoho 62 1.1 jruoho #include <sys/param.h> 63 1.1 jruoho #include <sys/device.h> 64 1.1 jruoho #include <sys/kmem.h> 65 1.3 jmcneill #include <sys/module.h> 66 1.1 jruoho 67 1.1 jruoho #include <dev/acpi/acpireg.h> 68 1.1 jruoho #include <dev/acpi/acpivar.h> 69 1.1 jruoho #include <dev/acpi/wmi/wmi_acpivar.h> 70 1.1 jruoho 71 1.1 jruoho #include <dev/sysmon/sysmonvar.h> 72 1.1 jruoho 73 1.7 cegger #include <sys/sysctl.h> 74 1.7 cegger 75 1.7 cegger /* 76 1.7 cegger * HP CMI whitepaper: 77 1.7 cegger * http://h20331.www2.hp.com/Hpsub/downloads/cmi_whitepaper.pdf 78 1.7 cegger */ 79 1.7 cegger 80 1.1 jruoho #define _COMPONENT ACPI_RESOURCE_COMPONENT 81 1.1 jruoho ACPI_MODULE_NAME ("wmi_hp") 82 1.1 jruoho 83 1.1 jruoho #define WMI_HP_METHOD_ARG_READ 0x01 84 1.1 jruoho #define WMI_HP_METHOD_ARG_WRITE 0x02 85 1.1 jruoho #define WMI_HP_METHOD_ARG_WRITE_SIZE 0x04 86 1.1 jruoho #define WMI_HP_METHOD_ARG_MAGIC 0x55434553 87 1.1 jruoho #define WMI_HP_METHOD_ARG_SIZE 0x05 * sizeof(uint32_t) 88 1.1 jruoho 89 1.1 jruoho #define WMI_HP_METHOD_CMD_DISPLAY 0x01 90 1.1 jruoho #define WMI_HP_METHOD_CMD_HDDTEMP 0x02 91 1.1 jruoho #define WMI_HP_METHOD_CMD_ALS 0x03 92 1.1 jruoho #define WMI_HP_METHOD_CMD_DOCK 0x04 93 1.1 jruoho #define WMI_HP_METHOD_CMD_SWITCH 0x05 94 1.1 jruoho #define WMI_HP_METHOD_CMD_HOTKEY 0x0C 95 1.1 jruoho 96 1.1 jruoho #define WMI_HP_EVENT_DOCK 0x01 97 1.1 jruoho #define WMI_HP_EVENT_HOTKEY 0x04 98 1.1 jruoho #define WMI_HP_EVENT_SWITCH 0x05 99 1.1 jruoho /* WMI_HP_EVENT_UNKNOWN 0xXX */ 100 1.1 jruoho 101 1.1 jruoho #define WMI_HP_HOTKEY_BRIGHTNESS_UP 0x02 102 1.1 jruoho #define WMI_HP_HOTKEY_BRIGHTNESS_DOWN 0x03 103 1.7 cegger #define WMI_HP_HOTKEY_PROG1 0x20e6 104 1.7 cegger #define WMI_HP_HOTKEY_MEDIA1 0x20e8 105 1.7 cegger #define WMI_HP_HOTKEY_MEDIA2 0x2142 106 1.7 cegger #define WMI_HP_HOTKEY_INFO 0x213b 107 1.7 cegger #define WMI_HP_HOTKEY_DIRECTION 0x2169 108 1.7 cegger #define WMI_HP_HOTKEY_HELP 0x231b 109 1.1 jruoho /* WMI_HP_HOTKEY_UNKNOWN 0xXX */ 110 1.1 jruoho 111 1.1 jruoho #define WMI_HP_SWITCH_WLAN 0x01 112 1.1 jruoho #define WMI_HP_SWITCH_BT 0x02 113 1.1 jruoho #define WMI_HP_SWITCH_WWAN 0x04 114 1.1 jruoho 115 1.1 jruoho #define WMI_HP_SWITCH_ARG_WLAN_OFF 0x100 116 1.1 jruoho #define WMI_HP_SWITCH_ARG_WLAN_ON 0x101 117 1.1 jruoho #define WMI_HP_SWITCH_ARG_BT_OFF 0x200 118 1.1 jruoho #define WMI_HP_SWITCH_ARG_BT_ON 0x202 119 1.1 jruoho #define WMI_HP_SWITCH_ARG_WWAN_OFF 0x400 120 1.1 jruoho #define WMI_HP_SWITCH_ARG_WWAN_ON 0x404 121 1.1 jruoho 122 1.1 jruoho #define WMI_HP_SWITCH_MASK_WLAN_ONAIR __BIT(8) 123 1.1 jruoho #define WMI_HP_SWITCH_MASK_WLAN_ENABLED __BIT(9) 124 1.1 jruoho #define WMI_HP_SWITCH_MASK_WLAN_RADIO __BIT(11) 125 1.1 jruoho #define WMI_HP_SWITCH_MASK_BT_ONAIR __BIT(16) 126 1.1 jruoho #define WMI_HP_SWITCH_MASK_BT_ENABLED __BIT(17) 127 1.1 jruoho #define WMI_HP_SWITCH_MASK_BT_RADIO __BIT(19) 128 1.1 jruoho #define WMI_HP_SWITCH_MASK_WWAN_ONAIR __BIT(24) 129 1.1 jruoho #define WMI_HP_SWITCH_MASK_WWAN_ENABLED __BIT(25) 130 1.1 jruoho #define WMI_HP_SWITCH_MASK_WWAN_RADIO __BIT(27) 131 1.1 jruoho 132 1.1 jruoho #define WMI_HP_GUID_EVENT "95F24279-4D7B-4334-9387-ACCDC67EF61C" 133 1.1 jruoho #define WMI_HP_GUID_METHOD "5FB7F034-2C63-45E9-BE91-3D44E2C707E4" 134 1.7 cegger #define WMI_HP_GUID_CMI "2D114B49-2DFB-4130-B8FE-4A3C09E75133" 135 1.1 jruoho 136 1.1 jruoho #define WMI_HP_SENSOR_WLAN 0 137 1.1 jruoho #define WMI_HP_SENSOR_BT 1 138 1.1 jruoho #define WMI_HP_SENSOR_WWAN 2 139 1.7 cegger #define WMI_HP_SENSOR_HDDTEMP 3 140 1.7 cegger #define WMI_HP_SENSOR_DISPLAY 4 141 1.7 cegger #define WMI_HP_SENSOR_DOCK 5 142 1.7 cegger #define WMI_HP_SENSOR_COUNT 6 143 1.7 cegger #define WMI_HP_SENSOR_SIZE WMI_HP_SENSOR_COUNT * sizeof(envsys_data_t) 144 1.7 cegger 145 1.7 cegger #define ACPI_HP_CMI_PATHS 0x01 146 1.7 cegger #define ACPI_HP_CMI_ENUMS 0x02 147 1.7 cegger #define ACPI_HP_CMI_FLAGS 0x04 148 1.7 cegger #define ACPI_HP_CMI_MAX_INSTANCE 0x08 149 1.1 jruoho 150 1.1 jruoho struct wmi_hp_softc { 151 1.1 jruoho device_t sc_dev; 152 1.1 jruoho device_t sc_parent; 153 1.1 jruoho struct sysmon_envsys *sc_sme; 154 1.1 jruoho envsys_data_t *sc_sensor; 155 1.1 jruoho uint32_t *sc_arg; 156 1.1 jruoho uint32_t sc_val; 157 1.1 jruoho }; 158 1.1 jruoho 159 1.1 jruoho static int wmi_hp_match(device_t, cfdata_t, void *); 160 1.1 jruoho static void wmi_hp_attach(device_t, device_t, void *); 161 1.1 jruoho static int wmi_hp_detach(device_t, int); 162 1.1 jruoho static bool wmi_hp_suspend(device_t, const pmf_qual_t *); 163 1.1 jruoho static bool wmi_hp_resume(device_t, const pmf_qual_t *); 164 1.1 jruoho static void wmi_hp_notify_handler(ACPI_HANDLE, uint32_t, void *); 165 1.1 jruoho static void wmi_hp_hotkey(void *); 166 1.1 jruoho static bool wmi_hp_method(struct wmi_hp_softc *); 167 1.1 jruoho static bool wmi_hp_method_read(struct wmi_hp_softc *, uint8_t); 168 1.1 jruoho static bool wmi_hp_method_write(struct wmi_hp_softc *, uint8_t, uint32_t); 169 1.1 jruoho 170 1.1 jruoho static void wmi_hp_sensor_init(struct wmi_hp_softc *); 171 1.7 cegger static void wmi_hp_sensor_switch_update(void *); 172 1.7 cegger static void wmi_hp_sensor_refresh(struct sysmon_envsys *, envsys_data_t *); 173 1.7 cegger 174 1.7 cegger static void sysctl_wmi_hp_setup(struct wmi_hp_softc *); 175 1.7 cegger static int sysctl_wmi_hp_set_als(SYSCTLFN_PROTO); 176 1.7 cegger static struct sysctllog *wmihp_sysctllog = NULL; 177 1.7 cegger static int wmihp_als = 0; 178 1.7 cegger static struct wmi_hp_softc *wmi_hp_sc = NULL; /* XXX */ 179 1.1 jruoho 180 1.1 jruoho CFATTACH_DECL_NEW(wmihp, sizeof(struct wmi_hp_softc), 181 1.1 jruoho wmi_hp_match, wmi_hp_attach, wmi_hp_detach, NULL); 182 1.1 jruoho 183 1.1 jruoho static int 184 1.1 jruoho wmi_hp_match(device_t parent, cfdata_t match, void *aux) 185 1.1 jruoho { 186 1.1 jruoho return acpi_wmi_guid_match(parent, WMI_HP_GUID_METHOD); 187 1.1 jruoho } 188 1.1 jruoho 189 1.1 jruoho static void 190 1.1 jruoho wmi_hp_attach(device_t parent, device_t self, void *aux) 191 1.1 jruoho { 192 1.1 jruoho struct wmi_hp_softc *sc = device_private(self); 193 1.1 jruoho ACPI_STATUS rv = AE_ERROR; 194 1.1 jruoho 195 1.1 jruoho sc->sc_dev = self; 196 1.1 jruoho sc->sc_parent = parent; 197 1.1 jruoho 198 1.1 jruoho sc->sc_sme = NULL; 199 1.1 jruoho sc->sc_sensor = NULL; 200 1.1 jruoho 201 1.1 jruoho sc->sc_arg = kmem_alloc(WMI_HP_METHOD_ARG_SIZE, KM_SLEEP); 202 1.1 jruoho aprint_naive("\n"); 203 1.1 jruoho aprint_normal(": HP WMI mappings\n"); 204 1.1 jruoho 205 1.1 jruoho (void)pmf_device_register(sc->sc_dev, wmi_hp_suspend, wmi_hp_resume); 206 1.1 jruoho 207 1.1 jruoho if (acpi_wmi_guid_match(parent, WMI_HP_GUID_EVENT) != 0) 208 1.1 jruoho rv = acpi_wmi_event_register(parent, wmi_hp_notify_handler); 209 1.1 jruoho 210 1.1 jruoho if (ACPI_FAILURE(rv)) 211 1.1 jruoho return; 212 1.1 jruoho 213 1.1 jruoho sc->sc_sensor = kmem_alloc(WMI_HP_SENSOR_SIZE, KM_SLEEP); 214 1.1 jruoho 215 1.7 cegger wmi_hp_sc = sc; /* XXX Can I pass sc as a cookie to sysctl? */ 216 1.1 jruoho wmi_hp_sensor_init(sc); 217 1.7 cegger sysctl_wmi_hp_setup(sc); 218 1.1 jruoho } 219 1.1 jruoho 220 1.1 jruoho static int 221 1.1 jruoho wmi_hp_detach(device_t self, int flags) 222 1.1 jruoho { 223 1.1 jruoho struct wmi_hp_softc *sc = device_private(self); 224 1.1 jruoho device_t parent = sc->sc_parent; 225 1.1 jruoho 226 1.1 jruoho (void)acpi_wmi_event_deregister(parent); 227 1.1 jruoho 228 1.1 jruoho if (sc->sc_sme != NULL) 229 1.1 jruoho sysmon_envsys_unregister(sc->sc_sme); 230 1.1 jruoho 231 1.1 jruoho if (sc->sc_sensor != NULL) 232 1.1 jruoho kmem_free(sc->sc_sensor, WMI_HP_SENSOR_SIZE); 233 1.1 jruoho 234 1.1 jruoho if (sc->sc_arg != NULL) 235 1.1 jruoho kmem_free(sc->sc_arg, WMI_HP_METHOD_ARG_SIZE); 236 1.1 jruoho 237 1.1 jruoho pmf_device_deregister(self); 238 1.1 jruoho 239 1.7 cegger if (wmihp_sysctllog != NULL) 240 1.7 cegger sysctl_teardown(&wmihp_sysctllog); 241 1.7 cegger wmihp_sysctllog = NULL; 242 1.7 cegger wmi_hp_sc = NULL; 243 1.7 cegger 244 1.1 jruoho return 0; 245 1.1 jruoho } 246 1.1 jruoho 247 1.1 jruoho static bool 248 1.1 jruoho wmi_hp_suspend(device_t self, const pmf_qual_t *qual) 249 1.1 jruoho { 250 1.1 jruoho struct wmi_hp_softc *sc = device_private(self); 251 1.1 jruoho device_t parent = sc->sc_parent; 252 1.1 jruoho 253 1.1 jruoho if (sc->sc_sensor != NULL) 254 1.1 jruoho (void)acpi_wmi_event_deregister(parent); 255 1.1 jruoho 256 1.1 jruoho return true; 257 1.1 jruoho } 258 1.1 jruoho 259 1.1 jruoho static bool 260 1.1 jruoho wmi_hp_resume(device_t self, const pmf_qual_t *qual) 261 1.1 jruoho { 262 1.1 jruoho struct wmi_hp_softc *sc = device_private(self); 263 1.1 jruoho device_t parent = sc->sc_parent; 264 1.1 jruoho 265 1.1 jruoho if (sc->sc_sensor != NULL) 266 1.1 jruoho (void)acpi_wmi_event_register(parent, wmi_hp_notify_handler); 267 1.1 jruoho 268 1.1 jruoho return true; 269 1.1 jruoho } 270 1.1 jruoho 271 1.1 jruoho static void 272 1.1 jruoho wmi_hp_notify_handler(ACPI_HANDLE hdl, uint32_t evt, void *aux) 273 1.1 jruoho { 274 1.1 jruoho static const int handler = OSL_NOTIFY_HANDLER; 275 1.1 jruoho struct wmi_hp_softc *sc; 276 1.1 jruoho device_t self = aux; 277 1.1 jruoho ACPI_OBJECT *obj; 278 1.1 jruoho ACPI_BUFFER buf; 279 1.1 jruoho ACPI_STATUS rv; 280 1.1 jruoho uint32_t val; 281 1.1 jruoho 282 1.2 jruoho buf.Pointer = NULL; 283 1.2 jruoho 284 1.1 jruoho sc = device_private(self); 285 1.1 jruoho rv = acpi_wmi_event_get(sc->sc_parent, evt, &buf); 286 1.1 jruoho 287 1.1 jruoho if (ACPI_FAILURE(rv)) 288 1.1 jruoho goto out; 289 1.1 jruoho 290 1.1 jruoho obj = buf.Pointer; 291 1.1 jruoho 292 1.1 jruoho if (obj->Type != ACPI_TYPE_BUFFER) { 293 1.1 jruoho rv = AE_TYPE; 294 1.1 jruoho goto out; 295 1.1 jruoho } 296 1.1 jruoho 297 1.1 jruoho if (obj->Buffer.Length != 8) { 298 1.1 jruoho rv = AE_LIMIT; 299 1.1 jruoho goto out; 300 1.1 jruoho } 301 1.1 jruoho 302 1.1 jruoho val = *((uint8_t *)obj->Buffer.Pointer); 303 1.1 jruoho 304 1.1 jruoho if (val == 0x00) { 305 1.1 jruoho rv = AE_BAD_DATA; 306 1.1 jruoho goto out; 307 1.1 jruoho } 308 1.1 jruoho 309 1.1 jruoho switch (val) { 310 1.1 jruoho 311 1.1 jruoho case WMI_HP_EVENT_SWITCH: 312 1.7 cegger rv = AcpiOsExecute(handler, wmi_hp_sensor_switch_update, self); 313 1.1 jruoho break; 314 1.1 jruoho 315 1.1 jruoho case WMI_HP_EVENT_HOTKEY: 316 1.1 jruoho rv = AcpiOsExecute(handler, wmi_hp_hotkey, self); 317 1.1 jruoho break; 318 1.1 jruoho 319 1.1 jruoho case WMI_HP_EVENT_DOCK: /* FALLTHROUGH */ 320 1.1 jruoho 321 1.1 jruoho default: 322 1.1 jruoho aprint_debug_dev(sc->sc_dev, "unknown event 0x%02X\n", evt); 323 1.1 jruoho break; 324 1.1 jruoho } 325 1.1 jruoho 326 1.1 jruoho out: 327 1.1 jruoho if (buf.Pointer != NULL) 328 1.1 jruoho ACPI_FREE(buf.Pointer); 329 1.1 jruoho 330 1.1 jruoho if (ACPI_FAILURE(rv)) 331 1.1 jruoho aprint_error_dev(sc->sc_dev, "failed to get data for " 332 1.1 jruoho "event 0x%02X: %s\n", evt, AcpiFormatException(rv)); 333 1.1 jruoho } 334 1.1 jruoho 335 1.1 jruoho static void 336 1.1 jruoho wmi_hp_hotkey(void *aux) 337 1.1 jruoho { 338 1.1 jruoho struct wmi_hp_softc *sc; 339 1.1 jruoho device_t self = aux; 340 1.1 jruoho 341 1.1 jruoho sc = device_private(self); 342 1.1 jruoho 343 1.1 jruoho if (wmi_hp_method_read(sc, WMI_HP_METHOD_CMD_HOTKEY) != true) 344 1.1 jruoho return; 345 1.1 jruoho 346 1.1 jruoho switch (sc->sc_val) { 347 1.1 jruoho 348 1.1 jruoho case WMI_HP_HOTKEY_BRIGHTNESS_UP: 349 1.1 jruoho pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_UP); 350 1.1 jruoho break; 351 1.1 jruoho 352 1.1 jruoho case WMI_HP_HOTKEY_BRIGHTNESS_DOWN: 353 1.1 jruoho pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_DOWN); 354 1.1 jruoho break; 355 1.1 jruoho 356 1.7 cegger case WMI_HP_HOTKEY_PROG1: 357 1.7 cegger aprint_debug_dev(self, "PROG1 hotkey pressed\n"); 358 1.7 cegger break; 359 1.7 cegger case WMI_HP_HOTKEY_MEDIA1: 360 1.7 cegger aprint_debug_dev(self, "MEDIA1 hotkey pressed\n"); 361 1.7 cegger break; 362 1.7 cegger case WMI_HP_HOTKEY_MEDIA2: 363 1.7 cegger aprint_debug_dev(self, "MEDIA2 hotkey pressed\n"); 364 1.7 cegger break; 365 1.7 cegger case WMI_HP_HOTKEY_INFO: 366 1.7 cegger aprint_debug_dev(self, "INFO hotkey pressed\n"); 367 1.7 cegger break; 368 1.7 cegger case WMI_HP_HOTKEY_DIRECTION: 369 1.7 cegger aprint_debug_dev(self, "DIRECTION hotkey pressed\n"); 370 1.7 cegger break; 371 1.7 cegger case WMI_HP_HOTKEY_HELP: 372 1.7 cegger aprint_debug_dev(self, "HELP hotkey pressed\n"); 373 1.7 cegger break; 374 1.1 jruoho default: 375 1.1 jruoho aprint_debug_dev(self, "unknown hotkey 0x%02x\n", sc->sc_val); 376 1.1 jruoho break; 377 1.1 jruoho } 378 1.1 jruoho } 379 1.1 jruoho 380 1.1 jruoho static bool 381 1.1 jruoho wmi_hp_method(struct wmi_hp_softc *sc) 382 1.1 jruoho { 383 1.1 jruoho ACPI_BUFFER ibuf, obuf; 384 1.1 jruoho ACPI_STATUS rv = AE_OK; 385 1.1 jruoho ACPI_OBJECT *obj; 386 1.1 jruoho uint32_t cmd, *val; 387 1.1 jruoho 388 1.1 jruoho cmd = sc->sc_arg[2]; 389 1.1 jruoho 390 1.1 jruoho KDASSERT(cmd != 0); 391 1.1 jruoho KDASSERT(sc->sc_arg[0] == WMI_HP_METHOD_ARG_MAGIC); 392 1.1 jruoho 393 1.2 jruoho obuf.Pointer = NULL; 394 1.1 jruoho ibuf.Pointer = sc->sc_arg; 395 1.1 jruoho ibuf.Length = WMI_HP_METHOD_ARG_SIZE; 396 1.1 jruoho 397 1.1 jruoho rv = acpi_wmi_method(sc->sc_parent, 398 1.1 jruoho WMI_HP_GUID_METHOD, 0, 3, &ibuf, &obuf); 399 1.1 jruoho 400 1.1 jruoho if (ACPI_FAILURE(rv)) 401 1.1 jruoho goto out; 402 1.1 jruoho 403 1.1 jruoho obj = obuf.Pointer; 404 1.1 jruoho 405 1.1 jruoho if (obj->Type != ACPI_TYPE_BUFFER) { 406 1.1 jruoho rv = AE_TYPE; 407 1.1 jruoho goto out; 408 1.1 jruoho } 409 1.1 jruoho 410 1.1 jruoho /* 411 1.1 jruoho * val[0] unknown 412 1.1 jruoho * val[1] error code 413 1.1 jruoho * val[2] return value 414 1.1 jruoho */ 415 1.1 jruoho val = (uint32_t *)obj->Buffer.Pointer; 416 1.1 jruoho 417 1.7 cegger sc->sc_val = val[2]; 418 1.7 cegger 419 1.7 cegger switch (val[1]) { 420 1.7 cegger case 0: /* Ok. */ 421 1.7 cegger break; 422 1.7 cegger case 2: /* wrong signature */ 423 1.7 cegger rv = AE_ERROR; 424 1.7 cegger aprint_debug_dev(sc->sc_dev, "wrong signature " 425 1.7 cegger "(cmd = 0x%02X): %s\n", cmd, AcpiFormatException(rv)); 426 1.7 cegger break; 427 1.7 cegger case 3: /* unknown command */ 428 1.7 cegger rv = AE_ERROR; 429 1.7 cegger aprint_debug_dev(sc->sc_dev, "unknown command " 430 1.7 cegger "(cmd = 0x%02X): %s\n", cmd, AcpiFormatException(rv)); 431 1.7 cegger break; 432 1.7 cegger case 4: /* unknown command type */ 433 1.7 cegger rv = AE_ERROR; 434 1.7 cegger aprint_debug_dev(sc->sc_dev, "unknown command type " 435 1.7 cegger "(cmd = 0x%02X): %s\n", cmd, AcpiFormatException(rv)); 436 1.7 cegger break; 437 1.7 cegger case 5: /* invalid parameters */ 438 1.1 jruoho rv = AE_ERROR; 439 1.7 cegger aprint_debug_dev(sc->sc_dev, "invalid parameters " 440 1.7 cegger "(cmd = 0x%02X): %s\n", cmd, AcpiFormatException(rv)); 441 1.7 cegger break; 442 1.7 cegger default: /* unknown error */ 443 1.7 cegger rv = AE_ERROR; 444 1.7 cegger aprint_debug_dev(sc->sc_dev, "unknown error " 445 1.7 cegger "(cmd = 0x%02X): %s\n", cmd, AcpiFormatException(rv)); 446 1.7 cegger break; 447 1.1 jruoho } 448 1.1 jruoho out: 449 1.1 jruoho if (obuf.Pointer != NULL) 450 1.1 jruoho ACPI_FREE(obuf.Pointer); 451 1.1 jruoho 452 1.1 jruoho if (ACPI_FAILURE(rv)) { 453 1.1 jruoho aprint_debug_dev(sc->sc_dev, "failed to evaluate method " 454 1.1 jruoho "(cmd = 0x%02X): %s\n", cmd, AcpiFormatException(rv)); 455 1.1 jruoho return false; 456 1.1 jruoho } 457 1.1 jruoho 458 1.1 jruoho return true; 459 1.1 jruoho } 460 1.1 jruoho 461 1.1 jruoho static bool 462 1.1 jruoho wmi_hp_method_read(struct wmi_hp_softc *sc, uint8_t cmd) 463 1.1 jruoho { 464 1.1 jruoho 465 1.1 jruoho sc->sc_arg[0] = WMI_HP_METHOD_ARG_MAGIC; 466 1.1 jruoho sc->sc_arg[1] = WMI_HP_METHOD_ARG_READ; 467 1.1 jruoho sc->sc_arg[2] = cmd; 468 1.1 jruoho sc->sc_arg[3] = 0; 469 1.1 jruoho sc->sc_arg[4] = 0; 470 1.1 jruoho 471 1.1 jruoho return wmi_hp_method(sc); 472 1.1 jruoho } 473 1.1 jruoho 474 1.1 jruoho static bool 475 1.1 jruoho wmi_hp_method_write(struct wmi_hp_softc *sc, uint8_t cmd, uint32_t val) 476 1.1 jruoho { 477 1.1 jruoho 478 1.1 jruoho sc->sc_arg[0] = WMI_HP_METHOD_ARG_MAGIC; 479 1.1 jruoho sc->sc_arg[1] = WMI_HP_METHOD_ARG_WRITE; 480 1.1 jruoho sc->sc_arg[2] = cmd; 481 1.1 jruoho sc->sc_arg[3] = WMI_HP_METHOD_ARG_WRITE_SIZE; 482 1.1 jruoho sc->sc_arg[4] = val; 483 1.1 jruoho 484 1.1 jruoho return wmi_hp_method(sc); 485 1.1 jruoho } 486 1.7 cegger 487 1.1 jruoho 488 1.1 jruoho static void 489 1.7 cegger wmi_hp_switch_init(struct wmi_hp_softc *sc) 490 1.1 jruoho { 491 1.7 cegger int i, sensor[3]; 492 1.1 jruoho 493 1.1 jruoho const char desc[][ENVSYS_DESCLEN] = { 494 1.1 jruoho "wireless", "bluetooth", "mobile" 495 1.1 jruoho }; 496 1.1 jruoho 497 1.1 jruoho if (wmi_hp_method_read(sc, WMI_HP_METHOD_CMD_SWITCH) != true) 498 1.1 jruoho return; 499 1.1 jruoho 500 1.1 jruoho sensor[0] = WMI_HP_SWITCH_WLAN; 501 1.1 jruoho sensor[1] = WMI_HP_SWITCH_BT; 502 1.1 jruoho sensor[2] = WMI_HP_SWITCH_WWAN; 503 1.1 jruoho 504 1.1 jruoho CTASSERT(WMI_HP_SENSOR_WLAN == 0); 505 1.1 jruoho CTASSERT(WMI_HP_SENSOR_BT == 1); 506 1.1 jruoho CTASSERT(WMI_HP_SENSOR_WWAN == 2); 507 1.1 jruoho 508 1.7 cegger for (i = 0; i < 3; i++) { 509 1.1 jruoho 510 1.1 jruoho if ((sc->sc_val & sensor[i]) == 0) 511 1.1 jruoho continue; 512 1.1 jruoho 513 1.1 jruoho (void)strlcpy(sc->sc_sensor[i].desc, desc[i], ENVSYS_DESCLEN); 514 1.1 jruoho 515 1.1 jruoho sc->sc_sensor[i].state = ENVSYS_SINVALID; 516 1.1 jruoho sc->sc_sensor[i].units = ENVSYS_INDICATOR; 517 1.1 jruoho 518 1.1 jruoho if (sysmon_envsys_sensor_attach(sc->sc_sme, 519 1.1 jruoho &sc->sc_sensor[i]) != 0) 520 1.7 cegger break; 521 1.7 cegger } 522 1.7 cegger } 523 1.7 cegger 524 1.7 cegger static void 525 1.7 cegger wmi_hp_sensor_init(struct wmi_hp_softc *sc) 526 1.7 cegger { 527 1.7 cegger int sensor; 528 1.1 jruoho 529 1.7 cegger KDASSERT(sc->sc_sme == NULL); 530 1.7 cegger KDASSERT(sc->sc_sensor != NULL); 531 1.7 cegger 532 1.7 cegger (void)memset(sc->sc_sensor, 0, WMI_HP_SENSOR_SIZE); 533 1.7 cegger 534 1.7 cegger sc->sc_sme = sysmon_envsys_create(); 535 1.7 cegger 536 1.7 cegger wmi_hp_switch_init(sc); 537 1.7 cegger 538 1.7 cegger if (wmi_hp_method_read(sc, WMI_HP_METHOD_CMD_HDDTEMP) == true) { 539 1.7 cegger sensor = WMI_HP_SENSOR_HDDTEMP; 540 1.7 cegger (void)strlcpy(sc->sc_sensor[sensor].desc, "hddtemp", 541 1.7 cegger ENVSYS_DESCLEN); 542 1.7 cegger sc->sc_sensor[sensor].state = ENVSYS_SVALID; 543 1.7 cegger sc->sc_sensor[sensor].units = ENVSYS_STEMP; 544 1.7 cegger sc->sc_sensor[sensor].value_cur = 545 1.7 cegger sc->sc_val * 1000000 + 273150000; 546 1.7 cegger 547 1.7 cegger sysmon_envsys_sensor_attach(sc->sc_sme, 548 1.7 cegger &sc->sc_sensor[sensor]); 549 1.7 cegger } 550 1.7 cegger 551 1.7 cegger if (wmi_hp_method_read(sc, WMI_HP_METHOD_CMD_DISPLAY) == true) { 552 1.7 cegger sensor = WMI_HP_SENSOR_DISPLAY; 553 1.7 cegger (void)strlcpy(sc->sc_sensor[sensor].desc, "display", 554 1.7 cegger ENVSYS_DESCLEN); 555 1.7 cegger sc->sc_sensor[sensor].state = ENVSYS_SVALID; 556 1.7 cegger sc->sc_sensor[sensor].units = ENVSYS_INDICATOR; 557 1.7 cegger sc->sc_sensor[sensor].value_cur = sc->sc_val; 558 1.7 cegger 559 1.7 cegger sysmon_envsys_sensor_attach(sc->sc_sme, 560 1.7 cegger &sc->sc_sensor[sensor]); 561 1.7 cegger } 562 1.7 cegger 563 1.7 cegger if (wmi_hp_method_read(sc, WMI_HP_METHOD_CMD_DOCK) == true) { 564 1.7 cegger sensor = WMI_HP_SENSOR_DOCK; 565 1.7 cegger (void)strlcpy(sc->sc_sensor[sensor].desc, "docking station", 566 1.7 cegger ENVSYS_DESCLEN); 567 1.7 cegger sc->sc_sensor[sensor].state = ENVSYS_SVALID; 568 1.7 cegger sc->sc_sensor[sensor].units = ENVSYS_INDICATOR; 569 1.7 cegger sc->sc_sensor[sensor].value_cur = sc->sc_val; 570 1.7 cegger 571 1.7 cegger sysmon_envsys_sensor_attach(sc->sc_sme, 572 1.7 cegger &sc->sc_sensor[sensor]); 573 1.1 jruoho } 574 1.1 jruoho 575 1.7 cegger sc->sc_sme->sme_cookie = sc; 576 1.7 cegger sc->sc_sme->sme_refresh = wmi_hp_sensor_refresh; 577 1.1 jruoho sc->sc_sme->sme_name = device_xname(sc->sc_dev); 578 1.1 jruoho 579 1.1 jruoho if (sysmon_envsys_register(sc->sc_sme) != 0) 580 1.1 jruoho goto fail; 581 1.1 jruoho 582 1.7 cegger wmi_hp_sensor_switch_update(sc->sc_dev); 583 1.1 jruoho 584 1.1 jruoho return; 585 1.1 jruoho 586 1.1 jruoho fail: 587 1.1 jruoho aprint_debug_dev(sc->sc_dev, "failed to initialize sysmon\n"); 588 1.1 jruoho 589 1.1 jruoho sysmon_envsys_destroy(sc->sc_sme); 590 1.1 jruoho kmem_free(sc->sc_sensor, WMI_HP_SENSOR_SIZE); 591 1.1 jruoho 592 1.1 jruoho sc->sc_sme = NULL; 593 1.1 jruoho sc->sc_sensor = NULL; 594 1.1 jruoho } 595 1.1 jruoho 596 1.1 jruoho static void 597 1.7 cegger wmi_hp_sensor_switch_update(void *aux) 598 1.1 jruoho { 599 1.1 jruoho struct wmi_hp_softc *sc; 600 1.1 jruoho device_t self = aux; 601 1.1 jruoho 602 1.1 jruoho sc = device_private(self); 603 1.1 jruoho 604 1.1 jruoho if (sc->sc_sme == NULL || sc->sc_sensor == NULL) 605 1.1 jruoho return; 606 1.1 jruoho 607 1.1 jruoho if (wmi_hp_method_read(sc, WMI_HP_METHOD_CMD_SWITCH) != true) { 608 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_WLAN].state = ENVSYS_SINVALID; 609 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_WWAN].state = ENVSYS_SINVALID; 610 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_BT].state = ENVSYS_SINVALID; 611 1.1 jruoho return; 612 1.1 jruoho } 613 1.1 jruoho 614 1.1 jruoho if ((sc->sc_val & WMI_HP_SWITCH_WLAN) != 0) { 615 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_WLAN].value_cur = 0; 616 1.1 jruoho 617 1.1 jruoho if ((sc->sc_val & WMI_HP_SWITCH_MASK_WLAN_ONAIR) != 0) 618 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_WLAN].value_cur = 1; 619 1.1 jruoho 620 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_WLAN].state = ENVSYS_SVALID; 621 1.1 jruoho } 622 1.1 jruoho 623 1.1 jruoho if ((sc->sc_val & WMI_HP_SWITCH_BT) != 0) { 624 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_BT].value_cur = 0; 625 1.1 jruoho 626 1.1 jruoho if ((sc->sc_val & WMI_HP_SWITCH_MASK_BT_ONAIR) != 0) 627 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_BT].value_cur = 1; 628 1.1 jruoho 629 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_BT].state = ENVSYS_SVALID; 630 1.1 jruoho } 631 1.1 jruoho 632 1.1 jruoho if ((sc->sc_val & WMI_HP_SWITCH_WWAN) != 0) { 633 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_WWAN].value_cur = 0; 634 1.1 jruoho 635 1.1 jruoho if ((sc->sc_val & WMI_HP_SWITCH_MASK_WWAN_ONAIR) != 0) 636 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_WWAN].value_cur = 1; 637 1.1 jruoho 638 1.1 jruoho sc->sc_sensor[WMI_HP_SENSOR_WWAN].state = ENVSYS_SVALID; 639 1.1 jruoho } 640 1.1 jruoho } 641 1.3 jmcneill 642 1.7 cegger static void 643 1.7 cegger wmi_hp_sensor_read(struct wmi_hp_softc *sc, envsys_data_t *sensor, int cmd) 644 1.7 cegger { 645 1.7 cegger if (wmi_hp_method_read(sc, cmd) == true) { 646 1.7 cegger sensor->state = ENVSYS_SVALID; 647 1.7 cegger sensor->value_cur = sc->sc_val; 648 1.7 cegger } else { 649 1.7 cegger sensor->state = ENVSYS_SINVALID; 650 1.7 cegger } 651 1.7 cegger } 652 1.7 cegger 653 1.7 cegger static void 654 1.7 cegger wmi_hp_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 655 1.7 cegger { 656 1.7 cegger struct wmi_hp_softc *sc = sme->sme_cookie; 657 1.7 cegger envsys_data_t *sensor; 658 1.7 cegger 659 1.7 cegger sensor = &sc->sc_sensor[WMI_HP_SENSOR_HDDTEMP]; 660 1.7 cegger wmi_hp_sensor_read(sc, sensor, WMI_HP_METHOD_CMD_HDDTEMP); 661 1.7 cegger if (sensor->state == ENVSYS_SVALID) { 662 1.7 cegger sensor->value_cur = sensor->value_cur * 1000000 + 663 1.7 cegger 273150000; 664 1.7 cegger } 665 1.7 cegger 666 1.7 cegger wmi_hp_sensor_read(sc, &sc->sc_sensor[WMI_HP_SENSOR_DISPLAY], 667 1.7 cegger WMI_HP_METHOD_CMD_DISPLAY); 668 1.7 cegger 669 1.7 cegger wmi_hp_sensor_read(sc, &sc->sc_sensor[WMI_HP_SENSOR_DOCK], 670 1.7 cegger WMI_HP_METHOD_CMD_DOCK); 671 1.7 cegger } 672 1.7 cegger 673 1.9 pgoyette MODULE(MODULE_CLASS_DRIVER, wmihp, "acpiwmi,sysmon_envsys"); 674 1.3 jmcneill 675 1.5 jruoho #ifdef _MODULE 676 1.5 jruoho #include "ioconf.c" 677 1.5 jruoho #endif 678 1.3 jmcneill 679 1.3 jmcneill static int 680 1.5 jruoho wmihp_modcmd(modcmd_t cmd, void *aux) 681 1.3 jmcneill { 682 1.5 jruoho int rv = 0; 683 1.3 jmcneill 684 1.3 jmcneill switch (cmd) { 685 1.3 jmcneill 686 1.3 jmcneill case MODULE_CMD_INIT: 687 1.3 jmcneill 688 1.5 jruoho #ifdef _MODULE 689 1.5 jruoho rv = config_init_component(cfdriver_ioconf_wmihp, 690 1.5 jruoho cfattach_ioconf_wmihp, cfdata_ioconf_wmihp); 691 1.5 jruoho #endif 692 1.5 jruoho break; 693 1.3 jmcneill 694 1.3 jmcneill case MODULE_CMD_FINI: 695 1.3 jmcneill 696 1.5 jruoho #ifdef _MODULE 697 1.5 jruoho rv = config_fini_component(cfdriver_ioconf_wmihp, 698 1.5 jruoho cfattach_ioconf_wmihp, cfdata_ioconf_wmihp); 699 1.5 jruoho #endif 700 1.5 jruoho break; 701 1.3 jmcneill 702 1.3 jmcneill default: 703 1.5 jruoho rv = ENOTTY; 704 1.3 jmcneill } 705 1.5 jruoho 706 1.5 jruoho return rv; 707 1.3 jmcneill } 708 1.7 cegger 709 1.7 cegger static int 710 1.7 cegger sysctl_wmi_hp_set_als(SYSCTLFN_ARGS) 711 1.7 cegger { 712 1.7 cegger struct sysctlnode node; 713 1.7 cegger int err; 714 1.7 cegger int als = wmihp_als; 715 1.7 cegger struct wmi_hp_softc *sc = wmi_hp_sc; 716 1.7 cegger 717 1.7 cegger node = *rnode; 718 1.7 cegger node.sysctl_data = &als; 719 1.7 cegger 720 1.7 cegger err = sysctl_lookup(SYSCTLFN_CALL(&node)); 721 1.7 cegger 722 1.7 cegger if (err != 0 || newp == NULL) 723 1.11 maya return err; 724 1.7 cegger 725 1.7 cegger if (als < 0 || als > 1) 726 1.7 cegger return EINVAL; 727 1.7 cegger 728 1.7 cegger if (wmi_hp_method_write(sc, WMI_HP_METHOD_CMD_ALS, als) == true) { 729 1.7 cegger wmihp_als = als; 730 1.7 cegger return 0; 731 1.7 cegger } 732 1.7 cegger 733 1.7 cegger return EIO; 734 1.7 cegger } 735 1.7 cegger 736 1.7 cegger static void 737 1.7 cegger sysctl_wmi_hp_setup(struct wmi_hp_softc *sc) 738 1.7 cegger { 739 1.7 cegger const struct sysctlnode *rnode; 740 1.7 cegger int err; 741 1.7 cegger 742 1.7 cegger err = sysctl_createv(&wmihp_sysctllog, 0, NULL, &rnode, 743 1.7 cegger CTLFLAG_PERMANENT, CTLTYPE_NODE, "acpi", NULL, 744 1.8 pooka NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); 745 1.7 cegger 746 1.7 cegger if (err != 0) 747 1.7 cegger return; 748 1.7 cegger 749 1.7 cegger err = sysctl_createv(&wmihp_sysctllog, 0, &rnode, &rnode, 750 1.7 cegger 0, CTLTYPE_NODE, "wmi", SYSCTL_DESCR("ACPI HP WMI"), 751 1.7 cegger NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 752 1.7 cegger 753 1.7 cegger if (err != 0) 754 1.7 cegger return; 755 1.7 cegger 756 1.7 cegger if (wmi_hp_method_read(sc, WMI_HP_METHOD_CMD_ALS) == true) { 757 1.7 cegger (void)sysctl_createv(NULL, 0, &rnode, NULL, 758 1.7 cegger CTLFLAG_READWRITE, CTLTYPE_BOOL, "als", 759 1.7 cegger SYSCTL_DESCR("Ambient Light Sensor"), 760 1.7 cegger sysctl_wmi_hp_set_als, 0, NULL, 0, CTL_CREATE, CTL_EOL); 761 1.7 cegger } 762 1.7 cegger } 763