Home | History | Annotate | Line # | Download | only in acpi
vald_acpi.c revision 1.4.4.2
      1 /*	$NetBSD: vald_acpi.c,v 1.4.4.2 2010/05/30 05:17:17 rmind Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Masanori Kanaoka.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright 2001 Bill Sommerfeld.
     34  * All rights reserved.
     35  *
     36  * Redistribution and use in source and binary forms, with or without
     37  * modification, are permitted provided that the following conditions
     38  * are met:
     39  * 1. Redistributions of source code must retain the above copyright
     40  *    notice, this list of conditions and the following disclaimer.
     41  * 2. Redistributions in binary form must reproduce the above copyright
     42  *    notice, this list of conditions and the following disclaimer in the
     43  *    documentation and/or other materials provided with the distribution.
     44  * 3. All advertising materials mentioning features or use of this software
     45  *    must display the following acknowledgement:
     46  *	This product includes software developed for the NetBSD Project by
     47  *	Wasabi Systems, Inc.
     48  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     49  *    or promote products derived from this software without specific prior
     50  *    written permission.
     51  *
     52  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     54  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     55  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     56  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     57  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     58  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     59  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     60  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     61  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     62  * POSSIBILITY OF SUCH DAMAGE.
     63  */
     64 
     65 /*
     66  * ACPI VALD Driver for Toshiba Libretto L3.
     67  *	This driver is based on acpibat driver.
     68  */
     69 
     70 /*
     71  * Obtain information of Toshiba "GHCI" Method from next URL.
     72  *           http://www.buzzard.org.uk/toshiba/docs.html
     73  *           http://memebeam.org/toys/ToshibaAcpiDriver
     74  */
     75 
     76 #include <sys/cdefs.h>
     77 __KERNEL_RCSID(0, "$NetBSD: vald_acpi.c,v 1.4.4.2 2010/05/30 05:17:17 rmind Exp $");
     78 
     79 #include <sys/param.h>
     80 #include <sys/systm.h>
     81 #include <sys/device.h>
     82 
     83 #include <dev/acpi/acpica.h>
     84 #include <dev/acpi/acpireg.h>
     85 #include <dev/acpi/acpivar.h>
     86 
     87 #define _COMPONENT          ACPI_RESOURCE_COMPONENT
     88 ACPI_MODULE_NAME            ("vald_acpi")
     89 
     90 #define GHCI_WORDS 6
     91 #define GHCI_FIFO_EMPTY  0x8c00
     92 #define GHCI_NOT_SUPPORT  0x8000
     93 
     94 #define GHCI_BACKLIGHT		0x0002
     95 #define GHCI_ACADAPTOR		0x0003
     96 #define GHCI_FAN		0x0004
     97 #define GHCI_SYSTEM_EVENT_FIFO	0x0016
     98 #define GHCI_DISPLAY_DEVICE	0x001C
     99 #define GHCI_HOTKEY_EVENT	0x001E
    100 
    101 #define GHCI_ON			0x0001
    102 #define GHCI_OFF		0x0000
    103 #define GHCI_ENABLE		0x0001
    104 #define GHCI_DISABLE		0x0000
    105 
    106 #define GHCI_CRT		0x0002
    107 #define GHCI_LCD		0x0001
    108 
    109 
    110 struct vald_acpi_softc {
    111 	device_t sc_dev;		/* base device glue */
    112 	struct acpi_devnode *sc_node;	/* our ACPI devnode */
    113 	int sc_flags;			/* see below */
    114 
    115 	ACPI_HANDLE lcd_handle;		/* lcd handle */
    116 	int *lcd_level;			/* lcd brightness table */
    117 	int lcd_num;			/* size of lcd brightness table */
    118 	int lcd_index;			/* index of lcd brightness table */
    119 
    120 	ACPI_INTEGER sc_ac_status;	/* AC adaptor status when attach */
    121 };
    122 
    123 static const char * const vald_acpi_hids[] = {
    124 	"TOS6200",
    125 	NULL
    126 };
    127 
    128 #define LIBRIGHT_HOLD	0x00
    129 #define LIBRIGHT_UP	0x01
    130 #define LIBRIGHT_DOWN	0x02
    131 
    132 static int	vald_acpi_match(device_t, cfdata_t, void *);
    133 static void	vald_acpi_attach(device_t, device_t, void *);
    134 
    135 static void	vald_acpi_event(void *);
    136 static void	vald_acpi_notify_handler(ACPI_HANDLE, uint32_t, void *);
    137 
    138 #define ACPI_NOTIFY_ValdStatusChanged	0x80
    139 
    140 
    141 static ACPI_STATUS	vald_acpi_ghci_get(struct vald_acpi_softc *, uint32_t,
    142 					uint32_t *, uint32_t *);
    143 static ACPI_STATUS	vald_acpi_ghci_set(struct vald_acpi_softc *, uint32_t,
    144 					uint32_t, uint32_t *);
    145 
    146 static ACPI_STATUS	vald_acpi_libright_get_bus(ACPI_HANDLE, uint32_t,
    147 					void *, void **);
    148 static void		vald_acpi_libright_get(struct vald_acpi_softc *);
    149 static void		vald_acpi_libright_set(struct vald_acpi_softc *, int);
    150 
    151 static void		vald_acpi_video_switch(struct vald_acpi_softc *);
    152 static void		vald_acpi_fan_switch(struct vald_acpi_softc *);
    153 
    154 static ACPI_STATUS	vald_acpi_bcm_set(ACPI_HANDLE, uint32_t);
    155 static ACPI_STATUS	vald_acpi_dssx_set(uint32_t);
    156 
    157 CFATTACH_DECL_NEW(vald_acpi, sizeof(struct vald_acpi_softc),
    158     vald_acpi_match, vald_acpi_attach, NULL, NULL);
    159 
    160 /*
    161  * vald_acpi_match:
    162  *
    163  *	Autoconfiguration `match' routine.
    164  */
    165 static int
    166 vald_acpi_match(device_t parent, cfdata_t match, void *aux)
    167 {
    168 	struct acpi_attach_args *aa = aux;
    169 
    170 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
    171 		return (0);
    172 
    173 	return (acpi_match_hid(aa->aa_node->ad_devinfo, vald_acpi_hids));
    174 }
    175 
    176 /*
    177  * vald_acpi_attach:
    178  *
    179  *	Autoconfiguration `attach' routine.
    180  */
    181 static void
    182 vald_acpi_attach(device_t parent, device_t self, void *aux)
    183 {
    184 	struct vald_acpi_softc *sc = device_private(self);
    185 	struct acpi_attach_args *aa = aux;
    186 	ACPI_STATUS rv;
    187 	uint32_t value, result;
    188 
    189 	aprint_naive(": Toshiba VALD\n");
    190 	aprint_normal(": Toshiba VALD\n");
    191 
    192 	sc->sc_node = aa->aa_node;
    193 	sc->sc_dev = self;
    194 
    195 	/* Get AC adaptor status via _PSR. */
    196 	rv = acpi_eval_integer(ACPI_ROOT_OBJECT, "\\_SB_.ADP1._PSR",
    197 	    &sc->sc_ac_status);
    198 	if (ACPI_FAILURE(rv))
    199 		aprint_error_dev(self, "Unable to evaluate _PSR: %s\n",
    200 		    AcpiFormatException(rv));
    201 	else
    202 		aprint_verbose_dev(self, "AC adaptor %sconnected\n",
    203 		    (sc->sc_ac_status == 0 ? "not ": ""));
    204 
    205 	/* Get LCD backlight status. */
    206 	rv = vald_acpi_ghci_get(sc, GHCI_BACKLIGHT, &value, &result);
    207 	if (ACPI_SUCCESS(rv)) {
    208 		if (result != 0)
    209 			aprint_error_dev(self, "can't get backlight status error=%d\n",
    210 			    result);
    211 		else
    212 			aprint_verbose_dev(self, "LCD backlight %s\n",
    213 			    ((value == GHCI_ON) ? "on" : "off"));
    214 	}
    215 
    216 	/* Enable SystemEventFIFO,HotkeyEvent */
    217 	rv = vald_acpi_ghci_set(sc, GHCI_SYSTEM_EVENT_FIFO, GHCI_ENABLE,
    218 	    &result);
    219 	if (ACPI_SUCCESS(rv) && result != 0)
    220 		aprint_error_dev(self, "can't enable SystemEventFIFO error=%d\n",
    221 		    result);
    222 
    223 	rv = vald_acpi_ghci_set(sc, GHCI_HOTKEY_EVENT, GHCI_ENABLE, &result);
    224 	if (ACPI_SUCCESS(rv) && result != 0)
    225 		aprint_error_dev(self, "can't enable HotkeyEvent error=%d\n",
    226 		    result);
    227 
    228 	/* Check SystemFIFO events. */
    229 	vald_acpi_event(sc);
    230 
    231 	/* Get LCD brightness level via _BCL. */
    232 	vald_acpi_libright_get(sc);
    233 
    234 	/* Set LCD brightness level via _BCM. */
    235 	vald_acpi_libright_set(sc, LIBRIGHT_HOLD);
    236 
    237 	/* enable vald notify */
    238 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "ENAB", NULL, NULL);
    239 
    240 	if (ACPI_SUCCESS(rv))
    241 		(void)acpi_register_notify(sc->sc_node,
    242 		    vald_acpi_notify_handler);
    243 }
    244 
    245 /*
    246  * vald_acpi_notify_handler:
    247  *
    248  *	Notify handler.
    249  */
    250 static void
    251 vald_acpi_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context)
    252 {
    253 	struct vald_acpi_softc *sc;
    254 	device_t self = context;
    255 
    256 	sc = device_private(self);
    257 
    258 	switch (notify) {
    259 
    260 	case ACPI_NOTIFY_ValdStatusChanged:
    261 		(void)AcpiOsExecute(OSL_NOTIFY_HANDLER, vald_acpi_event, sc);
    262 		break;
    263 
    264 	default:
    265 		aprint_error_dev(sc->sc_dev,
    266 		    "unknown notify 0x%02X\n", notify);
    267 		break;
    268 	}
    269 }
    270 
    271 /*
    272  * vald_acpi_event:
    273  *
    274  *	Check hotkey event and do it, if event occur.
    275  */
    276 static void
    277 vald_acpi_event(void *arg)
    278 {
    279 	struct vald_acpi_softc *sc = arg;
    280 	ACPI_STATUS rv;
    281 	uint32_t value, result;
    282 
    283 	while(1) {
    284 		rv = vald_acpi_ghci_get(sc, GHCI_SYSTEM_EVENT_FIFO, &value,
    285 		    &result);
    286 		if (ACPI_SUCCESS(rv) && result == 0) {
    287 
    288 			switch (value) {
    289 			case 0x1c3: /* Fn + F9 */
    290 				break;
    291 			case 0x1c2: /* Fn + F8 */
    292 				vald_acpi_fan_switch(sc);
    293 				break;
    294 			case 0x1c1: /* Fn + F7 */
    295 				vald_acpi_libright_set(sc, LIBRIGHT_UP);
    296 				break;
    297 			case 0x1c0: /* Fn + F6 */
    298 				vald_acpi_libright_set(sc, LIBRIGHT_DOWN);
    299 				break;
    300 			case 0x1bf: /* Fn + F5 */
    301 				vald_acpi_video_switch(sc);
    302 				break;
    303 			default:
    304 				break;
    305 			}
    306 		}
    307 		if (ACPI_FAILURE(rv) || result == GHCI_FIFO_EMPTY)
    308 			break;
    309 	}
    310 }
    311 
    312 /*
    313  * vald_acpi_ghci_get:
    314  *
    315  *	Get value via "GHCI" Method.
    316  */
    317 static ACPI_STATUS
    318 vald_acpi_ghci_get(struct vald_acpi_softc *sc,
    319     uint32_t reg, uint32_t *value, uint32_t *result)
    320 {
    321 	ACPI_STATUS rv;
    322 	ACPI_OBJECT Arg[GHCI_WORDS];
    323 	ACPI_OBJECT_LIST ArgList;
    324 	ACPI_OBJECT *param, *PrtElement;
    325 	ACPI_BUFFER buf;
    326 	int		i;
    327 
    328 	for (i = 0; i < GHCI_WORDS; i++) {
    329 		Arg[i].Type = ACPI_TYPE_INTEGER;
    330 		Arg[i].Integer.Value = 0;
    331 	}
    332 
    333 	Arg[0].Integer.Value = 0xfe00;
    334 	Arg[1].Integer.Value = reg;
    335 	Arg[2].Integer.Value = 0;
    336 
    337 	ArgList.Count = GHCI_WORDS;
    338 	ArgList.Pointer = Arg;
    339 
    340 	buf.Pointer = NULL;
    341 	buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    342 
    343 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle,
    344 	    "GHCI", &ArgList, &buf);
    345 	if (ACPI_FAILURE(rv)) {
    346 		aprint_error_dev(sc->sc_dev, "failed to evaluate GHCI: %s\n",
    347 		    AcpiFormatException(rv));
    348 		return (rv);
    349 	}
    350 
    351 	*result = GHCI_NOT_SUPPORT;
    352 	*value = 0;
    353 	param = buf.Pointer;
    354 	if (param->Type == ACPI_TYPE_PACKAGE) {
    355 		PrtElement = param->Package.Elements;
    356 		if (PrtElement->Type == ACPI_TYPE_INTEGER)
    357 			*result = PrtElement->Integer.Value;
    358 		PrtElement++;
    359 		PrtElement++;
    360 		if (PrtElement->Type == ACPI_TYPE_INTEGER)
    361 			*value = PrtElement->Integer.Value;
    362 	}
    363 
    364 	if (buf.Pointer)
    365 		ACPI_FREE(buf.Pointer);
    366 	return (rv);
    367 }
    368 
    369 /*
    370  * vald_acpi_ghci_set:
    371  *
    372  *	Set value via "GHCI" Method.
    373  */
    374 static ACPI_STATUS
    375 vald_acpi_ghci_set(struct vald_acpi_softc *sc,
    376     uint32_t reg, uint32_t value, uint32_t *result)
    377 {
    378 	ACPI_STATUS rv;
    379 	ACPI_OBJECT Arg[GHCI_WORDS];
    380 	ACPI_OBJECT_LIST ArgList;
    381 	ACPI_OBJECT *param, *PrtElement;
    382 	ACPI_BUFFER buf;
    383 	int	i;
    384 
    385 
    386 	for (i = 0; i < GHCI_WORDS; i++) {
    387 		Arg[i].Type = ACPI_TYPE_INTEGER;
    388 		Arg[i].Integer.Value = 0;
    389 	}
    390 
    391 	Arg[0].Integer.Value = 0xff00;
    392 	Arg[1].Integer.Value = reg;
    393 	Arg[2].Integer.Value = value;
    394 
    395 	ArgList.Count = GHCI_WORDS;
    396 	ArgList.Pointer = Arg;
    397 
    398 	buf.Pointer = NULL;
    399 	buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    400 
    401 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle,
    402 	    "GHCI", &ArgList, &buf);
    403 	if (ACPI_FAILURE(rv)) {
    404 		aprint_error_dev(sc->sc_dev, "failed to evaluate GHCI: %s\n",
    405 		    AcpiFormatException(rv));
    406 		return (rv);
    407 	}
    408 
    409 	*result = GHCI_NOT_SUPPORT;
    410 	param = buf.Pointer;
    411 	if (param->Type == ACPI_TYPE_PACKAGE) {
    412 		PrtElement = param->Package.Elements;
    413 	    	if (PrtElement->Type == ACPI_TYPE_INTEGER)
    414 			*result = PrtElement->Integer.Value;
    415 	}
    416 
    417 	if (buf.Pointer)
    418 		ACPI_FREE(buf.Pointer);
    419 	return (rv);
    420 }
    421 
    422 /*
    423  * vald_acpi_libright_get_bus:
    424  *
    425  *	Get LCD brightness level via "_BCL" Method,
    426  *	and save this handle.
    427  */
    428 static ACPI_STATUS
    429 vald_acpi_libright_get_bus(ACPI_HANDLE handle, uint32_t level,
    430     void *context, void **status)
    431 {
    432 	struct vald_acpi_softc *sc = context;
    433 	ACPI_STATUS rv;
    434 	ACPI_BUFFER buf;
    435 	ACPI_OBJECT *param, *PrtElement;
    436 	int i, *pi;
    437 
    438 	rv = acpi_eval_struct(handle, "_BCL", &buf);
    439 	if (ACPI_FAILURE(rv))
    440 		return (AE_OK);
    441 
    442 	sc->lcd_handle = handle;
    443 	param = buf.Pointer;
    444 	if (param->Type == ACPI_TYPE_PACKAGE) {
    445 		printf("_BCL retrun: %d packages\n", param->Package.Count);
    446 
    447 		sc->lcd_num = param->Package.Count;
    448 		sc->lcd_level = ACPI_ALLOCATE(sizeof(int) * sc->lcd_num);
    449 		if (sc->lcd_level == NULL) {
    450 			if (buf.Pointer)
    451 				ACPI_FREE(buf.Pointer);
    452 			return (AE_NO_MEMORY);
    453 		}
    454 
    455 		PrtElement = param->Package.Elements;
    456 		pi = sc->lcd_level;
    457 		for (i = 0; i < param->Package.Count; i++) {
    458 			if (PrtElement->Type == ACPI_TYPE_INTEGER) {
    459 				*pi = (unsigned)PrtElement->Integer.Value;
    460 				PrtElement++;
    461 				pi++;
    462 			}
    463 		}
    464 		if (sc->sc_ac_status == 1) /* AC adaptor on when attach */
    465 			sc->lcd_index = sc->lcd_num -1; /* MAX Brightness */
    466 		else
    467 			sc->lcd_index = 3;
    468 
    469 #ifdef ACPI_DEBUG
    470 		pi = sc->lcd_level;
    471 		printf("\t Full Power Level: %d\n", *pi);
    472 		printf("\t on Battery Level: %d\n", *(pi+1));
    473 		printf("\t Possible Level: ");
    474 		for (i = 2;i < sc->lcd_num; i++)
    475 			printf(" %d", *(pi+i));
    476 		printf("\n");
    477 #endif
    478 	}
    479 
    480 	if (buf.Pointer)
    481 		ACPI_FREE(buf.Pointer);
    482 	return (AE_OK);
    483 }
    484 
    485 /*
    486  * vald_acpi_libright_get:
    487  *
    488  *	Search node that have "_BCL" Method.
    489  */
    490 static void
    491 vald_acpi_libright_get(struct vald_acpi_softc *sc)
    492 {
    493 	ACPI_HANDLE parent;
    494 	ACPI_STATUS rv;
    495 
    496 	aprint_verbose_dev(sc->sc_dev, "get LCD brightness via _BCL\n");
    497 
    498 #ifdef ACPI_DEBUG
    499 	printf("acpi_libright_get: start\n");
    500 #endif
    501 	rv = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent);
    502 	if (ACPI_FAILURE(rv))
    503 		return;
    504 
    505 	AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100,
    506 	    vald_acpi_libright_get_bus, NULL, sc, NULL);
    507 }
    508 
    509 /*
    510  * vald_acpi_libright_set:
    511  *
    512  *	Figure up next status and set it.
    513  */
    514 static void
    515 vald_acpi_libright_set(struct vald_acpi_softc *sc, int UpDown)
    516 {
    517 	uint32_t backlight, backlight_new, result, bright;
    518 	ACPI_STATUS rv;
    519 	int *pi;
    520 
    521 	/* Skip,if it does not support _BCL. */
    522 	if (sc->lcd_handle == NULL)
    523 		return;
    524 
    525 	/* Get LCD backlight status. */
    526 	rv = vald_acpi_ghci_get(sc, GHCI_BACKLIGHT, &backlight, &result);
    527 	if (ACPI_FAILURE(rv) || result != 0)
    528 		return;
    529 
    530 	/* Figure up next status. */
    531 	backlight_new = backlight;
    532 	if (UpDown == LIBRIGHT_UP) {
    533 		if (backlight == 1)
    534 			sc->lcd_index++;
    535 		else {
    536 			/* backlight on */
    537 			backlight_new = 1;
    538 			sc->lcd_index = 2;
    539 		}
    540 	} else if (UpDown == LIBRIGHT_DOWN) {
    541 		if ((backlight == 1) && (sc->lcd_index > 2))
    542 			sc->lcd_index--;
    543 		else {
    544 			/* backlight off */
    545 			backlight_new = 0;
    546 			sc->lcd_index = 2;
    547 		}
    548 	}
    549 
    550 	/* Check index value. */
    551 	if (sc->lcd_index < 2)
    552 		sc->lcd_index = 2; /* index Minium Value */
    553 	if (sc->lcd_index >= sc->lcd_num)
    554 		sc->lcd_index = sc->lcd_num - 1;
    555 
    556 	/* Set LCD backlight,if status is changed. */
    557 	if (backlight_new != backlight) {
    558 		rv = vald_acpi_ghci_set(sc, GHCI_BACKLIGHT, backlight_new,
    559 		    &result);
    560 		if (ACPI_SUCCESS(rv) && result != 0)
    561 			aprint_error_dev(sc->sc_dev, "can't set LCD backlight %s error=%x\n",
    562 			    ((backlight_new == 1) ? "on" : "off"), result);
    563 	}
    564 
    565 	if (backlight_new == 1) {
    566 
    567 		pi = sc->lcd_level;
    568 		bright = *(pi + sc->lcd_index);
    569 
    570 		rv = vald_acpi_bcm_set(sc->lcd_handle, bright);
    571 		if (ACPI_FAILURE(rv))
    572 			aprint_error_dev(sc->sc_dev, "unable to evaluate _BCM: %s\n",
    573 			    AcpiFormatException(rv));
    574 	} else {
    575 		bright = 0;
    576 	}
    577 #ifdef ACPI_DEBUG
    578 	printf("LCD bright");
    579 	printf(" %s", ((UpDown == LIBRIGHT_UP) ? "up":""));
    580 	printf("%s\n", ((UpDown == LIBRIGHT_DOWN) ? "down":""));
    581 	printf("\t acpi_libright_set: Set brightness to %d%%\n", bright);
    582 #endif
    583 }
    584 
    585 /*
    586  * vald_acpi_video_switch:
    587  *
    588  *	Get video status(LCD/CRT) and set new video status.
    589  */
    590 static void
    591 vald_acpi_video_switch(struct vald_acpi_softc *sc)
    592 {
    593 	ACPI_STATUS	rv;
    594 	uint32_t	value, result;
    595 
    596 	/* Get video status. */
    597 	rv = vald_acpi_ghci_get(sc, GHCI_DISPLAY_DEVICE, &value, &result);
    598 	if (ACPI_FAILURE(rv))
    599 		return;
    600 	if (result != 0) {
    601 		aprint_error_dev(sc->sc_dev, "can't get video status  error=%x\n",
    602 		    result);
    603 		return;
    604 	}
    605 
    606 #ifdef ACPI_DEBUG
    607 	printf("Toggle LCD/CRT\n");
    608 	printf("\t Before switch, video status:   %s",
    609 	    (((value & GHCI_LCD) == GHCI_LCD) ? "LCD" : ""));
    610 	printf("%s\n", (((value & GHCI_CRT) == GHCI_CRT) ? "CRT": ""));
    611 #endif
    612 
    613 	/* Toggle LCD/CRT */
    614 	if (value & GHCI_LCD) {
    615 		value &= ~GHCI_LCD;
    616 		value |= GHCI_CRT;
    617 	} else if (value & GHCI_CRT){
    618 		value &= ~GHCI_CRT;
    619 		value |= GHCI_LCD;
    620 	}
    621 
    622 	rv = vald_acpi_dssx_set(value);
    623 	if (ACPI_FAILURE(rv))
    624 		aprint_error_dev(sc->sc_dev, "unable to evaluate DSSX: %s\n",
    625 		    AcpiFormatException(rv));
    626 
    627 }
    628 
    629 /*
    630  * vald_acpi_bcm_set:
    631  *
    632  *	Set LCD brightness via "_BCM" Method.
    633  */
    634 static ACPI_STATUS
    635 vald_acpi_bcm_set(ACPI_HANDLE handle, uint32_t bright)
    636 {
    637 	ACPI_STATUS rv;
    638 	ACPI_OBJECT Arg;
    639 	ACPI_OBJECT_LIST ArgList;
    640 
    641 	ArgList.Count = 1;
    642 	ArgList.Pointer = &Arg;
    643 
    644 	Arg.Type = ACPI_TYPE_INTEGER;
    645 	Arg.Integer.Value = bright;
    646 
    647 	rv = AcpiEvaluateObject(handle, "_BCM", &ArgList, NULL);
    648 	return (rv);
    649 }
    650 
    651 /*
    652  * vald_acpi_dssx_set:
    653  *
    654  *	Set value via "\\_SB_.VALX.DSSX" Method.
    655  */
    656 static ACPI_STATUS
    657 vald_acpi_dssx_set(uint32_t value)
    658 {
    659 	return acpi_eval_set_integer(NULL, "\\_SB_.VALX.DSSX", value);
    660 }
    661 
    662 /*
    663  * vald_acpi_fan_switch:
    664  *
    665  *	Get FAN status and set new FAN status.
    666  */
    667 static void
    668 vald_acpi_fan_switch(struct vald_acpi_softc *sc)
    669 {
    670 	ACPI_STATUS rv;
    671 	uint32_t value, result;
    672 
    673 	/* Get FAN status */
    674 	rv = vald_acpi_ghci_get(sc, GHCI_FAN, &value, &result);
    675 	if (ACPI_FAILURE(rv))
    676 		return;
    677 	if (result != 0) {
    678 		aprint_error_dev(sc->sc_dev, "can't get FAN status error=%d\n",
    679 		    result);
    680 		return;
    681 	}
    682 
    683 #ifdef ACPI_DEBUG
    684 	printf("Toggle FAN on/off\n");
    685 	printf("\t Before toggle, FAN status %s\n",
    686 	    (value == GHCI_OFF ? "off" : "on"));
    687 #endif
    688 
    689 	/* Toggle FAN on/off */
    690 	if (value == GHCI_OFF)
    691 		value = GHCI_ON;
    692 	else
    693 		value = GHCI_OFF;
    694 
    695 	/* Set FAN new status. */
    696 	rv = vald_acpi_ghci_set(sc, GHCI_FAN, value, &result);
    697 	if (ACPI_FAILURE(rv))
    698 		return;
    699 	if (result != 0) {
    700 		aprint_error_dev(sc->sc_dev, "can't set FAN status error=%d\n",
    701 		    result);
    702 		return;
    703 	}
    704 
    705 #ifdef ACPI_DEBUG
    706 	printf("\t After toggle, FAN status %s\n",
    707 	    (value == GHCI_OFF ? "off" : "on"));
    708 #endif
    709 }
    710