Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b121bc2 authored by Corentin Chary's avatar Corentin Chary Committed by Len Brown
Browse files

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: default avatarMatthew Garrett <mjg@redhat.com>
Signed-off-by: default avatarCorentin Chary <corentincj@iksaif.net>
Tested-by: default avatarDarren Salt <linux@youmustbejoking.demon.co.uk>
Signed-off-by: default avatarRandy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 28d0325c
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -357,6 +357,8 @@ config EEEPC_LAPTOP
	depends on RFKILL || RFKILL = n
	depends on RFKILL || RFKILL = n
	select BACKLIGHT_CLASS_DEVICE
	select BACKLIGHT_CLASS_DEVICE
	select HWMON
	select HWMON
	select HOTPLUG
	select HOTPLUG_PCI if PCI
	---help---
	---help---
	  This driver supports the Fn-Fx keys on Eee PC laptops.
	  This driver supports the Fn-Fx keys on Eee PC laptops.


+87 −0
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@
#include <linux/input.h>
#include <linux/input.h>
#include <linux/rfkill.h>
#include <linux/rfkill.h>
#include <linux/pci.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>


#define EEEPC_LAPTOP_VERSION	"0.1"
#define EEEPC_LAPTOP_VERSION	"0.1"


@@ -143,6 +144,7 @@ struct eeepc_hotk {
	u16 *keycode_map;
	u16 *keycode_map;
	struct rfkill *eeepc_wlan_rfkill;
	struct rfkill *eeepc_wlan_rfkill;
	struct rfkill *eeepc_bluetooth_rfkill;
	struct rfkill *eeepc_bluetooth_rfkill;
	struct hotplug_slot *hotplug_slot;
};
};


/* The actual device the driver binds to */
/* The actual device the driver binds to */
@@ -213,6 +215,15 @@ static struct acpi_driver eeepc_hotk_driver = {
	},
	},
};
};


/* PCI hotplug ops */
static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value);

static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
	.owner = THIS_MODULE,
	.get_adapter_status = eeepc_get_adapter_status,
	.get_power_status = eeepc_get_adapter_status,
};

/* The backlight device /sys/class/backlight */
/* The backlight device /sys/class/backlight */
static struct backlight_device *eeepc_backlight_device;
static struct backlight_device *eeepc_backlight_device;


@@ -612,6 +623,19 @@ static int notify_brn(void)
	return -1;
	return -1;
}
}


static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
				    u8 *value)
{
	int val = get_acpi(CM_ASL_WLAN);

	if (val == 1 || val == 0)
		*value = val;
	else
		return -EINVAL;

	return 0;
}

static void eeepc_rfkill_hotplug(void)
static void eeepc_rfkill_hotplug(void)
{
{
	struct pci_dev *dev;
	struct pci_dev *dev;
@@ -744,6 +768,54 @@ static void eeepc_unregister_rfkill_notifier(char *node)
	}
	}
}
}


static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
{
	kfree(hotplug_slot->info);
	kfree(hotplug_slot);
}

static int eeepc_setup_pci_hotplug(void)
{
	int ret = -ENOMEM;
	struct pci_bus *bus = pci_find_bus(0, 1);

	if (!bus) {
		printk(EEEPC_ERR "Unable to find wifi PCI bus\n");
		return -ENODEV;
	}

	ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
	if (!ehotk->hotplug_slot)
		goto error_slot;

	ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
					    GFP_KERNEL);
	if (!ehotk->hotplug_slot->info)
		goto error_info;

	ehotk->hotplug_slot->private = ehotk;
	ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug;
	ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
	eeepc_get_adapter_status(ehotk->hotplug_slot,
				 &ehotk->hotplug_slot->info->adapter_status);

	ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi");
	if (ret) {
		printk(EEEPC_ERR "Unable to register hotplug slot - %d\n", ret);
		goto error_register;
	}

	return 0;

error_register:
	kfree(ehotk->hotplug_slot->info);
error_info:
	kfree(ehotk->hotplug_slot);
	ehotk->hotplug_slot = NULL;
error_slot:
	return ret;
}

static int eeepc_hotk_add(struct acpi_device *device)
static int eeepc_hotk_add(struct acpi_device *device)
{
{
	int result;
	int result;
@@ -802,8 +874,21 @@ static int eeepc_hotk_add(struct acpi_device *device)
			goto bluetooth_fail;
			goto bluetooth_fail;
	}
	}


	result = eeepc_setup_pci_hotplug();
	/*
	 * If we get -EBUSY then something else is handling the PCI hotplug -
	 * don't fail in this case
	 */
	if (result == -EBUSY)
		return 0;
		return 0;
	else if (result)
		goto pci_fail;


	return 0;

 pci_fail:
	if (ehotk->eeepc_bluetooth_rfkill)
		rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
 bluetooth_fail:
 bluetooth_fail:
	rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
	rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
	rfkill_unregister(ehotk->eeepc_wlan_rfkill);
	rfkill_unregister(ehotk->eeepc_wlan_rfkill);
@@ -825,6 +910,8 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)


	eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
	eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
	eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
	eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
	if (ehotk->hotplug_slot)
		pci_hp_deregister(ehotk->hotplug_slot);


	kfree(ehotk);
	kfree(ehotk);
	return 0;
	return 0;