#include "internal.h"
 #include "sleep.h"
 
+struct acpi_wakeup_handler {
+       struct list_head list_node;
+       bool (*wakeup)(void *context);
+       void *context;
+};
+
+static LIST_HEAD(acpi_wakeup_handler_head);
+static DEFINE_MUTEX(acpi_wakeup_handler_mutex);
+
 /*
  * We didn't lock acpi_device_lock in the file, because it invokes oops in
  * suspend/resume and isn't really required as this is called in S-state. At
        mutex_unlock(&acpi_device_lock);
        return 0;
 }
+
+/**
+ * acpi_register_wakeup_handler - Register wakeup handler
+ * @wake_irq: The IRQ through which the device may receive wakeups
+ * @wakeup:   Wakeup-handler to call when the SCI has triggered a wakeup
+ * @context:  Context to pass to the handler when calling it
+ *
+ * Drivers which may share an IRQ with the SCI can use this to register
+ * a handler which returns true when the device they are managing wants
+ * to trigger a wakeup.
+ */
+int acpi_register_wakeup_handler(int wake_irq, bool (*wakeup)(void *context),
+                                void *context)
+{
+       struct acpi_wakeup_handler *handler;
+
+       /*
+        * If the device is not sharing its IRQ with the SCI, there is no
+        * need to register the handler.
+        */
+       if (!acpi_sci_irq_valid() || wake_irq != acpi_sci_irq)
+               return 0;
+
+       handler = kmalloc(sizeof(*handler), GFP_KERNEL);
+       if (!handler)
+               return -ENOMEM;
+
+       handler->wakeup = wakeup;
+       handler->context = context;
+
+       mutex_lock(&acpi_wakeup_handler_mutex);
+       list_add(&handler->list_node, &acpi_wakeup_handler_head);
+       mutex_unlock(&acpi_wakeup_handler_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_register_wakeup_handler);
+
+/**
+ * acpi_unregister_wakeup_handler - Unregister wakeup handler
+ * @wakeup:   Wakeup-handler passed to acpi_register_wakeup_handler()
+ * @context:  Context passed to acpi_register_wakeup_handler()
+ */
+void acpi_unregister_wakeup_handler(bool (*wakeup)(void *context),
+                                   void *context)
+{
+       struct acpi_wakeup_handler *handler;
+
+       mutex_lock(&acpi_wakeup_handler_mutex);
+       list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) {
+               if (handler->wakeup == wakeup && handler->context == context) {
+                       list_del(&handler->list_node);
+                       kfree(handler);
+                       break;
+               }
+       }
+       mutex_unlock(&acpi_wakeup_handler_mutex);
+}
+EXPORT_SYMBOL_GPL(acpi_unregister_wakeup_handler);
+
+bool acpi_check_wakeup_handlers(void)
+{
+       struct acpi_wakeup_handler *handler;
+
+       /* No need to lock, nothing else is running when we're called. */
+       list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) {
+               if (handler->wakeup(handler->context))
+                       return true;
+       }
+
+       return false;
+}
 
 void __init acpi_sleep_no_blacklist(void);
 #endif /* CONFIG_PM_SLEEP */
 
+int acpi_register_wakeup_handler(
+       int wake_irq, bool (*wakeup)(void *context), void *context);
+void acpi_unregister_wakeup_handler(
+       bool (*wakeup)(void *context), void *context);
+
 struct acpi_osc_context {
        char *uuid_str;                 /* UUID string */
        int rev;