Skip to content

Commit

Permalink
eeepc-laptop: Implement rfkill hotplugging in eeepc-laptop
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Matthew Garrett authored and lenb committed Jan 20, 2009
1 parent c9ddf8f commit 5740294
Showing 1 changed file with 83 additions and 0 deletions.
83 changes: 83 additions & 0 deletions drivers/platform/x86/eeepc-laptop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 5740294

Please sign in to comment.