8b80893
Bugzilla: 958826
8b80893
Upstream-status: 3.13
8b80893
8b80893
From 4cc8a57425c623753b10b77b15392e5b83baa5a3 Mon Sep 17 00:00:00 2001
8b80893
From: Hans de Goede <hdegoede@redhat.com>
8b80893
Date: Sun, 17 Nov 2013 14:00:16 +0100
ec30fcc
Subject: [PATCH 01/12] Revert "dell-laptop: Remove rfkill code"
8b80893
8b80893
Without rfkill functionality in dell-laptop I have the following problems:
8b80893
-If the hardware radio switch is set to disable the radio, then userspace
8b80893
 will still think it can use wireless and bluetooth.
8b80893
-The wwan / 3g modem cannot be soft blocked without the dell-laptop rfkill
8b80893
 functionality
8b80893
8b80893
I know the rfkill functionality was removed from the dell-laptop driver because
8b80893
it caused more problems then it fixed, and the blacklist for it was growing out
8b80893
of control.
8b80893
8b80893
But in the thread discussing this Dell mentioned that they only QA the rfkill
8b80893
acpi interface on Latitudes and indeed there have been no blacklist entries
8b80893
for Latitudes. Therefor I would like to bring the rfkill functionality back
8b80893
only for Latitudes. This patch is a straight-forward revert. The next patch
8b80893
in this set will drop the blacklist and replace it with a Latitude check.
8b80893
8b80893
This reverts commit a6c2390cd6d2083d27a2359658e08f2d3df375ac.
8b80893
8b80893
Conflicts:
8b80893
	drivers/platform/x86/dell-laptop.c
8b80893
8b80893
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
8b80893
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
8b80893
---
8b80893
 drivers/platform/x86/dell-laptop.c | 289 +++++++++++++++++++++++++++++++++++++
8b80893
 1 file changed, 289 insertions(+)
8b80893
8b80893
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
8b80893
index bb77e18..55f75a2 100644
8b80893
--- a/drivers/platform/x86/dell-laptop.c
8b80893
+++ b/drivers/platform/x86/dell-laptop.c
8b80893
@@ -21,6 +21,7 @@
8b80893
 #include <linux/err.h>
8b80893
 #include <linux/dmi.h>
8b80893
 #include <linux/io.h>
8b80893
+#include <linux/rfkill.h>
8b80893
 #include <linux/power_supply.h>
8b80893
 #include <linux/acpi.h>
8b80893
 #include <linux/mm.h>
8b80893
@@ -89,6 +90,9 @@ static struct platform_driver platform_driver = {
8b80893
 
8b80893
 static struct platform_device *platform_device;
8b80893
 static struct backlight_device *dell_backlight_device;
8b80893
+static struct rfkill *wifi_rfkill;
8b80893
+static struct rfkill *bluetooth_rfkill;
8b80893
+static struct rfkill *wwan_rfkill;
8b80893
 
8b80893
 static const struct dmi_system_id dell_device_table[] __initconst = {
8b80893
 	{
8b80893
@@ -115,6 +119,53 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
8b80893
 };
8b80893
 MODULE_DEVICE_TABLE(dmi, dell_device_table);
8b80893
 
8b80893
+static struct dmi_system_id dell_blacklist[] = {
8b80893
+	/* Supported by compal-laptop */
8b80893
+	{
8b80893
+		.ident = "Dell Mini 9",
8b80893
+		.matches = {
8b80893
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
8b80893
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
8b80893
+		},
8b80893
+	},
8b80893
+	{
8b80893
+		.ident = "Dell Mini 10",
8b80893
+		.matches = {
8b80893
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
8b80893
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
8b80893
+		},
8b80893
+	},
8b80893
+	{
8b80893
+		.ident = "Dell Mini 10v",
8b80893
+		.matches = {
8b80893
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
8b80893
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
8b80893
+		},
8b80893
+	},
8b80893
+	{
8b80893
+		.ident = "Dell Mini 1012",
8b80893
+		.matches = {
8b80893
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
8b80893
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
8b80893
+		},
8b80893
+	},
8b80893
+	{
8b80893
+		.ident = "Dell Inspiron 11z",
8b80893
+		.matches = {
8b80893
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
8b80893
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
8b80893
+		},
8b80893
+	},
8b80893
+	{
8b80893
+		.ident = "Dell Mini 12",
8b80893
+		.matches = {
8b80893
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
8b80893
+			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
8b80893
+		},
8b80893
+	},
8b80893
+	{}
8b80893
+};
8b80893
+
8b80893
 static struct dmi_system_id dell_quirks[] = {
8b80893
 	{
8b80893
 		.callback = dmi_matched,
8b80893
@@ -355,6 +406,94 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
8b80893
 	return buffer;
8b80893
 }
8b80893
 
8b80893
+/* Derived from information in DellWirelessCtl.cpp:
8b80893
+   Class 17, select 11 is radio control. It returns an array of 32-bit values.
8b80893
+
8b80893
+   Input byte 0 = 0: Wireless information
8b80893
+
8b80893
+   result[0]: return code
8b80893
+   result[1]:
8b80893
+     Bit 0:      Hardware switch supported
8b80893
+     Bit 1:      Wifi locator supported
8b80893
+     Bit 2:      Wifi is supported
8b80893
+     Bit 3:      Bluetooth is supported
8b80893
+     Bit 4:      WWAN is supported
8b80893
+     Bit 5:      Wireless keyboard supported
8b80893
+     Bits 6-7:   Reserved
8b80893
+     Bit 8:      Wifi is installed
8b80893
+     Bit 9:      Bluetooth is installed
8b80893
+     Bit 10:     WWAN is installed
8b80893
+     Bits 11-15: Reserved
8b80893
+     Bit 16:     Hardware switch is on
8b80893
+     Bit 17:     Wifi is blocked
8b80893
+     Bit 18:     Bluetooth is blocked
8b80893
+     Bit 19:     WWAN is blocked
8b80893
+     Bits 20-31: Reserved
8b80893
+   result[2]: NVRAM size in bytes
8b80893
+   result[3]: NVRAM format version number
8b80893
+
8b80893
+   Input byte 0 = 2: Wireless switch configuration
8b80893
+   result[0]: return code
8b80893
+   result[1]:
8b80893
+     Bit 0:      Wifi controlled by switch
8b80893
+     Bit 1:      Bluetooth controlled by switch
8b80893
+     Bit 2:      WWAN controlled by switch
8b80893
+     Bits 3-6:   Reserved
8b80893
+     Bit 7:      Wireless switch config locked
8b80893
+     Bit 8:      Wifi locator enabled
8b80893
+     Bits 9-14:  Reserved
8b80893
+     Bit 15:     Wifi locator setting locked
8b80893
+     Bits 16-31: Reserved
8b80893
+*/
8b80893
+
8b80893
+static int dell_rfkill_set(void *data, bool blocked)
8b80893
+{
8b80893
+	int disable = blocked ? 1 : 0;
8b80893
+	unsigned long radio = (unsigned long)data;
8b80893
+	int hwswitch_bit = (unsigned long)data - 1;
8b80893
+	int ret = 0;
8b80893
+
8b80893
+	get_buffer();
8b80893
+	dell_send_request(buffer, 17, 11);
8b80893
+
8b80893
+	/* If the hardware switch controls this radio, and the hardware
8b80893
+	   switch is disabled, don't allow changing the software state */
8b80893
+	if ((hwswitch_state & BIT(hwswitch_bit)) &&
8b80893
+	    !(buffer->output[1] & BIT(16))) {
8b80893
+		ret = -EINVAL;
8b80893
+		goto out;
8b80893
+	}
8b80893
+
8b80893
+	buffer->input[0] = (1 | (radio<<8) | (disable << 16));
8b80893
+	dell_send_request(buffer, 17, 11);
8b80893
+
8b80893
+out:
8b80893
+	release_buffer();
8b80893
+	return ret;
8b80893
+}
8b80893
+
8b80893
+static void dell_rfkill_query(struct rfkill *rfkill, void *data)
8b80893
+{
8b80893
+	int status;
8b80893
+	int bit = (unsigned long)data + 16;
8b80893
+	int hwswitch_bit = (unsigned long)data - 1;
8b80893
+
8b80893
+	get_buffer();
8b80893
+	dell_send_request(buffer, 17, 11);
8b80893
+	status = buffer->output[1];
8b80893
+	release_buffer();
8b80893
+
8b80893
+	rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));
8b80893
+
8b80893
+	if (hwswitch_state & (BIT(hwswitch_bit)))
8b80893
+		rfkill_set_hw_state(rfkill, !(status & BIT(16)));
8b80893
+}
8b80893
+
8b80893
+static const struct rfkill_ops dell_rfkill_ops = {
8b80893
+	.set_block = dell_rfkill_set,
8b80893
+	.query = dell_rfkill_query,
8b80893
+};
8b80893
+
8b80893
 static struct dentry *dell_laptop_dir;
8b80893
 
8b80893
 static int dell_debugfs_show(struct seq_file *s, void *data)
8b80893
@@ -424,6 +563,108 @@ static const struct file_operations dell_debugfs_fops = {
8b80893
 	.release = single_release,
8b80893
 };
8b80893
 
8b80893
+static void dell_update_rfkill(struct work_struct *ignored)
8b80893
+{
8b80893
+	if (wifi_rfkill)
8b80893
+		dell_rfkill_query(wifi_rfkill, (void *)1);
8b80893
+	if (bluetooth_rfkill)
8b80893
+		dell_rfkill_query(bluetooth_rfkill, (void *)2);
8b80893
+	if (wwan_rfkill)
8b80893
+		dell_rfkill_query(wwan_rfkill, (void *)3);
8b80893
+}
8b80893
+static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
8b80893
+
8b80893
+
8b80893
+static int __init dell_setup_rfkill(void)
8b80893
+{
8b80893
+	int status;
8b80893
+	int ret;
8b80893
+
8b80893
+	if (dmi_check_system(dell_blacklist)) {
8b80893
+		pr_info("Blacklisted hardware detected - not enabling rfkill\n");
8b80893
+		return 0;
8b80893
+	}
8b80893
+
8b80893
+	get_buffer();
8b80893
+	dell_send_request(buffer, 17, 11);
8b80893
+	status = buffer->output[1];
8b80893
+	buffer->input[0] = 0x2;
8b80893
+	dell_send_request(buffer, 17, 11);
8b80893
+	hwswitch_state = buffer->output[1];
8b80893
+	release_buffer();
8b80893
+
8b80893
+	if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
8b80893
+		wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
8b80893
+					   RFKILL_TYPE_WLAN,
8b80893
+					   &dell_rfkill_ops, (void *) 1);
8b80893
+		if (!wifi_rfkill) {
8b80893
+			ret = -ENOMEM;
8b80893
+			goto err_wifi;
8b80893
+		}
8b80893
+		ret = rfkill_register(wifi_rfkill);
8b80893
+		if (ret)
8b80893
+			goto err_wifi;
8b80893
+	}
8b80893
+
8b80893
+	if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
8b80893
+		bluetooth_rfkill = rfkill_alloc("dell-bluetooth",
8b80893
+						&platform_device->dev,
8b80893
+						RFKILL_TYPE_BLUETOOTH,
8b80893
+						&dell_rfkill_ops, (void *) 2);
8b80893
+		if (!bluetooth_rfkill) {
8b80893
+			ret = -ENOMEM;
8b80893
+			goto err_bluetooth;
8b80893
+		}
8b80893
+		ret = rfkill_register(bluetooth_rfkill);
8b80893
+		if (ret)
8b80893
+			goto err_bluetooth;
8b80893
+	}
8b80893
+
8b80893
+	if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
8b80893
+		wwan_rfkill = rfkill_alloc("dell-wwan",
8b80893
+					   &platform_device->dev,
8b80893
+					   RFKILL_TYPE_WWAN,
8b80893
+					   &dell_rfkill_ops, (void *) 3);
8b80893
+		if (!wwan_rfkill) {
8b80893
+			ret = -ENOMEM;
8b80893
+			goto err_wwan;
8b80893
+		}
8b80893
+		ret = rfkill_register(wwan_rfkill);
8b80893
+		if (ret)
8b80893
+			goto err_wwan;
8b80893
+	}
8b80893
+
8b80893
+	return 0;
8b80893
+err_wwan:
8b80893
+	rfkill_destroy(wwan_rfkill);
8b80893
+	if (bluetooth_rfkill)
8b80893
+		rfkill_unregister(bluetooth_rfkill);
8b80893
+err_bluetooth:
8b80893
+	rfkill_destroy(bluetooth_rfkill);
8b80893
+	if (wifi_rfkill)
8b80893
+		rfkill_unregister(wifi_rfkill);
8b80893
+err_wifi:
8b80893
+	rfkill_destroy(wifi_rfkill);
8b80893
+
8b80893
+	return ret;
8b80893
+}
8b80893
+
8b80893
+static void dell_cleanup_rfkill(void)
8b80893
+{
8b80893
+	if (wifi_rfkill) {
8b80893
+		rfkill_unregister(wifi_rfkill);
8b80893
+		rfkill_destroy(wifi_rfkill);
8b80893
+	}
8b80893
+	if (bluetooth_rfkill) {
8b80893
+		rfkill_unregister(bluetooth_rfkill);
8b80893
+		rfkill_destroy(bluetooth_rfkill);
8b80893
+	}
8b80893
+	if (wwan_rfkill) {
8b80893
+		rfkill_unregister(wwan_rfkill);
8b80893
+		rfkill_destroy(wwan_rfkill);
8b80893
+	}
8b80893
+}
8b80893
+
8b80893
 static int dell_send_intensity(struct backlight_device *bd)
8b80893
 {
8b80893
 	int ret = 0;
8b80893
@@ -515,6 +756,30 @@ static void touchpad_led_exit(void)
8b80893
 	led_classdev_unregister(&touchpad_led);
8b80893
 }
8b80893
 
8b80893
+static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
8b80893
+			      struct serio *port)
8b80893
+{
8b80893
+	static bool extended;
8b80893
+
8b80893
+	if (str & 0x20)
8b80893
+		return false;
8b80893
+
8b80893
+	if (unlikely(data == 0xe0)) {
8b80893
+		extended = true;
8b80893
+		return false;
8b80893
+	} else if (unlikely(extended)) {
8b80893
+		switch (data) {
8b80893
+		case 0x8:
8b80893
+			schedule_delayed_work(&dell_rfkill_work,
8b80893
+					      round_jiffies_relative(HZ));
8b80893
+			break;
8b80893
+		}
8b80893
+		extended = false;
8b80893
+	}
8b80893
+
8b80893
+	return false;
8b80893
+}
8b80893
+
8b80893
 static int __init dell_init(void)
8b80893
 {
8b80893
 	int max_intensity = 0;
8b80893
@@ -557,10 +822,26 @@ static int __init dell_init(void)
8b80893
 	}
8b80893
 	buffer = page_address(bufferpage);
8b80893
 
8b80893
+	ret = dell_setup_rfkill();
8b80893
+
8b80893
+	if (ret) {
8b80893
+		pr_warn("Unable to setup rfkill\n");
8b80893
+		goto fail_rfkill;
8b80893
+	}
8b80893
+
8b80893
+	ret = i8042_install_filter(dell_laptop_i8042_filter);
8b80893
+	if (ret) {
8b80893
+		pr_warn("Unable to install key filter\n");
8b80893
+		goto fail_filter;
8b80893
+	}
8b80893
+
8b80893
 	if (quirks && quirks->touchpad_led)
8b80893
 		touchpad_led_init(&platform_device->dev);
8b80893
 
8b80893
 	dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
8b80893
+	if (dell_laptop_dir != NULL)
8b80893
+		debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
8b80893
+				    &dell_debugfs_fops);
8b80893
 
8b80893
 #ifdef CONFIG_ACPI
8b80893
 	/* In the event of an ACPI backlight being available, don't
8b80893
@@ -603,6 +884,11 @@ static int __init dell_init(void)
8b80893
 	return 0;
8b80893
 
8b80893
 fail_backlight:
8b80893
+	i8042_remove_filter(dell_laptop_i8042_filter);
8b80893
+	cancel_delayed_work_sync(&dell_rfkill_work);
8b80893
+fail_filter:
8b80893
+	dell_cleanup_rfkill();
8b80893
+fail_rfkill:
8b80893
 	free_page((unsigned long)bufferpage);
8b80893
 fail_buffer:
8b80893
 	platform_device_del(platform_device);
8b80893
@@ -620,7 +906,10 @@ static void __exit dell_exit(void)
8b80893
 	debugfs_remove_recursive(dell_laptop_dir);
8b80893
 	if (quirks && quirks->touchpad_led)
8b80893
 		touchpad_led_exit();
8b80893
+	i8042_remove_filter(dell_laptop_i8042_filter);
8b80893
+	cancel_delayed_work_sync(&dell_rfkill_work);
8b80893
 	backlight_device_unregister(dell_backlight_device);
8b80893
+	dell_cleanup_rfkill();
8b80893
 	if (platform_device) {
8b80893
 		platform_device_unregister(platform_device);
8b80893
 		platform_driver_unregister(&platform_driver);
8b80893
-- 
8b80893
1.8.3.1
8b80893
ec30fcc
ec30fcc
From 2a92551845bbbc8421ba908cd14bbdf065e0f454 Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:17 +0100
ec30fcc
Subject: [PATCH 02/12] dell-laptop: Only enable rfkill on Latitudes
ec30fcc
ec30fcc
The rfkill functionality was removed from the dell-laptop driver because it
ec30fcc
was causing problems on various non Latitude models, and the blacklist kept
ec30fcc
growing and growing. In the thread discussing this Dell mentioned that they
ec30fcc
only QA the rfkill acpi interface on Latitudes and indeed there have been
ec30fcc
no blacklist entries for Latitudes.
ec30fcc
ec30fcc
Note that the blacklist contained no Vostros either, and most Vostros have
ec30fcc
a hardware switch too, so we could consider supporting Vostros with a
ec30fcc
hardware switch too.
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 57 +++++---------------------------------
ec30fcc
 1 file changed, 7 insertions(+), 50 deletions(-)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index 55f75a2..bae932b 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -119,53 +119,6 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
ec30fcc
 };
ec30fcc
 MODULE_DEVICE_TABLE(dmi, dell_device_table);
ec30fcc
 
ec30fcc
-static struct dmi_system_id dell_blacklist[] = {
ec30fcc
-	/* Supported by compal-laptop */
ec30fcc
-	{
ec30fcc
-		.ident = "Dell Mini 9",
ec30fcc
-		.matches = {
ec30fcc
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
ec30fcc
-			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
ec30fcc
-		},
ec30fcc
-	},
ec30fcc
-	{
ec30fcc
-		.ident = "Dell Mini 10",
ec30fcc
-		.matches = {
ec30fcc
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
ec30fcc
-			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
ec30fcc
-		},
ec30fcc
-	},
ec30fcc
-	{
ec30fcc
-		.ident = "Dell Mini 10v",
ec30fcc
-		.matches = {
ec30fcc
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
ec30fcc
-			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
ec30fcc
-		},
ec30fcc
-	},
ec30fcc
-	{
ec30fcc
-		.ident = "Dell Mini 1012",
ec30fcc
-		.matches = {
ec30fcc
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
ec30fcc
-			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
ec30fcc
-		},
ec30fcc
-	},
ec30fcc
-	{
ec30fcc
-		.ident = "Dell Inspiron 11z",
ec30fcc
-		.matches = {
ec30fcc
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
ec30fcc
-			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
ec30fcc
-		},
ec30fcc
-	},
ec30fcc
-	{
ec30fcc
-		.ident = "Dell Mini 12",
ec30fcc
-		.matches = {
ec30fcc
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
ec30fcc
-			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
ec30fcc
-		},
ec30fcc
-	},
ec30fcc
-	{}
ec30fcc
-};
ec30fcc
-
ec30fcc
 static struct dmi_system_id dell_quirks[] = {
ec30fcc
 	{
ec30fcc
 		.callback = dmi_matched,
ec30fcc
@@ -579,11 +532,15 @@ static int __init dell_setup_rfkill(void)
ec30fcc
 {
ec30fcc
 	int status;
ec30fcc
 	int ret;
ec30fcc
+	const char *product;
ec30fcc
 
ec30fcc
-	if (dmi_check_system(dell_blacklist)) {
ec30fcc
-		pr_info("Blacklisted hardware detected - not enabling rfkill\n");
ec30fcc
+	/*
ec30fcc
+	 * rfkill causes trouble on various non Latitudes, according to Dell
ec30fcc
+	 * actually testing the rfkill functionality is only done on Latitudes.
ec30fcc
+	 */
ec30fcc
+	product = dmi_get_system_info(DMI_PRODUCT_NAME);
ec30fcc
+	if (!product || strncmp(product, "Latitude", 8))
ec30fcc
 		return 0;
ec30fcc
-	}
ec30fcc
 
ec30fcc
 	get_buffer();
ec30fcc
 	dell_send_request(buffer, 17, 11);
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc
ec30fcc
ec30fcc
From ddde708217af6d5fe43c0086247c05ed317076b4 Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:18 +0100
ec30fcc
Subject: [PATCH 03/12] dell-laptop: If there is no hwswitch, then clear all
ec30fcc
 hw-controlled bits
ec30fcc
ec30fcc
To ensure we don't enter any hw-switch related code paths on machines without
ec30fcc
a hw-switch.
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 3 +++
ec30fcc
 1 file changed, 3 insertions(+)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index bae932b..48fabf6 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -548,6 +548,9 @@ static int __init dell_setup_rfkill(void)
ec30fcc
 	buffer->input[0] = 0x2;
ec30fcc
 	dell_send_request(buffer, 17, 11);
ec30fcc
 	hwswitch_state = buffer->output[1];
ec30fcc
+	/* If there is no hwswitch, then clear all hw-controlled bits */
ec30fcc
+	if (!(status & BIT(0)))
ec30fcc
+		hwswitch_state &= ~7;
ec30fcc
 	release_buffer();
ec30fcc
 
ec30fcc
 	if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc
ec30fcc
ec30fcc
From d038880efd9dd222c67fd31fbfca3440d0db3a06 Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:19 +0100
ec30fcc
Subject: [PATCH 04/12] dell-laptop: Only get status from BIOS once when
ec30fcc
 updating
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 28 +++++++++++++++++++---------
ec30fcc
 1 file changed, 19 insertions(+), 9 deletions(-)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index 48fabf6..06f281b 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -425,21 +425,24 @@ out:
ec30fcc
 	return ret;
ec30fcc
 }
ec30fcc
 
ec30fcc
+static void dell_rfkill_update(struct rfkill *rfkill, int radio, int status)
ec30fcc
+{
ec30fcc
+	rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
ec30fcc
+
ec30fcc
+	if (hwswitch_state & (BIT(radio - 1)))
ec30fcc
+		rfkill_set_hw_state(rfkill, !(status & BIT(16)));
ec30fcc
+}
ec30fcc
+
ec30fcc
 static void dell_rfkill_query(struct rfkill *rfkill, void *data)
ec30fcc
 {
ec30fcc
 	int status;
ec30fcc
-	int bit = (unsigned long)data + 16;
ec30fcc
-	int hwswitch_bit = (unsigned long)data - 1;
ec30fcc
 
ec30fcc
 	get_buffer();
ec30fcc
 	dell_send_request(buffer, 17, 11);
ec30fcc
 	status = buffer->output[1];
ec30fcc
 	release_buffer();
ec30fcc
 
ec30fcc
-	rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));
ec30fcc
-
ec30fcc
-	if (hwswitch_state & (BIT(hwswitch_bit)))
ec30fcc
-		rfkill_set_hw_state(rfkill, !(status & BIT(16)));
ec30fcc
+	dell_rfkill_update(rfkill, (unsigned long)data, status);
ec30fcc
 }
ec30fcc
 
ec30fcc
 static const struct rfkill_ops dell_rfkill_ops = {
ec30fcc
@@ -518,12 +521,19 @@ static const struct file_operations dell_debugfs_fops = {
ec30fcc
 
ec30fcc
 static void dell_update_rfkill(struct work_struct *ignored)
ec30fcc
 {
ec30fcc
+	int status;
ec30fcc
+
ec30fcc
+	get_buffer();
ec30fcc
+	dell_send_request(buffer, 17, 11);
ec30fcc
+	status = buffer->output[1];
ec30fcc
+	release_buffer();
ec30fcc
+
ec30fcc
 	if (wifi_rfkill)
ec30fcc
-		dell_rfkill_query(wifi_rfkill, (void *)1);
ec30fcc
+		dell_rfkill_update(wifi_rfkill, 1, status);
ec30fcc
 	if (bluetooth_rfkill)
ec30fcc
-		dell_rfkill_query(bluetooth_rfkill, (void *)2);
ec30fcc
+		dell_rfkill_update(bluetooth_rfkill, 2, status);
ec30fcc
 	if (wwan_rfkill)
ec30fcc
-		dell_rfkill_query(wwan_rfkill, (void *)3);
ec30fcc
+		dell_rfkill_update(wwan_rfkill, 3, status);
ec30fcc
 }
ec30fcc
 static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
ec30fcc
 
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc
ec30fcc
ec30fcc
From 33f9359abb9f6ded3e7b6dc98b1468c83404af49 Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:20 +0100
ec30fcc
Subject: [PATCH 05/12] dell-laptop: Don't set sw_state from the query callback
ec30fcc
ec30fcc
The query callback should only update the hw_state, see the comment in
ec30fcc
net/rfkill/core.c in rfkill_set_block, which is its only caller.
ec30fcc
ec30fcc
rfkill_set_block will modify the sw_state directly after calling query so
ec30fcc
calling set_sw_state is an expensive NOP.
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 27 +++++++++++++++++++--------
ec30fcc
 1 file changed, 19 insertions(+), 8 deletions(-)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index 06f281b..7f47396 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -425,10 +425,15 @@ out:
ec30fcc
 	return ret;
ec30fcc
 }
ec30fcc
 
ec30fcc
-static void dell_rfkill_update(struct rfkill *rfkill, int radio, int status)
ec30fcc
+static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
ec30fcc
+					int status)
ec30fcc
 {
ec30fcc
 	rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
ec30fcc
+}
ec30fcc
 
ec30fcc
+static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio,
ec30fcc
+					int status)
ec30fcc
+{
ec30fcc
 	if (hwswitch_state & (BIT(radio - 1)))
ec30fcc
 		rfkill_set_hw_state(rfkill, !(status & BIT(16)));
ec30fcc
 }
ec30fcc
@@ -442,7 +447,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data)
ec30fcc
 	status = buffer->output[1];
ec30fcc
 	release_buffer();
ec30fcc
 
ec30fcc
-	dell_rfkill_update(rfkill, (unsigned long)data, status);
ec30fcc
+	dell_rfkill_update_hw_state(rfkill, (unsigned long)data, status);
ec30fcc
 }
ec30fcc
 
ec30fcc
 static const struct rfkill_ops dell_rfkill_ops = {
ec30fcc
@@ -528,12 +533,18 @@ static void dell_update_rfkill(struct work_struct *ignored)
ec30fcc
 	status = buffer->output[1];
ec30fcc
 	release_buffer();
ec30fcc
 
ec30fcc
-	if (wifi_rfkill)
ec30fcc
-		dell_rfkill_update(wifi_rfkill, 1, status);
ec30fcc
-	if (bluetooth_rfkill)
ec30fcc
-		dell_rfkill_update(bluetooth_rfkill, 2, status);
ec30fcc
-	if (wwan_rfkill)
ec30fcc
-		dell_rfkill_update(wwan_rfkill, 3, status);
ec30fcc
+	if (wifi_rfkill) {
ec30fcc
+		dell_rfkill_update_hw_state(wifi_rfkill, 1, status);
ec30fcc
+		dell_rfkill_update_sw_state(wifi_rfkill, 1, status);
ec30fcc
+	}
ec30fcc
+	if (bluetooth_rfkill) {
ec30fcc
+		dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status);
ec30fcc
+		dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status);
ec30fcc
+	}
ec30fcc
+	if (wwan_rfkill) {
ec30fcc
+		dell_rfkill_update_hw_state(wwan_rfkill, 3, status);
ec30fcc
+		dell_rfkill_update_sw_state(wwan_rfkill, 3, status);
ec30fcc
+	}
ec30fcc
 }
ec30fcc
 static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
ec30fcc
 
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc
ec30fcc
ec30fcc
From 3f56588a79a06a0499db0077cad6675762ddc40e Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:21 +0100
ec30fcc
Subject: [PATCH 06/12] dell-laptop: Don't read-back sw_state on machines with
ec30fcc
 a hardware switch
ec30fcc
ec30fcc
On machines with a hardware switch, the blocking settings can not be changed
ec30fcc
through a Fn + wireless-key combo, so there is no reason to read back the
ec30fcc
blocking state from the BIOS.
ec30fcc
ec30fcc
Reading back is not only not necessary it is actually harmful, since on some
ec30fcc
machines the blocking state will be cleared to all 0 after a wireless switch
ec30fcc
toggle, even for radios not controlled by the hw-switch (yeah firmware bugs).
ec30fcc
ec30fcc
This causes "magic" changes to the sw_state. This is inconsistent with other
ec30fcc
rfkill drivers which preserve the sw_state over a hw kill on / off.
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 5 ++++-
ec30fcc
 1 file changed, 4 insertions(+), 1 deletion(-)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index 7f47396..80de0cc 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -428,7 +428,10 @@ out:
ec30fcc
 static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
ec30fcc
 					int status)
ec30fcc
 {
ec30fcc
-	rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
ec30fcc
+	if (!(status & BIT(0))) {
ec30fcc
+		/* No hw-switch, sync BIOS state to sw_state */
ec30fcc
+		rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
ec30fcc
+	}
ec30fcc
 }
ec30fcc
 
ec30fcc
 static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio,
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc
ec30fcc
ec30fcc
From 4d39d88ceb83e88953a76df8b1fa10f43f328038 Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:22 +0100
ec30fcc
Subject: [PATCH 07/12] dell-laptop: Allow changing the sw_state while the
ec30fcc
 radio is blocked by hw
ec30fcc
ec30fcc
This makes dell-laptop's rfkill code consistent with other drivers which
ec30fcc
allow sw_state changes while hw blocked.
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 7 ++-----
ec30fcc
 1 file changed, 2 insertions(+), 5 deletions(-)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index 80de0cc..834f499 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -404,7 +404,6 @@ static int dell_rfkill_set(void *data, bool blocked)
ec30fcc
 	int disable = blocked ? 1 : 0;
ec30fcc
 	unsigned long radio = (unsigned long)data;
ec30fcc
 	int hwswitch_bit = (unsigned long)data - 1;
ec30fcc
-	int ret = 0;
ec30fcc
 
ec30fcc
 	get_buffer();
ec30fcc
 	dell_send_request(buffer, 17, 11);
ec30fcc
@@ -412,17 +411,15 @@ static int dell_rfkill_set(void *data, bool blocked)
ec30fcc
 	/* If the hardware switch controls this radio, and the hardware
ec30fcc
 	   switch is disabled, don't allow changing the software state */
ec30fcc
 	if ((hwswitch_state & BIT(hwswitch_bit)) &&
ec30fcc
-	    !(buffer->output[1] & BIT(16))) {
ec30fcc
-		ret = -EINVAL;
ec30fcc
+	    !(buffer->output[1] & BIT(16)))
ec30fcc
 		goto out;
ec30fcc
-	}
ec30fcc
 
ec30fcc
 	buffer->input[0] = (1 | (radio<<8) | (disable << 16));
ec30fcc
 	dell_send_request(buffer, 17, 11);
ec30fcc
 
ec30fcc
 out:
ec30fcc
 	release_buffer();
ec30fcc
-	return ret;
ec30fcc
+	return 0;
ec30fcc
 }
ec30fcc
 
ec30fcc
 static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc
ec30fcc
ec30fcc
From 04c9a3a06c47b337b90a91e458716262cc45b103 Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:23 +0100
ec30fcc
Subject: [PATCH 08/12] dell-laptop: Sync current block state to BIOS on hw
ec30fcc
 switch change
ec30fcc
ec30fcc
This is necessary for 3 reasons:
ec30fcc
1) To apply sw_state changes made while hw-blocked
ec30fcc
2) To set all the blocked bits for hw-switch controlled radios to 1 when the
ec30fcc
   switch gets changed to off, this is necessary on some models to actually
ec30fcc
   turn the radio status LEDs off.
ec30fcc
3) On some models non hw-switch controlled radios will have their block bit
ec30fcc
   cleared (potentially undoing a soft-block) on hw-switch toggle, this
ec30fcc
   restores the sw-block in this case.
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 14 +++++++++++---
ec30fcc
 1 file changed, 11 insertions(+), 3 deletions(-)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index 834f499..7f59624 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -422,10 +422,16 @@ out:
ec30fcc
 	return 0;
ec30fcc
 }
ec30fcc
 
ec30fcc
+/* Must be called with the buffer held */
ec30fcc
 static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
ec30fcc
 					int status)
ec30fcc
 {
ec30fcc
-	if (!(status & BIT(0))) {
ec30fcc
+	if (status & BIT(0)) {
ec30fcc
+		/* Has hw-switch, sync sw_state to BIOS */
ec30fcc
+		int block = rfkill_blocked(rfkill);
ec30fcc
+		buffer->input[0] = (1 | (radio << 8) | (block << 16));
ec30fcc
+		dell_send_request(buffer, 17, 11);
ec30fcc
+	} else {
ec30fcc
 		/* No hw-switch, sync BIOS state to sw_state */
ec30fcc
 		rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
ec30fcc
 	}
ec30fcc
@@ -445,9 +451,10 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data)
ec30fcc
 	get_buffer();
ec30fcc
 	dell_send_request(buffer, 17, 11);
ec30fcc
 	status = buffer->output[1];
ec30fcc
-	release_buffer();
ec30fcc
 
ec30fcc
 	dell_rfkill_update_hw_state(rfkill, (unsigned long)data, status);
ec30fcc
+
ec30fcc
+	release_buffer();
ec30fcc
 }
ec30fcc
 
ec30fcc
 static const struct rfkill_ops dell_rfkill_ops = {
ec30fcc
@@ -531,7 +538,6 @@ static void dell_update_rfkill(struct work_struct *ignored)
ec30fcc
 	get_buffer();
ec30fcc
 	dell_send_request(buffer, 17, 11);
ec30fcc
 	status = buffer->output[1];
ec30fcc
-	release_buffer();
ec30fcc
 
ec30fcc
 	if (wifi_rfkill) {
ec30fcc
 		dell_rfkill_update_hw_state(wifi_rfkill, 1, status);
ec30fcc
@@ -545,6 +551,8 @@ static void dell_update_rfkill(struct work_struct *ignored)
ec30fcc
 		dell_rfkill_update_hw_state(wwan_rfkill, 3, status);
ec30fcc
 		dell_rfkill_update_sw_state(wwan_rfkill, 3, status);
ec30fcc
 	}
ec30fcc
+
ec30fcc
+	release_buffer();
ec30fcc
 }
ec30fcc
 static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
ec30fcc
 
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc
ec30fcc
ec30fcc
From ed1128989ab242f44664b446702a512e5695c4b7 Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:24 +0100
ec30fcc
Subject: [PATCH 09/12] dell-laptop: Do not skip setting blocked bit rfkill_set
ec30fcc
 while hw-blocked
ec30fcc
ec30fcc
Instead when hw-blocked always write 1 to the blocked bit for the radio in
ec30fcc
question. This is necessary to properly set all the blocked bits for hw-switch
ec30fcc
controlled radios to 1 after power-on and resume.
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 5 ++---
ec30fcc
 1 file changed, 2 insertions(+), 3 deletions(-)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index 7f59624..b33b779 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -409,15 +409,14 @@ static int dell_rfkill_set(void *data, bool blocked)
ec30fcc
 	dell_send_request(buffer, 17, 11);
ec30fcc
 
ec30fcc
 	/* If the hardware switch controls this radio, and the hardware
ec30fcc
-	   switch is disabled, don't allow changing the software state */
ec30fcc
+	   switch is disabled, always disable the radio */
ec30fcc
 	if ((hwswitch_state & BIT(hwswitch_bit)) &&
ec30fcc
 	    !(buffer->output[1] & BIT(16)))
ec30fcc
-		goto out;
ec30fcc
+		disable = 1;
ec30fcc
 
ec30fcc
 	buffer->input[0] = (1 | (radio<<8) | (disable << 16));
ec30fcc
 	dell_send_request(buffer, 17, 11);
ec30fcc
 
ec30fcc
-out:
ec30fcc
 	release_buffer();
ec30fcc
 	return 0;
ec30fcc
 }
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc
ec30fcc
ec30fcc
From 26c22d63a70f62e0832c6d9f2a2690ab0155d584 Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:25 +0100
ec30fcc
Subject: [PATCH 10/12] dell-laptop: Wait less long before updating rfkill
ec30fcc
 after an rfkill keypress
ec30fcc
ec30fcc
Some time is needed for the BIOS to do its work, but 250ms should be plenty.
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 2 +-
ec30fcc
 1 file changed, 1 insertion(+), 1 deletion(-)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index b33b779..fe20f67 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -759,7 +759,7 @@ static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
ec30fcc
 		switch (data) {
ec30fcc
 		case 0x8:
ec30fcc
 			schedule_delayed_work(&dell_rfkill_work,
ec30fcc
-					      round_jiffies_relative(HZ));
ec30fcc
+					      round_jiffies_relative(HZ / 4));
ec30fcc
 			break;
ec30fcc
 		}
ec30fcc
 		extended = false;
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc
ec30fcc
ec30fcc
From 8e0e668d0aa09d2eb0a7a260b6c7801796e01bd3 Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:26 +0100
ec30fcc
Subject: [PATCH 11/12] dell-laptop: Add a force_rfkill module parameter
ec30fcc
ec30fcc
Setting force_rfkill will cause the dell-laptop rfkill code to skip its
ec30fcc
whitelist checks, this will allow individual users to override the whitelist,
ec30fcc
as well as to gather info from users to improve the checks.
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 6 +++++-
ec30fcc
 1 file changed, 5 insertions(+), 1 deletion(-)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index fe20f67..bd67c89 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -93,6 +93,10 @@ static struct backlight_device *dell_backlight_device;
ec30fcc
 static struct rfkill *wifi_rfkill;
ec30fcc
 static struct rfkill *bluetooth_rfkill;
ec30fcc
 static struct rfkill *wwan_rfkill;
ec30fcc
+static bool force_rfkill;
ec30fcc
+
ec30fcc
+module_param(force_rfkill, bool, 0444);
ec30fcc
+MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models");
ec30fcc
 
ec30fcc
 static const struct dmi_system_id dell_device_table[] __initconst = {
ec30fcc
 	{
ec30fcc
@@ -567,7 +571,7 @@ static int __init dell_setup_rfkill(void)
ec30fcc
 	 * actually testing the rfkill functionality is only done on Latitudes.
ec30fcc
 	 */
ec30fcc
 	product = dmi_get_system_info(DMI_PRODUCT_NAME);
ec30fcc
-	if (!product || strncmp(product, "Latitude", 8))
ec30fcc
+	if (!force_rfkill && (!product || strncmp(product, "Latitude", 8)))
ec30fcc
 		return 0;
ec30fcc
 
ec30fcc
 	get_buffer();
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc
ec30fcc
ec30fcc
From 2bd4ac139259bb605fc0325a7dda33e2fbb67ae3 Mon Sep 17 00:00:00 2001
ec30fcc
From: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Date: Sun, 17 Nov 2013 14:00:27 +0100
ec30fcc
Subject: [PATCH 12/12] dell-laptop: Only enable rfkill functionality on
ec30fcc
 laptops with a hw killswitch
ec30fcc
ec30fcc
All my testing has been on laptops with a hw killswitch, so to be on the
ec30fcc
safe side disable rfkill functionality on models without a hw killswitch for
ec30fcc
now. Once we gather some feedback on laptops without a hw killswitch this
ec30fcc
decision maybe reconsidered.
ec30fcc
ec30fcc
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
ec30fcc
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
ec30fcc
---
ec30fcc
 drivers/platform/x86/dell-laptop.c | 13 ++++++++++---
ec30fcc
 1 file changed, 10 insertions(+), 3 deletions(-)
ec30fcc
ec30fcc
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
ec30fcc
index bd67c89..c608b1d 100644
ec30fcc
--- a/drivers/platform/x86/dell-laptop.c
ec30fcc
+++ b/drivers/platform/x86/dell-laptop.c
ec30fcc
@@ -580,11 +580,18 @@ static int __init dell_setup_rfkill(void)
ec30fcc
 	buffer->input[0] = 0x2;
ec30fcc
 	dell_send_request(buffer, 17, 11);
ec30fcc
 	hwswitch_state = buffer->output[1];
ec30fcc
-	/* If there is no hwswitch, then clear all hw-controlled bits */
ec30fcc
-	if (!(status & BIT(0)))
ec30fcc
-		hwswitch_state &= ~7;
ec30fcc
 	release_buffer();
ec30fcc
 
ec30fcc
+	if (!(status & BIT(0))) {
ec30fcc
+		if (force_rfkill) {
ec30fcc
+			/* No hwsitch, clear all hw-controlled bits */
ec30fcc
+			hwswitch_state &= ~7;
ec30fcc
+		} else {
ec30fcc
+			/* rfkill is only tested on laptops with a hwswitch */
ec30fcc
+			return 0;
ec30fcc
+		}
ec30fcc
+	}
ec30fcc
+
ec30fcc
 	if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
ec30fcc
 		wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
ec30fcc
 					   RFKILL_TYPE_WLAN,
ec30fcc
-- 
ec30fcc
1.8.3.1
ec30fcc