platform-drivers-x86 for 3.19

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
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJUkw1OAAoJEKbMaAwKp364N0AH/A/1YQDjiIsrRe7/J65rfna+
 zrH6QoQfEaTbkJX3p8VFElh0Tlx9EO7kYfxhHm45kjWjfuJsyZtEonl+CeZTEe2s
 SGP1v3wSUbHc8MI1sRqqDUSTNihJPWEPjc8jFKqyJ3iOO0r6F/UuYajPwEGpjAjh
 etHY9HBS8FNwaevh6T3tiKeyy+z34OZHsASCnZEYLKWYXRu/0dL3yNY1vIs3Ybux
 bnH+sbBUXSu3rir4V6q/4j6f1B6RnXqirPLq5rsNHhHETGCJUy+phUWZRYMEVzR3
 A3rEuHXcHMgqlVLqa+ph3nN3iyNYXVVkOfENUCp/2WDdagBqpD5isc6YmPCzsJk=
 =1/XE
 -----END PGP SIGNATURE-----

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()
  ...
This commit is contained in:
Linus Torvalds 2014-12-18 20:24:55 -08:00
commit 385336e321
22 changed files with 1781 additions and 415 deletions

View File

@ -0,0 +1,60 @@
What: /sys/class/leds/dell::kbd_backlight/als_setting
Date: December 2014
KernelVersion: 3.19
Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>,
Pali Rohár <pali.rohar@gmail.com>
Description:
This file allows to control the automatic keyboard
illumination mode on some systems that have an ambient
light sensor. Write 1 to this file to enable the auto
mode, 0 to disable it.
What: /sys/class/leds/dell::kbd_backlight/start_triggers
Date: December 2014
KernelVersion: 3.19
Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>,
Pali Rohár <pali.rohar@gmail.com>
Description:
This file allows to control the input triggers that
turn on the keyboard backlight illumination that is
disabled because of inactivity.
Read the file to see the triggers available. The ones
enabled are preceded by '+', those disabled by '-'.
To enable a trigger, write its name preceded by '+' to
this file. To disable a trigger, write its name preceded
by '-' instead.
For example, to enable the keyboard as trigger run:
echo +keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers
To disable it:
echo -keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers
Note that not all the available triggers can be configured.
What: /sys/class/leds/dell::kbd_backlight/stop_timeout
Date: December 2014
KernelVersion: 3.19
Contact: Gabriele Mazzotta <gabriele.mzt@gmail.com>,
Pali Rohár <pali.rohar@gmail.com>
Description:
This file allows to specify the interval after which the
keyboard illumination is disabled because of inactivity.
The timeouts are expressed in seconds, minutes, hours and
days, for which the symbols are 's', 'm', 'h' and 'd'
respectively.
To configure the timeout, write to this file a value along
with any the above units. If no unit is specified, the value
is assumed to be expressed in seconds.
For example, to set the timeout to 10 minutes run:
echo 10m > /sys/class/leds/dell::kbd_backlight/stop_timeout
Note that when this file is read, the returned value might be
expressed in a different unit than the one used when the timeout
was set.
Also note that only some timeouts are supported and that
some systems might fall back to a specific timeout in case
an invalid timeout is written to this file.

View File

@ -304,60 +304,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
* Linux ignores it, except for the machines enumerated below. * Linux ignores it, except for the machines enumerated below.
*/ */
/*
* Lenovo has a mix of systems OSI(Linux) situations
* and thus we can not wildcard the vendor.
*
* _OSI(Linux) helps sound
* DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
* DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
* T400, T500
* _OSI(Linux) has Linux specific hooks
* DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"),
* _OSI(Linux) is a NOP:
* DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
* DMI_MATCH(DMI_PRODUCT_VERSION, "LENOVO3000 V100"),
*/
{
.callback = dmi_enable_osi_linux,
.ident = "Lenovo ThinkPad R61",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
},
},
{
.callback = dmi_enable_osi_linux,
.ident = "Lenovo ThinkPad T61",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
},
},
{
.callback = dmi_enable_osi_linux,
.ident = "Lenovo ThinkPad X61",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"),
},
},
{
.callback = dmi_enable_osi_linux,
.ident = "Lenovo ThinkPad T400",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T400"),
},
},
{
.callback = dmi_enable_osi_linux,
.ident = "Lenovo ThinkPad T500",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T500"),
},
},
/* /*
* Without this this EEEpc exports a non working WMI interface, with * Without this this EEEpc exports a non working WMI interface, with
* this it exports a working "good old" eeepc_laptop interface, fixing * this it exports a working "good old" eeepc_laptop interface, fixing

View File

@ -38,7 +38,8 @@ config ACER_WMI
config ACERHDF config ACERHDF
tristate "Acer Aspire One temperature and fan driver" tristate "Acer Aspire One temperature and fan driver"
depends on THERMAL && ACPI depends on ACPI && THERMAL
select THERMAL_GOV_BANG_BANG
---help--- ---help---
This is a driver for Acer Aspire One netbooks. It allows to access This is a driver for Acer Aspire One netbooks. It allows to access
the temperature sensor and to control the fan. the temperature sensor and to control the fan.
@ -128,10 +129,10 @@ config DELL_WMI_AIO
be called dell-wmi-aio. be called dell-wmi-aio.
config DELL_SMO8800 config DELL_SMO8800
tristate "Dell Latitude freefall driver (ACPI SMO8800/SMO8810)" tristate "Dell Latitude freefall driver (ACPI SMO88XX)"
depends on ACPI depends on ACPI
---help--- ---help---
Say Y here if you want to support SMO8800/SMO8810 freefall device Say Y here if you want to support SMO88XX freefall devices
on Dell Latitude laptops. on Dell Latitude laptops.
To compile this driver as a module, choose M here: the module will To compile this driver as a module, choose M here: the module will

View File

@ -50,7 +50,7 @@
*/ */
#undef START_IN_KERNEL_MODE #undef START_IN_KERNEL_MODE
#define DRV_VER "0.5.26" #define DRV_VER "0.7.0"
/* /*
* According to the Atom N270 datasheet, * According to the Atom N270 datasheet,
@ -119,116 +119,152 @@ struct fancmd {
u8 cmd_auto; u8 cmd_auto;
}; };
struct manualcmd {
u8 mreg;
u8 moff;
};
/* default register and command to disable fan in manual mode */
static const struct manualcmd mcmd = {
.mreg = 0x94,
.moff = 0xff,
};
/* BIOS settings */ /* BIOS settings */
struct bios_settings_t { struct bios_settings {
const char *vendor; const char *vendor;
const char *product; const char *product;
const char *version; const char *version;
unsigned char fanreg; u8 fanreg;
unsigned char tempreg; u8 tempreg;
struct fancmd cmd; struct fancmd cmd;
int mcmd_enable;
}; };
/* Register addresses and values for different BIOS versions */ /* Register addresses and values for different BIOS versions */
static const struct bios_settings_t bios_tbl[] = { static const struct bios_settings bios_tbl[] = {
/* AOA110 */ /* AOA110 */
{"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00}, 0},
{"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0},
{"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00}, 0},
{"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00}, 0},
{"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00}, 0},
{"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} }, {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00}, 0},
{"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00}, 0},
{"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00}, 0},
{"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00}, 0},
/* AOA150 */ /* AOA150 */
{"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0},
{"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00}, 0},
{"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00}, 0},
{"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00}, 0},
{"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00}, 0},
{"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00}, 0},
{"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00}, 0},
{"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00}, 0},
/* LT1005u */ /* LT1005u */
{"Acer", "LT-10Q", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "LT-10Q", "v0.3310", 0x55, 0x58, {0x20, 0x00}, 0},
/* Acer 1410 */ /* Acer 1410 */
{"Acer", "Aspire 1410", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1410", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1410", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1410", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1410", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1410", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1410", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1410", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1410", "v1.3314", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1410", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0},
/* Acer 1810xx */ /* Acer 1810xx */
{"Acer", "Aspire 1810TZ", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810TZ", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810TZ", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810TZ", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810TZ", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810TZ", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810TZ", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1810T", "v1.3314", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0},
/* Acer 5755G */
{"Acer", "Aspire 5755G", "V1.20", 0xab, 0xb4, {0x00, 0x08}, 0},
{"Acer", "Aspire 5755G", "V1.21", 0xab, 0xb3, {0x00, 0x08}, 0},
/* Acer 521 */
{"Acer", "AO521", "V1.11", 0x55, 0x58, {0x1f, 0x00}, 0},
/* Acer 531 */ /* Acer 531 */
{"Acer", "AO531h", "v0.3104", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AO531h", "v0.3104", 0x55, 0x58, {0x20, 0x00}, 0},
{"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00}, 0},
{"Acer", "AO531h", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, {"Acer", "AO531h", "v0.3304", 0x55, 0x58, {0x20, 0x00}, 0},
/* Acer 751 */ /* Acer 751 */
{"Acer", "AO751h", "V0.3212", 0x55, 0x58, {0x21, 0x00} }, {"Acer", "AO751h", "V0.3206", 0x55, 0x58, {0x21, 0x00}, 0},
{"Acer", "AO751h", "V0.3212", 0x55, 0x58, {0x21, 0x00}, 0},
/* Acer 753 */
{"Acer", "Aspire One 753", "V1.24", 0x93, 0xac, {0x14, 0x04}, 1},
/* Acer 1825 */ /* Acer 1825 */
{"Acer", "Aspire 1825PTZ", "V1.3118", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1825PTZ", "V1.3118", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Acer", "Aspire 1825PTZ", "V1.3127", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1825PTZ", "V1.3127", 0x55, 0x58, {0x9e, 0x00}, 0},
/* Acer Extensa 5420 */
{"Acer", "Extensa 5420", "V1.17", 0x93, 0xac, {0x14, 0x04}, 1},
/* Acer Aspire 5315 */
{"Acer", "Aspire 5315", "V1.19", 0x93, 0xac, {0x14, 0x04}, 1},
/* Acer Aspire 5739 */
{"Acer", "Aspire 5739G", "V1.3311", 0x55, 0x58, {0x20, 0x00}, 0},
/* Acer TravelMate 7730 */ /* Acer TravelMate 7730 */
{"Acer", "TravelMate 7730G", "v0.3509", 0x55, 0x58, {0xaf, 0x00} }, {"Acer", "TravelMate 7730G", "v0.3509", 0x55, 0x58, {0xaf, 0x00}, 0},
/* Acer TravelMate TM8573T */
{"Acer", "TM8573T", "V1.13", 0x93, 0xa8, {0x14, 0x04}, 1},
/* Gateway */ /* Gateway */
{"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00}, 0},
{"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} }, {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00}, 0},
{"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x9e, 0x00} }, {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00} }, {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00} }, {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Gateway", "LT31", "v1.3303t", 0x55, 0x58, {0x9e, 0x00} }, {"Gateway", "LT31", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0},
/* Packard Bell */ /* Packard Bell */
{"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} }, {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00}, 0},
{"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0},
{"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00}, 0},
{"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0},
{"Packard Bell", "ENBFT", "V1.3118", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "ENBFT", "V1.3118", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "ENBFT", "V1.3127", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "ENBFT", "V1.3127", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMU", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMU", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMU", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMU", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMU", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMU", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMU", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMU", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMU", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMU", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMU", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMU", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMA", "v1.3201", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMA", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMA", "v1.3302", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMA", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTMA", "v1.3303t", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTMA", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Packard Bell", "DOTVR46", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, {"Packard Bell", "DOTVR46", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0},
/* pewpew-terminator */ /* pewpew-terminator */
{"", "", "", 0, 0, {0, 0} } {"", "", "", 0, 0, {0, 0}, 0}
}; };
static const struct bios_settings_t *bios_cfg __read_mostly; static const struct bios_settings *bios_cfg __read_mostly;
/*
* this struct is used to instruct thermal layer to use bang_bang instead of
* default governor for acerhdf
*/
static struct thermal_zone_params acerhdf_zone_params = {
.governor_name = "bang_bang",
};
static int acerhdf_get_temp(int *temp) static int acerhdf_get_temp(int *temp)
{ {
@ -275,6 +311,12 @@ static void acerhdf_change_fanstate(int state)
fanstate = state; fanstate = state;
ec_write(bios_cfg->fanreg, cmd); ec_write(bios_cfg->fanreg, cmd);
if (bios_cfg->mcmd_enable && state == ACERHDF_FAN_OFF) {
if (verbose)
pr_notice("turning off fan manually\n");
ec_write(mcmd.mreg, mcmd.moff);
}
} }
static void acerhdf_check_param(struct thermal_zone_device *thermal) static void acerhdf_check_param(struct thermal_zone_device *thermal)
@ -401,6 +443,21 @@ static int acerhdf_get_trip_type(struct thermal_zone_device *thermal, int trip,
{ {
if (trip == 0) if (trip == 0)
*type = THERMAL_TRIP_ACTIVE; *type = THERMAL_TRIP_ACTIVE;
else if (trip == 1)
*type = THERMAL_TRIP_CRITICAL;
else
return -EINVAL;
return 0;
}
static int acerhdf_get_trip_hyst(struct thermal_zone_device *thermal, int trip,
unsigned long *temp)
{
if (trip != 0)
return -EINVAL;
*temp = fanon - fanoff;
return 0; return 0;
} }
@ -410,6 +467,10 @@ static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip,
{ {
if (trip == 0) if (trip == 0)
*temp = fanon; *temp = fanon;
else if (trip == 1)
*temp = ACERHDF_TEMP_CRIT;
else
return -EINVAL;
return 0; return 0;
} }
@ -429,6 +490,7 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
.get_mode = acerhdf_get_mode, .get_mode = acerhdf_get_mode,
.set_mode = acerhdf_set_mode, .set_mode = acerhdf_set_mode,
.get_trip_type = acerhdf_get_trip_type, .get_trip_type = acerhdf_get_trip_type,
.get_trip_hyst = acerhdf_get_trip_hyst,
.get_trip_temp = acerhdf_get_trip_temp, .get_trip_temp = acerhdf_get_trip_temp,
.get_crit_temp = acerhdf_get_crit_temp, .get_crit_temp = acerhdf_get_crit_temp,
}; };
@ -481,9 +543,7 @@ static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
} }
if (state == 0) { if (state == 0) {
/* turn fan off only if below fanoff temperature */ if (cur_state == ACERHDF_FAN_AUTO)
if ((cur_state == ACERHDF_FAN_AUTO) &&
(cur_temp < fanoff))
acerhdf_change_fanstate(ACERHDF_FAN_OFF); acerhdf_change_fanstate(ACERHDF_FAN_OFF);
} else { } else {
if (cur_state == ACERHDF_FAN_OFF) if (cur_state == ACERHDF_FAN_OFF)
@ -558,7 +618,7 @@ static int str_starts_with(const char *str, const char *start)
static int acerhdf_check_hardware(void) static int acerhdf_check_hardware(void)
{ {
char const *vendor, *version, *product; char const *vendor, *version, *product;
const struct bios_settings_t *bt = NULL; const struct bios_settings *bt = NULL;
/* get BIOS data */ /* get BIOS data */
vendor = dmi_get_system_info(DMI_SYS_VENDOR); vendor = dmi_get_system_info(DMI_SYS_VENDOR);
@ -660,12 +720,20 @@ static int acerhdf_register_thermal(void)
if (IS_ERR(cl_dev)) if (IS_ERR(cl_dev))
return -EINVAL; return -EINVAL;
thz_dev = thermal_zone_device_register("acerhdf", 1, 0, NULL, thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
&acerhdf_dev_ops, NULL, 0, &acerhdf_dev_ops,
&acerhdf_zone_params, 0,
(kernelmode) ? interval*1000 : 0); (kernelmode) ? interval*1000 : 0);
if (IS_ERR(thz_dev)) if (IS_ERR(thz_dev))
return -EINVAL; return -EINVAL;
if (strcmp(thz_dev->governor->name,
acerhdf_zone_params.governor_name)) {
pr_err("Didn't get thermal governor %s, perhaps not compiled into thermal subsystem.\n",
acerhdf_zone_params.governor_name);
return -EINVAL;
}
return 0; return 0;
} }
@ -722,9 +790,15 @@ MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAO751h*:"); MODULE_ALIAS("dmi:*:*Acer*:pnAO751h*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1410*:"); MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1410*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1810*:"); MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1810*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5755G:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1825PTZ:"); MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1825PTZ:");
MODULE_ALIAS("dmi:*:*Acer*:pnAO521*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:"); MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5739G:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire*One*753:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5315:");
MODULE_ALIAS("dmi:*:*Acer*:TravelMate*7730G:"); MODULE_ALIAS("dmi:*:*Acer*:TravelMate*7730G:");
MODULE_ALIAS("dmi:*:*Acer*:TM8573T:");
MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:"); MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:");
MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:"); MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:");
MODULE_ALIAS("dmi:*:*Packard*Bell*:pnAOA*:"); MODULE_ALIAS("dmi:*:*Packard*Bell*:pnAOA*:");
@ -733,6 +807,7 @@ MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMU*:");
MODULE_ALIAS("dmi:*:*Packard*Bell*:pnENBFT*:"); MODULE_ALIAS("dmi:*:*Packard*Bell*:pnENBFT*:");
MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMA*:"); MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMA*:");
MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTVR46*:"); MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTVR46*:");
MODULE_ALIAS("dmi:*:*Acer*:pnExtensa 5420*:");
module_init(acerhdf_init); module_init(acerhdf_init);
module_exit(acerhdf_exit); module_exit(acerhdf_exit);

View File

@ -843,8 +843,7 @@ static int asus_backlight_init(struct asus_laptop *asus)
static void asus_backlight_exit(struct asus_laptop *asus) static void asus_backlight_exit(struct asus_laptop *asus)
{ {
if (asus->backlight_device) backlight_device_unregister(asus->backlight_device);
backlight_device_unregister(asus->backlight_device);
asus->backlight_device = NULL; asus->backlight_device = NULL;
} }

View File

@ -189,6 +189,15 @@ static const struct dmi_system_id asus_quirks[] = {
}, },
.driver_data = &quirk_asus_wapf4, .driver_data = &quirk_asus_wapf4,
}, },
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. X551CA",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X551CA"),
},
.driver_data = &quirk_asus_wapf4,
},
{ {
.callback = dmi_matched, .callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. X55A", .ident = "ASUSTeK COMPUTER INC. X55A",

View File

@ -1308,8 +1308,7 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
static void asus_wmi_backlight_exit(struct asus_wmi *asus) static void asus_wmi_backlight_exit(struct asus_wmi *asus)
{ {
if (asus->backlight_device) backlight_device_unregister(asus->backlight_device);
backlight_device_unregister(asus->backlight_device);
asus->backlight_device = NULL; asus->backlight_device = NULL;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/* /*
* dell-smo8800.c - Dell Latitude ACPI SMO8800/SMO8810 freefall sensor driver * dell-smo8800.c - Dell Latitude ACPI SMO88XX freefall sensor driver
* *
* Copyright (C) 2012 Sonal Santan <sonal.santan@gmail.com> * Copyright (C) 2012 Sonal Santan <sonal.santan@gmail.com>
* Copyright (C) 2014 Pali Rohár <pali.rohar@gmail.com> * Copyright (C) 2014 Pali Rohár <pali.rohar@gmail.com>
@ -209,7 +209,13 @@ static int smo8800_remove(struct acpi_device *device)
static const struct acpi_device_id smo8800_ids[] = { static const struct acpi_device_id smo8800_ids[] = {
{ "SMO8800", 0 }, { "SMO8800", 0 },
{ "SMO8801", 0 },
{ "SMO8810", 0 }, { "SMO8810", 0 },
{ "SMO8811", 0 },
{ "SMO8820", 0 },
{ "SMO8821", 0 },
{ "SMO8830", 0 },
{ "SMO8831", 0 },
{ "", 0 }, { "", 0 },
}; };
@ -228,6 +234,6 @@ static struct acpi_driver smo8800_driver = {
module_acpi_driver(smo8800_driver); module_acpi_driver(smo8800_driver);
MODULE_DESCRIPTION("Dell Latitude freefall driver (ACPI SMO8800/SMO8810)"); MODULE_DESCRIPTION("Dell Latitude freefall driver (ACPI SMO88XX)");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sonal Santan, Pali Rohár"); MODULE_AUTHOR("Sonal Santan, Pali Rohár");

View File

@ -65,10 +65,8 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
/* Battery health status button */ /* Battery health status button */
{ KE_KEY, 0xe007, { KEY_BATTERY } }, { KE_KEY, 0xe007, { KEY_BATTERY } },
/* This is actually for all radios. Although physically a /* Radio devices state change */
* switch, the notification does not provide an indication of { KE_IGNORE, 0xe008, { KEY_RFKILL } },
* state and so it should be reported as a key */
{ KE_KEY, 0xe008, { KEY_WLAN } },
/* The next device is at offset 6, the active devices are at /* The next device is at offset 6, the active devices are at
offset 8 and the attached devices at offset 10 */ offset 8 and the attached devices at offset 10 */
@ -145,57 +143,154 @@ static const u16 bios_to_linux_keycode[256] __initconst = {
static struct input_dev *dell_wmi_input_dev; static struct input_dev *dell_wmi_input_dev;
static void dell_wmi_process_key(int reported_key)
{
const struct key_entry *key;
key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
reported_key);
if (!key) {
pr_info("Unknown key %x pressed\n", reported_key);
return;
}
pr_debug("Key %x pressed\n", reported_key);
/* Don't report brightness notifications that will also come via ACPI */
if ((key->keycode == KEY_BRIGHTNESSUP ||
key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video)
return;
sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true);
}
static void dell_wmi_notify(u32 value, void *context) static void dell_wmi_notify(u32 value, void *context)
{ {
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj; union acpi_object *obj;
acpi_status status; acpi_status status;
acpi_size buffer_size;
u16 *buffer_entry, *buffer_end;
int len, i;
status = wmi_get_event_data(value, &response); status = wmi_get_event_data(value, &response);
if (status != AE_OK) { if (status != AE_OK) {
pr_info("bad event status 0x%x\n", status); pr_warn("bad event status 0x%x\n", status);
return; return;
} }
obj = (union acpi_object *)response.pointer; obj = (union acpi_object *)response.pointer;
if (!obj) {
if (obj && obj->type == ACPI_TYPE_BUFFER) { pr_warn("no response\n");
const struct key_entry *key; return;
int reported_key;
u16 *buffer_entry = (u16 *)obj->buffer.pointer;
int buffer_size = obj->buffer.length/2;
if (buffer_size >= 2 && dell_new_hk_type && buffer_entry[1] != 0x10) {
pr_info("Received unknown WMI event (0x%x)\n",
buffer_entry[1]);
kfree(obj);
return;
}
if (buffer_size >= 3 && (dell_new_hk_type || buffer_entry[1] == 0x0))
reported_key = (int)buffer_entry[2];
else if (buffer_size >= 2)
reported_key = (int)buffer_entry[1] & 0xffff;
else {
pr_info("Received unknown WMI event\n");
kfree(obj);
return;
}
key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
reported_key);
if (!key) {
pr_info("Unknown key %x pressed\n", reported_key);
} else if ((key->keycode == KEY_BRIGHTNESSUP ||
key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) {
/* Don't report brightness notifications that will also
* come via ACPI */
;
} else {
sparse_keymap_report_entry(dell_wmi_input_dev, key,
1, true);
}
} }
if (obj->type != ACPI_TYPE_BUFFER) {
pr_warn("bad response type %x\n", obj->type);
kfree(obj);
return;
}
pr_debug("Received WMI event (%*ph)\n",
obj->buffer.length, obj->buffer.pointer);
buffer_entry = (u16 *)obj->buffer.pointer;
buffer_size = obj->buffer.length/2;
if (!dell_new_hk_type) {
if (buffer_size >= 3 && buffer_entry[1] == 0x0)
dell_wmi_process_key(buffer_entry[2]);
else if (buffer_size >= 2)
dell_wmi_process_key(buffer_entry[1]);
else
pr_info("Received unknown WMI event\n");
kfree(obj);
return;
}
buffer_end = buffer_entry + buffer_size;
while (buffer_entry < buffer_end) {
len = buffer_entry[0];
if (len == 0)
break;
len++;
if (buffer_entry + len > buffer_end) {
pr_warn("Invalid length of WMI event\n");
break;
}
pr_debug("Process buffer (%*ph)\n", len*2, buffer_entry);
switch (buffer_entry[1]) {
case 0x00:
for (i = 2; i < len; ++i) {
switch (buffer_entry[i]) {
case 0xe043:
/* NIC Link is Up */
pr_debug("NIC Link is Up\n");
break;
case 0xe044:
/* NIC Link is Down */
pr_debug("NIC Link is Down\n");
break;
case 0xe045:
/* Unknown event but defined in DSDT */
default:
/* Unknown event */
pr_info("Unknown WMI event type 0x00: "
"0x%x\n", (int)buffer_entry[i]);
break;
}
}
break;
case 0x10:
/* Keys pressed */
for (i = 2; i < len; ++i)
dell_wmi_process_key(buffer_entry[i]);
break;
case 0x11:
for (i = 2; i < len; ++i) {
switch (buffer_entry[i]) {
case 0xfff0:
/* Battery unplugged */
pr_debug("Battery unplugged\n");
break;
case 0xfff1:
/* Battery inserted */
pr_debug("Battery inserted\n");
break;
case 0x01e1:
case 0x02ea:
case 0x02eb:
case 0x02ec:
case 0x02f6:
/* Keyboard backlight level changed */
pr_debug("Keyboard backlight level "
"changed\n");
break;
default:
/* Unknown event */
pr_info("Unknown WMI event type 0x11: "
"0x%x\n", (int)buffer_entry[i]);
break;
}
}
break;
default:
/* Unknown event */
pr_info("Unknown WMI event type 0x%x\n",
(int)buffer_entry[1]);
break;
}
buffer_entry += len;
}
kfree(obj); kfree(obj);
} }
@ -213,11 +308,16 @@ static const struct key_entry * __init dell_wmi_prepare_new_keymap(void)
for (i = 0; i < hotkey_num; i++) { for (i = 0; i < hotkey_num; i++) {
const struct dell_bios_keymap_entry *bios_entry = const struct dell_bios_keymap_entry *bios_entry =
&dell_bios_hotkey_table->keymap[i]; &dell_bios_hotkey_table->keymap[i];
keymap[i].type = KE_KEY; u16 keycode = bios_entry->keycode < 256 ?
keymap[i].code = bios_entry->scancode;
keymap[i].keycode = bios_entry->keycode < 256 ?
bios_to_linux_keycode[bios_entry->keycode] : bios_to_linux_keycode[bios_entry->keycode] :
KEY_RESERVED; KEY_RESERVED;
if (keycode == KEY_KBDILLUMTOGGLE)
keymap[i].type = KE_IGNORE;
else
keymap[i].type = KE_KEY;
keymap[i].code = bios_entry->scancode;
keymap[i].keycode = keycode;
} }
keymap[hotkey_num].type = KE_END; keymap[hotkey_num].type = KE_END;

View File

@ -417,8 +417,7 @@ static ssize_t cpufv_disabled_store(struct device *dev,
switch (value) { switch (value) {
case 0: case 0:
if (eeepc->cpufv_disabled) if (eeepc->cpufv_disabled)
pr_warn("cpufv enabled (not officially supported " pr_warn("cpufv enabled (not officially supported on this model)\n");
"on this model)\n");
eeepc->cpufv_disabled = false; eeepc->cpufv_disabled = false;
return count; return count;
case 1: case 1:
@ -580,60 +579,59 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
mutex_lock(&eeepc->hotplug_lock); mutex_lock(&eeepc->hotplug_lock);
pci_lock_rescan_remove(); pci_lock_rescan_remove();
if (eeepc->hotplug_slot) { if (!eeepc->hotplug_slot)
port = acpi_get_pci_dev(handle); goto out_unlock;
if (!port) {
pr_warning("Unable to find port\n");
goto out_unlock;
}
bus = port->subordinate; port = acpi_get_pci_dev(handle);
if (!port) {
if (!bus) { pr_warning("Unable to find port\n");
pr_warn("Unable to find PCI bus 1?\n"); goto out_unlock;
goto out_put_dev;
}
if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
pr_err("Unable to read PCI config space?\n");
goto out_put_dev;
}
absent = (l == 0xffffffff);
if (blocked != absent) {
pr_warn("BIOS says wireless lan is %s, "
"but the pci device is %s\n",
blocked ? "blocked" : "unblocked",
absent ? "absent" : "present");
pr_warn("skipped wireless hotplug as probably "
"inappropriate for this model\n");
goto out_put_dev;
}
if (!blocked) {
dev = pci_get_slot(bus, 0);
if (dev) {
/* Device already present */
pci_dev_put(dev);
goto out_put_dev;
}
dev = pci_scan_single_device(bus, 0);
if (dev) {
pci_bus_assign_resources(bus);
pci_bus_add_device(dev);
}
} else {
dev = pci_get_slot(bus, 0);
if (dev) {
pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
}
out_put_dev:
pci_dev_put(port);
} }
bus = port->subordinate;
if (!bus) {
pr_warn("Unable to find PCI bus 1?\n");
goto out_put_dev;
}
if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
pr_err("Unable to read PCI config space?\n");
goto out_put_dev;
}
absent = (l == 0xffffffff);
if (blocked != absent) {
pr_warn("BIOS says wireless lan is %s, but the pci device is %s\n",
blocked ? "blocked" : "unblocked",
absent ? "absent" : "present");
pr_warn("skipped wireless hotplug as probably inappropriate for this model\n");
goto out_put_dev;
}
if (!blocked) {
dev = pci_get_slot(bus, 0);
if (dev) {
/* Device already present */
pci_dev_put(dev);
goto out_put_dev;
}
dev = pci_scan_single_device(bus, 0);
if (dev) {
pci_bus_assign_resources(bus);
pci_bus_add_device(dev);
}
} else {
dev = pci_get_slot(bus, 0);
if (dev) {
pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
}
out_put_dev:
pci_dev_put(port);
out_unlock: out_unlock:
pci_unlock_rescan_remove(); pci_unlock_rescan_remove();
mutex_unlock(&eeepc->hotplug_lock); mutex_unlock(&eeepc->hotplug_lock);
@ -821,11 +819,15 @@ static int eeepc_new_rfkill(struct eeepc_laptop *eeepc,
return 0; return 0;
} }
static char EEEPC_RFKILL_NODE_1[] = "\\_SB.PCI0.P0P5";
static char EEEPC_RFKILL_NODE_2[] = "\\_SB.PCI0.P0P6";
static char EEEPC_RFKILL_NODE_3[] = "\\_SB.PCI0.P0P7";
static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc) static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc)
{ {
eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_1);
eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_2);
eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_3);
if (eeepc->wlan_rfkill) { if (eeepc->wlan_rfkill) {
rfkill_unregister(eeepc->wlan_rfkill); rfkill_unregister(eeepc->wlan_rfkill);
rfkill_destroy(eeepc->wlan_rfkill); rfkill_destroy(eeepc->wlan_rfkill);
@ -897,9 +899,9 @@ static int eeepc_rfkill_init(struct eeepc_laptop *eeepc)
if (result == -EBUSY) if (result == -EBUSY)
result = 0; result = 0;
eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_1);
eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_2);
eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_3);
exit: exit:
if (result && result != -ENODEV) if (result && result != -ENODEV)
@ -915,7 +917,7 @@ static int eeepc_hotk_thaw(struct device *device)
struct eeepc_laptop *eeepc = dev_get_drvdata(device); struct eeepc_laptop *eeepc = dev_get_drvdata(device);
if (eeepc->wlan_rfkill) { if (eeepc->wlan_rfkill) {
bool wlan; int wlan;
/* /*
* Work around bios bug - acpi _PTS turns off the wireless led * Work around bios bug - acpi _PTS turns off the wireless led
@ -923,7 +925,8 @@ static int eeepc_hotk_thaw(struct device *device)
* we should kick it ourselves in case hibernation is aborted. * we should kick it ourselves in case hibernation is aborted.
*/ */
wlan = get_acpi(eeepc, CM_ASL_WLAN); wlan = get_acpi(eeepc, CM_ASL_WLAN);
set_acpi(eeepc, CM_ASL_WLAN, wlan); if (wlan >= 0)
set_acpi(eeepc, CM_ASL_WLAN, wlan);
} }
return 0; return 0;
@ -935,9 +938,9 @@ static int eeepc_hotk_restore(struct device *device)
/* Refresh both wlan rfkill state and pci hotplug */ /* Refresh both wlan rfkill state and pci hotplug */
if (eeepc->wlan_rfkill) { if (eeepc->wlan_rfkill) {
eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P5"); eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_1);
eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P6"); eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_2);
eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P7"); eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_3);
} }
if (eeepc->bluetooth_rfkill) if (eeepc->bluetooth_rfkill)
@ -977,18 +980,28 @@ static struct platform_driver platform_driver = {
#define EEEPC_EC_SFB0 0xD0 #define EEEPC_EC_SFB0 0xD0
#define EEEPC_EC_FAN_CTRL (EEEPC_EC_SFB0 + 3) /* Byte containing SF25 */ #define EEEPC_EC_FAN_CTRL (EEEPC_EC_SFB0 + 3) /* Byte containing SF25 */
static inline int eeepc_pwm_to_lmsensors(int value)
{
return value * 255 / 100;
}
static inline int eeepc_lmsensors_to_pwm(int value)
{
value = clamp_val(value, 0, 255);
return value * 100 / 255;
}
static int eeepc_get_fan_pwm(void) static int eeepc_get_fan_pwm(void)
{ {
u8 value = 0; u8 value = 0;
ec_read(EEEPC_EC_FAN_PWM, &value); ec_read(EEEPC_EC_FAN_PWM, &value);
return value * 255 / 100; return eeepc_pwm_to_lmsensors(value);
} }
static void eeepc_set_fan_pwm(int value) static void eeepc_set_fan_pwm(int value)
{ {
value = clamp_val(value, 0, 255); value = eeepc_lmsensors_to_pwm(value);
value = value * 100 / 255;
ec_write(EEEPC_EC_FAN_PWM, value); ec_write(EEEPC_EC_FAN_PWM, value);
} }
@ -1002,15 +1015,19 @@ static int eeepc_get_fan_rpm(void)
return high << 8 | low; return high << 8 | low;
} }
#define EEEPC_EC_FAN_CTRL_BIT 0x02
#define EEEPC_FAN_CTRL_MANUAL 1
#define EEEPC_FAN_CTRL_AUTO 2
static int eeepc_get_fan_ctrl(void) static int eeepc_get_fan_ctrl(void)
{ {
u8 value = 0; u8 value = 0;
ec_read(EEEPC_EC_FAN_CTRL, &value); ec_read(EEEPC_EC_FAN_CTRL, &value);
if (value & 0x02) if (value & EEEPC_EC_FAN_CTRL_BIT)
return 1; /* manual */ return EEEPC_FAN_CTRL_MANUAL;
else else
return 2; /* automatic */ return EEEPC_FAN_CTRL_AUTO;
} }
static void eeepc_set_fan_ctrl(int manual) static void eeepc_set_fan_ctrl(int manual)
@ -1018,10 +1035,10 @@ static void eeepc_set_fan_ctrl(int manual)
u8 value = 0; u8 value = 0;
ec_read(EEEPC_EC_FAN_CTRL, &value); ec_read(EEEPC_EC_FAN_CTRL, &value);
if (manual == 1) if (manual == EEEPC_FAN_CTRL_MANUAL)
value |= 0x02; value |= EEEPC_EC_FAN_CTRL_BIT;
else else
value &= ~0x02; value &= ~EEEPC_EC_FAN_CTRL_BIT;
ec_write(EEEPC_EC_FAN_CTRL, value); ec_write(EEEPC_EC_FAN_CTRL, value);
} }
@ -1156,8 +1173,7 @@ static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
static void eeepc_backlight_exit(struct eeepc_laptop *eeepc) static void eeepc_backlight_exit(struct eeepc_laptop *eeepc)
{ {
if (eeepc->backlight_device) backlight_device_unregister(eeepc->backlight_device);
backlight_device_unregister(eeepc->backlight_device);
eeepc->backlight_device = NULL; eeepc->backlight_device = NULL;
} }
@ -1216,7 +1232,7 @@ static void eeepc_input_exit(struct eeepc_laptop *eeepc)
static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event) static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
{ {
if (!eeepc->inputdev) if (!eeepc->inputdev)
return ; return;
if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true)) if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))
pr_info("Unknown key %x pressed\n", event); pr_info("Unknown key %x pressed\n", event);
} }
@ -1224,6 +1240,7 @@ static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
static void eeepc_acpi_notify(struct acpi_device *device, u32 event) static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
{ {
struct eeepc_laptop *eeepc = acpi_driver_data(device); struct eeepc_laptop *eeepc = acpi_driver_data(device);
int old_brightness, new_brightness;
u16 count; u16 count;
if (event > ACPI_MAX_SYS_NOTIFY) if (event > ACPI_MAX_SYS_NOTIFY)
@ -1234,34 +1251,32 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
count); count);
/* Brightness events are special */ /* Brightness events are special */
if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) { if (event < NOTIFY_BRN_MIN || event > NOTIFY_BRN_MAX) {
/* Ignore them completely if the acpi video driver is used */
if (eeepc->backlight_device != NULL) {
int old_brightness, new_brightness;
/* Update the backlight device. */
old_brightness = eeepc_backlight_notify(eeepc);
/* Convert event to keypress (obsolescent hack) */
new_brightness = event - NOTIFY_BRN_MIN;
if (new_brightness < old_brightness) {
event = NOTIFY_BRN_MIN; /* brightness down */
} else if (new_brightness > old_brightness) {
event = NOTIFY_BRN_MAX; /* brightness up */
} else {
/*
* no change in brightness - already at min/max,
* event will be desired value (or else ignored)
*/
}
eeepc_input_notify(eeepc, event);
}
} else {
/* Everything else is a bona-fide keypress event */
eeepc_input_notify(eeepc, event); eeepc_input_notify(eeepc, event);
return;
} }
/* Ignore them completely if the acpi video driver is used */
if (!eeepc->backlight_device)
return;
/* Update the backlight device. */
old_brightness = eeepc_backlight_notify(eeepc);
/* Convert event to keypress (obsolescent hack) */
new_brightness = event - NOTIFY_BRN_MIN;
if (new_brightness < old_brightness) {
event = NOTIFY_BRN_MIN; /* brightness down */
} else if (new_brightness > old_brightness) {
event = NOTIFY_BRN_MAX; /* brightness up */
} else {
/*
* no change in brightness - already at min/max,
* event will be desired value (or else ignored)
*/
}
eeepc_input_notify(eeepc, event);
} }
static void eeepc_dmi_check(struct eeepc_laptop *eeepc) static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
@ -1293,8 +1308,8 @@ static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
*/ */
if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) { if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
eeepc->cpufv_disabled = true; eeepc->cpufv_disabled = true;
pr_info("model %s does not officially support setting cpu " pr_info("model %s does not officially support setting cpu speed\n",
"speed\n", model); model);
pr_info("cpufv disabled to avoid instability\n"); pr_info("cpufv disabled to avoid instability\n");
} }
@ -1320,8 +1335,8 @@ static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)
Check if cm_getv[cm] works and, if yes, assume cm should be set. */ Check if cm_getv[cm] works and, if yes, assume cm should be set. */
if (!(eeepc->cm_supported & (1 << cm)) if (!(eeepc->cm_supported & (1 << cm))
&& !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {
pr_info("%s (%x) not reported by BIOS," pr_info("%s (%x) not reported by BIOS, enabling anyway\n",
" enabling anyway\n", name, 1 << cm); name, 1 << cm);
eeepc->cm_supported |= 1 << cm; eeepc->cm_supported |= 1 << cm;
} }
} }

View File

@ -1153,8 +1153,7 @@ static int __init fujitsu_init(void)
fail_hotkey: fail_hotkey:
platform_driver_unregister(&fujitsupf_driver); platform_driver_unregister(&fujitsupf_driver);
fail_backlight: fail_backlight:
if (fujitsu->bl_device) backlight_device_unregister(fujitsu->bl_device);
backlight_device_unregister(fujitsu->bl_device);
fail_sysfs_group: fail_sysfs_group:
sysfs_remove_group(&fujitsu->pf_device->dev.kobj, sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
&fujitsupf_attribute_group); &fujitsupf_attribute_group);
@ -1178,8 +1177,7 @@ static void __exit fujitsu_cleanup(void)
platform_driver_unregister(&fujitsupf_driver); platform_driver_unregister(&fujitsupf_driver);
if (fujitsu->bl_device) backlight_device_unregister(fujitsu->bl_device);
backlight_device_unregister(fujitsu->bl_device);
sysfs_remove_group(&fujitsu->pf_device->dev.kobj, sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
&fujitsupf_attribute_group); &fujitsupf_attribute_group);

View File

@ -85,6 +85,9 @@ static int hpwl_add(struct acpi_device *device)
int err; int err;
err = hp_wireless_input_setup(); err = hp_wireless_input_setup();
if (err)
pr_err("Failed to setup hp wireless hotkeys\n");
return err; return err;
} }

View File

@ -246,6 +246,7 @@ static const struct dmi_system_id lis3lv02d_dmi_ids[] = {
AXIS_DMI_MATCH("HPB64xx", "HP ProBook 64", xy_swap), AXIS_DMI_MATCH("HPB64xx", "HP ProBook 64", xy_swap),
AXIS_DMI_MATCH("HPB64xx", "HP EliteBook 84", xy_swap), AXIS_DMI_MATCH("HPB64xx", "HP EliteBook 84", xy_swap),
AXIS_DMI_MATCH("HPB65xx", "HP ProBook 65", x_inverted), AXIS_DMI_MATCH("HPB65xx", "HP ProBook 65", x_inverted),
AXIS_DMI_MATCH("HPZBook15", "HP ZBook 15", x_inverted),
{ NULL, } { NULL, }
/* Laptop models without axis info (yet): /* Laptop models without axis info (yet):
* "NC6910" "HP Compaq 6910" * "NC6910" "HP Compaq 6910"

View File

@ -729,8 +729,7 @@ static int ideapad_backlight_init(struct ideapad_private *priv)
static void ideapad_backlight_exit(struct ideapad_private *priv) static void ideapad_backlight_exit(struct ideapad_private *priv)
{ {
if (priv->blightdev) backlight_device_unregister(priv->blightdev);
backlight_device_unregister(priv->blightdev);
priv->blightdev = NULL; priv->blightdev = NULL;
} }

View File

@ -33,7 +33,7 @@
* performance by allocating more power or thermal budget to the CPU or GPU * performance by allocating more power or thermal budget to the CPU or GPU
* based on available headroom and activity. * based on available headroom and activity.
* *
* The basic algorithm is driven by a 5s moving average of tempurature. If * The basic algorithm is driven by a 5s moving average of temperature. If
* thermal headroom is available, the CPU and/or GPU power clamps may be * thermal headroom is available, the CPU and/or GPU power clamps may be
* adjusted upwards. If we hit the thermal ceiling or a thermal trigger, * adjusted upwards. If we hit the thermal ceiling or a thermal trigger,
* we scale back the clamp. Aside from trigger events (when we're critically * we scale back the clamp. Aside from trigger events (when we're critically

View File

@ -271,8 +271,7 @@ static int oaktrail_backlight_init(void)
static void oaktrail_backlight_exit(void) static void oaktrail_backlight_exit(void)
{ {
if (oaktrail_bl_device) backlight_device_unregister(oaktrail_bl_device);
backlight_device_unregister(oaktrail_bl_device);
} }
static int oaktrail_probe(struct platform_device *pdev) static int oaktrail_probe(struct platform_device *pdev)

View File

@ -820,7 +820,7 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
{ {
static bool extended; static bool extended;
if (str & 0x20) if (str & I8042_STR_AUXDATA)
return false; return false;
/* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/ /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/

View File

@ -354,8 +354,7 @@ static void __exit msi_wmi_exit(void)
sparse_keymap_free(msi_wmi_input_dev); sparse_keymap_free(msi_wmi_input_dev);
input_unregister_device(msi_wmi_input_dev); input_unregister_device(msi_wmi_input_dev);
} }
if (backlight) backlight_device_unregister(backlight);
backlight_device_unregister(backlight);
} }
module_init(msi_wmi_init); module_init(msi_wmi_init);

View File

@ -3140,8 +3140,7 @@ static void sony_nc_backlight_setup(void)
static void sony_nc_backlight_cleanup(void) static void sony_nc_backlight_cleanup(void)
{ {
if (sony_bl_props.dev) backlight_device_unregister(sony_bl_props.dev);
backlight_device_unregister(sony_bl_props.dev);
} }
static int sony_nc_add(struct acpi_device *device) static int sony_nc_add(struct acpi_device *device)
@ -3716,8 +3715,7 @@ static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
dev->event_types = type2_events; dev->event_types = type2_events;
out: out:
if (pcidev) pci_dev_put(pcidev);
pci_dev_put(pcidev);
pr_info("detected Type%d model\n", pr_info("detected Type%d model\n",
dev->model == SONYPI_DEVICE_TYPE1 ? 1 : dev->model == SONYPI_DEVICE_TYPE1 ? 1 :

View File

@ -6557,6 +6557,17 @@ static struct ibm_struct brightness_driver_data = {
* bits 3-0 (volume). Other bits in NVRAM may have other functions, * bits 3-0 (volume). Other bits in NVRAM may have other functions,
* such as bit 7 which is used to detect repeated presses of MUTE, * such as bit 7 which is used to detect repeated presses of MUTE,
* and we leave them unchanged. * and we leave them unchanged.
*
* On newer Lenovo ThinkPads, the EC can automatically change the volume
* in response to user input. Unfortunately, this rarely works well.
* The laptop changes the state of its internal MUTE gate and, on some
* models, sends KEY_MUTE, causing any user code that responds to the
* mute button to get confused. The hardware MUTE gate is also
* unnecessary, since user code can handle the mute button without
* kernel or EC help.
*
* To avoid confusing userspace, we simply disable all EC-based mute
* and volume controls when possible.
*/ */
#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT #ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
@ -6611,11 +6622,21 @@ enum tpacpi_volume_capabilities {
TPACPI_VOL_CAP_MAX TPACPI_VOL_CAP_MAX
}; };
enum tpacpi_mute_btn_mode {
TP_EC_MUTE_BTN_LATCH = 0, /* Mute mutes; up/down unmutes */
/* We don't know what mode 1 is. */
TP_EC_MUTE_BTN_NONE = 2, /* Mute and up/down are just keys */
TP_EC_MUTE_BTN_TOGGLE = 3, /* Mute toggles; up/down unmutes */
};
static enum tpacpi_volume_access_mode volume_mode = static enum tpacpi_volume_access_mode volume_mode =
TPACPI_VOL_MODE_MAX; TPACPI_VOL_MODE_MAX;
static enum tpacpi_volume_capabilities volume_capabilities; static enum tpacpi_volume_capabilities volume_capabilities;
static bool volume_control_allowed; static bool volume_control_allowed;
static bool software_mute_requested = true;
static bool software_mute_active;
static int software_mute_orig_mode;
/* /*
* Used to syncronize writers to TP_EC_AUDIO and * Used to syncronize writers to TP_EC_AUDIO and
@ -6633,6 +6654,8 @@ static void tpacpi_volume_checkpoint_nvram(void)
return; return;
if (!volume_control_allowed) if (!volume_control_allowed)
return; return;
if (software_mute_active)
return;
vdbg_printk(TPACPI_DBG_MIXER, vdbg_printk(TPACPI_DBG_MIXER,
"trying to checkpoint mixer state to NVRAM...\n"); "trying to checkpoint mixer state to NVRAM...\n");
@ -6694,6 +6717,12 @@ static int volume_set_status_ec(const u8 status)
dbg_printk(TPACPI_DBG_MIXER, "set EC mixer to 0x%02x\n", status); dbg_printk(TPACPI_DBG_MIXER, "set EC mixer to 0x%02x\n", status);
/*
* On X200s, and possibly on others, it can take a while for
* reads to become correct.
*/
msleep(1);
return 0; return 0;
} }
@ -6776,6 +6805,57 @@ static int __volume_set_volume_ec(const u8 vol)
return rc; return rc;
} }
static int volume_set_software_mute(bool startup)
{
int result;
if (!tpacpi_is_lenovo())
return -ENODEV;
if (startup) {
if (!acpi_evalf(ec_handle, &software_mute_orig_mode,
"HAUM", "qd"))
return -EIO;
dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
"Initial HAUM setting was %d\n",
software_mute_orig_mode);
}
if (!acpi_evalf(ec_handle, &result, "SAUM", "qdd",
(int)TP_EC_MUTE_BTN_NONE))
return -EIO;
if (result != TP_EC_MUTE_BTN_NONE)
pr_warn("Unexpected SAUM result %d\n",
result);
/*
* In software mute mode, the standard codec controls take
* precendence, so we unmute the ThinkPad HW switch at
* startup. Just on case there are SAUM-capable ThinkPads
* with level controls, set max HW volume as well.
*/
if (tp_features.mixer_no_level_control)
result = volume_set_mute(false);
else
result = volume_set_status(TP_EC_VOLUME_MAX);
if (result != 0)
pr_warn("Failed to unmute the HW mute switch\n");
return 0;
}
static void volume_exit_software_mute(void)
{
int r;
if (!acpi_evalf(ec_handle, &r, "SAUM", "qdd", software_mute_orig_mode)
|| r != software_mute_orig_mode)
pr_warn("Failed to restore mute mode\n");
}
static int volume_alsa_set_volume(const u8 vol) static int volume_alsa_set_volume(const u8 vol)
{ {
dbg_printk(TPACPI_DBG_MIXER, dbg_printk(TPACPI_DBG_MIXER,
@ -6883,7 +6963,12 @@ static void volume_suspend(void)
static void volume_resume(void) static void volume_resume(void)
{ {
volume_alsa_notify_change(); if (software_mute_active) {
if (volume_set_software_mute(false) < 0)
pr_warn("Failed to restore software mute\n");
} else {
volume_alsa_notify_change();
}
} }
static void volume_shutdown(void) static void volume_shutdown(void)
@ -6899,6 +6984,9 @@ static void volume_exit(void)
} }
tpacpi_volume_checkpoint_nvram(); tpacpi_volume_checkpoint_nvram();
if (software_mute_active)
volume_exit_software_mute();
} }
static int __init volume_create_alsa_mixer(void) static int __init volume_create_alsa_mixer(void)
@ -7083,16 +7171,20 @@ static int __init volume_init(struct ibm_init_struct *iibm)
"mute is supported, volume control is %s\n", "mute is supported, volume control is %s\n",
str_supported(!tp_features.mixer_no_level_control)); str_supported(!tp_features.mixer_no_level_control));
rc = volume_create_alsa_mixer(); if (software_mute_requested && volume_set_software_mute(true) == 0) {
if (rc) { software_mute_active = true;
pr_err("Could not create the ALSA mixer interface\n"); } else {
return rc; rc = volume_create_alsa_mixer();
} if (rc) {
pr_err("Could not create the ALSA mixer interface\n");
return rc;
}
pr_info("Console audio control enabled, mode: %s\n", pr_info("Console audio control enabled, mode: %s\n",
(volume_control_allowed) ? (volume_control_allowed) ?
"override (read/write)" : "override (read/write)" :
"monitor (read only)"); "monitor (read only)");
}
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
"registering volume hotkeys as change notification\n"); "registering volume hotkeys as change notification\n");
@ -9089,6 +9181,10 @@ MODULE_PARM_DESC(volume_control,
"Enables software override for the console audio " "Enables software override for the console audio "
"control when true"); "control when true");
module_param_named(software_mute, software_mute_requested, bool, 0444);
MODULE_PARM_DESC(software_mute,
"Request full software mute control");
/* ALSA module API parameters */ /* ALSA module API parameters */
module_param_named(index, alsa_index, int, 0444); module_param_named(index, alsa_index, int, 0444);
MODULE_PARM_DESC(index, "ALSA index for the ACPI EC Mixer"); MODULE_PARM_DESC(index, "ALSA index for the ACPI EC Mixer");

View File

@ -186,6 +186,7 @@ static struct toshiba_acpi_dev *toshiba_acpi;
static const struct acpi_device_id toshiba_device_ids[] = { static const struct acpi_device_id toshiba_device_ids[] = {
{"TOS6200", 0}, {"TOS6200", 0},
{"TOS6207", 0},
{"TOS6208", 0}, {"TOS6208", 0},
{"TOS1900", 0}, {"TOS1900", 0},
{"", 0}, {"", 0},
@ -928,9 +929,7 @@ static int lcd_proc_open(struct inode *inode, struct file *file)
static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
{ {
u32 in[TCI_WORDS] = { HCI_SET, HCI_LCD_BRIGHTNESS, 0, 0, 0, 0 }; u32 hci_result;
u32 out[TCI_WORDS];
acpi_status status;
if (dev->tr_backlight_supported) { if (dev->tr_backlight_supported) {
bool enable = !value; bool enable = !value;
@ -941,20 +940,9 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
value--; value--;
} }
in[2] = value << HCI_LCD_BRIGHTNESS_SHIFT; value = value << HCI_LCD_BRIGHTNESS_SHIFT;
status = tci_raw(dev, in, out); hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value);
if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { return hci_result == TOS_SUCCESS ? 0 : -EIO;
pr_err("ACPI call to set brightness failed");
return -EIO;
}
/* Extra check for "incomplete" backlight method, where the AML code
* doesn't check for HCI_SET or HCI_GET and returns TOS_SUCCESS,
* the actual brightness, and in some cases the max brightness.
*/
if (out[2] > 0 || out[3] == 0xE000)
return -ENODEV;
return out[0] == TOS_SUCCESS ? 0 : -EIO;
} }
static int set_lcd_status(struct backlight_device *bd) static int set_lcd_status(struct backlight_device *bd)
@ -1406,12 +1394,6 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
if (ret) if (ret)
return ret; return ret;
/* Update sysfs entries on successful mode change*/
ret = sysfs_update_group(&toshiba->acpi_dev->dev.kobj,
&toshiba_attr_group);
if (ret)
return ret;
toshiba->kbd_mode = mode; toshiba->kbd_mode = mode;
} }
@ -1586,10 +1568,32 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
return exists ? attr->mode : 0; return exists ? attr->mode : 0;
} }
/*
* Hotkeys
*/
static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
{
acpi_status status;
u32 result;
status = acpi_evaluate_object(dev->acpi_dev->handle,
"ENAB", NULL, NULL);
if (ACPI_FAILURE(status))
return -ENODEV;
result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
if (result == TOS_FAILURE)
return -EIO;
else if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
return 0;
}
static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
struct serio *port) struct serio *port)
{ {
if (str & 0x20) if (str & I8042_STR_AUXDATA)
return false; return false;
if (unlikely(data == 0xe0)) if (unlikely(data == 0xe0))
@ -1648,9 +1652,45 @@ static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
pr_info("Unknown key %x\n", scancode); pr_info("Unknown key %x\n", scancode);
} }
static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
{
u32 hci_result, value;
int retries = 3;
int scancode;
if (dev->info_supported) {
scancode = toshiba_acpi_query_hotkey(dev);
if (scancode < 0)
pr_err("Failed to query hotkey event\n");
else if (scancode != 0)
toshiba_acpi_report_hotkey(dev, scancode);
} else if (dev->system_event_supported) {
do {
hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value);
switch (hci_result) {
case TOS_SUCCESS:
toshiba_acpi_report_hotkey(dev, (int)value);
break;
case TOS_NOT_SUPPORTED:
/*
* This is a workaround for an unresolved
* issue on some machines where system events
* sporadically become disabled.
*/
hci_result =
hci_write1(dev, HCI_SYSTEM_EVENT, 1);
pr_notice("Re-enabled hotkeys\n");
/* fall through */
default:
retries--;
break;
}
} while (retries && hci_result != TOS_FIFO_EMPTY);
}
}
static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
{ {
acpi_status status;
acpi_handle ec_handle; acpi_handle ec_handle;
int error; int error;
u32 hci_result; u32 hci_result;
@ -1677,7 +1717,6 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
* supported, so if it's present set up an i8042 key filter * supported, so if it's present set up an i8042 key filter
* for this purpose. * for this purpose.
*/ */
status = AE_ERROR;
ec_handle = ec_get_handle(); ec_handle = ec_get_handle();
if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
@ -1708,10 +1747,9 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
goto err_remove_filter; goto err_remove_filter;
} }
status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL); error = toshiba_acpi_enable_hotkeys(dev);
if (ACPI_FAILURE(status)) { if (error) {
pr_info("Unable to enable hotkeys\n"); pr_info("Unable to enable hotkeys\n");
error = -ENODEV;
goto err_remove_filter; goto err_remove_filter;
} }
@ -1721,7 +1759,6 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
goto err_remove_filter; goto err_remove_filter;
} }
hci_result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
return 0; return 0;
err_remove_filter: err_remove_filter:
@ -1810,8 +1847,7 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
rfkill_destroy(dev->bt_rfk); rfkill_destroy(dev->bt_rfk);
} }
if (dev->backlight_dev) backlight_device_unregister(dev->backlight_dev);
backlight_device_unregister(dev->backlight_dev);
if (dev->illumination_supported) if (dev->illumination_supported)
led_classdev_unregister(&dev->led_dev); led_classdev_unregister(&dev->led_dev);
@ -1967,41 +2003,29 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
{ {
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
u32 hci_result, value; int ret;
int retries = 3;
int scancode;
if (event != 0x80) switch (event) {
return; case 0x80: /* Hotkeys and some system events */
toshiba_acpi_process_hotkeys(dev);
if (dev->info_supported) { break;
scancode = toshiba_acpi_query_hotkey(dev); case 0x92: /* Keyboard backlight mode changed */
if (scancode < 0) /* Update sysfs entries */
pr_err("Failed to query hotkey event\n"); ret = sysfs_update_group(&acpi_dev->dev.kobj,
else if (scancode != 0) &toshiba_attr_group);
toshiba_acpi_report_hotkey(dev, scancode); if (ret)
} else if (dev->system_event_supported) { pr_err("Unable to update sysfs entries\n");
do { break;
hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); case 0x81: /* Unknown */
switch (hci_result) { case 0x82: /* Unknown */
case TOS_SUCCESS: case 0x83: /* Unknown */
toshiba_acpi_report_hotkey(dev, (int)value); case 0x8c: /* Unknown */
break; case 0x8e: /* Unknown */
case TOS_NOT_SUPPORTED: case 0x8f: /* Unknown */
/* case 0x90: /* Unknown */
* This is a workaround for an unresolved default:
* issue on some machines where system events pr_info("Unknown event received %x\n", event);
* sporadically become disabled. break;
*/
hci_result =
hci_write1(dev, HCI_SYSTEM_EVENT, 1);
pr_notice("Re-enabled hotkeys\n");
/* fall through */
default:
retries--;
break;
}
} while (retries && hci_result != TOS_FIFO_EMPTY);
} }
} }
@ -2020,16 +2044,12 @@ static int toshiba_acpi_suspend(struct device *device)
static int toshiba_acpi_resume(struct device *device) static int toshiba_acpi_resume(struct device *device)
{ {
struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
u32 result; int error;
acpi_status status;
if (dev->hotkey_dev) { if (dev->hotkey_dev) {
status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", error = toshiba_acpi_enable_hotkeys(dev);
NULL, NULL); if (error)
if (ACPI_FAILURE(status))
pr_info("Unable to re-enable hotkeys\n"); pr_info("Unable to re-enable hotkeys\n");
result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
} }
return 0; return 0;