xref: /netbsd-src/sys/dev/acpi/wmi/wmi_msi.c (revision 3993e0d154b47d192c9d455b791b704da4d244d4)
1*3993e0d1Sjruoho /*	$NetBSD: wmi_msi.c,v 1.5 2011/02/16 13:15:49 jruoho Exp $ */
2117351d1Sjruoho 
3117351d1Sjruoho /*-
4117351d1Sjruoho  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5117351d1Sjruoho  * All rights reserved.
6117351d1Sjruoho  *
7117351d1Sjruoho  * This code is derived from software contributed to The NetBSD Foundation
8117351d1Sjruoho  * by Jukka Ruohonen.
9117351d1Sjruoho  *
10117351d1Sjruoho  * Redistribution and use in source and binary forms, with or without
11117351d1Sjruoho  * modification, are permitted provided that the following conditions
12117351d1Sjruoho  * are met:
13117351d1Sjruoho  *
14117351d1Sjruoho  * 1. Redistributions of source code must retain the above copyright
15117351d1Sjruoho  *    notice, this list of conditions and the following disclaimer.
16117351d1Sjruoho  * 2. Redistributions in binary form must reproduce the above copyright
17117351d1Sjruoho  *    notice, this list of conditions and the following disclaimer in the
18117351d1Sjruoho  *    documentation and/or other materials provided with the distribution.
19117351d1Sjruoho  *
20117351d1Sjruoho  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21117351d1Sjruoho  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22117351d1Sjruoho  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23117351d1Sjruoho  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24117351d1Sjruoho  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25117351d1Sjruoho  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26117351d1Sjruoho  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27117351d1Sjruoho  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28117351d1Sjruoho  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29117351d1Sjruoho  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30117351d1Sjruoho  * SUCH DAMAGE.
31117351d1Sjruoho  */
32117351d1Sjruoho 
33117351d1Sjruoho #include <sys/cdefs.h>
34*3993e0d1Sjruoho __KERNEL_RCSID(0, "$NetBSD: wmi_msi.c,v 1.5 2011/02/16 13:15:49 jruoho Exp $");
35117351d1Sjruoho 
36117351d1Sjruoho #include <sys/param.h>
37117351d1Sjruoho #include <sys/device.h>
384e449995Sjmcneill #include <sys/module.h>
39117351d1Sjruoho 
40117351d1Sjruoho #include <dev/acpi/acpireg.h>
41117351d1Sjruoho #include <dev/acpi/acpivar.h>
42117351d1Sjruoho #include <dev/acpi/wmi/wmi_acpivar.h>
43117351d1Sjruoho 
44117351d1Sjruoho #define _COMPONENT			ACPI_RESOURCE_COMPONENT
45117351d1Sjruoho ACPI_MODULE_NAME			("wmi_msi")
46117351d1Sjruoho 
47117351d1Sjruoho #define WMI_MSI_HOTKEY_BRIGHTNESS_UP	0xD0
48117351d1Sjruoho #define WMI_MSI_HOTKEY_BRIGHTNESS_DOWN	0xD1
49117351d1Sjruoho #define WMI_MSI_HOTKEY_VOLUME_UP	0xD2
50117351d1Sjruoho #define WMI_MSI_HOTKEY_VOLUME_DOWN	0xD3
51117351d1Sjruoho /*      WMI_MSI_HOTKEY_UNKNOWN		0xXXXX */
52117351d1Sjruoho 
53117351d1Sjruoho #define WMI_MSI_GUID_EVENT		"B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"
54117351d1Sjruoho 
55117351d1Sjruoho struct wmi_msi_softc {
56117351d1Sjruoho 	device_t		sc_dev;
57117351d1Sjruoho 	device_t		sc_parent;
58117351d1Sjruoho };
59117351d1Sjruoho 
60117351d1Sjruoho static int	wmi_msi_match(device_t, cfdata_t, void *);
61117351d1Sjruoho static void	wmi_msi_attach(device_t, device_t, void *);
62117351d1Sjruoho static int	wmi_msi_detach(device_t, int);
63117351d1Sjruoho static void	wmi_msi_notify_handler(ACPI_HANDLE, uint32_t, void *);
64117351d1Sjruoho static bool	wmi_msi_suspend(device_t, const pmf_qual_t *);
65117351d1Sjruoho static bool	wmi_msi_resume(device_t, const pmf_qual_t *);
66117351d1Sjruoho 
67117351d1Sjruoho CFATTACH_DECL_NEW(wmimsi, sizeof(struct wmi_msi_softc),
68117351d1Sjruoho     wmi_msi_match, wmi_msi_attach, wmi_msi_detach, NULL);
69117351d1Sjruoho 
70117351d1Sjruoho static int
wmi_msi_match(device_t parent,cfdata_t match,void * aux)71117351d1Sjruoho wmi_msi_match(device_t parent, cfdata_t match, void *aux)
72117351d1Sjruoho {
73117351d1Sjruoho 	return acpi_wmi_guid_match(parent, WMI_MSI_GUID_EVENT);
74117351d1Sjruoho }
75117351d1Sjruoho 
76117351d1Sjruoho static void
wmi_msi_attach(device_t parent,device_t self,void * aux)77117351d1Sjruoho wmi_msi_attach(device_t parent, device_t self, void *aux)
78117351d1Sjruoho {
79117351d1Sjruoho 	struct wmi_msi_softc *sc = device_private(self);
80117351d1Sjruoho 	ACPI_STATUS rv;
81117351d1Sjruoho 
82117351d1Sjruoho 	sc->sc_dev = self;
83117351d1Sjruoho 	sc->sc_parent = parent;
84117351d1Sjruoho 
85117351d1Sjruoho 	rv = acpi_wmi_event_register(parent, wmi_msi_notify_handler);
86117351d1Sjruoho 
87117351d1Sjruoho 	if (ACPI_FAILURE(rv)) {
88117351d1Sjruoho 		aprint_error(": failed to install WMI notify handler\n");
89117351d1Sjruoho 		return;
90117351d1Sjruoho 	}
91117351d1Sjruoho 
92117351d1Sjruoho 	aprint_naive("\n");
93117351d1Sjruoho 	aprint_normal(": MSI WMI mappings\n");
94117351d1Sjruoho 
95117351d1Sjruoho 	(void)pmf_device_register(self, wmi_msi_suspend, wmi_msi_resume);
96117351d1Sjruoho }
97117351d1Sjruoho 
98117351d1Sjruoho static int
wmi_msi_detach(device_t self,int flags)99117351d1Sjruoho wmi_msi_detach(device_t self, int flags)
100117351d1Sjruoho {
101117351d1Sjruoho 	struct wmi_msi_softc *sc = device_private(self);
102117351d1Sjruoho 	device_t parent = sc->sc_parent;
103117351d1Sjruoho 
104117351d1Sjruoho 	(void)pmf_device_deregister(self);
105117351d1Sjruoho 	(void)acpi_wmi_event_deregister(parent);
106117351d1Sjruoho 
107117351d1Sjruoho 	return 0;
108117351d1Sjruoho }
109117351d1Sjruoho 
110117351d1Sjruoho static bool
wmi_msi_suspend(device_t self,const pmf_qual_t * qual)111117351d1Sjruoho wmi_msi_suspend(device_t self, const pmf_qual_t *qual)
112117351d1Sjruoho {
113117351d1Sjruoho 	struct wmi_msi_softc *sc = device_private(self);
114117351d1Sjruoho 	device_t parent = sc->sc_parent;
115117351d1Sjruoho 
116117351d1Sjruoho 	(void)acpi_wmi_event_deregister(parent);
117117351d1Sjruoho 
118117351d1Sjruoho 	return true;
119117351d1Sjruoho }
120117351d1Sjruoho 
121117351d1Sjruoho static bool
wmi_msi_resume(device_t self,const pmf_qual_t * qual)122117351d1Sjruoho wmi_msi_resume(device_t self, const pmf_qual_t *qual)
123117351d1Sjruoho {
124117351d1Sjruoho 	struct wmi_msi_softc *sc = device_private(self);
125117351d1Sjruoho 	device_t parent = sc->sc_parent;
126117351d1Sjruoho 
127117351d1Sjruoho 	(void)acpi_wmi_event_register(parent, wmi_msi_notify_handler);
128117351d1Sjruoho 
129117351d1Sjruoho 	return true;
130117351d1Sjruoho }
131117351d1Sjruoho 
132117351d1Sjruoho static void
wmi_msi_notify_handler(ACPI_HANDLE hdl,uint32_t evt,void * aux)133117351d1Sjruoho wmi_msi_notify_handler(ACPI_HANDLE hdl, uint32_t evt, void *aux)
134117351d1Sjruoho {
135117351d1Sjruoho 	struct wmi_msi_softc *sc;
136117351d1Sjruoho 	device_t self = aux;
137117351d1Sjruoho 	ACPI_OBJECT *obj;
138117351d1Sjruoho 	ACPI_BUFFER buf;
139117351d1Sjruoho 	ACPI_STATUS rv;
140117351d1Sjruoho 	uint32_t val;
141117351d1Sjruoho 
142117351d1Sjruoho 	buf.Pointer = NULL;
143117351d1Sjruoho 
144117351d1Sjruoho 	sc = device_private(self);
145117351d1Sjruoho 	rv = acpi_wmi_event_get(sc->sc_parent, evt, &buf);
146117351d1Sjruoho 
147117351d1Sjruoho 	if (ACPI_FAILURE(rv))
148117351d1Sjruoho 		goto out;
149117351d1Sjruoho 
150117351d1Sjruoho 	obj = buf.Pointer;
151117351d1Sjruoho 
152117351d1Sjruoho 	if (obj->Type != ACPI_TYPE_INTEGER) {
153117351d1Sjruoho 		rv = AE_TYPE;
154117351d1Sjruoho 		goto out;
155117351d1Sjruoho 	}
156117351d1Sjruoho 
157117351d1Sjruoho 	if (obj->Integer.Value > UINT32_MAX) {
158117351d1Sjruoho 		rv = AE_AML_NUMERIC_OVERFLOW;
159117351d1Sjruoho 		goto out;
160117351d1Sjruoho 	}
161117351d1Sjruoho 
162117351d1Sjruoho 	val = obj->Integer.Value;
163117351d1Sjruoho 
164117351d1Sjruoho 	switch (val) {
165117351d1Sjruoho 
166117351d1Sjruoho 	case WMI_MSI_HOTKEY_BRIGHTNESS_DOWN:
167117351d1Sjruoho 		pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_DOWN);
168117351d1Sjruoho 		break;
169117351d1Sjruoho 
170117351d1Sjruoho 	case WMI_MSI_HOTKEY_BRIGHTNESS_UP:
171117351d1Sjruoho 		pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_UP);
172117351d1Sjruoho 		break;
173117351d1Sjruoho 
174117351d1Sjruoho 	case WMI_MSI_HOTKEY_VOLUME_DOWN:
175117351d1Sjruoho 		pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_DOWN);
176117351d1Sjruoho 		break;
177117351d1Sjruoho 
178117351d1Sjruoho 	case WMI_MSI_HOTKEY_VOLUME_UP:
179117351d1Sjruoho 		pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_UP);
180117351d1Sjruoho 		break;
181117351d1Sjruoho 
182117351d1Sjruoho 	default:
183117351d1Sjruoho 		aprint_normal_dev(sc->sc_dev,
184117351d1Sjruoho 		    "unknown key 0x%02X for event 0x%02X\n", val, evt);
185117351d1Sjruoho 		break;
186117351d1Sjruoho 	}
187117351d1Sjruoho 
188117351d1Sjruoho out:
189117351d1Sjruoho 	if (buf.Pointer != NULL)
190117351d1Sjruoho 		ACPI_FREE(buf.Pointer);
191117351d1Sjruoho 
192117351d1Sjruoho 	if (ACPI_FAILURE(rv))
193117351d1Sjruoho 		aprint_error_dev(sc->sc_dev, "failed to get data for "
194117351d1Sjruoho 		    "event 0x%02X: %s\n", evt, AcpiFormatException(rv));
195117351d1Sjruoho }
1964e449995Sjmcneill 
197*3993e0d1Sjruoho MODULE(MODULE_CLASS_DRIVER, wmimsi, "acpiwmi");
1984e449995Sjmcneill 
199b9f301d5Sjruoho #ifdef _MODULE
200b9f301d5Sjruoho #include "ioconf.c"
201b9f301d5Sjruoho #endif
2024e449995Sjmcneill 
2034e449995Sjmcneill static int
wmimsi_modcmd(modcmd_t cmd,void * aux)204b9f301d5Sjruoho wmimsi_modcmd(modcmd_t cmd, void *aux)
2054e449995Sjmcneill {
206b9f301d5Sjruoho 	int rv = 0;
2074e449995Sjmcneill 
2084e449995Sjmcneill 	switch (cmd) {
2094e449995Sjmcneill 
2104e449995Sjmcneill 	case MODULE_CMD_INIT:
2114e449995Sjmcneill 
212b9f301d5Sjruoho #ifdef _MODULE
213b9f301d5Sjruoho 		rv = config_init_component(cfdriver_ioconf_wmimsi,
214b9f301d5Sjruoho 		    cfattach_ioconf_wmimsi, cfdata_ioconf_wmimsi);
215b9f301d5Sjruoho #endif
216b9f301d5Sjruoho 		break;
2174e449995Sjmcneill 
2184e449995Sjmcneill 	case MODULE_CMD_FINI:
2194e449995Sjmcneill 
220b9f301d5Sjruoho #ifdef _MODULE
221b9f301d5Sjruoho 		rv = config_fini_component(cfdriver_ioconf_wmimsi,
222b9f301d5Sjruoho 		    cfattach_ioconf_wmimsi, cfdata_ioconf_wmimsi);
223b9f301d5Sjruoho #endif
224b9f301d5Sjruoho 		break;
2254e449995Sjmcneill 
2264e449995Sjmcneill 	default:
227b9f301d5Sjruoho 		rv = ENOTTY;
2284e449995Sjmcneill 	}
2294e449995Sjmcneill 
230b9f301d5Sjruoho 	return rv;
231b9f301d5Sjruoho }
232