|
12 | 12 | #include "internal.h"
|
13 | 13 | #include "sleep.h"
|
14 | 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 | + |
15 | 24 | /*
|
16 | 25 | * We didn't lock acpi_device_lock in the file, because it invokes oops in
|
17 | 26 | * suspend/resume and isn't really required as this is called in S-state. At
|
@@ -90,3 +99,75 @@ int __init acpi_wakeup_device_init(void)
|
90 | 99 | mutex_unlock(&acpi_device_lock);
|
91 | 100 | return 0;
|
92 | 101 | }
|
| 102 | + |
| 103 | +/** |
| 104 | + * acpi_register_wakeup_handler - Register wakeup handler |
| 105 | + * @wake_irq: The IRQ through which the device may receive wakeups |
| 106 | + * @wakeup: Wakeup-handler to call when the SCI has triggered a wakeup |
| 107 | + * @context: Context to pass to the handler when calling it |
| 108 | + * |
| 109 | + * Drivers which may share an IRQ with the SCI can use this to register |
| 110 | + * a handler which returns true when the device they are managing wants |
| 111 | + * to trigger a wakeup. |
| 112 | + */ |
| 113 | +int acpi_register_wakeup_handler(int wake_irq, bool (*wakeup)(void *context), |
| 114 | + void *context) |
| 115 | +{ |
| 116 | + struct acpi_wakeup_handler *handler; |
| 117 | + |
| 118 | + /* |
| 119 | + * If the device is not sharing its IRQ with the SCI, there is no |
| 120 | + * need to register the handler. |
| 121 | + */ |
| 122 | + if (!acpi_sci_irq_valid() || wake_irq != acpi_sci_irq) |
| 123 | + return 0; |
| 124 | + |
| 125 | + handler = kmalloc(sizeof(*handler), GFP_KERNEL); |
| 126 | + if (!handler) |
| 127 | + return -ENOMEM; |
| 128 | + |
| 129 | + handler->wakeup = wakeup; |
| 130 | + handler->context = context; |
| 131 | + |
| 132 | + mutex_lock(&acpi_wakeup_handler_mutex); |
| 133 | + list_add(&handler->list_node, &acpi_wakeup_handler_head); |
| 134 | + mutex_unlock(&acpi_wakeup_handler_mutex); |
| 135 | + |
| 136 | + return 0; |
| 137 | +} |
| 138 | +EXPORT_SYMBOL_GPL(acpi_register_wakeup_handler); |
| 139 | + |
| 140 | +/** |
| 141 | + * acpi_unregister_wakeup_handler - Unregister wakeup handler |
| 142 | + * @wakeup: Wakeup-handler passed to acpi_register_wakeup_handler() |
| 143 | + * @context: Context passed to acpi_register_wakeup_handler() |
| 144 | + */ |
| 145 | +void acpi_unregister_wakeup_handler(bool (*wakeup)(void *context), |
| 146 | + void *context) |
| 147 | +{ |
| 148 | + struct acpi_wakeup_handler *handler; |
| 149 | + |
| 150 | + mutex_lock(&acpi_wakeup_handler_mutex); |
| 151 | + list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) { |
| 152 | + if (handler->wakeup == wakeup && handler->context == context) { |
| 153 | + list_del(&handler->list_node); |
| 154 | + kfree(handler); |
| 155 | + break; |
| 156 | + } |
| 157 | + } |
| 158 | + mutex_unlock(&acpi_wakeup_handler_mutex); |
| 159 | +} |
| 160 | +EXPORT_SYMBOL_GPL(acpi_unregister_wakeup_handler); |
| 161 | + |
| 162 | +bool acpi_check_wakeup_handlers(void) |
| 163 | +{ |
| 164 | + struct acpi_wakeup_handler *handler; |
| 165 | + |
| 166 | + /* No need to lock, nothing else is running when we're called. */ |
| 167 | + list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) { |
| 168 | + if (handler->wakeup(handler->context)) |
| 169 | + return true; |
| 170 | + } |
| 171 | + |
| 172 | + return false; |
| 173 | +} |
0 commit comments