1 1.57 christos /* $NetBSD: thinkpad_acpi.c,v 1.57 2024/04/27 14:50:18 christos Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2007 Jared D. McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 14 1.1 jmcneill * documentation and/or other materials provided with the distribution. 15 1.1 jmcneill * 16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE. 27 1.1 jmcneill */ 28 1.1 jmcneill 29 1.1 jmcneill #include <sys/cdefs.h> 30 1.57 christos __KERNEL_RCSID(0, "$NetBSD: thinkpad_acpi.c,v 1.57 2024/04/27 14:50:18 christos Exp $"); 31 1.1 jmcneill 32 1.1 jmcneill #include <sys/param.h> 33 1.28 jruoho #include <sys/device.h> 34 1.27 jruoho #include <sys/module.h> 35 1.51 riastrad #include <sys/sdt.h> 36 1.28 jruoho #include <sys/systm.h> 37 1.57 christos #include <sys/sysctl.h> 38 1.1 jmcneill 39 1.24 jruoho #include <dev/acpi/acpireg.h> 40 1.1 jmcneill #include <dev/acpi/acpivar.h> 41 1.5 jmcneill #include <dev/acpi/acpi_ecvar.h> 42 1.36 jruoho #include <dev/acpi/acpi_power.h> 43 1.1 jmcneill 44 1.13 jmcneill #include <dev/isa/isareg.h> 45 1.1 jmcneill 46 1.24 jruoho #define _COMPONENT ACPI_RESOURCE_COMPONENT 47 1.24 jruoho ACPI_MODULE_NAME ("thinkpad_acpi") 48 1.24 jruoho 49 1.16 jmcneill #define THINKPAD_NTEMPSENSORS 8 50 1.16 jmcneill #define THINKPAD_NFANSENSORS 1 51 1.16 jmcneill #define THINKPAD_NSENSORS (THINKPAD_NTEMPSENSORS + THINKPAD_NFANSENSORS) 52 1.5 jmcneill 53 1.57 christos typedef struct tp_sysctl_param { 54 1.57 christos device_t sp_dev; 55 1.57 christos int sp_bat; 56 1.57 christos } tp_sysctl_param_t; 57 1.57 christos 58 1.57 christos typedef union tp_batctl { 59 1.57 christos int have_any; 60 1.57 christos struct { 61 1.57 christos int charge_start:1; 62 1.57 christos int charge_stop:1; 63 1.57 christos int charge_inhibit:1; 64 1.57 christos int force_discharge:1; 65 1.57 christos int individual_control:1; 66 1.57 christos } have; 67 1.57 christos } tp_batctl_t; 68 1.57 christos 69 1.1 jmcneill typedef struct thinkpad_softc { 70 1.1 jmcneill device_t sc_dev; 71 1.5 jmcneill device_t sc_ecdev; 72 1.1 jmcneill struct acpi_devnode *sc_node; 73 1.57 christos struct sysctllog *sc_log; 74 1.36 jruoho ACPI_HANDLE sc_powhdl; 75 1.1 jmcneill ACPI_HANDLE sc_cmoshdl; 76 1.53 riastrad ACPI_INTEGER sc_ver; 77 1.1 jmcneill 78 1.43 christos #define TP_PSW_SLEEP 0 /* FnF4 */ 79 1.43 christos #define TP_PSW_HIBERNATE 1 /* FnF12 */ 80 1.43 christos #define TP_PSW_DISPLAY_CYCLE 2 /* FnF7 */ 81 1.43 christos #define TP_PSW_LOCK_SCREEN 3 /* FnF2 */ 82 1.43 christos #define TP_PSW_BATTERY_INFO 4 /* FnF3 */ 83 1.43 christos #define TP_PSW_EJECT_BUTTON 5 /* FnF9 */ 84 1.43 christos #define TP_PSW_ZOOM_BUTTON 6 /* FnSPACE */ 85 1.43 christos #define TP_PSW_VENDOR_BUTTON 7 /* ThinkVantage */ 86 1.43 christos #define TP_PSW_FNF1_BUTTON 8 /* FnF1 */ 87 1.43 christos #define TP_PSW_WIRELESS_BUTTON 9 /* FnF5 */ 88 1.43 christos #define TP_PSW_WWAN_BUTTON 10 /* FnF6 */ 89 1.43 christos #define TP_PSW_POINTER_BUTTON 11 /* FnF8 */ 90 1.43 christos #define TP_PSW_FNF10_BUTTON 12 /* FnF10 */ 91 1.43 christos #define TP_PSW_FNF11_BUTTON 13 /* FnF11 */ 92 1.43 christos #define TP_PSW_BRIGHTNESS_UP 14 93 1.43 christos #define TP_PSW_BRIGHTNESS_DOWN 15 94 1.43 christos #define TP_PSW_THINKLIGHT 16 95 1.43 christos #define TP_PSW_VOLUME_UP 17 96 1.43 christos #define TP_PSW_VOLUME_DOWN 18 97 1.43 christos #define TP_PSW_VOLUME_MUTE 19 98 1.52 riastrad #define TP_PSW_STAR_BUTTON 20 99 1.52 riastrad #define TP_PSW_SCISSORS_BUTTON 21 100 1.52 riastrad #define TP_PSW_BLUETOOTH_BUTTON 22 101 1.52 riastrad #define TP_PSW_KEYBOARD_BUTTON 23 102 1.52 riastrad #define TP_PSW_LAST 24 103 1.43 christos 104 1.9 jmcneill struct sysmon_pswitch sc_smpsw[TP_PSW_LAST]; 105 1.1 jmcneill bool sc_smpsw_valid; 106 1.5 jmcneill 107 1.5 jmcneill struct sysmon_envsys *sc_sme; 108 1.5 jmcneill envsys_data_t sc_sensor[THINKPAD_NSENSORS]; 109 1.8 jmcneill 110 1.8 jmcneill int sc_display_state; 111 1.57 christos 112 1.57 christos #define THINKPAD_BAT_ANY 0 113 1.57 christos #define THINKPAD_BAT_PRIMARY 1 114 1.57 christos #define THINKPAD_BAT_SECONDARY 2 115 1.57 christos #define THINKPAD_BAT_LAST 3 116 1.57 christos 117 1.57 christos tp_batctl_t sc_batctl; 118 1.57 christos tp_sysctl_param_t sc_scparam[THINKPAD_BAT_LAST]; 119 1.1 jmcneill } thinkpad_softc_t; 120 1.1 jmcneill 121 1.1 jmcneill /* Hotkey events */ 122 1.1 jmcneill #define THINKPAD_NOTIFY_FnF1 0x001 123 1.1 jmcneill #define THINKPAD_NOTIFY_LockScreen 0x002 124 1.1 jmcneill #define THINKPAD_NOTIFY_BatteryInfo 0x003 125 1.1 jmcneill #define THINKPAD_NOTIFY_SleepButton 0x004 126 1.1 jmcneill #define THINKPAD_NOTIFY_WirelessSwitch 0x005 127 1.40 spz #define THINKPAD_NOTIFY_wWANSwitch 0x006 128 1.1 jmcneill #define THINKPAD_NOTIFY_DisplayCycle 0x007 129 1.1 jmcneill #define THINKPAD_NOTIFY_PointerSwitch 0x008 130 1.1 jmcneill #define THINKPAD_NOTIFY_EjectButton 0x009 131 1.43 christos #define THINKPAD_NOTIFY_FnF10 0x00a /* XXX: Not seen on T61 */ 132 1.1 jmcneill #define THINKPAD_NOTIFY_FnF11 0x00b 133 1.1 jmcneill #define THINKPAD_NOTIFY_HibernateButton 0x00c 134 1.1 jmcneill #define THINKPAD_NOTIFY_BrightnessUp 0x010 135 1.1 jmcneill #define THINKPAD_NOTIFY_BrightnessDown 0x011 136 1.1 jmcneill #define THINKPAD_NOTIFY_ThinkLight 0x012 137 1.1 jmcneill #define THINKPAD_NOTIFY_Zoom 0x014 138 1.43 christos #define THINKPAD_NOTIFY_VolumeUp 0x015 /* XXX: Not seen on T61 */ 139 1.43 christos #define THINKPAD_NOTIFY_VolumeDown 0x016 /* XXX: Not seen on T61 */ 140 1.43 christos #define THINKPAD_NOTIFY_VolumeMute 0x017 /* XXX: Not seen on T61 */ 141 1.1 jmcneill #define THINKPAD_NOTIFY_ThinkVantage 0x018 142 1.52 riastrad #define THINKPAD_NOTIFY_Star 0x311 143 1.52 riastrad #define THINKPAD_NOTIFY_Scissors 0x312 144 1.52 riastrad #define THINKPAD_NOTIFY_Bluetooth 0x314 145 1.52 riastrad #define THINKPAD_NOTIFY_Keyboard 0x315 146 1.1 jmcneill 147 1.1 jmcneill #define THINKPAD_CMOS_BRIGHTNESS_UP 0x04 148 1.1 jmcneill #define THINKPAD_CMOS_BRIGHTNESS_DOWN 0x05 149 1.1 jmcneill 150 1.50 riastrad #define THINKPAD_HKEY_VERSION_1 0x0100 151 1.50 riastrad #define THINKPAD_HKEY_VERSION_2 0x0200 152 1.2 jmcneill 153 1.8 jmcneill #define THINKPAD_DISPLAY_LCD 0x01 154 1.8 jmcneill #define THINKPAD_DISPLAY_CRT 0x02 155 1.8 jmcneill #define THINKPAD_DISPLAY_DVI 0x08 156 1.8 jmcneill #define THINKPAD_DISPLAY_ALL \ 157 1.8 jmcneill (THINKPAD_DISPLAY_LCD | THINKPAD_DISPLAY_CRT | THINKPAD_DISPLAY_DVI) 158 1.8 jmcneill 159 1.57 christos #define THINKPAD_GET_CHARGE_START "BCTG" 160 1.57 christos #define THINKPAD_SET_CHARGE_START "BCCS" 161 1.57 christos #define THINKPAD_GET_CHARGE_STOP "BCSG" 162 1.57 christos #define THINKPAD_SET_CHARGE_STOP "BCSS" 163 1.57 christos #define THINKPAD_GET_FORCE_DISCHARGE "BDSG" 164 1.57 christos #define THINKPAD_SET_FORCE_DISCHARGE "BDSS" 165 1.57 christos #define THINKPAD_GET_CHARGE_INHIBIT "BICG" 166 1.57 christos #define THINKPAD_SET_CHARGE_INHIBIT "BICS" 167 1.57 christos 168 1.57 christos #define THINKPAD_CALL_ERROR 0x80000000 169 1.57 christos 170 1.46 mlelstv #define THINKPAD_BLUETOOTH_HWPRESENT 0x01 171 1.46 mlelstv #define THINKPAD_BLUETOOTH_RADIOSSW 0x02 172 1.46 mlelstv #define THINKPAD_BLUETOOTH_RESUMECTRL 0x04 173 1.46 mlelstv 174 1.46 mlelstv #define THINKPAD_WWAN_HWPRESENT 0x01 175 1.46 mlelstv #define THINKPAD_WWAN_RADIOSSW 0x02 176 1.46 mlelstv #define THINKPAD_WWAN_RESUMECTRL 0x04 177 1.46 mlelstv 178 1.56 christos #define THINKPAD_UWB_HWPRESENT 0x01 179 1.56 christos #define THINKPAD_UWB_RADIOSSW 0x02 180 1.46 mlelstv 181 1.46 mlelstv #define THINKPAD_RFK_BLUETOOTH 0 182 1.46 mlelstv #define THINKPAD_RFK_WWAN 1 183 1.46 mlelstv #define THINKPAD_RFK_UWB 2 184 1.46 mlelstv 185 1.19 cegger static int thinkpad_match(device_t, cfdata_t, void *); 186 1.1 jmcneill static void thinkpad_attach(device_t, device_t, void *); 187 1.25 jruoho static int thinkpad_detach(device_t, int); 188 1.1 jmcneill 189 1.1 jmcneill static ACPI_STATUS thinkpad_mask_init(thinkpad_softc_t *, uint32_t); 190 1.29 jruoho static void thinkpad_notify_handler(ACPI_HANDLE, uint32_t, void *); 191 1.4 jmcneill static void thinkpad_get_hotkeys(void *); 192 1.1 jmcneill 193 1.16 jmcneill static void thinkpad_sensors_init(thinkpad_softc_t *); 194 1.16 jmcneill static void thinkpad_sensors_refresh(struct sysmon_envsys *, envsys_data_t *); 195 1.5 jmcneill static void thinkpad_temp_refresh(struct sysmon_envsys *, envsys_data_t *); 196 1.16 jmcneill static void thinkpad_fan_refresh(struct sysmon_envsys *, envsys_data_t *); 197 1.5 jmcneill 198 1.46 mlelstv static void thinkpad_uwb_toggle(thinkpad_softc_t *); 199 1.40 spz static void thinkpad_wwan_toggle(thinkpad_softc_t *); 200 1.46 mlelstv static void thinkpad_bluetooth_toggle(thinkpad_softc_t *); 201 1.6 jmcneill 202 1.26 dyoung static bool thinkpad_resume(device_t, const pmf_qual_t *); 203 1.1 jmcneill static void thinkpad_brightness_up(device_t); 204 1.1 jmcneill static void thinkpad_brightness_down(device_t); 205 1.56 christos static uint8_t thinkpad_brightness_read(thinkpad_softc_t *); 206 1.1 jmcneill static void thinkpad_cmos(thinkpad_softc_t *, uint8_t); 207 1.1 jmcneill 208 1.57 christos static void thinkpad_battery_probe_support(device_t); 209 1.57 christos static void thinkpad_battery_sysctl_setup(device_t); 210 1.57 christos 211 1.46 mlelstv CFATTACH_DECL3_NEW(thinkpad, sizeof(thinkpad_softc_t), 212 1.46 mlelstv thinkpad_match, thinkpad_attach, thinkpad_detach, NULL, NULL, NULL, 213 1.55 riastrad 0); 214 1.1 jmcneill 215 1.49 thorpej static const struct device_compatible_entry compat_data[] = { 216 1.49 thorpej { .compat = "IBM0068" }, 217 1.49 thorpej { .compat = "LEN0068" }, 218 1.50 riastrad { .compat = "LEN0268" }, 219 1.49 thorpej DEVICE_COMPAT_EOL 220 1.1 jmcneill }; 221 1.1 jmcneill 222 1.1 jmcneill static int 223 1.19 cegger thinkpad_match(device_t parent, cfdata_t match, void *opaque) 224 1.1 jmcneill { 225 1.1 jmcneill struct acpi_attach_args *aa = (struct acpi_attach_args *)opaque; 226 1.2 jmcneill ACPI_INTEGER ver; 227 1.49 thorpej int ret; 228 1.1 jmcneill 229 1.49 thorpej ret = acpi_compatible_match(aa, compat_data); 230 1.49 thorpej if (ret == 0) 231 1.1 jmcneill return 0; 232 1.1 jmcneill 233 1.50 riastrad /* We only support hotkey versions 0x0100 and 0x0200 */ 234 1.3 jmcneill if (ACPI_FAILURE(acpi_eval_integer(aa->aa_node->ad_handle, "MHKV", 235 1.3 jmcneill &ver))) 236 1.2 jmcneill return 0; 237 1.2 jmcneill 238 1.50 riastrad switch (ver) { 239 1.50 riastrad case THINKPAD_HKEY_VERSION_1: 240 1.50 riastrad case THINKPAD_HKEY_VERSION_2: 241 1.50 riastrad break; 242 1.50 riastrad default: 243 1.2 jmcneill return 0; 244 1.50 riastrad } 245 1.2 jmcneill 246 1.1 jmcneill /* Cool, looks like we're good to go */ 247 1.49 thorpej return ret; 248 1.1 jmcneill } 249 1.1 jmcneill 250 1.1 jmcneill static void 251 1.1 jmcneill thinkpad_attach(device_t parent, device_t self, void *opaque) 252 1.1 jmcneill { 253 1.1 jmcneill thinkpad_softc_t *sc = device_private(self); 254 1.1 jmcneill struct acpi_attach_args *aa = (struct acpi_attach_args *)opaque; 255 1.9 jmcneill struct sysmon_pswitch *psw; 256 1.5 jmcneill device_t curdev; 257 1.20 dyoung deviter_t di; 258 1.1 jmcneill ACPI_STATUS rv; 259 1.1 jmcneill ACPI_INTEGER val; 260 1.9 jmcneill int i; 261 1.1 jmcneill 262 1.36 jruoho sc->sc_dev = self; 263 1.57 christos sc->sc_log = NULL; 264 1.36 jruoho sc->sc_powhdl = NULL; 265 1.37 jruoho sc->sc_cmoshdl = NULL; 266 1.1 jmcneill sc->sc_node = aa->aa_node; 267 1.8 jmcneill sc->sc_display_state = THINKPAD_DISPLAY_LCD; 268 1.1 jmcneill 269 1.1 jmcneill aprint_naive("\n"); 270 1.1 jmcneill aprint_normal("\n"); 271 1.1 jmcneill 272 1.5 jmcneill sc->sc_ecdev = NULL; 273 1.20 dyoung for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); 274 1.56 christos curdev != NULL; curdev = deviter_next(&di)) 275 1.5 jmcneill if (device_is_a(curdev, "acpiecdt") || 276 1.5 jmcneill device_is_a(curdev, "acpiec")) { 277 1.5 jmcneill sc->sc_ecdev = curdev; 278 1.5 jmcneill break; 279 1.5 jmcneill } 280 1.20 dyoung deviter_release(&di); 281 1.20 dyoung 282 1.5 jmcneill if (sc->sc_ecdev) 283 1.18 jmcneill aprint_debug_dev(self, "using EC at %s\n", 284 1.5 jmcneill device_xname(sc->sc_ecdev)); 285 1.5 jmcneill 286 1.53 riastrad /* Query the version number */ 287 1.53 riastrad rv = acpi_eval_integer(aa->aa_node->ad_handle, "MHKV", &sc->sc_ver); 288 1.1 jmcneill if (ACPI_FAILURE(rv)) { 289 1.53 riastrad aprint_error_dev(self, "couldn't evaluate MHKV: %s\n", 290 1.1 jmcneill AcpiFormatException(rv)); 291 1.1 jmcneill goto fail; 292 1.1 jmcneill } 293 1.53 riastrad aprint_normal_dev(self, "version %04x\n", (unsigned)sc->sc_ver); 294 1.53 riastrad 295 1.53 riastrad /* Get the supported event mask */ 296 1.53 riastrad switch (sc->sc_ver) { 297 1.53 riastrad case THINKPAD_HKEY_VERSION_1: 298 1.53 riastrad rv = acpi_eval_integer(sc->sc_node->ad_handle, "MHKA", &val); 299 1.53 riastrad if (ACPI_FAILURE(rv)) { 300 1.53 riastrad aprint_error_dev(self, "couldn't evaluate MHKA: %s\n", 301 1.53 riastrad AcpiFormatException(rv)); 302 1.53 riastrad goto fail; 303 1.53 riastrad } 304 1.53 riastrad break; 305 1.53 riastrad case THINKPAD_HKEY_VERSION_2: { 306 1.53 riastrad ACPI_OBJECT args[1] = { 307 1.53 riastrad [0] = { .Integer = { 308 1.53 riastrad .Type = ACPI_TYPE_INTEGER, 309 1.53 riastrad .Value = 1, /* hotkey events */ 310 1.53 riastrad } }, 311 1.53 riastrad }; 312 1.53 riastrad ACPI_OBJECT_LIST arglist = { 313 1.53 riastrad .Count = __arraycount(args), 314 1.53 riastrad .Pointer = args, 315 1.53 riastrad }; 316 1.53 riastrad ACPI_OBJECT ret; 317 1.53 riastrad ACPI_BUFFER buf = { .Pointer = &ret, .Length = sizeof(ret) }; 318 1.53 riastrad 319 1.53 riastrad rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "MHKA", 320 1.53 riastrad &arglist, &buf); 321 1.53 riastrad if (ACPI_FAILURE(rv)) { 322 1.53 riastrad aprint_error_dev(self, "couldn't evaluate MHKA(1):" 323 1.53 riastrad " %s\n", 324 1.53 riastrad AcpiFormatException(rv)); 325 1.53 riastrad goto fail; 326 1.53 riastrad } 327 1.53 riastrad if (buf.Length == 0 || ret.Type != ACPI_TYPE_INTEGER) { 328 1.53 riastrad aprint_error_dev(self, "failed to evaluate MHKA(1)\n"); 329 1.53 riastrad goto fail; 330 1.53 riastrad } 331 1.53 riastrad val = ret.Integer.Value; 332 1.53 riastrad break; 333 1.53 riastrad } 334 1.53 riastrad default: 335 1.53 riastrad panic("%s: invalid version %jd", device_xname(self), 336 1.53 riastrad (intmax_t)sc->sc_ver); 337 1.53 riastrad } 338 1.1 jmcneill 339 1.1 jmcneill /* Enable all supported events */ 340 1.1 jmcneill rv = thinkpad_mask_init(sc, val); 341 1.1 jmcneill if (ACPI_FAILURE(rv)) { 342 1.1 jmcneill aprint_error_dev(self, "couldn't set event mask: %s\n", 343 1.1 jmcneill AcpiFormatException(rv)); 344 1.1 jmcneill goto fail; 345 1.1 jmcneill } 346 1.1 jmcneill 347 1.30 jruoho (void)acpi_register_notify(sc->sc_node, thinkpad_notify_handler); 348 1.1 jmcneill 349 1.36 jruoho /* 350 1.37 jruoho * Obtain a handle for CMOS commands. This is used by T61. 351 1.37 jruoho */ 352 1.37 jruoho (void)AcpiGetHandle(NULL, "\\UCMS", &sc->sc_cmoshdl); 353 1.37 jruoho 354 1.37 jruoho /* 355 1.36 jruoho * Obtain a handle to the power resource available on many models. 356 1.36 jruoho * Since pmf(9) is not yet integrated with the ACPI power resource 357 1.36 jruoho * code, this must be turned on manually upon resume. Otherwise the 358 1.36 jruoho * system may, for instance, resume from S3 with usb(4) powered down. 359 1.36 jruoho */ 360 1.36 jruoho (void)AcpiGetHandle(NULL, "\\_SB.PCI0.LPC.EC.PUBS", &sc->sc_powhdl); 361 1.36 jruoho 362 1.5 jmcneill /* Register power switches with sysmon */ 363 1.9 jmcneill psw = sc->sc_smpsw; 364 1.1 jmcneill sc->sc_smpsw_valid = true; 365 1.1 jmcneill 366 1.9 jmcneill psw[TP_PSW_SLEEP].smpsw_name = device_xname(self); 367 1.9 jmcneill psw[TP_PSW_SLEEP].smpsw_type = PSWITCH_TYPE_SLEEP; 368 1.1 jmcneill #if notyet 369 1.9 jmcneill psw[TP_PSW_HIBERNATE].smpsw_name = device_xname(self); 370 1.9 jmcneill mpsw[TP_PSW_HIBERNATE].smpsw_type = PSWITCH_TYPE_HIBERNATE; 371 1.1 jmcneill #endif 372 1.9 jmcneill for (i = TP_PSW_DISPLAY_CYCLE; i < TP_PSW_LAST; i++) 373 1.9 jmcneill sc->sc_smpsw[i].smpsw_type = PSWITCH_TYPE_HOTKEY; 374 1.56 christos 375 1.56 christos psw[TP_PSW_DISPLAY_CYCLE].smpsw_name = PSWITCH_HK_DISPLAY_CYCLE; 376 1.56 christos psw[TP_PSW_LOCK_SCREEN].smpsw_name = PSWITCH_HK_LOCK_SCREEN; 377 1.56 christos psw[TP_PSW_BATTERY_INFO].smpsw_name = PSWITCH_HK_BATTERY_INFO; 378 1.56 christos psw[TP_PSW_EJECT_BUTTON].smpsw_name = PSWITCH_HK_EJECT_BUTTON; 379 1.56 christos psw[TP_PSW_ZOOM_BUTTON].smpsw_name = PSWITCH_HK_ZOOM_BUTTON; 380 1.56 christos psw[TP_PSW_VENDOR_BUTTON].smpsw_name = PSWITCH_HK_VENDOR_BUTTON; 381 1.44 christos #ifndef THINKPAD_NORMAL_HOTKEYS 382 1.56 christos psw[TP_PSW_FNF1_BUTTON].smpsw_name = PSWITCH_HK_FNF1_BUTTON; 383 1.56 christos psw[TP_PSW_WIRELESS_BUTTON].smpsw_name = PSWITCH_HK_WIRELESS_BUTTON; 384 1.56 christos psw[TP_PSW_WWAN_BUTTON].smpsw_name = PSWITCH_HK_WWAN_BUTTON; 385 1.56 christos psw[TP_PSW_POINTER_BUTTON].smpsw_name = PSWITCH_HK_POINTER_BUTTON; 386 1.56 christos psw[TP_PSW_FNF10_BUTTON].smpsw_name = PSWITCH_HK_FNF10_BUTTON; 387 1.56 christos psw[TP_PSW_FNF11_BUTTON].smpsw_name = PSWITCH_HK_FNF11_BUTTON; 388 1.56 christos psw[TP_PSW_BRIGHTNESS_UP].smpsw_name = PSWITCH_HK_BRIGHTNESS_UP; 389 1.56 christos psw[TP_PSW_BRIGHTNESS_DOWN].smpsw_name = PSWITCH_HK_BRIGHTNESS_DOWN; 390 1.56 christos psw[TP_PSW_THINKLIGHT].smpsw_name = PSWITCH_HK_THINKLIGHT; 391 1.56 christos psw[TP_PSW_VOLUME_UP].smpsw_name = PSWITCH_HK_VOLUME_UP; 392 1.56 christos psw[TP_PSW_VOLUME_DOWN].smpsw_name = PSWITCH_HK_VOLUME_DOWN; 393 1.56 christos psw[TP_PSW_VOLUME_MUTE].smpsw_name = PSWITCH_HK_VOLUME_MUTE; 394 1.56 christos psw[TP_PSW_STAR_BUTTON].smpsw_name = PSWITCH_HK_STAR_BUTTON; 395 1.56 christos psw[TP_PSW_SCISSORS_BUTTON].smpsw_name = PSWITCH_HK_SCISSORS_BUTTON; 396 1.56 christos psw[TP_PSW_BLUETOOTH_BUTTON].smpsw_name = PSWITCH_HK_BLUETOOTH_BUTTON; 397 1.56 christos psw[TP_PSW_KEYBOARD_BUTTON].smpsw_name = PSWITCH_HK_KEYBOARD_BUTTON; 398 1.44 christos #endif /* THINKPAD_NORMAL_HOTKEYS */ 399 1.9 jmcneill 400 1.9 jmcneill for (i = 0; i < TP_PSW_LAST; i++) { 401 1.9 jmcneill /* not supported yet */ 402 1.9 jmcneill if (i == TP_PSW_HIBERNATE) 403 1.9 jmcneill continue; 404 1.9 jmcneill if (sysmon_pswitch_register(&sc->sc_smpsw[i]) != 0) { 405 1.9 jmcneill aprint_error_dev(self, 406 1.9 jmcneill "couldn't register with sysmon\n"); 407 1.9 jmcneill sc->sc_smpsw_valid = false; 408 1.9 jmcneill break; 409 1.9 jmcneill } 410 1.1 jmcneill } 411 1.1 jmcneill 412 1.16 jmcneill /* Register temperature and fan sensors with envsys */ 413 1.16 jmcneill thinkpad_sensors_init(sc); 414 1.5 jmcneill 415 1.57 christos /* Probe supported battery charge/control operations */ 416 1.57 christos thinkpad_battery_probe_support(self); 417 1.57 christos 418 1.57 christos if (sc->sc_batctl.have_any) { 419 1.57 christos for (i = 0; i < THINKPAD_BAT_LAST; i++) { 420 1.57 christos sc->sc_scparam[i].sp_dev = self; 421 1.57 christos sc->sc_scparam[i].sp_bat = i; 422 1.57 christos } 423 1.57 christos thinkpad_battery_sysctl_setup(self); 424 1.57 christos } 425 1.57 christos 426 1.1 jmcneill fail: 427 1.11 jmcneill if (!pmf_device_register(self, NULL, thinkpad_resume)) 428 1.1 jmcneill aprint_error_dev(self, "couldn't establish power handler\n"); 429 1.1 jmcneill if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP, 430 1.1 jmcneill thinkpad_brightness_up, true)) 431 1.1 jmcneill aprint_error_dev(self, "couldn't register event handler\n"); 432 1.1 jmcneill if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, 433 1.1 jmcneill thinkpad_brightness_down, true)) 434 1.1 jmcneill aprint_error_dev(self, "couldn't register event handler\n"); 435 1.1 jmcneill } 436 1.1 jmcneill 437 1.25 jruoho static int 438 1.25 jruoho thinkpad_detach(device_t self, int flags) 439 1.25 jruoho { 440 1.25 jruoho struct thinkpad_softc *sc = device_private(self); 441 1.25 jruoho int i; 442 1.25 jruoho 443 1.30 jruoho acpi_deregister_notify(sc->sc_node); 444 1.25 jruoho 445 1.25 jruoho for (i = 0; i < TP_PSW_LAST; i++) 446 1.25 jruoho sysmon_pswitch_unregister(&sc->sc_smpsw[i]); 447 1.25 jruoho 448 1.25 jruoho if (sc->sc_sme != NULL) 449 1.25 jruoho sysmon_envsys_unregister(sc->sc_sme); 450 1.25 jruoho 451 1.57 christos if (sc->sc_log != NULL) 452 1.57 christos sysctl_teardown(&sc->sc_log); 453 1.57 christos 454 1.25 jruoho pmf_device_deregister(self); 455 1.25 jruoho 456 1.25 jruoho pmf_event_deregister(self, PMFE_DISPLAY_BRIGHTNESS_UP, 457 1.25 jruoho thinkpad_brightness_up, true); 458 1.25 jruoho 459 1.25 jruoho pmf_event_deregister(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, 460 1.25 jruoho thinkpad_brightness_down, true); 461 1.25 jruoho 462 1.25 jruoho return 0; 463 1.25 jruoho } 464 1.25 jruoho 465 1.1 jmcneill static void 466 1.29 jruoho thinkpad_notify_handler(ACPI_HANDLE hdl, uint32_t notify, void *opaque) 467 1.1 jmcneill { 468 1.30 jruoho device_t self = opaque; 469 1.30 jruoho thinkpad_softc_t *sc; 470 1.30 jruoho 471 1.30 jruoho sc = device_private(self); 472 1.30 jruoho 473 1.1 jmcneill if (notify != 0x80) { 474 1.1 jmcneill aprint_debug_dev(self, "unknown notify 0x%02x\n", notify); 475 1.1 jmcneill return; 476 1.1 jmcneill } 477 1.1 jmcneill 478 1.30 jruoho (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, thinkpad_get_hotkeys, sc); 479 1.4 jmcneill } 480 1.4 jmcneill 481 1.51 riastrad SDT_PROBE_DEFINE2(sdt, thinkpad, hotkey, MHKP, 482 1.51 riastrad "struct thinkpad_softc *"/*sc*/, 483 1.51 riastrad "ACPI_INTEGER"/*val*/); 484 1.51 riastrad 485 1.4 jmcneill static void 486 1.4 jmcneill thinkpad_get_hotkeys(void *opaque) 487 1.4 jmcneill { 488 1.4 jmcneill thinkpad_softc_t *sc = (thinkpad_softc_t *)opaque; 489 1.4 jmcneill device_t self = sc->sc_dev; 490 1.4 jmcneill ACPI_STATUS rv; 491 1.4 jmcneill ACPI_INTEGER val; 492 1.4 jmcneill int type, event; 493 1.32 jruoho 494 1.2 jmcneill for (;;) { 495 1.2 jmcneill rv = acpi_eval_integer(sc->sc_node->ad_handle, "MHKP", &val); 496 1.2 jmcneill if (ACPI_FAILURE(rv)) { 497 1.2 jmcneill aprint_error_dev(self, "couldn't evaluate MHKP: %s\n", 498 1.2 jmcneill AcpiFormatException(rv)); 499 1.2 jmcneill return; 500 1.2 jmcneill } 501 1.51 riastrad SDT_PROBE2(sdt, thinkpad, hotkey, MHKP, sc, val); 502 1.2 jmcneill 503 1.2 jmcneill if (val == 0) 504 1.2 jmcneill return; 505 1.2 jmcneill 506 1.2 jmcneill type = (val & 0xf000) >> 12; 507 1.2 jmcneill event = val & 0x0fff; 508 1.2 jmcneill 509 1.2 jmcneill if (type != 1) 510 1.2 jmcneill /* Only type 1 events are supported for now */ 511 1.2 jmcneill continue; 512 1.2 jmcneill 513 1.2 jmcneill switch (event) { 514 1.2 jmcneill case THINKPAD_NOTIFY_BrightnessUp: 515 1.2 jmcneill thinkpad_brightness_up(self); 516 1.44 christos #ifndef THINKPAD_NORMAL_HOTKEYS 517 1.43 christos if (sc->sc_smpsw_valid == false) 518 1.43 christos break; 519 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_BRIGHTNESS_UP], 520 1.43 christos PSWITCH_EVENT_PRESSED); 521 1.43 christos #endif 522 1.2 jmcneill break; 523 1.2 jmcneill case THINKPAD_NOTIFY_BrightnessDown: 524 1.2 jmcneill thinkpad_brightness_down(self); 525 1.44 christos #ifndef THINKPAD_NORMAL_HOTKEYS 526 1.43 christos if (sc->sc_smpsw_valid == false) 527 1.43 christos break; 528 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_BRIGHTNESS_DOWN], 529 1.43 christos PSWITCH_EVENT_PRESSED); 530 1.43 christos #endif 531 1.2 jmcneill break; 532 1.6 jmcneill case THINKPAD_NOTIFY_WirelessSwitch: 533 1.46 mlelstv thinkpad_uwb_toggle(sc); 534 1.46 mlelstv thinkpad_wwan_toggle(sc); 535 1.46 mlelstv thinkpad_bluetooth_toggle(sc); 536 1.44 christos #ifndef THINKPAD_NORMAL_HOTKEYS 537 1.43 christos if (sc->sc_smpsw_valid == false) 538 1.43 christos break; 539 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_WIRELESS_BUTTON], 540 1.43 christos PSWITCH_EVENT_PRESSED); 541 1.43 christos #endif 542 1.6 jmcneill break; 543 1.52 riastrad case THINKPAD_NOTIFY_Bluetooth: 544 1.52 riastrad thinkpad_bluetooth_toggle(sc); 545 1.52 riastrad #ifndef THINKPAD_NORMAL_HOTKEYS 546 1.52 riastrad if (sc->sc_smpsw_valid == false) 547 1.52 riastrad break; 548 1.52 riastrad sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_BLUETOOTH_BUTTON], 549 1.52 riastrad PSWITCH_EVENT_PRESSED); 550 1.52 riastrad #endif 551 1.52 riastrad break; 552 1.40 spz case THINKPAD_NOTIFY_wWANSwitch: 553 1.40 spz thinkpad_wwan_toggle(sc); 554 1.44 christos #ifndef THINKPAD_NORMAL_HOTKEYS 555 1.43 christos if (sc->sc_smpsw_valid == false) 556 1.43 christos break; 557 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_WWAN_BUTTON], 558 1.43 christos PSWITCH_EVENT_PRESSED); 559 1.43 christos #endif 560 1.40 spz break; 561 1.2 jmcneill case THINKPAD_NOTIFY_SleepButton: 562 1.2 jmcneill if (sc->sc_smpsw_valid == false) 563 1.2 jmcneill break; 564 1.2 jmcneill sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_SLEEP], 565 1.2 jmcneill PSWITCH_EVENT_PRESSED); 566 1.2 jmcneill break; 567 1.2 jmcneill case THINKPAD_NOTIFY_HibernateButton: 568 1.1 jmcneill #if notyet 569 1.2 jmcneill if (sc->sc_smpsw_valid == false) 570 1.2 jmcneill break; 571 1.2 jmcneill sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_HIBERNATE], 572 1.2 jmcneill PSWITCH_EVENT_PRESSED); 573 1.6 jmcneill #endif 574 1.1 jmcneill break; 575 1.9 jmcneill case THINKPAD_NOTIFY_DisplayCycle: 576 1.9 jmcneill if (sc->sc_smpsw_valid == false) 577 1.9 jmcneill break; 578 1.9 jmcneill sysmon_pswitch_event( 579 1.9 jmcneill &sc->sc_smpsw[TP_PSW_DISPLAY_CYCLE], 580 1.9 jmcneill PSWITCH_EVENT_PRESSED); 581 1.9 jmcneill break; 582 1.2 jmcneill case THINKPAD_NOTIFY_LockScreen: 583 1.9 jmcneill if (sc->sc_smpsw_valid == false) 584 1.9 jmcneill break; 585 1.9 jmcneill sysmon_pswitch_event( 586 1.9 jmcneill &sc->sc_smpsw[TP_PSW_LOCK_SCREEN], 587 1.9 jmcneill PSWITCH_EVENT_PRESSED); 588 1.9 jmcneill break; 589 1.2 jmcneill case THINKPAD_NOTIFY_BatteryInfo: 590 1.9 jmcneill if (sc->sc_smpsw_valid == false) 591 1.9 jmcneill break; 592 1.9 jmcneill sysmon_pswitch_event( 593 1.9 jmcneill &sc->sc_smpsw[TP_PSW_BATTERY_INFO], 594 1.9 jmcneill PSWITCH_EVENT_PRESSED); 595 1.9 jmcneill break; 596 1.9 jmcneill case THINKPAD_NOTIFY_EjectButton: 597 1.9 jmcneill if (sc->sc_smpsw_valid == false) 598 1.9 jmcneill break; 599 1.9 jmcneill sysmon_pswitch_event( 600 1.9 jmcneill &sc->sc_smpsw[TP_PSW_EJECT_BUTTON], 601 1.9 jmcneill PSWITCH_EVENT_PRESSED); 602 1.9 jmcneill break; 603 1.9 jmcneill case THINKPAD_NOTIFY_Zoom: 604 1.9 jmcneill if (sc->sc_smpsw_valid == false) 605 1.9 jmcneill break; 606 1.9 jmcneill sysmon_pswitch_event( 607 1.9 jmcneill &sc->sc_smpsw[TP_PSW_ZOOM_BUTTON], 608 1.9 jmcneill PSWITCH_EVENT_PRESSED); 609 1.9 jmcneill break; 610 1.9 jmcneill case THINKPAD_NOTIFY_ThinkVantage: 611 1.9 jmcneill if (sc->sc_smpsw_valid == false) 612 1.9 jmcneill break; 613 1.9 jmcneill sysmon_pswitch_event( 614 1.9 jmcneill &sc->sc_smpsw[TP_PSW_VENDOR_BUTTON], 615 1.9 jmcneill PSWITCH_EVENT_PRESSED); 616 1.9 jmcneill break; 617 1.44 christos #ifndef THINKPAD_NORMAL_HOTKEYS 618 1.43 christos case THINKPAD_NOTIFY_FnF1: 619 1.43 christos if (sc->sc_smpsw_valid == false) 620 1.43 christos break; 621 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_FNF1_BUTTON], 622 1.43 christos PSWITCH_EVENT_PRESSED); 623 1.43 christos break; 624 1.43 christos case THINKPAD_NOTIFY_PointerSwitch: 625 1.43 christos if (sc->sc_smpsw_valid == false) 626 1.43 christos break; 627 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_POINTER_BUTTON], 628 1.43 christos PSWITCH_EVENT_PRESSED); 629 1.43 christos break; 630 1.43 christos case THINKPAD_NOTIFY_FnF11: 631 1.43 christos if (sc->sc_smpsw_valid == false) 632 1.43 christos break; 633 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_FNF11_BUTTON], 634 1.43 christos PSWITCH_EVENT_PRESSED); 635 1.43 christos break; 636 1.43 christos case THINKPAD_NOTIFY_ThinkLight: 637 1.43 christos if (sc->sc_smpsw_valid == false) 638 1.43 christos break; 639 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_THINKLIGHT], 640 1.43 christos PSWITCH_EVENT_PRESSED); 641 1.43 christos break; 642 1.43 christos /* 643 1.43 christos * For some reason the next four aren't seen on my T61. 644 1.43 christos */ 645 1.43 christos case THINKPAD_NOTIFY_FnF10: 646 1.43 christos if (sc->sc_smpsw_valid == false) 647 1.43 christos break; 648 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_FNF10_BUTTON], 649 1.43 christos PSWITCH_EVENT_PRESSED); 650 1.43 christos break; 651 1.43 christos case THINKPAD_NOTIFY_VolumeUp: 652 1.43 christos if (sc->sc_smpsw_valid == false) 653 1.43 christos break; 654 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_VOLUME_UP], 655 1.43 christos PSWITCH_EVENT_PRESSED); 656 1.43 christos break; 657 1.43 christos case THINKPAD_NOTIFY_VolumeDown: 658 1.43 christos if (sc->sc_smpsw_valid == false) 659 1.43 christos break; 660 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_VOLUME_DOWN], 661 1.43 christos PSWITCH_EVENT_PRESSED); 662 1.43 christos break; 663 1.43 christos case THINKPAD_NOTIFY_VolumeMute: 664 1.43 christos if (sc->sc_smpsw_valid == false) 665 1.43 christos break; 666 1.43 christos sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_VOLUME_MUTE], 667 1.43 christos PSWITCH_EVENT_PRESSED); 668 1.43 christos break; 669 1.52 riastrad case THINKPAD_NOTIFY_Star: 670 1.52 riastrad if (sc->sc_smpsw_valid == false) 671 1.52 riastrad break; 672 1.52 riastrad sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_STAR_BUTTON], 673 1.52 riastrad PSWITCH_EVENT_PRESSED); 674 1.52 riastrad break; 675 1.52 riastrad case THINKPAD_NOTIFY_Scissors: 676 1.52 riastrad if (sc->sc_smpsw_valid == false) 677 1.52 riastrad break; 678 1.52 riastrad sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_SCISSORS_BUTTON], 679 1.52 riastrad PSWITCH_EVENT_PRESSED); 680 1.52 riastrad break; 681 1.52 riastrad case THINKPAD_NOTIFY_Keyboard: 682 1.52 riastrad if (sc->sc_smpsw_valid == false) 683 1.52 riastrad break; 684 1.52 riastrad sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_KEYBOARD_BUTTON], 685 1.52 riastrad PSWITCH_EVENT_PRESSED); 686 1.52 riastrad break; 687 1.43 christos #else 688 1.9 jmcneill case THINKPAD_NOTIFY_FnF1: 689 1.2 jmcneill case THINKPAD_NOTIFY_PointerSwitch: 690 1.2 jmcneill case THINKPAD_NOTIFY_FnF10: 691 1.2 jmcneill case THINKPAD_NOTIFY_FnF11: 692 1.2 jmcneill case THINKPAD_NOTIFY_ThinkLight: 693 1.23 jruoho case THINKPAD_NOTIFY_VolumeUp: 694 1.23 jruoho case THINKPAD_NOTIFY_VolumeDown: 695 1.23 jruoho case THINKPAD_NOTIFY_VolumeMute: 696 1.52 riastrad case THINKPAD_NOTIFY_Star: 697 1.52 riastrad case THINKPAD_NOTIFY_Scissors: 698 1.52 riastrad case THINKPAD_NOTIFY_Keyboard: 699 1.2 jmcneill /* XXXJDM we should deliver hotkeys as keycodes */ 700 1.2 jmcneill break; 701 1.44 christos #endif /* THINKPAD_NORMAL_HOTKEYS */ 702 1.2 jmcneill default: 703 1.2 jmcneill aprint_debug_dev(self, "notify event 0x%03x\n", event); 704 1.2 jmcneill break; 705 1.2 jmcneill } 706 1.1 jmcneill } 707 1.1 jmcneill } 708 1.1 jmcneill 709 1.1 jmcneill static ACPI_STATUS 710 1.1 jmcneill thinkpad_mask_init(thinkpad_softc_t *sc, uint32_t mask) 711 1.1 jmcneill { 712 1.1 jmcneill ACPI_OBJECT param[2]; 713 1.1 jmcneill ACPI_OBJECT_LIST params; 714 1.1 jmcneill ACPI_STATUS rv; 715 1.1 jmcneill int i; 716 1.1 jmcneill 717 1.1 jmcneill /* Update hotkey mask */ 718 1.1 jmcneill params.Count = 2; 719 1.1 jmcneill params.Pointer = param; 720 1.1 jmcneill param[0].Type = param[1].Type = ACPI_TYPE_INTEGER; 721 1.1 jmcneill 722 1.1 jmcneill for (i = 0; i < 32; i++) { 723 1.1 jmcneill param[0].Integer.Value = i + 1; 724 1.47 msaitoh param[1].Integer.Value = ((__BIT(i) & mask) != 0); 725 1.1 jmcneill 726 1.1 jmcneill rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "MHKM", 727 1.1 jmcneill ¶ms, NULL); 728 1.1 jmcneill if (ACPI_FAILURE(rv)) 729 1.1 jmcneill return rv; 730 1.1 jmcneill } 731 1.1 jmcneill 732 1.1 jmcneill /* Enable hotkey events */ 733 1.21 cegger rv = acpi_eval_set_integer(sc->sc_node->ad_handle, "MHKC", 1); 734 1.1 jmcneill if (ACPI_FAILURE(rv)) { 735 1.1 jmcneill aprint_error_dev(sc->sc_dev, "couldn't enable hotkeys: %s\n", 736 1.1 jmcneill AcpiFormatException(rv)); 737 1.1 jmcneill return rv; 738 1.1 jmcneill } 739 1.1 jmcneill 740 1.4 jmcneill /* Claim ownership of brightness control */ 741 1.21 cegger (void)acpi_eval_set_integer(sc->sc_node->ad_handle, "PWMS", 0); 742 1.4 jmcneill 743 1.1 jmcneill return AE_OK; 744 1.1 jmcneill } 745 1.1 jmcneill 746 1.5 jmcneill static void 747 1.16 jmcneill thinkpad_sensors_init(thinkpad_softc_t *sc) 748 1.5 jmcneill { 749 1.25 jruoho int i, j; 750 1.5 jmcneill 751 1.5 jmcneill if (sc->sc_ecdev == NULL) 752 1.5 jmcneill return; /* no chance of this working */ 753 1.5 jmcneill 754 1.5 jmcneill sc->sc_sme = sysmon_envsys_create(); 755 1.25 jruoho 756 1.25 jruoho for (i = j = 0; i < THINKPAD_NTEMPSENSORS; i++) { 757 1.25 jruoho 758 1.5 jmcneill sc->sc_sensor[i].units = ENVSYS_STEMP; 759 1.39 pgoyette sc->sc_sensor[i].state = ENVSYS_SINVALID; 760 1.41 jruoho sc->sc_sensor[i].flags = ENVSYS_FHAS_ENTROPY; 761 1.5 jmcneill 762 1.25 jruoho (void)snprintf(sc->sc_sensor[i].desc, 763 1.32 jruoho sizeof(sc->sc_sensor[i].desc), "temperature %d", i); 764 1.25 jruoho 765 1.25 jruoho if (sysmon_envsys_sensor_attach(sc->sc_sme, 766 1.25 jruoho &sc->sc_sensor[i]) != 0) 767 1.25 jruoho goto fail; 768 1.25 jruoho } 769 1.25 jruoho 770 1.25 jruoho for (i = THINKPAD_NTEMPSENSORS; i < THINKPAD_NSENSORS; i++, j++) { 771 1.25 jruoho 772 1.16 jmcneill sc->sc_sensor[i].units = ENVSYS_SFANRPM; 773 1.39 pgoyette sc->sc_sensor[i].state = ENVSYS_SINVALID; 774 1.41 jruoho sc->sc_sensor[i].flags = ENVSYS_FHAS_ENTROPY; 775 1.16 jmcneill 776 1.25 jruoho (void)snprintf(sc->sc_sensor[i].desc, 777 1.32 jruoho sizeof(sc->sc_sensor[i].desc), "fan speed %d", j); 778 1.25 jruoho 779 1.25 jruoho if (sysmon_envsys_sensor_attach(sc->sc_sme, 780 1.25 jruoho &sc->sc_sensor[i]) != 0) 781 1.25 jruoho goto fail; 782 1.16 jmcneill } 783 1.5 jmcneill 784 1.5 jmcneill sc->sc_sme->sme_name = device_xname(sc->sc_dev); 785 1.5 jmcneill sc->sc_sme->sme_cookie = sc; 786 1.16 jmcneill sc->sc_sme->sme_refresh = thinkpad_sensors_refresh; 787 1.5 jmcneill 788 1.25 jruoho if (sysmon_envsys_register(sc->sc_sme) != 0) 789 1.25 jruoho goto fail; 790 1.25 jruoho 791 1.25 jruoho return; 792 1.25 jruoho 793 1.25 jruoho fail: 794 1.25 jruoho aprint_error_dev(sc->sc_dev, "failed to initialize sysmon\n"); 795 1.25 jruoho sysmon_envsys_destroy(sc->sc_sme); 796 1.25 jruoho sc->sc_sme = NULL; 797 1.5 jmcneill } 798 1.5 jmcneill 799 1.5 jmcneill static void 800 1.16 jmcneill thinkpad_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 801 1.16 jmcneill { 802 1.16 jmcneill switch (edata->units) { 803 1.16 jmcneill case ENVSYS_STEMP: 804 1.16 jmcneill thinkpad_temp_refresh(sme, edata); 805 1.16 jmcneill break; 806 1.16 jmcneill case ENVSYS_SFANRPM: 807 1.16 jmcneill thinkpad_fan_refresh(sme, edata); 808 1.16 jmcneill break; 809 1.16 jmcneill default: 810 1.16 jmcneill break; 811 1.16 jmcneill } 812 1.16 jmcneill } 813 1.16 jmcneill 814 1.16 jmcneill static void 815 1.5 jmcneill thinkpad_temp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 816 1.5 jmcneill { 817 1.5 jmcneill thinkpad_softc_t *sc = sme->sme_cookie; 818 1.5 jmcneill char sname[5] = "TMP?"; 819 1.5 jmcneill ACPI_INTEGER val; 820 1.5 jmcneill ACPI_STATUS rv; 821 1.5 jmcneill int temp; 822 1.5 jmcneill 823 1.5 jmcneill sname[3] = '0' + edata->sensor; 824 1.5 jmcneill rv = acpi_eval_integer(acpiec_get_handle(sc->sc_ecdev), sname, &val); 825 1.5 jmcneill if (ACPI_FAILURE(rv)) { 826 1.5 jmcneill edata->state = ENVSYS_SINVALID; 827 1.5 jmcneill return; 828 1.5 jmcneill } 829 1.5 jmcneill temp = (int)val; 830 1.5 jmcneill if (temp > 127 || temp < -127) { 831 1.5 jmcneill edata->state = ENVSYS_SINVALID; 832 1.5 jmcneill return; 833 1.5 jmcneill } 834 1.5 jmcneill 835 1.5 jmcneill edata->value_cur = temp * 1000000 + 273150000; 836 1.5 jmcneill edata->state = ENVSYS_SVALID; 837 1.5 jmcneill } 838 1.5 jmcneill 839 1.6 jmcneill static void 840 1.16 jmcneill thinkpad_fan_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 841 1.16 jmcneill { 842 1.16 jmcneill thinkpad_softc_t *sc = sme->sme_cookie; 843 1.16 jmcneill ACPI_INTEGER lo; 844 1.16 jmcneill ACPI_INTEGER hi; 845 1.16 jmcneill ACPI_STATUS rv; 846 1.16 jmcneill int rpm; 847 1.16 jmcneill 848 1.16 jmcneill /* 849 1.16 jmcneill * Read the low byte first to avoid a firmware bug. 850 1.16 jmcneill */ 851 1.16 jmcneill rv = acpiec_bus_read(sc->sc_ecdev, 0x84, &lo, 1); 852 1.16 jmcneill if (ACPI_FAILURE(rv)) { 853 1.16 jmcneill edata->state = ENVSYS_SINVALID; 854 1.16 jmcneill return; 855 1.16 jmcneill } 856 1.16 jmcneill rv = acpiec_bus_read(sc->sc_ecdev, 0x85, &hi, 1); 857 1.16 jmcneill if (ACPI_FAILURE(rv)) { 858 1.16 jmcneill edata->state = ENVSYS_SINVALID; 859 1.16 jmcneill return; 860 1.16 jmcneill } 861 1.48 mlelstv 862 1.16 jmcneill rpm = ((((int)hi) << 8) | ((int)lo)); 863 1.16 jmcneill if (rpm < 0) { 864 1.16 jmcneill edata->state = ENVSYS_SINVALID; 865 1.16 jmcneill return; 866 1.16 jmcneill } 867 1.16 jmcneill 868 1.16 jmcneill edata->value_cur = rpm; 869 1.16 jmcneill edata->state = ENVSYS_SVALID; 870 1.16 jmcneill } 871 1.16 jmcneill 872 1.16 jmcneill static void 873 1.46 mlelstv thinkpad_bluetooth_toggle(thinkpad_softc_t *sc) 874 1.6 jmcneill { 875 1.46 mlelstv ACPI_BUFFER buf; 876 1.46 mlelstv ACPI_OBJECT retobj; 877 1.46 mlelstv ACPI_OBJECT param[1]; 878 1.46 mlelstv ACPI_OBJECT_LIST params; 879 1.46 mlelstv ACPI_STATUS rv; 880 1.46 mlelstv 881 1.7 jmcneill /* Ignore return value, as the hardware may not support bluetooth */ 882 1.46 mlelstv rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "BTGL", NULL, NULL); 883 1.46 mlelstv if (!ACPI_FAILURE(rv)) 884 1.46 mlelstv return; 885 1.46 mlelstv 886 1.46 mlelstv buf.Pointer = &retobj; 887 1.46 mlelstv buf.Length = sizeof(retobj); 888 1.46 mlelstv 889 1.46 mlelstv rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "GBDC", NULL, &buf); 890 1.46 mlelstv if (ACPI_FAILURE(rv)) 891 1.46 mlelstv return; 892 1.46 mlelstv 893 1.46 mlelstv params.Count = 1; 894 1.46 mlelstv params.Pointer = param; 895 1.46 mlelstv param[0].Type = ACPI_TYPE_INTEGER; 896 1.46 mlelstv param[0].Integer.Value = 897 1.46 mlelstv (retobj.Integer.Value & THINKPAD_BLUETOOTH_RADIOSSW) == 0 898 1.46 mlelstv ? THINKPAD_BLUETOOTH_RADIOSSW | THINKPAD_BLUETOOTH_RESUMECTRL 899 1.46 mlelstv : 0; 900 1.46 mlelstv 901 1.46 mlelstv (void)AcpiEvaluateObject(sc->sc_node->ad_handle, "SBDC", ¶ms, NULL); 902 1.6 jmcneill } 903 1.6 jmcneill 904 1.40 spz static void 905 1.40 spz thinkpad_wwan_toggle(thinkpad_softc_t *sc) 906 1.40 spz { 907 1.46 mlelstv ACPI_BUFFER buf; 908 1.46 mlelstv ACPI_OBJECT retobj; 909 1.46 mlelstv ACPI_OBJECT param[1]; 910 1.46 mlelstv ACPI_OBJECT_LIST params; 911 1.46 mlelstv ACPI_STATUS rv; 912 1.46 mlelstv 913 1.46 mlelstv buf.Pointer = &retobj; 914 1.46 mlelstv buf.Length = sizeof(retobj); 915 1.46 mlelstv 916 1.46 mlelstv rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "GWAN", NULL, &buf); 917 1.46 mlelstv if (ACPI_FAILURE(rv)) 918 1.46 mlelstv return; 919 1.46 mlelstv 920 1.46 mlelstv params.Count = 1; 921 1.46 mlelstv params.Pointer = param; 922 1.46 mlelstv param[0].Type = ACPI_TYPE_INTEGER; 923 1.46 mlelstv param[0].Integer.Value = 924 1.46 mlelstv (retobj.Integer.Value & THINKPAD_WWAN_RADIOSSW) == 0 925 1.46 mlelstv ? THINKPAD_WWAN_RADIOSSW | THINKPAD_WWAN_RESUMECTRL 926 1.46 mlelstv : 0; 927 1.46 mlelstv 928 1.46 mlelstv (void)AcpiEvaluateObject(sc->sc_node->ad_handle, "SWAN", ¶ms, NULL); 929 1.46 mlelstv } 930 1.46 mlelstv 931 1.46 mlelstv static void 932 1.46 mlelstv thinkpad_uwb_toggle(thinkpad_softc_t *sc) 933 1.46 mlelstv { 934 1.46 mlelstv ACPI_BUFFER buf; 935 1.46 mlelstv ACPI_OBJECT retobj; 936 1.46 mlelstv ACPI_OBJECT param[1]; 937 1.46 mlelstv ACPI_OBJECT_LIST params; 938 1.46 mlelstv ACPI_STATUS rv; 939 1.46 mlelstv 940 1.46 mlelstv buf.Pointer = &retobj; 941 1.46 mlelstv buf.Length = sizeof(retobj); 942 1.46 mlelstv 943 1.46 mlelstv rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "GUWB", NULL, &buf); 944 1.46 mlelstv if (ACPI_FAILURE(rv)) 945 1.46 mlelstv return; 946 1.46 mlelstv 947 1.46 mlelstv params.Count = 1; 948 1.46 mlelstv params.Pointer = param; 949 1.46 mlelstv param[0].Type = ACPI_TYPE_INTEGER; 950 1.46 mlelstv param[0].Integer.Value = 951 1.46 mlelstv (retobj.Integer.Value & THINKPAD_UWB_RADIOSSW) == 0 952 1.46 mlelstv ? THINKPAD_UWB_RADIOSSW 953 1.46 mlelstv : 0; 954 1.46 mlelstv 955 1.46 mlelstv (void)AcpiEvaluateObject(sc->sc_node->ad_handle, "SUWB", ¶ms, NULL); 956 1.40 spz } 957 1.40 spz 958 1.1 jmcneill static uint8_t 959 1.1 jmcneill thinkpad_brightness_read(thinkpad_softc_t *sc) 960 1.1 jmcneill { 961 1.33 jmcneill uint32_t val = 0; 962 1.33 jmcneill 963 1.33 jmcneill AcpiOsWritePort(IO_RTC, 0x6c, 8); 964 1.33 jmcneill AcpiOsReadPort(IO_RTC + 1, &val, 8); 965 1.33 jmcneill 966 1.33 jmcneill return val & 7; 967 1.1 jmcneill } 968 1.1 jmcneill 969 1.1 jmcneill static void 970 1.1 jmcneill thinkpad_brightness_up(device_t self) 971 1.1 jmcneill { 972 1.1 jmcneill thinkpad_softc_t *sc = device_private(self); 973 1.1 jmcneill 974 1.1 jmcneill if (thinkpad_brightness_read(sc) == 7) 975 1.1 jmcneill return; 976 1.37 jruoho 977 1.1 jmcneill thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_UP); 978 1.1 jmcneill } 979 1.1 jmcneill 980 1.1 jmcneill static void 981 1.1 jmcneill thinkpad_brightness_down(device_t self) 982 1.1 jmcneill { 983 1.1 jmcneill thinkpad_softc_t *sc = device_private(self); 984 1.1 jmcneill 985 1.1 jmcneill if (thinkpad_brightness_read(sc) == 0) 986 1.1 jmcneill return; 987 1.37 jruoho 988 1.1 jmcneill thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_DOWN); 989 1.1 jmcneill } 990 1.1 jmcneill 991 1.1 jmcneill static void 992 1.1 jmcneill thinkpad_cmos(thinkpad_softc_t *sc, uint8_t cmd) 993 1.1 jmcneill { 994 1.1 jmcneill ACPI_STATUS rv; 995 1.1 jmcneill 996 1.37 jruoho if (sc->sc_cmoshdl == NULL) 997 1.1 jmcneill return; 998 1.32 jruoho 999 1.21 cegger rv = acpi_eval_set_integer(sc->sc_cmoshdl, NULL, cmd); 1000 1.37 jruoho 1001 1.1 jmcneill if (ACPI_FAILURE(rv)) 1002 1.37 jruoho aprint_error_dev(sc->sc_dev, "couldn't evaluate CMOS: %s\n", 1003 1.1 jmcneill AcpiFormatException(rv)); 1004 1.1 jmcneill } 1005 1.11 jmcneill 1006 1.57 christos static uint32_t 1007 1.57 christos thinkpad_call_method(device_t self, const char *path, uint32_t arg) 1008 1.57 christos { 1009 1.57 christos thinkpad_softc_t *sc = device_private(self); 1010 1.57 christos ACPI_HANDLE handle = sc->sc_node->ad_handle; 1011 1.57 christos ACPI_OBJECT args[1]; 1012 1.57 christos ACPI_OBJECT_LIST arg_list; 1013 1.57 christos ACPI_OBJECT rval; 1014 1.57 christos ACPI_BUFFER buf; 1015 1.57 christos ACPI_STATUS rv; 1016 1.57 christos 1017 1.57 christos args[0].Type = ACPI_TYPE_INTEGER; 1018 1.57 christos args[0].Integer.Value = arg; 1019 1.57 christos arg_list.Pointer = &args[0]; 1020 1.57 christos arg_list.Count = __arraycount(args); 1021 1.57 christos 1022 1.57 christos memset(&rval, 0, sizeof rval); 1023 1.57 christos buf.Pointer = &rval; 1024 1.57 christos buf.Length = sizeof rval; 1025 1.57 christos 1026 1.57 christos rv = AcpiEvaluateObjectTyped(handle, path, &arg_list, &buf, 1027 1.57 christos ACPI_TYPE_INTEGER); 1028 1.57 christos 1029 1.57 christos if (ACPI_FAILURE(rv)) { 1030 1.57 christos aprint_error_dev(self, "call %s.%s(%x) failed: %s\n", 1031 1.57 christos acpi_name(handle), path, (unsigned)arg, 1032 1.57 christos AcpiFormatException(rv)); 1033 1.57 christos return THINKPAD_CALL_ERROR; 1034 1.57 christos } 1035 1.57 christos 1036 1.57 christos return rval.Integer.Value; 1037 1.57 christos } 1038 1.57 christos 1039 1.57 christos static void 1040 1.57 christos thinkpad_battery_probe_support(device_t self) 1041 1.57 christos { 1042 1.57 christos thinkpad_softc_t *sc = device_private(self); 1043 1.57 christos ACPI_HANDLE hdl = sc->sc_node->ad_handle, tmp; 1044 1.57 christos ACPI_STATUS rv; 1045 1.57 christos uint32_t val; 1046 1.57 christos 1047 1.57 christos sc->sc_batctl.have_any = 0; 1048 1.57 christos 1049 1.57 christos rv = AcpiGetHandle(hdl, THINKPAD_GET_CHARGE_START, &tmp); 1050 1.57 christos if (ACPI_SUCCESS(rv)) { 1051 1.57 christos val = thinkpad_call_method(self, THINKPAD_GET_CHARGE_START, 1052 1.57 christos THINKPAD_BAT_PRIMARY); 1053 1.57 christos if (!(val & THINKPAD_CALL_ERROR) && (val & 0x100)) { 1054 1.57 christos sc->sc_batctl.have.charge_start = 1; 1055 1.57 christos if (val & 0x200) 1056 1.57 christos sc->sc_batctl.have.individual_control = 1; 1057 1.57 christos } 1058 1.57 christos } 1059 1.57 christos 1060 1.57 christos rv = AcpiGetHandle(hdl, THINKPAD_GET_CHARGE_STOP, &tmp); 1061 1.57 christos if (ACPI_SUCCESS(rv)) { 1062 1.57 christos val = thinkpad_call_method(self, THINKPAD_GET_CHARGE_STOP, 1063 1.57 christos THINKPAD_BAT_PRIMARY); 1064 1.57 christos if (!(val & THINKPAD_CALL_ERROR) && (val & 0x100)) 1065 1.57 christos sc->sc_batctl.have.charge_stop = 1; 1066 1.57 christos } 1067 1.57 christos 1068 1.57 christos rv = AcpiGetHandle(hdl, THINKPAD_GET_FORCE_DISCHARGE, &tmp); 1069 1.57 christos if (ACPI_SUCCESS(rv)) { 1070 1.57 christos val = thinkpad_call_method(self, THINKPAD_GET_FORCE_DISCHARGE, 1071 1.57 christos THINKPAD_BAT_PRIMARY); 1072 1.57 christos if (!(val & THINKPAD_CALL_ERROR) && (val & 0x100)) 1073 1.57 christos sc->sc_batctl.have.force_discharge = 1; 1074 1.57 christos } 1075 1.57 christos 1076 1.57 christos rv = AcpiGetHandle(hdl, THINKPAD_GET_CHARGE_INHIBIT, &tmp); 1077 1.57 christos if (ACPI_SUCCESS(rv)) { 1078 1.57 christos val = thinkpad_call_method(self, THINKPAD_GET_CHARGE_INHIBIT, 1079 1.57 christos THINKPAD_BAT_PRIMARY); 1080 1.57 christos if (!(val & THINKPAD_CALL_ERROR) && (val & 0x20)) 1081 1.57 christos sc->sc_batctl.have.charge_inhibit = 1; 1082 1.57 christos } 1083 1.57 christos 1084 1.57 christos if (sc->sc_batctl.have_any) 1085 1.57 christos aprint_verbose_dev(self, "battery control capabilities: %x\n", 1086 1.57 christos sc->sc_batctl.have_any); 1087 1.57 christos } 1088 1.57 christos 1089 1.57 christos static int 1090 1.57 christos thinkpad_battery_sysctl_charge_start(SYSCTLFN_ARGS) 1091 1.57 christos { 1092 1.57 christos struct sysctlnode node = *rnode; 1093 1.57 christos tp_sysctl_param_t *sp = node.sysctl_data; 1094 1.57 christos int charge_start; 1095 1.57 christos int err; 1096 1.57 christos 1097 1.57 christos charge_start = thinkpad_call_method(sp->sp_dev, 1098 1.57 christos THINKPAD_GET_CHARGE_START, sp->sp_bat) & 0xff; 1099 1.57 christos 1100 1.57 christos node.sysctl_data = &charge_start; 1101 1.57 christos err = sysctl_lookup(SYSCTLFN_CALL(&node)); 1102 1.57 christos if (err || newp == NULL) 1103 1.57 christos return err; 1104 1.57 christos 1105 1.57 christos if (charge_start < 0 || charge_start > 99) 1106 1.57 christos return EINVAL; 1107 1.57 christos 1108 1.57 christos if (thinkpad_call_method(sp->sp_dev, THINKPAD_SET_CHARGE_START, 1109 1.57 christos charge_start | sp->sp_bat<<8) & THINKPAD_CALL_ERROR) 1110 1.57 christos return EIO; 1111 1.57 christos 1112 1.57 christos return 0; 1113 1.57 christos } 1114 1.57 christos 1115 1.57 christos static int 1116 1.57 christos thinkpad_battery_sysctl_charge_stop(SYSCTLFN_ARGS) 1117 1.57 christos { 1118 1.57 christos struct sysctlnode node = *rnode; 1119 1.57 christos tp_sysctl_param_t *sp = node.sysctl_data; 1120 1.57 christos int charge_stop; 1121 1.57 christos int err; 1122 1.57 christos 1123 1.57 christos charge_stop = thinkpad_call_method(sp->sp_dev, 1124 1.57 christos THINKPAD_GET_CHARGE_STOP, sp->sp_bat) & 0xff; 1125 1.57 christos 1126 1.57 christos if (charge_stop == 0) 1127 1.57 christos charge_stop = 100; 1128 1.57 christos 1129 1.57 christos node.sysctl_data = &charge_stop; 1130 1.57 christos err = sysctl_lookup(SYSCTLFN_CALL(&node)); 1131 1.57 christos if (err || newp == NULL) 1132 1.57 christos return err; 1133 1.57 christos 1134 1.57 christos if (charge_stop < 1 || charge_stop > 100) 1135 1.57 christos return EINVAL; 1136 1.57 christos 1137 1.57 christos if (charge_stop == 100) 1138 1.57 christos charge_stop = 0; 1139 1.57 christos 1140 1.57 christos if (thinkpad_call_method(sp->sp_dev, THINKPAD_SET_CHARGE_STOP, 1141 1.57 christos charge_stop | sp->sp_bat<<8) & THINKPAD_CALL_ERROR) 1142 1.57 christos return EIO; 1143 1.57 christos 1144 1.57 christos return 0; 1145 1.57 christos } 1146 1.57 christos 1147 1.57 christos static int 1148 1.57 christos thinkpad_battery_sysctl_charge_inhibit(SYSCTLFN_ARGS) 1149 1.57 christos { 1150 1.57 christos struct sysctlnode node = *rnode; 1151 1.57 christos tp_sysctl_param_t *sp = node.sysctl_data; 1152 1.57 christos bool charge_inhibit; 1153 1.57 christos int err; 1154 1.57 christos 1155 1.57 christos charge_inhibit = thinkpad_call_method(sp->sp_dev, 1156 1.57 christos THINKPAD_GET_CHARGE_INHIBIT, sp->sp_bat) & 0x01; 1157 1.57 christos 1158 1.57 christos node.sysctl_data = &charge_inhibit; 1159 1.57 christos err = sysctl_lookup(SYSCTLFN_CALL(&node)); 1160 1.57 christos if (err || newp == NULL) 1161 1.57 christos return err; 1162 1.57 christos 1163 1.57 christos if (thinkpad_call_method(sp->sp_dev, THINKPAD_SET_CHARGE_INHIBIT, 1164 1.57 christos charge_inhibit | sp->sp_bat<<4 | 0xffff<<8) & THINKPAD_CALL_ERROR) 1165 1.57 christos return EIO; 1166 1.57 christos 1167 1.57 christos return 0; 1168 1.57 christos } 1169 1.57 christos 1170 1.57 christos static int 1171 1.57 christos thinkpad_battery_sysctl_force_discharge(SYSCTLFN_ARGS) 1172 1.57 christos { 1173 1.57 christos struct sysctlnode node = *rnode; 1174 1.57 christos tp_sysctl_param_t *sp = node.sysctl_data; 1175 1.57 christos bool force_discharge; 1176 1.57 christos int err; 1177 1.57 christos 1178 1.57 christos force_discharge = thinkpad_call_method(sp->sp_dev, 1179 1.57 christos THINKPAD_GET_FORCE_DISCHARGE, sp->sp_bat) & 0x01; 1180 1.57 christos 1181 1.57 christos node.sysctl_data = &force_discharge; 1182 1.57 christos err = sysctl_lookup(SYSCTLFN_CALL(&node)); 1183 1.57 christos if (err || newp == NULL) 1184 1.57 christos return err; 1185 1.57 christos 1186 1.57 christos if (thinkpad_call_method(sp->sp_dev, THINKPAD_SET_FORCE_DISCHARGE, 1187 1.57 christos force_discharge | sp->sp_bat<<8) & THINKPAD_CALL_ERROR) 1188 1.57 christos return EIO; 1189 1.57 christos 1190 1.57 christos return 0; 1191 1.57 christos } 1192 1.57 christos 1193 1.57 christos static void 1194 1.57 christos thinkpad_battery_sysctl_setup_controls(device_t self, 1195 1.57 christos const struct sysctlnode *rnode, int battery) 1196 1.57 christos { 1197 1.57 christos thinkpad_softc_t *sc = device_private(self); 1198 1.57 christos 1199 1.57 christos if (sc->sc_batctl.have.charge_start) 1200 1.57 christos (void)sysctl_createv(&sc->sc_log, 0, &rnode, NULL, 1201 1.57 christos CTLFLAG_READWRITE, CTLTYPE_INT, "charge_start", 1202 1.57 christos SYSCTL_DESCR("charge start threshold (0-99)"), 1203 1.57 christos thinkpad_battery_sysctl_charge_start, 0, 1204 1.57 christos (void *)&(sc->sc_scparam[battery]), 0, 1205 1.57 christos CTL_CREATE, CTL_EOL); 1206 1.57 christos 1207 1.57 christos if (sc->sc_batctl.have.charge_stop) 1208 1.57 christos (void)sysctl_createv(&sc->sc_log, 0, &rnode, NULL, 1209 1.57 christos CTLFLAG_READWRITE, CTLTYPE_INT, "charge_stop", 1210 1.57 christos SYSCTL_DESCR("charge stop threshold (1-100)"), 1211 1.57 christos thinkpad_battery_sysctl_charge_stop, 0, 1212 1.57 christos (void *)&(sc->sc_scparam[battery]), 0, 1213 1.57 christos CTL_CREATE, CTL_EOL); 1214 1.57 christos 1215 1.57 christos if (sc->sc_batctl.have.charge_inhibit) 1216 1.57 christos (void)sysctl_createv(&sc->sc_log, 0, &rnode, NULL, 1217 1.57 christos CTLFLAG_READWRITE, CTLTYPE_BOOL, "charge_inhibit", 1218 1.57 christos SYSCTL_DESCR("charge inhibit"), 1219 1.57 christos thinkpad_battery_sysctl_charge_inhibit, 0, 1220 1.57 christos (void *)&(sc->sc_scparam[battery]), 0, 1221 1.57 christos CTL_CREATE, CTL_EOL); 1222 1.57 christos 1223 1.57 christos if (sc->sc_batctl.have.force_discharge) 1224 1.57 christos (void)sysctl_createv(&sc->sc_log, 0, &rnode, NULL, 1225 1.57 christos CTLFLAG_READWRITE, CTLTYPE_BOOL, "force_discharge", 1226 1.57 christos SYSCTL_DESCR("force discharge"), 1227 1.57 christos thinkpad_battery_sysctl_force_discharge, 0, 1228 1.57 christos (void *)&(sc->sc_scparam[battery]), 0, 1229 1.57 christos CTL_CREATE, CTL_EOL); 1230 1.57 christos } 1231 1.57 christos 1232 1.57 christos static void 1233 1.57 christos thinkpad_battery_sysctl_setup(device_t self) 1234 1.57 christos { 1235 1.57 christos thinkpad_softc_t *sc = device_private(self); 1236 1.57 christos const struct sysctlnode *rnode, *cnode; 1237 1.57 christos int err; 1238 1.57 christos 1239 1.57 christos err = sysctl_createv(&sc->sc_log, 0, NULL, &rnode, 1240 1.57 christos 0, CTLTYPE_NODE, "acpi", NULL, 1241 1.57 christos NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); 1242 1.57 christos if (err) 1243 1.57 christos goto fail; 1244 1.57 christos 1245 1.57 christos err = sysctl_createv(&sc->sc_log, 0, &rnode, &rnode, 1246 1.57 christos 0, CTLTYPE_NODE, device_xname(self), 1247 1.57 christos SYSCTL_DESCR("ThinkPad ACPI controls"), 1248 1.57 christos NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 1249 1.57 christos if (err) 1250 1.57 christos goto fail; 1251 1.57 christos 1252 1.57 christos if (sc->sc_batctl.have.individual_control) { 1253 1.57 christos err = sysctl_createv(&sc->sc_log, 0, &rnode, &cnode, 1254 1.57 christos 0, CTLTYPE_NODE, "bat0", 1255 1.57 christos SYSCTL_DESCR("battery charge controls (primary battery)"), 1256 1.57 christos NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 1257 1.57 christos if (err) 1258 1.57 christos goto fail; 1259 1.57 christos 1260 1.57 christos thinkpad_battery_sysctl_setup_controls(self, cnode, 1261 1.57 christos THINKPAD_BAT_PRIMARY); 1262 1.57 christos 1263 1.57 christos err = sysctl_createv(&sc->sc_log, 0, &rnode, &cnode, 1264 1.57 christos 0, CTLTYPE_NODE, "bat1", 1265 1.57 christos SYSCTL_DESCR("battery charge controls (secondary battery)"), 1266 1.57 christos NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 1267 1.57 christos if (err) 1268 1.57 christos goto fail; 1269 1.57 christos 1270 1.57 christos thinkpad_battery_sysctl_setup_controls(self, cnode, 1271 1.57 christos THINKPAD_BAT_SECONDARY); 1272 1.57 christos } else { 1273 1.57 christos err = sysctl_createv(&sc->sc_log, 0, &rnode, &cnode, 1274 1.57 christos 0, CTLTYPE_NODE, "bat", 1275 1.57 christos SYSCTL_DESCR("battery charge controls"), 1276 1.57 christos NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 1277 1.57 christos if (err) 1278 1.57 christos goto fail; 1279 1.57 christos 1280 1.57 christos thinkpad_battery_sysctl_setup_controls(self, cnode, 1281 1.57 christos THINKPAD_BAT_ANY); 1282 1.57 christos } 1283 1.57 christos 1284 1.57 christos return; 1285 1.57 christos 1286 1.57 christos fail: 1287 1.57 christos aprint_error_dev(self, "unable to add sysctl nodes (%d)\n", err); 1288 1.57 christos } 1289 1.57 christos 1290 1.11 jmcneill static bool 1291 1.26 dyoung thinkpad_resume(device_t dv, const pmf_qual_t *qual) 1292 1.11 jmcneill { 1293 1.36 jruoho thinkpad_softc_t *sc = device_private(dv); 1294 1.11 jmcneill 1295 1.36 jruoho if (sc->sc_powhdl == NULL) 1296 1.36 jruoho return true; 1297 1.11 jmcneill 1298 1.36 jruoho (void)acpi_power_res(sc->sc_powhdl, sc->sc_node->ad_handle, true); 1299 1.11 jmcneill 1300 1.11 jmcneill return true; 1301 1.11 jmcneill } 1302 1.27 jruoho 1303 1.45 pgoyette MODULE(MODULE_CLASS_DRIVER, thinkpad, "sysmon_envsys,sysmon_power"); 1304 1.27 jruoho 1305 1.34 jruoho #ifdef _MODULE 1306 1.34 jruoho #include "ioconf.c" 1307 1.34 jruoho #endif 1308 1.27 jruoho 1309 1.27 jruoho static int 1310 1.34 jruoho thinkpad_modcmd(modcmd_t cmd, void *aux) 1311 1.27 jruoho { 1312 1.34 jruoho int rv = 0; 1313 1.27 jruoho 1314 1.27 jruoho switch (cmd) { 1315 1.27 jruoho 1316 1.27 jruoho case MODULE_CMD_INIT: 1317 1.27 jruoho 1318 1.34 jruoho #ifdef _MODULE 1319 1.34 jruoho rv = config_init_component(cfdriver_ioconf_thinkpad, 1320 1.34 jruoho cfattach_ioconf_thinkpad, cfdata_ioconf_thinkpad); 1321 1.34 jruoho #endif 1322 1.34 jruoho break; 1323 1.27 jruoho 1324 1.27 jruoho case MODULE_CMD_FINI: 1325 1.27 jruoho 1326 1.34 jruoho #ifdef _MODULE 1327 1.34 jruoho rv = config_fini_component(cfdriver_ioconf_thinkpad, 1328 1.34 jruoho cfattach_ioconf_thinkpad, cfdata_ioconf_thinkpad); 1329 1.34 jruoho #endif 1330 1.34 jruoho break; 1331 1.27 jruoho 1332 1.27 jruoho default: 1333 1.34 jruoho rv = ENOTTY; 1334 1.27 jruoho } 1335 1.34 jruoho 1336 1.34 jruoho return rv; 1337 1.27 jruoho } 1338