1 /* $OpenBSD: acpisurface.c,v 1.3 2024/08/15 17:30:40 deraadt Exp $ */
2 /*
3 * Copyright (c) 2018 Mike Larkin <mlarkin@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20
21 #include <dev/acpi/acpireg.h>
22 #include <dev/acpi/acpivar.h>
23 #include <dev/acpi/acpidev.h>
24 #include <dev/acpi/amltypes.h>
25 #include <dev/acpi/dsdt.h>
26
27 #include "audio.h"
28 #include "wskbd.h"
29
30 /* #define ACPISURFACE_DEBUG */
31
32 #ifdef ACPISURFACE_DEBUG
33 #define DPRINTF(x...) do { printf(x); } while(0)
34 #else
35 #define DPRINTF(x...)
36 #endif /* ACPISURFACE_DEBUG */
37
38 #define SURFACE_ACCESSORY_REMOVED 0xC8
39 #define SURFACE_WINDOWS_KEY_PRESSED 0xC4
40 #define SURFACE_WINDOWS_KEY_RELEASED 0xC5
41 #define SURFACE_VOLUME_UP_PRESSED 0xC0
42 #define SURFACE_VOLUME_UP_RELEASED 0xC1
43 #define SURFACE_VOLUME_DOWN_PRESSED 0xC2
44 #define SURFACE_VOLUME_DOWN_RELEASED 0xC3
45 #define SURFACE_POWER_BUTTON_PRESSED 0xC6
46 #define SURFACE_POWER_BUTTON_RELEASED 0xC7
47
48 struct acpisurface_softc {
49 struct device sc_dev;
50
51 struct acpiec_softc *sc_ec;
52 struct acpi_softc *sc_acpi;
53 struct aml_node *sc_devnode;
54 };
55
56 int surface_match(struct device *, void *, void *);
57 void surface_attach(struct device *, struct device *, void *);
58 int surface_hotkey(struct aml_node *, int, void *);
59
60 #if NAUDIO > 0 && NWSKBD > 0
61 extern int wskbd_set_mixervolume(long, long);
62 #endif
63
64 const struct cfattach acpisurface_ca = {
65 sizeof(struct acpisurface_softc), surface_match, surface_attach,
66 NULL, NULL
67 };
68
69 struct cfdriver acpisurface_cd = {
70 NULL, "acpisurface", DV_DULL
71 };
72
73 const char *acpisurface_hids[] = {
74 "MSHW0040",
75 NULL
76 };
77
78 int
surface_match(struct device * parent,void * match,void * aux)79 surface_match(struct device *parent, void *match, void *aux)
80 {
81 struct acpi_attach_args *aa = aux;
82 struct cfdata *cf = match;
83
84 if (!acpi_matchhids(aa, acpisurface_hids, cf->cf_driver->cd_name))
85 return (0);
86
87 return (1);
88 }
89
90 void
surface_attach(struct device * parent,struct device * self,void * aux)91 surface_attach(struct device *parent, struct device *self, void *aux)
92 {
93 struct acpisurface_softc *sc = (struct acpisurface_softc *)self;
94 struct acpi_attach_args *aa = aux;
95
96 sc->sc_acpi = (struct acpi_softc *)parent;
97 sc->sc_devnode = aa->aaa_node;
98
99 printf("\n");
100
101 /* Run surface_hotkey on button presses */
102 aml_register_notify(sc->sc_devnode, aa->aaa_dev,
103 surface_hotkey, sc, ACPIDEV_NOPOLL);
104 }
105
106 int
surface_hotkey(struct aml_node * node,int notify_type,void * arg)107 surface_hotkey(struct aml_node *node, int notify_type, void *arg)
108 {
109 struct acpisurface_softc *sc = arg;
110
111 switch (notify_type) {
112 case SURFACE_ACCESSORY_REMOVED:
113 DPRINTF("%s: accessory removed\n", __func__);
114 break;
115 case SURFACE_VOLUME_UP_PRESSED:
116 DPRINTF("%s: volume up pressed\n", __func__);
117 #if NAUDIO > 0 && NWSKBD > 0
118 wskbd_set_mixervolume(1, 10);
119 #endif
120 break;
121 case SURFACE_VOLUME_UP_RELEASED:
122 DPRINTF("%s: volume up released\n", __func__);
123 break;
124 case SURFACE_VOLUME_DOWN_PRESSED:
125 DPRINTF("%s: volume down pressed\n", __func__);
126 #if NAUDIO > 0 && NWSKBD > 0
127 wskbd_set_mixervolume(-1, 10);
128 #endif
129 break;
130 case SURFACE_VOLUME_DOWN_RELEASED:
131 DPRINTF("%s: volume down released\n", __func__);
132 break;
133 case SURFACE_POWER_BUTTON_PRESSED:
134 DPRINTF("%s: power button pressed\n", __func__);
135 break;
136 case SURFACE_POWER_BUTTON_RELEASED:
137 DPRINTF("%s: power button released\n", __func__);
138 acpi_addtask(sc->sc_acpi, acpi_powerdown_task,
139 sc->sc_acpi, 0);
140 break;
141 case SURFACE_WINDOWS_KEY_PRESSED:
142 DPRINTF("%s: windows key pressed\n", __func__);
143 break;
144 case SURFACE_WINDOWS_KEY_RELEASED:
145 DPRINTF("%s: windows key released\n", __func__);
146 break;
147 default:
148 DPRINTF("%s: unknown notification 0x%x\n", __func__,
149 notify_type);
150 }
151
152 return (0);
153 }
154