aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorCorentin Chary <corentincj@iksaif.net>2009-06-25 07:25:36 -0400
committerLen Brown <len.brown@intel.com>2009-06-26 00:23:29 -0400
commit2b121bc262fa03c94e653b2d44356c2f86c1bcdc (patch)
tree683ce60fa8911d4e394712a60e4378f4eaa6a60a /drivers/platform
parent28d0325ce6e0a52f53d8af687e6427fee59004d3 (diff)
eeepc-laptop: Register as a pci-hotplug device
The eee contains a logically (but not physically) hotpluggable PCIe slot. Currently this is handled by adding or removing the PCI device in response to rfkill events, but if a user has forced pciehp to bind to it (with the force=1 argument) then both drivers will try to handle the event and hilarity (in the form of oopses) will ensue. This can be avoided by having eee-laptop register the slot as a hotplug slot. Only one of pciehp and eee-laptop will successfully register this, avoiding the problem. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Corentin Chary <corentincj@iksaif.net> Tested-by: Darren Salt <linux@youmustbejoking.demon.co.uk> Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig2
-rw-r--r--drivers/platform/x86/eeepc-laptop.c87
2 files changed, 89 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 7232fe7104a..fee6a4022bc 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -357,6 +357,8 @@ config EEEPC_LAPTOP
357 depends on RFKILL || RFKILL = n 357 depends on RFKILL || RFKILL = n
358 select BACKLIGHT_CLASS_DEVICE 358 select BACKLIGHT_CLASS_DEVICE
359 select HWMON 359 select HWMON
360 select HOTPLUG
361 select HOTPLUG_PCI if PCI
360 ---help--- 362 ---help---
361 This driver supports the Fn-Fx keys on Eee PC laptops. 363 This driver supports the Fn-Fx keys on Eee PC laptops.
362 364
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 4207b26ff99..c0b203ca29f 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -31,6 +31,7 @@
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#include <linux/pci.h>
34#include <linux/pci_hotplug.h>
34 35
35#define EEEPC_LAPTOP_VERSION "0.1" 36#define EEEPC_LAPTOP_VERSION "0.1"
36 37
@@ -143,6 +144,7 @@ struct eeepc_hotk {
143 u16 *keycode_map; 144 u16 *keycode_map;
144 struct rfkill *eeepc_wlan_rfkill; 145 struct rfkill *eeepc_wlan_rfkill;
145 struct rfkill *eeepc_bluetooth_rfkill; 146 struct rfkill *eeepc_bluetooth_rfkill;
147 struct hotplug_slot *hotplug_slot;
146}; 148};
147 149
148/* The actual device the driver binds to */ 150/* The actual device the driver binds to */
@@ -213,6 +215,15 @@ static struct acpi_driver eeepc_hotk_driver = {
213 }, 215 },
214}; 216};
215 217
218/* PCI hotplug ops */
219static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value);
220
221static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
222 .owner = THIS_MODULE,
223 .get_adapter_status = eeepc_get_adapter_status,
224 .get_power_status = eeepc_get_adapter_status,
225};
226
216/* The backlight device /sys/class/backlight */ 227/* The backlight device /sys/class/backlight */
217static struct backlight_device *eeepc_backlight_device; 228static struct backlight_device *eeepc_backlight_device;
218 229
@@ -612,6 +623,19 @@ static int notify_brn(void)
612 return -1; 623 return -1;
613} 624}
614 625
626static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
627 u8 *value)
628{
629 int val = get_acpi(CM_ASL_WLAN);
630
631 if (val == 1 || val == 0)
632 *value = val;
633 else
634 return -EINVAL;
635
636 return 0;
637}
638
615static void eeepc_rfkill_hotplug(void) 639static void eeepc_rfkill_hotplug(void)
616{ 640{
617 struct pci_dev *dev; 641 struct pci_dev *dev;
@@ -744,6 +768,54 @@ static void eeepc_unregister_rfkill_notifier(char *node)
744 } 768 }
745} 769}
746 770
771static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
772{
773 kfree(hotplug_slot->info);
774 kfree(hotplug_slot);
775}
776
777static int eeepc_setup_pci_hotplug(void)
778{
779 int ret = -ENOMEM;
780 struct pci_bus *bus = pci_find_bus(0, 1);
781
782 if (!bus) {
783 printk(EEEPC_ERR "Unable to find wifi PCI bus\n");
784 return -ENODEV;
785 }
786
787 ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
788 if (!ehotk->hotplug_slot)
789 goto error_slot;
790
791 ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
792 GFP_KERNEL);
793 if (!ehotk->hotplug_slot->info)
794 goto error_info;
795
796 ehotk->hotplug_slot->private = ehotk;
797 ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug;
798 ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
799 eeepc_get_adapter_status(ehotk->hotplug_slot,
800 &ehotk->hotplug_slot->info->adapter_status);
801
802 ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi");
803 if (ret) {
804 printk(EEEPC_ERR "Unable to register hotplug slot - %d\n", ret);
805 goto error_register;
806 }
807
808 return 0;
809
810error_register:
811 kfree(ehotk->hotplug_slot->info);
812error_info:
813 kfree(ehotk->hotplug_slot);
814 ehotk->hotplug_slot = NULL;
815error_slot:
816 return ret;
817}
818
747static int eeepc_hotk_add(struct acpi_device *device) 819static int eeepc_hotk_add(struct acpi_device *device)
748{ 820{
749 int result; 821 int result;
@@ -802,8 +874,21 @@ static int eeepc_hotk_add(struct acpi_device *device)
802 goto bluetooth_fail; 874 goto bluetooth_fail;
803 } 875 }
804 876
877 result = eeepc_setup_pci_hotplug();
878 /*
879 * If we get -EBUSY then something else is handling the PCI hotplug -
880 * don't fail in this case
881 */
882 if (result == -EBUSY)
883 return 0;
884 else if (result)
885 goto pci_fail;
886
805 return 0; 887 return 0;
806 888
889 pci_fail:
890 if (ehotk->eeepc_bluetooth_rfkill)
891 rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
807 bluetooth_fail: 892 bluetooth_fail:
808 rfkill_destroy(ehotk->eeepc_bluetooth_rfkill); 893 rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
809 rfkill_unregister(ehotk->eeepc_wlan_rfkill); 894 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
@@ -825,6 +910,8 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
825 910
826 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); 911 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
827 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); 912 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
913 if (ehotk->hotplug_slot)
914 pci_hp_deregister(ehotk->hotplug_slot);
828 915
829 kfree(ehotk); 916 kfree(ehotk);
830 return 0; 917 return 0;