Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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
...

+1377 -275
+83
Documentation/ABI/testing/sysfs-platform-msi-laptop
··· 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 +
+14 -1
drivers/platform/x86/Kconfig
··· 79 79 80 80 If you have an ACPI-compatible ASUS laptop, say Y or M here. 81 81 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 + 82 93 config DELL_LAPTOP 83 94 tristate "Dell Laptop Extras" 84 95 depends on X86 ··· 299 288 depends on ACPI 300 289 depends on RFKILL && INPUT 301 290 depends on SERIO_I8042 291 + depends on BACKLIGHT_CLASS_DEVICE 302 292 select INPUT_SPARSEKMAP 303 293 help 304 - This is a driver for the rfkill switches on Lenovo IdeaPad netbooks. 294 + This is a driver for Lenovo IdeaPad netbooks contains drivers for 295 + rfkill switch, hotkey, fan control and backlight control. 305 296 306 297 config THINKPAD_ACPI 307 298 tristate "ThinkPad ACPI Laptop Extras"
+1
drivers/platform/x86/Makefile
··· 50 50 obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o 51 51 obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o 52 52 obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o 53 + obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
+21
drivers/platform/x86/acer-wmi.c
··· 511 511 }, 512 512 .driver_data = &quirk_fujitsu_amilo_li_1718, 513 513 }, 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 + }, 514 532 {} 515 533 }; 516 534 ··· 1222 1204 devices = *((u32 *) obj->buffer.pointer); 1223 1205 } else if (obj->type == ACPI_TYPE_INTEGER) { 1224 1206 devices = (u32) obj->integer.value; 1207 + } else { 1208 + kfree(out.pointer); 1209 + return AE_ERROR; 1225 1210 } 1226 1211 } else { 1227 1212 kfree(out.pointer);
+58 -27
drivers/platform/x86/asus-laptop.c
··· 128 128 /* 129 129 * Some events we use, same for all Asus 130 130 */ 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 135 137 #define ATKD_LCD_ON 0x33 136 138 #define ATKD_LCD_OFF 0x34 137 139 ··· 303 301 {KE_KEY, 0x17, { KEY_ZOOM } }, 304 302 {KE_KEY, 0x1f, { KEY_BATTERY } }, 305 303 /* End of Lenovo SL Specific keycodes */ 304 + {KE_KEY, ATKD_BRNDOWN, { KEY_BRIGHTNESSDOWN } }, 305 + {KE_KEY, ATKD_BRNUP, { KEY_BRIGHTNESSUP } }, 306 306 {KE_KEY, 0x30, { KEY_VOLUMEUP } }, 307 307 {KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, 308 308 {KE_KEY, 0x32, { KEY_MUTE } }, 309 - {KE_KEY, 0x33, { KEY_SWITCHVIDEOMODE } }, 310 - {KE_KEY, 0x34, { KEY_SWITCHVIDEOMODE } }, 309 + {KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */ 310 + {KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */ 311 311 {KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, 312 312 {KE_KEY, 0x41, { KEY_NEXTSONG } }, 313 - {KE_KEY, 0x43, { KEY_STOPCD } }, 313 + {KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */ 314 314 {KE_KEY, 0x45, { KEY_PLAYPAUSE } }, 315 - {KE_KEY, 0x4c, { KEY_MEDIA } }, 315 + {KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */ 316 316 {KE_KEY, 0x50, { KEY_EMAIL } }, 317 317 {KE_KEY, 0x51, { KEY_WWW } }, 318 318 {KE_KEY, 0x55, { KEY_CALC } }, 319 + {KE_IGNORE, 0x57, }, /* Battery mode */ 320 + {KE_IGNORE, 0x58, }, /* AC mode */ 319 321 {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */ 320 - {KE_KEY, 0x5D, { KEY_WLAN } }, 321 - {KE_KEY, 0x5E, { KEY_WLAN } }, 322 - {KE_KEY, 0x5F, { KEY_WLAN } }, 323 - {KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, 324 - {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, 325 - {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, 326 - {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, 327 - {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */ 322 + {KE_KEY, 0x5D, { KEY_WLAN } }, /* WLAN Toggle */ 323 + {KE_KEY, 0x5E, { KEY_WLAN } }, /* WLAN Enable */ 324 + {KE_KEY, 0x5F, { KEY_WLAN } }, /* WLAN Disable */ 325 + {KE_KEY, 0x60, { KEY_TOUCHPAD_ON } }, 326 + {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */ 327 + {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */ 328 + {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */ 329 + {KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */ 330 + {KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */ 331 + {KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */ 332 + {KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */ 333 + {KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, /* Lock Touchpad */ 328 334 {KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */ 329 335 {KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */ 330 - {KE_KEY, 0x7E, { KEY_BLUETOOTH } }, 331 - {KE_KEY, 0x7D, { KEY_BLUETOOTH } }, 336 + {KE_IGNORE, 0x6E, }, /* Low Battery notification */ 337 + {KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */ 338 + {KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */ 332 339 {KE_KEY, 0x82, { KEY_CAMERA } }, 333 - {KE_KEY, 0x88, { KEY_WLAN } }, 334 - {KE_KEY, 0x8A, { KEY_PROG1 } }, 340 + {KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */ 341 + {KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */ 342 + {KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */ 343 + {KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */ 344 + {KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */ 345 + {KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */ 346 + {KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */ 347 + {KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */ 348 + {KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */ 349 + {KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */ 335 350 {KE_KEY, 0x95, { KEY_MEDIA } }, 336 351 {KE_KEY, 0x99, { KEY_PHONE } }, 337 - {KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, 338 - {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, 339 - {KE_KEY, 0xb5, { KEY_CALC } }, 352 + {KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */ 353 + {KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */ 354 + {KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */ 355 + {KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */ 356 + {KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */ 357 + {KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */ 358 + {KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */ 359 + {KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */ 360 + {KE_KEY, 0xB5, { KEY_CALC } }, 361 + {KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, 362 + {KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, 340 363 {KE_END, 0}, 341 364 }; 342 365 ··· 1548 1521 dev_name(&asus->device->dev), event, 1549 1522 count); 1550 1523 1551 - /* Brightness events are special */ 1552 - if (event >= ATKD_BR_MIN && event <= ATKD_BR_MAX) { 1524 + if (event >= ATKD_BRNUP_MIN && event <= ATKD_BRNUP_MAX) 1525 + event = ATKD_BRNUP; 1526 + else if (event >= ATKD_BRNDOWN_MIN && 1527 + event <= ATKD_BRNDOWN_MAX) 1528 + event = ATKD_BRNDOWN; 1553 1529 1554 - /* Ignore them completely if the acpi video driver is used */ 1530 + /* Brightness events are special */ 1531 + if (event == ATKD_BRNDOWN || event == ATKD_BRNUP) { 1555 1532 if (asus->backlight_device != NULL) { 1556 1533 /* Update the backlight device. */ 1557 1534 asus_backlight_notify(asus); 1535 + return ; 1558 1536 } 1559 - return ; 1560 1537 } 1561 1538 1562 1539 /* Accelerometer "coarse orientation change" event */
+62 -14
drivers/platform/x86/asus-nb-wmi.c
··· 59 59 .wapf = 0, 60 60 }; 61 61 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 + 62 73 static struct quirk_entry quirk_asus_x401u = { 63 74 .wapf = 4, 64 75 }; ··· 88 77 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 89 78 DMI_MATCH(DMI_PRODUCT_NAME, "X401U"), 90 79 }, 80 + .driver_data = &quirk_asus_x55u, 81 + }, 82 + { 83 + .callback = dmi_matched, 84 + .ident = "ASUSTeK COMPUTER INC. X401A", 85 + .matches = { 86 + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 87 + DMI_MATCH(DMI_PRODUCT_NAME, "X401A"), 88 + }, 91 89 .driver_data = &quirk_asus_x401u, 92 90 }, 93 91 { ··· 114 94 .matches = { 115 95 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 116 96 DMI_MATCH(DMI_PRODUCT_NAME, "X501U"), 97 + }, 98 + .driver_data = &quirk_asus_x55u, 99 + }, 100 + { 101 + .callback = dmi_matched, 102 + .ident = "ASUSTeK COMPUTER INC. X501A", 103 + .matches = { 104 + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 105 + DMI_MATCH(DMI_PRODUCT_NAME, "X501A"), 117 106 }, 118 107 .driver_data = &quirk_asus_x401u, 119 108 }, ··· 160 131 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 161 132 DMI_MATCH(DMI_PRODUCT_NAME, "X55U"), 162 133 }, 163 - .driver_data = &quirk_asus_x401u, 134 + .driver_data = &quirk_asus_x55u, 164 135 }, 165 136 { 166 137 .callback = dmi_matched, ··· 190 161 } 191 162 192 163 static const struct key_entry asus_nb_wmi_keymap[] = { 164 + { KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } }, 165 + { KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } }, 193 166 { KE_KEY, 0x30, { KEY_VOLUMEUP } }, 194 167 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, 195 168 { KE_KEY, 0x32, { KEY_MUTE } }, ··· 199 168 { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */ 200 169 { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, 201 170 { KE_KEY, 0x41, { KEY_NEXTSONG } }, 202 - { KE_KEY, 0x43, { KEY_STOPCD } }, 171 + { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */ 203 172 { KE_KEY, 0x45, { KEY_PLAYPAUSE } }, 204 - { KE_KEY, 0x4c, { KEY_MEDIA } }, 173 + { KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */ 205 174 { KE_KEY, 0x50, { KEY_EMAIL } }, 206 175 { KE_KEY, 0x51, { KEY_WWW } }, 207 176 { KE_KEY, 0x55, { KEY_CALC } }, ··· 211 180 { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */ 212 181 { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */ 213 182 { KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */ 214 - { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, 215 - { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, 216 - { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, 217 - { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, 183 + { KE_KEY, 0x60, { KEY_TOUCHPAD_ON } }, 184 + { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */ 185 + { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */ 186 + { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */ 187 + { KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */ 188 + { KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */ 189 + { KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */ 190 + { KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */ 218 191 { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, 219 - { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, 220 - { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, 192 + { KE_IGNORE, 0x6E, }, /* Low Battery notification */ 193 + { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */ 194 + { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */ 221 195 { KE_KEY, 0x82, { KEY_CAMERA } }, 222 - { KE_KEY, 0x88, { KEY_RFKILL } }, 223 - { KE_KEY, 0x8A, { KEY_PROG1 } }, 196 + { KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */ 197 + { KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */ 198 + { KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */ 199 + { KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */ 200 + { KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */ 201 + { KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */ 202 + { KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */ 203 + { KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */ 204 + { KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */ 205 + { KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */ 224 206 { KE_KEY, 0x95, { KEY_MEDIA } }, 225 207 { KE_KEY, 0x99, { KEY_PHONE } }, 226 208 { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */ 227 209 { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */ 228 210 { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */ 229 211 { KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */ 230 - { KE_KEY, 0xb5, { KEY_CALC } }, 231 - { KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, 232 - { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, 212 + { KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */ 213 + { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */ 214 + { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */ 215 + { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */ 216 + { KE_KEY, 0xB5, { KEY_CALC } }, 217 + { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, 218 + { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, 233 219 { KE_END, 0}, 234 220 }; 235 221
+102 -6
drivers/platform/x86/asus-wmi.c
··· 187 187 struct device *hwmon_device; 188 188 struct platform_device *platform_device; 189 189 190 + struct led_classdev wlan_led; 191 + int wlan_led_wk; 190 192 struct led_classdev tpd_led; 191 193 int tpd_led_wk; 192 194 struct led_classdev kbd_led; ··· 196 194 struct workqueue_struct *led_workqueue; 197 195 struct work_struct tpd_led_work; 198 196 struct work_struct kbd_led_work; 197 + struct work_struct wlan_led_work; 199 198 200 199 struct asus_rfkill wlan; 201 200 struct asus_rfkill bluetooth; ··· 459 456 return value; 460 457 } 461 458 459 + static int wlan_led_unknown_state(struct asus_wmi *asus) 460 + { 461 + u32 result; 462 + 463 + asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); 464 + 465 + return result & ASUS_WMI_DSTS_UNKNOWN_BIT; 466 + } 467 + 468 + static int wlan_led_presence(struct asus_wmi *asus) 469 + { 470 + u32 result; 471 + 472 + asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); 473 + 474 + return result & ASUS_WMI_DSTS_PRESENCE_BIT; 475 + } 476 + 477 + static void wlan_led_update(struct work_struct *work) 478 + { 479 + int ctrl_param; 480 + struct asus_wmi *asus; 481 + 482 + asus = container_of(work, struct asus_wmi, wlan_led_work); 483 + 484 + ctrl_param = asus->wlan_led_wk; 485 + asus_wmi_set_devstate(ASUS_WMI_DEVID_WIRELESS_LED, ctrl_param, NULL); 486 + } 487 + 488 + static void wlan_led_set(struct led_classdev *led_cdev, 489 + enum led_brightness value) 490 + { 491 + struct asus_wmi *asus; 492 + 493 + asus = container_of(led_cdev, struct asus_wmi, wlan_led); 494 + 495 + asus->wlan_led_wk = !!value; 496 + queue_work(asus->led_workqueue, &asus->wlan_led_work); 497 + } 498 + 499 + static enum led_brightness wlan_led_get(struct led_classdev *led_cdev) 500 + { 501 + struct asus_wmi *asus; 502 + u32 result; 503 + 504 + asus = container_of(led_cdev, struct asus_wmi, wlan_led); 505 + asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); 506 + 507 + return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK; 508 + } 509 + 462 510 static void asus_wmi_led_exit(struct asus_wmi *asus) 463 511 { 464 512 if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) 465 513 led_classdev_unregister(&asus->kbd_led); 466 514 if (!IS_ERR_OR_NULL(asus->tpd_led.dev)) 467 515 led_classdev_unregister(&asus->tpd_led); 516 + if (!IS_ERR_OR_NULL(asus->wlan_led.dev)) 517 + led_classdev_unregister(&asus->wlan_led); 468 518 if (asus->led_workqueue) 469 519 destroy_workqueue(asus->led_workqueue); 470 520 } ··· 554 498 555 499 rv = led_classdev_register(&asus->platform_device->dev, 556 500 &asus->kbd_led); 501 + if (rv) 502 + goto error; 503 + } 504 + 505 + if (wlan_led_presence(asus)) { 506 + INIT_WORK(&asus->wlan_led_work, wlan_led_update); 507 + 508 + asus->wlan_led.name = "asus::wlan"; 509 + asus->wlan_led.brightness_set = wlan_led_set; 510 + if (!wlan_led_unknown_state(asus)) 511 + asus->wlan_led.brightness_get = wlan_led_get; 512 + asus->wlan_led.flags = LED_CORE_SUSPENDRESUME; 513 + asus->wlan_led.max_brightness = 1; 514 + asus->wlan_led.default_trigger = "asus-wlan"; 515 + 516 + rv = led_classdev_register(&asus->platform_device->dev, 517 + &asus->wlan_led); 557 518 } 558 519 559 520 error: ··· 885 812 886 813 if (!*rfkill) 887 814 return -EINVAL; 815 + 816 + if (dev_id == ASUS_WMI_DEVID_WLAN) 817 + rfkill_set_led_trigger_name(*rfkill, "asus-wlan"); 888 818 889 819 rfkill_init_sw_state(*rfkill, !result); 890 820 result = rfkill_register(*rfkill); ··· 1341 1265 asus->backlight_device = NULL; 1342 1266 } 1343 1267 1268 + static int is_display_toggle(int code) 1269 + { 1270 + /* display toggle keys */ 1271 + if ((code >= 0x61 && code <= 0x67) || 1272 + (code >= 0x8c && code <= 0x93) || 1273 + (code >= 0xa0 && code <= 0xa7) || 1274 + (code >= 0xd0 && code <= 0xd5)) 1275 + return 1; 1276 + 1277 + return 0; 1278 + } 1279 + 1344 1280 static void asus_wmi_notify(u32 value, void *context) 1345 1281 { 1346 1282 struct asus_wmi *asus = context; ··· 1386 1298 } 1387 1299 1388 1300 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) 1389 - code = NOTIFY_BRNUP_MIN; 1301 + code = ASUS_WMI_BRN_UP; 1390 1302 else if (code >= NOTIFY_BRNDOWN_MIN && 1391 1303 code <= NOTIFY_BRNDOWN_MAX) 1392 - code = NOTIFY_BRNDOWN_MIN; 1304 + code = ASUS_WMI_BRN_DOWN; 1393 1305 1394 - if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { 1395 - if (!acpi_video_backlight_support()) 1306 + if (code == ASUS_WMI_BRN_DOWN || code == ASUS_WMI_BRN_UP) { 1307 + if (!acpi_video_backlight_support()) { 1396 1308 asus_wmi_backlight_notify(asus, orig_code); 1397 - } else if (!sparse_keymap_report_event(asus->inputdev, code, 1398 - key_value, autorelease)) 1309 + goto exit; 1310 + } 1311 + } 1312 + 1313 + if (is_display_toggle(code) && 1314 + asus->driver->quirks->no_display_toggle) 1315 + goto exit; 1316 + 1317 + if (!sparse_keymap_report_event(asus->inputdev, code, 1318 + key_value, autorelease)) 1399 1319 pr_info("Unknown key %x pressed\n", code); 1400 1320 1401 1321 exit:
+9
drivers/platform/x86/asus-wmi.h
··· 30 30 #include <linux/platform_device.h> 31 31 32 32 #define ASUS_WMI_KEY_IGNORE (-1) 33 + #define ASUS_WMI_BRN_DOWN 0x20 34 + #define ASUS_WMI_BRN_UP 0x2f 33 35 34 36 struct module; 35 37 struct key_entry; ··· 43 41 bool store_backlight_power; 44 42 bool wmi_backlight_power; 45 43 int wapf; 44 + /* 45 + * For machines with AMD graphic chips, it will send out WMI event 46 + * and ACPI interrupt at the same time while hitting the hotkey. 47 + * To simplify the problem, we just have to ignore the WMI event, 48 + * and let the ACPI interrupt to send out the key event. 49 + */ 50 + int no_display_toggle; 46 51 }; 47 52 48 53 struct asus_wmi_driver {
+371
drivers/platform/x86/chromeos_laptop.c
··· 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");
+2
drivers/platform/x86/eeepc-wmi.c
··· 63 63 #define HOME_RELEASE 0xe5 64 64 65 65 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 } }, 66 68 /* Sleep already handled via generic ACPI code */ 67 69 { KE_KEY, 0x30, { KEY_VOLUMEUP } }, 68 70 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
+78 -41
drivers/platform/x86/hp-wmi.c
··· 60 60 HPWMI_WIFI = 0, 61 61 HPWMI_BLUETOOTH = 1, 62 62 HPWMI_WWAN = 2, 63 + HPWMI_GPS = 3, 63 64 }; 64 65 65 66 enum hp_wmi_event_ids { ··· 72 71 HPWMI_CPU_BATTERY_THROTTLE = 6, 73 72 HPWMI_LOCK_SWITCH = 7, 74 73 }; 75 - 76 - static int hp_wmi_bios_setup(struct platform_device *device); 77 - static int __exit hp_wmi_bios_remove(struct platform_device *device); 78 - static int hp_wmi_resume_handler(struct device *device); 79 74 80 75 struct bios_args { 81 76 u32 signature; ··· 134 137 { KE_KEY, 0x2142, { KEY_MEDIA } }, 135 138 { KE_KEY, 0x213b, { KEY_INFO } }, 136 139 { KE_KEY, 0x2169, { KEY_DIRECTION } }, 140 + { KE_KEY, 0x216a, { KEY_SETUP } }, 137 141 { KE_KEY, 0x231b, { KEY_HELP } }, 138 142 { KE_END, 0 } 139 143 }; ··· 145 147 static struct rfkill *wifi_rfkill; 146 148 static struct rfkill *bluetooth_rfkill; 147 149 static struct rfkill *wwan_rfkill; 150 + static struct rfkill *gps_rfkill; 148 151 149 152 struct rfkill2_device { 150 153 u8 id; ··· 155 156 156 157 static int rfkill2_count; 157 158 static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; 158 - 159 - static const struct dev_pm_ops hp_wmi_pm_ops = { 160 - .resume = hp_wmi_resume_handler, 161 - .restore = hp_wmi_resume_handler, 162 - }; 163 - 164 - static struct platform_driver hp_wmi_driver = { 165 - .driver = { 166 - .name = "hp-wmi", 167 - .owner = THIS_MODULE, 168 - .pm = &hp_wmi_pm_ops, 169 - }, 170 - .probe = hp_wmi_bios_setup, 171 - .remove = hp_wmi_bios_remove, 172 - }; 173 159 174 160 /* 175 161 * hp_wmi_perform_query ··· 527 543 rfkill_set_states(wwan_rfkill, 528 544 hp_wmi_get_sw_state(HPWMI_WWAN), 529 545 hp_wmi_get_hw_state(HPWMI_WWAN)); 546 + if (gps_rfkill) 547 + rfkill_set_states(gps_rfkill, 548 + hp_wmi_get_sw_state(HPWMI_GPS), 549 + hp_wmi_get_hw_state(HPWMI_GPS)); 530 550 break; 531 551 case HPWMI_CPU_BATTERY_THROTTLE: 532 552 pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n"); ··· 658 670 (void *) HPWMI_WWAN); 659 671 if (!wwan_rfkill) { 660 672 err = -ENOMEM; 661 - goto register_bluetooth_error; 673 + goto register_gps_error; 662 674 } 663 675 rfkill_init_sw_state(wwan_rfkill, 664 676 hp_wmi_get_sw_state(HPWMI_WWAN)); ··· 669 681 goto register_wwan_err; 670 682 } 671 683 684 + if (wireless & 0x8) { 685 + gps_rfkill = rfkill_alloc("hp-gps", &device->dev, 686 + RFKILL_TYPE_GPS, 687 + &hp_wmi_rfkill_ops, 688 + (void *) HPWMI_GPS); 689 + if (!gps_rfkill) { 690 + err = -ENOMEM; 691 + goto register_bluetooth_error; 692 + } 693 + rfkill_init_sw_state(gps_rfkill, 694 + hp_wmi_get_sw_state(HPWMI_GPS)); 695 + rfkill_set_hw_state(bluetooth_rfkill, 696 + hp_wmi_get_hw_state(HPWMI_GPS)); 697 + err = rfkill_register(gps_rfkill); 698 + if (err) 699 + goto register_gps_error; 700 + } 701 + 672 702 return 0; 673 703 register_wwan_err: 674 704 rfkill_destroy(wwan_rfkill); 675 705 wwan_rfkill = NULL; 706 + if (gps_rfkill) 707 + rfkill_unregister(gps_rfkill); 708 + register_gps_error: 709 + rfkill_destroy(gps_rfkill); 710 + gps_rfkill = NULL; 676 711 if (bluetooth_rfkill) 677 712 rfkill_unregister(bluetooth_rfkill); 678 713 register_bluetooth_error: ··· 739 728 case HPWMI_WWAN: 740 729 type = RFKILL_TYPE_WWAN; 741 730 name = "hp-wwan"; 731 + break; 732 + case HPWMI_GPS: 733 + type = RFKILL_TYPE_GPS; 734 + name = "hp-gps"; 742 735 break; 743 736 default: 744 737 pr_warn("unknown device type 0x%x\n", ··· 793 778 return err; 794 779 } 795 780 796 - static int hp_wmi_bios_setup(struct platform_device *device) 781 + static int __init hp_wmi_bios_setup(struct platform_device *device) 797 782 { 798 783 int err; 799 784 ··· 801 786 wifi_rfkill = NULL; 802 787 bluetooth_rfkill = NULL; 803 788 wwan_rfkill = NULL; 789 + gps_rfkill = NULL; 804 790 rfkill2_count = 0; 805 791 806 792 if (hp_wmi_rfkill_setup(device)) ··· 851 835 rfkill_unregister(wwan_rfkill); 852 836 rfkill_destroy(wwan_rfkill); 853 837 } 838 + if (gps_rfkill) { 839 + rfkill_unregister(gps_rfkill); 840 + rfkill_destroy(gps_rfkill); 841 + } 854 842 855 843 return 0; 856 844 } ··· 890 870 rfkill_set_states(wwan_rfkill, 891 871 hp_wmi_get_sw_state(HPWMI_WWAN), 892 872 hp_wmi_get_hw_state(HPWMI_WWAN)); 873 + if (gps_rfkill) 874 + rfkill_set_states(gps_rfkill, 875 + hp_wmi_get_sw_state(HPWMI_GPS), 876 + hp_wmi_get_hw_state(HPWMI_GPS)); 893 877 894 878 return 0; 895 879 } 880 + 881 + static const struct dev_pm_ops hp_wmi_pm_ops = { 882 + .resume = hp_wmi_resume_handler, 883 + .restore = hp_wmi_resume_handler, 884 + }; 885 + 886 + static struct platform_driver hp_wmi_driver = { 887 + .driver = { 888 + .name = "hp-wmi", 889 + .owner = THIS_MODULE, 890 + .pm = &hp_wmi_pm_ops, 891 + }, 892 + .remove = __exit_p(hp_wmi_bios_remove), 893 + }; 896 894 897 895 static int __init hp_wmi_init(void) 898 896 { ··· 918 880 int event_capable = wmi_has_guid(HPWMI_EVENT_GUID); 919 881 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); 920 882 883 + if (!bios_capable && !event_capable) 884 + return -ENODEV; 885 + 921 886 if (event_capable) { 922 887 err = hp_wmi_input_setup(); 923 888 if (err) 924 889 return err; 890 + 891 + //Enable magic for hotkeys that run on the SMBus 892 + ec_write(0xe6,0x6e); 925 893 } 926 894 927 895 if (bios_capable) { 928 - err = platform_driver_register(&hp_wmi_driver); 929 - if (err) 930 - goto err_driver_reg; 931 - hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1); 932 - if (!hp_wmi_platform_dev) { 933 - err = -ENOMEM; 934 - goto err_device_alloc; 896 + hp_wmi_platform_dev = 897 + platform_device_register_simple("hp-wmi", -1, NULL, 0); 898 + if (IS_ERR(hp_wmi_platform_dev)) { 899 + err = PTR_ERR(hp_wmi_platform_dev); 900 + goto err_destroy_input; 935 901 } 936 - err = platform_device_add(hp_wmi_platform_dev); 937 - if (err) 938 - goto err_device_add; 939 - } 940 902 941 - if (!bios_capable && !event_capable) 942 - return -ENODEV; 903 + err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup); 904 + if (err) 905 + goto err_unregister_device; 906 + } 943 907 944 908 return 0; 945 909 946 - err_device_add: 947 - platform_device_put(hp_wmi_platform_dev); 948 - err_device_alloc: 949 - platform_driver_unregister(&hp_wmi_driver); 950 - err_driver_reg: 910 + err_unregister_device: 911 + platform_device_unregister(hp_wmi_platform_dev); 912 + err_destroy_input: 951 913 if (event_capable) 952 914 hp_wmi_input_destroy(); 953 915 954 916 return err; 955 917 } 918 + module_init(hp_wmi_init); 956 919 957 920 static void __exit hp_wmi_exit(void) 958 921 { ··· 965 926 platform_driver_unregister(&hp_wmi_driver); 966 927 } 967 928 } 968 - 969 - module_init(hp_wmi_init); 970 929 module_exit(hp_wmi_exit);
+284 -92
drivers/platform/x86/msi-laptop.c
··· 82 82 #define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d 83 83 #define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) 84 84 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 */ 86 91 #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) 87 98 88 99 #ifdef CONFIG_PM_SLEEP 89 100 static int msi_laptop_resume(struct device *device); ··· 119 108 120 109 static struct input_dev *msi_laptop_input_dev; 121 110 122 - static bool old_ec_model; 123 111 static int wlan_s, bluetooth_s, threeg_s; 124 112 static int threeg_exists; 125 - 126 - /* Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G, 127 - * those netbook will load the SCM (windows app) to disable the original 128 - * Wlan/Bluetooth control by BIOS when user press fn key, then control 129 - * Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user 130 - * cann't on/off 3G module on those 3G netbook. 131 - * On Linux, msi-laptop driver will do the same thing to disable the 132 - * original BIOS control, then might need use HAL or other userland 133 - * application to do the software control that simulate with SCM. 134 - * e.g. MSI N034 netbook 135 - */ 136 - static bool load_scm_model; 137 113 static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg; 114 + 115 + /* MSI laptop quirks */ 116 + struct quirk_entry { 117 + bool old_ec_model; 118 + 119 + /* Some MSI 3G netbook only have one fn key to control 120 + * Wlan/Bluetooth/3G, those netbook will load the SCM (windows app) to 121 + * disable the original Wlan/Bluetooth control by BIOS when user press 122 + * fn key, then control Wlan/Bluetooth/3G by SCM (software control by 123 + * OS). Without SCM, user cann't on/off 3G module on those 3G netbook. 124 + * On Linux, msi-laptop driver will do the same thing to disable the 125 + * original BIOS control, then might need use HAL or other userland 126 + * application to do the software control that simulate with SCM. 127 + * e.g. MSI N034 netbook 128 + */ 129 + bool load_scm_model; 130 + 131 + /* Some MSI laptops need delay before reading from EC */ 132 + bool ec_delay; 133 + 134 + /* Some MSI Wind netbooks (e.g. MSI Wind U100) need loading SCM to get 135 + * some features working (e.g. ECO mode), but we cannot change 136 + * Wlan/Bluetooth state in software and we can only read its state. 137 + */ 138 + bool ec_read_only; 139 + }; 140 + 141 + static struct quirk_entry *quirks; 138 142 139 143 /* Hardware access */ 140 144 ··· 221 195 if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1)) 222 196 return -EINVAL; 223 197 198 + if (quirks->ec_read_only) 199 + return -EOPNOTSUPP; 200 + 224 201 /* read current device state */ 225 202 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata); 226 203 if (result < 0) 227 - return -EINVAL; 204 + return result; 228 205 229 206 if (!!(rdata & mask) != status) { 230 207 /* reverse device bit */ ··· 238 209 239 210 result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata); 240 211 if (result < 0) 241 - return -EINVAL; 212 + return result; 242 213 } 243 214 244 215 return count; ··· 251 222 252 223 result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1); 253 224 if (result < 0) 254 - return -1; 225 + return result; 255 226 256 227 if (wlan) 257 228 *wlan = !!(rdata & 8); ··· 269 240 270 241 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata); 271 242 if (result < 0) 272 - return -1; 243 + return result; 273 244 274 245 wlan_s = !!(rdata & MSI_STANDARD_EC_WLAN_MASK); 275 246 ··· 287 258 288 259 result = ec_read(MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS, &rdata); 289 260 if (result < 0) 290 - return -1; 261 + return result; 291 262 292 263 threeg_exists = !!(rdata & MSI_STANDARD_EC_3G_MASK); 293 264 ··· 320 291 struct device_attribute *attr, char *buf) 321 292 { 322 293 323 - int ret, enabled; 294 + int ret, enabled = 0; 324 295 325 - if (old_ec_model) { 296 + if (quirks->old_ec_model) { 326 297 ret = get_wireless_state(&enabled, NULL); 327 298 } else { 328 299 ret = get_wireless_state_ec_standard(); ··· 344 315 struct device_attribute *attr, char *buf) 345 316 { 346 317 347 - int ret, enabled; 318 + int ret, enabled = 0; 348 319 349 - if (old_ec_model) { 320 + if (quirks->old_ec_model) { 350 321 ret = get_wireless_state(NULL, &enabled); 351 322 } else { 352 323 ret = get_wireless_state_ec_standard(); ··· 371 342 int ret; 372 343 373 344 /* old msi ec not support 3G */ 374 - if (old_ec_model) 375 - return -1; 345 + if (quirks->old_ec_model) 346 + return -ENODEV; 376 347 377 348 ret = get_wireless_state_ec_standard(); 378 349 if (ret < 0) ··· 446 417 return count; 447 418 } 448 419 420 + static ssize_t show_touchpad(struct device *dev, 421 + struct device_attribute *attr, char *buf) 422 + { 423 + 424 + u8 rdata; 425 + int result; 426 + 427 + result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata); 428 + if (result < 0) 429 + return result; 430 + 431 + return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TOUCHPAD_MASK)); 432 + } 433 + 434 + static ssize_t show_turbo(struct device *dev, 435 + struct device_attribute *attr, char *buf) 436 + { 437 + 438 + u8 rdata; 439 + int result; 440 + 441 + result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata); 442 + if (result < 0) 443 + return result; 444 + 445 + return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TURBO_MASK)); 446 + } 447 + 448 + static ssize_t show_eco(struct device *dev, 449 + struct device_attribute *attr, char *buf) 450 + { 451 + 452 + u8 rdata; 453 + int result; 454 + 455 + result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata); 456 + if (result < 0) 457 + return result; 458 + 459 + return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_ECO_MASK)); 460 + } 461 + 462 + static ssize_t show_turbo_cooldown(struct device *dev, 463 + struct device_attribute *attr, char *buf) 464 + { 465 + 466 + u8 rdata; 467 + int result; 468 + 469 + result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata); 470 + if (result < 0) 471 + return result; 472 + 473 + return sprintf(buf, "%i\n", (!!(rdata & MSI_STANDARD_EC_TURBO_MASK)) | 474 + (!!(rdata & MSI_STANDARD_EC_TURBO_COOLDOWN_MASK) << 1)); 475 + } 476 + 477 + static ssize_t show_auto_fan(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_FAN_ADDRESS, &rdata); 485 + if (result < 0) 486 + return result; 487 + 488 + return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_AUTOFAN_MASK)); 489 + } 490 + 491 + static ssize_t store_auto_fan(struct device *dev, 492 + struct device_attribute *attr, const char *buf, size_t count) 493 + { 494 + 495 + int enable, result; 496 + 497 + if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1))) 498 + return -EINVAL; 499 + 500 + result = ec_write(MSI_STANDARD_EC_FAN_ADDRESS, enable); 501 + if (result < 0) 502 + return result; 503 + 504 + return count; 505 + } 506 + 449 507 static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); 450 508 static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, 451 509 store_auto_brightness); 452 510 static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL); 453 511 static DEVICE_ATTR(wlan, 0444, show_wlan, NULL); 454 512 static DEVICE_ATTR(threeg, 0444, show_threeg, NULL); 513 + static DEVICE_ATTR(touchpad, 0444, show_touchpad, NULL); 514 + static DEVICE_ATTR(turbo_mode, 0444, show_turbo, NULL); 515 + static DEVICE_ATTR(eco_mode, 0444, show_eco, NULL); 516 + static DEVICE_ATTR(turbo_cooldown, 0444, show_turbo_cooldown, NULL); 517 + static DEVICE_ATTR(auto_fan, 0644, show_auto_fan, store_auto_fan); 455 518 456 519 static struct attribute *msipf_attributes[] = { 457 - &dev_attr_lcd_level.attr, 458 - &dev_attr_auto_brightness.attr, 459 520 &dev_attr_bluetooth.attr, 460 521 &dev_attr_wlan.attr, 522 + &dev_attr_touchpad.attr, 523 + &dev_attr_turbo_mode.attr, 524 + &dev_attr_eco_mode.attr, 525 + &dev_attr_turbo_cooldown.attr, 526 + &dev_attr_auto_fan.attr, 527 + NULL 528 + }; 529 + 530 + static struct attribute *msipf_old_attributes[] = { 531 + &dev_attr_lcd_level.attr, 532 + &dev_attr_auto_brightness.attr, 461 533 NULL 462 534 }; 463 535 464 536 static struct attribute_group msipf_attribute_group = { 465 537 .attrs = msipf_attributes 538 + }; 539 + 540 + static struct attribute_group msipf_old_attribute_group = { 541 + .attrs = msipf_old_attributes 466 542 }; 467 543 468 544 static struct platform_driver msipf_driver = { ··· 582 448 583 449 /* Initialization */ 584 450 585 - static int dmi_check_cb(const struct dmi_system_id *id) 451 + static struct quirk_entry quirk_old_ec_model = { 452 + .old_ec_model = true, 453 + }; 454 + 455 + static struct quirk_entry quirk_load_scm_model = { 456 + .load_scm_model = true, 457 + .ec_delay = true, 458 + }; 459 + 460 + static struct quirk_entry quirk_load_scm_ro_model = { 461 + .load_scm_model = true, 462 + .ec_read_only = true, 463 + }; 464 + 465 + static int dmi_check_cb(const struct dmi_system_id *dmi) 586 466 { 587 - pr_info("Identified laptop model '%s'\n", id->ident); 467 + pr_info("Identified laptop model '%s'\n", dmi->ident); 468 + 469 + quirks = dmi->driver_data; 470 + 588 471 return 1; 589 472 } 590 473 ··· 615 464 DMI_MATCH(DMI_CHASSIS_VENDOR, 616 465 "MICRO-STAR INT'L CO.,LTD") 617 466 }, 467 + .driver_data = &quirk_old_ec_model, 618 468 .callback = dmi_check_cb 619 469 }, 620 470 { ··· 626 474 DMI_MATCH(DMI_PRODUCT_VERSION, "0581"), 627 475 DMI_MATCH(DMI_BOARD_NAME, "MS-1058") 628 476 }, 477 + .driver_data = &quirk_old_ec_model, 629 478 .callback = dmi_check_cb 630 479 }, 631 480 { ··· 637 484 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), 638 485 DMI_MATCH(DMI_BOARD_NAME, "MS-1412") 639 486 }, 487 + .driver_data = &quirk_old_ec_model, 640 488 .callback = dmi_check_cb 641 489 }, 642 490 { ··· 649 495 DMI_MATCH(DMI_CHASSIS_VENDOR, 650 496 "MICRO-STAR INT'L CO.,LTD") 651 497 }, 498 + .driver_data = &quirk_old_ec_model, 652 499 .callback = dmi_check_cb 653 500 }, 654 - { } 655 - }; 656 - 657 - static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { 658 501 { 659 502 .ident = "MSI N034", 660 503 .matches = { ··· 661 510 DMI_MATCH(DMI_CHASSIS_VENDOR, 662 511 "MICRO-STAR INTERNATIONAL CO., LTD") 663 512 }, 513 + .driver_data = &quirk_load_scm_model, 664 514 .callback = dmi_check_cb 665 515 }, 666 516 { ··· 673 521 DMI_MATCH(DMI_CHASSIS_VENDOR, 674 522 "MICRO-STAR INTERNATIONAL CO., LTD") 675 523 }, 524 + .driver_data = &quirk_load_scm_model, 676 525 .callback = dmi_check_cb 677 526 }, 678 527 { ··· 683 530 "MICRO-STAR INTERNATIONAL CO., LTD"), 684 531 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"), 685 532 }, 533 + .driver_data = &quirk_load_scm_model, 686 534 .callback = dmi_check_cb 687 535 }, 688 536 { ··· 693 539 "Micro-Star International"), 694 540 DMI_MATCH(DMI_PRODUCT_NAME, "CR620"), 695 541 }, 542 + .driver_data = &quirk_load_scm_model, 696 543 .callback = dmi_check_cb 697 544 }, 698 545 { ··· 703 548 "Micro-Star International Co., Ltd."), 704 549 DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"), 705 550 }, 551 + .driver_data = &quirk_load_scm_model, 552 + .callback = dmi_check_cb 553 + }, 554 + { 555 + .ident = "MSI U90/U100", 556 + .matches = { 557 + DMI_MATCH(DMI_SYS_VENDOR, 558 + "MICRO-STAR INTERNATIONAL CO., LTD"), 559 + DMI_MATCH(DMI_PRODUCT_NAME, "U90/U100"), 560 + }, 561 + .driver_data = &quirk_load_scm_ro_model, 706 562 .callback = dmi_check_cb 707 563 }, 708 564 { } ··· 726 560 * blocked == false is on 727 561 * blocked == true is off 728 562 */ 729 - if (blocked) 730 - set_device_state("0", 0, MSI_STANDARD_EC_BLUETOOTH_MASK); 731 - else 732 - set_device_state("1", 0, MSI_STANDARD_EC_BLUETOOTH_MASK); 563 + int result = set_device_state(blocked ? "0" : "1", 0, 564 + MSI_STANDARD_EC_BLUETOOTH_MASK); 733 565 734 - return 0; 566 + return min(result, 0); 735 567 } 736 568 737 569 static int rfkill_wlan_set(void *data, bool blocked) 738 570 { 739 - if (blocked) 740 - set_device_state("0", 0, MSI_STANDARD_EC_WLAN_MASK); 741 - else 742 - set_device_state("1", 0, MSI_STANDARD_EC_WLAN_MASK); 571 + int result = set_device_state(blocked ? "0" : "1", 0, 572 + MSI_STANDARD_EC_WLAN_MASK); 743 573 744 - return 0; 574 + return min(result, 0); 745 575 } 746 576 747 577 static int rfkill_threeg_set(void *data, bool blocked) 748 578 { 749 - if (blocked) 750 - set_device_state("0", 0, MSI_STANDARD_EC_3G_MASK); 751 - else 752 - set_device_state("1", 0, MSI_STANDARD_EC_3G_MASK); 579 + int result = set_device_state(blocked ? "0" : "1", 0, 580 + MSI_STANDARD_EC_3G_MASK); 753 581 754 - return 0; 582 + return min(result, 0); 755 583 } 756 584 757 585 static const struct rfkill_ops rfkill_bluetooth_ops = { ··· 778 618 } 779 619 } 780 620 621 + static bool msi_rfkill_set_state(struct rfkill *rfkill, bool blocked) 622 + { 623 + if (quirks->ec_read_only) 624 + return rfkill_set_hw_state(rfkill, blocked); 625 + else 626 + return rfkill_set_sw_state(rfkill, blocked); 627 + } 628 + 781 629 static void msi_update_rfkill(struct work_struct *ignored) 782 630 { 783 631 get_wireless_state_ec_standard(); 784 632 785 633 if (rfk_wlan) 786 - rfkill_set_sw_state(rfk_wlan, !wlan_s); 634 + msi_rfkill_set_state(rfk_wlan, !wlan_s); 787 635 if (rfk_bluetooth) 788 - rfkill_set_sw_state(rfk_bluetooth, !bluetooth_s); 636 + msi_rfkill_set_state(rfk_bluetooth, !bluetooth_s); 789 637 if (rfk_threeg) 790 - rfkill_set_sw_state(rfk_threeg, !threeg_s); 638 + msi_rfkill_set_state(rfk_threeg, !threeg_s); 791 639 } 792 - static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); 640 + static DECLARE_DELAYED_WORK(msi_rfkill_dwork, msi_update_rfkill); 641 + static DECLARE_WORK(msi_rfkill_work, msi_update_rfkill); 793 642 794 643 static void msi_send_touchpad_key(struct work_struct *ignored) 795 644 { 796 645 u8 rdata; 797 646 int result; 798 647 799 - result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata); 648 + result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata); 800 649 if (result < 0) 801 650 return; 802 651 ··· 813 644 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ? 814 645 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true); 815 646 } 816 - static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key); 647 + static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key); 648 + static DECLARE_WORK(msi_touchpad_work, msi_send_touchpad_key); 817 649 818 650 static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, 819 651 struct serio *port) ··· 832 662 extended = false; 833 663 switch (data) { 834 664 case 0xE4: 835 - schedule_delayed_work(&msi_touchpad_work, 836 - round_jiffies_relative(0.5 * HZ)); 665 + if (quirks->ec_delay) { 666 + schedule_delayed_work(&msi_touchpad_dwork, 667 + round_jiffies_relative(0.5 * HZ)); 668 + } else 669 + schedule_work(&msi_touchpad_work); 837 670 break; 838 671 case 0x54: 839 672 case 0x62: 840 673 case 0x76: 841 - schedule_delayed_work(&msi_rfkill_work, 842 - round_jiffies_relative(0.5 * HZ)); 674 + if (quirks->ec_delay) { 675 + schedule_delayed_work(&msi_rfkill_dwork, 676 + round_jiffies_relative(0.5 * HZ)); 677 + } else 678 + schedule_work(&msi_rfkill_work); 843 679 break; 844 680 } 845 681 } ··· 912 736 } 913 737 914 738 /* schedule to run rfkill state initial */ 915 - schedule_delayed_work(&msi_rfkill_init, 916 - round_jiffies_relative(1 * HZ)); 739 + if (quirks->ec_delay) { 740 + schedule_delayed_work(&msi_rfkill_init, 741 + round_jiffies_relative(1 * HZ)); 742 + } else 743 + schedule_work(&msi_rfkill_work); 917 744 918 745 return 0; 919 746 ··· 940 761 u8 data; 941 762 int result; 942 763 943 - if (!load_scm_model) 764 + if (!quirks->load_scm_model) 944 765 return 0; 945 766 946 767 /* set load SCM to disable hardware control by fn key */ ··· 998 819 u8 data; 999 820 int result; 1000 821 1001 - /* allow userland write sysfs file */ 1002 - dev_attr_bluetooth.store = store_bluetooth; 1003 - dev_attr_wlan.store = store_wlan; 1004 - dev_attr_threeg.store = store_threeg; 1005 - dev_attr_bluetooth.attr.mode |= S_IWUSR; 1006 - dev_attr_wlan.attr.mode |= S_IWUSR; 1007 - dev_attr_threeg.attr.mode |= S_IWUSR; 822 + if (!quirks->ec_read_only) { 823 + /* allow userland write sysfs file */ 824 + dev_attr_bluetooth.store = store_bluetooth; 825 + dev_attr_wlan.store = store_wlan; 826 + dev_attr_threeg.store = store_threeg; 827 + dev_attr_bluetooth.attr.mode |= S_IWUSR; 828 + dev_attr_wlan.attr.mode |= S_IWUSR; 829 + dev_attr_threeg.attr.mode |= S_IWUSR; 830 + } 1008 831 1009 832 /* disable hardware control by fn key */ 1010 833 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data); ··· 1055 874 if (acpi_disabled) 1056 875 return -ENODEV; 1057 876 1058 - if (force || dmi_check_system(msi_dmi_table)) 1059 - old_ec_model = 1; 877 + dmi_check_system(msi_dmi_table); 878 + if (!quirks) 879 + /* quirks may be NULL if no match in DMI table */ 880 + quirks = &quirk_load_scm_model; 881 + if (force) 882 + quirks = &quirk_old_ec_model; 1060 883 1061 - if (!old_ec_model) 884 + if (!quirks->old_ec_model) 1062 885 get_threeg_exists(); 1063 - 1064 - if (!old_ec_model && dmi_check_system(msi_load_scm_models_dmi_table)) 1065 - load_scm_model = 1; 1066 886 1067 887 if (auto_brightness < 0 || auto_brightness > 2) 1068 888 return -EINVAL; 1069 889 1070 890 /* Register backlight stuff */ 1071 891 1072 - if (acpi_video_backlight_support()) { 892 + if (!quirks->old_ec_model || acpi_video_backlight_support()) { 1073 893 pr_info("Brightness ignored, must be controlled by ACPI video driver\n"); 1074 894 } else { 1075 895 struct backlight_properties props; ··· 1100 918 if (ret) 1101 919 goto fail_platform_device1; 1102 920 1103 - if (load_scm_model && (load_scm_model_init(msipf_device) < 0)) { 921 + if (quirks->load_scm_model && (load_scm_model_init(msipf_device) < 0)) { 1104 922 ret = -EINVAL; 1105 923 goto fail_platform_device1; 1106 924 } ··· 1110 928 if (ret) 1111 929 goto fail_platform_device2; 1112 930 1113 - if (!old_ec_model) { 931 + if (!quirks->old_ec_model) { 1114 932 if (threeg_exists) 1115 933 ret = device_create_file(&msipf_device->dev, 1116 934 &dev_attr_threeg); 1117 935 if (ret) 1118 936 goto fail_platform_device2; 937 + } else { 938 + ret = sysfs_create_group(&msipf_device->dev.kobj, 939 + &msipf_old_attribute_group); 940 + if (ret) 941 + goto fail_platform_device2; 942 + 943 + /* Disable automatic brightness control by default because 944 + * this module was probably loaded to do brightness control in 945 + * software. */ 946 + 947 + if (auto_brightness != 2) 948 + set_auto_brightness(auto_brightness); 1119 949 } 1120 - 1121 - /* Disable automatic brightness control by default because 1122 - * this module was probably loaded to do brightness control in 1123 - * software. */ 1124 - 1125 - if (auto_brightness != 2) 1126 - set_auto_brightness(auto_brightness); 1127 950 1128 951 pr_info("driver " MSI_DRIVER_VERSION " successfully loaded\n"); 1129 952 ··· 1136 949 1137 950 fail_platform_device2: 1138 951 1139 - if (load_scm_model) { 952 + if (quirks->load_scm_model) { 1140 953 i8042_remove_filter(msi_laptop_i8042_filter); 1141 - cancel_delayed_work_sync(&msi_rfkill_work); 954 + cancel_delayed_work_sync(&msi_rfkill_dwork); 955 + cancel_work_sync(&msi_rfkill_work); 1142 956 rfkill_cleanup(); 1143 957 } 1144 958 platform_device_del(msipf_device); ··· 1161 973 1162 974 static void __exit msi_cleanup(void) 1163 975 { 1164 - if (load_scm_model) { 976 + if (quirks->load_scm_model) { 1165 977 i8042_remove_filter(msi_laptop_i8042_filter); 1166 978 msi_laptop_input_destroy(); 1167 - cancel_delayed_work_sync(&msi_rfkill_work); 979 + cancel_delayed_work_sync(&msi_rfkill_dwork); 980 + cancel_work_sync(&msi_rfkill_work); 1168 981 rfkill_cleanup(); 1169 982 } 1170 983 1171 984 sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); 1172 - if (!old_ec_model && threeg_exists) 985 + if (!quirks->old_ec_model && threeg_exists) 1173 986 device_remove_file(&msipf_device->dev, &dev_attr_threeg); 1174 987 platform_device_unregister(msipf_device); 1175 988 platform_driver_unregister(&msipf_driver); 1176 989 backlight_device_unregister(msibl_device); 1177 990 1178 - /* Enable automatic brightness control again */ 1179 - if (auto_brightness != 2) 1180 - set_auto_brightness(1); 991 + if (quirks->old_ec_model) { 992 + /* Enable automatic brightness control again */ 993 + if (auto_brightness != 2) 994 + set_auto_brightness(1); 995 + } 1181 996 1182 997 pr_info("driver unloaded\n"); 1183 998 } ··· 1202 1011 MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*"); 1203 1012 MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*"); 1204 1013 MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*"); 1014 + MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnU90/U100:*");
+146 -78
drivers/platform/x86/msi-wmi.c
··· 34 34 MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver"); 35 35 MODULE_LICENSE("GPL"); 36 36 37 - MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45"); 38 - MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"); 39 - 40 37 #define DRV_NAME "msi-wmi" 41 38 42 39 #define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45" 43 - #define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2" 40 + #define MSIWMI_MSI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2" 41 + #define MSIWMI_WIND_EVENT_GUID "5B3CC38A-40D9-7245-8AE6-1145B751BE3F" 44 42 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) 51 - 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} 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 */ 58 61 }; 59 - static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1]; 62 + static struct key_entry msi_wmi_keymap[] = { 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 }, 95 + }; 60 96 61 97 static struct backlight_device *backlight; 62 98 ··· 185 149 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 186 150 static struct key_entry *key; 187 151 union acpi_object *obj; 188 - ktime_t cur; 189 152 acpi_status status; 190 153 191 154 status = wmi_get_event_data(value, &response); ··· 200 165 pr_debug("Eventcode: 0x%x\n", eventcode); 201 166 key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev, 202 167 eventcode); 203 - if (key) { 204 - ktime_t diff; 205 - cur = ktime_get_real(); 206 - diff = ktime_sub(cur, last_pressed[key->code - 207 - SCANCODE_BASE]); 208 - /* Ignore event if the same event happened in a 50 ms 168 + if (!key) { 169 + pr_info("Unknown key pressed - %x\n", eventcode); 170 + goto msi_wmi_notify_exit; 171 + } 172 + 173 + if (event_wmi->quirk_last_pressed) { 174 + ktime_t cur = ktime_get_real(); 175 + ktime_t diff = ktime_sub(cur, last_pressed); 176 + /* Ignore event if any event happened in a 50 ms 209 177 timeframe -> Key press may result in 10-20 GPEs */ 210 178 if (ktime_to_us(diff) < 1000 * 50) { 211 179 pr_debug("Suppressed key event 0x%X - " 212 180 "Last press was %lld us ago\n", 213 181 key->code, ktime_to_us(diff)); 214 - return; 182 + goto msi_wmi_notify_exit; 215 183 } 216 - last_pressed[key->code - SCANCODE_BASE] = cur; 184 + last_pressed = cur; 185 + } 217 186 218 - if (key->type == KE_KEY && 219 - /* Brightness is served via acpi video driver */ 220 - (!acpi_video_backlight_support() || 221 - (key->code != MSI_WMI_BRIGHTNESSUP && 222 - key->code != MSI_WMI_BRIGHTNESSDOWN))) { 223 - pr_debug("Send key: 0x%X - " 224 - "Input layer keycode: %d\n", 225 - key->code, key->keycode); 226 - sparse_keymap_report_entry(msi_wmi_input_dev, 227 - key, 1, true); 228 - } 229 - } else 230 - pr_info("Unknown key pressed - %x\n", eventcode); 187 + if (key->type == KE_KEY && 188 + /* Brightness is served via acpi video driver */ 189 + (backlight || 190 + (key->code != MSI_KEY_BRIGHTNESSUP && 191 + key->code != MSI_KEY_BRIGHTNESSDOWN))) { 192 + pr_debug("Send key: 0x%X - Input layer keycode: %d\n", 193 + key->code, key->keycode); 194 + sparse_keymap_report_entry(msi_wmi_input_dev, key, 1, 195 + true); 196 + } 231 197 } else 232 198 pr_info("Unknown event received\n"); 199 + 200 + msi_wmi_notify_exit: 233 201 kfree(response.pointer); 202 + } 203 + 204 + static int __init msi_wmi_backlight_setup(void) 205 + { 206 + int err; 207 + struct backlight_properties props; 208 + 209 + memset(&props, 0, sizeof(struct backlight_properties)); 210 + props.type = BACKLIGHT_PLATFORM; 211 + props.max_brightness = ARRAY_SIZE(backlight_map) - 1; 212 + backlight = backlight_device_register(DRV_NAME, NULL, NULL, 213 + &msi_backlight_ops, 214 + &props); 215 + if (IS_ERR(backlight)) 216 + return PTR_ERR(backlight); 217 + 218 + err = bl_get(NULL); 219 + if (err < 0) { 220 + backlight_device_unregister(backlight); 221 + return err; 222 + } 223 + 224 + backlight->props.brightness = err; 225 + 226 + return 0; 234 227 } 235 228 236 229 static int __init msi_wmi_input_setup(void) ··· 282 219 if (err) 283 220 goto err_free_keymap; 284 221 285 - memset(last_pressed, 0, sizeof(last_pressed)); 222 + last_pressed = ktime_set(0, 0); 286 223 287 224 return 0; 288 225 ··· 296 233 static int __init msi_wmi_init(void) 297 234 { 298 235 int err; 236 + int i; 299 237 300 - if (!wmi_has_guid(MSIWMI_EVENT_GUID)) { 301 - pr_err("This machine doesn't have MSI-hotkeys through WMI\n"); 302 - return -ENODEV; 303 - } 304 - err = wmi_install_notify_handler(MSIWMI_EVENT_GUID, 238 + for (i = 0; i < ARRAY_SIZE(event_wmis); i++) { 239 + if (!wmi_has_guid(event_wmis[i].guid)) 240 + continue; 241 + 242 + err = msi_wmi_input_setup(); 243 + if (err) { 244 + pr_err("Unable to setup input device\n"); 245 + return err; 246 + } 247 + 248 + err = wmi_install_notify_handler(event_wmis[i].guid, 305 249 msi_wmi_notify, NULL); 306 - if (ACPI_FAILURE(err)) 307 - return -EINVAL; 308 - 309 - err = msi_wmi_input_setup(); 310 - if (err) 311 - goto err_uninstall_notifier; 312 - 313 - if (!acpi_video_backlight_support()) { 314 - struct backlight_properties props; 315 - memset(&props, 0, sizeof(struct backlight_properties)); 316 - props.type = BACKLIGHT_PLATFORM; 317 - props.max_brightness = ARRAY_SIZE(backlight_map) - 1; 318 - backlight = backlight_device_register(DRV_NAME, NULL, NULL, 319 - &msi_backlight_ops, 320 - &props); 321 - if (IS_ERR(backlight)) { 322 - err = PTR_ERR(backlight); 250 + if (ACPI_FAILURE(err)) { 251 + pr_err("Unable to setup WMI notify handler\n"); 323 252 goto err_free_input; 324 253 } 325 254 326 - err = bl_get(NULL); 327 - if (err < 0) 328 - goto err_free_backlight; 329 - 330 - backlight->props.brightness = err; 255 + pr_debug("Event handler installed\n"); 256 + event_wmi = &event_wmis[i]; 257 + break; 331 258 } 332 - pr_debug("Event handler installed\n"); 259 + 260 + if (wmi_has_guid(MSIWMI_BIOS_GUID) && !acpi_video_backlight_support()) { 261 + err = msi_wmi_backlight_setup(); 262 + if (err) { 263 + pr_err("Unable to setup backlight device\n"); 264 + goto err_uninstall_handler; 265 + } 266 + pr_debug("Backlight device created\n"); 267 + } 268 + 269 + if (!event_wmi && !backlight) { 270 + pr_err("This machine doesn't have neither MSI-hotkeys nor backlight through WMI\n"); 271 + return -ENODEV; 272 + } 333 273 334 274 return 0; 335 275 336 - err_free_backlight: 337 - backlight_device_unregister(backlight); 276 + err_uninstall_handler: 277 + if (event_wmi) 278 + wmi_remove_notify_handler(event_wmi->guid); 338 279 err_free_input: 339 - sparse_keymap_free(msi_wmi_input_dev); 340 - input_unregister_device(msi_wmi_input_dev); 341 - err_uninstall_notifier: 342 - wmi_remove_notify_handler(MSIWMI_EVENT_GUID); 280 + if (event_wmi) { 281 + sparse_keymap_free(msi_wmi_input_dev); 282 + input_unregister_device(msi_wmi_input_dev); 283 + } 343 284 return err; 344 285 } 345 286 346 287 static void __exit msi_wmi_exit(void) 347 288 { 348 - if (wmi_has_guid(MSIWMI_EVENT_GUID)) { 349 - wmi_remove_notify_handler(MSIWMI_EVENT_GUID); 289 + if (event_wmi) { 290 + wmi_remove_notify_handler(event_wmi->guid); 350 291 sparse_keymap_free(msi_wmi_input_dev); 351 292 input_unregister_device(msi_wmi_input_dev); 352 - backlight_device_unregister(backlight); 353 293 } 294 + if (backlight) 295 + backlight_device_unregister(backlight); 354 296 } 355 297 356 298 module_init(msi_wmi_init);
+134 -11
drivers/platform/x86/sony-laptop.c
··· 158 158 static int sony_nc_lid_resume_setup(struct platform_device *pd); 159 159 static void sony_nc_lid_resume_cleanup(struct platform_device *pd); 160 160 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 + 161 166 static int sony_nc_highspeed_charging_setup(struct platform_device *pd); 162 167 static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); 163 168 ··· 1246 1241 /* Hybrid GFX switching */ 1247 1242 sony_call_snc_handle(handle, 0x0000, &result); 1248 1243 dprintk("GFX switch event received (reason: %s)\n", 1249 - (result & 0x01) ? 1250 - "switch change" : "unknown"); 1251 - 1252 - /* verify the switch state 1253 - * 1: discrete GFX 1254 - * 0: integrated GFX 1255 - */ 1256 - sony_call_snc_handle(handle, 0x0100, &result); 1244 + (result == 0x1) ? "switch change" : 1245 + (result == 0x2) ? "output switch" : 1246 + (result == 0x3) ? "output switch" : 1247 + ""); 1257 1248 1258 1249 ev_type = GFX_SWITCH; 1259 - real_ev = result & 0xff; 1250 + real_ev = __sony_nc_gfx_switch_status_get(); 1260 1251 break; 1261 1252 1262 1253 default: ··· 1351 1350 pr_err("couldn't set up thermal profile function (%d)\n", 1352 1351 result); 1353 1352 break; 1353 + case 0x0128: 1354 + case 0x0146: 1355 + result = sony_nc_gfx_switch_setup(pf_device, handle); 1356 + if (result) 1357 + pr_err("couldn't set up GFX Switch status (%d)\n", 1358 + result); 1359 + break; 1354 1360 case 0x0131: 1355 1361 result = sony_nc_highspeed_charging_setup(pf_device); 1356 1362 if (result) ··· 1373 1365 break; 1374 1366 case 0x0137: 1375 1367 case 0x0143: 1368 + case 0x014b: 1369 + case 0x014c: 1376 1370 result = sony_nc_kbd_backlight_setup(pf_device, handle); 1377 1371 if (result) 1378 1372 pr_err("couldn't set up keyboard backlight function (%d)\n", ··· 1424 1414 case 0x0122: 1425 1415 sony_nc_thermal_cleanup(pd); 1426 1416 break; 1417 + case 0x0128: 1418 + case 0x0146: 1419 + sony_nc_gfx_switch_cleanup(pd); 1420 + break; 1427 1421 case 0x0131: 1428 1422 sony_nc_highspeed_charging_cleanup(pd); 1429 1423 break; ··· 1437 1423 break; 1438 1424 case 0x0137: 1439 1425 case 0x0143: 1426 + case 0x014b: 1427 + case 0x014c: 1440 1428 sony_nc_kbd_backlight_cleanup(pd); 1441 1429 break; 1442 1430 default: ··· 1483 1467 break; 1484 1468 case 0x0137: 1485 1469 case 0x0143: 1470 + case 0x014b: 1471 + case 0x014c: 1486 1472 sony_nc_kbd_backlight_resume(); 1487 1473 break; 1488 1474 default: ··· 1552 1534 int argument = sony_rfkill_address[(long) data] + 0x100; 1553 1535 1554 1536 if (!blocked) 1555 - argument |= 0x030000; 1537 + argument |= 0x070000; 1556 1538 1557 1539 return sony_call_snc_handle(sony_rfkill_handle, argument, &result); 1558 1540 } ··· 2351 2333 return 0; 2352 2334 2353 2335 liderror: 2354 - for (; i > 0; i--) 2336 + for (i--; i >= 0; i--) 2355 2337 device_remove_file(&pd->dev, &lid_ctl->attrs[i]); 2356 2338 2357 2339 kfree(lid_ctl); ··· 2370 2352 2371 2353 kfree(lid_ctl); 2372 2354 lid_ctl = NULL; 2355 + } 2356 + } 2357 + 2358 + /* GFX Switch position */ 2359 + enum gfx_switch { 2360 + SPEED, 2361 + STAMINA, 2362 + AUTO 2363 + }; 2364 + struct snc_gfx_switch_control { 2365 + struct device_attribute attr; 2366 + unsigned int handle; 2367 + }; 2368 + static struct snc_gfx_switch_control *gfxs_ctl; 2369 + 2370 + /* returns 0 for speed, 1 for stamina */ 2371 + static int __sony_nc_gfx_switch_status_get(void) 2372 + { 2373 + unsigned int result; 2374 + 2375 + if (sony_call_snc_handle(gfxs_ctl->handle, 0x0100, &result)) 2376 + return -EIO; 2377 + 2378 + switch (gfxs_ctl->handle) { 2379 + case 0x0146: 2380 + /* 1: discrete GFX (speed) 2381 + * 0: integrated GFX (stamina) 2382 + */ 2383 + return result & 0x1 ? SPEED : STAMINA; 2384 + break; 2385 + case 0x0128: 2386 + /* it's a more elaborated bitmask, for now: 2387 + * 2: integrated GFX (stamina) 2388 + * 0: discrete GFX (speed) 2389 + */ 2390 + dprintk("GFX Status: 0x%x\n", result); 2391 + return result & 0x80 ? AUTO : 2392 + result & 0x02 ? STAMINA : SPEED; 2393 + break; 2394 + } 2395 + return -EINVAL; 2396 + } 2397 + 2398 + static ssize_t sony_nc_gfx_switch_status_show(struct device *dev, 2399 + struct device_attribute *attr, 2400 + char *buffer) 2401 + { 2402 + int pos = __sony_nc_gfx_switch_status_get(); 2403 + 2404 + if (pos < 0) 2405 + return pos; 2406 + 2407 + return snprintf(buffer, PAGE_SIZE, "%s\n", pos ? "speed" : "stamina"); 2408 + } 2409 + 2410 + static int sony_nc_gfx_switch_setup(struct platform_device *pd, 2411 + unsigned int handle) 2412 + { 2413 + unsigned int result; 2414 + 2415 + gfxs_ctl = kzalloc(sizeof(struct snc_gfx_switch_control), GFP_KERNEL); 2416 + if (!gfxs_ctl) 2417 + return -ENOMEM; 2418 + 2419 + gfxs_ctl->handle = handle; 2420 + 2421 + sysfs_attr_init(&gfxs_ctl->attr.attr); 2422 + gfxs_ctl->attr.attr.name = "gfx_switch_status"; 2423 + gfxs_ctl->attr.attr.mode = S_IRUGO; 2424 + gfxs_ctl->attr.show = sony_nc_gfx_switch_status_show; 2425 + 2426 + result = device_create_file(&pd->dev, &gfxs_ctl->attr); 2427 + if (result) 2428 + goto gfxerror; 2429 + 2430 + return 0; 2431 + 2432 + gfxerror: 2433 + kfree(gfxs_ctl); 2434 + gfxs_ctl = NULL; 2435 + 2436 + return result; 2437 + } 2438 + 2439 + static void sony_nc_gfx_switch_cleanup(struct platform_device *pd) 2440 + { 2441 + if (gfxs_ctl) { 2442 + device_remove_file(&pd->dev, &gfxs_ctl->attr); 2443 + 2444 + kfree(gfxs_ctl); 2445 + gfxs_ctl = NULL; 2373 2446 } 2374 2447 } 2375 2448 ··· 2642 2533 lvl_table_len = 9; 2643 2534 break; 2644 2535 case 0x143: 2536 + case 0x14b: 2537 + case 0x14c: 2645 2538 lvl_table_len = 16; 2646 2539 break; 2647 2540 } ··· 2693 2582 ops = &sony_backlight_ng_ops; 2694 2583 sony_bl_props.cmd_base = 0x3000; 2695 2584 sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props); 2585 + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; 2586 + 2587 + } else if (sony_find_snc_handle(0x14b) >= 0) { 2588 + ops = &sony_backlight_ng_ops; 2589 + sony_bl_props.cmd_base = 0x3000; 2590 + sony_nc_backlight_ng_read_limits(0x14b, &sony_bl_props); 2591 + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; 2592 + 2593 + } else if (sony_find_snc_handle(0x14c) >= 0) { 2594 + ops = &sony_backlight_ng_ops; 2595 + sony_bl_props.cmd_base = 0x3000; 2596 + sony_nc_backlight_ng_read_limits(0x14c, &sony_bl_props); 2696 2597 max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; 2697 2598 2698 2599 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
+12 -5
drivers/platform/x86/thinkpad_acpi.c
··· 209 209 TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */ 210 210 TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* thermal table changed */ 211 211 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 */ 215 214 216 215 /* Misc */ 217 216 TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */ ··· 3628 3629 "a sensor reports something is extremely hot!\n"); 3629 3630 /* recommended action: immediate sleep/hibernate */ 3630 3631 break; 3632 + case TP_HKEY_EV_AC_CHANGED: 3633 + /* X120e, X121e, X220, X220i, X220t, X230, T420, T420s, W520: 3634 + * AC status changed; can be triggered by plugging or 3635 + * unplugging AC adapter, docking or undocking. */ 3636 + 3637 + /* fallthrough */ 3631 3638 3632 3639 case TP_HKEY_EV_KEY_NUMLOCK: 3633 3640 case TP_HKEY_EV_KEY_FN: ··· 8579 8574 return s && strlen(s) >= 8 && 8580 8575 tpacpi_is_fw_digit(s[0]) && 8581 8576 tpacpi_is_fw_digit(s[1]) && 8582 - s[2] == t && s[3] == 'T' && 8577 + s[2] == t && 8578 + (s[3] == 'T' || s[3] == 'N') && 8583 8579 tpacpi_is_fw_digit(s[4]) && 8584 8580 tpacpi_is_fw_digit(s[5]); 8585 8581 } ··· 8613 8607 return -ENOMEM; 8614 8608 8615 8609 /* Really ancient ThinkPad 240X will fail this, which is fine */ 8616 - if (!tpacpi_is_valid_fw_id(tp->bios_version_str, 'E')) 8610 + if (!(tpacpi_is_valid_fw_id(tp->bios_version_str, 'E') || 8611 + tpacpi_is_valid_fw_id(tp->bios_version_str, 'C'))) 8617 8612 return 0; 8618 8613 8619 8614 tp->bios_model = tp->bios_version_str[0]