1bca7db71SImre Vadász /* 2bca7db71SImre Vadász * Copyright (c) 2016 The DragonFly Project. All rights reserved. 3bca7db71SImre Vadász * 4bca7db71SImre Vadász * This code is derived from software contributed to The DragonFly Project 5bca7db71SImre Vadász * by Imre Vadász <imre@vdsz.com> 6bca7db71SImre Vadász * 7bca7db71SImre Vadász * Redistribution and use in source and binary forms, with or without 8bca7db71SImre Vadász * modification, are permitted provided that the following conditions 9bca7db71SImre Vadász * are met: 10bca7db71SImre Vadász * 11bca7db71SImre Vadász * 1. Redistributions of source code must retain the above copyright 12bca7db71SImre Vadász * notice, this list of conditions and the following disclaimer. 13bca7db71SImre Vadász * 2. Redistributions in binary form must reproduce the above copyright 14bca7db71SImre Vadász * notice, this list of conditions and the following disclaimer in 15bca7db71SImre Vadász * the documentation and/or other materials provided with the 16bca7db71SImre Vadász * distribution. 17bca7db71SImre Vadász * 3. Neither the name of The DragonFly Project nor the names of its 18bca7db71SImre Vadász * contributors may be used to endorse or promote products derived 19bca7db71SImre Vadász * from this software without specific, prior written permission. 20bca7db71SImre Vadász * 21bca7db71SImre Vadász * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22bca7db71SImre Vadász * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23bca7db71SImre Vadász * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24bca7db71SImre Vadász * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25bca7db71SImre Vadász * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26bca7db71SImre Vadász * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27bca7db71SImre Vadász * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28bca7db71SImre Vadász * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29bca7db71SImre Vadász * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30bca7db71SImre Vadász * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31bca7db71SImre Vadász * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32bca7db71SImre Vadász * SUCH DAMAGE. 33bca7db71SImre Vadász */ 34bca7db71SImre Vadász 35bca7db71SImre Vadász #include <sys/param.h> 36bca7db71SImre Vadász #include <sys/systm.h> 37bca7db71SImre Vadász #include <sys/kernel.h> 38bca7db71SImre Vadász #include <sys/module.h> 39bca7db71SImre Vadász #include <sys/errno.h> 40bca7db71SImre Vadász #include <sys/lock.h> 41bca7db71SImre Vadász #include <sys/mutex.h> 42bca7db71SImre Vadász #include <sys/bus.h> 43bca7db71SImre Vadász 44bca7db71SImre Vadász #include "opt_acpi.h" 4585e653c7SImre Vadász #include "acpi.h" 46bca7db71SImre Vadász #include <dev/acpica/acpivar.h> 47bca7db71SImre Vadász 48bca7db71SImre Vadász #include "gpio_acpivar.h" 49bca7db71SImre Vadász 50bca7db71SImre Vadász #include "gpio_if.h" 51bca7db71SImre Vadász 52bca7db71SImre Vadász struct acpi_event_info { 53bca7db71SImre Vadász device_t dev; 54ad9cd008SImre Vadász u_int pin; 55ad9cd008SImre Vadász void *cookie; 56bca7db71SImre Vadász int trigger; 57bca7db71SImre Vadász }; 58bca7db71SImre Vadász 59bca7db71SImre Vadász struct acpi_gpio_handler_data { 60bca7db71SImre Vadász struct acpi_connection_info info; 61bca7db71SImre Vadász device_t dev; 62bca7db71SImre Vadász }; 63bca7db71SImre Vadász 64bca7db71SImre Vadász struct gpio_acpi_data { 65bca7db71SImre Vadász struct acpi_event_info *infos; 66bca7db71SImre Vadász int num_aei; 67bca7db71SImre Vadász struct acpi_gpio_handler_data space_handler_data; 68bca7db71SImre Vadász }; 69bca7db71SImre Vadász 701ad3434bSImre Vadász static BOOLEAN gpio_acpi_check_gpioint(device_t dev, ACPI_RESOURCE_GPIO *gpio); 71*d56572d4SImre Vadász static void **gpioio_alloc_pins(device_t dev, device_t provider, 72*d56572d4SImre Vadász ACPI_RESOURCE_GPIO *gpio, uint16_t idx, uint16_t length, 73*d56572d4SImre Vadász void **buf); 741ad3434bSImre Vadász 75bca7db71SImre Vadász /* GPIO Address Space Handler */ 76bca7db71SImre Vadász static void gpio_acpi_install_address_space_handler(device_t dev, 77bca7db71SImre Vadász struct acpi_gpio_handler_data *data); 78bca7db71SImre Vadász static void gpio_acpi_remove_address_space_handler(device_t dev, 79bca7db71SImre Vadász struct acpi_gpio_handler_data *data); 80bca7db71SImre Vadász static ACPI_STATUS gpio_acpi_space_handler(UINT32 Function, 81bca7db71SImre Vadász ACPI_PHYSICAL_ADDRESS Address, UINT32 BitWidth, 82bca7db71SImre Vadász UINT64 *Value, void *HandlerContext, 83bca7db71SImre Vadász void *RegionContext); 84bca7db71SImre Vadász 85bca7db71SImre Vadász /* ACPI Event Interrupts */ 86bca7db71SImre Vadász static void gpio_acpi_do_map_aei(device_t dev, 87bca7db71SImre Vadász struct acpi_event_info *info, ACPI_RESOURCE_GPIO *gpio); 88bca7db71SImre Vadász static void *gpio_acpi_map_aei(device_t dev, int *num_aei); 89bca7db71SImre Vadász static void gpio_acpi_unmap_aei(device_t dev, struct gpio_acpi_data *data); 90bca7db71SImre Vadász static void gpio_acpi_handle_event(void *Context); 91bca7db71SImre Vadász static void gpio_acpi_aei_handler(void *arg); 92bca7db71SImre Vadász 93bca7db71SImre Vadász /* Register GPIO device with ACPICA for ACPI-5.0 GPIO functionality */ 94bca7db71SImre Vadász void * 95bca7db71SImre Vadász gpio_acpi_register(device_t dev) 96bca7db71SImre Vadász { 97bca7db71SImre Vadász struct gpio_acpi_data *data; 98bca7db71SImre Vadász 99bca7db71SImre Vadász data = kmalloc(sizeof(*data), M_DEVBUF, M_WAITOK | M_ZERO); 100bca7db71SImre Vadász 101bca7db71SImre Vadász gpio_acpi_install_address_space_handler(dev, 102bca7db71SImre Vadász &data->space_handler_data); 103bca7db71SImre Vadász 104bca7db71SImre Vadász data->infos = gpio_acpi_map_aei(dev, &data->num_aei); 105bca7db71SImre Vadász 106bca7db71SImre Vadász return data; 107bca7db71SImre Vadász } 108bca7db71SImre Vadász 109bca7db71SImre Vadász void 110bca7db71SImre Vadász gpio_acpi_unregister(device_t dev, void *arg) 111bca7db71SImre Vadász { 112bca7db71SImre Vadász struct gpio_acpi_data *data = (struct gpio_acpi_data *)arg; 113bca7db71SImre Vadász 114bca7db71SImre Vadász if (data->infos != NULL) 115bca7db71SImre Vadász gpio_acpi_unmap_aei(dev, data); 116bca7db71SImre Vadász 117bca7db71SImre Vadász gpio_acpi_remove_address_space_handler(dev, &data->space_handler_data); 118bca7db71SImre Vadász 119bca7db71SImre Vadász kfree(data, M_DEVBUF); 120bca7db71SImre Vadász } 121bca7db71SImre Vadász 1221ad3434bSImre Vadász /* Sanity-Check for GpioInt resources */ 1231ad3434bSImre Vadász static BOOLEAN 1241ad3434bSImre Vadász gpio_acpi_check_gpioint(device_t dev, ACPI_RESOURCE_GPIO *gpio) 1251ad3434bSImre Vadász { 1261ad3434bSImre Vadász 1271ad3434bSImre Vadász if (gpio->PinTableLength != 1) { 1281ad3434bSImre Vadász device_printf(dev, 1291ad3434bSImre Vadász "Unexepcted GpioInt resource PinTableLength %d\n", 1301ad3434bSImre Vadász gpio->PinTableLength); 1311ad3434bSImre Vadász return (FALSE); 1321ad3434bSImre Vadász } 1331ad3434bSImre Vadász switch (gpio->Triggering) { 1341ad3434bSImre Vadász case ACPI_LEVEL_SENSITIVE: 1351ad3434bSImre Vadász case ACPI_EDGE_SENSITIVE: 1361ad3434bSImre Vadász break; 1371ad3434bSImre Vadász default: 1381ad3434bSImre Vadász device_printf(dev, "Invalid GpioInt resource Triggering: %d\n", 1391ad3434bSImre Vadász gpio->Triggering); 1401ad3434bSImre Vadász return (FALSE); 1411ad3434bSImre Vadász } 1421ad3434bSImre Vadász switch (gpio->Polarity) { 1431ad3434bSImre Vadász case ACPI_ACTIVE_HIGH: 1441ad3434bSImre Vadász case ACPI_ACTIVE_LOW: 1451ad3434bSImre Vadász case ACPI_ACTIVE_BOTH: 1461ad3434bSImre Vadász break; 1471ad3434bSImre Vadász default: 1481ad3434bSImre Vadász device_printf(dev, "Invalid GpioInt resource Polarity: %d\n", 1491ad3434bSImre Vadász gpio->Polarity); 1501ad3434bSImre Vadász return (FALSE); 1511ad3434bSImre Vadász } 1521ad3434bSImre Vadász 1531ad3434bSImre Vadász return (TRUE); 1541ad3434bSImre Vadász } 1551ad3434bSImre Vadász 156bca7db71SImre Vadász /* 157*d56572d4SImre Vadász * GpioIo ACPI resource handling 158*d56572d4SImre Vadász */ 159*d56572d4SImre Vadász 160*d56572d4SImre Vadász static void ** 161*d56572d4SImre Vadász gpioio_alloc_pins(device_t dev, device_t provider, ACPI_RESOURCE_GPIO *gpio, 162*d56572d4SImre Vadász uint16_t idx, uint16_t length, void **buf) 163*d56572d4SImre Vadász { 164*d56572d4SImre Vadász void **pins; 165*d56572d4SImre Vadász int flags, i, j; 166*d56572d4SImre Vadász 167*d56572d4SImre Vadász if (buf == NULL) { 168*d56572d4SImre Vadász pins = kmalloc(sizeof(*pins) * length, M_DEVBUF, 169*d56572d4SImre Vadász M_WAITOK | M_ZERO); 170*d56572d4SImre Vadász } else { 171*d56572d4SImre Vadász pins = buf; 172*d56572d4SImre Vadász } 173*d56572d4SImre Vadász 174*d56572d4SImre Vadász if (gpio->IoRestriction == ACPI_IO_RESTRICT_INPUT) { 175*d56572d4SImre Vadász flags = (1U << 0); 176*d56572d4SImre Vadász } else if (gpio->IoRestriction == 177*d56572d4SImre Vadász ACPI_IO_RESTRICT_OUTPUT) { 178*d56572d4SImre Vadász flags = (1U << 1); 179*d56572d4SImre Vadász } else { 180*d56572d4SImre Vadász flags = (1U << 0) | (1U << 1); 181*d56572d4SImre Vadász } 182*d56572d4SImre Vadász for (i = 0; i < length; i++) { 183*d56572d4SImre Vadász if (GPIO_ALLOC_IO_PIN(provider, gpio->PinTable[idx + i], flags, 184*d56572d4SImre Vadász &pins[i]) != 0) { 185*d56572d4SImre Vadász device_printf(dev, "Failed to alloc GpioIo pin %u on " 186*d56572d4SImre Vadász "ResourceSource \"%s\"\n", gpio->PinTable[idx + i], 187*d56572d4SImre Vadász gpio->ResourceSource.StringPtr); 188*d56572d4SImre Vadász /* Release already alloc-ed pins */ 189*d56572d4SImre Vadász for (j = 0; j < i; j++) 190*d56572d4SImre Vadász GPIO_RELEASE_IO_PIN(provider, pins[j]); 191*d56572d4SImre Vadász goto err; 192*d56572d4SImre Vadász } 193*d56572d4SImre Vadász } 194*d56572d4SImre Vadász 195*d56572d4SImre Vadász return (pins); 196*d56572d4SImre Vadász 197*d56572d4SImre Vadász err: 198*d56572d4SImre Vadász if (buf == NULL) 199*d56572d4SImre Vadász kfree(pins, M_DEVBUF); 200*d56572d4SImre Vadász return (NULL); 201*d56572d4SImre Vadász } 202*d56572d4SImre Vadász 203*d56572d4SImre Vadász /* 204bca7db71SImre Vadász * GPIO Address space handler 205bca7db71SImre Vadász */ 206bca7db71SImre Vadász 207bca7db71SImre Vadász static void 208bca7db71SImre Vadász gpio_acpi_install_address_space_handler(device_t dev, 209bca7db71SImre Vadász struct acpi_gpio_handler_data *data) 210bca7db71SImre Vadász { 211bca7db71SImre Vadász ACPI_HANDLE handle; 212bca7db71SImre Vadász ACPI_STATUS s; 213bca7db71SImre Vadász 214bca7db71SImre Vadász handle = acpi_get_handle(dev); 215bca7db71SImre Vadász data->dev = dev; 216bca7db71SImre Vadász s = AcpiInstallAddressSpaceHandler(handle, ACPI_ADR_SPACE_GPIO, 217bca7db71SImre Vadász &gpio_acpi_space_handler, NULL, data); 2181ad3434bSImre Vadász if (ACPI_FAILURE(s)) { 219bca7db71SImre Vadász device_printf(dev, 220bca7db71SImre Vadász "Failed to install GPIO Address Space Handler in ACPI\n"); 221bca7db71SImre Vadász } 222bca7db71SImre Vadász } 223bca7db71SImre Vadász 224bca7db71SImre Vadász static void 225bca7db71SImre Vadász gpio_acpi_remove_address_space_handler(device_t dev, 226bca7db71SImre Vadász struct acpi_gpio_handler_data *data) 227bca7db71SImre Vadász { 228bca7db71SImre Vadász ACPI_HANDLE handle; 229bca7db71SImre Vadász ACPI_STATUS s; 230bca7db71SImre Vadász 231bca7db71SImre Vadász handle = acpi_get_handle(dev); 232bca7db71SImre Vadász s = AcpiRemoveAddressSpaceHandler(handle, ACPI_ADR_SPACE_GPIO, 233bca7db71SImre Vadász &gpio_acpi_space_handler); 2341ad3434bSImre Vadász if (ACPI_FAILURE(s)) { 235bca7db71SImre Vadász device_printf(dev, 236bca7db71SImre Vadász "Failed to remove GPIO Address Space Handler from ACPI\n"); 237bca7db71SImre Vadász } 238bca7db71SImre Vadász } 239bca7db71SImre Vadász 240bca7db71SImre Vadász static ACPI_STATUS 241bca7db71SImre Vadász gpio_acpi_space_handler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, 242bca7db71SImre Vadász UINT32 BitWidth, UINT64 *Value, void *HandlerContext, void *RegionContext) 243bca7db71SImre Vadász { 244bca7db71SImre Vadász struct acpi_gpio_handler_data *data = HandlerContext; 245bca7db71SImre Vadász device_t dev = data->dev; 246bca7db71SImre Vadász struct acpi_connection_info *info = &data->info; 247bca7db71SImre Vadász struct acpi_resource_gpio *gpio; 248bca7db71SImre Vadász UINT64 val; 249bca7db71SImre Vadász UINT8 action = Function & ACPI_IO_MASK; 250bca7db71SImre Vadász ACPI_RESOURCE *Resource; 251bca7db71SImre Vadász ACPI_STATUS s = AE_OK; 252*d56572d4SImre Vadász void **pins; 253bca7db71SImre Vadász int i; 254bca7db71SImre Vadász 255*d56572d4SImre Vadász if (Value == NULL) 256*d56572d4SImre Vadász return (AE_BAD_PARAMETER); 257bca7db71SImre Vadász 258bca7db71SImre Vadász /* XXX probably unnecessary */ 259*d56572d4SImre Vadász if (BitWidth == 0 || BitWidth > 64) 260*d56572d4SImre Vadász return (AE_BAD_PARAMETER); 261*d56572d4SImre Vadász 262*d56572d4SImre Vadász s = AcpiBufferToResource(info->Connection, info->Length, &Resource); 263*d56572d4SImre Vadász if (ACPI_FAILURE(s)) { 264*d56572d4SImre Vadász device_printf(dev, "AcpiBufferToResource failed\n"); 265*d56572d4SImre Vadász return (s); 266*d56572d4SImre Vadász } 267*d56572d4SImre Vadász if (Resource->Type != ACPI_RESOURCE_TYPE_GPIO) { 268*d56572d4SImre Vadász device_printf(dev, "Resource->Type is wrong\n"); 269*d56572d4SImre Vadász s = AE_BAD_PARAMETER; 270*d56572d4SImre Vadász goto err; 271*d56572d4SImre Vadász } 272*d56572d4SImre Vadász gpio = &Resource->Data.Gpio; 273*d56572d4SImre Vadász if (gpio->ConnectionType != ACPI_RESOURCE_GPIO_TYPE_IO) { 274*d56572d4SImre Vadász device_printf(dev, "gpio->ConnectionType is wrong\n"); 275bca7db71SImre Vadász s = AE_BAD_PARAMETER; 276bca7db71SImre Vadász goto err; 277bca7db71SImre Vadász } 278bca7db71SImre Vadász 279bca7db71SImre Vadász if (Address + BitWidth > gpio->PinTableLength) { 280*d56572d4SImre Vadász device_printf(dev, "Address + BitWidth out of range\n"); 281bca7db71SImre Vadász s = AE_BAD_ADDRESS; 282bca7db71SImre Vadász goto err; 283bca7db71SImre Vadász } 284bca7db71SImre Vadász 285*d56572d4SImre Vadász if (gpio->IoRestriction == ACPI_IO_RESTRICT_OUTPUT && 286*d56572d4SImre Vadász action == ACPI_READ) { 287*d56572d4SImre Vadász device_printf(dev, 288*d56572d4SImre Vadász "IoRestriction is output only, but action is ACPI_READ\n"); 289bca7db71SImre Vadász s = AE_BAD_PARAMETER; 290bca7db71SImre Vadász goto err; 291bca7db71SImre Vadász } 292*d56572d4SImre Vadász if (gpio->IoRestriction == ACPI_IO_RESTRICT_INPUT && 293*d56572d4SImre Vadász action == ACPI_WRITE) { 294*d56572d4SImre Vadász device_printf(dev, 295*d56572d4SImre Vadász "IoRestriction is input only, but action is ACPI_WRITE\n"); 296*d56572d4SImre Vadász s = AE_BAD_PARAMETER; 297*d56572d4SImre Vadász goto err; 298*d56572d4SImre Vadász } 299*d56572d4SImre Vadász 300*d56572d4SImre Vadász /* Make sure we can access all pins, before trying actual read/write */ 301*d56572d4SImre Vadász pins = gpioio_alloc_pins(dev, dev, gpio, Address, BitWidth, NULL); 302*d56572d4SImre Vadász if (pins == NULL) { 303*d56572d4SImre Vadász s = AE_BAD_PARAMETER; 304*d56572d4SImre Vadász goto err; 305*d56572d4SImre Vadász } 306*d56572d4SImre Vadász 307*d56572d4SImre Vadász if (action == ACPI_READ) { 308bca7db71SImre Vadász *Value = 0; 309bca7db71SImre Vadász for (i = 0; i < BitWidth; i++) { 310*d56572d4SImre Vadász val = GPIO_READ_PIN(dev, pins[i]); 311bca7db71SImre Vadász *Value |= val << i; 312bca7db71SImre Vadász } 313bca7db71SImre Vadász } else { 314bca7db71SImre Vadász for (i = 0; i < BitWidth; i++) { 315*d56572d4SImre Vadász GPIO_WRITE_PIN(dev, pins[i], 316*d56572d4SImre Vadász (*Value & (1ULL << i)) ? 1 : 0); 317bca7db71SImre Vadász } 318bca7db71SImre Vadász } 319*d56572d4SImre Vadász for (i = 0; i < BitWidth; i++) 320*d56572d4SImre Vadász GPIO_RELEASE_IO_PIN(dev, pins[i]); 321*d56572d4SImre Vadász kfree(pins, M_DEVBUF); 322bca7db71SImre Vadász 323bca7db71SImre Vadász err: 324bca7db71SImre Vadász ACPI_FREE(Resource); 325bca7db71SImre Vadász return (s); 326bca7db71SImre Vadász } 327bca7db71SImre Vadász 328bca7db71SImre Vadász /* 329bca7db71SImre Vadász * ACPI Event Interrupts 330bca7db71SImre Vadász */ 331bca7db71SImre Vadász 332bca7db71SImre Vadász static void 333bca7db71SImre Vadász gpio_acpi_handle_event(void *Context) 334bca7db71SImre Vadász { 335bca7db71SImre Vadász struct acpi_event_info *info = (struct acpi_event_info *)Context; 336bca7db71SImre Vadász ACPI_HANDLE handle, h; 337bca7db71SImre Vadász ACPI_STATUS s; 338bca7db71SImre Vadász char buf[5]; 339bca7db71SImre Vadász 340bca7db71SImre Vadász handle = acpi_get_handle(info->dev); 341bca7db71SImre Vadász if (info->trigger == ACPI_EDGE_SENSITIVE) { 342bca7db71SImre Vadász ksnprintf(buf, sizeof(buf), "_E%02X", info->pin); 343bca7db71SImre Vadász } else { 344bca7db71SImre Vadász ksnprintf(buf, sizeof(buf), "_L%02X", info->pin); 345bca7db71SImre Vadász } 346bca7db71SImre Vadász if (info->pin <= 255 && ACPI_SUCCESS(AcpiGetHandle(handle, buf, &h))) { 347bca7db71SImre Vadász s = AcpiEvaluateObject(handle, buf, NULL, NULL); 3481ad3434bSImre Vadász if (ACPI_FAILURE(s)) 349bca7db71SImre Vadász device_printf(info->dev, "evaluating %s failed\n", buf); 350bca7db71SImre Vadász } else { 351bca7db71SImre Vadász ACPI_OBJECT_LIST arglist; 352bca7db71SImre Vadász ACPI_OBJECT arg; 353bca7db71SImre Vadász 354bca7db71SImre Vadász arglist.Pointer = &arg; 355bca7db71SImre Vadász arglist.Count = 1; 356bca7db71SImre Vadász arg.Type = ACPI_TYPE_INTEGER; 357bca7db71SImre Vadász arg.Integer.Value = info->pin; 358bca7db71SImre Vadász s = AcpiEvaluateObject(handle, "_EVT", &arglist, NULL); 3591ad3434bSImre Vadász if (ACPI_FAILURE(s)) 360bca7db71SImre Vadász device_printf(info->dev, "evaluating _EVT failed\n"); 361bca7db71SImre Vadász } 362bca7db71SImre Vadász } 363bca7db71SImre Vadász 364bca7db71SImre Vadász static void 365bca7db71SImre Vadász gpio_acpi_aei_handler(void *arg) 366bca7db71SImre Vadász { 367bca7db71SImre Vadász struct acpi_event_info *info = (struct acpi_event_info *)arg; 368bca7db71SImre Vadász ACPI_STATUS s; 369bca7db71SImre Vadász 370bca7db71SImre Vadász s = AcpiOsExecute(OSL_GPE_HANDLER, gpio_acpi_handle_event, arg); 3711ad3434bSImre Vadász if (ACPI_FAILURE(s)) { 372bca7db71SImre Vadász device_printf(info->dev, 373bca7db71SImre Vadász "AcpiOsExecute for Acpi Event handler failed\n"); 374bca7db71SImre Vadász } 375bca7db71SImre Vadász } 376bca7db71SImre Vadász 377bca7db71SImre Vadász static void 378bca7db71SImre Vadász gpio_acpi_do_map_aei(device_t dev, struct acpi_event_info *info, 379bca7db71SImre Vadász ACPI_RESOURCE_GPIO *gpio) 380bca7db71SImre Vadász { 381bca7db71SImre Vadász uint16_t pin; 382ad9cd008SImre Vadász void *cookie; 383bca7db71SImre Vadász 384bca7db71SImre Vadász if (gpio->ConnectionType != ACPI_RESOURCE_GPIO_TYPE_INT) { 385bca7db71SImre Vadász device_printf(dev, "Unexpected gpio type %d\n", 386bca7db71SImre Vadász gpio->ConnectionType); 387bca7db71SImre Vadász return; 388bca7db71SImre Vadász } 389bca7db71SImre Vadász 3901ad3434bSImre Vadász if (!gpio_acpi_check_gpioint(dev, gpio)) 391bca7db71SImre Vadász return; 392bca7db71SImre Vadász 3930b0166b0SImre Vadász pin = gpio->PinTable[0]; 3940b0166b0SImre Vadász 3950b0166b0SImre Vadász if (GPIO_ALLOC_INTR(dev, pin, gpio->Triggering, gpio->Polarity, 396ad9cd008SImre Vadász gpio->PinConfig, &cookie) != 0) { 3970b0166b0SImre Vadász device_printf(dev, 3980b0166b0SImre Vadász "Failed to allocate AEI interrupt on pin %d\n", pin); 3990b0166b0SImre Vadász return; 4000b0166b0SImre Vadász } 4010b0166b0SImre Vadász 402bca7db71SImre Vadász info->dev = dev; 403bca7db71SImre Vadász info->pin = pin; 404bca7db71SImre Vadász info->trigger = gpio->Triggering; 405ad9cd008SImre Vadász info->cookie = cookie; 406bca7db71SImre Vadász 407ad9cd008SImre Vadász GPIO_SETUP_INTR(dev, cookie, info, gpio_acpi_aei_handler); 408bca7db71SImre Vadász } 409bca7db71SImre Vadász 410bca7db71SImre Vadász /* Map ACPI events */ 411bca7db71SImre Vadász static void * 412bca7db71SImre Vadász gpio_acpi_map_aei(device_t dev, int *num_aei) 413bca7db71SImre Vadász { 414bca7db71SImre Vadász ACPI_HANDLE handle = acpi_get_handle(dev); 415bca7db71SImre Vadász ACPI_RESOURCE_GPIO *gpio; 416bca7db71SImre Vadász ACPI_RESOURCE *res, *end; 417bca7db71SImre Vadász ACPI_BUFFER b; 418bca7db71SImre Vadász ACPI_STATUS s; 419bca7db71SImre Vadász struct acpi_event_info *infos = NULL; 420bca7db71SImre Vadász int n; 421bca7db71SImre Vadász 422bca7db71SImre Vadász *num_aei = 0; 423bca7db71SImre Vadász 424bca7db71SImre Vadász b.Pointer = NULL; 425bca7db71SImre Vadász b.Length = ACPI_ALLOCATE_BUFFER; 426bca7db71SImre Vadász s = AcpiGetEventResources(handle, &b); 427bca7db71SImre Vadász if (ACPI_SUCCESS(s)) { 428bca7db71SImre Vadász end = (ACPI_RESOURCE *)((char *)b.Pointer + b.Length); 429bca7db71SImre Vadász /* Count Gpio connections */ 430bca7db71SImre Vadász n = 0; 431bca7db71SImre Vadász for (res = (ACPI_RESOURCE *)b.Pointer; res < end; 432bca7db71SImre Vadász res = ACPI_NEXT_RESOURCE(res)) { 433*d56572d4SImre Vadász if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) { 434bca7db71SImre Vadász break; 435*d56572d4SImre Vadász } else if (res->Type == ACPI_RESOURCE_TYPE_GPIO) { 436bca7db71SImre Vadász n++; 437*d56572d4SImre Vadász } else { 438*d56572d4SImre Vadász device_printf(dev, 439*d56572d4SImre Vadász "Unexpected resource type %d\n", 440*d56572d4SImre Vadász res->Type); 441bca7db71SImre Vadász } 442bca7db71SImre Vadász } 443bca7db71SImre Vadász if (n <= 0) { 444bca7db71SImre Vadász AcpiOsFree(b.Pointer); 445bca7db71SImre Vadász return (infos); 446bca7db71SImre Vadász } 447bca7db71SImre Vadász infos = kmalloc(n*sizeof(*infos), M_DEVBUF, M_WAITOK | M_ZERO); 448bca7db71SImre Vadász *num_aei = n; 449bca7db71SImre Vadász n = 0; 450bca7db71SImre Vadász for (res = (ACPI_RESOURCE *)b.Pointer; res < end; 451bca7db71SImre Vadász res = ACPI_NEXT_RESOURCE(res)) { 452bca7db71SImre Vadász if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) 453bca7db71SImre Vadász break; 454*d56572d4SImre Vadász if (res->Type == ACPI_RESOURCE_TYPE_GPIO) { 455bca7db71SImre Vadász gpio = (ACPI_RESOURCE_GPIO *)&res->Data; 456bca7db71SImre Vadász gpio_acpi_do_map_aei(dev, &infos[n++], gpio); 457*d56572d4SImre Vadász } 458bca7db71SImre Vadász } 459bca7db71SImre Vadász AcpiOsFree(b.Pointer); 460bca7db71SImre Vadász } 461bca7db71SImre Vadász return (infos); 462bca7db71SImre Vadász } 463bca7db71SImre Vadász 464bca7db71SImre Vadász /* Unmap ACPI events */ 465bca7db71SImre Vadász static void 466bca7db71SImre Vadász gpio_acpi_unmap_aei(device_t dev, struct gpio_acpi_data *data) 467bca7db71SImre Vadász { 468bca7db71SImre Vadász struct acpi_event_info *info; 469bca7db71SImre Vadász int i; 470bca7db71SImre Vadász 471bca7db71SImre Vadász for (i = 0; i < data->num_aei; i++) { 472bca7db71SImre Vadász info = &data->infos[i]; 473bca7db71SImre Vadász if (info->dev != NULL) { 474ad9cd008SImre Vadász GPIO_TEARDOWN_INTR(dev, info->cookie); 475ad9cd008SImre Vadász GPIO_FREE_INTR(dev, info->cookie); 476bca7db71SImre Vadász /* XXX Wait until ACPI Event handler has finished */ 477bca7db71SImre Vadász memset(info, 0, sizeof(*info)); 478bca7db71SImre Vadász } 479bca7db71SImre Vadász } 480bca7db71SImre Vadász kfree(data->infos, M_DEVBUF); 481bca7db71SImre Vadász } 482bca7db71SImre Vadász 483bca7db71SImre Vadász MODULE_DEPEND(gpio_acpi, acpi, 1, 1, 1); 484bca7db71SImre Vadász MODULE_VERSION(gpio_acpi, 1); 485