1 /* $OpenBSD: acpithinkpad.c,v 1.64 2019/03/08 16:33:23 jcs 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 21 #include <dev/acpi/acpireg.h> 22 #include <dev/acpi/acpivar.h> 23 #include <dev/acpi/acpidev.h> 24 #include <dev/acpi/amltypes.h> 25 #include <dev/acpi/dsdt.h> 26 #include <dev/wscons/wsconsio.h> 27 28 #include <machine/apmvar.h> 29 30 #include "audio.h" 31 #include "wskbd.h" 32 33 /* #define ACPITHINKPAD_DEBUG */ 34 35 #ifdef ACPITHINKPAD_DEBUG 36 #define DPRINTF(x) printf x 37 #else 38 #define DPRINTF(x) 39 #endif 40 41 #define THINKPAD_HKEY_VERSION1 0x0100 42 #define THINKPAD_HKEY_VERSION2 0x0200 43 44 #define THINKPAD_CMOS_VOLUME_DOWN 0x00 45 #define THINKPAD_CMOS_VOLUME_UP 0x01 46 #define THINKPAD_CMOS_VOLUME_MUTE 0x02 47 #define THINKPAD_CMOS_BRIGHTNESS_UP 0x04 48 #define THINKPAD_CMOS_BRIGHTNESS_DOWN 0x05 49 50 #define THINKPAD_BLUETOOTH_PRESENT 0x01 51 #define THINKPAD_BLUETOOTH_ENABLED 0x02 52 53 /* wan (not wifi) card */ 54 #define THINKPAD_WAN_PRESENT 0x01 55 #define THINKPAD_WAN_ENABLED 0x02 56 57 #define THINKPAD_BUTTON_FN_F1 0x1001 58 #define THINKPAD_BUTTON_LOCK_SCREEN 0x1002 59 #define THINKPAD_BUTTON_BATTERY_INFO 0x1003 60 #define THINKPAD_BUTTON_SUSPEND 0x1004 61 #define THINKPAD_BUTTON_WIRELESS 0x1005 62 #define THINKPAD_BUTTON_FN_F6 0x1006 63 #define THINKPAD_BUTTON_EXTERNAL_SCREEN 0x1007 64 #define THINKPAD_BUTTON_POINTER_SWITCH 0x1008 65 #define THINKPAD_BUTTON_EJECT 0x1009 66 #define THINKPAD_BUTTON_FN_F11 0x100b 67 #define THINKPAD_BUTTON_HIBERNATE 0x100c 68 #define THINKPAD_BUTTON_BRIGHTNESS_UP 0x1010 69 #define THINKPAD_BUTTON_BRIGHTNESS_DOWN 0x1011 70 #define THINKPAD_BUTTON_THINKLIGHT 0x1012 71 #define THINKPAD_BUTTON_FN_SPACE 0x1014 72 #define THINKPAD_BUTTON_VOLUME_UP 0x1015 73 #define THINKPAD_BUTTON_VOLUME_DOWN 0x1016 74 #define THINKPAD_BUTTON_VOLUME_MUTE 0x1017 75 #define THINKPAD_BUTTON_THINKVANTAGE 0x1018 76 #define THINKPAD_BUTTON_BLACK 0x101a 77 #define THINKPAD_BUTTON_MICROPHONE_MUTE 0x101b 78 #define THINKPAD_KEYLIGHT_CHANGED 0x101c 79 #define THINKPAD_BUTTON_CONFIG 0x101d 80 #define THINKPAD_BUTTON_FIND 0x101e 81 #define THINKPAD_BUTTON_ALL_ACTIVEPROGS 0x101f 82 #define THINKPAD_BUTTON_ALL_PROGS 0x1020 83 84 #define THINKPAD_ADAPTIVE_NEXT 0x1101 85 #define THINKPAD_ADAPTIVE_QUICK 0x1102 86 #define THINKPAD_ADAPTIVE_SNIP 0x1105 87 #define THINKPAD_ADAPTIVE_VOICE 0x1108 88 #define THINKPAD_ADAPTIVE_GESTURES 0x110a 89 #define THINKPAD_ADAPTIVE_SETTINGS 0x110e 90 #define THINKPAD_ADAPTIVE_TAB 0x110f 91 #define THINKPAD_ADAPTIVE_REFRESH 0x1110 92 #define THINKPAD_ADAPTIVE_BACK 0x1111 93 #define THINKPAD_PORT_REPL_DOCKED 0x4010 94 #define THINKPAD_PORT_REPL_UNDOCKED 0x4011 95 #define THINKPAD_TABLET_DOCKED 0x4012 96 #define THINKPAD_TABLET_UNDOCKED 0x4013 97 #define THINKPAD_LID_OPEN 0x5001 98 #define THINKPAD_LID_CLOSED 0x5002 99 #define THINKPAD_TABLET_SCREEN_NORMAL 0x500a 100 #define THINKPAD_TABLET_SCREEN_ROTATED 0x5009 101 #define THINKPAD_BRIGHTNESS_CHANGED 0x5010 102 #define THINKPAD_TABLET_PEN_INSERTED 0x500b 103 #define THINKPAD_TABLET_PEN_REMOVED 0x500c 104 #define THINKPAD_SWITCH_NUMLOCK 0x6000 105 #define THINKPAD_BUTTON_ROTATION_LOCK 0x6020 106 #define THINKPAD_THERMAL_TABLE_CHANGED 0x6030 107 #define THINKPAD_POWER_CHANGED 0x6040 108 #define THINKPAD_BACKLIGHT_CHANGED 0x6050 109 #define THINKPAD_BUTTON_FN_TOGGLE 0x6060 110 #define THINKPAD_TABLET_SCREEN_CHANGED 0x60c0 111 #define THINKPAD_SWITCH_WIRELESS 0x7000 112 113 #define THINKPAD_NSENSORS 10 114 #define THINKPAD_NTEMPSENSORS 8 115 116 #define THINKPAD_SENSOR_FANRPM THINKPAD_NTEMPSENSORS 117 #define THINKPAD_SENSOR_PORTREPL THINKPAD_NTEMPSENSORS + 1 118 119 #define THINKPAD_ECOFFSET_VOLUME 0x30 120 #define THINKPAD_ECOFFSET_VOLUME_MUTE_MASK 0x40 121 #define THINKPAD_ECOFFSET_FANLO 0x84 122 #define THINKPAD_ECOFFSET_FANHI 0x85 123 124 #define THINKPAD_ADAPTIVE_MODE_HOME 1 125 #define THINKPAD_ADAPTIVE_MODE_FUNCTION 3 126 127 #define THINKPAD_MASK_MIC_MUTE (1 << 14) 128 #define THINKPAD_MASK_BRIGHTNESS_UP (1 << 15) 129 #define THINKPAD_MASK_BRIGHTNESS_DOWN (1 << 16) 130 #define THINKPAD_MASK_KBD_BACKLIGHT (1 << 17) 131 132 struct acpithinkpad_softc { 133 struct device sc_dev; 134 135 struct acpiec_softc *sc_ec; 136 struct acpi_softc *sc_acpi; 137 struct aml_node *sc_devnode; 138 139 struct ksensor sc_sens[THINKPAD_NSENSORS]; 140 struct ksensordev sc_sensdev; 141 142 uint64_t sc_hkey_version; 143 144 uint64_t sc_thinklight; 145 const char *sc_thinklight_get; 146 const char *sc_thinklight_set; 147 148 uint64_t sc_brightness; 149 }; 150 151 extern void acpiec_read(struct acpiec_softc *, uint8_t, int, uint8_t *); 152 153 int thinkpad_match(struct device *, void *, void *); 154 void thinkpad_attach(struct device *, struct device *, void *); 155 int thinkpad_hotkey(struct aml_node *, int, void *); 156 int thinkpad_enable_events(struct acpithinkpad_softc *); 157 int thinkpad_toggle_bluetooth(struct acpithinkpad_softc *); 158 int thinkpad_toggle_wan(struct acpithinkpad_softc *); 159 int thinkpad_cmos(struct acpithinkpad_softc *sc, uint8_t); 160 int thinkpad_volume_down(struct acpithinkpad_softc *); 161 int thinkpad_volume_up(struct acpithinkpad_softc *); 162 int thinkpad_volume_mute(struct acpithinkpad_softc *); 163 int thinkpad_brightness_up(struct acpithinkpad_softc *); 164 int thinkpad_brightness_down(struct acpithinkpad_softc *); 165 int thinkpad_adaptive_change(struct acpithinkpad_softc *); 166 int thinkpad_activate(struct device *, int); 167 168 /* wscons hook functions */ 169 void thinkpad_get_thinklight(struct acpithinkpad_softc *); 170 void thinkpad_set_thinklight(void *, int); 171 int thinkpad_get_kbd_backlight(struct wskbd_backlight *); 172 int thinkpad_set_kbd_backlight(struct wskbd_backlight *); 173 extern int (*wskbd_get_backlight)(struct wskbd_backlight *); 174 extern int (*wskbd_set_backlight)(struct wskbd_backlight *); 175 int thinkpad_get_brightness(struct acpithinkpad_softc *); 176 int thinkpad_set_brightness(void *, int); 177 int thinkpad_get_param(struct wsdisplay_param *); 178 int thinkpad_set_param(struct wsdisplay_param *); 179 extern int (*ws_get_param)(struct wsdisplay_param *); 180 extern int (*ws_set_param)(struct wsdisplay_param *); 181 182 void thinkpad_sensor_attach(struct acpithinkpad_softc *sc); 183 void thinkpad_sensor_refresh(void *); 184 185 #if NAUDIO > 0 && NWSKBD > 0 186 void thinkpad_attach_deferred(void *); 187 int thinkpad_get_volume_mute(struct acpithinkpad_softc *); 188 extern int wskbd_set_mixermute(long, long); 189 extern int wskbd_set_mixervolume(long, long); 190 #endif 191 192 struct cfattach acpithinkpad_ca = { 193 sizeof(struct acpithinkpad_softc), thinkpad_match, thinkpad_attach, 194 NULL, thinkpad_activate 195 }; 196 197 struct cfdriver acpithinkpad_cd = { 198 NULL, "acpithinkpad", DV_DULL 199 }; 200 201 const char *acpithinkpad_hids[] = { 202 "IBM0068", 203 "LEN0068", 204 "LEN0268", 205 NULL 206 }; 207 208 int 209 thinkpad_match(struct device *parent, void *match, void *aux) 210 { 211 struct acpi_attach_args *aa = aux; 212 struct cfdata *cf = match; 213 int64_t res; 214 215 if (!acpi_matchhids(aa, acpithinkpad_hids, cf->cf_driver->cd_name)) 216 return (0); 217 218 if (aml_evalinteger((struct acpi_softc *)parent, aa->aaa_node, 219 "MHKV", 0, NULL, &res)) 220 return (0); 221 222 if (!(res == THINKPAD_HKEY_VERSION1 || res == THINKPAD_HKEY_VERSION2)) 223 return (0); 224 225 return (1); 226 } 227 228 void 229 thinkpad_sensor_attach(struct acpithinkpad_softc *sc) 230 { 231 int i; 232 233 if (sc->sc_acpi->sc_ec == NULL) 234 return; 235 sc->sc_ec = sc->sc_acpi->sc_ec; 236 237 /* Add temperature probes */ 238 strlcpy(sc->sc_sensdev.xname, DEVNAME(sc), 239 sizeof(sc->sc_sensdev.xname)); 240 for (i=0; i<THINKPAD_NTEMPSENSORS; i++) { 241 sc->sc_sens[i].type = SENSOR_TEMP; 242 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[i]); 243 } 244 245 /* Add fan probe */ 246 sc->sc_sens[THINKPAD_SENSOR_FANRPM].type = SENSOR_FANRPM; 247 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[THINKPAD_SENSOR_FANRPM]); 248 249 /* Add port replicator indicator */ 250 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].type = SENSOR_INDICATOR; 251 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].status = SENSOR_S_UNKNOWN; 252 strlcpy(sc->sc_sens[THINKPAD_SENSOR_PORTREPL].desc, "port replicator", 253 sizeof(sc->sc_sens[THINKPAD_SENSOR_PORTREPL].desc)); 254 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[THINKPAD_SENSOR_PORTREPL]); 255 256 sensordev_install(&sc->sc_sensdev); 257 } 258 259 void 260 thinkpad_sensor_refresh(void *arg) 261 { 262 struct acpithinkpad_softc *sc = arg; 263 uint8_t lo, hi, i; 264 int64_t tmp; 265 char sname[5]; 266 267 /* Refresh sensor readings */ 268 for (i=0; i<THINKPAD_NTEMPSENSORS; i++) { 269 snprintf(sname, sizeof(sname), "TMP%d", i); 270 aml_evalinteger(sc->sc_acpi, sc->sc_ec->sc_devnode, 271 sname, 0, 0, &tmp); 272 sc->sc_sens[i].value = (tmp * 1000000) + 273150000; 273 if (tmp > 127 || tmp < -127) 274 sc->sc_sens[i].flags = SENSOR_FINVALID; 275 } 276 277 /* Read fan RPM */ 278 acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANLO, 1, &lo); 279 acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANHI, 1, &hi); 280 sc->sc_sens[THINKPAD_SENSOR_FANRPM].value = ((hi << 8L) + lo); 281 } 282 283 void 284 thinkpad_attach(struct device *parent, struct device *self, void *aux) 285 { 286 struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self; 287 struct acpi_attach_args *aa = aux; 288 289 sc->sc_acpi = (struct acpi_softc *)parent; 290 sc->sc_devnode = aa->aaa_node; 291 292 printf("\n"); 293 294 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MHKV", 0, NULL, 295 &sc->sc_hkey_version)) 296 sc->sc_hkey_version = THINKPAD_HKEY_VERSION1; 297 298 #if NAUDIO > 0 && NWSKBD > 0 299 /* Defer speaker mute */ 300 if (thinkpad_get_volume_mute(sc) == 1) 301 startuphook_establish(thinkpad_attach_deferred, sc); 302 #endif 303 304 /* Set event mask to receive everything */ 305 thinkpad_enable_events(sc); 306 thinkpad_sensor_attach(sc); 307 308 /* Check for ThinkLight or keyboard backlight */ 309 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "KLCG", 310 0, NULL, &sc->sc_thinklight) == 0) { 311 sc->sc_thinklight_get = "KLCG"; 312 sc->sc_thinklight_set = "KLCS"; 313 wskbd_get_backlight = thinkpad_get_kbd_backlight; 314 wskbd_set_backlight = thinkpad_set_kbd_backlight; 315 } else if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MLCG", 316 0, NULL, &sc->sc_thinklight) == 0) { 317 sc->sc_thinklight_get = "MLCG"; 318 sc->sc_thinklight_set = "MLCS"; 319 wskbd_get_backlight = thinkpad_get_kbd_backlight; 320 wskbd_set_backlight = thinkpad_set_kbd_backlight; 321 } 322 323 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "PBLG", 324 0, NULL, &sc->sc_brightness) == 0) { 325 ws_get_param = thinkpad_get_param; 326 ws_set_param = thinkpad_set_param; 327 } 328 329 /* Run thinkpad_hotkey on button presses */ 330 aml_register_notify(sc->sc_devnode, aa->aaa_dev, 331 thinkpad_hotkey, sc, ACPIDEV_POLL); 332 } 333 334 int 335 thinkpad_enable_events(struct acpithinkpad_softc *sc) 336 { 337 struct aml_value arg, args[2]; 338 int64_t mask; 339 int i; 340 341 /* Get the default event mask */ 342 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MHKA", 343 0, NULL, &mask)) { 344 printf("%s: no MHKA\n", DEVNAME(sc)); 345 return (1); 346 } 347 348 /* Enable events we need to know about */ 349 mask |= (THINKPAD_MASK_MIC_MUTE | 350 THINKPAD_MASK_BRIGHTNESS_UP | 351 THINKPAD_MASK_BRIGHTNESS_DOWN | 352 THINKPAD_MASK_KBD_BACKLIGHT); 353 354 DPRINTF(("%s: setting event mask to 0x%llx\n", DEVNAME(sc), mask)); 355 356 /* Update hotkey mask */ 357 bzero(args, sizeof(args)); 358 args[0].type = args[1].type = AML_OBJTYPE_INTEGER; 359 for (i = 0; i < 32; i++) { 360 args[0].v_integer = i + 1; 361 args[1].v_integer = (((1 << i) & mask) != 0); 362 363 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKM", 364 2, args, NULL)) { 365 printf("%s: couldn't toggle MHKM\n", DEVNAME(sc)); 366 return (1); 367 } 368 } 369 370 /* Enable hotkeys */ 371 bzero(&arg, sizeof(arg)); 372 arg.type = AML_OBJTYPE_INTEGER; 373 arg.v_integer = 1; 374 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKC", 375 1, &arg, NULL)) { 376 printf("%s: couldn't enable hotkeys\n", DEVNAME(sc)); 377 return (1); 378 } 379 380 return (0); 381 } 382 383 int 384 thinkpad_hotkey(struct aml_node *node, int notify_type, void *arg) 385 { 386 struct acpithinkpad_softc *sc = arg; 387 int64_t event; 388 389 if (notify_type == 0x00) { 390 /* Poll sensors */ 391 thinkpad_sensor_refresh(sc); 392 return (0); 393 } 394 395 if (notify_type != 0x80) 396 return (1); 397 398 for (;;) { 399 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MHKP", 400 0, NULL, &event)) 401 break; 402 403 DPRINTF(("%s: event 0x%03llx\n", DEVNAME(sc), event)); 404 if (event == 0) 405 break; 406 407 switch (event) { 408 case THINKPAD_BUTTON_BRIGHTNESS_UP: 409 thinkpad_brightness_up(sc); 410 break; 411 case THINKPAD_BUTTON_BRIGHTNESS_DOWN: 412 thinkpad_brightness_down(sc); 413 break; 414 case THINKPAD_BUTTON_WIRELESS: 415 thinkpad_toggle_bluetooth(sc); 416 break; 417 case THINKPAD_BUTTON_SUSPEND: 418 #ifndef SMALL_KERNEL 419 if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) 420 acpi_addtask(sc->sc_acpi, acpi_sleep_task, 421 sc->sc_acpi, ACPI_SLEEP_SUSPEND); 422 #endif 423 break; 424 case THINKPAD_BUTTON_VOLUME_MUTE: 425 thinkpad_volume_mute(sc); 426 break; 427 case THINKPAD_BUTTON_VOLUME_DOWN: 428 thinkpad_volume_down(sc); 429 break; 430 case THINKPAD_BUTTON_VOLUME_UP: 431 thinkpad_volume_up(sc); 432 break; 433 case THINKPAD_BUTTON_MICROPHONE_MUTE: 434 #if NAUDIO > 0 && NWSKBD > 0 435 wskbd_set_mixervolume(0, 0); 436 #endif 437 break; 438 case THINKPAD_BUTTON_HIBERNATE: 439 #if defined(HIBERNATE) && !defined(SMALL_KERNEL) 440 if (acpi_record_event(sc->sc_acpi, APM_USER_HIBERNATE_REQ)) 441 acpi_addtask(sc->sc_acpi, acpi_sleep_task, 442 sc->sc_acpi, ACPI_SLEEP_HIBERNATE); 443 #endif 444 break; 445 case THINKPAD_BUTTON_THINKLIGHT: 446 thinkpad_get_thinklight(sc); 447 break; 448 case THINKPAD_ADAPTIVE_NEXT: 449 case THINKPAD_ADAPTIVE_QUICK: 450 thinkpad_adaptive_change(sc); 451 break; 452 case THINKPAD_BACKLIGHT_CHANGED: 453 thinkpad_get_brightness(sc); 454 break; 455 case THINKPAD_PORT_REPL_DOCKED: 456 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].value = 1; 457 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].status = 458 SENSOR_S_OK; 459 break; 460 case THINKPAD_PORT_REPL_UNDOCKED: 461 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].value = 0; 462 sc->sc_sens[THINKPAD_SENSOR_PORTREPL].status = 463 SENSOR_S_OK; 464 break; 465 default: 466 /* unknown or boring event */ 467 DPRINTF(("%s: unhandled event 0x%03llx\n", DEVNAME(sc), 468 event)); 469 break; 470 } 471 } 472 473 return (0); 474 } 475 476 int 477 thinkpad_toggle_bluetooth(struct acpithinkpad_softc *sc) 478 { 479 struct aml_value arg; 480 int64_t bluetooth; 481 482 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GBDC", 483 0, NULL, &bluetooth)) 484 return (1); 485 486 if (!(bluetooth & THINKPAD_BLUETOOTH_PRESENT)) 487 return (1); 488 489 bzero(&arg, sizeof(arg)); 490 arg.type = AML_OBJTYPE_INTEGER; 491 arg.v_integer = bluetooth ^ THINKPAD_BLUETOOTH_ENABLED; 492 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBDC", 493 1, &arg, NULL)) { 494 printf("%s: couldn't toggle bluetooth\n", DEVNAME(sc)); 495 return (1); 496 } 497 498 return (0); 499 } 500 501 int 502 thinkpad_toggle_wan(struct acpithinkpad_softc *sc) 503 { 504 struct aml_value arg; 505 int64_t wan; 506 507 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GWAN", 508 0, NULL, &wan)) 509 return (1); 510 511 if (!(wan & THINKPAD_WAN_PRESENT)) 512 return (1); 513 514 bzero(&arg, sizeof(arg)); 515 arg.type = AML_OBJTYPE_INTEGER; 516 arg.v_integer = wan ^ THINKPAD_WAN_ENABLED; 517 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SWAN", 518 1, &arg, NULL)) { 519 printf("%s: couldn't toggle wan\n", DEVNAME(sc)); 520 return (1); 521 } 522 523 return (0); 524 } 525 526 int 527 thinkpad_cmos(struct acpithinkpad_softc *sc, uint8_t cmd) 528 { 529 struct aml_value arg; 530 531 bzero(&arg, sizeof(arg)); 532 arg.type = AML_OBJTYPE_INTEGER; 533 arg.v_integer = cmd; 534 aml_evalname(sc->sc_acpi, sc->sc_devnode, "\\UCMS", 1, &arg, NULL); 535 return (0); 536 } 537 538 int 539 thinkpad_volume_down(struct acpithinkpad_softc *sc) 540 { 541 return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_DOWN)); 542 } 543 544 int 545 thinkpad_volume_up(struct acpithinkpad_softc *sc) 546 { 547 return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_UP)); 548 } 549 550 int 551 thinkpad_volume_mute(struct acpithinkpad_softc *sc) 552 { 553 return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_MUTE)); 554 } 555 556 int 557 thinkpad_brightness_up(struct acpithinkpad_softc *sc) 558 { 559 int b; 560 561 if (thinkpad_get_brightness(sc) == 0) { 562 b = sc->sc_brightness & 0xff; 563 if (b < ((sc->sc_brightness >> 8) & 0xff)) { 564 sc->sc_brightness = b + 1; 565 thinkpad_set_brightness(sc, 0); 566 } 567 568 return (0); 569 } else 570 return (thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_UP)); 571 } 572 573 int 574 thinkpad_brightness_down(struct acpithinkpad_softc *sc) 575 { 576 int b; 577 578 if (thinkpad_get_brightness(sc) == 0) { 579 b = sc->sc_brightness & 0xff; 580 if (b > 0) { 581 sc->sc_brightness = b - 1; 582 thinkpad_set_brightness(sc, 0); 583 } 584 585 return (0); 586 } else 587 return (thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_DOWN)); 588 } 589 590 int 591 thinkpad_adaptive_change(struct acpithinkpad_softc *sc) 592 { 593 struct aml_value arg; 594 int64_t mode; 595 596 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GTRW", 597 0, NULL, &mode)) { 598 printf("%s: couldn't get adaptive keyboard mode\n", DEVNAME(sc)); 599 return (1); 600 } 601 602 bzero(&arg, sizeof(arg)); 603 arg.type = AML_OBJTYPE_INTEGER; 604 605 if (mode == THINKPAD_ADAPTIVE_MODE_FUNCTION) 606 arg.v_integer = THINKPAD_ADAPTIVE_MODE_HOME; 607 else 608 arg.v_integer = THINKPAD_ADAPTIVE_MODE_FUNCTION; 609 610 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "STRW", 611 1, &arg, NULL)) { 612 printf("%s: couldn't set adaptive keyboard mode\n", DEVNAME(sc)); 613 return (1); 614 } 615 616 return (0); 617 } 618 619 int 620 thinkpad_activate(struct device *self, int act) 621 { 622 623 struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self; 624 int64_t res; 625 #if NAUDIO > 0 && NWSKBD > 0 626 int mute; 627 #endif 628 629 switch (act) { 630 case DVACT_WAKEUP: 631 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GTRW", 632 0, NULL, &res) == 0) 633 thinkpad_adaptive_change(sc); 634 #if NAUDIO > 0 && NWSKBD > 0 635 mute = thinkpad_get_volume_mute(sc); 636 if (mute != -1) 637 wskbd_set_mixermute(mute, 1); 638 #endif 639 break; 640 } 641 return (0); 642 } 643 644 void 645 thinkpad_get_thinklight(struct acpithinkpad_softc *sc) 646 { 647 if (sc->sc_thinklight_get) 648 aml_evalinteger(sc->sc_acpi, sc->sc_devnode, 649 sc->sc_thinklight_get, 0, NULL, &sc->sc_thinklight); 650 } 651 652 void 653 thinkpad_set_thinklight(void *arg0, int arg1) 654 { 655 struct acpithinkpad_softc *sc = arg0; 656 struct aml_value arg; 657 658 memset(&arg, 0, sizeof(arg)); 659 arg.type = AML_OBJTYPE_INTEGER; 660 arg.v_integer = sc->sc_thinklight & 0x0f; 661 aml_evalname(sc->sc_acpi, sc->sc_devnode, 662 sc->sc_thinklight_set, 1, &arg, NULL); 663 } 664 665 int 666 thinkpad_get_kbd_backlight(struct wskbd_backlight *kbl) 667 { 668 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 669 670 KASSERT(sc != NULL); 671 672 kbl->min = 0; 673 kbl->max = (sc->sc_thinklight >> 8) & 0x0f; 674 kbl->curval = sc->sc_thinklight & 0x0f; 675 676 if (kbl->max == 0) 677 return (ENOTTY); 678 679 return 0; 680 } 681 682 int 683 thinkpad_set_kbd_backlight(struct wskbd_backlight *kbl) 684 { 685 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 686 int maxval; 687 688 KASSERT(sc != NULL); 689 690 maxval = (sc->sc_thinklight >> 8) & 0x0f; 691 692 if (maxval == 0) 693 return (ENOTTY); 694 695 if (kbl->curval > maxval) 696 return EINVAL; 697 698 sc->sc_thinklight &= ~0xff; 699 sc->sc_thinklight |= kbl->curval; 700 acpi_addtask(sc->sc_acpi, thinkpad_set_thinklight, sc, 0); 701 acpi_wakeup(sc->sc_acpi); 702 return 0; 703 } 704 705 int 706 thinkpad_get_brightness(struct acpithinkpad_softc *sc) 707 { 708 int ret; 709 710 ret = aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "PBLG", 0, NULL, 711 &sc->sc_brightness); 712 713 DPRINTF(("%s: %s: 0x%llx\n", DEVNAME(sc), __func__, sc->sc_brightness)); 714 715 return ret; 716 } 717 718 int 719 thinkpad_set_brightness(void *arg0, int arg1) 720 { 721 struct acpithinkpad_softc *sc = arg0; 722 struct aml_value arg; 723 int ret; 724 725 DPRINTF(("%s: %s: 0x%llx\n", DEVNAME(sc), __func__, sc->sc_brightness)); 726 727 memset(&arg, 0, sizeof(arg)); 728 arg.type = AML_OBJTYPE_INTEGER; 729 arg.v_integer = sc->sc_brightness & 0xff; 730 ret = aml_evalname(sc->sc_acpi, sc->sc_devnode, "PBLS", 1, &arg, NULL); 731 732 if (ret) 733 return ret; 734 735 thinkpad_get_brightness(sc); 736 737 return 0; 738 } 739 740 int 741 thinkpad_get_param(struct wsdisplay_param *dp) 742 { 743 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 744 745 if (sc == NULL) 746 return -1; 747 748 switch (dp->param) { 749 case WSDISPLAYIO_PARAM_BRIGHTNESS: 750 dp->min = 0; 751 dp->max = (sc->sc_brightness >> 8) & 0xff; 752 dp->curval = sc->sc_brightness & 0xff; 753 return 0; 754 default: 755 return -1; 756 } 757 } 758 759 int 760 thinkpad_set_param(struct wsdisplay_param *dp) 761 { 762 struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0]; 763 int maxval; 764 765 if (sc == NULL) 766 return -1; 767 768 maxval = (sc->sc_brightness >> 8) & 0xff; 769 770 switch (dp->param) { 771 case WSDISPLAYIO_PARAM_BRIGHTNESS: 772 if (dp->curval < 0) 773 dp->curval = 0; 774 if (dp->curval > maxval) 775 dp->curval = maxval; 776 sc->sc_brightness &= ~0xff; 777 sc->sc_brightness |= dp->curval; 778 acpi_addtask(sc->sc_acpi, (void *)thinkpad_set_brightness, sc, 779 0); 780 acpi_wakeup(sc->sc_acpi); 781 return 0; 782 default: 783 return -1; 784 } 785 } 786 787 #if NAUDIO > 0 && NWSKBD > 0 788 void 789 thinkpad_attach_deferred(void *v __unused) 790 { 791 wskbd_set_mixermute(1, 1); 792 } 793 794 int 795 thinkpad_get_volume_mute(struct acpithinkpad_softc *sc) 796 { 797 uint8_t vol = 0; 798 799 if (sc->sc_acpi->sc_ec == NULL) 800 return (-1); 801 802 acpiec_read(sc->sc_acpi->sc_ec, THINKPAD_ECOFFSET_VOLUME, 1, &vol); 803 return ((vol & THINKPAD_ECOFFSET_VOLUME_MUTE_MASK) == 804 THINKPAD_ECOFFSET_VOLUME_MUTE_MASK); 805 } 806 #endif 807