valz_acpi.c revision 1.1
11.1Sjakllsch/* $NetBSD: valz_acpi.c,v 1.1 2010/04/11 22:42:30 jakllsch Exp $ */ 21.1Sjakllsch 31.1Sjakllsch/* 41.1Sjakllsch * Copyright (c) 2010 Jonathan A. Kollasch 51.1Sjakllsch * All rights reserved. 61.1Sjakllsch * 71.1Sjakllsch * Redistribution and use in source and binary forms, with or without 81.1Sjakllsch * modification, are permitted provided that the following conditions 91.1Sjakllsch * are met: 101.1Sjakllsch * 1. Redistributions of source code must retain the above copyright 111.1Sjakllsch * notice, this list of conditions and the following disclaimer. 121.1Sjakllsch * 2. Redistributions in binary form must reproduce the above copyright 131.1Sjakllsch * notice, this list of conditions and the following disclaimer in the 141.1Sjakllsch * documentation and/or other materials provided with the distribution. 151.1Sjakllsch * 161.1Sjakllsch * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171.1Sjakllsch * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 181.1Sjakllsch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 191.1Sjakllsch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 201.1Sjakllsch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 211.1Sjakllsch * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 221.1Sjakllsch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 231.1Sjakllsch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 241.1Sjakllsch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 251.1Sjakllsch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 261.1Sjakllsch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 271.1Sjakllsch */ 281.1Sjakllsch 291.1Sjakllsch#include <sys/cdefs.h> 301.1Sjakllsch__KERNEL_RCSID(0, "$NetBSD: valz_acpi.c,v 1.1 2010/04/11 22:42:30 jakllsch Exp $"); 311.1Sjakllsch 321.1Sjakllsch#include <sys/param.h> 331.1Sjakllsch#include <sys/systm.h> 341.1Sjakllsch#include <sys/syslog.h> 351.1Sjakllsch 361.1Sjakllsch#include <dev/acpi/acpireg.h> 371.1Sjakllsch#include <dev/acpi/acpivar.h> 381.1Sjakllsch 391.1Sjakllschstruct valz_softc { 401.1Sjakllsch device_t sc_dev; 411.1Sjakllsch ACPI_HANDLE sc_lcd; 421.1Sjakllsch}; 431.1Sjakllsch 441.1Sjakllschenum valz_action { 451.1Sjakllsch VALZ_BACKLIGHT_NOCHANGE, 461.1Sjakllsch VALZ_BACKLIGHT_DECREASE, 471.1Sjakllsch VALZ_BACKLIGHT_INCREASE, 481.1Sjakllsch}; 491.1Sjakllsch 501.1Sjakllschstatic const char * const valz_hids[] = { 511.1Sjakllsch "TOS1900", 521.1Sjakllsch NULL 531.1Sjakllsch}; 541.1Sjakllsch 551.1Sjakllschstatic int valz_match(device_t, cfdata_t, void *); 561.1Sjakllschstatic void valz_attach(device_t, device_t, void *); 571.1Sjakllschstatic ACPI_STATUS valz_check_bcl(ACPI_HANDLE, UINT32, void*, void **); 581.1Sjakllschstatic void valz_locate_lcd(struct valz_softc *); 591.1Sjakllschstatic void valz_lcd_notify_handler(ACPI_HANDLE, UINT32, void *); 601.1Sjakllschstatic void valz_adjust_backlight(struct valz_softc *, enum valz_action); 611.1Sjakllschstatic void valz_pmf_brightness_decrease(device_t); 621.1Sjakllschstatic void valz_pmf_brightness_increase(device_t); 631.1Sjakllsch 641.1SjakllschCFATTACH_DECL_NEW(valz, sizeof(struct valz_softc), 651.1Sjakllsch valz_match, valz_attach, NULL, NULL); 661.1Sjakllsch 671.1Sjakllschstatic int 681.1Sjakllschvalz_match(device_t parent, cfdata_t match, void *aux) 691.1Sjakllsch{ 701.1Sjakllsch struct acpi_attach_args *aa = aux; 711.1Sjakllsch 721.1Sjakllsch if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) 731.1Sjakllsch return 0; 741.1Sjakllsch 751.1Sjakllsch return acpi_match_hid(aa->aa_node->ad_devinfo, valz_hids); 761.1Sjakllsch} 771.1Sjakllsch 781.1Sjakllschstatic void 791.1Sjakllschvalz_attach(device_t parent, device_t self, void *aux) 801.1Sjakllsch{ 811.1Sjakllsch struct valz_softc *sc; 821.1Sjakllsch ACPI_STATUS rv; 831.1Sjakllsch 841.1Sjakllsch aprint_naive("\n"); 851.1Sjakllsch aprint_normal("\n"); 861.1Sjakllsch 871.1Sjakllsch sc = device_private(self); 881.1Sjakllsch sc->sc_dev = self; 891.1Sjakllsch sc->sc_lcd = NULL; 901.1Sjakllsch 911.1Sjakllsch valz_locate_lcd(sc); 921.1Sjakllsch 931.1Sjakllsch if (sc->sc_lcd == NULL) { 941.1Sjakllsch aprint_error_dev(self, "failed to find a usable LCD\n"); 951.1Sjakllsch return; 961.1Sjakllsch } 971.1Sjakllsch 981.1Sjakllsch if(!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, 991.1Sjakllsch valz_pmf_brightness_decrease, false)) 1001.1Sjakllsch aprint_error_dev(self, "failed to register event handler\n"); 1011.1Sjakllsch 1021.1Sjakllsch if(!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP, 1031.1Sjakllsch valz_pmf_brightness_increase, false)) 1041.1Sjakllsch aprint_error_dev(self, "failed to register event handler\n"); 1051.1Sjakllsch 1061.1Sjakllsch rv = AcpiInstallNotifyHandler(sc->sc_lcd, ACPI_DEVICE_NOTIFY, 1071.1Sjakllsch valz_lcd_notify_handler, sc); 1081.1Sjakllsch if (ACPI_FAILURE(rv)) 1091.1Sjakllsch aprint_error_dev(self, "failed to install notify handler; %s\n", 1101.1Sjakllsch AcpiFormatException(rv)); 1111.1Sjakllsch} 1121.1Sjakllsch 1131.1Sjakllschstatic void 1141.1Sjakllschvalz_lcd_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context) 1151.1Sjakllsch{ 1161.1Sjakllsch struct valz_softc *sc = context; 1171.1Sjakllsch 1181.1Sjakllsch /* XXX magic */ 1191.1Sjakllsch switch (notify) { 1201.1Sjakllsch case 0x86: 1211.1Sjakllsch pmf_event_inject(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_UP); 1221.1Sjakllsch break; 1231.1Sjakllsch case 0x87: 1241.1Sjakllsch pmf_event_inject(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_DOWN); 1251.1Sjakllsch break; 1261.1Sjakllsch default: 1271.1Sjakllsch log(LOG_INFO, "%s: unknown notify: 0x%x\n", 1281.1Sjakllsch device_xname(sc->sc_dev), notify); 1291.1Sjakllsch break; 1301.1Sjakllsch } 1311.1Sjakllsch} 1321.1Sjakllsch 1331.1Sjakllschstatic void 1341.1Sjakllschvalz_locate_lcd(struct valz_softc *sc) 1351.1Sjakllsch{ 1361.1Sjakllsch ACPI_HANDLE parent; 1371.1Sjakllsch ACPI_STATUS rv; 1381.1Sjakllsch 1391.1Sjakllsch rv = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent); 1401.1Sjakllsch if (ACPI_FAILURE(rv)) 1411.1Sjakllsch return; 1421.1Sjakllsch 1431.1Sjakllsch AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100, 1441.1Sjakllsch valz_check_bcl, NULL, sc, NULL); 1451.1Sjakllsch} 1461.1Sjakllsch 1471.1Sjakllschstatic ACPI_STATUS 1481.1Sjakllschvalz_check_bcl(ACPI_HANDLE handle, UINT32 level, void *context, void **status) 1491.1Sjakllsch{ 1501.1Sjakllsch struct valz_softc *sc = context; 1511.1Sjakllsch ACPI_STATUS rv; 1521.1Sjakllsch ACPI_BUFFER buf; 1531.1Sjakllsch 1541.1Sjakllsch rv = acpi_eval_struct(handle, "_BCL", &buf); 1551.1Sjakllsch if (ACPI_FAILURE(rv)) 1561.1Sjakllsch return AE_OK; 1571.1Sjakllsch 1581.1Sjakllsch sc->sc_lcd = handle; 1591.1Sjakllsch 1601.1Sjakllsch if (buf.Pointer) 1611.1Sjakllsch AcpiOsFree(buf.Pointer); 1621.1Sjakllsch 1631.1Sjakllsch return AE_OK; 1641.1Sjakllsch} 1651.1Sjakllsch 1661.1Sjakllschstatic void 1671.1Sjakllschvalz_adjust_backlight(struct valz_softc *sc, enum valz_action action) 1681.1Sjakllsch{ 1691.1Sjakllsch ACPI_STATUS rv; 1701.1Sjakllsch ACPI_INTEGER old_level, new_level; 1711.1Sjakllsch 1721.1Sjakllsch if (sc->sc_lcd == NULL) 1731.1Sjakllsch return; 1741.1Sjakllsch 1751.1Sjakllsch /* Get current backlight level. */ 1761.1Sjakllsch rv = acpi_eval_integer(sc->sc_lcd, "_BQC", &old_level); 1771.1Sjakllsch if (ACPI_FAILURE(rv)) { 1781.1Sjakllsch log(LOG_CRIT, "%s: _BQC failed evaluation: %s\n", 1791.1Sjakllsch device_xname(sc->sc_dev), AcpiFormatException(rv)); 1801.1Sjakllsch return; 1811.1Sjakllsch } 1821.1Sjakllsch 1831.1Sjakllsch new_level = old_level; 1841.1Sjakllsch 1851.1Sjakllsch switch (action) { 1861.1Sjakllsch case VALZ_BACKLIGHT_DECREASE: 1871.1Sjakllsch if(old_level >= 10) 1881.1Sjakllsch new_level -= 10; 1891.1Sjakllsch break; 1901.1Sjakllsch case VALZ_BACKLIGHT_INCREASE: 1911.1Sjakllsch if(old_level <= 60) 1921.1Sjakllsch new_level += 10; 1931.1Sjakllsch break; 1941.1Sjakllsch default: 1951.1Sjakllsch return; 1961.1Sjakllsch } 1971.1Sjakllsch 1981.1Sjakllsch if (new_level == old_level) 1991.1Sjakllsch return; 2001.1Sjakllsch 2011.1Sjakllsch rv = acpi_eval_set_integer(sc->sc_lcd, "_BCM", new_level); 2021.1Sjakllsch if (ACPI_FAILURE(rv)) 2031.1Sjakllsch log(LOG_CRIT, "%s: _BCM failed evaluation: %s\n", 2041.1Sjakllsch device_xname(sc->sc_dev), AcpiFormatException(rv)); 2051.1Sjakllsch} 2061.1Sjakllsch 2071.1Sjakllschstatic void 2081.1Sjakllschvalz_pmf_brightness_decrease(device_t self) 2091.1Sjakllsch{ 2101.1Sjakllsch struct valz_softc *sc; 2111.1Sjakllsch sc = device_private(self); 2121.1Sjakllsch valz_adjust_backlight(sc, VALZ_BACKLIGHT_DECREASE); 2131.1Sjakllsch} 2141.1Sjakllsch 2151.1Sjakllschstatic void 2161.1Sjakllschvalz_pmf_brightness_increase(device_t self) 2171.1Sjakllsch{ 2181.1Sjakllsch struct valz_softc *sc; 2191.1Sjakllsch sc = device_private(self); 2201.1Sjakllsch valz_adjust_backlight(sc, VALZ_BACKLIGHT_INCREASE); 2211.1Sjakllsch} 222