Suspend-related patches for 2.6.27
[safe/jmp/linux-2.6] / drivers / acpi / glue.c
index 9950087..06f8634 100644 (file)
@@ -16,7 +16,7 @@
 #if ACPI_GLUE_DEBUG
 #define DBG(x...) printk(PREFIX x)
 #else
-#define DBG(x...)
+#define DBG(x...) do { } while(0)
 #endif
 static LIST_HEAD(bus_type_list);
 static DECLARE_RWSEM(bus_type_sem);
@@ -36,8 +36,6 @@ int register_acpi_bus_type(struct acpi_bus_type *type)
        return -ENODEV;
 }
 
-EXPORT_SYMBOL(register_acpi_bus_type);
-
 int unregister_acpi_bus_type(struct acpi_bus_type *type)
 {
        if (acpi_disabled)
@@ -53,8 +51,6 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type)
        return -ENODEV;
 }
 
-EXPORT_SYMBOL(unregister_acpi_bus_type);
-
 static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
 {
        struct acpi_bus_type *tmp, *ret = NULL;
@@ -146,6 +142,7 @@ EXPORT_SYMBOL(acpi_get_physical_device);
 
 static int acpi_bind_one(struct device *dev, acpi_handle handle)
 {
+       struct acpi_device *acpi_dev;
        acpi_status status;
 
        if (dev->archdata.acpi_handle) {
@@ -161,6 +158,16 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
        }
        dev->archdata.acpi_handle = handle;
 
+       status = acpi_bus_get_device(handle, &acpi_dev);
+       if (!ACPI_FAILURE(status)) {
+               int ret;
+
+               ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
+                               "firmware_node");
+               ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
+                               "physical_node");
+       }
+
        return 0;
 }
 
@@ -169,8 +176,17 @@ static int acpi_unbind_one(struct device *dev)
        if (!dev->archdata.acpi_handle)
                return 0;
        if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) {
+               struct acpi_device *acpi_dev;
+
                /* acpi_get_physical_device increase refcnt by one */
                put_device(dev);
+
+               if (!acpi_bus_get_device(dev->archdata.acpi_handle,
+                                       &acpi_dev)) {
+                       sysfs_remove_link(&dev->kobj, "firmware_node");
+                       sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node");
+               }
+
                acpi_detach_data(dev->archdata.acpi_handle,
                                 acpi_glue_data_handler);
                dev->archdata.acpi_handle = NULL;
@@ -245,6 +261,35 @@ arch_initcall(init_acpi_device_notify);
 
 #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
 
+#ifdef CONFIG_PM
+static u32 rtc_handler(void *context)
+{
+       acpi_clear_event(ACPI_EVENT_RTC);
+       acpi_disable_event(ACPI_EVENT_RTC, 0);
+       return ACPI_INTERRUPT_HANDLED;
+}
+
+static inline void rtc_wake_setup(void)
+{
+       acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+}
+
+static void rtc_wake_on(struct device *dev)
+{
+       acpi_clear_event(ACPI_EVENT_RTC);
+       acpi_enable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_off(struct device *dev)
+{
+       acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+#else
+#define rtc_wake_setup()       do{}while(0)
+#define rtc_wake_on            NULL
+#define rtc_wake_off           NULL
+#endif
+
 /* Every ACPI platform has a mc146818 compatible "cmos rtc".  Here we find
  * its device node and pass extra config data.  This helps its driver use
  * capabilities that the now-obsolete mc146818 didn't have, and informs it
@@ -255,8 +300,6 @@ arch_initcall(init_acpi_device_notify);
 static struct cmos_rtc_board_info rtc_info;
 
 
-#ifdef CONFIG_PNPACPI
-
 /* PNP devices are registered in a subsys_initcall();
  * ACPI specifies the PNP IDs to use.
  */
@@ -280,41 +323,29 @@ static struct device *__init get_rtc_dev(void)
        return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match);
 }
 
-#else
-
-/* We expect non-PNPACPI platforms to register an RTC device, usually
- * at or near arch_initcall().  That also helps for example PCs that
- * aren't configured with ACPI (where this code wouldn't run, but the
- * RTC would still be available).  The device name matches the driver;
- * that's how the platform bus works.
- */
-#include <linux/platform_device.h>
-
-static int __init platform_match(struct device *dev, void *data)
-{
-       struct platform_device  *pdev;
-
-       pdev = container_of(dev, struct platform_device, dev);
-       return strcmp(pdev->name, "rtc_cmos") == 0;
-}
-
-static struct device *__init get_rtc_dev(void)
-{
-       return bus_find_device(&platform_bus_type, NULL, NULL, platform_match);
-}
-
-#endif
-
 static int __init acpi_rtc_init(void)
 {
        struct device *dev = get_rtc_dev();
 
        if (dev) {
+               rtc_wake_setup();
+               rtc_info.wake_on = rtc_wake_on;
+               rtc_info.wake_off = rtc_wake_off;
+
+               /* workaround bug in some ACPI tables */
+               if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
+                       DBG("bogus FADT month_alarm\n");
+                       acpi_gbl_FADT.month_alarm = 0;
+               }
+
                rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
                rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
                rtc_info.rtc_century = acpi_gbl_FADT.century;
 
-               /* NOTE:  acpi_gbl_FADT->rtcs4 is NOT currently useful */
+               /* NOTE:  S4_RTC_WAKE is NOT currently useful to Linux */
+               if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
+                       printk(PREFIX "RTC can wake from S4\n");
+
 
                dev->platform_data = &rtc_info;
 
@@ -323,7 +354,7 @@ static int __init acpi_rtc_init(void)
 
                put_device(dev);
        } else
-               pr_debug("ACPI: RTC unavailable?\n");
+               DBG("RTC unavailable?\n");
        return 0;
 }
 /* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */