platform-drivers-x86 for 4.1
dell-laptop: Add support for keyboard backlight. toshiba_acpi: Adaptive keyboard, hotkey, USB sleep and charge, and backlight updates. Update sysfs documentation. toshiba_bluetooth: Fix enabling/disabling loop on recent devices apple-gmux: lock iGP IO to protect from vgaarb changes other: Fix typos, clear gcc warnings, clarify pr_* messages, correct return types, update MAINTAINERS. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJVOzXzAAoJEKbMaAwKp364yjQH/3RJQAiemygVKTv8npk6am4W 6NjoQHwFbvbHnea1DsMBI66DgvDFuXBi04/eKoFtZiSQdt3LOWyF04VY7yPdGKT/ 0yIgxMonhLk/lbBiU1PmyAsloOI4mG3zylOO+zJv66LeW0q2vjlLK7xE7AJn0dVU hRn+Wl0YCjPzEEB4uZpKY6V0+7ys0Odxd2MeYu7pcs5DQzbvzeo4JRwUL4VtNiX9 M1I4ucBRA9jjnuNDzr4d9WtttorOOymoBYy3KFE+2QzDr5chhXTbWp6mRzwnYRvy siOEPLzeR9jTSB4U514I1CktsCmYxvGnrGcNj1IgiY8VFujoh9j6Ndh339f8064= =O+n4 -----END PGP SIGNATURE----- Merge tag 'platform-drivers-x86-v4.1-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86 Pull x86 platform driver updates from Darren Hart: "This series includes significant updates to the toshiba_acpi driver and the reintroduction of the dell-laptop keyboard backlight additions I had to revert previously. Also included are various fixes for typos, warnings, correctness, and minor bugs. Specifics: dell-laptop: - add support for keyboard backlight. toshiba_acpi: - adaptive keyboard, hotkey, USB sleep and charge, and backlight updates. Update sysfs documentation. toshiba_bluetooth: - fix enabling/disabling loop on recent devices apple-gmux: - lock iGP IO to protect from vgaarb changes other: - Fix typos, clear gcc warnings, clarify pr_* messages, correct return types, update MAINTAINERS" * tag 'platform-drivers-x86-v4.1-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (25 commits) toshiba_acpi: Do not register vendor backlight when acpi_video bl is available MAINTAINERS: Add me on list of Dell laptop drivers platform: x86: dell-laptop: Add support for keyboard backlight Documentation/ABI: Update sysfs-driver-toshiba_acpi entry toshiba_acpi: Fix pr_* messages from USB Sleep Functions toshiba_acpi: Update and fix USB Sleep and Charge modes wmi: Use bool function return values of true/false not 1/0 toshiba_bluetooth: Fix enabling/disabling loop on recent devices toshiba_bluetooth: Clean up *_add function and disable BT device at removal toshiba_bluetooth: Add three new functions to the driver toshiba_acpi: Fix the enabling of the Special Functions toshiba_acpi: Use the Hotkey Event Type function for keymap choosing toshiba_acpi: Add Hotkey Event Type function and definitions x86/wmi: delete unused wmi_data_lock mutex causing gcc warning apple-gmux: lock iGP IO to protect from vgaarb changes MAINTAINERS: Add missing Toshiba devices and add myself as maintainer toshiba_acpi: Update events in toshiba_acpi_notify intel-oaktrail: Fix trivial typo in comment thinkpad_acpi: off by one in adaptive_keyboard_hotkey_notify_hotkey() thinkpad_acpi: signedness bugs getting current_mode ...
This commit is contained in:
commit
78d4256772
|
@ -8,9 +8,11 @@ Description: This file controls the keyboard backlight operation mode, valid
|
|||
* 0x2 -> AUTO (also called TIMER)
|
||||
* 0x8 -> ON
|
||||
* 0x10 -> OFF
|
||||
Note that the kernel 3.16 onwards this file accepts all listed
|
||||
Note that from kernel 3.16 onwards this file accepts all listed
|
||||
parameters, kernel 3.15 only accepts the first two (FN-Z and
|
||||
AUTO).
|
||||
Also note that toggling this value on type 1 devices, requires
|
||||
a reboot for changes to take effect.
|
||||
Users: KToshiba
|
||||
|
||||
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_backlight_timeout
|
||||
|
@ -67,15 +69,72 @@ Description: This file shows the current keyboard backlight type,
|
|||
* 2 -> Type 2, supporting modes TIMER, ON and OFF
|
||||
Users: KToshiba
|
||||
|
||||
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_sleep_charge
|
||||
Date: January 23, 2015
|
||||
KernelVersion: 4.0
|
||||
Contact: Azael Avalos <coproscefalo@gmail.com>
|
||||
Description: This file controls the USB Sleep & Charge charging mode, which
|
||||
can be:
|
||||
* 0 -> Disabled (0x00)
|
||||
* 1 -> Alternate (0x09)
|
||||
* 2 -> Auto (0x21)
|
||||
* 3 -> Typical (0x11)
|
||||
Note that from kernel 4.1 onwards this file accepts all listed
|
||||
values, kernel 4.0 only supports the first three.
|
||||
Note that this feature only works when connected to power, if
|
||||
you want to use it under battery, see the entry named
|
||||
"sleep_functions_on_battery"
|
||||
Users: KToshiba
|
||||
|
||||
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/sleep_functions_on_battery
|
||||
Date: January 23, 2015
|
||||
KernelVersion: 4.0
|
||||
Contact: Azael Avalos <coproscefalo@gmail.com>
|
||||
Description: This file controls the USB Sleep Functions under battery, and
|
||||
set the level at which point they will be disabled, accepted
|
||||
values can be:
|
||||
* 0 -> Disabled
|
||||
* 1-100 -> Battery level to disable sleep functions
|
||||
Currently it prints two values, the first one indicates if the
|
||||
feature is enabled or disabled, while the second one shows the
|
||||
current battery level set.
|
||||
Note that when the value is set to disabled, the sleep function
|
||||
will only work when connected to power.
|
||||
Users: KToshiba
|
||||
|
||||
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_rapid_charge
|
||||
Date: January 23, 2015
|
||||
KernelVersion: 4.0
|
||||
Contact: Azael Avalos <coproscefalo@gmail.com>
|
||||
Description: This file controls the USB Rapid Charge state, which can be:
|
||||
* 0 -> Disabled
|
||||
* 1 -> Enabled
|
||||
Note that toggling this value requires a reboot for changes to
|
||||
take effect.
|
||||
Users: KToshiba
|
||||
|
||||
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_sleep_music
|
||||
Date: January 23, 2015
|
||||
KernelVersion: 4.0
|
||||
Contact: Azael Avalos <coproscefalo@gmail.com>
|
||||
Description: This file controls the Sleep & Music state, which values can be:
|
||||
* 0 -> Disabled
|
||||
* 1 -> Enabled
|
||||
Note that this feature only works when connected to power, if
|
||||
you want to use it under battery, see the entry named
|
||||
"sleep_functions_on_battery"
|
||||
Users: KToshiba
|
||||
|
||||
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/version
|
||||
Date: February, 2015
|
||||
KernelVersion: 3.20
|
||||
Date: February 12, 2015
|
||||
KernelVersion: 4.0
|
||||
Contact: Azael Avalos <coproscefalo@gmail.com>
|
||||
Description: This file shows the current version of the driver
|
||||
Users: KToshiba
|
||||
|
||||
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/fan
|
||||
Date: February, 2015
|
||||
KernelVersion: 3.20
|
||||
Date: February 12, 2015
|
||||
KernelVersion: 4.0
|
||||
Contact: Azael Avalos <coproscefalo@gmail.com>
|
||||
Description: This file controls the state of the internal fan, valid
|
||||
values are:
|
||||
|
@ -83,8 +142,8 @@ Description: This file controls the state of the internal fan, valid
|
|||
* 1 -> ON
|
||||
|
||||
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_function_keys
|
||||
Date: February, 2015
|
||||
KernelVersion: 3.20
|
||||
Date: February 12, 2015
|
||||
KernelVersion: 4.0
|
||||
Contact: Azael Avalos <coproscefalo@gmail.com>
|
||||
Description: This file controls the Special Functions (hotkeys) operation
|
||||
mode, valid values are:
|
||||
|
@ -94,21 +153,29 @@ Description: This file controls the Special Functions (hotkeys) operation
|
|||
and the hotkeys are accessed via FN-F{1-12}.
|
||||
In the "Special Functions" mode, the F{1-12} keys trigger the
|
||||
hotkey and the F{1-12} keys are accessed via FN-F{1-12}.
|
||||
Note that toggling this value requires a reboot for changes to
|
||||
take effect.
|
||||
Users: KToshiba
|
||||
|
||||
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/panel_power_on
|
||||
Date: February, 2015
|
||||
KernelVersion: 3.20
|
||||
Date: February 12, 2015
|
||||
KernelVersion: 4.0
|
||||
Contact: Azael Avalos <coproscefalo@gmail.com>
|
||||
Description: This file controls whether the laptop should turn ON whenever
|
||||
the LID is opened, valid values are:
|
||||
* 0 -> Disabled
|
||||
* 1 -> Enabled
|
||||
Note that toggling this value requires a reboot for changes to
|
||||
take effect.
|
||||
Users: KToshiba
|
||||
|
||||
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_three
|
||||
Date: February, 2015
|
||||
KernelVersion: 3.20
|
||||
Date: February 12, 2015
|
||||
KernelVersion: 4.0
|
||||
Contact: Azael Avalos <coproscefalo@gmail.com>
|
||||
Description: This file controls whether the USB 3 functionality, valid
|
||||
values are:
|
||||
Description: This file controls the USB 3 functionality, valid values are:
|
||||
* 0 -> Disabled (Acts as a regular USB 2)
|
||||
* 1 -> Enabled (Full USB 3 functionality)
|
||||
Note that toggling this value requires a reboot for changes to
|
||||
take effect.
|
||||
Users: KToshiba
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
What: /sys/class/leds/dell::kbd_backlight/als_enabled
|
||||
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/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 specifiy the on/off threshold value,
|
||||
as reported by the ambient light sensor.
|
||||
|
||||
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.
|
|
@ -1355,6 +1355,24 @@ Sysfs notes:
|
|||
rfkill controller switch "tpacpi_uwb_sw": refer to
|
||||
Documentation/rfkill.txt for details.
|
||||
|
||||
Adaptive keyboard
|
||||
-----------------
|
||||
|
||||
sysfs device attribute: adaptive_kbd_mode
|
||||
|
||||
This sysfs attribute controls the keyboard "face" that will be shown on the
|
||||
Lenovo X1 Carbon 2nd gen (2014)'s adaptive keyboard. The value can be read
|
||||
and set.
|
||||
|
||||
1 = Home mode
|
||||
2 = Web-browser mode
|
||||
3 = Web-conference mode
|
||||
4 = Function mode
|
||||
5 = Layflat mode
|
||||
|
||||
For more details about which buttons will appear depending on the mode, please
|
||||
review the laptop's user guide:
|
||||
http://www.lenovo.com/shop/americas/content/user_guides/x1carbon_2_ug_en.pdf
|
||||
|
||||
Multiple Commands, Module Parameters
|
||||
------------------------------------
|
||||
|
|
22
MAINTAINERS
22
MAINTAINERS
|
@ -3066,10 +3066,16 @@ F: drivers/net/fddi/defxx.*
|
|||
|
||||
DELL LAPTOP DRIVER
|
||||
M: Matthew Garrett <mjg59@srcf.ucam.org>
|
||||
M: Pali Rohár <pali.rohar@gmail.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/dell-laptop.c
|
||||
|
||||
DELL LAPTOP FREEFALL DRIVER
|
||||
M: Pali Rohár <pali.rohar@gmail.com>
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/dell-smo8800.c
|
||||
|
||||
DELL LAPTOP SMM DRIVER
|
||||
M: Guenter Roeck <linux@roeck-us.net>
|
||||
S: Maintained
|
||||
|
@ -3084,6 +3090,7 @@ F: drivers/firmware/dcdbas.*
|
|||
|
||||
DELL WMI EXTRAS DRIVER
|
||||
M: Matthew Garrett <mjg59@srcf.ucam.org>
|
||||
M: Pali Rohár <pali.rohar@gmail.com>
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/dell-wmi.c
|
||||
|
||||
|
@ -9949,10 +9956,23 @@ S: Maintained
|
|||
F: drivers/platform/x86/topstar-laptop.c
|
||||
|
||||
TOSHIBA ACPI EXTRAS DRIVER
|
||||
M: Azael Avalos <coproscefalo@gmail.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Orphan
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/toshiba_acpi.c
|
||||
|
||||
TOSHIBA BLUETOOTH DRIVER
|
||||
M: Azael Avalos <coproscefalo@gmail.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/toshiba_bluetooth.c
|
||||
|
||||
TOSHIBA HDD ACTIVE PROTECTION SENSOR DRIVER
|
||||
M: Azael Avalos <coproscefalo@gmail.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/toshiba_haps.c
|
||||
|
||||
TOSHIBA SMM DRIVER
|
||||
M: Jonathan Buzzard <jonathan@buzzard.org.uk>
|
||||
L: tlinux-users@tce.toshiba-dme.co.jp
|
||||
|
|
|
@ -614,6 +614,7 @@ config ACPI_TOSHIBA
|
|||
depends on INPUT
|
||||
depends on RFKILL || RFKILL = n
|
||||
depends on SERIO_I8042 || SERIO_I8042 = n
|
||||
depends on ACPI_VIDEO || ACPI_VIDEO = n
|
||||
select INPUT_POLLDEV
|
||||
select INPUT_SPARSEKMAP
|
||||
---help---
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
#include <linux/vgaarb.h>
|
||||
#include <acpi/video.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
@ -31,6 +32,7 @@ struct apple_gmux_data {
|
|||
bool indexed;
|
||||
struct mutex index_lock;
|
||||
|
||||
struct pci_dev *pdev;
|
||||
struct backlight_device *bdev;
|
||||
|
||||
/* switcheroo data */
|
||||
|
@ -415,6 +417,23 @@ static int gmux_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_dev *gmux_get_io_pdev(void)
|
||||
{
|
||||
struct pci_dev *pdev = NULL;
|
||||
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) {
|
||||
u16 cmd;
|
||||
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
|
||||
if (!(cmd & PCI_COMMAND_IO))
|
||||
continue;
|
||||
|
||||
return pdev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
|
||||
{
|
||||
struct apple_gmux_data *gmux_data;
|
||||
|
@ -425,6 +444,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
|
|||
int ret = -ENXIO;
|
||||
acpi_status status;
|
||||
unsigned long long gpe;
|
||||
struct pci_dev *pdev = NULL;
|
||||
|
||||
if (apple_gmux_data)
|
||||
return -EBUSY;
|
||||
|
@ -475,7 +495,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
|
|||
ver_minor = (version >> 16) & 0xff;
|
||||
ver_release = (version >> 8) & 0xff;
|
||||
} else {
|
||||
pr_info("gmux device not present\n");
|
||||
pr_info("gmux device not present or IO disabled\n");
|
||||
ret = -ENODEV;
|
||||
goto err_release;
|
||||
}
|
||||
|
@ -483,6 +503,23 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
|
|||
pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
|
||||
ver_release, (gmux_data->indexed ? "indexed" : "classic"));
|
||||
|
||||
/*
|
||||
* Apple systems with gmux are EFI based and normally don't use
|
||||
* VGA. In addition changing IO+MEM ownership between IGP and dGPU
|
||||
* disables IO/MEM used for backlight control on some systems.
|
||||
* Lock IO+MEM to GPU with active IO to prevent switch.
|
||||
*/
|
||||
pdev = gmux_get_io_pdev();
|
||||
if (pdev && vga_tryget(pdev,
|
||||
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)) {
|
||||
pr_err("IO+MEM vgaarb-locking for PCI:%s failed\n",
|
||||
pci_name(pdev));
|
||||
ret = -EBUSY;
|
||||
goto err_release;
|
||||
} else if (pdev)
|
||||
pr_info("locked IO for PCI:%s\n", pci_name(pdev));
|
||||
gmux_data->pdev = pdev;
|
||||
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
|
||||
|
@ -574,6 +611,10 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
|
|||
err_notify:
|
||||
backlight_device_unregister(bdev);
|
||||
err_release:
|
||||
if (gmux_data->pdev)
|
||||
vga_put(gmux_data->pdev,
|
||||
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM);
|
||||
pci_dev_put(pdev);
|
||||
release_region(gmux_data->iostart, gmux_data->iolen);
|
||||
err_free:
|
||||
kfree(gmux_data);
|
||||
|
@ -593,6 +634,11 @@ static void gmux_remove(struct pnp_dev *pnp)
|
|||
&gmux_notify_handler);
|
||||
}
|
||||
|
||||
if (gmux_data->pdev) {
|
||||
vga_put(gmux_data->pdev,
|
||||
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM);
|
||||
pci_dev_put(gmux_data->pdev);
|
||||
}
|
||||
backlight_device_unregister(gmux_data->bdev);
|
||||
|
||||
release_region(gmux_data->iostart, gmux_data->iolen);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -62,7 +62,7 @@
|
|||
* (1 << 1): Bluetooth enable/disable, RW.
|
||||
* (1 << 2): GPS enable/disable, RW.
|
||||
* (1 << 3): WiFi enable/disable, RW.
|
||||
* (1 << 4): WWAN (3G) enable/disalbe, RW.
|
||||
* (1 << 4): WWAN (3G) enable/disable, RW.
|
||||
* (1 << 5): Touchscreen enable/disable, Read Only.
|
||||
*/
|
||||
#define OT_EC_DEVICE_STATE_ADDRESS 0xD6
|
||||
|
|
|
@ -319,6 +319,7 @@ static struct {
|
|||
u32 sensors_pdrv_attrs_registered:1;
|
||||
u32 sensors_pdev_attrs_registered:1;
|
||||
u32 hotkey_poll_active:1;
|
||||
u32 has_adaptive_kbd:1;
|
||||
} tp_features;
|
||||
|
||||
static struct {
|
||||
|
@ -1911,6 +1912,27 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */
|
|||
TP_ACPI_HOTKEYSCAN_UNK7,
|
||||
TP_ACPI_HOTKEYSCAN_UNK8,
|
||||
|
||||
TP_ACPI_HOTKEYSCAN_MUTE2,
|
||||
TP_ACPI_HOTKEYSCAN_BRIGHTNESS_ZERO,
|
||||
TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL,
|
||||
TP_ACPI_HOTKEYSCAN_CLOUD,
|
||||
TP_ACPI_HOTKEYSCAN_UNK9,
|
||||
TP_ACPI_HOTKEYSCAN_VOICE,
|
||||
TP_ACPI_HOTKEYSCAN_UNK10,
|
||||
TP_ACPI_HOTKEYSCAN_GESTURES,
|
||||
TP_ACPI_HOTKEYSCAN_UNK11,
|
||||
TP_ACPI_HOTKEYSCAN_UNK12,
|
||||
TP_ACPI_HOTKEYSCAN_UNK13,
|
||||
TP_ACPI_HOTKEYSCAN_CONFIG,
|
||||
TP_ACPI_HOTKEYSCAN_NEW_TAB,
|
||||
TP_ACPI_HOTKEYSCAN_RELOAD,
|
||||
TP_ACPI_HOTKEYSCAN_BACK,
|
||||
TP_ACPI_HOTKEYSCAN_MIC_DOWN,
|
||||
TP_ACPI_HOTKEYSCAN_MIC_UP,
|
||||
TP_ACPI_HOTKEYSCAN_MIC_CANCELLATION,
|
||||
TP_ACPI_HOTKEYSCAN_CAMERA_MODE,
|
||||
TP_ACPI_HOTKEYSCAN_ROTATE_DISPLAY,
|
||||
|
||||
/* Hotkey keymap size */
|
||||
TPACPI_HOTKEY_MAP_LEN
|
||||
};
|
||||
|
@ -2647,9 +2669,7 @@ static ssize_t hotkey_enable_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_enable =
|
||||
__ATTR(hotkey_enable, S_IWUSR | S_IRUGO,
|
||||
hotkey_enable_show, hotkey_enable_store);
|
||||
static DEVICE_ATTR_RW(hotkey_enable);
|
||||
|
||||
/* sysfs hotkey mask --------------------------------------------------- */
|
||||
static ssize_t hotkey_mask_show(struct device *dev,
|
||||
|
@ -2685,9 +2705,7 @@ static ssize_t hotkey_mask_store(struct device *dev,
|
|||
return (res) ? res : count;
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_mask =
|
||||
__ATTR(hotkey_mask, S_IWUSR | S_IRUGO,
|
||||
hotkey_mask_show, hotkey_mask_store);
|
||||
static DEVICE_ATTR_RW(hotkey_mask);
|
||||
|
||||
/* sysfs hotkey bios_enabled ------------------------------------------- */
|
||||
static ssize_t hotkey_bios_enabled_show(struct device *dev,
|
||||
|
@ -2697,8 +2715,7 @@ static ssize_t hotkey_bios_enabled_show(struct device *dev,
|
|||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_bios_enabled =
|
||||
__ATTR(hotkey_bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL);
|
||||
static DEVICE_ATTR_RO(hotkey_bios_enabled);
|
||||
|
||||
/* sysfs hotkey bios_mask ---------------------------------------------- */
|
||||
static ssize_t hotkey_bios_mask_show(struct device *dev,
|
||||
|
@ -2710,8 +2727,7 @@ static ssize_t hotkey_bios_mask_show(struct device *dev,
|
|||
return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_bios_mask =
|
||||
__ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
|
||||
static DEVICE_ATTR_RO(hotkey_bios_mask);
|
||||
|
||||
/* sysfs hotkey all_mask ----------------------------------------------- */
|
||||
static ssize_t hotkey_all_mask_show(struct device *dev,
|
||||
|
@ -2722,8 +2738,7 @@ static ssize_t hotkey_all_mask_show(struct device *dev,
|
|||
hotkey_all_mask | hotkey_source_mask);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_all_mask =
|
||||
__ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL);
|
||||
static DEVICE_ATTR_RO(hotkey_all_mask);
|
||||
|
||||
/* sysfs hotkey recommended_mask --------------------------------------- */
|
||||
static ssize_t hotkey_recommended_mask_show(struct device *dev,
|
||||
|
@ -2735,9 +2750,7 @@ static ssize_t hotkey_recommended_mask_show(struct device *dev,
|
|||
& ~hotkey_reserved_mask);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_recommended_mask =
|
||||
__ATTR(hotkey_recommended_mask, S_IRUGO,
|
||||
hotkey_recommended_mask_show, NULL);
|
||||
static DEVICE_ATTR_RO(hotkey_recommended_mask);
|
||||
|
||||
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
|
||||
|
||||
|
@ -2792,9 +2805,7 @@ static ssize_t hotkey_source_mask_store(struct device *dev,
|
|||
return (rc < 0) ? rc : count;
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_source_mask =
|
||||
__ATTR(hotkey_source_mask, S_IWUSR | S_IRUGO,
|
||||
hotkey_source_mask_show, hotkey_source_mask_store);
|
||||
static DEVICE_ATTR_RW(hotkey_source_mask);
|
||||
|
||||
/* sysfs hotkey hotkey_poll_freq --------------------------------------- */
|
||||
static ssize_t hotkey_poll_freq_show(struct device *dev,
|
||||
|
@ -2826,9 +2837,7 @@ static ssize_t hotkey_poll_freq_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_poll_freq =
|
||||
__ATTR(hotkey_poll_freq, S_IWUSR | S_IRUGO,
|
||||
hotkey_poll_freq_show, hotkey_poll_freq_store);
|
||||
static DEVICE_ATTR_RW(hotkey_poll_freq);
|
||||
|
||||
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
|
||||
|
||||
|
@ -2849,8 +2858,7 @@ static ssize_t hotkey_radio_sw_show(struct device *dev,
|
|||
(res == TPACPI_RFK_RADIO_OFF) ? 0 : 1);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_radio_sw =
|
||||
__ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
|
||||
static DEVICE_ATTR_RO(hotkey_radio_sw);
|
||||
|
||||
static void hotkey_radio_sw_notify_change(void)
|
||||
{
|
||||
|
@ -2872,8 +2880,7 @@ static ssize_t hotkey_tablet_mode_show(struct device *dev,
|
|||
return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_tablet_mode =
|
||||
__ATTR(hotkey_tablet_mode, S_IRUGO, hotkey_tablet_mode_show, NULL);
|
||||
static DEVICE_ATTR_RO(hotkey_tablet_mode);
|
||||
|
||||
static void hotkey_tablet_mode_notify_change(void)
|
||||
{
|
||||
|
@ -2890,8 +2897,7 @@ static ssize_t hotkey_wakeup_reason_show(struct device *dev,
|
|||
return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_wakeup_reason =
|
||||
__ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL);
|
||||
static DEVICE_ATTR_RO(hotkey_wakeup_reason);
|
||||
|
||||
static void hotkey_wakeup_reason_notify_change(void)
|
||||
{
|
||||
|
@ -2907,9 +2913,7 @@ static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev,
|
|||
return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete =
|
||||
__ATTR(wakeup_hotunplug_complete, S_IRUGO,
|
||||
hotkey_wakeup_hotunplug_complete_show, NULL);
|
||||
static DEVICE_ATTR_RO(hotkey_wakeup_hotunplug_complete);
|
||||
|
||||
static void hotkey_wakeup_hotunplug_complete_notify_change(void)
|
||||
{
|
||||
|
@ -2917,6 +2921,57 @@ static void hotkey_wakeup_hotunplug_complete_notify_change(void)
|
|||
"wakeup_hotunplug_complete");
|
||||
}
|
||||
|
||||
/* sysfs adaptive kbd mode --------------------------------------------- */
|
||||
|
||||
static int adaptive_keyboard_get_mode(void);
|
||||
static int adaptive_keyboard_set_mode(int new_mode);
|
||||
|
||||
enum ADAPTIVE_KEY_MODE {
|
||||
HOME_MODE,
|
||||
WEB_BROWSER_MODE,
|
||||
WEB_CONFERENCE_MODE,
|
||||
FUNCTION_MODE,
|
||||
LAYFLAT_MODE
|
||||
};
|
||||
|
||||
static ssize_t adaptive_kbd_mode_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int current_mode;
|
||||
|
||||
current_mode = adaptive_keyboard_get_mode();
|
||||
if (current_mode < 0)
|
||||
return current_mode;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", current_mode);
|
||||
}
|
||||
|
||||
static ssize_t adaptive_kbd_mode_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long t;
|
||||
int res;
|
||||
|
||||
if (parse_strtoul(buf, LAYFLAT_MODE, &t))
|
||||
return -EINVAL;
|
||||
|
||||
res = adaptive_keyboard_set_mode(t);
|
||||
return (res < 0) ? res : count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(adaptive_kbd_mode);
|
||||
|
||||
static struct attribute *adaptive_kbd_attributes[] = {
|
||||
&dev_attr_adaptive_kbd_mode.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adaptive_kbd_attr_group = {
|
||||
.attrs = adaptive_kbd_attributes,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static struct attribute *hotkey_attributes[] __initdata = {
|
||||
|
@ -3118,6 +3173,13 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
/* (assignments unknown, please report if found) */
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
|
||||
/* No assignments, only used for Adaptive keyboards. */
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
},
|
||||
|
||||
/* Generic keymap for Lenovo ThinkPads */
|
||||
|
@ -3174,6 +3236,35 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
|
||||
/* Extra keys in use since the X240 / T440 / T540 */
|
||||
KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_FILE,
|
||||
|
||||
/*
|
||||
* These are the adaptive keyboard keycodes for Carbon X1 2014.
|
||||
* The first item in this list is the Mute button which is
|
||||
* emitted with 0x103 through
|
||||
* adaptive_keyboard_hotkey_notify_hotkey() when the sound
|
||||
* symbol is held.
|
||||
* We'll need to offset those by 0x20.
|
||||
*/
|
||||
KEY_RESERVED, /* Mute held, 0x103 */
|
||||
KEY_BRIGHTNESS_MIN, /* Backlight off */
|
||||
KEY_RESERVED, /* Clipping tool */
|
||||
KEY_RESERVED, /* Cloud */
|
||||
KEY_RESERVED,
|
||||
KEY_VOICECOMMAND, /* Voice */
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED, /* Gestures */
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_CONFIG, /* Settings */
|
||||
KEY_RESERVED, /* New tab */
|
||||
KEY_REFRESH, /* Reload */
|
||||
KEY_BACK, /* Back */
|
||||
KEY_RESERVED, /* Microphone down */
|
||||
KEY_RESERVED, /* Microphone up */
|
||||
KEY_RESERVED, /* Microphone cancellation */
|
||||
KEY_RESERVED, /* Camera mode */
|
||||
KEY_RESERVED, /* Rotate display, 0x116 */
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -3227,6 +3318,20 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
if (!tp_features.hotkey)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Check if we have an adaptive keyboard, like on the
|
||||
* Lenovo Carbon X1 2014 (2nd Gen).
|
||||
*/
|
||||
if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
|
||||
if ((hkeyv >> 8) == 2) {
|
||||
tp_features.has_adaptive_kbd = true;
|
||||
res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
|
||||
&adaptive_kbd_attr_group);
|
||||
if (res)
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
|
||||
quirks = tpacpi_check_quirks(tpacpi_hotkey_qtable,
|
||||
ARRAY_SIZE(tpacpi_hotkey_qtable));
|
||||
|
||||
|
@ -3437,6 +3542,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
|
||||
err_exit:
|
||||
delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
|
||||
sysfs_remove_group(&tpacpi_pdev->dev.kobj,
|
||||
&adaptive_kbd_attr_group);
|
||||
|
||||
hotkey_dev_attributes = NULL;
|
||||
|
||||
return (res < 0) ? res : 1;
|
||||
|
@ -3449,14 +3557,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
* Will consider support rest of modes in future.
|
||||
*
|
||||
*/
|
||||
enum ADAPTIVE_KEY_MODE {
|
||||
HOME_MODE,
|
||||
WEB_BROWSER_MODE,
|
||||
WEB_CONFERENCE_MODE,
|
||||
FUNCTION_MODE,
|
||||
LAYFLAT_MODE
|
||||
};
|
||||
|
||||
static const int adaptive_keyboard_modes[] = {
|
||||
HOME_MODE,
|
||||
/* WEB_BROWSER_MODE = 2,
|
||||
|
@ -3466,6 +3566,8 @@ static const int adaptive_keyboard_modes[] = {
|
|||
|
||||
#define DFR_CHANGE_ROW 0x101
|
||||
#define DFR_SHOW_QUICKVIEW_ROW 0x102
|
||||
#define FIRST_ADAPTIVE_KEY 0x103
|
||||
#define ADAPTIVE_KEY_OFFSET 0x020
|
||||
|
||||
/* press Fn key a while second, it will switch to Function Mode. Then
|
||||
* release Fn key, previous mode be restored.
|
||||
|
@ -3473,6 +3575,32 @@ static const int adaptive_keyboard_modes[] = {
|
|||
static bool adaptive_keyboard_mode_is_saved;
|
||||
static int adaptive_keyboard_prev_mode;
|
||||
|
||||
static int adaptive_keyboard_get_mode(void)
|
||||
{
|
||||
int mode = 0;
|
||||
|
||||
if (!acpi_evalf(hkey_handle, &mode, "GTRW", "dd", 0)) {
|
||||
pr_err("Cannot read adaptive keyboard mode\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int adaptive_keyboard_set_mode(int new_mode)
|
||||
{
|
||||
if (new_mode < 0 ||
|
||||
new_mode > LAYFLAT_MODE)
|
||||
return -EINVAL;
|
||||
|
||||
if (!acpi_evalf(hkey_handle, NULL, "STRW", "vd", new_mode)) {
|
||||
pr_err("Cannot set adaptive keyboard mode\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adaptive_keyboard_get_next_mode(int mode)
|
||||
{
|
||||
size_t i;
|
||||
|
@ -3493,8 +3621,9 @@ static int adaptive_keyboard_get_next_mode(int mode)
|
|||
|
||||
static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode)
|
||||
{
|
||||
u32 current_mode = 0;
|
||||
int current_mode = 0;
|
||||
int new_mode = 0;
|
||||
int keycode;
|
||||
|
||||
switch (scancode) {
|
||||
case DFR_CHANGE_ROW:
|
||||
|
@ -3502,43 +3631,51 @@ static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode)
|
|||
new_mode = adaptive_keyboard_prev_mode;
|
||||
adaptive_keyboard_mode_is_saved = false;
|
||||
} else {
|
||||
if (!acpi_evalf(
|
||||
hkey_handle, ¤t_mode,
|
||||
"GTRW", "dd", 0)) {
|
||||
pr_err("Cannot read adaptive keyboard mode\n");
|
||||
current_mode = adaptive_keyboard_get_mode();
|
||||
if (current_mode < 0)
|
||||
return false;
|
||||
} else {
|
||||
new_mode = adaptive_keyboard_get_next_mode(
|
||||
current_mode);
|
||||
}
|
||||
new_mode = adaptive_keyboard_get_next_mode(
|
||||
current_mode);
|
||||
}
|
||||
|
||||
if (!acpi_evalf(hkey_handle, NULL, "STRW", "vd", new_mode)) {
|
||||
pr_err("Cannot set adaptive keyboard mode\n");
|
||||
if (adaptive_keyboard_set_mode(new_mode) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
case DFR_SHOW_QUICKVIEW_ROW:
|
||||
if (!acpi_evalf(hkey_handle,
|
||||
&adaptive_keyboard_prev_mode,
|
||||
"GTRW", "dd", 0)) {
|
||||
pr_err("Cannot read adaptive keyboard mode\n");
|
||||
current_mode = adaptive_keyboard_get_mode();
|
||||
if (current_mode < 0)
|
||||
return false;
|
||||
} else {
|
||||
adaptive_keyboard_mode_is_saved = true;
|
||||
|
||||
if (!acpi_evalf(hkey_handle,
|
||||
NULL, "STRW", "vd", FUNCTION_MODE)) {
|
||||
pr_err("Cannot set adaptive keyboard mode\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
adaptive_keyboard_prev_mode = current_mode;
|
||||
adaptive_keyboard_mode_is_saved = true;
|
||||
|
||||
if (adaptive_keyboard_set_mode (FUNCTION_MODE) < 0)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
if (scancode < FIRST_ADAPTIVE_KEY ||
|
||||
scancode >= FIRST_ADAPTIVE_KEY + TPACPI_HOTKEY_MAP_LEN -
|
||||
ADAPTIVE_KEY_OFFSET) {
|
||||
pr_info("Unhandled adaptive keyboard key: 0x%x\n",
|
||||
scancode);
|
||||
return false;
|
||||
}
|
||||
keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY + ADAPTIVE_KEY_OFFSET];
|
||||
if (keycode != KEY_RESERVED) {
|
||||
mutex_lock(&tpacpi_inputdev_send_mutex);
|
||||
|
||||
input_report_key(tpacpi_inputdev, keycode, 1);
|
||||
input_sync(tpacpi_inputdev);
|
||||
|
||||
input_report_key(tpacpi_inputdev, keycode, 0);
|
||||
input_sync(tpacpi_inputdev);
|
||||
|
||||
mutex_unlock(&tpacpi_inputdev_send_mutex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3836,28 +3973,21 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
|
|||
|
||||
static void hotkey_suspend(void)
|
||||
{
|
||||
int hkeyv;
|
||||
|
||||
/* Do these on suspend, we get the events on early resume! */
|
||||
hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
|
||||
hotkey_autosleep_ack = 0;
|
||||
|
||||
/* save previous mode of adaptive keyboard of X1 Carbon */
|
||||
if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
|
||||
if ((hkeyv >> 8) == 2) {
|
||||
if (!acpi_evalf(hkey_handle,
|
||||
&adaptive_keyboard_prev_mode,
|
||||
"GTRW", "dd", 0)) {
|
||||
pr_err("Cannot read adaptive keyboard mode.\n");
|
||||
}
|
||||
if (tp_features.has_adaptive_kbd) {
|
||||
if (!acpi_evalf(hkey_handle, &adaptive_keyboard_prev_mode,
|
||||
"GTRW", "dd", 0)) {
|
||||
pr_err("Cannot read adaptive keyboard mode.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hotkey_resume(void)
|
||||
{
|
||||
int hkeyv;
|
||||
|
||||
tpacpi_disable_brightness_delay();
|
||||
|
||||
if (hotkey_status_set(true) < 0 ||
|
||||
|
@ -3872,14 +4002,10 @@ static void hotkey_resume(void)
|
|||
hotkey_poll_setup_safe(false);
|
||||
|
||||
/* restore previous mode of adapive keyboard of X1 Carbon */
|
||||
if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
|
||||
if ((hkeyv >> 8) == 2) {
|
||||
if (!acpi_evalf(hkey_handle,
|
||||
NULL,
|
||||
"STRW", "vd",
|
||||
adaptive_keyboard_prev_mode)) {
|
||||
pr_err("Cannot set adaptive keyboard mode.\n");
|
||||
}
|
||||
if (tp_features.has_adaptive_kbd) {
|
||||
if (!acpi_evalf(hkey_handle, NULL, "STRW", "vd",
|
||||
adaptive_keyboard_prev_mode)) {
|
||||
pr_err("Cannot set adaptive keyboard mode.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4079,9 +4205,7 @@ static ssize_t bluetooth_enable_store(struct device *dev,
|
|||
attr, buf, count);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_bluetooth_enable =
|
||||
__ATTR(bluetooth_enable, S_IWUSR | S_IRUGO,
|
||||
bluetooth_enable_show, bluetooth_enable_store);
|
||||
static DEVICE_ATTR_RW(bluetooth_enable);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
|
@ -4269,9 +4393,7 @@ static ssize_t wan_enable_store(struct device *dev,
|
|||
attr, buf, count);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_wan_enable =
|
||||
__ATTR(wwan_enable, S_IWUSR | S_IRUGO,
|
||||
wan_enable_show, wan_enable_store);
|
||||
static DEVICE_ATTR_RW(wan_enable);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
|
@ -5048,8 +5170,7 @@ static ssize_t cmos_command_store(struct device *dev,
|
|||
return (res) ? res : count;
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_cmos_command =
|
||||
__ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store);
|
||||
static DEVICE_ATTR_WO(cmos_command);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
|
@ -8017,9 +8138,7 @@ static ssize_t fan_pwm1_enable_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_fan_pwm1_enable =
|
||||
__ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
|
||||
fan_pwm1_enable_show, fan_pwm1_enable_store);
|
||||
static DEVICE_ATTR_RW(fan_pwm1_enable);
|
||||
|
||||
/* sysfs fan pwm1 ------------------------------------------------------ */
|
||||
static ssize_t fan_pwm1_show(struct device *dev,
|
||||
|
@ -8079,9 +8198,7 @@ static ssize_t fan_pwm1_store(struct device *dev,
|
|||
return (rc) ? rc : count;
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_fan_pwm1 =
|
||||
__ATTR(pwm1, S_IWUSR | S_IRUGO,
|
||||
fan_pwm1_show, fan_pwm1_store);
|
||||
static DEVICE_ATTR_RW(fan_pwm1);
|
||||
|
||||
/* sysfs fan fan1_input ------------------------------------------------ */
|
||||
static ssize_t fan_fan1_input_show(struct device *dev,
|
||||
|
@ -8098,9 +8215,7 @@ static ssize_t fan_fan1_input_show(struct device *dev,
|
|||
return snprintf(buf, PAGE_SIZE, "%u\n", speed);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_fan_fan1_input =
|
||||
__ATTR(fan1_input, S_IRUGO,
|
||||
fan_fan1_input_show, NULL);
|
||||
static DEVICE_ATTR_RO(fan_fan1_input);
|
||||
|
||||
/* sysfs fan fan2_input ------------------------------------------------ */
|
||||
static ssize_t fan_fan2_input_show(struct device *dev,
|
||||
|
@ -8117,9 +8232,7 @@ static ssize_t fan_fan2_input_show(struct device *dev,
|
|||
return snprintf(buf, PAGE_SIZE, "%u\n", speed);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_fan_fan2_input =
|
||||
__ATTR(fan2_input, S_IRUGO,
|
||||
fan_fan2_input_show, NULL);
|
||||
static DEVICE_ATTR_RO(fan_fan2_input);
|
||||
|
||||
/* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */
|
||||
static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
|
||||
|
@ -8735,8 +8848,7 @@ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev,
|
|||
return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
|
||||
__ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL);
|
||||
static DEVICE_ATTR_RO(thinkpad_acpi_pdev_name);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <acpi/video.h>
|
||||
|
||||
MODULE_AUTHOR("John Belmonte");
|
||||
MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
|
||||
|
@ -116,6 +117,7 @@ MODULE_LICENSE("GPL");
|
|||
#define HCI_KBD_ILLUMINATION 0x0095
|
||||
#define HCI_ECO_MODE 0x0097
|
||||
#define HCI_ACCELEROMETER2 0x00a6
|
||||
#define HCI_SYSTEM_INFO 0xc000
|
||||
#define SCI_PANEL_POWER_ON 0x010d
|
||||
#define SCI_ILLUMINATION 0x014e
|
||||
#define SCI_USB_SLEEP_CHARGE 0x0150
|
||||
|
@ -129,10 +131,13 @@ MODULE_LICENSE("GPL");
|
|||
#define HCI_ACCEL_MASK 0x7fff
|
||||
#define HCI_HOTKEY_DISABLE 0x0b
|
||||
#define HCI_HOTKEY_ENABLE 0x09
|
||||
#define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10
|
||||
#define HCI_LCD_BRIGHTNESS_BITS 3
|
||||
#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
|
||||
#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
|
||||
#define HCI_MISC_SHIFT 0x10
|
||||
#define HCI_SYSTEM_TYPE1 0x10
|
||||
#define HCI_SYSTEM_TYPE2 0x11
|
||||
#define HCI_VIDEO_OUT_LCD 0x1
|
||||
#define HCI_VIDEO_OUT_CRT 0x2
|
||||
#define HCI_VIDEO_OUT_TV 0x4
|
||||
|
@ -147,9 +152,10 @@ MODULE_LICENSE("GPL");
|
|||
#define SCI_KBD_MODE_OFF 0x10
|
||||
#define SCI_KBD_TIME_MAX 0x3c001a
|
||||
#define SCI_USB_CHARGE_MODE_MASK 0xff
|
||||
#define SCI_USB_CHARGE_DISABLED 0x30000
|
||||
#define SCI_USB_CHARGE_ALTERNATE 0x30009
|
||||
#define SCI_USB_CHARGE_AUTO 0x30021
|
||||
#define SCI_USB_CHARGE_DISABLED 0x00
|
||||
#define SCI_USB_CHARGE_ALTERNATE 0x09
|
||||
#define SCI_USB_CHARGE_TYPICAL 0x11
|
||||
#define SCI_USB_CHARGE_AUTO 0x21
|
||||
#define SCI_USB_CHARGE_BAT_MASK 0x7
|
||||
#define SCI_USB_CHARGE_BAT_LVL_OFF 0x1
|
||||
#define SCI_USB_CHARGE_BAT_LVL_ON 0x4
|
||||
|
@ -174,6 +180,8 @@ struct toshiba_acpi_dev {
|
|||
int kbd_mode;
|
||||
int kbd_time;
|
||||
int usbsc_bat_level;
|
||||
int usbsc_mode_base;
|
||||
int hotkey_event_type;
|
||||
|
||||
unsigned int illumination_supported:1;
|
||||
unsigned int video_supported:1;
|
||||
|
@ -243,29 +251,6 @@ static const struct key_entry toshiba_acpi_keymap[] = {
|
|||
{ KE_END, 0 },
|
||||
};
|
||||
|
||||
/* alternative keymap */
|
||||
static const struct dmi_system_id toshiba_alt_keymap_dmi[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A50-A"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct key_entry toshiba_acpi_alt_keymap[] = {
|
||||
{ KE_KEY, 0x157, { KEY_MUTE } },
|
||||
{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
|
||||
|
@ -280,6 +265,14 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = {
|
|||
{ KE_END, 0 },
|
||||
};
|
||||
|
||||
/*
|
||||
* List of models which have a broken acpi-video backlight interface and thus
|
||||
* need to use the toshiba (vendor) interface instead.
|
||||
*/
|
||||
static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Utility
|
||||
*/
|
||||
|
@ -819,6 +812,54 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
|
|||
}
|
||||
|
||||
/* Sleep (Charge and Music) utilities support */
|
||||
static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev)
|
||||
{
|
||||
u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
|
||||
u32 out[TCI_WORDS];
|
||||
acpi_status status;
|
||||
|
||||
/* Set the feature to "not supported" in case of error */
|
||||
dev->usb_sleep_charge_supported = 0;
|
||||
|
||||
if (!sci_open(dev))
|
||||
return;
|
||||
|
||||
status = tci_raw(dev, in, out);
|
||||
if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
|
||||
pr_err("ACPI call to get USB Sleep and Charge mode failed\n");
|
||||
sci_close(dev);
|
||||
return;
|
||||
} else if (out[0] == TOS_NOT_SUPPORTED) {
|
||||
pr_info("USB Sleep and Charge not supported\n");
|
||||
sci_close(dev);
|
||||
return;
|
||||
} else if (out[0] == TOS_SUCCESS) {
|
||||
dev->usbsc_mode_base = out[4];
|
||||
}
|
||||
|
||||
in[5] = SCI_USB_CHARGE_BAT_LVL;
|
||||
status = tci_raw(dev, in, out);
|
||||
if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
|
||||
pr_err("ACPI call to get USB Sleep and Charge mode failed\n");
|
||||
sci_close(dev);
|
||||
return;
|
||||
} else if (out[0] == TOS_NOT_SUPPORTED) {
|
||||
pr_info("USB Sleep and Charge not supported\n");
|
||||
sci_close(dev);
|
||||
return;
|
||||
} else if (out[0] == TOS_SUCCESS) {
|
||||
dev->usbsc_bat_level = out[2];
|
||||
/*
|
||||
* If we reach this point, it means that the laptop has support
|
||||
* for this feature and all values are initialized.
|
||||
* Set it as supported.
|
||||
*/
|
||||
dev->usb_sleep_charge_supported = 1;
|
||||
}
|
||||
|
||||
sci_close(dev);
|
||||
}
|
||||
|
||||
static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
|
||||
u32 *mode)
|
||||
{
|
||||
|
@ -934,11 +975,11 @@ static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
|
|||
status = tci_raw(dev, in, out);
|
||||
sci_close(dev);
|
||||
if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
|
||||
pr_err("ACPI call to get USB S&C battery level failed\n");
|
||||
pr_err("ACPI call to get USB Rapid Charge failed\n");
|
||||
return -EIO;
|
||||
} else if (out[0] == TOS_NOT_SUPPORTED ||
|
||||
out[0] == TOS_INPUT_DATA_ERROR) {
|
||||
pr_info("USB Sleep and Charge not supported\n");
|
||||
pr_info("USB Rapid Charge not supported\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -962,10 +1003,10 @@ static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
|
|||
status = tci_raw(dev, in, out);
|
||||
sci_close(dev);
|
||||
if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
|
||||
pr_err("ACPI call to set USB S&C battery level failed\n");
|
||||
pr_err("ACPI call to set USB Rapid Charge failed\n");
|
||||
return -EIO;
|
||||
} else if (out[0] == TOS_NOT_SUPPORTED) {
|
||||
pr_info("USB Sleep and Charge not supported\n");
|
||||
pr_info("USB Rapid Charge not supported\n");
|
||||
return -ENODEV;
|
||||
} else if (out[0] == TOS_INPUT_DATA_ERROR) {
|
||||
return -EIO;
|
||||
|
@ -984,10 +1025,10 @@ static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
|
|||
result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state);
|
||||
sci_close(dev);
|
||||
if (result == TOS_FAILURE) {
|
||||
pr_err("ACPI call to set USB S&C mode failed\n");
|
||||
pr_err("ACPI call to get Sleep and Music failed\n");
|
||||
return -EIO;
|
||||
} else if (result == TOS_NOT_SUPPORTED) {
|
||||
pr_info("USB Sleep and Charge not supported\n");
|
||||
pr_info("Sleep and Music not supported\n");
|
||||
return -ENODEV;
|
||||
} else if (result == TOS_INPUT_DATA_ERROR) {
|
||||
return -EIO;
|
||||
|
@ -1006,10 +1047,10 @@ static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
|
|||
result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state);
|
||||
sci_close(dev);
|
||||
if (result == TOS_FAILURE) {
|
||||
pr_err("ACPI call to set USB S&C mode failed\n");
|
||||
pr_err("ACPI call to set Sleep and Music failed\n");
|
||||
return -EIO;
|
||||
} else if (result == TOS_NOT_SUPPORTED) {
|
||||
pr_info("USB Sleep and Charge not supported\n");
|
||||
pr_info("Sleep and Music not supported\n");
|
||||
return -ENODEV;
|
||||
} else if (result == TOS_INPUT_DATA_ERROR) {
|
||||
return -EIO;
|
||||
|
@ -1149,6 +1190,28 @@ static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Hotkey Event type */
|
||||
static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev,
|
||||
u32 *type)
|
||||
{
|
||||
u32 val1 = 0x03;
|
||||
u32 val2 = 0;
|
||||
u32 result;
|
||||
|
||||
result = hci_read2(dev, HCI_SYSTEM_INFO, &val1, &val2);
|
||||
if (result == TOS_FAILURE) {
|
||||
pr_err("ACPI call to get System type failed\n");
|
||||
return -EIO;
|
||||
} else if (result == TOS_NOT_SUPPORTED) {
|
||||
pr_info("System type not supported\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
*type = val2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bluetooth rfkill handlers */
|
||||
|
||||
static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
|
||||
|
@ -1973,17 +2036,21 @@ static ssize_t usb_sleep_charge_store(struct device *dev,
|
|||
* 0 - Disabled
|
||||
* 1 - Alternate (Non USB conformant devices that require more power)
|
||||
* 2 - Auto (USB conformant devices)
|
||||
* 3 - Typical
|
||||
*/
|
||||
if (state != 0 && state != 1 && state != 2)
|
||||
if (state != 0 && state != 1 && state != 2 && state != 3)
|
||||
return -EINVAL;
|
||||
|
||||
/* Set the USB charging mode to internal value */
|
||||
mode = toshiba->usbsc_mode_base;
|
||||
if (state == 0)
|
||||
mode = SCI_USB_CHARGE_DISABLED;
|
||||
mode |= SCI_USB_CHARGE_DISABLED;
|
||||
else if (state == 1)
|
||||
mode = SCI_USB_CHARGE_ALTERNATE;
|
||||
mode |= SCI_USB_CHARGE_ALTERNATE;
|
||||
else if (state == 2)
|
||||
mode = SCI_USB_CHARGE_AUTO;
|
||||
mode |= SCI_USB_CHARGE_AUTO;
|
||||
else if (state == 3)
|
||||
mode |= SCI_USB_CHARGE_TYPICAL;
|
||||
|
||||
ret = toshiba_usb_sleep_charge_set(toshiba, mode);
|
||||
if (ret)
|
||||
|
@ -2333,6 +2400,20 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void toshiba_acpi_enable_special_functions(struct toshiba_acpi_dev *dev)
|
||||
{
|
||||
u32 result;
|
||||
|
||||
/*
|
||||
* Re-activate the hotkeys, but this time, we are using the
|
||||
* "Special Functions" mode.
|
||||
*/
|
||||
result = hci_write1(dev, HCI_HOTKEY_EVENT,
|
||||
HCI_HOTKEY_SPECIAL_FUNCTIONS);
|
||||
if (result != TOS_SUCCESS)
|
||||
pr_err("Could not enable the Special Function mode\n");
|
||||
}
|
||||
|
||||
static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
|
||||
struct serio *port)
|
||||
{
|
||||
|
@ -2434,10 +2515,22 @@ static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
|
|||
|
||||
static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
|
||||
{
|
||||
acpi_handle ec_handle;
|
||||
int error;
|
||||
u32 hci_result;
|
||||
const struct key_entry *keymap = toshiba_acpi_keymap;
|
||||
acpi_handle ec_handle;
|
||||
u32 events_type;
|
||||
u32 hci_result;
|
||||
int error;
|
||||
|
||||
error = toshiba_acpi_enable_hotkeys(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = toshiba_hotkey_event_type_get(dev, &events_type);
|
||||
if (error) {
|
||||
pr_err("Unable to query Hotkey Event Type\n");
|
||||
return error;
|
||||
}
|
||||
dev->hotkey_event_type = events_type;
|
||||
|
||||
dev->hotkey_dev = input_allocate_device();
|
||||
if (!dev->hotkey_dev)
|
||||
|
@ -2447,8 +2540,14 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
|
|||
dev->hotkey_dev->phys = "toshiba_acpi/input0";
|
||||
dev->hotkey_dev->id.bustype = BUS_HOST;
|
||||
|
||||
if (dmi_check_system(toshiba_alt_keymap_dmi))
|
||||
if (events_type == HCI_SYSTEM_TYPE1 ||
|
||||
!dev->kbd_function_keys_supported)
|
||||
keymap = toshiba_acpi_keymap;
|
||||
else if (events_type == HCI_SYSTEM_TYPE2 ||
|
||||
dev->kbd_function_keys_supported)
|
||||
keymap = toshiba_acpi_alt_keymap;
|
||||
else
|
||||
pr_info("Unknown event type received %x\n", events_type);
|
||||
error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
|
||||
if (error)
|
||||
goto err_free_dev;
|
||||
|
@ -2490,12 +2589,6 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
|
|||
goto err_remove_filter;
|
||||
}
|
||||
|
||||
error = toshiba_acpi_enable_hotkeys(dev);
|
||||
if (error) {
|
||||
pr_info("Unable to enable hotkeys\n");
|
||||
goto err_remove_filter;
|
||||
}
|
||||
|
||||
error = input_register_device(dev->hotkey_dev);
|
||||
if (error) {
|
||||
pr_info("Unable to register input device\n");
|
||||
|
@ -2541,6 +2634,20 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
|
|||
ret = get_tr_backlight_status(dev, &enabled);
|
||||
dev->tr_backlight_supported = !ret;
|
||||
|
||||
/*
|
||||
* Tell acpi-video-detect code to prefer vendor backlight on all
|
||||
* systems with transflective backlight and on dmi matched systems.
|
||||
*/
|
||||
if (dev->tr_backlight_supported ||
|
||||
dmi_check_system(toshiba_vendor_backlight_dmi))
|
||||
acpi_video_dmi_promote_vendor();
|
||||
|
||||
if (acpi_video_backlight_support())
|
||||
return 0;
|
||||
|
||||
/* acpi-video may have loaded before we called dmi_promote_vendor() */
|
||||
acpi_video_unregister_backlight();
|
||||
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
|
||||
|
@ -2624,6 +2731,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
|||
{
|
||||
struct toshiba_acpi_dev *dev;
|
||||
const char *hci_method;
|
||||
u32 special_functions;
|
||||
u32 dummy;
|
||||
bool bt_present;
|
||||
int ret = 0;
|
||||
|
@ -2648,6 +2756,16 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
|||
acpi_dev->driver_data = dev;
|
||||
dev_set_drvdata(&acpi_dev->dev, dev);
|
||||
|
||||
/* Query the BIOS for supported features */
|
||||
|
||||
/*
|
||||
* The "Special Functions" are always supported by the laptops
|
||||
* with the new keyboard layout, query for its presence to help
|
||||
* determine the keymap layout to use.
|
||||
*/
|
||||
ret = toshiba_function_keys_get(dev, &special_functions);
|
||||
dev->kbd_function_keys_supported = !ret;
|
||||
|
||||
if (toshiba_acpi_setup_keyboard(dev))
|
||||
pr_info("Unable to activate hotkeys\n");
|
||||
|
||||
|
@ -2716,8 +2834,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
|||
ret = toshiba_accelerometer_supported(dev);
|
||||
dev->accelerometer_supported = !ret;
|
||||
|
||||
ret = toshiba_usb_sleep_charge_get(dev, &dummy);
|
||||
dev->usb_sleep_charge_supported = !ret;
|
||||
toshiba_usb_sleep_charge_available(dev);
|
||||
|
||||
ret = toshiba_usb_rapid_charge_get(dev, &dummy);
|
||||
dev->usb_rapid_charge_supported = !ret;
|
||||
|
@ -2725,23 +2842,25 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
|||
ret = toshiba_usb_sleep_music_get(dev, &dummy);
|
||||
dev->usb_sleep_music_supported = !ret;
|
||||
|
||||
ret = toshiba_function_keys_get(dev, &dummy);
|
||||
dev->kbd_function_keys_supported = !ret;
|
||||
|
||||
ret = toshiba_panel_power_on_get(dev, &dummy);
|
||||
dev->panel_power_on_supported = !ret;
|
||||
|
||||
ret = toshiba_usb_three_get(dev, &dummy);
|
||||
dev->usb_three_supported = !ret;
|
||||
|
||||
/* Determine whether or not BIOS supports fan and video interfaces */
|
||||
|
||||
ret = get_video_status(dev, &dummy);
|
||||
dev->video_supported = !ret;
|
||||
|
||||
ret = get_fan_status(dev, &dummy);
|
||||
dev->fan_supported = !ret;
|
||||
|
||||
/*
|
||||
* Enable the "Special Functions" mode only if they are
|
||||
* supported and if they are activated.
|
||||
*/
|
||||
if (dev->kbd_function_keys_supported && special_functions)
|
||||
toshiba_acpi_enable_special_functions(dev);
|
||||
|
||||
ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
|
||||
&toshiba_attr_group);
|
||||
if (ret) {
|
||||
|
@ -2770,6 +2889,21 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
|
|||
case 0x80: /* Hotkeys and some system events */
|
||||
toshiba_acpi_process_hotkeys(dev);
|
||||
break;
|
||||
case 0x81: /* Dock events */
|
||||
case 0x82:
|
||||
case 0x83:
|
||||
pr_info("Dock event received %x\n", event);
|
||||
break;
|
||||
case 0x88: /* Thermal events */
|
||||
pr_info("Thermal event received\n");
|
||||
break;
|
||||
case 0x8f: /* LID closed */
|
||||
case 0x90: /* LID is closed and Dock has been ejected */
|
||||
break;
|
||||
case 0x8c: /* SATA power events */
|
||||
case 0x8b:
|
||||
pr_info("SATA power event received %x\n", event);
|
||||
break;
|
||||
case 0x92: /* Keyboard backlight mode changed */
|
||||
/* Update sysfs entries */
|
||||
ret = sysfs_update_group(&acpi_dev->dev.kobj,
|
||||
|
@ -2777,17 +2911,19 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
|
|||
if (ret)
|
||||
pr_err("Unable to update sysfs entries\n");
|
||||
break;
|
||||
case 0x81: /* Unknown */
|
||||
case 0x82: /* Unknown */
|
||||
case 0x83: /* Unknown */
|
||||
case 0x8c: /* Unknown */
|
||||
case 0x85: /* Unknown */
|
||||
case 0x8d: /* Unknown */
|
||||
case 0x8e: /* Unknown */
|
||||
case 0x8f: /* Unknown */
|
||||
case 0x90: /* Unknown */
|
||||
case 0x94: /* Unknown */
|
||||
case 0x95: /* Unknown */
|
||||
default:
|
||||
pr_info("Unknown event received %x\n", event);
|
||||
break;
|
||||
}
|
||||
|
||||
acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class,
|
||||
dev_name(&acpi_dev->dev),
|
||||
event, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Toshiba Bluetooth Enable Driver
|
||||
*
|
||||
* Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com>
|
||||
* Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.com>
|
||||
*
|
||||
* Thanks to Matthew Garrett for background info on ACPI innards which
|
||||
* normal people aren't meant to understand :-)
|
||||
|
@ -25,6 +26,10 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define BT_KILLSWITCH_MASK 0x01
|
||||
#define BT_PLUGGED_MASK 0x40
|
||||
#define BT_POWER_MASK 0x80
|
||||
|
||||
MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>");
|
||||
MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -57,32 +62,107 @@ static struct acpi_driver toshiba_bt_rfkill_driver = {
|
|||
.drv.pm = &toshiba_bt_pm,
|
||||
};
|
||||
|
||||
static int toshiba_bluetooth_present(acpi_handle handle)
|
||||
{
|
||||
acpi_status result;
|
||||
u64 bt_present;
|
||||
|
||||
/*
|
||||
* Some Toshiba laptops may have a fake TOS6205 device in
|
||||
* their ACPI BIOS, so query the _STA method to see if there
|
||||
* is really anything there.
|
||||
*/
|
||||
result = acpi_evaluate_integer(handle, "_STA", NULL, &bt_present);
|
||||
if (ACPI_FAILURE(result)) {
|
||||
pr_err("ACPI call to query Bluetooth presence failed");
|
||||
return -ENXIO;
|
||||
} else if (!bt_present) {
|
||||
pr_info("Bluetooth device not present\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int toshiba_bluetooth_status(acpi_handle handle)
|
||||
{
|
||||
acpi_status result;
|
||||
u64 status;
|
||||
|
||||
result = acpi_evaluate_integer(handle, "BTST", NULL, &status);
|
||||
if (ACPI_FAILURE(result)) {
|
||||
pr_err("Could not get Bluetooth device status\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
pr_info("Bluetooth status %llu\n", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int toshiba_bluetooth_enable(acpi_handle handle)
|
||||
{
|
||||
acpi_status res1, res2;
|
||||
u64 result;
|
||||
acpi_status result;
|
||||
bool killswitch;
|
||||
bool powered;
|
||||
bool plugged;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Query ACPI to verify RFKill switch is set to 'on'.
|
||||
* If not, we return silently, no need to report it as
|
||||
* an error.
|
||||
*/
|
||||
res1 = acpi_evaluate_integer(handle, "BTST", NULL, &result);
|
||||
if (ACPI_FAILURE(res1))
|
||||
return res1;
|
||||
if (!(result & 0x01))
|
||||
status = toshiba_bluetooth_status(handle);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
killswitch = (status & BT_KILLSWITCH_MASK) ? true : false;
|
||||
powered = (status & BT_POWER_MASK) ? true : false;
|
||||
plugged = (status & BT_PLUGGED_MASK) ? true : false;
|
||||
|
||||
if (!killswitch)
|
||||
return 0;
|
||||
/*
|
||||
* This check ensures to only enable the device if it is powered
|
||||
* off or detached, as some recent devices somehow pass the killswitch
|
||||
* test, causing a loop enabling/disabling the device, see bug 93911.
|
||||
*/
|
||||
if (powered || plugged)
|
||||
return 0;
|
||||
|
||||
pr_info("Re-enabling Toshiba Bluetooth\n");
|
||||
res1 = acpi_evaluate_object(handle, "AUSB", NULL, NULL);
|
||||
res2 = acpi_evaluate_object(handle, "BTPO", NULL, NULL);
|
||||
if (!ACPI_FAILURE(res1) || !ACPI_FAILURE(res2))
|
||||
return 0;
|
||||
result = acpi_evaluate_object(handle, "AUSB", NULL, NULL);
|
||||
if (ACPI_FAILURE(result)) {
|
||||
pr_err("Could not attach USB Bluetooth device\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
pr_warn("Failed to re-enable Toshiba Bluetooth\n");
|
||||
result = acpi_evaluate_object(handle, "BTPO", NULL, NULL);
|
||||
if (ACPI_FAILURE(result)) {
|
||||
pr_err("Could not power ON Bluetooth device\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int toshiba_bluetooth_disable(acpi_handle handle)
|
||||
{
|
||||
acpi_status result;
|
||||
|
||||
result = acpi_evaluate_object(handle, "BTPF", NULL, NULL);
|
||||
if (ACPI_FAILURE(result)) {
|
||||
pr_err("Could not power OFF Bluetooth device\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
result = acpi_evaluate_object(handle, "DUSB", NULL, NULL);
|
||||
if (ACPI_FAILURE(result)) {
|
||||
pr_err("Could not detach USB Bluetooth device\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
|
||||
|
@ -99,23 +179,18 @@ static int toshiba_bt_resume(struct device *dev)
|
|||
|
||||
static int toshiba_bt_rfkill_add(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status;
|
||||
u64 bt_present;
|
||||
int result = -ENODEV;
|
||||
int result;
|
||||
|
||||
/*
|
||||
* Some Toshiba laptops may have a fake TOS6205 device in
|
||||
* their ACPI BIOS, so query the _STA method to see if there
|
||||
* is really anything there, before trying to enable it.
|
||||
*/
|
||||
status = acpi_evaluate_integer(device->handle, "_STA", NULL,
|
||||
&bt_present);
|
||||
result = toshiba_bluetooth_present(device->handle);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (!ACPI_FAILURE(status) && bt_present) {
|
||||
pr_info("Detected Toshiba ACPI Bluetooth device - "
|
||||
"installing RFKill handler\n");
|
||||
result = toshiba_bluetooth_enable(device->handle);
|
||||
}
|
||||
pr_info("Toshiba ACPI Bluetooth device driver\n");
|
||||
|
||||
/* Enable the BT device */
|
||||
result = toshiba_bluetooth_enable(device->handle);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -123,7 +198,7 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device)
|
|||
static int toshiba_bt_rfkill_remove(struct acpi_device *device)
|
||||
{
|
||||
/* clean up */
|
||||
return 0;
|
||||
return toshiba_bluetooth_disable(device->handle);
|
||||
}
|
||||
|
||||
module_acpi_driver(toshiba_bt_rfkill_driver);
|
||||
|
|
|
@ -45,7 +45,6 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
#define ACPI_WMI_CLASS "wmi"
|
||||
|
||||
static DEFINE_MUTEX(wmi_data_lock);
|
||||
static LIST_HEAD(wmi_block_list);
|
||||
|
||||
struct guid_block {
|
||||
|
@ -240,10 +239,10 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
|
|||
if (memcmp(block->guid, guid_input, 16) == 0) {
|
||||
if (out)
|
||||
*out = wblock;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
|
||||
|
|
Loading…
Reference in New Issue