1 /* $OpenBSD: acpiasus.c,v 1.20 2022/04/06 18:59:27 naddy 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 const 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[] = {
99 "ASUS010",
100 NULL
101 };
102
103 int
acpiasus_match(struct device * parent,void * match,void * aux)104 acpiasus_match(struct device *parent, void *match, void *aux)
105 {
106 struct acpi_attach_args *aa = aux;
107 struct cfdata *cf = match;
108
109 return (acpi_matchhids(aa, acpiasus_hids, cf->cf_driver->cd_name));
110 }
111
112 void
acpiasus_attach(struct device * parent,struct device * self,void * aux)113 acpiasus_attach(struct device *parent, struct device *self, void *aux)
114 {
115 struct acpiasus_softc *sc = (struct acpiasus_softc *)self;
116 struct acpi_attach_args *aa = aux;
117
118 sc->sc_acpi = (struct acpi_softc *)parent;
119 sc->sc_devnode = aa->aaa_node;
120
121 printf("\n");
122
123 acpiasus_init(self);
124
125 aml_register_notify(sc->sc_devnode, aa->aaa_dev,
126 acpiasus_notify, sc, ACPIDEV_NOPOLL);
127 }
128
129 void
acpiasus_init(struct device * self)130 acpiasus_init(struct device *self)
131 {
132 struct acpiasus_softc *sc = (struct acpiasus_softc *)self;
133 struct aml_value cmd;
134 struct aml_value ret;
135
136 bzero(&cmd, sizeof(cmd));
137 cmd.type = AML_OBJTYPE_INTEGER;
138 cmd.v_integer = 0x40; /* Disable ASL display switching. */
139
140 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "INIT", 1, &cmd, &ret))
141 printf("%s: no INIT\n", DEVNAME(sc));
142 else
143 aml_freevalue(&ret);
144 }
145
146 int
acpiasus_notify(struct aml_node * node,int notify,void * arg)147 acpiasus_notify(struct aml_node *node, int notify, void *arg)
148 {
149 struct acpiasus_softc *sc = arg;
150
151 if (notify >= ASUS_NOTIFY_BRIGHTNESSLOW &&
152 notify <= ASUS_NOTIFY_BRIGHTNESSHIGH) {
153 #ifdef ACPIASUS_DEBUG
154 printf("%s: brightness %d percent\n", DEVNAME(sc),
155 (notify & 0xf) * 100 / 0xf);
156 #endif
157 return 0;
158 }
159
160 switch (notify) {
161 case ASUS_NOTIFY_WIRELESSON: /* Handled by AML. */
162 case ASUS_NOTIFY_WIRELESSOFF: /* Handled by AML. */
163 break;
164 case ASUS_NOTIFY_TASKSWITCH:
165 break;
166 case ASUS_NOTIFY_DISPLAYCYCLEDOWN:
167 case ASUS_NOTIFY_DISPLAYCYCLEUP:
168 break;
169 #if NAUDIO > 0 && NWSKBD > 0
170 case ASUS_NOTIFY_VOLUMEMUTE:
171 wskbd_set_mixervolume(0, 1);
172 break;
173 case ASUS_NOTIFY_VOLUMEDOWN:
174 wskbd_set_mixervolume(-1, 1);
175 break;
176 case ASUS_NOTIFY_VOLUMEUP:
177 wskbd_set_mixervolume(1, 1);
178 break;
179 #else
180 case ASUS_NOTIFY_VOLUMEMUTE:
181 case ASUS_NOTIFY_VOLUMEDOWN:
182 case ASUS_NOTIFY_VOLUMEUP:
183 break;
184 #endif
185 case ASUS_NOTIFY_POWERCONNECT:
186 case ASUS_NOTIFY_POWERDISCONNECT:
187 break;
188
189 case ASUS_NOTIFY_LCDSWITCHOFF0:
190 case ASUS_NOTIFY_LCDSWITCHOFF1:
191 break;
192
193 case ASUS_NOTIFY_LCDCHANGERES:
194 break;
195
196 case ASUS_NOTIFY_USERDEF0:
197 case ASUS_NOTIFY_USERDEF1:
198 break;
199
200 default:
201 printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
202 break;
203 }
204
205 return 0;
206 }
207
208 int
acpiasus_activate(struct device * self,int act)209 acpiasus_activate(struct device *self, int act)
210 {
211 struct acpiasus_softc *sc = (struct acpiasus_softc *)self;
212 struct aml_value cmd;
213 struct aml_value ret;
214
215 switch (act) {
216 case DVACT_WAKEUP:
217 acpiasus_init(self);
218
219 bzero(&cmd, sizeof(cmd));
220 cmd.type = AML_OBJTYPE_INTEGER;
221 cmd.v_integer = ASUS_SDSP_LCD;
222
223 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SDSP", 1,
224 &cmd, &ret))
225 printf("%s: no SDSP\n", DEVNAME(sc));
226 else
227 aml_freevalue(&ret);
228 break;
229 }
230 return (0);
231 }
232