Home | History | Annotate | Line # | Download | only in acpi
vald_acpi.c revision 1.5.32.1
      1 /*	$NetBSD: vald_acpi.c,v 1.5.32.1 2021/04/03 22:28:43 thorpej 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.5.32.1 2021/04/03 22:28:43 thorpej 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 struct device_compatible_entry compat_data[] = {
    124 	{ .compat = "TOS6200" },
    125 	DEVICE_COMPAT_EOL
    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 	return acpi_compatible_match(aa, compat_data);
    171 }
    172 
    173 /*
    174  * vald_acpi_attach:
    175  *
    176  *	Autoconfiguration `attach' routine.
    177  */
    178 static void
    179 vald_acpi_attach(device_t parent, device_t self, void *aux)
    180 {
    181 	struct vald_acpi_softc *sc = device_private(self);
    182 	struct acpi_attach_args *aa = aux;
    183 	ACPI_STATUS rv;
    184 	uint32_t value, result;
    185 
    186 	aprint_naive(": Toshiba VALD\n");
    187 	aprint_normal(": Toshiba VALD\n");
    188 
    189 	sc->sc_node = aa->aa_node;
    190 	sc->sc_dev = self;
    191 
    192 	/* Get AC adaptor status via _PSR. */
    193 	rv = acpi_eval_integer(ACPI_ROOT_OBJECT, "\\_SB_.ADP1._PSR",
    194 	    &sc->sc_ac_status);
    195 	if (ACPI_FAILURE(rv))
    196 		aprint_error_dev(self, "Unable to evaluate _PSR: %s\n",
    197 		    AcpiFormatException(rv));
    198 	else
    199 		aprint_verbose_dev(self, "AC adaptor %sconnected\n",
    200 		    (sc->sc_ac_status == 0 ? "not ": ""));
    201 
    202 	/* Get LCD backlight status. */
    203 	rv = vald_acpi_ghci_get(sc, GHCI_BACKLIGHT, &value, &result);
    204 	if (ACPI_SUCCESS(rv)) {
    205 		if (result != 0)
    206 			aprint_error_dev(self,
    207 			    "can't get backlight status error=%d\n", result);
    208 		else
    209 			aprint_verbose_dev(self, "LCD backlight %s\n",
    210 			    ((value == GHCI_ON) ? "on" : "off"));
    211 	}
    212 
    213 	/* Enable SystemEventFIFO,HotkeyEvent */
    214 	rv = vald_acpi_ghci_set(sc, GHCI_SYSTEM_EVENT_FIFO, GHCI_ENABLE,
    215 	    &result);
    216 	if (ACPI_SUCCESS(rv) && result != 0)
    217 		aprint_error_dev(self,
    218 		    "can't enable SystemEventFIFO error=%d\n", result);
    219 
    220 	rv = vald_acpi_ghci_set(sc, GHCI_HOTKEY_EVENT, GHCI_ENABLE, &result);
    221 	if (ACPI_SUCCESS(rv) && result != 0)
    222 		aprint_error_dev(self, "can't enable HotkeyEvent error=%d\n",
    223 		    result);
    224 
    225 	/* Check SystemFIFO events. */
    226 	vald_acpi_event(sc);
    227 
    228 	/* Get LCD brightness level via _BCL. */
    229 	vald_acpi_libright_get(sc);
    230 
    231 	/* Set LCD brightness level via _BCM. */
    232 	vald_acpi_libright_set(sc, LIBRIGHT_HOLD);
    233 
    234 	/* enable vald notify */
    235 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "ENAB", NULL, NULL);
    236 
    237 	if (ACPI_SUCCESS(rv))
    238 		(void)acpi_register_notify(sc->sc_node,
    239 		    vald_acpi_notify_handler);
    240 }
    241 
    242 /*
    243  * vald_acpi_notify_handler:
    244  *
    245  *	Notify handler.
    246  */
    247 static void
    248 vald_acpi_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context)
    249 {
    250 	struct vald_acpi_softc *sc;
    251 	device_t self = context;
    252 
    253 	sc = device_private(self);
    254 
    255 	switch (notify) {
    256 
    257 	case ACPI_NOTIFY_ValdStatusChanged:
    258 		(void)AcpiOsExecute(OSL_NOTIFY_HANDLER, vald_acpi_event, sc);
    259 		break;
    260 
    261 	default:
    262 		aprint_error_dev(sc->sc_dev,
    263 		    "unknown notify 0x%02X\n", notify);
    264 		break;
    265 	}
    266 }
    267 
    268 /*
    269  * vald_acpi_event:
    270  *
    271  *	Check hotkey event and do it, if event occur.
    272  */
    273 static void
    274 vald_acpi_event(void *arg)
    275 {
    276 	struct vald_acpi_softc *sc = arg;
    277 	ACPI_STATUS rv;
    278 	uint32_t value, result;
    279 
    280 	while(1) {
    281 		rv = vald_acpi_ghci_get(sc, GHCI_SYSTEM_EVENT_FIFO, &value,
    282 		    &result);
    283 		if (ACPI_SUCCESS(rv) && result == 0) {
    284 
    285 			switch (value) {
    286 			case 0x1c3: /* Fn + F9 */
    287 				break;
    288 			case 0x1c2: /* Fn + F8 */
    289 				vald_acpi_fan_switch(sc);
    290 				break;
    291 			case 0x1c1: /* Fn + F7 */
    292 				vald_acpi_libright_set(sc, LIBRIGHT_UP);
    293 				break;
    294 			case 0x1c0: /* Fn + F6 */
    295 				vald_acpi_libright_set(sc, LIBRIGHT_DOWN);
    296 				break;
    297 			case 0x1bf: /* Fn + F5 */
    298 				vald_acpi_video_switch(sc);
    299 				break;
    300 			default:
    301 				break;
    302 			}
    303 		}
    304 		if (ACPI_FAILURE(rv) || result == GHCI_FIFO_EMPTY)
    305 			break;
    306 	}
    307 }
    308 
    309 /*
    310  * vald_acpi_ghci_get:
    311  *
    312  *	Get value via "GHCI" Method.
    313  */
    314 static ACPI_STATUS
    315 vald_acpi_ghci_get(struct vald_acpi_softc *sc,
    316     uint32_t reg, uint32_t *value, uint32_t *result)
    317 {
    318 	ACPI_STATUS rv;
    319 	ACPI_OBJECT Arg[GHCI_WORDS];
    320 	ACPI_OBJECT_LIST ArgList;
    321 	ACPI_OBJECT *param, *PrtElement;
    322 	ACPI_BUFFER buf;
    323 	int		i;
    324 
    325 	for (i = 0; i < GHCI_WORDS; i++) {
    326 		Arg[i].Type = ACPI_TYPE_INTEGER;
    327 		Arg[i].Integer.Value = 0;
    328 	}
    329 
    330 	Arg[0].Integer.Value = 0xfe00;
    331 	Arg[1].Integer.Value = reg;
    332 	Arg[2].Integer.Value = 0;
    333 
    334 	ArgList.Count = GHCI_WORDS;
    335 	ArgList.Pointer = Arg;
    336 
    337 	buf.Pointer = NULL;
    338 	buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    339 
    340 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle,
    341 	    "GHCI", &ArgList, &buf);
    342 	if (ACPI_FAILURE(rv)) {
    343 		aprint_error_dev(sc->sc_dev, "failed to evaluate GHCI: %s\n",
    344 		    AcpiFormatException(rv));
    345 		return (rv);
    346 	}
    347 
    348 	*result = GHCI_NOT_SUPPORT;
    349 	*value = 0;
    350 	param = buf.Pointer;
    351 	if (param->Type == ACPI_TYPE_PACKAGE) {
    352 		PrtElement = param->Package.Elements;
    353 		if (PrtElement->Type == ACPI_TYPE_INTEGER)
    354 			*result = PrtElement->Integer.Value;
    355 		PrtElement++;
    356 		PrtElement++;
    357 		if (PrtElement->Type == ACPI_TYPE_INTEGER)
    358 			*value = PrtElement->Integer.Value;
    359 	}
    360 
    361 	if (buf.Pointer)
    362 		ACPI_FREE(buf.Pointer);
    363 	return (rv);
    364 }
    365 
    366 /*
    367  * vald_acpi_ghci_set:
    368  *
    369  *	Set value via "GHCI" Method.
    370  */
    371 static ACPI_STATUS
    372 vald_acpi_ghci_set(struct vald_acpi_softc *sc,
    373     uint32_t reg, uint32_t value, uint32_t *result)
    374 {
    375 	ACPI_STATUS rv;
    376 	ACPI_OBJECT Arg[GHCI_WORDS];
    377 	ACPI_OBJECT_LIST ArgList;
    378 	ACPI_OBJECT *param, *PrtElement;
    379 	ACPI_BUFFER buf;
    380 	int	i;
    381 
    382 
    383 	for (i = 0; i < GHCI_WORDS; i++) {
    384 		Arg[i].Type = ACPI_TYPE_INTEGER;
    385 		Arg[i].Integer.Value = 0;
    386 	}
    387 
    388 	Arg[0].Integer.Value = 0xff00;
    389 	Arg[1].Integer.Value = reg;
    390 	Arg[2].Integer.Value = value;
    391 
    392 	ArgList.Count = GHCI_WORDS;
    393 	ArgList.Pointer = Arg;
    394 
    395 	buf.Pointer = NULL;
    396 	buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    397 
    398 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle,
    399 	    "GHCI", &ArgList, &buf);
    400 	if (ACPI_FAILURE(rv)) {
    401 		aprint_error_dev(sc->sc_dev, "failed to evaluate GHCI: %s\n",
    402 		    AcpiFormatException(rv));
    403 		return (rv);
    404 	}
    405 
    406 	*result = GHCI_NOT_SUPPORT;
    407 	param = buf.Pointer;
    408 	if (param->Type == ACPI_TYPE_PACKAGE) {
    409 		PrtElement = param->Package.Elements;
    410 	    	if (PrtElement->Type == ACPI_TYPE_INTEGER)
    411 			*result = PrtElement->Integer.Value;
    412 	}
    413 
    414 	if (buf.Pointer)
    415 		ACPI_FREE(buf.Pointer);
    416 	return (rv);
    417 }
    418 
    419 /*
    420  * vald_acpi_libright_get_bus:
    421  *
    422  *	Get LCD brightness level via "_BCL" Method,
    423  *	and save this handle.
    424  */
    425 static ACPI_STATUS
    426 vald_acpi_libright_get_bus(ACPI_HANDLE handle, uint32_t level,
    427     void *context, void **status)
    428 {
    429 	struct vald_acpi_softc *sc = context;
    430 	ACPI_STATUS rv;
    431 	ACPI_BUFFER buf;
    432 	ACPI_OBJECT *param, *PrtElement;
    433 	int i, *pi;
    434 
    435 	rv = acpi_eval_struct(handle, "_BCL", &buf);
    436 	if (ACPI_FAILURE(rv))
    437 		return (AE_OK);
    438 
    439 	sc->lcd_handle = handle;
    440 	param = buf.Pointer;
    441 	if (param->Type == ACPI_TYPE_PACKAGE) {
    442 		printf("_BCL retrun: %d packages\n", param->Package.Count);
    443 
    444 		sc->lcd_num = param->Package.Count;
    445 		sc->lcd_level = ACPI_ALLOCATE(sizeof(int) * sc->lcd_num);
    446 		if (sc->lcd_level == NULL) {
    447 			if (buf.Pointer)
    448 				ACPI_FREE(buf.Pointer);
    449 			return (AE_NO_MEMORY);
    450 		}
    451 
    452 		PrtElement = param->Package.Elements;
    453 		pi = sc->lcd_level;
    454 		for (i = 0; i < param->Package.Count; i++) {
    455 			if (PrtElement->Type == ACPI_TYPE_INTEGER) {
    456 				*pi = (unsigned)PrtElement->Integer.Value;
    457 				PrtElement++;
    458 				pi++;
    459 			}
    460 		}
    461 		if (sc->sc_ac_status == 1) /* AC adaptor on when attach */
    462 			sc->lcd_index = sc->lcd_num -1; /* MAX Brightness */
    463 		else
    464 			sc->lcd_index = 3;
    465 
    466 #ifdef ACPI_DEBUG
    467 		pi = sc->lcd_level;
    468 		printf("\t Full Power Level: %d\n", *pi);
    469 		printf("\t on Battery Level: %d\n", *(pi+1));
    470 		printf("\t Possible Level: ");
    471 		for (i = 2;i < sc->lcd_num; i++)
    472 			printf(" %d", *(pi+i));
    473 		printf("\n");
    474 #endif
    475 	}
    476 
    477 	if (buf.Pointer)
    478 		ACPI_FREE(buf.Pointer);
    479 	return (AE_OK);
    480 }
    481 
    482 /*
    483  * vald_acpi_libright_get:
    484  *
    485  *	Search node that have "_BCL" Method.
    486  */
    487 static void
    488 vald_acpi_libright_get(struct vald_acpi_softc *sc)
    489 {
    490 	ACPI_HANDLE parent;
    491 	ACPI_STATUS rv;
    492 
    493 	aprint_verbose_dev(sc->sc_dev, "get LCD brightness via _BCL\n");
    494 
    495 #ifdef ACPI_DEBUG
    496 	printf("acpi_libright_get: start\n");
    497 #endif
    498 	rv = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent);
    499 	if (ACPI_FAILURE(rv))
    500 		return;
    501 
    502 	AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100,
    503 	    vald_acpi_libright_get_bus, NULL, sc, NULL);
    504 }
    505 
    506 /*
    507  * vald_acpi_libright_set:
    508  *
    509  *	Figure up next status and set it.
    510  */
    511 static void
    512 vald_acpi_libright_set(struct vald_acpi_softc *sc, int UpDown)
    513 {
    514 	uint32_t backlight, backlight_new, result, bright;
    515 	ACPI_STATUS rv;
    516 	int *pi;
    517 
    518 	/* Skip,if it does not support _BCL. */
    519 	if (sc->lcd_handle == NULL)
    520 		return;
    521 
    522 	/* Get LCD backlight status. */
    523 	rv = vald_acpi_ghci_get(sc, GHCI_BACKLIGHT, &backlight, &result);
    524 	if (ACPI_FAILURE(rv) || result != 0)
    525 		return;
    526 
    527 	/* Figure up next status. */
    528 	backlight_new = backlight;
    529 	if (UpDown == LIBRIGHT_UP) {
    530 		if (backlight == 1)
    531 			sc->lcd_index++;
    532 		else {
    533 			/* backlight on */
    534 			backlight_new = 1;
    535 			sc->lcd_index = 2;
    536 		}
    537 	} else if (UpDown == LIBRIGHT_DOWN) {
    538 		if ((backlight == 1) && (sc->lcd_index > 2))
    539 			sc->lcd_index--;
    540 		else {
    541 			/* backlight off */
    542 			backlight_new = 0;
    543 			sc->lcd_index = 2;
    544 		}
    545 	}
    546 
    547 	/* Check index value. */
    548 	if (sc->lcd_index < 2)
    549 		sc->lcd_index = 2; /* index Minium Value */
    550 	if (sc->lcd_index >= sc->lcd_num)
    551 		sc->lcd_index = sc->lcd_num - 1;
    552 
    553 	/* Set LCD backlight,if status is changed. */
    554 	if (backlight_new != backlight) {
    555 		rv = vald_acpi_ghci_set(sc, GHCI_BACKLIGHT, backlight_new,
    556 		    &result);
    557 		if (ACPI_SUCCESS(rv) && result != 0)
    558 			aprint_error_dev(sc->sc_dev,
    559 			    "can't set LCD backlight %s error=%x\n",
    560 			    ((backlight_new == 1) ? "on" : "off"), result);
    561 	}
    562 
    563 	if (backlight_new == 1) {
    564 
    565 		pi = sc->lcd_level;
    566 		bright = *(pi + sc->lcd_index);
    567 
    568 		rv = vald_acpi_bcm_set(sc->lcd_handle, bright);
    569 		if (ACPI_FAILURE(rv))
    570 			aprint_error_dev(sc->sc_dev,
    571 			    "unable to evaluate _BCM: %s\n",
    572 			    AcpiFormatException(rv));
    573 	} else {
    574 		bright = 0;
    575 	}
    576 #ifdef ACPI_DEBUG
    577 	printf("LCD bright");
    578 	printf(" %s", ((UpDown == LIBRIGHT_UP) ? "up":""));
    579 	printf("%s\n", ((UpDown == LIBRIGHT_DOWN) ? "down":""));
    580 	printf("\t acpi_libright_set: Set brightness to %d%%\n", bright);
    581 #endif
    582 }
    583 
    584 /*
    585  * vald_acpi_video_switch:
    586  *
    587  *	Get video status(LCD/CRT) and set new video status.
    588  */
    589 static void
    590 vald_acpi_video_switch(struct vald_acpi_softc *sc)
    591 {
    592 	ACPI_STATUS	rv;
    593 	uint32_t	value, result;
    594 
    595 	/* Get video status. */
    596 	rv = vald_acpi_ghci_get(sc, GHCI_DISPLAY_DEVICE, &value, &result);
    597 	if (ACPI_FAILURE(rv))
    598 		return;
    599 	if (result != 0) {
    600 		aprint_error_dev(sc->sc_dev,
    601 		    "can't get video status  error=%x\n", result);
    602 		return;
    603 	}
    604 
    605 #ifdef ACPI_DEBUG
    606 	printf("Toggle LCD/CRT\n");
    607 	printf("\t Before switch, video status:   %s",
    608 	    (((value & GHCI_LCD) == GHCI_LCD) ? "LCD" : ""));
    609 	printf("%s\n", (((value & GHCI_CRT) == GHCI_CRT) ? "CRT": ""));
    610 #endif
    611 
    612 	/* Toggle LCD/CRT */
    613 	if (value & GHCI_LCD) {
    614 		value &= ~GHCI_LCD;
    615 		value |= GHCI_CRT;
    616 	} else if (value & GHCI_CRT){
    617 		value &= ~GHCI_CRT;
    618 		value |= GHCI_LCD;
    619 	}
    620 
    621 	rv = vald_acpi_dssx_set(value);
    622 	if (ACPI_FAILURE(rv))
    623 		aprint_error_dev(sc->sc_dev, "unable to evaluate DSSX: %s\n",
    624 		    AcpiFormatException(rv));
    625 
    626 }
    627 
    628 /*
    629  * vald_acpi_bcm_set:
    630  *
    631  *	Set LCD brightness via "_BCM" Method.
    632  */
    633 static ACPI_STATUS
    634 vald_acpi_bcm_set(ACPI_HANDLE handle, uint32_t bright)
    635 {
    636 	ACPI_STATUS rv;
    637 	ACPI_OBJECT Arg;
    638 	ACPI_OBJECT_LIST ArgList;
    639 
    640 	ArgList.Count = 1;
    641 	ArgList.Pointer = &Arg;
    642 
    643 	Arg.Type = ACPI_TYPE_INTEGER;
    644 	Arg.Integer.Value = bright;
    645 
    646 	rv = AcpiEvaluateObject(handle, "_BCM", &ArgList, NULL);
    647 	return (rv);
    648 }
    649 
    650 /*
    651  * vald_acpi_dssx_set:
    652  *
    653  *	Set value via "\\_SB_.VALX.DSSX" Method.
    654  */
    655 static ACPI_STATUS
    656 vald_acpi_dssx_set(uint32_t value)
    657 {
    658 	return acpi_eval_set_integer(NULL, "\\_SB_.VALX.DSSX", value);
    659 }
    660 
    661 /*
    662  * vald_acpi_fan_switch:
    663  *
    664  *	Get FAN status and set new FAN status.
    665  */
    666 static void
    667 vald_acpi_fan_switch(struct vald_acpi_softc *sc)
    668 {
    669 	ACPI_STATUS rv;
    670 	uint32_t value, result;
    671 
    672 	/* Get FAN status */
    673 	rv = vald_acpi_ghci_get(sc, GHCI_FAN, &value, &result);
    674 	if (ACPI_FAILURE(rv))
    675 		return;
    676 	if (result != 0) {
    677 		aprint_error_dev(sc->sc_dev, "can't get FAN status error=%d\n",
    678 		    result);
    679 		return;
    680 	}
    681 
    682 #ifdef ACPI_DEBUG
    683 	printf("Toggle FAN on/off\n");
    684 	printf("\t Before toggle, FAN status %s\n",
    685 	    (value == GHCI_OFF ? "off" : "on"));
    686 #endif
    687 
    688 	/* Toggle FAN on/off */
    689 	if (value == GHCI_OFF)
    690 		value = GHCI_ON;
    691 	else
    692 		value = GHCI_OFF;
    693 
    694 	/* Set FAN new status. */
    695 	rv = vald_acpi_ghci_set(sc, GHCI_FAN, value, &result);
    696 	if (ACPI_FAILURE(rv))
    697 		return;
    698 	if (result != 0) {
    699 		aprint_error_dev(sc->sc_dev, "can't set FAN status error=%d\n",
    700 		    result);
    701 		return;
    702 	}
    703 
    704 #ifdef ACPI_DEBUG
    705 	printf("\t After toggle, FAN status %s\n",
    706 	    (value == GHCI_OFF ? "off" : "on"));
    707 #endif
    708 }
    709