platform-drivers-x86 for v4.13-1
Introduce new bus architecture for WMI and expose BMOF data through sysfs. Correct several assumptions about WMI instance number from 1 to 0. Further fujitsu-laptop cleanups, continuing to prepare for separation into two modules. Add support for several new ideapad laptops and silead-based tablets. Various minor fixes and const cleanups. sony-laptop: - constify attribute_group and input index array fujitsu-laptop: - rework debugging - do not evaluate ACPI _INI methods - do not update ACPI device power status - sanitize hotkey input device identification - use strcpy to set ACPI device names and classes - remove redundant safety checks - use device-specific data in remaining module code - use device-specific data in LED-related code - explicitly pass ACPI device to call_fext_func() - track the last instantiated FUJ02E3 ACPI device - allocate fujitsu_laptop in acpi_fujitsu_laptop_add() - use device-specific data in backlight code - allocate fujitsu_bl in acpi_fujitsu_bl_add() - distinguish current uses of device-specific data msi-laptop: - constify msipf*_attribute_group eeepc-laptop: - constify platform_attribute_group toshiba_haps: - constify haps_attr_group dell-wmi-led: - Adjust instance of wmi_evaluate_method calls to 0 alienware-wmi: - Adjust instance of wmi_evaluate_method calls to 0 intel_menlow: - Add const to thermal_cooling_device_ops structure acerhdf: - Add const to thermal_cooling_device_ops structure dell-laptop: - Fix bogus keyboard backlight sysfs interface acer-wmi: - Using zero as first WMI instance number - Detect RF Button capability ideapad-laptop: - Add Y720-15IKBN to no_hw_rfkill - Add Y520-15IKBN to no_hw_rfkill - constify rfkill_ops structure - Squelch ACPI event 1 - hide unused 'touchpad_store' - Switch touchpad attribute to be RO - Add sysfs interface for touchpad state silead_dmi: - Add touchscreen info for PoV mobii wintab p800w - Add touchscreen info for Pipo W2S tablet - Add touchscreen info for GP-electronic T701 dell-rbtn: - constify rfkill_ops structures - Improve explanation about DELLABC6 samsung-laptop: - constify rfkill_ops structures panasonic-laptop: - remove unused code samsung-laptop: - Initialize loca variable dell-wmi: - Convert to the WMI bus infrastructure - Add a better description for "stealth mode" - Add a comment explaining the 0xb2 magic number wmi-bmof: - New driver to expose embedded Binary WMI MOF metadata wmi*: - Fix printing info about WDG structure - Add recent copyright statements - Require query for data blocks, rename writable to setable - Add an interface for subdrivers to access sibling devices - Bind the platform device, not the ACPI node - Add a new interface to read block data - Incorporate acpi_install_notify_handler - Instantiate all devices before adding them - Probe data objects for read and write capabilities - Split devices into types and add basic sysfs attributes - Fix error handling when creating devices - Turn WMI into a bus driver - Track wmi devices per ACPI device - Clean up acpi_wmi_add - Pass the acpi_device through to parse_wdg - Drop "Mapper (un)loaded" messages intel_cht_int33fe: - Set supplied-from property on max17047 dev intel_pmc_ipc: - Mark ipc_data_readb() as __maybe_unused topstar-laptop: - Add new device id peaq-wmi: - Add new peaq-wmi driver thinkpad_acpi: - Add a comment about 0 in module_param_call() - Join string literals back toshiba_acpi: - use memdup_user_nul -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJZXSzcAAoJEKbMaAwKp364hSEIAKC0xJRZWv1aI1f69JCSZR0+ 5/6tMsps9nK4LtaKQCvPHeOCxmwpE4tZYzyuYHyHW+pfUMquIdRVQRMe3u2FTrKS HuvCgmYAkZqCzy/zQIPaVU2K9m7/9HubXYy0Q1qkjlGZp/IYMFoeo7DU65Ajm+HS wrRXIYIKSbjAU0pmzW//MFauEi26MWpAHMraw+HCJbXcGwhokSrtTYitqFpQXnhJ kdguSkEluW1NoG3Tv7CbfXWXge7zwxlrmI06b4FtkpFK6b2LCZcYeUhIn33yNYT1 IwhNOsaWlxNw3K3c1IRZSwYoJ6dmBJ+cxmZ0sd3cr8jahgpHB/nJiRElHmTdf2M= =PbWU -----END PGP SIGNATURE----- Merge tag 'platform-drivers-x86-v4.13-1' of git://git.infradead.org/linux-platform-drivers-x86 Pull x86 platform driver updates from Darren Hart: "Introduce new bus architecture for WMI and expose BMOF data through sysfs. Correct several assumptions about WMI instance number from 1 to 0. Further fujitsu-laptop cleanups, continuing to prepare for separation into two modules. Add support for several new ideapad laptops and silead-based tablets. Various minor fixes and const cleanups. Detail summary: sony-laptop: - constify attribute_group and input index array fujitsu-laptop: - rework debugging - do not evaluate ACPI _INI methods - do not update ACPI device power status - sanitize hotkey input device identification - use strcpy to set ACPI device names and classes - remove redundant safety checks - use device-specific data in remaining module code - use device-specific data in LED-related code - explicitly pass ACPI device to call_fext_func() - track the last instantiated FUJ02E3 ACPI device - allocate fujitsu_laptop in acpi_fujitsu_laptop_add() - use device-specific data in backlight code - allocate fujitsu_bl in acpi_fujitsu_bl_add() - distinguish current uses of device-specific data msi-laptop: - constify msipf*_attribute_group eeepc-laptop: - constify platform_attribute_group toshiba_haps: - constify haps_attr_group dell-wmi-led: - Adjust instance of wmi_evaluate_method calls to 0 alienware-wmi: - Adjust instance of wmi_evaluate_method calls to 0 intel_menlow: - Add const to thermal_cooling_device_ops structure acerhdf: - Add const to thermal_cooling_device_ops structure dell-laptop: - Fix bogus keyboard backlight sysfs interface acer-wmi: - Using zero as first WMI instance number - Detect RF Button capability ideapad-laptop: - Add Y720-15IKBN to no_hw_rfkill - Add Y520-15IKBN to no_hw_rfkill - constify rfkill_ops structure - Squelch ACPI event 1 - hide unused 'touchpad_store' - Switch touchpad attribute to be RO - Add sysfs interface for touchpad state silead_dmi: - Add touchscreen info for PoV mobii wintab p800w - Add touchscreen info for Pipo W2S tablet - Add touchscreen info for GP-electronic T701 dell-rbtn: - constify rfkill_ops structures - Improve explanation about DELLABC6 samsung-laptop: - constify rfkill_ops structures panasonic-laptop: - remove unused code samsung-laptop: - Initialize loca variable dell-wmi: - Convert to the WMI bus infrastructure - Add a better description for "stealth mode" - Add a comment explaining the 0xb2 magic number wmi-bmof: - New driver to expose embedded Binary WMI MOF metadata wmi*: - Fix printing info about WDG structure - Add recent copyright statements - Require query for data blocks, rename writable to setable - Add an interface for subdrivers to access sibling devices - Bind the platform device, not the ACPI node - Add a new interface to read block data - Incorporate acpi_install_notify_handler - Instantiate all devices before adding them - Probe data objects for read and write capabilities - Split devices into types and add basic sysfs attributes - Fix error handling when creating devices - Turn WMI into a bus driver - Track wmi devices per ACPI device - Clean up acpi_wmi_add - Pass the acpi_device through to parse_wdg - Drop "Mapper (un)loaded" messages intel_cht_int33fe: - Set supplied-from property on max17047 dev intel_pmc_ipc: - Mark ipc_data_readb() as __maybe_unused topstar-laptop: - Add new device id peaq-wmi: - Add new peaq-wmi driver thinkpad_acpi: - Add a comment about 0 in module_param_call() - Join string literals back toshiba_acpi: - use memdup_user_nul" * tag 'platform-drivers-x86-v4.13-1' of git://git.infradead.org/linux-platform-drivers-x86: (67 commits) platform/x86: sony-laptop: constify attribute_group and input index array platform/x86: fujitsu-laptop: rework debugging platform/x86: fujitsu-laptop: do not evaluate ACPI _INI methods platform/x86: fujitsu-laptop: do not update ACPI device power status platform/x86: fujitsu-laptop: sanitize hotkey input device identification platform/x86: fujitsu-laptop: use strcpy to set ACPI device names and classes platform/x86: fujitsu-laptop: remove redundant safety checks platform/x86: msi-laptop: constify msipf*_attribute_group platform/x86: eeepc-laptop: constify platform_attribute_group platform/x86: toshiba_haps: constify haps_attr_group platform/x86: dell-wmi-led: Adjust instance of wmi_evaluate_method calls to 0 platform/x86: alienware-wmi: Adjust instance of wmi_evaluate_method calls to 0 platform/x86: intel_menlow: Add const to thermal_cooling_device_ops structure platform/x86: acerhdf: Add const to thermal_cooling_device_ops structure platform/x86: dell-laptop: Fix bogus keyboard backlight sysfs interface platform/x86: acer-wmi: Using zero as first WMI instance number platform/x86: ideapad-laptop: Add Y720-15IKBN to no_hw_rfkill platform/x86: ideapad-laptop: Add Y520-15IKBN to no_hw_rfkill platform/x86: silead_dmi: Add touchscreen info for PoV mobii wintab p800w platform/x86: silead_dmi: Add touchscreen info for Pipo W2S tablet ...
This commit is contained in:
Коммит
0dfaeb618f
|
@ -17,3 +17,11 @@ Description:
|
|||
* 2 -> Dust Cleaning
|
||||
* 4 -> Efficient Thermal Dissipation Mode
|
||||
|
||||
What: /sys/devices/platform/ideapad/touchpad
|
||||
Date: May 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: "Ritesh Raj Sarraf <rrs@debian.org>"
|
||||
Description:
|
||||
Control touchpad mode.
|
||||
* 1 -> Switched On
|
||||
* 0 -> Switched Off
|
||||
|
|
|
@ -195,16 +195,6 @@ config FUJITSU_LAPTOP
|
|||
|
||||
If you have a Fujitsu laptop, say Y or M here.
|
||||
|
||||
config FUJITSU_LAPTOP_DEBUG
|
||||
bool "Verbose debug mode for Fujitsu Laptop Extras"
|
||||
depends on FUJITSU_LAPTOP
|
||||
default n
|
||||
---help---
|
||||
Enables extra debug output from the fujitsu extras driver, at the
|
||||
expense of a slight increase in driver size.
|
||||
|
||||
If you are not sure, say N here.
|
||||
|
||||
config FUJITSU_TABLET
|
||||
tristate "Fujitsu Tablet Extras"
|
||||
depends on ACPI
|
||||
|
@ -656,6 +646,18 @@ config ACPI_WMI
|
|||
It is safe to enable this driver even if your DSDT doesn't define
|
||||
any ACPI-WMI devices.
|
||||
|
||||
config WMI_BMOF
|
||||
tristate "WMI embedded Binary MOF driver"
|
||||
depends on ACPI_WMI
|
||||
default ACPI_WMI
|
||||
---help---
|
||||
Say Y here if you want to be able to read a firmware-embedded
|
||||
WMI Binary MOF data. Using this requires userspace tools and may be
|
||||
rather tedious.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called wmi-bmof.
|
||||
|
||||
config MSI_WMI
|
||||
tristate "MSI WMI extras"
|
||||
depends on ACPI_WMI
|
||||
|
@ -669,6 +671,13 @@ config MSI_WMI
|
|||
To compile this driver as a module, choose M here: the module will
|
||||
be called msi-wmi.
|
||||
|
||||
config PEAQ_WMI
|
||||
tristate "PEAQ 2-in-1 WMI hotkey driver"
|
||||
depends on ACPI_WMI
|
||||
depends on INPUT
|
||||
help
|
||||
Say Y here if you want to support WMI-based hotkeys on PEAQ 2-in-1s.
|
||||
|
||||
config TOPSTAR_LAPTOP
|
||||
tristate "Topstar Laptop Extras"
|
||||
depends on ACPI
|
||||
|
|
|
@ -35,8 +35,10 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
|
|||
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
|
||||
obj-$(CONFIG_ACPI_WMI) += wmi.o
|
||||
obj-$(CONFIG_MSI_WMI) += msi-wmi.o
|
||||
obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o
|
||||
obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
|
||||
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
|
||||
obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o
|
||||
|
||||
# toshiba_acpi must link after wmi to ensure that wmi devices are found
|
||||
# before toshiba_acpi initializes
|
||||
|
|
|
@ -149,6 +149,8 @@ struct event_return_value {
|
|||
#define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */
|
||||
#define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */
|
||||
#define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */
|
||||
#define ACER_WMID3_GDS_RFBTN (1<<14) /* RF Button */
|
||||
|
||||
#define ACER_WMID3_GDS_TOUCHPAD (1<<1) /* Touchpad */
|
||||
|
||||
/* Hotkey Customized Setting and Acer Application Status.
|
||||
|
@ -221,6 +223,7 @@ struct hotkey_function_type_aa {
|
|||
#define ACER_CAP_BRIGHTNESS (1<<3)
|
||||
#define ACER_CAP_THREEG (1<<4)
|
||||
#define ACER_CAP_ACCEL (1<<5)
|
||||
#define ACER_CAP_RFBTN (1<<6)
|
||||
#define ACER_CAP_ANY (0xFFFFFFFF)
|
||||
|
||||
/*
|
||||
|
@ -700,7 +703,7 @@ struct acpi_buffer *result)
|
|||
input.length = sizeof(struct wmab_args);
|
||||
input.pointer = (u8 *)regbuf;
|
||||
|
||||
status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
|
||||
status = wmi_evaluate_method(AMW0_GUID1, 0, 1, &input, result);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -965,7 +968,7 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out)
|
|||
u32 tmp = 0;
|
||||
acpi_status status;
|
||||
|
||||
status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
|
||||
status = wmi_evaluate_method(WMID_GUID1, 0, method_id, &input, &result);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
@ -1264,6 +1267,10 @@ static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
|
|||
interface->capability |= ACER_CAP_THREEG;
|
||||
if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
|
||||
interface->capability |= ACER_CAP_BLUETOOTH;
|
||||
if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN) {
|
||||
interface->capability |= ACER_CAP_RFBTN;
|
||||
commun_func_bitmap &= ~ACER_WMID3_GDS_RFBTN;
|
||||
}
|
||||
|
||||
commun_fn_key_number = type_aa->commun_fn_key_number;
|
||||
}
|
||||
|
@ -1275,7 +1282,7 @@ static acpi_status __init WMID_set_capabilities(void)
|
|||
acpi_status status;
|
||||
u32 devices;
|
||||
|
||||
status = wmi_query_block(WMID_GUID2, 1, &out);
|
||||
status = wmi_query_block(WMID_GUID2, 0, &out);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
|
@ -2018,7 +2025,7 @@ static u32 get_wmid_devices(void)
|
|||
acpi_status status;
|
||||
u32 devices = 0;
|
||||
|
||||
status = wmi_query_block(WMID_GUID2, 1, &out);
|
||||
status = wmi_query_block(WMID_GUID2, 0, &out);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -557,7 +557,7 @@ err_out:
|
|||
}
|
||||
|
||||
/* bind fan callbacks to fan device */
|
||||
static struct thermal_cooling_device_ops acerhdf_cooling_ops = {
|
||||
static const struct thermal_cooling_device_ops acerhdf_cooling_ops = {
|
||||
.get_max_state = acerhdf_get_max_state,
|
||||
.get_cur_state = acerhdf_get_cur_state,
|
||||
.set_cur_state = acerhdf_set_cur_state,
|
||||
|
|
|
@ -303,7 +303,7 @@ static int alienware_update_led(struct platform_zone *zone)
|
|||
}
|
||||
pr_debug("alienware-wmi: guid %s method %d\n", guid, method_id);
|
||||
|
||||
status = wmi_evaluate_method(guid, 1, method_id, &input, NULL);
|
||||
status = wmi_evaluate_method(guid, 0, method_id, &input, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_err("alienware-wmi: zone set failure: %u\n", status);
|
||||
return ACPI_FAILURE(status);
|
||||
|
@ -352,7 +352,7 @@ static int wmax_brightness(int brightness)
|
|||
};
|
||||
input.length = (acpi_size) sizeof(args);
|
||||
input.pointer = &args;
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
|
||||
WMAX_METHOD_BRIGHTNESS, &input, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_err("alienware-wmi: brightness set failure: %u\n", status);
|
||||
|
@ -506,10 +506,10 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args,
|
|||
if (out_data != NULL) {
|
||||
output.length = ACPI_ALLOCATE_BUFFER;
|
||||
output.pointer = NULL;
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
|
||||
command, &input, &output);
|
||||
} else
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
|
||||
command, &input, NULL);
|
||||
|
||||
if (ACPI_SUCCESS(status) && out_data != NULL) {
|
||||
|
|
|
@ -1510,7 +1510,11 @@ static void kbd_init(void)
|
|||
ret = kbd_init_info();
|
||||
kbd_init_tokens();
|
||||
|
||||
if (kbd_token_bits != 0 || ret == 0)
|
||||
/*
|
||||
* Only supports keyboard backlight when it has at least two modes.
|
||||
*/
|
||||
if ((ret == 0 && (kbd_info.levels != 0 || kbd_mode_levels_count >= 2))
|
||||
|| kbd_get_valid_token_counts() >= 2)
|
||||
kbd_led_present = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ static int rbtn_rfkill_set_block(void *data, bool blocked)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct rfkill_ops rbtn_ops = {
|
||||
static const struct rfkill_ops rbtn_ops = {
|
||||
.query = rbtn_rfkill_query,
|
||||
.set_block = rbtn_rfkill_set_block,
|
||||
};
|
||||
|
@ -221,16 +221,27 @@ static const struct acpi_device_id rbtn_ids[] = {
|
|||
|
||||
/*
|
||||
* This driver can also handle the "DELLABC6" device that
|
||||
* appears on the XPS 13 9350, but that device is disabled
|
||||
* by the DSDT unless booted with acpi_osi="!Windows 2012"
|
||||
* acpi_osi="!Windows 2013". Even if we boot that and bind
|
||||
* the driver, we seem to have inconsistent behavior in
|
||||
* which NetworkManager can get out of sync with the rfkill
|
||||
* state.
|
||||
* appears on the XPS 13 9350, but that device is disabled by
|
||||
* the DSDT unless booted with acpi_osi="!Windows 2012"
|
||||
* acpi_osi="!Windows 2013".
|
||||
*
|
||||
* On the XPS 13 9350 and similar laptops, we're not supposed to
|
||||
* use DELLABC6 at all. Instead, we handle the rfkill button
|
||||
* via the intel-hid driver.
|
||||
* According to Mario at Dell:
|
||||
*
|
||||
* DELLABC6 is a custom interface that was created solely to
|
||||
* have airplane mode support for Windows 7. For Windows 10
|
||||
* the proper interface is to use that which is handled by
|
||||
* intel-hid. A OEM airplane mode driver is not used.
|
||||
*
|
||||
* Since the kernel doesn't identify as Windows 7 it would be
|
||||
* incorrect to do attempt to use that interface.
|
||||
*
|
||||
* Even if we override _OSI and bind to DELLABC6, we end up with
|
||||
* inconsistent behavior in which userspace can get out of sync
|
||||
* with the rfkill state as it conflicts with events from
|
||||
* intel-hid.
|
||||
*
|
||||
* The upshot is that it is better to just ignore DELLABC6
|
||||
* devices.
|
||||
*/
|
||||
|
||||
{ "", 0 },
|
||||
|
|
|
@ -68,7 +68,7 @@ static int dell_led_perform_fn(u8 length, u8 result_code, u8 device_id,
|
|||
input.length = sizeof(struct bios_args);
|
||||
input.pointer = &args;
|
||||
|
||||
status = wmi_evaluate_method(DELL_LED_BIOS_GUID, 1, 1, &input, &output);
|
||||
status = wmi_evaluate_method(DELL_LED_BIOS_GUID, 0, 1, &input, &output);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/wmi.h>
|
||||
#include <acpi/video.h>
|
||||
#include "dell-smbios.h"
|
||||
|
||||
|
@ -53,6 +54,10 @@ static bool wmi_requires_smbios_request;
|
|||
MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
|
||||
MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID);
|
||||
|
||||
struct dell_wmi_priv {
|
||||
struct input_dev *input_dev;
|
||||
};
|
||||
|
||||
static int __init dmi_matched(const struct dmi_system_id *dmi)
|
||||
{
|
||||
wmi_requires_smbios_request = 1;
|
||||
|
@ -86,7 +91,7 @@ static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = {
|
|||
* notifications (rather than requests for change) or are also sent
|
||||
* via the keyboard controller so should not be sent again.
|
||||
*/
|
||||
static const struct key_entry dell_wmi_keymap_type_0000[] __initconst = {
|
||||
static const struct key_entry dell_wmi_keymap_type_0000[] = {
|
||||
{ KE_IGNORE, 0x003a, { KEY_CAPSLOCK } },
|
||||
|
||||
/* Key code is followed by brightness level */
|
||||
|
@ -207,7 +212,7 @@ struct dell_dmi_results {
|
|||
};
|
||||
|
||||
/* Uninitialized entries here are KEY_RESERVED == 0. */
|
||||
static const u16 bios_to_linux_keycode[256] __initconst = {
|
||||
static const u16 bios_to_linux_keycode[256] = {
|
||||
[0] = KEY_MEDIA,
|
||||
[1] = KEY_NEXTSONG,
|
||||
[2] = KEY_PLAYPAUSE,
|
||||
|
@ -256,7 +261,7 @@ static const u16 bios_to_linux_keycode[256] __initconst = {
|
|||
* These are applied if the 0xB2 DMI hotkey table is present and doesn't
|
||||
* override them.
|
||||
*/
|
||||
static const struct key_entry dell_wmi_keymap_type_0010[] __initconst = {
|
||||
static const struct key_entry dell_wmi_keymap_type_0010[] = {
|
||||
/* Fn-lock */
|
||||
{ KE_IGNORE, 0x151, { KEY_RESERVED } },
|
||||
|
||||
|
@ -272,7 +277,12 @@ static const struct key_entry dell_wmi_keymap_type_0010[] __initconst = {
|
|||
/* RGB keyboard backlight control */
|
||||
{ KE_IGNORE, 0x154, { KEY_RESERVED } },
|
||||
|
||||
/* Stealth mode toggle */
|
||||
/*
|
||||
* Stealth mode toggle. This will "disable all lights and sounds".
|
||||
* The action is performed by the BIOS and EC; the WMI event is just
|
||||
* a notification. On the XPS 13 9350, this is Fn+F7, and there's
|
||||
* a BIOS setting to enable and disable the hotkey.
|
||||
*/
|
||||
{ KE_IGNORE, 0x155, { KEY_RESERVED } },
|
||||
|
||||
/* Rugged magnetic dock attach/detach events */
|
||||
|
@ -289,7 +299,7 @@ static const struct key_entry dell_wmi_keymap_type_0010[] __initconst = {
|
|||
/*
|
||||
* Keymap for WMI events of type 0x0011
|
||||
*/
|
||||
static const struct key_entry dell_wmi_keymap_type_0011[] __initconst = {
|
||||
static const struct key_entry dell_wmi_keymap_type_0011[] = {
|
||||
/* Battery unplugged */
|
||||
{ KE_IGNORE, 0xfff0, { KEY_RESERVED } },
|
||||
|
||||
|
@ -304,13 +314,12 @@ static const struct key_entry dell_wmi_keymap_type_0011[] __initconst = {
|
|||
{ KE_IGNORE, 0x02f6, { KEY_RESERVED } },
|
||||
};
|
||||
|
||||
static struct input_dev *dell_wmi_input_dev;
|
||||
|
||||
static void dell_wmi_process_key(int type, int code)
|
||||
static void dell_wmi_process_key(struct wmi_device *wdev, int type, int code)
|
||||
{
|
||||
struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
const struct key_entry *key;
|
||||
|
||||
key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
|
||||
key = sparse_keymap_entry_from_scancode(priv->input_dev,
|
||||
(type << 16) | code);
|
||||
if (!key) {
|
||||
pr_info("Unknown key with type 0x%04x and code 0x%04x pressed\n",
|
||||
|
@ -333,33 +342,18 @@ static void dell_wmi_process_key(int type, int code)
|
|||
dell_laptop_call_notifier(
|
||||
DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED, NULL);
|
||||
|
||||
sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true);
|
||||
sparse_keymap_report_entry(priv->input_dev, key, 1, true);
|
||||
}
|
||||
|
||||
static void dell_wmi_notify(u32 value, void *context)
|
||||
static void dell_wmi_notify(struct wmi_device *wdev,
|
||||
union acpi_object *obj)
|
||||
{
|
||||
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
acpi_size buffer_size;
|
||||
u16 *buffer_entry, *buffer_end;
|
||||
acpi_size buffer_size;
|
||||
int len, i;
|
||||
|
||||
status = wmi_get_event_data(value, &response);
|
||||
if (status != AE_OK) {
|
||||
pr_warn("bad event status 0x%x\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
obj = (union acpi_object *)response.pointer;
|
||||
if (!obj) {
|
||||
pr_warn("no response\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
pr_warn("bad response type %x\n", obj->type);
|
||||
kfree(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -404,13 +398,14 @@ static void dell_wmi_notify(u32 value, void *context)
|
|||
switch (buffer_entry[1]) {
|
||||
case 0x0000: /* One key pressed or event occurred */
|
||||
if (len > 2)
|
||||
dell_wmi_process_key(0x0000, buffer_entry[2]);
|
||||
dell_wmi_process_key(wdev, 0x0000,
|
||||
buffer_entry[2]);
|
||||
/* Other entries could contain additional information */
|
||||
break;
|
||||
case 0x0010: /* Sequence of keys pressed */
|
||||
case 0x0011: /* Sequence of events occurred */
|
||||
for (i = 2; i < len; ++i)
|
||||
dell_wmi_process_key(buffer_entry[1],
|
||||
dell_wmi_process_key(wdev, buffer_entry[1],
|
||||
buffer_entry[i]);
|
||||
break;
|
||||
default: /* Unknown event */
|
||||
|
@ -423,7 +418,6 @@ static void dell_wmi_notify(u32 value, void *context)
|
|||
|
||||
}
|
||||
|
||||
kfree(obj);
|
||||
}
|
||||
|
||||
static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len)
|
||||
|
@ -437,9 +431,7 @@ static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void __init handle_dmi_entry(const struct dmi_header *dm,
|
||||
void *opaque)
|
||||
|
||||
static void handle_dmi_entry(const struct dmi_header *dm, void *opaque)
|
||||
{
|
||||
struct dell_dmi_results *results = opaque;
|
||||
struct dell_bios_hotkey_table *table;
|
||||
|
@ -449,6 +441,7 @@ static void __init handle_dmi_entry(const struct dmi_header *dm,
|
|||
if (results->err || results->keymap)
|
||||
return; /* We already found the hotkey table. */
|
||||
|
||||
/* The Dell hotkey table is type 0xB2. Scan until we find it. */
|
||||
if (dm->type != 0xb2)
|
||||
return;
|
||||
|
||||
|
@ -509,19 +502,20 @@ static void __init handle_dmi_entry(const struct dmi_header *dm,
|
|||
results->keymap_size = pos;
|
||||
}
|
||||
|
||||
static int __init dell_wmi_input_setup(void)
|
||||
static int dell_wmi_input_setup(struct wmi_device *wdev)
|
||||
{
|
||||
struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
struct dell_dmi_results dmi_results = {};
|
||||
struct key_entry *keymap;
|
||||
int err, i, pos = 0;
|
||||
|
||||
dell_wmi_input_dev = input_allocate_device();
|
||||
if (!dell_wmi_input_dev)
|
||||
priv->input_dev = input_allocate_device();
|
||||
if (!priv->input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dell_wmi_input_dev->name = "Dell WMI hotkeys";
|
||||
dell_wmi_input_dev->phys = "wmi/input0";
|
||||
dell_wmi_input_dev->id.bustype = BUS_HOST;
|
||||
priv->input_dev->name = "Dell WMI hotkeys";
|
||||
priv->input_dev->id.bustype = BUS_HOST;
|
||||
priv->input_dev->dev.parent = &wdev->dev;
|
||||
|
||||
if (dmi_walk(handle_dmi_entry, &dmi_results)) {
|
||||
/*
|
||||
|
@ -596,7 +590,7 @@ static int __init dell_wmi_input_setup(void)
|
|||
|
||||
keymap[pos].type = KE_END;
|
||||
|
||||
err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL);
|
||||
err = sparse_keymap_setup(priv->input_dev, keymap, NULL);
|
||||
/*
|
||||
* Sparse keymap library makes a copy of keymap so we don't need the
|
||||
* original one that was allocated.
|
||||
|
@ -605,17 +599,24 @@ static int __init dell_wmi_input_setup(void)
|
|||
if (err)
|
||||
goto err_free_dev;
|
||||
|
||||
err = input_register_device(dell_wmi_input_dev);
|
||||
err = input_register_device(priv->input_dev);
|
||||
if (err)
|
||||
goto err_free_dev;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_dev:
|
||||
input_free_device(dell_wmi_input_dev);
|
||||
input_free_device(priv->input_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void dell_wmi_input_destroy(struct wmi_device *wdev)
|
||||
{
|
||||
struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
|
||||
input_unregister_device(priv->input_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Descriptor buffer is 128 byte long and contains:
|
||||
*
|
||||
|
@ -714,46 +715,55 @@ static int dell_wmi_events_set_enabled(bool enable)
|
|||
return dell_smbios_error(ret);
|
||||
}
|
||||
|
||||
static int dell_wmi_probe(struct wmi_device *wdev)
|
||||
{
|
||||
struct dell_wmi_priv *priv = devm_kzalloc(
|
||||
&wdev->dev, sizeof(struct dell_wmi_priv), GFP_KERNEL);
|
||||
|
||||
dev_set_drvdata(&wdev->dev, priv);
|
||||
|
||||
return dell_wmi_input_setup(wdev);
|
||||
}
|
||||
|
||||
static int dell_wmi_remove(struct wmi_device *wdev)
|
||||
{
|
||||
dell_wmi_input_destroy(wdev);
|
||||
return 0;
|
||||
}
|
||||
static const struct wmi_device_id dell_wmi_id_table[] = {
|
||||
{ .guid_string = DELL_EVENT_GUID },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct wmi_driver dell_wmi_driver = {
|
||||
.driver = {
|
||||
.name = "dell-wmi",
|
||||
},
|
||||
.id_table = dell_wmi_id_table,
|
||||
.probe = dell_wmi_probe,
|
||||
.remove = dell_wmi_remove,
|
||||
.notify = dell_wmi_notify,
|
||||
};
|
||||
|
||||
static int __init dell_wmi_init(void)
|
||||
{
|
||||
int err;
|
||||
acpi_status status;
|
||||
|
||||
if (!wmi_has_guid(DELL_EVENT_GUID) ||
|
||||
!wmi_has_guid(DELL_DESCRIPTOR_GUID)) {
|
||||
pr_warn("Dell WMI GUID were not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = dell_wmi_check_descriptor_buffer();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = dell_wmi_input_setup();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
status = wmi_install_notify_handler(DELL_EVENT_GUID,
|
||||
dell_wmi_notify, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
input_unregister_device(dell_wmi_input_dev);
|
||||
pr_err("Unable to register notify handler - %d\n", status);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dmi_check_system(dell_wmi_smbios_list);
|
||||
|
||||
if (wmi_requires_smbios_request) {
|
||||
err = dell_wmi_events_set_enabled(true);
|
||||
if (err) {
|
||||
pr_err("Failed to enable WMI events\n");
|
||||
wmi_remove_notify_handler(DELL_EVENT_GUID);
|
||||
input_unregister_device(dell_wmi_input_dev);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return wmi_driver_register(&dell_wmi_driver);
|
||||
}
|
||||
module_init(dell_wmi_init);
|
||||
|
||||
|
@ -761,7 +771,7 @@ static void __exit dell_wmi_exit(void)
|
|||
{
|
||||
if (wmi_requires_smbios_request)
|
||||
dell_wmi_events_set_enabled(false);
|
||||
wmi_remove_notify_handler(DELL_EVENT_GUID);
|
||||
input_unregister_device(dell_wmi_input_dev);
|
||||
|
||||
wmi_driver_unregister(&dell_wmi_driver);
|
||||
}
|
||||
module_exit(dell_wmi_exit);
|
||||
|
|
|
@ -445,7 +445,7 @@ static struct attribute *platform_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group platform_attribute_group = {
|
||||
static const struct attribute_group platform_attribute_group = {
|
||||
.attrs = platform_attributes
|
||||
};
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -423,9 +423,43 @@ static ssize_t store_ideapad_fan(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR(fan_mode, 0644, show_ideapad_fan, store_ideapad_fan);
|
||||
|
||||
static ssize_t touchpad_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ideapad_private *priv = dev_get_drvdata(dev);
|
||||
unsigned long result;
|
||||
|
||||
if (read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result))
|
||||
return sprintf(buf, "-1\n");
|
||||
return sprintf(buf, "%lu\n", result);
|
||||
}
|
||||
|
||||
/* Switch to RO for now: It might be revisited in the future */
|
||||
static ssize_t __maybe_unused touchpad_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ideapad_private *priv = dev_get_drvdata(dev);
|
||||
bool state;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(touchpad);
|
||||
|
||||
static struct attribute *ideapad_attributes[] = {
|
||||
&dev_attr_camera_power.attr,
|
||||
&dev_attr_fan_mode.attr,
|
||||
&dev_attr_touchpad.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -478,7 +512,7 @@ static int ideapad_rfk_set(void *data, bool blocked)
|
|||
return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
|
||||
}
|
||||
|
||||
static struct rfkill_ops ideapad_rfk_ops = {
|
||||
static const struct rfkill_ops ideapad_rfk_ops = {
|
||||
.set_block = ideapad_rfk_set,
|
||||
};
|
||||
|
||||
|
@ -810,7 +844,6 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
|
|||
case 8:
|
||||
case 7:
|
||||
case 6:
|
||||
case 1:
|
||||
ideapad_input_report(priv, vpc_bit);
|
||||
break;
|
||||
case 5:
|
||||
|
@ -828,6 +861,13 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
|
|||
case 0:
|
||||
ideapad_check_special_buttons(priv);
|
||||
break;
|
||||
case 1:
|
||||
/* Some IdeaPads report event 1 every ~20
|
||||
* seconds while on battery power; some
|
||||
* report this when changing to/from tablet
|
||||
* mode. Squelch this event.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
pr_info("Unknown event: %lu\n", vpc_bit);
|
||||
}
|
||||
|
@ -910,6 +950,20 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
|
|||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Legion Y520-15IKBN",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Legion Y720-15IKBN",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBN"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Yoga 2 11 / 13 / Pro",
|
||||
.matches = {
|
||||
|
|
|
@ -34,6 +34,13 @@ struct cht_int33fe_data {
|
|||
struct i2c_client *pi3usb30532;
|
||||
};
|
||||
|
||||
static const char * const max17047_suppliers[] = { "bq24190-charger" };
|
||||
|
||||
static const struct property_entry max17047_props[] = {
|
||||
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", max17047_suppliers),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int cht_int33fe_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
|
@ -70,6 +77,7 @@ static int cht_int33fe_probe(struct i2c_client *client)
|
|||
|
||||
memset(&board_info, 0, sizeof(board_info));
|
||||
strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
|
||||
board_info.properties = max17047_props;
|
||||
|
||||
data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
|
||||
if (!data->max17047)
|
||||
|
|
|
@ -142,7 +142,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_cooling_device_ops memory_cooling_ops = {
|
||||
static const struct thermal_cooling_device_ops memory_cooling_ops = {
|
||||
.get_max_state = memory_get_max_bandwidth,
|
||||
.get_cur_state = memory_get_cur_bandwidth,
|
||||
.set_cur_state = memory_set_cur_bandwidth,
|
||||
|
|
|
@ -186,7 +186,7 @@ static inline void ipc_data_writel(u32 data, u32 offset)
|
|||
writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset);
|
||||
}
|
||||
|
||||
static inline u8 ipc_data_readb(u32 offset)
|
||||
static inline u8 __maybe_unused ipc_data_readb(u32 offset)
|
||||
{
|
||||
return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
|
||||
}
|
||||
|
|
|
@ -563,11 +563,11 @@ static struct attribute *msipf_old_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group msipf_attribute_group = {
|
||||
static const struct attribute_group msipf_attribute_group = {
|
||||
.attrs = msipf_attributes
|
||||
};
|
||||
|
||||
static struct attribute_group msipf_old_attribute_group = {
|
||||
static const struct attribute_group msipf_old_attribute_group = {
|
||||
.attrs = msipf_old_attributes
|
||||
};
|
||||
|
||||
|
|
|
@ -228,10 +228,6 @@ struct pcc_acpi {
|
|||
struct backlight_device *backlight;
|
||||
};
|
||||
|
||||
struct pcc_keyinput {
|
||||
struct acpi_hotkey *hotkey;
|
||||
};
|
||||
|
||||
/* method access functions */
|
||||
static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* PEAQ 2-in-1 WMI hotkey driver
|
||||
* Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define PEAQ_DOLBY_BUTTON_GUID "ABBC0F6F-8EA1-11D1-00A0-C90629100000"
|
||||
#define PEAQ_DOLBY_BUTTON_METHOD_ID 5
|
||||
#define PEAQ_POLL_INTERVAL_MS 250
|
||||
#define PEAQ_POLL_IGNORE_MS 500
|
||||
#define PEAQ_POLL_MAX_MS 1000
|
||||
|
||||
MODULE_ALIAS("wmi:"PEAQ_DOLBY_BUTTON_GUID);
|
||||
|
||||
static unsigned int peaq_ignore_events_counter;
|
||||
static struct input_polled_dev *peaq_poll_dev;
|
||||
|
||||
/*
|
||||
* The Dolby button (yes really a Dolby button) causes an ACPI variable to get
|
||||
* set on both press and release. The WMI method checks and clears that flag.
|
||||
* So for a press + release we will get back One from the WMI method either once
|
||||
* (if polling after the release) or twice (polling between press and release).
|
||||
* We ignore events for 0.5s after the first event to avoid reporting 2 presses.
|
||||
*/
|
||||
static void peaq_wmi_poll(struct input_polled_dev *dev)
|
||||
{
|
||||
union acpi_object obj;
|
||||
acpi_status status;
|
||||
u32 dummy = 0;
|
||||
|
||||
struct acpi_buffer input = { sizeof(dummy), &dummy };
|
||||
struct acpi_buffer output = { sizeof(obj), &obj };
|
||||
|
||||
status = wmi_evaluate_method(PEAQ_DOLBY_BUTTON_GUID, 1,
|
||||
PEAQ_DOLBY_BUTTON_METHOD_ID,
|
||||
&input, &output);
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
|
||||
if (obj.type != ACPI_TYPE_INTEGER) {
|
||||
dev_err(&peaq_poll_dev->input->dev,
|
||||
"Error WMBC did not return an integer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (peaq_ignore_events_counter && --peaq_ignore_events_counter > 0)
|
||||
return;
|
||||
|
||||
if (obj.integer.value) {
|
||||
input_event(peaq_poll_dev->input, EV_KEY, KEY_SOUND, 1);
|
||||
input_sync(peaq_poll_dev->input);
|
||||
input_event(peaq_poll_dev->input, EV_KEY, KEY_SOUND, 0);
|
||||
input_sync(peaq_poll_dev->input);
|
||||
peaq_ignore_events_counter = max(1u,
|
||||
PEAQ_POLL_IGNORE_MS / peaq_poll_dev->poll_interval);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init peaq_wmi_init(void)
|
||||
{
|
||||
if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID))
|
||||
return -ENODEV;
|
||||
|
||||
peaq_poll_dev = input_allocate_polled_device();
|
||||
if (!peaq_poll_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
peaq_poll_dev->poll = peaq_wmi_poll;
|
||||
peaq_poll_dev->poll_interval = PEAQ_POLL_INTERVAL_MS;
|
||||
peaq_poll_dev->poll_interval_max = PEAQ_POLL_MAX_MS;
|
||||
peaq_poll_dev->input->name = "PEAQ WMI hotkeys";
|
||||
peaq_poll_dev->input->phys = "wmi/input0";
|
||||
peaq_poll_dev->input->id.bustype = BUS_HOST;
|
||||
input_set_capability(peaq_poll_dev->input, EV_KEY, KEY_SOUND);
|
||||
|
||||
return input_register_polled_device(peaq_poll_dev);
|
||||
}
|
||||
|
||||
static void __exit peaq_wmi_exit(void)
|
||||
{
|
||||
if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID))
|
||||
return;
|
||||
|
||||
input_unregister_polled_device(peaq_poll_dev);
|
||||
}
|
||||
|
||||
module_init(peaq_wmi_init);
|
||||
module_exit(peaq_wmi_exit);
|
||||
|
||||
MODULE_DESCRIPTION("PEAQ 2-in-1 WMI hotkey driver");
|
||||
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -591,7 +591,7 @@ static int seclinux_rfkill_set(void *data, bool blocked)
|
|||
!blocked);
|
||||
}
|
||||
|
||||
static struct rfkill_ops seclinux_rfkill_ops = {
|
||||
static const struct rfkill_ops seclinux_rfkill_ops = {
|
||||
.set_block = seclinux_rfkill_set,
|
||||
};
|
||||
|
||||
|
@ -651,7 +651,7 @@ static void swsmi_rfkill_query(struct rfkill *rfkill, void *priv)
|
|||
rfkill_set_sw_state(rfkill, !ret);
|
||||
}
|
||||
|
||||
static struct rfkill_ops swsmi_rfkill_ops = {
|
||||
static const struct rfkill_ops swsmi_rfkill_ops = {
|
||||
.set_block = swsmi_rfkill_set,
|
||||
.query = swsmi_rfkill_query,
|
||||
};
|
||||
|
@ -1446,9 +1446,9 @@ static int __init samsung_sabi_init(struct samsung_laptop *samsung)
|
|||
const struct sabi_config *config = NULL;
|
||||
const struct sabi_commands *commands;
|
||||
unsigned int ifaceP;
|
||||
int loca = 0xffff;
|
||||
int ret = 0;
|
||||
int i;
|
||||
int loca;
|
||||
|
||||
samsung->f0000_segment = ioremap_nocache(0xf0000, 0xffff);
|
||||
if (!samsung->f0000_segment) {
|
||||
|
|
|
@ -80,6 +80,48 @@ static const struct silead_ts_dmi_data surftab_wintron70_st70416_6_data = {
|
|||
.properties = surftab_wintron70_st70416_6_props,
|
||||
};
|
||||
|
||||
static const struct property_entry gp_electronic_t701_props[] = {
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-x", 960),
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-y", 640),
|
||||
PROPERTY_ENTRY_STRING("firmware-name",
|
||||
"gsl1680-gp-electronic-t701.fw"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct silead_ts_dmi_data gp_electronic_t701_data = {
|
||||
.acpi_name = "MSSL1680:00",
|
||||
.properties = gp_electronic_t701_props,
|
||||
};
|
||||
|
||||
static const struct property_entry pipo_w2s_props[] = {
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-x", 1660),
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-y", 880),
|
||||
PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
|
||||
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
|
||||
PROPERTY_ENTRY_STRING("firmware-name",
|
||||
"gsl1680-pipo-w2s.fw"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct silead_ts_dmi_data pipo_w2s_data = {
|
||||
.acpi_name = "MSSL1680:00",
|
||||
.properties = pipo_w2s_props,
|
||||
};
|
||||
|
||||
static const struct property_entry pov_mobii_wintab_p800w_props[] = {
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-x", 1800),
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-y", 1150),
|
||||
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
|
||||
PROPERTY_ENTRY_STRING("firmware-name",
|
||||
"gsl3692-pov-mobii-wintab-p800w.fw"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_data = {
|
||||
.acpi_name = "MSSL1680:00",
|
||||
.properties = pov_mobii_wintab_p800w_props,
|
||||
};
|
||||
|
||||
static const struct dmi_system_id silead_ts_dmi_table[] = {
|
||||
{
|
||||
/* CUBE iwork8 Air */
|
||||
|
@ -117,6 +159,34 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
|
|||
DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* GP-electronic T701 */
|
||||
.driver_data = (void *)&gp_electronic_t701_data,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "T701"),
|
||||
DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Pipo W2S */
|
||||
.driver_data = (void *)&pipo_w2s_data,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "PIPO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "W2S"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Point of View mobii wintab p800w */
|
||||
.driver_data = (void *)&pov_mobii_wintab_p800w_data,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
|
||||
DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"),
|
||||
/* Above matches are too generic, add bios-date match */
|
||||
DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"),
|
||||
},
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
|
@ -222,7 +222,7 @@ struct sony_laptop_keypress {
|
|||
/* Correspondance table between sonypi events
|
||||
* and input layer indexes in the keymap
|
||||
*/
|
||||
static int sony_laptop_input_index[] = {
|
||||
static const int sony_laptop_input_index[] = {
|
||||
-1, /* 0 no event */
|
||||
-1, /* 1 SONYPI_EVENT_JOGDIAL_DOWN */
|
||||
-1, /* 2 SONYPI_EVENT_JOGDIAL_UP */
|
||||
|
@ -4032,7 +4032,7 @@ static struct attribute *spic_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group spic_attribute_group = {
|
||||
static const struct attribute_group spic_attribute_group = {
|
||||
.attrs = spic_attributes
|
||||
};
|
||||
|
||||
|
|
|
@ -590,8 +590,8 @@ static int acpi_evalf(acpi_handle handle,
|
|||
break;
|
||||
/* add more types as needed */
|
||||
default:
|
||||
pr_err("acpi_evalf() called "
|
||||
"with invalid format character '%c'\n", c);
|
||||
pr_err("acpi_evalf() called with invalid format character '%c'\n",
|
||||
c);
|
||||
va_end(ap);
|
||||
return 0;
|
||||
}
|
||||
|
@ -619,8 +619,8 @@ static int acpi_evalf(acpi_handle handle,
|
|||
break;
|
||||
/* add more types as needed */
|
||||
default:
|
||||
pr_err("acpi_evalf() called "
|
||||
"with invalid format character '%c'\n", res_type);
|
||||
pr_err("acpi_evalf() called with invalid format character '%c'\n",
|
||||
res_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -790,8 +790,8 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
|
|||
ibm->acpi->type, dispatch_acpi_notify, ibm);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (status == AE_ALREADY_EXISTS) {
|
||||
pr_notice("another device driver is already "
|
||||
"handling %s events\n", ibm->name);
|
||||
pr_notice("another device driver is already handling %s events\n",
|
||||
ibm->name);
|
||||
} else {
|
||||
pr_err("acpi_install_notify_handler(%s) failed: %s\n",
|
||||
ibm->name, acpi_format_exception(status));
|
||||
|
@ -1095,8 +1095,7 @@ static void printk_deprecated_attribute(const char * const what,
|
|||
const char * const details)
|
||||
{
|
||||
tpacpi_log_usertask("deprecated sysfs attribute");
|
||||
pr_warn("WARNING: sysfs attribute %s is deprecated and "
|
||||
"will be removed. %s\n",
|
||||
pr_warn("WARNING: sysfs attribute %s is deprecated and will be removed. %s\n",
|
||||
what, details);
|
||||
}
|
||||
|
||||
|
@ -1796,8 +1795,7 @@ static void __init tpacpi_check_outdated_fw(void)
|
|||
* best if the user upgrades the firmware anyway.
|
||||
*/
|
||||
pr_warn("WARNING: Outdated ThinkPad BIOS/EC firmware\n");
|
||||
pr_warn("WARNING: This firmware may be missing critical bug "
|
||||
"fixes and/or important features\n");
|
||||
pr_warn("WARNING: This firmware may be missing critical bug fixes and/or important features\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2166,8 +2164,7 @@ static int hotkey_mask_set(u32 mask)
|
|||
* a given event.
|
||||
*/
|
||||
if (!hotkey_mask_get() && !rc && (fwmask & ~hotkey_acpi_mask)) {
|
||||
pr_notice("asked for hotkey mask 0x%08x, but "
|
||||
"firmware forced it to 0x%08x\n",
|
||||
pr_notice("asked for hotkey mask 0x%08x, but firmware forced it to 0x%08x\n",
|
||||
fwmask, hotkey_acpi_mask);
|
||||
}
|
||||
|
||||
|
@ -2192,11 +2189,9 @@ static int hotkey_user_mask_set(const u32 mask)
|
|||
(mask == 0xffff || mask == 0xffffff ||
|
||||
mask == 0xffffffff)) {
|
||||
tp_warned.hotkey_mask_ff = 1;
|
||||
pr_notice("setting the hotkey mask to 0x%08x is likely "
|
||||
"not the best way to go about it\n", mask);
|
||||
pr_notice("please consider using the driver defaults, "
|
||||
"and refer to up-to-date thinkpad-acpi "
|
||||
"documentation\n");
|
||||
pr_notice("setting the hotkey mask to 0x%08x is likely not the best way to go about it\n",
|
||||
mask);
|
||||
pr_notice("please consider using the driver defaults, and refer to up-to-date thinkpad-acpi documentation\n");
|
||||
}
|
||||
|
||||
/* Try to enable what the user asked for, plus whatever we need.
|
||||
|
@ -2571,17 +2566,14 @@ static void hotkey_poll_setup(const bool may_warn)
|
|||
NULL, TPACPI_NVRAM_KTHREAD_NAME);
|
||||
if (IS_ERR(tpacpi_hotkey_task)) {
|
||||
tpacpi_hotkey_task = NULL;
|
||||
pr_err("could not create kernel thread "
|
||||
"for hotkey polling\n");
|
||||
pr_err("could not create kernel thread for hotkey polling\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hotkey_poll_stop_sync();
|
||||
if (may_warn && (poll_driver_mask || poll_user_mask) &&
|
||||
hotkey_poll_freq == 0) {
|
||||
pr_notice("hot keys 0x%08x and/or events 0x%08x "
|
||||
"require polling, which is currently "
|
||||
"disabled\n",
|
||||
pr_notice("hot keys 0x%08x and/or events 0x%08x require polling, which is currently disabled\n",
|
||||
poll_user_mask, poll_driver_mask);
|
||||
}
|
||||
}
|
||||
|
@ -2808,12 +2800,10 @@ static ssize_t hotkey_source_mask_store(struct device *dev,
|
|||
mutex_unlock(&hotkey_mutex);
|
||||
|
||||
if (rc < 0)
|
||||
pr_err("hotkey_source_mask: "
|
||||
"failed to update the firmware event mask!\n");
|
||||
pr_err("hotkey_source_mask: failed to update the firmware event mask!\n");
|
||||
|
||||
if (r_ev)
|
||||
pr_notice("hotkey_source_mask: "
|
||||
"some important events were disabled: 0x%04x\n",
|
||||
pr_notice("hotkey_source_mask: some important events were disabled: 0x%04x\n",
|
||||
r_ev);
|
||||
|
||||
tpacpi_disclose_usertask("hotkey_source_mask", "set to 0x%08lx\n", t);
|
||||
|
@ -3074,8 +3064,7 @@ static void hotkey_exit(void)
|
|||
if (((tp_features.hotkey_mask &&
|
||||
hotkey_mask_set(hotkey_orig_mask)) |
|
||||
hotkey_status_set(false)) != 0)
|
||||
pr_err("failed to restore hot key mask "
|
||||
"to BIOS defaults\n");
|
||||
pr_err("failed to restore hot key mask to BIOS defaults\n");
|
||||
}
|
||||
|
||||
static void __init hotkey_unmap(const unsigned int scancode)
|
||||
|
@ -3587,11 +3576,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
* userspace. tpacpi_detect_brightness_capabilities() must have
|
||||
* been called before this point */
|
||||
if (acpi_video_get_backlight_type() != acpi_backlight_vendor) {
|
||||
pr_info("This ThinkPad has standard ACPI backlight "
|
||||
"brightness control, supported by the ACPI "
|
||||
"video driver\n");
|
||||
pr_notice("Disabling thinkpad-acpi brightness events "
|
||||
"by default...\n");
|
||||
pr_info("This ThinkPad has standard ACPI backlight brightness control, supported by the ACPI video driver\n");
|
||||
pr_notice("Disabling thinkpad-acpi brightness events by default...\n");
|
||||
|
||||
/* Disable brightness up/down on Lenovo thinkpads when
|
||||
* ACPI is handling them, otherwise it is plain impossible
|
||||
|
@ -3760,7 +3746,7 @@ static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode)
|
|||
TP_ACPI_HOTKEYSCAN_EXTENDED_START -
|
||||
TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) {
|
||||
pr_info("Unhandled adaptive keyboard key: 0x%x\n",
|
||||
scancode);
|
||||
scancode);
|
||||
return false;
|
||||
}
|
||||
keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY +
|
||||
|
@ -3957,14 +3943,12 @@ static bool hotkey_notify_6xxx(const u32 hkey,
|
|||
/* recommended action: immediate sleep/hibernate */
|
||||
break;
|
||||
case TP_HKEY_EV_ALARM_SENSOR_HOT:
|
||||
pr_crit("THERMAL ALARM: "
|
||||
"a sensor reports something is too hot!\n");
|
||||
pr_crit("THERMAL ALARM: a sensor reports something is too hot!\n");
|
||||
/* recommended action: warn user through gui, that */
|
||||
/* some internal component is too hot */
|
||||
break;
|
||||
case TP_HKEY_EV_ALARM_SENSOR_XHOT:
|
||||
pr_alert("THERMAL EMERGENCY: "
|
||||
"a sensor reports something is extremely hot!\n");
|
||||
pr_alert("THERMAL EMERGENCY: a sensor reports something is extremely hot!\n");
|
||||
/* recommended action: immediate sleep/hibernate */
|
||||
break;
|
||||
case TP_HKEY_EV_AC_CHANGED:
|
||||
|
@ -4089,8 +4073,8 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
|
|||
}
|
||||
if (!known_ev) {
|
||||
pr_notice("unhandled HKEY event 0x%04x\n", hkey);
|
||||
pr_notice("please report the conditions when this "
|
||||
"event happened to %s\n", TPACPI_MAIL);
|
||||
pr_notice("please report the conditions when this event happened to %s\n",
|
||||
TPACPI_MAIL);
|
||||
}
|
||||
|
||||
/* netlink events */
|
||||
|
@ -4124,8 +4108,7 @@ static void hotkey_resume(void)
|
|||
|
||||
if (hotkey_status_set(true) < 0 ||
|
||||
hotkey_mask_set(hotkey_acpi_mask) < 0)
|
||||
pr_err("error while attempting to reset the event "
|
||||
"firmware interface\n");
|
||||
pr_err("error while attempting to reset the event firmware interface\n");
|
||||
|
||||
tpacpi_send_radiosw_update();
|
||||
hotkey_tablet_mode_notify_change();
|
||||
|
@ -4177,12 +4160,8 @@ static void hotkey_enabledisable_warn(bool enable)
|
|||
{
|
||||
tpacpi_log_usertask("procfs hotkey enable/disable");
|
||||
if (!WARN((tpacpi_lifecycle == TPACPI_LIFE_RUNNING || !enable),
|
||||
pr_fmt("hotkey enable/disable functionality has been "
|
||||
"removed from the driver. "
|
||||
"Hotkeys are always enabled.\n")))
|
||||
pr_err("Please remove the hotkey=enable module "
|
||||
"parameter, it is deprecated. "
|
||||
"Hotkeys are always enabled.\n");
|
||||
pr_fmt("hotkey enable/disable functionality has been removed from the driver. Hotkeys are always enabled.\n")))
|
||||
pr_err("Please remove the hotkey=enable module parameter, it is deprecated. Hotkeys are always enabled.\n");
|
||||
}
|
||||
|
||||
static int hotkey_write(char *buf)
|
||||
|
@ -4840,8 +4819,7 @@ static void video_exit(void)
|
|||
dbg_printk(TPACPI_DBG_EXIT,
|
||||
"restoring original video autoswitch mode\n");
|
||||
if (video_autosw_set(video_orig_autosw))
|
||||
pr_err("error while trying to restore original "
|
||||
"video autoswitch mode\n");
|
||||
pr_err("error while trying to restore original video autoswitch mode\n");
|
||||
}
|
||||
|
||||
static int video_outputsw_get(void)
|
||||
|
@ -5931,8 +5909,7 @@ static int __init led_init(struct ibm_init_struct *iibm)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
|
||||
pr_notice("warning: userspace override of important "
|
||||
"firmware LEDs is enabled\n");
|
||||
pr_notice("warning: userspace override of important firmware LEDs is enabled\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -5961,8 +5938,7 @@ static int led_read(struct seq_file *m)
|
|||
}
|
||||
}
|
||||
|
||||
seq_printf(m, "commands:\t"
|
||||
"<led> on, <led> off, <led> blink (<led> is 0-15)\n");
|
||||
seq_printf(m, "commands:\t<led> on, <led> off, <led> blink (<led> is 0-15)\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6335,13 +6311,10 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
|
|||
if (ta1 == 0) {
|
||||
/* This is sheer paranoia, but we handle it anyway */
|
||||
if (acpi_tmp7) {
|
||||
pr_err("ThinkPad ACPI EC access misbehaving, "
|
||||
"falling back to ACPI TMPx access "
|
||||
"mode\n");
|
||||
pr_err("ThinkPad ACPI EC access misbehaving, falling back to ACPI TMPx access mode\n");
|
||||
thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
|
||||
} else {
|
||||
pr_err("ThinkPad ACPI EC access misbehaving, "
|
||||
"disabling thermal sensors access\n");
|
||||
pr_err("ThinkPad ACPI EC access misbehaving, disabling thermal sensors access\n");
|
||||
thermal_read_mode = TPACPI_THERMAL_NONE;
|
||||
}
|
||||
} else {
|
||||
|
@ -6820,26 +6793,20 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|||
|
||||
if (!brightness_enable) {
|
||||
dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
|
||||
"brightness support disabled by "
|
||||
"module parameter\n");
|
||||
"brightness support disabled by module parameter\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (acpi_video_get_backlight_type() != acpi_backlight_vendor) {
|
||||
if (brightness_enable > 1) {
|
||||
pr_info("Standard ACPI backlight interface "
|
||||
"available, not loading native one\n");
|
||||
pr_info("Standard ACPI backlight interface available, not loading native one\n");
|
||||
return 1;
|
||||
} else if (brightness_enable == 1) {
|
||||
pr_warn("Cannot enable backlight brightness support, "
|
||||
"ACPI is already handling it. Refer to the "
|
||||
"acpi_backlight kernel parameter.\n");
|
||||
pr_warn("Cannot enable backlight brightness support, ACPI is already handling it. Refer to the acpi_backlight kernel parameter.\n");
|
||||
return 1;
|
||||
}
|
||||
} else if (tp_features.bright_acpimode && brightness_enable > 1) {
|
||||
pr_notice("Standard ACPI backlight interface not "
|
||||
"available, thinkpad_acpi native "
|
||||
"brightness control enabled\n");
|
||||
pr_notice("Standard ACPI backlight interface not available, thinkpad_acpi native brightness control enabled\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -6890,10 +6857,10 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|||
"brightness is supported\n");
|
||||
|
||||
if (quirks & TPACPI_BRGHT_Q_ASK) {
|
||||
pr_notice("brightness: will use unverified default: "
|
||||
"brightness_mode=%d\n", brightness_mode);
|
||||
pr_notice("brightness: please report to %s whether it works well "
|
||||
"or not on your ThinkPad\n", TPACPI_MAIL);
|
||||
pr_notice("brightness: will use unverified default: brightness_mode=%d\n",
|
||||
brightness_mode);
|
||||
pr_notice("brightness: please report to %s whether it works well or not on your ThinkPad\n",
|
||||
TPACPI_MAIL);
|
||||
}
|
||||
|
||||
/* Added by mistake in early 2007. Probably useless, but it could
|
||||
|
@ -6903,8 +6870,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|||
backlight_update_status(ibm_backlight_device);
|
||||
|
||||
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
|
||||
"brightness: registering brightness hotkeys "
|
||||
"as change notification\n");
|
||||
"brightness: registering brightness hotkeys as change notification\n");
|
||||
tpacpi_hotkey_driver_mask_set(hotkey_driver_mask
|
||||
| TP_ACPI_HKEY_BRGHTUP_MASK
|
||||
| TP_ACPI_HKEY_BRGHTDWN_MASK);
|
||||
|
@ -7567,8 +7533,8 @@ static int __init volume_init(struct ibm_init_struct *iibm)
|
|||
return -EINVAL;
|
||||
|
||||
if (volume_mode == TPACPI_VOL_MODE_UCMS_STEP) {
|
||||
pr_err("UCMS step volume mode not implemented, "
|
||||
"please contact %s\n", TPACPI_MAIL);
|
||||
pr_err("UCMS step volume mode not implemented, please contact %s\n",
|
||||
TPACPI_MAIL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -7581,8 +7547,7 @@ static int __init volume_init(struct ibm_init_struct *iibm)
|
|||
*/
|
||||
if (!alsa_enable) {
|
||||
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
|
||||
"ALSA mixer disabled by parameter, "
|
||||
"not loading volume subdriver...\n");
|
||||
"ALSA mixer disabled by parameter, not loading volume subdriver...\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -7674,12 +7639,9 @@ static int volume_read(struct seq_file *m)
|
|||
if (volume_control_allowed) {
|
||||
seq_printf(m, "commands:\tunmute, mute\n");
|
||||
if (!tp_features.mixer_no_level_control) {
|
||||
seq_printf(m,
|
||||
"commands:\tup, down\n");
|
||||
seq_printf(m,
|
||||
"commands:\tlevel <level>"
|
||||
" (<level> is 0-%d)\n",
|
||||
TP_EC_VOLUME_MAX);
|
||||
seq_printf(m, "commands:\tup, down\n");
|
||||
seq_printf(m, "commands:\tlevel <level> (<level> is 0-%d)\n",
|
||||
TP_EC_VOLUME_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7702,10 +7664,8 @@ static int volume_write(char *buf)
|
|||
if (!volume_control_allowed && tpacpi_lifecycle != TPACPI_LIFE_INIT) {
|
||||
if (unlikely(!tp_warned.volume_ctrl_forbidden)) {
|
||||
tp_warned.volume_ctrl_forbidden = 1;
|
||||
pr_notice("Console audio control in monitor mode, "
|
||||
"changes are not allowed\n");
|
||||
pr_notice("Use the volume_control=1 module parameter "
|
||||
"to enable volume control\n");
|
||||
pr_notice("Console audio control in monitor mode, changes are not allowed\n");
|
||||
pr_notice("Use the volume_control=1 module parameter to enable volume control\n");
|
||||
}
|
||||
return -EPERM;
|
||||
}
|
||||
|
@ -7987,8 +7947,7 @@ TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */
|
|||
static void fan_quirk1_setup(void)
|
||||
{
|
||||
if (fan_control_initial_status == 0x07) {
|
||||
pr_notice("fan_init: initial fan status is unknown, "
|
||||
"assuming it is in auto mode\n");
|
||||
pr_notice("fan_init: initial fan status is unknown, assuming it is in auto mode\n");
|
||||
tp_features.fan_ctrl_status_undef = 1;
|
||||
}
|
||||
}
|
||||
|
@ -8385,8 +8344,8 @@ static void fan_watchdog_fire(struct work_struct *ignored)
|
|||
pr_notice("fan watchdog: enabling fan\n");
|
||||
rc = fan_set_enable();
|
||||
if (rc < 0) {
|
||||
pr_err("fan watchdog: error %d while enabling fan, "
|
||||
"will try again later...\n", -rc);
|
||||
pr_err("fan watchdog: error %d while enabling fan, will try again later...\n",
|
||||
rc);
|
||||
/* reschedule for later */
|
||||
fan_watchdog_reset();
|
||||
}
|
||||
|
@ -8680,8 +8639,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
|
|||
"secondary fan support enabled\n");
|
||||
}
|
||||
} else {
|
||||
pr_err("ThinkPad ACPI EC access misbehaving, "
|
||||
"fan status and control unavailable\n");
|
||||
pr_err("ThinkPad ACPI EC access misbehaving, fan status and control unavailable\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -8780,8 +8738,8 @@ static void fan_suspend(void)
|
|||
fan_control_resume_level = 0;
|
||||
rc = fan_get_status_safe(&fan_control_resume_level);
|
||||
if (rc < 0)
|
||||
pr_notice("failed to read fan level for later "
|
||||
"restore during resume: %d\n", rc);
|
||||
pr_notice("failed to read fan level for later restore during resume: %d\n",
|
||||
rc);
|
||||
|
||||
/* if it is undefined, don't attempt to restore it.
|
||||
* KEEP THIS LAST */
|
||||
|
@ -8900,20 +8858,17 @@ static int fan_read(struct seq_file *m)
|
|||
break;
|
||||
|
||||
default:
|
||||
seq_printf(m, " (<level> is 0-7, "
|
||||
"auto, disengaged, full-speed)\n");
|
||||
seq_printf(m, " (<level> is 0-7, auto, disengaged, full-speed)\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
|
||||
seq_printf(m, "commands:\tenable, disable\n"
|
||||
"commands:\twatchdog <timeout> (<timeout> "
|
||||
"is 0 (off), 1-120 (seconds))\n");
|
||||
"commands:\twatchdog <timeout> (<timeout> is 0 (off), 1-120 (seconds))\n");
|
||||
|
||||
if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
|
||||
seq_printf(m, "commands:\tspeed <speed>"
|
||||
" (<speed> is 0-65535)\n");
|
||||
seq_printf(m, "commands:\tspeed <speed> (<speed> is 0-65535)\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -9439,8 +9394,7 @@ static int __must_check __init get_thinkpad_model_data(
|
|||
tp->ec_release = (ec_fw_string[4] << 8)
|
||||
| ec_fw_string[5];
|
||||
} else {
|
||||
pr_notice("ThinkPad firmware release %s "
|
||||
"doesn't match the known patterns\n",
|
||||
pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
|
||||
ec_fw_string);
|
||||
pr_notice("please report this to %s\n",
|
||||
TPACPI_MAIL);
|
||||
|
@ -9635,8 +9589,7 @@ MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
|
|||
|
||||
module_param(force_load, bool, 0444);
|
||||
MODULE_PARM_DESC(force_load,
|
||||
"Attempts to load the driver even on a "
|
||||
"mis-identified ThinkPad when true");
|
||||
"Attempts to load the driver even on a mis-identified ThinkPad when true");
|
||||
|
||||
module_param_named(fan_control, fan_control_allowed, bool, 0444);
|
||||
MODULE_PARM_DESC(fan_control,
|
||||
|
@ -9644,8 +9597,7 @@ MODULE_PARM_DESC(fan_control,
|
|||
|
||||
module_param_named(brightness_mode, brightness_mode, uint, 0444);
|
||||
MODULE_PARM_DESC(brightness_mode,
|
||||
"Selects brightness control strategy: "
|
||||
"0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM");
|
||||
"Selects brightness control strategy: 0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM");
|
||||
|
||||
module_param(brightness_enable, uint, 0444);
|
||||
MODULE_PARM_DESC(brightness_enable,
|
||||
|
@ -9654,18 +9606,15 @@ MODULE_PARM_DESC(brightness_enable,
|
|||
#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
|
||||
module_param_named(volume_mode, volume_mode, uint, 0444);
|
||||
MODULE_PARM_DESC(volume_mode,
|
||||
"Selects volume control strategy: "
|
||||
"0=auto, 1=EC, 2=N/A, 3=EC+NVRAM");
|
||||
"Selects volume control strategy: 0=auto, 1=EC, 2=N/A, 3=EC+NVRAM");
|
||||
|
||||
module_param_named(volume_capabilities, volume_capabilities, uint, 0444);
|
||||
MODULE_PARM_DESC(volume_capabilities,
|
||||
"Selects the mixer capabilites: "
|
||||
"0=auto, 1=volume and mute, 2=mute only");
|
||||
"Selects the mixer capabilites: 0=auto, 1=volume and mute, 2=mute only");
|
||||
|
||||
module_param_named(volume_control, volume_control_allowed, bool, 0444);
|
||||
MODULE_PARM_DESC(volume_control,
|
||||
"Enables software override for the console audio "
|
||||
"control when true");
|
||||
"Enables software override for the console audio control when true");
|
||||
|
||||
module_param_named(software_mute, software_mute_requested, bool, 0444);
|
||||
MODULE_PARM_DESC(software_mute,
|
||||
|
@ -9680,10 +9629,10 @@ module_param_named(enable, alsa_enable, bool, 0444);
|
|||
MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer");
|
||||
#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
|
||||
|
||||
/* The module parameter can't be read back, that's why 0 is used here */
|
||||
#define TPACPI_PARAM(feature) \
|
||||
module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
|
||||
MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \
|
||||
"at module load, see documentation")
|
||||
MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command at module load, see documentation")
|
||||
|
||||
TPACPI_PARAM(hotkey);
|
||||
TPACPI_PARAM(bluetooth);
|
||||
|
|
|
@ -162,6 +162,7 @@ static int acpi_topstar_remove(struct acpi_device *device)
|
|||
}
|
||||
|
||||
static const struct acpi_device_id topstar_device_ids[] = {
|
||||
{ "TPS0001", 0 },
|
||||
{ "TPSACPI01", 0 },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
|
|
@ -1502,14 +1502,9 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
|
|||
int ret;
|
||||
u32 video_out;
|
||||
|
||||
cmd = kmalloc(count + 1, GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(cmd, buf, count)) {
|
||||
kfree(cmd);
|
||||
return -EFAULT;
|
||||
}
|
||||
cmd[count] = '\0';
|
||||
cmd = memdup_user_nul(buf, count);
|
||||
if (IS_ERR(cmd))
|
||||
return PTR_ERR(cmd);
|
||||
|
||||
buffer = cmd;
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ static struct attribute *haps_attributes[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group haps_attr_group = {
|
||||
static const struct attribute_group haps_attr_group = {
|
||||
.attrs = haps_attributes,
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* WMI embedded Binary MOF driver
|
||||
*
|
||||
* Copyright (c) 2015 Andrew Lutomirski
|
||||
* Copyright (C) 2017 VMware, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
#define WMI_BMOF_GUID "05901221-D566-11D1-B2F0-00A0C9062910"
|
||||
|
||||
struct bmof_priv {
|
||||
union acpi_object *bmofdata;
|
||||
struct bin_attribute bmof_bin_attr;
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
read_bmof(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct bmof_priv *priv =
|
||||
container_of(attr, struct bmof_priv, bmof_bin_attr);
|
||||
|
||||
if (off < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (off >= priv->bmofdata->buffer.length)
|
||||
return 0;
|
||||
|
||||
if (count > priv->bmofdata->buffer.length - off)
|
||||
count = priv->bmofdata->buffer.length - off;
|
||||
|
||||
memcpy(buf, priv->bmofdata->buffer.pointer + off, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int wmi_bmof_probe(struct wmi_device *wdev)
|
||||
{
|
||||
struct bmof_priv *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&wdev->dev, sizeof(struct bmof_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&wdev->dev, priv);
|
||||
|
||||
priv->bmofdata = wmidev_block_query(wdev, 0);
|
||||
if (!priv->bmofdata) {
|
||||
dev_err(&wdev->dev, "failed to read Binary MOF\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (priv->bmofdata->type != ACPI_TYPE_BUFFER) {
|
||||
dev_err(&wdev->dev, "Binary MOF is not a buffer\n");
|
||||
ret = -EIO;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
sysfs_bin_attr_init(&priv->bmof_bin_attr);
|
||||
priv->bmof_bin_attr.attr.name = "bmof";
|
||||
priv->bmof_bin_attr.attr.mode = 0400;
|
||||
priv->bmof_bin_attr.read = read_bmof;
|
||||
priv->bmof_bin_attr.size = priv->bmofdata->buffer.length;
|
||||
|
||||
ret = sysfs_create_bin_file(&wdev->dev.kobj, &priv->bmof_bin_attr);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
kfree(priv->bmofdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wmi_bmof_remove(struct wmi_device *wdev)
|
||||
{
|
||||
struct bmof_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
|
||||
sysfs_remove_bin_file(&wdev->dev.kobj, &priv->bmof_bin_attr);
|
||||
kfree(priv->bmofdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct wmi_device_id wmi_bmof_id_table[] = {
|
||||
{ .guid_string = WMI_BMOF_GUID },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct wmi_driver wmi_bmof_driver = {
|
||||
.driver = {
|
||||
.name = "wmi-bmof",
|
||||
},
|
||||
.probe = wmi_bmof_probe,
|
||||
.remove = wmi_bmof_remove,
|
||||
.id_table = wmi_bmof_id_table,
|
||||
};
|
||||
|
||||
module_wmi_driver(wmi_bmof_driver);
|
||||
|
||||
MODULE_ALIAS("wmi:" WMI_BMOF_GUID);
|
||||
MODULE_AUTHOR("Andrew Lutomirski <luto@kernel.org>");
|
||||
MODULE_DESCRIPTION("WMI embedded Binary MOF driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -8,6 +8,10 @@
|
|||
* Copyright (c) 2001-2007 Anton Altaparmakov
|
||||
* Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
|
||||
*
|
||||
* WMI bus infrastructure by Andrew Lutomirski and Darren Hart:
|
||||
* Copyright (C) 2015 Andrew Lutomirski
|
||||
* Copyright (C) 2017 VMware, Inc. All Rights Reserved.
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -37,6 +41,8 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/wmi.h>
|
||||
#include <linux/uuid.h>
|
||||
|
||||
ACPI_MODULE_NAME("wmi");
|
||||
|
@ -44,8 +50,6 @@ MODULE_AUTHOR("Carlos Corbacho");
|
|||
MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define ACPI_WMI_CLASS "wmi"
|
||||
|
||||
static LIST_HEAD(wmi_block_list);
|
||||
|
||||
struct guid_block {
|
||||
|
@ -62,12 +66,14 @@ struct guid_block {
|
|||
};
|
||||
|
||||
struct wmi_block {
|
||||
struct wmi_device dev;
|
||||
struct list_head list;
|
||||
struct guid_block gblock;
|
||||
acpi_handle handle;
|
||||
struct acpi_device *acpi_device;
|
||||
wmi_notify_handler handler;
|
||||
void *handler_data;
|
||||
struct device dev;
|
||||
|
||||
bool read_takes_no_args;
|
||||
};
|
||||
|
||||
|
||||
|
@ -90,9 +96,8 @@ module_param(debug_dump_wdg, bool, 0444);
|
|||
MODULE_PARM_DESC(debug_dump_wdg,
|
||||
"Dump available WMI interfaces [0/1]");
|
||||
|
||||
static int acpi_wmi_remove(struct acpi_device *device);
|
||||
static int acpi_wmi_add(struct acpi_device *device);
|
||||
static void acpi_wmi_notify(struct acpi_device *device, u32 event);
|
||||
static int acpi_wmi_remove(struct platform_device *device);
|
||||
static int acpi_wmi_probe(struct platform_device *device);
|
||||
|
||||
static const struct acpi_device_id wmi_device_ids[] = {
|
||||
{"PNP0C14", 0},
|
||||
|
@ -101,15 +106,13 @@ static const struct acpi_device_id wmi_device_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
|
||||
|
||||
static struct acpi_driver acpi_wmi_driver = {
|
||||
.name = "wmi",
|
||||
.class = ACPI_WMI_CLASS,
|
||||
.ids = wmi_device_ids,
|
||||
.ops = {
|
||||
.add = acpi_wmi_add,
|
||||
.remove = acpi_wmi_remove,
|
||||
.notify = acpi_wmi_notify,
|
||||
static struct platform_driver acpi_wmi_driver = {
|
||||
.driver = {
|
||||
.name = "acpi-wmi",
|
||||
.acpi_match_table = wmi_device_ids,
|
||||
},
|
||||
.probe = acpi_wmi_probe,
|
||||
.remove = acpi_wmi_remove,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -139,6 +142,30 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
|
|||
return false;
|
||||
}
|
||||
|
||||
static int get_subobj_info(acpi_handle handle, const char *pathname,
|
||||
struct acpi_device_info **info)
|
||||
{
|
||||
struct acpi_device_info *dummy_info, **info_ptr;
|
||||
acpi_handle subobj_handle;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_get_handle(handle, (char *)pathname, &subobj_handle);
|
||||
if (status == AE_NOT_FOUND)
|
||||
return -ENOENT;
|
||||
else if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
info_ptr = info ? info : &dummy_info;
|
||||
status = acpi_get_object_info(subobj_handle, info_ptr);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
if (!info)
|
||||
kfree(dummy_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
|
||||
{
|
||||
struct guid_block *block = NULL;
|
||||
|
@ -147,7 +174,7 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
|
|||
acpi_handle handle;
|
||||
|
||||
block = &wblock->gblock;
|
||||
handle = wblock->handle;
|
||||
handle = wblock->acpi_device->handle;
|
||||
|
||||
snprintf(method, 5, "WE%02X", block->notify_id);
|
||||
status = acpi_execute_simple_method(handle, method, enable);
|
||||
|
@ -186,7 +213,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
|
|||
return AE_ERROR;
|
||||
|
||||
block = &wblock->gblock;
|
||||
handle = wblock->handle;
|
||||
handle = wblock->acpi_device->handle;
|
||||
|
||||
if (!(block->flags & ACPI_WMI_METHOD))
|
||||
return AE_BAD_DATA;
|
||||
|
@ -221,19 +248,10 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_evaluate_method);
|
||||
|
||||
/**
|
||||
* wmi_query_block - Return contents of a WMI block
|
||||
* @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
|
||||
* @instance: Instance index
|
||||
* &out: Empty buffer to return the contents of the data block to
|
||||
*
|
||||
* Return the contents of an ACPI-WMI data block to a buffer
|
||||
*/
|
||||
acpi_status wmi_query_block(const char *guid_string, u8 instance,
|
||||
struct acpi_buffer *out)
|
||||
static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
|
||||
struct acpi_buffer *out)
|
||||
{
|
||||
struct guid_block *block = NULL;
|
||||
struct wmi_block *wblock = NULL;
|
||||
acpi_handle handle;
|
||||
acpi_status status, wc_status = AE_ERROR;
|
||||
struct acpi_object_list input;
|
||||
|
@ -241,14 +259,11 @@ struct acpi_buffer *out)
|
|||
char method[5];
|
||||
char wc_method[5] = "WC";
|
||||
|
||||
if (!guid_string || !out)
|
||||
if (!out)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
if (!find_guid(guid_string, &wblock))
|
||||
return AE_ERROR;
|
||||
|
||||
block = &wblock->gblock;
|
||||
handle = wblock->handle;
|
||||
handle = wblock->acpi_device->handle;
|
||||
|
||||
if (block->instance_count < instance)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
@ -262,6 +277,9 @@ struct acpi_buffer *out)
|
|||
wq_params[0].type = ACPI_TYPE_INTEGER;
|
||||
wq_params[0].integer.value = instance;
|
||||
|
||||
if (instance == 0 && wblock->read_takes_no_args)
|
||||
input.count = 0;
|
||||
|
||||
/*
|
||||
* If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
|
||||
* enable collection.
|
||||
|
@ -294,8 +312,59 @@ struct acpi_buffer *out)
|
|||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* wmi_query_block - Return contents of a WMI block (deprecated)
|
||||
* @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
|
||||
* @instance: Instance index
|
||||
* &out: Empty buffer to return the contents of the data block to
|
||||
*
|
||||
* Return the contents of an ACPI-WMI data block to a buffer
|
||||
*/
|
||||
acpi_status wmi_query_block(const char *guid_string, u8 instance,
|
||||
struct acpi_buffer *out)
|
||||
{
|
||||
struct wmi_block *wblock;
|
||||
|
||||
if (!guid_string)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
if (!find_guid(guid_string, &wblock))
|
||||
return AE_ERROR;
|
||||
|
||||
return __query_block(wblock, instance, out);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_query_block);
|
||||
|
||||
union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance)
|
||||
{
|
||||
struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);
|
||||
|
||||
if (ACPI_FAILURE(__query_block(wblock, instance, &out)))
|
||||
return NULL;
|
||||
|
||||
return (union acpi_object *)out.pointer;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmidev_block_query);
|
||||
|
||||
struct wmi_device *wmidev_get_other_guid(struct wmi_device *wdev,
|
||||
const char *guid_string)
|
||||
{
|
||||
struct wmi_block *this_wb = container_of(wdev, struct wmi_block, dev);
|
||||
struct wmi_block *other_wb;
|
||||
|
||||
if (!find_guid(guid_string, &other_wb))
|
||||
return NULL;
|
||||
|
||||
if (other_wb->acpi_device != this_wb->acpi_device)
|
||||
return NULL;
|
||||
|
||||
get_device(&other_wb->dev.dev);
|
||||
return &other_wb->dev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmidev_get_other_guid);
|
||||
|
||||
/**
|
||||
* wmi_set_block - Write to a WMI block
|
||||
* @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
|
||||
|
@ -305,7 +374,7 @@ EXPORT_SYMBOL_GPL(wmi_query_block);
|
|||
* Write the contents of the input buffer to an ACPI-WMI data block
|
||||
*/
|
||||
acpi_status wmi_set_block(const char *guid_string, u8 instance,
|
||||
const struct acpi_buffer *in)
|
||||
const struct acpi_buffer *in)
|
||||
{
|
||||
struct guid_block *block = NULL;
|
||||
struct wmi_block *wblock = NULL;
|
||||
|
@ -321,7 +390,7 @@ const struct acpi_buffer *in)
|
|||
return AE_ERROR;
|
||||
|
||||
block = &wblock->gblock;
|
||||
handle = wblock->handle;
|
||||
handle = wblock->acpi_device->handle;
|
||||
|
||||
if (block->instance_count < instance)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
@ -352,9 +421,10 @@ EXPORT_SYMBOL_GPL(wmi_set_block);
|
|||
static void wmi_dump_wdg(const struct guid_block *g)
|
||||
{
|
||||
pr_info("%pUL:\n", g->guid);
|
||||
pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
|
||||
pr_info("\tnotify_id: %02X\n", g->notify_id);
|
||||
pr_info("\treserved: %02X\n", g->reserved);
|
||||
if (g->flags & ACPI_WMI_EVENT)
|
||||
pr_info("\tnotify_id: 0x%02X\n", g->notify_id);
|
||||
else
|
||||
pr_info("\tobject_id: %2pE\n", g->object_id);
|
||||
pr_info("\tinstance_count: %d\n", g->instance_count);
|
||||
pr_info("\tflags: %#x", g->flags);
|
||||
if (g->flags) {
|
||||
|
@ -525,8 +595,8 @@ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
|
|||
|
||||
if ((gblock->flags & ACPI_WMI_EVENT) &&
|
||||
(gblock->notify_id == event))
|
||||
return acpi_evaluate_object(wblock->handle, "_WED",
|
||||
&input, out);
|
||||
return acpi_evaluate_object(wblock->acpi_device->handle,
|
||||
"_WED", &input, out);
|
||||
}
|
||||
|
||||
return AE_NOT_FOUND;
|
||||
|
@ -545,99 +615,320 @@ bool wmi_has_guid(const char *guid_string)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_has_guid);
|
||||
|
||||
static struct wmi_block *dev_to_wblock(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct wmi_block, dev.dev);
|
||||
}
|
||||
|
||||
static struct wmi_device *dev_to_wdev(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct wmi_device, dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* sysfs interface
|
||||
*/
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct wmi_block *wblock;
|
||||
|
||||
wblock = dev_get_drvdata(dev);
|
||||
if (!wblock) {
|
||||
strcat(buf, "\n");
|
||||
return strlen(buf);
|
||||
}
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
|
||||
return sprintf(buf, "wmi:%pUL\n", wblock->gblock.guid);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
|
||||
return sprintf(buf, "%pUL\n", wblock->gblock.guid);
|
||||
}
|
||||
static DEVICE_ATTR_RO(guid);
|
||||
|
||||
static ssize_t instance_count_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", (int)wblock->gblock.instance_count);
|
||||
}
|
||||
static DEVICE_ATTR_RO(instance_count);
|
||||
|
||||
static ssize_t expensive_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
(wblock->gblock.flags & ACPI_WMI_EXPENSIVE) != 0);
|
||||
}
|
||||
static DEVICE_ATTR_RO(expensive);
|
||||
|
||||
static struct attribute *wmi_attrs[] = {
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_guid.attr,
|
||||
&dev_attr_instance_count.attr,
|
||||
&dev_attr_expensive.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(wmi);
|
||||
|
||||
static ssize_t notify_id_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
|
||||
return sprintf(buf, "%02X\n", (unsigned int)wblock->gblock.notify_id);
|
||||
}
|
||||
static DEVICE_ATTR_RO(notify_id);
|
||||
|
||||
static struct attribute *wmi_event_attrs[] = {
|
||||
&dev_attr_notify_id.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(wmi_event);
|
||||
|
||||
static ssize_t object_id_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
|
||||
return sprintf(buf, "%c%c\n", wblock->gblock.object_id[0],
|
||||
wblock->gblock.object_id[1]);
|
||||
}
|
||||
static DEVICE_ATTR_RO(object_id);
|
||||
|
||||
static ssize_t setable_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct wmi_device *wdev = dev_to_wdev(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", (int)wdev->setable);
|
||||
}
|
||||
static DEVICE_ATTR_RO(setable);
|
||||
|
||||
static struct attribute *wmi_data_attrs[] = {
|
||||
&dev_attr_object_id.attr,
|
||||
&dev_attr_setable.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(wmi_data);
|
||||
|
||||
static struct attribute *wmi_method_attrs[] = {
|
||||
&dev_attr_object_id.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(wmi_method);
|
||||
|
||||
static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
char guid_string[37];
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
|
||||
struct wmi_block *wblock;
|
||||
|
||||
if (add_uevent_var(env, "MODALIAS="))
|
||||
if (add_uevent_var(env, "MODALIAS=wmi:%pUL", wblock->gblock.guid))
|
||||
return -ENOMEM;
|
||||
|
||||
wblock = dev_get_drvdata(dev);
|
||||
if (!wblock)
|
||||
if (add_uevent_var(env, "WMI_GUID=%pUL", wblock->gblock.guid))
|
||||
return -ENOMEM;
|
||||
|
||||
sprintf(guid_string, "%pUL", wblock->gblock.guid);
|
||||
|
||||
strcpy(&env->buf[env->buflen - 1], "wmi:");
|
||||
memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
|
||||
env->buflen += 40;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wmi_dev_free(struct device *dev)
|
||||
static void wmi_dev_release(struct device *dev)
|
||||
{
|
||||
struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
|
||||
kfree(wmi_block);
|
||||
kfree(wblock);
|
||||
}
|
||||
|
||||
static struct class wmi_class = {
|
||||
.name = "wmi",
|
||||
.dev_release = wmi_dev_free,
|
||||
.dev_uevent = wmi_dev_uevent,
|
||||
.dev_groups = wmi_groups,
|
||||
static int wmi_dev_match(struct device *dev, struct device_driver *driver)
|
||||
{
|
||||
struct wmi_driver *wmi_driver =
|
||||
container_of(driver, struct wmi_driver, driver);
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
const struct wmi_device_id *id = wmi_driver->id_table;
|
||||
|
||||
while (id->guid_string) {
|
||||
uuid_le driver_guid;
|
||||
|
||||
if (WARN_ON(uuid_le_to_bin(id->guid_string, &driver_guid)))
|
||||
continue;
|
||||
if (!memcmp(&driver_guid, wblock->gblock.guid, 16))
|
||||
return 1;
|
||||
|
||||
id++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wmi_dev_probe(struct device *dev)
|
||||
{
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
struct wmi_driver *wdriver =
|
||||
container_of(dev->driver, struct wmi_driver, driver);
|
||||
int ret = 0;
|
||||
|
||||
if (ACPI_FAILURE(wmi_method_enable(wblock, 1)))
|
||||
dev_warn(dev, "failed to enable device -- probing anyway\n");
|
||||
|
||||
if (wdriver->probe) {
|
||||
ret = wdriver->probe(dev_to_wdev(dev));
|
||||
if (ret != 0 && ACPI_FAILURE(wmi_method_enable(wblock, 0)))
|
||||
dev_warn(dev, "failed to disable device\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wmi_dev_remove(struct device *dev)
|
||||
{
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
struct wmi_driver *wdriver =
|
||||
container_of(dev->driver, struct wmi_driver, driver);
|
||||
int ret = 0;
|
||||
|
||||
if (wdriver->remove)
|
||||
ret = wdriver->remove(dev_to_wdev(dev));
|
||||
|
||||
if (ACPI_FAILURE(wmi_method_enable(wblock, 0)))
|
||||
dev_warn(dev, "failed to disable device\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct class wmi_bus_class = {
|
||||
.name = "wmi_bus",
|
||||
};
|
||||
|
||||
static int wmi_create_device(const struct guid_block *gblock,
|
||||
struct wmi_block *wblock, acpi_handle handle)
|
||||
static struct bus_type wmi_bus_type = {
|
||||
.name = "wmi",
|
||||
.dev_groups = wmi_groups,
|
||||
.match = wmi_dev_match,
|
||||
.uevent = wmi_dev_uevent,
|
||||
.probe = wmi_dev_probe,
|
||||
.remove = wmi_dev_remove,
|
||||
};
|
||||
|
||||
static struct device_type wmi_type_event = {
|
||||
.name = "event",
|
||||
.groups = wmi_event_groups,
|
||||
.release = wmi_dev_release,
|
||||
};
|
||||
|
||||
static struct device_type wmi_type_method = {
|
||||
.name = "method",
|
||||
.groups = wmi_method_groups,
|
||||
.release = wmi_dev_release,
|
||||
};
|
||||
|
||||
static struct device_type wmi_type_data = {
|
||||
.name = "data",
|
||||
.groups = wmi_data_groups,
|
||||
.release = wmi_dev_release,
|
||||
};
|
||||
|
||||
static int wmi_create_device(struct device *wmi_bus_dev,
|
||||
const struct guid_block *gblock,
|
||||
struct wmi_block *wblock,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
wblock->dev.class = &wmi_class;
|
||||
struct acpi_device_info *info;
|
||||
char method[5];
|
||||
int result;
|
||||
|
||||
dev_set_name(&wblock->dev, "%pUL", gblock->guid);
|
||||
if (gblock->flags & ACPI_WMI_EVENT) {
|
||||
wblock->dev.dev.type = &wmi_type_event;
|
||||
goto out_init;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&wblock->dev, wblock);
|
||||
if (gblock->flags & ACPI_WMI_METHOD) {
|
||||
wblock->dev.dev.type = &wmi_type_method;
|
||||
goto out_init;
|
||||
}
|
||||
|
||||
return device_register(&wblock->dev);
|
||||
/*
|
||||
* Data Block Query Control Method (WQxx by convention) is
|
||||
* required per the WMI documentation. If it is not present,
|
||||
* we ignore this data block.
|
||||
*/
|
||||
strcpy(method, "WQ");
|
||||
strncat(method, wblock->gblock.object_id, 2);
|
||||
result = get_subobj_info(device->handle, method, &info);
|
||||
|
||||
if (result) {
|
||||
dev_warn(wmi_bus_dev,
|
||||
"%s data block query control method not found",
|
||||
method);
|
||||
return result;
|
||||
}
|
||||
|
||||
wblock->dev.dev.type = &wmi_type_data;
|
||||
|
||||
/*
|
||||
* The Microsoft documentation specifically states:
|
||||
*
|
||||
* Data blocks registered with only a single instance
|
||||
* can ignore the parameter.
|
||||
*
|
||||
* ACPICA will get mad at us if we call the method with the wrong number
|
||||
* of arguments, so check what our method expects. (On some Dell
|
||||
* laptops, WQxx may not be a method at all.)
|
||||
*/
|
||||
if (info->type != ACPI_TYPE_METHOD || info->param_count == 0)
|
||||
wblock->read_takes_no_args = true;
|
||||
|
||||
kfree(info);
|
||||
|
||||
strcpy(method, "WS");
|
||||
strncat(method, wblock->gblock.object_id, 2);
|
||||
result = get_subobj_info(device->handle, method, NULL);
|
||||
|
||||
if (result == 0)
|
||||
wblock->dev.setable = true;
|
||||
|
||||
out_init:
|
||||
wblock->dev.dev.bus = &wmi_bus_type;
|
||||
wblock->dev.dev.parent = wmi_bus_dev;
|
||||
|
||||
dev_set_name(&wblock->dev.dev, "%pUL", gblock->guid);
|
||||
|
||||
device_initialize(&wblock->dev.dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wmi_free_devices(void)
|
||||
static void wmi_free_devices(struct acpi_device *device)
|
||||
{
|
||||
struct wmi_block *wblock, *next;
|
||||
|
||||
/* Delete devices for all the GUIDs */
|
||||
list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
|
||||
list_del(&wblock->list);
|
||||
if (wblock->dev.class)
|
||||
device_unregister(&wblock->dev);
|
||||
else
|
||||
kfree(wblock);
|
||||
if (wblock->acpi_device == device) {
|
||||
list_del(&wblock->list);
|
||||
device_unregister(&wblock->dev.dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool guid_already_parsed(const char *guid_string)
|
||||
static bool guid_already_parsed(struct acpi_device *device,
|
||||
const u8 *guid)
|
||||
{
|
||||
struct wmi_block *wblock;
|
||||
|
||||
list_for_each_entry(wblock, &wmi_block_list, list)
|
||||
if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
|
||||
list_for_each_entry(wblock, &wmi_block_list, list) {
|
||||
if (memcmp(wblock->gblock.guid, guid, 16) == 0) {
|
||||
/*
|
||||
* Because we historically didn't track the relationship
|
||||
* between GUIDs and ACPI nodes, we don't know whether
|
||||
* we need to suppress GUIDs that are unique on a
|
||||
* given node but duplicated across nodes.
|
||||
*/
|
||||
dev_warn(&device->dev, "duplicate WMI GUID %pUL (first instance was on %s)\n",
|
||||
guid, dev_name(&wblock->acpi_device->dev));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -645,17 +936,17 @@ static bool guid_already_parsed(const char *guid_string)
|
|||
/*
|
||||
* Parse the _WDG method for the GUID data blocks
|
||||
*/
|
||||
static int parse_wdg(acpi_handle handle)
|
||||
static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
|
||||
{
|
||||
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
union acpi_object *obj;
|
||||
const struct guid_block *gblock;
|
||||
struct wmi_block *wblock;
|
||||
struct wmi_block *wblock, *next;
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
int retval;
|
||||
int retval = 0;
|
||||
u32 i, total;
|
||||
|
||||
status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
|
||||
status = acpi_evaluate_object(device->handle, "_WDG", NULL, &out);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENXIO;
|
||||
|
||||
|
@ -675,25 +966,28 @@ static int parse_wdg(acpi_handle handle)
|
|||
if (debug_dump_wdg)
|
||||
wmi_dump_wdg(&gblock[i]);
|
||||
|
||||
wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
|
||||
if (!wblock)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* Some WMI devices, like those for nVidia hooks, have a
|
||||
* duplicate GUID. It's not clear what we should do in this
|
||||
* case yet, so for now, we'll just ignore the duplicate
|
||||
* for device creation.
|
||||
*/
|
||||
if (guid_already_parsed(device, gblock[i].guid))
|
||||
continue;
|
||||
|
||||
wblock->handle = handle;
|
||||
wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
|
||||
if (!wblock) {
|
||||
retval = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
wblock->acpi_device = device;
|
||||
wblock->gblock = gblock[i];
|
||||
|
||||
/*
|
||||
Some WMI devices, like those for nVidia hooks, have a
|
||||
duplicate GUID. It's not clear what we should do in this
|
||||
case yet, so for now, we'll just ignore the duplicate
|
||||
for device creation.
|
||||
*/
|
||||
if (!guid_already_parsed(gblock[i].guid)) {
|
||||
retval = wmi_create_device(&gblock[i], wblock, handle);
|
||||
if (retval) {
|
||||
wmi_free_devices();
|
||||
goto out_free_pointer;
|
||||
}
|
||||
retval = wmi_create_device(wmi_bus_dev, &gblock[i], wblock, device);
|
||||
if (retval) {
|
||||
kfree(wblock);
|
||||
continue;
|
||||
}
|
||||
|
||||
list_add_tail(&wblock->list, &wmi_block_list);
|
||||
|
@ -704,11 +998,27 @@ static int parse_wdg(acpi_handle handle)
|
|||
}
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
/*
|
||||
* Now that all of the devices are created, add them to the
|
||||
* device tree and probe subdrivers.
|
||||
*/
|
||||
list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
|
||||
if (wblock->acpi_device != device)
|
||||
continue;
|
||||
|
||||
retval = device_add(&wblock->dev.dev);
|
||||
if (retval) {
|
||||
dev_err(wmi_bus_dev, "failed to register %pULL\n",
|
||||
wblock->gblock.guid);
|
||||
if (debug_event)
|
||||
wmi_method_enable(wblock, 0);
|
||||
list_del(&wblock->list);
|
||||
put_device(&wblock->dev.dev);
|
||||
}
|
||||
}
|
||||
|
||||
out_free_pointer:
|
||||
kfree(out.pointer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -756,68 +1066,169 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
|
|||
}
|
||||
}
|
||||
|
||||
static void acpi_wmi_notify(struct acpi_device *device, u32 event)
|
||||
static void acpi_wmi_notify_handler(acpi_handle handle, u32 event,
|
||||
void *context)
|
||||
{
|
||||
struct guid_block *block;
|
||||
struct wmi_block *wblock;
|
||||
struct list_head *p;
|
||||
bool found_it = false;
|
||||
|
||||
list_for_each(p, &wmi_block_list) {
|
||||
wblock = list_entry(p, struct wmi_block, list);
|
||||
block = &wblock->gblock;
|
||||
|
||||
if ((block->flags & ACPI_WMI_EVENT) &&
|
||||
(block->notify_id == event)) {
|
||||
if (wblock->handler)
|
||||
wblock->handler(event, wblock->handler_data);
|
||||
if (debug_event) {
|
||||
pr_info("DEBUG Event GUID: %pUL\n",
|
||||
wblock->gblock.guid);
|
||||
}
|
||||
|
||||
acpi_bus_generate_netlink_event(
|
||||
device->pnp.device_class, dev_name(&device->dev),
|
||||
event, 0);
|
||||
if (wblock->acpi_device->handle == handle &&
|
||||
(block->flags & ACPI_WMI_EVENT) &&
|
||||
(block->notify_id == event))
|
||||
{
|
||||
found_it = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_it)
|
||||
return;
|
||||
|
||||
/* If a driver is bound, then notify the driver. */
|
||||
if (wblock->dev.dev.driver) {
|
||||
struct wmi_driver *driver;
|
||||
struct acpi_object_list input;
|
||||
union acpi_object params[1];
|
||||
struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_status status;
|
||||
|
||||
driver = container_of(wblock->dev.dev.driver,
|
||||
struct wmi_driver, driver);
|
||||
|
||||
input.count = 1;
|
||||
input.pointer = params;
|
||||
params[0].type = ACPI_TYPE_INTEGER;
|
||||
params[0].integer.value = event;
|
||||
|
||||
status = acpi_evaluate_object(wblock->acpi_device->handle,
|
||||
"_WED", &input, &evdata);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_warn(&wblock->dev.dev,
|
||||
"failed to get event data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (driver->notify)
|
||||
driver->notify(&wblock->dev,
|
||||
(union acpi_object *)evdata.pointer);
|
||||
|
||||
kfree(evdata.pointer);
|
||||
} else if (wblock->handler) {
|
||||
/* Legacy handler */
|
||||
wblock->handler(event, wblock->handler_data);
|
||||
}
|
||||
|
||||
if (debug_event) {
|
||||
pr_info("DEBUG Event GUID: %pUL\n",
|
||||
wblock->gblock.guid);
|
||||
}
|
||||
|
||||
acpi_bus_generate_netlink_event(
|
||||
wblock->acpi_device->pnp.device_class,
|
||||
dev_name(&wblock->dev.dev),
|
||||
event, 0);
|
||||
|
||||
}
|
||||
|
||||
static int acpi_wmi_remove(struct acpi_device *device)
|
||||
static int acpi_wmi_remove(struct platform_device *device)
|
||||
{
|
||||
acpi_remove_address_space_handler(device->handle,
|
||||
struct acpi_device *acpi_device = ACPI_COMPANION(&device->dev);
|
||||
|
||||
acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY,
|
||||
acpi_wmi_notify_handler);
|
||||
acpi_remove_address_space_handler(acpi_device->handle,
|
||||
ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
|
||||
wmi_free_devices();
|
||||
wmi_free_devices(acpi_device);
|
||||
device_unregister((struct device *)dev_get_drvdata(&device->dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_wmi_add(struct acpi_device *device)
|
||||
static int acpi_wmi_probe(struct platform_device *device)
|
||||
{
|
||||
struct acpi_device *acpi_device;
|
||||
struct device *wmi_bus_dev;
|
||||
acpi_status status;
|
||||
int error;
|
||||
|
||||
status = acpi_install_address_space_handler(device->handle,
|
||||
acpi_device = ACPI_COMPANION(&device->dev);
|
||||
if (!acpi_device) {
|
||||
dev_err(&device->dev, "ACPI companion is missing\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
status = acpi_install_address_space_handler(acpi_device->handle,
|
||||
ACPI_ADR_SPACE_EC,
|
||||
&acpi_wmi_ec_space_handler,
|
||||
NULL, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_err("Error installing EC region handler\n");
|
||||
dev_err(&device->dev, "Error installing EC region handler\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
error = parse_wdg(device->handle);
|
||||
status = acpi_install_notify_handler(acpi_device->handle,
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
acpi_wmi_notify_handler,
|
||||
NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(&device->dev, "Error installing notify handler\n");
|
||||
error = -ENODEV;
|
||||
goto err_remove_ec_handler;
|
||||
}
|
||||
|
||||
wmi_bus_dev = device_create(&wmi_bus_class, &device->dev, MKDEV(0, 0),
|
||||
NULL, "wmi_bus-%s", dev_name(&device->dev));
|
||||
if (IS_ERR(wmi_bus_dev)) {
|
||||
error = PTR_ERR(wmi_bus_dev);
|
||||
goto err_remove_notify_handler;
|
||||
}
|
||||
dev_set_drvdata(&device->dev, wmi_bus_dev);
|
||||
|
||||
error = parse_wdg(wmi_bus_dev, acpi_device);
|
||||
if (error) {
|
||||
acpi_remove_address_space_handler(device->handle,
|
||||
ACPI_ADR_SPACE_EC,
|
||||
&acpi_wmi_ec_space_handler);
|
||||
pr_err("Failed to parse WDG method\n");
|
||||
return error;
|
||||
goto err_remove_busdev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_busdev:
|
||||
device_unregister(wmi_bus_dev);
|
||||
|
||||
err_remove_notify_handler:
|
||||
acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY,
|
||||
acpi_wmi_notify_handler);
|
||||
|
||||
err_remove_ec_handler:
|
||||
acpi_remove_address_space_handler(acpi_device->handle,
|
||||
ACPI_ADR_SPACE_EC,
|
||||
&acpi_wmi_ec_space_handler);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int __must_check __wmi_driver_register(struct wmi_driver *driver,
|
||||
struct module *owner)
|
||||
{
|
||||
driver->driver.owner = owner;
|
||||
driver->driver.bus = &wmi_bus_type;
|
||||
|
||||
return driver_register(&driver->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(__wmi_driver_register);
|
||||
|
||||
void wmi_driver_unregister(struct wmi_driver *driver)
|
||||
{
|
||||
driver_unregister(&driver->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(wmi_driver_unregister);
|
||||
|
||||
static int __init acpi_wmi_init(void)
|
||||
{
|
||||
int error;
|
||||
|
@ -825,27 +1236,36 @@ static int __init acpi_wmi_init(void)
|
|||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
error = class_register(&wmi_class);
|
||||
error = class_register(&wmi_bus_class);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = acpi_bus_register_driver(&acpi_wmi_driver);
|
||||
error = bus_register(&wmi_bus_type);
|
||||
if (error)
|
||||
goto err_unreg_class;
|
||||
|
||||
error = platform_driver_register(&acpi_wmi_driver);
|
||||
if (error) {
|
||||
pr_err("Error loading mapper\n");
|
||||
class_unregister(&wmi_class);
|
||||
return error;
|
||||
goto err_unreg_bus;
|
||||
}
|
||||
|
||||
pr_info("Mapper loaded\n");
|
||||
return 0;
|
||||
|
||||
err_unreg_class:
|
||||
class_unregister(&wmi_bus_class);
|
||||
|
||||
err_unreg_bus:
|
||||
bus_unregister(&wmi_bus_type);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void __exit acpi_wmi_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&acpi_wmi_driver);
|
||||
class_unregister(&wmi_class);
|
||||
|
||||
pr_info("Mapper unloaded\n");
|
||||
platform_driver_unregister(&acpi_wmi_driver);
|
||||
class_unregister(&wmi_bus_class);
|
||||
bus_unregister(&wmi_bus_type);
|
||||
}
|
||||
|
||||
subsys_initcall(acpi_wmi_init);
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* wmi.h - ACPI WMI interface
|
||||
*
|
||||
* Copyright (c) 2015 Andrew Lutomirski
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_WMI_H
|
||||
#define _LINUX_WMI_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
struct wmi_device {
|
||||
struct device dev;
|
||||
|
||||
/* True for data blocks implementing the Set Control Method */
|
||||
bool setable;
|
||||
};
|
||||
|
||||
/* Caller must kfree the result. */
|
||||
extern union acpi_object *wmidev_block_query(struct wmi_device *wdev,
|
||||
u8 instance);
|
||||
|
||||
/* Gets another device on the same bus. Caller must put_device the result. */
|
||||
extern struct wmi_device *wmidev_get_other_guid(struct wmi_device *wdev,
|
||||
const char *guid_string);
|
||||
|
||||
struct wmi_device_id {
|
||||
const char *guid_string;
|
||||
};
|
||||
|
||||
struct wmi_driver {
|
||||
struct device_driver driver;
|
||||
const struct wmi_device_id *id_table;
|
||||
|
||||
int (*probe)(struct wmi_device *wdev);
|
||||
int (*remove)(struct wmi_device *wdev);
|
||||
void (*notify)(struct wmi_device *device, union acpi_object *data);
|
||||
};
|
||||
|
||||
extern int __must_check __wmi_driver_register(struct wmi_driver *driver,
|
||||
struct module *owner);
|
||||
extern void wmi_driver_unregister(struct wmi_driver *driver);
|
||||
#define wmi_driver_register(driver) __wmi_driver_register((driver), THIS_MODULE)
|
||||
|
||||
#define module_wmi_driver(__wmi_driver) \
|
||||
module_driver(__wmi_driver, wmi_driver_register, \
|
||||
wmi_driver_unregister)
|
||||
|
||||
#endif
|
Загрузка…
Ссылка в новой задаче