1 /* $OpenBSD: acpithinkpad.c,v 1.74 2023/07/07 07:37:59 claudio Exp $ */ 2 /* 3 * Copyright (c) 2008 joshua stein <jcs@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/sensors.h> 21 22 #include <dev/acpi/acpireg.h> 23 #include <dev/acpi/acpivar.h> 24 #include <dev/acpi/acpidev.h> 25 #include <dev/acpi/amltypes.h> 26 #include <dev/acpi/dsdt.h> 27 #include <dev/wscons/wsconsio.h> 28 #include <dev/wscons/wsdisplayvar.h> 29 30 #include <machine/apmvar.h> 31 32 #include "audio.h" 33 #include "wskbd.h" 34 35 /* #define ACPITHINKPAD_DEBUG */ 36 37 #ifdef ACPITHINKPAD_DEBUG 38 #define DPRINTF(x) printf x 39 #else 40 #define DPRINTF(x) 41 #endif 42 43 #define THINKPAD_HKEY_VERSION1 0x0100 44 #define THINKPAD_HKEY_VERSION2 0x0200 45 46 #define THINKPAD_CMOS_VOLUME_DOWN 0x00 47 #define THINKPAD_CMOS_VOLUME_UP 0x01 48 #define THINKPAD_CMOS_VOLUME_MUTE 0x02 49 #define THINKPAD_CMOS_BRIGHTNESS_UP 0x04 50 #define THINKPAD_CMOS_BRIGHTNESS_DOWN 0x05 51 52 #define THINKPAD_BLUETOOTH_PRESENT 0x01 53 #define THINKPAD_BLUETOOTH_ENABLED 0x02 54 55 /* wan (not wifi) card */ 56 #define THINKPAD_WAN_PRESENT 0x01 57 #define THINKPAD_WAN_ENABLED 0x02 58 59 #define THINKPAD_BUTTON_FN_F1 0x1001 60 #define THINKPAD_BUTTON_LOCK_SCREEN 0x1002 61 #define THINKPAD_BUTTON_BATTERY_INFO 0x1003 62 #define THINKPAD_BUTTON_SUSPEND 0x1004 63 #define THINKPAD_BUTTON_WIRELESS 0x1005 64 #define THINKPAD_BUTTON_FN_F6 0x1006 65 #define THINKPAD_BUTTON_EXTERNAL_SCREEN 0x1007 66 #define THINKPAD_BUTTON_POINTER_SWITCH 0x1008 67 #define THINKPAD_BUTTON_EJECT 0x1009 68 #define THINKPAD_BUTTON_FN_F11 0x100b 69 #define THINKPAD_BUTTON_HIBERNATE 0x100c 70 #define THINKPAD_BUTTON_BRIGHTNESS_UP 0x1010 71 #define THINKPAD_BUTTON_BRIGHTNESS_DOWN 0x1011 72 #define THINKPAD_BUTTON_THINKLIGHT 0x1012 73 #define THINKPAD_BUTTON_FN_SPACE 0x1014 74 #define THINKPAD_BUTTON_VOLUME_UP 0x1015 75 #define THINKPAD_BUTTON_VOLUME_DOWN 0x1016 76 #define THINKPAD_BUTTON_VOLUME_MUTE 0x1017 77 #define THINKPAD_BUTTON_THINKVANTAGE 0x1018 78 #define THINKPAD_BUTTON_BLACK 0x101a 79 #define THINKPAD_BUTTON_MICROPHONE_MUTE 0x101b 80 #define THINKPAD_KEYLIGHT_CHANGED 0x101c 81 #define THINKPAD_BUTTON_CONFIG 0x101d 82 #define THINKPAD_BUTTON_FIND 0x101e 83 #define THINKPAD_BUTTON_ALL_ACTIVEPROGS 0x101f 84 #define THINKPAD_BUTTON_ALL_PROGS 0x1020 85 86 #define THINKPAD_ADAPTIVE_NEXT 0x1101 87 #define THINKPAD_ADAPTIVE_QUICK 0x1102 88 #define THINKPAD_ADAPTIVE_SNIP 0x1105 89 #define THINKPAD_ADAPTIVE_VOICE 0x1108 90 #define THINKPAD_ADAPTIVE_GESTURES 0x110a 91 #define THINKPAD_ADAPTIVE_SETTINGS 0x110e 92 #define THINKPAD_ADAPTIVE_TAB 0x110f 93 #define THINKPAD_ADAPTIVE_REFRESH 0x1110 94 #define THINKPAD_ADAPTIVE_BACK 0x1111 95 #define THINKPAD_PORT_REPL_DOCKED 0x4010 96 #define THINKPAD_PORT_REPL_UNDOCKED 0x4011 97 #define THINKPAD_TABLET_DOCKED 0x4012 98 #define THINKPAD_TABLET_UNDOCKED 0x4013 99 #define THINKPAD_LID_OPEN 0x5001 100 #define THINKPAD_LID_CLOSED 0x5002 101 #define THINKPAD_TABLET_SCREEN_NORMAL 0x500a 102 #define THINKPAD_TABLET_SCREEN_ROTATED 0x5009 103 #define THINKPAD_BRIGHTNESS_CHANGED 0x5010 104 #define THINKPAD_TABLET_PEN_INSERTED 0x500b 105 #define THINKPAD_TABLET_PEN_REMOVED 0x500c 106 #define THINKPAD_SWITCH_NUMLOCK 0x6000 107 #define THINKPAD_BUTTON_ROTATION_LOCK 0x6020 108 #define THINKPAD_THERMAL_TABLE_CHANGED 0x6030 109 #define THINKPAD_POWER_CHANGED 0x6040 110 #define THINKPAD_BACKLIGHT_CHANGED 0x6050 111 #define THINKPAD_BUTTON_FN_TOGGLE 0x6060 112 #define THINKPAD_TABLET_SCREEN_CHANGED 0x60c0 113 #define THINKPAD_SWITCH_WIRELESS 0x7000 114 115 #define THINKPAD_SENSOR_FANRPM 0 116 #define THINKPAD_SENSOR_PORTREPL 1 117 #define THINKPAD_SENSOR_TMP0 2 118 #define THINKPAD_NSENSORS 10 119 120 #define THINKPAD_ECOFFSET_VOLUME 0x30 121 #define THINKPAD_ECOFFSET_VOLUME_MUTE_MASK 0x40 122 #define THINKPAD_ECOFFSET_FANLO 0x84 123 #define THINKPAD_ECOFFSET_FANHI 0x85 124 125 #define THINKPAD_ADAPTIVE_MODE_HOME 1 126 #define THINKPAD_ADAPTIVE_MODE_FUNCTION 3 127 128 #define THINKPAD_MASK_MIC_MUTE (1 << 14) 129 #define THINKPAD_MASK_BRIGHTNESS_UP (1 << 15) 130 #define THINKPAD_MASK_BRIGHTNESS_DOWN (1 << 16) 131 #define THINKPAD_MASK_KBD_BACKLIGHT (1 << 17) 132 133 #define THINKPAD_BATTERY_ERROR 0x80000000 134 #define THINKPAD_BATTERY_SUPPORT 0x00000100 135 #define THINKPAD_BATTERY_SUPPORT_BICG 0x00000020 136 #define THINKPAD_BATTERY_SHIFT 8 137 138 struct acpithinkpad_softc { 139 struct device sc_dev; 140 141 struct acpiec_softc *sc_ec; 142 struct acpi_softc *sc_acpi; 143 struct aml_node *sc_devnode; 144 145 struct ksensor sc_sens[THINKPAD_NSENSORS]; 146 struct ksensordev sc_sensdev; 147 int sc_ntempsens; 148 149 uint64_t sc_hkey_version; 150 151 uint64_t sc_thinklight; 152 const char *sc_thinklight_get; 153 const char *sc_thinklight_set; 154 155 uint64_t sc_brightness; 156 }; 157 158 extern void acpiec_read(struct acpiec_softc *, uint8_t, int, uint8_t *); 159 160 int thinkpad_match(struct device *, void *, void *); 161 void thinkpad_attach(struct device *, struct device *, void *); 162 int thinkpad_hotkey(struct aml_node *, int, void *); 163 int thinkpad_enable_events(struct acpithinkpad_softc *); 164 int thinkpad_toggle_bluetooth(struct acpithinkpad_softc *); 165 int thinkpad_toggle_wan(struct acpithinkpad_softc *); 166 int thinkpad_cmos(struct acpithinkpad_softc *sc, uint8_t); 167 int thinkpad_volume_down(struct acpithinkpad_softc *); 168 int thinkpad_volume_up(struct acpithinkpad_softc *); 169 int thinkpad_volume_mute(struct acpithinkpad_softc *); 170 int thinkpad_brightness_up(struct acpithinkpad_softc *); 171 int thinkpad_brightness_down(struct acpithinkpad_softc *); 172 int thinkpad_adaptive_change(struct acpithinkpad_softc *); 173 int thinkpad_activate(struct device *, int); 174 175 /* wscons hook functions */ 176 void thinkpad_get_thinklight(struct acpithinkpad_softc *); 177 void thinkpad_set_thinklight(void *, int); 178 int thinkpad_get_kbd_backlight(struct wskbd_backlight *); 179 int thinkpad_set_kbd_backlight(struct wskbd_backlight *); 180 extern int (*wskbd_get_backlight)(struct wskbd_backlight *); 181 extern int (*wskbd_set_backlight)(struct wskbd_backlight *); 182 int thinkpad_get_brightness(struct acpithinkpad_softc *); 183 int thinkpad_set_brightness(void *, int); 184 int thinkpad_get_param(struct wsdisplay_param *); 185 int thinkpad_set_param(struct wsdisplay_param *); 186 int thinkpad_get_temp(struct acpithinkpad_softc *, int, int64_t *); 187 188 void thinkpad_sensor_attach(struct acpithinkpad_softc *sc); 189 void thinkpad_sensor_refresh(void *); 190 191 #if NAUDIO > 0 && NWSKBD > 0 192 void thinkpad_attach_deferred(void *); 193 int thinkpad_get_volume_mute(struct acpithinkpad_softc *); 194 extern int wskbd_set_mixermute(long, long); 195 extern int wskbd_set_mixervolume(long, long); 196 #endif 197 198 int thinkpad_battery_setchargemode(int); 199 int thinkpad_battery_setchargestart(int); 200 int thinkpad_battery_setchargestop(int); 201 202 extern int (*hw_battery_setchargemode)(int); 203 extern int (*hw_battery_setchargestart)(int); 204 extern int (*hw_battery_setchargestop)(int); 205 extern int hw_battery_chargemode; 206 extern int hw_battery_chargestart; 207 extern int hw_battery_chargestop; 208 209 const struct cfattach acpithinkpad_ca = { 210 sizeof(struct acpithinkpad_softc), thinkpad_match, thinkpad_attach, 211 NULL, thinkpad_activate 212 }; 213 214 struct cfdriver acpithinkpad_cd = { 215 NULL, "acpithinkpad", DV_DULL 216 }; 217 218 const char *acpithinkpad_hids[] = { 219 "IBM0068", 220 "LEN0068", 221 "LEN0268", 222 NULL 223 }; 224 225 int 226 thinkpad_match(struct device *parent, void *match, void *aux) 227 { 228 struct acpi_attach_args *aa = aux; 229 struct cfdata *cf = match; 230 int64_t res; 231 232 if (!acpi_matchhids(aa, acpithinkpad_hids, cf->cf_driver->cd_name)) 233 return (0); 234 235 if (aml_evalinteger((struct acpi_softc *)parent, aa->aaa_node, 236 "MHKV", 0, NULL, &res)) 237 return (0); 238 239 if (!(res == THINKPAD_HKEY_VERSION1 || res == THINKPAD_HKEY_VERSION2)) 240 return (0); 241 242 return (1); 243 } 244 245 void 246 thinkpad_sensor_attach(struct acpithinkpad_softc *sc) 247 { 248 int64_t tmp; 249 int i; 250 251 if (sc->sc_acpi->sc_ec == NULL) 252 return; 253 sc->sc_ec = sc->sc_acpi->sc_ec; 254 255 /* Add temperature probes */ 256 strlcpy(sc->sc_sensdev.xname, DEVNAME(sc), 257 sizeof(sc->sc_sensdev.xname)); 258 sc->sc_ntempsens = 0; 259 for (i = 0; i < THINKPAD_NSENSORS - THINKPAD_SENSOR_TMP0; i++) { 260 if (thinkpad_get_temp(sc, i, &tmp) != 0) 261 break; 262 263 sc->sc_sens[THINKPAD_SENSOR_TMP0 + i].type = SENSOR_TEMP; 264 sensor_attach(&sc->sc_sensdev, 265 &sc->sc_sens[THINKPAD_SENSOR_TMP0 + i]); 266 sc->sc_ntempsens++; 267 } 268 269 /* Add fan probe */ 270 sc->sc_sens[THINKPAD_SENSOR_FANRPM].type = SENSOR_FANRPM; 271 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[THINKPAD_SENSOR_FANRPM]); 272 273 /* Add port replicator indicator */ 274 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].type = SENSOR_INDICATOR; 275 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].status = SENSOR_S_UNKNOWN; 276 strlcpy(sc->sc_sens[THINKPAD_SENSOR_PORTREPL].desc, "port replicator", 277 sizeof(sc->sc_sens[THINKPAD_SENSOR_PORTREPL].desc)); 278 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[THINKPAD_SENSOR_PORTREPL]); 279 280 sensordev_install(&sc->sc_sensdev); 281 } 282 283 void 284 thinkpad_sensor_refresh(void *arg) 285 { 286 struct acpithinkpad_softc *sc = arg; 287 uint8_t lo, hi, i; 288 int64_t tmp; 289 290 /* Refresh sensor readings */ 291 for (i = 0; i < sc->sc_ntempsens; i++) { 292 if (thinkpad_get_temp(sc, i, &tmp) != 0) { 293 sc->sc_sens[i].flags = SENSOR_FINVALID; 294 continue; 295 } 296 297 sc->sc_sens[THINKPAD_SENSOR_TMP0 + i].value = 298 (tmp * 1000000) + 273150000; 299 sc->sc_sens[THINKPAD_SENSOR_TMP0 + i].flags = 300 (tmp > 127 || tmp < -127) ? SENSOR_FINVALID : 0; 301 } 302 303 /* Read fan RPM */ 304 acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANLO, 1, &lo); 305 acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANHI, 1, &hi); 306 if (hi == 0xff && lo == 0xff) { 307 sc->sc_sens[THINKPAD_SENSOR_FANRPM].flags = SENSOR_FINVALID; 308 } else { 309 sc->sc_sens[THINKPAD_SENSOR_FANRPM].value = ((hi << 8L) + lo); 310 sc->sc_sens[THINKPAD_SENSOR_FANRPM].flags = 0; 311 } 312 } 313 314 void 315 thinkpad_attach(struct device *parent, struct device *self, void *aux) 316 { 317 struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self; 318 struct acpi_attach_args *aa = aux; 319 struct aml_value arg; 320 uint64_t ret; 321 322 sc->sc_acpi = (struct acpi_softc *)parent; 323 sc->sc_devnode = aa->aaa_node; 324 325 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MHKV", 0, NULL, 326 &sc->sc_hkey_version)) 327 sc->sc_hkey_version = THINKPAD_HKEY_VERSION1; 328 329 printf(": version %lld.%lld\n", sc->sc_hkey_version >> 8, 330 sc->sc_hkey_version & 0xff); 331 332 #if NAUDIO > 0 && NWSKBD > 0 333 /* Defer speaker mute */ 334 if (thinkpad_get_volume_mute(sc) == 1) 335 startuphook_establish(thinkpad_attach_deferred, sc); 336 #endif 337 338 /* Set event mask to receive everything */ 339 thinkpad_enable_events(sc); 340 thinkpad_sensor_attach(sc); 341 342 /* Check for ThinkLight or keyboard backlight */ 343 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "KLCG", 344 0, NULL, &sc->sc_thinklight) == 0) { 345 sc->sc_thinklight_get = "KLCG"; 346 sc->sc_thinklight_set = "KLCS"; 347 wskbd_get_backlight = thinkpad_get_kbd_backlight; 348 wskbd_set_backlight = thinkpad_set_kbd_backlight; 349 } else if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MLCG", 350 0, NULL, &sc->sc_thinklight) == 0) { 351 sc->sc_thinklight_get = "MLCG"; 352 sc->sc_thinklight_set = "MLCS"; 353 wskbd_get_backlight = thinkpad_get_kbd_backlight; 354 wskbd_set_backlight = thinkpad_set_kbd_backlight; 355 } 356 357 /* On version 2 and newer, let *drm or acpivout control brightness */ 358 if (sc->sc_hkey_version == THINKPAD_HKEY_VERSION1 && 359 (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "PBLG", 360 0, NULL, &sc->sc_brightness) == 0)) { 361 ws_get_param = thinkpad_get_param; 362 ws_set_param = thinkpad_set_param; 363 } 364 365 memset(&arg, 0, sizeof(arg)); 366 arg.type = AML_OBJTYPE_INTEGER; 367 arg.v_integer = 1; 368 369 hw_battery_chargemode = 1; 370 hw_battery_chargestart = 0; 371 hw_battery_chargestop = 100; 372 373 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BCTG", 374 1, &arg, &ret) == 0 && (ret & THINKPAD_BATTERY_ERROR) == 0) { 375 if (ret & THINKPAD_BATTERY_SUPPORT) { 376 hw_battery_chargestart = ret & 0xff; 377 hw_battery_setchargestart = 378 thinkpad_battery_setchargestart; 379 } 380 } 381 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BCSG", 382 1, &arg, &ret) == 0 && (ret & THINKPAD_BATTERY_ERROR) == 0) { 383 if (ret & THINKPAD_BATTERY_SUPPORT) { 384 if ((ret & 0xff) == 0) 385 hw_battery_chargestop = 100; 386 else 387 hw_battery_chargestop = ret & 0xff; 388 hw_battery_setchargestop = 389 thinkpad_battery_setchargestop; 390 } 391 } 392 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BDSG", 393 1, &arg, &ret) == 0 && (ret & THINKPAD_BATTERY_ERROR) == 0) { 394 if (ret & THINKPAD_BATTERY_SUPPORT) { 395 if (ret & 0x1) 396 hw_battery_chargemode = -1; 397 hw_battery_setchargemode = 398 thinkpad_battery_setchargemode; 399 } 400 } 401 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BICG", 402 1, &arg, &ret) == 0 && (ret & THINKPAD_BATTERY_ERROR) == 0) { 403 if (ret & THINKPAD_BATTERY_SUPPORT_BICG) { 404 if (ret & 0x1) 405 hw_battery_chargemode = 0; 406 hw_battery_setchargemode = 407 thinkpad_battery_setchargemode; 408 } 409 } 410 411 /* Run thinkpad_hotkey on button presses */ 412 aml_register_notify(sc->sc_devnode, aa->aaa_dev, 413 thinkpad_hotkey, sc, ACPIDEV_POLL); 414 } 415 416 int 417 thinkpad_enable_events(struct acpithinkpad_softc *sc) 418 { 419 struct aml_value arg, args[2]; 420 int64_t mask; 421 int i; 422 423 /* Get the default event mask */ 424 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MHKA", 425 0, NULL, &mask)) { 426 printf("%s: no MHKA\n", DEVNAME(sc)); 427 return (1); 428 } 429 430 /* Enable events we need to know about */ 431 mask |= (THINKPAD_MASK_MIC_MUTE | 432 THINKPAD_MASK_BRIGHTNESS_UP | 433 THINKPAD_MASK_BRIGHTNESS_DOWN | 434 THINKPAD_MASK_KBD_BACKLIGHT); 435 436 DPRINTF(("%s: setting event mask to 0x%llx\n", DEVNAME(sc), mask)); 437 438 /* Update hotkey mask */ 439 bzero(args, sizeof(args)); 440 args[0].type = args[1].type = AML_OBJTYPE_INTEGER; 441 for (i = 0; i < 32; i++) { 442 args[0].v_integer = i + 1; 443 args[1].v_integer = (((1 << i) & mask) != 0); 444 445 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKM", 446 2, args, NULL)) { 447 printf("%s: couldn't toggle MHKM\n", DEVNAME(sc)); 448 return (1); 449 } 450 } 451 452 /* Enable hotkeys */ 453 bzero(&arg, sizeof(arg)); 454 arg.type = AML_OBJTYPE_INTEGER; 455 arg.v_integer = 1; 456 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKC", 457 1, &arg, NULL)) { 458 printf("%s: couldn't enable hotkeys\n", DEVNAME(sc)); 459 return (1); 460 } 461 462 return (0); 463 } 464 465 int 466 thinkpad_hotkey(struct aml_node *node, int notify_type, void *arg) 467 { 468 struct acpithinkpad_softc *sc = arg; 469 int64_t event; 470 471 if (notify_type == 0x00) { 472 /* Poll sensors */ 473 thinkpad_sensor_refresh(sc); 474 return (0); 475 } 476 477 if (notify_type != 0x80) 478 return (1); 479 480 for (;;) { 481 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MHKP", 482 0, NULL, &event)) 483 break; 484 485 DPRINTF(("%s: event 0x%03llx\n", DEVNAME(sc), event)); 486 if (event == 0) 487 break; 488 489 switch (event) { 490 case THINKPAD_BUTTON_BRIGHTNESS_UP: 491 thinkpad_brightness_up(sc); 492 break; 493 case THINKPAD_BUTTON_BRIGHTNESS_DOWN: 494 thinkpad_brightness_down(sc); 495 break; 496 case THINKPAD_BUTTON_WIRELESS: 497 thinkpad_toggle_bluetooth(sc); 498 break; 499 case THINKPAD_BUTTON_SUSPEND: 500 #ifndef SMALL_KERNEL 501 if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) 502 acpi_addtask(sc->sc_acpi, acpi_sleep_task, 503 sc->sc_acpi, SLEEP_SUSPEND); 504 #endif 505 break; 506 case THINKPAD_BUTTON_VOLUME_MUTE: 507 thinkpad_volume_mute(sc); 508 break; 509 case THINKPAD_BUTTON_VOLUME_DOWN: 510 thinkpad_volume_down(sc); 511 break; 512 case THINKPAD_BUTTON_VOLUME_UP: 513 thinkpad_volume_up(sc); 514 break; 515 case THINKPAD_BUTTON_MICROPHONE_MUTE: 516 #if NAUDIO > 0 && NWSKBD > 0 517 wskbd_set_mixervolume(0, 0); 518 #endif 519 break; 520 case THINKPAD_BUTTON_HIBERNATE: 521 #if defined(HIBERNATE) && !defined(SMALL_KERNEL) 522 if (acpi_record_event(sc->sc_acpi, APM_USER_HIBERNATE_REQ)) 523 acpi_addtask(sc->sc_acpi, acpi_sleep_task, 524 sc->sc_acpi, SLEEP_HIBERNATE); 525 #endif 526 break; 527 case THINKPAD_BUTTON_THINKLIGHT: 528 thinkpad_get_thinklight(sc); 529 break; 530 case THINKPAD_ADAPTIVE_NEXT: 531 case THINKPAD_ADAPTIVE_QUICK: 532 thinkpad_adaptive_change(sc); 533 break; 534 case THINKPAD_BACKLIGHT_CHANGED: 535 thinkpad_get_brightness(sc); 536 break; 537 case THINKPAD_PORT_REPL_DOCKED: 538 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].value = 1; 539 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].status = 540 SENSOR_S_OK; 541 break; 542 case THINKPAD_PORT_REPL_UNDOCKED: 543 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].value = 0; 544 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].status = 545 SENSOR_S_OK; 546 break; 547 default: 548 /* unknown or boring event */ 549 DPRINTF(("%s: unhandled event 0x%03llx\n", DEVNAME(sc), 550 event)); 551 break; 552 } 553 } 554 555 return (0); 556 } 557 558 int 559 thinkpad_toggle_bluetooth(struct acpithinkpad_softc *sc) 560 { 561 struct aml_value arg; 562 int64_t bluetooth; 563 564 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GBDC", 565 0, NULL, &bluetooth)) 566 return (1); 567 568 if (!(bluetooth & THINKPAD_BLUETOOTH_PRESENT)) 569 return (1); 570 571 bzero(&arg, sizeof(arg)); 572 arg.type = AML_OBJTYPE_INTEGER; 573 arg.v_integer = bluetooth ^ THINKPAD_BLUETOOTH_ENABLED; 574 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBDC", 575 1, &arg, NULL)) { 576 printf("%s: couldn't toggle bluetooth\n", DEVNAME(sc)); 577 return (1); 578 } 579 580 return (0); 581 } 582 583 int 584 thinkpad_toggle_wan(struct acpithinkpad_softc *sc) 585 { 586 struct aml_value arg; 587 int64_t wan; 588 589 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GWAN", 590 0, NULL, &wan)) 591 return (1); 592 593 if (!(wan & THINKPAD_WAN_PRESENT)) 594 return (1); 595 596 bzero(&arg, sizeof(arg)); 597 arg.type = AML_OBJTYPE_INTEGER; 598 arg.v_integer = wan ^ THINKPAD_WAN_ENABLED; 599 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SWAN", 600 1, &arg, NULL)) { 601 printf("%s: couldn't toggle wan\n", DEVNAME(sc)); 602 return (1); 603 } 604 605 return (0); 606 } 607 608 int 609 thinkpad_cmos(struct acpithinkpad_softc *sc, uint8_t cmd) 610 { 611 struct aml_value arg; 612 613 bzero(&arg, sizeof(arg)); 614 arg.type = AML_OBJTYPE_INTEGER; 615 arg.v_integer = cmd; 616 aml_evalname(sc->sc_acpi, sc->sc_devnode, "\\UCMS", 1, &arg, NULL); 617 return (0); 618 } 619 620 int 621 thinkpad_volume_down(struct acpithinkpad_softc *sc) 622 { 623 return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_DOWN)); 624 } 625 626 int 627 thinkpad_volume_up(struct acpithinkpad_softc *sc) 628 { 629 return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_UP)); 630 } 631 632 int 633 thinkpad_volume_mute(struct acpithinkpad_softc *sc) 634 { 635 return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_MUTE)); 636 } 637 638 int 639 thinkpad_brightness_up(struct acpithinkpad_softc *sc) 640 { 641 int b; 642 643 if (thinkpad_get_brightness(sc) == 0) { 644 b = sc->sc_brightness & 0xff; 645 if (b < ((sc->sc_brightness >> 8) & 0xff)) { 646 sc->sc_brightness = b + 1; 647 thinkpad_set_brightness(sc, 0); 648 } 649 650 return (0); 651 } else 652 return (thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_UP)); 653 } 654 655 int 656 thinkpad_brightness_down(struct acpithinkpad_softc *sc) 657 { 658 int b; 659 660 if (thinkpad_get_brightness(sc) == 0) { 661 b = sc->sc_brightness & 0xff; 662 if (b > 0) { 663 sc->sc_brightness = b - 1; 664 thinkpad_set_brightness(sc, 0); 665 } 666 667 return (0); 668 } else 669 return (thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_DOWN)); 670 } 671 672 int 673 thinkpad_adaptive_change(struct acpithinkpad_softc *sc) 674 { 675 struct aml_value arg; 676 int64_t mode; 677 678 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GTRW", 679 0, NULL, &mode)) { 680 printf("%s: couldn't get adaptive keyboard mode\n", DEVNAME(sc)); 681 return (1); 682 } 683 684 bzero(&arg, sizeof(arg)); 685 arg.type = AML_OBJTYPE_INTEGER; 686 687 if (mode == THINKPAD_ADAPTIVE_MODE_FUNCTION) 688 arg.v_integer = THINKPAD_ADAPTIVE_MODE_HOME; 689 else 690 arg.v_integer = THINKPAD_ADAPTIVE_MODE_FUNCTION; 691 692 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "STRW", 693 1, &arg, NULL)) { 694 printf("%s: couldn't set adaptive keyboard mode\n", DEVNAME(sc)); 695 return (1); 696 } 697 698 return (0); 699 } 700 701 int 702 thinkpad_activate(struct device *self, int act) 703 { 704 705 struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self; 706 int64_t res; 707 #if NAUDIO > 0 && NWSKBD > 0 708 int mute; 709 #endif 710 711 switch (act) { 712 case DVACT_WAKEUP: 713 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GTRW", 714 0, NULL, &res) == 0) 715 thinkpad_adaptive_change(sc); 716 #if NAUDIO > 0 && NWSKBD > 0 717 mute = thinkpad_get_volume_mute(sc); 718 if (mute != -1) 719 wskbd_set_mixermute(mute, 1); 720 #endif 721 break; 722 } 723 return (0); 724 } 725 726 void 727 thinkpad_get_thinklight(struct acpithinkpad_softc *sc) 728 { 729 if (sc->sc_thinklight_get) 730 aml_evalinteger(sc->sc_acpi, sc->sc_devnode, 731 sc->sc_thinklight_get, 0, NULL, &sc->sc_thinklight); 732 } 733 734 void 735 thinkpad_set_thinklight(void *arg0, int arg1) 736 { 737 struct acpithinkpad_softc *sc = arg0; 738 struct aml_value arg; 739 740 memset(&arg, 0, sizeof(arg)); 741 arg.type = AML_OBJTYPE_INTEGER; 742 arg.v_integer = sc->sc_thinklight & 0x0f; 743 aml_evalname(sc->sc_acpi, sc->sc_devnode, 744 sc->sc_thinklight_set, 1, &arg, NULL); 745 } 746 747 int 748 thinkpad_get_kbd_backlight(struct wskbd_backlight *kbl) 749 { 750 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 751 752 KASSERT(sc != NULL); 753 754 kbl->min = 0; 755 kbl->max = (sc->sc_thinklight >> 8) & 0x0f; 756 kbl->curval = sc->sc_thinklight & 0x0f; 757 758 if (kbl->max == 0) 759 return (ENOTTY); 760 761 return 0; 762 } 763 764 int 765 thinkpad_set_kbd_backlight(struct wskbd_backlight *kbl) 766 { 767 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 768 int maxval; 769 770 KASSERT(sc != NULL); 771 772 maxval = (sc->sc_thinklight >> 8) & 0x0f; 773 774 if (maxval == 0) 775 return (ENOTTY); 776 777 if (kbl->curval > maxval) 778 return EINVAL; 779 780 sc->sc_thinklight &= ~0xff; 781 sc->sc_thinklight |= kbl->curval; 782 acpi_addtask(sc->sc_acpi, thinkpad_set_thinklight, sc, 0); 783 acpi_wakeup(sc->sc_acpi); 784 return 0; 785 } 786 787 int 788 thinkpad_get_brightness(struct acpithinkpad_softc *sc) 789 { 790 int ret; 791 792 ret = aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "PBLG", 0, NULL, 793 &sc->sc_brightness); 794 795 DPRINTF(("%s: %s: 0x%llx\n", DEVNAME(sc), __func__, sc->sc_brightness)); 796 797 return ret; 798 } 799 800 int 801 thinkpad_set_brightness(void *arg0, int arg1) 802 { 803 struct acpithinkpad_softc *sc = arg0; 804 struct aml_value arg; 805 int ret; 806 807 DPRINTF(("%s: %s: 0x%llx\n", DEVNAME(sc), __func__, sc->sc_brightness)); 808 809 memset(&arg, 0, sizeof(arg)); 810 arg.type = AML_OBJTYPE_INTEGER; 811 arg.v_integer = sc->sc_brightness & 0xff; 812 ret = aml_evalname(sc->sc_acpi, sc->sc_devnode, "PBLS", 1, &arg, NULL); 813 814 if (ret) 815 return ret; 816 817 thinkpad_get_brightness(sc); 818 819 return 0; 820 } 821 822 int 823 thinkpad_get_param(struct wsdisplay_param *dp) 824 { 825 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 826 827 if (sc == NULL) 828 return -1; 829 830 switch (dp->param) { 831 case WSDISPLAYIO_PARAM_BRIGHTNESS: 832 dp->min = 0; 833 dp->max = (sc->sc_brightness >> 8) & 0xff; 834 dp->curval = sc->sc_brightness & 0xff; 835 return 0; 836 default: 837 return -1; 838 } 839 } 840 841 int 842 thinkpad_set_param(struct wsdisplay_param *dp) 843 { 844 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 845 int maxval; 846 847 if (sc == NULL) 848 return -1; 849 850 maxval = (sc->sc_brightness >> 8) & 0xff; 851 852 switch (dp->param) { 853 case WSDISPLAYIO_PARAM_BRIGHTNESS: 854 if (dp->curval < 0) 855 dp->curval = 0; 856 if (dp->curval > maxval) 857 dp->curval = maxval; 858 sc->sc_brightness &= ~0xff; 859 sc->sc_brightness |= dp->curval; 860 acpi_addtask(sc->sc_acpi, (void *)thinkpad_set_brightness, sc, 861 0); 862 acpi_wakeup(sc->sc_acpi); 863 return 0; 864 default: 865 return -1; 866 } 867 } 868 869 int 870 thinkpad_get_temp(struct acpithinkpad_softc *sc, int idx, int64_t *temp) 871 { 872 char sname[5]; 873 874 snprintf(sname, sizeof(sname), "TMP%d", idx); 875 876 if (aml_evalinteger(sc->sc_acpi, sc->sc_ec->sc_devnode, sname, 0, 0, 877 temp) != 0) 878 return (1); 879 880 return (0); 881 } 882 883 #if NAUDIO > 0 && NWSKBD > 0 884 void 885 thinkpad_attach_deferred(void *v __unused) 886 { 887 wskbd_set_mixermute(1, 1); 888 } 889 890 int 891 thinkpad_get_volume_mute(struct acpithinkpad_softc *sc) 892 { 893 uint8_t vol = 0; 894 895 if (sc->sc_acpi->sc_ec == NULL) 896 return (-1); 897 898 acpiec_read(sc->sc_acpi->sc_ec, THINKPAD_ECOFFSET_VOLUME, 1, &vol); 899 return ((vol & THINKPAD_ECOFFSET_VOLUME_MUTE_MASK) == 900 THINKPAD_ECOFFSET_VOLUME_MUTE_MASK); 901 } 902 #endif 903 904 int 905 thinkpad_battery_inhibit_charge(int state) 906 { 907 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 908 struct aml_value arg; 909 int battery, count; 910 uint64_t ret; 911 912 count = acpi_batcount(sc->sc_acpi); 913 for (battery = 1; battery <= count; battery++) { 914 memset(&arg, 0, sizeof(arg)); 915 arg.type = AML_OBJTYPE_INTEGER; 916 arg.v_integer = (0xffff << 8) | (battery << 4) | state; 917 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BICS", 918 1, &arg, &ret) || (ret & THINKPAD_BATTERY_ERROR)) 919 return EIO; 920 } 921 return 0; 922 } 923 924 int 925 thinkpad_battery_force_discharge(int state) 926 { 927 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 928 struct aml_value arg; 929 int battery, count; 930 uint64_t ret; 931 932 count = acpi_batcount(sc->sc_acpi); 933 for (battery = 1; battery <= count; battery++) { 934 memset(&arg, 0, sizeof(arg)); 935 arg.type = AML_OBJTYPE_INTEGER; 936 arg.v_integer = (battery << THINKPAD_BATTERY_SHIFT) | state; 937 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BDSS", 938 1, &arg, &ret) || (ret & THINKPAD_BATTERY_ERROR)) 939 return EIO; 940 } 941 return 0; 942 } 943 944 int 945 thinkpad_battery_setchargemode(int mode) 946 { 947 int error; 948 949 switch (mode) { 950 case -1: 951 error = thinkpad_battery_inhibit_charge(1); 952 if (error) 953 return error; 954 error = thinkpad_battery_force_discharge(1); 955 if (error) 956 return error; 957 break; 958 case 0: 959 error = thinkpad_battery_force_discharge(0); 960 if (error) 961 return error; 962 error = thinkpad_battery_inhibit_charge(1); 963 if (error) 964 return error; 965 break; 966 case 1: 967 error = thinkpad_battery_force_discharge(0); 968 if (error) 969 return error; 970 error = thinkpad_battery_inhibit_charge(0); 971 if (error) 972 return error; 973 break; 974 default: 975 return EOPNOTSUPP; 976 } 977 978 hw_battery_chargemode = mode; 979 return 0; 980 } 981 982 int 983 thinkpad_battery_setchargestart(int start) 984 { 985 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 986 struct aml_value arg; 987 int battery, count; 988 uint64_t ret; 989 990 if (start >= hw_battery_chargestop) 991 return EINVAL; 992 993 count = acpi_batcount(sc->sc_acpi); 994 for (battery = 1; battery <= count; battery++) { 995 memset(&arg, 0, sizeof(arg)); 996 arg.type = AML_OBJTYPE_INTEGER; 997 arg.v_integer = (battery << THINKPAD_BATTERY_SHIFT) | start; 998 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BCCS", 999 1, &arg, &ret) || (ret & THINKPAD_BATTERY_ERROR)) 1000 return EIO; 1001 } 1002 hw_battery_chargestart = start; 1003 return 0; 1004 } 1005 1006 int 1007 thinkpad_battery_setchargestop(int stop) 1008 { 1009 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 1010 struct aml_value arg; 1011 int battery, count; 1012 uint64_t ret; 1013 1014 if (stop <= hw_battery_chargestart) 1015 return EINVAL; 1016 1017 if (stop == 100) 1018 stop = 0; 1019 1020 count = acpi_batcount(sc->sc_acpi); 1021 for (battery = 1; battery <= count; battery++) { 1022 memset(&arg, 0, sizeof(arg)); 1023 arg.type = AML_OBJTYPE_INTEGER; 1024 arg.v_integer = (battery << THINKPAD_BATTERY_SHIFT) | stop; 1025 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BCSS", 1026 1, &arg, &ret) || (ret & THINKPAD_BATTERY_ERROR)) 1027 return EIO; 1028 } 1029 hw_battery_chargestop = (stop == 0) ? 100 : stop; 1030 return 0; 1031 } 1032