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