aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/stable/sysfs-class-backlight36
-rw-r--r--Documentation/ABI/testing/sysfs-class-lcd23
-rw-r--r--Documentation/ABI/testing/sysfs-class-led28
-rw-r--r--Documentation/ABI/testing/sysfs-platform-asus-laptop52
-rw-r--r--Documentation/ABI/testing/sysfs-platform-eeepc-laptop50
-rw-r--r--Documentation/laptops/asus-laptop.txt258
-rw-r--r--Documentation/leds-class.txt9
-rw-r--r--drivers/platform/x86/asus-laptop.c227
-rw-r--r--drivers/platform/x86/eeepc-laptop.c340
9 files changed, 830 insertions, 193 deletions
diff --git a/Documentation/ABI/stable/sysfs-class-backlight b/Documentation/ABI/stable/sysfs-class-backlight
new file mode 100644
index 000000000000..4d637e1c4ff7
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-class-backlight
@@ -0,0 +1,36 @@
1What: /sys/class/backlight/<backlight>/bl_power
2Date: April 2005
3KernelVersion: 2.6.12
4Contact: Richard Purdie <rpurdie@rpsys.net>
5Description:
6 Control BACKLIGHT power, values are FB_BLANK_* from fb.h
7 - FB_BLANK_UNBLANK (0) : power on.
8 - FB_BLANK_POWERDOWN (4) : power off
9Users: HAL
10
11What: /sys/class/backlight/<backlight>/brightness
12Date: April 2005
13KernelVersion: 2.6.12
14Contact: Richard Purdie <rpurdie@rpsys.net>
15Description:
16 Control the brightness for this <backlight>. Values
17 are between 0 and max_brightness. This file will also
18 show the brightness level stored in the driver, which
19 may not be the actual brightness (see actual_brightness).
20Users: HAL
21
22What: /sys/class/backlight/<backlight>/actual_brightness
23Date: March 2006
24KernelVersion: 2.6.17
25Contact: Richard Purdie <rpurdie@rpsys.net>
26Description:
27 Show the actual brightness by querying the hardware.
28Users: HAL
29
30What: /sys/class/backlight/<backlight>/max_brightness
31Date: April 2005
32KernelVersion: 2.6.12
33Contact: Richard Purdie <rpurdie@rpsys.net>
34Description:
35 Maximum brightness for <backlight>.
36Users: HAL
diff --git a/Documentation/ABI/testing/sysfs-class-lcd b/Documentation/ABI/testing/sysfs-class-lcd
new file mode 100644
index 000000000000..35906bf7aa70
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-lcd
@@ -0,0 +1,23 @@
1What: /sys/class/lcd/<lcd>/lcd_power
2Date: April 2005
3KernelVersion: 2.6.12
4Contact: Richard Purdie <rpurdie@rpsys.net>
5Description:
6 Control LCD power, values are FB_BLANK_* from fb.h
7 - FB_BLANK_UNBLANK (0) : power on.
8 - FB_BLANK_POWERDOWN (4) : power off
9
10What: /sys/class/lcd/<lcd>/contrast
11Date: April 2005
12KernelVersion: 2.6.12
13Contact: Richard Purdie <rpurdie@rpsys.net>
14Description:
15 Current contrast of this LCD device. Value is between 0 and
16 /sys/class/lcd/<lcd>/max_contrast.
17
18What: /sys/class/lcd/<lcd>/max_contrast
19Date: April 2005
20KernelVersion: 2.6.12
21Contact: Richard Purdie <rpurdie@rpsys.net>
22Description:
23 Maximum contrast for this LCD device.
diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/testing/sysfs-class-led
new file mode 100644
index 000000000000..9e4541d71cb6
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-led
@@ -0,0 +1,28 @@
1What: /sys/class/leds/<led>/brightness
2Date: March 2006
3KernelVersion: 2.6.17
4Contact: Richard Purdie <rpurdie@rpsys.net>
5Description:
6 Set the brightness of the LED. Most LEDs don't
7 have hardware brightness support so will just be turned on for
8 non-zero brightness settings. The value is between 0 and
9 /sys/class/leds/<led>/max_brightness.
10
11What: /sys/class/leds/<led>/max_brightness
12Date: March 2006
13KernelVersion: 2.6.17
14Contact: Richard Purdie <rpurdie@rpsys.net>
15Description:
16 Maximum brightness level for this led, default is 255 (LED_FULL).
17
18What: /sys/class/leds/<led>/trigger
19Date: March 2006
20KernelVersion: 2.6.17
21Contact: Richard Purdie <rpurdie@rpsys.net>
22Description:
23 Set the trigger for this LED. A trigger is a kernel based source
24 of led events.
25 You can change triggers in a similar manner to the way an IO
26 scheduler is chosen. Trigger specific parameters can appear in
27 /sys/class/leds/<led> once a given trigger is selected.
28
diff --git a/Documentation/ABI/testing/sysfs-platform-asus-laptop b/Documentation/ABI/testing/sysfs-platform-asus-laptop
new file mode 100644
index 000000000000..a1cb660c50cf
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-asus-laptop
@@ -0,0 +1,52 @@
1What: /sys/devices/platform/asus-laptop/display
2Date: January 2007
3KernelVersion: 2.6.20
4Contact: "Corentin Chary" <corentincj@iksaif.net>
5Description:
6 This file allows display switching. The value
7 is composed by 4 bits and defined as follow:
8 4321
9 |||`- LCD
10 ||`-- CRT
11 |`--- TV
12 `---- DVI
13 Ex: - 0 (0000b) means no display
14 - 3 (0011b) CRT+LCD.
15
16What: /sys/devices/platform/asus-laptop/gps
17Date: January 2007
18KernelVersion: 2.6.20
19Contact: "Corentin Chary" <corentincj@iksaif.net>
20Description:
21 Control the gps device. 1 means on, 0 means off.
22Users: Lapsus
23
24What: /sys/devices/platform/asus-laptop/ledd
25Date: January 2007
26KernelVersion: 2.6.20
27Contact: "Corentin Chary" <corentincj@iksaif.net>
28Description:
29 Some models like the W1N have a LED display that can be
30 used to display several informations.
31 To control the LED display, use the following :
32 echo 0x0T000DDD > /sys/devices/platform/asus-laptop/
33 where T control the 3 letters display, and DDD the 3 digits display.
34 The DDD table can be found in Documentation/laptops/asus-laptop.txt
35
36What: /sys/devices/platform/asus-laptop/bluetooth
37Date: January 2007
38KernelVersion: 2.6.20
39Contact: "Corentin Chary" <corentincj@iksaif.net>
40Description:
41 Control the bluetooth device. 1 means on, 0 means off.
42 This may control the led, the device or both.
43Users: Lapsus
44
45What: /sys/devices/platform/asus-laptop/wlan
46Date: January 2007
47KernelVersion: 2.6.20
48Contact: "Corentin Chary" <corentincj@iksaif.net>
49Description:
50 Control the bluetooth device. 1 means on, 0 means off.
51 This may control the led, the device or both.
52Users: Lapsus
diff --git a/Documentation/ABI/testing/sysfs-platform-eeepc-laptop b/Documentation/ABI/testing/sysfs-platform-eeepc-laptop
new file mode 100644
index 000000000000..7445dfb321b5
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-eeepc-laptop
@@ -0,0 +1,50 @@
1What: /sys/devices/platform/eeepc-laptop/disp
2Date: May 2008
3KernelVersion: 2.6.26
4Contact: "Corentin Chary" <corentincj@iksaif.net>
5Description:
6 This file allows display switching.
7 - 1 = LCD
8 - 2 = CRT
9 - 3 = LCD+CRT
10 If you run X11, you should use xrandr instead.
11
12What: /sys/devices/platform/eeepc-laptop/camera
13Date: May 2008
14KernelVersion: 2.6.26
15Contact: "Corentin Chary" <corentincj@iksaif.net>
16Description:
17 Control the camera. 1 means on, 0 means off.
18
19What: /sys/devices/platform/eeepc-laptop/cardr
20Date: May 2008
21KernelVersion: 2.6.26
22Contact: "Corentin Chary" <corentincj@iksaif.net>
23Description:
24 Control the card reader. 1 means on, 0 means off.
25
26What: /sys/devices/platform/eeepc-laptop/cpufv
27Date: Jun 2009
28KernelVersion: 2.6.31
29Contact: "Corentin Chary" <corentincj@iksaif.net>
30Description:
31 Change CPU clock configuration.
32 On the Eee PC 1000H there are three available clock configuration:
33 * 0 -> Super Performance Mode
34 * 1 -> High Performance Mode
35 * 2 -> Power Saving Mode
36 On Eee PC 701 there is only 2 available clock configurations.
37 Available configuration are listed in available_cpufv file.
38 Reading this file will show the raw hexadecimal value which
39 is defined as follow:
40 | 8 bit | 8 bit |
41 | `---- Current mode
42 `------------ Availables modes
43 For example, 0x301 means: mode 1 selected, 3 available modes.
44
45What: /sys/devices/platform/eeepc-laptop/available_cpufv
46Date: Jun 2009
47KernelVersion: 2.6.31
48Contact: "Corentin Chary" <corentincj@iksaif.net>
49Description:
50 List available cpufv modes.
diff --git a/Documentation/laptops/asus-laptop.txt b/Documentation/laptops/asus-laptop.txt
new file mode 100644
index 000000000000..c1c5be84e4b1
--- /dev/null
+++ b/Documentation/laptops/asus-laptop.txt
@@ -0,0 +1,258 @@
1Asus Laptop Extras
2
3Version 0.1
4August 6, 2009
5
6Corentin Chary <corentincj@iksaif.net>
7http://acpi4asus.sf.net/
8
9 This driver provides support for extra features of ACPI-compatible ASUS laptops.
10 It may also support some MEDION, JVC or VICTOR laptops (such as MEDION 9675 or
11 VICTOR XP7210 for example). It makes all the extra buttons generate standard
12 ACPI events that go through /proc/acpi/events and input events (like keyboards).
13 On some models adds support for changing the display brightness and output,
14 switching the LCD backlight on and off, and most importantly, allows you to
15 blink those fancy LEDs intended for reporting mail and wireless status.
16
17This driver supercedes the old asus_acpi driver.
18
19Requirements
20------------
21
22 Kernel 2.6.X sources, configured for your computer, with ACPI support.
23 You also need CONFIG_INPUT and CONFIG_ACPI.
24
25Status
26------
27
28 The features currently supported are the following (see below for
29 detailed description):
30
31 - Fn key combinations
32 - Bluetooth enable and disable
33 - Wlan enable and disable
34 - GPS enable and disable
35 - Video output switching
36 - Ambient Light Sensor on and off
37 - LED control
38 - LED Display control
39 - LCD brightness control
40 - LCD on and off
41
42 A compatibility table by model and feature is maintained on the web
43 site, http://acpi4asus.sf.net/.
44
45Usage
46-----
47
48 Try "modprobe asus_acpi". Check your dmesg (simply type dmesg). You should
49 see some lines like this :
50
51 Asus Laptop Extras version 0.42
52 L2D model detected.
53
54 If it is not the output you have on your laptop, send it (and the laptop's
55 DSDT) to me.
56
57 That's all, now, all the events generated by the hotkeys of your laptop
58 should be reported in your /proc/acpi/event entry. You can check with
59 "acpi_listen".
60
61 Hotkeys are also reported as input keys (like keyboards) you can check
62 which key are supported using "xev" under X11.
63
64 You can get informations on the version of your DSDT table by reading the
65 /sys/devices/platform/asus-laptop/infos entry. If you have a question or a
66 bug report to do, please include the output of this entry.
67
68LEDs
69----
70
71 You can modify LEDs be echoing values to /sys/class/leds/asus::*/brightness :
72 echo 1 > /sys/class/leds/asus::mail/brightness
73 will switch the mail LED on.
74 You can also know if they are on/off by reading their content and use
75 kernel triggers like ide-disk or heartbeat.
76
77Backlight
78---------
79
80 You can control lcd backlight power and brightness with
81 /sys/class/backlight/asus-laptop/. Brightness Values are between 0 and 15.
82
83Wireless devices
84---------------
85
86 You can turn the internal Bluetooth adapter on/off with the bluetooth entry
87 (only on models with Bluetooth). This usually controls the associated LED.
88 Same for Wlan adapter.
89
90Display switching
91-----------------
92
93 Note: the display switching code is currently considered EXPERIMENTAL.
94
95 Switching works for the following models:
96 L3800C
97 A2500H
98 L5800C
99 M5200N
100 W1000N (albeit with some glitches)
101 M6700R
102 A6JC
103 F3J
104
105 Switching doesn't work for the following:
106 M3700N
107 L2X00D (locks the laptop under certain conditions)
108
109 To switch the displays, echo values from 0 to 15 to
110 /sys/devices/platform/asus-laptop/display. The significance of those values
111 is as follows:
112
113 +-------+-----+-----+-----+-----+-----+
114 | Bin | Val | DVI | TV | CRT | LCD |
115 +-------+-----+-----+-----+-----+-----+
116 + 0000 + 0 + + + + +
117 +-------+-----+-----+-----+-----+-----+
118 + 0001 + 1 + + + + X +
119 +-------+-----+-----+-----+-----+-----+
120 + 0010 + 2 + + + X + +
121 +-------+-----+-----+-----+-----+-----+
122 + 0011 + 3 + + + X + X +
123 +-------+-----+-----+-----+-----+-----+
124 + 0100 + 4 + + X + + +
125 +-------+-----+-----+-----+-----+-----+
126 + 0101 + 5 + + X + + X +
127 +-------+-----+-----+-----+-----+-----+
128 + 0110 + 6 + + X + X + +
129 +-------+-----+-----+-----+-----+-----+
130 + 0111 + 7 + + X + X + X +
131 +-------+-----+-----+-----+-----+-----+
132 + 1000 + 8 + X + + + +
133 +-------+-----+-----+-----+-----+-----+
134 + 1001 + 9 + X + + + X +
135 +-------+-----+-----+-----+-----+-----+
136 + 1010 + 10 + X + + X + +
137 +-------+-----+-----+-----+-----+-----+
138 + 1011 + 11 + X + + X + X +
139 +-------+-----+-----+-----+-----+-----+
140 + 1100 + 12 + X + X + + +
141 +-------+-----+-----+-----+-----+-----+
142 + 1101 + 13 + X + X + + X +
143 +-------+-----+-----+-----+-----+-----+
144 + 1110 + 14 + X + X + X + +
145 +-------+-----+-----+-----+-----+-----+
146 + 1111 + 15 + X + X + X + X +
147 +-------+-----+-----+-----+-----+-----+
148
149 In most cases, the appropriate displays must be plugged in for the above
150 combinations to work. TV-Out may need to be initialized at boot time.
151
152 Debugging:
153 1) Check whether the Fn+F8 key:
154 a) does not lock the laptop (try disabling CONFIG_X86_UP_APIC or boot with
155 noapic / nolapic if it does)
156 b) generates events (0x6n, where n is the value corresponding to the
157 configuration above)
158 c) actually works
159 Record the disp value at every configuration.
160 2) Echo values from 0 to 15 to /sys/devices/platform/asus-laptop/display.
161 Record its value, note any change. If nothing changes, try a broader range,
162 up to 65535.
163 3) Send ANY output (both positive and negative reports are needed, unless your
164 machine is already listed above) to the acpi4asus-user mailing list.
165
166 Note: on some machines (e.g. L3C), after the module has been loaded, only 0x6n
167 events are generated and no actual switching occurs. In such a case, a line
168 like:
169
170 echo $((10#$arg-60)) > /sys/devices/platform/asus-laptop/display
171
172 will usually do the trick ($arg is the 0000006n-like event passed to acpid).
173
174 Note: there is currently no reliable way to read display status on xxN
175 (Centrino) models.
176
177LED display
178-----------
179
180 Some models like the W1N have a LED display that can be used to display
181 several informations.
182
183 LED display works for the following models:
184 W1000N
185 W1J
186
187 To control the LED display, use the following :
188
189 echo 0x0T000DDD > /sys/devices/platform/asus-laptop/
190
191 where T control the 3 letters display, and DDD the 3 digits display,
192 according to the tables below.
193
194 DDD (digits)
195 000 to 999 = display digits
196 AAA = ---
197 BBB to FFF = turn-off
198
199 T (type)
200 0 = off
201 1 = dvd
202 2 = vcd
203 3 = mp3
204 4 = cd
205 5 = tv
206 6 = cpu
207 7 = vol
208
209 For example "echo 0x01000001 >/sys/devices/platform/asus-laptop/ledd"
210 would display "DVD001".
211
212Driver options:
213---------------
214
215 Options can be passed to the asus-laptop driver using the standard
216 module argument syntax (<param>=<value> when passing the option to the
217 module or asus-laptop.<param>=<value> on the kernel boot line when
218 asus-laptop is statically linked into the kernel).
219
220 wapf: WAPF defines the behavior of the Fn+Fx wlan key
221 The significance of values is yet to be found, but
222 most of the time:
223 - 0x0 should do nothing
224 - 0x1 should allow to control the device with Fn+Fx key.
225 - 0x4 should send an ACPI event (0x88) while pressing the Fn+Fx key
226 - 0x5 like 0x1 or 0x4
227
228 The default value is 0x1.
229
230Unsupported models
231------------------
232
233 These models will never be supported by this module, as they use a completely
234 different mechanism to handle LEDs and extra stuff (meaning we have no clue
235 how it works):
236
237 - ASUS A1300 (A1B), A1370D
238 - ASUS L7300G
239 - ASUS L8400
240
241Patches, Errors, Questions:
242--------------------------
243
244 I appreciate any success or failure
245 reports, especially if they add to or correct the compatibility table.
246 Please include the following information in your report:
247
248 - Asus model name
249 - a copy of your ACPI tables, using the "acpidump" utility
250 - a copy of /sys/devices/platform/asus-laptop/infos
251 - which driver features work and which don't
252 - the observed behavior of non-working features
253
254 Any other comments or patches are also more than welcome.
255
256 acpi4asus-user@lists.sourceforge.net
257 http://sourceforge.net/projects/acpi4asus
258
diff --git a/Documentation/leds-class.txt b/Documentation/leds-class.txt
index 6399557cdab3..8fd5ca2ae32d 100644
--- a/Documentation/leds-class.txt
+++ b/Documentation/leds-class.txt
@@ -1,3 +1,4 @@
1
1LED handling under Linux 2LED handling under Linux
2======================== 3========================
3 4
@@ -5,10 +6,10 @@ If you're reading this and thinking about keyboard leds, these are
5handled by the input subsystem and the led class is *not* needed. 6handled by the input subsystem and the led class is *not* needed.
6 7
7In its simplest form, the LED class just allows control of LEDs from 8In its simplest form, the LED class just allows control of LEDs from
8userspace. LEDs appear in /sys/class/leds/. The brightness file will 9userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the
9set the brightness of the LED (taking a value 0-255). Most LEDs don't 10LED is defined in max_brightness file. The brightness file will set the brightness
10have hardware brightness support so will just be turned on for non-zero 11of the LED (taking a value 0-max_brightness). Most LEDs don't have hardware
11brightness settings. 12brightness support so will just be turned on for non-zero brightness settings.
12 13
13The class also introduces the optional concept of an LED trigger. A trigger 14The class also introduces the optional concept of an LED trigger. A trigger
14is a kernel based source of led events. Triggers can either be simple or 15is a kernel based source of led events. Triggers can either be simple or
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index db657bbeec90..b39d2bb3e75b 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -77,15 +77,16 @@
77 * Flags for hotk status 77 * Flags for hotk status
78 * WL_ON and BT_ON are also used for wireless_status() 78 * WL_ON and BT_ON are also used for wireless_status()
79 */ 79 */
80#define WL_ON 0x01 //internal Wifi 80#define WL_ON 0x01 /* internal Wifi */
81#define BT_ON 0x02 //internal Bluetooth 81#define BT_ON 0x02 /* internal Bluetooth */
82#define MLED_ON 0x04 //mail LED 82#define MLED_ON 0x04 /* mail LED */
83#define TLED_ON 0x08 //touchpad LED 83#define TLED_ON 0x08 /* touchpad LED */
84#define RLED_ON 0x10 //Record LED 84#define RLED_ON 0x10 /* Record LED */
85#define PLED_ON 0x20 //Phone LED 85#define PLED_ON 0x20 /* Phone LED */
86#define GLED_ON 0x40 //Gaming LED 86#define GLED_ON 0x40 /* Gaming LED */
87#define LCD_ON 0x80 //LCD backlight 87#define LCD_ON 0x80 /* LCD backlight */
88#define GPS_ON 0x100 //GPS 88#define GPS_ON 0x100 /* GPS */
89#define KEY_ON 0x200 /* Keyboard backlight */
89 90
90#define ASUS_LOG ASUS_HOTK_FILE ": " 91#define ASUS_LOG ASUS_HOTK_FILE ": "
91#define ASUS_ERR KERN_ERR ASUS_LOG 92#define ASUS_ERR KERN_ERR ASUS_LOG
@@ -98,7 +99,8 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
98MODULE_DESCRIPTION(ASUS_HOTK_NAME); 99MODULE_DESCRIPTION(ASUS_HOTK_NAME);
99MODULE_LICENSE("GPL"); 100MODULE_LICENSE("GPL");
100 101
101/* WAPF defines the behavior of the Fn+Fx wlan key 102/*
103 * WAPF defines the behavior of the Fn+Fx wlan key
102 * The significance of values is yet to be found, but 104 * The significance of values is yet to be found, but
103 * most of the time: 105 * most of the time:
104 * 0x0 will do nothing 106 * 0x0 will do nothing
@@ -125,7 +127,8 @@ ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */
125/* LEDD */ 127/* LEDD */
126ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); 128ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
127 129
128/* Bluetooth and WLAN 130/*
131 * Bluetooth and WLAN
129 * WLED and BLED are not handled like other XLED, because in some dsdt 132 * WLED and BLED are not handled like other XLED, because in some dsdt
130 * they also control the WLAN/Bluetooth device. 133 * they also control the WLAN/Bluetooth device.
131 */ 134 */
@@ -149,22 +152,32 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
149 152
150/* Display */ 153/* Display */
151ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); 154ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
152ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G 155ASUS_HANDLE(display_get,
153 M6A M6V VX-1 V6J V6V W3Z */ 156 /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
154 "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V 157 "\\_SB.PCI0.P0P1.VGA.GETD",
155 S5A M5A z33A W1Jc W2V G1 */ 158 /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
156 "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ 159 "\\_SB.PCI0.P0P2.VGA.GETD",
157 "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ 160 /* A6V A6Q */
158 "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ 161 "\\_SB.PCI0.P0P3.VGA.GETD",
159 "\\_SB.PCI0.VGA.GETD", /* Z96F */ 162 /* A6T, A6M */
160 "\\ACTD", /* A2D */ 163 "\\_SB.PCI0.P0PA.VGA.GETD",
161 "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ 164 /* L3C */
162 "\\DNXT", /* P30 */ 165 "\\_SB.PCI0.PCI1.VGAC.NMAP",
163 "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ 166 /* Z96F */
164 "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */ 167 "\\_SB.PCI0.VGA.GETD",
165 168 /* A2D */
166ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ 169 "\\ACTD",
167ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ 170 /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
171 "\\ADVG",
172 /* P30 */
173 "\\DNXT",
174 /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
175 "\\INFB",
176 /* A3F A6F A3N A3L M6N W3N W6A */
177 "\\SSTE");
178
179ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
180ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
168 181
169/* GPS */ 182/* GPS */
170/* R2H use different handle for GPS on/off */ 183/* R2H use different handle for GPS on/off */
@@ -172,19 +185,23 @@ ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */
172ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ 185ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */
173ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); 186ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST");
174 187
188/* Keyboard light */
189ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB");
190ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB");
191
175/* 192/*
176 * This is the main structure, we can use it to store anything interesting 193 * This is the main structure, we can use it to store anything interesting
177 * about the hotk device 194 * about the hotk device
178 */ 195 */
179struct asus_hotk { 196struct asus_hotk {
180 char *name; //laptop name 197 char *name; /* laptop name */
181 struct acpi_device *device; //the device we are in 198 struct acpi_device *device; /* the device we are in */
182 acpi_handle handle; //the handle of the hotk device 199 acpi_handle handle; /* the handle of the hotk device */
183 char status; //status of the hotk, for LEDs, ... 200 char status; /* status of the hotk, for LEDs, ... */
184 u32 ledd_status; //status of the LED display 201 u32 ledd_status; /* status of the LED display */
185 u8 light_level; //light sensor level 202 u8 light_level; /* light sensor level */
186 u8 light_switch; //light sensor switch value 203 u8 light_switch; /* light sensor switch value */
187 u16 event_count[128]; //count for each event TODO make this better 204 u16 event_count[128]; /* count for each event TODO make this better */
188 struct input_dev *inputdev; 205 struct input_dev *inputdev;
189 u16 *keycode_map; 206 u16 *keycode_map;
190}; 207};
@@ -237,28 +254,35 @@ static struct backlight_ops asusbl_ops = {
237 .update_status = update_bl_status, 254 .update_status = update_bl_status,
238}; 255};
239 256
240/* These functions actually update the LED's, and are called from a 257/*
258 * These functions actually update the LED's, and are called from a
241 * workqueue. By doing this as separate work rather than when the LED 259 * workqueue. By doing this as separate work rather than when the LED
242 * subsystem asks, we avoid messing with the Asus ACPI stuff during a 260 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
243 * potentially bad time, such as a timer interrupt. */ 261 * potentially bad time, such as a timer interrupt.
262 */
244static struct workqueue_struct *led_workqueue; 263static struct workqueue_struct *led_workqueue;
245 264
246#define ASUS_LED(object, ledname) \ 265#define ASUS_LED(object, ledname, max) \
247 static void object##_led_set(struct led_classdev *led_cdev, \ 266 static void object##_led_set(struct led_classdev *led_cdev, \
248 enum led_brightness value); \ 267 enum led_brightness value); \
268 static enum led_brightness object##_led_get( \
269 struct led_classdev *led_cdev); \
249 static void object##_led_update(struct work_struct *ignored); \ 270 static void object##_led_update(struct work_struct *ignored); \
250 static int object##_led_wk; \ 271 static int object##_led_wk; \
251 static DECLARE_WORK(object##_led_work, object##_led_update); \ 272 static DECLARE_WORK(object##_led_work, object##_led_update); \
252 static struct led_classdev object##_led = { \ 273 static struct led_classdev object##_led = { \
253 .name = "asus::" ledname, \ 274 .name = "asus::" ledname, \
254 .brightness_set = object##_led_set, \ 275 .brightness_set = object##_led_set, \
276 .brightness_get = object##_led_get, \
277 .max_brightness = max \
255 } 278 }
256 279
257ASUS_LED(mled, "mail"); 280ASUS_LED(mled, "mail", 1);
258ASUS_LED(tled, "touchpad"); 281ASUS_LED(tled, "touchpad", 1);
259ASUS_LED(rled, "record"); 282ASUS_LED(rled, "record", 1);
260ASUS_LED(pled, "phone"); 283ASUS_LED(pled, "phone", 1);
261ASUS_LED(gled, "gaming"); 284ASUS_LED(gled, "gaming", 1);
285ASUS_LED(kled, "kbd_backlight", 3);
262 286
263struct key_entry { 287struct key_entry {
264 char type; 288 char type;
@@ -278,16 +302,23 @@ static struct key_entry asus_keymap[] = {
278 {KE_KEY, 0x41, KEY_NEXTSONG}, 302 {KE_KEY, 0x41, KEY_NEXTSONG},
279 {KE_KEY, 0x43, KEY_STOPCD}, 303 {KE_KEY, 0x43, KEY_STOPCD},
280 {KE_KEY, 0x45, KEY_PLAYPAUSE}, 304 {KE_KEY, 0x45, KEY_PLAYPAUSE},
305 {KE_KEY, 0x4c, KEY_MEDIA},
281 {KE_KEY, 0x50, KEY_EMAIL}, 306 {KE_KEY, 0x50, KEY_EMAIL},
282 {KE_KEY, 0x51, KEY_WWW}, 307 {KE_KEY, 0x51, KEY_WWW},
308 {KE_KEY, 0x55, KEY_CALC},
283 {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ 309 {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */
284 {KE_KEY, 0x5D, KEY_WLAN}, 310 {KE_KEY, 0x5D, KEY_WLAN},
311 {KE_KEY, 0x5E, KEY_WLAN},
312 {KE_KEY, 0x5F, KEY_WLAN},
313 {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE},
285 {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, 314 {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
286 {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */ 315 {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */
287 {KE_KEY, 0x82, KEY_CAMERA}, 316 {KE_KEY, 0x82, KEY_CAMERA},
288 {KE_KEY, 0x8A, KEY_PROG1}, 317 {KE_KEY, 0x8A, KEY_PROG1},
289 {KE_KEY, 0x95, KEY_MEDIA}, 318 {KE_KEY, 0x95, KEY_MEDIA},
290 {KE_KEY, 0x99, KEY_PHONE}, 319 {KE_KEY, 0x99, KEY_PHONE},
320 {KE_KEY, 0xc4, KEY_KBDILLUMUP},
321 {KE_KEY, 0xc5, KEY_KBDILLUMDOWN},
291 {KE_END, 0}, 322 {KE_END, 0},
292}; 323};
293 324
@@ -301,8 +332,8 @@ static struct key_entry asus_keymap[] = {
301static int write_acpi_int(acpi_handle handle, const char *method, int val, 332static int write_acpi_int(acpi_handle handle, const char *method, int val,
302 struct acpi_buffer *output) 333 struct acpi_buffer *output)
303{ 334{
304 struct acpi_object_list params; //list of input parameters (an int here) 335 struct acpi_object_list params; /* list of input parameters (an int) */
305 union acpi_object in_obj; //the only param we use 336 union acpi_object in_obj; /* the only param we use */
306 acpi_status status; 337 acpi_status status;
307 338
308 if (!handle) 339 if (!handle)
@@ -399,6 +430,11 @@ static void write_status(acpi_handle handle, int out, int mask)
399 { \ 430 { \
400 int value = object##_led_wk; \ 431 int value = object##_led_wk; \
401 write_status(object##_set_handle, value, (mask)); \ 432 write_status(object##_set_handle, value, (mask)); \
433 } \
434 static enum led_brightness object##_led_get( \
435 struct led_classdev *led_cdev) \
436 { \
437 return led_cdev->brightness; \
402 } 438 }
403 439
404ASUS_LED_HANDLER(mled, MLED_ON); 440ASUS_LED_HANDLER(mled, MLED_ON);
@@ -407,6 +443,60 @@ ASUS_LED_HANDLER(rled, RLED_ON);
407ASUS_LED_HANDLER(tled, TLED_ON); 443ASUS_LED_HANDLER(tled, TLED_ON);
408ASUS_LED_HANDLER(gled, GLED_ON); 444ASUS_LED_HANDLER(gled, GLED_ON);
409 445
446/*
447 * Keyboard backlight
448 */
449static int get_kled_lvl(void)
450{
451 unsigned long long kblv;
452 struct acpi_object_list params;
453 union acpi_object in_obj;
454 acpi_status rv;
455
456 params.count = 1;
457 params.pointer = &in_obj;
458 in_obj.type = ACPI_TYPE_INTEGER;
459 in_obj.integer.value = 2;
460
461 rv = acpi_evaluate_integer(kled_get_handle, NULL, &params, &kblv);
462 if (ACPI_FAILURE(rv)) {
463 pr_warning("Error reading kled level\n");
464 return 0;
465 }
466 return kblv;
467}
468
469static int set_kled_lvl(int kblv)
470{
471 if (kblv > 0)
472 kblv = (1 << 7) | (kblv & 0x7F);
473 else
474 kblv = 0;
475
476 if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) {
477 pr_warning("Keyboard LED display write failed\n");
478 return -EINVAL;
479 }
480 return 0;
481}
482
483static void kled_led_set(struct led_classdev *led_cdev,
484 enum led_brightness value)
485{
486 kled_led_wk = value;
487 queue_work(led_workqueue, &kled_led_work);
488}
489
490static void kled_led_update(struct work_struct *ignored)
491{
492 set_kled_lvl(kled_led_wk);
493}
494
495static enum led_brightness kled_led_get(struct led_classdev *led_cdev)
496{
497 return get_kled_lvl();
498}
499
410static int get_lcd_state(void) 500static int get_lcd_state(void)
411{ 501{
412 return read_status(LCD_ON); 502 return read_status(LCD_ON);
@@ -498,7 +588,7 @@ static ssize_t show_infos(struct device *dev,
498{ 588{
499 int len = 0; 589 int len = 0;
500 unsigned long long temp; 590 unsigned long long temp;
501 char buf[16]; //enough for all info 591 char buf[16]; /* enough for all info */
502 acpi_status rv = AE_OK; 592 acpi_status rv = AE_OK;
503 593
504 /* 594 /*
@@ -516,7 +606,17 @@ static ssize_t show_infos(struct device *dev,
516 */ 606 */
517 rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp); 607 rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
518 if (!ACPI_FAILURE(rv)) 608 if (!ACPI_FAILURE(rv))
519 len += sprintf(page + len, "SFUN value : 0x%04x\n", 609 len += sprintf(page + len, "SFUN value : %#x\n",
610 (uint) temp);
611 /*
612 * The HWRS method return informations about the hardware.
613 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
614 * The significance of others is yet to be found.
615 * If we don't find the method, we assume the device are present.
616 */
617 rv = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &temp);
618 if (!ACPI_FAILURE(rv))
619 len += sprintf(page + len, "HRWS value : %#x\n",
520 (uint) temp); 620 (uint) temp);
521 /* 621 /*
522 * Another value for userspace: the ASYM method returns 0x02 for 622 * Another value for userspace: the ASYM method returns 0x02 for
@@ -527,7 +627,7 @@ static ssize_t show_infos(struct device *dev,
527 */ 627 */
528 rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp); 628 rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
529 if (!ACPI_FAILURE(rv)) 629 if (!ACPI_FAILURE(rv))
530 len += sprintf(page + len, "ASYM value : 0x%04x\n", 630 len += sprintf(page + len, "ASYM value : %#x\n",
531 (uint) temp); 631 (uint) temp);
532 if (asus_info) { 632 if (asus_info) {
533 snprintf(buf, 16, "%d", asus_info->length); 633 snprintf(buf, 16, "%d", asus_info->length);
@@ -648,8 +748,10 @@ static int read_display(void)
648 unsigned long long value = 0; 748 unsigned long long value = 0;
649 acpi_status rv = AE_OK; 749 acpi_status rv = AE_OK;
650 750
651 /* In most of the case, we know how to set the display, but sometime 751 /*
652 we can't read it */ 752 * In most of the case, we know how to set the display, but sometime
753 * we can't read it
754 */
653 if (display_get_handle) { 755 if (display_get_handle) {
654 rv = acpi_evaluate_integer(display_get_handle, NULL, 756 rv = acpi_evaluate_integer(display_get_handle, NULL,
655 NULL, &value); 757 NULL, &value);
@@ -1037,6 +1139,9 @@ static int asus_hotk_get_info(void)
1037 1139
1038 ASUS_HANDLE_INIT(ledd_set); 1140 ASUS_HANDLE_INIT(ledd_set);
1039 1141
1142 ASUS_HANDLE_INIT(kled_set);
1143 ASUS_HANDLE_INIT(kled_get);
1144
1040 /* 1145 /*
1041 * The HWRS method return informations about the hardware. 1146 * The HWRS method return informations about the hardware.
1042 * 0x80 bit is for WLAN, 0x100 for Bluetooth. 1147 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
@@ -1063,8 +1168,10 @@ static int asus_hotk_get_info(void)
1063 ASUS_HANDLE_INIT(display_set); 1168 ASUS_HANDLE_INIT(display_set);
1064 ASUS_HANDLE_INIT(display_get); 1169 ASUS_HANDLE_INIT(display_get);
1065 1170
1066 /* There is a lot of models with "ALSL", but a few get 1171 /*
1067 a real light sens, so we need to check it. */ 1172 * There is a lot of models with "ALSL", but a few get
1173 * a real light sens, so we need to check it.
1174 */
1068 if (!ASUS_HANDLE_INIT(ls_switch)) 1175 if (!ASUS_HANDLE_INIT(ls_switch))
1069 ASUS_HANDLE_INIT(ls_level); 1176 ASUS_HANDLE_INIT(ls_level);
1070 1177
@@ -1168,6 +1275,10 @@ static int asus_hotk_add(struct acpi_device *device)
1168 /* LCD Backlight is on by default */ 1275 /* LCD Backlight is on by default */
1169 write_status(NULL, 1, LCD_ON); 1276 write_status(NULL, 1, LCD_ON);
1170 1277
1278 /* Keyboard Backlight is on by default */
1279 if (kled_set_handle)
1280 set_kled_lvl(1);
1281
1171 /* LED display is off by default */ 1282 /* LED display is off by default */
1172 hotk->ledd_status = 0xFFF; 1283 hotk->ledd_status = 0xFFF;
1173 1284
@@ -1222,6 +1333,7 @@ static void asus_led_exit(void)
1222 ASUS_LED_UNREGISTER(pled); 1333 ASUS_LED_UNREGISTER(pled);
1223 ASUS_LED_UNREGISTER(rled); 1334 ASUS_LED_UNREGISTER(rled);
1224 ASUS_LED_UNREGISTER(gled); 1335 ASUS_LED_UNREGISTER(gled);
1336 ASUS_LED_UNREGISTER(kled);
1225} 1337}
1226 1338
1227static void asus_input_exit(void) 1339static void asus_input_exit(void)
@@ -1301,13 +1413,20 @@ static int asus_led_init(struct device *dev)
1301 if (rv) 1413 if (rv)
1302 goto out4; 1414 goto out4;
1303 1415
1416 if (kled_set_handle && kled_get_handle)
1417 rv = ASUS_LED_REGISTER(kled, dev);
1418 if (rv)
1419 goto out5;
1420
1304 led_workqueue = create_singlethread_workqueue("led_workqueue"); 1421 led_workqueue = create_singlethread_workqueue("led_workqueue");
1305 if (!led_workqueue) 1422 if (!led_workqueue)
1306 goto out5; 1423 goto out6;
1307 1424
1308 return 0; 1425 return 0;
1309out5: 1426out6:
1310 rv = -ENOMEM; 1427 rv = -ENOMEM;
1428 ASUS_LED_UNREGISTER(kled);
1429out5:
1311 ASUS_LED_UNREGISTER(gled); 1430 ASUS_LED_UNREGISTER(gled);
1312out4: 1431out4:
1313 ASUS_LED_UNREGISTER(pled); 1432 ASUS_LED_UNREGISTER(pled);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 222ffb892f22..da3c08b3dcc1 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -142,18 +142,28 @@ struct eeepc_hotk {
142 struct rfkill *wlan_rfkill; 142 struct rfkill *wlan_rfkill;
143 struct rfkill *bluetooth_rfkill; 143 struct rfkill *bluetooth_rfkill;
144 struct rfkill *wwan3g_rfkill; 144 struct rfkill *wwan3g_rfkill;
145 struct rfkill *wimax_rfkill;
145 struct hotplug_slot *hotplug_slot; 146 struct hotplug_slot *hotplug_slot;
146 struct work_struct hotplug_work; 147 struct mutex hotplug_lock;
147}; 148};
148 149
149/* The actual device the driver binds to */ 150/* The actual device the driver binds to */
150static struct eeepc_hotk *ehotk; 151static struct eeepc_hotk *ehotk;
151 152
152/* Platform device/driver */ 153/* Platform device/driver */
154static int eeepc_hotk_thaw(struct device *device);
155static int eeepc_hotk_restore(struct device *device);
156
157static struct dev_pm_ops eeepc_pm_ops = {
158 .thaw = eeepc_hotk_thaw,
159 .restore = eeepc_hotk_restore,
160};
161
153static struct platform_driver platform_driver = { 162static struct platform_driver platform_driver = {
154 .driver = { 163 .driver = {
155 .name = EEEPC_HOTK_FILE, 164 .name = EEEPC_HOTK_FILE,
156 .owner = THIS_MODULE, 165 .owner = THIS_MODULE,
166 .pm = &eeepc_pm_ops,
157 } 167 }
158}; 168};
159 169
@@ -192,7 +202,6 @@ static struct key_entry eeepc_keymap[] = {
192 */ 202 */
193static int eeepc_hotk_add(struct acpi_device *device); 203static int eeepc_hotk_add(struct acpi_device *device);
194static int eeepc_hotk_remove(struct acpi_device *device, int type); 204static int eeepc_hotk_remove(struct acpi_device *device, int type);
195static int eeepc_hotk_resume(struct acpi_device *device);
196static void eeepc_hotk_notify(struct acpi_device *device, u32 event); 205static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
197 206
198static const struct acpi_device_id eeepc_device_ids[] = { 207static const struct acpi_device_id eeepc_device_ids[] = {
@@ -209,7 +218,6 @@ static struct acpi_driver eeepc_hotk_driver = {
209 .ops = { 218 .ops = {
210 .add = eeepc_hotk_add, 219 .add = eeepc_hotk_add,
211 .remove = eeepc_hotk_remove, 220 .remove = eeepc_hotk_remove,
212 .resume = eeepc_hotk_resume,
213 .notify = eeepc_hotk_notify, 221 .notify = eeepc_hotk_notify,
214 }, 222 },
215}; 223};
@@ -579,7 +587,6 @@ static void cmsg_quirks(void)
579 587
580static int eeepc_hotk_check(void) 588static int eeepc_hotk_check(void)
581{ 589{
582 const struct key_entry *key;
583 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 590 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
584 int result; 591 int result;
585 592
@@ -604,31 +611,6 @@ static int eeepc_hotk_check(void)
604 pr_info("Get control methods supported: 0x%x\n", 611 pr_info("Get control methods supported: 0x%x\n",
605 ehotk->cm_supported); 612 ehotk->cm_supported);
606 } 613 }
607 ehotk->inputdev = input_allocate_device();
608 if (!ehotk->inputdev) {
609 pr_info("Unable to allocate input device\n");
610 return 0;
611 }
612 ehotk->inputdev->name = "Asus EeePC extra buttons";
613 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
614 ehotk->inputdev->id.bustype = BUS_HOST;
615 ehotk->inputdev->getkeycode = eeepc_getkeycode;
616 ehotk->inputdev->setkeycode = eeepc_setkeycode;
617
618 for (key = eeepc_keymap; key->type != KE_END; key++) {
619 switch (key->type) {
620 case KE_KEY:
621 set_bit(EV_KEY, ehotk->inputdev->evbit);
622 set_bit(key->keycode, ehotk->inputdev->keybit);
623 break;
624 }
625 }
626 result = input_register_device(ehotk->inputdev);
627 if (result) {
628 pr_info("Unable to register input device\n");
629 input_free_device(ehotk->inputdev);
630 return 0;
631 }
632 } else { 614 } else {
633 pr_err("Hotkey device not present, aborting\n"); 615 pr_err("Hotkey device not present, aborting\n");
634 return -EINVAL; 616 return -EINVAL;
@@ -661,40 +643,48 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
661 return 0; 643 return 0;
662} 644}
663 645
664static void eeepc_hotplug_work(struct work_struct *work) 646static void eeepc_rfkill_hotplug(void)
665{ 647{
666 struct pci_dev *dev; 648 struct pci_dev *dev;
667 struct pci_bus *bus = pci_find_bus(0, 1); 649 struct pci_bus *bus;
668 bool blocked; 650 bool blocked = eeepc_wlan_rfkill_blocked();
669 651
670 if (!bus) { 652 if (ehotk->wlan_rfkill)
671 pr_warning("Unable to find PCI bus 1?\n"); 653 rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
672 return;
673 }
674 654
675 blocked = eeepc_wlan_rfkill_blocked(); 655 mutex_lock(&ehotk->hotplug_lock);
676 if (!blocked) { 656
677 dev = pci_get_slot(bus, 0); 657 if (ehotk->hotplug_slot) {
678 if (dev) { 658 bus = pci_find_bus(0, 1);
679 /* Device already present */ 659 if (!bus) {
680 pci_dev_put(dev); 660 pr_warning("Unable to find PCI bus 1?\n");
681 return; 661 goto out_unlock;
682 }
683 dev = pci_scan_single_device(bus, 0);
684 if (dev) {
685 pci_bus_assign_resources(bus);
686 if (pci_bus_add_device(dev))
687 pr_err("Unable to hotplug wifi\n");
688 } 662 }
689 } else { 663
690 dev = pci_get_slot(bus, 0); 664 if (!blocked) {
691 if (dev) { 665 dev = pci_get_slot(bus, 0);
692 pci_remove_bus_device(dev); 666 if (dev) {
693 pci_dev_put(dev); 667 /* Device already present */
668 pci_dev_put(dev);
669 goto out_unlock;
670 }
671 dev = pci_scan_single_device(bus, 0);
672 if (dev) {
673 pci_bus_assign_resources(bus);
674 if (pci_bus_add_device(dev))
675 pr_err("Unable to hotplug wifi\n");
676 }
677 } else {
678 dev = pci_get_slot(bus, 0);
679 if (dev) {
680 pci_remove_bus_device(dev);
681 pci_dev_put(dev);
682 }
694 } 683 }
695 } 684 }
696 685
697 rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); 686out_unlock:
687 mutex_unlock(&ehotk->hotplug_lock);
698} 688}
699 689
700static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) 690static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
@@ -702,7 +692,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
702 if (event != ACPI_NOTIFY_BUS_CHECK) 692 if (event != ACPI_NOTIFY_BUS_CHECK)
703 return; 693 return;
704 694
705 schedule_work(&ehotk->hotplug_work); 695 eeepc_rfkill_hotplug();
706} 696}
707 697
708static void eeepc_hotk_notify(struct acpi_device *device, u32 event) 698static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
@@ -839,66 +829,38 @@ error_slot:
839 return ret; 829 return ret;
840} 830}
841 831
842static int eeepc_hotk_add(struct acpi_device *device) 832static int eeepc_hotk_thaw(struct device *device)
843{
844 int result;
845
846 if (!device)
847 return -EINVAL;
848 pr_notice(EEEPC_HOTK_NAME "\n");
849 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
850 if (!ehotk)
851 return -ENOMEM;
852 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
853 ehotk->handle = device->handle;
854 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
855 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
856 device->driver_data = ehotk;
857 ehotk->device = device;
858 result = eeepc_hotk_check();
859 if (result)
860 goto ehotk_fail;
861
862 return 0;
863
864 ehotk_fail:
865 kfree(ehotk);
866 ehotk = NULL;
867
868 return result;
869}
870
871static int eeepc_hotk_remove(struct acpi_device *device, int type)
872{
873 if (!device || !acpi_driver_data(device))
874 return -EINVAL;
875
876 kfree(ehotk);
877 return 0;
878}
879
880static int eeepc_hotk_resume(struct acpi_device *device)
881{ 833{
882 if (ehotk->wlan_rfkill) { 834 if (ehotk->wlan_rfkill) {
883 bool wlan; 835 bool wlan;
884 836
885 /* Workaround - it seems that _PTS disables the wireless 837 /*
886 without notification or changing the value read by WLAN. 838 * Work around bios bug - acpi _PTS turns off the wireless led
887 Normally this is fine because the correct value is restored 839 * during suspend. Normally it restores it on resume, but
888 from the non-volatile storage on resume, but we need to do 840 * we should kick it ourselves in case hibernation is aborted.
889 it ourself if case suspend is aborted, or we lose wireless.
890 */ 841 */
891 wlan = get_acpi(CM_ASL_WLAN); 842 wlan = get_acpi(CM_ASL_WLAN);
892 set_acpi(CM_ASL_WLAN, wlan); 843 set_acpi(CM_ASL_WLAN, wlan);
844 }
893 845
894 rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1); 846 return 0;
847}
895 848
896 schedule_work(&ehotk->hotplug_work); 849static int eeepc_hotk_restore(struct device *device)
897 } 850{
851 /* Refresh both wlan rfkill state and pci hotplug */
852 if (ehotk->wlan_rfkill)
853 eeepc_rfkill_hotplug();
898 854
899 if (ehotk->bluetooth_rfkill) 855 if (ehotk->bluetooth_rfkill)
900 rfkill_set_sw_state(ehotk->bluetooth_rfkill, 856 rfkill_set_sw_state(ehotk->bluetooth_rfkill,
901 get_acpi(CM_ASL_BLUETOOTH) != 1); 857 get_acpi(CM_ASL_BLUETOOTH) != 1);
858 if (ehotk->wwan3g_rfkill)
859 rfkill_set_sw_state(ehotk->wwan3g_rfkill,
860 get_acpi(CM_ASL_3G) != 1);
861 if (ehotk->wimax_rfkill)
862 rfkill_set_sw_state(ehotk->wimax_rfkill,
863 get_acpi(CM_ASL_WIMAX) != 1);
902 864
903 return 0; 865 return 0;
904} 866}
@@ -1019,16 +981,37 @@ static void eeepc_backlight_exit(void)
1019 981
1020static void eeepc_rfkill_exit(void) 982static void eeepc_rfkill_exit(void)
1021{ 983{
984 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5");
1022 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); 985 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
1023 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); 986 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
1024 if (ehotk->wlan_rfkill) 987 if (ehotk->wlan_rfkill) {
1025 rfkill_unregister(ehotk->wlan_rfkill); 988 rfkill_unregister(ehotk->wlan_rfkill);
1026 if (ehotk->bluetooth_rfkill) 989 rfkill_destroy(ehotk->wlan_rfkill);
1027 rfkill_unregister(ehotk->bluetooth_rfkill); 990 ehotk->wlan_rfkill = NULL;
1028 if (ehotk->wwan3g_rfkill) 991 }
1029 rfkill_unregister(ehotk->wwan3g_rfkill); 992 /*
993 * Refresh pci hotplug in case the rfkill state was changed after
994 * eeepc_unregister_rfkill_notifier()
995 */
996 eeepc_rfkill_hotplug();
1030 if (ehotk->hotplug_slot) 997 if (ehotk->hotplug_slot)
1031 pci_hp_deregister(ehotk->hotplug_slot); 998 pci_hp_deregister(ehotk->hotplug_slot);
999
1000 if (ehotk->bluetooth_rfkill) {
1001 rfkill_unregister(ehotk->bluetooth_rfkill);
1002 rfkill_destroy(ehotk->bluetooth_rfkill);
1003 ehotk->bluetooth_rfkill = NULL;
1004 }
1005 if (ehotk->wwan3g_rfkill) {
1006 rfkill_unregister(ehotk->wwan3g_rfkill);
1007 rfkill_destroy(ehotk->wwan3g_rfkill);
1008 ehotk->wwan3g_rfkill = NULL;
1009 }
1010 if (ehotk->wimax_rfkill) {
1011 rfkill_unregister(ehotk->wimax_rfkill);
1012 rfkill_destroy(ehotk->wimax_rfkill);
1013 ehotk->wimax_rfkill = NULL;
1014 }
1032} 1015}
1033 1016
1034static void eeepc_input_exit(void) 1017static void eeepc_input_exit(void)
@@ -1050,19 +1033,6 @@ static void eeepc_hwmon_exit(void)
1050 eeepc_hwmon_device = NULL; 1033 eeepc_hwmon_device = NULL;
1051} 1034}
1052 1035
1053static void __exit eeepc_laptop_exit(void)
1054{
1055 eeepc_backlight_exit();
1056 eeepc_rfkill_exit();
1057 eeepc_input_exit();
1058 eeepc_hwmon_exit();
1059 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1060 sysfs_remove_group(&platform_device->dev.kobj,
1061 &platform_attribute_group);
1062 platform_device_unregister(platform_device);
1063 platform_driver_unregister(&platform_driver);
1064}
1065
1066static int eeepc_new_rfkill(struct rfkill **rfkill, 1036static int eeepc_new_rfkill(struct rfkill **rfkill,
1067 const char *name, struct device *dev, 1037 const char *name, struct device *dev,
1068 enum rfkill_type type, int cm) 1038 enum rfkill_type type, int cm)
@@ -1094,10 +1064,7 @@ static int eeepc_rfkill_init(struct device *dev)
1094{ 1064{
1095 int result = 0; 1065 int result = 0;
1096 1066
1097 INIT_WORK(&ehotk->hotplug_work, eeepc_hotplug_work); 1067 mutex_init(&ehotk->hotplug_lock);
1098
1099 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
1100 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
1101 1068
1102 result = eeepc_new_rfkill(&ehotk->wlan_rfkill, 1069 result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
1103 "eeepc-wlan", dev, 1070 "eeepc-wlan", dev,
@@ -1120,6 +1087,13 @@ static int eeepc_rfkill_init(struct device *dev)
1120 if (result && result != -ENODEV) 1087 if (result && result != -ENODEV)
1121 goto exit; 1088 goto exit;
1122 1089
1090 result = eeepc_new_rfkill(&ehotk->wimax_rfkill,
1091 "eeepc-wimax", dev,
1092 RFKILL_TYPE_WIMAX, CM_ASL_WIMAX);
1093
1094 if (result && result != -ENODEV)
1095 goto exit;
1096
1123 result = eeepc_setup_pci_hotplug(); 1097 result = eeepc_setup_pci_hotplug();
1124 /* 1098 /*
1125 * If we get -EBUSY then something else is handling the PCI hotplug - 1099 * If we get -EBUSY then something else is handling the PCI hotplug -
@@ -1128,6 +1102,15 @@ static int eeepc_rfkill_init(struct device *dev)
1128 if (result == -EBUSY) 1102 if (result == -EBUSY)
1129 result = 0; 1103 result = 0;
1130 1104
1105 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5");
1106 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
1107 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
1108 /*
1109 * Refresh pci hotplug in case the rfkill state was changed during
1110 * setup.
1111 */
1112 eeepc_rfkill_hotplug();
1113
1131exit: 1114exit:
1132 if (result && result != -ENODEV) 1115 if (result && result != -ENODEV)
1133 eeepc_rfkill_exit(); 1116 eeepc_rfkill_exit();
@@ -1172,21 +1155,61 @@ static int eeepc_hwmon_init(struct device *dev)
1172 return result; 1155 return result;
1173} 1156}
1174 1157
1175static int __init eeepc_laptop_init(void) 1158static int eeepc_input_init(struct device *dev)
1176{ 1159{
1177 struct device *dev; 1160 const struct key_entry *key;
1178 int result; 1161 int result;
1179 1162
1180 if (acpi_disabled) 1163 ehotk->inputdev = input_allocate_device();
1181 return -ENODEV; 1164 if (!ehotk->inputdev) {
1182 result = acpi_bus_register_driver(&eeepc_hotk_driver); 1165 pr_info("Unable to allocate input device\n");
1183 if (result < 0) 1166 return -ENOMEM;
1167 }
1168 ehotk->inputdev->name = "Asus EeePC extra buttons";
1169 ehotk->inputdev->dev.parent = dev;
1170 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
1171 ehotk->inputdev->id.bustype = BUS_HOST;
1172 ehotk->inputdev->getkeycode = eeepc_getkeycode;
1173 ehotk->inputdev->setkeycode = eeepc_setkeycode;
1174
1175 for (key = eeepc_keymap; key->type != KE_END; key++) {
1176 switch (key->type) {
1177 case KE_KEY:
1178 set_bit(EV_KEY, ehotk->inputdev->evbit);
1179 set_bit(key->keycode, ehotk->inputdev->keybit);
1180 break;
1181 }
1182 }
1183 result = input_register_device(ehotk->inputdev);
1184 if (result) {
1185 pr_info("Unable to register input device\n");
1186 input_free_device(ehotk->inputdev);
1184 return result; 1187 return result;
1185 if (!ehotk) {
1186 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1187 return -ENODEV;
1188 } 1188 }
1189 return 0;
1190}
1191
1192static int eeepc_hotk_add(struct acpi_device *device)
1193{
1194 struct device *dev;
1195 int result;
1189 1196
1197 if (!device)
1198 return -EINVAL;
1199 pr_notice(EEEPC_HOTK_NAME "\n");
1200 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
1201 if (!ehotk)
1202 return -ENOMEM;
1203 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
1204 ehotk->handle = device->handle;
1205 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
1206 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
1207 device->driver_data = ehotk;
1208 ehotk->device = device;
1209
1210 result = eeepc_hotk_check();
1211 if (result)
1212 goto fail_platform_driver;
1190 eeepc_enable_camera(); 1213 eeepc_enable_camera();
1191 1214
1192 /* Register platform stuff */ 1215 /* Register platform stuff */
@@ -1216,6 +1239,10 @@ static int __init eeepc_laptop_init(void)
1216 pr_info("Backlight controlled by ACPI video " 1239 pr_info("Backlight controlled by ACPI video "
1217 "driver\n"); 1240 "driver\n");
1218 1241
1242 result = eeepc_input_init(dev);
1243 if (result)
1244 goto fail_input;
1245
1219 result = eeepc_hwmon_init(dev); 1246 result = eeepc_hwmon_init(dev);
1220 if (result) 1247 if (result)
1221 goto fail_hwmon; 1248 goto fail_hwmon;
@@ -1225,9 +1252,12 @@ static int __init eeepc_laptop_init(void)
1225 goto fail_rfkill; 1252 goto fail_rfkill;
1226 1253
1227 return 0; 1254 return 0;
1255
1228fail_rfkill: 1256fail_rfkill:
1229 eeepc_hwmon_exit(); 1257 eeepc_hwmon_exit();
1230fail_hwmon: 1258fail_hwmon:
1259 eeepc_input_exit();
1260fail_input:
1231 eeepc_backlight_exit(); 1261 eeepc_backlight_exit();
1232fail_backlight: 1262fail_backlight:
1233 sysfs_remove_group(&platform_device->dev.kobj, 1263 sysfs_remove_group(&platform_device->dev.kobj,
@@ -1239,9 +1269,49 @@ fail_platform_device2:
1239fail_platform_device1: 1269fail_platform_device1:
1240 platform_driver_unregister(&platform_driver); 1270 platform_driver_unregister(&platform_driver);
1241fail_platform_driver: 1271fail_platform_driver:
1242 eeepc_input_exit(); 1272 kfree(ehotk);
1273
1243 return result; 1274 return result;
1244} 1275}
1245 1276
1277static int eeepc_hotk_remove(struct acpi_device *device, int type)
1278{
1279 if (!device || !acpi_driver_data(device))
1280 return -EINVAL;
1281
1282 eeepc_backlight_exit();
1283 eeepc_rfkill_exit();
1284 eeepc_input_exit();
1285 eeepc_hwmon_exit();
1286 sysfs_remove_group(&platform_device->dev.kobj,
1287 &platform_attribute_group);
1288 platform_device_unregister(platform_device);
1289 platform_driver_unregister(&platform_driver);
1290
1291 kfree(ehotk);
1292 return 0;
1293}
1294
1295static int __init eeepc_laptop_init(void)
1296{
1297 int result;
1298
1299 if (acpi_disabled)
1300 return -ENODEV;
1301 result = acpi_bus_register_driver(&eeepc_hotk_driver);
1302 if (result < 0)
1303 return result;
1304 if (!ehotk) {
1305 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1306 return -ENODEV;
1307 }
1308 return 0;
1309}
1310
1311static void __exit eeepc_laptop_exit(void)
1312{
1313 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1314}
1315
1246module_init(eeepc_laptop_init); 1316module_init(eeepc_laptop_init);
1247module_exit(eeepc_laptop_exit); 1317module_exit(eeepc_laptop_exit);