diff options
| author | Matthew Garrett <mjg@redhat.com> | 2009-01-20 10:17:48 -0500 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2009-01-20 14:36:53 -0500 |
| commit | 5740294ca3a9b113fe146f2826effb69ca50008d (patch) | |
| tree | 00e571fce1111310ef4e12801a657aeaf80ae77f | |
| parent | c9ddf8fede1271bde0a512fa94f77c4cb1ef4040 (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>
| -rw-r--r-- | drivers/platform/x86/eeepc-laptop.c | 83 |
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 | ||
| 521 | static 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 | |||
| 520 | static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) | 556 | static 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 | ||
| 582 | static 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 | |||
| 603 | static 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 | |||
| 546 | static int eeepc_hotk_add(struct acpi_device *device) | 621 | static 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 | } |
