| 1 | // SPDX-License-Identifier: GPL-2.0 | 
|---|
| 2 | /* | 
|---|
| 3 | * wakeup.c - support wakeup devices | 
|---|
| 4 | * Copyright (C) 2004 Li Shaohua <shaohua.li@intel.com> | 
|---|
| 5 | */ | 
|---|
| 6 |  | 
|---|
| 7 | #include <linux/init.h> | 
|---|
| 8 | #include <linux/acpi.h> | 
|---|
| 9 | #include <linux/kernel.h> | 
|---|
| 10 | #include <linux/types.h> | 
|---|
| 11 |  | 
|---|
| 12 | #include "internal.h" | 
|---|
| 13 | #include "sleep.h" | 
|---|
| 14 |  | 
|---|
| 15 | struct acpi_wakeup_handler { | 
|---|
| 16 | struct list_head list_node; | 
|---|
| 17 | bool (*wakeup)(void *context); | 
|---|
| 18 | void *context; | 
|---|
| 19 | }; | 
|---|
| 20 |  | 
|---|
| 21 | static LIST_HEAD(acpi_wakeup_handler_head); | 
|---|
| 22 | static DEFINE_MUTEX(acpi_wakeup_handler_mutex); | 
|---|
| 23 |  | 
|---|
| 24 | /* | 
|---|
| 25 | * We didn't lock acpi_device_lock in the file, because it invokes oops in | 
|---|
| 26 | * suspend/resume and isn't really required as this is called in S-state. At | 
|---|
| 27 | * that time, there is no device hotplug | 
|---|
| 28 | **/ | 
|---|
| 29 |  | 
|---|
| 30 | /** | 
|---|
| 31 | * acpi_enable_wakeup_devices - Enable wake-up device GPEs. | 
|---|
| 32 | * @sleep_state: ACPI system sleep state. | 
|---|
| 33 | * | 
|---|
| 34 | * Enable wakeup device power of devices with the state.enable flag set and set | 
|---|
| 35 | * the wakeup enable mask bits in the GPE registers that correspond to wakeup | 
|---|
| 36 | * devices. | 
|---|
| 37 | */ | 
|---|
| 38 | void acpi_enable_wakeup_devices(u8 sleep_state) | 
|---|
| 39 | { | 
|---|
| 40 | struct acpi_device *dev, *tmp; | 
|---|
| 41 |  | 
|---|
| 42 | list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list, | 
|---|
| 43 | wakeup_list) { | 
|---|
| 44 | if (!dev->wakeup.flags.valid | 
|---|
| 45 | || sleep_state > dev->wakeup.sleep_state | 
|---|
| 46 | || !(device_may_wakeup(dev: &dev->dev) | 
|---|
| 47 | || dev->wakeup.prepare_count)) | 
|---|
| 48 | continue; | 
|---|
| 49 |  | 
|---|
| 50 | if (device_may_wakeup(dev: &dev->dev)) | 
|---|
| 51 | acpi_enable_wakeup_device_power(dev, state: sleep_state); | 
|---|
| 52 |  | 
|---|
| 53 | /* The wake-up power should have been enabled already. */ | 
|---|
| 54 | acpi_set_gpe_wake_mask(gpe_device: dev->wakeup.gpe_device, gpe_number: dev->wakeup.gpe_number, | 
|---|
| 55 | ACPI_GPE_ENABLE); | 
|---|
| 56 | } | 
|---|
| 57 | } | 
|---|
| 58 |  | 
|---|
| 59 | /** | 
|---|
| 60 | * acpi_disable_wakeup_devices - Disable devices' wakeup capability. | 
|---|
| 61 | * @sleep_state: ACPI system sleep state. | 
|---|
| 62 | */ | 
|---|
| 63 | void acpi_disable_wakeup_devices(u8 sleep_state) | 
|---|
| 64 | { | 
|---|
| 65 | struct acpi_device *dev, *tmp; | 
|---|
| 66 |  | 
|---|
| 67 | list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list, | 
|---|
| 68 | wakeup_list) { | 
|---|
| 69 | if (!dev->wakeup.flags.valid | 
|---|
| 70 | || sleep_state > dev->wakeup.sleep_state | 
|---|
| 71 | || !(device_may_wakeup(dev: &dev->dev) | 
|---|
| 72 | || dev->wakeup.prepare_count)) | 
|---|
| 73 | continue; | 
|---|
| 74 |  | 
|---|
| 75 | acpi_set_gpe_wake_mask(gpe_device: dev->wakeup.gpe_device, gpe_number: dev->wakeup.gpe_number, | 
|---|
| 76 | ACPI_GPE_DISABLE); | 
|---|
| 77 |  | 
|---|
| 78 | if (device_may_wakeup(dev: &dev->dev)) | 
|---|
| 79 | acpi_disable_wakeup_device_power(dev); | 
|---|
| 80 | } | 
|---|
| 81 | } | 
|---|
| 82 |  | 
|---|
| 83 | int __init acpi_wakeup_device_init(void) | 
|---|
| 84 | { | 
|---|
| 85 | struct acpi_device *dev, *tmp; | 
|---|
| 86 |  | 
|---|
| 87 | mutex_lock(lock: &acpi_device_lock); | 
|---|
| 88 | list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list, | 
|---|
| 89 | wakeup_list) { | 
|---|
| 90 | if (device_can_wakeup(dev: &dev->dev)) { | 
|---|
| 91 | /* Button GPEs are supposed to be always enabled. */ | 
|---|
| 92 | acpi_enable_gpe(gpe_device: dev->wakeup.gpe_device, | 
|---|
| 93 | gpe_number: dev->wakeup.gpe_number); | 
|---|
| 94 | device_set_wakeup_enable(dev: &dev->dev, enable: true); | 
|---|
| 95 | } | 
|---|
| 96 | } | 
|---|
| 97 | mutex_unlock(lock: &acpi_device_lock); | 
|---|
| 98 | return 0; | 
|---|
| 99 | } | 
|---|
| 100 |  | 
|---|
| 101 | /** | 
|---|
| 102 | * acpi_register_wakeup_handler - Register wakeup handler | 
|---|
| 103 | * @wake_irq: The IRQ through which the device may receive wakeups | 
|---|
| 104 | * @wakeup:   Wakeup-handler to call when the SCI has triggered a wakeup | 
|---|
| 105 | * @context:  Context to pass to the handler when calling it | 
|---|
| 106 | * | 
|---|
| 107 | * Drivers which may share an IRQ with the SCI can use this to register | 
|---|
| 108 | * a handler which returns true when the device they are managing wants | 
|---|
| 109 | * to trigger a wakeup. | 
|---|
| 110 | */ | 
|---|
| 111 | int acpi_register_wakeup_handler(int wake_irq, bool (*wakeup)(void *context), | 
|---|
| 112 | void *context) | 
|---|
| 113 | { | 
|---|
| 114 | struct acpi_wakeup_handler *handler; | 
|---|
| 115 |  | 
|---|
| 116 | /* | 
|---|
| 117 | * If the device is not sharing its IRQ with the SCI, there is no | 
|---|
| 118 | * need to register the handler. | 
|---|
| 119 | */ | 
|---|
| 120 | if (!acpi_sci_irq_valid() || wake_irq != acpi_sci_irq) | 
|---|
| 121 | return 0; | 
|---|
| 122 |  | 
|---|
| 123 | handler = kmalloc(sizeof(*handler), GFP_KERNEL); | 
|---|
| 124 | if (!handler) | 
|---|
| 125 | return -ENOMEM; | 
|---|
| 126 |  | 
|---|
| 127 | handler->wakeup = wakeup; | 
|---|
| 128 | handler->context = context; | 
|---|
| 129 |  | 
|---|
| 130 | mutex_lock(lock: &acpi_wakeup_handler_mutex); | 
|---|
| 131 | list_add(new: &handler->list_node, head: &acpi_wakeup_handler_head); | 
|---|
| 132 | mutex_unlock(lock: &acpi_wakeup_handler_mutex); | 
|---|
| 133 |  | 
|---|
| 134 | return 0; | 
|---|
| 135 | } | 
|---|
| 136 | EXPORT_SYMBOL_GPL(acpi_register_wakeup_handler); | 
|---|
| 137 |  | 
|---|
| 138 | /** | 
|---|
| 139 | * acpi_unregister_wakeup_handler - Unregister wakeup handler | 
|---|
| 140 | * @wakeup:   Wakeup-handler passed to acpi_register_wakeup_handler() | 
|---|
| 141 | * @context:  Context passed to acpi_register_wakeup_handler() | 
|---|
| 142 | */ | 
|---|
| 143 | void acpi_unregister_wakeup_handler(bool (*wakeup)(void *context), | 
|---|
| 144 | void *context) | 
|---|
| 145 | { | 
|---|
| 146 | struct acpi_wakeup_handler *handler; | 
|---|
| 147 |  | 
|---|
| 148 | mutex_lock(lock: &acpi_wakeup_handler_mutex); | 
|---|
| 149 | list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) { | 
|---|
| 150 | if (handler->wakeup == wakeup && handler->context == context) { | 
|---|
| 151 | list_del(entry: &handler->list_node); | 
|---|
| 152 | kfree(objp: handler); | 
|---|
| 153 | break; | 
|---|
| 154 | } | 
|---|
| 155 | } | 
|---|
| 156 | mutex_unlock(lock: &acpi_wakeup_handler_mutex); | 
|---|
| 157 | } | 
|---|
| 158 | EXPORT_SYMBOL_GPL(acpi_unregister_wakeup_handler); | 
|---|
| 159 |  | 
|---|
| 160 | bool acpi_check_wakeup_handlers(void) | 
|---|
| 161 | { | 
|---|
| 162 | struct acpi_wakeup_handler *handler; | 
|---|
| 163 |  | 
|---|
| 164 | /* No need to lock, nothing else is running when we're called. */ | 
|---|
| 165 | list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) { | 
|---|
| 166 | if (handler->wakeup(handler->context)) | 
|---|
| 167 | return true; | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 170 | return false; | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|