]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 23 Nov 2013 00:47:28 +0000 (16:47 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 23 Nov 2013 00:47:28 +0000 (16:47 -0800)
Pull x86 platform driver updates from Matthew Garrett:
 "A moderate diffstat, but it's almost entirely just moving the
  chromebook driver into its own directory in order to ease ARM support,
  adding back rfkill support to the one Dell laptop model where it's
  expected to work, updates to the Intel IPC driver for hardware I've
  never actually seen and the usual set of small fixes"

[ This actually came in before the merge window closed, and I had just
  missed it because it didn't match my git pull email pattern.  - Linus ]

* 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: (24 commits)
  x86, wmi fix modalias_show return values
  ipc: Added support for IPC interrupt mode
  ipc: Handle error conditions in ipc command
  ipc: Enabled ipc support for additional intel platforms
  ipc: Added platform data structure
  thinkpad_acpi: Fix build error when CONFIG_SND_MAX_CARDS > 32
  platform: add chrome platform directory
  hp-wmi: detect "2009 BIOS or later" flag by WMI 0x0d for wireless cmd
  dell-wmi: Add KEY_MICMUTE to bios_to_linux_keycode
  platform:x86: Remove OOM message after input_allocate_device
  sony-laptop: fixe typos in sony_laptop_input_keycode_map
  sony-laptop: warn on multiple KBD backlight handles
  dell-laptop: Only enable rfkill functionality on laptops with a hw killswitch
  dell-laptop: Add a force_rfkill module parameter
  dell-laptop: Wait less long before updating rfkill after an rfkill keypress
  dell-laptop: Do not skip setting blocked bit rfkill_set while hw-blocked
  dell-laptop: Sync current block state to BIOS on hw switch change
  dell-laptop: Allow changing the sw_state while the radio is blocked by hw
  dell-laptop: Don't read-back sw_state on machines with a hardware switch
  dell-laptop: Don't set sw_state from the query callback
  ...

22 files changed:
MAINTAINERS
drivers/platform/Kconfig
drivers/platform/Makefile
drivers/platform/chrome/Kconfig [new file with mode: 0644]
drivers/platform/chrome/Makefile [new file with mode: 0644]
drivers/platform/chrome/chromeos_laptop.c [moved from drivers/platform/x86/chromeos_laptop.c with 100% similarity]
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-wmi.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_mid_powerbtn.c
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/topstar-laptop.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/wmi.c

index 8285ed4676b6388502be84ddde71d1e201827ce8..f216db8470227446313fc15b75b8501835bd6cf4 100644 (file)
@@ -2142,6 +2142,11 @@ L:       linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/chipidea/
 
+CHROME HARDWARE PLATFORM SUPPORT
+M:     Olof Johansson <olof@lixom.net>
+S:     Maintained
+F:     drivers/platform/chrome/
+
 CISCO VIC ETHERNET NIC DRIVER
 M:     Christian Benvenuti <benve@cisco.com>
 M:     Sujith Sankar <ssujith@cisco.com>
index 69616aeaa966218efa16eb3858324107e816e7bf..09fde58b12e0fa1e2446d56218fa644f32aeeef1 100644 (file)
@@ -5,3 +5,4 @@ if GOLDFISH
 source "drivers/platform/goldfish/Kconfig"
 endif
 
+source "drivers/platform/chrome/Kconfig"
index 8a44a4cd6d1efc30789d5da4cc392447695d68ae..3656b7b17b99ee8ecc806fd21f3fa493873ff122 100644 (file)
@@ -5,3 +5,4 @@
 obj-$(CONFIG_X86)              += x86/
 obj-$(CONFIG_OLPC)             += olpc/
 obj-$(CONFIG_GOLDFISH)         += goldfish/
+obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
new file mode 100644 (file)
index 0000000..b13303e
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# Platform support for Chrome OS hardware (Chromebooks and Chromeboxes)
+#
+
+menuconfig CHROME_PLATFORMS
+       bool "Platform support for Chrome hardware"
+       depends on X86
+       ---help---
+         Say Y here to get to see options for platform support for
+         various Chromebooks and Chromeboxes. This option alone does
+         not add any kernel code.
+
+         If you say N, all options in this submenu will be skipped and disabled.
+
+if CHROME_PLATFORMS
+
+config CHROMEOS_LAPTOP
+       tristate "Chrome OS Laptop"
+       depends on I2C
+       depends on DMI
+       ---help---
+         This driver instantiates i2c and smbus devices such as
+         light sensors and touchpads.
+
+         If you have a supported Chromebook, choose Y or M here.
+         The module will be called chromeos_laptop.
+
+endif # CHROMEOS_PLATFORMS
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
new file mode 100644 (file)
index 0000000..015e919
--- /dev/null
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_CHROMEOS_LAPTOP)  += chromeos_laptop.o
index b51a7460cc49bc03b4c055e8f46bfe2fedf718ff..d9dcd37b5a521e86baf54702ff96f91657037aff 100644 (file)
@@ -79,17 +79,6 @@ config ASUS_LAPTOP
 
          If you have an ACPI-compatible ASUS laptop, say Y or M here.
 
-config CHROMEOS_LAPTOP
-       tristate "Chrome OS Laptop"
-       depends on I2C
-       depends on DMI
-       ---help---
-         This driver instantiates i2c and smbus devices such as
-         light sensors and touchpads.
-
-         If you have a supported Chromebook, choose Y or M here.
-         The module will be called chromeos_laptop.
-
 config DELL_LAPTOP
        tristate "Dell Laptop Extras"
        depends on X86
index 5dbe193243510a94db296ba690ded6fa1af768e5..f0e6aa407ffb9ee8786e7aa71f5c76ed00ec6d81 100644 (file)
@@ -50,7 +50,6 @@ obj-$(CONFIG_INTEL_MID_POWER_BUTTON)  += intel_mid_powerbtn.o
 obj-$(CONFIG_INTEL_OAKTRAIL)   += intel_oaktrail.o
 obj-$(CONFIG_SAMSUNG_Q10)      += samsung-q10.o
 obj-$(CONFIG_APPLE_GMUX)       += apple-gmux.o
-obj-$(CONFIG_CHROMEOS_LAPTOP)  += chromeos_laptop.o
 obj-$(CONFIG_INTEL_RST)                += intel-rst.o
 obj-$(CONFIG_INTEL_SMARTCONNECT)       += intel-smartconnect.o
 
index 0e9c169b42f82a782b1166b2c05880ad4e1ad0da..594323a926cf0b8c62c4accfd88d297fe0caa567 100644 (file)
@@ -1494,10 +1494,9 @@ static int asus_input_init(struct asus_laptop *asus)
        int error;
 
        input = input_allocate_device();
-       if (!input) {
-               pr_warn("Unable to allocate input device\n");
+       if (!input)
                return -ENOMEM;
-       }
+
        input->name = "Asus Laptop extra buttons";
        input->phys = ASUS_LAPTOP_FILE "/input0";
        input->id.bustype = BUS_HOST;
index bb77e18b3dd4d5a8ce882f883dddbd98a28e037f..c608b1d33f4a60893a3bdc87b52773f872259f6d 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/err.h>
 #include <linux/dmi.h>
 #include <linux/io.h>
+#include <linux/rfkill.h>
 #include <linux/power_supply.h>
 #include <linux/acpi.h>
 #include <linux/mm.h>
@@ -89,6 +90,13 @@ 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 bool force_rfkill;
+
+module_param(force_rfkill, bool, 0444);
+MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models");
 
 static const struct dmi_system_id dell_device_table[] __initconst = {
        {
@@ -355,6 +363,108 @@ 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;
+
+       get_buffer();
+       dell_send_request(buffer, 17, 11);
+
+       /* If the hardware switch controls this radio, and the hardware
+          switch is disabled, always disable the radio */
+       if ((hwswitch_state & BIT(hwswitch_bit)) &&
+           !(buffer->output[1] & BIT(16)))
+               disable = 1;
+
+       buffer->input[0] = (1 | (radio<<8) | (disable << 16));
+       dell_send_request(buffer, 17, 11);
+
+       release_buffer();
+       return 0;
+}
+
+/* Must be called with the buffer held */
+static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
+                                       int status)
+{
+       if (status & BIT(0)) {
+               /* Has hw-switch, sync sw_state to BIOS */
+               int block = rfkill_blocked(rfkill);
+               buffer->input[0] = (1 | (radio << 8) | (block << 16));
+               dell_send_request(buffer, 17, 11);
+       } else {
+               /* No hw-switch, sync BIOS state to sw_state */
+               rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
+       }
+}
+
+static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio,
+                                       int status)
+{
+       if (hwswitch_state & (BIT(radio - 1)))
+               rfkill_set_hw_state(rfkill, !(status & BIT(16)));
+}
+
+static void dell_rfkill_query(struct rfkill *rfkill, void *data)
+{
+       int status;
+
+       get_buffer();
+       dell_send_request(buffer, 17, 11);
+       status = buffer->output[1];
+
+       dell_rfkill_update_hw_state(rfkill, (unsigned long)data, status);
+
+       release_buffer();
+}
+
+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 +534,136 @@ static const struct file_operations dell_debugfs_fops = {
        .release = single_release,
 };
 
+static void dell_update_rfkill(struct work_struct *ignored)
+{
+       int status;
+
+       get_buffer();
+       dell_send_request(buffer, 17, 11);
+       status = buffer->output[1];
+
+       if (wifi_rfkill) {
+               dell_rfkill_update_hw_state(wifi_rfkill, 1, status);
+               dell_rfkill_update_sw_state(wifi_rfkill, 1, status);
+       }
+       if (bluetooth_rfkill) {
+               dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status);
+               dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status);
+       }
+       if (wwan_rfkill) {
+               dell_rfkill_update_hw_state(wwan_rfkill, 3, status);
+               dell_rfkill_update_sw_state(wwan_rfkill, 3, status);
+       }
+
+       release_buffer();
+}
+static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
+
+
+static int __init dell_setup_rfkill(void)
+{
+       int status;
+       int ret;
+       const char *product;
+
+       /*
+        * 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 (!force_rfkill && (!product || strncmp(product, "Latitude", 8)))
+               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 & BIT(0))) {
+               if (force_rfkill) {
+                       /* No hwsitch, clear all hw-controlled bits */
+                       hwswitch_state &= ~7;
+               } else {
+                       /* rfkill is only tested on laptops with a hwswitch */
+                       return 0;
+               }
+       }
+
+       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 +755,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 / 4));
+                       break;
+               }
+               extended = false;
+       }
+
+       return false;
+}
+
 static int __init dell_init(void)
 {
        int max_intensity = 0;
@@ -557,10 +821,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 +883,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 +905,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);
index fa9a2171cc134b733c837f89a4f1b80aeb0989ea..60e0900bc117995e6373bfb5bedfcc1c8aac2aed 100644 (file)
@@ -130,7 +130,8 @@ static const u16 bios_to_linux_keycode[256] __initconst = {
        KEY_BRIGHTNESSUP,       KEY_UNKNOWN,    KEY_KBDILLUMTOGGLE,
        KEY_UNKNOWN,    KEY_SWITCHVIDEOMODE,    KEY_UNKNOWN, KEY_UNKNOWN,
        KEY_SWITCHVIDEOMODE,    KEY_UNKNOWN,    KEY_UNKNOWN, KEY_PROG2,
-       KEY_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       KEY_UNKNOWN,    KEY_UNKNOWN,    KEY_UNKNOWN,    KEY_UNKNOWN,
+       KEY_UNKNOWN,    KEY_UNKNOWN,    KEY_UNKNOWN,    KEY_MICMUTE,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -139,8 +140,8 @@ static const u16 bios_to_linux_keycode[256] __initconst = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       KEY_PROG3
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_PROG3
 };
 
 static struct input_dev *dell_wmi_input_dev;
index aefcc32e563479d2b22404fdd75ceb7072423d16..dec68e7a99c79482f5f7cf4eb78b98bd0e2cd58d 100644 (file)
@@ -1203,10 +1203,8 @@ static int eeepc_input_init(struct eeepc_laptop *eeepc)
        int error;
 
        input = input_allocate_device();
-       if (!input) {
-               pr_info("Unable to allocate input device\n");
+       if (!input)
                return -ENOMEM;
-       }
 
        input->name = "Asus EeePC extra buttons";
        input->phys = EEEPC_LAPTOP_FILE "/input0";
index 1c86fa0857c8eb73dfb64ec90ee9e7f7e50404c3..8ba8956b5a48f7f1fccc37df42cdaf4772892209 100644 (file)
@@ -54,6 +54,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
 #define HPWMI_HARDWARE_QUERY 0x4
 #define HPWMI_WIRELESS_QUERY 0x5
 #define HPWMI_HOTKEY_QUERY 0xc
+#define HPWMI_FEATURE_QUERY 0xd
 #define HPWMI_WIRELESS2_QUERY 0x1b
 #define HPWMI_POSTCODEERROR_QUERY 0x2a
 
@@ -292,6 +293,17 @@ static int hp_wmi_tablet_state(void)
        return (state & 0x4) ? 1 : 0;
 }
 
+static int hp_wmi_bios_2009_later(void)
+{
+       int state = 0;
+       int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state,
+                                      sizeof(state), sizeof(state));
+       if (ret)
+               return ret;
+
+       return (state & 0x10) ? 1 : 0;
+}
+
 static int hp_wmi_set_block(void *data, bool blocked)
 {
        enum hp_wmi_radio r = (enum hp_wmi_radio) data;
@@ -871,7 +883,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
        gps_rfkill = NULL;
        rfkill2_count = 0;
 
-       if (hp_wmi_rfkill_setup(device))
+       if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device))
                hp_wmi_rfkill2_setup(device);
 
        err = device_create_file(&device->dev, &dev_attr_display);
index 6788acc22ab97f01b410240eef0a5b2082c98550..19ec95147f6925d1de52e99886f7efc6a10dff7a 100644 (file)
@@ -570,10 +570,8 @@ static int ideapad_input_init(struct ideapad_private *priv)
        int error;
 
        inputdev = input_allocate_device();
-       if (!inputdev) {
-               pr_info("Unable to allocate input device\n");
+       if (!inputdev)
                return -ENOMEM;
-       }
 
        inputdev->name = "Ideapad extra buttons";
        inputdev->phys = "ideapad/input0";
index 6b18aba82cfae450bde3cad8fd2b2d01f20b3d03..8d6775266d66263bac3bdd45d7a5f580e598731e 100644 (file)
@@ -66,10 +66,8 @@ static int mfld_pb_probe(struct platform_device *pdev)
                return -EINVAL;
 
        input = input_allocate_device();
-       if (!input) {
-               dev_err(&pdev->dev, "Input device allocation error\n");
+       if (!input)
                return -ENOMEM;
-       }
 
        input->name = pdev->name;
        input->phys = "power-button/input0";
index d654f831410de9621df488aadbca2d6c6d174721..60ea476a91305c8f357f1950064cee54e92f0f29 100644 (file)
  *    message handler is called within firmware.
  */
 
-#define IPC_BASE_ADDR     0xFF11C000   /* IPC1 base register address */
-#define IPC_MAX_ADDR      0x100                /* Maximum IPC regisers */
 #define IPC_WWBUF_SIZE    20           /* IPC Write buffer Size */
 #define IPC_RWBUF_SIZE    20           /* IPC Read buffer Size */
-#define IPC_I2C_BASE      0xFF12B000   /* I2C control register base address */
-#define IPC_I2C_MAX_ADDR  0x10         /* Maximum I2C regisers */
+#define IPC_IOC                  0x100         /* IPC command register IOC bit */
+
+enum {
+       SCU_IPC_LINCROFT,
+       SCU_IPC_PENWELL,
+       SCU_IPC_CLOVERVIEW,
+       SCU_IPC_TANGIER,
+};
+
+/* intel scu ipc driver data*/
+struct intel_scu_ipc_pdata_t {
+       u32 ipc_base;
+       u32 i2c_base;
+       u32 ipc_len;
+       u32 i2c_len;
+       u8 irq_mode;
+};
+
+static struct intel_scu_ipc_pdata_t intel_scu_ipc_pdata[] = {
+       [SCU_IPC_LINCROFT] = {
+               .ipc_base = 0xff11c000,
+               .i2c_base = 0xff12b000,
+               .ipc_len = 0x100,
+               .i2c_len = 0x10,
+               .irq_mode = 0,
+       },
+       [SCU_IPC_PENWELL] = {
+               .ipc_base = 0xff11c000,
+               .i2c_base = 0xff12b000,
+               .ipc_len = 0x100,
+               .i2c_len = 0x10,
+               .irq_mode = 1,
+       },
+       [SCU_IPC_CLOVERVIEW] = {
+               .ipc_base = 0xff11c000,
+               .i2c_base = 0xff12b000,
+               .ipc_len = 0x100,
+               .i2c_len = 0x10,
+               .irq_mode = 1,
+       },
+       [SCU_IPC_TANGIER] = {
+               .ipc_base = 0xff009000,
+               .i2c_base  = 0xff00d000,
+               .ipc_len  = 0x100,
+               .i2c_len = 0x10,
+               .irq_mode = 0,
+       },
+};
 
 static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id);
 static void ipc_remove(struct pci_dev *pdev);
@@ -72,6 +116,8 @@ struct intel_scu_ipc_dev {
        struct pci_dev *pdev;
        void __iomem *ipc_base;
        void __iomem *i2c_base;
+       struct completion cmd_complete;
+       u8 irq_mode;
 };
 
 static struct intel_scu_ipc_dev  ipcdev; /* Only one for now */
@@ -98,6 +144,10 @@ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
  */
 static inline void ipc_command(u32 cmd) /* Send ipc command */
 {
+       if (ipcdev.irq_mode) {
+               reinit_completion(&ipcdev.cmd_complete);
+               writel(cmd | IPC_IOC, ipcdev.ipc_base);
+       }
        writel(cmd, ipcdev.ipc_base);
 }
 
@@ -156,6 +206,30 @@ static inline int busy_loop(void) /* Wait till scu status is busy */
        return 0;
 }
 
+/* Wait till ipc ioc interrupt is received or timeout in 3 HZ */
+static inline int ipc_wait_for_interrupt(void)
+{
+       int status;
+
+       if (!wait_for_completion_timeout(&ipcdev.cmd_complete, 3 * HZ)) {
+               struct device *dev = &ipcdev.pdev->dev;
+               dev_err(dev, "IPC timed out\n");
+               return -ETIMEDOUT;
+       }
+
+       status = ipc_read_status();
+
+       if ((status >> 1) & 1)
+               return -EIO;
+
+       return 0;
+}
+
+int intel_scu_ipc_check_status(void)
+{
+       return ipcdev.irq_mode ? ipc_wait_for_interrupt() : busy_loop();
+}
+
 /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
 static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 {
@@ -196,8 +270,8 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
                ipc_command(4 << 16 |  id << 12 | 0 << 8 | op);
        }
 
-       err = busy_loop();
-       if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
+       err = intel_scu_ipc_check_status();
+       if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
                /* Workaround: values are read as 0 without memcpy_fromio */
                memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16);
                for (nc = 0; nc < count; nc++)
@@ -391,7 +465,7 @@ int intel_scu_ipc_simple_command(int cmd, int sub)
                return -ENODEV;
        }
        ipc_command(sub << 12 | cmd);
-       err = busy_loop();
+       err = intel_scu_ipc_check_status();
        mutex_unlock(&ipclock);
        return err;
 }
@@ -425,10 +499,12 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
                ipc_data_writel(*in++, 4 * i);
 
        ipc_command((inlen << 16) | (sub << 12) | cmd);
-       err = busy_loop();
+       err = intel_scu_ipc_check_status();
 
-       for (i = 0; i < outlen; i++)
-               *out++ = ipc_data_readl(4 * i);
+       if (!err) {
+               for (i = 0; i < outlen; i++)
+                       *out++ = ipc_data_readl(4 * i);
+       }
 
        mutex_unlock(&ipclock);
        return err;
@@ -491,6 +567,9 @@ EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
  */
 static irqreturn_t ioc(int irq, void *dev_id)
 {
+       if (ipcdev.irq_mode)
+               complete(&ipcdev.cmd_complete);
+
        return IRQ_HANDLED;
 }
 
@@ -504,13 +583,18 @@ static irqreturn_t ioc(int irq, void *dev_id)
  */
 static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       int err;
+       int err, pid;
+       struct intel_scu_ipc_pdata_t *pdata;
        resource_size_t pci_resource;
 
        if (ipcdev.pdev)                /* We support only one SCU */
                return -EBUSY;
 
+       pid = id->driver_data;
+       pdata = &intel_scu_ipc_pdata[pid];
+
        ipcdev.pdev = pci_dev_get(dev);
+       ipcdev.irq_mode = pdata->irq_mode;
 
        err = pci_enable_device(dev);
        if (err)
@@ -524,14 +608,16 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if (!pci_resource)
                return -ENOMEM;
 
+       init_completion(&ipcdev.cmd_complete);
+
        if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev))
                return -EBUSY;
 
-       ipcdev.ipc_base = ioremap_nocache(IPC_BASE_ADDR, IPC_MAX_ADDR);
+       ipcdev.ipc_base = ioremap_nocache(pdata->ipc_base, pdata->ipc_len);
        if (!ipcdev.ipc_base)
                return -ENOMEM;
 
-       ipcdev.i2c_base = ioremap_nocache(IPC_I2C_BASE, IPC_I2C_MAX_ADDR);
+       ipcdev.i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len);
        if (!ipcdev.i2c_base) {
                iounmap(ipcdev.ipc_base);
                return -ENOMEM;
@@ -564,7 +650,10 @@ static void ipc_remove(struct pci_dev *pdev)
 }
 
 static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},
+       {PCI_VDEVICE(INTEL, 0x082a), SCU_IPC_LINCROFT},
+       {PCI_VDEVICE(INTEL, 0x080e), SCU_IPC_PENWELL},
+       {PCI_VDEVICE(INTEL, 0x08ea), SCU_IPC_CLOVERVIEW},
+       {PCI_VDEVICE(INTEL, 0x11a0), SCU_IPC_TANGIER},
        { 0,}
 };
 MODULE_DEVICE_TABLE(pci, pci_ids);
index 10d12b221601ddae853fe3b0e8554d99d0c5ef06..3008fd20572e96a2d93823c4d15db27592fed2e2 100644 (file)
@@ -490,11 +490,8 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc)
        int error;
 
        input_dev = input_allocate_device();
-       if (!input_dev) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "Couldn't allocate input device for hotkey"));
+       if (!input_dev)
                return -ENOMEM;
-       }
 
        input_dev->name = ACPI_PCC_DRIVER_NAME;
        input_dev->phys = ACPI_PCC_INPUT_PHYS;
index 47caab0ea7a14faa1051b35eafe1ff8e53703ee0..c45c60f7ea2fd3696a51e7c4959b1e1c2a27dbcb 100644 (file)
@@ -145,7 +145,8 @@ static void sony_nc_thermal_resume(void);
 #endif
 static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
                unsigned int handle);
-static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
+static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd,
+               unsigned int handle);
 
 static int sony_nc_battery_care_setup(struct platform_device *pd,
                unsigned int handle);
@@ -304,8 +305,8 @@ static int sony_laptop_input_keycode_map[] = {
        KEY_FN_F10,     /* 14 SONYPI_EVENT_FNKEY_F10 */
        KEY_FN_F11,     /* 15 SONYPI_EVENT_FNKEY_F11 */
        KEY_FN_F12,     /* 16 SONYPI_EVENT_FNKEY_F12 */
-       KEY_FN_F1,      /* 17 SONYPI_EVENT_FNKEY_1 */
-       KEY_FN_F2,      /* 18 SONYPI_EVENT_FNKEY_2 */
+       KEY_FN_1,       /* 17 SONYPI_EVENT_FNKEY_1 */
+       KEY_FN_2,       /* 18 SONYPI_EVENT_FNKEY_2 */
        KEY_FN_D,       /* 19 SONYPI_EVENT_FNKEY_D */
        KEY_FN_E,       /* 20 SONYPI_EVENT_FNKEY_E */
        KEY_FN_F,       /* 21 SONYPI_EVENT_FNKEY_F */
@@ -1444,7 +1445,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
                case 0x014b:
                case 0x014c:
                case 0x0163:
-                       sony_nc_kbd_backlight_cleanup(pd);
+                       sony_nc_kbd_backlight_cleanup(pd, handle);
                        break;
                default:
                        continue;
@@ -1822,6 +1823,12 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
        int result;
        int ret = 0;
 
+       if (kbdbl_ctl) {
+               pr_warn("handle 0x%.4x: keyboard backlight setup already done for 0x%.4x\n",
+                               handle, kbdbl_ctl->handle);
+               return -EBUSY;
+       }
+
        /* verify the kbd backlight presence, these handles are not used for
         * keyboard backlight only
         */
@@ -1881,9 +1888,10 @@ outkzalloc:
        return ret;
 }
 
-static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
+static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd,
+               unsigned int handle)
 {
-       if (kbdbl_ctl) {
+       if (kbdbl_ctl && handle == kbdbl_ctl->handle) {
                device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
                device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr);
                kfree(kbdbl_ctl);
index 05e046aa5e314be112b0e165f93fd82c6ab16fe5..58b0274d24cc2968e35e6a9cdad75b1533c35e2d 100644 (file)
@@ -6438,7 +6438,12 @@ static struct ibm_struct brightness_driver_data = {
 #define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control"
 #define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME
 
-static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */
+#if SNDRV_CARDS <= 32
+#define DEFAULT_ALSA_IDX               ~((1 << (SNDRV_CARDS - 3)) - 1)
+#else
+#define DEFAULT_ALSA_IDX               ~((1 << (32 - 3)) - 1)
+#endif
+static int alsa_index = DEFAULT_ALSA_IDX; /* last three slots */
 static char *alsa_id = "ThinkPadEC";
 static bool alsa_enable = SNDRV_DEFAULT_ENABLE1;
 
@@ -9163,7 +9168,6 @@ static int __init thinkpad_acpi_module_init(void)
        mutex_init(&tpacpi_inputdev_send_mutex);
        tpacpi_inputdev = input_allocate_device();
        if (!tpacpi_inputdev) {
-               pr_err("unable to allocate input device\n");
                thinkpad_acpi_module_exit();
                return -ENOMEM;
        } else {
index 67897c8740ba58ea3c93cf54b0a2a3e74a1e3a84..e597de05e6c27badfe97ea533ddb2f7a6c41d3b5 100644 (file)
@@ -97,10 +97,8 @@ static int acpi_topstar_init_hkey(struct topstar_hkey *hkey)
        int error;
 
        input = input_allocate_device();
-       if (!input) {
-               pr_err("Unable to allocate input device\n");
+       if (!input)
                return -ENOMEM;
-       }
 
        input->name = "Topstar Laptop extra buttons";
        input->phys = "topstar/input0";
index 0cfadb65f7c639597abce1d1bcb81ba3a04ff1d3..7fce391818d30a183962b7888a8bfd275b10423c 100644 (file)
@@ -975,10 +975,8 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
        u32 hci_result;
 
        dev->hotkey_dev = input_allocate_device();
-       if (!dev->hotkey_dev) {
-               pr_info("Unable to register input device\n");
+       if (!dev->hotkey_dev)
                return -ENOMEM;
-       }
 
        dev->hotkey_dev->name = "Toshiba input device";
        dev->hotkey_dev->phys = "toshiba_acpi/input0";
index 62e8c221d01ea10a5f105a0a44b2d2d8277d7878..c2e7b2657aeb31bf5ab50a4f8a8821e2ad53f696 100644 (file)
@@ -672,8 +672,10 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
        struct wmi_block *wblock;
 
        wblock = dev_get_drvdata(dev);
-       if (!wblock)
-               return -ENOMEM;
+       if (!wblock) {
+               strcat(buf, "\n");
+               return strlen(buf);
+       }
 
        wmi_gtoa(wblock->gblock.guid, guid_string);