2019-05-27 14:55:05 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
2011-02-26 17:20:31 +08:00
|
|
|
/*
|
|
|
|
* Asus PC WMI hotkey driver
|
|
|
|
*
|
|
|
|
* Copyright(C) 2010 Intel Corporation.
|
|
|
|
* Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
|
|
|
|
*
|
|
|
|
* Portions based on wistron_btns.c:
|
|
|
|
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
|
|
|
|
* Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
|
|
|
|
* Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _ASUS_WMI_H_
|
|
|
|
#define _ASUS_WMI_H_
|
|
|
|
|
|
|
|
#include <linux/platform_device.h>
|
platform/x86: asus-wmi: Filter buggy scan codes on ASUS Q500A
Some revisions of the ASUS Q500A series have a keyboard related
issue which is reproducible only after Windows with installed ASUS
tools is started.
In this case the Linux side will have a blocked keyboard or
report incorrect or incomplete hotkey events.
To make Linux work properly again, a complete power down
(unplug power supply and remove battery) is needed.
Linux/atkbd after a clean start will get the following code on VOLUME_UP
key: {0xe0, 0x30, 0xe0, 0xb0}. After Windows, the same key will generate
this codes: {0xe1, 0x23, 0xe0, 0x30, 0xe0, 0xb0}. As result atkdb will
be confused by buggy codes.
This patch is filtering this buggy code out.
https://bugzilla.kernel.org/show_bug.cgi?id=119391
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Cc: Alex Henrie <alexhenrie24@gmail.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Corentin Chary <corentin.chary@gmail.com>
Cc: acpi4asus-user@lists.sourceforge.net
Cc: platform-driver-x86@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
[dvhart: Add return after pr_warn to avoid false confirmation of filter]
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
2016-09-12 23:48:17 +08:00
|
|
|
#include <linux/i8042.h>
|
2011-02-26 17:20:31 +08:00
|
|
|
|
2011-07-01 17:34:27 +08:00
|
|
|
#define ASUS_WMI_KEY_IGNORE (-1)
|
2012-11-29 16:12:38 +08:00
|
|
|
#define ASUS_WMI_BRN_DOWN 0x20
|
|
|
|
#define ASUS_WMI_BRN_UP 0x2f
|
2011-07-01 17:34:27 +08:00
|
|
|
|
2011-02-26 17:20:31 +08:00
|
|
|
struct module;
|
|
|
|
struct key_entry;
|
|
|
|
struct asus_wmi;
|
|
|
|
|
2012-03-20 16:53:08 +08:00
|
|
|
struct quirk_entry {
|
|
|
|
bool hotplug_wireless;
|
|
|
|
bool scalar_panel_brightness;
|
asus-wmi: store backlight power status for AIO machine
Due to some implementation reasons, ASUS ET2012 All-in-One machines
can't report the correct backlight power status, it will always return
1. To track the backlight power status correctly, we have to store the
status by ourselves.
BTW, by the BIOS design, the backlight power will be turn on/off
sequently, no matter what the value of the parameter will be.
More over, the brightness adjustment command will turn on the backlight
power. Those behaviors will make us fail to track the backlight power
status.
For example, While we are trying to turn on the backlight power,
we will send out the brightness adjustment command and then trying to
figure out if we have to turn on the backlight power, then send out
the command. But, the real case is that, the backlight power turns on
while sending the brightness adjustment command, and then we send out
the command to turn on the backlight power, it actually will turn off
the backlight power and the backlight power status we recorded becomes
wrong. So, we have to seperate these two commands by a if statement.
Signed-off-by: AceLan Kao <acelan.kao@canonical.com>
Signed-off-by: Corentin Chary <corentin.chary@gmail.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
2012-03-20 16:53:09 +08:00
|
|
|
bool store_backlight_power;
|
2012-06-13 15:32:06 +08:00
|
|
|
bool wmi_backlight_power;
|
2016-08-28 16:12:06 +08:00
|
|
|
bool wmi_backlight_native;
|
2019-06-12 15:02:02 +08:00
|
|
|
bool wmi_backlight_set_devstate;
|
2017-04-28 22:19:49 +08:00
|
|
|
bool wmi_force_als_set;
|
2020-09-16 22:14:39 +08:00
|
|
|
bool use_kbd_dock_devid;
|
2012-03-20 16:53:10 +08:00
|
|
|
int wapf;
|
asus-wmi: add display toggle quirk
For machines with AMD graphic chips, it will send out WMI event and ACPI
interrupt at the same time while hitting the hotkey. BIOS will notify the
system the next display output mode throught WMI event code, so that
windows' application can show an OSD to tell the user which mode will be
taken effect. User can hit the display toggle key many times within 2
seconds to choose the mode they want. After 2 seconds, WMI dirver should
send a WMIMethod(SDSP) command to tell the BIOS which mode the user chose.
And then BIOS will raise another ACPI interrupt to tell the system to
really switch the display mode.
In Linux desktop, we don't have this kind of OSD to let users to choose
the mode they want, so we don't need to call WMIMethod(SDSP) to have
another ACPI interrupt. To simplify the problem, we just have to ignore
the WMI event, and let the first ACPI interrupt to send out the key event.
For the need, here comes another quirk to add machines with this kind of
behavior. When the WMI driver receives the display toggle WMI event, and
found the machin is in the list, it will do nothing and let ACPI video
driver to report the key event.
Signed-off-by: AceLan Kao <acelan.kao@canonical.com>
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
2012-10-03 17:26:31 +08:00
|
|
|
/*
|
|
|
|
* For machines with AMD graphic chips, it will send out WMI event
|
|
|
|
* and ACPI interrupt at the same time while hitting the hotkey.
|
|
|
|
* To simplify the problem, we just have to ignore the WMI event,
|
|
|
|
* and let the ACPI interrupt to send out the key event.
|
|
|
|
*/
|
|
|
|
int no_display_toggle;
|
platform/x86: asus-wmi: Set specified XUSB2PR value for X550LB
The bluetooth adapter Atheros AR3012 can't be enumerated
and make the bluetooth function broken.
T: Bus=02 Lev=01 Prnt=01 Port=05 Cnt=02 Dev#= 5 Spd=12 MxCh= 0
D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=13d3 ProdID=3362 Rev=00.02
S: Manufacturer=Atheros Communications
S: Product=Bluetooth USB Host Controller
S: SerialNumber=Alaska Day 2006
C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA
I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
The error is:
usb 2-6: device not accepting address 7, error -62
usb usb2-port6: unable to enumerate USB device
It is caused by adapter's connected port is mapped to xHC
controller, but the xHCI is not supported by the usb device.
The output of 'sudo lspci -nnxxx -s 00:14.0':
00:14.0 USB controller [0c03]: Intel Corporation 8 Series USB xHCI HC [8086:9c31] (rev 04)
00: 86 80 31 9c 06 04 90 02 04 30 03 0c 00 00 00 00
10: 04 00 a0 f7 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 43 10 1f 20
30: 00 00 00 00 70 00 00 00 00 00 00 00 0b 01 00 00
40: fd 01 36 80 89 c6 0f 80 00 00 00 00 00 00 00 00
50: 5f 2e ce 0f 00 00 00 00 00 00 00 00 00 00 00 00
60: 30 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 01 80 c2 c1 08 00 00 00 00 00 00 00 00 00 00 00
80: 05 00 87 00 0c a0 e0 fe 00 00 00 00 a1 41 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 01 04 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 0f 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 03 c0 30 00 00 00 00 00 03 0c 00 00 00 00 00 00
d0: f9 01 00 00 f9 01 00 00 0f 00 00 00 0f 00 00 00
e0: 00 08 00 00 00 00 00 00 00 00 00 00 d8 d8 00 00
f0: 00 00 00 00 00 00 00 00 b1 0f 04 08 00 00 00 00
By referencing Intel Platform Controller Hub(PCH) datasheet,
the xHC USB 2.0 Port Routing(XUSB2PR) at offset 0xD0-0xD3h
decides the setting of mapping the port to EHCI controller or
xHC controller. And the port mapped to xHC will enable xHCI
during bus resume.
The setting of disabling bluetooth adapter's connected port is
0x000001D9. The value can be obtained by few times 1 bit flip
operation. The suited configuration should have the 'lsusb -t'
result with bluetooth using ehci:
/: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/9p, 480M
|__ Port 5: Dev 2, If 0, Class=Video, Driver=uvcvideo, 480M
|__ Port 5: Dev 2, If 1, Class=Video, Driver=uvcvideo, 480M
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M
|__ Port 6: Dev 3, If 0, Class=Wireless, Driver=btusb, 12M
|__ Port 6: Dev 3, If 1, Class=Wireless, Driver=btusb, 12M
Signed-off-by: Kai-Chuan Hsieh <kai.chiuan@gmail.com>
Acked-by: Corentin Chary <corentin.chary@gmail.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
[andy: resolve merge conflict in asus-wmi.h]
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
2016-09-01 23:55:55 +08:00
|
|
|
u32 xusb2pr;
|
platform/x86: asus-wmi: Filter buggy scan codes on ASUS Q500A
Some revisions of the ASUS Q500A series have a keyboard related
issue which is reproducible only after Windows with installed ASUS
tools is started.
In this case the Linux side will have a blocked keyboard or
report incorrect or incomplete hotkey events.
To make Linux work properly again, a complete power down
(unplug power supply and remove battery) is needed.
Linux/atkbd after a clean start will get the following code on VOLUME_UP
key: {0xe0, 0x30, 0xe0, 0xb0}. After Windows, the same key will generate
this codes: {0xe1, 0x23, 0xe0, 0x30, 0xe0, 0xb0}. As result atkdb will
be confused by buggy codes.
This patch is filtering this buggy code out.
https://bugzilla.kernel.org/show_bug.cgi?id=119391
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Cc: Alex Henrie <alexhenrie24@gmail.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Corentin Chary <corentin.chary@gmail.com>
Cc: acpi4asus-user@lists.sourceforge.net
Cc: platform-driver-x86@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
[dvhart: Add return after pr_warn to avoid false confirmation of filter]
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
2016-09-12 23:48:17 +08:00
|
|
|
|
|
|
|
bool (*i8042_filter)(unsigned char data, unsigned char str,
|
|
|
|
struct serio *serio);
|
2012-03-20 16:53:08 +08:00
|
|
|
};
|
|
|
|
|
2011-02-26 17:20:31 +08:00
|
|
|
struct asus_wmi_driver {
|
2012-03-20 16:53:08 +08:00
|
|
|
int brightness;
|
asus-wmi: store backlight power status for AIO machine
Due to some implementation reasons, ASUS ET2012 All-in-One machines
can't report the correct backlight power status, it will always return
1. To track the backlight power status correctly, we have to store the
status by ourselves.
BTW, by the BIOS design, the backlight power will be turn on/off
sequently, no matter what the value of the parameter will be.
More over, the brightness adjustment command will turn on the backlight
power. Those behaviors will make us fail to track the backlight power
status.
For example, While we are trying to turn on the backlight power,
we will send out the brightness adjustment command and then trying to
figure out if we have to turn on the backlight power, then send out
the command. But, the real case is that, the backlight power turns on
while sending the brightness adjustment command, and then we send out
the command to turn on the backlight power, it actually will turn off
the backlight power and the backlight power status we recorded becomes
wrong. So, we have to seperate these two commands by a if statement.
Signed-off-by: AceLan Kao <acelan.kao@canonical.com>
Signed-off-by: Corentin Chary <corentin.chary@gmail.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
2012-03-20 16:53:09 +08:00
|
|
|
int panel_power;
|
asus-wmi: record wlan status while controlled by userapp
If the user bit is set, that mean BIOS can't set and record the wlan
status, it will report the value read from id ASUS_WMI_DEVID_WLAN_LED
(0x00010012) while we query the wlan status by id ASUS_WMI_DEVID_WLAN
(0x00010011) through WMI.
So, we have to record wlan status in id ASUS_WMI_DEVID_WLAN_LED
(0x00010012) while setting the wlan status through WMI.
This is also the behavior that windows app will do.
Quote from ASUS application engineer
===
When you call WMIMethod(DSTS, 0x00010011) to get WLAN status, it may return
(1) 0x00050001 (On)
(2) 0x00050000 (Off)
(3) 0x00030001 (On)
(4) 0x00030000 (Off)
(5) 0x00000002 (Unknown)
(1), (2) means that the model has hardware GPIO for WLAN, you can call
WMIMethod(DEVS, 0x00010011, 1 or 0) to turn WLAN on/off.
(3), (4) means that the model doesn’t have hardware GPIO, you need to use
API or driver library to turn WLAN on/off, and call
WMIMethod(DEVS, 0x00010012, 1 or 0) to set WLAN LED status.
After you set WLAN LED status, you can see the WLAN status is changed with
WMIMethod(DSTS, 0x00010011). Because the status is recorded lastly
(ex: Windows), you can use it for synchronization.
(5) means that the model doesn’t have WLAN device.
WLAN is the ONLY special case with upper rule.
For other device, like Bluetooth, you just need use
WMIMethod(DSTS, 0x00010013) to get, and WMIMethod(DEVS, 0x00010013, 1 or 0)
to set.
===
Signed-off-by: AceLan Kao <acelan.kao@canonical.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
2012-07-26 17:13:31 +08:00
|
|
|
int wlan_ctrl_by_user;
|
2011-02-26 17:20:31 +08:00
|
|
|
|
|
|
|
const char *name;
|
|
|
|
struct module *owner;
|
|
|
|
|
|
|
|
const char *event_guid;
|
|
|
|
|
|
|
|
const struct key_entry *keymap;
|
|
|
|
const char *input_name;
|
|
|
|
const char *input_phys;
|
2012-03-20 16:53:08 +08:00
|
|
|
struct quirk_entry *quirks;
|
2011-07-01 17:34:27 +08:00
|
|
|
/* Returns new code, value, and autorelease values in arguments.
|
|
|
|
* Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */
|
|
|
|
void (*key_filter) (struct asus_wmi_driver *driver, int *code,
|
|
|
|
unsigned int *value, bool *autorelease);
|
2011-02-26 17:20:31 +08:00
|
|
|
|
|
|
|
int (*probe) (struct platform_device *device);
|
2012-03-20 16:53:08 +08:00
|
|
|
void (*detect_quirks) (struct asus_wmi_driver *driver);
|
2011-02-26 17:20:31 +08:00
|
|
|
|
|
|
|
struct platform_driver platform_driver;
|
|
|
|
struct platform_device *platform_device;
|
|
|
|
};
|
|
|
|
|
|
|
|
int asus_wmi_register_driver(struct asus_wmi_driver *driver);
|
|
|
|
void asus_wmi_unregister_driver(struct asus_wmi_driver *driver);
|
|
|
|
|
|
|
|
#endif /* !_ASUS_WMI_H_ */
|