1 /*-
2 * Copyright (c) 2022 Takanori Watanabe
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include "opt_acpi.h"
30
31 #include <sys/param.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
36 #include <sys/rman.h>
37
38 #include <contrib/dev/acpica/include/acpi.h>
39 #include <contrib/dev/acpica/include/accommon.h>
40 #include <dev/acpica/acpivar.h>
41
42 /* Hooks for the ACPI CA debugging infrastructure */
43 #define _COMPONENT ACPI_BUS
44 ACPI_MODULE_NAME("GED")
45
46 static MALLOC_DEFINE(M_ACPIGED, "acpiged", "ACPI Generic event data");
47
48 struct acpi_ged_event {
49 device_t dev;
50 struct resource *r;
51 int rid;
52 void *cookie;
53 ACPI_HANDLE ah;
54 ACPI_OBJECT_LIST args;
55 ACPI_OBJECT arg1;
56 };
57
58 struct acpi_ged_softc {
59 int numevts;
60 struct acpi_ged_event *evts;
61 };
62
63 static int acpi_ged_probe(device_t dev);
64 static int acpi_ged_attach(device_t dev);
65 static int acpi_ged_detach(device_t dev);
66
67 static char *ged_ids[] = { "ACPI0013", NULL };
68
69 static device_method_t acpi_ged_methods[] = {
70 /* Device interface */
71 DEVMETHOD(device_probe, acpi_ged_probe),
72 DEVMETHOD(device_attach, acpi_ged_attach),
73 DEVMETHOD(device_detach, acpi_ged_detach),
74 DEVMETHOD_END
75 };
76
77 static driver_t acpi_ged_driver = {
78 "acpi_ged",
79 acpi_ged_methods,
80 sizeof(struct acpi_ged_softc),
81 };
82
83 DRIVER_MODULE(acpi_ged, acpi, acpi_ged_driver, 0, 0);
84 MODULE_DEPEND(acpi_ged, acpi, 1, 1, 1);
85
86 static void
87 acpi_ged_evt(void *arg)
88 {
89 struct acpi_ged_event *evt = arg;
90
91 AcpiEvaluateObject(evt->ah, NULL, &evt->args, NULL);
92 }
93
94 static void
95 acpi_ged_intr(void *arg)
96 {
97 AcpiOsExecute(OSL_GPE_HANDLER, acpi_ged_evt, arg);
98 }
99 static int
100 acpi_ged_probe(device_t dev)
101 {
102 int rv;
103
104 if (acpi_disabled("ged"))
105 return (ENXIO);
106 rv = ACPI_ID_PROBE(device_get_parent(dev), dev, ged_ids, NULL);
107 if (rv > 0)
108 return (ENXIO);
109
110 device_set_desc(dev, "Generic Event Device");
111 return (rv);
112 }
113
114 /*this should be in acpi_resource.*/
115 static int
116 acpi_get_trigger(ACPI_RESOURCE *res)
117 {
118 int trig;
119
120 switch (res->Type) {
121 case ACPI_RESOURCE_TYPE_IRQ:
122 KASSERT(res->Data.Irq.InterruptCount == 1,
123 ("%s: multiple interrupts", __func__));
124 trig = res->Data.Irq.Triggering;
125 break;
126 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
127 KASSERT(res->Data.ExtendedIrq.InterruptCount == 1,
128 ("%s: multiple interrupts", __func__));
129 trig = res->Data.ExtendedIrq.Triggering;
130 break;
131 default:
132 panic("%s: bad resource type %u", __func__, res->Type);
133 }
134
135 return (trig == ACPI_EDGE_SENSITIVE)
136 ? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL;
137 }
138
139 static int
140 acpi_ged_attach(device_t dev)
141 {
142 struct acpi_ged_softc *sc = device_get_softc(dev);
143 struct resource_list *rl;
144 struct resource_list_entry *rle;
145 ACPI_RESOURCE ares;
146 ACPI_HANDLE evt_method;
147 int i;
148 int rawirq, trig;
149 char name[] = "_Xnn";
150
151 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
152
153 if (ACPI_FAILURE(AcpiGetHandle(acpi_get_handle(dev), "_EVT",
154 &evt_method))) {
155 device_printf(dev, "_EVT not found\n");
156 evt_method = NULL;
157 }
158
159 rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
160 STAILQ_FOREACH(rle, rl, link) {
161 if (rle->type == SYS_RES_IRQ) {
162 sc->numevts++;
163 }
164 }
165 sc->evts = mallocarray(sc->numevts, sizeof(*sc->evts), M_ACPIGED,
166 M_WAITOK | M_ZERO);
167 for (i = 0; i < sc->numevts; i++) {
168 sc->evts[i].dev = dev;
169 sc->evts[i].rid = i;
170 sc->evts[i].r = bus_alloc_resource_any(dev, SYS_RES_IRQ,
171 &sc->evts[i].rid, RF_ACTIVE | RF_SHAREABLE);
172 if (sc->evts[i].r == NULL) {
173 device_printf(dev, "Cannot alloc %dth irq\n", i);
174 continue;
175 }
176 #ifdef INTRNG
177 {
178 struct intr_map_data_acpi *ima;
179 ima = rman_get_virtual(sc->evts[i].r);
180 if (ima == NULL) {
181 device_printf(dev, "map not found"
182 " non-intrng?\n");
183 rawirq = rman_get_start(sc->evts[i].r);
184 trig = INTR_TRIGGER_LEVEL;
185 if (ACPI_SUCCESS(acpi_lookup_irq_resource
186 (dev, sc->evts[i].rid,
187 sc->evts[i].r, &ares))) {
188 trig = acpi_get_trigger(&ares);
189 }
190 } else if (ima->hdr.type == INTR_MAP_DATA_ACPI) {
191 device_printf(dev, "Raw IRQ %d\n", ima->irq);
192 rawirq = ima->irq;
193 trig = ima->trig;
194 } else {
195 device_printf(dev, "Not supported intr"
196 " type%d\n", ima->hdr.type);
197 continue;
198 }
199 }
200 #else
201 rawirq = rman_get_start(sc->evts[i].r);
202 trig = INTR_TRIGGER_LEVEL;
203 if (ACPI_SUCCESS(acpi_lookup_irq_resource
204 (dev, sc->evts[i].rid,
205 sc->evts[i].r, &ares))) {
206 trig = acpi_get_trigger(&ares);
207 }
208 #endif
209 if (rawirq < 0x100) {
210 sprintf(name, "_%c%02X",
211 ((trig == INTR_TRIGGER_EDGE) ? 'E' : 'L'),
212 rawirq);
213 if (ACPI_SUCCESS(AcpiGetHandle
214 (acpi_get_handle(dev),
215 name, &sc->evts[i].ah))) {
216 sc->evts[i].args.Count = 0; /* ensure */
217 } else {
218 sc->evts[i].ah = NULL; /* ensure */
219 }
220 }
221
222 if (sc->evts[i].ah == NULL) {
223 if (evt_method != NULL) {
224 sc->evts[i].ah = evt_method;
225 sc->evts[i].arg1.Type = ACPI_TYPE_INTEGER;
226 sc->evts[i].arg1.Integer.Value = rawirq;
227 sc->evts[i].args.Count = 1;
228 sc->evts[i].args.Pointer = &sc->evts[i].arg1;
229 } else{
230 device_printf
231 (dev,
232 "Cannot find handler method %d\n",
233 i);
234 continue;
235 }
236 }
237
238 if (bus_setup_intr(dev, sc->evts[i].r,
239 INTR_TYPE_MISC | INTR_MPSAFE, NULL, acpi_ged_intr,
240 &sc->evts[i], &sc->evts[i].cookie) != 0) {
241 device_printf(dev, "Failed to setup intr %d\n", i);
242 }
243 }
244
245 return_VALUE(0);
246 }
247
248 static int
249 acpi_ged_detach(device_t dev)
250 {
251 struct acpi_ged_softc *sc = device_get_softc(dev);
252 int i;
253
254 for (i = 0; i < sc->numevts; i++) {
255 if (sc->evts[i].cookie) {
256 bus_teardown_intr(dev, sc->evts[i].r,
257 sc->evts[i].cookie);
258 }
259 if (sc->evts[i].r) {
260 bus_release_resource(dev, SYS_RES_IRQ, sc->evts[i].rid,
261 sc->evts[i].r);
262 }
263 }
264 free(sc->evts, M_ACPIGED);
265
266 return (0);
267 }
Cache object: de771d32bf15f045e104fa0db86c8072
|