xref: /netbsd-src/sys/dev/acpi/vald_acpi.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: vald_acpi.c,v 1.4 2010/04/15 07:02:24 jruoho 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 2010/04/15 07:02:24 jruoho 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