aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2009-01-20 10:17:48 -0500
committerLen Brown <len.brown@intel.com>2009-01-20 14:36:53 -0500
commit5740294ca3a9b113fe146f2826effb69ca50008d (patch)
tree00e571fce1111310ef4e12801a657aeaf80ae77f /drivers/platform
parentc9ddf8fede1271bde0a512fa94f77c4cb1ef4040 (diff)
eeepc-laptop: Implement rfkill hotplugging in eeepc-laptop
The Eee implements rfkill by logically unplugging the wireless card from the PCI bus. Despite sending ACPI notifications, this does not appear to be implemented using standard ACPI hotplug - nor does the firmware provide the _OSC method required to support native PCIe hotplug. The only sensible choice appears to be to handle the hotplugging directly in the eeepc-laptop driver. Tested successfully on a 700, 900 and 901. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/eeepc-laptop.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 21e5206ed28b..66655d2b4ce9 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -30,6 +30,7 @@
30#include <linux/uaccess.h> 30#include <linux/uaccess.h>
31#include <linux/input.h> 31#include <linux/input.h>
32#include <linux/rfkill.h> 32#include <linux/rfkill.h>
33#include <linux/pci.h>
33 34
34#define EEEPC_LAPTOP_VERSION "0.1" 35#define EEEPC_LAPTOP_VERSION "0.1"
35 36
@@ -517,6 +518,41 @@ static void notify_brn(void)
517 bd->props.brightness = read_brightness(bd); 518 bd->props.brightness = read_brightness(bd);
518} 519}
519 520
521static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
522{
523 struct pci_dev *dev;
524 struct pci_bus *bus = pci_find_bus(0, 1);
525
526 if (event != ACPI_NOTIFY_BUS_CHECK)
527 return;
528
529 if (!bus) {
530 printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
531 return;
532 }
533
534 if (get_acpi(CM_ASL_WLAN) == 1) {
535 dev = pci_get_slot(bus, 0);
536 if (dev) {
537 /* Device already present */
538 pci_dev_put(dev);
539 return;
540 }
541 dev = pci_scan_single_device(bus, 0);
542 if (dev) {
543 pci_bus_assign_resources(bus);
544 if (pci_bus_add_device(dev))
545 printk(EEEPC_ERR "Unable to hotplug wifi\n");
546 }
547 } else {
548 dev = pci_get_slot(bus, 0);
549 if (dev) {
550 pci_remove_bus_device(dev);
551 pci_dev_put(dev);
552 }
553 }
554}
555
520static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) 556static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
521{ 557{
522 static struct key_entry *key; 558 static struct key_entry *key;
@@ -543,6 +579,45 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
543 } 579 }
544} 580}
545 581
582static int eeepc_register_rfkill_notifier(char *node)
583{
584 acpi_status status = AE_OK;
585 acpi_handle handle;
586
587 status = acpi_get_handle(NULL, node, &handle);
588
589 if (ACPI_SUCCESS(status)) {
590 status = acpi_install_notify_handler(handle,
591 ACPI_SYSTEM_NOTIFY,
592 eeepc_rfkill_notify,
593 NULL);
594 if (ACPI_FAILURE(status))
595 printk(EEEPC_WARNING
596 "Failed to register notify on %s\n", node);
597 } else
598 return -ENODEV;
599
600 return 0;
601}
602
603static void eeepc_unregister_rfkill_notifier(char *node)
604{
605 acpi_status status = AE_OK;
606 acpi_handle handle;
607
608 status = acpi_get_handle(NULL, node, &handle);
609
610 if (ACPI_SUCCESS(status)) {
611 status = acpi_remove_notify_handler(handle,
612 ACPI_SYSTEM_NOTIFY,
613 eeepc_rfkill_notify);
614 if (ACPI_FAILURE(status))
615 printk(EEEPC_ERR
616 "Error removing rfkill notify handler %s\n",
617 node);
618 }
619}
620
546static int eeepc_hotk_add(struct acpi_device *device) 621static int eeepc_hotk_add(struct acpi_device *device)
547{ 622{
548 acpi_status status = AE_OK; 623 acpi_status status = AE_OK;
@@ -622,6 +697,10 @@ static int eeepc_hotk_add(struct acpi_device *device)
622 if (result) 697 if (result)
623 goto bluetooth_fail; 698 goto bluetooth_fail;
624 } 699 }
700
701 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
702 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
703
625 return 0; 704 return 0;
626 705
627 bluetooth_fail: 706 bluetooth_fail:
@@ -649,6 +728,10 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
649 eeepc_hotk_notify); 728 eeepc_hotk_notify);
650 if (ACPI_FAILURE(status)) 729 if (ACPI_FAILURE(status))
651 printk(EEEPC_ERR "Error removing notify handler\n"); 730 printk(EEEPC_ERR "Error removing notify handler\n");
731
732 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
733 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
734
652 kfree(ehotk); 735 kfree(ehotk);
653 return 0; 736 return 0;
654} 737}