Commit b56ab33d authored by Darren Salt's avatar Darren Salt Committed by Len Brown

eeepc-laptop: Prevent a panic when disabling RT2860 wireless when associated

This works around what I think is actually a bug in rt2860sta which is
triggered when the hardware "disappears" from beneath the driver, i.e. when
wireless is toggled off via ACPI. It does so by ensuring that the rfkill
soft-block flag is set before the hardware is disabled.

I do not know whether this patch is required if rt2800pci is in use instead
of rt2860sta; at the time of submission of this patch, I've not been able to
test this.

(Ref. http://bugzilla.kernel.org/show_bug.cgi?id=13390)
Signed-off-by: default avatarDarren Salt <linux@youmustbejoking.demon.co.uk>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent dcb73eed
...@@ -150,6 +150,8 @@ struct eeepc_hotk { ...@@ -150,6 +150,8 @@ struct eeepc_hotk {
/* The actual device the driver binds to */ /* The actual device the driver binds to */
static struct eeepc_hotk *ehotk; static struct eeepc_hotk *ehotk;
static void eeepc_rfkill_hotplug(bool real);
/* Platform device/driver */ /* Platform device/driver */
static int eeepc_hotk_thaw(struct device *device); static int eeepc_hotk_thaw(struct device *device);
static int eeepc_hotk_restore(struct device *device); static int eeepc_hotk_restore(struct device *device);
...@@ -343,7 +345,16 @@ static bool eeepc_wlan_rfkill_blocked(void) ...@@ -343,7 +345,16 @@ static bool eeepc_wlan_rfkill_blocked(void)
static int eeepc_rfkill_set(void *data, bool blocked) static int eeepc_rfkill_set(void *data, bool blocked)
{ {
unsigned long asl = (unsigned long)data; unsigned long asl = (unsigned long)data;
return set_acpi(asl, !blocked); int ret;
if (asl != CM_ASL_WLAN)
return set_acpi(asl, !blocked);
/* hack to avoid panic with rt2860sta */
if (blocked)
eeepc_rfkill_hotplug(false);
ret = set_acpi(asl, !blocked);
return ret;
} }
static const struct rfkill_ops eeepc_rfkill_ops = { static const struct rfkill_ops eeepc_rfkill_ops = {
...@@ -643,13 +654,13 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, ...@@ -643,13 +654,13 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
return 0; return 0;
} }
static void eeepc_rfkill_hotplug(void) static void eeepc_rfkill_hotplug(bool real)
{ {
struct pci_dev *dev; struct pci_dev *dev;
struct pci_bus *bus; struct pci_bus *bus;
bool blocked = eeepc_wlan_rfkill_blocked(); bool blocked = real ? eeepc_wlan_rfkill_blocked() : true;
if (ehotk->wlan_rfkill) if (real && ehotk->wlan_rfkill)
rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
mutex_lock(&ehotk->hotplug_lock); mutex_lock(&ehotk->hotplug_lock);
...@@ -692,7 +703,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) ...@@ -692,7 +703,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
if (event != ACPI_NOTIFY_BUS_CHECK) if (event != ACPI_NOTIFY_BUS_CHECK)
return; return;
eeepc_rfkill_hotplug(); eeepc_rfkill_hotplug(true);
} }
static void eeepc_hotk_notify(struct acpi_device *device, u32 event) static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
...@@ -850,7 +861,7 @@ static int eeepc_hotk_restore(struct device *device) ...@@ -850,7 +861,7 @@ static int eeepc_hotk_restore(struct device *device)
{ {
/* Refresh both wlan rfkill state and pci hotplug */ /* Refresh both wlan rfkill state and pci hotplug */
if (ehotk->wlan_rfkill) if (ehotk->wlan_rfkill)
eeepc_rfkill_hotplug(); eeepc_rfkill_hotplug(true);
if (ehotk->bluetooth_rfkill) if (ehotk->bluetooth_rfkill)
rfkill_set_sw_state(ehotk->bluetooth_rfkill, rfkill_set_sw_state(ehotk->bluetooth_rfkill,
...@@ -993,7 +1004,7 @@ static void eeepc_rfkill_exit(void) ...@@ -993,7 +1004,7 @@ static void eeepc_rfkill_exit(void)
* Refresh pci hotplug in case the rfkill state was changed after * Refresh pci hotplug in case the rfkill state was changed after
* eeepc_unregister_rfkill_notifier() * eeepc_unregister_rfkill_notifier()
*/ */
eeepc_rfkill_hotplug(); eeepc_rfkill_hotplug(true);
if (ehotk->hotplug_slot) if (ehotk->hotplug_slot)
pci_hp_deregister(ehotk->hotplug_slot); pci_hp_deregister(ehotk->hotplug_slot);
...@@ -1109,7 +1120,7 @@ static int eeepc_rfkill_init(struct device *dev) ...@@ -1109,7 +1120,7 @@ static int eeepc_rfkill_init(struct device *dev)
* Refresh pci hotplug in case the rfkill state was changed during * Refresh pci hotplug in case the rfkill state was changed during
* setup. * setup.
*/ */
eeepc_rfkill_hotplug(); eeepc_rfkill_hotplug(true);
exit: exit:
if (result && result != -ENODEV) if (result && result != -ENODEV)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment