1 /* $NetBSD: vald_acpi.c,v 1.30 2009/09/16 10:47:54 mlelstv Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Copyright 2001 Bill Sommerfeld.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
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
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.
65 /* #define VALD_ACPI_DEBUG */
68 * ACPI VALD Driver for Toshiba Libretto L3.
69 * This driver is based on acpibat driver.
73 * Obtain information of Toshiba "GHCI" Method from next URL.
74 * http://www.buzzard.org.uk/toshiba/docs.html
75 * http://memebeam.org/toys/ToshibaAcpiDriver
78 #include <sys/cdefs.h>
79 __KERNEL_RCSID(0, "$NetBSD: vald_acpi.c,v 1.30 2009/09/16 10:47:54 mlelstv Exp $");
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/device.h>
85 #include <dev/acpi/acpica.h>
86 #include <dev/acpi/acpireg.h>
87 #include <dev/acpi/acpivar.h>
89 #define _COMPONENT ACPI_RESOURCE_COMPONENT
90 ACPI_MODULE_NAME ("vald_acpi")
93 #define GHCI_FIFO_EMPTY 0x8c00
94 #define GHCI_NOT_SUPPORT 0x8000
96 #define GHCI_BACKLIGHT 0x0002
97 #define GHCI_ACADAPTOR 0x0003
98 #define GHCI_FAN 0x0004
99 #define GHCI_SYSTEM_EVENT_FIFO 0x0016
100 #define GHCI_DISPLAY_DEVICE 0x001C
101 #define GHCI_HOTKEY_EVENT 0x001E
103 #define GHCI_ON 0x0001
104 #define GHCI_OFF 0x0000
105 #define GHCI_ENABLE 0x0001
106 #define GHCI_DISABLE 0x0000
108 #define GHCI_CRT 0x0002
109 #define GHCI_LCD 0x0001
112 struct vald_acpi_softc
{
113 device_t sc_dev
; /* base device glue */
114 struct acpi_devnode
*sc_node
; /* our ACPI devnode */
115 int sc_flags
; /* see below */
117 ACPI_HANDLE lcd_handle
; /* lcd handle */
118 int *lcd_level
; /* lcd brightness table */
119 int lcd_num
; /* size of lcd brightness table */
120 int lcd_index
; /* index of lcd brightness table */
122 ACPI_INTEGER sc_ac_status
; /* AC adaptor status when attach */
125 static const char * const vald_acpi_hids
[] = {
130 #define AVALD_F_VERBOSE 0x01 /* verbose events */
132 #define LIBRIGHT_HOLD 0x00
133 #define LIBRIGHT_UP 0x01
134 #define LIBRIGHT_DOWN 0x02
136 static int vald_acpi_match(device_t
, cfdata_t
, void *);
137 static void vald_acpi_attach(device_t
, device_t
, void *);
139 static void vald_acpi_event(void *);
140 static void vald_acpi_notify_handler(ACPI_HANDLE
, UINT32
, void *);
142 #define ACPI_NOTIFY_ValdStatusChanged 0x80
145 static ACPI_STATUS
vald_acpi_ghci_get(struct vald_acpi_softc
*, UINT32
,
147 static ACPI_STATUS
vald_acpi_ghci_set(struct vald_acpi_softc
*, UINT32
,
150 static ACPI_STATUS
vald_acpi_libright_get_bus(ACPI_HANDLE
, UINT32
, void *,
152 static void vald_acpi_libright_get(struct vald_acpi_softc
*);
153 static void vald_acpi_libright_set(struct vald_acpi_softc
*, int);
155 static void vald_acpi_video_switch(struct vald_acpi_softc
*);
156 static void vald_acpi_fan_switch(struct vald_acpi_softc
*);
158 static ACPI_STATUS
vald_acpi_bcm_set(ACPI_HANDLE
, UINT32
);
159 static ACPI_STATUS
vald_acpi_dssx_set(UINT32
);
161 CFATTACH_DECL_NEW(vald_acpi
, sizeof(struct vald_acpi_softc
),
162 vald_acpi_match
, vald_acpi_attach
, NULL
, NULL
);
167 * Autoconfiguration `match' routine.
170 vald_acpi_match(device_t parent
, cfdata_t match
, void *aux
)
172 struct acpi_attach_args
*aa
= aux
;
174 if (aa
->aa_node
->ad_type
!= ACPI_TYPE_DEVICE
)
177 return (acpi_match_hid(aa
->aa_node
->ad_devinfo
, vald_acpi_hids
));
183 * Autoconfiguration `attach' routine.
186 vald_acpi_attach(device_t parent
, device_t self
, void *aux
)
188 struct vald_acpi_softc
*sc
= device_private(self
);
189 struct acpi_attach_args
*aa
= aux
;
191 UINT32 value
, result
;
193 aprint_naive(": Toshiba VALD\n");
194 aprint_normal(": Toshiba VALD\n");
196 sc
->sc_node
= aa
->aa_node
;
199 /* Get AC adaptor status via _PSR. */
200 rv
= acpi_eval_integer(ACPI_ROOT_OBJECT
, "\\_SB_.ADP1._PSR",
202 if (ACPI_FAILURE(rv
))
203 aprint_error_dev(self
, "Unable to evaluate _PSR: %s\n",
204 AcpiFormatException(rv
));
206 aprint_verbose_dev(self
, "AC adaptor %sconnected\n",
207 (sc
->sc_ac_status
== 0 ? "not ": ""));
209 /* Get LCD backlight status. */
210 rv
= vald_acpi_ghci_get(sc
, GHCI_BACKLIGHT
, &value
, &result
);
211 if (ACPI_SUCCESS(rv
)) {
213 aprint_error_dev(self
, "can't get backlight status error=%d\n",
216 aprint_verbose_dev(self
, "LCD backlight %s\n",
217 ((value
== GHCI_ON
) ? "on" : "off"));
220 /* Enable SystemEventFIFO,HotkeyEvent */
221 rv
= vald_acpi_ghci_set(sc
, GHCI_SYSTEM_EVENT_FIFO
, GHCI_ENABLE
,
223 if (ACPI_SUCCESS(rv
) && result
!= 0)
224 aprint_error_dev(self
, "can't enable SystemEventFIFO error=%d\n",
227 rv
= vald_acpi_ghci_set(sc
, GHCI_HOTKEY_EVENT
, GHCI_ENABLE
, &result
);
228 if (ACPI_SUCCESS(rv
) && result
!= 0)
229 aprint_error_dev(self
, "can't enable HotkeyEvent error=%d\n",
232 /* Check SystemFIFO events. */
235 /* Get LCD brightness level via _BCL. */
236 vald_acpi_libright_get(sc
);
238 /* Set LCD brightness level via _BCM. */
239 vald_acpi_libright_set(sc
, LIBRIGHT_HOLD
);
241 /* enable vald notify */
242 AcpiEvaluateObject(sc
->sc_node
->ad_handle
, "ENAB", NULL
, NULL
);
243 rv
= AcpiInstallNotifyHandler(sc
->sc_node
->ad_handle
,
244 ACPI_DEVICE_NOTIFY
, vald_acpi_notify_handler
, sc
);
245 if (ACPI_FAILURE(rv
))
246 aprint_error_dev(self
, "can't install DEVICE NOTIFY handler: %s\n",
247 AcpiFormatException(rv
));
251 * vald_acpi_notify_handler:
256 vald_acpi_notify_handler(ACPI_HANDLE handle
, UINT32 notify
,
259 struct vald_acpi_softc
*sc
= context
;
263 case ACPI_NOTIFY_ValdStatusChanged
:
264 #ifdef VALD_ACPI_DEBUG
265 printf("%s: received ValdStatusChanged message.\n",
266 device_xname(sc
->sc_dev
));
267 #endif /* VALD_ACPI_DEBUG */
269 rv
= AcpiOsExecute(OSL_NOTIFY_HANDLER
, vald_acpi_event
, sc
);
271 if (ACPI_FAILURE(rv
))
272 aprint_error_dev(sc
->sc_dev
, "WARNING: unable to queue vald change "
273 "event: %s\n", AcpiFormatException(rv
));
277 aprint_error_dev(sc
->sc_dev
, "received unknown notify messages: 0x%x\n",
286 * Check hotkey event and do it, if event occur.
289 vald_acpi_event(void *arg
)
291 struct vald_acpi_softc
*sc
= arg
;
293 UINT32 value
, result
;
296 rv
= vald_acpi_ghci_get(sc
, GHCI_SYSTEM_EVENT_FIFO
, &value
,
298 if (ACPI_SUCCESS(rv
) && result
== 0) {
299 #ifdef VALD_ACPI_DEBUG
300 printf("%s: System Event %x\n", device_xname(sc
->sc_dev
),
304 case 0x1c3: /* Fn + F9 */
306 case 0x1c2: /* Fn + F8 */
307 vald_acpi_fan_switch(sc
);
309 case 0x1c1: /* Fn + F7 */
310 vald_acpi_libright_set(sc
, LIBRIGHT_UP
);
312 case 0x1c0: /* Fn + F6 */
313 vald_acpi_libright_set(sc
, LIBRIGHT_DOWN
);
315 case 0x1bf: /* Fn + F5 */
316 vald_acpi_video_switch(sc
);
322 if (ACPI_FAILURE(rv
) || result
== GHCI_FIFO_EMPTY
)
328 * vald_acpi_ghci_get:
330 * Get value via "GHCI" Method.
333 vald_acpi_ghci_get(struct vald_acpi_softc
*sc
,
334 UINT32 reg
, UINT32
*value
, UINT32
*result
)
337 ACPI_OBJECT Arg
[GHCI_WORDS
];
338 ACPI_OBJECT_LIST ArgList
;
339 ACPI_OBJECT
*param
, *PrtElement
;
343 for (i
= 0; i
< GHCI_WORDS
; i
++) {
344 Arg
[i
].Type
= ACPI_TYPE_INTEGER
;
345 Arg
[i
].Integer
.Value
= 0;
348 Arg
[0].Integer
.Value
= 0xfe00;
349 Arg
[1].Integer
.Value
= reg
;
350 Arg
[2].Integer
.Value
= 0;
352 ArgList
.Count
= GHCI_WORDS
;
353 ArgList
.Pointer
= Arg
;
356 buf
.Length
= ACPI_ALLOCATE_LOCAL_BUFFER
;
358 rv
= AcpiEvaluateObject(sc
->sc_node
->ad_handle
,
359 "GHCI", &ArgList
, &buf
);
360 if (ACPI_FAILURE(rv
)) {
361 aprint_error_dev(sc
->sc_dev
, "failed to evaluate GHCI: %s\n",
362 AcpiFormatException(rv
));
366 *result
= GHCI_NOT_SUPPORT
;
368 param
= (ACPI_OBJECT
*)buf
.Pointer
;
369 if (param
->Type
== ACPI_TYPE_PACKAGE
) {
370 PrtElement
= param
->Package
.Elements
;
371 if (PrtElement
->Type
== ACPI_TYPE_INTEGER
)
372 *result
= PrtElement
->Integer
.Value
;
375 if (PrtElement
->Type
== ACPI_TYPE_INTEGER
)
376 *value
= PrtElement
->Integer
.Value
;
380 ACPI_FREE(buf
.Pointer
);
385 * vald_acpi_ghci_set:
387 * Set value via "GHCI" Method.
390 vald_acpi_ghci_set(struct vald_acpi_softc
*sc
,
391 UINT32 reg
, UINT32 value
, UINT32
*result
)
394 ACPI_OBJECT Arg
[GHCI_WORDS
];
395 ACPI_OBJECT_LIST ArgList
;
396 ACPI_OBJECT
*param
, *PrtElement
;
401 for (i
= 0; i
< GHCI_WORDS
; i
++) {
402 Arg
[i
].Type
= ACPI_TYPE_INTEGER
;
403 Arg
[i
].Integer
.Value
= 0;
406 Arg
[0].Integer
.Value
= 0xff00;
407 Arg
[1].Integer
.Value
= reg
;
408 Arg
[2].Integer
.Value
= value
;
410 ArgList
.Count
= GHCI_WORDS
;
411 ArgList
.Pointer
= Arg
;
414 buf
.Length
= ACPI_ALLOCATE_LOCAL_BUFFER
;
416 rv
= AcpiEvaluateObject(sc
->sc_node
->ad_handle
,
417 "GHCI", &ArgList
, &buf
);
418 if (ACPI_FAILURE(rv
)) {
419 aprint_error_dev(sc
->sc_dev
, "failed to evaluate GHCI: %s\n",
420 AcpiFormatException(rv
));
424 *result
= GHCI_NOT_SUPPORT
;
425 param
= (ACPI_OBJECT
*)buf
.Pointer
;
426 if (param
->Type
== ACPI_TYPE_PACKAGE
) {
427 PrtElement
= param
->Package
.Elements
;
428 if (PrtElement
->Type
== ACPI_TYPE_INTEGER
)
429 *result
= PrtElement
->Integer
.Value
;
433 ACPI_FREE(buf
.Pointer
);
438 * vald_acpi_libright_get_bus:
440 * Get LCD brightness level via "_BCL" Method,
441 * and save this handle.
444 vald_acpi_libright_get_bus(ACPI_HANDLE handle
, UINT32 level
,
445 void *context
, void **status
)
447 struct vald_acpi_softc
*sc
= context
;
450 ACPI_OBJECT
*param
, *PrtElement
;
453 rv
= acpi_eval_struct(handle
, "_BCL", &buf
);
454 if (ACPI_FAILURE(rv
))
457 sc
->lcd_handle
= handle
;
458 param
= (ACPI_OBJECT
*)buf
.Pointer
;
459 if (param
->Type
== ACPI_TYPE_PACKAGE
) {
460 printf("_BCL retrun: %d packages\n", param
->Package
.Count
);
462 sc
->lcd_num
= param
->Package
.Count
;
463 sc
->lcd_level
= ACPI_ALLOCATE(sizeof(int) * sc
->lcd_num
);
464 if (sc
->lcd_level
== NULL
) {
466 ACPI_FREE(buf
.Pointer
);
467 return (AE_NO_MEMORY
);
470 PrtElement
= param
->Package
.Elements
;
472 for (i
= 0; i
< param
->Package
.Count
; i
++) {
473 if (PrtElement
->Type
== ACPI_TYPE_INTEGER
) {
474 *pi
= (unsigned)PrtElement
->Integer
.Value
;
479 if (sc
->sc_ac_status
== 1) /* AC adaptor on when attach */
480 sc
->lcd_index
= sc
->lcd_num
-1; /* MAX Brightness */
486 printf("\t Full Power Level: %d\n", *pi
);
487 printf("\t on Battery Level: %d\n", *(pi
+1));
488 printf("\t Possible Level: ");
489 for (i
= 2;i
< sc
->lcd_num
; i
++)
490 printf(" %d", *(pi
+i
));
496 ACPI_FREE(buf
.Pointer
);
501 * vald_acpi_libright_get:
503 * Search node that have "_BCL" Method.
506 vald_acpi_libright_get(struct vald_acpi_softc
*sc
)
511 aprint_verbose_dev(sc
->sc_dev
, "get LCD brightness via _BCL\n");
514 printf("acpi_libright_get: start\n");
516 rv
= AcpiGetHandle(ACPI_ROOT_OBJECT
, "\\_SB_", &parent
);
517 if (ACPI_FAILURE(rv
))
520 AcpiWalkNamespace(ACPI_TYPE_DEVICE
, parent
, 100,
521 vald_acpi_libright_get_bus
, sc
, NULL
);
525 * vald_acpi_libright_set:
527 * Figure up next status and set it.
530 vald_acpi_libright_set(struct vald_acpi_softc
*sc
, int UpDown
)
534 UINT32 backlight
, backlight_new
, result
, bright
;
536 /* Skip,if it does not support _BCL. */
537 if (sc
->lcd_handle
== NULL
)
540 /* Get LCD backlight status. */
541 rv
= vald_acpi_ghci_get(sc
, GHCI_BACKLIGHT
, &backlight
, &result
);
542 if (ACPI_FAILURE(rv
) || result
!= 0)
545 /* Figure up next status. */
546 backlight_new
= backlight
;
547 if (UpDown
== LIBRIGHT_UP
) {
555 } else if (UpDown
== LIBRIGHT_DOWN
) {
556 if ((backlight
== 1) && (sc
->lcd_index
> 2))
565 /* Check index value. */
566 if (sc
->lcd_index
< 2)
567 sc
->lcd_index
= 2; /* index Minium Value */
568 if (sc
->lcd_index
>= sc
->lcd_num
)
569 sc
->lcd_index
= sc
->lcd_num
- 1;
571 /* Set LCD backlight,if status is changed. */
572 if (backlight_new
!= backlight
) {
573 rv
= vald_acpi_ghci_set(sc
, GHCI_BACKLIGHT
, backlight_new
,
575 if (ACPI_SUCCESS(rv
) && result
!= 0)
576 aprint_error_dev(sc
->sc_dev
, "can't set LCD backlight %s error=%x\n",
577 ((backlight_new
== 1) ? "on" : "off"), result
);
580 if (backlight_new
== 1) {
583 bright
= *(pi
+ sc
->lcd_index
);
585 rv
= vald_acpi_bcm_set(sc
->lcd_handle
, bright
);
586 if (ACPI_FAILURE(rv
))
587 aprint_error_dev(sc
->sc_dev
, "unable to evaluate _BCM: %s\n",
588 AcpiFormatException(rv
));
593 printf("LCD bright");
594 printf(" %s", ((UpDown
== LIBRIGHT_UP
) ? "up":""));
595 printf("%s\n", ((UpDown
== LIBRIGHT_DOWN
) ? "down":""));
596 printf("\t acpi_libright_set: Set brightness to %d%%\n", bright
);
601 * vald_acpi_video_switch:
603 * Get video status(LCD/CRT) and set new video status.
606 vald_acpi_video_switch(struct vald_acpi_softc
*sc
)
609 UINT32 value
, result
;
611 /* Get video status. */
612 rv
= vald_acpi_ghci_get(sc
, GHCI_DISPLAY_DEVICE
, &value
, &result
);
613 if (ACPI_FAILURE(rv
))
616 aprint_error_dev(sc
->sc_dev
, "can't get video status error=%x\n",
622 printf("Toggle LCD/CRT\n");
623 printf("\t Before switch, video status: %s",
624 (((value
& GHCI_LCD
) == GHCI_LCD
) ? "LCD" : ""));
625 printf("%s\n", (((value
& GHCI_CRT
) == GHCI_CRT
) ? "CRT": ""));
629 if (value
& GHCI_LCD
) {
632 } else if (value
& GHCI_CRT
){
637 rv
= vald_acpi_dssx_set(value
);
638 if (ACPI_FAILURE(rv
))
639 aprint_error_dev(sc
->sc_dev
, "unable to evaluate DSSX: %s\n",
640 AcpiFormatException(rv
));
647 * Set LCD brightness via "_BCM" Method.
650 vald_acpi_bcm_set(ACPI_HANDLE handle
, UINT32 bright
)
654 ACPI_OBJECT_LIST ArgList
;
657 ArgList
.Pointer
= &Arg
;
659 Arg
.Type
= ACPI_TYPE_INTEGER
;
660 Arg
.Integer
.Value
= bright
;
662 rv
= AcpiEvaluateObject(handle
, "_BCM", &ArgList
, NULL
);
667 * vald_acpi_dssx_set:
669 * Set value via "\\_SB_.VALX.DSSX" Method.
672 vald_acpi_dssx_set(UINT32 value
)
674 return acpi_eval_set_integer(NULL
, "\\_SB_.VALX.DSSX", value
);
678 * vald_acpi_fan_switch:
680 * Get FAN status and set new FAN status.
683 vald_acpi_fan_switch(struct vald_acpi_softc
*sc
)
686 UINT32 value
, result
;
689 rv
= vald_acpi_ghci_get(sc
, GHCI_FAN
, &value
, &result
);
690 if (ACPI_FAILURE(rv
))
693 aprint_error_dev(sc
->sc_dev
, "can't get FAN status error=%d\n",
699 printf("Toggle FAN on/off\n");
700 printf("\t Before toggle, FAN status %s\n",
701 (value
== GHCI_OFF
? "off" : "on"));
704 /* Toggle FAN on/off */
705 if (value
== GHCI_OFF
)
710 /* Set FAN new status. */
711 rv
= vald_acpi_ghci_set(sc
, GHCI_FAN
, value
, &result
);
712 if (ACPI_FAILURE(rv
))
715 aprint_error_dev(sc
->sc_dev
, "can't set FAN status error=%d\n",
721 printf("\t After toggle, FAN status %s\n",
722 (value
== GHCI_OFF
? "off" : "on"));