1dab39c11SEmmanuel Vadot /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3dab39c11SEmmanuel Vadot * 4dab39c11SEmmanuel Vadot * Copyright (c) 2018 Johannes Lundberg <johalun@FreeBSD.org> 5dab39c11SEmmanuel Vadot * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org> 6dab39c11SEmmanuel Vadot * 7dab39c11SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 8dab39c11SEmmanuel Vadot * modification, are permitted provided that the following conditions are 9dab39c11SEmmanuel Vadot * met: 10dab39c11SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 11dab39c11SEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 12dab39c11SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 13dab39c11SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in 14dab39c11SEmmanuel Vadot * the documentation and/or other materials provided with the 15dab39c11SEmmanuel Vadot * distribution. 16dab39c11SEmmanuel Vadot * 17dab39c11SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18dab39c11SEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19dab39c11SEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20dab39c11SEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21dab39c11SEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22dab39c11SEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23dab39c11SEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24dab39c11SEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25dab39c11SEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26dab39c11SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27dab39c11SEmmanuel Vadot * SUCH DAMAGE. 28dab39c11SEmmanuel Vadot * 29dab39c11SEmmanuel Vadot * $FreeBSD$ 30dab39c11SEmmanuel Vadot */ 31dab39c11SEmmanuel Vadot 32dab39c11SEmmanuel Vadot #include "opt_acpi.h" 33dab39c11SEmmanuel Vadot 34dab39c11SEmmanuel Vadot #include <sys/types.h> 35dab39c11SEmmanuel Vadot #include <sys/bus.h> 36dab39c11SEmmanuel Vadot #include <sys/eventhandler.h> 37dab39c11SEmmanuel Vadot #include <sys/kernel.h> 38dab39c11SEmmanuel Vadot 39dab39c11SEmmanuel Vadot #include <contrib/dev/acpica/include/acpi.h> 40dab39c11SEmmanuel Vadot #include <dev/acpica/acpivar.h> 41dab39c11SEmmanuel Vadot 42dab39c11SEmmanuel Vadot #include <linux/notifier.h> 43ccd31b46SJean-Sébastien Pédron #include <linux/suspend.h> 44dab39c11SEmmanuel Vadot 45dab39c11SEmmanuel Vadot #include <acpi/acpi_bus.h> 46dab39c11SEmmanuel Vadot #include <acpi/video.h> 47dab39c11SEmmanuel Vadot 48dab39c11SEmmanuel Vadot #define ACPI_AC_CLASS "ac_adapter" 49dab39c11SEmmanuel Vadot 50dab39c11SEmmanuel Vadot ACPI_MODULE_NAME("linux_acpi") 51dab39c11SEmmanuel Vadot 52dab39c11SEmmanuel Vadot enum { 53dab39c11SEmmanuel Vadot LINUX_ACPI_ACAD, 54dab39c11SEmmanuel Vadot LINUX_ACPI_VIDEO, 55dab39c11SEmmanuel Vadot LINUX_ACPI_TAGS /* must be last */ 56dab39c11SEmmanuel Vadot }; 57dab39c11SEmmanuel Vadot _Static_assert(LINUX_ACPI_TAGS <= LINUX_NOTIFY_TAGS, 58dab39c11SEmmanuel Vadot "Not enough space for tags in notifier_block structure"); 59dab39c11SEmmanuel Vadot 60dab39c11SEmmanuel Vadot #ifdef DEV_ACPI 61dab39c11SEmmanuel Vadot 62ccd31b46SJean-Sébastien Pédron suspend_state_t pm_suspend_target_state = PM_SUSPEND_ON; 63ccd31b46SJean-Sébastien Pédron 64dab39c11SEmmanuel Vadot static uint32_t linux_acpi_target_sleep_state = ACPI_STATE_S0; 65dab39c11SEmmanuel Vadot 66dab39c11SEmmanuel Vadot static eventhandler_tag resume_tag; 67dab39c11SEmmanuel Vadot static eventhandler_tag suspend_tag; 68dab39c11SEmmanuel Vadot 69dab39c11SEmmanuel Vadot ACPI_HANDLE 70dab39c11SEmmanuel Vadot bsd_acpi_get_handle(device_t bsddev) 71dab39c11SEmmanuel Vadot { 72dab39c11SEmmanuel Vadot return (acpi_get_handle(bsddev)); 73dab39c11SEmmanuel Vadot } 74dab39c11SEmmanuel Vadot 75dab39c11SEmmanuel Vadot bool 76dab39c11SEmmanuel Vadot acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev, uint64_t funcs) 77dab39c11SEmmanuel Vadot { 78dab39c11SEmmanuel Vadot 79dab39c11SEmmanuel Vadot if (funcs == 0) 80dab39c11SEmmanuel Vadot return (false); 81dab39c11SEmmanuel Vadot 82dab39c11SEmmanuel Vadot /* 83dab39c11SEmmanuel Vadot * From ACPI 6.3 spec 9.1.1: 84dab39c11SEmmanuel Vadot * Bit 0 indicates whether there is support for any functions other 85dab39c11SEmmanuel Vadot * than function 0 for the specified UUID and Revision ID. If set to 86dab39c11SEmmanuel Vadot * zero, no functions are supported (other than function zero) for the 87dab39c11SEmmanuel Vadot * specified UUID and Revision ID. 88dab39c11SEmmanuel Vadot */ 89dab39c11SEmmanuel Vadot funcs |= 1 << 0; 90dab39c11SEmmanuel Vadot 91dab39c11SEmmanuel Vadot return ((acpi_DSMQuery(handle, uuid, rev) & funcs) == funcs); 92dab39c11SEmmanuel Vadot } 93dab39c11SEmmanuel Vadot 94dab39c11SEmmanuel Vadot ACPI_OBJECT * 95dab39c11SEmmanuel Vadot acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const char *uuid, int rev, 96dab39c11SEmmanuel Vadot int func, ACPI_OBJECT *argv4, ACPI_OBJECT_TYPE type) 97dab39c11SEmmanuel Vadot { 98dab39c11SEmmanuel Vadot ACPI_BUFFER buf; 99dab39c11SEmmanuel Vadot 100dab39c11SEmmanuel Vadot return (ACPI_SUCCESS(acpi_EvaluateDSMTyped(handle, uuid, rev, func, 101dab39c11SEmmanuel Vadot argv4, &buf, type)) ? (ACPI_OBJECT *)buf.Pointer : NULL); 102dab39c11SEmmanuel Vadot } 103dab39c11SEmmanuel Vadot 104dab39c11SEmmanuel Vadot static void 105dab39c11SEmmanuel Vadot linux_handle_power_suspend_event(void *arg __unused) 106dab39c11SEmmanuel Vadot { 107dab39c11SEmmanuel Vadot /* 108dab39c11SEmmanuel Vadot * Only support S3 for now. 109dab39c11SEmmanuel Vadot * acpi_sleep_event isn't always called so we use power_suspend_early 110dab39c11SEmmanuel Vadot * instead which means we don't know what state we're switching to. 111dab39c11SEmmanuel Vadot * TODO: Make acpi_sleep_event consistent 112dab39c11SEmmanuel Vadot */ 113dab39c11SEmmanuel Vadot linux_acpi_target_sleep_state = ACPI_STATE_S3; 114dab39c11SEmmanuel Vadot } 115dab39c11SEmmanuel Vadot 116dab39c11SEmmanuel Vadot static void 117dab39c11SEmmanuel Vadot linux_handle_power_resume_event(void *arg __unused) 118dab39c11SEmmanuel Vadot { 119dab39c11SEmmanuel Vadot linux_acpi_target_sleep_state = ACPI_STATE_S0; 120dab39c11SEmmanuel Vadot } 121dab39c11SEmmanuel Vadot 122dab39c11SEmmanuel Vadot static void 123dab39c11SEmmanuel Vadot linux_handle_acpi_acad_event(void *arg, int data) 124dab39c11SEmmanuel Vadot { 125dab39c11SEmmanuel Vadot struct notifier_block *nb = arg; 126dab39c11SEmmanuel Vadot /* 127dab39c11SEmmanuel Vadot * Event type information is lost ATM in FreeBSD ACPI event handler. 128dab39c11SEmmanuel Vadot * Fortunately, drm-kmod do not distinct AC event types too, so we can 129dab39c11SEmmanuel Vadot * use any type e.g. ACPI_NOTIFY_BUS_CHECK that suits notifier handler. 130dab39c11SEmmanuel Vadot */ 131dab39c11SEmmanuel Vadot struct acpi_bus_event abe = { 132dab39c11SEmmanuel Vadot .device_class = ACPI_AC_CLASS, 133dab39c11SEmmanuel Vadot .type = ACPI_NOTIFY_BUS_CHECK, 134dab39c11SEmmanuel Vadot .data = data, 135dab39c11SEmmanuel Vadot }; 136dab39c11SEmmanuel Vadot 137dab39c11SEmmanuel Vadot nb->notifier_call(nb, 0, &abe); 138dab39c11SEmmanuel Vadot } 139dab39c11SEmmanuel Vadot 140dab39c11SEmmanuel Vadot static void 141dab39c11SEmmanuel Vadot linux_handle_acpi_video_event(void *arg, int type) 142dab39c11SEmmanuel Vadot { 143dab39c11SEmmanuel Vadot struct notifier_block *nb = arg; 144dab39c11SEmmanuel Vadot struct acpi_bus_event abe = { 145dab39c11SEmmanuel Vadot .device_class = ACPI_VIDEO_CLASS, 146dab39c11SEmmanuel Vadot .type = type, 147dab39c11SEmmanuel Vadot .data = 0, 148dab39c11SEmmanuel Vadot }; 149dab39c11SEmmanuel Vadot 150dab39c11SEmmanuel Vadot nb->notifier_call(nb, 0, &abe); 151dab39c11SEmmanuel Vadot } 152dab39c11SEmmanuel Vadot 153dab39c11SEmmanuel Vadot int 154dab39c11SEmmanuel Vadot register_acpi_notifier(struct notifier_block *nb) 155dab39c11SEmmanuel Vadot { 156dab39c11SEmmanuel Vadot nb->tags[LINUX_ACPI_ACAD] = EVENTHANDLER_REGISTER(acpi_acad_event, 157dab39c11SEmmanuel Vadot linux_handle_acpi_acad_event, nb, EVENTHANDLER_PRI_FIRST); 158dab39c11SEmmanuel Vadot nb->tags[LINUX_ACPI_VIDEO] = EVENTHANDLER_REGISTER(acpi_video_event, 159dab39c11SEmmanuel Vadot linux_handle_acpi_video_event, nb, EVENTHANDLER_PRI_FIRST); 160dab39c11SEmmanuel Vadot 161dab39c11SEmmanuel Vadot return (0); 162dab39c11SEmmanuel Vadot } 163dab39c11SEmmanuel Vadot 164dab39c11SEmmanuel Vadot int 165dab39c11SEmmanuel Vadot unregister_acpi_notifier(struct notifier_block *nb) 166dab39c11SEmmanuel Vadot { 167dab39c11SEmmanuel Vadot EVENTHANDLER_DEREGISTER(acpi_acad_event, nb->tags[LINUX_ACPI_ACAD]); 168dab39c11SEmmanuel Vadot EVENTHANDLER_DEREGISTER(acpi_video_event, nb->tags[LINUX_ACPI_VIDEO]); 169dab39c11SEmmanuel Vadot 170dab39c11SEmmanuel Vadot return (0); 171dab39c11SEmmanuel Vadot } 172dab39c11SEmmanuel Vadot 173dab39c11SEmmanuel Vadot uint32_t 174dab39c11SEmmanuel Vadot acpi_target_system_state(void) 175dab39c11SEmmanuel Vadot { 176dab39c11SEmmanuel Vadot return (linux_acpi_target_sleep_state); 177dab39c11SEmmanuel Vadot } 178dab39c11SEmmanuel Vadot 179dab39c11SEmmanuel Vadot static void 180dab39c11SEmmanuel Vadot linux_register_acpi_event_handlers(void *arg __unused) 181dab39c11SEmmanuel Vadot { 182dab39c11SEmmanuel Vadot /* 183dab39c11SEmmanuel Vadot * XXX johalun: acpi_{sleep,wakeup}_event can't be trusted, use 184dab39c11SEmmanuel Vadot * power_{suspend_early,resume} 'acpiconf -s 3' or 'zzz' will not 185dab39c11SEmmanuel Vadot * generate acpi_sleep_event... Lid open or wake on button generates 186dab39c11SEmmanuel Vadot * acpi_wakeup_event on one of my Dell laptops but not the other 187dab39c11SEmmanuel Vadot * (but it does power on)... is this a general thing? 188dab39c11SEmmanuel Vadot */ 189dab39c11SEmmanuel Vadot resume_tag = EVENTHANDLER_REGISTER(power_resume, 190dab39c11SEmmanuel Vadot linux_handle_power_resume_event, NULL, EVENTHANDLER_PRI_FIRST); 191dab39c11SEmmanuel Vadot suspend_tag = EVENTHANDLER_REGISTER(power_suspend_early, 192dab39c11SEmmanuel Vadot linux_handle_power_suspend_event, NULL, EVENTHANDLER_PRI_FIRST); 193dab39c11SEmmanuel Vadot } 194dab39c11SEmmanuel Vadot 195dab39c11SEmmanuel Vadot static void 196dab39c11SEmmanuel Vadot linux_deregister_acpi_event_handlers(void *arg __unused) 197dab39c11SEmmanuel Vadot { 198dab39c11SEmmanuel Vadot EVENTHANDLER_DEREGISTER(power_resume, resume_tag); 199dab39c11SEmmanuel Vadot EVENTHANDLER_DEREGISTER(power_suspend_early, suspend_tag); 200dab39c11SEmmanuel Vadot } 201dab39c11SEmmanuel Vadot 202dab39c11SEmmanuel Vadot SYSINIT(linux_acpi_events, SI_SUB_DRIVERS, SI_ORDER_ANY, 203dab39c11SEmmanuel Vadot linux_register_acpi_event_handlers, NULL); 204dab39c11SEmmanuel Vadot SYSUNINIT(linux_acpi_events, SI_SUB_DRIVERS, SI_ORDER_ANY, 205dab39c11SEmmanuel Vadot linux_deregister_acpi_event_handlers, NULL); 206dab39c11SEmmanuel Vadot 207dab39c11SEmmanuel Vadot #else /* !DEV_ACPI */ 208dab39c11SEmmanuel Vadot 209dab39c11SEmmanuel Vadot ACPI_HANDLE 210dab39c11SEmmanuel Vadot bsd_acpi_get_handle(device_t bsddev) 211dab39c11SEmmanuel Vadot { 212dab39c11SEmmanuel Vadot return (NULL); 213dab39c11SEmmanuel Vadot } 214dab39c11SEmmanuel Vadot 215dab39c11SEmmanuel Vadot bool 216dab39c11SEmmanuel Vadot acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev, uint64_t funcs) 217dab39c11SEmmanuel Vadot { 218dab39c11SEmmanuel Vadot return (false); 219dab39c11SEmmanuel Vadot } 220dab39c11SEmmanuel Vadot 221dab39c11SEmmanuel Vadot ACPI_OBJECT * 222dab39c11SEmmanuel Vadot acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const char *uuid, int rev, 223dab39c11SEmmanuel Vadot int func, ACPI_OBJECT *argv4, ACPI_OBJECT_TYPE type) 224dab39c11SEmmanuel Vadot { 225dab39c11SEmmanuel Vadot return (NULL); 226dab39c11SEmmanuel Vadot } 227dab39c11SEmmanuel Vadot 228dab39c11SEmmanuel Vadot int 229dab39c11SEmmanuel Vadot register_acpi_notifier(struct notifier_block *nb) 230dab39c11SEmmanuel Vadot { 231dab39c11SEmmanuel Vadot return (0); 232dab39c11SEmmanuel Vadot } 233dab39c11SEmmanuel Vadot 234dab39c11SEmmanuel Vadot int 235dab39c11SEmmanuel Vadot unregister_acpi_notifier(struct notifier_block *nb) 236dab39c11SEmmanuel Vadot { 237dab39c11SEmmanuel Vadot return (0); 238dab39c11SEmmanuel Vadot } 239dab39c11SEmmanuel Vadot 240dab39c11SEmmanuel Vadot uint32_t 241dab39c11SEmmanuel Vadot acpi_target_system_state(void) 242dab39c11SEmmanuel Vadot { 243dab39c11SEmmanuel Vadot return (ACPI_STATE_S0); 244dab39c11SEmmanuel Vadot } 245dab39c11SEmmanuel Vadot 246dab39c11SEmmanuel Vadot #endif /* !DEV_ACPI */ 247