forked from Minki/linux
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>
This commit is contained in:
parent
c9ddf8fede
commit
5740294ca3
@ -30,6 +30,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#define EEEPC_LAPTOP_VERSION "0.1"
|
||||
|
||||
@ -517,6 +518,41 @@ static void notify_brn(void)
|
||||
bd->props.brightness = read_brightness(bd);
|
||||
}
|
||||
|
||||
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *bus = pci_find_bus(0, 1);
|
||||
|
||||
if (event != ACPI_NOTIFY_BUS_CHECK)
|
||||
return;
|
||||
|
||||
if (!bus) {
|
||||
printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_acpi(CM_ASL_WLAN) == 1) {
|
||||
dev = pci_get_slot(bus, 0);
|
||||
if (dev) {
|
||||
/* Device already present */
|
||||
pci_dev_put(dev);
|
||||
return;
|
||||
}
|
||||
dev = pci_scan_single_device(bus, 0);
|
||||
if (dev) {
|
||||
pci_bus_assign_resources(bus);
|
||||
if (pci_bus_add_device(dev))
|
||||
printk(EEEPC_ERR "Unable to hotplug wifi\n");
|
||||
}
|
||||
} else {
|
||||
dev = pci_get_slot(bus, 0);
|
||||
if (dev) {
|
||||
pci_remove_bus_device(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
static struct key_entry *key;
|
||||
@ -543,6 +579,45 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
static int eeepc_register_rfkill_notifier(char *node)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
acpi_handle handle;
|
||||
|
||||
status = acpi_get_handle(NULL, node, &handle);
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
status = acpi_install_notify_handler(handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
eeepc_rfkill_notify,
|
||||
NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
printk(EEEPC_WARNING
|
||||
"Failed to register notify on %s\n", node);
|
||||
} else
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void eeepc_unregister_rfkill_notifier(char *node)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
acpi_handle handle;
|
||||
|
||||
status = acpi_get_handle(NULL, node, &handle);
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
status = acpi_remove_notify_handler(handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
eeepc_rfkill_notify);
|
||||
if (ACPI_FAILURE(status))
|
||||
printk(EEEPC_ERR
|
||||
"Error removing rfkill notify handler %s\n",
|
||||
node);
|
||||
}
|
||||
}
|
||||
|
||||
static int eeepc_hotk_add(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
@ -622,6 +697,10 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
||||
if (result)
|
||||
goto bluetooth_fail;
|
||||
}
|
||||
|
||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
|
||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
|
||||
|
||||
return 0;
|
||||
|
||||
bluetooth_fail:
|
||||
@ -649,6 +728,10 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
|
||||
eeepc_hotk_notify);
|
||||
if (ACPI_FAILURE(status))
|
||||
printk(EEEPC_ERR "Error removing notify handler\n");
|
||||
|
||||
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
|
||||
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
|
||||
|
||||
kfree(ehotk);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user