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

Merge tag 'platform-drivers-x86-v3.19-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86

Pull x86 platform driver update from Darren Hart:
- thinkpad-acpi: Switch to software mute, cleanups
- acerhdf: Bang-bang thermal governor, new models, cleanups
- dell-laptop: New keyboard backlight support and documentation
- toshiba_acpi: Keyboard backlight updates, hotkey handling
- dell-wmi: Keypress filtering, WMI event processing
- eeepc-laptop: Multiple cleanups, improved error handling, documentation
- hp_wireless: Inform the user if hp_wireless_input_setup()/add() fails
- misc: Code cleanups, quirks, various new IDs

* tag 'platform-drivers-x86-v3.19-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (33 commits)
platform/x86/acerhdf: Still depends on THERMAL
Documentation: Add entry for dell-laptop sysfs interface
acpi: Remove _OSI(Linux) for ThinkPads
thinkpad-acpi: Try to use full software mute control
acerhdf: minor clean up
acerhdf: added critical trip point
acerhdf: Use bang-bang thermal governor
acerhdf: Adding support for new models
acerhdf: Adding support for "manual mode"
dell-smo8800: Add more ACPI ids and change description of driver
platform: x86: dell-laptop: Add support for keyboard backlight
toshiba_acpi: Add keyboard backlight mode change event
toshiba_acpi: Change notify funtion to handle more events
toshiba_acpi: Move hotkey enabling code to its own function
dell-wmi: Don't report keypresses on keybord illumination change
dell-wmi: Don't report keypresses for radio state changes
hp_wireless: Inform the user if hp_wireless_input_setup()/add() fails
toshiba-acpi: Add missing ID (TOS6207)
Sony-laptop: Deletion of an unnecessary check before the function call "pci_dev_put"
platform: x86: Deletion of checks before backlight_device_unregister()
...

+1781 -415
+60
Documentation/ABI/testing/sysfs-platform-dell-laptop
··· 1 + What: /sys/class/leds/dell::kbd_backlight/als_setting 2 + Date: December 2014 3 + KernelVersion: 3.19 4 + Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, 5 + Pali Rohár <pali.rohar@gmail.com> 6 + Description: 7 + This file allows to control the automatic keyboard 8 + illumination mode on some systems that have an ambient 9 + light sensor. Write 1 to this file to enable the auto 10 + mode, 0 to disable it. 11 + 12 + What: /sys/class/leds/dell::kbd_backlight/start_triggers 13 + Date: December 2014 14 + KernelVersion: 3.19 15 + Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, 16 + Pali Rohár <pali.rohar@gmail.com> 17 + Description: 18 + This file allows to control the input triggers that 19 + turn on the keyboard backlight illumination that is 20 + disabled because of inactivity. 21 + Read the file to see the triggers available. The ones 22 + enabled are preceded by '+', those disabled by '-'. 23 + 24 + To enable a trigger, write its name preceded by '+' to 25 + this file. To disable a trigger, write its name preceded 26 + by '-' instead. 27 + 28 + For example, to enable the keyboard as trigger run: 29 + echo +keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers 30 + To disable it: 31 + echo -keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers 32 + 33 + Note that not all the available triggers can be configured. 34 + 35 + What: /sys/class/leds/dell::kbd_backlight/stop_timeout 36 + Date: December 2014 37 + KernelVersion: 3.19 38 + Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>, 39 + Pali Rohár <pali.rohar@gmail.com> 40 + Description: 41 + This file allows to specify the interval after which the 42 + keyboard illumination is disabled because of inactivity. 43 + The timeouts are expressed in seconds, minutes, hours and 44 + days, for which the symbols are 's', 'm', 'h' and 'd' 45 + respectively. 46 + 47 + To configure the timeout, write to this file a value along 48 + with any the above units. If no unit is specified, the value 49 + is assumed to be expressed in seconds. 50 + 51 + For example, to set the timeout to 10 minutes run: 52 + echo 10m > /sys/class/leds/dell::kbd_backlight/stop_timeout 53 + 54 + Note that when this file is read, the returned value might be 55 + expressed in a different unit than the one used when the timeout 56 + was set. 57 + 58 + Also note that only some timeouts are supported and that 59 + some systems might fall back to a specific timeout in case 60 + an invalid timeout is written to this file.
-54
drivers/acpi/blacklist.c
··· 305 305 */ 306 306 307 307 /* 308 - * Lenovo has a mix of systems OSI(Linux) situations 309 - * and thus we can not wildcard the vendor. 310 - * 311 - * _OSI(Linux) helps sound 312 - * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"), 313 - * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"), 314 - * T400, T500 315 - * _OSI(Linux) has Linux specific hooks 316 - * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"), 317 - * _OSI(Linux) is a NOP: 318 - * DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"), 319 - * DMI_MATCH(DMI_PRODUCT_VERSION, "LENOVO3000 V100"), 320 - */ 321 - { 322 - .callback = dmi_enable_osi_linux, 323 - .ident = "Lenovo ThinkPad R61", 324 - .matches = { 325 - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 326 - DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"), 327 - }, 328 - }, 329 - { 330 - .callback = dmi_enable_osi_linux, 331 - .ident = "Lenovo ThinkPad T61", 332 - .matches = { 333 - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 334 - DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"), 335 - }, 336 - }, 337 - { 338 - .callback = dmi_enable_osi_linux, 339 - .ident = "Lenovo ThinkPad X61", 340 - .matches = { 341 - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 342 - DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"), 343 - }, 344 - }, 345 - { 346 - .callback = dmi_enable_osi_linux, 347 - .ident = "Lenovo ThinkPad T400", 348 - .matches = { 349 - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 350 - DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T400"), 351 - }, 352 - }, 353 - { 354 - .callback = dmi_enable_osi_linux, 355 - .ident = "Lenovo ThinkPad T500", 356 - .matches = { 357 - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 358 - DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T500"), 359 - }, 360 - }, 361 - /* 362 308 * Without this this EEEpc exports a non working WMI interface, with 363 309 * this it exports a working "good old" eeepc_laptop interface, fixing 364 310 * both brightness control, and rfkill not working.
+4 -3
drivers/platform/x86/Kconfig
··· 38 38 39 39 config ACERHDF 40 40 tristate "Acer Aspire One temperature and fan driver" 41 - depends on THERMAL && ACPI 41 + depends on ACPI && THERMAL 42 + select THERMAL_GOV_BANG_BANG 42 43 ---help--- 43 44 This is a driver for Acer Aspire One netbooks. It allows to access 44 45 the temperature sensor and to control the fan. ··· 129 128 be called dell-wmi-aio. 130 129 131 130 config DELL_SMO8800 132 - tristate "Dell Latitude freefall driver (ACPI SMO8800/SMO8810)" 131 + tristate "Dell Latitude freefall driver (ACPI SMO88XX)" 133 132 depends on ACPI 134 133 ---help--- 135 - Say Y here if you want to support SMO8800/SMO8810 freefall device 134 + Say Y here if you want to support SMO88XX freefall devices 136 135 on Dell Latitude laptops. 137 136 138 137 To compile this driver as a module, choose M here: the module will
+170 -95
drivers/platform/x86/acerhdf.c
··· 50 50 */ 51 51 #undef START_IN_KERNEL_MODE 52 52 53 - #define DRV_VER "0.5.26" 53 + #define DRV_VER "0.7.0" 54 54 55 55 /* 56 56 * According to the Atom N270 datasheet, ··· 119 119 u8 cmd_auto; 120 120 }; 121 121 122 + struct manualcmd { 123 + u8 mreg; 124 + u8 moff; 125 + }; 126 + 127 + /* default register and command to disable fan in manual mode */ 128 + static const struct manualcmd mcmd = { 129 + .mreg = 0x94, 130 + .moff = 0xff, 131 + }; 132 + 122 133 /* BIOS settings */ 123 - struct bios_settings_t { 134 + struct bios_settings { 124 135 const char *vendor; 125 136 const char *product; 126 137 const char *version; 127 - unsigned char fanreg; 128 - unsigned char tempreg; 138 + u8 fanreg; 139 + u8 tempreg; 129 140 struct fancmd cmd; 141 + int mcmd_enable; 130 142 }; 131 143 132 144 /* Register addresses and values for different BIOS versions */ 133 - static const struct bios_settings_t bios_tbl[] = { 145 + static const struct bios_settings bios_tbl[] = { 134 146 /* AOA110 */ 135 - {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, 136 - {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, 137 - {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, 138 - {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, 139 - {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, 140 - {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} }, 141 - {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, 142 - {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, 143 - {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, 147 + {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00}, 0}, 148 + {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0}, 149 + {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00}, 0}, 150 + {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00}, 0}, 151 + {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00}, 0}, 152 + {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00}, 0}, 153 + {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00}, 0}, 154 + {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00}, 0}, 155 + {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00}, 0}, 144 156 /* AOA150 */ 145 - {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, 146 - {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} }, 147 - {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, 148 - {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} }, 149 - {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} }, 150 - {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} }, 151 - {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} }, 152 - {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, 157 + {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0}, 158 + {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00}, 0}, 159 + {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00}, 0}, 160 + {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00}, 0}, 161 + {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00}, 0}, 162 + {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00}, 0}, 163 + {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00}, 0}, 164 + {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00}, 0}, 153 165 /* LT1005u */ 154 - {"Acer", "LT-10Q", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, 166 + {"Acer", "LT-10Q", "v0.3310", 0x55, 0x58, {0x20, 0x00}, 0}, 155 167 /* Acer 1410 */ 156 - {"Acer", "Aspire 1410", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, 157 - {"Acer", "Aspire 1410", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, 158 - {"Acer", "Aspire 1410", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, 159 - {"Acer", "Aspire 1410", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, 160 - {"Acer", "Aspire 1410", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, 161 - {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, 162 - {"Acer", "Aspire 1410", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, 163 - {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, 164 - {"Acer", "Aspire 1410", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, 165 - {"Acer", "Aspire 1410", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, 166 - {"Acer", "Aspire 1410", "v1.3314", 0x55, 0x58, {0x9e, 0x00} }, 168 + {"Acer", "Aspire 1410", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0}, 169 + {"Acer", "Aspire 1410", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0}, 170 + {"Acer", "Aspire 1410", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0}, 171 + {"Acer", "Aspire 1410", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0}, 172 + {"Acer", "Aspire 1410", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0}, 173 + {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0}, 174 + {"Acer", "Aspire 1410", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0}, 175 + {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0}, 176 + {"Acer", "Aspire 1410", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0}, 177 + {"Acer", "Aspire 1410", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0}, 178 + {"Acer", "Aspire 1410", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0}, 167 179 /* Acer 1810xx */ 168 - {"Acer", "Aspire 1810TZ", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, 169 - {"Acer", "Aspire 1810T", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, 170 - {"Acer", "Aspire 1810TZ", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, 171 - {"Acer", "Aspire 1810T", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, 172 - {"Acer", "Aspire 1810TZ", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, 173 - {"Acer", "Aspire 1810T", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, 174 - {"Acer", "Aspire 1810TZ", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, 175 - {"Acer", "Aspire 1810T", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, 176 - {"Acer", "Aspire 1810TZ", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, 177 - {"Acer", "Aspire 1810T", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, 178 - {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, 179 - {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, 180 - {"Acer", "Aspire 1810TZ", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, 181 - {"Acer", "Aspire 1810T", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, 182 - {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, 183 - {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, 184 - {"Acer", "Aspire 1810TZ", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, 185 - {"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, 186 - {"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, 187 - {"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, 188 - {"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00} }, 189 - {"Acer", "Aspire 1810T", "v1.3314", 0x55, 0x58, {0x9e, 0x00} }, 180 + {"Acer", "Aspire 1810TZ", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0}, 181 + {"Acer", "Aspire 1810T", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0}, 182 + {"Acer", "Aspire 1810TZ", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0}, 183 + {"Acer", "Aspire 1810T", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0}, 184 + {"Acer", "Aspire 1810TZ", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0}, 185 + {"Acer", "Aspire 1810T", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0}, 186 + {"Acer", "Aspire 1810TZ", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0}, 187 + {"Acer", "Aspire 1810T", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0}, 188 + {"Acer", "Aspire 1810TZ", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0}, 189 + {"Acer", "Aspire 1810T", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0}, 190 + {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0}, 191 + {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0}, 192 + {"Acer", "Aspire 1810TZ", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0}, 193 + {"Acer", "Aspire 1810T", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0}, 194 + {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0}, 195 + {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0}, 196 + {"Acer", "Aspire 1810TZ", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0}, 197 + {"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0}, 198 + {"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0}, 199 + {"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0}, 200 + {"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0}, 201 + {"Acer", "Aspire 1810T", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0}, 202 + /* Acer 5755G */ 203 + {"Acer", "Aspire 5755G", "V1.20", 0xab, 0xb4, {0x00, 0x08}, 0}, 204 + {"Acer", "Aspire 5755G", "V1.21", 0xab, 0xb3, {0x00, 0x08}, 0}, 205 + /* Acer 521 */ 206 + {"Acer", "AO521", "V1.11", 0x55, 0x58, {0x1f, 0x00}, 0}, 190 207 /* Acer 531 */ 191 - {"Acer", "AO531h", "v0.3104", 0x55, 0x58, {0x20, 0x00} }, 192 - {"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00} }, 193 - {"Acer", "AO531h", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, 208 + {"Acer", "AO531h", "v0.3104", 0x55, 0x58, {0x20, 0x00}, 0}, 209 + {"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00}, 0}, 210 + {"Acer", "AO531h", "v0.3304", 0x55, 0x58, {0x20, 0x00}, 0}, 194 211 /* Acer 751 */ 195 - {"Acer", "AO751h", "V0.3212", 0x55, 0x58, {0x21, 0x00} }, 212 + {"Acer", "AO751h", "V0.3206", 0x55, 0x58, {0x21, 0x00}, 0}, 213 + {"Acer", "AO751h", "V0.3212", 0x55, 0x58, {0x21, 0x00}, 0}, 214 + /* Acer 753 */ 215 + {"Acer", "Aspire One 753", "V1.24", 0x93, 0xac, {0x14, 0x04}, 1}, 196 216 /* Acer 1825 */ 197 - {"Acer", "Aspire 1825PTZ", "V1.3118", 0x55, 0x58, {0x9e, 0x00} }, 198 - {"Acer", "Aspire 1825PTZ", "V1.3127", 0x55, 0x58, {0x9e, 0x00} }, 217 + {"Acer", "Aspire 1825PTZ", "V1.3118", 0x55, 0x58, {0x9e, 0x00}, 0}, 218 + {"Acer", "Aspire 1825PTZ", "V1.3127", 0x55, 0x58, {0x9e, 0x00}, 0}, 219 + /* Acer Extensa 5420 */ 220 + {"Acer", "Extensa 5420", "V1.17", 0x93, 0xac, {0x14, 0x04}, 1}, 221 + /* Acer Aspire 5315 */ 222 + {"Acer", "Aspire 5315", "V1.19", 0x93, 0xac, {0x14, 0x04}, 1}, 223 + /* Acer Aspire 5739 */ 224 + {"Acer", "Aspire 5739G", "V1.3311", 0x55, 0x58, {0x20, 0x00}, 0}, 199 225 /* Acer TravelMate 7730 */ 200 - {"Acer", "TravelMate 7730G", "v0.3509", 0x55, 0x58, {0xaf, 0x00} }, 226 + {"Acer", "TravelMate 7730G", "v0.3509", 0x55, 0x58, {0xaf, 0x00}, 0}, 227 + /* Acer TravelMate TM8573T */ 228 + {"Acer", "TM8573T", "V1.13", 0x93, 0xa8, {0x14, 0x04}, 1}, 201 229 /* Gateway */ 202 - {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, 203 - {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} }, 204 - {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x9e, 0x00} }, 205 - {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00} }, 206 - {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00} }, 207 - {"Gateway", "LT31", "v1.3303t", 0x55, 0x58, {0x9e, 0x00} }, 230 + {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00}, 0}, 231 + {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00}, 0}, 232 + {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x9e, 0x00}, 0}, 233 + {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0}, 234 + {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0}, 235 + {"Gateway", "LT31", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0}, 208 236 /* Packard Bell */ 209 - {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} }, 210 - {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, 211 - {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, 212 - {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, 213 - {"Packard Bell", "ENBFT", "V1.3118", 0x55, 0x58, {0x9e, 0x00} }, 214 - {"Packard Bell", "ENBFT", "V1.3127", 0x55, 0x58, {0x9e, 0x00} }, 215 - {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, 216 - {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, 217 - {"Packard Bell", "DOTMU", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, 218 - {"Packard Bell", "DOTMU", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, 219 - {"Packard Bell", "DOTMU", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, 220 - {"Packard Bell", "DOTMU", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, 221 - {"Packard Bell", "DOTMU", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, 222 - {"Packard Bell", "DOTMU", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, 223 - {"Packard Bell", "DOTMA", "v1.3201", 0x55, 0x58, {0x9e, 0x00} }, 224 - {"Packard Bell", "DOTMA", "v1.3302", 0x55, 0x58, {0x9e, 0x00} }, 225 - {"Packard Bell", "DOTMA", "v1.3303t", 0x55, 0x58, {0x9e, 0x00} }, 226 - {"Packard Bell", "DOTVR46", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, 237 + {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00}, 0}, 238 + {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0}, 239 + {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00}, 0}, 240 + {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0}, 241 + {"Packard Bell", "ENBFT", "V1.3118", 0x55, 0x58, {0x9e, 0x00}, 0}, 242 + {"Packard Bell", "ENBFT", "V1.3127", 0x55, 0x58, {0x9e, 0x00}, 0}, 243 + {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0}, 244 + {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0}, 245 + {"Packard Bell", "DOTMU", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0}, 246 + {"Packard Bell", "DOTMU", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0}, 247 + {"Packard Bell", "DOTMU", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0}, 248 + {"Packard Bell", "DOTMU", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0}, 249 + {"Packard Bell", "DOTMU", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0}, 250 + {"Packard Bell", "DOTMU", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0}, 251 + {"Packard Bell", "DOTMA", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0}, 252 + {"Packard Bell", "DOTMA", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0}, 253 + {"Packard Bell", "DOTMA", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0}, 254 + {"Packard Bell", "DOTVR46", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0}, 227 255 /* pewpew-terminator */ 228 - {"", "", "", 0, 0, {0, 0} } 256 + {"", "", "", 0, 0, {0, 0}, 0} 229 257 }; 230 258 231 - static const struct bios_settings_t *bios_cfg __read_mostly; 259 + static const struct bios_settings *bios_cfg __read_mostly; 260 + 261 + /* 262 + * this struct is used to instruct thermal layer to use bang_bang instead of 263 + * default governor for acerhdf 264 + */ 265 + static struct thermal_zone_params acerhdf_zone_params = { 266 + .governor_name = "bang_bang", 267 + }; 232 268 233 269 static int acerhdf_get_temp(int *temp) 234 270 { ··· 311 275 fanstate = state; 312 276 313 277 ec_write(bios_cfg->fanreg, cmd); 278 + 279 + if (bios_cfg->mcmd_enable && state == ACERHDF_FAN_OFF) { 280 + if (verbose) 281 + pr_notice("turning off fan manually\n"); 282 + ec_write(mcmd.mreg, mcmd.moff); 283 + } 314 284 } 315 285 316 286 static void acerhdf_check_param(struct thermal_zone_device *thermal) ··· 443 401 { 444 402 if (trip == 0) 445 403 *type = THERMAL_TRIP_ACTIVE; 404 + else if (trip == 1) 405 + *type = THERMAL_TRIP_CRITICAL; 406 + else 407 + return -EINVAL; 408 + 409 + return 0; 410 + } 411 + 412 + static int acerhdf_get_trip_hyst(struct thermal_zone_device *thermal, int trip, 413 + unsigned long *temp) 414 + { 415 + if (trip != 0) 416 + return -EINVAL; 417 + 418 + *temp = fanon - fanoff; 446 419 447 420 return 0; 448 421 } ··· 467 410 { 468 411 if (trip == 0) 469 412 *temp = fanon; 413 + else if (trip == 1) 414 + *temp = ACERHDF_TEMP_CRIT; 415 + else 416 + return -EINVAL; 470 417 471 418 return 0; 472 419 } ··· 490 429 .get_mode = acerhdf_get_mode, 491 430 .set_mode = acerhdf_set_mode, 492 431 .get_trip_type = acerhdf_get_trip_type, 432 + .get_trip_hyst = acerhdf_get_trip_hyst, 493 433 .get_trip_temp = acerhdf_get_trip_temp, 494 434 .get_crit_temp = acerhdf_get_crit_temp, 495 435 }; ··· 543 481 } 544 482 545 483 if (state == 0) { 546 - /* turn fan off only if below fanoff temperature */ 547 - if ((cur_state == ACERHDF_FAN_AUTO) && 548 - (cur_temp < fanoff)) 484 + if (cur_state == ACERHDF_FAN_AUTO) 549 485 acerhdf_change_fanstate(ACERHDF_FAN_OFF); 550 486 } else { 551 487 if (cur_state == ACERHDF_FAN_OFF) ··· 618 558 static int acerhdf_check_hardware(void) 619 559 { 620 560 char const *vendor, *version, *product; 621 - const struct bios_settings_t *bt = NULL; 561 + const struct bios_settings *bt = NULL; 622 562 623 563 /* get BIOS data */ 624 564 vendor = dmi_get_system_info(DMI_SYS_VENDOR); ··· 720 660 if (IS_ERR(cl_dev)) 721 661 return -EINVAL; 722 662 723 - thz_dev = thermal_zone_device_register("acerhdf", 1, 0, NULL, 724 - &acerhdf_dev_ops, NULL, 0, 663 + thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL, 664 + &acerhdf_dev_ops, 665 + &acerhdf_zone_params, 0, 725 666 (kernelmode) ? interval*1000 : 0); 726 667 if (IS_ERR(thz_dev)) 727 668 return -EINVAL; 669 + 670 + if (strcmp(thz_dev->governor->name, 671 + acerhdf_zone_params.governor_name)) { 672 + pr_err("Didn't get thermal governor %s, perhaps not compiled into thermal subsystem.\n", 673 + acerhdf_zone_params.governor_name); 674 + return -EINVAL; 675 + } 728 676 729 677 return 0; 730 678 } ··· 790 722 MODULE_ALIAS("dmi:*:*Acer*:pnAO751h*:"); 791 723 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1410*:"); 792 724 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1810*:"); 725 + MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5755G:"); 793 726 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1825PTZ:"); 727 + MODULE_ALIAS("dmi:*:*Acer*:pnAO521*:"); 794 728 MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:"); 729 + MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5739G:"); 730 + MODULE_ALIAS("dmi:*:*Acer*:pnAspire*One*753:"); 731 + MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5315:"); 795 732 MODULE_ALIAS("dmi:*:*Acer*:TravelMate*7730G:"); 733 + MODULE_ALIAS("dmi:*:*Acer*:TM8573T:"); 796 734 MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:"); 797 735 MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:"); 798 736 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnAOA*:"); ··· 807 733 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnENBFT*:"); 808 734 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMA*:"); 809 735 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTVR46*:"); 736 + MODULE_ALIAS("dmi:*:*Acer*:pnExtensa 5420*:"); 810 737 811 738 module_init(acerhdf_init); 812 739 module_exit(acerhdf_exit);
+1 -2
drivers/platform/x86/asus-laptop.c
··· 843 843 844 844 static void asus_backlight_exit(struct asus_laptop *asus) 845 845 { 846 - if (asus->backlight_device) 847 - backlight_device_unregister(asus->backlight_device); 846 + backlight_device_unregister(asus->backlight_device); 848 847 asus->backlight_device = NULL; 849 848 } 850 849
+9
drivers/platform/x86/asus-nb-wmi.c
··· 191 191 }, 192 192 { 193 193 .callback = dmi_matched, 194 + .ident = "ASUSTeK COMPUTER INC. X551CA", 195 + .matches = { 196 + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 197 + DMI_MATCH(DMI_PRODUCT_NAME, "X551CA"), 198 + }, 199 + .driver_data = &quirk_asus_wapf4, 200 + }, 201 + { 202 + .callback = dmi_matched, 194 203 .ident = "ASUSTeK COMPUTER INC. X55A", 195 204 .matches = { 196 205 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+1 -2
drivers/platform/x86/asus-wmi.c
··· 1308 1308 1309 1309 static void asus_wmi_backlight_exit(struct asus_wmi *asus) 1310 1310 { 1311 - if (asus->backlight_device) 1312 - backlight_device_unregister(asus->backlight_device); 1311 + backlight_device_unregister(asus->backlight_device); 1313 1312 1314 1313 asus->backlight_device = NULL; 1315 1314 }
+1050 -7
drivers/platform/x86/dell-laptop.c
··· 2 2 * Driver for Dell laptop extras 3 3 * 4 4 * Copyright (c) Red Hat <mjg@redhat.com> 5 + * Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com> 6 + * Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com> 5 7 * 6 - * Based on documentation in the libsmbios package, Copyright (C) 2005 Dell 7 - * Inc. 8 + * Based on documentation in the libsmbios package: 9 + * Copyright (C) 2005-2014 Dell Inc. 8 10 * 9 11 * This program is free software; you can redistribute it and/or modify 10 12 * it under the terms of the GNU General Public License version 2 as ··· 34 32 #include "../../firmware/dcdbas.h" 35 33 36 34 #define BRIGHTNESS_TOKEN 0x7d 35 + #define KBD_LED_OFF_TOKEN 0x01E1 36 + #define KBD_LED_ON_TOKEN 0x01E2 37 + #define KBD_LED_AUTO_TOKEN 0x01E3 38 + #define KBD_LED_AUTO_25_TOKEN 0x02EA 39 + #define KBD_LED_AUTO_50_TOKEN 0x02EB 40 + #define KBD_LED_AUTO_75_TOKEN 0x02EC 41 + #define KBD_LED_AUTO_100_TOKEN 0x02F6 37 42 38 43 /* This structure will be modified by the firmware when we enter 39 44 * system management mode, hence the volatiles */ ··· 71 62 72 63 struct quirk_entry { 73 64 u8 touchpad_led; 65 + 66 + int needs_kbd_timeouts; 67 + /* 68 + * Ordered list of timeouts expressed in seconds. 69 + * The list must end with -1 70 + */ 71 + int kbd_timeouts[]; 74 72 }; 75 73 76 74 static struct quirk_entry *quirks; ··· 91 75 quirks = dmi->driver_data; 92 76 return 1; 93 77 } 78 + 79 + /* 80 + * These values come from Windows utility provided by Dell. If any other value 81 + * is used then BIOS silently set timeout to 0 without any error message. 82 + */ 83 + static struct quirk_entry quirk_dell_xps13_9333 = { 84 + .needs_kbd_timeouts = 1, 85 + .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, 86 + }; 94 87 95 88 static int da_command_address; 96 89 static int da_command_code; ··· 292 267 }, 293 268 .driver_data = &quirk_dell_vostro_v130, 294 269 }, 270 + { 271 + .callback = dmi_matched, 272 + .ident = "Dell XPS13 9333", 273 + .matches = { 274 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 275 + DMI_MATCH(DMI_PRODUCT_NAME, "XPS13 9333"), 276 + }, 277 + .driver_data = &quirk_dell_xps13_9333, 278 + }, 295 279 { } 296 280 }; 297 281 ··· 365 331 } 366 332 } 367 333 368 - static int find_token_location(int tokenid) 334 + static int find_token_id(int tokenid) 369 335 { 370 336 int i; 337 + 371 338 for (i = 0; i < da_num_tokens; i++) { 372 339 if (da_tokens[i].tokenID == tokenid) 373 - return da_tokens[i].location; 340 + return i; 374 341 } 375 342 376 343 return -1; 344 + } 345 + 346 + static int find_token_location(int tokenid) 347 + { 348 + int id; 349 + 350 + id = find_token_id(tokenid); 351 + if (id == -1) 352 + return -1; 353 + 354 + return da_tokens[id].location; 377 355 } 378 356 379 357 static struct calling_interface_buffer * ··· 406 360 dcdbas_smi_request(&command); 407 361 408 362 return buffer; 363 + } 364 + 365 + static inline int dell_smi_error(int value) 366 + { 367 + switch (value) { 368 + case 0: /* Completed successfully */ 369 + return 0; 370 + case -1: /* Completed with error */ 371 + return -EIO; 372 + case -2: /* Function not supported */ 373 + return -ENXIO; 374 + default: /* Unknown error */ 375 + return -EINVAL; 376 + } 409 377 } 410 378 411 379 /* Derived from information in DellWirelessCtl.cpp: ··· 623 563 { 624 564 static bool extended; 625 565 626 - if (str & 0x20) 566 + if (str & I8042_STR_AUXDATA) 627 567 return false; 628 568 629 569 if (unlikely(data == 0xe0)) { ··· 776 716 else 777 717 dell_send_request(buffer, 1, 1); 778 718 779 - out: 719 + out: 780 720 release_buffer(); 781 721 return ret; 782 722 } ··· 800 740 801 741 ret = buffer->output[1]; 802 742 803 - out: 743 + out: 804 744 release_buffer(); 805 745 return ret; 806 746 } ··· 847 787 static void touchpad_led_exit(void) 848 788 { 849 789 led_classdev_unregister(&touchpad_led); 790 + } 791 + 792 + /* 793 + * Derived from information in smbios-keyboard-ctl: 794 + * 795 + * cbClass 4 796 + * cbSelect 11 797 + * Keyboard illumination 798 + * cbArg1 determines the function to be performed 799 + * 800 + * cbArg1 0x0 = Get Feature Information 801 + * cbRES1 Standard return codes (0, -1, -2) 802 + * cbRES2, word0 Bitmap of user-selectable modes 803 + * bit 0 Always off (All systems) 804 + * bit 1 Always on (Travis ATG, Siberia) 805 + * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) 806 + * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off 807 + * bit 4 Auto: Input-activity-based On; input-activity based Off 808 + * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off 809 + * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off 810 + * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off 811 + * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off 812 + * bits 9-15 Reserved for future use 813 + * cbRES2, byte2 Reserved for future use 814 + * cbRES2, byte3 Keyboard illumination type 815 + * 0 Reserved 816 + * 1 Tasklight 817 + * 2 Backlight 818 + * 3-255 Reserved for future use 819 + * cbRES3, byte0 Supported auto keyboard illumination trigger bitmap. 820 + * bit 0 Any keystroke 821 + * bit 1 Touchpad activity 822 + * bit 2 Pointing stick 823 + * bit 3 Any mouse 824 + * bits 4-7 Reserved for future use 825 + * cbRES3, byte1 Supported timeout unit bitmap 826 + * bit 0 Seconds 827 + * bit 1 Minutes 828 + * bit 2 Hours 829 + * bit 3 Days 830 + * bits 4-7 Reserved for future use 831 + * cbRES3, byte2 Number of keyboard light brightness levels 832 + * cbRES4, byte0 Maximum acceptable seconds value (0 if seconds not supported). 833 + * cbRES4, byte1 Maximum acceptable minutes value (0 if minutes not supported). 834 + * cbRES4, byte2 Maximum acceptable hours value (0 if hours not supported). 835 + * cbRES4, byte3 Maximum acceptable days value (0 if days not supported) 836 + * 837 + * cbArg1 0x1 = Get Current State 838 + * cbRES1 Standard return codes (0, -1, -2) 839 + * cbRES2, word0 Bitmap of current mode state 840 + * bit 0 Always off (All systems) 841 + * bit 1 Always on (Travis ATG, Siberia) 842 + * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) 843 + * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off 844 + * bit 4 Auto: Input-activity-based On; input-activity based Off 845 + * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off 846 + * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off 847 + * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off 848 + * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off 849 + * bits 9-15 Reserved for future use 850 + * Note: Only One bit can be set 851 + * cbRES2, byte2 Currently active auto keyboard illumination triggers. 852 + * bit 0 Any keystroke 853 + * bit 1 Touchpad activity 854 + * bit 2 Pointing stick 855 + * bit 3 Any mouse 856 + * bits 4-7 Reserved for future use 857 + * cbRES2, byte3 Current Timeout 858 + * bits 7:6 Timeout units indicator: 859 + * 00b Seconds 860 + * 01b Minutes 861 + * 10b Hours 862 + * 11b Days 863 + * bits 5:0 Timeout value (0-63) in sec/min/hr/day 864 + * NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte 865 + * are set upon return from the [Get feature information] call. 866 + * cbRES3, byte0 Current setting of ALS value that turns the light on or off. 867 + * cbRES3, byte1 Current ALS reading 868 + * cbRES3, byte2 Current keyboard light level. 869 + * 870 + * cbArg1 0x2 = Set New State 871 + * cbRES1 Standard return codes (0, -1, -2) 872 + * cbArg2, word0 Bitmap of current mode state 873 + * bit 0 Always off (All systems) 874 + * bit 1 Always on (Travis ATG, Siberia) 875 + * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) 876 + * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off 877 + * bit 4 Auto: Input-activity-based On; input-activity based Off 878 + * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off 879 + * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off 880 + * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off 881 + * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off 882 + * bits 9-15 Reserved for future use 883 + * Note: Only One bit can be set 884 + * cbArg2, byte2 Desired auto keyboard illumination triggers. Must remain inactive to allow 885 + * keyboard to turn off automatically. 886 + * bit 0 Any keystroke 887 + * bit 1 Touchpad activity 888 + * bit 2 Pointing stick 889 + * bit 3 Any mouse 890 + * bits 4-7 Reserved for future use 891 + * cbArg2, byte3 Desired Timeout 892 + * bits 7:6 Timeout units indicator: 893 + * 00b Seconds 894 + * 01b Minutes 895 + * 10b Hours 896 + * 11b Days 897 + * bits 5:0 Timeout value (0-63) in sec/min/hr/day 898 + * cbArg3, byte0 Desired setting of ALS value that turns the light on or off. 899 + * cbArg3, byte2 Desired keyboard light level. 900 + */ 901 + 902 + 903 + enum kbd_timeout_unit { 904 + KBD_TIMEOUT_SECONDS = 0, 905 + KBD_TIMEOUT_MINUTES, 906 + KBD_TIMEOUT_HOURS, 907 + KBD_TIMEOUT_DAYS, 908 + }; 909 + 910 + enum kbd_mode_bit { 911 + KBD_MODE_BIT_OFF = 0, 912 + KBD_MODE_BIT_ON, 913 + KBD_MODE_BIT_ALS, 914 + KBD_MODE_BIT_TRIGGER_ALS, 915 + KBD_MODE_BIT_TRIGGER, 916 + KBD_MODE_BIT_TRIGGER_25, 917 + KBD_MODE_BIT_TRIGGER_50, 918 + KBD_MODE_BIT_TRIGGER_75, 919 + KBD_MODE_BIT_TRIGGER_100, 920 + }; 921 + 922 + #define kbd_is_als_mode_bit(bit) \ 923 + ((bit) == KBD_MODE_BIT_ALS || (bit) == KBD_MODE_BIT_TRIGGER_ALS) 924 + #define kbd_is_trigger_mode_bit(bit) \ 925 + ((bit) >= KBD_MODE_BIT_TRIGGER_ALS && (bit) <= KBD_MODE_BIT_TRIGGER_100) 926 + #define kbd_is_level_mode_bit(bit) \ 927 + ((bit) >= KBD_MODE_BIT_TRIGGER_25 && (bit) <= KBD_MODE_BIT_TRIGGER_100) 928 + 929 + struct kbd_info { 930 + u16 modes; 931 + u8 type; 932 + u8 triggers; 933 + u8 levels; 934 + u8 seconds; 935 + u8 minutes; 936 + u8 hours; 937 + u8 days; 938 + }; 939 + 940 + struct kbd_state { 941 + u8 mode_bit; 942 + u8 triggers; 943 + u8 timeout_value; 944 + u8 timeout_unit; 945 + u8 als_setting; 946 + u8 als_value; 947 + u8 level; 948 + }; 949 + 950 + static const int kbd_tokens[] = { 951 + KBD_LED_OFF_TOKEN, 952 + KBD_LED_AUTO_25_TOKEN, 953 + KBD_LED_AUTO_50_TOKEN, 954 + KBD_LED_AUTO_75_TOKEN, 955 + KBD_LED_AUTO_100_TOKEN, 956 + KBD_LED_ON_TOKEN, 957 + }; 958 + 959 + static u16 kbd_token_bits; 960 + 961 + static struct kbd_info kbd_info; 962 + static bool kbd_als_supported; 963 + static bool kbd_triggers_supported; 964 + 965 + static u8 kbd_mode_levels[16]; 966 + static int kbd_mode_levels_count; 967 + 968 + static u8 kbd_previous_level; 969 + static u8 kbd_previous_mode_bit; 970 + 971 + static bool kbd_led_present; 972 + 973 + /* 974 + * NOTE: there are three ways to set the keyboard backlight level. 975 + * First, via kbd_state.mode_bit (assigning KBD_MODE_BIT_TRIGGER_* value). 976 + * Second, via kbd_state.level (assigning numerical value <= kbd_info.levels). 977 + * Third, via SMBIOS tokens (KBD_LED_* in kbd_tokens) 978 + * 979 + * There are laptops which support only one of these methods. If we want to 980 + * support as many machines as possible we need to implement all three methods. 981 + * The first two methods use the kbd_state structure. The third uses SMBIOS 982 + * tokens. If kbd_info.levels == 0, the machine does not support setting the 983 + * keyboard backlight level via kbd_state.level. 984 + */ 985 + 986 + static int kbd_get_info(struct kbd_info *info) 987 + { 988 + u8 units; 989 + int ret; 990 + 991 + get_buffer(); 992 + 993 + buffer->input[0] = 0x0; 994 + dell_send_request(buffer, 4, 11); 995 + ret = buffer->output[0]; 996 + 997 + if (ret) { 998 + ret = dell_smi_error(ret); 999 + goto out; 1000 + } 1001 + 1002 + info->modes = buffer->output[1] & 0xFFFF; 1003 + info->type = (buffer->output[1] >> 24) & 0xFF; 1004 + info->triggers = buffer->output[2] & 0xFF; 1005 + units = (buffer->output[2] >> 8) & 0xFF; 1006 + info->levels = (buffer->output[2] >> 16) & 0xFF; 1007 + 1008 + if (units & BIT(0)) 1009 + info->seconds = (buffer->output[3] >> 0) & 0xFF; 1010 + if (units & BIT(1)) 1011 + info->minutes = (buffer->output[3] >> 8) & 0xFF; 1012 + if (units & BIT(2)) 1013 + info->hours = (buffer->output[3] >> 16) & 0xFF; 1014 + if (units & BIT(3)) 1015 + info->days = (buffer->output[3] >> 24) & 0xFF; 1016 + 1017 + out: 1018 + release_buffer(); 1019 + return ret; 1020 + } 1021 + 1022 + static unsigned int kbd_get_max_level(void) 1023 + { 1024 + if (kbd_info.levels != 0) 1025 + return kbd_info.levels; 1026 + if (kbd_mode_levels_count > 0) 1027 + return kbd_mode_levels_count - 1; 1028 + return 0; 1029 + } 1030 + 1031 + static int kbd_get_level(struct kbd_state *state) 1032 + { 1033 + int i; 1034 + 1035 + if (kbd_info.levels != 0) 1036 + return state->level; 1037 + 1038 + if (kbd_mode_levels_count > 0) { 1039 + for (i = 0; i < kbd_mode_levels_count; ++i) 1040 + if (kbd_mode_levels[i] == state->mode_bit) 1041 + return i; 1042 + return 0; 1043 + } 1044 + 1045 + return -EINVAL; 1046 + } 1047 + 1048 + static int kbd_set_level(struct kbd_state *state, u8 level) 1049 + { 1050 + if (kbd_info.levels != 0) { 1051 + if (level != 0) 1052 + kbd_previous_level = level; 1053 + if (state->level == level) 1054 + return 0; 1055 + state->level = level; 1056 + if (level != 0 && state->mode_bit == KBD_MODE_BIT_OFF) 1057 + state->mode_bit = kbd_previous_mode_bit; 1058 + else if (level == 0 && state->mode_bit != KBD_MODE_BIT_OFF) { 1059 + kbd_previous_mode_bit = state->mode_bit; 1060 + state->mode_bit = KBD_MODE_BIT_OFF; 1061 + } 1062 + return 0; 1063 + } 1064 + 1065 + if (kbd_mode_levels_count > 0 && level < kbd_mode_levels_count) { 1066 + if (level != 0) 1067 + kbd_previous_level = level; 1068 + state->mode_bit = kbd_mode_levels[level]; 1069 + return 0; 1070 + } 1071 + 1072 + return -EINVAL; 1073 + } 1074 + 1075 + static int kbd_get_state(struct kbd_state *state) 1076 + { 1077 + int ret; 1078 + 1079 + get_buffer(); 1080 + 1081 + buffer->input[0] = 0x1; 1082 + dell_send_request(buffer, 4, 11); 1083 + ret = buffer->output[0]; 1084 + 1085 + if (ret) { 1086 + ret = dell_smi_error(ret); 1087 + goto out; 1088 + } 1089 + 1090 + state->mode_bit = ffs(buffer->output[1] & 0xFFFF); 1091 + if (state->mode_bit != 0) 1092 + state->mode_bit--; 1093 + 1094 + state->triggers = (buffer->output[1] >> 16) & 0xFF; 1095 + state->timeout_value = (buffer->output[1] >> 24) & 0x3F; 1096 + state->timeout_unit = (buffer->output[1] >> 30) & 0x3; 1097 + state->als_setting = buffer->output[2] & 0xFF; 1098 + state->als_value = (buffer->output[2] >> 8) & 0xFF; 1099 + state->level = (buffer->output[2] >> 16) & 0xFF; 1100 + 1101 + out: 1102 + release_buffer(); 1103 + return ret; 1104 + } 1105 + 1106 + static int kbd_set_state(struct kbd_state *state) 1107 + { 1108 + int ret; 1109 + 1110 + get_buffer(); 1111 + buffer->input[0] = 0x2; 1112 + buffer->input[1] = BIT(state->mode_bit) & 0xFFFF; 1113 + buffer->input[1] |= (state->triggers & 0xFF) << 16; 1114 + buffer->input[1] |= (state->timeout_value & 0x3F) << 24; 1115 + buffer->input[1] |= (state->timeout_unit & 0x3) << 30; 1116 + buffer->input[2] = state->als_setting & 0xFF; 1117 + buffer->input[2] |= (state->level & 0xFF) << 16; 1118 + dell_send_request(buffer, 4, 11); 1119 + ret = buffer->output[0]; 1120 + release_buffer(); 1121 + 1122 + return dell_smi_error(ret); 1123 + } 1124 + 1125 + static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) 1126 + { 1127 + int ret; 1128 + 1129 + ret = kbd_set_state(state); 1130 + if (ret == 0) 1131 + return 0; 1132 + 1133 + /* 1134 + * When setting the new state fails,try to restore the previous one. 1135 + * This is needed on some machines where BIOS sets a default state when 1136 + * setting a new state fails. This default state could be all off. 1137 + */ 1138 + 1139 + if (kbd_set_state(old)) 1140 + pr_err("Setting old previous keyboard state failed\n"); 1141 + 1142 + return ret; 1143 + } 1144 + 1145 + static int kbd_set_token_bit(u8 bit) 1146 + { 1147 + int id; 1148 + int ret; 1149 + 1150 + if (bit >= ARRAY_SIZE(kbd_tokens)) 1151 + return -EINVAL; 1152 + 1153 + id = find_token_id(kbd_tokens[bit]); 1154 + if (id == -1) 1155 + return -EINVAL; 1156 + 1157 + get_buffer(); 1158 + buffer->input[0] = da_tokens[id].location; 1159 + buffer->input[1] = da_tokens[id].value; 1160 + dell_send_request(buffer, 1, 0); 1161 + ret = buffer->output[0]; 1162 + release_buffer(); 1163 + 1164 + return dell_smi_error(ret); 1165 + } 1166 + 1167 + static int kbd_get_token_bit(u8 bit) 1168 + { 1169 + int id; 1170 + int ret; 1171 + int val; 1172 + 1173 + if (bit >= ARRAY_SIZE(kbd_tokens)) 1174 + return -EINVAL; 1175 + 1176 + id = find_token_id(kbd_tokens[bit]); 1177 + if (id == -1) 1178 + return -EINVAL; 1179 + 1180 + get_buffer(); 1181 + buffer->input[0] = da_tokens[id].location; 1182 + dell_send_request(buffer, 0, 0); 1183 + ret = buffer->output[0]; 1184 + val = buffer->output[1]; 1185 + release_buffer(); 1186 + 1187 + if (ret) 1188 + return dell_smi_error(ret); 1189 + 1190 + return (val == da_tokens[id].value); 1191 + } 1192 + 1193 + static int kbd_get_first_active_token_bit(void) 1194 + { 1195 + int i; 1196 + int ret; 1197 + 1198 + for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) { 1199 + ret = kbd_get_token_bit(i); 1200 + if (ret == 1) 1201 + return i; 1202 + } 1203 + 1204 + return ret; 1205 + } 1206 + 1207 + static int kbd_get_valid_token_counts(void) 1208 + { 1209 + return hweight16(kbd_token_bits); 1210 + } 1211 + 1212 + static inline int kbd_init_info(void) 1213 + { 1214 + struct kbd_state state; 1215 + int ret; 1216 + int i; 1217 + 1218 + ret = kbd_get_info(&kbd_info); 1219 + if (ret) 1220 + return ret; 1221 + 1222 + kbd_get_state(&state); 1223 + 1224 + /* NOTE: timeout value is stored in 6 bits so max value is 63 */ 1225 + if (kbd_info.seconds > 63) 1226 + kbd_info.seconds = 63; 1227 + if (kbd_info.minutes > 63) 1228 + kbd_info.minutes = 63; 1229 + if (kbd_info.hours > 63) 1230 + kbd_info.hours = 63; 1231 + if (kbd_info.days > 63) 1232 + kbd_info.days = 63; 1233 + 1234 + /* NOTE: On tested machines ON mode did not work and caused 1235 + * problems (turned backlight off) so do not use it 1236 + */ 1237 + kbd_info.modes &= ~BIT(KBD_MODE_BIT_ON); 1238 + 1239 + kbd_previous_level = kbd_get_level(&state); 1240 + kbd_previous_mode_bit = state.mode_bit; 1241 + 1242 + if (kbd_previous_level == 0 && kbd_get_max_level() != 0) 1243 + kbd_previous_level = 1; 1244 + 1245 + if (kbd_previous_mode_bit == KBD_MODE_BIT_OFF) { 1246 + kbd_previous_mode_bit = 1247 + ffs(kbd_info.modes & ~BIT(KBD_MODE_BIT_OFF)); 1248 + if (kbd_previous_mode_bit != 0) 1249 + kbd_previous_mode_bit--; 1250 + } 1251 + 1252 + if (kbd_info.modes & (BIT(KBD_MODE_BIT_ALS) | 1253 + BIT(KBD_MODE_BIT_TRIGGER_ALS))) 1254 + kbd_als_supported = true; 1255 + 1256 + if (kbd_info.modes & ( 1257 + BIT(KBD_MODE_BIT_TRIGGER_ALS) | BIT(KBD_MODE_BIT_TRIGGER) | 1258 + BIT(KBD_MODE_BIT_TRIGGER_25) | BIT(KBD_MODE_BIT_TRIGGER_50) | 1259 + BIT(KBD_MODE_BIT_TRIGGER_75) | BIT(KBD_MODE_BIT_TRIGGER_100) 1260 + )) 1261 + kbd_triggers_supported = true; 1262 + 1263 + /* kbd_mode_levels[0] is reserved, see below */ 1264 + for (i = 0; i < 16; ++i) 1265 + if (kbd_is_level_mode_bit(i) && (BIT(i) & kbd_info.modes)) 1266 + kbd_mode_levels[1 + kbd_mode_levels_count++] = i; 1267 + 1268 + /* 1269 + * Find the first supported mode and assign to kbd_mode_levels[0]. 1270 + * This should be 0 (off), but we cannot depend on the BIOS to 1271 + * support 0. 1272 + */ 1273 + if (kbd_mode_levels_count > 0) { 1274 + for (i = 0; i < 16; ++i) { 1275 + if (BIT(i) & kbd_info.modes) { 1276 + kbd_mode_levels[0] = i; 1277 + break; 1278 + } 1279 + } 1280 + kbd_mode_levels_count++; 1281 + } 1282 + 1283 + return 0; 1284 + 1285 + } 1286 + 1287 + static inline void kbd_init_tokens(void) 1288 + { 1289 + int i; 1290 + 1291 + for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) 1292 + if (find_token_id(kbd_tokens[i]) != -1) 1293 + kbd_token_bits |= BIT(i); 1294 + } 1295 + 1296 + static void kbd_init(void) 1297 + { 1298 + int ret; 1299 + 1300 + ret = kbd_init_info(); 1301 + kbd_init_tokens(); 1302 + 1303 + if (kbd_token_bits != 0 || ret == 0) 1304 + kbd_led_present = true; 1305 + } 1306 + 1307 + static ssize_t kbd_led_timeout_store(struct device *dev, 1308 + struct device_attribute *attr, 1309 + const char *buf, size_t count) 1310 + { 1311 + struct kbd_state new_state; 1312 + struct kbd_state state; 1313 + bool convert; 1314 + int value; 1315 + int ret; 1316 + char ch; 1317 + u8 unit; 1318 + int i; 1319 + 1320 + ret = sscanf(buf, "%d %c", &value, &ch); 1321 + if (ret < 1) 1322 + return -EINVAL; 1323 + else if (ret == 1) 1324 + ch = 's'; 1325 + 1326 + if (value < 0) 1327 + return -EINVAL; 1328 + 1329 + convert = false; 1330 + 1331 + switch (ch) { 1332 + case 's': 1333 + if (value > kbd_info.seconds) 1334 + convert = true; 1335 + unit = KBD_TIMEOUT_SECONDS; 1336 + break; 1337 + case 'm': 1338 + if (value > kbd_info.minutes) 1339 + convert = true; 1340 + unit = KBD_TIMEOUT_MINUTES; 1341 + break; 1342 + case 'h': 1343 + if (value > kbd_info.hours) 1344 + convert = true; 1345 + unit = KBD_TIMEOUT_HOURS; 1346 + break; 1347 + case 'd': 1348 + if (value > kbd_info.days) 1349 + convert = true; 1350 + unit = KBD_TIMEOUT_DAYS; 1351 + break; 1352 + default: 1353 + return -EINVAL; 1354 + } 1355 + 1356 + if (quirks && quirks->needs_kbd_timeouts) 1357 + convert = true; 1358 + 1359 + if (convert) { 1360 + /* Convert value from current units to seconds */ 1361 + switch (unit) { 1362 + case KBD_TIMEOUT_DAYS: 1363 + value *= 24; 1364 + case KBD_TIMEOUT_HOURS: 1365 + value *= 60; 1366 + case KBD_TIMEOUT_MINUTES: 1367 + value *= 60; 1368 + unit = KBD_TIMEOUT_SECONDS; 1369 + } 1370 + 1371 + if (quirks && quirks->needs_kbd_timeouts) { 1372 + for (i = 0; quirks->kbd_timeouts[i] != -1; i++) { 1373 + if (value <= quirks->kbd_timeouts[i]) { 1374 + value = quirks->kbd_timeouts[i]; 1375 + break; 1376 + } 1377 + } 1378 + } 1379 + 1380 + if (value <= kbd_info.seconds && kbd_info.seconds) { 1381 + unit = KBD_TIMEOUT_SECONDS; 1382 + } else if (value / 60 <= kbd_info.minutes && kbd_info.minutes) { 1383 + value /= 60; 1384 + unit = KBD_TIMEOUT_MINUTES; 1385 + } else if (value / (60 * 60) <= kbd_info.hours && kbd_info.hours) { 1386 + value /= (60 * 60); 1387 + unit = KBD_TIMEOUT_HOURS; 1388 + } else if (value / (60 * 60 * 24) <= kbd_info.days && kbd_info.days) { 1389 + value /= (60 * 60 * 24); 1390 + unit = KBD_TIMEOUT_DAYS; 1391 + } else { 1392 + return -EINVAL; 1393 + } 1394 + } 1395 + 1396 + ret = kbd_get_state(&state); 1397 + if (ret) 1398 + return ret; 1399 + 1400 + new_state = state; 1401 + new_state.timeout_value = value; 1402 + new_state.timeout_unit = unit; 1403 + 1404 + ret = kbd_set_state_safe(&new_state, &state); 1405 + if (ret) 1406 + return ret; 1407 + 1408 + return count; 1409 + } 1410 + 1411 + static ssize_t kbd_led_timeout_show(struct device *dev, 1412 + struct device_attribute *attr, char *buf) 1413 + { 1414 + struct kbd_state state; 1415 + int ret; 1416 + int len; 1417 + 1418 + ret = kbd_get_state(&state); 1419 + if (ret) 1420 + return ret; 1421 + 1422 + len = sprintf(buf, "%d", state.timeout_value); 1423 + 1424 + switch (state.timeout_unit) { 1425 + case KBD_TIMEOUT_SECONDS: 1426 + return len + sprintf(buf+len, "s\n"); 1427 + case KBD_TIMEOUT_MINUTES: 1428 + return len + sprintf(buf+len, "m\n"); 1429 + case KBD_TIMEOUT_HOURS: 1430 + return len + sprintf(buf+len, "h\n"); 1431 + case KBD_TIMEOUT_DAYS: 1432 + return len + sprintf(buf+len, "d\n"); 1433 + default: 1434 + return -EINVAL; 1435 + } 1436 + 1437 + return len; 1438 + } 1439 + 1440 + static DEVICE_ATTR(stop_timeout, S_IRUGO | S_IWUSR, 1441 + kbd_led_timeout_show, kbd_led_timeout_store); 1442 + 1443 + static const char * const kbd_led_triggers[] = { 1444 + "keyboard", 1445 + "touchpad", 1446 + /*"trackstick"*/ NULL, /* NOTE: trackstick is just alias for touchpad */ 1447 + "mouse", 1448 + }; 1449 + 1450 + static ssize_t kbd_led_triggers_store(struct device *dev, 1451 + struct device_attribute *attr, 1452 + const char *buf, size_t count) 1453 + { 1454 + struct kbd_state new_state; 1455 + struct kbd_state state; 1456 + bool triggers_enabled = false; 1457 + bool als_enabled = false; 1458 + bool disable_als = false; 1459 + bool enable_als = false; 1460 + int trigger_bit = -1; 1461 + char trigger[21]; 1462 + int i, ret; 1463 + 1464 + ret = sscanf(buf, "%20s", trigger); 1465 + if (ret != 1) 1466 + return -EINVAL; 1467 + 1468 + if (trigger[0] != '+' && trigger[0] != '-') 1469 + return -EINVAL; 1470 + 1471 + ret = kbd_get_state(&state); 1472 + if (ret) 1473 + return ret; 1474 + 1475 + if (kbd_als_supported) 1476 + als_enabled = kbd_is_als_mode_bit(state.mode_bit); 1477 + 1478 + if (kbd_triggers_supported) 1479 + triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit); 1480 + 1481 + if (kbd_als_supported) { 1482 + if (strcmp(trigger, "+als") == 0) { 1483 + if (als_enabled) 1484 + return count; 1485 + enable_als = true; 1486 + } else if (strcmp(trigger, "-als") == 0) { 1487 + if (!als_enabled) 1488 + return count; 1489 + disable_als = true; 1490 + } 1491 + } 1492 + 1493 + if (enable_als || disable_als) { 1494 + new_state = state; 1495 + if (enable_als) { 1496 + if (triggers_enabled) 1497 + new_state.mode_bit = KBD_MODE_BIT_TRIGGER_ALS; 1498 + else 1499 + new_state.mode_bit = KBD_MODE_BIT_ALS; 1500 + } else { 1501 + if (triggers_enabled) { 1502 + new_state.mode_bit = KBD_MODE_BIT_TRIGGER; 1503 + kbd_set_level(&new_state, kbd_previous_level); 1504 + } else { 1505 + new_state.mode_bit = KBD_MODE_BIT_ON; 1506 + } 1507 + } 1508 + if (!(kbd_info.modes & BIT(new_state.mode_bit))) 1509 + return -EINVAL; 1510 + ret = kbd_set_state_safe(&new_state, &state); 1511 + if (ret) 1512 + return ret; 1513 + kbd_previous_mode_bit = new_state.mode_bit; 1514 + return count; 1515 + } 1516 + 1517 + if (kbd_triggers_supported) { 1518 + for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); ++i) { 1519 + if (!(kbd_info.triggers & BIT(i))) 1520 + continue; 1521 + if (!kbd_led_triggers[i]) 1522 + continue; 1523 + if (strcmp(trigger+1, kbd_led_triggers[i]) != 0) 1524 + continue; 1525 + if (trigger[0] == '+' && 1526 + triggers_enabled && (state.triggers & BIT(i))) 1527 + return count; 1528 + if (trigger[0] == '-' && 1529 + (!triggers_enabled || !(state.triggers & BIT(i)))) 1530 + return count; 1531 + trigger_bit = i; 1532 + break; 1533 + } 1534 + } 1535 + 1536 + if (trigger_bit != -1) { 1537 + new_state = state; 1538 + if (trigger[0] == '+') 1539 + new_state.triggers |= BIT(trigger_bit); 1540 + else { 1541 + new_state.triggers &= ~BIT(trigger_bit); 1542 + /* NOTE: trackstick bit (2) must be disabled when 1543 + * disabling touchpad bit (1), otherwise touchpad 1544 + * bit (1) will not be disabled */ 1545 + if (trigger_bit == 1) 1546 + new_state.triggers &= ~BIT(2); 1547 + } 1548 + if ((kbd_info.triggers & new_state.triggers) != 1549 + new_state.triggers) 1550 + return -EINVAL; 1551 + if (new_state.triggers && !triggers_enabled) { 1552 + if (als_enabled) 1553 + new_state.mode_bit = KBD_MODE_BIT_TRIGGER_ALS; 1554 + else { 1555 + new_state.mode_bit = KBD_MODE_BIT_TRIGGER; 1556 + kbd_set_level(&new_state, kbd_previous_level); 1557 + } 1558 + } else if (new_state.triggers == 0) { 1559 + if (als_enabled) 1560 + new_state.mode_bit = KBD_MODE_BIT_ALS; 1561 + else 1562 + kbd_set_level(&new_state, 0); 1563 + } 1564 + if (!(kbd_info.modes & BIT(new_state.mode_bit))) 1565 + return -EINVAL; 1566 + ret = kbd_set_state_safe(&new_state, &state); 1567 + if (ret) 1568 + return ret; 1569 + if (new_state.mode_bit != KBD_MODE_BIT_OFF) 1570 + kbd_previous_mode_bit = new_state.mode_bit; 1571 + return count; 1572 + } 1573 + 1574 + return -EINVAL; 1575 + } 1576 + 1577 + static ssize_t kbd_led_triggers_show(struct device *dev, 1578 + struct device_attribute *attr, char *buf) 1579 + { 1580 + struct kbd_state state; 1581 + bool triggers_enabled; 1582 + int level, i, ret; 1583 + int len = 0; 1584 + 1585 + ret = kbd_get_state(&state); 1586 + if (ret) 1587 + return ret; 1588 + 1589 + len = 0; 1590 + 1591 + if (kbd_triggers_supported) { 1592 + triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit); 1593 + level = kbd_get_level(&state); 1594 + for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); ++i) { 1595 + if (!(kbd_info.triggers & BIT(i))) 1596 + continue; 1597 + if (!kbd_led_triggers[i]) 1598 + continue; 1599 + if ((triggers_enabled || level <= 0) && 1600 + (state.triggers & BIT(i))) 1601 + buf[len++] = '+'; 1602 + else 1603 + buf[len++] = '-'; 1604 + len += sprintf(buf+len, "%s ", kbd_led_triggers[i]); 1605 + } 1606 + } 1607 + 1608 + if (kbd_als_supported) { 1609 + if (kbd_is_als_mode_bit(state.mode_bit)) 1610 + len += sprintf(buf+len, "+als "); 1611 + else 1612 + len += sprintf(buf+len, "-als "); 1613 + } 1614 + 1615 + if (len) 1616 + buf[len - 1] = '\n'; 1617 + 1618 + return len; 1619 + } 1620 + 1621 + static DEVICE_ATTR(start_triggers, S_IRUGO | S_IWUSR, 1622 + kbd_led_triggers_show, kbd_led_triggers_store); 1623 + 1624 + static ssize_t kbd_led_als_store(struct device *dev, 1625 + struct device_attribute *attr, 1626 + const char *buf, size_t count) 1627 + { 1628 + struct kbd_state state; 1629 + struct kbd_state new_state; 1630 + u8 setting; 1631 + int ret; 1632 + 1633 + ret = kstrtou8(buf, 10, &setting); 1634 + if (ret) 1635 + return ret; 1636 + 1637 + ret = kbd_get_state(&state); 1638 + if (ret) 1639 + return ret; 1640 + 1641 + new_state = state; 1642 + new_state.als_setting = setting; 1643 + 1644 + ret = kbd_set_state_safe(&new_state, &state); 1645 + if (ret) 1646 + return ret; 1647 + 1648 + return count; 1649 + } 1650 + 1651 + static ssize_t kbd_led_als_show(struct device *dev, 1652 + struct device_attribute *attr, char *buf) 1653 + { 1654 + struct kbd_state state; 1655 + int ret; 1656 + 1657 + ret = kbd_get_state(&state); 1658 + if (ret) 1659 + return ret; 1660 + 1661 + return sprintf(buf, "%d\n", state.als_setting); 1662 + } 1663 + 1664 + static DEVICE_ATTR(als_setting, S_IRUGO | S_IWUSR, 1665 + kbd_led_als_show, kbd_led_als_store); 1666 + 1667 + static struct attribute *kbd_led_attrs[] = { 1668 + &dev_attr_stop_timeout.attr, 1669 + &dev_attr_start_triggers.attr, 1670 + &dev_attr_als_setting.attr, 1671 + NULL, 1672 + }; 1673 + ATTRIBUTE_GROUPS(kbd_led); 1674 + 1675 + static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev) 1676 + { 1677 + int ret; 1678 + u16 num; 1679 + struct kbd_state state; 1680 + 1681 + if (kbd_get_max_level()) { 1682 + ret = kbd_get_state(&state); 1683 + if (ret) 1684 + return 0; 1685 + ret = kbd_get_level(&state); 1686 + if (ret < 0) 1687 + return 0; 1688 + return ret; 1689 + } 1690 + 1691 + if (kbd_get_valid_token_counts()) { 1692 + ret = kbd_get_first_active_token_bit(); 1693 + if (ret < 0) 1694 + return 0; 1695 + for (num = kbd_token_bits; num != 0 && ret > 0; --ret) 1696 + num &= num - 1; /* clear the first bit set */ 1697 + if (num == 0) 1698 + return 0; 1699 + return ffs(num) - 1; 1700 + } 1701 + 1702 + pr_warn("Keyboard brightness level control not supported\n"); 1703 + return 0; 1704 + } 1705 + 1706 + static void kbd_led_level_set(struct led_classdev *led_cdev, 1707 + enum led_brightness value) 1708 + { 1709 + struct kbd_state state; 1710 + struct kbd_state new_state; 1711 + u16 num; 1712 + 1713 + if (kbd_get_max_level()) { 1714 + if (kbd_get_state(&state)) 1715 + return; 1716 + new_state = state; 1717 + if (kbd_set_level(&new_state, value)) 1718 + return; 1719 + kbd_set_state_safe(&new_state, &state); 1720 + return; 1721 + } 1722 + 1723 + if (kbd_get_valid_token_counts()) { 1724 + for (num = kbd_token_bits; num != 0 && value > 0; --value) 1725 + num &= num - 1; /* clear the first bit set */ 1726 + if (num == 0) 1727 + return; 1728 + kbd_set_token_bit(ffs(num) - 1); 1729 + return; 1730 + } 1731 + 1732 + pr_warn("Keyboard brightness level control not supported\n"); 1733 + } 1734 + 1735 + static struct led_classdev kbd_led = { 1736 + .name = "dell::kbd_backlight", 1737 + .brightness_set = kbd_led_level_set, 1738 + .brightness_get = kbd_led_level_get, 1739 + .groups = kbd_led_groups, 1740 + }; 1741 + 1742 + static int __init kbd_led_init(struct device *dev) 1743 + { 1744 + kbd_init(); 1745 + if (!kbd_led_present) 1746 + return -ENODEV; 1747 + kbd_led.max_brightness = kbd_get_max_level(); 1748 + if (!kbd_led.max_brightness) { 1749 + kbd_led.max_brightness = kbd_get_valid_token_counts(); 1750 + if (kbd_led.max_brightness) 1751 + kbd_led.max_brightness--; 1752 + } 1753 + return led_classdev_register(dev, &kbd_led); 1754 + } 1755 + 1756 + static void brightness_set_exit(struct led_classdev *led_cdev, 1757 + enum led_brightness value) 1758 + { 1759 + /* Don't change backlight level on exit */ 1760 + }; 1761 + 1762 + static void kbd_led_exit(void) 1763 + { 1764 + if (!kbd_led_present) 1765 + return; 1766 + kbd_led.brightness_set = brightness_set_exit; 1767 + led_classdev_unregister(&kbd_led); 850 1768 } 851 1769 852 1770 static int __init dell_init(void) ··· 1878 840 1879 841 if (quirks && quirks->touchpad_led) 1880 842 touchpad_led_init(&platform_device->dev); 843 + 844 + kbd_led_init(&platform_device->dev); 1881 845 1882 846 dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); 1883 847 if (dell_laptop_dir != NULL) ··· 1948 908 debugfs_remove_recursive(dell_laptop_dir); 1949 909 if (quirks && quirks->touchpad_led) 1950 910 touchpad_led_exit(); 911 + kbd_led_exit(); 1951 912 i8042_remove_filter(dell_laptop_i8042_filter); 1952 913 cancel_delayed_work_sync(&dell_rfkill_work); 1953 914 backlight_device_unregister(dell_backlight_device); ··· 1965 924 module_exit(dell_exit); 1966 925 1967 926 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); 927 + MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>"); 928 + MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); 1968 929 MODULE_DESCRIPTION("Dell laptop driver"); 1969 930 MODULE_LICENSE("GPL");
+8 -2
drivers/platform/x86/dell-smo8800.c
··· 1 1 /* 2 - * dell-smo8800.c - Dell Latitude ACPI SMO8800/SMO8810 freefall sensor driver 2 + * dell-smo8800.c - Dell Latitude ACPI SMO88XX freefall sensor driver 3 3 * 4 4 * Copyright (C) 2012 Sonal Santan <sonal.santan@gmail.com> 5 5 * Copyright (C) 2014 Pali Rohár <pali.rohar@gmail.com> ··· 209 209 210 210 static const struct acpi_device_id smo8800_ids[] = { 211 211 { "SMO8800", 0 }, 212 + { "SMO8801", 0 }, 212 213 { "SMO8810", 0 }, 214 + { "SMO8811", 0 }, 215 + { "SMO8820", 0 }, 216 + { "SMO8821", 0 }, 217 + { "SMO8830", 0 }, 218 + { "SMO8831", 0 }, 213 219 { "", 0 }, 214 220 }; 215 221 ··· 234 228 235 229 module_acpi_driver(smo8800_driver); 236 230 237 - MODULE_DESCRIPTION("Dell Latitude freefall driver (ACPI SMO8800/SMO8810)"); 231 + MODULE_DESCRIPTION("Dell Latitude freefall driver (ACPI SMO88XX)"); 238 232 MODULE_LICENSE("GPL"); 239 233 MODULE_AUTHOR("Sonal Santan, Pali Rohár");
+145 -45
drivers/platform/x86/dell-wmi.c
··· 65 65 /* Battery health status button */ 66 66 { KE_KEY, 0xe007, { KEY_BATTERY } }, 67 67 68 - /* This is actually for all radios. Although physically a 69 - * switch, the notification does not provide an indication of 70 - * state and so it should be reported as a key */ 71 - { KE_KEY, 0xe008, { KEY_WLAN } }, 68 + /* Radio devices state change */ 69 + { KE_IGNORE, 0xe008, { KEY_RFKILL } }, 72 70 73 71 /* The next device is at offset 6, the active devices are at 74 72 offset 8 and the attached devices at offset 10 */ ··· 143 145 144 146 static struct input_dev *dell_wmi_input_dev; 145 147 148 + static void dell_wmi_process_key(int reported_key) 149 + { 150 + const struct key_entry *key; 151 + 152 + key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, 153 + reported_key); 154 + if (!key) { 155 + pr_info("Unknown key %x pressed\n", reported_key); 156 + return; 157 + } 158 + 159 + pr_debug("Key %x pressed\n", reported_key); 160 + 161 + /* Don't report brightness notifications that will also come via ACPI */ 162 + if ((key->keycode == KEY_BRIGHTNESSUP || 163 + key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) 164 + return; 165 + 166 + sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); 167 + } 168 + 146 169 static void dell_wmi_notify(u32 value, void *context) 147 170 { 148 171 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 149 172 union acpi_object *obj; 150 173 acpi_status status; 174 + acpi_size buffer_size; 175 + u16 *buffer_entry, *buffer_end; 176 + int len, i; 151 177 152 178 status = wmi_get_event_data(value, &response); 153 179 if (status != AE_OK) { 154 - pr_info("bad event status 0x%x\n", status); 180 + pr_warn("bad event status 0x%x\n", status); 155 181 return; 156 182 } 157 183 158 184 obj = (union acpi_object *)response.pointer; 159 - 160 - if (obj && obj->type == ACPI_TYPE_BUFFER) { 161 - const struct key_entry *key; 162 - int reported_key; 163 - u16 *buffer_entry = (u16 *)obj->buffer.pointer; 164 - int buffer_size = obj->buffer.length/2; 165 - 166 - if (buffer_size >= 2 && dell_new_hk_type && buffer_entry[1] != 0x10) { 167 - pr_info("Received unknown WMI event (0x%x)\n", 168 - buffer_entry[1]); 169 - kfree(obj); 170 - return; 171 - } 172 - 173 - if (buffer_size >= 3 && (dell_new_hk_type || buffer_entry[1] == 0x0)) 174 - reported_key = (int)buffer_entry[2]; 175 - else if (buffer_size >= 2) 176 - reported_key = (int)buffer_entry[1] & 0xffff; 177 - else { 178 - pr_info("Received unknown WMI event\n"); 179 - kfree(obj); 180 - return; 181 - } 182 - 183 - key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, 184 - reported_key); 185 - if (!key) { 186 - pr_info("Unknown key %x pressed\n", reported_key); 187 - } else if ((key->keycode == KEY_BRIGHTNESSUP || 188 - key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) { 189 - /* Don't report brightness notifications that will also 190 - * come via ACPI */ 191 - ; 192 - } else { 193 - sparse_keymap_report_entry(dell_wmi_input_dev, key, 194 - 1, true); 195 - } 185 + if (!obj) { 186 + pr_warn("no response\n"); 187 + return; 196 188 } 189 + 190 + if (obj->type != ACPI_TYPE_BUFFER) { 191 + pr_warn("bad response type %x\n", obj->type); 192 + kfree(obj); 193 + return; 194 + } 195 + 196 + pr_debug("Received WMI event (%*ph)\n", 197 + obj->buffer.length, obj->buffer.pointer); 198 + 199 + buffer_entry = (u16 *)obj->buffer.pointer; 200 + buffer_size = obj->buffer.length/2; 201 + 202 + if (!dell_new_hk_type) { 203 + if (buffer_size >= 3 && buffer_entry[1] == 0x0) 204 + dell_wmi_process_key(buffer_entry[2]); 205 + else if (buffer_size >= 2) 206 + dell_wmi_process_key(buffer_entry[1]); 207 + else 208 + pr_info("Received unknown WMI event\n"); 209 + kfree(obj); 210 + return; 211 + } 212 + 213 + buffer_end = buffer_entry + buffer_size; 214 + 215 + while (buffer_entry < buffer_end) { 216 + 217 + len = buffer_entry[0]; 218 + if (len == 0) 219 + break; 220 + 221 + len++; 222 + 223 + if (buffer_entry + len > buffer_end) { 224 + pr_warn("Invalid length of WMI event\n"); 225 + break; 226 + } 227 + 228 + pr_debug("Process buffer (%*ph)\n", len*2, buffer_entry); 229 + 230 + switch (buffer_entry[1]) { 231 + case 0x00: 232 + for (i = 2; i < len; ++i) { 233 + switch (buffer_entry[i]) { 234 + case 0xe043: 235 + /* NIC Link is Up */ 236 + pr_debug("NIC Link is Up\n"); 237 + break; 238 + case 0xe044: 239 + /* NIC Link is Down */ 240 + pr_debug("NIC Link is Down\n"); 241 + break; 242 + case 0xe045: 243 + /* Unknown event but defined in DSDT */ 244 + default: 245 + /* Unknown event */ 246 + pr_info("Unknown WMI event type 0x00: " 247 + "0x%x\n", (int)buffer_entry[i]); 248 + break; 249 + } 250 + } 251 + break; 252 + case 0x10: 253 + /* Keys pressed */ 254 + for (i = 2; i < len; ++i) 255 + dell_wmi_process_key(buffer_entry[i]); 256 + break; 257 + case 0x11: 258 + for (i = 2; i < len; ++i) { 259 + switch (buffer_entry[i]) { 260 + case 0xfff0: 261 + /* Battery unplugged */ 262 + pr_debug("Battery unplugged\n"); 263 + break; 264 + case 0xfff1: 265 + /* Battery inserted */ 266 + pr_debug("Battery inserted\n"); 267 + break; 268 + case 0x01e1: 269 + case 0x02ea: 270 + case 0x02eb: 271 + case 0x02ec: 272 + case 0x02f6: 273 + /* Keyboard backlight level changed */ 274 + pr_debug("Keyboard backlight level " 275 + "changed\n"); 276 + break; 277 + default: 278 + /* Unknown event */ 279 + pr_info("Unknown WMI event type 0x11: " 280 + "0x%x\n", (int)buffer_entry[i]); 281 + break; 282 + } 283 + } 284 + break; 285 + default: 286 + /* Unknown event */ 287 + pr_info("Unknown WMI event type 0x%x\n", 288 + (int)buffer_entry[1]); 289 + break; 290 + } 291 + 292 + buffer_entry += len; 293 + 294 + } 295 + 197 296 kfree(obj); 198 297 } 199 298 ··· 308 213 for (i = 0; i < hotkey_num; i++) { 309 214 const struct dell_bios_keymap_entry *bios_entry = 310 215 &dell_bios_hotkey_table->keymap[i]; 311 - keymap[i].type = KE_KEY; 312 - keymap[i].code = bios_entry->scancode; 313 - keymap[i].keycode = bios_entry->keycode < 256 ? 216 + u16 keycode = bios_entry->keycode < 256 ? 314 217 bios_to_linux_keycode[bios_entry->keycode] : 315 218 KEY_RESERVED; 219 + 220 + if (keycode == KEY_KBDILLUMTOGGLE) 221 + keymap[i].type = KE_IGNORE; 222 + else 223 + keymap[i].type = KE_KEY; 224 + keymap[i].code = bios_entry->scancode; 225 + keymap[i].keycode = keycode; 316 226 } 317 227 318 228 keymap[hotkey_num].type = KE_END;
+121 -106
drivers/platform/x86/eeepc-laptop.c
··· 417 417 switch (value) { 418 418 case 0: 419 419 if (eeepc->cpufv_disabled) 420 - pr_warn("cpufv enabled (not officially supported " 421 - "on this model)\n"); 420 + pr_warn("cpufv enabled (not officially supported on this model)\n"); 422 421 eeepc->cpufv_disabled = false; 423 422 return count; 424 423 case 1: ··· 579 580 mutex_lock(&eeepc->hotplug_lock); 580 581 pci_lock_rescan_remove(); 581 582 582 - if (eeepc->hotplug_slot) { 583 - port = acpi_get_pci_dev(handle); 584 - if (!port) { 585 - pr_warning("Unable to find port\n"); 586 - goto out_unlock; 587 - } 583 + if (!eeepc->hotplug_slot) 584 + goto out_unlock; 588 585 589 - bus = port->subordinate; 590 - 591 - if (!bus) { 592 - pr_warn("Unable to find PCI bus 1?\n"); 593 - goto out_put_dev; 594 - } 595 - 596 - if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { 597 - pr_err("Unable to read PCI config space?\n"); 598 - goto out_put_dev; 599 - } 600 - 601 - absent = (l == 0xffffffff); 602 - 603 - if (blocked != absent) { 604 - pr_warn("BIOS says wireless lan is %s, " 605 - "but the pci device is %s\n", 606 - blocked ? "blocked" : "unblocked", 607 - absent ? "absent" : "present"); 608 - pr_warn("skipped wireless hotplug as probably " 609 - "inappropriate for this model\n"); 610 - goto out_put_dev; 611 - } 612 - 613 - if (!blocked) { 614 - dev = pci_get_slot(bus, 0); 615 - if (dev) { 616 - /* Device already present */ 617 - pci_dev_put(dev); 618 - goto out_put_dev; 619 - } 620 - dev = pci_scan_single_device(bus, 0); 621 - if (dev) { 622 - pci_bus_assign_resources(bus); 623 - pci_bus_add_device(dev); 624 - } 625 - } else { 626 - dev = pci_get_slot(bus, 0); 627 - if (dev) { 628 - pci_stop_and_remove_bus_device(dev); 629 - pci_dev_put(dev); 630 - } 631 - } 632 - out_put_dev: 633 - pci_dev_put(port); 586 + port = acpi_get_pci_dev(handle); 587 + if (!port) { 588 + pr_warning("Unable to find port\n"); 589 + goto out_unlock; 634 590 } 591 + 592 + bus = port->subordinate; 593 + 594 + if (!bus) { 595 + pr_warn("Unable to find PCI bus 1?\n"); 596 + goto out_put_dev; 597 + } 598 + 599 + if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { 600 + pr_err("Unable to read PCI config space?\n"); 601 + goto out_put_dev; 602 + } 603 + 604 + absent = (l == 0xffffffff); 605 + 606 + if (blocked != absent) { 607 + pr_warn("BIOS says wireless lan is %s, but the pci device is %s\n", 608 + blocked ? "blocked" : "unblocked", 609 + absent ? "absent" : "present"); 610 + pr_warn("skipped wireless hotplug as probably inappropriate for this model\n"); 611 + goto out_put_dev; 612 + } 613 + 614 + if (!blocked) { 615 + dev = pci_get_slot(bus, 0); 616 + if (dev) { 617 + /* Device already present */ 618 + pci_dev_put(dev); 619 + goto out_put_dev; 620 + } 621 + dev = pci_scan_single_device(bus, 0); 622 + if (dev) { 623 + pci_bus_assign_resources(bus); 624 + pci_bus_add_device(dev); 625 + } 626 + } else { 627 + dev = pci_get_slot(bus, 0); 628 + if (dev) { 629 + pci_stop_and_remove_bus_device(dev); 630 + pci_dev_put(dev); 631 + } 632 + } 633 + out_put_dev: 634 + pci_dev_put(port); 635 635 636 636 out_unlock: 637 637 pci_unlock_rescan_remove(); ··· 819 821 return 0; 820 822 } 821 823 824 + static char EEEPC_RFKILL_NODE_1[] = "\\_SB.PCI0.P0P5"; 825 + static char EEEPC_RFKILL_NODE_2[] = "\\_SB.PCI0.P0P6"; 826 + static char EEEPC_RFKILL_NODE_3[] = "\\_SB.PCI0.P0P7"; 827 + 822 828 static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc) 823 829 { 824 - eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); 825 - eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); 826 - eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); 830 + eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_1); 831 + eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_2); 832 + eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_3); 827 833 if (eeepc->wlan_rfkill) { 828 834 rfkill_unregister(eeepc->wlan_rfkill); 829 835 rfkill_destroy(eeepc->wlan_rfkill); ··· 899 897 if (result == -EBUSY) 900 898 result = 0; 901 899 902 - eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); 903 - eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); 904 - eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); 900 + eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_1); 901 + eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_2); 902 + eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_3); 905 903 906 904 exit: 907 905 if (result && result != -ENODEV) ··· 917 915 struct eeepc_laptop *eeepc = dev_get_drvdata(device); 918 916 919 917 if (eeepc->wlan_rfkill) { 920 - bool wlan; 918 + int wlan; 921 919 922 920 /* 923 921 * Work around bios bug - acpi _PTS turns off the wireless led ··· 925 923 * we should kick it ourselves in case hibernation is aborted. 926 924 */ 927 925 wlan = get_acpi(eeepc, CM_ASL_WLAN); 928 - set_acpi(eeepc, CM_ASL_WLAN, wlan); 926 + if (wlan >= 0) 927 + set_acpi(eeepc, CM_ASL_WLAN, wlan); 929 928 } 930 929 931 930 return 0; ··· 938 935 939 936 /* Refresh both wlan rfkill state and pci hotplug */ 940 937 if (eeepc->wlan_rfkill) { 941 - eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P5"); 942 - eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P6"); 943 - eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P7"); 938 + eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_1); 939 + eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_2); 940 + eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_3); 944 941 } 945 942 946 943 if (eeepc->bluetooth_rfkill) ··· 980 977 #define EEEPC_EC_SFB0 0xD0 981 978 #define EEEPC_EC_FAN_CTRL (EEEPC_EC_SFB0 + 3) /* Byte containing SF25 */ 982 979 980 + static inline int eeepc_pwm_to_lmsensors(int value) 981 + { 982 + return value * 255 / 100; 983 + } 984 + 985 + static inline int eeepc_lmsensors_to_pwm(int value) 986 + { 987 + value = clamp_val(value, 0, 255); 988 + return value * 100 / 255; 989 + } 990 + 983 991 static int eeepc_get_fan_pwm(void) 984 992 { 985 993 u8 value = 0; 986 994 987 995 ec_read(EEEPC_EC_FAN_PWM, &value); 988 - return value * 255 / 100; 996 + return eeepc_pwm_to_lmsensors(value); 989 997 } 990 998 991 999 static void eeepc_set_fan_pwm(int value) 992 1000 { 993 - value = clamp_val(value, 0, 255); 994 - value = value * 100 / 255; 1001 + value = eeepc_lmsensors_to_pwm(value); 995 1002 ec_write(EEEPC_EC_FAN_PWM, value); 996 1003 } 997 1004 ··· 1015 1002 return high << 8 | low; 1016 1003 } 1017 1004 1005 + #define EEEPC_EC_FAN_CTRL_BIT 0x02 1006 + #define EEEPC_FAN_CTRL_MANUAL 1 1007 + #define EEEPC_FAN_CTRL_AUTO 2 1008 + 1018 1009 static int eeepc_get_fan_ctrl(void) 1019 1010 { 1020 1011 u8 value = 0; 1021 1012 1022 1013 ec_read(EEEPC_EC_FAN_CTRL, &value); 1023 - if (value & 0x02) 1024 - return 1; /* manual */ 1014 + if (value & EEEPC_EC_FAN_CTRL_BIT) 1015 + return EEEPC_FAN_CTRL_MANUAL; 1025 1016 else 1026 - return 2; /* automatic */ 1017 + return EEEPC_FAN_CTRL_AUTO; 1027 1018 } 1028 1019 1029 1020 static void eeepc_set_fan_ctrl(int manual) ··· 1035 1018 u8 value = 0; 1036 1019 1037 1020 ec_read(EEEPC_EC_FAN_CTRL, &value); 1038 - if (manual == 1) 1039 - value |= 0x02; 1021 + if (manual == EEEPC_FAN_CTRL_MANUAL) 1022 + value |= EEEPC_EC_FAN_CTRL_BIT; 1040 1023 else 1041 - value &= ~0x02; 1024 + value &= ~EEEPC_EC_FAN_CTRL_BIT; 1042 1025 ec_write(EEEPC_EC_FAN_CTRL, value); 1043 1026 } 1044 1027 ··· 1173 1156 1174 1157 static void eeepc_backlight_exit(struct eeepc_laptop *eeepc) 1175 1158 { 1176 - if (eeepc->backlight_device) 1177 - backlight_device_unregister(eeepc->backlight_device); 1159 + backlight_device_unregister(eeepc->backlight_device); 1178 1160 eeepc->backlight_device = NULL; 1179 1161 } 1180 1162 ··· 1232 1216 static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event) 1233 1217 { 1234 1218 if (!eeepc->inputdev) 1235 - return ; 1219 + return; 1236 1220 if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true)) 1237 1221 pr_info("Unknown key %x pressed\n", event); 1238 1222 } ··· 1240 1224 static void eeepc_acpi_notify(struct acpi_device *device, u32 event) 1241 1225 { 1242 1226 struct eeepc_laptop *eeepc = acpi_driver_data(device); 1227 + int old_brightness, new_brightness; 1243 1228 u16 count; 1244 1229 1245 1230 if (event > ACPI_MAX_SYS_NOTIFY) ··· 1251 1234 count); 1252 1235 1253 1236 /* Brightness events are special */ 1254 - if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) { 1255 - 1256 - /* Ignore them completely if the acpi video driver is used */ 1257 - if (eeepc->backlight_device != NULL) { 1258 - int old_brightness, new_brightness; 1259 - 1260 - /* Update the backlight device. */ 1261 - old_brightness = eeepc_backlight_notify(eeepc); 1262 - 1263 - /* Convert event to keypress (obsolescent hack) */ 1264 - new_brightness = event - NOTIFY_BRN_MIN; 1265 - 1266 - if (new_brightness < old_brightness) { 1267 - event = NOTIFY_BRN_MIN; /* brightness down */ 1268 - } else if (new_brightness > old_brightness) { 1269 - event = NOTIFY_BRN_MAX; /* brightness up */ 1270 - } else { 1271 - /* 1272 - * no change in brightness - already at min/max, 1273 - * event will be desired value (or else ignored) 1274 - */ 1275 - } 1276 - eeepc_input_notify(eeepc, event); 1277 - } 1278 - } else { 1279 - /* Everything else is a bona-fide keypress event */ 1237 + if (event < NOTIFY_BRN_MIN || event > NOTIFY_BRN_MAX) { 1280 1238 eeepc_input_notify(eeepc, event); 1239 + return; 1281 1240 } 1241 + 1242 + /* Ignore them completely if the acpi video driver is used */ 1243 + if (!eeepc->backlight_device) 1244 + return; 1245 + 1246 + /* Update the backlight device. */ 1247 + old_brightness = eeepc_backlight_notify(eeepc); 1248 + 1249 + /* Convert event to keypress (obsolescent hack) */ 1250 + new_brightness = event - NOTIFY_BRN_MIN; 1251 + 1252 + if (new_brightness < old_brightness) { 1253 + event = NOTIFY_BRN_MIN; /* brightness down */ 1254 + } else if (new_brightness > old_brightness) { 1255 + event = NOTIFY_BRN_MAX; /* brightness up */ 1256 + } else { 1257 + /* 1258 + * no change in brightness - already at min/max, 1259 + * event will be desired value (or else ignored) 1260 + */ 1261 + } 1262 + eeepc_input_notify(eeepc, event); 1282 1263 } 1283 1264 1284 1265 static void eeepc_dmi_check(struct eeepc_laptop *eeepc) ··· 1308 1293 */ 1309 1294 if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) { 1310 1295 eeepc->cpufv_disabled = true; 1311 - pr_info("model %s does not officially support setting cpu " 1312 - "speed\n", model); 1296 + pr_info("model %s does not officially support setting cpu speed\n", 1297 + model); 1313 1298 pr_info("cpufv disabled to avoid instability\n"); 1314 1299 } 1315 1300 ··· 1335 1320 Check if cm_getv[cm] works and, if yes, assume cm should be set. */ 1336 1321 if (!(eeepc->cm_supported & (1 << cm)) 1337 1322 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { 1338 - pr_info("%s (%x) not reported by BIOS," 1339 - " enabling anyway\n", name, 1 << cm); 1323 + pr_info("%s (%x) not reported by BIOS, enabling anyway\n", 1324 + name, 1 << cm); 1340 1325 eeepc->cm_supported |= 1 << cm; 1341 1326 } 1342 1327 }
+2 -4
drivers/platform/x86/fujitsu-laptop.c
··· 1153 1153 fail_hotkey: 1154 1154 platform_driver_unregister(&fujitsupf_driver); 1155 1155 fail_backlight: 1156 - if (fujitsu->bl_device) 1157 - backlight_device_unregister(fujitsu->bl_device); 1156 + backlight_device_unregister(fujitsu->bl_device); 1158 1157 fail_sysfs_group: 1159 1158 sysfs_remove_group(&fujitsu->pf_device->dev.kobj, 1160 1159 &fujitsupf_attribute_group); ··· 1177 1178 1178 1179 platform_driver_unregister(&fujitsupf_driver); 1179 1180 1180 - if (fujitsu->bl_device) 1181 - backlight_device_unregister(fujitsu->bl_device); 1181 + backlight_device_unregister(fujitsu->bl_device); 1182 1182 1183 1183 sysfs_remove_group(&fujitsu->pf_device->dev.kobj, 1184 1184 &fujitsupf_attribute_group);
+3
drivers/platform/x86/hp-wireless.c
··· 85 85 int err; 86 86 87 87 err = hp_wireless_input_setup(); 88 + if (err) 89 + pr_err("Failed to setup hp wireless hotkeys\n"); 90 + 88 91 return err; 89 92 } 90 93
+1
drivers/platform/x86/hp_accel.c
··· 246 246 AXIS_DMI_MATCH("HPB64xx", "HP ProBook 64", xy_swap), 247 247 AXIS_DMI_MATCH("HPB64xx", "HP EliteBook 84", xy_swap), 248 248 AXIS_DMI_MATCH("HPB65xx", "HP ProBook 65", x_inverted), 249 + AXIS_DMI_MATCH("HPZBook15", "HP ZBook 15", x_inverted), 249 250 { NULL, } 250 251 /* Laptop models without axis info (yet): 251 252 * "NC6910" "HP Compaq 6910"
+1 -2
drivers/platform/x86/ideapad-laptop.c
··· 729 729 730 730 static void ideapad_backlight_exit(struct ideapad_private *priv) 731 731 { 732 - if (priv->blightdev) 733 - backlight_device_unregister(priv->blightdev); 732 + backlight_device_unregister(priv->blightdev); 734 733 priv->blightdev = NULL; 735 734 } 736 735
+1 -1
drivers/platform/x86/intel_ips.c
··· 33 33 * performance by allocating more power or thermal budget to the CPU or GPU 34 34 * based on available headroom and activity. 35 35 * 36 - * The basic algorithm is driven by a 5s moving average of tempurature. If 36 + * The basic algorithm is driven by a 5s moving average of temperature. If 37 37 * thermal headroom is available, the CPU and/or GPU power clamps may be 38 38 * adjusted upwards. If we hit the thermal ceiling or a thermal trigger, 39 39 * we scale back the clamp. Aside from trigger events (when we're critically
+1 -2
drivers/platform/x86/intel_oaktrail.c
··· 271 271 272 272 static void oaktrail_backlight_exit(void) 273 273 { 274 - if (oaktrail_bl_device) 275 - backlight_device_unregister(oaktrail_bl_device); 274 + backlight_device_unregister(oaktrail_bl_device); 276 275 } 277 276 278 277 static int oaktrail_probe(struct platform_device *pdev)
+1 -1
drivers/platform/x86/msi-laptop.c
··· 820 820 { 821 821 static bool extended; 822 822 823 - if (str & 0x20) 823 + if (str & I8042_STR_AUXDATA) 824 824 return false; 825 825 826 826 /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/
+1 -2
drivers/platform/x86/msi-wmi.c
··· 354 354 sparse_keymap_free(msi_wmi_input_dev); 355 355 input_unregister_device(msi_wmi_input_dev); 356 356 } 357 - if (backlight) 358 - backlight_device_unregister(backlight); 357 + backlight_device_unregister(backlight); 359 358 } 360 359 361 360 module_init(msi_wmi_init);
+2 -4
drivers/platform/x86/sony-laptop.c
··· 3140 3140 3141 3141 static void sony_nc_backlight_cleanup(void) 3142 3142 { 3143 - if (sony_bl_props.dev) 3144 - backlight_device_unregister(sony_bl_props.dev); 3143 + backlight_device_unregister(sony_bl_props.dev); 3145 3144 } 3146 3145 3147 3146 static int sony_nc_add(struct acpi_device *device) ··· 3715 3716 dev->event_types = type2_events; 3716 3717 3717 3718 out: 3718 - if (pcidev) 3719 - pci_dev_put(pcidev); 3719 + pci_dev_put(pcidev); 3720 3720 3721 3721 pr_info("detected Type%d model\n", 3722 3722 dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
+106 -10
drivers/platform/x86/thinkpad_acpi.c
··· 6557 6557 * bits 3-0 (volume). Other bits in NVRAM may have other functions, 6558 6558 * such as bit 7 which is used to detect repeated presses of MUTE, 6559 6559 * and we leave them unchanged. 6560 + * 6561 + * On newer Lenovo ThinkPads, the EC can automatically change the volume 6562 + * in response to user input. Unfortunately, this rarely works well. 6563 + * The laptop changes the state of its internal MUTE gate and, on some 6564 + * models, sends KEY_MUTE, causing any user code that responds to the 6565 + * mute button to get confused. The hardware MUTE gate is also 6566 + * unnecessary, since user code can handle the mute button without 6567 + * kernel or EC help. 6568 + * 6569 + * To avoid confusing userspace, we simply disable all EC-based mute 6570 + * and volume controls when possible. 6560 6571 */ 6561 6572 6562 6573 #ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT ··· 6622 6611 TPACPI_VOL_CAP_MAX 6623 6612 }; 6624 6613 6614 + enum tpacpi_mute_btn_mode { 6615 + TP_EC_MUTE_BTN_LATCH = 0, /* Mute mutes; up/down unmutes */ 6616 + /* We don't know what mode 1 is. */ 6617 + TP_EC_MUTE_BTN_NONE = 2, /* Mute and up/down are just keys */ 6618 + TP_EC_MUTE_BTN_TOGGLE = 3, /* Mute toggles; up/down unmutes */ 6619 + }; 6620 + 6625 6621 static enum tpacpi_volume_access_mode volume_mode = 6626 6622 TPACPI_VOL_MODE_MAX; 6627 6623 6628 6624 static enum tpacpi_volume_capabilities volume_capabilities; 6629 6625 static bool volume_control_allowed; 6626 + static bool software_mute_requested = true; 6627 + static bool software_mute_active; 6628 + static int software_mute_orig_mode; 6630 6629 6631 6630 /* 6632 6631 * Used to syncronize writers to TP_EC_AUDIO and ··· 6653 6632 if (volume_mode != TPACPI_VOL_MODE_ECNVRAM) 6654 6633 return; 6655 6634 if (!volume_control_allowed) 6635 + return; 6636 + if (software_mute_active) 6656 6637 return; 6657 6638 6658 6639 vdbg_printk(TPACPI_DBG_MIXER, ··· 6716 6693 return -EIO; 6717 6694 6718 6695 dbg_printk(TPACPI_DBG_MIXER, "set EC mixer to 0x%02x\n", status); 6696 + 6697 + /* 6698 + * On X200s, and possibly on others, it can take a while for 6699 + * reads to become correct. 6700 + */ 6701 + msleep(1); 6719 6702 6720 6703 return 0; 6721 6704 } ··· 6803 6774 unlock: 6804 6775 mutex_unlock(&volume_mutex); 6805 6776 return rc; 6777 + } 6778 + 6779 + static int volume_set_software_mute(bool startup) 6780 + { 6781 + int result; 6782 + 6783 + if (!tpacpi_is_lenovo()) 6784 + return -ENODEV; 6785 + 6786 + if (startup) { 6787 + if (!acpi_evalf(ec_handle, &software_mute_orig_mode, 6788 + "HAUM", "qd")) 6789 + return -EIO; 6790 + 6791 + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, 6792 + "Initial HAUM setting was %d\n", 6793 + software_mute_orig_mode); 6794 + } 6795 + 6796 + if (!acpi_evalf(ec_handle, &result, "SAUM", "qdd", 6797 + (int)TP_EC_MUTE_BTN_NONE)) 6798 + return -EIO; 6799 + 6800 + if (result != TP_EC_MUTE_BTN_NONE) 6801 + pr_warn("Unexpected SAUM result %d\n", 6802 + result); 6803 + 6804 + /* 6805 + * In software mute mode, the standard codec controls take 6806 + * precendence, so we unmute the ThinkPad HW switch at 6807 + * startup. Just on case there are SAUM-capable ThinkPads 6808 + * with level controls, set max HW volume as well. 6809 + */ 6810 + if (tp_features.mixer_no_level_control) 6811 + result = volume_set_mute(false); 6812 + else 6813 + result = volume_set_status(TP_EC_VOLUME_MAX); 6814 + 6815 + if (result != 0) 6816 + pr_warn("Failed to unmute the HW mute switch\n"); 6817 + 6818 + return 0; 6819 + } 6820 + 6821 + static void volume_exit_software_mute(void) 6822 + { 6823 + int r; 6824 + 6825 + if (!acpi_evalf(ec_handle, &r, "SAUM", "qdd", software_mute_orig_mode) 6826 + || r != software_mute_orig_mode) 6827 + pr_warn("Failed to restore mute mode\n"); 6806 6828 } 6807 6829 6808 6830 static int volume_alsa_set_volume(const u8 vol) ··· 6963 6883 6964 6884 static void volume_resume(void) 6965 6885 { 6966 - volume_alsa_notify_change(); 6886 + if (software_mute_active) { 6887 + if (volume_set_software_mute(false) < 0) 6888 + pr_warn("Failed to restore software mute\n"); 6889 + } else { 6890 + volume_alsa_notify_change(); 6891 + } 6967 6892 } 6968 6893 6969 6894 static void volume_shutdown(void) ··· 6984 6899 } 6985 6900 6986 6901 tpacpi_volume_checkpoint_nvram(); 6902 + 6903 + if (software_mute_active) 6904 + volume_exit_software_mute(); 6987 6905 } 6988 6906 6989 6907 static int __init volume_create_alsa_mixer(void) ··· 7171 7083 "mute is supported, volume control is %s\n", 7172 7084 str_supported(!tp_features.mixer_no_level_control)); 7173 7085 7174 - rc = volume_create_alsa_mixer(); 7175 - if (rc) { 7176 - pr_err("Could not create the ALSA mixer interface\n"); 7177 - return rc; 7178 - } 7086 + if (software_mute_requested && volume_set_software_mute(true) == 0) { 7087 + software_mute_active = true; 7088 + } else { 7089 + rc = volume_create_alsa_mixer(); 7090 + if (rc) { 7091 + pr_err("Could not create the ALSA mixer interface\n"); 7092 + return rc; 7093 + } 7179 7094 7180 - pr_info("Console audio control enabled, mode: %s\n", 7181 - (volume_control_allowed) ? 7182 - "override (read/write)" : 7183 - "monitor (read only)"); 7095 + pr_info("Console audio control enabled, mode: %s\n", 7096 + (volume_control_allowed) ? 7097 + "override (read/write)" : 7098 + "monitor (read only)"); 7099 + } 7184 7100 7185 7101 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, 7186 7102 "registering volume hotkeys as change notification\n"); ··· 9180 9088 MODULE_PARM_DESC(volume_control, 9181 9089 "Enables software override for the console audio " 9182 9090 "control when true"); 9091 + 9092 + module_param_named(software_mute, software_mute_requested, bool, 0444); 9093 + MODULE_PARM_DESC(software_mute, 9094 + "Request full software mute control"); 9183 9095 9184 9096 /* ALSA module API parameters */ 9185 9097 module_param_named(index, alsa_index, int, 0444);
+93 -73
drivers/platform/x86/toshiba_acpi.c
··· 186 186 187 187 static const struct acpi_device_id toshiba_device_ids[] = { 188 188 {"TOS6200", 0}, 189 + {"TOS6207", 0}, 189 190 {"TOS6208", 0}, 190 191 {"TOS1900", 0}, 191 192 {"", 0}, ··· 929 928 930 929 static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 931 930 { 932 - u32 in[TCI_WORDS] = { HCI_SET, HCI_LCD_BRIGHTNESS, 0, 0, 0, 0 }; 933 - u32 out[TCI_WORDS]; 934 - acpi_status status; 931 + u32 hci_result; 935 932 936 933 if (dev->tr_backlight_supported) { 937 934 bool enable = !value; ··· 940 941 value--; 941 942 } 942 943 943 - in[2] = value << HCI_LCD_BRIGHTNESS_SHIFT; 944 - status = tci_raw(dev, in, out); 945 - if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 946 - pr_err("ACPI call to set brightness failed"); 947 - return -EIO; 948 - } 949 - /* Extra check for "incomplete" backlight method, where the AML code 950 - * doesn't check for HCI_SET or HCI_GET and returns TOS_SUCCESS, 951 - * the actual brightness, and in some cases the max brightness. 952 - */ 953 - if (out[2] > 0 || out[3] == 0xE000) 954 - return -ENODEV; 955 - 956 - return out[0] == TOS_SUCCESS ? 0 : -EIO; 944 + value = value << HCI_LCD_BRIGHTNESS_SHIFT; 945 + hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value); 946 + return hci_result == TOS_SUCCESS ? 0 : -EIO; 957 947 } 958 948 959 949 static int set_lcd_status(struct backlight_device *bd) ··· 1394 1406 if (ret) 1395 1407 return ret; 1396 1408 1397 - /* Update sysfs entries on successful mode change*/ 1398 - ret = sysfs_update_group(&toshiba->acpi_dev->dev.kobj, 1399 - &toshiba_attr_group); 1400 - if (ret) 1401 - return ret; 1402 - 1403 1409 toshiba->kbd_mode = mode; 1404 1410 } 1405 1411 ··· 1568 1586 return exists ? attr->mode : 0; 1569 1587 } 1570 1588 1589 + /* 1590 + * Hotkeys 1591 + */ 1592 + static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 1593 + { 1594 + acpi_status status; 1595 + u32 result; 1596 + 1597 + status = acpi_evaluate_object(dev->acpi_dev->handle, 1598 + "ENAB", NULL, NULL); 1599 + if (ACPI_FAILURE(status)) 1600 + return -ENODEV; 1601 + 1602 + result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 1603 + if (result == TOS_FAILURE) 1604 + return -EIO; 1605 + else if (result == TOS_NOT_SUPPORTED) 1606 + return -ENODEV; 1607 + 1608 + return 0; 1609 + } 1610 + 1571 1611 static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 1572 1612 struct serio *port) 1573 1613 { 1574 - if (str & 0x20) 1614 + if (str & I8042_STR_AUXDATA) 1575 1615 return false; 1576 1616 1577 1617 if (unlikely(data == 0xe0)) ··· 1652 1648 pr_info("Unknown key %x\n", scancode); 1653 1649 } 1654 1650 1651 + static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 1652 + { 1653 + u32 hci_result, value; 1654 + int retries = 3; 1655 + int scancode; 1656 + 1657 + if (dev->info_supported) { 1658 + scancode = toshiba_acpi_query_hotkey(dev); 1659 + if (scancode < 0) 1660 + pr_err("Failed to query hotkey event\n"); 1661 + else if (scancode != 0) 1662 + toshiba_acpi_report_hotkey(dev, scancode); 1663 + } else if (dev->system_event_supported) { 1664 + do { 1665 + hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); 1666 + switch (hci_result) { 1667 + case TOS_SUCCESS: 1668 + toshiba_acpi_report_hotkey(dev, (int)value); 1669 + break; 1670 + case TOS_NOT_SUPPORTED: 1671 + /* 1672 + * This is a workaround for an unresolved 1673 + * issue on some machines where system events 1674 + * sporadically become disabled. 1675 + */ 1676 + hci_result = 1677 + hci_write1(dev, HCI_SYSTEM_EVENT, 1); 1678 + pr_notice("Re-enabled hotkeys\n"); 1679 + /* fall through */ 1680 + default: 1681 + retries--; 1682 + break; 1683 + } 1684 + } while (retries && hci_result != TOS_FIFO_EMPTY); 1685 + } 1686 + } 1687 + 1655 1688 static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 1656 1689 { 1657 - acpi_status status; 1658 1690 acpi_handle ec_handle; 1659 1691 int error; 1660 1692 u32 hci_result; ··· 1717 1677 * supported, so if it's present set up an i8042 key filter 1718 1678 * for this purpose. 1719 1679 */ 1720 - status = AE_ERROR; 1721 1680 ec_handle = ec_get_handle(); 1722 1681 if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 1723 1682 INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); ··· 1747 1708 goto err_remove_filter; 1748 1709 } 1749 1710 1750 - status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL); 1751 - if (ACPI_FAILURE(status)) { 1711 + error = toshiba_acpi_enable_hotkeys(dev); 1712 + if (error) { 1752 1713 pr_info("Unable to enable hotkeys\n"); 1753 - error = -ENODEV; 1754 1714 goto err_remove_filter; 1755 1715 } 1756 1716 ··· 1759 1721 goto err_remove_filter; 1760 1722 } 1761 1723 1762 - hci_result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 1763 1724 return 0; 1764 1725 1765 1726 err_remove_filter: ··· 1847 1810 rfkill_destroy(dev->bt_rfk); 1848 1811 } 1849 1812 1850 - if (dev->backlight_dev) 1851 - backlight_device_unregister(dev->backlight_dev); 1813 + backlight_device_unregister(dev->backlight_dev); 1852 1814 1853 1815 if (dev->illumination_supported) 1854 1816 led_classdev_unregister(&dev->led_dev); ··· 2003 1967 static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2004 1968 { 2005 1969 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2006 - u32 hci_result, value; 2007 - int retries = 3; 2008 - int scancode; 1970 + int ret; 2009 1971 2010 - if (event != 0x80) 2011 - return; 2012 - 2013 - if (dev->info_supported) { 2014 - scancode = toshiba_acpi_query_hotkey(dev); 2015 - if (scancode < 0) 2016 - pr_err("Failed to query hotkey event\n"); 2017 - else if (scancode != 0) 2018 - toshiba_acpi_report_hotkey(dev, scancode); 2019 - } else if (dev->system_event_supported) { 2020 - do { 2021 - hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); 2022 - switch (hci_result) { 2023 - case TOS_SUCCESS: 2024 - toshiba_acpi_report_hotkey(dev, (int)value); 2025 - break; 2026 - case TOS_NOT_SUPPORTED: 2027 - /* 2028 - * This is a workaround for an unresolved 2029 - * issue on some machines where system events 2030 - * sporadically become disabled. 2031 - */ 2032 - hci_result = 2033 - hci_write1(dev, HCI_SYSTEM_EVENT, 1); 2034 - pr_notice("Re-enabled hotkeys\n"); 2035 - /* fall through */ 2036 - default: 2037 - retries--; 2038 - break; 2039 - } 2040 - } while (retries && hci_result != TOS_FIFO_EMPTY); 1972 + switch (event) { 1973 + case 0x80: /* Hotkeys and some system events */ 1974 + toshiba_acpi_process_hotkeys(dev); 1975 + break; 1976 + case 0x92: /* Keyboard backlight mode changed */ 1977 + /* Update sysfs entries */ 1978 + ret = sysfs_update_group(&acpi_dev->dev.kobj, 1979 + &toshiba_attr_group); 1980 + if (ret) 1981 + pr_err("Unable to update sysfs entries\n"); 1982 + break; 1983 + case 0x81: /* Unknown */ 1984 + case 0x82: /* Unknown */ 1985 + case 0x83: /* Unknown */ 1986 + case 0x8c: /* Unknown */ 1987 + case 0x8e: /* Unknown */ 1988 + case 0x8f: /* Unknown */ 1989 + case 0x90: /* Unknown */ 1990 + default: 1991 + pr_info("Unknown event received %x\n", event); 1992 + break; 2041 1993 } 2042 1994 } 2043 1995 ··· 2044 2020 static int toshiba_acpi_resume(struct device *device) 2045 2021 { 2046 2022 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 2047 - u32 result; 2048 - acpi_status status; 2023 + int error; 2049 2024 2050 2025 if (dev->hotkey_dev) { 2051 - status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", 2052 - NULL, NULL); 2053 - if (ACPI_FAILURE(status)) 2026 + error = toshiba_acpi_enable_hotkeys(dev); 2027 + if (error) 2054 2028 pr_info("Unable to re-enable hotkeys\n"); 2055 - 2056 - result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 2057 2029 } 2058 2030 2059 2031 return 0;