acpi_asus.c revision 133628
1128561Sphilip/*- 2128561Sphilip * Copyright (c) 2004 Philip Paeps <philip@FreeBSD.org> 3128561Sphilip * All rights reserved. 4128561Sphilip * 5128561Sphilip * Redistribution and use in source and binary forms, with or without 6128561Sphilip * modification, are permitted provided that the following conditions 7128561Sphilip * are met: 8128561Sphilip * 1. Redistributions of source code must retain the above copyright 9128561Sphilip * notice, this list of conditions and the following disclaimer. 10128561Sphilip * 2. Redistributions in binary form must reproduce the above copyright 11128561Sphilip * notice, this list of conditions and the following disclaimer in the 12128561Sphilip * documentation and/or other materials provided with the distribution. 13128561Sphilip * 14128561Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15128561Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16128561Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17128561Sphilip * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18128561Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19128561Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20128561Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21128561Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22128561Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23128561Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24128561Sphilip * SUCH DAMAGE. 25128561Sphilip * 26128561Sphilip */ 27128561Sphilip 28128561Sphilip#include <sys/cdefs.h> 29128561Sphilip__FBSDID("$FreeBSD: head/sys/dev/acpi_support/acpi_asus.c 133628 2004-08-13 06:22:29Z njl $"); 30128561Sphilip 31128561Sphilip/* 32128561Sphilip * Driver for extra ACPI-controlled gadgets (hotkeys, leds, etc) found on 33133095Sphilip * recent Asus (and Medion) laptops. Inspired by the acpi4asus project which 34128561Sphilip * implements these features in the Linux kernel. 35128561Sphilip * 36128561Sphilip * <http://sourceforge.net/projects/acpi4asus/> 37128561Sphilip * 38128561Sphilip * Currently should support most features, but could use some more testing. 39128561Sphilip * Particularly the display-switching stuff is a bit hairy. If you have an 40128561Sphilip * Asus laptop which doesn't appear to be supported, or strange things happen 41128561Sphilip * when using this driver, please report to <acpi@FreeBSD.org>. 42128561Sphilip * 43128561Sphilip */ 44128561Sphilip 45128561Sphilip#include "opt_acpi.h" 46128561Sphilip#include <sys/param.h> 47128561Sphilip#include <sys/kernel.h> 48129882Sphk#include <sys/module.h> 49128561Sphilip#include <sys/bus.h> 50128561Sphilip#include <sys/sbuf.h> 51128561Sphilip 52128561Sphilip#include "acpi.h" 53128561Sphilip#include <dev/acpica/acpivar.h> 54128561Sphilip#include <dev/led/led.h> 55128561Sphilip 56128561Sphilip#define _COMPONENT ACPI_ASUS 57128561SphilipACPI_MODULE_NAME("ASUS") 58128561Sphilip 59128561Sphilipstruct acpi_asus_model { 60128561Sphilip char *name; 61128561Sphilip 62128561Sphilip char *mled_set; 63128561Sphilip char *tled_set; 64128561Sphilip char *wled_set; 65128561Sphilip 66128561Sphilip char *brn_get; 67128561Sphilip char *brn_set; 68128561Sphilip char *brn_up; 69128561Sphilip char *brn_dn; 70128561Sphilip 71128561Sphilip char *lcd_get; 72128561Sphilip char *lcd_set; 73128561Sphilip 74128561Sphilip char *disp_get; 75128561Sphilip char *disp_set; 76128561Sphilip}; 77128561Sphilip 78133095Sphilipstruct acpi_asus_led { 79133095Sphilip struct cdev *cdev; 80133095Sphilip device_t dev; 81133095Sphilip enum { 82133095Sphilip ACPI_ASUS_LED_MLED, 83133095Sphilip ACPI_ASUS_LED_TLED, 84133095Sphilip ACPI_ASUS_LED_WLED, 85133095Sphilip } type; 86133095Sphilip}; 87133095Sphilip 88128561Sphilipstruct acpi_asus_softc { 89128561Sphilip device_t dev; 90128561Sphilip ACPI_HANDLE handle; 91128561Sphilip 92128561Sphilip struct acpi_asus_model *model; 93128561Sphilip struct sysctl_ctx_list sysctl_ctx; 94128561Sphilip struct sysctl_oid *sysctl_tree; 95128561Sphilip 96133095Sphilip struct acpi_asus_led s_mled; 97133095Sphilip struct acpi_asus_led s_tled; 98133095Sphilip struct acpi_asus_led s_wled; 99128561Sphilip 100128561Sphilip int s_brn; 101128561Sphilip int s_disp; 102128561Sphilip int s_lcd; 103128561Sphilip}; 104128561Sphilip 105128561Sphilip/* Models we know about */ 106128561Sphilipstatic struct acpi_asus_model acpi_asus_models[] = { 107128561Sphilip { 108128561Sphilip .name = "L2D", 109128561Sphilip .mled_set = "MLED", 110128561Sphilip .wled_set = "WLED", 111128561Sphilip .brn_up = "\\Q0E", 112128561Sphilip .brn_dn = "\\Q0F", 113128561Sphilip .lcd_get = "\\SGP0", 114128561Sphilip .lcd_set = "\\Q10" 115128561Sphilip }, 116128561Sphilip { 117128561Sphilip .name = "L3C", 118128561Sphilip .mled_set = "MLED", 119128561Sphilip .wled_set = "WLED", 120128561Sphilip .brn_get = "GPLV", 121128561Sphilip .brn_set = "SPLV", 122128561Sphilip .lcd_get = "\\GL32", 123128561Sphilip .lcd_set = "\\_SB.PCI0.PX40.ECD0._Q10" 124128561Sphilip }, 125128561Sphilip { 126128561Sphilip .name = "L3D", 127128561Sphilip .mled_set = "MLED", 128128561Sphilip .wled_set = "WLED", 129128561Sphilip .brn_get = "GPLV", 130128561Sphilip .brn_set = "SPLV", 131128561Sphilip .lcd_get = "\\BKLG", 132128561Sphilip .lcd_set = "\\Q10" 133128561Sphilip }, 134128561Sphilip { 135128561Sphilip .name = "L3H", 136128561Sphilip .mled_set = "MLED", 137128561Sphilip .wled_set = "WLED", 138128561Sphilip .brn_get = "GPLV", 139128561Sphilip .brn_set = "SPLV", 140128561Sphilip .lcd_get = "\\_SB.PCI0.PM.PBC", 141128561Sphilip .lcd_set = "EHK", 142128561Sphilip .disp_get = "\\_SB.INFB", 143128561Sphilip .disp_set = "SDSP" 144128561Sphilip }, 145128561Sphilip { 146128561Sphilip .name = "L8L" 147128561Sphilip /* Only has hotkeys, apparantly */ 148128561Sphilip }, 149128561Sphilip { 150128561Sphilip .name = "M1A", 151128561Sphilip .mled_set = "MLED", 152128561Sphilip .brn_up = "\\_SB.PCI0.PX40.EC0.Q0E", 153128561Sphilip .brn_dn = "\\_SB.PCI0.PX40.EC0.Q0F", 154128561Sphilip .lcd_get = "\\PNOF", 155128561Sphilip .lcd_set = "\\_SB.PCI0.PX40.EC0.Q10" 156128561Sphilip }, 157128561Sphilip { 158128561Sphilip .name = "M2E", 159128561Sphilip .mled_set = "MLED", 160128561Sphilip .wled_set = "WLED", 161128561Sphilip .brn_get = "GPLV", 162128561Sphilip .brn_set = "SPLV", 163128561Sphilip .lcd_get = "\\GP06", 164128561Sphilip .lcd_set = "\\Q10" 165128561Sphilip }, 166128561Sphilip { 167128561Sphilip .name = "P30", 168128561Sphilip .wled_set = "WLED", 169128561Sphilip .brn_up = "\\_SB.PCI0.LPCB.EC0._Q68", 170128561Sphilip .brn_dn = "\\_SB.PCI0.LPCB.EC0._Q69", 171128561Sphilip .lcd_get = "\\BKLT", 172128561Sphilip .lcd_set = "\\_SB.PCI0.LPCB.EC0._Q0E" 173128561Sphilip }, 174128561Sphilip 175128561Sphilip { .name = NULL } 176128561Sphilip}; 177128561Sphilip 178133628SnjlACPI_SERIAL_DECL(asus, "ACPI ASUS extras"); 179133628Snjl 180128561Sphilip/* Function prototypes */ 181128561Sphilipstatic int acpi_asus_probe(device_t dev); 182128561Sphilipstatic int acpi_asus_attach(device_t dev); 183128561Sphilipstatic int acpi_asus_detach(device_t dev); 184128561Sphilip 185133095Sphilipstatic void acpi_asus_led(struct acpi_asus_led *led, int state); 186128561Sphilip 187128561Sphilipstatic int acpi_asus_sysctl_brn(SYSCTL_HANDLER_ARGS); 188128561Sphilipstatic int acpi_asus_sysctl_lcd(SYSCTL_HANDLER_ARGS); 189128561Sphilipstatic int acpi_asus_sysctl_disp(SYSCTL_HANDLER_ARGS); 190128561Sphilip 191128561Sphilipstatic void acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context); 192128561Sphilip 193128561Sphilipstatic device_method_t acpi_asus_methods[] = { 194128561Sphilip DEVMETHOD(device_probe, acpi_asus_probe), 195128561Sphilip DEVMETHOD(device_attach, acpi_asus_attach), 196128561Sphilip DEVMETHOD(device_detach, acpi_asus_detach), 197128561Sphilip 198128561Sphilip { 0, 0 } 199128561Sphilip}; 200128561Sphilip 201128561Sphilipstatic driver_t acpi_asus_driver = { 202128561Sphilip "acpi_asus", 203128561Sphilip acpi_asus_methods, 204128561Sphilip sizeof(struct acpi_asus_softc) 205128561Sphilip}; 206128561Sphilip 207128561Sphilipstatic devclass_t acpi_asus_devclass; 208128561Sphilip 209128561SphilipDRIVER_MODULE(acpi_asus, acpi, acpi_asus_driver, acpi_asus_devclass, 0, 0); 210128561SphilipMODULE_DEPEND(acpi_asus, acpi, 1, 1, 1); 211128561Sphilip 212128561Sphilipstatic int 213128561Sphilipacpi_asus_probe(device_t dev) 214128561Sphilip{ 215128561Sphilip struct acpi_asus_model *model; 216128561Sphilip struct acpi_asus_softc *sc; 217128561Sphilip struct sbuf *sb; 218128561Sphilip ACPI_BUFFER Buf; 219128561Sphilip ACPI_OBJECT Arg, *Obj; 220128561Sphilip ACPI_OBJECT_LIST Args; 221131284Snjl static char *asus_ids[] = { "ATK0100", NULL }; 222128561Sphilip 223128561Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 224128561Sphilip 225128561Sphilip if (!acpi_disabled("asus") && 226131284Snjl ACPI_ID_PROBE(device_get_parent(dev), dev, asus_ids)) { 227128561Sphilip sc = device_get_softc(dev); 228128561Sphilip sc->dev = dev; 229128561Sphilip sc->handle = acpi_get_handle(dev); 230128561Sphilip 231128561Sphilip sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 232128561Sphilip 233128561Sphilip if (sb == NULL) 234128561Sphilip return (ENOMEM); 235128561Sphilip 236128561Sphilip Arg.Type = ACPI_TYPE_INTEGER; 237128561Sphilip Arg.Integer.Value = 0; 238128561Sphilip 239128561Sphilip Args.Count = 1; 240128561Sphilip Args.Pointer = &Arg; 241128561Sphilip 242128561Sphilip Buf.Pointer = NULL; 243128561Sphilip Buf.Length = ACPI_ALLOCATE_BUFFER; 244128561Sphilip 245128561Sphilip AcpiEvaluateObject(sc->handle, "INIT", &Args, &Buf); 246128561Sphilip 247128561Sphilip Obj = Buf.Pointer; 248128561Sphilip 249128561Sphilip for (model = acpi_asus_models; model->name != NULL; model++) 250128561Sphilip if (strcmp(Obj->String.Pointer, model->name) == 0) { 251128561Sphilip sbuf_printf(sb, "Asus %s Laptop Extras", 252128561Sphilip Obj->String.Pointer); 253128561Sphilip sbuf_finish(sb); 254128561Sphilip 255128561Sphilip sc->model = model; 256128561Sphilip device_set_desc(dev, sbuf_data(sb)); 257128561Sphilip 258128561Sphilip sbuf_delete(sb); 259128561Sphilip AcpiOsFree(Buf.Pointer); 260128561Sphilip return (0); 261128561Sphilip } 262128561Sphilip 263128561Sphilip sbuf_printf(sb, "Unsupported Asus laptop detected: %s\n", 264128561Sphilip Obj->String.Pointer); 265128561Sphilip sbuf_finish(sb); 266128561Sphilip 267128561Sphilip device_printf(dev, sbuf_data(sb)); 268128561Sphilip 269128561Sphilip sbuf_delete(sb); 270128561Sphilip AcpiOsFree(Buf.Pointer); 271128561Sphilip } 272128561Sphilip 273128561Sphilip return (ENXIO); 274128561Sphilip} 275128561Sphilip 276128561Sphilipstatic int 277128561Sphilipacpi_asus_attach(device_t dev) 278128561Sphilip{ 279128561Sphilip struct acpi_asus_softc *sc; 280128561Sphilip struct acpi_softc *acpi_sc; 281128561Sphilip 282128561Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 283128561Sphilip 284128561Sphilip sc = device_get_softc(dev); 285128561Sphilip acpi_sc = acpi_device_get_parent_softc(dev); 286128561Sphilip 287128561Sphilip /* Build sysctl tree */ 288128561Sphilip sysctl_ctx_init(&sc->sysctl_ctx); 289128561Sphilip sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 290128561Sphilip SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 291128561Sphilip OID_AUTO, "asus", CTLFLAG_RD, 0, ""); 292128561Sphilip 293128561Sphilip /* Attach leds */ 294133095Sphilip if (sc->model->mled_set) { 295133095Sphilip sc->s_mled.dev = dev; 296133095Sphilip sc->s_mled.type = ACPI_ASUS_LED_MLED; 297133095Sphilip sc->s_mled.cdev = 298133095Sphilip led_create((led_t *)acpi_asus_led, &sc->s_mled, "mled"); 299133095Sphilip } 300128561Sphilip 301133095Sphilip if (sc->model->tled_set) { 302133095Sphilip sc->s_tled.dev = dev; 303133095Sphilip sc->s_tled.type = ACPI_ASUS_LED_TLED; 304133095Sphilip sc->s_tled.cdev = 305133095Sphilip led_create((led_t *)acpi_asus_led, &sc->s_tled, "tled"); 306133095Sphilip } 307128561Sphilip 308133095Sphilip if (sc->model->wled_set) { 309133095Sphilip sc->s_wled.dev = dev; 310133095Sphilip sc->s_wled.type = ACPI_ASUS_LED_WLED; 311133095Sphilip sc->s_wled.cdev = 312133095Sphilip led_create((led_t *)acpi_asus_led, &sc->s_wled, "wled"); 313133095Sphilip } 314128561Sphilip 315128561Sphilip /* Attach brightness for GPLV/SPLV models */ 316132610Snjl if (sc->model->brn_get && ACPI_SUCCESS(acpi_GetInteger(sc->handle, 317132610Snjl sc->model->brn_get, &sc->s_brn))) 318128561Sphilip SYSCTL_ADD_PROC(&sc->sysctl_ctx, 319128561Sphilip SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 320128561Sphilip "lcd_brightness", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 321128561Sphilip acpi_asus_sysctl_brn, "I", "brightness of the lcd panel"); 322128561Sphilip 323128561Sphilip /* Attach brightness for other models */ 324128561Sphilip if (sc->model->brn_up && 325132610Snjl ACPI_SUCCESS(AcpiEvaluateObject(sc->handle, sc->model->brn_up, 326132610Snjl NULL, NULL)) && 327132610Snjl ACPI_SUCCESS(AcpiEvaluateObject(sc->handle, sc->model->brn_dn, 328132610Snjl NULL, NULL))) 329128561Sphilip SYSCTL_ADD_PROC(&sc->sysctl_ctx, 330128561Sphilip SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 331128561Sphilip "lcd_brightness", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 332128561Sphilip acpi_asus_sysctl_brn, "I", "brightness of the lcd panel"); 333128561Sphilip 334128561Sphilip /* Attach display switching */ 335132610Snjl if (sc->model->disp_get && ACPI_SUCCESS(acpi_GetInteger(sc->handle, 336132610Snjl sc->model->disp_get, &sc->s_disp))) 337128561Sphilip SYSCTL_ADD_PROC(&sc->sysctl_ctx, 338128561Sphilip SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 339128561Sphilip "video_output", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 340128561Sphilip acpi_asus_sysctl_disp, "I", "display output state"); 341128561Sphilip 342128561Sphilip /* Attach LCD state, easy for most models... */ 343132610Snjl if (sc->model->lcd_get && strncmp(sc->model->name, "L3H", 3) != 0 && 344132610Snjl ACPI_SUCCESS(acpi_GetInteger(sc->handle, sc->model->lcd_get, 345133092Snjl &sc->s_lcd))) { 346128561Sphilip SYSCTL_ADD_PROC(&sc->sysctl_ctx, 347128561Sphilip SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 348128561Sphilip "lcd_backlight", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 349128561Sphilip acpi_asus_sysctl_lcd, "I", "state of the lcd backlight"); 350133092Snjl } else if (sc->model->lcd_get) { 351128561Sphilip ACPI_BUFFER Buf; 352128561Sphilip ACPI_OBJECT Arg[2], Obj; 353128561Sphilip ACPI_OBJECT_LIST Args; 354128561Sphilip 355133092Snjl /* ...a nightmare for the L3H */ 356128561Sphilip Arg[0].Type = ACPI_TYPE_INTEGER; 357128561Sphilip Arg[0].Integer.Value = 0x02; 358128561Sphilip Arg[1].Type = ACPI_TYPE_INTEGER; 359128561Sphilip Arg[1].Integer.Value = 0x03; 360128561Sphilip 361128561Sphilip Args.Count = 2; 362128561Sphilip Args.Pointer = Arg; 363128561Sphilip 364128561Sphilip Buf.Length = sizeof(Obj); 365128561Sphilip Buf.Pointer = &Obj; 366128561Sphilip 367128561Sphilip if (ACPI_SUCCESS(AcpiEvaluateObject(sc->handle, 368132610Snjl sc->model->lcd_get, &Args, &Buf)) && 369128561Sphilip Obj.Type == ACPI_TYPE_INTEGER) { 370128561Sphilip sc->s_lcd = Obj.Integer.Value >> 8; 371128561Sphilip 372128561Sphilip SYSCTL_ADD_PROC(&sc->sysctl_ctx, 373128561Sphilip SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 374128561Sphilip "lcd_backlight", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 375128561Sphilip acpi_asus_sysctl_lcd, "I", 376128561Sphilip "state of the lcd backlight"); 377128561Sphilip } 378128561Sphilip } 379128561Sphilip 380128561Sphilip /* Activate hotkeys */ 381128561Sphilip AcpiEvaluateObject(sc->handle, "BSTS", NULL, NULL); 382128561Sphilip 383128561Sphilip /* Handle notifies */ 384132610Snjl AcpiInstallNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY, 385132610Snjl acpi_asus_notify, dev); 386128561Sphilip 387128561Sphilip return (0); 388128561Sphilip} 389128561Sphilip 390128561Sphilipstatic int 391128561Sphilipacpi_asus_detach(device_t dev) 392128561Sphilip{ 393128561Sphilip struct acpi_asus_softc *sc; 394128561Sphilip 395128561Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 396128561Sphilip 397128561Sphilip sc = device_get_softc(dev); 398128561Sphilip 399128561Sphilip /* Turn the lights off */ 400128561Sphilip if (sc->model->mled_set) 401133095Sphilip led_destroy(sc->s_mled.cdev); 402128561Sphilip 403128561Sphilip if (sc->model->tled_set) 404133095Sphilip led_destroy(sc->s_tled.cdev); 405128561Sphilip 406128561Sphilip if (sc->model->wled_set) 407133095Sphilip led_destroy(sc->s_wled.cdev); 408128561Sphilip 409128561Sphilip /* Remove notify handler */ 410132610Snjl AcpiRemoveNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY, 411132610Snjl acpi_asus_notify); 412128561Sphilip 413128561Sphilip /* Free sysctl tree */ 414128561Sphilip sysctl_ctx_free(&sc->sysctl_ctx); 415128561Sphilip 416128561Sphilip return (0); 417128561Sphilip} 418128561Sphilip 419128561Sphilipstatic void 420133095Sphilipacpi_asus_led(struct acpi_asus_led *led, int state) 421128561Sphilip{ 422128561Sphilip struct acpi_asus_softc *sc; 423133095Sphilip char *method; 424128561Sphilip 425128561Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 426128561Sphilip 427133095Sphilip sc = device_get_softc(led->dev); 428128561Sphilip 429133095Sphilip switch (led->type) { 430133095Sphilip case ACPI_ASUS_LED_MLED: 431133095Sphilip method = sc->model->mled_set; 432128561Sphilip 433133095Sphilip /* Note: inverted */ 434133095Sphilip state = !state; 435133095Sphilip break; 436133095Sphilip case ACPI_ASUS_LED_TLED: 437133095Sphilip method = sc->model->tled_set; 438133095Sphilip break; 439133095Sphilip case ACPI_ASUS_LED_WLED: 440133095Sphilip method = sc->model->wled_set; 441133095Sphilip break; 442133118Sphilip default: 443133118Sphilip printf("acpi_asus_led: invalid LED type %d\n", 444133118Sphilip (int)led->type); 445133118Sphilip return; 446133095Sphilip } 447128561Sphilip 448133095Sphilip acpi_SetInteger(sc->handle, method, state); 449128561Sphilip} 450128561Sphilip 451128561Sphilipstatic int 452128561Sphilipacpi_asus_sysctl_brn(SYSCTL_HANDLER_ARGS) 453128561Sphilip{ 454128561Sphilip struct acpi_asus_softc *sc; 455128561Sphilip int brn, err; 456128561Sphilip 457128561Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 458128561Sphilip 459128561Sphilip sc = (struct acpi_asus_softc *)oidp->oid_arg1; 460133628Snjl ACPI_SERIAL_BEGIN(asus); 461128561Sphilip 462128561Sphilip /* Sanity check */ 463128561Sphilip brn = sc->s_brn; 464128561Sphilip err = sysctl_handle_int(oidp, &brn, 0, req); 465128561Sphilip 466132610Snjl if (err != 0 || req->newptr == NULL) 467133092Snjl goto out; 468128561Sphilip 469133092Snjl if (brn < 0 || brn > 15) { 470133092Snjl err = EINVAL; 471133092Snjl goto out; 472133092Snjl } 473128561Sphilip 474128561Sphilip /* Keep track and update */ 475128561Sphilip sc->s_brn = brn; 476128561Sphilip 477128561Sphilip if (sc->model->brn_set) 478133092Snjl acpi_SetInteger(sc->handle, sc->model->brn_set, brn); 479128561Sphilip else { 480128561Sphilip brn -= sc->s_brn; 481128561Sphilip 482128561Sphilip while (brn != 0) { 483132610Snjl AcpiEvaluateObject(sc->handle, (brn > 0) ? 484128561Sphilip sc->model->brn_up : sc->model->brn_dn, 485128561Sphilip NULL, NULL); 486128561Sphilip (brn > 0) ? brn-- : brn++; 487128561Sphilip } 488128561Sphilip } 489128561Sphilip 490133092Snjlout: 491133628Snjl ACPI_SERIAL_END(asus); 492133092Snjl return (err); 493128561Sphilip} 494128561Sphilip 495128561Sphilipstatic int 496128561Sphilipacpi_asus_sysctl_lcd(SYSCTL_HANDLER_ARGS) 497128561Sphilip{ 498128561Sphilip struct acpi_asus_softc *sc; 499128561Sphilip int lcd, err; 500128561Sphilip 501128561Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 502128561Sphilip 503128561Sphilip sc = (struct acpi_asus_softc *)oidp->oid_arg1; 504133628Snjl ACPI_SERIAL_BEGIN(asus); 505128561Sphilip 506128561Sphilip /* Sanity check */ 507128561Sphilip lcd = sc->s_lcd; 508128561Sphilip err = sysctl_handle_int(oidp, &lcd, 0, req); 509128561Sphilip 510132610Snjl if (err != 0 || req->newptr == NULL) 511133092Snjl goto out; 512128561Sphilip 513133092Snjl if (lcd < 0 || lcd > 1) { 514133092Snjl err = EINVAL; 515133092Snjl goto out; 516133092Snjl } 517128561Sphilip 518128561Sphilip /* Keep track and update */ 519128561Sphilip sc->s_lcd = lcd; 520128561Sphilip 521128561Sphilip /* Most models just need a lcd_set evaluated, the L3H is trickier */ 522128561Sphilip if (strncmp(sc->model->name, "L3H", 3) != 0) 523132610Snjl AcpiEvaluateObject(sc->handle, sc->model->lcd_set, NULL, NULL); 524133092Snjl else 525133092Snjl acpi_SetInteger(sc->handle, sc->model->lcd_set, 0x7); 526128561Sphilip 527133092Snjlout: 528133628Snjl ACPI_SERIAL_END(asus); 529133092Snjl return (err); 530128561Sphilip} 531128561Sphilip 532128561Sphilipstatic int 533128561Sphilipacpi_asus_sysctl_disp(SYSCTL_HANDLER_ARGS) 534128561Sphilip{ 535128561Sphilip struct acpi_asus_softc *sc; 536128561Sphilip int disp, err; 537128561Sphilip 538128561Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 539128561Sphilip 540128561Sphilip sc = (struct acpi_asus_softc *)oidp->oid_arg1; 541128561Sphilip 542128561Sphilip /* Sanity check */ 543133628Snjl ACPI_SERIAL_BEGIN(asus); 544128561Sphilip disp = sc->s_disp; 545128561Sphilip err = sysctl_handle_int(oidp, &disp, 0, req); 546128561Sphilip 547132610Snjl if (err != 0 || req->newptr == NULL) 548133092Snjl goto out; 549128561Sphilip 550133092Snjl if (disp < 0 || disp > 7) { 551133092Snjl err = EINVAL; 552133092Snjl goto out; 553133092Snjl } 554128561Sphilip 555128561Sphilip /* Keep track and update */ 556128561Sphilip sc->s_disp = disp; 557133092Snjl acpi_SetInteger(sc->handle, sc->model->disp_set, disp); 558128561Sphilip 559133092Snjlout: 560133628Snjl ACPI_SERIAL_END(asus); 561133092Snjl return (err); 562128561Sphilip} 563128561Sphilip 564128561Sphilipstatic void 565128561Sphilipacpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context) 566128561Sphilip{ 567128561Sphilip struct acpi_asus_softc *sc; 568128561Sphilip struct acpi_softc *acpi_sc; 569128561Sphilip 570128561Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 571128561Sphilip 572128561Sphilip sc = device_get_softc((device_t)context); 573128561Sphilip acpi_sc = acpi_device_get_parent_softc(sc->dev); 574128561Sphilip 575133628Snjl ACPI_SERIAL_BEGIN(asus); 576128561Sphilip if ((notify & ~0x10) <= 15) { 577132610Snjl sc->s_brn = notify & ~0x10; 578128561Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n"); 579128561Sphilip } else if ((notify & ~0x20) <= 15) { 580132610Snjl sc->s_brn = notify & ~0x20; 581128561Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Brightness decreased\n"); 582128561Sphilip } else if (notify == 0x33) { 583128561Sphilip sc->s_lcd = 1; 584128561Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned on\n"); 585128561Sphilip } else if (notify == 0x34) { 586128561Sphilip sc->s_lcd = 0; 587128561Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned off\n"); 588128561Sphilip } else { 589128561Sphilip /* Notify devd(8) */ 590128561Sphilip acpi_UserNotify("ASUS", h, notify); 591128561Sphilip } 592133628Snjl ACPI_SERIAL_END(asus); 593128561Sphilip} 594