mirror of https://gitee.com/openkylin/linux.git
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:
commit
385336e321
|
@ -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.
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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*/
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 :
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue