acpiasus.c revision 1.17
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
46struct 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
79int	acpiasus_match(struct device *, void *, void *);
80void	acpiasus_attach(struct device *, struct device *, void *);
81void	acpiasus_init(struct device *);
82int	acpiasus_notify(struct aml_node *, int, void *);
83int	acpiasus_activate(struct device *, int);
84
85#if NAUDIO > 0 && NWSKBD > 0
86extern int wskbd_set_mixervolume(long, long);
87#endif
88
89struct cfattach acpiasus_ca = {
90	sizeof(struct acpiasus_softc), acpiasus_match, acpiasus_attach,
91	NULL, acpiasus_activate
92};
93
94struct cfdriver acpiasus_cd = {
95	NULL, "acpiasus", DV_DULL
96};
97
98const char *acpiasus_hids[] = { ACPI_DEV_ASUS, 0 };
99
100int
101acpiasus_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
109void
110acpiasus_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
126void
127acpiasus_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
143int
144acpiasus_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
205int
206acpiasus_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