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 #include "opt_acpi.h" 28 29 #include <sys/param.h> 30 #include <sys/bus.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 #include <sys/module.h> 34 #include <sys/rman.h> 35 36 #include <contrib/dev/acpica/include/acpi.h> 37 #include <contrib/dev/acpica/include/accommon.h> 38 #include <dev/acpica/acpivar.h> 39 40 /* Hooks for the ACPI CA debugging infrastructure */ 41 #define _COMPONENT ACPI_BUS 42 ACPI_MODULE_NAME("GED") 43 44 static MALLOC_DEFINE(M_ACPIGED, "acpiged", "ACPI Generic event data"); 45 46 struct acpi_ged_event { 47 device_t dev; 48 struct resource *r; 49 int rid; 50 void *cookie; 51 ACPI_HANDLE ah; 52 ACPI_OBJECT_LIST args; 53 ACPI_OBJECT arg1; 54 }; 55 56 struct acpi_ged_softc { 57 int numevts; 58 struct acpi_ged_event *evts; 59 }; 60 61 static int acpi_ged_probe(device_t dev); 62 static int acpi_ged_attach(device_t dev); 63 static int acpi_ged_detach(device_t dev); 64 65 static char *ged_ids[] = { "ACPI0013", NULL }; 66 67 static device_method_t acpi_ged_methods[] = { 68 /* Device interface */ 69 DEVMETHOD(device_probe, acpi_ged_probe), 70 DEVMETHOD(device_attach, acpi_ged_attach), 71 DEVMETHOD(device_detach, acpi_ged_detach), 72 DEVMETHOD_END 73 }; 74 75 static driver_t acpi_ged_driver = { 76 "acpi_ged", 77 acpi_ged_methods, 78 sizeof(struct acpi_ged_softc), 79 }; 80 81 DRIVER_MODULE(acpi_ged, acpi, acpi_ged_driver, 0, 0); 82 MODULE_DEPEND(acpi_ged, acpi, 1, 1, 1); 83 84 static void 85 acpi_ged_evt(void *arg) 86 { 87 struct acpi_ged_event *evt = arg; 88 89 AcpiEvaluateObject(evt->ah, NULL, &evt->args, NULL); 90 } 91 92 static void 93 acpi_ged_intr(void *arg) 94 { 95 AcpiOsExecute(OSL_GPE_HANDLER, acpi_ged_evt, arg); 96 } 97 static int 98 acpi_ged_probe(device_t dev) 99 { 100 int rv; 101 102 if (acpi_disabled("ged")) 103 return (ENXIO); 104 rv = ACPI_ID_PROBE(device_get_parent(dev), dev, ged_ids, NULL); 105 if (rv > 0) 106 return (ENXIO); 107 108 device_set_desc(dev, "Generic Event Device"); 109 return (rv); 110 } 111 112 /*this should be in acpi_resource.*/ 113 static int 114 acpi_get_trigger(ACPI_RESOURCE *res) 115 { 116 int trig; 117 118 switch (res->Type) { 119 case ACPI_RESOURCE_TYPE_IRQ: 120 KASSERT(res->Data.Irq.InterruptCount == 1, 121 ("%s: multiple interrupts", __func__)); 122 trig = res->Data.Irq.Triggering; 123 break; 124 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 125 KASSERT(res->Data.ExtendedIrq.InterruptCount == 1, 126 ("%s: multiple interrupts", __func__)); 127 trig = res->Data.ExtendedIrq.Triggering; 128 break; 129 default: 130 panic("%s: bad resource type %u", __func__, res->Type); 131 } 132 133 return (trig == ACPI_EDGE_SENSITIVE) 134 ? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL; 135 } 136 137 static int 138 acpi_ged_attach(device_t dev) 139 { 140 struct acpi_ged_softc *sc = device_get_softc(dev); 141 struct resource_list *rl; 142 struct resource_list_entry *rle; 143 ACPI_RESOURCE ares; 144 ACPI_HANDLE evt_method; 145 int i; 146 int rawirq, trig; 147 char name[] = "_Xnn"; 148 149 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 150 151 if (ACPI_FAILURE(AcpiGetHandle(acpi_get_handle(dev), "_EVT", 152 &evt_method))) { 153 device_printf(dev, "_EVT not found\n"); 154 evt_method = NULL; 155 } 156 157 rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 158 STAILQ_FOREACH(rle, rl, link) { 159 if (rle->type == SYS_RES_IRQ) { 160 sc->numevts++; 161 } 162 } 163 sc->evts = mallocarray(sc->numevts, sizeof(*sc->evts), M_ACPIGED, 164 M_WAITOK | M_ZERO); 165 for (i = 0; i < sc->numevts; i++) { 166 sc->evts[i].dev = dev; 167 sc->evts[i].rid = i; 168 sc->evts[i].r = bus_alloc_resource_any(dev, SYS_RES_IRQ, 169 &sc->evts[i].rid, RF_ACTIVE | RF_SHAREABLE); 170 if (sc->evts[i].r == NULL) { 171 device_printf(dev, "Cannot alloc %dth irq\n", i); 172 continue; 173 } 174 #ifdef INTRNG 175 { 176 struct intr_map_data_acpi *ima; 177 ima = rman_get_virtual(sc->evts[i].r); 178 if (ima == NULL) { 179 device_printf(dev, "map not found" 180 " non-intrng?\n"); 181 rawirq = rman_get_start(sc->evts[i].r); 182 trig = INTR_TRIGGER_LEVEL; 183 if (ACPI_SUCCESS(acpi_lookup_irq_resource 184 (dev, sc->evts[i].rid, 185 sc->evts[i].r, &ares))) { 186 trig = acpi_get_trigger(&ares); 187 } 188 } else if (ima->hdr.type == INTR_MAP_DATA_ACPI) { 189 device_printf(dev, "Raw IRQ %d\n", ima->irq); 190 rawirq = ima->irq; 191 trig = ima->trig; 192 } else { 193 device_printf(dev, "Not supported intr" 194 " type%d\n", ima->hdr.type); 195 continue; 196 } 197 } 198 #else 199 rawirq = rman_get_start(sc->evts[i].r); 200 trig = INTR_TRIGGER_LEVEL; 201 if (ACPI_SUCCESS(acpi_lookup_irq_resource 202 (dev, sc->evts[i].rid, 203 sc->evts[i].r, &ares))) { 204 trig = acpi_get_trigger(&ares); 205 } 206 #endif 207 if (rawirq < 0x100) { 208 sprintf(name, "_%c%02X", 209 ((trig == INTR_TRIGGER_EDGE) ? 'E' : 'L'), 210 rawirq); 211 if (ACPI_SUCCESS(AcpiGetHandle 212 (acpi_get_handle(dev), 213 name, &sc->evts[i].ah))) { 214 sc->evts[i].args.Count = 0; /* ensure */ 215 } else { 216 sc->evts[i].ah = NULL; /* ensure */ 217 } 218 } 219 220 if (sc->evts[i].ah == NULL) { 221 if (evt_method != NULL) { 222 sc->evts[i].ah = evt_method; 223 sc->evts[i].arg1.Type = ACPI_TYPE_INTEGER; 224 sc->evts[i].arg1.Integer.Value = rawirq; 225 sc->evts[i].args.Count = 1; 226 sc->evts[i].args.Pointer = &sc->evts[i].arg1; 227 } else{ 228 device_printf 229 (dev, 230 "Cannot find handler method %d\n", 231 i); 232 continue; 233 } 234 } 235 236 if (bus_setup_intr(dev, sc->evts[i].r, 237 INTR_TYPE_MISC | INTR_MPSAFE, NULL, acpi_ged_intr, 238 &sc->evts[i], &sc->evts[i].cookie) != 0) { 239 device_printf(dev, "Failed to setup intr %d\n", i); 240 } 241 } 242 243 return_VALUE(0); 244 } 245 246 static int 247 acpi_ged_detach(device_t dev) 248 { 249 struct acpi_ged_softc *sc = device_get_softc(dev); 250 int i; 251 252 for (i = 0; i < sc->numevts; i++) { 253 if (sc->evts[i].cookie) { 254 bus_teardown_intr(dev, sc->evts[i].r, 255 sc->evts[i].cookie); 256 } 257 if (sc->evts[i].r) { 258 bus_release_resource(dev, SYS_RES_IRQ, sc->evts[i].rid, 259 sc->evts[i].r); 260 } 261 } 262 free(sc->evts, M_ACPIGED); 263 264 return (0); 265 } 266