History

Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86

Pull x86 platform driver updates from Matthew Garrett: "Mostly relatively small updates, along with some hardware enablement for Sony hardware and a pile of updates to Google's Chromebook driver" * 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: (49 commits) ideapad-laptop: Depend on BACKLIGHT_CLASS_DEVICE instead of selecting it ideapad: depends on backlight subsystem and update comment Platform: x86: chromeos_laptop - add i915 gmbuses to adapter names Platform: x86: chromeos_laptop - Add isl light sensor for Pixel Platform: x86: chromeos_laptop - Add a more general add_i2c_device Platform: x86: chromeos_laptop - Add Pixel Touchscreen Platform: x86: chromeos_laptop - Add support for probing devices Platform: x86: chromeos_laptop - Add Pixel Trackpad hp-wmi: fix handling of platform device sony-laptop: leak in error handling sony_nc_lid_resume_setup() hp-wmi: Add support for SMBus hotkeys asus-wmi: Fix unused function build warning acer-wmi: avoid the warning of 'devices' may be used uninitialized drivers/platform/x86/thinkpad_acpi.c: Handle HKEY event 0x6040 Platform: x86: chromeos_laptop - Add HP Pavilion 14 Platform: x86: chromeos_laptop - Add Taos tsl2583 device Platform: x86: chromeos_laptop - Add Taos tsl2563 device Platform: x86: chromeos_laptop - Add Acer C7 trackpad Platform: x86: chromeos_laptop - Rename setup_lumpy_tp to setup_cyapa_smbus_tp asus-laptop: always report brightness key events ...

Linus Torvalds committed 13 years ago

Commit 23caaee2 parents a7c1120 445e8d015 files · +1375 −273Browse files

Unified · Split

15 files
  1. Documentation/ABI/testing/sysfs-platform-msi-laptop +83 −0
  2. drivers/platform/x86/Kconfig +14 −1
  3. drivers/platform/x86/Makefile +1 −0
  4. drivers/platform/x86/acer-wmi.c +21 −0
  5. drivers/platform/x86/asus-laptop.c +58 −27
  6. drivers/platform/x86/asus-nb-wmi.c +62 −14
  7. drivers/platform/x86/asus-wmi.c +102 −6
  8. drivers/platform/x86/asus-wmi.h +9 −0
  9. drivers/platform/x86/chromeos_laptop.c +371 −0
  10. drivers/platform/x86/eeepc-wmi.c +2 −0
  11. drivers/platform/x86/hp-wmi.c +77 −40
  12. drivers/platform/x86/msi-laptop.c +283 −91
  13. drivers/platform/x86/msi-wmi.c +146 −78
  14. drivers/platform/x86/sony-laptop.c +134 −11
  15. drivers/platform/x86/thinkpad_acpi.c +12 −5
Documentation/ABI/testing/sysfs-platform-msi-laptop+83−0
@@ -0,0 +1,83 @@
1+What: /sys/devices/platform/msi-laptop-pf/lcd_level
2+Date: Oct 2006
3+KernelVersion: 2.6.19
4+Contact: "Lennart Poettering <mzxreary@0pointer.de>"
5+Description:
6+ Screen brightness: contains a single integer in the range 0..8.
7+
8+What: /sys/devices/platform/msi-laptop-pf/auto_brightness
9+Date: Oct 2006
10+KernelVersion: 2.6.19
11+Contact: "Lennart Poettering <mzxreary@0pointer.de>"
12+Description:
13+ Enable automatic brightness control: contains either 0 or 1. If
14+ set to 1 the hardware adjusts the screen brightness
15+ automatically when the power cord is plugged/unplugged.
16+
17+What: /sys/devices/platform/msi-laptop-pf/wlan
18+Date: Oct 2006
19+KernelVersion: 2.6.19
20+Contact: "Lennart Poettering <mzxreary@0pointer.de>"
21+Description:
22+ WLAN subsystem enabled: contains either 0 or 1.
23+
24+What: /sys/devices/platform/msi-laptop-pf/bluetooth
25+Date: Oct 2006
26+KernelVersion: 2.6.19
27+Contact: "Lennart Poettering <mzxreary@0pointer.de>"
28+Description:
29+ Bluetooth subsystem enabled: contains either 0 or 1. Please
30+ note that this file is constantly 0 if no Bluetooth hardware is
31+ available.
32+
33+What: /sys/devices/platform/msi-laptop-pf/touchpad
34+Date: Nov 2012
35+KernelVersion: 3.8
36+Contact: "Maxim Mikityanskiy <maxtram95@gmail.com>"
37+Description:
38+ Contains either 0 or 1 and indicates if touchpad is turned on.
39+ Touchpad state can only be toggled by pressing Fn+F3.
40+
41+What: /sys/devices/platform/msi-laptop-pf/turbo_mode
42+Date: Nov 2012
43+KernelVersion: 3.8
44+Contact: "Maxim Mikityanskiy <maxtram95@gmail.com>"
45+Description:
46+ Contains either 0 or 1 and indicates if turbo mode is turned
47+ on. In turbo mode power LED is orange and processor is
48+ overclocked. Turbo mode is available only if charging. It is
49+ only possible to toggle turbo mode state by pressing Fn+F10,
50+ and there is a few seconds cooldown between subsequent toggles.
51+ If user presses Fn+F10 too frequent, turbo mode state is not
52+ changed.
53+
54+What: /sys/devices/platform/msi-laptop-pf/eco_mode
55+Date: Nov 2012
56+KernelVersion: 3.8
57+Contact: "Maxim Mikityanskiy <maxtram95@gmail.com>"
58+Description:
59+ Contains either 0 or 1 and indicates if ECO mode is turned on.
60+ In ECO mode power LED is green and userspace should do some
61+ powersaving actions. ECO mode is available only on battery
62+ power. ECO mode can only be toggled by pressing Fn+F10.
63+
64+What: /sys/devices/platform/msi-laptop-pf/turbo_cooldown
65+Date: Nov 2012
66+KernelVersion: 3.8
67+Contact: "Maxim Mikityanskiy <maxtram95@gmail.com>"
68+Description:
69+ Contains value in range 0..3:
70+ * 0 -> Turbo mode is off
71+ * 1 -> Turbo mode is on, cannot be turned off yet
72+ * 2 -> Turbo mode is off, cannot be turned on yet
73+ * 3 -> Turbo mode is on
74+
75+What: /sys/devices/platform/msi-laptop-pf/auto_fan
76+Date: Nov 2012
77+KernelVersion: 3.8
78+Contact: "Maxim Mikityanskiy <maxtram95@gmail.com>"
79+Description:
80+ Contains either 0 or 1 and indicates if fan speed is controlled
81+ automatically (1) or fan runs at maximal speed (0). Can be
82+ toggled in software.
83+
drivers/platform/x86/Kconfig+14−1
@@ -79,6 +79,17 @@ config ASUS_LAPTOP · 78 unmodified lines
7979
8080 If you have an ACPI-compatible ASUS laptop, say Y or M here.
8181
82+config CHROMEOS_LAPTOP
83+ tristate "Chrome OS Laptop"
84+ depends on I2C
85+ depends on DMI
86+ ---help---
87+ This driver instantiates i2c and smbus devices such as
88+ light sensors and touchpads.
89+
90+ If you have a supported Chromebook, choose Y or M here.
91+ The module will be called chromeos_laptop.
92+
8293 config DELL_LAPTOP
8394 tristate "Dell Laptop Extras"
8495 depends on X86
@@ -288,9 +299,11 @@ config IDEAPAD_LAPTOP · 203 unmodified lines
288299 depends on ACPI
289300 depends on RFKILL && INPUT
290301 depends on SERIO_I8042
302+ depends on BACKLIGHT_CLASS_DEVICE
291303 select INPUT_SPARSEKMAP
292304 help
293− This is a driver for the rfkill switches on Lenovo IdeaPad netbooks.
305+ This is a driver for Lenovo IdeaPad netbooks contains drivers for
306+ rfkill switch, hotkey, fan control and backlight control.
294307
295308 config THINKPAD_ACPI
296309 tristate "ThinkPad ACPI Laptop Extras"
drivers/platform/x86/Makefile+1−0
@@ -50,3 +50,4 @@ obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o · 49 unmodified lines
5050 obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
5151 obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
5252 obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
53+obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
drivers/platform/x86/acer-wmi.c+21−0
@@ -511,6 +511,24 @@ static struct dmi_system_id acer_quirks[] = { · 510 unmodified lines
511511 },
512512 .driver_data = &quirk_fujitsu_amilo_li_1718,
513513 },
514+ {
515+ .callback = dmi_matched,
516+ .ident = "Lenovo Ideapad S205-10382JG",
517+ .matches = {
518+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
519+ DMI_MATCH(DMI_PRODUCT_NAME, "10382JG"),
520+ },
521+ .driver_data = &quirk_lenovo_ideapad_s205,
522+ },
523+ {
524+ .callback = dmi_matched,
525+ .ident = "Lenovo Ideapad S205-1038DPG",
526+ .matches = {
527+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
528+ DMI_MATCH(DMI_PRODUCT_NAME, "1038DPG"),
529+ },
530+ .driver_data = &quirk_lenovo_ideapad_s205,
531+ },
514532 {}
515533 };
516534
@@ -1204,6 +1222,9 @@ static acpi_status WMID_set_capabilities(void) · 687 unmodified lines
12041222 devices = *((u32 *) obj->buffer.pointer);
12051223 } else if (obj->type == ACPI_TYPE_INTEGER) {
12061224 devices = (u32) obj->integer.value;
1225+ } else {
1226+ kfree(out.pointer);
1227+ return AE_ERROR;
12071228 }
12081229 } else {
12091230 kfree(out.pointer);
drivers/platform/x86/asus-laptop.c+58−27
@@ -128,10 +128,12 @@ MODULE_PARM_DESC(als_status, "Set the ALS status on boot " · 127 unmodified lines
128128 /*
129129 * Some events we use, same for all Asus
130130 */
131−#define ATKD_BR_UP 0x10 /* (event & ~ATKD_BR_UP) = brightness level */
132−#define ATKD_BR_DOWN 0x20 /* (event & ~ATKD_BR_DOWN) = britghness level */
133−#define ATKD_BR_MIN ATKD_BR_UP
134−#define ATKD_BR_MAX (ATKD_BR_DOWN | 0xF) /* 0x2f */
131+#define ATKD_BRNUP_MIN 0x10
132+#define ATKD_BRNUP_MAX 0x1f
133+#define ATKD_BRNDOWN_MIN 0x20
134+#define ATKD_BRNDOWN_MAX 0x2f
135+#define ATKD_BRNDOWN 0x20
136+#define ATKD_BRNUP 0x2f
135137 #define ATKD_LCD_ON 0x33
136138 #define ATKD_LCD_OFF 0x34
137139
@@ -301,40 +303,65 @@ static const struct key_entry asus_keymap[] = { · 163 unmodified lines
301303 {KE_KEY, 0x17, { KEY_ZOOM } },
302304 {KE_KEY, 0x1f, { KEY_BATTERY } },
303305 /* End of Lenovo SL Specific keycodes */
306+ {KE_KEY, ATKD_BRNDOWN, { KEY_BRIGHTNESSDOWN } },
307+ {KE_KEY, ATKD_BRNUP, { KEY_BRIGHTNESSUP } },
304308 {KE_KEY, 0x30, { KEY_VOLUMEUP } },
305309 {KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
306310 {KE_KEY, 0x32, { KEY_MUTE } },
307− {KE_KEY, 0x33, { KEY_SWITCHVIDEOMODE } },
308− {KE_KEY, 0x34, { KEY_SWITCHVIDEOMODE } },
311+ {KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */
312+ {KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
309313 {KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
310314 {KE_KEY, 0x41, { KEY_NEXTSONG } },
311− {KE_KEY, 0x43, { KEY_STOPCD } },
315+ {KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
312316 {KE_KEY, 0x45, { KEY_PLAYPAUSE } },
313− {KE_KEY, 0x4c, { KEY_MEDIA } },
317+ {KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */
314318 {KE_KEY, 0x50, { KEY_EMAIL } },
315319 {KE_KEY, 0x51, { KEY_WWW } },
316320 {KE_KEY, 0x55, { KEY_CALC } },
321+ {KE_IGNORE, 0x57, }, /* Battery mode */
322+ {KE_IGNORE, 0x58, }, /* AC mode */
317323 {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */
318− {KE_KEY, 0x5D, { KEY_WLAN } },
319− {KE_KEY, 0x5E, { KEY_WLAN } },
320− {KE_KEY, 0x5F, { KEY_WLAN } },
321− {KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
322− {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
323− {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
324− {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
325− {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
324+ {KE_KEY, 0x5D, { KEY_WLAN } }, /* WLAN Toggle */
325+ {KE_KEY, 0x5E, { KEY_WLAN } }, /* WLAN Enable */
326+ {KE_KEY, 0x5F, { KEY_WLAN } }, /* WLAN Disable */
327+ {KE_KEY, 0x60, { KEY_TOUCHPAD_ON } },
328+ {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */
329+ {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */
330+ {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */
331+ {KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */
332+ {KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */
333+ {KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */
334+ {KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */
335+ {KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, /* Lock Touchpad */
326336 {KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
327337 {KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
328− {KE_KEY, 0x7E, { KEY_BLUETOOTH } },
329− {KE_KEY, 0x7D, { KEY_BLUETOOTH } },
338+ {KE_IGNORE, 0x6E, }, /* Low Battery notification */
339+ {KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
340+ {KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
330341 {KE_KEY, 0x82, { KEY_CAMERA } },
331− {KE_KEY, 0x88, { KEY_WLAN } },
332− {KE_KEY, 0x8A, { KEY_PROG1 } },
342+ {KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */
343+ {KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */
344+ {KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */
345+ {KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */
346+ {KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */
347+ {KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */
348+ {KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */
349+ {KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */
350+ {KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */
351+ {KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */
333352 {KE_KEY, 0x95, { KEY_MEDIA } },
334353 {KE_KEY, 0x99, { KEY_PHONE } },
335− {KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
336− {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
337− {KE_KEY, 0xb5, { KEY_CALC } },
354+ {KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */
355+ {KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */
356+ {KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */
357+ {KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */
358+ {KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */
359+ {KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
360+ {KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
361+ {KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
362+ {KE_KEY, 0xB5, { KEY_CALC } },
363+ {KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
364+ {KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
338365 {KE_END, 0},
339366 };
340367
@@ -1521,15 +1548,19 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) · 1180 unmodified lines
15211548 dev_name(&asus->device->dev), event,
15221549 count);
15231550
1524− /* Brightness events are special */
1525− if (event >= ATKD_BR_MIN && event <= ATKD_BR_MAX) {
1551+ if (event >= ATKD_BRNUP_MIN && event <= ATKD_BRNUP_MAX)
1552+ event = ATKD_BRNUP;
1553+ else if (event >= ATKD_BRNDOWN_MIN &&
1554+ event <= ATKD_BRNDOWN_MAX)
1555+ event = ATKD_BRNDOWN;
15261556
1527− /* Ignore them completely if the acpi video driver is used */
1557+ /* Brightness events are special */
1558+ if (event == ATKD_BRNDOWN || event == ATKD_BRNUP) {
15281559 if (asus->backlight_device != NULL) {
15291560 /* Update the backlight device. */
15301561 asus_backlight_notify(asus);
1562+ return ;
15311563 }
1532− return ;
15331564 }
15341565
15351566 /* Accelerometer "coarse orientation change" event */
drivers/platform/x86/asus-nb-wmi.c+62−14
@@ -59,6 +59,17 @@ static struct quirk_entry quirk_asus_unknown = { · 58 unmodified lines
5959 .wapf = 0,
6060 };
6161
62+/*
63+ * For those machines that need software to control bt/wifi status
64+ * and can't adjust brightness through ACPI interface
65+ * and have duplicate events(ACPI and WMI) for display toggle
66+ */
67+static struct quirk_entry quirk_asus_x55u = {
68+ .wapf = 4,
69+ .wmi_backlight_power = true,
70+ .no_display_toggle = true,
71+};
72+
6273 static struct quirk_entry quirk_asus_x401u = {
6374 .wapf = 4,
6475 };
@@ -77,6 +88,15 @@ static struct dmi_system_id asus_quirks[] = { · 12 unmodified lines
7788 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
7889 DMI_MATCH(DMI_PRODUCT_NAME, "X401U"),
7990 },
91+ .driver_data = &quirk_asus_x55u,
92+ },
93+ {
94+ .callback = dmi_matched,
95+ .ident = "ASUSTeK COMPUTER INC. X401A",
96+ .matches = {
97+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
98+ DMI_MATCH(DMI_PRODUCT_NAME, "X401A"),
99+ },
80100 .driver_data = &quirk_asus_x401u,
81101 },
82102 {
@@ -95,6 +115,15 @@ static struct dmi_system_id asus_quirks[] = { · 12 unmodified lines
95115 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
96116 DMI_MATCH(DMI_PRODUCT_NAME, "X501U"),
97117 },
118+ .driver_data = &quirk_asus_x55u,
119+ },
120+ {
121+ .callback = dmi_matched,
122+ .ident = "ASUSTeK COMPUTER INC. X501A",
123+ .matches = {
124+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
125+ DMI_MATCH(DMI_PRODUCT_NAME, "X501A"),
126+ },
98127 .driver_data = &quirk_asus_x401u,
99128 },
100129 {
@@ -131,7 +160,7 @@ static struct dmi_system_id asus_quirks[] = { · 30 unmodified lines
131160 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
132161 DMI_MATCH(DMI_PRODUCT_NAME, "X55U"),
133162 },
134− .driver_data = &quirk_asus_x401u,
163+ .driver_data = &quirk_asus_x55u,
135164 },
136165 {
137166 .callback = dmi_matched,
@@ -161,6 +190,8 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) · 23 unmodified lines
161190 }
162191
163192 static const struct key_entry asus_nb_wmi_keymap[] = {
193+ { KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } },
194+ { KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } },
164195 { KE_KEY, 0x30, { KEY_VOLUMEUP } },
165196 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
166197 { KE_KEY, 0x32, { KEY_MUTE } },
@@ -168,9 +199,9 @@ static const struct key_entry asus_nb_wmi_keymap[] = { · 1 unmodified line
168199 { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
169200 { KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
170201 { KE_KEY, 0x41, { KEY_NEXTSONG } },
171− { KE_KEY, 0x43, { KEY_STOPCD } },
202+ { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
172203 { KE_KEY, 0x45, { KEY_PLAYPAUSE } },
173− { KE_KEY, 0x4c, { KEY_MEDIA } },
204+ { KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */
174205 { KE_KEY, 0x50, { KEY_EMAIL } },
175206 { KE_KEY, 0x51, { KEY_WWW } },
176207 { KE_KEY, 0x55, { KEY_CALC } },
@@ -180,25 +211,42 @@ static const struct key_entry asus_nb_wmi_keymap[] = { · 3 unmodified lines
180211 { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
181212 { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
182213 { KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */
183− { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
184− { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
185− { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
186− { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
214+ { KE_KEY, 0x60, { KEY_TOUCHPAD_ON } },
215+ { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */
216+ { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */
217+ { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */
218+ { KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */
219+ { KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */
220+ { KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */
221+ { KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */
187222 { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
188− { KE_KEY, 0x7D, { KEY_BLUETOOTH } },
189− { KE_KEY, 0x7E, { KEY_BLUETOOTH } },
223+ { KE_IGNORE, 0x6E, }, /* Low Battery notification */
224+ { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
225+ { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
190226 { KE_KEY, 0x82, { KEY_CAMERA } },
191− { KE_KEY, 0x88, { KEY_RFKILL } },
192− { KE_KEY, 0x8A, { KEY_PROG1 } },
227+ { KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */
228+ { KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */
229+ { KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */
230+ { KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */
231+ { KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */
232+ { KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */
233+ { KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */
234+ { KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */
235+ { KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */
236+ { KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */
193237 { KE_KEY, 0x95, { KEY_MEDIA } },
194238 { KE_KEY, 0x99, { KEY_PHONE } },
195239 { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */
196240 { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */
197241 { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */
198242 { KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */
199− { KE_KEY, 0xb5, { KEY_CALC } },
200− { KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
201− { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
243+ { KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */
244+ { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
245+ { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
246+ { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
247+ { KE_KEY, 0xB5, { KEY_CALC } },
248+ { KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
249+ { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
202250 { KE_END, 0},
203251 };
204252
drivers/platform/x86/asus-wmi.c+102−6
@@ -187,6 +187,8 @@ struct asus_wmi { · 186 unmodified lines
187187 struct device *hwmon_device;
188188 struct platform_device *platform_device;
189189
190+ struct led_classdev wlan_led;
191+ int wlan_led_wk;
190192 struct led_classdev tpd_led;
191193 int tpd_led_wk;
192194 struct led_classdev kbd_led;
@@ -194,6 +196,7 @@ struct asus_wmi { · 1 unmodified line
194196 struct workqueue_struct *led_workqueue;
195197 struct work_struct tpd_led_work;
196198 struct work_struct kbd_led_work;
199+ struct work_struct wlan_led_work;
197200
198201 struct asus_rfkill wlan;
199202 struct asus_rfkill bluetooth;
@@ -456,12 +459,65 @@ static enum led_brightness kbd_led_get(struct led_classdev *led_cdev) · 256 unmodified lines
456459 return value;
457460 }
458461
462+static int wlan_led_unknown_state(struct asus_wmi *asus)
463+{
464+ u32 result;
465+
466+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result);
467+
468+ return result & ASUS_WMI_DSTS_UNKNOWN_BIT;
469+}
470+
471+static int wlan_led_presence(struct asus_wmi *asus)
472+{
473+ u32 result;
474+
475+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result);
476+
477+ return result & ASUS_WMI_DSTS_PRESENCE_BIT;
478+}
479+
480+static void wlan_led_update(struct work_struct *work)
481+{
482+ int ctrl_param;
483+ struct asus_wmi *asus;
484+
485+ asus = container_of(work, struct asus_wmi, wlan_led_work);
486+
487+ ctrl_param = asus->wlan_led_wk;
488+ asus_wmi_set_devstate(ASUS_WMI_DEVID_WIRELESS_LED, ctrl_param, NULL);
489+}
490+
491+static void wlan_led_set(struct led_classdev *led_cdev,
492+ enum led_brightness value)
493+{
494+ struct asus_wmi *asus;
495+
496+ asus = container_of(led_cdev, struct asus_wmi, wlan_led);
497+
498+ asus->wlan_led_wk = !!value;
499+ queue_work(asus->led_workqueue, &asus->wlan_led_work);
500+}
501+
502+static enum led_brightness wlan_led_get(struct led_classdev *led_cdev)
503+{
504+ struct asus_wmi *asus;
505+ u32 result;
506+
507+ asus = container_of(led_cdev, struct asus_wmi, wlan_led);
508+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result);
509+
510+ return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
511+}
512+
459513 static void asus_wmi_led_exit(struct asus_wmi *asus)
460514 {
461515 if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
462516 led_classdev_unregister(&asus->kbd_led);
463517 if (!IS_ERR_OR_NULL(asus->tpd_led.dev))
464518 led_classdev_unregister(&asus->tpd_led);
519+ if (!IS_ERR_OR_NULL(asus->wlan_led.dev))
520+ led_classdev_unregister(&asus->wlan_led);
465521 if (asus->led_workqueue)
466522 destroy_workqueue(asus->led_workqueue);
467523 }
@@ -498,6 +554,23 @@ static int asus_wmi_led_init(struct asus_wmi *asus) · 30 unmodified lines
498554
499555 rv = led_classdev_register(&asus->platform_device->dev,
500556 &asus->kbd_led);
557+ if (rv)
558+ goto error;
559+ }
560+
561+ if (wlan_led_presence(asus)) {
562+ INIT_WORK(&asus->wlan_led_work, wlan_led_update);
563+
564+ asus->wlan_led.name = "asus::wlan";
565+ asus->wlan_led.brightness_set = wlan_led_set;
566+ if (!wlan_led_unknown_state(asus))
567+ asus->wlan_led.brightness_get = wlan_led_get;
568+ asus->wlan_led.flags = LED_CORE_SUSPENDRESUME;
569+ asus->wlan_led.max_brightness = 1;
570+ asus->wlan_led.default_trigger = "asus-wlan";
571+
572+ rv = led_classdev_register(&asus->platform_device->dev,
573+ &asus->wlan_led);
501574 }
502575
503576 error:
@@ -813,6 +886,9 @@ static int asus_new_rfkill(struct asus_wmi *asus, · 309 unmodified lines
813886 if (!*rfkill)
814887 return -EINVAL;
815888
889+ if (dev_id == ASUS_WMI_DEVID_WLAN)
890+ rfkill_set_led_trigger_name(*rfkill, "asus-wlan");
891+
816892 rfkill_init_sw_state(*rfkill, !result);
817893 result = rfkill_register(*rfkill);
818894 if (result) {
@@ -1265,6 +1341,18 @@ static void asus_wmi_backlight_exit(struct asus_wmi *asus) · 446 unmodified lines
12651341 asus->backlight_device = NULL;
12661342 }
12671343
1344+static int is_display_toggle(int code)
1345+{
1346+ /* display toggle keys */
1347+ if ((code >= 0x61 && code <= 0x67) ||
1348+ (code >= 0x8c && code <= 0x93) ||
1349+ (code >= 0xa0 && code <= 0xa7) ||
1350+ (code >= 0xd0 && code <= 0xd5))
1351+ return 1;
1352+
1353+ return 0;
1354+}
1355+
12681356 static void asus_wmi_notify(u32 value, void *context)
12691357 {
12701358 struct asus_wmi *asus = context;
@@ -1298,16 +1386,24 @@ static void asus_wmi_notify(u32 value, void *context) · 27 unmodified lines
12981386 }
12991387
13001388 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
1301− code = NOTIFY_BRNUP_MIN;
1389+ code = ASUS_WMI_BRN_UP;
13021390 else if (code >= NOTIFY_BRNDOWN_MIN &&
13031391 code <= NOTIFY_BRNDOWN_MAX)
1304− code = NOTIFY_BRNDOWN_MIN;
1392+ code = ASUS_WMI_BRN_DOWN;
13051393
1306− if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
1307− if (!acpi_video_backlight_support())
1394+ if (code == ASUS_WMI_BRN_DOWN || code == ASUS_WMI_BRN_UP) {
1395+ if (!acpi_video_backlight_support()) {
13081396 asus_wmi_backlight_notify(asus, orig_code);
1309− } else if (!sparse_keymap_report_event(asus->inputdev, code,
1310− key_value, autorelease))
1397+ goto exit;
1398+ }
1399+ }
1400+
1401+ if (is_display_toggle(code) &&
1402+ asus->driver->quirks->no_display_toggle)
1403+ goto exit;
1404+
1405+ if (!sparse_keymap_report_event(asus->inputdev, code,
1406+ key_value, autorelease))
13111407 pr_info("Unknown key %x pressed\n", code);
13121408
13131409 exit:
drivers/platform/x86/asus-wmi.h+9−0
@@ -30,6 +30,8 @@ · 29 unmodified lines
3030 #include <linux/platform_device.h>
3131
3232 #define ASUS_WMI_KEY_IGNORE (-1)
33+#define ASUS_WMI_BRN_DOWN 0x20
34+#define ASUS_WMI_BRN_UP 0x2f
3335
3436 struct module;
3537 struct key_entry;
@@ -41,6 +43,13 @@ struct quirk_entry { · 5 unmodified lines
4143 bool store_backlight_power;
4244 bool wmi_backlight_power;
4345 int wapf;
46+ /*
47+ * For machines with AMD graphic chips, it will send out WMI event
48+ * and ACPI interrupt at the same time while hitting the hotkey.
49+ * To simplify the problem, we just have to ignore the WMI event,
50+ * and let the ACPI interrupt to send out the key event.
51+ */
52+ int no_display_toggle;
4453 };
4554
4655 struct asus_wmi_driver {
drivers/platform/x86/chromeos_laptop.c+371−0
@@ -0,0 +1,371 @@
1+/*
2+ * chromeos_laptop.c - Driver to instantiate Chromebook i2c/smbus devices.
3+ *
4+ * Author : Benson Leung <bleung@chromium.org>
5+ *
6+ * Copyright (C) 2012 Google, Inc.
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
11+ * (at your option) any later version.
12+ *
13+ * This program is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ * GNU General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU General Public License
19+ * along with this program; if not, write to the Free Software
20+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21+ *
22+ */
23+
24+#include <linux/dmi.h>
25+#include <linux/i2c.h>
26+#include <linux/module.h>
27+
28+#define ATMEL_TP_I2C_ADDR 0x4b
29+#define ATMEL_TP_I2C_BL_ADDR 0x25
30+#define ATMEL_TS_I2C_ADDR 0x4a
31+#define ATMEL_TS_I2C_BL_ADDR 0x26
32+#define CYAPA_TP_I2C_ADDR 0x67
33+#define ISL_ALS_I2C_ADDR 0x44
34+#define TAOS_ALS_I2C_ADDR 0x29
35+
36+static struct i2c_client *als;
37+static struct i2c_client *tp;
38+static struct i2c_client *ts;
39+
40+const char *i2c_adapter_names[] = {
41+ "SMBus I801 adapter",
42+ "i915 gmbus vga",
43+ "i915 gmbus panel",
44+};
45+
46+/* Keep this enum consistent with i2c_adapter_names */
47+enum i2c_adapter_type {
48+ I2C_ADAPTER_SMBUS = 0,
49+ I2C_ADAPTER_VGADDC,
50+ I2C_ADAPTER_PANEL,
51+};
52+
53+static struct i2c_board_info __initdata cyapa_device = {
54+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
55+ .flags = I2C_CLIENT_WAKE,
56+};
57+
58+static struct i2c_board_info __initdata isl_als_device = {
59+ I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
60+};
61+
62+static struct i2c_board_info __initdata tsl2583_als_device = {
63+ I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
64+};
65+
66+static struct i2c_board_info __initdata tsl2563_als_device = {
67+ I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
68+};
69+
70+static struct i2c_board_info __initdata atmel_224s_tp_device = {
71+ I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR),
72+ .platform_data = NULL,
73+ .flags = I2C_CLIENT_WAKE,
74+};
75+
76+static struct i2c_board_info __initdata atmel_1664s_device = {
77+ I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR),
78+ .platform_data = NULL,
79+ .flags = I2C_CLIENT_WAKE,
80+};
81+
82+static struct i2c_client __init *__add_probed_i2c_device(
83+ const char *name,
84+ int bus,
85+ struct i2c_board_info *info,
86+ const unsigned short *addrs)
87+{
88+ const struct dmi_device *dmi_dev;
89+ const struct dmi_dev_onboard *dev_data;
90+ struct i2c_adapter *adapter;
91+ struct i2c_client *client;
92+
93+ if (bus < 0)
94+ return NULL;
95+ /*
96+ * If a name is specified, look for irq platform information stashed
97+ * in DMI_DEV_TYPE_DEV_ONBOARD by the Chrome OS custom system firmware.
98+ */
99+ if (name) {
100+ dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, name, NULL);
101+ if (!dmi_dev) {
102+ pr_err("%s failed to dmi find device %s.\n",
103+ __func__,
104+ name);
105+ return NULL;
106+ }
107+ dev_data = (struct dmi_dev_onboard *)dmi_dev->device_data;
108+ if (!dev_data) {
109+ pr_err("%s failed to get data from dmi for %s.\n",
110+ __func__, name);
111+ return NULL;
112+ }
113+ info->irq = dev_data->instance;
114+ }
115+
116+ adapter = i2c_get_adapter(bus);
117+ if (!adapter) {
118+ pr_err("%s failed to get i2c adapter %d.\n", __func__, bus);
119+ return NULL;
120+ }
121+
122+ /* add the i2c device */
123+ client = i2c_new_probed_device(adapter, info, addrs, NULL);
124+ if (!client)
125+ pr_err("%s failed to register device %d-%02x\n",
126+ __func__, bus, info->addr);
127+ else
128+ pr_debug("%s added i2c device %d-%02x\n",
129+ __func__, bus, info->addr);
130+
131+ i2c_put_adapter(adapter);
132+ return client;
133+}
134+
135+static int __init __find_i2c_adap(struct device *dev, void *data)
136+{
137+ const char *name = data;
138+ static const char *prefix = "i2c-";
139+ struct i2c_adapter *adapter;
140+ if (strncmp(dev_name(dev), prefix, strlen(prefix)) != 0)
141+ return 0;
142+ adapter = to_i2c_adapter(dev);
143+ return (strncmp(adapter->name, name, strlen(name)) == 0);
144+}
145+
146+static int __init find_i2c_adapter_num(enum i2c_adapter_type type)
147+{
148+ struct device *dev = NULL;
149+ struct i2c_adapter *adapter;
150+ const char *name = i2c_adapter_names[type];
151+ /* find the adapter by name */
152+ dev = bus_find_device(&i2c_bus_type, NULL, (void *)name,
153+ __find_i2c_adap);
154+ if (!dev) {
155+ pr_err("%s: i2c adapter %s not found on system.\n", __func__,
156+ name);
157+ return -ENODEV;
158+ }
159+ adapter = to_i2c_adapter(dev);
160+ return adapter->nr;
161+}
162+
163+/*
164+ * Takes a list of addresses in addrs as such :
165+ * { addr1, ... , addrn, I2C_CLIENT_END };
166+ * add_probed_i2c_device will use i2c_new_probed_device
167+ * and probe for devices at all of the addresses listed.
168+ * Returns NULL if no devices found.
169+ * See Documentation/i2c/instantiating-devices for more information.
170+ */
171+static __init struct i2c_client *add_probed_i2c_device(
172+ const char *name,
173+ enum i2c_adapter_type type,
174+ struct i2c_board_info *info,
175+ const unsigned short *addrs)
176+{
177+ return __add_probed_i2c_device(name,
178+ find_i2c_adapter_num(type),
179+ info,
180+ addrs);
181+}
182+
183+/*
184+ * Probes for a device at a single address, the one provided by
185+ * info->addr.
186+ * Returns NULL if no device found.
187+ */
188+static __init struct i2c_client *add_i2c_device(const char *name,
189+ enum i2c_adapter_type type,
190+ struct i2c_board_info *info)
191+{
192+ const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };
193+ return __add_probed_i2c_device(name,
194+ find_i2c_adapter_num(type),
195+ info,
196+ addr_list);
197+}
198+
199+
200+static struct i2c_client __init *add_smbus_device(const char *name,
201+ struct i2c_board_info *info)
202+{
203+ return add_i2c_device(name, I2C_ADAPTER_SMBUS, info);
204+}
205+
206+static int __init setup_cyapa_smbus_tp(const struct dmi_system_id *id)
207+{
208+ /* add cyapa touchpad on smbus */
209+ tp = add_smbus_device("trackpad", &cyapa_device);
210+ return 0;
211+}
212+
213+static int __init setup_atmel_224s_tp(const struct dmi_system_id *id)
214+{
215+ const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR,
216+ ATMEL_TP_I2C_ADDR,
217+ I2C_CLIENT_END };
218+
219+ /* add atmel mxt touchpad on VGA DDC GMBus */
220+ tp = add_probed_i2c_device("trackpad", I2C_ADAPTER_VGADDC,
221+ &atmel_224s_tp_device, addr_list);
222+ return 0;
223+}
224+
225+static int __init setup_atmel_1664s_ts(const struct dmi_system_id *id)
226+{
227+ const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR,
228+ ATMEL_TS_I2C_ADDR,
229+ I2C_CLIENT_END };
230+
231+ /* add atmel mxt touch device on PANEL GMBus */
232+ ts = add_probed_i2c_device("touchscreen", I2C_ADAPTER_PANEL,
233+ &atmel_1664s_device, addr_list);
234+ return 0;
235+}
236+
237+
238+static int __init setup_isl29018_als(const struct dmi_system_id *id)
239+{
240+ /* add isl29018 light sensor */
241+ als = add_smbus_device("lightsensor", &isl_als_device);
242+ return 0;
243+}
244+
245+static int __init setup_isl29023_als(const struct dmi_system_id *id)
246+{
247+ /* add isl29023 light sensor on Panel GMBus */
248+ als = add_i2c_device("lightsensor", I2C_ADAPTER_PANEL,
249+ &isl_als_device);
250+ return 0;
251+}
252+
253+static int __init setup_tsl2583_als(const struct dmi_system_id *id)
254+{
255+ /* add tsl2583 light sensor on smbus */
256+ als = add_smbus_device(NULL, &tsl2583_als_device);
257+ return 0;
258+}
259+
260+static int __init setup_tsl2563_als(const struct dmi_system_id *id)
261+{
262+ /* add tsl2563 light sensor on smbus */
263+ als = add_smbus_device(NULL, &tsl2563_als_device);
264+ return 0;
265+}
266+
267+static struct dmi_system_id __initdata chromeos_laptop_dmi_table[] = {
268+ {
269+ .ident = "Samsung Series 5 550 - Touchpad",
270+ .matches = {
271+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
272+ DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
273+ },
274+ .callback = setup_cyapa_smbus_tp,
275+ },
276+ {
277+ .ident = "Chromebook Pixel - Touchscreen",
278+ .matches = {
279+ DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
280+ DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
281+ },
282+ .callback = setup_atmel_1664s_ts,
283+ },
284+ {
285+ .ident = "Chromebook Pixel - Touchpad",
286+ .matches = {
287+ DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
288+ DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
289+ },
290+ .callback = setup_atmel_224s_tp,
291+ },
292+ {
293+ .ident = "Samsung Series 5 550 - Light Sensor",
294+ .matches = {
295+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
296+ DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
297+ },
298+ .callback = setup_isl29018_als,
299+ },
300+ {
301+ .ident = "Chromebook Pixel - Light Sensor",
302+ .matches = {
303+ DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
304+ DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
305+ },
306+ .callback = setup_isl29023_als,
307+ },
308+ {
309+ .ident = "Acer C7 Chromebook - Touchpad",
310+ .matches = {
311+ DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
312+ },
313+ .callback = setup_cyapa_smbus_tp,
314+ },
315+ {
316+ .ident = "HP Pavilion 14 Chromebook - Touchpad",
317+ .matches = {
318+ DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
319+ },
320+ .callback = setup_cyapa_smbus_tp,
321+ },
322+ {
323+ .ident = "Samsung Series 5 - Light Sensor",
324+ .matches = {
325+ DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
326+ },
327+ .callback = setup_tsl2583_als,
328+ },
329+ {
330+ .ident = "Cr-48 - Light Sensor",
331+ .matches = {
332+ DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
333+ },
334+ .callback = setup_tsl2563_als,
335+ },
336+ {
337+ .ident = "Acer AC700 - Light Sensor",
338+ .matches = {
339+ DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
340+ },
341+ .callback = setup_tsl2563_als,
342+ },
343+ { }
344+};
345+MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
346+
347+static int __init chromeos_laptop_init(void)
348+{
349+ if (!dmi_check_system(chromeos_laptop_dmi_table)) {
350+ pr_debug("%s unsupported system.\n", __func__);
351+ return -ENODEV;
352+ }
353+ return 0;
354+}
355+
356+static void __exit chromeos_laptop_exit(void)
357+{
358+ if (als)
359+ i2c_unregister_device(als);
360+ if (tp)
361+ i2c_unregister_device(tp);
362+ if (ts)
363+ i2c_unregister_device(ts);
364+}
365+
366+module_init(chromeos_laptop_init);
367+module_exit(chromeos_laptop_exit);
368+
369+MODULE_DESCRIPTION("Chrome OS Laptop driver");
370+MODULE_AUTHOR("Benson Leung <bleung@chromium.org>");
371+MODULE_LICENSE("GPL");
drivers/platform/x86/eeepc-wmi.c+2−0
@@ -63,6 +63,8 @@ MODULE_PARM_DESC(hotplug_wireless, · 62 unmodified lines
6363 #define HOME_RELEASE 0xe5
6464
6565 static const struct key_entry eeepc_wmi_keymap[] = {
66+ { KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } },
67+ { KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } },
6668 /* Sleep already handled via generic ACPI code */
6769 { KE_KEY, 0x30, { KEY_VOLUMEUP } },
6870 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
drivers/platform/x86/hp-wmi.c+77−40
@@ -60,6 +60,7 @@ enum hp_wmi_radio { · 59 unmodified lines
6060 HPWMI_WIFI = 0,
6161 HPWMI_BLUETOOTH = 1,
6262 HPWMI_WWAN = 2,
63+ HPWMI_GPS = 3,
6364 };
6465
6566 enum hp_wmi_event_ids {
@@ -72,10 +73,6 @@ enum hp_wmi_event_ids { · 6 unmodified lines
7273 HPWMI_LOCK_SWITCH = 7,
7374 };
7475
75−static int hp_wmi_bios_setup(struct platform_device *device);
76−static int __exit hp_wmi_bios_remove(struct platform_device *device);
77−static int hp_wmi_resume_handler(struct device *device);
78−
7976 struct bios_args {
8077 u32 signature;
8178 u32 command;
@@ -137,6 +134,7 @@ static const struct key_entry hp_wmi_keymap[] = { · 55 unmodified lines
137134 { KE_KEY, 0x2142, { KEY_MEDIA } },
138135 { KE_KEY, 0x213b, { KEY_INFO } },
139136 { KE_KEY, 0x2169, { KEY_DIRECTION } },
137+ { KE_KEY, 0x216a, { KEY_SETUP } },
140138 { KE_KEY, 0x231b, { KEY_HELP } },
141139 { KE_END, 0 }
142140 };
@@ -147,6 +145,7 @@ static struct platform_device *hp_wmi_platform_dev; · 4 unmodified lines
147145 static struct rfkill *wifi_rfkill;
148146 static struct rfkill *bluetooth_rfkill;
149147 static struct rfkill *wwan_rfkill;
148+static struct rfkill *gps_rfkill;
150149
151150 struct rfkill2_device {
152151 u8 id;
@@ -157,21 +156,6 @@ struct rfkill2_device { · 4 unmodified lines
157156 static int rfkill2_count;
158157 static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
159158
160−static const struct dev_pm_ops hp_wmi_pm_ops = {
161− .resume = hp_wmi_resume_handler,
162− .restore = hp_wmi_resume_handler,
163−};
164−
165−static struct platform_driver hp_wmi_driver = {
166− .driver = {
167− .name = "hp-wmi",
168− .owner = THIS_MODULE,
169− .pm = &hp_wmi_pm_ops,
170− },
171− .probe = hp_wmi_bios_setup,
172− .remove = hp_wmi_bios_remove,
173−};
174−
175159 /*
176160 * hp_wmi_perform_query
177161 *
@@ -543,6 +527,10 @@ static void hp_wmi_notify(u32 value, void *context) · 365 unmodified lines
543527 rfkill_set_states(wwan_rfkill,
544528 hp_wmi_get_sw_state(HPWMI_WWAN),
545529 hp_wmi_get_hw_state(HPWMI_WWAN));
530+ if (gps_rfkill)
531+ rfkill_set_states(gps_rfkill,
532+ hp_wmi_get_sw_state(HPWMI_GPS),
533+ hp_wmi_get_hw_state(HPWMI_GPS));
546534 break;
547535 case HPWMI_CPU_BATTERY_THROTTLE:
548536 pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");
@@ -670,7 +658,7 @@ static int hp_wmi_rfkill_setup(struct platform_device *device) · 121 unmodified lines
670658 (void *) HPWMI_WWAN);
671659 if (!wwan_rfkill) {
672660 err = -ENOMEM;
673− goto register_bluetooth_error;
661+ goto register_gps_error;
674662 }
675663 rfkill_init_sw_state(wwan_rfkill,
676664 hp_wmi_get_sw_state(HPWMI_WWAN));
@@ -681,10 +669,33 @@ static int hp_wmi_rfkill_setup(struct platform_device *device) · 4 unmodified lines
681669 goto register_wwan_err;
682670 }
683671
672+ if (wireless & 0x8) {
673+ gps_rfkill = rfkill_alloc("hp-gps", &device->dev,
674+ RFKILL_TYPE_GPS,
675+ &hp_wmi_rfkill_ops,
676+ (void *) HPWMI_GPS);
677+ if (!gps_rfkill) {
678+ err = -ENOMEM;
679+ goto register_bluetooth_error;
680+ }
681+ rfkill_init_sw_state(gps_rfkill,
682+ hp_wmi_get_sw_state(HPWMI_GPS));
683+ rfkill_set_hw_state(bluetooth_rfkill,
684+ hp_wmi_get_hw_state(HPWMI_GPS));
685+ err = rfkill_register(gps_rfkill);
686+ if (err)
687+ goto register_gps_error;
688+ }
689+
684690 return 0;
685691 register_wwan_err:
686692 rfkill_destroy(wwan_rfkill);
687693 wwan_rfkill = NULL;
694+ if (gps_rfkill)
695+ rfkill_unregister(gps_rfkill);
696+register_gps_error:
697+ rfkill_destroy(gps_rfkill);
698+ gps_rfkill = NULL;
688699 if (bluetooth_rfkill)
689700 rfkill_unregister(bluetooth_rfkill);
690701 register_bluetooth_error:
@@ -729,6 +740,10 @@ static int hp_wmi_rfkill2_setup(struct platform_device *device) · 38 unmodified lines
729740 type = RFKILL_TYPE_WWAN;
730741 name = "hp-wwan";
731742 break;
743+ case HPWMI_GPS:
744+ type = RFKILL_TYPE_GPS;
745+ name = "hp-gps";
746+ break;
732747 default:
733748 pr_warn("unknown device type 0x%x\n",
734749 state.device[i].radio_type);
@@ -778,7 +793,7 @@ fail: · 43 unmodified lines
778793 return err;
779794 }
780795
781−static int hp_wmi_bios_setup(struct platform_device *device)
796+static int __init hp_wmi_bios_setup(struct platform_device *device)
782797 {
783798 int err;
784799
@@ -786,6 +801,7 @@ static int hp_wmi_bios_setup(struct platform_device *device) · 1 unmodified line
786801 wifi_rfkill = NULL;
787802 bluetooth_rfkill = NULL;
788803 wwan_rfkill = NULL;
804+ gps_rfkill = NULL;
789805 rfkill2_count = 0;
790806
791807 if (hp_wmi_rfkill_setup(device))
@@ -835,6 +851,10 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) · 43 unmodified lines
835851 rfkill_unregister(wwan_rfkill);
836852 rfkill_destroy(wwan_rfkill);
837853 }
854+ if (gps_rfkill) {
855+ rfkill_unregister(gps_rfkill);
856+ rfkill_destroy(gps_rfkill);
857+ }
838858
839859 return 0;
840860 }
@@ -870,51 +890,70 @@ static int hp_wmi_resume_handler(struct device *device) · 29 unmodified lines
870890 rfkill_set_states(wwan_rfkill,
871891 hp_wmi_get_sw_state(HPWMI_WWAN),
872892 hp_wmi_get_hw_state(HPWMI_WWAN));
893+ if (gps_rfkill)
894+ rfkill_set_states(gps_rfkill,
895+ hp_wmi_get_sw_state(HPWMI_GPS),
896+ hp_wmi_get_hw_state(HPWMI_GPS));
873897
874898 return 0;
875899 }
876900
901+static const struct dev_pm_ops hp_wmi_pm_ops = {
902+ .resume = hp_wmi_resume_handler,
903+ .restore = hp_wmi_resume_handler,
904+};
905+
906+static struct platform_driver hp_wmi_driver = {
907+ .driver = {
908+ .name = "hp-wmi",
909+ .owner = THIS_MODULE,
910+ .pm = &hp_wmi_pm_ops,
911+ },
912+ .remove = __exit_p(hp_wmi_bios_remove),
913+};
914+
877915 static int __init hp_wmi_init(void)
878916 {
879917 int err;
880918 int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
881919 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
882920
921+ if (!bios_capable && !event_capable)
922+ return -ENODEV;
923+
883924 if (event_capable) {
884925 err = hp_wmi_input_setup();
885926 if (err)
886927 return err;
928+
929+ //Enable magic for hotkeys that run on the SMBus
930+ ec_write(0xe6,0x6e);
887931 }
888932
889933 if (bios_capable) {
890− err = platform_driver_register(&hp_wmi_driver);
891− if (err)
892− goto err_driver_reg;
893− hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1);
894− if (!hp_wmi_platform_dev) {
895− err = -ENOMEM;
896− goto err_device_alloc;
934+ hp_wmi_platform_dev =
935+ platform_device_register_simple("hp-wmi", -1, NULL, 0);
936+ if (IS_ERR(hp_wmi_platform_dev)) {
937+ err = PTR_ERR(hp_wmi_platform_dev);
938+ goto err_destroy_input;
897939 }
898− err = platform_device_add(hp_wmi_platform_dev);
940+
941+ err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup);
899942 if (err)
900− goto err_device_add;
943+ goto err_unregister_device;
901944 }
902945
903− if (!bios_capable && !event_capable)
904− return -ENODEV;
905−
906946 return 0;
907947
908−err_device_add:
909− platform_device_put(hp_wmi_platform_dev);
910−err_device_alloc:
911− platform_driver_unregister(&hp_wmi_driver);
912−err_driver_reg:
948+err_unregister_device:
949+ platform_device_unregister(hp_wmi_platform_dev);
950+err_destroy_input:
913951 if (event_capable)
914952 hp_wmi_input_destroy();
915953
916954 return err;
917955 }
956+module_init(hp_wmi_init);
918957
919958 static void __exit hp_wmi_exit(void)
920959 {
@@ -926,6 +965,4 @@ static void __exit hp_wmi_exit(void) · 5 unmodified lines
926965 platform_driver_unregister(&hp_wmi_driver);
927966 }
928967 }
929−
930−module_init(hp_wmi_init);
931968 module_exit(hp_wmi_exit);
drivers/platform/x86/msi-laptop.c+283−91
@@ -82,8 +82,19 @@ · 81 unmodified lines
8282 #define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
8383 #define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
8484
85−#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4
85+#define MSI_STANDARD_EC_FUNCTIONS_ADDRESS 0xe4
86+/* Power LED is orange - Turbo mode */
87+#define MSI_STANDARD_EC_TURBO_MASK (1 << 1)
88+/* Power LED is green - ECO mode */
89+#define MSI_STANDARD_EC_ECO_MASK (1 << 3)
90+/* Touchpad is turned on */
8691 #define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
92+/* If this bit != bit 1, turbo mode can't be toggled */
93+#define MSI_STANDARD_EC_TURBO_COOLDOWN_MASK (1 << 7)
94+
95+#define MSI_STANDARD_EC_FAN_ADDRESS 0x33
96+/* If zero, fan rotates at maximal speed */
97+#define MSI_STANDARD_EC_AUTOFAN_MASK (1 << 0)
8798
8899 #ifdef CONFIG_PM_SLEEP
89100 static int msi_laptop_resume(struct device *device);
@@ -108,23 +119,38 @@ static const struct key_entry msi_laptop_keymap[] = { · 18 unmodified lines
108119
109120 static struct input_dev *msi_laptop_input_dev;
110121
111−static bool old_ec_model;
112122 static int wlan_s, bluetooth_s, threeg_s;
113123 static int threeg_exists;
114−
115−/* Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G,
116− * those netbook will load the SCM (windows app) to disable the original
117− * Wlan/Bluetooth control by BIOS when user press fn key, then control
118− * Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user
119− * cann't on/off 3G module on those 3G netbook.
120− * On Linux, msi-laptop driver will do the same thing to disable the
121− * original BIOS control, then might need use HAL or other userland
122− * application to do the software control that simulate with SCM.
123− * e.g. MSI N034 netbook
124− */
125−static bool load_scm_model;
126124 static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg;
127125
126+/* MSI laptop quirks */
127+struct quirk_entry {
128+ bool old_ec_model;
129+
130+ /* Some MSI 3G netbook only have one fn key to control
131+ * Wlan/Bluetooth/3G, those netbook will load the SCM (windows app) to
132+ * disable the original Wlan/Bluetooth control by BIOS when user press
133+ * fn key, then control Wlan/Bluetooth/3G by SCM (software control by
134+ * OS). Without SCM, user cann't on/off 3G module on those 3G netbook.
135+ * On Linux, msi-laptop driver will do the same thing to disable the
136+ * original BIOS control, then might need use HAL or other userland
137+ * application to do the software control that simulate with SCM.
138+ * e.g. MSI N034 netbook
139+ */
140+ bool load_scm_model;
141+
142+ /* Some MSI laptops need delay before reading from EC */
143+ bool ec_delay;
144+
145+ /* Some MSI Wind netbooks (e.g. MSI Wind U100) need loading SCM to get
146+ * some features working (e.g. ECO mode), but we cannot change
147+ * Wlan/Bluetooth state in software and we can only read its state.
148+ */
149+ bool ec_read_only;
150+};
151+
152+static struct quirk_entry *quirks;
153+
128154 /* Hardware access */
129155
130156 static int set_lcd_level(int level)
@@ -195,10 +221,13 @@ static ssize_t set_device_state(const char *buf, size_t count, u8 mask) · 64 unmodified lines
195221 if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1))
196222 return -EINVAL;
197223
224+ if (quirks->ec_read_only)
225+ return -EOPNOTSUPP;
226+
198227 /* read current device state */
199228 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
200229 if (result < 0)
201− return -EINVAL;
230+ return result;
202231
203232 if (!!(rdata & mask) != status) {
204233 /* reverse device bit */
@@ -209,7 +238,7 @@ static ssize_t set_device_state(const char *buf, size_t count, u8 mask) · 4 unmodified lines
209238
210239 result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata);
211240 if (result < 0)
212− return -EINVAL;
241+ return result;
213242 }
214243
215244 return count;
@@ -222,7 +251,7 @@ static int get_wireless_state(int *wlan, int *bluetooth) · 6 unmodified lines
222251
223252 result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
224253 if (result < 0)
225− return -1;
254+ return result;
226255
227256 if (wlan)
228257 *wlan = !!(rdata & 8);
@@ -240,7 +269,7 @@ static int get_wireless_state_ec_standard(void) · 11 unmodified lines
240269
241270 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
242271 if (result < 0)
243− return -1;
272+ return result;
244273
245274 wlan_s = !!(rdata & MSI_STANDARD_EC_WLAN_MASK);
246275
@@ -258,7 +287,7 @@ static int get_threeg_exists(void) · 11 unmodified lines
258287
259288 result = ec_read(MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS, &rdata);
260289 if (result < 0)
261− return -1;
290+ return result;
262291
263292 threeg_exists = !!(rdata & MSI_STANDARD_EC_3G_MASK);
264293
@@ -291,9 +320,9 @@ static ssize_t show_wlan(struct device *dev, · 26 unmodified lines
291320 struct device_attribute *attr, char *buf)
292321 {
293322
294− int ret, enabled;
323+ int ret, enabled = 0;
295324
296− if (old_ec_model) {
325+ if (quirks->old_ec_model) {
297326 ret = get_wireless_state(&enabled, NULL);
298327 } else {
299328 ret = get_wireless_state_ec_standard();
@@ -315,9 +344,9 @@ static ssize_t show_bluetooth(struct device *dev, · 15 unmodified lines
315344 struct device_attribute *attr, char *buf)
316345 {
317346
318− int ret, enabled;
347+ int ret, enabled = 0;
319348
320− if (old_ec_model) {
349+ if (quirks->old_ec_model) {
321350 ret = get_wireless_state(NULL, &enabled);
322351 } else {
323352 ret = get_wireless_state_ec_standard();
@@ -342,8 +371,8 @@ static ssize_t show_threeg(struct device *dev, · 18 unmodified lines
342371 int ret;
343372
344373 /* old msi ec not support 3G */
345− if (old_ec_model)
346− return -1;
374+ if (quirks->old_ec_model)
375+ return -ENODEV;
347376
348377 ret = get_wireless_state_ec_standard();
349378 if (ret < 0)
@@ -417,18 +446,119 @@ static ssize_t store_auto_brightness(struct device *dev, · 67 unmodified lines
417446 return count;
418447 }
419448
449+static ssize_t show_touchpad(struct device *dev,
450+ struct device_attribute *attr, char *buf)
451+{
452+
453+ u8 rdata;
454+ int result;
455+
456+ result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
457+ if (result < 0)
458+ return result;
459+
460+ return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TOUCHPAD_MASK));
461+}
462+
463+static ssize_t show_turbo(struct device *dev,
464+ struct device_attribute *attr, char *buf)
465+{
466+
467+ u8 rdata;
468+ int result;
469+
470+ result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
471+ if (result < 0)
472+ return result;
473+
474+ return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TURBO_MASK));
475+}
476+
477+static ssize_t show_eco(struct device *dev,
478+ struct device_attribute *attr, char *buf)
479+{
480+
481+ u8 rdata;
482+ int result;
483+
484+ result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
485+ if (result < 0)
486+ return result;
487+
488+ return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_ECO_MASK));
489+}
490+
491+static ssize_t show_turbo_cooldown(struct device *dev,
492+ struct device_attribute *attr, char *buf)
493+{
494+
495+ u8 rdata;
496+ int result;
497+
498+ result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
499+ if (result < 0)
500+ return result;
501+
502+ return sprintf(buf, "%i\n", (!!(rdata & MSI_STANDARD_EC_TURBO_MASK)) |
503+ (!!(rdata & MSI_STANDARD_EC_TURBO_COOLDOWN_MASK) << 1));
504+}
505+
506+static ssize_t show_auto_fan(struct device *dev,
507+ struct device_attribute *attr, char *buf)
508+{
509+
510+ u8 rdata;
511+ int result;
512+
513+ result = ec_read(MSI_STANDARD_EC_FAN_ADDRESS, &rdata);
514+ if (result < 0)
515+ return result;
516+
517+ return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_AUTOFAN_MASK));
518+}
519+
520+static ssize_t store_auto_fan(struct device *dev,
521+ struct device_attribute *attr, const char *buf, size_t count)
522+{
523+
524+ int enable, result;
525+
526+ if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
527+ return -EINVAL;
528+
529+ result = ec_write(MSI_STANDARD_EC_FAN_ADDRESS, enable);
530+ if (result < 0)
531+ return result;
532+
533+ return count;
534+}
535+
420536 static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
421537 static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness,
422538 store_auto_brightness);
423539 static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
424540 static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
425541 static DEVICE_ATTR(threeg, 0444, show_threeg, NULL);
542+static DEVICE_ATTR(touchpad, 0444, show_touchpad, NULL);
543+static DEVICE_ATTR(turbo_mode, 0444, show_turbo, NULL);
544+static DEVICE_ATTR(eco_mode, 0444, show_eco, NULL);
545+static DEVICE_ATTR(turbo_cooldown, 0444, show_turbo_cooldown, NULL);
546+static DEVICE_ATTR(auto_fan, 0644, show_auto_fan, store_auto_fan);
426547
427548 static struct attribute *msipf_attributes[] = {
428− &dev_attr_lcd_level.attr,
429− &dev_attr_auto_brightness.attr,
430549 &dev_attr_bluetooth.attr,
431550 &dev_attr_wlan.attr,
551+ &dev_attr_touchpad.attr,
552+ &dev_attr_turbo_mode.attr,
553+ &dev_attr_eco_mode.attr,
554+ &dev_attr_turbo_cooldown.attr,
555+ &dev_attr_auto_fan.attr,
556+ NULL
557+};
558+
559+static struct attribute *msipf_old_attributes[] = {
560+ &dev_attr_lcd_level.attr,
561+ &dev_attr_auto_brightness.attr,
432562 NULL
433563 };
434564
@@ -436,6 +566,10 @@ static struct attribute_group msipf_attribute_group = { · 1 unmodified line
436566 .attrs = msipf_attributes
437567 };
438568
569+static struct attribute_group msipf_old_attribute_group = {
570+ .attrs = msipf_old_attributes
571+};
572+
439573 static struct platform_driver msipf_driver = {
440574 .driver = {
441575 .name = "msi-laptop-pf",
@@ -448,9 +582,26 @@ static struct platform_device *msipf_device; · 6 unmodified lines
448582
449583 /* Initialization */
450584
451−static int dmi_check_cb(const struct dmi_system_id *id)
585+static struct quirk_entry quirk_old_ec_model = {
586+ .old_ec_model = true,
587+};
588+
589+static struct quirk_entry quirk_load_scm_model = {
590+ .load_scm_model = true,
591+ .ec_delay = true,
592+};
593+
594+static struct quirk_entry quirk_load_scm_ro_model = {
595+ .load_scm_model = true,
596+ .ec_read_only = true,
597+};
598+
599+static int dmi_check_cb(const struct dmi_system_id *dmi)
452600 {
453− pr_info("Identified laptop model '%s'\n", id->ident);
601+ pr_info("Identified laptop model '%s'\n", dmi->ident);
602+
603+ quirks = dmi->driver_data;
604+
454605 return 1;
455606 }
456607
@@ -464,6 +615,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = { · 7 unmodified lines
464615 DMI_MATCH(DMI_CHASSIS_VENDOR,
465616 "MICRO-STAR INT'L CO.,LTD")
466617 },
618+ .driver_data = &quirk_old_ec_model,
467619 .callback = dmi_check_cb
468620 },
469621 {
@@ -474,6 +626,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = { · 4 unmodified lines
474626 DMI_MATCH(DMI_PRODUCT_VERSION, "0581"),
475627 DMI_MATCH(DMI_BOARD_NAME, "MS-1058")
476628 },
629+ .driver_data = &quirk_old_ec_model,
477630 .callback = dmi_check_cb
478631 },
479632 {
@@ -484,6 +637,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = { · 4 unmodified lines
484637 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
485638 DMI_MATCH(DMI_BOARD_NAME, "MS-1412")
486639 },
640+ .driver_data = &quirk_old_ec_model,
487641 .callback = dmi_check_cb
488642 },
489643 {
@@ -495,12 +649,9 @@ static struct dmi_system_id __initdata msi_dmi_table[] = { · 5 unmodified lines
495649 DMI_MATCH(DMI_CHASSIS_VENDOR,
496650 "MICRO-STAR INT'L CO.,LTD")
497651 },
652+ .driver_data = &quirk_old_ec_model,
498653 .callback = dmi_check_cb
499654 },
500− { }
501−};
502−
503−static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
504655 {
505656 .ident = "MSI N034",
506657 .matches = {
@@ -510,6 +661,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { · 3 unmodified lines
510661 DMI_MATCH(DMI_CHASSIS_VENDOR,
511662 "MICRO-STAR INTERNATIONAL CO., LTD")
512663 },
664+ .driver_data = &quirk_load_scm_model,
513665 .callback = dmi_check_cb
514666 },
515667 {
@@ -521,6 +673,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { · 5 unmodified lines
521673 DMI_MATCH(DMI_CHASSIS_VENDOR,
522674 "MICRO-STAR INTERNATIONAL CO., LTD")
523675 },
676+ .driver_data = &quirk_load_scm_model,
524677 .callback = dmi_check_cb
525678 },
526679 {
@@ -530,6 +683,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { · 3 unmodified lines
530683 "MICRO-STAR INTERNATIONAL CO., LTD"),
531684 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"),
532685 },
686+ .driver_data = &quirk_load_scm_model,
533687 .callback = dmi_check_cb
534688 },
535689 {
@@ -539,6 +693,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { · 3 unmodified lines
539693 "Micro-Star International"),
540694 DMI_MATCH(DMI_PRODUCT_NAME, "CR620"),
541695 },
696+ .driver_data = &quirk_load_scm_model,
542697 .callback = dmi_check_cb
543698 },
544699 {
@@ -548,6 +703,17 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { · 3 unmodified lines
548703 "Micro-Star International Co., Ltd."),
549704 DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"),
550705 },
706+ .driver_data = &quirk_load_scm_model,
707+ .callback = dmi_check_cb
708+ },
709+ {
710+ .ident = "MSI U90/U100",
711+ .matches = {
712+ DMI_MATCH(DMI_SYS_VENDOR,
713+ "MICRO-STAR INTERNATIONAL CO., LTD"),
714+ DMI_MATCH(DMI_PRODUCT_NAME, "U90/U100"),
715+ },
716+ .driver_data = &quirk_load_scm_ro_model,
551717 .callback = dmi_check_cb
552718 },
553719 { }
@@ -560,32 +726,26 @@ static int rfkill_bluetooth_set(void *data, bool blocked) · 6 unmodified lines
560726 * blocked == false is on
561727 * blocked == true is off
562728 */
563− if (blocked)
564− set_device_state("0", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
565− else
566− set_device_state("1", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
729+ int result = set_device_state(blocked ? "0" : "1", 0,
730+ MSI_STANDARD_EC_BLUETOOTH_MASK);
567731
568− return 0;
732+ return min(result, 0);
569733 }
570734
571735 static int rfkill_wlan_set(void *data, bool blocked)
572736 {
573− if (blocked)
574− set_device_state("0", 0, MSI_STANDARD_EC_WLAN_MASK);
575− else
576− set_device_state("1", 0, MSI_STANDARD_EC_WLAN_MASK);
737+ int result = set_device_state(blocked ? "0" : "1", 0,
738+ MSI_STANDARD_EC_WLAN_MASK);
577739
578− return 0;
740+ return min(result, 0);
579741 }
580742
581743 static int rfkill_threeg_set(void *data, bool blocked)
582744 {
583− if (blocked)
584− set_device_state("0", 0, MSI_STANDARD_EC_3G_MASK);
585− else
586− set_device_state("1", 0, MSI_STANDARD_EC_3G_MASK);
745+ int result = set_device_state(blocked ? "0" : "1", 0,
746+ MSI_STANDARD_EC_3G_MASK);
587747
588− return 0;
748+ return min(result, 0);
589749 }
590750
591751 static const struct rfkill_ops rfkill_bluetooth_ops = {
@@ -618,25 +778,34 @@ static void rfkill_cleanup(void) · 26 unmodified lines
618778 }
619779 }
620780
781+static bool msi_rfkill_set_state(struct rfkill *rfkill, bool blocked)
782+{
783+ if (quirks->ec_read_only)
784+ return rfkill_set_hw_state(rfkill, blocked);
785+ else
786+ return rfkill_set_sw_state(rfkill, blocked);
787+}
788+
621789 static void msi_update_rfkill(struct work_struct *ignored)
622790 {
623791 get_wireless_state_ec_standard();
624792
625793 if (rfk_wlan)
626− rfkill_set_sw_state(rfk_wlan, !wlan_s);
794+ msi_rfkill_set_state(rfk_wlan, !wlan_s);
627795 if (rfk_bluetooth)
628− rfkill_set_sw_state(rfk_bluetooth, !bluetooth_s);
796+ msi_rfkill_set_state(rfk_bluetooth, !bluetooth_s);
629797 if (rfk_threeg)
630− rfkill_set_sw_state(rfk_threeg, !threeg_s);
798+ msi_rfkill_set_state(rfk_threeg, !threeg_s);
631799 }
632−static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill);
800+static DECLARE_DELAYED_WORK(msi_rfkill_dwork, msi_update_rfkill);
801+static DECLARE_WORK(msi_rfkill_work, msi_update_rfkill);
633802
634803 static void msi_send_touchpad_key(struct work_struct *ignored)
635804 {
636805 u8 rdata;
637806 int result;
638807
639− result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata);
808+ result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
640809 if (result < 0)
641810 return;
642811
@@ -644,7 +813,8 @@ static void msi_send_touchpad_key(struct work_struct *ignored) · 1 unmodified line
644813 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
645814 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
646815 }
647−static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key);
816+static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key);
817+static DECLARE_WORK(msi_touchpad_work, msi_send_touchpad_key);
648818
649819 static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
650820 struct serio *port)
@@ -662,14 +832,20 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, · 11 unmodified lines
662832 extended = false;
663833 switch (data) {
664834 case 0xE4:
665− schedule_delayed_work(&msi_touchpad_work,
666− round_jiffies_relative(0.5 * HZ));
835+ if (quirks->ec_delay) {
836+ schedule_delayed_work(&msi_touchpad_dwork,
837+ round_jiffies_relative(0.5 * HZ));
838+ } else
839+ schedule_work(&msi_touchpad_work);
667840 break;
668841 case 0x54:
669842 case 0x62:
670843 case 0x76:
671− schedule_delayed_work(&msi_rfkill_work,
672− round_jiffies_relative(0.5 * HZ));
844+ if (quirks->ec_delay) {
845+ schedule_delayed_work(&msi_rfkill_dwork,
846+ round_jiffies_relative(0.5 * HZ));
847+ } else
848+ schedule_work(&msi_rfkill_work);
673849 break;
674850 }
675851 }
@@ -736,8 +912,11 @@ static int rfkill_init(struct platform_device *sdev) · 60 unmodified lines
736912 }
737913
738914 /* schedule to run rfkill state initial */
739− schedule_delayed_work(&msi_rfkill_init,
740− round_jiffies_relative(1 * HZ));
915+ if (quirks->ec_delay) {
916+ schedule_delayed_work(&msi_rfkill_init,
917+ round_jiffies_relative(1 * HZ));
918+ } else
919+ schedule_work(&msi_rfkill_work);
741920
742921 return 0;
743922
@@ -761,7 +940,7 @@ static int msi_laptop_resume(struct device *device) · 17 unmodified lines
761940 u8 data;
762941 int result;
763942
764− if (!load_scm_model)
943+ if (!quirks->load_scm_model)
765944 return 0;
766945
767946 /* set load SCM to disable hardware control by fn key */
@@ -819,13 +998,15 @@ static int __init load_scm_model_init(struct platform_device *sdev) · 51 unmodified lines
819998 u8 data;
820999 int result;
8211000
822− /* allow userland write sysfs file */
823− dev_attr_bluetooth.store = store_bluetooth;
824− dev_attr_wlan.store = store_wlan;
825− dev_attr_threeg.store = store_threeg;
826− dev_attr_bluetooth.attr.mode |= S_IWUSR;
827− dev_attr_wlan.attr.mode |= S_IWUSR;
828− dev_attr_threeg.attr.mode |= S_IWUSR;
1001+ if (!quirks->ec_read_only) {
1002+ /* allow userland write sysfs file */
1003+ dev_attr_bluetooth.store = store_bluetooth;
1004+ dev_attr_wlan.store = store_wlan;
1005+ dev_attr_threeg.store = store_threeg;
1006+ dev_attr_bluetooth.attr.mode |= S_IWUSR;
1007+ dev_attr_wlan.attr.mode |= S_IWUSR;
1008+ dev_attr_threeg.attr.mode |= S_IWUSR;
1009+ }
8291010
8301011 /* disable hardware control by fn key */
8311012 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
@@ -874,21 +1055,22 @@ static int __init msi_init(void) · 42 unmodified lines
8741055 if (acpi_disabled)
8751056 return -ENODEV;
8761057
877− if (force || dmi_check_system(msi_dmi_table))
878− old_ec_model = 1;
1058+ dmi_check_system(msi_dmi_table);
1059+ if (!quirks)
1060+ /* quirks may be NULL if no match in DMI table */
1061+ quirks = &quirk_load_scm_model;
1062+ if (force)
1063+ quirks = &quirk_old_ec_model;
8791064
880− if (!old_ec_model)
1065+ if (!quirks->old_ec_model)
8811066 get_threeg_exists();
8821067
883− if (!old_ec_model && dmi_check_system(msi_load_scm_models_dmi_table))
884− load_scm_model = 1;
885−
8861068 if (auto_brightness < 0 || auto_brightness > 2)
8871069 return -EINVAL;
8881070
8891071 /* Register backlight stuff */
8901072
891− if (acpi_video_backlight_support()) {
1073+ if (!quirks->old_ec_model || acpi_video_backlight_support()) {
8921074 pr_info("Brightness ignored, must be controlled by ACPI video driver\n");
8931075 } else {
8941076 struct backlight_properties props;
@@ -918,7 +1100,7 @@ static int __init msi_init(void) · 23 unmodified lines
9181100 if (ret)
9191101 goto fail_platform_device1;
9201102
921− if (load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
1103+ if (quirks->load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
9221104 ret = -EINVAL;
9231105 goto fail_platform_device1;
9241106 }
@@ -928,20 +1110,25 @@ static int __init msi_init(void) · 3 unmodified lines
9281110 if (ret)
9291111 goto fail_platform_device2;
9301112
931− if (!old_ec_model) {
1113+ if (!quirks->old_ec_model) {
9321114 if (threeg_exists)
9331115 ret = device_create_file(&msipf_device->dev,
9341116 &dev_attr_threeg);
9351117 if (ret)
9361118 goto fail_platform_device2;
937− }
1119+ } else {
1120+ ret = sysfs_create_group(&msipf_device->dev.kobj,
1121+ &msipf_old_attribute_group);
1122+ if (ret)
1123+ goto fail_platform_device2;
9381124
939− /* Disable automatic brightness control by default because
940− * this module was probably loaded to do brightness control in
941− * software. */
1125+ /* Disable automatic brightness control by default because
1126+ * this module was probably loaded to do brightness control in
1127+ * software. */
9421128
943− if (auto_brightness != 2)
944− set_auto_brightness(auto_brightness);
1129+ if (auto_brightness != 2)
1130+ set_auto_brightness(auto_brightness);
1131+ }
9451132
9461133 pr_info("driver " MSI_DRIVER_VERSION " successfully loaded\n");
9471134
@@ -949,9 +1136,10 @@ static int __init msi_init(void) · 1 unmodified line
9491136
9501137 fail_platform_device2:
9511138
952− if (load_scm_model) {
1139+ if (quirks->load_scm_model) {
9531140 i8042_remove_filter(msi_laptop_i8042_filter);
954− cancel_delayed_work_sync(&msi_rfkill_work);
1141+ cancel_delayed_work_sync(&msi_rfkill_dwork);
1142+ cancel_work_sync(&msi_rfkill_work);
9551143 rfkill_cleanup();
9561144 }
9571145 platform_device_del(msipf_device);
@@ -973,23 +1161,26 @@ fail_backlight: · 15 unmodified lines
9731161
9741162 static void __exit msi_cleanup(void)
9751163 {
976− if (load_scm_model) {
1164+ if (quirks->load_scm_model) {
9771165 i8042_remove_filter(msi_laptop_i8042_filter);
9781166 msi_laptop_input_destroy();
979− cancel_delayed_work_sync(&msi_rfkill_work);
1167+ cancel_delayed_work_sync(&msi_rfkill_dwork);
1168+ cancel_work_sync(&msi_rfkill_work);
9801169 rfkill_cleanup();
9811170 }
9821171
9831172 sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
984− if (!old_ec_model && threeg_exists)
1173+ if (!quirks->old_ec_model && threeg_exists)
9851174 device_remove_file(&msipf_device->dev, &dev_attr_threeg);
9861175 platform_device_unregister(msipf_device);
9871176 platform_driver_unregister(&msipf_driver);
9881177 backlight_device_unregister(msibl_device);
9891178
990− /* Enable automatic brightness control again */
991− if (auto_brightness != 2)
992− set_auto_brightness(1);
1179+ if (quirks->old_ec_model) {
1180+ /* Enable automatic brightness control again */
1181+ if (auto_brightness != 2)
1182+ set_auto_brightness(1);
1183+ }
9931184
9941185 pr_info("driver unloaded\n");
9951186 }
@@ -1011,3 +1202,4 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*"); · 15 unmodified lines
10111202 MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*");
10121203 MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*");
10131204 MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*");
1205+MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnU90/U100:*");
drivers/platform/x86/msi-wmi.c+146−78
@@ -34,29 +34,65 @@ MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>"); · 33 unmodified lines
3434 MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver");
3535 MODULE_LICENSE("GPL");
3636
37−MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45");
38−MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2");
39−
4037 #define DRV_NAME "msi-wmi"
4138
4239 #define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45"
43−#define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"
44−
45−#define SCANCODE_BASE 0xD0
46−#define MSI_WMI_BRIGHTNESSUP SCANCODE_BASE
47−#define MSI_WMI_BRIGHTNESSDOWN (SCANCODE_BASE + 1)
48−#define MSI_WMI_VOLUMEUP (SCANCODE_BASE + 2)
49−#define MSI_WMI_VOLUMEDOWN (SCANCODE_BASE + 3)
50−#define MSI_WMI_MUTE (SCANCODE_BASE + 4)
40+#define MSIWMI_MSI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"
41+#define MSIWMI_WIND_EVENT_GUID "5B3CC38A-40D9-7245-8AE6-1145B751BE3F"
42+
43+MODULE_ALIAS("wmi:" MSIWMI_BIOS_GUID);
44+MODULE_ALIAS("wmi:" MSIWMI_MSI_EVENT_GUID);
45+MODULE_ALIAS("wmi:" MSIWMI_WIND_EVENT_GUID);
46+
47+enum msi_scancodes {
48+ /* Generic MSI keys (not present on MSI Wind) */
49+ MSI_KEY_BRIGHTNESSUP = 0xD0,
50+ MSI_KEY_BRIGHTNESSDOWN,
51+ MSI_KEY_VOLUMEUP,
52+ MSI_KEY_VOLUMEDOWN,
53+ MSI_KEY_MUTE,
54+ /* MSI Wind keys */
55+ WIND_KEY_TOUCHPAD = 0x08, /* Fn+F3 touchpad toggle */
56+ WIND_KEY_BLUETOOTH = 0x56, /* Fn+F11 Bluetooth toggle */
57+ WIND_KEY_CAMERA, /* Fn+F6 webcam toggle */
58+ WIND_KEY_WLAN = 0x5f, /* Fn+F11 Wi-Fi toggle */
59+ WIND_KEY_TURBO, /* Fn+F10 turbo mode toggle */
60+ WIND_KEY_ECO = 0x69, /* Fn+F10 ECO mode toggle */
61+};
5162 static struct key_entry msi_wmi_keymap[] = {
52− { KE_KEY, MSI_WMI_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} },
53− { KE_KEY, MSI_WMI_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} },
54− { KE_KEY, MSI_WMI_VOLUMEUP, {KEY_VOLUMEUP} },
55− { KE_KEY, MSI_WMI_VOLUMEDOWN, {KEY_VOLUMEDOWN} },
56− { KE_KEY, MSI_WMI_MUTE, {KEY_MUTE} },
57− { KE_END, 0}
63+ { KE_KEY, MSI_KEY_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} },
64+ { KE_KEY, MSI_KEY_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} },
65+ { KE_KEY, MSI_KEY_VOLUMEUP, {KEY_VOLUMEUP} },
66+ { KE_KEY, MSI_KEY_VOLUMEDOWN, {KEY_VOLUMEDOWN} },
67+ { KE_KEY, MSI_KEY_MUTE, {KEY_MUTE} },
68+
69+ /* These keys work without WMI. Ignore them to avoid double keycodes */
70+ { KE_IGNORE, WIND_KEY_TOUCHPAD, {KEY_TOUCHPAD_TOGGLE} },
71+ { KE_IGNORE, WIND_KEY_BLUETOOTH, {KEY_BLUETOOTH} },
72+ { KE_IGNORE, WIND_KEY_CAMERA, {KEY_CAMERA} },
73+ { KE_IGNORE, WIND_KEY_WLAN, {KEY_WLAN} },
74+
75+ /* These are unknown WMI events found on MSI Wind */
76+ { KE_IGNORE, 0x00 },
77+ { KE_IGNORE, 0x62 },
78+ { KE_IGNORE, 0x63 },
79+
80+ /* These are MSI Wind keys that should be handled via WMI */
81+ { KE_KEY, WIND_KEY_TURBO, {KEY_PROG1} },
82+ { KE_KEY, WIND_KEY_ECO, {KEY_PROG2} },
83+
84+ { KE_END, 0 }
85+};
86+
87+static ktime_t last_pressed;
88+
89+static const struct {
90+ const char *guid;
91+ bool quirk_last_pressed;
92+} *event_wmi, event_wmis[] = {
93+ { MSIWMI_MSI_EVENT_GUID, true },
94+ { MSIWMI_WIND_EVENT_GUID, false },
5895 };
59−static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1];
6096
6197 static struct backlight_device *backlight;
6298
@@ -149,7 +185,6 @@ static void msi_wmi_notify(u32 value, void *context) · 86 unmodified lines
149185 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
150186 static struct key_entry *key;
151187 union acpi_object *obj;
152− ktime_t cur;
153188 acpi_status status;
154189
155190 status = wmi_get_event_data(value, &response);
@@ -165,39 +200,67 @@ static void msi_wmi_notify(u32 value, void *context) · 9 unmodified lines
165200 pr_debug("Eventcode: 0x%x\n", eventcode);
166201 key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev,
167202 eventcode);
168− if (key) {
169− ktime_t diff;
170− cur = ktime_get_real();
171− diff = ktime_sub(cur, last_pressed[key->code -
172− SCANCODE_BASE]);
173− /* Ignore event if the same event happened in a 50 ms
203+ if (!key) {
204+ pr_info("Unknown key pressed - %x\n", eventcode);
205+ goto msi_wmi_notify_exit;
206+ }
207+
208+ if (event_wmi->quirk_last_pressed) {
209+ ktime_t cur = ktime_get_real();
210+ ktime_t diff = ktime_sub(cur, last_pressed);
211+ /* Ignore event if any event happened in a 50 ms
174212 timeframe -> Key press may result in 10-20 GPEs */
175213 if (ktime_to_us(diff) < 1000 * 50) {
176214 pr_debug("Suppressed key event 0x%X - "
177215 "Last press was %lld us ago\n",
178216 key->code, ktime_to_us(diff));
179− return;
180− }
181− last_pressed[key->code - SCANCODE_BASE] = cur;
182−
183− if (key->type == KE_KEY &&
184− /* Brightness is served via acpi video driver */
185− (!acpi_video_backlight_support() ||
186− (key->code != MSI_WMI_BRIGHTNESSUP &&
187− key->code != MSI_WMI_BRIGHTNESSDOWN))) {
188− pr_debug("Send key: 0x%X - "
189− "Input layer keycode: %d\n",
190− key->code, key->keycode);
191− sparse_keymap_report_entry(msi_wmi_input_dev,
192− key, 1, true);
217+ goto msi_wmi_notify_exit;
193218 }
194− } else
195− pr_info("Unknown key pressed - %x\n", eventcode);
219+ last_pressed = cur;
220+ }
221+
222+ if (key->type == KE_KEY &&
223+ /* Brightness is served via acpi video driver */
224+ (backlight ||
225+ (key->code != MSI_KEY_BRIGHTNESSUP &&
226+ key->code != MSI_KEY_BRIGHTNESSDOWN))) {
227+ pr_debug("Send key: 0x%X - Input layer keycode: %d\n",
228+ key->code, key->keycode);
229+ sparse_keymap_report_entry(msi_wmi_input_dev, key, 1,
230+ true);
231+ }
196232 } else
197233 pr_info("Unknown event received\n");
234+
235+msi_wmi_notify_exit:
198236 kfree(response.pointer);
199237 }
200238
239+static int __init msi_wmi_backlight_setup(void)
240+{
241+ int err;
242+ struct backlight_properties props;
243+
244+ memset(&props, 0, sizeof(struct backlight_properties));
245+ props.type = BACKLIGHT_PLATFORM;
246+ props.max_brightness = ARRAY_SIZE(backlight_map) - 1;
247+ backlight = backlight_device_register(DRV_NAME, NULL, NULL,
248+ &msi_backlight_ops,
249+ &props);
250+ if (IS_ERR(backlight))
251+ return PTR_ERR(backlight);
252+
253+ err = bl_get(NULL);
254+ if (err < 0) {
255+ backlight_device_unregister(backlight);
256+ return err;
257+ }
258+
259+ backlight->props.brightness = err;
260+
261+ return 0;
262+}
263+
201264 static int __init msi_wmi_input_setup(void)
202265 {
203266 int err;
@@ -219,7 +282,7 @@ static int __init msi_wmi_input_setup(void) · 15 unmodified lines
219282 if (err)
220283 goto err_free_keymap;
221284
222− memset(last_pressed, 0, sizeof(last_pressed));
285+ last_pressed = ktime_set(0, 0);
223286
224287 return 0;
225288
@@ -233,61 +296,66 @@ err_free_dev: · 7 unmodified lines
233296 static int __init msi_wmi_init(void)
234297 {
235298 int err;
299+ int i;
236300
237− if (!wmi_has_guid(MSIWMI_EVENT_GUID)) {
238− pr_err("This machine doesn't have MSI-hotkeys through WMI\n");
239− return -ENODEV;
240− }
241− err = wmi_install_notify_handler(MSIWMI_EVENT_GUID,
242− msi_wmi_notify, NULL);
243− if (ACPI_FAILURE(err))
244− return -EINVAL;
301+ for (i = 0; i < ARRAY_SIZE(event_wmis); i++) {
302+ if (!wmi_has_guid(event_wmis[i].guid))
303+ continue;
245304
246− err = msi_wmi_input_setup();
247− if (err)
248− goto err_uninstall_notifier;
249−
250− if (!acpi_video_backlight_support()) {
251− struct backlight_properties props;
252− memset(&props, 0, sizeof(struct backlight_properties));
253− props.type = BACKLIGHT_PLATFORM;
254− props.max_brightness = ARRAY_SIZE(backlight_map) - 1;
255− backlight = backlight_device_register(DRV_NAME, NULL, NULL,
256− &msi_backlight_ops,
257− &props);
258− if (IS_ERR(backlight)) {
259− err = PTR_ERR(backlight);
305+ err = msi_wmi_input_setup();
306+ if (err) {
307+ pr_err("Unable to setup input device\n");
308+ return err;
309+ }
310+
311+ err = wmi_install_notify_handler(event_wmis[i].guid,
312+ msi_wmi_notify, NULL);
313+ if (ACPI_FAILURE(err)) {
314+ pr_err("Unable to setup WMI notify handler\n");
260315 goto err_free_input;
261316 }
262317
263− err = bl_get(NULL);
264− if (err < 0)
265− goto err_free_backlight;
318+ pr_debug("Event handler installed\n");
319+ event_wmi = &event_wmis[i];
320+ break;
321+ }
266322
267− backlight->props.brightness = err;
323+ if (wmi_has_guid(MSIWMI_BIOS_GUID) && !acpi_video_backlight_support()) {
324+ err = msi_wmi_backlight_setup();
325+ if (err) {
326+ pr_err("Unable to setup backlight device\n");
327+ goto err_uninstall_handler;
328+ }
329+ pr_debug("Backlight device created\n");
330+ }
331+
332+ if (!event_wmi && !backlight) {
333+ pr_err("This machine doesn't have neither MSI-hotkeys nor backlight through WMI\n");
334+ return -ENODEV;
268335 }
269− pr_debug("Event handler installed\n");
270336
271337 return 0;
272338
273−err_free_backlight:
274− backlight_device_unregister(backlight);
339+err_uninstall_handler:
340+ if (event_wmi)
341+ wmi_remove_notify_handler(event_wmi->guid);
275342 err_free_input:
276− sparse_keymap_free(msi_wmi_input_dev);
277− input_unregister_device(msi_wmi_input_dev);
278−err_uninstall_notifier:
279− wmi_remove_notify_handler(MSIWMI_EVENT_GUID);
343+ if (event_wmi) {
344+ sparse_keymap_free(msi_wmi_input_dev);
345+ input_unregister_device(msi_wmi_input_dev);
346+ }
280347 return err;
281348 }
282349
283350 static void __exit msi_wmi_exit(void)
284351 {
285− if (wmi_has_guid(MSIWMI_EVENT_GUID)) {
286− wmi_remove_notify_handler(MSIWMI_EVENT_GUID);
352+ if (event_wmi) {
353+ wmi_remove_notify_handler(event_wmi->guid);
287354 sparse_keymap_free(msi_wmi_input_dev);
288355 input_unregister_device(msi_wmi_input_dev);
289− backlight_device_unregister(backlight);
290356 }
357+ if (backlight)
358+ backlight_device_unregister(backlight);
291359 }
292360
293361 module_init(msi_wmi_init);
drivers/platform/x86/sony-laptop.c+134−11
@@ -158,6 +158,11 @@ static void sony_nc_thermal_cleanup(struct platform_device *pd); · 157 unmodified lines
158158 static int sony_nc_lid_resume_setup(struct platform_device *pd);
159159 static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
160160
161+static int sony_nc_gfx_switch_setup(struct platform_device *pd,
162+ unsigned int handle);
163+static void sony_nc_gfx_switch_cleanup(struct platform_device *pd);
164+static int __sony_nc_gfx_switch_status_get(void);
165+
161166 static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
162167 static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
163168
@@ -1241,17 +1246,13 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) · 1077 unmodified lines
12411246 /* Hybrid GFX switching */
12421247 sony_call_snc_handle(handle, 0x0000, &result);
12431248 dprintk("GFX switch event received (reason: %s)\n",
1244− (result & 0x01) ?
1245− "switch change" : "unknown");
1246−
1247− /* verify the switch state
1248− * 1: discrete GFX
1249− * 0: integrated GFX
1250− */
1251− sony_call_snc_handle(handle, 0x0100, &result);
1249+ (result == 0x1) ? "switch change" :
1250+ (result == 0x2) ? "output switch" :
1251+ (result == 0x3) ? "output switch" :
1252+ "");
12521253
12531254 ev_type = GFX_SWITCH;
1254− real_ev = result & 0xff;
1255+ real_ev = __sony_nc_gfx_switch_status_get();
12551256 break;
12561257
12571258 default:
@@ -1350,6 +1351,13 @@ static void sony_nc_function_setup(struct acpi_device *device, · 92 unmodified lines
13501351 pr_err("couldn't set up thermal profile function (%d)\n",
13511352 result);
13521353 break;
1354+ case 0x0128:
1355+ case 0x0146:
1356+ result = sony_nc_gfx_switch_setup(pf_device, handle);
1357+ if (result)
1358+ pr_err("couldn't set up GFX Switch status (%d)\n",
1359+ result);
1360+ break;
13531361 case 0x0131:
13541362 result = sony_nc_highspeed_charging_setup(pf_device);
13551363 if (result)
@@ -1365,6 +1373,8 @@ static void sony_nc_function_setup(struct acpi_device *device, · 9 unmodified lines
13651373 break;
13661374 case 0x0137:
13671375 case 0x0143:
1376+ case 0x014b:
1377+ case 0x014c:
13681378 result = sony_nc_kbd_backlight_setup(pf_device, handle);
13691379 if (result)
13701380 pr_err("couldn't set up keyboard backlight function (%d)\n",
@@ -1414,6 +1424,10 @@ static void sony_nc_function_cleanup(struct platform_device *pd) · 43 unmodified lines
14141424 case 0x0122:
14151425 sony_nc_thermal_cleanup(pd);
14161426 break;
1427+ case 0x0128:
1428+ case 0x0146:
1429+ sony_nc_gfx_switch_cleanup(pd);
1430+ break;
14171431 case 0x0131:
14181432 sony_nc_highspeed_charging_cleanup(pd);
14191433 break;
@@ -1423,6 +1437,8 @@ static void sony_nc_function_cleanup(struct platform_device *pd) · 3 unmodified lines
14231437 break;
14241438 case 0x0137:
14251439 case 0x0143:
1440+ case 0x014b:
1441+ case 0x014c:
14261442 sony_nc_kbd_backlight_cleanup(pd);
14271443 break;
14281444 default:
@@ -1467,6 +1483,8 @@ static void sony_nc_function_resume(void) · 38 unmodified lines
14671483 break;
14681484 case 0x0137:
14691485 case 0x0143:
1486+ case 0x014b:
1487+ case 0x014c:
14701488 sony_nc_kbd_backlight_resume();
14711489 break;
14721490 default:
@@ -1534,7 +1552,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked) · 61 unmodified lines
15341552 int argument = sony_rfkill_address[(long) data] + 0x100;
15351553
15361554 if (!blocked)
1537− argument |= 0x030000;
1555+ argument |= 0x070000;
15381556
15391557 return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
15401558 }
@@ -2333,7 +2351,7 @@ static int sony_nc_lid_resume_setup(struct platform_device *pd) · 792 unmodified lines
23332351 return 0;
23342352
23352353 liderror:
2336− for (; i > 0; i--)
2354+ for (i--; i >= 0; i--)
23372355 device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
23382356
23392357 kfree(lid_ctl);
@@ -2355,6 +2373,97 @@ static void sony_nc_lid_resume_cleanup(struct platform_device *pd) · 15 unmodified lines
23552373 }
23562374 }
23572375
2376+/* GFX Switch position */
2377+enum gfx_switch {
2378+ SPEED,
2379+ STAMINA,
2380+ AUTO
2381+};
2382+struct snc_gfx_switch_control {
2383+ struct device_attribute attr;
2384+ unsigned int handle;
2385+};
2386+static struct snc_gfx_switch_control *gfxs_ctl;
2387+
2388+/* returns 0 for speed, 1 for stamina */
2389+static int __sony_nc_gfx_switch_status_get(void)
2390+{
2391+ unsigned int result;
2392+
2393+ if (sony_call_snc_handle(gfxs_ctl->handle, 0x0100, &result))
2394+ return -EIO;
2395+
2396+ switch (gfxs_ctl->handle) {
2397+ case 0x0146:
2398+ /* 1: discrete GFX (speed)
2399+ * 0: integrated GFX (stamina)
2400+ */
2401+ return result & 0x1 ? SPEED : STAMINA;
2402+ break;
2403+ case 0x0128:
2404+ /* it's a more elaborated bitmask, for now:
2405+ * 2: integrated GFX (stamina)
2406+ * 0: discrete GFX (speed)
2407+ */
2408+ dprintk("GFX Status: 0x%x\n", result);
2409+ return result & 0x80 ? AUTO :
2410+ result & 0x02 ? STAMINA : SPEED;
2411+ break;
2412+ }
2413+ return -EINVAL;
2414+}
2415+
2416+static ssize_t sony_nc_gfx_switch_status_show(struct device *dev,
2417+ struct device_attribute *attr,
2418+ char *buffer)
2419+{
2420+ int pos = __sony_nc_gfx_switch_status_get();
2421+
2422+ if (pos < 0)
2423+ return pos;
2424+
2425+ return snprintf(buffer, PAGE_SIZE, "%s\n", pos ? "speed" : "stamina");
2426+}
2427+
2428+static int sony_nc_gfx_switch_setup(struct platform_device *pd,
2429+ unsigned int handle)
2430+{
2431+ unsigned int result;
2432+
2433+ gfxs_ctl = kzalloc(sizeof(struct snc_gfx_switch_control), GFP_KERNEL);
2434+ if (!gfxs_ctl)
2435+ return -ENOMEM;
2436+
2437+ gfxs_ctl->handle = handle;
2438+
2439+ sysfs_attr_init(&gfxs_ctl->attr.attr);
2440+ gfxs_ctl->attr.attr.name = "gfx_switch_status";
2441+ gfxs_ctl->attr.attr.mode = S_IRUGO;
2442+ gfxs_ctl->attr.show = sony_nc_gfx_switch_status_show;
2443+
2444+ result = device_create_file(&pd->dev, &gfxs_ctl->attr);
2445+ if (result)
2446+ goto gfxerror;
2447+
2448+ return 0;
2449+
2450+gfxerror:
2451+ kfree(gfxs_ctl);
2452+ gfxs_ctl = NULL;
2453+
2454+ return result;
2455+}
2456+
2457+static void sony_nc_gfx_switch_cleanup(struct platform_device *pd)
2458+{
2459+ if (gfxs_ctl) {
2460+ device_remove_file(&pd->dev, &gfxs_ctl->attr);
2461+
2462+ kfree(gfxs_ctl);
2463+ gfxs_ctl = NULL;
2464+ }
2465+}
2466+
23582467 /* High speed charging function */
23592468 static struct device_attribute *hsc_handle;
23602469
@@ -2533,6 +2642,8 @@ static void sony_nc_backlight_ng_read_limits(int handle, · 172 unmodified lines
25332642 lvl_table_len = 9;
25342643 break;
25352644 case 0x143:
2645+ case 0x14b:
2646+ case 0x14c:
25362647 lvl_table_len = 16;
25372648 break;
25382649 }
@@ -2584,6 +2695,18 @@ static void sony_nc_backlight_setup(void) · 45 unmodified lines
25842695 sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
25852696 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
25862697
2698+ } else if (sony_find_snc_handle(0x14b) >= 0) {
2699+ ops = &sony_backlight_ng_ops;
2700+ sony_bl_props.cmd_base = 0x3000;
2701+ sony_nc_backlight_ng_read_limits(0x14b, &sony_bl_props);
2702+ max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
2703+
2704+ } else if (sony_find_snc_handle(0x14c) >= 0) {
2705+ ops = &sony_backlight_ng_ops;
2706+ sony_bl_props.cmd_base = 0x3000;
2707+ sony_nc_backlight_ng_read_limits(0x14c, &sony_bl_props);
2708+ max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
2709+
25872710 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
25882711 &unused))) {
25892712 ops = &sony_backlight_ops;
drivers/platform/x86/thinkpad_acpi.c+12−5
@@ -209,9 +209,8 @@ enum tpacpi_hkey_event_t { · 208 unmodified lines
209209 TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */
210210 TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* thermal table changed */
211211
212− TP_HKEY_EV_UNK_6040 = 0x6040, /* Related to AC change?
213− some sort of APM hint,
214− W520 */
212+ /* AC-related events */
213+ TP_HKEY_EV_AC_CHANGED = 0x6040, /* AC status changed */
215214
216215 /* Misc */
217216 TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */
@@ -3629,6 +3628,12 @@ static bool hotkey_notify_6xxx(const u32 hkey, · 3411 unmodified lines
36293628 "a sensor reports something is extremely hot!\n");
36303629 /* recommended action: immediate sleep/hibernate */
36313630 break;
3631+ case TP_HKEY_EV_AC_CHANGED:
3632+ /* X120e, X121e, X220, X220i, X220t, X230, T420, T420s, W520:
3633+ * AC status changed; can be triggered by plugging or
3634+ * unplugging AC adapter, docking or undocking. */
3635+
3636+ /* fallthrough */
36323637
36333638 case TP_HKEY_EV_KEY_NUMLOCK:
36343639 case TP_HKEY_EV_KEY_FN:
@@ -8574,7 +8579,8 @@ static bool __pure __init tpacpi_is_valid_fw_id(const char* const s, · 4939 unmodified lines
85748579 return s && strlen(s) >= 8 &&
85758580 tpacpi_is_fw_digit(s[0]) &&
85768581 tpacpi_is_fw_digit(s[1]) &&
8577− s[2] == t && s[3] == 'T' &&
8582+ s[2] == t &&
8583+ (s[3] == 'T' || s[3] == 'N') &&
85788584 tpacpi_is_fw_digit(s[4]) &&
85798585 tpacpi_is_fw_digit(s[5]);
85808586 }
@@ -8607,7 +8613,8 @@ static int __must_check __init get_thinkpad_model_data( · 26 unmodified lines
86078613 return -ENOMEM;
86088614
86098615 /* Really ancient ThinkPad 240X will fail this, which is fine */
8610− if (!tpacpi_is_valid_fw_id(tp->bios_version_str, 'E'))
8616+ if (!(tpacpi_is_valid_fw_id(tp->bios_version_str, 'E') ||
8617+ tpacpi_is_valid_fw_id(tp->bios_version_str, 'C')))
86118618 return 0;
86128619
86138620 tp->bios_model = tp->bios_version_str[0]

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t