xref: /openbsd-src/sys/dev/acpi/acpiasus.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: acpiasus.c,v 1.17 2014/02/21 18:49:06 deraadt Exp $ */
2 /* $NetBSD: asus_acpi.c,v 1.2.2.2 2008/04/03 12:42:37 mjf Exp $ */
3 /*
4  * Copyright (c) 2007, 2008 Jared D. McNeill <jmcneill@invisible.ca>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * ASUS ACPI hotkeys driver.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/systm.h>
36 
37 #include <dev/acpi/acpireg.h>
38 #include <dev/acpi/acpivar.h>
39 #include <dev/acpi/acpidev.h>
40 #include <dev/acpi/amltypes.h>
41 #include <dev/acpi/dsdt.h>
42 
43 #include "audio.h"
44 #include "wskbd.h"
45 
46 struct acpiasus_softc {
47 	struct device		sc_dev;
48 
49 	struct acpi_softc	*sc_acpi;
50 	struct aml_node		*sc_devnode;
51 };
52 
53 #define ASUS_NOTIFY_WIRELESSON		0x10
54 #define ASUS_NOTIFY_WIRELESSOFF		0x11
55 #define ASUS_NOTIFY_TASKSWITCH		0x12
56 #define ASUS_NOTIFY_VOLUMEMUTE		0x13
57 #define ASUS_NOTIFY_VOLUMEDOWN		0x14
58 #define ASUS_NOTIFY_VOLUMEUP		0x15
59 #define ASUS_NOTIFY_LCDSWITCHOFF0	0x16
60 #define ASUS_NOTIFY_LCDSWITCHOFF1	0x1a
61 #define ASUS_NOTIFY_LCDCHANGERES	0x1b
62 #define ASUS_NOTIFY_USERDEF0		0x1c
63 #define ASUS_NOTIFY_USERDEF1		0x1d
64 #define ASUS_NOTIFY_BRIGHTNESSLOW	0x20
65 #define ASUS_NOTIFY_BRIGHTNESSHIGH	0x2f
66 #define ASUS_NOTIFY_DISPLAYCYCLEDOWN	0x30
67 #define ASUS_NOTIFY_DISPLAYCYCLEUP	0x32
68 
69 #define ASUS_NOTIFY_POWERCONNECT	0x50
70 #define ASUS_NOTIFY_POWERDISCONNECT	0x51
71 
72 #define	ASUS_SDSP_LCD			0x01
73 #define	ASUS_SDSP_CRT			0x02
74 #define	ASUS_SDSP_TV			0x04
75 #define	ASUS_SDSP_DVI			0x08
76 #define	ASUS_SDSP_ALL \
77 	(ASUS_SDSP_LCD | ASUS_SDSP_CRT | ASUS_SDSP_TV | ASUS_SDSP_DVI)
78 
79 int	acpiasus_match(struct device *, void *, void *);
80 void	acpiasus_attach(struct device *, struct device *, void *);
81 void	acpiasus_init(struct device *);
82 int	acpiasus_notify(struct aml_node *, int, void *);
83 int	acpiasus_activate(struct device *, int);
84 
85 #if NAUDIO > 0 && NWSKBD > 0
86 extern int wskbd_set_mixervolume(long, long);
87 #endif
88 
89 struct cfattach acpiasus_ca = {
90 	sizeof(struct acpiasus_softc), acpiasus_match, acpiasus_attach,
91 	NULL, acpiasus_activate
92 };
93 
94 struct cfdriver acpiasus_cd = {
95 	NULL, "acpiasus", DV_DULL
96 };
97 
98 const char *acpiasus_hids[] = { ACPI_DEV_ASUS, 0 };
99 
100 int
101 acpiasus_match(struct device *parent, void *match, void *aux)
102 {
103 	struct acpi_attach_args *aa = aux;
104 	struct cfdata *cf = match;
105 
106 	return (acpi_matchhids(aa, acpiasus_hids, cf->cf_driver->cd_name));
107 }
108 
109 void
110 acpiasus_attach(struct device *parent, struct device *self, void *aux)
111 {
112 	struct acpiasus_softc *sc = (struct acpiasus_softc *)self;
113 	struct acpi_attach_args *aa = aux;
114 
115 	sc->sc_acpi = (struct acpi_softc *)parent;
116 	sc->sc_devnode = aa->aaa_node;
117 
118 	printf("\n");
119 
120 	acpiasus_init(self);
121 
122 	aml_register_notify(sc->sc_devnode, aa->aaa_dev,
123 	    acpiasus_notify, sc, ACPIDEV_NOPOLL);
124 }
125 
126 void
127 acpiasus_init(struct device *self)
128 {
129 	struct acpiasus_softc *sc = (struct acpiasus_softc *)self;
130 	struct aml_value cmd;
131 	struct aml_value ret;
132 
133 	bzero(&cmd, sizeof(cmd));
134 	cmd.type = AML_OBJTYPE_INTEGER;
135 	cmd.v_integer = 0x40;		/* Disable ASL display switching. */
136 
137 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "INIT", 1, &cmd, &ret))
138 		printf("%s: no INIT\n", DEVNAME(sc));
139 	else
140 		aml_freevalue(&ret);
141 }
142 
143 int
144 acpiasus_notify(struct aml_node *node, int notify, void *arg)
145 {
146 	struct acpiasus_softc *sc = arg;
147 
148 	if (notify >= ASUS_NOTIFY_BRIGHTNESSLOW &&
149 	    notify <= ASUS_NOTIFY_BRIGHTNESSHIGH) {
150 #ifdef ACPIASUS_DEBUG
151 		printf("%s: brightness %d percent\n", DEVNAME(sc),
152 		    (notify & 0xf) * 100 / 0xf);
153 #endif
154 		return 0;
155 	}
156 
157 	switch (notify) {
158 	case ASUS_NOTIFY_WIRELESSON:	/* Handled by AML. */
159 	case ASUS_NOTIFY_WIRELESSOFF:	/* Handled by AML. */
160 		break;
161 	case ASUS_NOTIFY_TASKSWITCH:
162 		break;
163 	case ASUS_NOTIFY_DISPLAYCYCLEDOWN:
164 	case ASUS_NOTIFY_DISPLAYCYCLEUP:
165 		break;
166 #if NAUDIO > 0 && NWSKBD > 0
167 	case ASUS_NOTIFY_VOLUMEMUTE:
168 		wskbd_set_mixervolume(0, 1);
169 		break;
170 	case ASUS_NOTIFY_VOLUMEDOWN:
171 		wskbd_set_mixervolume(-1, 1);
172 		break;
173 	case ASUS_NOTIFY_VOLUMEUP:
174 		wskbd_set_mixervolume(1, 1);
175 		break;
176 #else
177 	case ASUS_NOTIFY_VOLUMEMUTE:
178 	case ASUS_NOTIFY_VOLUMEDOWN:
179 	case ASUS_NOTIFY_VOLUMEUP:
180 		break;
181 #endif
182 	case ASUS_NOTIFY_POWERCONNECT:
183 	case ASUS_NOTIFY_POWERDISCONNECT:
184 		break;
185 
186 	case ASUS_NOTIFY_LCDSWITCHOFF0:
187 	case ASUS_NOTIFY_LCDSWITCHOFF1:
188 		break;
189 
190 	case ASUS_NOTIFY_LCDCHANGERES:
191 		break;
192 
193 	case ASUS_NOTIFY_USERDEF0:
194 	case ASUS_NOTIFY_USERDEF1:
195 		break;
196 
197 	default:
198 		printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
199 		break;
200 	}
201 
202 	return 0;
203 }
204 
205 int
206 acpiasus_activate(struct device *self, int act)
207 {
208 	struct acpiasus_softc *sc = (struct acpiasus_softc *)self;
209 	struct aml_value cmd;
210 	struct aml_value ret;
211 
212 	switch (act) {
213 	case DVACT_WAKEUP:
214 		acpiasus_init(self);
215 
216 		bzero(&cmd, sizeof(cmd));
217 		cmd.type = AML_OBJTYPE_INTEGER;
218 		cmd.v_integer = ASUS_SDSP_LCD;
219 
220 		if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SDSP", 1,
221 		    &cmd, &ret))
222 			printf("%s: no SDSP\n", DEVNAME(sc));
223 		else
224 			aml_freevalue(&ret);
225 		break;
226 	}
227 	return (0);
228 }
229