aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-28 18:16:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-28 18:16:10 -0400
commitbaaca1a61497d97cec595fedce03b0a23b983e64 (patch)
tree1ac5caab635956fceb0f5d7b00d41e56981ce9d5
parentbc5bbc4541c4098603edcf9b0b960a71741e79de (diff)
parent72ed73c3f0801e860ee27e53ab6aaf47941ba324 (diff)
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86: (81 commits) xo15-ebook: Remove device.wakeup_count ips: use interruptible waits in ips-monitor acer-wmi: does not poll device status when WMI event is available acer-wmi: does not set persistence state by rfkill_init_sw_state platform-drivers: x86: fix common misspellings acer-wmi: use pr_<level> for messages asus-wmi: potential NULL dereference in show_call() asus-wmi: signedness bug in read_brightness() platform-driver-x86: samsung-laptop: make dmi_check_cb to return 1 instead of 0 platform-driver-x86: fix wrong merge for compal-laptop.c msi-laptop: use pr_<level> for messages Platform: add Samsung Laptop platform driver acer-wmi: Fix WMI ID acer-wmi: deactive mail led when power off msi-laptop: send out touchpad on/off key acer-wmi: set the touchpad toggle key code to KEY_TOUCHPAD_TOGGLE platform-driver-x86: intel_mid_thermal: fix unterminated platform_device_id table sony-laptop: potential null dereference sony-laptop: handle allocation failures sony-laptop: return negative on failure in sony_nc_add() ...
-rw-r--r--Documentation/ABI/testing/sysfs-driver-samsung-laptop19
-rw-r--r--Documentation/ABI/testing/sysfs-platform-asus-wmi31
-rw-r--r--Documentation/ABI/testing/sysfs-platform-eeepc-wmi10
-rw-r--r--Documentation/laptops/sony-laptop.txt37
-rw-r--r--MAINTAINERS30
-rw-r--r--drivers/platform/x86/Kconfig90
-rw-r--r--drivers/platform/x86/Makefile9
-rw-r--r--drivers/platform/x86/acer-wmi.c127
-rw-r--r--drivers/platform/x86/asus-laptop.c182
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c98
-rw-r--r--drivers/platform/x86/asus-wmi.c1656
-rw-r--r--drivers/platform/x86/asus-wmi.h58
-rw-r--r--drivers/platform/x86/compal-laptop.c8
-rw-r--r--drivers/platform/x86/dell-wmi-aio.c171
-rw-r--r--drivers/platform/x86/eeepc-laptop.c2
-rw-r--r--drivers/platform/x86/eeepc-wmi.c912
-rw-r--r--drivers/platform/x86/hp-wmi.c312
-rw-r--r--drivers/platform/x86/ideapad-laptop.c2
-rw-r--r--drivers/platform/x86/intel_ips.c2
-rw-r--r--drivers/platform/x86/intel_mid_powerbtn.c148
-rw-r--r--drivers/platform/x86/intel_mid_thermal.c576
-rw-r--r--drivers/platform/x86/intel_rar_register.c2
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c2
-rw-r--r--drivers/platform/x86/msi-laptop.c95
-rw-r--r--drivers/platform/x86/samsung-laptop.c832
-rw-r--r--drivers/platform/x86/sony-laptop.c501
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c4
-rw-r--r--drivers/platform/x86/xo15-ebook.c180
-rw-r--r--include/linux/input.h7
-rw-r--r--include/linux/sonypi.h1
30 files changed, 4845 insertions, 1259 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
new file mode 100644
index 000000000000..0a810231aad4
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
@@ -0,0 +1,19 @@
1What: /sys/devices/platform/samsung/performance_level
2Date: January 1, 2010
3KernelVersion: 2.6.33
4Contact: Greg Kroah-Hartman <gregkh@suse.de>
5Description: Some Samsung laptops have different "performance levels"
6 that are can be modified by a function key, and by this
7 sysfs file. These values don't always make a whole lot
8 of sense, but some users like to modify them to keep
9 their fans quiet at all costs. Reading from this file
10 will show the current performance level. Writing to the
11 file can change this value.
12 Valid options:
13 "silent"
14 "normal"
15 "overclock"
16 Note that not all laptops support all of these options.
17 Specifically, not all support the "overclock" option,
18 and it's still unknown if this value even changes
19 anything, other than making the user feel a bit better.
diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
new file mode 100644
index 000000000000..2e7df91620de
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
@@ -0,0 +1,31 @@
1What: /sys/devices/platform/<platform>/cpufv
2Date: Oct 2010
3KernelVersion: 2.6.37
4Contact: "Corentin Chary" <corentincj@iksaif.net>
5Description:
6 Change CPU clock configuration (write-only).
7 There are three available clock configuration:
8 * 0 -> Super Performance Mode
9 * 1 -> High Performance Mode
10 * 2 -> Power Saving Mode
11
12What: /sys/devices/platform/<platform>/camera
13Date: Jan 2010
14KernelVersion: 2.6.39
15Contact: "Corentin Chary" <corentincj@iksaif.net>
16Description:
17 Control the camera. 1 means on, 0 means off.
18
19What: /sys/devices/platform/<platform>/cardr
20Date: Jan 2010
21KernelVersion: 2.6.39
22Contact: "Corentin Chary" <corentincj@iksaif.net>
23Description:
24 Control the card reader. 1 means on, 0 means off.
25
26What: /sys/devices/platform/<platform>/touchpad
27Date: Jan 2010
28KernelVersion: 2.6.39
29Contact: "Corentin Chary" <corentincj@iksaif.net>
30Description:
31 Control the card touchpad. 1 means on, 0 means off.
diff --git a/Documentation/ABI/testing/sysfs-platform-eeepc-wmi b/Documentation/ABI/testing/sysfs-platform-eeepc-wmi
deleted file mode 100644
index e4b5fef5fadd..000000000000
--- a/Documentation/ABI/testing/sysfs-platform-eeepc-wmi
+++ /dev/null
@@ -1,10 +0,0 @@
1What: /sys/devices/platform/eeepc-wmi/cpufv
2Date: Oct 2010
3KernelVersion: 2.6.37
4Contact: "Corentin Chary" <corentincj@iksaif.net>
5Description:
6 Change CPU clock configuration (write-only).
7 There are three available clock configuration:
8 * 0 -> Super Performance Mode
9 * 1 -> High Performance Mode
10 * 2 -> Power Saving Mode
diff --git a/Documentation/laptops/sony-laptop.txt b/Documentation/laptops/sony-laptop.txt
index 23ce7d350d1a..2bd4e82e5d9f 100644
--- a/Documentation/laptops/sony-laptop.txt
+++ b/Documentation/laptops/sony-laptop.txt
@@ -14,7 +14,8 @@ Some models report hotkeys through the SNC or SPIC devices, such events are
14reported both through the ACPI subsystem as acpi events and through the INPUT 14reported both through the ACPI subsystem as acpi events and through the INPUT
15subsystem. See the logs of acpid or /proc/acpi/event and 15subsystem. See the logs of acpid or /proc/acpi/event and
16/proc/bus/input/devices to find out what those events are and which input 16/proc/bus/input/devices to find out what those events are and which input
17devices are created by the driver. 17devices are created by the driver. Additionally, loading the driver with the
18debug option will report all events in the kernel log.
18 19
19Backlight control: 20Backlight control:
20------------------ 21------------------
@@ -64,6 +65,16 @@ powers off the sound card,
64 # echo "1" > /sys/devices/platform/sony-laptop/audiopower 65 # echo "1" > /sys/devices/platform/sony-laptop/audiopower
65powers on the sound card. 66powers on the sound card.
66 67
68
69RFkill control:
70---------------
71More recent Vaio models expose a consistent set of ACPI methods to
72control radio frequency emitting devices. If you are a lucky owner of
73such a laptop you will find the necessary rfkill devices under
74/sys/class/rfkill. Check those starting with sony-* in
75 # grep . /sys/class/rfkill/*/{state,name}
76
77
67Development: 78Development:
68------------ 79------------
69 80
@@ -75,8 +86,21 @@ pass the option 'debug=1'.
75REPEAT: DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS. 86REPEAT: DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS.
76 87
77In your kernel logs you will find the list of all ACPI methods 88In your kernel logs you will find the list of all ACPI methods
78the SNC device has on your laptop. You can see the GCDP/GCDP methods 89the SNC device has on your laptop.
79used to pwer on/off the CD drive, but there are others. 90
91* For new models you will see a long list of meaningless method names,
92reading the DSDT table source should reveal that:
93(1) the SNC device uses an internal capability lookup table
94(2) SN00 is used to find values in the lookup table
95(3) SN06 and SN07 are used to call into the real methods based on
96 offsets you can obtain iterating the table using SN00
97(4) SN02 used to enable events.
98Some values in the capability lookup table are more or less known, see
99the code for all sony_call_snc_handle calls, others are more obscure.
100
101* For old models you can see the GCDP/GCDP methods used to pwer on/off
102the CD drive, but there are others and they are usually different from
103model to model.
80 104
81I HAVE NO IDEA WHAT THOSE METHODS DO. 105I HAVE NO IDEA WHAT THOSE METHODS DO.
82 106
@@ -108,9 +132,8 @@ Bugs/Limitations:
108 laptop, including permanent damage. 132 laptop, including permanent damage.
109 133
110* The sony-laptop and sonypi drivers do not interact at all. In the 134* The sony-laptop and sonypi drivers do not interact at all. In the
111 future, sonypi could use sony-laptop to do (part of) its business. 135 future, sonypi will be removed and replaced by sony-laptop.
112 136
113* spicctrl, which is the userspace tool used to communicate with the 137* spicctrl, which is the userspace tool used to communicate with the
114 sonypi driver (through /dev/sonypi) does not try to use the 138 sonypi driver (through /dev/sonypi) is deprecated as well since all
115 sony-laptop driver. In the future, spicctrl could try sonypi first, 139 its features are now available under the sysfs tree via sony-laptop.
116 and if it isn't present, try sony-laptop instead.
diff --git a/MAINTAINERS b/MAINTAINERS
index 8aa1cacddbcc..6b4b9cdec370 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1157,14 +1157,14 @@ S: Maintained
1157F: Documentation/hwmon/asc7621 1157F: Documentation/hwmon/asc7621
1158F: drivers/hwmon/asc7621.c 1158F: drivers/hwmon/asc7621.c
1159 1159
1160ASUS ACPI EXTRAS DRIVER 1160ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
1161M: Corentin Chary <corentincj@iksaif.net> 1161M: Corentin Chary <corentincj@iksaif.net>
1162M: Karol Kozimor <sziwan@users.sourceforge.net>
1163L: acpi4asus-user@lists.sourceforge.net 1162L: acpi4asus-user@lists.sourceforge.net
1164L: platform-driver-x86@vger.kernel.org 1163L: platform-driver-x86@vger.kernel.org
1165W: http://acpi4asus.sf.net 1164W: http://acpi4asus.sf.net
1166S: Maintained 1165S: Maintained
1167F: drivers/platform/x86/asus_acpi.c 1166F: drivers/platform/x86/asus*.c
1167F: drivers/platform/x86/eeepc*.c
1168 1168
1169ASUS ASB100 HARDWARE MONITOR DRIVER 1169ASUS ASB100 HARDWARE MONITOR DRIVER
1170M: "Mark M. Hoffman" <mhoffman@lightlink.com> 1170M: "Mark M. Hoffman" <mhoffman@lightlink.com>
@@ -1172,14 +1172,6 @@ L: lm-sensors@lm-sensors.org
1172S: Maintained 1172S: Maintained
1173F: drivers/hwmon/asb100.c 1173F: drivers/hwmon/asb100.c
1174 1174
1175ASUS LAPTOP EXTRAS DRIVER
1176M: Corentin Chary <corentincj@iksaif.net>
1177L: acpi4asus-user@lists.sourceforge.net
1178L: platform-driver-x86@vger.kernel.org
1179W: http://acpi4asus.sf.net
1180S: Maintained
1181F: drivers/platform/x86/asus-laptop.c
1182
1183ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API 1175ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
1184M: Dan Williams <dan.j.williams@intel.com> 1176M: Dan Williams <dan.j.williams@intel.com>
1185W: http://sourceforge.net/projects/xscaleiop 1177W: http://sourceforge.net/projects/xscaleiop
@@ -2414,22 +2406,6 @@ T: git git://git.alsa-project.org/alsa-kernel.git
2414S: Maintained 2406S: Maintained
2415F: sound/usb/misc/ua101.c 2407F: sound/usb/misc/ua101.c
2416 2408
2417EEEPC LAPTOP EXTRAS DRIVER
2418M: Corentin Chary <corentincj@iksaif.net>
2419L: acpi4asus-user@lists.sourceforge.net
2420L: platform-driver-x86@vger.kernel.org
2421W: http://acpi4asus.sf.net
2422S: Maintained
2423F: drivers/platform/x86/eeepc-laptop.c
2424
2425EEEPC WMI EXTRAS DRIVER
2426M: Corentin Chary <corentincj@iksaif.net>
2427L: acpi4asus-user@lists.sourceforge.net
2428L: platform-driver-x86@vger.kernel.org
2429W: http://acpi4asus.sf.net
2430S: Maintained
2431F: drivers/platform/x86/eeepc-wmi.c
2432
2433EFIFB FRAMEBUFFER DRIVER 2409EFIFB FRAMEBUFFER DRIVER
2434L: linux-fbdev@vger.kernel.org 2410L: linux-fbdev@vger.kernel.org
2435M: Peter Jones <pjones@redhat.com> 2411M: Peter Jones <pjones@redhat.com>
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 222dfb737b11..2ee442c2a5db 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -101,6 +101,19 @@ config DELL_WMI
101 To compile this driver as a module, choose M here: the module will 101 To compile this driver as a module, choose M here: the module will
102 be called dell-wmi. 102 be called dell-wmi.
103 103
104config DELL_WMI_AIO
105 tristate "WMI Hotkeys for Dell All-In-One series"
106 depends on ACPI_WMI
107 depends on INPUT
108 select INPUT_SPARSEKMAP
109 ---help---
110 Say Y here if you want to support WMI-based hotkeys on Dell
111 All-In-One machines.
112
113 To compile this driver as a module, choose M here: the module will
114 be called dell-wmi.
115
116
104config FUJITSU_LAPTOP 117config FUJITSU_LAPTOP
105 tristate "Fujitsu Laptop Extras" 118 tristate "Fujitsu Laptop Extras"
106 depends on ACPI 119 depends on ACPI
@@ -438,23 +451,53 @@ config EEEPC_LAPTOP
438 Bluetooth, backlight and allows powering on/off some other 451 Bluetooth, backlight and allows powering on/off some other
439 devices. 452 devices.
440 453
441 If you have an Eee PC laptop, say Y or M here. 454 If you have an Eee PC laptop, say Y or M here. If this driver
455 doesn't work on your Eee PC, try eeepc-wmi instead.
442 456
443config EEEPC_WMI 457config ASUS_WMI
444 tristate "Eee PC WMI Hotkey Driver (EXPERIMENTAL)" 458 tristate "ASUS WMI Driver (EXPERIMENTAL)"
445 depends on ACPI_WMI 459 depends on ACPI_WMI
446 depends on INPUT 460 depends on INPUT
461 depends on HWMON
447 depends on EXPERIMENTAL 462 depends on EXPERIMENTAL
448 depends on BACKLIGHT_CLASS_DEVICE 463 depends on BACKLIGHT_CLASS_DEVICE
449 depends on RFKILL || RFKILL = n 464 depends on RFKILL || RFKILL = n
465 depends on HOTPLUG_PCI
450 select INPUT_SPARSEKMAP 466 select INPUT_SPARSEKMAP
451 select LEDS_CLASS 467 select LEDS_CLASS
452 select NEW_LEDS 468 select NEW_LEDS
453 ---help--- 469 ---help---
454 Say Y here if you want to support WMI-based hotkeys on Eee PC laptops. 470 Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new
471 Asus Notebooks).
455 472
456 To compile this driver as a module, choose M here: the module will 473 To compile this driver as a module, choose M here: the module will
457 be called eeepc-wmi. 474 be called asus-wmi.
475
476config ASUS_NB_WMI
477 tristate "Asus Notebook WMI Driver (EXPERIMENTAL)"
478 depends on ASUS_WMI
479 ---help---
480 This is a driver for newer Asus notebooks. It adds extra features
481 like wireless radio and bluetooth control, leds, hotkeys, backlight...
482
483 For more informations, see
484 <file:Documentation/ABI/testing/sysfs-platform-asus-wmi>
485
486 If you have an ACPI-WMI compatible Asus Notebook, say Y or M
487 here.
488
489config EEEPC_WMI
490 tristate "Eee PC WMI Driver (EXPERIMENTAL)"
491 depends on ASUS_WMI
492 ---help---
493 This is a driver for newer Eee PC laptops. It adds extra features
494 like wireless radio and bluetooth control, leds, hotkeys, backlight...
495
496 For more informations, see
497 <file:Documentation/ABI/testing/sysfs-platform-asus-wmi>
498
499 If you have an ACPI-WMI compatible Eee PC laptop (>= 1000), say Y or M
500 here.
458 501
459config ACPI_WMI 502config ACPI_WMI
460 tristate "WMI" 503 tristate "WMI"
@@ -616,6 +659,21 @@ config GPIO_INTEL_PMIC
616 Say Y here to support GPIO via the SCU IPC interface 659 Say Y here to support GPIO via the SCU IPC interface
617 on Intel MID platforms. 660 on Intel MID platforms.
618 661
662config INTEL_MID_POWER_BUTTON
663 tristate "power button driver for Intel MID platforms"
664 depends on INTEL_SCU_IPC && INPUT
665 help
666 This driver handles the power button on the Intel MID platforms.
667
668 If unsure, say N.
669
670config INTEL_MFLD_THERMAL
671 tristate "Thermal driver for Intel Medfield platform"
672 depends on INTEL_SCU_IPC && THERMAL
673 help
674 Say Y here to enable thermal driver support for the Intel Medfield
675 platform.
676
619config RAR_REGISTER 677config RAR_REGISTER
620 bool "Restricted Access Region Register Driver" 678 bool "Restricted Access Region Register Driver"
621 depends on PCI && X86_MRST 679 depends on PCI && X86_MRST
@@ -672,4 +730,26 @@ config XO1_RFKILL
672 Support for enabling/disabling the WLAN interface on the OLPC XO-1 730 Support for enabling/disabling the WLAN interface on the OLPC XO-1
673 laptop. 731 laptop.
674 732
733config XO15_EBOOK
734 tristate "OLPC XO-1.5 ebook switch"
735 depends on ACPI && INPUT
736 ---help---
737 Support for the ebook switch on the OLPC XO-1.5 laptop.
738
739 This switch is triggered as the screen is rotated and folded down to
740 convert the device into ebook form.
741
742config SAMSUNG_LAPTOP
743 tristate "Samsung Laptop driver"
744 depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
745 ---help---
746 This module implements a driver for a wide range of different
747 Samsung laptops. It offers control over the different
748 function keys, wireless LED, LCD backlight level, and
749 sometimes provides a "performance_control" sysfs file to allow
750 the performance level of the laptop to be changed.
751
752 To compile this driver as a module, choose M here: the module
753 will be called samsung-laptop.
754
675endif # X86_PLATFORM_DEVICES 755endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 299aefb3e74c..029e8861d086 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -3,6 +3,8 @@
3# x86 Platform-Specific Drivers 3# x86 Platform-Specific Drivers
4# 4#
5obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 5obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
6obj-$(CONFIG_ASUS_WMI) += asus-wmi.o
7obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o
6obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o 8obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
7obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o 9obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
8obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o 10obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
@@ -10,6 +12,7 @@ obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o
10obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o 12obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
11obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 13obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
12obj-$(CONFIG_DELL_WMI) += dell-wmi.o 14obj-$(CONFIG_DELL_WMI) += dell-wmi.o
15obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
13obj-$(CONFIG_ACER_WMI) += acer-wmi.o 16obj-$(CONFIG_ACER_WMI) += acer-wmi.o
14obj-$(CONFIG_ACERHDF) += acerhdf.o 17obj-$(CONFIG_ACERHDF) += acerhdf.o
15obj-$(CONFIG_HP_ACCEL) += hp_accel.o 18obj-$(CONFIG_HP_ACCEL) += hp_accel.o
@@ -29,9 +32,13 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
29obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 32obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
30obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o 33obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
31obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 34obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
32obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o 35obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
36obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
33obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o 37obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
34obj-$(CONFIG_INTEL_IPS) += intel_ips.o 38obj-$(CONFIG_INTEL_IPS) += intel_ips.o
35obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o 39obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
36obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o 40obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o
41obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o
37obj-$(CONFIG_IBM_RTL) += ibm_rtl.o 42obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
43obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
44obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index c9784705f6ac..5ea6c3477d17 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -22,6 +22,8 @@
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */ 23 */
24 24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
25#include <linux/kernel.h> 27#include <linux/kernel.h>
26#include <linux/module.h> 28#include <linux/module.h>
27#include <linux/init.h> 29#include <linux/init.h>
@@ -46,12 +48,6 @@ MODULE_AUTHOR("Carlos Corbacho");
46MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); 48MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
47MODULE_LICENSE("GPL"); 49MODULE_LICENSE("GPL");
48 50
49#define ACER_LOGPREFIX "acer-wmi: "
50#define ACER_ERR KERN_ERR ACER_LOGPREFIX
51#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
52#define ACER_INFO KERN_INFO ACER_LOGPREFIX
53#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
54
55/* 51/*
56 * Magic Number 52 * Magic Number
57 * Meaning is unknown - this number is required for writing to ACPI for AMW0 53 * Meaning is unknown - this number is required for writing to ACPI for AMW0
@@ -84,7 +80,7 @@ MODULE_LICENSE("GPL");
84#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" 80#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
85#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" 81#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
86#define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3" 82#define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
87#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" 83#define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A"
88#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" 84#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
89 85
90/* 86/*
@@ -93,7 +89,7 @@ MODULE_LICENSE("GPL");
93#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" 89#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
94 90
95MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 91MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
96MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); 92MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3");
97MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); 93MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
98 94
99enum acer_wmi_event_ids { 95enum acer_wmi_event_ids {
@@ -108,7 +104,7 @@ static const struct key_entry acer_wmi_keymap[] = {
108 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ 104 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
109 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ 105 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
110 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ 106 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
111 {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */ 107 {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */
112 {KE_END, 0} 108 {KE_END, 0}
113}; 109};
114 110
@@ -221,6 +217,7 @@ struct acer_debug {
221static struct rfkill *wireless_rfkill; 217static struct rfkill *wireless_rfkill;
222static struct rfkill *bluetooth_rfkill; 218static struct rfkill *bluetooth_rfkill;
223static struct rfkill *threeg_rfkill; 219static struct rfkill *threeg_rfkill;
220static bool rfkill_inited;
224 221
225/* Each low-level interface must define at least some of the following */ 222/* Each low-level interface must define at least some of the following */
226struct wmi_interface { 223struct wmi_interface {
@@ -845,7 +842,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
845 has_type_aa = true; 842 has_type_aa = true;
846 type_aa = (struct hotkey_function_type_aa *) header; 843 type_aa = (struct hotkey_function_type_aa *) header;
847 844
848 printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n", 845 pr_info("Function bitmap for Communication Button: 0x%x\n",
849 type_aa->commun_func_bitmap); 846 type_aa->commun_func_bitmap);
850 847
851 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) 848 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
@@ -991,6 +988,7 @@ static int __devinit acer_led_init(struct device *dev)
991 988
992static void acer_led_exit(void) 989static void acer_led_exit(void)
993{ 990{
991 set_u32(LED_OFF, ACER_CAP_MAILLED);
994 led_classdev_unregister(&mail_led); 992 led_classdev_unregister(&mail_led);
995} 993}
996 994
@@ -1036,7 +1034,7 @@ static int __devinit acer_backlight_init(struct device *dev)
1036 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, 1034 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
1037 &props); 1035 &props);
1038 if (IS_ERR(bd)) { 1036 if (IS_ERR(bd)) {
1039 printk(ACER_ERR "Could not register Acer backlight device\n"); 1037 pr_err("Could not register Acer backlight device\n");
1040 acer_backlight_device = NULL; 1038 acer_backlight_device = NULL;
1041 return PTR_ERR(bd); 1039 return PTR_ERR(bd);
1042 } 1040 }
@@ -1083,8 +1081,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
1083 return AE_ERROR; 1081 return AE_ERROR;
1084 } 1082 }
1085 if (obj->buffer.length != 8) { 1083 if (obj->buffer.length != 8) {
1086 printk(ACER_WARNING "Unknown buffer length %d\n", 1084 pr_warning("Unknown buffer length %d\n", obj->buffer.length);
1087 obj->buffer.length);
1088 kfree(obj); 1085 kfree(obj);
1089 return AE_ERROR; 1086 return AE_ERROR;
1090 } 1087 }
@@ -1093,7 +1090,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
1093 kfree(obj); 1090 kfree(obj);
1094 1091
1095 if (return_value.error_code || return_value.ec_return_value) 1092 if (return_value.error_code || return_value.ec_return_value)
1096 printk(ACER_WARNING "Get Device Status failed: " 1093 pr_warning("Get Device Status failed: "
1097 "0x%x - 0x%x\n", return_value.error_code, 1094 "0x%x - 0x%x\n", return_value.error_code,
1098 return_value.ec_return_value); 1095 return_value.ec_return_value);
1099 else 1096 else
@@ -1161,9 +1158,13 @@ static int acer_rfkill_set(void *data, bool blocked)
1161{ 1158{
1162 acpi_status status; 1159 acpi_status status;
1163 u32 cap = (unsigned long)data; 1160 u32 cap = (unsigned long)data;
1164 status = set_u32(!blocked, cap); 1161
1165 if (ACPI_FAILURE(status)) 1162 if (rfkill_inited) {
1166 return -ENODEV; 1163 status = set_u32(!blocked, cap);
1164 if (ACPI_FAILURE(status))
1165 return -ENODEV;
1166 }
1167
1167 return 0; 1168 return 0;
1168} 1169}
1169 1170
@@ -1187,14 +1188,16 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
1187 return ERR_PTR(-ENOMEM); 1188 return ERR_PTR(-ENOMEM);
1188 1189
1189 status = get_device_status(&state, cap); 1190 status = get_device_status(&state, cap);
1190 if (ACPI_SUCCESS(status))
1191 rfkill_init_sw_state(rfkill_dev, !state);
1192 1191
1193 err = rfkill_register(rfkill_dev); 1192 err = rfkill_register(rfkill_dev);
1194 if (err) { 1193 if (err) {
1195 rfkill_destroy(rfkill_dev); 1194 rfkill_destroy(rfkill_dev);
1196 return ERR_PTR(err); 1195 return ERR_PTR(err);
1197 } 1196 }
1197
1198 if (ACPI_SUCCESS(status))
1199 rfkill_set_sw_state(rfkill_dev, !state);
1200
1198 return rfkill_dev; 1201 return rfkill_dev;
1199} 1202}
1200 1203
@@ -1229,14 +1232,19 @@ static int acer_rfkill_init(struct device *dev)
1229 } 1232 }
1230 } 1233 }
1231 1234
1232 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 1235 rfkill_inited = true;
1236
1237 if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID))
1238 schedule_delayed_work(&acer_rfkill_work,
1239 round_jiffies_relative(HZ));
1233 1240
1234 return 0; 1241 return 0;
1235} 1242}
1236 1243
1237static void acer_rfkill_exit(void) 1244static void acer_rfkill_exit(void)
1238{ 1245{
1239 cancel_delayed_work_sync(&acer_rfkill_work); 1246 if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID))
1247 cancel_delayed_work_sync(&acer_rfkill_work);
1240 1248
1241 rfkill_unregister(wireless_rfkill); 1249 rfkill_unregister(wireless_rfkill);
1242 rfkill_destroy(wireless_rfkill); 1250 rfkill_destroy(wireless_rfkill);
@@ -1309,7 +1317,7 @@ static void acer_wmi_notify(u32 value, void *context)
1309 1317
1310 status = wmi_get_event_data(value, &response); 1318 status = wmi_get_event_data(value, &response);
1311 if (status != AE_OK) { 1319 if (status != AE_OK) {
1312 printk(ACER_WARNING "bad event status 0x%x\n", status); 1320 pr_warning("bad event status 0x%x\n", status);
1313 return; 1321 return;
1314 } 1322 }
1315 1323
@@ -1318,14 +1326,12 @@ static void acer_wmi_notify(u32 value, void *context)
1318 if (!obj) 1326 if (!obj)
1319 return; 1327 return;
1320 if (obj->type != ACPI_TYPE_BUFFER) { 1328 if (obj->type != ACPI_TYPE_BUFFER) {
1321 printk(ACER_WARNING "Unknown response received %d\n", 1329 pr_warning("Unknown response received %d\n", obj->type);
1322 obj->type);
1323 kfree(obj); 1330 kfree(obj);
1324 return; 1331 return;
1325 } 1332 }
1326 if (obj->buffer.length != 8) { 1333 if (obj->buffer.length != 8) {
1327 printk(ACER_WARNING "Unknown buffer length %d\n", 1334 pr_warning("Unknown buffer length %d\n", obj->buffer.length);
1328 obj->buffer.length);
1329 kfree(obj); 1335 kfree(obj);
1330 return; 1336 return;
1331 } 1337 }
@@ -1335,13 +1341,26 @@ static void acer_wmi_notify(u32 value, void *context)
1335 1341
1336 switch (return_value.function) { 1342 switch (return_value.function) {
1337 case WMID_HOTKEY_EVENT: 1343 case WMID_HOTKEY_EVENT:
1344 if (return_value.device_state) {
1345 u16 device_state = return_value.device_state;
1346 pr_debug("deivces states: 0x%x\n", device_state);
1347 if (has_cap(ACER_CAP_WIRELESS))
1348 rfkill_set_sw_state(wireless_rfkill,
1349 !(device_state & ACER_WMID3_GDS_WIRELESS));
1350 if (has_cap(ACER_CAP_BLUETOOTH))
1351 rfkill_set_sw_state(bluetooth_rfkill,
1352 !(device_state & ACER_WMID3_GDS_BLUETOOTH));
1353 if (has_cap(ACER_CAP_THREEG))
1354 rfkill_set_sw_state(threeg_rfkill,
1355 !(device_state & ACER_WMID3_GDS_THREEG));
1356 }
1338 if (!sparse_keymap_report_event(acer_wmi_input_dev, 1357 if (!sparse_keymap_report_event(acer_wmi_input_dev,
1339 return_value.key_num, 1, true)) 1358 return_value.key_num, 1, true))
1340 printk(ACER_WARNING "Unknown key number - 0x%x\n", 1359 pr_warning("Unknown key number - 0x%x\n",
1341 return_value.key_num); 1360 return_value.key_num);
1342 break; 1361 break;
1343 default: 1362 default:
1344 printk(ACER_WARNING "Unknown function number - %d - %d\n", 1363 pr_warning("Unknown function number - %d - %d\n",
1345 return_value.function, return_value.key_num); 1364 return_value.function, return_value.key_num);
1346 break; 1365 break;
1347 } 1366 }
@@ -1370,8 +1389,7 @@ wmid3_set_lm_mode(struct lm_input_params *params,
1370 return AE_ERROR; 1389 return AE_ERROR;
1371 } 1390 }
1372 if (obj->buffer.length != 4) { 1391 if (obj->buffer.length != 4) {
1373 printk(ACER_WARNING "Unknown buffer length %d\n", 1392 pr_warning("Unknown buffer length %d\n", obj->buffer.length);
1374 obj->buffer.length);
1375 kfree(obj); 1393 kfree(obj);
1376 return AE_ERROR; 1394 return AE_ERROR;
1377 } 1395 }
@@ -1396,11 +1414,11 @@ static int acer_wmi_enable_ec_raw(void)
1396 status = wmid3_set_lm_mode(&params, &return_value); 1414 status = wmid3_set_lm_mode(&params, &return_value);
1397 1415
1398 if (return_value.error_code || return_value.ec_return_value) 1416 if (return_value.error_code || return_value.ec_return_value)
1399 printk(ACER_WARNING "Enabling EC raw mode failed: " 1417 pr_warning("Enabling EC raw mode failed: "
1400 "0x%x - 0x%x\n", return_value.error_code, 1418 "0x%x - 0x%x\n", return_value.error_code,
1401 return_value.ec_return_value); 1419 return_value.ec_return_value);
1402 else 1420 else
1403 printk(ACER_INFO "Enabled EC raw mode"); 1421 pr_info("Enabled EC raw mode");
1404 1422
1405 return status; 1423 return status;
1406} 1424}
@@ -1419,7 +1437,7 @@ static int acer_wmi_enable_lm(void)
1419 status = wmid3_set_lm_mode(&params, &return_value); 1437 status = wmid3_set_lm_mode(&params, &return_value);
1420 1438
1421 if (return_value.error_code || return_value.ec_return_value) 1439 if (return_value.error_code || return_value.ec_return_value)
1422 printk(ACER_WARNING "Enabling Launch Manager failed: " 1440 pr_warning("Enabling Launch Manager failed: "
1423 "0x%x - 0x%x\n", return_value.error_code, 1441 "0x%x - 0x%x\n", return_value.error_code,
1424 return_value.ec_return_value); 1442 return_value.ec_return_value);
1425 1443
@@ -1553,6 +1571,7 @@ pm_message_t state)
1553 1571
1554 if (has_cap(ACER_CAP_MAILLED)) { 1572 if (has_cap(ACER_CAP_MAILLED)) {
1555 get_u32(&value, ACER_CAP_MAILLED); 1573 get_u32(&value, ACER_CAP_MAILLED);
1574 set_u32(LED_OFF, ACER_CAP_MAILLED);
1556 data->mailled = value; 1575 data->mailled = value;
1557 } 1576 }
1558 1577
@@ -1580,6 +1599,17 @@ static int acer_platform_resume(struct platform_device *device)
1580 return 0; 1599 return 0;
1581} 1600}
1582 1601
1602static void acer_platform_shutdown(struct platform_device *device)
1603{
1604 struct acer_data *data = &interface->data;
1605
1606 if (!data)
1607 return;
1608
1609 if (has_cap(ACER_CAP_MAILLED))
1610 set_u32(LED_OFF, ACER_CAP_MAILLED);
1611}
1612
1583static struct platform_driver acer_platform_driver = { 1613static struct platform_driver acer_platform_driver = {
1584 .driver = { 1614 .driver = {
1585 .name = "acer-wmi", 1615 .name = "acer-wmi",
@@ -1589,6 +1619,7 @@ static struct platform_driver acer_platform_driver = {
1589 .remove = acer_platform_remove, 1619 .remove = acer_platform_remove,
1590 .suspend = acer_platform_suspend, 1620 .suspend = acer_platform_suspend,
1591 .resume = acer_platform_resume, 1621 .resume = acer_platform_resume,
1622 .shutdown = acer_platform_shutdown,
1592}; 1623};
1593 1624
1594static struct platform_device *acer_platform_device; 1625static struct platform_device *acer_platform_device;
@@ -1636,7 +1667,7 @@ static int create_debugfs(void)
1636{ 1667{
1637 interface->debug.root = debugfs_create_dir("acer-wmi", NULL); 1668 interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
1638 if (!interface->debug.root) { 1669 if (!interface->debug.root) {
1639 printk(ACER_ERR "Failed to create debugfs directory"); 1670 pr_err("Failed to create debugfs directory");
1640 return -ENOMEM; 1671 return -ENOMEM;
1641 } 1672 }
1642 1673
@@ -1657,11 +1688,10 @@ static int __init acer_wmi_init(void)
1657{ 1688{
1658 int err; 1689 int err;
1659 1690
1660 printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); 1691 pr_info("Acer Laptop ACPI-WMI Extras\n");
1661 1692
1662 if (dmi_check_system(acer_blacklist)) { 1693 if (dmi_check_system(acer_blacklist)) {
1663 printk(ACER_INFO "Blacklisted hardware detected - " 1694 pr_info("Blacklisted hardware detected - not loading\n");
1664 "not loading\n");
1665 return -ENODEV; 1695 return -ENODEV;
1666 } 1696 }
1667 1697
@@ -1678,12 +1708,11 @@ static int __init acer_wmi_init(void)
1678 1708
1679 if (wmi_has_guid(WMID_GUID2) && interface) { 1709 if (wmi_has_guid(WMID_GUID2) && interface) {
1680 if (ACPI_FAILURE(WMID_set_capabilities())) { 1710 if (ACPI_FAILURE(WMID_set_capabilities())) {
1681 printk(ACER_ERR "Unable to detect available WMID " 1711 pr_err("Unable to detect available WMID devices\n");
1682 "devices\n");
1683 return -ENODEV; 1712 return -ENODEV;
1684 } 1713 }
1685 } else if (!wmi_has_guid(WMID_GUID2) && interface) { 1714 } else if (!wmi_has_guid(WMID_GUID2) && interface) {
1686 printk(ACER_ERR "No WMID device detection method found\n"); 1715 pr_err("No WMID device detection method found\n");
1687 return -ENODEV; 1716 return -ENODEV;
1688 } 1717 }
1689 1718
@@ -1691,8 +1720,7 @@ static int __init acer_wmi_init(void)
1691 interface = &AMW0_interface; 1720 interface = &AMW0_interface;
1692 1721
1693 if (ACPI_FAILURE(AMW0_set_capabilities())) { 1722 if (ACPI_FAILURE(AMW0_set_capabilities())) {
1694 printk(ACER_ERR "Unable to detect available AMW0 " 1723 pr_err("Unable to detect available AMW0 devices\n");
1695 "devices\n");
1696 return -ENODEV; 1724 return -ENODEV;
1697 } 1725 }
1698 } 1726 }
@@ -1701,8 +1729,7 @@ static int __init acer_wmi_init(void)
1701 AMW0_find_mailled(); 1729 AMW0_find_mailled();
1702 1730
1703 if (!interface) { 1731 if (!interface) {
1704 printk(ACER_INFO "No or unsupported WMI interface, unable to " 1732 pr_err("No or unsupported WMI interface, unable to load\n");
1705 "load\n");
1706 return -ENODEV; 1733 return -ENODEV;
1707 } 1734 }
1708 1735
@@ -1710,22 +1737,22 @@ static int __init acer_wmi_init(void)
1710 1737
1711 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { 1738 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) {
1712 interface->capability &= ~ACER_CAP_BRIGHTNESS; 1739 interface->capability &= ~ACER_CAP_BRIGHTNESS;
1713 printk(ACER_INFO "Brightness must be controlled by " 1740 pr_info("Brightness must be controlled by "
1714 "generic video driver\n"); 1741 "generic video driver\n");
1715 } 1742 }
1716 1743
1717 if (wmi_has_guid(WMID_GUID3)) { 1744 if (wmi_has_guid(WMID_GUID3)) {
1718 if (ec_raw_mode) { 1745 if (ec_raw_mode) {
1719 if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { 1746 if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
1720 printk(ACER_ERR "Cannot enable EC raw mode\n"); 1747 pr_err("Cannot enable EC raw mode\n");
1721 return -ENODEV; 1748 return -ENODEV;
1722 } 1749 }
1723 } else if (ACPI_FAILURE(acer_wmi_enable_lm())) { 1750 } else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
1724 printk(ACER_ERR "Cannot enable Launch Manager mode\n"); 1751 pr_err("Cannot enable Launch Manager mode\n");
1725 return -ENODEV; 1752 return -ENODEV;
1726 } 1753 }
1727 } else if (ec_raw_mode) { 1754 } else if (ec_raw_mode) {
1728 printk(ACER_INFO "No WMID EC raw mode enable method\n"); 1755 pr_info("No WMID EC raw mode enable method\n");
1729 } 1756 }
1730 1757
1731 if (wmi_has_guid(ACERWMID_EVENT_GUID)) { 1758 if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
@@ -1736,7 +1763,7 @@ static int __init acer_wmi_init(void)
1736 1763
1737 err = platform_driver_register(&acer_platform_driver); 1764 err = platform_driver_register(&acer_platform_driver);
1738 if (err) { 1765 if (err) {
1739 printk(ACER_ERR "Unable to register platform driver.\n"); 1766 pr_err("Unable to register platform driver.\n");
1740 goto error_platform_register; 1767 goto error_platform_register;
1741 } 1768 }
1742 1769
@@ -1791,7 +1818,7 @@ static void __exit acer_wmi_exit(void)
1791 platform_device_unregister(acer_platform_device); 1818 platform_device_unregister(acer_platform_device);
1792 platform_driver_unregister(&acer_platform_driver); 1819 platform_driver_unregister(&acer_platform_driver);
1793 1820
1794 printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); 1821 pr_info("Acer Laptop WMI Extras unloaded\n");
1795 return; 1822 return;
1796} 1823}
1797 1824
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 5a6f7d7575d6..c53b3ff7978a 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -29,7 +29,7 @@
29 * John Belmonte - ACPI code for Toshiba laptop was a good starting point. 29 * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
30 * Eric Burghard - LED display support for W1N 30 * Eric Burghard - LED display support for W1N
31 * Josh Green - Light Sens support 31 * Josh Green - Light Sens support
32 * Thomas Tuttle - His first patch for led support was very helpfull 32 * Thomas Tuttle - His first patch for led support was very helpful
33 * Sam Lin - GPS support 33 * Sam Lin - GPS support
34 */ 34 */
35 35
@@ -50,6 +50,7 @@
50#include <linux/input/sparse-keymap.h> 50#include <linux/input/sparse-keymap.h>
51#include <linux/rfkill.h> 51#include <linux/rfkill.h>
52#include <linux/slab.h> 52#include <linux/slab.h>
53#include <linux/dmi.h>
53#include <acpi/acpi_drivers.h> 54#include <acpi/acpi_drivers.h>
54#include <acpi/acpi_bus.h> 55#include <acpi/acpi_bus.h>
55 56
@@ -157,46 +158,9 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
157#define METHOD_BRIGHTNESS_SET "SPLV" 158#define METHOD_BRIGHTNESS_SET "SPLV"
158#define METHOD_BRIGHTNESS_GET "GPLV" 159#define METHOD_BRIGHTNESS_GET "GPLV"
159 160
160/* Backlight */
161static acpi_handle lcd_switch_handle;
162static char *lcd_switch_paths[] = {
163 "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
164 "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */
165 "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
166 "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
167 "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
168 "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
169 "\\_SB.PCI0.PX40.Q10", /* S1x */
170 "\\Q10"}; /* A2x, L2D, L3D, M2E */
171
172/* Display */ 161/* Display */
173#define METHOD_SWITCH_DISPLAY "SDSP" 162#define METHOD_SWITCH_DISPLAY "SDSP"
174 163
175static acpi_handle display_get_handle;
176static char *display_get_paths[] = {
177 /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
178 "\\_SB.PCI0.P0P1.VGA.GETD",
179 /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
180 "\\_SB.PCI0.P0P2.VGA.GETD",
181 /* A6V A6Q */
182 "\\_SB.PCI0.P0P3.VGA.GETD",
183 /* A6T, A6M */
184 "\\_SB.PCI0.P0PA.VGA.GETD",
185 /* L3C */
186 "\\_SB.PCI0.PCI1.VGAC.NMAP",
187 /* Z96F */
188 "\\_SB.PCI0.VGA.GETD",
189 /* A2D */
190 "\\ACTD",
191 /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
192 "\\ADVG",
193 /* P30 */
194 "\\DNXT",
195 /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
196 "\\INFB",
197 /* A3F A6F A3N A3L M6N W3N W6A */
198 "\\SSTE"};
199
200#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ 164#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */
201#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ 165#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */
202 166
@@ -246,7 +210,6 @@ struct asus_laptop {
246 210
247 int wireless_status; 211 int wireless_status;
248 bool have_rsts; 212 bool have_rsts;
249 int lcd_state;
250 213
251 struct rfkill *gps_rfkill; 214 struct rfkill *gps_rfkill;
252 215
@@ -559,48 +522,6 @@ error:
559/* 522/*
560 * Backlight device 523 * Backlight device
561 */ 524 */
562static int asus_lcd_status(struct asus_laptop *asus)
563{
564 return asus->lcd_state;
565}
566
567static int asus_lcd_set(struct asus_laptop *asus, int value)
568{
569 int lcd = 0;
570 acpi_status status = 0;
571
572 lcd = !!value;
573
574 if (lcd == asus_lcd_status(asus))
575 return 0;
576
577 if (!lcd_switch_handle)
578 return -ENODEV;
579
580 status = acpi_evaluate_object(lcd_switch_handle,
581 NULL, NULL, NULL);
582
583 if (ACPI_FAILURE(status)) {
584 pr_warning("Error switching LCD\n");
585 return -ENODEV;
586 }
587
588 asus->lcd_state = lcd;
589 return 0;
590}
591
592static void lcd_blank(struct asus_laptop *asus, int blank)
593{
594 struct backlight_device *bd = asus->backlight_device;
595
596 asus->lcd_state = (blank == FB_BLANK_UNBLANK);
597
598 if (bd) {
599 bd->props.power = blank;
600 backlight_update_status(bd);
601 }
602}
603
604static int asus_read_brightness(struct backlight_device *bd) 525static int asus_read_brightness(struct backlight_device *bd)
605{ 526{
606 struct asus_laptop *asus = bl_get_data(bd); 527 struct asus_laptop *asus = bl_get_data(bd);
@@ -628,16 +549,9 @@ static int asus_set_brightness(struct backlight_device *bd, int value)
628 549
629static int update_bl_status(struct backlight_device *bd) 550static int update_bl_status(struct backlight_device *bd)
630{ 551{
631 struct asus_laptop *asus = bl_get_data(bd);
632 int rv;
633 int value = bd->props.brightness; 552 int value = bd->props.brightness;
634 553
635 rv = asus_set_brightness(bd, value); 554 return asus_set_brightness(bd, value);
636 if (rv)
637 return rv;
638
639 value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0;
640 return asus_lcd_set(asus, value);
641} 555}
642 556
643static const struct backlight_ops asusbl_ops = { 557static const struct backlight_ops asusbl_ops = {
@@ -661,8 +575,7 @@ static int asus_backlight_init(struct asus_laptop *asus)
661 struct backlight_properties props; 575 struct backlight_properties props;
662 576
663 if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) || 577 if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) ||
664 acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) || 578 acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL))
665 !lcd_switch_handle)
666 return 0; 579 return 0;
667 580
668 memset(&props, 0, sizeof(struct backlight_properties)); 581 memset(&props, 0, sizeof(struct backlight_properties));
@@ -971,41 +884,6 @@ static void asus_set_display(struct asus_laptop *asus, int value)
971 return; 884 return;
972} 885}
973 886
974static int read_display(struct asus_laptop *asus)
975{
976 unsigned long long value = 0;
977 acpi_status rv = AE_OK;
978
979 /*
980 * In most of the case, we know how to set the display, but sometime
981 * we can't read it
982 */
983 if (display_get_handle) {
984 rv = acpi_evaluate_integer(display_get_handle, NULL,
985 NULL, &value);
986 if (ACPI_FAILURE(rv))
987 pr_warning("Error reading display status\n");
988 }
989
990 value &= 0x0F; /* needed for some models, shouldn't hurt others */
991
992 return value;
993}
994
995/*
996 * Now, *this* one could be more user-friendly, but so far, no-one has
997 * complained. The significance of bits is the same as in store_disp()
998 */
999static ssize_t show_disp(struct device *dev,
1000 struct device_attribute *attr, char *buf)
1001{
1002 struct asus_laptop *asus = dev_get_drvdata(dev);
1003
1004 if (!display_get_handle)
1005 return -ENODEV;
1006 return sprintf(buf, "%d\n", read_display(asus));
1007}
1008
1009/* 887/*
1010 * Experimental support for display switching. As of now: 1 should activate 888 * Experimental support for display switching. As of now: 1 should activate
1011 * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. 889 * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
@@ -1247,15 +1125,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
1247 struct asus_laptop *asus = acpi_driver_data(device); 1125 struct asus_laptop *asus = acpi_driver_data(device);
1248 u16 count; 1126 u16 count;
1249 1127
1250 /*
1251 * We need to tell the backlight device when the backlight power is
1252 * switched
1253 */
1254 if (event == ATKD_LCD_ON)
1255 lcd_blank(asus, FB_BLANK_UNBLANK);
1256 else if (event == ATKD_LCD_OFF)
1257 lcd_blank(asus, FB_BLANK_POWERDOWN);
1258
1259 /* TODO Find a better way to handle events count. */ 1128 /* TODO Find a better way to handle events count. */
1260 count = asus->event_count[event % 128]++; 1129 count = asus->event_count[event % 128]++;
1261 acpi_bus_generate_proc_event(asus->device, event, count); 1130 acpi_bus_generate_proc_event(asus->device, event, count);
@@ -1282,7 +1151,7 @@ static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
1282 show_bluetooth, store_bluetooth); 1151 show_bluetooth, store_bluetooth);
1283static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); 1152static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
1284static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); 1153static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
1285static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); 1154static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp);
1286static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); 1155static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
1287static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); 1156static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
1288static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); 1157static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
@@ -1393,26 +1262,6 @@ static struct platform_driver platform_driver = {
1393 } 1262 }
1394}; 1263};
1395 1264
1396static int asus_handle_init(char *name, acpi_handle * handle,
1397 char **paths, int num_paths)
1398{
1399 int i;
1400 acpi_status status;
1401
1402 for (i = 0; i < num_paths; i++) {
1403 status = acpi_get_handle(NULL, paths[i], handle);
1404 if (ACPI_SUCCESS(status))
1405 return 0;
1406 }
1407
1408 *handle = NULL;
1409 return -ENODEV;
1410}
1411
1412#define ASUS_HANDLE_INIT(object) \
1413 asus_handle_init(#object, &object##_handle, object##_paths, \
1414 ARRAY_SIZE(object##_paths))
1415
1416/* 1265/*
1417 * This function is used to initialize the context with right values. In this 1266 * This function is used to initialize the context with right values. In this
1418 * method, we can make all the detection we want, and modify the asus_laptop 1267 * method, we can make all the detection we want, and modify the asus_laptop
@@ -1498,10 +1347,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
1498 if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) 1347 if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
1499 asus->have_rsts = true; 1348 asus->have_rsts = true;
1500 1349
1501 /* Scheduled for removal */
1502 ASUS_HANDLE_INIT(lcd_switch);
1503 ASUS_HANDLE_INIT(display_get);
1504
1505 kfree(model); 1350 kfree(model);
1506 1351
1507 return AE_OK; 1352 return AE_OK;
@@ -1553,10 +1398,23 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
1553 asus_als_level(asus, asus->light_level); 1398 asus_als_level(asus, asus->light_level);
1554 } 1399 }
1555 1400
1556 asus->lcd_state = 1; /* LCD should be on when the module load */
1557 return result; 1401 return result;
1558} 1402}
1559 1403
1404static void __devinit asus_dmi_check(void)
1405{
1406 const char *model;
1407
1408 model = dmi_get_system_info(DMI_PRODUCT_NAME);
1409 if (!model)
1410 return;
1411
1412 /* On L1400B WLED control the sound card, don't mess with it ... */
1413 if (strncmp(model, "L1400B", 6) == 0) {
1414 wlan_status = -1;
1415 }
1416}
1417
1560static bool asus_device_present; 1418static bool asus_device_present;
1561 1419
1562static int __devinit asus_acpi_add(struct acpi_device *device) 1420static int __devinit asus_acpi_add(struct acpi_device *device)
@@ -1575,6 +1433,8 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
1575 device->driver_data = asus; 1433 device->driver_data = asus;
1576 asus->device = device; 1434 asus->device = device;
1577 1435
1436 asus_dmi_check();
1437
1578 result = asus_acpi_init(asus); 1438 result = asus_acpi_init(asus);
1579 if (result) 1439 if (result)
1580 goto fail_platform; 1440 goto fail_platform;
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
new file mode 100644
index 000000000000..0580d99b0798
--- /dev/null
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -0,0 +1,98 @@
1/*
2 * Asus Notebooks WMI hotkey driver
3 *
4 * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/input.h>
27#include <linux/input/sparse-keymap.h>
28
29#include "asus-wmi.h"
30
31#define ASUS_NB_WMI_FILE "asus-nb-wmi"
32
33MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>");
34MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver");
35MODULE_LICENSE("GPL");
36
37#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
38
39MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID);
40
41static const struct key_entry asus_nb_wmi_keymap[] = {
42 { KE_KEY, 0x30, { KEY_VOLUMEUP } },
43 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
44 { KE_KEY, 0x32, { KEY_MUTE } },
45 { KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */
46 { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
47 { KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
48 { KE_KEY, 0x41, { KEY_NEXTSONG } },
49 { KE_KEY, 0x43, { KEY_STOPCD } },
50 { KE_KEY, 0x45, { KEY_PLAYPAUSE } },
51 { KE_KEY, 0x4c, { KEY_MEDIA } },
52 { KE_KEY, 0x50, { KEY_EMAIL } },
53 { KE_KEY, 0x51, { KEY_WWW } },
54 { KE_KEY, 0x55, { KEY_CALC } },
55 { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */
56 { KE_KEY, 0x5D, { KEY_WLAN } },
57 { KE_KEY, 0x5E, { KEY_WLAN } },
58 { KE_KEY, 0x5F, { KEY_WLAN } },
59 { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
60 { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
61 { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
62 { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
63 { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
64 { KE_KEY, 0x7E, { KEY_BLUETOOTH } },
65 { KE_KEY, 0x7D, { KEY_BLUETOOTH } },
66 { KE_KEY, 0x82, { KEY_CAMERA } },
67 { KE_KEY, 0x88, { KEY_RFKILL } },
68 { KE_KEY, 0x8A, { KEY_PROG1 } },
69 { KE_KEY, 0x95, { KEY_MEDIA } },
70 { KE_KEY, 0x99, { KEY_PHONE } },
71 { KE_KEY, 0xb5, { KEY_CALC } },
72 { KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
73 { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
74 { KE_END, 0},
75};
76
77static struct asus_wmi_driver asus_nb_wmi_driver = {
78 .name = ASUS_NB_WMI_FILE,
79 .owner = THIS_MODULE,
80 .event_guid = ASUS_NB_WMI_EVENT_GUID,
81 .keymap = asus_nb_wmi_keymap,
82 .input_name = "Asus WMI hotkeys",
83 .input_phys = ASUS_NB_WMI_FILE "/input0",
84};
85
86
87static int __init asus_nb_wmi_init(void)
88{
89 return asus_wmi_register_driver(&asus_nb_wmi_driver);
90}
91
92static void __exit asus_nb_wmi_exit(void)
93{
94 asus_wmi_unregister_driver(&asus_nb_wmi_driver);
95}
96
97module_init(asus_nb_wmi_init);
98module_exit(asus_nb_wmi_exit);
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
new file mode 100644
index 000000000000..efc776cb0c66
--- /dev/null
+++ b/drivers/platform/x86/asus-wmi.c
@@ -0,0 +1,1656 @@
1/*
2 * Asus PC WMI hotkey driver
3 *
4 * Copyright(C) 2010 Intel Corporation.
5 * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
6 *
7 * Portions based on wistron_btns.c:
8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
9 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
10 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28
29#include <linux/kernel.h>
30#include <linux/module.h>
31#include <linux/init.h>
32#include <linux/types.h>
33#include <linux/slab.h>
34#include <linux/input.h>
35#include <linux/input/sparse-keymap.h>
36#include <linux/fb.h>
37#include <linux/backlight.h>
38#include <linux/leds.h>
39#include <linux/rfkill.h>
40#include <linux/pci.h>
41#include <linux/pci_hotplug.h>
42#include <linux/hwmon.h>
43#include <linux/hwmon-sysfs.h>
44#include <linux/debugfs.h>
45#include <linux/seq_file.h>
46#include <linux/platform_device.h>
47#include <acpi/acpi_bus.h>
48#include <acpi/acpi_drivers.h>
49
50#include "asus-wmi.h"
51
52MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>, "
53 "Yong Wang <yong.y.wang@intel.com>");
54MODULE_DESCRIPTION("Asus Generic WMI Driver");
55MODULE_LICENSE("GPL");
56
57#define to_platform_driver(drv) \
58 (container_of((drv), struct platform_driver, driver))
59
60#define to_asus_wmi_driver(pdrv) \
61 (container_of((pdrv), struct asus_wmi_driver, platform_driver))
62
63#define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
64
65#define NOTIFY_BRNUP_MIN 0x11
66#define NOTIFY_BRNUP_MAX 0x1f
67#define NOTIFY_BRNDOWN_MIN 0x20
68#define NOTIFY_BRNDOWN_MAX 0x2e
69
70/* WMI Methods */
71#define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */
72#define ASUS_WMI_METHODID_SFBD 0x44424653 /* Set First Boot Device */
73#define ASUS_WMI_METHODID_GLCD 0x44434C47 /* Get LCD status */
74#define ASUS_WMI_METHODID_GPID 0x44495047 /* Get Panel ID?? (Resol) */
75#define ASUS_WMI_METHODID_QMOD 0x444F4D51 /* Quiet MODe */
76#define ASUS_WMI_METHODID_SPLV 0x4C425053 /* Set Panel Light Value */
77#define ASUS_WMI_METHODID_SFUN 0x4E554653 /* FUNCtionalities */
78#define ASUS_WMI_METHODID_SDSP 0x50534453 /* Set DiSPlay output */
79#define ASUS_WMI_METHODID_GDSP 0x50534447 /* Get DiSPlay output */
80#define ASUS_WMI_METHODID_DEVP 0x50564544 /* DEVice Policy */
81#define ASUS_WMI_METHODID_OSVR 0x5256534F /* OS VeRsion */
82#define ASUS_WMI_METHODID_DSTS 0x53544344 /* Device STatuS */
83#define ASUS_WMI_METHODID_DSTS2 0x53545344 /* Device STatuS #2*/
84#define ASUS_WMI_METHODID_BSTS 0x53545342 /* Bios STatuS ? */
85#define ASUS_WMI_METHODID_DEVS 0x53564544 /* DEVice Set */
86#define ASUS_WMI_METHODID_CFVS 0x53564643 /* CPU Frequency Volt Set */
87#define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */
88#define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */
89#define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */
90
91#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
92
93/* Wireless */
94#define ASUS_WMI_DEVID_HW_SWITCH 0x00010001
95#define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002
96#define ASUS_WMI_DEVID_WLAN 0x00010011
97#define ASUS_WMI_DEVID_BLUETOOTH 0x00010013
98#define ASUS_WMI_DEVID_GPS 0x00010015
99#define ASUS_WMI_DEVID_WIMAX 0x00010017
100#define ASUS_WMI_DEVID_WWAN3G 0x00010019
101#define ASUS_WMI_DEVID_UWB 0x00010021
102
103/* Leds */
104/* 0x000200XX and 0x000400XX */
105
106/* Backlight and Brightness */
107#define ASUS_WMI_DEVID_BACKLIGHT 0x00050011
108#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
109#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
110#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */
111
112/* Misc */
113#define ASUS_WMI_DEVID_CAMERA 0x00060013
114
115/* Storage */
116#define ASUS_WMI_DEVID_CARDREADER 0x00080013
117
118/* Input */
119#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
120#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
121
122/* Fan, Thermal */
123#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
124#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012
125
126/* Power */
127#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
128
129/* DSTS masks */
130#define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
131#define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
132#define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000
133#define ASUS_WMI_DSTS_USER_BIT 0x00020000
134#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000
135#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
136#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
137
138struct bios_args {
139 u32 arg0;
140 u32 arg1;
141} __packed;
142
143/*
144 * <platform>/ - debugfs root directory
145 * dev_id - current dev_id
146 * ctrl_param - current ctrl_param
147 * method_id - current method_id
148 * devs - call DEVS(dev_id, ctrl_param) and print result
149 * dsts - call DSTS(dev_id) and print result
150 * call - call method_id(dev_id, ctrl_param) and print result
151 */
152struct asus_wmi_debug {
153 struct dentry *root;
154 u32 method_id;
155 u32 dev_id;
156 u32 ctrl_param;
157};
158
159struct asus_rfkill {
160 struct asus_wmi *asus;
161 struct rfkill *rfkill;
162 u32 dev_id;
163};
164
165struct asus_wmi {
166 int dsts_id;
167 int spec;
168 int sfun;
169
170 struct input_dev *inputdev;
171 struct backlight_device *backlight_device;
172 struct device *hwmon_device;
173 struct platform_device *platform_device;
174
175 struct led_classdev tpd_led;
176 int tpd_led_wk;
177 struct workqueue_struct *led_workqueue;
178 struct work_struct tpd_led_work;
179
180 struct asus_rfkill wlan;
181 struct asus_rfkill bluetooth;
182 struct asus_rfkill wimax;
183 struct asus_rfkill wwan3g;
184
185 struct hotplug_slot *hotplug_slot;
186 struct mutex hotplug_lock;
187 struct mutex wmi_lock;
188 struct workqueue_struct *hotplug_workqueue;
189 struct work_struct hotplug_work;
190
191 struct asus_wmi_debug debug;
192
193 struct asus_wmi_driver *driver;
194};
195
196static int asus_wmi_input_init(struct asus_wmi *asus)
197{
198 int err;
199
200 asus->inputdev = input_allocate_device();
201 if (!asus->inputdev)
202 return -ENOMEM;
203
204 asus->inputdev->name = asus->driver->input_phys;
205 asus->inputdev->phys = asus->driver->input_name;
206 asus->inputdev->id.bustype = BUS_HOST;
207 asus->inputdev->dev.parent = &asus->platform_device->dev;
208
209 err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL);
210 if (err)
211 goto err_free_dev;
212
213 err = input_register_device(asus->inputdev);
214 if (err)
215 goto err_free_keymap;
216
217 return 0;
218
219err_free_keymap:
220 sparse_keymap_free(asus->inputdev);
221err_free_dev:
222 input_free_device(asus->inputdev);
223 return err;
224}
225
226static void asus_wmi_input_exit(struct asus_wmi *asus)
227{
228 if (asus->inputdev) {
229 sparse_keymap_free(asus->inputdev);
230 input_unregister_device(asus->inputdev);
231 }
232
233 asus->inputdev = NULL;
234}
235
236static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
237 u32 *retval)
238{
239 struct bios_args args = {
240 .arg0 = arg0,
241 .arg1 = arg1,
242 };
243 struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
244 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
245 acpi_status status;
246 union acpi_object *obj;
247 u32 tmp;
248
249 status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id,
250 &input, &output);
251
252 if (ACPI_FAILURE(status))
253 goto exit;
254
255 obj = (union acpi_object *)output.pointer;
256 if (obj && obj->type == ACPI_TYPE_INTEGER)
257 tmp = (u32) obj->integer.value;
258 else
259 tmp = 0;
260
261 if (retval)
262 *retval = tmp;
263
264 kfree(obj);
265
266exit:
267 if (ACPI_FAILURE(status))
268 return -EIO;
269
270 if (tmp == ASUS_WMI_UNSUPPORTED_METHOD)
271 return -ENODEV;
272
273 return 0;
274}
275
276static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval)
277{
278 return asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval);
279}
280
281static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
282 u32 *retval)
283{
284 return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id,
285 ctrl_param, retval);
286}
287
288/* Helper for special devices with magic return codes */
289static int asus_wmi_get_devstate_bits(struct asus_wmi *asus,
290 u32 dev_id, u32 mask)
291{
292 u32 retval = 0;
293 int err;
294
295 err = asus_wmi_get_devstate(asus, dev_id, &retval);
296
297 if (err < 0)
298 return err;
299
300 if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT))
301 return -ENODEV;
302
303 if (mask == ASUS_WMI_DSTS_STATUS_BIT) {
304 if (retval & ASUS_WMI_DSTS_UNKNOWN_BIT)
305 return -ENODEV;
306 }
307
308 return retval & mask;
309}
310
311static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id)
312{
313 return asus_wmi_get_devstate_bits(asus, dev_id,
314 ASUS_WMI_DSTS_STATUS_BIT);
315}
316
317/*
318 * LEDs
319 */
320/*
321 * These functions actually update the LED's, and are called from a
322 * workqueue. By doing this as separate work rather than when the LED
323 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
324 * potentially bad time, such as a timer interrupt.
325 */
326static void tpd_led_update(struct work_struct *work)
327{
328 int ctrl_param;
329 struct asus_wmi *asus;
330
331 asus = container_of(work, struct asus_wmi, tpd_led_work);
332
333 ctrl_param = asus->tpd_led_wk;
334 asus_wmi_set_devstate(ASUS_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL);
335}
336
337static void tpd_led_set(struct led_classdev *led_cdev,
338 enum led_brightness value)
339{
340 struct asus_wmi *asus;
341
342 asus = container_of(led_cdev, struct asus_wmi, tpd_led);
343
344 asus->tpd_led_wk = !!value;
345 queue_work(asus->led_workqueue, &asus->tpd_led_work);
346}
347
348static int read_tpd_led_state(struct asus_wmi *asus)
349{
350 return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED);
351}
352
353static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
354{
355 struct asus_wmi *asus;
356
357 asus = container_of(led_cdev, struct asus_wmi, tpd_led);
358
359 return read_tpd_led_state(asus);
360}
361
362static int asus_wmi_led_init(struct asus_wmi *asus)
363{
364 int rv;
365
366 if (read_tpd_led_state(asus) < 0)
367 return 0;
368
369 asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
370 if (!asus->led_workqueue)
371 return -ENOMEM;
372 INIT_WORK(&asus->tpd_led_work, tpd_led_update);
373
374 asus->tpd_led.name = "asus::touchpad";
375 asus->tpd_led.brightness_set = tpd_led_set;
376 asus->tpd_led.brightness_get = tpd_led_get;
377 asus->tpd_led.max_brightness = 1;
378
379 rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led);
380 if (rv) {
381 destroy_workqueue(asus->led_workqueue);
382 return rv;
383 }
384
385 return 0;
386}
387
388static void asus_wmi_led_exit(struct asus_wmi *asus)
389{
390 if (asus->tpd_led.dev)
391 led_classdev_unregister(&asus->tpd_led);
392 if (asus->led_workqueue)
393 destroy_workqueue(asus->led_workqueue);
394}
395
396/*
397 * PCI hotplug (for wlan rfkill)
398 */
399static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus)
400{
401 int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
402
403 if (result < 0)
404 return false;
405 return !result;
406}
407
408static void asus_rfkill_hotplug(struct asus_wmi *asus)
409{
410 struct pci_dev *dev;
411 struct pci_bus *bus;
412 bool blocked;
413 bool absent;
414 u32 l;
415
416 mutex_lock(&asus->wmi_lock);
417 blocked = asus_wlan_rfkill_blocked(asus);
418 mutex_unlock(&asus->wmi_lock);
419
420 mutex_lock(&asus->hotplug_lock);
421
422 if (asus->wlan.rfkill)
423 rfkill_set_sw_state(asus->wlan.rfkill, blocked);
424
425 if (asus->hotplug_slot) {
426 bus = pci_find_bus(0, 1);
427 if (!bus) {
428 pr_warning("Unable to find PCI bus 1?\n");
429 goto out_unlock;
430 }
431
432 if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
433 pr_err("Unable to read PCI config space?\n");
434 goto out_unlock;
435 }
436 absent = (l == 0xffffffff);
437
438 if (blocked != absent) {
439 pr_warning("BIOS says wireless lan is %s, "
440 "but the pci device is %s\n",
441 blocked ? "blocked" : "unblocked",
442 absent ? "absent" : "present");
443 pr_warning("skipped wireless hotplug as probably "
444 "inappropriate for this model\n");
445 goto out_unlock;
446 }
447
448 if (!blocked) {
449 dev = pci_get_slot(bus, 0);
450 if (dev) {
451 /* Device already present */
452 pci_dev_put(dev);
453 goto out_unlock;
454 }
455 dev = pci_scan_single_device(bus, 0);
456 if (dev) {
457 pci_bus_assign_resources(bus);
458 if (pci_bus_add_device(dev))
459 pr_err("Unable to hotplug wifi\n");
460 }
461 } else {
462 dev = pci_get_slot(bus, 0);
463 if (dev) {
464 pci_remove_bus_device(dev);
465 pci_dev_put(dev);
466 }
467 }
468 }
469
470out_unlock:
471 mutex_unlock(&asus->hotplug_lock);
472}
473
474static void asus_rfkill_notify(acpi_handle handle, u32 event, void *data)
475{
476 struct asus_wmi *asus = data;
477
478 if (event != ACPI_NOTIFY_BUS_CHECK)
479 return;
480
481 /*
482 * We can't call directly asus_rfkill_hotplug because most
483 * of the time WMBC is still being executed and not reetrant.
484 * There is currently no way to tell ACPICA that we want this
485 * method to be serialized, we schedule a asus_rfkill_hotplug
486 * call later, in a safer context.
487 */
488 queue_work(asus->hotplug_workqueue, &asus->hotplug_work);
489}
490
491static int asus_register_rfkill_notifier(struct asus_wmi *asus, char *node)
492{
493 acpi_status status;
494 acpi_handle handle;
495
496 status = acpi_get_handle(NULL, node, &handle);
497
498 if (ACPI_SUCCESS(status)) {
499 status = acpi_install_notify_handler(handle,
500 ACPI_SYSTEM_NOTIFY,
501 asus_rfkill_notify, asus);
502 if (ACPI_FAILURE(status))
503 pr_warning("Failed to register notify on %s\n", node);
504 } else
505 return -ENODEV;
506
507 return 0;
508}
509
510static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node)
511{
512 acpi_status status = AE_OK;
513 acpi_handle handle;
514
515 status = acpi_get_handle(NULL, node, &handle);
516
517 if (ACPI_SUCCESS(status)) {
518 status = acpi_remove_notify_handler(handle,
519 ACPI_SYSTEM_NOTIFY,
520 asus_rfkill_notify);
521 if (ACPI_FAILURE(status))
522 pr_err("Error removing rfkill notify handler %s\n",
523 node);
524 }
525}
526
527static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot,
528 u8 *value)
529{
530 struct asus_wmi *asus = hotplug_slot->private;
531 int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
532
533 if (result < 0)
534 return result;
535
536 *value = !!result;
537 return 0;
538}
539
540static void asus_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
541{
542 kfree(hotplug_slot->info);
543 kfree(hotplug_slot);
544}
545
546static struct hotplug_slot_ops asus_hotplug_slot_ops = {
547 .owner = THIS_MODULE,
548 .get_adapter_status = asus_get_adapter_status,
549 .get_power_status = asus_get_adapter_status,
550};
551
552static void asus_hotplug_work(struct work_struct *work)
553{
554 struct asus_wmi *asus;
555
556 asus = container_of(work, struct asus_wmi, hotplug_work);
557 asus_rfkill_hotplug(asus);
558}
559
560static int asus_setup_pci_hotplug(struct asus_wmi *asus)
561{
562 int ret = -ENOMEM;
563 struct pci_bus *bus = pci_find_bus(0, 1);
564
565 if (!bus) {
566 pr_err("Unable to find wifi PCI bus\n");
567 return -ENODEV;
568 }
569
570 asus->hotplug_workqueue =
571 create_singlethread_workqueue("hotplug_workqueue");
572 if (!asus->hotplug_workqueue)
573 goto error_workqueue;
574
575 INIT_WORK(&asus->hotplug_work, asus_hotplug_work);
576
577 asus->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
578 if (!asus->hotplug_slot)
579 goto error_slot;
580
581 asus->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
582 GFP_KERNEL);
583 if (!asus->hotplug_slot->info)
584 goto error_info;
585
586 asus->hotplug_slot->private = asus;
587 asus->hotplug_slot->release = &asus_cleanup_pci_hotplug;
588 asus->hotplug_slot->ops = &asus_hotplug_slot_ops;
589 asus_get_adapter_status(asus->hotplug_slot,
590 &asus->hotplug_slot->info->adapter_status);
591
592 ret = pci_hp_register(asus->hotplug_slot, bus, 0, "asus-wifi");
593 if (ret) {
594 pr_err("Unable to register hotplug slot - %d\n", ret);
595 goto error_register;
596 }
597
598 return 0;
599
600error_register:
601 kfree(asus->hotplug_slot->info);
602error_info:
603 kfree(asus->hotplug_slot);
604 asus->hotplug_slot = NULL;
605error_slot:
606 destroy_workqueue(asus->hotplug_workqueue);
607error_workqueue:
608 return ret;
609}
610
611/*
612 * Rfkill devices
613 */
614static int asus_rfkill_set(void *data, bool blocked)
615{
616 struct asus_rfkill *priv = data;
617 u32 ctrl_param = !blocked;
618
619 return asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL);
620}
621
622static void asus_rfkill_query(struct rfkill *rfkill, void *data)
623{
624 struct asus_rfkill *priv = data;
625 int result;
626
627 result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id);
628
629 if (result < 0)
630 return;
631
632 rfkill_set_sw_state(priv->rfkill, !result);
633}
634
635static int asus_rfkill_wlan_set(void *data, bool blocked)
636{
637 struct asus_rfkill *priv = data;
638 struct asus_wmi *asus = priv->asus;
639 int ret;
640
641 /*
642 * This handler is enabled only if hotplug is enabled.
643 * In this case, the asus_wmi_set_devstate() will
644 * trigger a wmi notification and we need to wait
645 * this call to finish before being able to call
646 * any wmi method
647 */
648 mutex_lock(&asus->wmi_lock);
649 ret = asus_rfkill_set(data, blocked);
650 mutex_unlock(&asus->wmi_lock);
651 return ret;
652}
653
654static const struct rfkill_ops asus_rfkill_wlan_ops = {
655 .set_block = asus_rfkill_wlan_set,
656 .query = asus_rfkill_query,
657};
658
659static const struct rfkill_ops asus_rfkill_ops = {
660 .set_block = asus_rfkill_set,
661 .query = asus_rfkill_query,
662};
663
664static int asus_new_rfkill(struct asus_wmi *asus,
665 struct asus_rfkill *arfkill,
666 const char *name, enum rfkill_type type, int dev_id)
667{
668 int result = asus_wmi_get_devstate_simple(asus, dev_id);
669 struct rfkill **rfkill = &arfkill->rfkill;
670
671 if (result < 0)
672 return result;
673
674 arfkill->dev_id = dev_id;
675 arfkill->asus = asus;
676
677 if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless)
678 *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
679 &asus_rfkill_wlan_ops, arfkill);
680 else
681 *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
682 &asus_rfkill_ops, arfkill);
683
684 if (!*rfkill)
685 return -EINVAL;
686
687 rfkill_init_sw_state(*rfkill, !result);
688 result = rfkill_register(*rfkill);
689 if (result) {
690 rfkill_destroy(*rfkill);
691 *rfkill = NULL;
692 return result;
693 }
694 return 0;
695}
696
697static void asus_wmi_rfkill_exit(struct asus_wmi *asus)
698{
699 asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5");
700 asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6");
701 asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7");
702 if (asus->wlan.rfkill) {
703 rfkill_unregister(asus->wlan.rfkill);
704 rfkill_destroy(asus->wlan.rfkill);
705 asus->wlan.rfkill = NULL;
706 }
707 /*
708 * Refresh pci hotplug in case the rfkill state was changed after
709 * asus_unregister_rfkill_notifier()
710 */
711 asus_rfkill_hotplug(asus);
712 if (asus->hotplug_slot)
713 pci_hp_deregister(asus->hotplug_slot);
714 if (asus->hotplug_workqueue)
715 destroy_workqueue(asus->hotplug_workqueue);
716
717 if (asus->bluetooth.rfkill) {
718 rfkill_unregister(asus->bluetooth.rfkill);
719 rfkill_destroy(asus->bluetooth.rfkill);
720 asus->bluetooth.rfkill = NULL;
721 }
722 if (asus->wimax.rfkill) {
723 rfkill_unregister(asus->wimax.rfkill);
724 rfkill_destroy(asus->wimax.rfkill);
725 asus->wimax.rfkill = NULL;
726 }
727 if (asus->wwan3g.rfkill) {
728 rfkill_unregister(asus->wwan3g.rfkill);
729 rfkill_destroy(asus->wwan3g.rfkill);
730 asus->wwan3g.rfkill = NULL;
731 }
732}
733
734static int asus_wmi_rfkill_init(struct asus_wmi *asus)
735{
736 int result = 0;
737
738 mutex_init(&asus->hotplug_lock);
739 mutex_init(&asus->wmi_lock);
740
741 result = asus_new_rfkill(asus, &asus->wlan, "asus-wlan",
742 RFKILL_TYPE_WLAN, ASUS_WMI_DEVID_WLAN);
743
744 if (result && result != -ENODEV)
745 goto exit;
746
747 result = asus_new_rfkill(asus, &asus->bluetooth,
748 "asus-bluetooth", RFKILL_TYPE_BLUETOOTH,
749 ASUS_WMI_DEVID_BLUETOOTH);
750
751 if (result && result != -ENODEV)
752 goto exit;
753
754 result = asus_new_rfkill(asus, &asus->wimax, "asus-wimax",
755 RFKILL_TYPE_WIMAX, ASUS_WMI_DEVID_WIMAX);
756
757 if (result && result != -ENODEV)
758 goto exit;
759
760 result = asus_new_rfkill(asus, &asus->wwan3g, "asus-wwan3g",
761 RFKILL_TYPE_WWAN, ASUS_WMI_DEVID_WWAN3G);
762
763 if (result && result != -ENODEV)
764 goto exit;
765
766 if (!asus->driver->hotplug_wireless)
767 goto exit;
768
769 result = asus_setup_pci_hotplug(asus);
770 /*
771 * If we get -EBUSY then something else is handling the PCI hotplug -
772 * don't fail in this case
773 */
774 if (result == -EBUSY)
775 result = 0;
776
777 asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P5");
778 asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P6");
779 asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P7");
780 /*
781 * Refresh pci hotplug in case the rfkill state was changed during
782 * setup.
783 */
784 asus_rfkill_hotplug(asus);
785
786exit:
787 if (result && result != -ENODEV)
788 asus_wmi_rfkill_exit(asus);
789
790 if (result == -ENODEV)
791 result = 0;
792
793 return result;
794}
795
796/*
797 * Hwmon device
798 */
799static ssize_t asus_hwmon_pwm1(struct device *dev,
800 struct device_attribute *attr,
801 char *buf)
802{
803 struct asus_wmi *asus = dev_get_drvdata(dev);
804 u32 value;
805 int err;
806
807 err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value);
808
809 if (err < 0)
810 return err;
811
812 value |= 0xFF;
813
814 if (value == 1) /* Low Speed */
815 value = 85;
816 else if (value == 2)
817 value = 170;
818 else if (value == 3)
819 value = 255;
820 else if (value != 0) {
821 pr_err("Unknown fan speed %#x", value);
822 value = -1;
823 }
824
825 return sprintf(buf, "%d\n", value);
826}
827
828static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0);
829
830static ssize_t
831show_name(struct device *dev, struct device_attribute *attr, char *buf)
832{
833 return sprintf(buf, "asus\n");
834}
835static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
836
837static struct attribute *hwmon_attributes[] = {
838 &sensor_dev_attr_pwm1.dev_attr.attr,
839 &sensor_dev_attr_name.dev_attr.attr,
840 NULL
841};
842
843static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
844 struct attribute *attr, int idx)
845{
846 struct device *dev = container_of(kobj, struct device, kobj);
847 struct platform_device *pdev = to_platform_device(dev->parent);
848 struct asus_wmi *asus = platform_get_drvdata(pdev);
849 bool ok = true;
850 int dev_id = -1;
851 u32 value = ASUS_WMI_UNSUPPORTED_METHOD;
852
853 if (attr == &sensor_dev_attr_pwm1.dev_attr.attr)
854 dev_id = ASUS_WMI_DEVID_FAN_CTRL;
855
856 if (dev_id != -1) {
857 int err = asus_wmi_get_devstate(asus, dev_id, &value);
858
859 if (err < 0)
860 return err;
861 }
862
863 if (dev_id == ASUS_WMI_DEVID_FAN_CTRL) {
864 /*
865 * We need to find a better way, probably using sfun,
866 * bits or spec ...
867 * Currently we disable it if:
868 * - ASUS_WMI_UNSUPPORTED_METHOD is returned
869 * - reverved bits are non-zero
870 * - sfun and presence bit are not set
871 */
872 if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
873 || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT)))
874 ok = false;
875 }
876
877 return ok ? attr->mode : 0;
878}
879
880static struct attribute_group hwmon_attribute_group = {
881 .is_visible = asus_hwmon_sysfs_is_visible,
882 .attrs = hwmon_attributes
883};
884
885static void asus_wmi_hwmon_exit(struct asus_wmi *asus)
886{
887 struct device *hwmon;
888
889 hwmon = asus->hwmon_device;
890 if (!hwmon)
891 return;
892 sysfs_remove_group(&hwmon->kobj, &hwmon_attribute_group);
893 hwmon_device_unregister(hwmon);
894 asus->hwmon_device = NULL;
895}
896
897static int asus_wmi_hwmon_init(struct asus_wmi *asus)
898{
899 struct device *hwmon;
900 int result;
901
902 hwmon = hwmon_device_register(&asus->platform_device->dev);
903 if (IS_ERR(hwmon)) {
904 pr_err("Could not register asus hwmon device\n");
905 return PTR_ERR(hwmon);
906 }
907 asus->hwmon_device = hwmon;
908 result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group);
909 if (result)
910 asus_wmi_hwmon_exit(asus);
911 return result;
912}
913
914/*
915 * Backlight
916 */
917static int read_backlight_power(struct asus_wmi *asus)
918{
919 int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT);
920
921 if (ret < 0)
922 return ret;
923
924 return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
925}
926
927static int read_brightness_max(struct asus_wmi *asus)
928{
929 u32 retval;
930 int err;
931
932 err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval);
933
934 if (err < 0)
935 return err;
936
937 retval = retval & ASUS_WMI_DSTS_MAX_BRIGTH_MASK;
938 retval >>= 8;
939
940 if (!retval)
941 return -ENODEV;
942
943 return retval;
944}
945
946static int read_brightness(struct backlight_device *bd)
947{
948 struct asus_wmi *asus = bl_get_data(bd);
949 u32 retval;
950 int err;
951
952 err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval);
953
954 if (err < 0)
955 return err;
956
957 return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
958}
959
960static int update_bl_status(struct backlight_device *bd)
961{
962 struct asus_wmi *asus = bl_get_data(bd);
963 u32 ctrl_param;
964 int power, err;
965
966 ctrl_param = bd->props.brightness;
967
968 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
969 ctrl_param, NULL);
970
971 if (err < 0)
972 return err;
973
974 power = read_backlight_power(asus);
975 if (power != -ENODEV && bd->props.power != power) {
976 ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK);
977 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT,
978 ctrl_param, NULL);
979 }
980 return err;
981}
982
983static const struct backlight_ops asus_wmi_bl_ops = {
984 .get_brightness = read_brightness,
985 .update_status = update_bl_status,
986};
987
988static int asus_wmi_backlight_notify(struct asus_wmi *asus, int code)
989{
990 struct backlight_device *bd = asus->backlight_device;
991 int old = bd->props.brightness;
992 int new = old;
993
994 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
995 new = code - NOTIFY_BRNUP_MIN + 1;
996 else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
997 new = code - NOTIFY_BRNDOWN_MIN;
998
999 bd->props.brightness = new;
1000 backlight_update_status(bd);
1001 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
1002
1003 return old;
1004}
1005
1006static int asus_wmi_backlight_init(struct asus_wmi *asus)
1007{
1008 struct backlight_device *bd;
1009 struct backlight_properties props;
1010 int max;
1011 int power;
1012
1013 max = read_brightness_max(asus);
1014
1015 if (max == -ENODEV)
1016 max = 0;
1017 else if (max < 0)
1018 return max;
1019
1020 power = read_backlight_power(asus);
1021
1022 if (power == -ENODEV)
1023 power = FB_BLANK_UNBLANK;
1024 else if (power < 0)
1025 return power;
1026
1027 memset(&props, 0, sizeof(struct backlight_properties));
1028 props.max_brightness = max;
1029 bd = backlight_device_register(asus->driver->name,
1030 &asus->platform_device->dev, asus,
1031 &asus_wmi_bl_ops, &props);
1032 if (IS_ERR(bd)) {
1033 pr_err("Could not register backlight device\n");
1034 return PTR_ERR(bd);
1035 }
1036
1037 asus->backlight_device = bd;
1038
1039 bd->props.brightness = read_brightness(bd);
1040 bd->props.power = power;
1041 backlight_update_status(bd);
1042
1043 return 0;
1044}
1045
1046static void asus_wmi_backlight_exit(struct asus_wmi *asus)
1047{
1048 if (asus->backlight_device)
1049 backlight_device_unregister(asus->backlight_device);
1050
1051 asus->backlight_device = NULL;
1052}
1053
1054static void asus_wmi_notify(u32 value, void *context)
1055{
1056 struct asus_wmi *asus = context;
1057 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
1058 union acpi_object *obj;
1059 acpi_status status;
1060 int code;
1061 int orig_code;
1062
1063 status = wmi_get_event_data(value, &response);
1064 if (status != AE_OK) {
1065 pr_err("bad event status 0x%x\n", status);
1066 return;
1067 }
1068
1069 obj = (union acpi_object *)response.pointer;
1070
1071 if (!obj || obj->type != ACPI_TYPE_INTEGER)
1072 goto exit;
1073
1074 code = obj->integer.value;
1075 orig_code = code;
1076
1077 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
1078 code = NOTIFY_BRNUP_MIN;
1079 else if (code >= NOTIFY_BRNDOWN_MIN &&
1080 code <= NOTIFY_BRNDOWN_MAX)
1081 code = NOTIFY_BRNDOWN_MIN;
1082
1083 if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
1084 if (!acpi_video_backlight_support())
1085 asus_wmi_backlight_notify(asus, orig_code);
1086 } else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true))
1087 pr_info("Unknown key %x pressed\n", code);
1088
1089exit:
1090 kfree(obj);
1091}
1092
1093/*
1094 * Sys helpers
1095 */
1096static int parse_arg(const char *buf, unsigned long count, int *val)
1097{
1098 if (!count)
1099 return 0;
1100 if (sscanf(buf, "%i", val) != 1)
1101 return -EINVAL;
1102 return count;
1103}
1104
1105static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid,
1106 const char *buf, size_t count)
1107{
1108 u32 retval;
1109 int rv, err, value;
1110
1111 value = asus_wmi_get_devstate_simple(asus, devid);
1112 if (value == -ENODEV) /* Check device presence */
1113 return value;
1114
1115 rv = parse_arg(buf, count, &value);
1116 err = asus_wmi_set_devstate(devid, value, &retval);
1117
1118 if (err < 0)
1119 return err;
1120
1121 return rv;
1122}
1123
1124static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf)
1125{
1126 int value = asus_wmi_get_devstate_simple(asus, devid);
1127
1128 if (value < 0)
1129 return value;
1130
1131 return sprintf(buf, "%d\n", value);
1132}
1133
1134#define ASUS_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \
1135 static ssize_t show_##_name(struct device *dev, \
1136 struct device_attribute *attr, \
1137 char *buf) \
1138 { \
1139 struct asus_wmi *asus = dev_get_drvdata(dev); \
1140 \
1141 return show_sys_wmi(asus, _cm, buf); \
1142 } \
1143 static ssize_t store_##_name(struct device *dev, \
1144 struct device_attribute *attr, \
1145 const char *buf, size_t count) \
1146 { \
1147 struct asus_wmi *asus = dev_get_drvdata(dev); \
1148 \
1149 return store_sys_wmi(asus, _cm, buf, count); \
1150 } \
1151 static struct device_attribute dev_attr_##_name = { \
1152 .attr = { \
1153 .name = __stringify(_name), \
1154 .mode = _mode }, \
1155 .show = show_##_name, \
1156 .store = store_##_name, \
1157 }
1158
1159ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD);
1160ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA);
1161ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER);
1162
1163static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
1164 const char *buf, size_t count)
1165{
1166 int value;
1167
1168 if (!count || sscanf(buf, "%i", &value) != 1)
1169 return -EINVAL;
1170 if (value < 0 || value > 2)
1171 return -EINVAL;
1172
1173 return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL);
1174}
1175
1176static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
1177
1178static struct attribute *platform_attributes[] = {
1179 &dev_attr_cpufv.attr,
1180 &dev_attr_camera.attr,
1181 &dev_attr_cardr.attr,
1182 &dev_attr_touchpad.attr,
1183 NULL
1184};
1185
1186static mode_t asus_sysfs_is_visible(struct kobject *kobj,
1187 struct attribute *attr, int idx)
1188{
1189 struct device *dev = container_of(kobj, struct device, kobj);
1190 struct platform_device *pdev = to_platform_device(dev);
1191 struct asus_wmi *asus = platform_get_drvdata(pdev);
1192 bool ok = true;
1193 int devid = -1;
1194
1195 if (attr == &dev_attr_camera.attr)
1196 devid = ASUS_WMI_DEVID_CAMERA;
1197 else if (attr == &dev_attr_cardr.attr)
1198 devid = ASUS_WMI_DEVID_CARDREADER;
1199 else if (attr == &dev_attr_touchpad.attr)
1200 devid = ASUS_WMI_DEVID_TOUCHPAD;
1201
1202 if (devid != -1)
1203 ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
1204
1205 return ok ? attr->mode : 0;
1206}
1207
1208static struct attribute_group platform_attribute_group = {
1209 .is_visible = asus_sysfs_is_visible,
1210 .attrs = platform_attributes
1211};
1212
1213static void asus_wmi_sysfs_exit(struct platform_device *device)
1214{
1215 sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
1216}
1217
1218static int asus_wmi_sysfs_init(struct platform_device *device)
1219{
1220 return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
1221}
1222
1223/*
1224 * Platform device
1225 */
1226static int __init asus_wmi_platform_init(struct asus_wmi *asus)
1227{
1228 int rv;
1229
1230 /* INIT enable hotkeys on some models */
1231 if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv))
1232 pr_info("Initialization: %#x", rv);
1233
1234 /* We don't know yet what to do with this version... */
1235 if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) {
1236 pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF);
1237 asus->spec = rv;
1238 }
1239
1240 /*
1241 * The SFUN method probably allows the original driver to get the list
1242 * of features supported by a given model. For now, 0x0100 or 0x0800
1243 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
1244 * The significance of others is yet to be found.
1245 */
1246 if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) {
1247 pr_info("SFUN value: %#x", rv);
1248 asus->sfun = rv;
1249 }
1250
1251 /*
1252 * Eee PC and Notebooks seems to have different method_id for DSTS,
1253 * but it may also be related to the BIOS's SPEC.
1254 * Note, on most Eeepc, there is no way to check if a method exist
1255 * or note, while on notebooks, they returns 0xFFFFFFFE on failure,
1256 * but once again, SPEC may probably be used for that kind of things.
1257 */
1258 if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL))
1259 asus->dsts_id = ASUS_WMI_METHODID_DSTS;
1260 else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL))
1261 asus->dsts_id = ASUS_WMI_METHODID_DSTS2;
1262
1263 if (!asus->dsts_id) {
1264 pr_err("Can't find DSTS");
1265 return -ENODEV;
1266 }
1267
1268 return asus_wmi_sysfs_init(asus->platform_device);
1269}
1270
1271static void asus_wmi_platform_exit(struct asus_wmi *asus)
1272{
1273 asus_wmi_sysfs_exit(asus->platform_device);
1274}
1275
1276/*
1277 * debugfs
1278 */
1279struct asus_wmi_debugfs_node {
1280 struct asus_wmi *asus;
1281 char *name;
1282 int (*show) (struct seq_file *m, void *data);
1283};
1284
1285static int show_dsts(struct seq_file *m, void *data)
1286{
1287 struct asus_wmi *asus = m->private;
1288 int err;
1289 u32 retval = -1;
1290
1291 err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval);
1292
1293 if (err < 0)
1294 return err;
1295
1296 seq_printf(m, "DSTS(%#x) = %#x\n", asus->debug.dev_id, retval);
1297
1298 return 0;
1299}
1300
1301static int show_devs(struct seq_file *m, void *data)
1302{
1303 struct asus_wmi *asus = m->private;
1304 int err;
1305 u32 retval = -1;
1306
1307 err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param,
1308 &retval);
1309
1310 if (err < 0)
1311 return err;
1312
1313 seq_printf(m, "DEVS(%#x, %#x) = %#x\n", asus->debug.dev_id,
1314 asus->debug.ctrl_param, retval);
1315
1316 return 0;
1317}
1318
1319static int show_call(struct seq_file *m, void *data)
1320{
1321 struct asus_wmi *asus = m->private;
1322 struct bios_args args = {
1323 .arg0 = asus->debug.dev_id,
1324 .arg1 = asus->debug.ctrl_param,
1325 };
1326 struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
1327 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1328 union acpi_object *obj;
1329 acpi_status status;
1330
1331 status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID,
1332 1, asus->debug.method_id,
1333 &input, &output);
1334
1335 if (ACPI_FAILURE(status))
1336 return -EIO;
1337
1338 obj = (union acpi_object *)output.pointer;
1339 if (obj && obj->type == ACPI_TYPE_INTEGER)
1340 seq_printf(m, "%#x(%#x, %#x) = %#x\n", asus->debug.method_id,
1341 asus->debug.dev_id, asus->debug.ctrl_param,
1342 (u32) obj->integer.value);
1343 else
1344 seq_printf(m, "%#x(%#x, %#x) = t:%d\n", asus->debug.method_id,
1345 asus->debug.dev_id, asus->debug.ctrl_param,
1346 obj ? obj->type : -1);
1347
1348 kfree(obj);
1349
1350 return 0;
1351}
1352
1353static struct asus_wmi_debugfs_node asus_wmi_debug_files[] = {
1354 {NULL, "devs", show_devs},
1355 {NULL, "dsts", show_dsts},
1356 {NULL, "call", show_call},
1357};
1358
1359static int asus_wmi_debugfs_open(struct inode *inode, struct file *file)
1360{
1361 struct asus_wmi_debugfs_node *node = inode->i_private;
1362
1363 return single_open(file, node->show, node->asus);
1364}
1365
1366static const struct file_operations asus_wmi_debugfs_io_ops = {
1367 .owner = THIS_MODULE,
1368 .open = asus_wmi_debugfs_open,
1369 .read = seq_read,
1370 .llseek = seq_lseek,
1371 .release = single_release,
1372};
1373
1374static void asus_wmi_debugfs_exit(struct asus_wmi *asus)
1375{
1376 debugfs_remove_recursive(asus->debug.root);
1377}
1378
1379static int asus_wmi_debugfs_init(struct asus_wmi *asus)
1380{
1381 struct dentry *dent;
1382 int i;
1383
1384 asus->debug.root = debugfs_create_dir(asus->driver->name, NULL);
1385 if (!asus->debug.root) {
1386 pr_err("failed to create debugfs directory");
1387 goto error_debugfs;
1388 }
1389
1390 dent = debugfs_create_x32("method_id", S_IRUGO | S_IWUSR,
1391 asus->debug.root, &asus->debug.method_id);
1392 if (!dent)
1393 goto error_debugfs;
1394
1395 dent = debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR,
1396 asus->debug.root, &asus->debug.dev_id);
1397 if (!dent)
1398 goto error_debugfs;
1399
1400 dent = debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR,
1401 asus->debug.root, &asus->debug.ctrl_param);
1402 if (!dent)
1403 goto error_debugfs;
1404
1405 for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) {
1406 struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i];
1407
1408 node->asus = asus;
1409 dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
1410 asus->debug.root, node,
1411 &asus_wmi_debugfs_io_ops);
1412 if (!dent) {
1413 pr_err("failed to create debug file: %s\n", node->name);
1414 goto error_debugfs;
1415 }
1416 }
1417
1418 return 0;
1419
1420error_debugfs:
1421 asus_wmi_debugfs_exit(asus);
1422 return -ENOMEM;
1423}
1424
1425/*
1426 * WMI Driver
1427 */
1428static int asus_wmi_add(struct platform_device *pdev)
1429{
1430 struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
1431 struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
1432 struct asus_wmi *asus;
1433 acpi_status status;
1434 int err;
1435
1436 asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL);
1437 if (!asus)
1438 return -ENOMEM;
1439
1440 asus->driver = wdrv;
1441 asus->platform_device = pdev;
1442 wdrv->platform_device = pdev;
1443 platform_set_drvdata(asus->platform_device, asus);
1444
1445 if (wdrv->quirks)
1446 wdrv->quirks(asus->driver);
1447
1448 err = asus_wmi_platform_init(asus);
1449 if (err)
1450 goto fail_platform;
1451
1452 err = asus_wmi_input_init(asus);
1453 if (err)
1454 goto fail_input;
1455
1456 err = asus_wmi_hwmon_init(asus);
1457 if (err)
1458 goto fail_hwmon;
1459
1460 err = asus_wmi_led_init(asus);
1461 if (err)
1462 goto fail_leds;
1463
1464 err = asus_wmi_rfkill_init(asus);
1465 if (err)
1466 goto fail_rfkill;
1467
1468 if (!acpi_video_backlight_support()) {
1469 err = asus_wmi_backlight_init(asus);
1470 if (err && err != -ENODEV)
1471 goto fail_backlight;
1472 } else
1473 pr_info("Backlight controlled by ACPI video driver\n");
1474
1475 status = wmi_install_notify_handler(asus->driver->event_guid,
1476 asus_wmi_notify, asus);
1477 if (ACPI_FAILURE(status)) {
1478 pr_err("Unable to register notify handler - %d\n", status);
1479 err = -ENODEV;
1480 goto fail_wmi_handler;
1481 }
1482
1483 err = asus_wmi_debugfs_init(asus);
1484 if (err)
1485 goto fail_debugfs;
1486
1487 return 0;
1488
1489fail_debugfs:
1490 wmi_remove_notify_handler(asus->driver->event_guid);
1491fail_wmi_handler:
1492 asus_wmi_backlight_exit(asus);
1493fail_backlight:
1494 asus_wmi_rfkill_exit(asus);
1495fail_rfkill:
1496 asus_wmi_led_exit(asus);
1497fail_leds:
1498 asus_wmi_hwmon_exit(asus);
1499fail_hwmon:
1500 asus_wmi_input_exit(asus);
1501fail_input:
1502 asus_wmi_platform_exit(asus);
1503fail_platform:
1504 kfree(asus);
1505 return err;
1506}
1507
1508static int asus_wmi_remove(struct platform_device *device)
1509{
1510 struct asus_wmi *asus;
1511
1512 asus = platform_get_drvdata(device);
1513 wmi_remove_notify_handler(asus->driver->event_guid);
1514 asus_wmi_backlight_exit(asus);
1515 asus_wmi_input_exit(asus);
1516 asus_wmi_hwmon_exit(asus);
1517 asus_wmi_led_exit(asus);
1518 asus_wmi_rfkill_exit(asus);
1519 asus_wmi_debugfs_exit(asus);
1520 asus_wmi_platform_exit(asus);
1521
1522 kfree(asus);
1523 return 0;
1524}
1525
1526/*
1527 * Platform driver - hibernate/resume callbacks
1528 */
1529static int asus_hotk_thaw(struct device *device)
1530{
1531 struct asus_wmi *asus = dev_get_drvdata(device);
1532
1533 if (asus->wlan.rfkill) {
1534 bool wlan;
1535
1536 /*
1537 * Work around bios bug - acpi _PTS turns off the wireless led
1538 * during suspend. Normally it restores it on resume, but
1539 * we should kick it ourselves in case hibernation is aborted.
1540 */
1541 wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
1542 asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL);
1543 }
1544
1545 return 0;
1546}
1547
1548static int asus_hotk_restore(struct device *device)
1549{
1550 struct asus_wmi *asus = dev_get_drvdata(device);
1551 int bl;
1552
1553 /* Refresh both wlan rfkill state and pci hotplug */
1554 if (asus->wlan.rfkill)
1555 asus_rfkill_hotplug(asus);
1556
1557 if (asus->bluetooth.rfkill) {
1558 bl = !asus_wmi_get_devstate_simple(asus,
1559 ASUS_WMI_DEVID_BLUETOOTH);
1560 rfkill_set_sw_state(asus->bluetooth.rfkill, bl);
1561 }
1562 if (asus->wimax.rfkill) {
1563 bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX);
1564 rfkill_set_sw_state(asus->wimax.rfkill, bl);
1565 }
1566 if (asus->wwan3g.rfkill) {
1567 bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G);
1568 rfkill_set_sw_state(asus->wwan3g.rfkill, bl);
1569 }
1570
1571 return 0;
1572}
1573
1574static const struct dev_pm_ops asus_pm_ops = {
1575 .thaw = asus_hotk_thaw,
1576 .restore = asus_hotk_restore,
1577};
1578
1579static int asus_wmi_probe(struct platform_device *pdev)
1580{
1581 struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
1582 struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
1583 int ret;
1584
1585 if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) {
1586 pr_warning("Management GUID not found\n");
1587 return -ENODEV;
1588 }
1589
1590 if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) {
1591 pr_warning("Event GUID not found\n");
1592 return -ENODEV;
1593 }
1594
1595 if (wdrv->probe) {
1596 ret = wdrv->probe(pdev);
1597 if (ret)
1598 return ret;
1599 }
1600
1601 return asus_wmi_add(pdev);
1602}
1603
1604static bool used;
1605
1606int asus_wmi_register_driver(struct asus_wmi_driver *driver)
1607{
1608 struct platform_driver *platform_driver;
1609 struct platform_device *platform_device;
1610
1611 if (used)
1612 return -EBUSY;
1613
1614 platform_driver = &driver->platform_driver;
1615 platform_driver->remove = asus_wmi_remove;
1616 platform_driver->driver.owner = driver->owner;
1617 platform_driver->driver.name = driver->name;
1618 platform_driver->driver.pm = &asus_pm_ops;
1619
1620 platform_device = platform_create_bundle(platform_driver,
1621 asus_wmi_probe,
1622 NULL, 0, NULL, 0);
1623 if (IS_ERR(platform_device))
1624 return PTR_ERR(platform_device);
1625
1626 used = true;
1627 return 0;
1628}
1629EXPORT_SYMBOL_GPL(asus_wmi_register_driver);
1630
1631void asus_wmi_unregister_driver(struct asus_wmi_driver *driver)
1632{
1633 platform_device_unregister(driver->platform_device);
1634 platform_driver_unregister(&driver->platform_driver);
1635 used = false;
1636}
1637EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver);
1638
1639static int __init asus_wmi_init(void)
1640{
1641 if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) {
1642 pr_info("Asus Management GUID not found");
1643 return -ENODEV;
1644 }
1645
1646 pr_info("ASUS WMI generic driver loaded");
1647 return 0;
1648}
1649
1650static void __exit asus_wmi_exit(void)
1651{
1652 pr_info("ASUS WMI generic driver unloaded");
1653}
1654
1655module_init(asus_wmi_init);
1656module_exit(asus_wmi_exit);
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
new file mode 100644
index 000000000000..c044522c8766
--- /dev/null
+++ b/drivers/platform/x86/asus-wmi.h
@@ -0,0 +1,58 @@
1/*
2 * Asus PC WMI hotkey driver
3 *
4 * Copyright(C) 2010 Intel Corporation.
5 * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
6 *
7 * Portions based on wistron_btns.c:
8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
9 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
10 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#ifndef _ASUS_WMI_H_
28#define _ASUS_WMI_H_
29
30#include <linux/platform_device.h>
31
32struct module;
33struct key_entry;
34struct asus_wmi;
35
36struct asus_wmi_driver {
37 bool hotplug_wireless;
38
39 const char *name;
40 struct module *owner;
41
42 const char *event_guid;
43
44 const struct key_entry *keymap;
45 const char *input_name;
46 const char *input_phys;
47
48 int (*probe) (struct platform_device *device);
49 void (*quirks) (struct asus_wmi_driver *driver);
50
51 struct platform_driver platform_driver;
52 struct platform_device *platform_device;
53};
54
55int asus_wmi_register_driver(struct asus_wmi_driver *driver);
56void asus_wmi_unregister_driver(struct asus_wmi_driver *driver);
57
58#endif /* !_ASUS_WMI_H_ */
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index eb95878fa583..c16a27641ced 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -201,7 +201,7 @@ static bool extra_features;
201 * into 0x4F and read a few bytes from the output, like so: 201 * into 0x4F and read a few bytes from the output, like so:
202 * u8 writeData = 0x33; 202 * u8 writeData = 0x33;
203 * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0); 203 * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0);
204 * That address is labled "fan1 table information" in the service manual. 204 * That address is labelled "fan1 table information" in the service manual.
205 * It should be clear which value in 'buffer' changes). This seems to be 205 * It should be clear which value in 'buffer' changes). This seems to be
206 * related to fan speed. It isn't a proper 'realtime' fan speed value 206 * related to fan speed. It isn't a proper 'realtime' fan speed value
207 * though, because physically stopping or speeding up the fan doesn't 207 * though, because physically stopping or speeding up the fan doesn't
@@ -275,7 +275,7 @@ static int set_backlight_level(int level)
275 275
276 ec_write(BACKLIGHT_LEVEL_ADDR, level); 276 ec_write(BACKLIGHT_LEVEL_ADDR, level);
277 277
278 return 1; 278 return 0;
279} 279}
280 280
281static int get_backlight_level(void) 281static int get_backlight_level(void)
@@ -763,7 +763,7 @@ static int dmi_check_cb(const struct dmi_system_id *id)
763 printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n", 763 printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n",
764 id->ident); 764 id->ident);
765 extra_features = false; 765 extra_features = false;
766 return 0; 766 return 1;
767} 767}
768 768
769static int dmi_check_cb_extra(const struct dmi_system_id *id) 769static int dmi_check_cb_extra(const struct dmi_system_id *id)
@@ -772,7 +772,7 @@ static int dmi_check_cb_extra(const struct dmi_system_id *id)
772 "enabling extra features\n", 772 "enabling extra features\n",
773 id->ident); 773 id->ident);
774 extra_features = true; 774 extra_features = true;
775 return 0; 775 return 1;
776} 776}
777 777
778static struct dmi_system_id __initdata compal_dmi_table[] = { 778static struct dmi_system_id __initdata compal_dmi_table[] = {
diff --git a/drivers/platform/x86/dell-wmi-aio.c b/drivers/platform/x86/dell-wmi-aio.c
new file mode 100644
index 000000000000..0ed84573ae1f
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-aio.c
@@ -0,0 +1,171 @@
1/*
2 * WMI hotkeys support for Dell All-In-One series
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/types.h>
24#include <linux/input.h>
25#include <linux/input/sparse-keymap.h>
26#include <acpi/acpi_drivers.h>
27#include <linux/acpi.h>
28#include <linux/string.h>
29
30MODULE_DESCRIPTION("WMI hotkeys driver for Dell All-In-One series");
31MODULE_LICENSE("GPL");
32
33#define EVENT_GUID1 "284A0E6B-380E-472A-921F-E52786257FB4"
34#define EVENT_GUID2 "02314822-307C-4F66-BF0E-48AEAEB26CC8"
35
36static const char *dell_wmi_aio_guids[] = {
37 EVENT_GUID1,
38 EVENT_GUID2,
39 NULL
40};
41
42MODULE_ALIAS("wmi:"EVENT_GUID1);
43MODULE_ALIAS("wmi:"EVENT_GUID2);
44
45static const struct key_entry dell_wmi_aio_keymap[] = {
46 { KE_KEY, 0xc0, { KEY_VOLUMEUP } },
47 { KE_KEY, 0xc1, { KEY_VOLUMEDOWN } },
48 { KE_END, 0 }
49};
50
51static struct input_dev *dell_wmi_aio_input_dev;
52
53static void dell_wmi_aio_notify(u32 value, void *context)
54{
55 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
56 union acpi_object *obj;
57 acpi_status status;
58
59 status = wmi_get_event_data(value, &response);
60 if (status != AE_OK) {
61 pr_info("bad event status 0x%x\n", status);
62 return;
63 }
64
65 obj = (union acpi_object *)response.pointer;
66 if (obj) {
67 unsigned int scancode;
68
69 switch (obj->type) {
70 case ACPI_TYPE_INTEGER:
71 /* Most All-In-One correctly return integer scancode */
72 scancode = obj->integer.value;
73 sparse_keymap_report_event(dell_wmi_aio_input_dev,
74 scancode, 1, true);
75 break;
76 case ACPI_TYPE_BUFFER:
77 /* Broken machines return the scancode in a buffer */
78 if (obj->buffer.pointer && obj->buffer.length > 0) {
79 scancode = obj->buffer.pointer[0];
80 sparse_keymap_report_event(
81 dell_wmi_aio_input_dev,
82 scancode, 1, true);
83 }
84 break;
85 }
86 }
87 kfree(obj);
88}
89
90static int __init dell_wmi_aio_input_setup(void)
91{
92 int err;
93
94 dell_wmi_aio_input_dev = input_allocate_device();
95
96 if (!dell_wmi_aio_input_dev)
97 return -ENOMEM;
98
99 dell_wmi_aio_input_dev->name = "Dell AIO WMI hotkeys";
100 dell_wmi_aio_input_dev->phys = "wmi/input0";
101 dell_wmi_aio_input_dev->id.bustype = BUS_HOST;
102
103 err = sparse_keymap_setup(dell_wmi_aio_input_dev,
104 dell_wmi_aio_keymap, NULL);
105 if (err) {
106 pr_err("Unable to setup input device keymap\n");
107 goto err_free_dev;
108 }
109 err = input_register_device(dell_wmi_aio_input_dev);
110 if (err) {
111 pr_info("Unable to register input device\n");
112 goto err_free_keymap;
113 }
114 return 0;
115
116err_free_keymap:
117 sparse_keymap_free(dell_wmi_aio_input_dev);
118err_free_dev:
119 input_free_device(dell_wmi_aio_input_dev);
120 return err;
121}
122
123static const char *dell_wmi_aio_find(void)
124{
125 int i;
126
127 for (i = 0; dell_wmi_aio_guids[i] != NULL; i++)
128 if (wmi_has_guid(dell_wmi_aio_guids[i]))
129 return dell_wmi_aio_guids[i];
130
131 return NULL;
132}
133
134static int __init dell_wmi_aio_init(void)
135{
136 int err;
137 const char *guid;
138
139 guid = dell_wmi_aio_find();
140 if (!guid) {
141 pr_warning("No known WMI GUID found\n");
142 return -ENXIO;
143 }
144
145 err = dell_wmi_aio_input_setup();
146 if (err)
147 return err;
148
149 err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL);
150 if (err) {
151 pr_err("Unable to register notify handler - %d\n", err);
152 sparse_keymap_free(dell_wmi_aio_input_dev);
153 input_unregister_device(dell_wmi_aio_input_dev);
154 return err;
155 }
156
157 return 0;
158}
159
160static void __exit dell_wmi_aio_exit(void)
161{
162 const char *guid;
163
164 guid = dell_wmi_aio_find();
165 wmi_remove_notify_handler(guid);
166 sparse_keymap_free(dell_wmi_aio_input_dev);
167 input_unregister_device(dell_wmi_aio_input_dev);
168}
169
170module_init(dell_wmi_aio_init);
171module_exit(dell_wmi_aio_exit);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 6605beac0d0e..5f2dd386152b 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1322,7 +1322,7 @@ static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)
1322{ 1322{
1323 int dummy; 1323 int dummy;
1324 1324
1325 /* Some BIOSes do not report cm although it is avaliable. 1325 /* Some BIOSes do not report cm although it is available.
1326 Check if cm_getv[cm] works and, if yes, assume cm should be set. */ 1326 Check if cm_getv[cm] works and, if yes, assume cm should be set. */
1327 if (!(eeepc->cm_supported & (1 << cm)) 1327 if (!(eeepc->cm_supported & (1 << cm))
1328 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { 1328 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 4d38f98aa976..0ddc434fb93b 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -2,7 +2,7 @@
2 * Eee PC WMI hotkey driver 2 * Eee PC WMI hotkey driver
3 * 3 *
4 * Copyright(C) 2010 Intel Corporation. 4 * Copyright(C) 2010 Intel Corporation.
5 * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com> 5 * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
6 * 6 *
7 * Portions based on wistron_btns.c: 7 * Portions based on wistron_btns.c:
8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
@@ -29,841 +29,57 @@
29#include <linux/kernel.h> 29#include <linux/kernel.h>
30#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/init.h> 31#include <linux/init.h>
32#include <linux/types.h>
33#include <linux/slab.h>
34#include <linux/input.h> 32#include <linux/input.h>
35#include <linux/input/sparse-keymap.h> 33#include <linux/input/sparse-keymap.h>
36#include <linux/fb.h> 34#include <linux/dmi.h>
37#include <linux/backlight.h>
38#include <linux/leds.h>
39#include <linux/rfkill.h>
40#include <linux/debugfs.h>
41#include <linux/seq_file.h>
42#include <linux/platform_device.h>
43#include <acpi/acpi_bus.h> 35#include <acpi/acpi_bus.h>
44#include <acpi/acpi_drivers.h> 36
37#include "asus-wmi.h"
45 38
46#define EEEPC_WMI_FILE "eeepc-wmi" 39#define EEEPC_WMI_FILE "eeepc-wmi"
47 40
48MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>"); 41MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>");
49MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); 42MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
50MODULE_LICENSE("GPL"); 43MODULE_LICENSE("GPL");
51 44
52#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ 45#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */
53 46
54#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" 47#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
55#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
56 48
57MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); 49MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
58MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
59
60#define NOTIFY_BRNUP_MIN 0x11
61#define NOTIFY_BRNUP_MAX 0x1f
62#define NOTIFY_BRNDOWN_MIN 0x20
63#define NOTIFY_BRNDOWN_MAX 0x2e
64 50
65#define EEEPC_WMI_METHODID_DEVS 0x53564544 51static bool hotplug_wireless;
66#define EEEPC_WMI_METHODID_DSTS 0x53544344
67#define EEEPC_WMI_METHODID_CFVS 0x53564643
68 52
69#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 53module_param(hotplug_wireless, bool, 0444);
70#define EEEPC_WMI_DEVID_TPDLED 0x00100011 54MODULE_PARM_DESC(hotplug_wireless,
71#define EEEPC_WMI_DEVID_WLAN 0x00010011 55 "Enable hotplug for wireless device. "
72#define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 56 "If your laptop needs that, please report to "
73#define EEEPC_WMI_DEVID_WWAN3G 0x00010019 57 "acpi4asus-user@lists.sourceforge.net.");
74 58
75static const struct key_entry eeepc_wmi_keymap[] = { 59static const struct key_entry eeepc_wmi_keymap[] = {
76 /* Sleep already handled via generic ACPI code */ 60 /* Sleep already handled via generic ACPI code */
77 { KE_KEY, 0x5d, { KEY_WLAN } },
78 { KE_KEY, 0x32, { KEY_MUTE } },
79 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
80 { KE_KEY, 0x30, { KEY_VOLUMEUP } }, 61 { KE_KEY, 0x30, { KEY_VOLUMEUP } },
81 { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, 62 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
82 { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } }, 63 { KE_KEY, 0x32, { KEY_MUTE } },
64 { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */
65 { KE_KEY, 0x5d, { KEY_WLAN } },
66 { KE_KEY, 0x6b, { KEY_TOUCHPAD_TOGGLE } }, /* Toggle Touchpad */
67 { KE_KEY, 0x82, { KEY_CAMERA } },
68 { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } },
69 { KE_KEY, 0x88, { KEY_WLAN } },
83 { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, 70 { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
84 { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ 71 { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */
85 { KE_KEY, 0xe1, { KEY_F14 } }, 72 { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */
86 { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } }, 73 { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } },
87 { KE_KEY, 0xe0, { KEY_PROG1 } }, 74 { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } },
88 { KE_KEY, 0x5c, { KEY_F15 } }, 75 { KE_KEY, 0xec, { KEY_CAMERA_UP } },
76 { KE_KEY, 0xed, { KEY_CAMERA_DOWN } },
77 { KE_KEY, 0xee, { KEY_CAMERA_LEFT } },
78 { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } },
89 { KE_END, 0}, 79 { KE_END, 0},
90}; 80};
91 81
92struct bios_args { 82static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level,
93 u32 dev_id;
94 u32 ctrl_param;
95};
96
97/*
98 * eeepc-wmi/ - debugfs root directory
99 * dev_id - current dev_id
100 * ctrl_param - current ctrl_param
101 * devs - call DEVS(dev_id, ctrl_param) and print result
102 * dsts - call DSTS(dev_id) and print result
103 */
104struct eeepc_wmi_debug {
105 struct dentry *root;
106 u32 dev_id;
107 u32 ctrl_param;
108};
109
110struct eeepc_wmi {
111 struct input_dev *inputdev;
112 struct backlight_device *backlight_device;
113 struct platform_device *platform_device;
114
115 struct led_classdev tpd_led;
116 int tpd_led_wk;
117 struct workqueue_struct *led_workqueue;
118 struct work_struct tpd_led_work;
119
120 struct rfkill *wlan_rfkill;
121 struct rfkill *bluetooth_rfkill;
122 struct rfkill *wwan3g_rfkill;
123
124 struct eeepc_wmi_debug debug;
125};
126
127/* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */
128static struct platform_device *platform_device;
129
130static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc)
131{
132 int err;
133
134 eeepc->inputdev = input_allocate_device();
135 if (!eeepc->inputdev)
136 return -ENOMEM;
137
138 eeepc->inputdev->name = "Eee PC WMI hotkeys";
139 eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0";
140 eeepc->inputdev->id.bustype = BUS_HOST;
141 eeepc->inputdev->dev.parent = &eeepc->platform_device->dev;
142
143 err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL);
144 if (err)
145 goto err_free_dev;
146
147 err = input_register_device(eeepc->inputdev);
148 if (err)
149 goto err_free_keymap;
150
151 return 0;
152
153err_free_keymap:
154 sparse_keymap_free(eeepc->inputdev);
155err_free_dev:
156 input_free_device(eeepc->inputdev);
157 return err;
158}
159
160static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc)
161{
162 if (eeepc->inputdev) {
163 sparse_keymap_free(eeepc->inputdev);
164 input_unregister_device(eeepc->inputdev);
165 }
166
167 eeepc->inputdev = NULL;
168}
169
170static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval)
171{
172 struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id };
173 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
174 union acpi_object *obj;
175 acpi_status status;
176 u32 tmp;
177
178 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
179 1, EEEPC_WMI_METHODID_DSTS, &input, &output);
180
181 if (ACPI_FAILURE(status))
182 return status;
183
184 obj = (union acpi_object *)output.pointer;
185 if (obj && obj->type == ACPI_TYPE_INTEGER)
186 tmp = (u32)obj->integer.value;
187 else
188 tmp = 0;
189
190 if (retval)
191 *retval = tmp;
192
193 kfree(obj);
194
195 return status;
196
197}
198
199static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
200 u32 *retval)
201{
202 struct bios_args args = {
203 .dev_id = dev_id,
204 .ctrl_param = ctrl_param,
205 };
206 struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
207 acpi_status status;
208
209 if (!retval) {
210 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1,
211 EEEPC_WMI_METHODID_DEVS,
212 &input, NULL);
213 } else {
214 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
215 union acpi_object *obj;
216 u32 tmp;
217
218 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1,
219 EEEPC_WMI_METHODID_DEVS,
220 &input, &output);
221
222 if (ACPI_FAILURE(status))
223 return status;
224
225 obj = (union acpi_object *)output.pointer;
226 if (obj && obj->type == ACPI_TYPE_INTEGER)
227 tmp = (u32)obj->integer.value;
228 else
229 tmp = 0;
230
231 *retval = tmp;
232
233 kfree(obj);
234 }
235
236 return status;
237}
238
239/*
240 * LEDs
241 */
242/*
243 * These functions actually update the LED's, and are called from a
244 * workqueue. By doing this as separate work rather than when the LED
245 * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a
246 * potentially bad time, such as a timer interrupt.
247 */
248static void tpd_led_update(struct work_struct *work)
249{
250 int ctrl_param;
251 struct eeepc_wmi *eeepc;
252
253 eeepc = container_of(work, struct eeepc_wmi, tpd_led_work);
254
255 ctrl_param = eeepc->tpd_led_wk;
256 eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL);
257}
258
259static void tpd_led_set(struct led_classdev *led_cdev,
260 enum led_brightness value)
261{
262 struct eeepc_wmi *eeepc;
263
264 eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led);
265
266 eeepc->tpd_led_wk = !!value;
267 queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
268}
269
270static int read_tpd_state(struct eeepc_wmi *eeepc)
271{
272 u32 retval;
273 acpi_status status;
274
275 status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval);
276
277 if (ACPI_FAILURE(status))
278 return -1;
279 else if (!retval || retval == 0x00060000)
280 /*
281 * if touchpad led is present, DSTS will set some bits,
282 * usually 0x00020000.
283 * 0x00060000 means that the device is not supported
284 */
285 return -ENODEV;
286 else
287 /* Status is stored in the first bit */
288 return retval & 0x1;
289}
290
291static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
292{
293 struct eeepc_wmi *eeepc;
294
295 eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led);
296
297 return read_tpd_state(eeepc);
298}
299
300static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc)
301{
302 int rv;
303
304 if (read_tpd_state(eeepc) < 0)
305 return 0;
306
307 eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");
308 if (!eeepc->led_workqueue)
309 return -ENOMEM;
310 INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);
311
312 eeepc->tpd_led.name = "eeepc::touchpad";
313 eeepc->tpd_led.brightness_set = tpd_led_set;
314 eeepc->tpd_led.brightness_get = tpd_led_get;
315 eeepc->tpd_led.max_brightness = 1;
316
317 rv = led_classdev_register(&eeepc->platform_device->dev,
318 &eeepc->tpd_led);
319 if (rv) {
320 destroy_workqueue(eeepc->led_workqueue);
321 return rv;
322 }
323
324 return 0;
325}
326
327static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc)
328{
329 if (eeepc->tpd_led.dev)
330 led_classdev_unregister(&eeepc->tpd_led);
331 if (eeepc->led_workqueue)
332 destroy_workqueue(eeepc->led_workqueue);
333}
334
335/*
336 * Rfkill devices
337 */
338static int eeepc_rfkill_set(void *data, bool blocked)
339{
340 int dev_id = (unsigned long)data;
341 u32 ctrl_param = !blocked;
342
343 return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL);
344}
345
346static void eeepc_rfkill_query(struct rfkill *rfkill, void *data)
347{
348 int dev_id = (unsigned long)data;
349 u32 retval;
350 acpi_status status;
351
352 status = eeepc_wmi_get_devstate(dev_id, &retval);
353
354 if (ACPI_FAILURE(status))
355 return ;
356
357 rfkill_set_sw_state(rfkill, !(retval & 0x1));
358}
359
360static const struct rfkill_ops eeepc_rfkill_ops = {
361 .set_block = eeepc_rfkill_set,
362 .query = eeepc_rfkill_query,
363};
364
365static int eeepc_new_rfkill(struct eeepc_wmi *eeepc,
366 struct rfkill **rfkill,
367 const char *name,
368 enum rfkill_type type, int dev_id)
369{
370 int result;
371 u32 retval;
372 acpi_status status;
373
374 status = eeepc_wmi_get_devstate(dev_id, &retval);
375
376 if (ACPI_FAILURE(status))
377 return -1;
378
379 /* If the device is present, DSTS will always set some bits
380 * 0x00070000 - 1110000000000000000 - device supported
381 * 0x00060000 - 1100000000000000000 - not supported
382 * 0x00020000 - 0100000000000000000 - device supported
383 * 0x00010000 - 0010000000000000000 - not supported / special mode ?
384 */
385 if (!retval || retval == 0x00060000)
386 return -ENODEV;
387
388 *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
389 &eeepc_rfkill_ops, (void *)(long)dev_id);
390
391 if (!*rfkill)
392 return -EINVAL;
393
394 rfkill_init_sw_state(*rfkill, !(retval & 0x1));
395 result = rfkill_register(*rfkill);
396 if (result) {
397 rfkill_destroy(*rfkill);
398 *rfkill = NULL;
399 return result;
400 }
401 return 0;
402}
403
404static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc)
405{
406 if (eeepc->wlan_rfkill) {
407 rfkill_unregister(eeepc->wlan_rfkill);
408 rfkill_destroy(eeepc->wlan_rfkill);
409 eeepc->wlan_rfkill = NULL;
410 }
411 if (eeepc->bluetooth_rfkill) {
412 rfkill_unregister(eeepc->bluetooth_rfkill);
413 rfkill_destroy(eeepc->bluetooth_rfkill);
414 eeepc->bluetooth_rfkill = NULL;
415 }
416 if (eeepc->wwan3g_rfkill) {
417 rfkill_unregister(eeepc->wwan3g_rfkill);
418 rfkill_destroy(eeepc->wwan3g_rfkill);
419 eeepc->wwan3g_rfkill = NULL;
420 }
421}
422
423static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc)
424{
425 int result = 0;
426
427 result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
428 "eeepc-wlan", RFKILL_TYPE_WLAN,
429 EEEPC_WMI_DEVID_WLAN);
430
431 if (result && result != -ENODEV)
432 goto exit;
433
434 result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
435 "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
436 EEEPC_WMI_DEVID_BLUETOOTH);
437
438 if (result && result != -ENODEV)
439 goto exit;
440
441 result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
442 "eeepc-wwan3g", RFKILL_TYPE_WWAN,
443 EEEPC_WMI_DEVID_WWAN3G);
444
445 if (result && result != -ENODEV)
446 goto exit;
447
448exit:
449 if (result && result != -ENODEV)
450 eeepc_wmi_rfkill_exit(eeepc);
451
452 if (result == -ENODEV)
453 result = 0;
454
455 return result;
456}
457
458/*
459 * Backlight
460 */
461static int read_brightness(struct backlight_device *bd)
462{
463 u32 retval;
464 acpi_status status;
465
466 status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval);
467
468 if (ACPI_FAILURE(status))
469 return -1;
470 else
471 return retval & 0xFF;
472}
473
474static int update_bl_status(struct backlight_device *bd)
475{
476
477 u32 ctrl_param;
478 acpi_status status;
479
480 ctrl_param = bd->props.brightness;
481
482 status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT,
483 ctrl_param, NULL);
484
485 if (ACPI_FAILURE(status))
486 return -1;
487 else
488 return 0;
489}
490
491static const struct backlight_ops eeepc_wmi_bl_ops = {
492 .get_brightness = read_brightness,
493 .update_status = update_bl_status,
494};
495
496static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code)
497{
498 struct backlight_device *bd = eeepc->backlight_device;
499 int old = bd->props.brightness;
500 int new = old;
501
502 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
503 new = code - NOTIFY_BRNUP_MIN + 1;
504 else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
505 new = code - NOTIFY_BRNDOWN_MIN;
506
507 bd->props.brightness = new;
508 backlight_update_status(bd);
509 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
510
511 return old;
512}
513
514static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc)
515{
516 struct backlight_device *bd;
517 struct backlight_properties props;
518
519 memset(&props, 0, sizeof(struct backlight_properties));
520 props.max_brightness = 15;
521 bd = backlight_device_register(EEEPC_WMI_FILE,
522 &eeepc->platform_device->dev, eeepc,
523 &eeepc_wmi_bl_ops, &props);
524 if (IS_ERR(bd)) {
525 pr_err("Could not register backlight device\n");
526 return PTR_ERR(bd);
527 }
528
529 eeepc->backlight_device = bd;
530
531 bd->props.brightness = read_brightness(bd);
532 bd->props.power = FB_BLANK_UNBLANK;
533 backlight_update_status(bd);
534
535 return 0;
536}
537
538static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc)
539{
540 if (eeepc->backlight_device)
541 backlight_device_unregister(eeepc->backlight_device);
542
543 eeepc->backlight_device = NULL;
544}
545
546static void eeepc_wmi_notify(u32 value, void *context)
547{
548 struct eeepc_wmi *eeepc = context;
549 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
550 union acpi_object *obj;
551 acpi_status status;
552 int code;
553 int orig_code;
554
555 status = wmi_get_event_data(value, &response);
556 if (status != AE_OK) {
557 pr_err("bad event status 0x%x\n", status);
558 return;
559 }
560
561 obj = (union acpi_object *)response.pointer;
562
563 if (obj && obj->type == ACPI_TYPE_INTEGER) {
564 code = obj->integer.value;
565 orig_code = code;
566
567 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
568 code = NOTIFY_BRNUP_MIN;
569 else if (code >= NOTIFY_BRNDOWN_MIN &&
570 code <= NOTIFY_BRNDOWN_MAX)
571 code = NOTIFY_BRNDOWN_MIN;
572
573 if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
574 if (!acpi_video_backlight_support())
575 eeepc_wmi_backlight_notify(eeepc, orig_code);
576 }
577
578 if (!sparse_keymap_report_event(eeepc->inputdev,
579 code, 1, true))
580 pr_info("Unknown key %x pressed\n", code);
581 }
582
583 kfree(obj);
584}
585
586static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
587 const char *buf, size_t count)
588{
589 int value;
590 struct acpi_buffer input = { (acpi_size)sizeof(value), &value };
591 acpi_status status;
592
593 if (!count || sscanf(buf, "%i", &value) != 1)
594 return -EINVAL;
595 if (value < 0 || value > 2)
596 return -EINVAL;
597
598 status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
599 1, EEEPC_WMI_METHODID_CFVS, &input, NULL);
600
601 if (ACPI_FAILURE(status))
602 return -EIO;
603 else
604 return count;
605}
606
607static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
608
609static struct attribute *platform_attributes[] = {
610 &dev_attr_cpufv.attr,
611 NULL
612};
613
614static struct attribute_group platform_attribute_group = {
615 .attrs = platform_attributes
616};
617
618static void eeepc_wmi_sysfs_exit(struct platform_device *device)
619{
620 sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
621}
622
623static int eeepc_wmi_sysfs_init(struct platform_device *device)
624{
625 return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
626}
627
628/*
629 * Platform device
630 */
631static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc)
632{
633 int err;
634
635 eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1);
636 if (!eeepc->platform_device)
637 return -ENOMEM;
638 platform_set_drvdata(eeepc->platform_device, eeepc);
639
640 err = platform_device_add(eeepc->platform_device);
641 if (err)
642 goto fail_platform_device;
643
644 err = eeepc_wmi_sysfs_init(eeepc->platform_device);
645 if (err)
646 goto fail_sysfs;
647 return 0;
648
649fail_sysfs:
650 platform_device_del(eeepc->platform_device);
651fail_platform_device:
652 platform_device_put(eeepc->platform_device);
653 return err;
654}
655
656static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc)
657{
658 eeepc_wmi_sysfs_exit(eeepc->platform_device);
659 platform_device_unregister(eeepc->platform_device);
660}
661
662/*
663 * debugfs
664 */
665struct eeepc_wmi_debugfs_node {
666 struct eeepc_wmi *eeepc;
667 char *name;
668 int (*show)(struct seq_file *m, void *data);
669};
670
671static int show_dsts(struct seq_file *m, void *data)
672{
673 struct eeepc_wmi *eeepc = m->private;
674 acpi_status status;
675 u32 retval = -1;
676
677 status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval);
678
679 if (ACPI_FAILURE(status))
680 return -EIO;
681
682 seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval);
683
684 return 0;
685}
686
687static int show_devs(struct seq_file *m, void *data)
688{
689 struct eeepc_wmi *eeepc = m->private;
690 acpi_status status;
691 u32 retval = -1;
692
693 status = eeepc_wmi_set_devstate(eeepc->debug.dev_id,
694 eeepc->debug.ctrl_param, &retval);
695 if (ACPI_FAILURE(status))
696 return -EIO;
697
698 seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id,
699 eeepc->debug.ctrl_param, retval);
700
701 return 0;
702}
703
704static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = {
705 { NULL, "devs", show_devs },
706 { NULL, "dsts", show_dsts },
707};
708
709static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file)
710{
711 struct eeepc_wmi_debugfs_node *node = inode->i_private;
712
713 return single_open(file, node->show, node->eeepc);
714}
715
716static const struct file_operations eeepc_wmi_debugfs_io_ops = {
717 .owner = THIS_MODULE,
718 .open = eeepc_wmi_debugfs_open,
719 .read = seq_read,
720 .llseek = seq_lseek,
721 .release = single_release,
722};
723
724static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc)
725{
726 debugfs_remove_recursive(eeepc->debug.root);
727}
728
729static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc)
730{
731 struct dentry *dent;
732 int i;
733
734 eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL);
735 if (!eeepc->debug.root) {
736 pr_err("failed to create debugfs directory");
737 goto error_debugfs;
738 }
739
740 dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR,
741 eeepc->debug.root, &eeepc->debug.dev_id);
742 if (!dent)
743 goto error_debugfs;
744
745 dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR,
746 eeepc->debug.root, &eeepc->debug.ctrl_param);
747 if (!dent)
748 goto error_debugfs;
749
750 for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) {
751 struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i];
752
753 node->eeepc = eeepc;
754 dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
755 eeepc->debug.root, node,
756 &eeepc_wmi_debugfs_io_ops);
757 if (!dent) {
758 pr_err("failed to create debug file: %s\n", node->name);
759 goto error_debugfs;
760 }
761 }
762
763 return 0;
764
765error_debugfs:
766 eeepc_wmi_debugfs_exit(eeepc);
767 return -ENOMEM;
768}
769
770/*
771 * WMI Driver
772 */
773static struct platform_device * __init eeepc_wmi_add(void)
774{
775 struct eeepc_wmi *eeepc;
776 acpi_status status;
777 int err;
778
779 eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL);
780 if (!eeepc)
781 return ERR_PTR(-ENOMEM);
782
783 /*
784 * Register the platform device first. It is used as a parent for the
785 * sub-devices below.
786 */
787 err = eeepc_wmi_platform_init(eeepc);
788 if (err)
789 goto fail_platform;
790
791 err = eeepc_wmi_input_init(eeepc);
792 if (err)
793 goto fail_input;
794
795 err = eeepc_wmi_led_init(eeepc);
796 if (err)
797 goto fail_leds;
798
799 err = eeepc_wmi_rfkill_init(eeepc);
800 if (err)
801 goto fail_rfkill;
802
803 if (!acpi_video_backlight_support()) {
804 err = eeepc_wmi_backlight_init(eeepc);
805 if (err)
806 goto fail_backlight;
807 } else
808 pr_info("Backlight controlled by ACPI video driver\n");
809
810 status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
811 eeepc_wmi_notify, eeepc);
812 if (ACPI_FAILURE(status)) {
813 pr_err("Unable to register notify handler - %d\n",
814 status);
815 err = -ENODEV;
816 goto fail_wmi_handler;
817 }
818
819 err = eeepc_wmi_debugfs_init(eeepc);
820 if (err)
821 goto fail_debugfs;
822
823 return eeepc->platform_device;
824
825fail_debugfs:
826 wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
827fail_wmi_handler:
828 eeepc_wmi_backlight_exit(eeepc);
829fail_backlight:
830 eeepc_wmi_rfkill_exit(eeepc);
831fail_rfkill:
832 eeepc_wmi_led_exit(eeepc);
833fail_leds:
834 eeepc_wmi_input_exit(eeepc);
835fail_input:
836 eeepc_wmi_platform_exit(eeepc);
837fail_platform:
838 kfree(eeepc);
839 return ERR_PTR(err);
840}
841
842static int eeepc_wmi_remove(struct platform_device *device)
843{
844 struct eeepc_wmi *eeepc;
845
846 eeepc = platform_get_drvdata(device);
847 wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
848 eeepc_wmi_backlight_exit(eeepc);
849 eeepc_wmi_input_exit(eeepc);
850 eeepc_wmi_led_exit(eeepc);
851 eeepc_wmi_rfkill_exit(eeepc);
852 eeepc_wmi_debugfs_exit(eeepc);
853 eeepc_wmi_platform_exit(eeepc);
854
855 kfree(eeepc);
856 return 0;
857}
858
859static struct platform_driver platform_driver = {
860 .driver = {
861 .name = EEEPC_WMI_FILE,
862 .owner = THIS_MODULE,
863 },
864};
865
866static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level,
867 void *context, void **retval) 83 void *context, void **retval)
868{ 84{
869 pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); 85 pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID);
@@ -871,7 +87,7 @@ static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level,
871 return AE_CTRL_TERMINATE; 87 return AE_CTRL_TERMINATE;
872} 88}
873 89
874static int __init eeepc_wmi_check_atkd(void) 90static int eeepc_wmi_check_atkd(void)
875{ 91{
876 acpi_status status; 92 acpi_status status;
877 bool found = false; 93 bool found = false;
@@ -884,16 +100,8 @@ static int __init eeepc_wmi_check_atkd(void)
884 return -1; 100 return -1;
885} 101}
886 102
887static int __init eeepc_wmi_init(void) 103static int eeepc_wmi_probe(struct platform_device *pdev)
888{ 104{
889 int err;
890
891 if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) ||
892 !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) {
893 pr_warning("No known WMI GUID found\n");
894 return -ENODEV;
895 }
896
897 if (eeepc_wmi_check_atkd()) { 105 if (eeepc_wmi_check_atkd()) {
898 pr_warning("WMI device present, but legacy ATKD device is also " 106 pr_warning("WMI device present, but legacy ATKD device is also "
899 "present and enabled."); 107 "present and enabled.");
@@ -901,33 +109,59 @@ static int __init eeepc_wmi_init(void)
901 "acpi_osi=\"!Windows 2009\""); 109 "acpi_osi=\"!Windows 2009\"");
902 pr_warning("Can't load eeepc-wmi, use default acpi_osi " 110 pr_warning("Can't load eeepc-wmi, use default acpi_osi "
903 "(preferred) or eeepc-laptop"); 111 "(preferred) or eeepc-laptop");
904 return -ENODEV; 112 return -EBUSY;
905 } 113 }
114 return 0;
115}
906 116
907 platform_device = eeepc_wmi_add(); 117static void eeepc_dmi_check(struct asus_wmi_driver *driver)
908 if (IS_ERR(platform_device)) { 118{
909 err = PTR_ERR(platform_device); 119 const char *model;
910 goto fail_eeepc_wmi; 120
911 } 121 model = dmi_get_system_info(DMI_PRODUCT_NAME);
122 if (!model)
123 return;
912 124
913 err = platform_driver_register(&platform_driver); 125 /*
914 if (err) { 126 * Whitelist for wlan hotplug
915 pr_warning("Unable to register platform driver\n"); 127 *
916 goto fail_platform_driver; 128 * Asus 1000H needs the current hotplug code to handle
129 * Fn+F2 correctly. We may add other Asus here later, but
130 * it seems that most of the laptops supported by asus-wmi
131 * don't need to be on this list
132 */
133 if (strcmp(model, "1000H") == 0) {
134 driver->hotplug_wireless = true;
135 pr_info("wlan hotplug enabled\n");
917 } 136 }
137}
138
139static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
140{
141 driver->hotplug_wireless = hotplug_wireless;
142 eeepc_dmi_check(driver);
143}
144
145static struct asus_wmi_driver asus_wmi_driver = {
146 .name = EEEPC_WMI_FILE,
147 .owner = THIS_MODULE,
148 .event_guid = EEEPC_WMI_EVENT_GUID,
149 .keymap = eeepc_wmi_keymap,
150 .input_name = "Eee PC WMI hotkeys",
151 .input_phys = EEEPC_WMI_FILE "/input0",
152 .probe = eeepc_wmi_probe,
153 .quirks = eeepc_wmi_quirks,
154};
918 155
919 return 0;
920 156
921fail_platform_driver: 157static int __init eeepc_wmi_init(void)
922 eeepc_wmi_remove(platform_device); 158{
923fail_eeepc_wmi: 159 return asus_wmi_register_driver(&asus_wmi_driver);
924 return err;
925} 160}
926 161
927static void __exit eeepc_wmi_exit(void) 162static void __exit eeepc_wmi_exit(void)
928{ 163{
929 eeepc_wmi_remove(platform_device); 164 asus_wmi_unregister_driver(&asus_wmi_driver);
930 platform_driver_unregister(&platform_driver);
931} 165}
932 166
933module_init(eeepc_wmi_init); 167module_init(eeepc_wmi_init);
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 9e05af9c41cb..1bc4a7539ba9 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -2,6 +2,7 @@
2 * HP WMI hotkeys 2 * HP WMI hotkeys
3 * 3 *
4 * Copyright (C) 2008 Red Hat <mjg@redhat.com> 4 * Copyright (C) 2008 Red Hat <mjg@redhat.com>
5 * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
5 * 6 *
6 * Portions based on wistron_btns.c: 7 * Portions based on wistron_btns.c:
7 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
@@ -51,6 +52,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
51#define HPWMI_HARDWARE_QUERY 0x4 52#define HPWMI_HARDWARE_QUERY 0x4
52#define HPWMI_WIRELESS_QUERY 0x5 53#define HPWMI_WIRELESS_QUERY 0x5
53#define HPWMI_HOTKEY_QUERY 0xc 54#define HPWMI_HOTKEY_QUERY 0xc
55#define HPWMI_WIRELESS2_QUERY 0x1b
54 56
55#define PREFIX "HP WMI: " 57#define PREFIX "HP WMI: "
56#define UNIMP "Unimplemented " 58#define UNIMP "Unimplemented "
@@ -86,7 +88,46 @@ struct bios_args {
86struct bios_return { 88struct bios_return {
87 u32 sigpass; 89 u32 sigpass;
88 u32 return_code; 90 u32 return_code;
89 u32 value; 91};
92
93enum hp_return_value {
94 HPWMI_RET_WRONG_SIGNATURE = 0x02,
95 HPWMI_RET_UNKNOWN_COMMAND = 0x03,
96 HPWMI_RET_UNKNOWN_CMDTYPE = 0x04,
97 HPWMI_RET_INVALID_PARAMETERS = 0x05,
98};
99
100enum hp_wireless2_bits {
101 HPWMI_POWER_STATE = 0x01,
102 HPWMI_POWER_SOFT = 0x02,
103 HPWMI_POWER_BIOS = 0x04,
104 HPWMI_POWER_HARD = 0x08,
105};
106
107#define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \
108 != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD))
109#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
110
111struct bios_rfkill2_device_state {
112 u8 radio_type;
113 u8 bus_type;
114 u16 vendor_id;
115 u16 product_id;
116 u16 subsys_vendor_id;
117 u16 subsys_product_id;
118 u8 rfkill_id;
119 u8 power;
120 u8 unknown[4];
121};
122
123/* 7 devices fit into the 128 byte buffer */
124#define HPWMI_MAX_RFKILL2_DEVICES 7
125
126struct bios_rfkill2_state {
127 u8 unknown[7];
128 u8 count;
129 u8 pad[8];
130 struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
90}; 131};
91 132
92static const struct key_entry hp_wmi_keymap[] = { 133static const struct key_entry hp_wmi_keymap[] = {
@@ -108,6 +149,15 @@ static struct rfkill *wifi_rfkill;
108static struct rfkill *bluetooth_rfkill; 149static struct rfkill *bluetooth_rfkill;
109static struct rfkill *wwan_rfkill; 150static struct rfkill *wwan_rfkill;
110 151
152struct rfkill2_device {
153 u8 id;
154 int num;
155 struct rfkill *rfkill;
156};
157
158static int rfkill2_count;
159static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
160
111static const struct dev_pm_ops hp_wmi_pm_ops = { 161static const struct dev_pm_ops hp_wmi_pm_ops = {
112 .resume = hp_wmi_resume_handler, 162 .resume = hp_wmi_resume_handler,
113 .restore = hp_wmi_resume_handler, 163 .restore = hp_wmi_resume_handler,
@@ -129,7 +179,8 @@ static struct platform_driver hp_wmi_driver = {
129 * query: The commandtype -> What should be queried 179 * query: The commandtype -> What should be queried
130 * write: The command -> 0 read, 1 write, 3 ODM specific 180 * write: The command -> 0 read, 1 write, 3 ODM specific
131 * buffer: Buffer used as input and/or output 181 * buffer: Buffer used as input and/or output
132 * buffersize: Size of buffer 182 * insize: Size of input buffer
183 * outsize: Size of output buffer
133 * 184 *
134 * returns zero on success 185 * returns zero on success
135 * an HP WMI query specific error code (which is positive) 186 * an HP WMI query specific error code (which is positive)
@@ -140,25 +191,29 @@ static struct platform_driver hp_wmi_driver = {
140 * size. E.g. Battery info query (0x7) is defined to have 1 byte input 191 * size. E.g. Battery info query (0x7) is defined to have 1 byte input
141 * and 128 byte output. The caller would do: 192 * and 128 byte output. The caller would do:
142 * buffer = kzalloc(128, GFP_KERNEL); 193 * buffer = kzalloc(128, GFP_KERNEL);
143 * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) 194 * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128)
144 */ 195 */
145static int hp_wmi_perform_query(int query, int write, u32 *buffer, 196static int hp_wmi_perform_query(int query, int write, void *buffer,
146 int buffersize) 197 int insize, int outsize)
147{ 198{
148 struct bios_return bios_return; 199 struct bios_return *bios_return;
149 acpi_status status; 200 int actual_outsize;
150 union acpi_object *obj; 201 union acpi_object *obj;
151 struct bios_args args = { 202 struct bios_args args = {
152 .signature = 0x55434553, 203 .signature = 0x55434553,
153 .command = write ? 0x2 : 0x1, 204 .command = write ? 0x2 : 0x1,
154 .commandtype = query, 205 .commandtype = query,
155 .datasize = buffersize, 206 .datasize = insize,
156 .data = *buffer, 207 .data = 0,
157 }; 208 };
158 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 209 struct acpi_buffer input = { sizeof(struct bios_args), &args };
159 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 210 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
160 211
161 status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); 212 if (WARN_ON(insize > sizeof(args.data)))
213 return -EINVAL;
214 memcpy(&args.data, buffer, insize);
215
216 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
162 217
163 obj = output.pointer; 218 obj = output.pointer;
164 219
@@ -169,10 +224,26 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
169 return -EINVAL; 224 return -EINVAL;
170 } 225 }
171 226
172 bios_return = *((struct bios_return *)obj->buffer.pointer); 227 bios_return = (struct bios_return *)obj->buffer.pointer;
173 228
174 memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); 229 if (bios_return->return_code) {
230 if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
231 printk(KERN_WARNING PREFIX "query 0x%x returned "
232 "error 0x%x\n",
233 query, bios_return->return_code);
234 kfree(obj);
235 return bios_return->return_code;
236 }
237
238 if (!outsize) {
239 /* ignore output data */
240 kfree(obj);
241 return 0;
242 }
175 243
244 actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
245 memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
246 memset(buffer + actual_outsize, 0, outsize - actual_outsize);
176 kfree(obj); 247 kfree(obj);
177 return 0; 248 return 0;
178} 249}
@@ -181,7 +252,7 @@ static int hp_wmi_display_state(void)
181{ 252{
182 int state = 0; 253 int state = 0;
183 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, 254 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state,
184 sizeof(state)); 255 sizeof(state), sizeof(state));
185 if (ret) 256 if (ret)
186 return -EINVAL; 257 return -EINVAL;
187 return state; 258 return state;
@@ -191,7 +262,7 @@ static int hp_wmi_hddtemp_state(void)
191{ 262{
192 int state = 0; 263 int state = 0;
193 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, 264 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state,
194 sizeof(state)); 265 sizeof(state), sizeof(state));
195 if (ret) 266 if (ret)
196 return -EINVAL; 267 return -EINVAL;
197 return state; 268 return state;
@@ -201,7 +272,7 @@ static int hp_wmi_als_state(void)
201{ 272{
202 int state = 0; 273 int state = 0;
203 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, 274 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state,
204 sizeof(state)); 275 sizeof(state), sizeof(state));
205 if (ret) 276 if (ret)
206 return -EINVAL; 277 return -EINVAL;
207 return state; 278 return state;
@@ -211,7 +282,7 @@ static int hp_wmi_dock_state(void)
211{ 282{
212 int state = 0; 283 int state = 0;
213 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 284 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
214 sizeof(state)); 285 sizeof(state), sizeof(state));
215 286
216 if (ret) 287 if (ret)
217 return -EINVAL; 288 return -EINVAL;
@@ -223,7 +294,7 @@ static int hp_wmi_tablet_state(void)
223{ 294{
224 int state = 0; 295 int state = 0;
225 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 296 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
226 sizeof(state)); 297 sizeof(state), sizeof(state));
227 if (ret) 298 if (ret)
228 return ret; 299 return ret;
229 300
@@ -237,7 +308,7 @@ static int hp_wmi_set_block(void *data, bool blocked)
237 int ret; 308 int ret;
238 309
239 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 310 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
240 &query, sizeof(query)); 311 &query, sizeof(query), 0);
241 if (ret) 312 if (ret)
242 return -EINVAL; 313 return -EINVAL;
243 return 0; 314 return 0;
@@ -252,7 +323,8 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
252 int wireless = 0; 323 int wireless = 0;
253 int mask; 324 int mask;
254 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 325 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
255 &wireless, sizeof(wireless)); 326 &wireless, sizeof(wireless),
327 sizeof(wireless));
256 /* TBD: Pass error */ 328 /* TBD: Pass error */
257 329
258 mask = 0x200 << (r * 8); 330 mask = 0x200 << (r * 8);
@@ -268,7 +340,8 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
268 int wireless = 0; 340 int wireless = 0;
269 int mask; 341 int mask;
270 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 342 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
271 &wireless, sizeof(wireless)); 343 &wireless, sizeof(wireless),
344 sizeof(wireless));
272 /* TBD: Pass error */ 345 /* TBD: Pass error */
273 346
274 mask = 0x800 << (r * 8); 347 mask = 0x800 << (r * 8);
@@ -279,6 +352,51 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
279 return true; 352 return true;
280} 353}
281 354
355static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
356{
357 int rfkill_id = (int)(long)data;
358 char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };
359
360 if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1,
361 buffer, sizeof(buffer), 0))
362 return -EINVAL;
363 return 0;
364}
365
366static const struct rfkill_ops hp_wmi_rfkill2_ops = {
367 .set_block = hp_wmi_rfkill2_set_block,
368};
369
370static int hp_wmi_rfkill2_refresh(void)
371{
372 int err, i;
373 struct bios_rfkill2_state state;
374
375 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
376 0, sizeof(state));
377 if (err)
378 return err;
379
380 for (i = 0; i < rfkill2_count; i++) {
381 int num = rfkill2[i].num;
382 struct bios_rfkill2_device_state *devstate;
383 devstate = &state.device[num];
384
385 if (num >= state.count ||
386 devstate->rfkill_id != rfkill2[i].id) {
387 printk(KERN_WARNING PREFIX "power configuration of "
388 "the wireless devices unexpectedly changed\n");
389 continue;
390 }
391
392 rfkill_set_states(rfkill2[i].rfkill,
393 IS_SWBLOCKED(devstate->power),
394 IS_HWBLOCKED(devstate->power));
395 }
396
397 return 0;
398}
399
282static ssize_t show_display(struct device *dev, struct device_attribute *attr, 400static ssize_t show_display(struct device *dev, struct device_attribute *attr,
283 char *buf) 401 char *buf)
284{ 402{
@@ -329,7 +447,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr,
329{ 447{
330 u32 tmp = simple_strtoul(buf, NULL, 10); 448 u32 tmp = simple_strtoul(buf, NULL, 10);
331 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, 449 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp,
332 sizeof(tmp)); 450 sizeof(tmp), sizeof(tmp));
333 if (ret) 451 if (ret)
334 return -EINVAL; 452 return -EINVAL;
335 453
@@ -402,6 +520,7 @@ static void hp_wmi_notify(u32 value, void *context)
402 case HPWMI_BEZEL_BUTTON: 520 case HPWMI_BEZEL_BUTTON:
403 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 521 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
404 &key_code, 522 &key_code,
523 sizeof(key_code),
405 sizeof(key_code)); 524 sizeof(key_code));
406 if (ret) 525 if (ret)
407 break; 526 break;
@@ -412,6 +531,11 @@ static void hp_wmi_notify(u32 value, void *context)
412 key_code); 531 key_code);
413 break; 532 break;
414 case HPWMI_WIRELESS: 533 case HPWMI_WIRELESS:
534 if (rfkill2_count) {
535 hp_wmi_rfkill2_refresh();
536 break;
537 }
538
415 if (wifi_rfkill) 539 if (wifi_rfkill)
416 rfkill_set_states(wifi_rfkill, 540 rfkill_set_states(wifi_rfkill,
417 hp_wmi_get_sw_state(HPWMI_WIFI), 541 hp_wmi_get_sw_state(HPWMI_WIFI),
@@ -502,32 +626,16 @@ static void cleanup_sysfs(struct platform_device *device)
502 device_remove_file(&device->dev, &dev_attr_tablet); 626 device_remove_file(&device->dev, &dev_attr_tablet);
503} 627}
504 628
505static int __devinit hp_wmi_bios_setup(struct platform_device *device) 629static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
506{ 630{
507 int err; 631 int err;
508 int wireless = 0; 632 int wireless = 0;
509 633
510 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, 634 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless,
511 sizeof(wireless)); 635 sizeof(wireless), sizeof(wireless));
512 if (err) 636 if (err)
513 return err; 637 return err;
514 638
515 err = device_create_file(&device->dev, &dev_attr_display);
516 if (err)
517 goto add_sysfs_error;
518 err = device_create_file(&device->dev, &dev_attr_hddtemp);
519 if (err)
520 goto add_sysfs_error;
521 err = device_create_file(&device->dev, &dev_attr_als);
522 if (err)
523 goto add_sysfs_error;
524 err = device_create_file(&device->dev, &dev_attr_dock);
525 if (err)
526 goto add_sysfs_error;
527 err = device_create_file(&device->dev, &dev_attr_tablet);
528 if (err)
529 goto add_sysfs_error;
530
531 if (wireless & 0x1) { 639 if (wireless & 0x1) {
532 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, 640 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
533 RFKILL_TYPE_WLAN, 641 RFKILL_TYPE_WLAN,
@@ -573,14 +681,131 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
573 return 0; 681 return 0;
574register_wwan_err: 682register_wwan_err:
575 rfkill_destroy(wwan_rfkill); 683 rfkill_destroy(wwan_rfkill);
684 wwan_rfkill = NULL;
576 if (bluetooth_rfkill) 685 if (bluetooth_rfkill)
577 rfkill_unregister(bluetooth_rfkill); 686 rfkill_unregister(bluetooth_rfkill);
578register_bluetooth_error: 687register_bluetooth_error:
579 rfkill_destroy(bluetooth_rfkill); 688 rfkill_destroy(bluetooth_rfkill);
689 bluetooth_rfkill = NULL;
580 if (wifi_rfkill) 690 if (wifi_rfkill)
581 rfkill_unregister(wifi_rfkill); 691 rfkill_unregister(wifi_rfkill);
582register_wifi_error: 692register_wifi_error:
583 rfkill_destroy(wifi_rfkill); 693 rfkill_destroy(wifi_rfkill);
694 wifi_rfkill = NULL;
695 return err;
696}
697
698static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
699{
700 int err, i;
701 struct bios_rfkill2_state state;
702 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
703 0, sizeof(state));
704 if (err)
705 return err;
706
707 if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
708 printk(KERN_WARNING PREFIX "unable to parse 0x1b query output\n");
709 return -EINVAL;
710 }
711
712 for (i = 0; i < state.count; i++) {
713 struct rfkill *rfkill;
714 enum rfkill_type type;
715 char *name;
716 switch (state.device[i].radio_type) {
717 case HPWMI_WIFI:
718 type = RFKILL_TYPE_WLAN;
719 name = "hp-wifi";
720 break;
721 case HPWMI_BLUETOOTH:
722 type = RFKILL_TYPE_BLUETOOTH;
723 name = "hp-bluetooth";
724 break;
725 case HPWMI_WWAN:
726 type = RFKILL_TYPE_WWAN;
727 name = "hp-wwan";
728 break;
729 default:
730 printk(KERN_WARNING PREFIX "unknown device type 0x%x\n",
731 state.device[i].radio_type);
732 continue;
733 }
734
735 if (!state.device[i].vendor_id) {
736 printk(KERN_WARNING PREFIX "zero device %d while %d "
737 "reported\n", i, state.count);
738 continue;
739 }
740
741 rfkill = rfkill_alloc(name, &device->dev, type,
742 &hp_wmi_rfkill2_ops, (void *)(long)i);
743 if (!rfkill) {
744 err = -ENOMEM;
745 goto fail;
746 }
747
748 rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
749 rfkill2[rfkill2_count].num = i;
750 rfkill2[rfkill2_count].rfkill = rfkill;
751
752 rfkill_init_sw_state(rfkill,
753 IS_SWBLOCKED(state.device[i].power));
754 rfkill_set_hw_state(rfkill,
755 IS_HWBLOCKED(state.device[i].power));
756
757 if (!(state.device[i].power & HPWMI_POWER_BIOS))
758 printk(KERN_INFO PREFIX "device %s blocked by BIOS\n",
759 name);
760
761 err = rfkill_register(rfkill);
762 if (err) {
763 rfkill_destroy(rfkill);
764 goto fail;
765 }
766
767 rfkill2_count++;
768 }
769
770 return 0;
771fail:
772 for (; rfkill2_count > 0; rfkill2_count--) {
773 rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
774 rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
775 }
776 return err;
777}
778
779static int __devinit hp_wmi_bios_setup(struct platform_device *device)
780{
781 int err;
782
783 /* clear detected rfkill devices */
784 wifi_rfkill = NULL;
785 bluetooth_rfkill = NULL;
786 wwan_rfkill = NULL;
787 rfkill2_count = 0;
788
789 if (hp_wmi_rfkill_setup(device))
790 hp_wmi_rfkill2_setup(device);
791
792 err = device_create_file(&device->dev, &dev_attr_display);
793 if (err)
794 goto add_sysfs_error;
795 err = device_create_file(&device->dev, &dev_attr_hddtemp);
796 if (err)
797 goto add_sysfs_error;
798 err = device_create_file(&device->dev, &dev_attr_als);
799 if (err)
800 goto add_sysfs_error;
801 err = device_create_file(&device->dev, &dev_attr_dock);
802 if (err)
803 goto add_sysfs_error;
804 err = device_create_file(&device->dev, &dev_attr_tablet);
805 if (err)
806 goto add_sysfs_error;
807 return 0;
808
584add_sysfs_error: 809add_sysfs_error:
585 cleanup_sysfs(device); 810 cleanup_sysfs(device);
586 return err; 811 return err;
@@ -588,8 +813,14 @@ add_sysfs_error:
588 813
589static int __exit hp_wmi_bios_remove(struct platform_device *device) 814static int __exit hp_wmi_bios_remove(struct platform_device *device)
590{ 815{
816 int i;
591 cleanup_sysfs(device); 817 cleanup_sysfs(device);
592 818
819 for (i = 0; i < rfkill2_count; i++) {
820 rfkill_unregister(rfkill2[i].rfkill);
821 rfkill_destroy(rfkill2[i].rfkill);
822 }
823
593 if (wifi_rfkill) { 824 if (wifi_rfkill) {
594 rfkill_unregister(wifi_rfkill); 825 rfkill_unregister(wifi_rfkill);
595 rfkill_destroy(wifi_rfkill); 826 rfkill_destroy(wifi_rfkill);
@@ -622,6 +853,9 @@ static int hp_wmi_resume_handler(struct device *device)
622 input_sync(hp_wmi_input_dev); 853 input_sync(hp_wmi_input_dev);
623 } 854 }
624 855
856 if (rfkill2_count)
857 hp_wmi_rfkill2_refresh();
858
625 if (wifi_rfkill) 859 if (wifi_rfkill)
626 rfkill_set_states(wifi_rfkill, 860 rfkill_set_states(wifi_rfkill,
627 hp_wmi_get_sw_state(HPWMI_WIFI), 861 hp_wmi_get_sw_state(HPWMI_WIFI),
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 114d95247cdf..21b101899bae 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -459,6 +459,8 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
459 if (test_bit(vpc_bit, &vpc1)) { 459 if (test_bit(vpc_bit, &vpc1)) {
460 if (vpc_bit == 9) 460 if (vpc_bit == 9)
461 ideapad_sync_rfk_state(adevice); 461 ideapad_sync_rfk_state(adevice);
462 else if (vpc_bit == 4)
463 read_ec_data(handle, 0x12, &vpc2);
462 else 464 else
463 ideapad_input_report(priv, vpc_bit); 465 ideapad_input_report(priv, vpc_bit);
464 } 466 }
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index 1294a39373ba..85c8ad43c0c5 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -1111,7 +1111,7 @@ static int ips_monitor(void *data)
1111 last_msecs = jiffies_to_msecs(jiffies); 1111 last_msecs = jiffies_to_msecs(jiffies);
1112 expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD); 1112 expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD);
1113 1113
1114 __set_current_state(TASK_UNINTERRUPTIBLE); 1114 __set_current_state(TASK_INTERRUPTIBLE);
1115 mod_timer(&timer, expire); 1115 mod_timer(&timer, expire);
1116 schedule(); 1116 schedule();
1117 1117
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c
new file mode 100644
index 000000000000..213e79ba68d5
--- /dev/null
+++ b/drivers/platform/x86/intel_mid_powerbtn.c
@@ -0,0 +1,148 @@
1/*
2 * Power button driver for Medfield.
3 *
4 * Copyright (C) 2010 Intel Corp
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
18 */
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/interrupt.h>
23#include <linux/slab.h>
24#include <linux/platform_device.h>
25#include <linux/input.h>
26#include <asm/intel_scu_ipc.h>
27
28#define DRIVER_NAME "msic_power_btn"
29
30#define MSIC_IRQ_STAT 0x02
31 #define MSIC_IRQ_PB (1 << 0)
32#define MSIC_PB_CONFIG 0x3e
33#define MSIC_PB_STATUS 0x3f
34 #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */
35
36struct mfld_pb_priv {
37 struct input_dev *input;
38 unsigned int irq;
39};
40
41static irqreturn_t mfld_pb_isr(int irq, void *dev_id)
42{
43 struct mfld_pb_priv *priv = dev_id;
44 int ret;
45 u8 pbstat;
46
47 ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat);
48 if (ret < 0)
49 return IRQ_HANDLED;
50
51 input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & MSIC_PB_LEVEL));
52 input_sync(priv->input);
53
54 return IRQ_HANDLED;
55}
56
57static int __devinit mfld_pb_probe(struct platform_device *pdev)
58{
59 struct mfld_pb_priv *priv;
60 struct input_dev *input;
61 int irq;
62 int error;
63
64 irq = platform_get_irq(pdev, 0);
65 if (irq < 0)
66 return -EINVAL;
67
68 priv = kzalloc(sizeof(struct mfld_pb_priv), GFP_KERNEL);
69 input = input_allocate_device();
70 if (!priv || !input) {
71 error = -ENOMEM;
72 goto err_free_mem;
73 }
74
75 priv->input = input;
76 priv->irq = irq;
77
78 input->name = pdev->name;
79 input->phys = "power-button/input0";
80 input->id.bustype = BUS_HOST;
81 input->dev.parent = &pdev->dev;
82
83 input_set_capability(input, EV_KEY, KEY_POWER);
84
85 error = request_threaded_irq(priv->irq, NULL, mfld_pb_isr,
86 0, DRIVER_NAME, priv);
87 if (error) {
88 dev_err(&pdev->dev,
89 "unable to request irq %d for mfld power button\n",
90 irq);
91 goto err_free_mem;
92 }
93
94 error = input_register_device(input);
95 if (error) {
96 dev_err(&pdev->dev,
97 "unable to register input dev, error %d\n", error);
98 goto err_free_irq;
99 }
100
101 platform_set_drvdata(pdev, priv);
102 return 0;
103
104err_free_irq:
105 free_irq(priv->irq, priv);
106err_free_mem:
107 input_free_device(input);
108 kfree(priv);
109 return error;
110}
111
112static int __devexit mfld_pb_remove(struct platform_device *pdev)
113{
114 struct mfld_pb_priv *priv = platform_get_drvdata(pdev);
115
116 free_irq(priv->irq, priv);
117 input_unregister_device(priv->input);
118 kfree(priv);
119
120 platform_set_drvdata(pdev, NULL);
121 return 0;
122}
123
124static struct platform_driver mfld_pb_driver = {
125 .driver = {
126 .name = DRIVER_NAME,
127 .owner = THIS_MODULE,
128 },
129 .probe = mfld_pb_probe,
130 .remove = __devexit_p(mfld_pb_remove),
131};
132
133static int __init mfld_pb_init(void)
134{
135 return platform_driver_register(&mfld_pb_driver);
136}
137module_init(mfld_pb_init);
138
139static void __exit mfld_pb_exit(void)
140{
141 platform_driver_unregister(&mfld_pb_driver);
142}
143module_exit(mfld_pb_exit);
144
145MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
146MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
147MODULE_LICENSE("GPL v2");
148MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
new file mode 100644
index 000000000000..6c12db503161
--- /dev/null
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -0,0 +1,576 @@
1/*
2 * intel_mid_thermal.c - Intel MID platform thermal driver
3 *
4 * Copyright (C) 2011 Intel Corporation
5 *
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 *
21 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22 * Author: Durgadoss R <durgadoss.r@intel.com>
23 */
24
25#define pr_fmt(fmt) "intel_mid_thermal: " fmt
26
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/err.h>
30#include <linux/param.h>
31#include <linux/device.h>
32#include <linux/platform_device.h>
33#include <linux/slab.h>
34#include <linux/pm.h>
35#include <linux/thermal.h>
36
37#include <asm/intel_scu_ipc.h>
38
39/* Number of thermal sensors */
40#define MSIC_THERMAL_SENSORS 4
41
42/* ADC1 - thermal registers */
43#define MSIC_THERM_ADC1CNTL1 0x1C0
44#define MSIC_ADC_ENBL 0x10
45#define MSIC_ADC_START 0x08
46
47#define MSIC_THERM_ADC1CNTL3 0x1C2
48#define MSIC_ADCTHERM_ENBL 0x04
49#define MSIC_ADCRRDATA_ENBL 0x05
50#define MSIC_CHANL_MASK_VAL 0x0F
51
52#define MSIC_STOPBIT_MASK 16
53#define MSIC_ADCTHERM_MASK 4
54#define ADC_CHANLS_MAX 15 /* Number of ADC channels */
55#define ADC_LOOP_MAX (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS)
56
57/* ADC channel code values */
58#define SKIN_SENSOR0_CODE 0x08
59#define SKIN_SENSOR1_CODE 0x09
60#define SYS_SENSOR_CODE 0x0A
61#define MSIC_DIE_SENSOR_CODE 0x03
62
63#define SKIN_THERM_SENSOR0 0
64#define SKIN_THERM_SENSOR1 1
65#define SYS_THERM_SENSOR2 2
66#define MSIC_DIE_THERM_SENSOR3 3
67
68/* ADC code range */
69#define ADC_MAX 977
70#define ADC_MIN 162
71#define ADC_VAL0C 887
72#define ADC_VAL20C 720
73#define ADC_VAL40C 508
74#define ADC_VAL60C 315
75
76/* ADC base addresses */
77#define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */
78#define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */
79
80/* MSIC die attributes */
81#define MSIC_DIE_ADC_MIN 488
82#define MSIC_DIE_ADC_MAX 1004
83
84/* This holds the address of the first free ADC channel,
85 * among the 15 channels
86 */
87static int channel_index;
88
89struct platform_info {
90 struct platform_device *pdev;
91 struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS];
92};
93
94struct thermal_device_info {
95 unsigned int chnl_addr;
96 int direct;
97 /* This holds the current temperature in millidegree celsius */
98 long curr_temp;
99};
100
101/**
102 * to_msic_die_temp - converts adc_val to msic_die temperature
103 * @adc_val: ADC value to be converted
104 *
105 * Can sleep
106 */
107static int to_msic_die_temp(uint16_t adc_val)
108{
109 return (368 * (adc_val) / 1000) - 220;
110}
111
112/**
113 * is_valid_adc - checks whether the adc code is within the defined range
114 * @min: minimum value for the sensor
115 * @max: maximum value for the sensor
116 *
117 * Can sleep
118 */
119static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max)
120{
121 return (adc_val >= min) && (adc_val <= max);
122}
123
124/**
125 * adc_to_temp - converts the ADC code to temperature in C
126 * @direct: true if ths channel is direct index
127 * @adc_val: the adc_val that needs to be converted
128 * @tp: temperature return value
129 *
130 * Linear approximation is used to covert the skin adc value into temperature.
131 * This technique is used to avoid very long look-up table to get
132 * the appropriate temp value from ADC value.
133 * The adc code vs sensor temp curve is split into five parts
134 * to achieve very close approximate temp value with less than
135 * 0.5C error
136 */
137static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp)
138{
139 int temp;
140
141 /* Direct conversion for die temperature */
142 if (direct) {
143 if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) {
144 *tp = to_msic_die_temp(adc_val) * 1000;
145 return 0;
146 }
147 return -ERANGE;
148 }
149
150 if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX))
151 return -ERANGE;
152
153 /* Linear approximation for skin temperature */
154 if (adc_val > ADC_VAL0C)
155 temp = 177 - (adc_val/5);
156 else if ((adc_val <= ADC_VAL0C) && (adc_val > ADC_VAL20C))
157 temp = 111 - (adc_val/8);
158 else if ((adc_val <= ADC_VAL20C) && (adc_val > ADC_VAL40C))
159 temp = 92 - (adc_val/10);
160 else if ((adc_val <= ADC_VAL40C) && (adc_val > ADC_VAL60C))
161 temp = 91 - (adc_val/10);
162 else
163 temp = 112 - (adc_val/6);
164
165 /* Convert temperature in celsius to milli degree celsius */
166 *tp = temp * 1000;
167 return 0;
168}
169
170/**
171 * mid_read_temp - read sensors for temperature
172 * @temp: holds the current temperature for the sensor after reading
173 *
174 * reads the adc_code from the channel and converts it to real
175 * temperature. The converted value is stored in temp.
176 *
177 * Can sleep
178 */
179static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp)
180{
181 struct thermal_device_info *td_info = tzd->devdata;
182 uint16_t adc_val, addr;
183 uint8_t data = 0;
184 int ret;
185 unsigned long curr_temp;
186
187
188 addr = td_info->chnl_addr;
189
190 /* Enable the msic for conversion before reading */
191 ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL);
192 if (ret)
193 return ret;
194
195 /* Re-toggle the RRDATARD bit (temporary workaround) */
196 ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL);
197 if (ret)
198 return ret;
199
200 /* Read the higher bits of data */
201 ret = intel_scu_ipc_ioread8(addr, &data);
202 if (ret)
203 return ret;
204
205 /* Shift bits to accomodate the lower two data bits */
206 adc_val = (data << 2);
207 addr++;
208
209 ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */
210 if (ret)
211 return ret;
212
213 /* Adding lower two bits to the higher bits */
214 data &= 03;
215 adc_val += data;
216
217 /* Convert ADC value to temperature */
218 ret = adc_to_temp(td_info->direct, adc_val, &curr_temp);
219 if (ret == 0)
220 *temp = td_info->curr_temp = curr_temp;
221 return ret;
222}
223
224/**
225 * configure_adc - enables/disables the ADC for conversion
226 * @val: zero: disables the ADC non-zero:enables the ADC
227 *
228 * Enable/Disable the ADC depending on the argument
229 *
230 * Can sleep
231 */
232static int configure_adc(int val)
233{
234 int ret;
235 uint8_t data;
236
237 ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
238 if (ret)
239 return ret;
240
241 if (val) {
242 /* Enable and start the ADC */
243 data |= (MSIC_ADC_ENBL | MSIC_ADC_START);
244 } else {
245 /* Just stop the ADC */
246 data &= (~MSIC_ADC_START);
247 }
248
249 return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data);
250}
251
252/**
253 * set_up_therm_channel - enable thermal channel for conversion
254 * @base_addr: index of free msic ADC channel
255 *
256 * Enable all the three channels for conversion
257 *
258 * Can sleep
259 */
260static int set_up_therm_channel(u16 base_addr)
261{
262 int ret;
263
264 /* Enable all the sensor channels */
265 ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE);
266 if (ret)
267 return ret;
268
269 ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE);
270 if (ret)
271 return ret;
272
273 ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE);
274 if (ret)
275 return ret;
276
277 /* Since this is the last channel, set the stop bit
278 to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
279 ret = intel_scu_ipc_iowrite8(base_addr + 3,
280 (MSIC_DIE_SENSOR_CODE | 0x10));
281 if (ret)
282 return ret;
283
284 /* Enable ADC and start it */
285 return configure_adc(1);
286}
287
288/**
289 * reset_stopbit - sets the stop bit to 0 on the given channel
290 * @addr: address of the channel
291 *
292 * Can sleep
293 */
294static int reset_stopbit(uint16_t addr)
295{
296 int ret;
297 uint8_t data;
298 ret = intel_scu_ipc_ioread8(addr, &data);
299 if (ret)
300 return ret;
301 /* Set the stop bit to zero */
302 return intel_scu_ipc_iowrite8(addr, (data & 0xEF));
303}
304
305/**
306 * find_free_channel - finds an empty channel for conversion
307 *
308 * If the ADC is not enabled then start using 0th channel
309 * itself. Otherwise find an empty channel by looking for a
310 * channel in which the stopbit is set to 1. returns the index
311 * of the first free channel if succeeds or an error code.
312 *
313 * Context: can sleep
314 *
315 * FIXME: Ultimately the channel allocator will move into the intel_scu_ipc
316 * code.
317 */
318static int find_free_channel(void)
319{
320 int ret;
321 int i;
322 uint8_t data;
323
324 /* check whether ADC is enabled */
325 ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
326 if (ret)
327 return ret;
328
329 if ((data & MSIC_ADC_ENBL) == 0)
330 return 0;
331
332 /* ADC is already enabled; Looking for an empty channel */
333 for (i = 0; i < ADC_CHANLS_MAX; i++) {
334 ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data);
335 if (ret)
336 return ret;
337
338 if (data & MSIC_STOPBIT_MASK) {
339 ret = i;
340 break;
341 }
342 }
343 return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret;
344}
345
346/**
347 * mid_initialize_adc - initializing the ADC
348 * @dev: our device structure
349 *
350 * Initialize the ADC for reading thermistor values. Can sleep.
351 */
352static int mid_initialize_adc(struct device *dev)
353{
354 u8 data;
355 u16 base_addr;
356 int ret;
357
358 /*
359 * Ensure that adctherm is disabled before we
360 * initialize the ADC
361 */
362 ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data);
363 if (ret)
364 return ret;
365
366 if (data & MSIC_ADCTHERM_MASK)
367 dev_warn(dev, "ADCTHERM already set");
368
369 /* Index of the first channel in which the stop bit is set */
370 channel_index = find_free_channel();
371 if (channel_index < 0) {
372 dev_err(dev, "No free ADC channels");
373 return channel_index;
374 }
375
376 base_addr = ADC_CHNL_START_ADDR + channel_index;
377
378 if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) {
379 /* Reset stop bit for channels other than 0 and 12 */
380 ret = reset_stopbit(base_addr);
381 if (ret)
382 return ret;
383
384 /* Index of the first free channel */
385 base_addr++;
386 channel_index++;
387 }
388
389 ret = set_up_therm_channel(base_addr);
390 if (ret) {
391 dev_err(dev, "unable to enable ADC");
392 return ret;
393 }
394 dev_dbg(dev, "ADC initialization successful");
395 return ret;
396}
397
398/**
399 * initialize_sensor - sets default temp and timer ranges
400 * @index: index of the sensor
401 *
402 * Context: can sleep
403 */
404static struct thermal_device_info *initialize_sensor(int index)
405{
406 struct thermal_device_info *td_info =
407 kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL);
408
409 if (!td_info)
410 return NULL;
411
412 /* Set the base addr of the channel for this sensor */
413 td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index);
414 /* Sensor 3 is direct conversion */
415 if (index == 3)
416 td_info->direct = 1;
417 return td_info;
418}
419
420/**
421 * mid_thermal_resume - resume routine
422 * @pdev: platform device structure
423 *
424 * mid thermal resume: re-initializes the adc. Can sleep.
425 */
426static int mid_thermal_resume(struct platform_device *pdev)
427{
428 return mid_initialize_adc(&pdev->dev);
429}
430
431/**
432 * mid_thermal_suspend - suspend routine
433 * @pdev: platform device structure
434 *
435 * mid thermal suspend implements the suspend functionality
436 * by stopping the ADC. Can sleep.
437 */
438static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg)
439{
440 /*
441 * This just stops the ADC and does not disable it.
442 * temporary workaround until we have a generic ADC driver.
443 * If 0 is passed, it disables the ADC.
444 */
445 return configure_adc(0);
446}
447
448/**
449 * read_curr_temp - reads the current temperature and stores in temp
450 * @temp: holds the current temperature value after reading
451 *
452 * Can sleep
453 */
454static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
455{
456 WARN_ON(tzd == NULL);
457 return mid_read_temp(tzd, temp);
458}
459
460/* Can't be const */
461static struct thermal_zone_device_ops tzd_ops = {
462 .get_temp = read_curr_temp,
463};
464
465
466/**
467 * mid_thermal_probe - mfld thermal initialize
468 * @pdev: platform device structure
469 *
470 * mid thermal probe initializes the hardware and registers
471 * all the sensors with the generic thermal framework. Can sleep.
472 */
473static int mid_thermal_probe(struct platform_device *pdev)
474{
475 static char *name[MSIC_THERMAL_SENSORS] = {
476 "skin0", "skin1", "sys", "msicdie"
477 };
478
479 int ret;
480 int i;
481 struct platform_info *pinfo;
482
483 pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL);
484 if (!pinfo)
485 return -ENOMEM;
486
487 /* Initializing the hardware */
488 ret = mid_initialize_adc(&pdev->dev);
489 if (ret) {
490 dev_err(&pdev->dev, "ADC init failed");
491 kfree(pinfo);
492 return ret;
493 }
494
495 /* Register each sensor with the generic thermal framework*/
496 for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
497 pinfo->tzd[i] = thermal_zone_device_register(name[i],
498 0, initialize_sensor(i),
499 &tzd_ops, 0, 0, 0, 0);
500 if (IS_ERR(pinfo->tzd[i]))
501 goto reg_fail;
502 }
503
504 pinfo->pdev = pdev;
505 platform_set_drvdata(pdev, pinfo);
506 return 0;
507
508reg_fail:
509 ret = PTR_ERR(pinfo->tzd[i]);
510 while (--i >= 0)
511 thermal_zone_device_unregister(pinfo->tzd[i]);
512 configure_adc(0);
513 kfree(pinfo);
514 return ret;
515}
516
517/**
518 * mid_thermal_remove - mfld thermal finalize
519 * @dev: platform device structure
520 *
521 * MLFD thermal remove unregisters all the sensors from the generic
522 * thermal framework. Can sleep.
523 */
524static int mid_thermal_remove(struct platform_device *pdev)
525{
526 int i;
527 struct platform_info *pinfo = platform_get_drvdata(pdev);
528
529 for (i = 0; i < MSIC_THERMAL_SENSORS; i++)
530 thermal_zone_device_unregister(pinfo->tzd[i]);
531
532 platform_set_drvdata(pdev, NULL);
533
534 /* Stop the ADC */
535 return configure_adc(0);
536}
537
538/*********************************************************************
539 * Driver initialisation and finalization
540 *********************************************************************/
541
542#define DRIVER_NAME "msic_sensor"
543
544static const struct platform_device_id therm_id_table[] = {
545 { DRIVER_NAME, 1 },
546 { }
547};
548
549static struct platform_driver mid_thermal_driver = {
550 .driver = {
551 .name = DRIVER_NAME,
552 .owner = THIS_MODULE,
553 },
554 .probe = mid_thermal_probe,
555 .suspend = mid_thermal_suspend,
556 .resume = mid_thermal_resume,
557 .remove = __devexit_p(mid_thermal_remove),
558 .id_table = therm_id_table,
559};
560
561static int __init mid_thermal_module_init(void)
562{
563 return platform_driver_register(&mid_thermal_driver);
564}
565
566static void __exit mid_thermal_module_exit(void)
567{
568 platform_driver_unregister(&mid_thermal_driver);
569}
570
571module_init(mid_thermal_module_init);
572module_exit(mid_thermal_module_exit);
573
574MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
575MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
576MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c
index 2b11a33325e6..bde47e9080cd 100644
--- a/drivers/platform/x86/intel_rar_register.c
+++ b/drivers/platform/x86/intel_rar_register.c
@@ -485,7 +485,7 @@ EXPORT_SYMBOL(rar_lock);
485 * 485 *
486 * The register_rar function is to used by other device drivers 486 * The register_rar function is to used by other device drivers
487 * to ensure that this driver is ready. As we cannot be sure of 487 * to ensure that this driver is ready. As we cannot be sure of
488 * the compile/execute order of drivers in ther kernel, it is 488 * the compile/execute order of drivers in the kernel, it is
489 * best to give this driver a callback function to call when 489 * best to give this driver a callback function to call when
490 * it is ready to give out addresses. The callback function 490 * it is ready to give out addresses. The callback function
491 * would have those steps that continue the initialization of 491 * would have those steps that continue the initialization of
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index a91d510a798b..940accbe28d3 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -9,7 +9,7 @@
9 * as published by the Free Software Foundation; version 2 9 * as published by the Free Software Foundation; version 2
10 * of the License. 10 * of the License.
11 * 11 *
12 * SCU runing in ARC processor communicates with other entity running in IA 12 * SCU running in ARC processor communicates with other entity running in IA
13 * core through IPC mechanism which in turn messaging between IA core ad SCU. 13 * core through IPC mechanism which in turn messaging between IA core ad SCU.
14 * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and 14 * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and
15 * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with 15 * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 142d38579314..23fb2afda00b 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -51,6 +51,8 @@
51 * laptop as MSI S270. YMMV. 51 * laptop as MSI S270. YMMV.
52 */ 52 */
53 53
54#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
55
54#include <linux/module.h> 56#include <linux/module.h>
55#include <linux/kernel.h> 57#include <linux/kernel.h>
56#include <linux/init.h> 58#include <linux/init.h>
@@ -60,6 +62,8 @@
60#include <linux/platform_device.h> 62#include <linux/platform_device.h>
61#include <linux/rfkill.h> 63#include <linux/rfkill.h>
62#include <linux/i8042.h> 64#include <linux/i8042.h>
65#include <linux/input.h>
66#include <linux/input/sparse-keymap.h>
63 67
64#define MSI_DRIVER_VERSION "0.5" 68#define MSI_DRIVER_VERSION "0.5"
65 69
@@ -78,6 +82,9 @@
78#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d 82#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
79#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) 83#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
80 84
85#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4
86#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
87
81static int msi_laptop_resume(struct platform_device *device); 88static int msi_laptop_resume(struct platform_device *device);
82 89
83#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f 90#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
@@ -90,6 +97,14 @@ static int auto_brightness;
90module_param(auto_brightness, int, 0); 97module_param(auto_brightness, int, 0);
91MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); 98MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
92 99
100static const struct key_entry msi_laptop_keymap[] = {
101 {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, /* Touch Pad On */
102 {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },/* Touch Pad On */
103 {KE_END, 0}
104};
105
106static struct input_dev *msi_laptop_input_dev;
107
93static bool old_ec_model; 108static bool old_ec_model;
94static int wlan_s, bluetooth_s, threeg_s; 109static int wlan_s, bluetooth_s, threeg_s;
95static int threeg_exists; 110static int threeg_exists;
@@ -432,8 +447,7 @@ static struct platform_device *msipf_device;
432 447
433static int dmi_check_cb(const struct dmi_system_id *id) 448static int dmi_check_cb(const struct dmi_system_id *id)
434{ 449{
435 printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n", 450 pr_info("Identified laptop model '%s'.\n", id->ident);
436 id->ident);
437 return 1; 451 return 1;
438} 452}
439 453
@@ -605,6 +619,21 @@ static void msi_update_rfkill(struct work_struct *ignored)
605} 619}
606static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); 620static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill);
607 621
622static void msi_send_touchpad_key(struct work_struct *ignored)
623{
624 u8 rdata;
625 int result;
626
627 result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata);
628 if (result < 0)
629 return;
630
631 sparse_keymap_report_event(msi_laptop_input_dev,
632 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
633 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
634}
635static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key);
636
608static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, 637static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
609 struct serio *port) 638 struct serio *port)
610{ 639{
@@ -613,12 +642,17 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
613 if (str & 0x20) 642 if (str & 0x20)
614 return false; 643 return false;
615 644
616 /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan*/ 645 /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/
617 if (unlikely(data == 0xe0)) { 646 if (unlikely(data == 0xe0)) {
618 extended = true; 647 extended = true;
619 return false; 648 return false;
620 } else if (unlikely(extended)) { 649 } else if (unlikely(extended)) {
650 extended = false;
621 switch (data) { 651 switch (data) {
652 case 0xE4:
653 schedule_delayed_work(&msi_touchpad_work,
654 round_jiffies_relative(0.5 * HZ));
655 break;
622 case 0x54: 656 case 0x54:
623 case 0x62: 657 case 0x62:
624 case 0x76: 658 case 0x76:
@@ -626,7 +660,6 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
626 round_jiffies_relative(0.5 * HZ)); 660 round_jiffies_relative(0.5 * HZ));
627 break; 661 break;
628 } 662 }
629 extended = false;
630 } 663 }
631 664
632 return false; 665 return false;
@@ -731,6 +764,42 @@ static int msi_laptop_resume(struct platform_device *device)
731 return 0; 764 return 0;
732} 765}
733 766
767static int __init msi_laptop_input_setup(void)
768{
769 int err;
770
771 msi_laptop_input_dev = input_allocate_device();
772 if (!msi_laptop_input_dev)
773 return -ENOMEM;
774
775 msi_laptop_input_dev->name = "MSI Laptop hotkeys";
776 msi_laptop_input_dev->phys = "msi-laptop/input0";
777 msi_laptop_input_dev->id.bustype = BUS_HOST;
778
779 err = sparse_keymap_setup(msi_laptop_input_dev,
780 msi_laptop_keymap, NULL);
781 if (err)
782 goto err_free_dev;
783
784 err = input_register_device(msi_laptop_input_dev);
785 if (err)
786 goto err_free_keymap;
787
788 return 0;
789
790err_free_keymap:
791 sparse_keymap_free(msi_laptop_input_dev);
792err_free_dev:
793 input_free_device(msi_laptop_input_dev);
794 return err;
795}
796
797static void msi_laptop_input_destroy(void)
798{
799 sparse_keymap_free(msi_laptop_input_dev);
800 input_unregister_device(msi_laptop_input_dev);
801}
802
734static int load_scm_model_init(struct platform_device *sdev) 803static int load_scm_model_init(struct platform_device *sdev)
735{ 804{
736 u8 data; 805 u8 data;
@@ -759,16 +828,23 @@ static int load_scm_model_init(struct platform_device *sdev)
759 if (result < 0) 828 if (result < 0)
760 goto fail_rfkill; 829 goto fail_rfkill;
761 830
831 /* setup input device */
832 result = msi_laptop_input_setup();
833 if (result)
834 goto fail_input;
835
762 result = i8042_install_filter(msi_laptop_i8042_filter); 836 result = i8042_install_filter(msi_laptop_i8042_filter);
763 if (result) { 837 if (result) {
764 printk(KERN_ERR 838 pr_err("Unable to install key filter\n");
765 "msi-laptop: Unable to install key filter\n");
766 goto fail_filter; 839 goto fail_filter;
767 } 840 }
768 841
769 return 0; 842 return 0;
770 843
771fail_filter: 844fail_filter:
845 msi_laptop_input_destroy();
846
847fail_input:
772 rfkill_cleanup(); 848 rfkill_cleanup();
773 849
774fail_rfkill: 850fail_rfkill:
@@ -799,7 +875,7 @@ static int __init msi_init(void)
799 /* Register backlight stuff */ 875 /* Register backlight stuff */
800 876
801 if (acpi_video_backlight_support()) { 877 if (acpi_video_backlight_support()) {
802 printk(KERN_INFO "MSI: Brightness ignored, must be controlled " 878 pr_info("Brightness ignored, must be controlled "
803 "by ACPI video driver\n"); 879 "by ACPI video driver\n");
804 } else { 880 } else {
805 struct backlight_properties props; 881 struct backlight_properties props;
@@ -854,7 +930,7 @@ static int __init msi_init(void)
854 if (auto_brightness != 2) 930 if (auto_brightness != 2)
855 set_auto_brightness(auto_brightness); 931 set_auto_brightness(auto_brightness);
856 932
857 printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); 933 pr_info("driver "MSI_DRIVER_VERSION" successfully loaded.\n");
858 934
859 return 0; 935 return 0;
860 936
@@ -886,6 +962,7 @@ static void __exit msi_cleanup(void)
886{ 962{
887 if (load_scm_model) { 963 if (load_scm_model) {
888 i8042_remove_filter(msi_laptop_i8042_filter); 964 i8042_remove_filter(msi_laptop_i8042_filter);
965 msi_laptop_input_destroy();
889 cancel_delayed_work_sync(&msi_rfkill_work); 966 cancel_delayed_work_sync(&msi_rfkill_work);
890 rfkill_cleanup(); 967 rfkill_cleanup();
891 } 968 }
@@ -901,7 +978,7 @@ static void __exit msi_cleanup(void)
901 if (auto_brightness != 2) 978 if (auto_brightness != 2)
902 set_auto_brightness(1); 979 set_auto_brightness(1);
903 980
904 printk(KERN_INFO "msi-laptop: driver unloaded.\n"); 981 pr_info("driver unloaded.\n");
905} 982}
906 983
907module_init(msi_init); 984module_init(msi_init);
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
new file mode 100644
index 000000000000..de434c6dc2d6
--- /dev/null
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -0,0 +1,832 @@
1/*
2 * Samsung Laptop driver
3 *
4 * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
5 * Copyright (C) 2009,2011 Novell Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 */
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/delay.h>
18#include <linux/pci.h>
19#include <linux/backlight.h>
20#include <linux/fb.h>
21#include <linux/dmi.h>
22#include <linux/platform_device.h>
23#include <linux/rfkill.h>
24
25/*
26 * This driver is needed because a number of Samsung laptops do not hook
27 * their control settings through ACPI. So we have to poke around in the
28 * BIOS to do things like brightness values, and "special" key controls.
29 */
30
31/*
32 * We have 0 - 8 as valid brightness levels. The specs say that level 0 should
33 * be reserved by the BIOS (which really doesn't make much sense), we tell
34 * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
35 */
36#define MAX_BRIGHT 0x07
37
38
39#define SABI_IFACE_MAIN 0x00
40#define SABI_IFACE_SUB 0x02
41#define SABI_IFACE_COMPLETE 0x04
42#define SABI_IFACE_DATA 0x05
43
44/* Structure to get data back to the calling function */
45struct sabi_retval {
46 u8 retval[20];
47};
48
49struct sabi_header_offsets {
50 u8 port;
51 u8 re_mem;
52 u8 iface_func;
53 u8 en_mem;
54 u8 data_offset;
55 u8 data_segment;
56};
57
58struct sabi_commands {
59 /*
60 * Brightness is 0 - 8, as described above.
61 * Value 0 is for the BIOS to use
62 */
63 u8 get_brightness;
64 u8 set_brightness;
65
66 /*
67 * first byte:
68 * 0x00 - wireless is off
69 * 0x01 - wireless is on
70 * second byte:
71 * 0x02 - 3G is off
72 * 0x03 - 3G is on
73 * TODO, verify 3G is correct, that doesn't seem right...
74 */
75 u8 get_wireless_button;
76 u8 set_wireless_button;
77
78 /* 0 is off, 1 is on */
79 u8 get_backlight;
80 u8 set_backlight;
81
82 /*
83 * 0x80 or 0x00 - no action
84 * 0x81 - recovery key pressed
85 */
86 u8 get_recovery_mode;
87 u8 set_recovery_mode;
88
89 /*
90 * on seclinux: 0 is low, 1 is high,
91 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
92 */
93 u8 get_performance_level;
94 u8 set_performance_level;
95
96 /*
97 * Tell the BIOS that Linux is running on this machine.
98 * 81 is on, 80 is off
99 */
100 u8 set_linux;
101};
102
103struct sabi_performance_level {
104 const char *name;
105 u8 value;
106};
107
108struct sabi_config {
109 const char *test_string;
110 u16 main_function;
111 const struct sabi_header_offsets header_offsets;
112 const struct sabi_commands commands;
113 const struct sabi_performance_level performance_levels[4];
114 u8 min_brightness;
115 u8 max_brightness;
116};
117
118static const struct sabi_config sabi_configs[] = {
119 {
120 .test_string = "SECLINUX",
121
122 .main_function = 0x4c49,
123
124 .header_offsets = {
125 .port = 0x00,
126 .re_mem = 0x02,
127 .iface_func = 0x03,
128 .en_mem = 0x04,
129 .data_offset = 0x05,
130 .data_segment = 0x07,
131 },
132
133 .commands = {
134 .get_brightness = 0x00,
135 .set_brightness = 0x01,
136
137 .get_wireless_button = 0x02,
138 .set_wireless_button = 0x03,
139
140 .get_backlight = 0x04,
141 .set_backlight = 0x05,
142
143 .get_recovery_mode = 0x06,
144 .set_recovery_mode = 0x07,
145
146 .get_performance_level = 0x08,
147 .set_performance_level = 0x09,
148
149 .set_linux = 0x0a,
150 },
151
152 .performance_levels = {
153 {
154 .name = "silent",
155 .value = 0,
156 },
157 {
158 .name = "normal",
159 .value = 1,
160 },
161 { },
162 },
163 .min_brightness = 1,
164 .max_brightness = 8,
165 },
166 {
167 .test_string = "SwSmi@",
168
169 .main_function = 0x5843,
170
171 .header_offsets = {
172 .port = 0x00,
173 .re_mem = 0x04,
174 .iface_func = 0x02,
175 .en_mem = 0x03,
176 .data_offset = 0x05,
177 .data_segment = 0x07,
178 },
179
180 .commands = {
181 .get_brightness = 0x10,
182 .set_brightness = 0x11,
183
184 .get_wireless_button = 0x12,
185 .set_wireless_button = 0x13,
186
187 .get_backlight = 0x2d,
188 .set_backlight = 0x2e,
189
190 .get_recovery_mode = 0xff,
191 .set_recovery_mode = 0xff,
192
193 .get_performance_level = 0x31,
194 .set_performance_level = 0x32,
195
196 .set_linux = 0xff,
197 },
198
199 .performance_levels = {
200 {
201 .name = "normal",
202 .value = 0,
203 },
204 {
205 .name = "silent",
206 .value = 1,
207 },
208 {
209 .name = "overclock",
210 .value = 2,
211 },
212 { },
213 },
214 .min_brightness = 0,
215 .max_brightness = 8,
216 },
217 { },
218};
219
220static const struct sabi_config *sabi_config;
221
222static void __iomem *sabi;
223static void __iomem *sabi_iface;
224static void __iomem *f0000_segment;
225static struct backlight_device *backlight_device;
226static struct mutex sabi_mutex;
227static struct platform_device *sdev;
228static struct rfkill *rfk;
229
230static int force;
231module_param(force, bool, 0);
232MODULE_PARM_DESC(force,
233 "Disable the DMI check and forces the driver to be loaded");
234
235static int debug;
236module_param(debug, bool, S_IRUGO | S_IWUSR);
237MODULE_PARM_DESC(debug, "Debug enabled or not");
238
239static int sabi_get_command(u8 command, struct sabi_retval *sretval)
240{
241 int retval = 0;
242 u16 port = readw(sabi + sabi_config->header_offsets.port);
243 u8 complete, iface_data;
244
245 mutex_lock(&sabi_mutex);
246
247 /* enable memory to be able to write to it */
248 outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
249
250 /* write out the command */
251 writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
252 writew(command, sabi_iface + SABI_IFACE_SUB);
253 writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
254 outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
255
256 /* write protect memory to make it safe */
257 outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
258
259 /* see if the command actually succeeded */
260 complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
261 iface_data = readb(sabi_iface + SABI_IFACE_DATA);
262 if (complete != 0xaa || iface_data == 0xff) {
263 pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
264 command, complete, iface_data);
265 retval = -EINVAL;
266 goto exit;
267 }
268 /*
269 * Save off the data into a structure so the caller use it.
270 * Right now we only want the first 4 bytes,
271 * There are commands that need more, but not for the ones we
272 * currently care about.
273 */
274 sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
275 sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
276 sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
277 sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
278
279exit:
280 mutex_unlock(&sabi_mutex);
281 return retval;
282
283}
284
285static int sabi_set_command(u8 command, u8 data)
286{
287 int retval = 0;
288 u16 port = readw(sabi + sabi_config->header_offsets.port);
289 u8 complete, iface_data;
290
291 mutex_lock(&sabi_mutex);
292
293 /* enable memory to be able to write to it */
294 outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
295
296 /* write out the command */
297 writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
298 writew(command, sabi_iface + SABI_IFACE_SUB);
299 writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
300 writeb(data, sabi_iface + SABI_IFACE_DATA);
301 outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
302
303 /* write protect memory to make it safe */
304 outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
305
306 /* see if the command actually succeeded */
307 complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
308 iface_data = readb(sabi_iface + SABI_IFACE_DATA);
309 if (complete != 0xaa || iface_data == 0xff) {
310 pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
311 command, complete, iface_data);
312 retval = -EINVAL;
313 }
314
315 mutex_unlock(&sabi_mutex);
316 return retval;
317}
318
319static void test_backlight(void)
320{
321 struct sabi_retval sretval;
322
323 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
324 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
325
326 sabi_set_command(sabi_config->commands.set_backlight, 0);
327 printk(KERN_DEBUG "backlight should be off\n");
328
329 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
330 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
331
332 msleep(1000);
333
334 sabi_set_command(sabi_config->commands.set_backlight, 1);
335 printk(KERN_DEBUG "backlight should be on\n");
336
337 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
338 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
339}
340
341static void test_wireless(void)
342{
343 struct sabi_retval sretval;
344
345 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
346 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
347
348 sabi_set_command(sabi_config->commands.set_wireless_button, 0);
349 printk(KERN_DEBUG "wireless led should be off\n");
350
351 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
352 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
353
354 msleep(1000);
355
356 sabi_set_command(sabi_config->commands.set_wireless_button, 1);
357 printk(KERN_DEBUG "wireless led should be on\n");
358
359 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
360 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
361}
362
363static u8 read_brightness(void)
364{
365 struct sabi_retval sretval;
366 int user_brightness = 0;
367 int retval;
368
369 retval = sabi_get_command(sabi_config->commands.get_brightness,
370 &sretval);
371 if (!retval) {
372 user_brightness = sretval.retval[0];
373 if (user_brightness != 0)
374 user_brightness -= sabi_config->min_brightness;
375 }
376 return user_brightness;
377}
378
379static void set_brightness(u8 user_brightness)
380{
381 u8 user_level = user_brightness - sabi_config->min_brightness;
382
383 sabi_set_command(sabi_config->commands.set_brightness, user_level);
384}
385
386static int get_brightness(struct backlight_device *bd)
387{
388 return (int)read_brightness();
389}
390
391static int update_status(struct backlight_device *bd)
392{
393 set_brightness(bd->props.brightness);
394
395 if (bd->props.power == FB_BLANK_UNBLANK)
396 sabi_set_command(sabi_config->commands.set_backlight, 1);
397 else
398 sabi_set_command(sabi_config->commands.set_backlight, 0);
399 return 0;
400}
401
402static const struct backlight_ops backlight_ops = {
403 .get_brightness = get_brightness,
404 .update_status = update_status,
405};
406
407static int rfkill_set(void *data, bool blocked)
408{
409 /* Do something with blocked...*/
410 /*
411 * blocked == false is on
412 * blocked == true is off
413 */
414 if (blocked)
415 sabi_set_command(sabi_config->commands.set_wireless_button, 0);
416 else
417 sabi_set_command(sabi_config->commands.set_wireless_button, 1);
418
419 return 0;
420}
421
422static struct rfkill_ops rfkill_ops = {
423 .set_block = rfkill_set,
424};
425
426static int init_wireless(struct platform_device *sdev)
427{
428 int retval;
429
430 rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
431 &rfkill_ops, NULL);
432 if (!rfk)
433 return -ENOMEM;
434
435 retval = rfkill_register(rfk);
436 if (retval) {
437 rfkill_destroy(rfk);
438 return -ENODEV;
439 }
440
441 return 0;
442}
443
444static void destroy_wireless(void)
445{
446 rfkill_unregister(rfk);
447 rfkill_destroy(rfk);
448}
449
450static ssize_t get_performance_level(struct device *dev,
451 struct device_attribute *attr, char *buf)
452{
453 struct sabi_retval sretval;
454 int retval;
455 int i;
456
457 /* Read the state */
458 retval = sabi_get_command(sabi_config->commands.get_performance_level,
459 &sretval);
460 if (retval)
461 return retval;
462
463 /* The logic is backwards, yeah, lots of fun... */
464 for (i = 0; sabi_config->performance_levels[i].name; ++i) {
465 if (sretval.retval[0] == sabi_config->performance_levels[i].value)
466 return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
467 }
468 return sprintf(buf, "%s\n", "unknown");
469}
470
471static ssize_t set_performance_level(struct device *dev,
472 struct device_attribute *attr, const char *buf,
473 size_t count)
474{
475 if (count >= 1) {
476 int i;
477 for (i = 0; sabi_config->performance_levels[i].name; ++i) {
478 const struct sabi_performance_level *level =
479 &sabi_config->performance_levels[i];
480 if (!strncasecmp(level->name, buf, strlen(level->name))) {
481 sabi_set_command(sabi_config->commands.set_performance_level,
482 level->value);
483 break;
484 }
485 }
486 if (!sabi_config->performance_levels[i].name)
487 return -EINVAL;
488 }
489 return count;
490}
491static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
492 get_performance_level, set_performance_level);
493
494
495static int __init dmi_check_cb(const struct dmi_system_id *id)
496{
497 pr_info("found laptop model '%s'\n",
498 id->ident);
499 return 1;
500}
501
502static struct dmi_system_id __initdata samsung_dmi_table[] = {
503 {
504 .ident = "N128",
505 .matches = {
506 DMI_MATCH(DMI_SYS_VENDOR,
507 "SAMSUNG ELECTRONICS CO., LTD."),
508 DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
509 DMI_MATCH(DMI_BOARD_NAME, "N128"),
510 },
511 .callback = dmi_check_cb,
512 },
513 {
514 .ident = "N130",
515 .matches = {
516 DMI_MATCH(DMI_SYS_VENDOR,
517 "SAMSUNG ELECTRONICS CO., LTD."),
518 DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
519 DMI_MATCH(DMI_BOARD_NAME, "N130"),
520 },
521 .callback = dmi_check_cb,
522 },
523 {
524 .ident = "X125",
525 .matches = {
526 DMI_MATCH(DMI_SYS_VENDOR,
527 "SAMSUNG ELECTRONICS CO., LTD."),
528 DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
529 DMI_MATCH(DMI_BOARD_NAME, "X125"),
530 },
531 .callback = dmi_check_cb,
532 },
533 {
534 .ident = "X120/X170",
535 .matches = {
536 DMI_MATCH(DMI_SYS_VENDOR,
537 "SAMSUNG ELECTRONICS CO., LTD."),
538 DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
539 DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
540 },
541 .callback = dmi_check_cb,
542 },
543 {
544 .ident = "NC10",
545 .matches = {
546 DMI_MATCH(DMI_SYS_VENDOR,
547 "SAMSUNG ELECTRONICS CO., LTD."),
548 DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
549 DMI_MATCH(DMI_BOARD_NAME, "NC10"),
550 },
551 .callback = dmi_check_cb,
552 },
553 {
554 .ident = "NP-Q45",
555 .matches = {
556 DMI_MATCH(DMI_SYS_VENDOR,
557 "SAMSUNG ELECTRONICS CO., LTD."),
558 DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
559 DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
560 },
561 .callback = dmi_check_cb,
562 },
563 {
564 .ident = "X360",
565 .matches = {
566 DMI_MATCH(DMI_SYS_VENDOR,
567 "SAMSUNG ELECTRONICS CO., LTD."),
568 DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
569 DMI_MATCH(DMI_BOARD_NAME, "X360"),
570 },
571 .callback = dmi_check_cb,
572 },
573 {
574 .ident = "R518",
575 .matches = {
576 DMI_MATCH(DMI_SYS_VENDOR,
577 "SAMSUNG ELECTRONICS CO., LTD."),
578 DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
579 DMI_MATCH(DMI_BOARD_NAME, "R518"),
580 },
581 .callback = dmi_check_cb,
582 },
583 {
584 .ident = "R519/R719",
585 .matches = {
586 DMI_MATCH(DMI_SYS_VENDOR,
587 "SAMSUNG ELECTRONICS CO., LTD."),
588 DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
589 DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
590 },
591 .callback = dmi_check_cb,
592 },
593 {
594 .ident = "N150/N210/N220",
595 .matches = {
596 DMI_MATCH(DMI_SYS_VENDOR,
597 "SAMSUNG ELECTRONICS CO., LTD."),
598 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
599 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
600 },
601 .callback = dmi_check_cb,
602 },
603 {
604 .ident = "N150P/N210P/N220P",
605 .matches = {
606 DMI_MATCH(DMI_SYS_VENDOR,
607 "SAMSUNG ELECTRONICS CO., LTD."),
608 DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
609 DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
610 },
611 .callback = dmi_check_cb,
612 },
613 {
614 .ident = "R530/R730",
615 .matches = {
616 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
617 DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
618 DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
619 },
620 .callback = dmi_check_cb,
621 },
622 {
623 .ident = "NF110/NF210/NF310",
624 .matches = {
625 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
626 DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
627 DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
628 },
629 .callback = dmi_check_cb,
630 },
631 {
632 .ident = "N145P/N250P/N260P",
633 .matches = {
634 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
635 DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
636 DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
637 },
638 .callback = dmi_check_cb,
639 },
640 {
641 .ident = "R70/R71",
642 .matches = {
643 DMI_MATCH(DMI_SYS_VENDOR,
644 "SAMSUNG ELECTRONICS CO., LTD."),
645 DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
646 DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
647 },
648 .callback = dmi_check_cb,
649 },
650 {
651 .ident = "P460",
652 .matches = {
653 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
654 DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
655 DMI_MATCH(DMI_BOARD_NAME, "P460"),
656 },
657 .callback = dmi_check_cb,
658 },
659 { },
660};
661MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
662
663static int find_signature(void __iomem *memcheck, const char *testStr)
664{
665 int i = 0;
666 int loca;
667
668 for (loca = 0; loca < 0xffff; loca++) {
669 char temp = readb(memcheck + loca);
670
671 if (temp == testStr[i]) {
672 if (i == strlen(testStr)-1)
673 break;
674 ++i;
675 } else {
676 i = 0;
677 }
678 }
679 return loca;
680}
681
682static int __init samsung_init(void)
683{
684 struct backlight_properties props;
685 struct sabi_retval sretval;
686 unsigned int ifaceP;
687 int i;
688 int loca;
689 int retval;
690
691 mutex_init(&sabi_mutex);
692
693 if (!force && !dmi_check_system(samsung_dmi_table))
694 return -ENODEV;
695
696 f0000_segment = ioremap_nocache(0xf0000, 0xffff);
697 if (!f0000_segment) {
698 pr_err("Can't map the segment at 0xf0000\n");
699 return -EINVAL;
700 }
701
702 /* Try to find one of the signatures in memory to find the header */
703 for (i = 0; sabi_configs[i].test_string != 0; ++i) {
704 sabi_config = &sabi_configs[i];
705 loca = find_signature(f0000_segment, sabi_config->test_string);
706 if (loca != 0xffff)
707 break;
708 }
709
710 if (loca == 0xffff) {
711 pr_err("This computer does not support SABI\n");
712 goto error_no_signature;
713 }
714
715 /* point to the SMI port Number */
716 loca += 1;
717 sabi = (f0000_segment + loca);
718
719 if (debug) {
720 printk(KERN_DEBUG "This computer supports SABI==%x\n",
721 loca + 0xf0000 - 6);
722 printk(KERN_DEBUG "SABI header:\n");
723 printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
724 readw(sabi + sabi_config->header_offsets.port));
725 printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
726 readb(sabi + sabi_config->header_offsets.iface_func));
727 printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
728 readb(sabi + sabi_config->header_offsets.en_mem));
729 printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
730 readb(sabi + sabi_config->header_offsets.re_mem));
731 printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
732 readw(sabi + sabi_config->header_offsets.data_offset));
733 printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
734 readw(sabi + sabi_config->header_offsets.data_segment));
735 }
736
737 /* Get a pointer to the SABI Interface */
738 ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
739 ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
740 sabi_iface = ioremap_nocache(ifaceP, 16);
741 if (!sabi_iface) {
742 pr_err("Can't remap %x\n", ifaceP);
743 goto exit;
744 }
745 if (debug) {
746 printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
747 printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
748
749 test_backlight();
750 test_wireless();
751
752 retval = sabi_get_command(sabi_config->commands.get_brightness,
753 &sretval);
754 printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
755 }
756
757 /* Turn on "Linux" mode in the BIOS */
758 if (sabi_config->commands.set_linux != 0xff) {
759 retval = sabi_set_command(sabi_config->commands.set_linux,
760 0x81);
761 if (retval) {
762 pr_warn("Linux mode was not set!\n");
763 goto error_no_platform;
764 }
765 }
766
767 /* knock up a platform device to hang stuff off of */
768 sdev = platform_device_register_simple("samsung", -1, NULL, 0);
769 if (IS_ERR(sdev))
770 goto error_no_platform;
771
772 /* create a backlight device to talk to this one */
773 memset(&props, 0, sizeof(struct backlight_properties));
774 props.max_brightness = sabi_config->max_brightness;
775 backlight_device = backlight_device_register("samsung", &sdev->dev,
776 NULL, &backlight_ops,
777 &props);
778 if (IS_ERR(backlight_device))
779 goto error_no_backlight;
780
781 backlight_device->props.brightness = read_brightness();
782 backlight_device->props.power = FB_BLANK_UNBLANK;
783 backlight_update_status(backlight_device);
784
785 retval = init_wireless(sdev);
786 if (retval)
787 goto error_no_rfk;
788
789 retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
790 if (retval)
791 goto error_file_create;
792
793exit:
794 return 0;
795
796error_file_create:
797 destroy_wireless();
798
799error_no_rfk:
800 backlight_device_unregister(backlight_device);
801
802error_no_backlight:
803 platform_device_unregister(sdev);
804
805error_no_platform:
806 iounmap(sabi_iface);
807
808error_no_signature:
809 iounmap(f0000_segment);
810 return -EINVAL;
811}
812
813static void __exit samsung_exit(void)
814{
815 /* Turn off "Linux" mode in the BIOS */
816 if (sabi_config->commands.set_linux != 0xff)
817 sabi_set_command(sabi_config->commands.set_linux, 0x80);
818
819 device_remove_file(&sdev->dev, &dev_attr_performance_level);
820 backlight_device_unregister(backlight_device);
821 destroy_wireless();
822 iounmap(sabi_iface);
823 iounmap(f0000_segment);
824 platform_device_unregister(sdev);
825}
826
827module_init(samsung_init);
828module_exit(samsung_exit);
829
830MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
831MODULE_DESCRIPTION("Samsung Backlight driver");
832MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 13d8d63bcca9..e642f5f29504 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -71,8 +71,9 @@
71#endif 71#endif
72 72
73#define DRV_PFX "sony-laptop: " 73#define DRV_PFX "sony-laptop: "
74#define dprintk(msg...) do { \ 74#define dprintk(msg...) do { \
75 if (debug) printk(KERN_WARNING DRV_PFX msg); \ 75 if (debug) \
76 pr_warn(DRV_PFX msg); \
76} while (0) 77} while (0)
77 78
78#define SONY_LAPTOP_DRIVER_VERSION "0.6" 79#define SONY_LAPTOP_DRIVER_VERSION "0.6"
@@ -124,6 +125,19 @@ MODULE_PARM_DESC(minor,
124 "default is -1 (automatic)"); 125 "default is -1 (automatic)");
125#endif 126#endif
126 127
128static int kbd_backlight; /* = 1 */
129module_param(kbd_backlight, int, 0444);
130MODULE_PARM_DESC(kbd_backlight,
131 "set this to 0 to disable keyboard backlight, "
132 "1 to enable it (default: 0)");
133
134static int kbd_backlight_timeout; /* = 0 */
135module_param(kbd_backlight_timeout, int, 0444);
136MODULE_PARM_DESC(kbd_backlight_timeout,
137 "set this to 0 to set the default 10 seconds timeout, "
138 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
139 "(default: 0)");
140
127enum sony_nc_rfkill { 141enum sony_nc_rfkill {
128 SONY_WIFI, 142 SONY_WIFI,
129 SONY_BLUETOOTH, 143 SONY_BLUETOOTH,
@@ -402,7 +416,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
402 error = kfifo_alloc(&sony_laptop_input.fifo, 416 error = kfifo_alloc(&sony_laptop_input.fifo,
403 SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); 417 SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
404 if (error) { 418 if (error) {
405 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 419 pr_err(DRV_PFX "kfifo_alloc failed\n");
406 goto err_dec_users; 420 goto err_dec_users;
407 } 421 }
408 422
@@ -591,7 +605,7 @@ struct sony_nc_value {
591 int value; /* current setting */ 605 int value; /* current setting */
592 int valid; /* Has ever been set */ 606 int valid; /* Has ever been set */
593 int debug; /* active only in debug mode ? */ 607 int debug; /* active only in debug mode ? */
594 struct device_attribute devattr; /* sysfs atribute */ 608 struct device_attribute devattr; /* sysfs attribute */
595}; 609};
596 610
597#define SNC_HANDLE_NAMES(_name, _values...) \ 611#define SNC_HANDLE_NAMES(_name, _values...) \
@@ -686,7 +700,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
686 return 0; 700 return 0;
687 } 701 }
688 702
689 printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); 703 pr_warn(DRV_PFX "acpi_callreadfunc failed\n");
690 704
691 return -1; 705 return -1;
692} 706}
@@ -712,7 +726,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
712 if (status == AE_OK) { 726 if (status == AE_OK) {
713 if (result != NULL) { 727 if (result != NULL) {
714 if (out_obj.type != ACPI_TYPE_INTEGER) { 728 if (out_obj.type != ACPI_TYPE_INTEGER) {
715 printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " 729 pr_warn(DRV_PFX "acpi_evaluate_object bad "
716 "return type\n"); 730 "return type\n");
717 return -1; 731 return -1;
718 } 732 }
@@ -721,34 +735,103 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
721 return 0; 735 return 0;
722 } 736 }
723 737
724 printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); 738 pr_warn(DRV_PFX "acpi_evaluate_object failed\n");
725 739
726 return -1; 740 return -1;
727} 741}
728 742
729static int sony_find_snc_handle(int handle) 743struct sony_nc_handles {
744 u16 cap[0x10];
745 struct device_attribute devattr;
746};
747
748static struct sony_nc_handles *handles;
749
750static ssize_t sony_nc_handles_show(struct device *dev,
751 struct device_attribute *attr, char *buffer)
752{
753 ssize_t len = 0;
754 int i;
755
756 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
757 len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
758 handles->cap[i]);
759 }
760 len += snprintf(buffer + len, PAGE_SIZE - len, "\n");
761
762 return len;
763}
764
765static int sony_nc_handles_setup(struct platform_device *pd)
730{ 766{
731 int i; 767 int i;
732 int result; 768 int result;
733 769
734 for (i = 0x20; i < 0x30; i++) { 770 handles = kzalloc(sizeof(*handles), GFP_KERNEL);
735 acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result); 771 if (!handles)
736 if (result == handle) 772 return -ENOMEM;
737 return i-0x20; 773
774 sysfs_attr_init(&handles->devattr.attr);
775 handles->devattr.attr.name = "handles";
776 handles->devattr.attr.mode = S_IRUGO;
777 handles->devattr.show = sony_nc_handles_show;
778
779 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
780 if (!acpi_callsetfunc(sony_nc_acpi_handle,
781 "SN00", i + 0x20, &result)) {
782 dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
783 result, i);
784 handles->cap[i] = result;
785 }
786 }
787
788 /* allow reading capabilities via sysfs */
789 if (device_create_file(&pd->dev, &handles->devattr)) {
790 kfree(handles);
791 handles = NULL;
792 return -1;
793 }
794
795 return 0;
796}
797
798static int sony_nc_handles_cleanup(struct platform_device *pd)
799{
800 if (handles) {
801 device_remove_file(&pd->dev, &handles->devattr);
802 kfree(handles);
803 handles = NULL;
738 } 804 }
805 return 0;
806}
739 807
808static int sony_find_snc_handle(int handle)
809{
810 int i;
811 for (i = 0; i < 0x10; i++) {
812 if (handles->cap[i] == handle) {
813 dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
814 handle, i);
815 return i;
816 }
817 }
818 dprintk("handle 0x%.4x not found\n", handle);
740 return -1; 819 return -1;
741} 820}
742 821
743static int sony_call_snc_handle(int handle, int argument, int *result) 822static int sony_call_snc_handle(int handle, int argument, int *result)
744{ 823{
824 int ret = 0;
745 int offset = sony_find_snc_handle(handle); 825 int offset = sony_find_snc_handle(handle);
746 826
747 if (offset < 0) 827 if (offset < 0)
748 return -1; 828 return -1;
749 829
750 return acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, 830 ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument,
751 result); 831 result);
832 dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument,
833 *result);
834 return ret;
752} 835}
753 836
754/* 837/*
@@ -857,11 +940,39 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
857 return value - 1; 940 return value - 1;
858} 941}
859 942
860static struct backlight_device *sony_backlight_device; 943static int sony_nc_get_brightness_ng(struct backlight_device *bd)
944{
945 int result;
946 int *handle = (int *)bl_get_data(bd);
947
948 sony_call_snc_handle(*handle, 0x0200, &result);
949
950 return result & 0xff;
951}
952
953static int sony_nc_update_status_ng(struct backlight_device *bd)
954{
955 int value, result;
956 int *handle = (int *)bl_get_data(bd);
957
958 value = bd->props.brightness;
959 sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result);
960
961 return sony_nc_get_brightness_ng(bd);
962}
963
861static const struct backlight_ops sony_backlight_ops = { 964static const struct backlight_ops sony_backlight_ops = {
965 .options = BL_CORE_SUSPENDRESUME,
862 .update_status = sony_backlight_update_status, 966 .update_status = sony_backlight_update_status,
863 .get_brightness = sony_backlight_get_brightness, 967 .get_brightness = sony_backlight_get_brightness,
864}; 968};
969static const struct backlight_ops sony_backlight_ng_ops = {
970 .options = BL_CORE_SUSPENDRESUME,
971 .update_status = sony_nc_update_status_ng,
972 .get_brightness = sony_nc_get_brightness_ng,
973};
974static int backlight_ng_handle;
975static struct backlight_device *sony_backlight_device;
865 976
866/* 977/*
867 * New SNC-only Vaios event mapping to driver known keys 978 * New SNC-only Vaios event mapping to driver known keys
@@ -972,7 +1083,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
972 } 1083 }
973 1084
974 if (!key_event->data) 1085 if (!key_event->data)
975 printk(KERN_INFO DRV_PFX 1086 pr_info(DRV_PFX
976 "Unknown event: 0x%x 0x%x\n", 1087 "Unknown event: 0x%x 0x%x\n",
977 key_handle, 1088 key_handle,
978 ev); 1089 ev);
@@ -996,7 +1107,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
996 struct acpi_device_info *info; 1107 struct acpi_device_info *info;
997 1108
998 if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { 1109 if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
999 printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", 1110 pr_warn(DRV_PFX "method: name: %4.4s, args %X\n",
1000 (char *)&info->name, info->param_count); 1111 (char *)&info->name, info->param_count);
1001 1112
1002 kfree(info); 1113 kfree(info);
@@ -1037,7 +1148,7 @@ static int sony_nc_resume(struct acpi_device *device)
1037 ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, 1148 ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
1038 item->value, NULL); 1149 item->value, NULL);
1039 if (ret < 0) { 1150 if (ret < 0) {
1040 printk("%s: %d\n", __func__, ret); 1151 pr_err(DRV_PFX "%s: %d\n", __func__, ret);
1041 break; 1152 break;
1042 } 1153 }
1043 } 1154 }
@@ -1054,11 +1165,6 @@ static int sony_nc_resume(struct acpi_device *device)
1054 sony_nc_function_setup(device); 1165 sony_nc_function_setup(device);
1055 } 1166 }
1056 1167
1057 /* set the last requested brightness level */
1058 if (sony_backlight_device &&
1059 sony_backlight_update_status(sony_backlight_device) < 0)
1060 printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n");
1061
1062 /* re-read rfkill state */ 1168 /* re-read rfkill state */
1063 sony_nc_rfkill_update(); 1169 sony_nc_rfkill_update();
1064 1170
@@ -1206,12 +1312,12 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
1206 1312
1207 device_enum = (union acpi_object *) buffer.pointer; 1313 device_enum = (union acpi_object *) buffer.pointer;
1208 if (!device_enum) { 1314 if (!device_enum) {
1209 pr_err("Invalid SN06 return object\n"); 1315 pr_err(DRV_PFX "No SN06 return object.");
1210 goto out_no_enum; 1316 goto out_no_enum;
1211 } 1317 }
1212 if (device_enum->type != ACPI_TYPE_BUFFER) { 1318 if (device_enum->type != ACPI_TYPE_BUFFER) {
1213 pr_err("Invalid SN06 return object type 0x%.2x\n", 1319 pr_err(DRV_PFX "Invalid SN06 return object 0x%.2x\n",
1214 device_enum->type); 1320 device_enum->type);
1215 goto out_no_enum; 1321 goto out_no_enum;
1216 } 1322 }
1217 1323
@@ -1245,6 +1351,209 @@ out_no_enum:
1245 return; 1351 return;
1246} 1352}
1247 1353
1354/* Keyboard backlight feature */
1355#define KBDBL_HANDLER 0x137
1356#define KBDBL_PRESENT 0xB00
1357#define SET_MODE 0xC00
1358#define SET_TIMEOUT 0xE00
1359
1360struct kbd_backlight {
1361 int mode;
1362 int timeout;
1363 struct device_attribute mode_attr;
1364 struct device_attribute timeout_attr;
1365};
1366
1367static struct kbd_backlight *kbdbl_handle;
1368
1369static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1370{
1371 int result;
1372
1373 if (value > 1)
1374 return -EINVAL;
1375
1376 if (sony_call_snc_handle(KBDBL_HANDLER,
1377 (value << 0x10) | SET_MODE, &result))
1378 return -EIO;
1379
1380 kbdbl_handle->mode = value;
1381
1382 return 0;
1383}
1384
1385static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
1386 struct device_attribute *attr,
1387 const char *buffer, size_t count)
1388{
1389 int ret = 0;
1390 unsigned long value;
1391
1392 if (count > 31)
1393 return -EINVAL;
1394
1395 if (strict_strtoul(buffer, 10, &value))
1396 return -EINVAL;
1397
1398 ret = __sony_nc_kbd_backlight_mode_set(value);
1399 if (ret < 0)
1400 return ret;
1401
1402 return count;
1403}
1404
1405static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
1406 struct device_attribute *attr, char *buffer)
1407{
1408 ssize_t count = 0;
1409 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode);
1410 return count;
1411}
1412
1413static int __sony_nc_kbd_backlight_timeout_set(u8 value)
1414{
1415 int result;
1416
1417 if (value > 3)
1418 return -EINVAL;
1419
1420 if (sony_call_snc_handle(KBDBL_HANDLER,
1421 (value << 0x10) | SET_TIMEOUT, &result))
1422 return -EIO;
1423
1424 kbdbl_handle->timeout = value;
1425
1426 return 0;
1427}
1428
1429static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
1430 struct device_attribute *attr,
1431 const char *buffer, size_t count)
1432{
1433 int ret = 0;
1434 unsigned long value;
1435
1436 if (count > 31)
1437 return -EINVAL;
1438
1439 if (strict_strtoul(buffer, 10, &value))
1440 return -EINVAL;
1441
1442 ret = __sony_nc_kbd_backlight_timeout_set(value);
1443 if (ret < 0)
1444 return ret;
1445
1446 return count;
1447}
1448
1449static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
1450 struct device_attribute *attr, char *buffer)
1451{
1452 ssize_t count = 0;
1453 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout);
1454 return count;
1455}
1456
1457static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
1458{
1459 int result;
1460
1461 if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result))
1462 return 0;
1463 if (!(result & 0x02))
1464 return 0;
1465
1466 kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
1467 if (!kbdbl_handle)
1468 return -ENOMEM;
1469
1470 sysfs_attr_init(&kbdbl_handle->mode_attr.attr);
1471 kbdbl_handle->mode_attr.attr.name = "kbd_backlight";
1472 kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
1473 kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show;
1474 kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store;
1475
1476 sysfs_attr_init(&kbdbl_handle->timeout_attr.attr);
1477 kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout";
1478 kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
1479 kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
1480 kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
1481
1482 if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr))
1483 goto outkzalloc;
1484
1485 if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr))
1486 goto outmode;
1487
1488 __sony_nc_kbd_backlight_mode_set(kbd_backlight);
1489 __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
1490
1491 return 0;
1492
1493outmode:
1494 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
1495outkzalloc:
1496 kfree(kbdbl_handle);
1497 kbdbl_handle = NULL;
1498 return -1;
1499}
1500
1501static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
1502{
1503 if (kbdbl_handle) {
1504 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
1505 device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
1506 kfree(kbdbl_handle);
1507 }
1508 return 0;
1509}
1510
1511static void sony_nc_backlight_setup(void)
1512{
1513 acpi_handle unused;
1514 int max_brightness = 0;
1515 const struct backlight_ops *ops = NULL;
1516 struct backlight_properties props;
1517
1518 if (sony_find_snc_handle(0x12f) != -1) {
1519 backlight_ng_handle = 0x12f;
1520 ops = &sony_backlight_ng_ops;
1521 max_brightness = 0xff;
1522
1523 } else if (sony_find_snc_handle(0x137) != -1) {
1524 backlight_ng_handle = 0x137;
1525 ops = &sony_backlight_ng_ops;
1526 max_brightness = 0xff;
1527
1528 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
1529 &unused))) {
1530 ops = &sony_backlight_ops;
1531 max_brightness = SONY_MAX_BRIGHTNESS - 1;
1532
1533 } else
1534 return;
1535
1536 memset(&props, 0, sizeof(struct backlight_properties));
1537 props.type = BACKLIGHT_PLATFORM;
1538 props.max_brightness = max_brightness;
1539 sony_backlight_device = backlight_device_register("sony", NULL,
1540 &backlight_ng_handle,
1541 ops, &props);
1542
1543 if (IS_ERR(sony_backlight_device)) {
1544 pr_warning(DRV_PFX "unable to register backlight device\n");
1545 sony_backlight_device = NULL;
1546 } else
1547 sony_backlight_device->props.brightness =
1548 ops->get_brightness(sony_backlight_device);
1549}
1550
1551static void sony_nc_backlight_cleanup(void)
1552{
1553 if (sony_backlight_device)
1554 backlight_device_unregister(sony_backlight_device);
1555}
1556
1248static int sony_nc_add(struct acpi_device *device) 1557static int sony_nc_add(struct acpi_device *device)
1249{ 1558{
1250 acpi_status status; 1559 acpi_status status;
@@ -1252,8 +1561,8 @@ static int sony_nc_add(struct acpi_device *device)
1252 acpi_handle handle; 1561 acpi_handle handle;
1253 struct sony_nc_value *item; 1562 struct sony_nc_value *item;
1254 1563
1255 printk(KERN_INFO DRV_PFX "%s v%s.\n", 1564 pr_info(DRV_PFX "%s v%s.\n", SONY_NC_DRIVER_NAME,
1256 SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); 1565 SONY_LAPTOP_DRIVER_VERSION);
1257 1566
1258 sony_nc_acpi_device = device; 1567 sony_nc_acpi_device = device;
1259 strcpy(acpi_device_class(device), "sony/hotkey"); 1568 strcpy(acpi_device_class(device), "sony/hotkey");
@@ -1269,13 +1578,18 @@ static int sony_nc_add(struct acpi_device *device)
1269 goto outwalk; 1578 goto outwalk;
1270 } 1579 }
1271 1580
1581 result = sony_pf_add();
1582 if (result)
1583 goto outpresent;
1584
1272 if (debug) { 1585 if (debug) {
1273 status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, 1586 status = acpi_walk_namespace(ACPI_TYPE_METHOD,
1274 1, sony_walk_callback, NULL, NULL, NULL); 1587 sony_nc_acpi_handle, 1, sony_walk_callback,
1588 NULL, NULL, NULL);
1275 if (ACPI_FAILURE(status)) { 1589 if (ACPI_FAILURE(status)) {
1276 printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); 1590 pr_warn(DRV_PFX "unable to walk acpi resources\n");
1277 result = -ENODEV; 1591 result = -ENODEV;
1278 goto outwalk; 1592 goto outpresent;
1279 } 1593 }
1280 } 1594 }
1281 1595
@@ -1288,6 +1602,12 @@ static int sony_nc_add(struct acpi_device *device)
1288 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", 1602 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
1289 &handle))) { 1603 &handle))) {
1290 dprintk("Doing SNC setup\n"); 1604 dprintk("Doing SNC setup\n");
1605 result = sony_nc_handles_setup(sony_pf_device);
1606 if (result)
1607 goto outpresent;
1608 result = sony_nc_kbd_backlight_setup(sony_pf_device);
1609 if (result)
1610 goto outsnc;
1291 sony_nc_function_setup(device); 1611 sony_nc_function_setup(device);
1292 sony_nc_rfkill_setup(device); 1612 sony_nc_rfkill_setup(device);
1293 } 1613 }
@@ -1295,40 +1615,17 @@ static int sony_nc_add(struct acpi_device *device)
1295 /* setup input devices and helper fifo */ 1615 /* setup input devices and helper fifo */
1296 result = sony_laptop_setup_input(device); 1616 result = sony_laptop_setup_input(device);
1297 if (result) { 1617 if (result) {
1298 printk(KERN_ERR DRV_PFX 1618 pr_err(DRV_PFX "Unable to create input devices.\n");
1299 "Unable to create input devices.\n"); 1619 goto outkbdbacklight;
1300 goto outwalk;
1301 } 1620 }
1302 1621
1303 if (acpi_video_backlight_support()) { 1622 if (acpi_video_backlight_support()) {
1304 printk(KERN_INFO DRV_PFX "brightness ignored, must be " 1623 pr_info(DRV_PFX "brightness ignored, must be "
1305 "controlled by ACPI video driver\n"); 1624 "controlled by ACPI video driver\n");
1306 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", 1625 } else {
1307 &handle))) { 1626 sony_nc_backlight_setup();
1308 struct backlight_properties props;
1309 memset(&props, 0, sizeof(struct backlight_properties));
1310 props.type = BACKLIGHT_PLATFORM;
1311 props.max_brightness = SONY_MAX_BRIGHTNESS - 1;
1312 sony_backlight_device = backlight_device_register("sony", NULL,
1313 NULL,
1314 &sony_backlight_ops,
1315 &props);
1316
1317 if (IS_ERR(sony_backlight_device)) {
1318 printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
1319 sony_backlight_device = NULL;
1320 } else {
1321 sony_backlight_device->props.brightness =
1322 sony_backlight_get_brightness
1323 (sony_backlight_device);
1324 }
1325
1326 } 1627 }
1327 1628
1328 result = sony_pf_add();
1329 if (result)
1330 goto outbacklight;
1331
1332 /* create sony_pf sysfs attributes related to the SNC device */ 1629 /* create sony_pf sysfs attributes related to the SNC device */
1333 for (item = sony_nc_values; item->name; ++item) { 1630 for (item = sony_nc_values; item->name; ++item) {
1334 1631
@@ -1374,14 +1671,19 @@ static int sony_nc_add(struct acpi_device *device)
1374 for (item = sony_nc_values; item->name; ++item) { 1671 for (item = sony_nc_values; item->name; ++item) {
1375 device_remove_file(&sony_pf_device->dev, &item->devattr); 1672 device_remove_file(&sony_pf_device->dev, &item->devattr);
1376 } 1673 }
1377 sony_pf_remove(); 1674 sony_nc_backlight_cleanup();
1378
1379 outbacklight:
1380 if (sony_backlight_device)
1381 backlight_device_unregister(sony_backlight_device);
1382 1675
1383 sony_laptop_remove_input(); 1676 sony_laptop_remove_input();
1384 1677
1678 outkbdbacklight:
1679 sony_nc_kbd_backlight_cleanup(sony_pf_device);
1680
1681 outsnc:
1682 sony_nc_handles_cleanup(sony_pf_device);
1683
1684 outpresent:
1685 sony_pf_remove();
1686
1385 outwalk: 1687 outwalk:
1386 sony_nc_rfkill_cleanup(); 1688 sony_nc_rfkill_cleanup();
1387 return result; 1689 return result;
@@ -1391,8 +1693,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
1391{ 1693{
1392 struct sony_nc_value *item; 1694 struct sony_nc_value *item;
1393 1695
1394 if (sony_backlight_device) 1696 sony_nc_backlight_cleanup();
1395 backlight_device_unregister(sony_backlight_device);
1396 1697
1397 sony_nc_acpi_device = NULL; 1698 sony_nc_acpi_device = NULL;
1398 1699
@@ -1400,6 +1701,8 @@ static int sony_nc_remove(struct acpi_device *device, int type)
1400 device_remove_file(&sony_pf_device->dev, &item->devattr); 1701 device_remove_file(&sony_pf_device->dev, &item->devattr);
1401 } 1702 }
1402 1703
1704 sony_nc_kbd_backlight_cleanup(sony_pf_device);
1705 sony_nc_handles_cleanup(sony_pf_device);
1403 sony_pf_remove(); 1706 sony_pf_remove();
1404 sony_laptop_remove_input(); 1707 sony_laptop_remove_input();
1405 sony_nc_rfkill_cleanup(); 1708 sony_nc_rfkill_cleanup();
@@ -1438,7 +1741,6 @@ static struct acpi_driver sony_nc_driver = {
1438#define SONYPI_DEVICE_TYPE1 0x00000001 1741#define SONYPI_DEVICE_TYPE1 0x00000001
1439#define SONYPI_DEVICE_TYPE2 0x00000002 1742#define SONYPI_DEVICE_TYPE2 0x00000002
1440#define SONYPI_DEVICE_TYPE3 0x00000004 1743#define SONYPI_DEVICE_TYPE3 0x00000004
1441#define SONYPI_DEVICE_TYPE4 0x00000008
1442 1744
1443#define SONYPI_TYPE1_OFFSET 0x04 1745#define SONYPI_TYPE1_OFFSET 0x04
1444#define SONYPI_TYPE2_OFFSET 0x12 1746#define SONYPI_TYPE2_OFFSET 0x12
@@ -1584,8 +1886,8 @@ static struct sonypi_event sonypi_blueev[] = {
1584 1886
1585/* The set of possible wireless events */ 1887/* The set of possible wireless events */
1586static struct sonypi_event sonypi_wlessev[] = { 1888static struct sonypi_event sonypi_wlessev[] = {
1587 { 0x59, SONYPI_EVENT_WIRELESS_ON }, 1889 { 0x59, SONYPI_EVENT_IGNORE },
1588 { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, 1890 { 0x5a, SONYPI_EVENT_IGNORE },
1589 { 0, 0 } 1891 { 0, 0 }
1590}; 1892};
1591 1893
@@ -1842,7 +2144,7 @@ out:
1842 if (pcidev) 2144 if (pcidev)
1843 pci_dev_put(pcidev); 2145 pci_dev_put(pcidev);
1844 2146
1845 printk(KERN_INFO DRV_PFX "detected Type%d model\n", 2147 pr_info(DRV_PFX "detected Type%d model\n",
1846 dev->model == SONYPI_DEVICE_TYPE1 ? 1 : 2148 dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
1847 dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3); 2149 dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
1848} 2150}
@@ -1890,7 +2192,7 @@ static int __sony_pic_camera_ready(void)
1890static int __sony_pic_camera_off(void) 2192static int __sony_pic_camera_off(void)
1891{ 2193{
1892 if (!camera) { 2194 if (!camera) {
1893 printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); 2195 pr_warn(DRV_PFX "camera control not enabled\n");
1894 return -ENODEV; 2196 return -ENODEV;
1895 } 2197 }
1896 2198
@@ -1910,7 +2212,7 @@ static int __sony_pic_camera_on(void)
1910 int i, j, x; 2212 int i, j, x;
1911 2213
1912 if (!camera) { 2214 if (!camera) {
1913 printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); 2215 pr_warn(DRV_PFX "camera control not enabled\n");
1914 return -ENODEV; 2216 return -ENODEV;
1915 } 2217 }
1916 2218
@@ -1933,7 +2235,7 @@ static int __sony_pic_camera_on(void)
1933 } 2235 }
1934 2236
1935 if (j == 0) { 2237 if (j == 0) {
1936 printk(KERN_WARNING DRV_PFX "failed to power on camera\n"); 2238 pr_warn(DRV_PFX "failed to power on camera\n");
1937 return -ENODEV; 2239 return -ENODEV;
1938 } 2240 }
1939 2241
@@ -1989,7 +2291,7 @@ int sony_pic_camera_command(int command, u8 value)
1989 ITERATIONS_SHORT); 2291 ITERATIONS_SHORT);
1990 break; 2292 break;
1991 default: 2293 default:
1992 printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n", 2294 pr_err(DRV_PFX "sony_pic_camera_command invalid: %d\n",
1993 command); 2295 command);
1994 break; 2296 break;
1995 } 2297 }
@@ -2396,7 +2698,7 @@ static int sonypi_compat_init(void)
2396 error = 2698 error =
2397 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); 2699 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
2398 if (error) { 2700 if (error) {
2399 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 2701 pr_err(DRV_PFX "kfifo_alloc failed\n");
2400 return error; 2702 return error;
2401 } 2703 }
2402 2704
@@ -2406,11 +2708,11 @@ static int sonypi_compat_init(void)
2406 sonypi_misc_device.minor = minor; 2708 sonypi_misc_device.minor = minor;
2407 error = misc_register(&sonypi_misc_device); 2709 error = misc_register(&sonypi_misc_device);
2408 if (error) { 2710 if (error) {
2409 printk(KERN_ERR DRV_PFX "misc_register failed\n"); 2711 pr_err(DRV_PFX "misc_register failed\n");
2410 goto err_free_kfifo; 2712 goto err_free_kfifo;
2411 } 2713 }
2412 if (minor == -1) 2714 if (minor == -1)
2413 printk(KERN_INFO DRV_PFX "device allocated minor is %d\n", 2715 pr_info(DRV_PFX "device allocated minor is %d\n",
2414 sonypi_misc_device.minor); 2716 sonypi_misc_device.minor);
2415 2717
2416 return 0; 2718 return 0;
@@ -2470,8 +2772,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
2470 } 2772 }
2471 for (i = 0; i < p->interrupt_count; i++) { 2773 for (i = 0; i < p->interrupt_count; i++) {
2472 if (!p->interrupts[i]) { 2774 if (!p->interrupts[i]) {
2473 printk(KERN_WARNING DRV_PFX 2775 pr_warn(DRV_PFX "Invalid IRQ %d\n",
2474 "Invalid IRQ %d\n",
2475 p->interrupts[i]); 2776 p->interrupts[i]);
2476 continue; 2777 continue;
2477 } 2778 }
@@ -2510,7 +2811,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
2510 ioport->io2.address_length); 2811 ioport->io2.address_length);
2511 } 2812 }
2512 else { 2813 else {
2513 printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); 2814 pr_err(DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
2514 return AE_ERROR; 2815 return AE_ERROR;
2515 } 2816 }
2516 return AE_OK; 2817 return AE_OK;
@@ -2538,7 +2839,7 @@ static int sony_pic_possible_resources(struct acpi_device *device)
2538 dprintk("Evaluating _STA\n"); 2839 dprintk("Evaluating _STA\n");
2539 result = acpi_bus_get_status(device); 2840 result = acpi_bus_get_status(device);
2540 if (result) { 2841 if (result) {
2541 printk(KERN_WARNING DRV_PFX "Unable to read status\n"); 2842 pr_warn(DRV_PFX "Unable to read status\n");
2542 goto end; 2843 goto end;
2543 } 2844 }
2544 2845
@@ -2554,8 +2855,7 @@ static int sony_pic_possible_resources(struct acpi_device *device)
2554 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, 2855 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
2555 sony_pic_read_possible_resource, &spic_dev); 2856 sony_pic_read_possible_resource, &spic_dev);
2556 if (ACPI_FAILURE(status)) { 2857 if (ACPI_FAILURE(status)) {
2557 printk(KERN_WARNING DRV_PFX 2858 pr_warn(DRV_PFX "Failure evaluating %s\n",
2558 "Failure evaluating %s\n",
2559 METHOD_NAME__PRS); 2859 METHOD_NAME__PRS);
2560 result = -ENODEV; 2860 result = -ENODEV;
2561 } 2861 }
@@ -2669,7 +2969,7 @@ static int sony_pic_enable(struct acpi_device *device,
2669 2969
2670 /* check for total failure */ 2970 /* check for total failure */
2671 if (ACPI_FAILURE(status)) { 2971 if (ACPI_FAILURE(status)) {
2672 printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); 2972 pr_err(DRV_PFX "Error evaluating _SRS\n");
2673 result = -ENODEV; 2973 result = -ENODEV;
2674 goto end; 2974 goto end;
2675 } 2975 }
@@ -2725,6 +3025,9 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
2725 if (ev == dev->event_types[i].events[j].data) { 3025 if (ev == dev->event_types[i].events[j].data) {
2726 device_event = 3026 device_event =
2727 dev->event_types[i].events[j].event; 3027 dev->event_types[i].events[j].event;
3028 /* some events may require ignoring */
3029 if (!device_event)
3030 return IRQ_HANDLED;
2728 goto found; 3031 goto found;
2729 } 3032 }
2730 } 3033 }
@@ -2744,7 +3047,6 @@ found:
2744 sony_laptop_report_input_event(device_event); 3047 sony_laptop_report_input_event(device_event);
2745 acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); 3048 acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
2746 sonypi_compat_report_event(device_event); 3049 sonypi_compat_report_event(device_event);
2747
2748 return IRQ_HANDLED; 3050 return IRQ_HANDLED;
2749} 3051}
2750 3052
@@ -2759,7 +3061,7 @@ static int sony_pic_remove(struct acpi_device *device, int type)
2759 struct sony_pic_irq *irq, *tmp_irq; 3061 struct sony_pic_irq *irq, *tmp_irq;
2760 3062
2761 if (sony_pic_disable(device)) { 3063 if (sony_pic_disable(device)) {
2762 printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); 3064 pr_err(DRV_PFX "Couldn't disable device.\n");
2763 return -ENXIO; 3065 return -ENXIO;
2764 } 3066 }
2765 3067
@@ -2799,8 +3101,8 @@ static int sony_pic_add(struct acpi_device *device)
2799 struct sony_pic_ioport *io, *tmp_io; 3101 struct sony_pic_ioport *io, *tmp_io;
2800 struct sony_pic_irq *irq, *tmp_irq; 3102 struct sony_pic_irq *irq, *tmp_irq;
2801 3103
2802 printk(KERN_INFO DRV_PFX "%s v%s.\n", 3104 pr_info(DRV_PFX "%s v%s.\n", SONY_PIC_DRIVER_NAME,
2803 SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); 3105 SONY_LAPTOP_DRIVER_VERSION);
2804 3106
2805 spic_dev.acpi_dev = device; 3107 spic_dev.acpi_dev = device;
2806 strcpy(acpi_device_class(device), "sony/hotkey"); 3108 strcpy(acpi_device_class(device), "sony/hotkey");
@@ -2810,16 +3112,14 @@ static int sony_pic_add(struct acpi_device *device)
2810 /* read _PRS resources */ 3112 /* read _PRS resources */
2811 result = sony_pic_possible_resources(device); 3113 result = sony_pic_possible_resources(device);
2812 if (result) { 3114 if (result) {
2813 printk(KERN_ERR DRV_PFX 3115 pr_err(DRV_PFX "Unable to read possible resources.\n");
2814 "Unable to read possible resources.\n");
2815 goto err_free_resources; 3116 goto err_free_resources;
2816 } 3117 }
2817 3118
2818 /* setup input devices and helper fifo */ 3119 /* setup input devices and helper fifo */
2819 result = sony_laptop_setup_input(device); 3120 result = sony_laptop_setup_input(device);
2820 if (result) { 3121 if (result) {
2821 printk(KERN_ERR DRV_PFX 3122 pr_err(DRV_PFX "Unable to create input devices.\n");
2822 "Unable to create input devices.\n");
2823 goto err_free_resources; 3123 goto err_free_resources;
2824 } 3124 }
2825 3125
@@ -2829,7 +3129,7 @@ static int sony_pic_add(struct acpi_device *device)
2829 /* request io port */ 3129 /* request io port */
2830 list_for_each_entry_reverse(io, &spic_dev.ioports, list) { 3130 list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
2831 if (request_region(io->io1.minimum, io->io1.address_length, 3131 if (request_region(io->io1.minimum, io->io1.address_length,
2832 "Sony Programable I/O Device")) { 3132 "Sony Programmable I/O Device")) {
2833 dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", 3133 dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
2834 io->io1.minimum, io->io1.maximum, 3134 io->io1.minimum, io->io1.maximum,
2835 io->io1.address_length); 3135 io->io1.address_length);
@@ -2837,7 +3137,7 @@ static int sony_pic_add(struct acpi_device *device)
2837 if (io->io2.minimum) { 3137 if (io->io2.minimum) {
2838 if (request_region(io->io2.minimum, 3138 if (request_region(io->io2.minimum,
2839 io->io2.address_length, 3139 io->io2.address_length,
2840 "Sony Programable I/O Device")) { 3140 "Sony Programmable I/O Device")) {
2841 dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", 3141 dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
2842 io->io2.minimum, io->io2.maximum, 3142 io->io2.minimum, io->io2.maximum,
2843 io->io2.address_length); 3143 io->io2.address_length);
@@ -2860,7 +3160,7 @@ static int sony_pic_add(struct acpi_device *device)
2860 } 3160 }
2861 } 3161 }
2862 if (!spic_dev.cur_ioport) { 3162 if (!spic_dev.cur_ioport) {
2863 printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); 3163 pr_err(DRV_PFX "Failed to request_region.\n");
2864 result = -ENODEV; 3164 result = -ENODEV;
2865 goto err_remove_compat; 3165 goto err_remove_compat;
2866 } 3166 }
@@ -2880,7 +3180,7 @@ static int sony_pic_add(struct acpi_device *device)
2880 } 3180 }
2881 } 3181 }
2882 if (!spic_dev.cur_irq) { 3182 if (!spic_dev.cur_irq) {
2883 printk(KERN_ERR DRV_PFX "Failed to request_irq.\n"); 3183 pr_err(DRV_PFX "Failed to request_irq.\n");
2884 result = -ENODEV; 3184 result = -ENODEV;
2885 goto err_release_region; 3185 goto err_release_region;
2886 } 3186 }
@@ -2888,7 +3188,7 @@ static int sony_pic_add(struct acpi_device *device)
2888 /* set resource status _SRS */ 3188 /* set resource status _SRS */
2889 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); 3189 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
2890 if (result) { 3190 if (result) {
2891 printk(KERN_ERR DRV_PFX "Couldn't enable device.\n"); 3191 pr_err(DRV_PFX "Couldn't enable device.\n");
2892 goto err_free_irq; 3192 goto err_free_irq;
2893 } 3193 }
2894 3194
@@ -2997,8 +3297,7 @@ static int __init sony_laptop_init(void)
2997 if (!no_spic && dmi_check_system(sonypi_dmi_table)) { 3297 if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
2998 result = acpi_bus_register_driver(&sony_pic_driver); 3298 result = acpi_bus_register_driver(&sony_pic_driver);
2999 if (result) { 3299 if (result) {
3000 printk(KERN_ERR DRV_PFX 3300 pr_err(DRV_PFX "Unable to register SPIC driver.");
3001 "Unable to register SPIC driver.");
3002 goto out; 3301 goto out;
3003 } 3302 }
3004 spic_drv_registered = 1; 3303 spic_drv_registered = 1;
@@ -3006,7 +3305,7 @@ static int __init sony_laptop_init(void)
3006 3305
3007 result = acpi_bus_register_driver(&sony_nc_driver); 3306 result = acpi_bus_register_driver(&sony_nc_driver);
3008 if (result) { 3307 if (result) {
3009 printk(KERN_ERR DRV_PFX "Unable to register SNC driver."); 3308 pr_err(DRV_PFX "Unable to register SNC driver.");
3010 goto out_unregister_pic; 3309 goto out_unregister_pic;
3011 } 3310 }
3012 3311
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 947bdcaa0ce9..a08561f5349e 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -2407,7 +2407,7 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
2407 * This code is supposed to duplicate the IBM firmware behaviour: 2407 * This code is supposed to duplicate the IBM firmware behaviour:
2408 * - Pressing MUTE issues mute hotkey message, even when already mute 2408 * - Pressing MUTE issues mute hotkey message, even when already mute
2409 * - Pressing Volume up/down issues volume up/down hotkey messages, 2409 * - Pressing Volume up/down issues volume up/down hotkey messages,
2410 * even when already at maximum or minumum volume 2410 * even when already at maximum or minimum volume
2411 * - The act of unmuting issues volume up/down notification, 2411 * - The act of unmuting issues volume up/down notification,
2412 * depending which key was used to unmute 2412 * depending which key was used to unmute
2413 * 2413 *
@@ -2990,7 +2990,7 @@ static void tpacpi_send_radiosw_update(void)
2990 * rfkill input events, or we will race the rfkill core input 2990 * rfkill input events, or we will race the rfkill core input
2991 * handler. 2991 * handler.
2992 * 2992 *
2993 * tpacpi_inputdev_send_mutex works as a syncronization point 2993 * tpacpi_inputdev_send_mutex works as a synchronization point
2994 * for the above. 2994 * for the above.
2995 * 2995 *
2996 * We optimize to avoid numerous calls to hotkey_get_wlsw. 2996 * We optimize to avoid numerous calls to hotkey_get_wlsw.
diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c
new file mode 100644
index 000000000000..c1372ed9d2e9
--- /dev/null
+++ b/drivers/platform/x86/xo15-ebook.c
@@ -0,0 +1,180 @@
1/*
2 * OLPC XO-1.5 ebook switch driver
3 * (based on generic ACPI button driver)
4 *
5 * Copyright (C) 2009 Paul Fox <pgf@laptop.org>
6 * Copyright (C) 2010 One Laptop per Child
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/types.h>
18#include <linux/input.h>
19#include <acpi/acpi_bus.h>
20#include <acpi/acpi_drivers.h>
21
22#define MODULE_NAME "xo15-ebook"
23#define PREFIX MODULE_NAME ": "
24
25#define XO15_EBOOK_CLASS MODULE_NAME
26#define XO15_EBOOK_TYPE_UNKNOWN 0x00
27#define XO15_EBOOK_NOTIFY_STATUS 0x80
28
29#define XO15_EBOOK_SUBCLASS "ebook"
30#define XO15_EBOOK_HID "XO15EBK"
31#define XO15_EBOOK_DEVICE_NAME "EBook Switch"
32
33ACPI_MODULE_NAME(MODULE_NAME);
34
35MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver");
36MODULE_LICENSE("GPL");
37
38static const struct acpi_device_id ebook_device_ids[] = {
39 { XO15_EBOOK_HID, 0 },
40 { "", 0 },
41};
42MODULE_DEVICE_TABLE(acpi, ebook_device_ids);
43
44struct ebook_switch {
45 struct input_dev *input;
46 char phys[32]; /* for input device */
47};
48
49static int ebook_send_state(struct acpi_device *device)
50{
51 struct ebook_switch *button = acpi_driver_data(device);
52 unsigned long long state;
53 acpi_status status;
54
55 status = acpi_evaluate_integer(device->handle, "EBK", NULL, &state);
56 if (ACPI_FAILURE(status))
57 return -EIO;
58
59 /* input layer checks if event is redundant */
60 input_report_switch(button->input, SW_TABLET_MODE, !state);
61 input_sync(button->input);
62 return 0;
63}
64
65static void ebook_switch_notify(struct acpi_device *device, u32 event)
66{
67 switch (event) {
68 case ACPI_FIXED_HARDWARE_EVENT:
69 case XO15_EBOOK_NOTIFY_STATUS:
70 ebook_send_state(device);
71 break;
72 default:
73 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
74 "Unsupported event [0x%x]\n", event));
75 break;
76 }
77}
78
79static int ebook_switch_resume(struct acpi_device *device)
80{
81 return ebook_send_state(device);
82}
83
84static int ebook_switch_add(struct acpi_device *device)
85{
86 struct ebook_switch *button;
87 struct input_dev *input;
88 const char *hid = acpi_device_hid(device);
89 char *name, *class;
90 int error;
91
92 button = kzalloc(sizeof(struct ebook_switch), GFP_KERNEL);
93 if (!button)
94 return -ENOMEM;
95
96 device->driver_data = button;
97
98 button->input = input = input_allocate_device();
99 if (!input) {
100 error = -ENOMEM;
101 goto err_free_button;
102 }
103
104 name = acpi_device_name(device);
105 class = acpi_device_class(device);
106
107 if (strcmp(hid, XO15_EBOOK_HID)) {
108 printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid);
109 error = -ENODEV;
110 goto err_free_input;
111 }
112
113 strcpy(name, XO15_EBOOK_DEVICE_NAME);
114 sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS);
115
116 snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
117
118 input->name = name;
119 input->phys = button->phys;
120 input->id.bustype = BUS_HOST;
121 input->dev.parent = &device->dev;
122
123 input->evbit[0] = BIT_MASK(EV_SW);
124 set_bit(SW_TABLET_MODE, input->swbit);
125
126 error = input_register_device(input);
127 if (error)
128 goto err_free_input;
129
130 ebook_send_state(device);
131
132 if (device->wakeup.flags.valid) {
133 /* Button's GPE is run-wake GPE */
134 acpi_enable_gpe(device->wakeup.gpe_device,
135 device->wakeup.gpe_number);
136 device_set_wakeup_enable(&device->dev, true);
137 }
138
139 return 0;
140
141 err_free_input:
142 input_free_device(input);
143 err_free_button:
144 kfree(button);
145 return error;
146}
147
148static int ebook_switch_remove(struct acpi_device *device, int type)
149{
150 struct ebook_switch *button = acpi_driver_data(device);
151
152 input_unregister_device(button->input);
153 kfree(button);
154 return 0;
155}
156
157static struct acpi_driver xo15_ebook_driver = {
158 .name = MODULE_NAME,
159 .class = XO15_EBOOK_CLASS,
160 .ids = ebook_device_ids,
161 .ops = {
162 .add = ebook_switch_add,
163 .resume = ebook_switch_resume,
164 .remove = ebook_switch_remove,
165 .notify = ebook_switch_notify,
166 },
167};
168
169static int __init xo15_ebook_init(void)
170{
171 return acpi_bus_register_driver(&xo15_ebook_driver);
172}
173
174static void __exit xo15_ebook_exit(void)
175{
176 acpi_bus_unregister_driver(&xo15_ebook_driver);
177}
178
179module_init(xo15_ebook_init);
180module_exit(xo15_ebook_exit);
diff --git a/include/linux/input.h b/include/linux/input.h
index 056ae8a5bd9b..f3a7794a18c4 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -664,6 +664,13 @@ struct input_keymap_entry {
664#define KEY_TOUCHPAD_ON 0x213 664#define KEY_TOUCHPAD_ON 0x213
665#define KEY_TOUCHPAD_OFF 0x214 665#define KEY_TOUCHPAD_OFF 0x214
666 666
667#define KEY_CAMERA_ZOOMIN 0x215
668#define KEY_CAMERA_ZOOMOUT 0x216
669#define KEY_CAMERA_UP 0x217
670#define KEY_CAMERA_DOWN 0x218
671#define KEY_CAMERA_LEFT 0x219
672#define KEY_CAMERA_RIGHT 0x21a
673
667#define BTN_TRIGGER_HAPPY 0x2c0 674#define BTN_TRIGGER_HAPPY 0x2c0
668#define BTN_TRIGGER_HAPPY1 0x2c0 675#define BTN_TRIGGER_HAPPY1 0x2c0
669#define BTN_TRIGGER_HAPPY2 0x2c1 676#define BTN_TRIGGER_HAPPY2 0x2c1
diff --git a/include/linux/sonypi.h b/include/linux/sonypi.h
index 0e6dc3891942..c0f87da78f8a 100644
--- a/include/linux/sonypi.h
+++ b/include/linux/sonypi.h
@@ -40,6 +40,7 @@
40 40
41/* events the user application reading /dev/sonypi can use */ 41/* events the user application reading /dev/sonypi can use */
42 42
43#define SONYPI_EVENT_IGNORE 0
43#define SONYPI_EVENT_JOGDIAL_DOWN 1 44#define SONYPI_EVENT_JOGDIAL_DOWN 1
44#define SONYPI_EVENT_JOGDIAL_UP 2 45#define SONYPI_EVENT_JOGDIAL_UP 2
45#define SONYPI_EVENT_JOGDIAL_DOWN_PRESSED 3 46#define SONYPI_EVENT_JOGDIAL_DOWN_PRESSED 3