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