xref: /netbsd-src/sys/dev/acpi/vald_acpi.c (revision f273a7a174ebed441f3363e0c944bd42390ca256)
1 /*	$NetBSD: vald_acpi.c,v 1.8 2021/12/07 21:37:36 andvar 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.8 2021/12/07 21:37:36 andvar 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
vald_acpi_match(device_t parent,cfdata_t match,void * aux)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
vald_acpi_attach(device_t parent,device_t self,void * aux)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
vald_acpi_notify_handler(ACPI_HANDLE handle,uint32_t notify,void * context)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
vald_acpi_event(void * arg)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
vald_acpi_ghci_get(struct vald_acpi_softc * sc,uint32_t reg,uint32_t * value,uint32_t * result)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
vald_acpi_ghci_set(struct vald_acpi_softc * sc,uint32_t reg,uint32_t value,uint32_t * result)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
vald_acpi_libright_get_bus(ACPI_HANDLE handle,uint32_t level,void * context,void ** 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 return: %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
vald_acpi_libright_get(struct vald_acpi_softc * sc)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
vald_acpi_libright_set(struct vald_acpi_softc * sc,int UpDown)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 Minimum 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
vald_acpi_video_switch(struct vald_acpi_softc * sc)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
vald_acpi_bcm_set(ACPI_HANDLE handle,uint32_t bright)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
vald_acpi_dssx_set(uint32_t value)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
vald_acpi_fan_switch(struct vald_acpi_softc * sc)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