Merge branch 'bjorn-notify' into release
[linux-block.git] / drivers / platform / x86 / eeepc-laptop.c
index 03bf522bd7abc40b7db141f34864b2674f0e59ef..46b5aa5e85f041214d4611a34b2282c516ec5f0e 100644 (file)
@@ -180,6 +180,8 @@ static struct key_entry eeepc_keymap[] = {
  */
 static int eeepc_hotk_add(struct acpi_device *device);
 static int eeepc_hotk_remove(struct acpi_device *device, int type);
+static int eeepc_hotk_resume(struct acpi_device *device);
+static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id eeepc_device_ids[] = {
        {EEEPC_HOTK_HID, 0},
@@ -191,9 +193,12 @@ static struct acpi_driver eeepc_hotk_driver = {
        .name = EEEPC_HOTK_NAME,
        .class = EEEPC_HOTK_CLASS,
        .ids = eeepc_device_ids,
+       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
        .ops = {
                .add = eeepc_hotk_add,
                .remove = eeepc_hotk_remove,
+               .resume = eeepc_hotk_resume,
+               .notify = eeepc_hotk_notify,
        },
 };
 
@@ -512,15 +517,12 @@ static int notify_brn(void)
        return -1;
 }
 
-static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
+static void eeepc_rfkill_hotplug(void)
 {
        struct pci_dev *dev;
        struct pci_bus *bus = pci_find_bus(0, 1);
        bool blocked;
 
-       if (event != ACPI_NOTIFY_BUS_CHECK)
-               return;
-
        if (!bus) {
                printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
                return;
@@ -551,7 +553,15 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
        rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
 }
 
-static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
+static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
+{
+       if (event != ACPI_NOTIFY_BUS_CHECK)
+               return;
+
+       eeepc_rfkill_hotplug();
+}
+
+static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
 {
        static struct key_entry *key;
        u16 count;
@@ -559,6 +569,8 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
 
        if (!ehotk)
                return;
+       if (event > ACPI_MAX_SYS_NOTIFY)
+               return;
        if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
                brn = notify_brn();
        count = ehotk->event_count[event % 128]++;
@@ -639,7 +651,6 @@ static void eeepc_unregister_rfkill_notifier(char *node)
 
 static int eeepc_hotk_add(struct acpi_device *device)
 {
-       acpi_status status = AE_OK;
        int result;
 
        if (!device)
@@ -657,10 +668,6 @@ static int eeepc_hotk_add(struct acpi_device *device)
        result = eeepc_hotk_check();
        if (result)
                goto ehotk_fail;
-       status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
-                                            eeepc_hotk_notify, ehotk);
-       if (ACPI_FAILURE(status))
-               printk(EEEPC_ERR "Error installing notify handler\n");
 
        eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
        eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
@@ -675,8 +682,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
                if (!ehotk->eeepc_wlan_rfkill)
                        goto wlan_fail;
 
-               rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill,
-                                   get_acpi(CM_ASL_WLAN) != 1);
+               rfkill_init_sw_state(ehotk->eeepc_wlan_rfkill,
+                                    get_acpi(CM_ASL_WLAN) != 1);
                result = rfkill_register(ehotk->eeepc_wlan_rfkill);
                if (result)
                        goto wlan_fail;
@@ -693,8 +700,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
                if (!ehotk->eeepc_bluetooth_rfkill)
                        goto bluetooth_fail;
 
-               rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill,
-                                   get_acpi(CM_ASL_BLUETOOTH) != 1);
+               rfkill_init_sw_state(ehotk->eeepc_bluetooth_rfkill,
+                                    get_acpi(CM_ASL_BLUETOOTH) != 1);
                result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
                if (result)
                        goto bluetooth_fail;
@@ -718,14 +725,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
 
 static int eeepc_hotk_remove(struct acpi_device *device, int type)
 {
-       acpi_status status = 0;
-
        if (!device || !acpi_driver_data(device))
                 return -EINVAL;
-       status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
-                                           eeepc_hotk_notify);
-       if (ACPI_FAILURE(status))
-               printk(EEEPC_ERR "Error removing notify handler\n");
 
        eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
        eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
@@ -734,6 +735,33 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+static int eeepc_hotk_resume(struct acpi_device *device)
+{
+       if (ehotk->eeepc_wlan_rfkill) {
+               bool wlan;
+
+               /* Workaround - it seems that _PTS disables the wireless
+                  without notification or changing the value read by WLAN.
+                  Normally this is fine because the correct value is restored
+                  from the non-volatile storage on resume, but we need to do
+                  it ourself if case suspend is aborted, or we lose wireless.
+                */
+               wlan = get_acpi(CM_ASL_WLAN);
+               set_acpi(CM_ASL_WLAN, wlan);
+
+               rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill,
+                                   wlan != 1);
+
+               eeepc_rfkill_hotplug();
+       }
+
+       if (ehotk->eeepc_bluetooth_rfkill)
+               rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill,
+                                   get_acpi(CM_ASL_BLUETOOTH) != 1);
+
+       return 0;
+}
+
 /*
  * Hwmon
  */