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>

authored by Matthew Garrett and committed by Len Brown 5740294c c9ddf8fe

+83
+83
drivers/platform/x86/eeepc-laptop.c
··· 30 #include <linux/uaccess.h> 31 #include <linux/input.h> 32 #include <linux/rfkill.h> 33 34 #define EEEPC_LAPTOP_VERSION "0.1" 35 ··· 518 bd->props.brightness = read_brightness(bd); 519 } 520 521 static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) 522 { 523 static struct key_entry *key; ··· 576 break; 577 } 578 } 579 } 580 } 581 ··· 697 if (result) 698 goto bluetooth_fail; 699 } 700 return 0; 701 702 bluetooth_fail: ··· 728 eeepc_hotk_notify); 729 if (ACPI_FAILURE(status)) 730 printk(EEEPC_ERR "Error removing notify handler\n"); 731 kfree(ehotk); 732 return 0; 733 }
··· 30 #include <linux/uaccess.h> 31 #include <linux/input.h> 32 #include <linux/rfkill.h> 33 + #include <linux/pci.h> 34 35 #define EEEPC_LAPTOP_VERSION "0.1" 36 ··· 517 bd->props.brightness = read_brightness(bd); 518 } 519 520 + static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) 521 + { 522 + struct pci_dev *dev; 523 + struct pci_bus *bus = pci_find_bus(0, 1); 524 + 525 + if (event != ACPI_NOTIFY_BUS_CHECK) 526 + return; 527 + 528 + if (!bus) { 529 + printk(EEEPC_WARNING "Unable to find PCI bus 1?\n"); 530 + return; 531 + } 532 + 533 + if (get_acpi(CM_ASL_WLAN) == 1) { 534 + dev = pci_get_slot(bus, 0); 535 + if (dev) { 536 + /* Device already present */ 537 + pci_dev_put(dev); 538 + return; 539 + } 540 + dev = pci_scan_single_device(bus, 0); 541 + if (dev) { 542 + pci_bus_assign_resources(bus); 543 + if (pci_bus_add_device(dev)) 544 + printk(EEEPC_ERR "Unable to hotplug wifi\n"); 545 + } 546 + } else { 547 + dev = pci_get_slot(bus, 0); 548 + if (dev) { 549 + pci_remove_bus_device(dev); 550 + pci_dev_put(dev); 551 + } 552 + } 553 + } 554 + 555 static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) 556 { 557 static struct key_entry *key; ··· 540 break; 541 } 542 } 543 + } 544 + } 545 + 546 + static int eeepc_register_rfkill_notifier(char *node) 547 + { 548 + acpi_status status = AE_OK; 549 + acpi_handle handle; 550 + 551 + status = acpi_get_handle(NULL, node, &handle); 552 + 553 + if (ACPI_SUCCESS(status)) { 554 + status = acpi_install_notify_handler(handle, 555 + ACPI_SYSTEM_NOTIFY, 556 + eeepc_rfkill_notify, 557 + NULL); 558 + if (ACPI_FAILURE(status)) 559 + printk(EEEPC_WARNING 560 + "Failed to register notify on %s\n", node); 561 + } else 562 + return -ENODEV; 563 + 564 + return 0; 565 + } 566 + 567 + static void eeepc_unregister_rfkill_notifier(char *node) 568 + { 569 + acpi_status status = AE_OK; 570 + acpi_handle handle; 571 + 572 + status = acpi_get_handle(NULL, node, &handle); 573 + 574 + if (ACPI_SUCCESS(status)) { 575 + status = acpi_remove_notify_handler(handle, 576 + ACPI_SYSTEM_NOTIFY, 577 + eeepc_rfkill_notify); 578 + if (ACPI_FAILURE(status)) 579 + printk(EEEPC_ERR 580 + "Error removing rfkill notify handler %s\n", 581 + node); 582 } 583 } 584 ··· 622 if (result) 623 goto bluetooth_fail; 624 } 625 + 626 + eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); 627 + eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); 628 + 629 return 0; 630 631 bluetooth_fail: ··· 649 eeepc_hotk_notify); 650 if (ACPI_FAILURE(status)) 651 printk(EEEPC_ERR "Error removing notify handler\n"); 652 + 653 + eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); 654 + eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); 655 + 656 kfree(ehotk); 657 return 0; 658 }