diff --git a/0001-Revert-dell-laptop-Remove-rfkill-code.patch b/0001-Revert-dell-laptop-Remove-rfkill-code.patch new file mode 100644 index 0000000..c9bf8c5 --- /dev/null +++ b/0001-Revert-dell-laptop-Remove-rfkill-code.patch @@ -0,0 +1,399 @@ +Bugzilla: 958826 +Upstream-status: 3.13 + +From 4cc8a57425c623753b10b77b15392e5b83baa5a3 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 17 Nov 2013 14:00:16 +0100 +Subject: [PATCH 1/2] Revert "dell-laptop: Remove rfkill code" + +Without rfkill functionality in dell-laptop I have the following problems: +-If the hardware radio switch is set to disable the radio, then userspace + will still think it can use wireless and bluetooth. +-The wwan / 3g modem cannot be soft blocked without the dell-laptop rfkill + functionality + +I know the rfkill functionality was removed from the dell-laptop driver because +it caused more problems then it fixed, and the blacklist for it was growing out +of control. + +But in the thread discussing this Dell mentioned that they only QA the rfkill +acpi interface on Latitudes and indeed there have been no blacklist entries +for Latitudes. Therefor I would like to bring the rfkill functionality back +only for Latitudes. This patch is a straight-forward revert. The next patch +in this set will drop the blacklist and replace it with a Latitude check. + +This reverts commit a6c2390cd6d2083d27a2359658e08f2d3df375ac. + +Conflicts: + drivers/platform/x86/dell-laptop.c + +Signed-off-by: Hans de Goede +Signed-off-by: Matthew Garrett +--- + drivers/platform/x86/dell-laptop.c | 289 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 289 insertions(+) + +diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c +index bb77e18..55f75a2 100644 +--- a/drivers/platform/x86/dell-laptop.c ++++ b/drivers/platform/x86/dell-laptop.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -89,6 +90,9 @@ static struct platform_driver platform_driver = { + + static struct platform_device *platform_device; + static struct backlight_device *dell_backlight_device; ++static struct rfkill *wifi_rfkill; ++static struct rfkill *bluetooth_rfkill; ++static struct rfkill *wwan_rfkill; + + static const struct dmi_system_id dell_device_table[] __initconst = { + { +@@ -115,6 +119,53 @@ static const struct dmi_system_id dell_device_table[] __initconst = { + }; + MODULE_DEVICE_TABLE(dmi, dell_device_table); + ++static struct dmi_system_id dell_blacklist[] = { ++ /* Supported by compal-laptop */ ++ { ++ .ident = "Dell Mini 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"), ++ }, ++ }, ++ { ++ .ident = "Dell Mini 10", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"), ++ }, ++ }, ++ { ++ .ident = "Dell Mini 10v", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"), ++ }, ++ }, ++ { ++ .ident = "Dell Mini 1012", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), ++ }, ++ }, ++ { ++ .ident = "Dell Inspiron 11z", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"), ++ }, ++ }, ++ { ++ .ident = "Dell Mini 12", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"), ++ }, ++ }, ++ {} ++}; ++ + static struct dmi_system_id dell_quirks[] = { + { + .callback = dmi_matched, +@@ -355,6 +406,94 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, + return buffer; + } + ++/* Derived from information in DellWirelessCtl.cpp: ++ Class 17, select 11 is radio control. It returns an array of 32-bit values. ++ ++ Input byte 0 = 0: Wireless information ++ ++ result[0]: return code ++ result[1]: ++ Bit 0: Hardware switch supported ++ Bit 1: Wifi locator supported ++ Bit 2: Wifi is supported ++ Bit 3: Bluetooth is supported ++ Bit 4: WWAN is supported ++ Bit 5: Wireless keyboard supported ++ Bits 6-7: Reserved ++ Bit 8: Wifi is installed ++ Bit 9: Bluetooth is installed ++ Bit 10: WWAN is installed ++ Bits 11-15: Reserved ++ Bit 16: Hardware switch is on ++ Bit 17: Wifi is blocked ++ Bit 18: Bluetooth is blocked ++ Bit 19: WWAN is blocked ++ Bits 20-31: Reserved ++ result[2]: NVRAM size in bytes ++ result[3]: NVRAM format version number ++ ++ Input byte 0 = 2: Wireless switch configuration ++ result[0]: return code ++ result[1]: ++ Bit 0: Wifi controlled by switch ++ Bit 1: Bluetooth controlled by switch ++ Bit 2: WWAN controlled by switch ++ Bits 3-6: Reserved ++ Bit 7: Wireless switch config locked ++ Bit 8: Wifi locator enabled ++ Bits 9-14: Reserved ++ Bit 15: Wifi locator setting locked ++ Bits 16-31: Reserved ++*/ ++ ++static int dell_rfkill_set(void *data, bool blocked) ++{ ++ int disable = blocked ? 1 : 0; ++ unsigned long radio = (unsigned long)data; ++ int hwswitch_bit = (unsigned long)data - 1; ++ int ret = 0; ++ ++ get_buffer(); ++ dell_send_request(buffer, 17, 11); ++ ++ /* If the hardware switch controls this radio, and the hardware ++ switch is disabled, don't allow changing the software state */ ++ if ((hwswitch_state & BIT(hwswitch_bit)) && ++ !(buffer->output[1] & BIT(16))) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ buffer->input[0] = (1 | (radio<<8) | (disable << 16)); ++ dell_send_request(buffer, 17, 11); ++ ++out: ++ release_buffer(); ++ return ret; ++} ++ ++static void dell_rfkill_query(struct rfkill *rfkill, void *data) ++{ ++ int status; ++ int bit = (unsigned long)data + 16; ++ int hwswitch_bit = (unsigned long)data - 1; ++ ++ get_buffer(); ++ dell_send_request(buffer, 17, 11); ++ status = buffer->output[1]; ++ release_buffer(); ++ ++ rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); ++ ++ if (hwswitch_state & (BIT(hwswitch_bit))) ++ rfkill_set_hw_state(rfkill, !(status & BIT(16))); ++} ++ ++static const struct rfkill_ops dell_rfkill_ops = { ++ .set_block = dell_rfkill_set, ++ .query = dell_rfkill_query, ++}; ++ + static struct dentry *dell_laptop_dir; + + static int dell_debugfs_show(struct seq_file *s, void *data) +@@ -424,6 +563,108 @@ static const struct file_operations dell_debugfs_fops = { + .release = single_release, + }; + ++static void dell_update_rfkill(struct work_struct *ignored) ++{ ++ if (wifi_rfkill) ++ dell_rfkill_query(wifi_rfkill, (void *)1); ++ if (bluetooth_rfkill) ++ dell_rfkill_query(bluetooth_rfkill, (void *)2); ++ if (wwan_rfkill) ++ dell_rfkill_query(wwan_rfkill, (void *)3); ++} ++static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); ++ ++ ++static int __init dell_setup_rfkill(void) ++{ ++ int status; ++ int ret; ++ ++ if (dmi_check_system(dell_blacklist)) { ++ pr_info("Blacklisted hardware detected - not enabling rfkill\n"); ++ return 0; ++ } ++ ++ get_buffer(); ++ dell_send_request(buffer, 17, 11); ++ status = buffer->output[1]; ++ buffer->input[0] = 0x2; ++ dell_send_request(buffer, 17, 11); ++ hwswitch_state = buffer->output[1]; ++ release_buffer(); ++ ++ if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { ++ wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, ++ RFKILL_TYPE_WLAN, ++ &dell_rfkill_ops, (void *) 1); ++ if (!wifi_rfkill) { ++ ret = -ENOMEM; ++ goto err_wifi; ++ } ++ ret = rfkill_register(wifi_rfkill); ++ if (ret) ++ goto err_wifi; ++ } ++ ++ if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { ++ bluetooth_rfkill = rfkill_alloc("dell-bluetooth", ++ &platform_device->dev, ++ RFKILL_TYPE_BLUETOOTH, ++ &dell_rfkill_ops, (void *) 2); ++ if (!bluetooth_rfkill) { ++ ret = -ENOMEM; ++ goto err_bluetooth; ++ } ++ ret = rfkill_register(bluetooth_rfkill); ++ if (ret) ++ goto err_bluetooth; ++ } ++ ++ if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { ++ wwan_rfkill = rfkill_alloc("dell-wwan", ++ &platform_device->dev, ++ RFKILL_TYPE_WWAN, ++ &dell_rfkill_ops, (void *) 3); ++ if (!wwan_rfkill) { ++ ret = -ENOMEM; ++ goto err_wwan; ++ } ++ ret = rfkill_register(wwan_rfkill); ++ if (ret) ++ goto err_wwan; ++ } ++ ++ return 0; ++err_wwan: ++ rfkill_destroy(wwan_rfkill); ++ if (bluetooth_rfkill) ++ rfkill_unregister(bluetooth_rfkill); ++err_bluetooth: ++ rfkill_destroy(bluetooth_rfkill); ++ if (wifi_rfkill) ++ rfkill_unregister(wifi_rfkill); ++err_wifi: ++ rfkill_destroy(wifi_rfkill); ++ ++ return ret; ++} ++ ++static void dell_cleanup_rfkill(void) ++{ ++ if (wifi_rfkill) { ++ rfkill_unregister(wifi_rfkill); ++ rfkill_destroy(wifi_rfkill); ++ } ++ if (bluetooth_rfkill) { ++ rfkill_unregister(bluetooth_rfkill); ++ rfkill_destroy(bluetooth_rfkill); ++ } ++ if (wwan_rfkill) { ++ rfkill_unregister(wwan_rfkill); ++ rfkill_destroy(wwan_rfkill); ++ } ++} ++ + static int dell_send_intensity(struct backlight_device *bd) + { + int ret = 0; +@@ -515,6 +756,30 @@ static void touchpad_led_exit(void) + led_classdev_unregister(&touchpad_led); + } + ++static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, ++ struct serio *port) ++{ ++ static bool extended; ++ ++ if (str & 0x20) ++ return false; ++ ++ if (unlikely(data == 0xe0)) { ++ extended = true; ++ return false; ++ } else if (unlikely(extended)) { ++ switch (data) { ++ case 0x8: ++ schedule_delayed_work(&dell_rfkill_work, ++ round_jiffies_relative(HZ)); ++ break; ++ } ++ extended = false; ++ } ++ ++ return false; ++} ++ + static int __init dell_init(void) + { + int max_intensity = 0; +@@ -557,10 +822,26 @@ static int __init dell_init(void) + } + buffer = page_address(bufferpage); + ++ ret = dell_setup_rfkill(); ++ ++ if (ret) { ++ pr_warn("Unable to setup rfkill\n"); ++ goto fail_rfkill; ++ } ++ ++ ret = i8042_install_filter(dell_laptop_i8042_filter); ++ if (ret) { ++ pr_warn("Unable to install key filter\n"); ++ goto fail_filter; ++ } ++ + if (quirks && quirks->touchpad_led) + touchpad_led_init(&platform_device->dev); + + dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); ++ if (dell_laptop_dir != NULL) ++ debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL, ++ &dell_debugfs_fops); + + #ifdef CONFIG_ACPI + /* In the event of an ACPI backlight being available, don't +@@ -603,6 +884,11 @@ static int __init dell_init(void) + return 0; + + fail_backlight: ++ i8042_remove_filter(dell_laptop_i8042_filter); ++ cancel_delayed_work_sync(&dell_rfkill_work); ++fail_filter: ++ dell_cleanup_rfkill(); ++fail_rfkill: + free_page((unsigned long)bufferpage); + fail_buffer: + platform_device_del(platform_device); +@@ -620,7 +906,10 @@ static void __exit dell_exit(void) + debugfs_remove_recursive(dell_laptop_dir); + if (quirks && quirks->touchpad_led) + touchpad_led_exit(); ++ i8042_remove_filter(dell_laptop_i8042_filter); ++ cancel_delayed_work_sync(&dell_rfkill_work); + backlight_device_unregister(dell_backlight_device); ++ dell_cleanup_rfkill(); + if (platform_device) { + platform_device_unregister(platform_device); + platform_driver_unregister(&platform_driver); +-- +1.8.3.1 + diff --git a/0002-dell-laptop-Only-enable-rfkill-on-Latitudes.patch b/0002-dell-laptop-Only-enable-rfkill-on-Latitudes.patch new file mode 100644 index 0000000..5a80e28 --- /dev/null +++ b/0002-dell-laptop-Only-enable-rfkill-on-Latitudes.patch @@ -0,0 +1,104 @@ +Bugzilla: 958826 +Upstream-status: 3.13 + +From 2a92551845bbbc8421ba908cd14bbdf065e0f454 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 17 Nov 2013 14:00:17 +0100 +Subject: [PATCH 2/2] dell-laptop: Only enable rfkill on Latitudes + +The rfkill functionality was removed from the dell-laptop driver because it +was causing problems on various non Latitude models, and the blacklist kept +growing and growing. In the thread discussing this Dell mentioned that they +only QA the rfkill acpi interface on Latitudes and indeed there have been +no blacklist entries for Latitudes. + +Note that the blacklist contained no Vostros either, and most Vostros have +a hardware switch too, so we could consider supporting Vostros with a +hardware switch too. + +Signed-off-by: Hans de Goede +Signed-off-by: Matthew Garrett +--- + drivers/platform/x86/dell-laptop.c | 57 +++++--------------------------------- + 1 file changed, 7 insertions(+), 50 deletions(-) + +diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c +index 55f75a2..bae932b 100644 +--- a/drivers/platform/x86/dell-laptop.c ++++ b/drivers/platform/x86/dell-laptop.c +@@ -119,53 +119,6 @@ static const struct dmi_system_id dell_device_table[] __initconst = { + }; + MODULE_DEVICE_TABLE(dmi, dell_device_table); + +-static struct dmi_system_id dell_blacklist[] = { +- /* Supported by compal-laptop */ +- { +- .ident = "Dell Mini 9", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"), +- }, +- }, +- { +- .ident = "Dell Mini 10", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"), +- }, +- }, +- { +- .ident = "Dell Mini 10v", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"), +- }, +- }, +- { +- .ident = "Dell Mini 1012", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), +- }, +- }, +- { +- .ident = "Dell Inspiron 11z", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"), +- }, +- }, +- { +- .ident = "Dell Mini 12", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"), +- }, +- }, +- {} +-}; +- + static struct dmi_system_id dell_quirks[] = { + { + .callback = dmi_matched, +@@ -579,11 +532,15 @@ static int __init dell_setup_rfkill(void) + { + int status; + int ret; ++ const char *product; + +- if (dmi_check_system(dell_blacklist)) { +- pr_info("Blacklisted hardware detected - not enabling rfkill\n"); ++ /* ++ * rfkill causes trouble on various non Latitudes, according to Dell ++ * actually testing the rfkill functionality is only done on Latitudes. ++ */ ++ product = dmi_get_system_info(DMI_PRODUCT_NAME); ++ if (!product || strncmp(product, "Latitude", 8)) + return 0; +- } + + get_buffer(); + dell_send_request(buffer, 17, 11); +-- +1.8.3.1 + diff --git a/kernel.spec b/kernel.spec index 6c7fc75..f6dfbb1 100644 --- a/kernel.spec +++ b/kernel.spec @@ -820,6 +820,10 @@ Patch25159: usbnet-fix-status-interrupt-urb-handling.patch Patch25161: inet-prevent-leakage-of-uninitialized-memory-to-user.patch Patch25162: inet-fix-addr_len-msg_namelen-assignment-in-recv_error-and-rxpmtu-functions.patch +#rhbz 958826 +Patch25164: 0001-Revert-dell-laptop-Remove-rfkill-code.patch +Patch25165: 0002-dell-laptop-Only-enable-rfkill-on-Latitudes.patch + # END OF PATCH DEFINITIONS %endif @@ -1577,6 +1581,10 @@ ApplyPatch usbnet-fix-status-interrupt-urb-handling.patch ApplyPatch inet-prevent-leakage-of-uninitialized-memory-to-user.patch ApplyPatch inet-fix-addr_len-msg_namelen-assignment-in-recv_error-and-rxpmtu-functions.patch +#rhbz 958826 +ApplyPatch 0001-Revert-dell-laptop-Remove-rfkill-code.patch +ApplyPatch 0002-dell-laptop-Only-enable-rfkill-on-Latitudes.patch + # END OF PATCH APPLICATIONS %endif @@ -2418,6 +2426,9 @@ fi # ||----w | # || || %changelog +* Tue Dec 03 2013 Josh Boyer +- Add patches to fix rfkill switch on Dell machines (rhbz 958826) + * Sat Nov 30 2013 Josh Boyer - CVE-2013-6405 net: leak of uninited mem to userspace via recv syscalls (rhbz 1035875 1035887)