Commit 5a010c73 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v4.6-1' of...

Merge tag 'platform-drivers-x86-v4.6-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86

Pull x86 platform driver updates from Darren Hart:
 "Significant refactoring of Dell laptop drivers, modularizing the
  smbios code.  Multiple new platforms added for ideapad, asus, dell,
  and alienware using existing quirks.  A few fixes and cleanups.

  hp-wmi:
   - Remove GPS rfkill support via pre-2009 interface
   - fix unregister order in hp_wmi_rfkill_setup() once again

  ideapad-laptop:
   - Add ideapad Y700 (15) to the no_hw_rfkill DMI list

  fujitsu-laptop:
   - Support radio toggle button

  intel-hid:
   - allocate correct amount of memory for private struct

  platform/x86:
   - Make intel_scu_ipc explicitly non-modular

  intel_pmc_ipc:
   - Avoid pending IPC1 command during legacy suspend
   - Fix GCR register base address and length

  asus-nb-wmi:
   - add wapf=4 quirk for ASUS X75VD

  intel_telemetry_pltdrv:
   - Change verbosity control bits

  dell-rbtn:
   - Add a comment about the XPS 13 9350

  dell-wmi, dell-laptop:
   - depends DMI

  dell-wmi:
   - support Dell Inspiron M5110
   - properly process Dell Instant Launch hotkey
   - enable receiving WMI events on Dell Vostro V131
   - Support new hotkeys on the XPS 13 9350 (Skylake)
   - Clean up hotkey table size check
   - Stop storing pointers to DMI tables

  dell-laptop:
   - move dell_smi_error() to dell-smbios
   - use dell_smbios_find_token() instead of find_token_location()
   - use dell_smbios_find_token() instead of find_token_id()
   - extract SMBIOS-related code to a separate module

  dell-smbios:
   - rename dell_smi_error() to dell_smbios_error()
   - make da_tokens static
   - remove find_token_{id,location}()
   - implement new function for finding DMI table 0xDA tokens
   - make the SMBIOS buffer static
   - return the SMBIOS buffer from dell_smbios_get_buffer()
   - don't return an SMBIOS buffer from dell_smbios_send_request()
   - don't pass an SMBIOS buffer to dell_smbios_send_request()
   - rename dell_send_request() to dell_smbios_send_request()
   - rename release_buffer() to dell_smbios_release_buffer()
   - rename clear_buffer() to dell_smbios_clear_buffer()
   - rename get_buffer() to dell_smbios_get_buffer()

  dell-led:
   - use dell_smbios_send_request() for performing SMBIOS calls
   - use dell_smbios_find_token() for finding mic DMI tokens

  toshiba_acpi:
   - Add a module parameter to disable hotkeys registration
   - Add sysfs entries for the Cooling Method feature
   - Add support for cooling method feature

  Documentation/ABI:
   - Update sysfs-driver-toshiba_acpi file

  thinkpad_acpi:
   - Remove ambiguous logging for "Unsupported brightness interface"

  alienware-wmi:
   - whitespace improvements
   - Add support for two new systems: ASM200 and ASM201.
   - Add support for deep sleep control.
   - Add initial support for alienware graphics amplifier.
   - Add support for new platform: X51-R3
   - Clean up whitespace for ASM100 platform"

* tag 'platform-drivers-x86-v4.6-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (47 commits)
  hp-wmi: Remove GPS rfkill support via pre-2009 interface
  hp-wmi: fix unregister order in hp_wmi_rfkill_setup() once again
  dell-wmi: support Dell Inspiron M5110
  dell-wmi: properly process Dell Instant Launch hotkey
  dell-wmi: enable receiving WMI events on Dell Vostro V131
  dell-smbios: rename dell_smi_error() to dell_smbios_error()
  dell-laptop: move dell_smi_error() to dell-smbios
  ideapad-laptop: Add ideapad Y700 (15) to the no_hw_rfkill DMI list
  fujitsu-laptop: Support radio toggle button
  intel-hid: allocate correct amount of memory for private struct
  platform/x86: Make intel_scu_ipc explicitly non-modular
  intel_pmc_ipc: Avoid pending IPC1 command during legacy suspend
  intel_pmc_ipc: Fix GCR register base address and length
  asus-nb-wmi: add wapf=4 quirk for ASUS X75VD
  intel_telemetry_pltdrv: Change verbosity control bits
  dell-rbtn: Add a comment about the XPS 13 9350
  dell-wmi: Support new hotkeys on the XPS 13 9350 (Skylake)
  dell-wmi: Clean up hotkey table size check
  dell-wmi, dell-laptop: depends DMI
  dell-wmi: Stop storing pointers to DMI tables
  ...
parents b615d3d4 fffcad87
......@@ -179,3 +179,19 @@ Description: This file controls the USB 3 functionality, valid values are:
Note that toggling this value requires a reboot for changes to
take effect.
Users: KToshiba
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/cooling_method
Date: 2016
KernelVersion: 4.6
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file controls the Cooling Method feature.
Reading this file prints two values, the first is the actual cooling method
and the second is the maximum cooling method supported.
When the maximum cooling method is ONE, valid values are:
* 0 -> Maximum Performance
* 1 -> Battery Optimized
When the maximum cooling method is TWO, valid values are:
* 0 -> Maximum Performance
* 1 -> Performance
* 2 -> Battery Optimized
Users: KToshiba
......@@ -443,6 +443,7 @@ config LEDS_DELL_NETBOOKS
tristate "External LED on Dell Business Netbooks"
depends on LEDS_CLASS
depends on X86 && ACPI_WMI
depends on DELL_SMBIOS
help
This adds support for the Latitude 2100 and similar
notebooks that have an external LED.
......
......@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/dmi.h>
#include <linux/dell-led.h>
#include "../platform/x86/dell-smbios.h"
MODULE_AUTHOR("Louis Davis/Jim Dailey");
MODULE_DESCRIPTION("Dell LED Control Driver");
......@@ -42,120 +43,32 @@ MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID);
#define CMD_LED_OFF 17
#define CMD_LED_BLINK 18
struct app_wmi_args {
u16 class;
u16 selector;
u32 arg1;
u32 arg2;
u32 arg3;
u32 arg4;
u32 res1;
u32 res2;
u32 res3;
u32 res4;
char dummy[92];
};
#define GLOBAL_MIC_MUTE_ENABLE 0x364
#define GLOBAL_MIC_MUTE_DISABLE 0x365
struct dell_bios_data_token {
u16 tokenid;
u16 location;
u16 value;
};
struct __attribute__ ((__packed__)) dell_bios_calling_interface {
struct dmi_header header;
u16 cmd_io_addr;
u8 cmd_io_code;
u32 supported_cmds;
struct dell_bios_data_token damap[];
};
static struct dell_bios_data_token dell_mic_tokens[2];
static int dell_wmi_perform_query(struct app_wmi_args *args)
{
struct app_wmi_args *bios_return;
union acpi_object *obj;
struct acpi_buffer input;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_status status;
u32 rc = -EINVAL;
input.length = 128;
input.pointer = args;
status = wmi_evaluate_method(DELL_APP_GUID, 0, 1, &input, &output);
if (!ACPI_SUCCESS(status))
goto err_out0;
obj = output.pointer;
if (!obj)
goto err_out0;
if (obj->type != ACPI_TYPE_BUFFER)
goto err_out1;
bios_return = (struct app_wmi_args *)obj->buffer.pointer;
rc = bios_return->res1;
if (rc)
goto err_out1;
memcpy(args, bios_return, sizeof(struct app_wmi_args));
rc = 0;
err_out1:
kfree(obj);
err_out0:
return rc;
}
static void __init find_micmute_tokens(const struct dmi_header *dm, void *dummy)
{
struct dell_bios_calling_interface *calling_interface;
struct dell_bios_data_token *token;
int token_size = sizeof(struct dell_bios_data_token);
int i = 0;
if (dm->type == 0xda && dm->length > 17) {
calling_interface = container_of(dm,
struct dell_bios_calling_interface, header);
token = &calling_interface->damap[i];
while (token->tokenid != 0xffff) {
if (token->tokenid == GLOBAL_MIC_MUTE_DISABLE)
memcpy(&dell_mic_tokens[0], token, token_size);
else if (token->tokenid == GLOBAL_MIC_MUTE_ENABLE)
memcpy(&dell_mic_tokens[1], token, token_size);
i++;
token = &calling_interface->damap[i];
}
}
}
static int dell_micmute_led_set(int state)
{
struct app_wmi_args args;
struct dell_bios_data_token *token;
struct calling_interface_buffer *buffer;
struct calling_interface_token *token;
if (!wmi_has_guid(DELL_APP_GUID))
return -ENODEV;
if (state == 0 || state == 1)
token = &dell_mic_tokens[state];
if (state == 0)
token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE);
else if (state == 1)
token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
else
return -EINVAL;
memset(&args, 0, sizeof(struct app_wmi_args));
args.class = 1;
args.arg1 = token->location;
args.arg2 = token->value;
if (!token)
return -ENODEV;
dell_wmi_perform_query(&args);
buffer = dell_smbios_get_buffer();
buffer->input[0] = token->location;
buffer->input[1] = token->value;
dell_smbios_send_request(1, 0);
dell_smbios_release_buffer();
return state;
}
......@@ -177,14 +90,6 @@ int dell_app_wmi_led_set(int whichled, int on)
}
EXPORT_SYMBOL_GPL(dell_app_wmi_led_set);
static int __init dell_micmute_led_init(void)
{
memset(dell_mic_tokens, 0, sizeof(struct dell_bios_data_token) * 2);
dmi_walk(find_micmute_tokens, NULL);
return 0;
}
struct bios_args {
unsigned char length;
unsigned char result_code;
......@@ -330,9 +235,6 @@ static int __init dell_led_init(void)
if (!wmi_has_guid(DELL_LED_BIOS_GUID) && !wmi_has_guid(DELL_APP_GUID))
return -ENODEV;
if (wmi_has_guid(DELL_APP_GUID))
error = dell_micmute_led_init();
if (wmi_has_guid(DELL_LED_BIOS_GUID)) {
error = led_off();
if (error != 0)
......
......@@ -91,10 +91,21 @@ config ASUS_LAPTOP
If you have an ACPI-compatible ASUS laptop, say Y or M here.
config DELL_SMBIOS
tristate "Dell SMBIOS Support"
depends on DCDBAS
default n
---help---
This module provides common functions for kernel modules using
Dell SMBIOS.
If you have a Dell laptop, say Y or M here.
config DELL_LAPTOP
tristate "Dell Laptop Extras"
depends on X86
depends on DCDBAS
depends on DELL_SMBIOS
depends on DMI
depends on BACKLIGHT_CLASS_DEVICE
depends on ACPI_VIDEO || ACPI_VIDEO = n
depends on RFKILL || RFKILL = n
......@@ -110,8 +121,10 @@ config DELL_LAPTOP
config DELL_WMI
tristate "Dell WMI extras"
depends on ACPI_WMI
depends on DMI
depends on INPUT
depends on ACPI_VIDEO || ACPI_VIDEO = n
depends on DELL_SMBIOS
select INPUT_SPARSEKMAP
---help---
Say Y here if you want to support WMI-based hotkeys on Dell laptops.
......
......@@ -11,6 +11,7 @@ obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o
obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o
obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
obj-$(CONFIG_DELL_WMI) += dell-wmi.o
obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
......
This diff is collapsed.
......@@ -270,6 +270,15 @@ static const struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. X75VD",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X75VD"),
},
.driver_data = &quirk_asus_wapf4,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. 1015E",
......
This diff is collapsed.
......@@ -217,6 +217,21 @@ static void rbtn_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id rbtn_ids[] = {
{ "DELRBTN", 0 },
{ "DELLABCE", 0 },
/*
* 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.
*
* 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.
*/
{ "", 0 },
};
......
/*
* Common functions for kernel modules using Dell SMBIOS
*
* Copyright (c) Red Hat <mjg@redhat.com>
* Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
* Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
*
* Based on documentation in the libsmbios package:
* Copyright (C) 2005-2014 Dell Inc.
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/gfp.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/io.h>
#include "../../firmware/dcdbas.h"
#include "dell-smbios.h"
struct calling_interface_structure {
struct dmi_header header;
u16 cmdIOAddress;
u8 cmdIOCode;
u32 supportedCmds;
struct calling_interface_token tokens[];
} __packed;
static struct calling_interface_buffer *buffer;
static DEFINE_MUTEX(buffer_mutex);
static int da_command_address;
static int da_command_code;
static int da_num_tokens;
static struct calling_interface_token *da_tokens;
int dell_smbios_error(int value)
{
switch (value) {
case 0: /* Completed successfully */
return 0;
case -1: /* Completed with error */
return -EIO;
case -2: /* Function not supported */
return -ENXIO;
default: /* Unknown error */
return -EINVAL;
}
}
EXPORT_SYMBOL_GPL(dell_smbios_error);
struct calling_interface_buffer *dell_smbios_get_buffer(void)
{
mutex_lock(&buffer_mutex);
dell_smbios_clear_buffer();
return buffer;
}
EXPORT_SYMBOL_GPL(dell_smbios_get_buffer);
void dell_smbios_clear_buffer(void)
{
memset(buffer, 0, sizeof(struct calling_interface_buffer));
}
EXPORT_SYMBOL_GPL(dell_smbios_clear_buffer);
void dell_smbios_release_buffer(void)
{
mutex_unlock(&buffer_mutex);
}
EXPORT_SYMBOL_GPL(dell_smbios_release_buffer);
void dell_smbios_send_request(int class, int select)
{
struct smi_cmd command;
command.magic = SMI_CMD_MAGIC;
command.command_address = da_command_address;
command.command_code = da_command_code;
command.ebx = virt_to_phys(buffer);
command.ecx = 0x42534931;
buffer->class = class;
buffer->select = select;
dcdbas_smi_request(&command);
}
EXPORT_SYMBOL_GPL(dell_smbios_send_request);
struct calling_interface_token *dell_smbios_find_token(int tokenid)
{
int i;
for (i = 0; i < da_num_tokens; i++) {
if (da_tokens[i].tokenID == tokenid)
return &da_tokens[i];
}
return NULL;
}
EXPORT_SYMBOL_GPL(dell_smbios_find_token);
static void __init parse_da_table(const struct dmi_header *dm)
{
/* Final token is a terminator, so we don't want to copy it */
int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1;
struct calling_interface_token *new_da_tokens;
struct calling_interface_structure *table =
container_of(dm, struct calling_interface_structure, header);
/* 4 bytes of table header, plus 7 bytes of Dell header, plus at least
6 bytes of entry */
if (dm->length < 17)
return;
da_command_address = table->cmdIOAddress;
da_command_code = table->cmdIOCode;
new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) *
sizeof(struct calling_interface_token),
GFP_KERNEL);
if (!new_da_tokens)
return;
da_tokens = new_da_tokens;
memcpy(da_tokens+da_num_tokens, table->tokens,
sizeof(struct calling_interface_token) * tokens);
da_num_tokens += tokens;
}
static void __init find_tokens(const struct dmi_header *dm, void *dummy)
{
switch (dm->type) {
case 0xd4: /* Indexed IO */
case 0xd5: /* Protected Area Type 1 */
case 0xd6: /* Protected Area Type 2 */
break;
case 0xda: /* Calling interface */
parse_da_table(dm);
break;
}
}
static int __init dell_smbios_init(void)
{
int ret;
dmi_walk(find_tokens, NULL);
if (!da_tokens) {
pr_info("Unable to find dmi tokens\n");
return -ENODEV;
}
/*
* Allocate buffer below 4GB for SMI data--only 32-bit physical addr
* is passed to SMI handler.
*/
buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32);
if (!buffer) {
ret = -ENOMEM;
goto fail_buffer;
}
return 0;
fail_buffer:
kfree(da_tokens);
return ret;
}
static void __exit dell_smbios_exit(void)
{
kfree(da_tokens);
free_page((unsigned long)buffer);
}
subsys_initcall(dell_smbios_init);
module_exit(dell_smbios_exit);
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS");
MODULE_LICENSE("GPL");
/*
* Common functions for kernel modules using Dell SMBIOS
*
* Copyright (c) Red Hat <mjg@redhat.com>
* Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
* Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
*
* Based on documentation in the libsmbios package:
* Copyright (C) 2005-2014 Dell Inc.
*
* 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.
*/
#ifndef _DELL_SMBIOS_H_
#define _DELL_SMBIOS_H_
/* This structure will be modified by the firmware when we enter
* system management mode, hence the volatiles */
struct calling_interface_buffer {
u16 class;
u16 select;
volatile u32 input[4];
volatile u32 output[4];
} __packed;
struct calling_interface_token {
u16 tokenID;
u16 location;
union {
u16 value;
u16 stringlength;
};
};
int dell_smbios_error(int value);
struct calling_interface_buffer *dell_smbios_get_buffer(void);
void dell_smbios_clear_buffer(void);
void dell_smbios_release_buffer(void);
void dell_smbios_send_request(int class, int select);
struct calling_interface_token *dell_smbios_find_token(int tokenid);
#endif
......@@ -37,6 +37,7 @@
#include <linux/string.h>
#include <linux/dmi.h>
#include <acpi/video.h>
#include "dell-smbios.h"
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
......@@ -47,10 +48,37 @@ MODULE_LICENSE("GPL");
#define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
static u32 dell_wmi_interface_version;
static bool wmi_requires_smbios_request;
MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID);
static int __init dmi_matched(const struct dmi_system_id *dmi)
{
wmi_requires_smbios_request = 1;
return 1;
}
static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = {
{
.callback = dmi_matched,
.ident = "Dell Inspiron M5110",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"),
},
},
{
.callback = dmi_matched,
.ident = "Dell Vostro V131",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
},
},
{ }
};
/*
* Certain keys are flagged as KE_IGNORE. All of these are either
* notifications (rather than requests for change) or are also sent
......@@ -90,8 +118,11 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
{ KE_IGNORE, 0xe020, { KEY_MUTE } },
/* Shortcut and audio panel keys */
{ KE_IGNORE, 0xe025, { KEY_RESERVED } },
/* Dell Instant Launch key */
{ KE_KEY, 0xe025, { KEY_PROG4 } },
{ KE_KEY, 0xe029, { KEY_PROG4 } },
/* Audio panel key */
{ KE_IGNORE, 0xe026, { KEY_RESERVED } },
{ KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },
......@@ -120,7 +151,10 @@ struct dell_bios_hotkey_table {
};
static const struct dell_bios_hotkey_table *dell_bios_hotkey_table;
struct dell_dmi_results {
int err;
struct key_entry *keymap;
};
/* Uninitialized entries here are KEY_RESERVED == 0. */
static const u16 bios_to_linux_keycode[256] __initconst = {
......@@ -166,6 +200,30 @@ static const u16 bios_to_linux_keycode[256] __initconst = {
[255] = KEY_PROG3,
};
/*
* These are applied if the 0xB2 DMI hotkey table is present and doesn't
* override them.
*/
static const struct key_entry dell_wmi_extra_keymap[] __initconst = {
/* Fn-lock */
{ KE_IGNORE, 0x151, { KEY_RESERVED } },
/* Change keyboard illumination */
{ KE_IGNORE, 0x152, { KEY_KBDILLUMTOGGLE } },
/*
* Radio disable (notify only -- there is no model for which the
* WMI event is supposed to trigger an action).
*/
{ KE_IGNORE, 0x153, { KEY_RFKILL } },
/* RGB keyboard backlight control */
{ KE_IGNORE, 0x154, { KEY_RESERVED } },
/* Stealth mode toggle */
{ KE_IGNORE, 0x155, { KEY_RESERVED } },
};
static struct input_dev *dell_wmi_input_dev;
static void dell_wmi_process_key(int reported_key)
......@@ -188,6 +246,9 @@ static void dell_wmi_process_key(int reported_key)
acpi_video_handles_brightness_key_presses())
return;
if (reported_key == 0xe025 && !wmi_requires_smbios_request)
return;
sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true);
}
......@@ -337,20 +398,60 @@ static void dell_wmi_notify(u32 value, void *context)
kfree(obj);
}
static const struct key_entry * __init dell_wmi_prepare_new_keymap(void)
static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len)
{
int hotkey_num = (dell_bios_hotkey_table->header.length - 4) /
sizeof(struct dell_bios_keymap_entry);
struct key_entry *keymap;
int i;
keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL);
if (!keymap)
return NULL;
for (i = 0; i < len; i++)
if (keymap[i].code == scancode)
return true;
return false;
}
static void __init handle_dmi_entry(const struct dmi_header *dm,
void *opaque)
{
struct dell_dmi_results *results = opaque;
struct dell_bios_hotkey_table *table;
int hotkey_num, i, pos = 0;
struct key_entry *keymap;
int num_bios_keys;
if (results->err || results->keymap)
return; /* We already found the hotkey table. */
if (dm->type != 0xb2)
return;
table = container_of(dm, struct dell_bios_hotkey_table, header);
hotkey_num = (table->header.length -
sizeof(struct dell_bios_hotkey_table)) /
sizeof(struct dell_bios_keymap_entry);
if (hotkey_num < 1) {
/*
* Historically, dell-wmi would ignore a DMI entry of
* fewer than 7 bytes. Sizes between 4 and 8 bytes are
* nonsensical (both the header and all entries are 4
* bytes), so we approximate the old behavior by
* ignoring tables with fewer than one entry.
*/
return;
}
keymap = kcalloc(hotkey_num + ARRAY_SIZE(dell_wmi_extra_keymap) + 1,
sizeof(struct key_entry), GFP_KERNEL);
if (!keymap) {
results->err = -ENOMEM;
return;
}
for (i = 0; i < hotkey_num; i++) {
const struct dell_bios_keymap_entry *bios_entry =
&dell_bios_hotkey_table->keymap[i];
&table->keymap[i];
/* Uninitialized entries are 0 aka KEY_RESERVED. */
u16 keycode = (bios_entry->keycode <
......@@ -370,20 +471,39 @@ static const struct key_entry * __init dell_wmi_prepare_new_keymap(void)
}
if (keycode == KEY_KBDILLUMTOGGLE)
keymap[i].type = KE_IGNORE;
keymap[pos].type = KE_IGNORE;
else
keymap[i].type = KE_KEY;
keymap[i].code = bios_entry->scancode;
keymap[i].keycode = keycode;
keymap[pos].type = KE_KEY;
keymap[pos].code = bios_entry->scancode;
keymap[pos].keycode = keycode;
pos++;
}
num_bios_keys = pos;
for (i = 0; i < ARRAY_SIZE(dell_wmi_extra_keymap); i++) {
const struct key_entry *entry = &dell_wmi_extra_keymap[i];
/*
* Check if we've already found this scancode. This takes
* quadratic time, but it doesn't matter unless the list
* of extra keys gets very long.
*/
if (!have_scancode(entry->code, keymap, num_bios_keys)) {
keymap[pos] = *entry;
pos++;
}
}
keymap[hotkey_num].type = KE_END;
keymap[pos].type = KE_END;
return keymap;
results->keymap = keymap;
}
static int __init dell_wmi_input_setup(void)
{
struct dell_dmi_results dmi_results = {};
int err;
dell_wmi_input_dev = input_allocate_device();
......@@ -394,20 +514,31 @@ static int __init dell_wmi_input_setup(void)
dell_wmi_input_dev->phys = "wmi/input0";
dell_wmi_input_dev->id.bustype = BUS_HOST;
if (dell_new_hk_type) {
const struct key_entry *keymap = dell_wmi_prepare_new_keymap();
if (!keymap) {
err = -ENOMEM;
goto err_free_dev;
}
if (dmi_walk(handle_dmi_entry, &dmi_results)) {
/*
* Historically, dell-wmi ignored dmi_walk errors. A failure
* is certainly surprising, but it probably just indicates
* a very old laptop.
*/
pr_warn("no DMI; using the old-style hotkey interface\n");
}
err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL);
if (dmi_results.err) {
err = dmi_results.err;
goto err_free_dev;
}
if (dmi_results.keymap) {
dell_new_hk_type = true;
err = sparse_keymap_setup(dell_wmi_input_dev,
dmi_results.keymap, NULL);
/*
* Sparse keymap library makes a copy of keymap so we
* don't need the original one that was allocated.
*/
kfree(keymap);
kfree(dmi_results.keymap);
} else {
err = sparse_keymap_setup(dell_wmi_input_dev,
dell_wmi_legacy_keymap, NULL);
......@@ -434,15 +565,6 @@ static void dell_wmi_input_destroy(void)
input_unregister_device(dell_wmi_input_dev);
}
static void __init find_hk_type(const struct dmi_header *dm, void *dummy)
{
if (dm->type == 0xb2 && dm->length > 6) {
dell_new_hk_type = true;
dell_bios_hotkey_table =
container_of(dm, struct dell_bios_hotkey_table, header);
}
}
/*
* Descriptor buffer is 128 byte long and contains:
*
......@@ -509,6 +631,38 @@ static int __init dell_wmi_check_descriptor_buffer(void)
return 0;
}
/*
* According to Dell SMBIOS documentation:
*
* 17 3 Application Program Registration
*
* cbArg1 Application ID 1 = 0x00010000
* cbArg2 Application ID 2
* QUICKSET/DCP = 0x51534554 "QSET"
* ALS Driver = 0x416c7353 "AlsS"
* Latitude ON = 0x4c6f6e52 "LonR"
* cbArg3 Application version or revision number
* cbArg4 0 = Unregister application
* 1 = Register application
* cbRes1 Standard return codes (0, -1, -2)
*/
static int dell_wmi_events_set_enabled(bool enable)
{
struct calling_interface_buffer *buffer;
int ret;
buffer = dell_smbios_get_buffer();
buffer->input[0] = 0x10000;
buffer->input[1] = 0x51534554;
buffer->input[3] = enable;
dell_smbios_send_request(17, 3);
ret = buffer->output[0];
dell_smbios_release_buffer();
return dell_smbios_error(ret);
}
static int __init dell_wmi_init(void)
{
int err;
......@@ -524,8 +678,6 @@ static int __init dell_wmi_init(void)
if (err)
return err;
dmi_walk(find_hk_type, NULL);
err = dell_wmi_input_setup();
if (err)
return err;
......@@ -538,12 +690,26 @@ static int __init dell_wmi_init(void)
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);
dell_wmi_input_destroy();
return err;
}
}
return 0;
}
module_init(dell_wmi_init);
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);
dell_wmi_input_destroy();
}
......
......@@ -114,6 +114,7 @@
#define KEY2_CODE 0x411
#define KEY3_CODE 0x412
#define KEY4_CODE 0x413
#define KEY5_CODE 0x420
#define MAX_HOTKEY_RINGBUFFER_SIZE 100
#define RINGBUFFERSIZE 40
......@@ -149,7 +150,7 @@ struct fujitsu_t {
char phys[32];
struct backlight_device *bl_device;
struct platform_device *pf_device;
int keycode1, keycode2, keycode3, keycode4;
int keycode1, keycode2, keycode3, keycode4, keycode5;
unsigned int max_brightness;
unsigned int brightness_changed;
......@@ -823,6 +824,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
set_bit(fujitsu->keycode2, input->keybit);
set_bit(fujitsu->keycode3, input->keybit);
set_bit(fujitsu->keycode4, input->keybit);
set_bit(fujitsu->keycode5, input->keybit);
set_bit(KEY_UNKNOWN, input->keybit);
error = input_register_device(input);
......@@ -962,6 +964,9 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
case KEY4_CODE:
keycode = fujitsu->keycode4;
break;
case KEY5_CODE:
keycode = fujitsu->keycode5;
break;
case 0:
keycode = 0;
break;
......@@ -1072,6 +1077,7 @@ static int __init fujitsu_init(void)
fujitsu->keycode2 = KEY_PROG2;
fujitsu->keycode3 = KEY_PROG3;
fujitsu->keycode4 = KEY_PROG4;
fujitsu->keycode5 = KEY_RFKILL;
dmi_check_system(fujitsu_dmi_table);
result = acpi_bus_register_driver(&acpi_fujitsu_driver);
......
......@@ -157,7 +157,6 @@ static struct platform_device *hp_wmi_platform_dev;
static struct rfkill *wifi_rfkill;
static struct rfkill *bluetooth_rfkill;
static struct rfkill *wwan_rfkill;
static struct rfkill *gps_rfkill;
struct rfkill2_device {
u8 id;
......@@ -613,10 +612,6 @@ static void hp_wmi_notify(u32 value, void *context)
rfkill_set_states(wwan_rfkill,
hp_wmi_get_sw_state(HPWMI_WWAN),
hp_wmi_get_hw_state(HPWMI_WWAN));
if (gps_rfkill)
rfkill_set_states(gps_rfkill,
hp_wmi_get_sw_state(HPWMI_GPS),
hp_wmi_get_hw_state(HPWMI_GPS));
break;
case HPWMI_CPU_BATTERY_THROTTLE:
pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");
......@@ -746,7 +741,7 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device)
(void *) HPWMI_BLUETOOTH);
if (!bluetooth_rfkill) {
err = -ENOMEM;
goto register_wifi_error;
goto register_bluetooth_error;
}
rfkill_init_sw_state(bluetooth_rfkill,
hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
......@@ -764,7 +759,7 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device)
(void *) HPWMI_WWAN);
if (!wwan_rfkill) {
err = -ENOMEM;
goto register_bluetooth_error;
goto register_wwan_error;
}
rfkill_init_sw_state(wwan_rfkill,
hp_wmi_get_sw_state(HPWMI_WWAN));
......@@ -775,35 +770,13 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device)
goto register_wwan_error;
}
if (wireless & 0x8) {
gps_rfkill = rfkill_alloc("hp-gps", &device->dev,
RFKILL_TYPE_GPS,
&hp_wmi_rfkill_ops,
(void *) HPWMI_GPS);
if (!gps_rfkill) {
err = -ENOMEM;
goto register_wwan_error;
}
rfkill_init_sw_state(gps_rfkill,
hp_wmi_get_sw_state(HPWMI_GPS));
rfkill_set_hw_state(gps_rfkill,
hp_wmi_get_hw_state(HPWMI_GPS));
err = rfkill_register(gps_rfkill);
if (err)
goto register_gps_error;
}
return 0;
register_gps_error:
rfkill_destroy(gps_rfkill);
gps_rfkill = NULL;
if (bluetooth_rfkill)
rfkill_unregister(bluetooth_rfkill);
register_wwan_error:
rfkill_destroy(wwan_rfkill);
wwan_rfkill = NULL;
if (gps_rfkill)
rfkill_unregister(gps_rfkill);
if (bluetooth_rfkill)
rfkill_unregister(bluetooth_rfkill);
register_bluetooth_error:
rfkill_destroy(bluetooth_rfkill);
bluetooth_rfkill = NULL;
......@@ -907,7 +880,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
wifi_rfkill = NULL;
bluetooth_rfkill = NULL;
wwan_rfkill = NULL;
gps_rfkill = NULL;
rfkill2_count = 0;
if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device))
......@@ -960,10 +932,6 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
rfkill_unregister(wwan_rfkill);
rfkill_destroy(wwan_rfkill);
}
if (gps_rfkill) {
rfkill_unregister(gps_rfkill);
rfkill_destroy(gps_rfkill);
}
return 0;
}
......@@ -999,10 +967,6 @@ static int hp_wmi_resume_handler(struct device *device)
rfkill_set_states(wwan_rfkill,
hp_wmi_get_sw_state(HPWMI_WWAN),
hp_wmi_get_hw_state(HPWMI_WWAN));
if (gps_rfkill)
rfkill_set_states(gps_rfkill,
hp_wmi_get_sw_state(HPWMI_GPS),
hp_wmi_get_hw_state(HPWMI_GPS));
return 0;
}
......
......@@ -864,6 +864,20 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"),
},
},
{
.ident = "Lenovo ideapad Y700-15ISK",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ISK"),
},
},
{
.ident = "Lenovo ideapad Y700 Touch-15ISK",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700 Touch-15ISK"),
},
},
{
.ident = "Lenovo ideapad Y700-17ISK",
.matches = {
......
......@@ -180,8 +180,7 @@ static int intel_hid_probe(struct platform_device *device)
return -ENODEV;
}
priv = devm_kzalloc(&device->dev,
sizeof(struct intel_hid_priv *), GFP_KERNEL);
priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dev_set_drvdata(&device->dev, priv);
......
......@@ -67,7 +67,8 @@
/* exported resources from IFWI */
#define PLAT_RESOURCE_IPC_INDEX 0
#define PLAT_RESOURCE_IPC_SIZE 0x1000
#define PLAT_RESOURCE_GCR_SIZE 0x1000
#define PLAT_RESOURCE_GCR_OFFSET 0x1008
#define PLAT_RESOURCE_GCR_SIZE 0x4
#define PLAT_RESOURCE_BIOS_DATA_INDEX 1
#define PLAT_RESOURCE_BIOS_IFACE_INDEX 2
#define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3
......@@ -766,7 +767,7 @@ static int ipc_plat_get_res(struct platform_device *pdev)
}
ipcdev.ipc_base = addr;
ipcdev.gcr_base = res->start + size;
ipcdev.gcr_base = res->start + PLAT_RESOURCE_GCR_OFFSET;
ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE;
dev_info(&pdev->dev, "ipc res: %pR\n", res);
......@@ -824,7 +825,8 @@ static int ipc_plat_probe(struct platform_device *pdev)
goto err_device;
}
if (request_irq(ipcdev.irq, ioc, 0, "intel_pmc_ipc", &ipcdev)) {
if (request_irq(ipcdev.irq, ioc, IRQF_NO_SUSPEND,
"intel_pmc_ipc", &ipcdev)) {
dev_err(&pdev->dev, "Failed to request irq\n");
ret = -EBUSY;
goto err_irq;
......
......@@ -24,7 +24,6 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/sfi.h>
#include <linux/module.h>
#include <asm/intel-mid.h>
#include <asm/intel_scu_ipc.h>
......@@ -611,28 +610,6 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
}
/**
* ipc_remove - remove a bound IPC device
* @pdev: PCI device
*
* In practice the SCU is not removable but this function is also
* called for each device on a module unload or cleanup which is the
* path that will get used.
*
* Free up the mappings and release the PCI resources
*/
static void ipc_remove(struct pci_dev *pdev)
{
struct intel_scu_ipc_dev *scu = pci_get_drvdata(pdev);
mutex_lock(&ipclock);
scu->dev = NULL;
mutex_unlock(&ipclock);
iounmap(scu->i2c_base);
intel_scu_devices_destroy();
}
static const struct pci_device_id pci_ids[] = {
{
PCI_VDEVICE(INTEL, PCI_DEVICE_ID_LINCROFT),
......@@ -650,17 +627,13 @@ static const struct pci_device_id pci_ids[] = {
0,
}
};
MODULE_DEVICE_TABLE(pci, pci_ids);
static struct pci_driver ipc_driver = {
.driver = {
.suppress_bind_attrs = true,
},
.name = "intel_scu_ipc",
.id_table = pci_ids,
.probe = ipc_probe,
.remove = ipc_remove,
};
module_pci_driver(ipc_driver);
MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>");
MODULE_DESCRIPTION("Intel SCU IPC driver");
MODULE_LICENSE("GPL");
builtin_pci_driver(ipc_driver);
......@@ -1029,9 +1029,20 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
mutex_lock(&(telm_conf->telem_trace_lock));
switch (telem_unit) {
case TELEM_PSS:
ret = intel_punit_ipc_command(
IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
0, 0, NULL, &temp);
if (ret) {
pr_err("PSS TRACE_CTRL Read Failed\n");
goto out;
}
TELEM_CLEAR_VERBOSITY_BITS(temp);
TELEM_SET_VERBOSITY_BITS(temp, verbosity);
ret = intel_punit_ipc_command(
IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL,
0, 0, &verbosity, NULL);
0, 0, &temp, NULL);
if (ret) {
pr_err("PSS TRACE_CTRL Verbosity Set Failed\n");
goto out;
......
......@@ -6653,18 +6653,16 @@ static void __init tpacpi_detect_brightness_capabilities(void)
switch (b) {
case 16:
bright_maxlvl = 15;
pr_info("detected a 16-level brightness capable ThinkPad\n");
break;
case 8:
case 0:
bright_maxlvl = 7;
pr_info("detected a 8-level brightness capable ThinkPad\n");
break;
default:
pr_info("Unsupported brightness interface\n");
tp_features.bright_unkfw = 1;
bright_maxlvl = b - 1;
}
pr_debug("detected %u brightness levels\n", bright_maxlvl + 1);
}
static int __init brightness_init(struct ibm_init_struct *iibm)
......
......@@ -36,6 +36,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
......@@ -117,6 +118,7 @@ MODULE_LICENSE("GPL");
#define HCI_LCD_BRIGHTNESS 0x002a
#define HCI_WIRELESS 0x0056
#define HCI_ACCELEROMETER 0x006d
#define HCI_COOLING_METHOD 0x007f
#define HCI_KBD_ILLUMINATION 0x0095
#define HCI_ECO_MODE 0x0097
#define HCI_ACCELEROMETER2 0x00a6
......@@ -186,6 +188,7 @@ struct toshiba_acpi_dev {
int usbsc_bat_level;
int usbsc_mode_base;
int hotkey_event_type;
int max_cooling_method;
unsigned int illumination_supported:1;
unsigned int video_supported:1;
......@@ -205,6 +208,7 @@ struct toshiba_acpi_dev {
unsigned int panel_power_on_supported:1;
unsigned int usb_three_supported:1;
unsigned int wwan_supported:1;
unsigned int cooling_method_supported:1;
unsigned int sysfs_created:1;
unsigned int special_functions;
......@@ -217,6 +221,10 @@ struct toshiba_acpi_dev {
static struct toshiba_acpi_dev *toshiba_acpi;
static bool disable_hotkeys;
module_param(disable_hotkeys, bool, 0444);
MODULE_PARM_DESC(disable_hotkeys, "Disables the hotkeys activation");
static const struct acpi_device_id toshiba_device_ids[] = {
{"TOS6200", 0},
{"TOS6207", 0},
......@@ -1194,6 +1202,53 @@ static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state)
return out[0] == TOS_SUCCESS ? 0 : -EIO;
}
/* Cooling Method */
static void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev)
{
u32 in[TCI_WORDS] = { HCI_GET, HCI_COOLING_METHOD, 0, 0, 0, 0 };
u32 out[TCI_WORDS];
acpi_status status;
dev->cooling_method_supported = 0;
dev->max_cooling_method = 0;
status = tci_raw(dev, in, out);
if (ACPI_FAILURE(status))
pr_err("ACPI call to get Cooling Method failed\n");
if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2)
return;
dev->cooling_method_supported = 1;
dev->max_cooling_method = out[3];
}
static int toshiba_cooling_method_get(struct toshiba_acpi_dev *dev, u32 *state)
{
u32 result = hci_read(dev, HCI_COOLING_METHOD, state);
if (result == TOS_FAILURE)
pr_err("ACPI call to get Cooling Method failed\n");
if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
}
static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state)
{
u32 result = hci_write(dev, HCI_COOLING_METHOD, state);
if (result == TOS_FAILURE)
pr_err("ACPI call to get Cooling Method failed\n");
if (result == TOS_NOT_SUPPORTED)
return -ENODEV;
return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
}
/* Transflective Backlight */
static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status)
{
......@@ -2239,6 +2294,54 @@ static ssize_t usb_three_store(struct device *dev,
}
static DEVICE_ATTR_RW(usb_three);
static ssize_t cooling_method_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int state;
int ret;
ret = toshiba_cooling_method_get(toshiba, &state);
if (ret < 0)
return ret;
return sprintf(buf, "%d %d\n", state, toshiba->max_cooling_method);
}
static ssize_t cooling_method_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int state;
int ret;
ret = kstrtoint(buf, 0, &state);
if (ret)
return ret;
/*
* Check for supported values
* Depending on the laptop model, some only support these two:
* 0 - Maximum Performance
* 1 - Battery Optimized
*
* While some others support all three methods:
* 0 - Maximum Performance
* 1 - Performance
* 2 - Battery Optimized
*/
if (state < 0 || state > toshiba->max_cooling_method)
return -EINVAL;
ret = toshiba_cooling_method_set(toshiba, state);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RW(cooling_method);
static struct attribute *toshiba_attributes[] = {
&dev_attr_version.attr,
&dev_attr_fan.attr,
......@@ -2255,6 +2358,7 @@ static struct attribute *toshiba_attributes[] = {
&dev_attr_kbd_function_keys.attr,
&dev_attr_panel_power_on.attr,
&dev_attr_usb_three.attr,
&dev_attr_cooling_method.attr,
NULL,
};
......@@ -2289,6 +2393,8 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
exists = (drv->panel_power_on_supported) ? true : false;
else if (attr == &dev_attr_usb_three.attr)
exists = (drv->usb_three_supported) ? true : false;
else if (attr == &dev_attr_cooling_method.attr)
exists = (drv->cooling_method_supported) ? true : false;
return exists ? attr->mode : 0;
}
......@@ -2591,6 +2697,11 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
acpi_handle ec_handle;
int error;
if (disable_hotkeys) {
pr_info("Hotkeys disabled by module parameter\n");
return 0;
}
if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) {
pr_info("WMI event detected, hotkeys will not be monitored\n");
return 0;
......@@ -2779,6 +2890,8 @@ static void print_supported_features(struct toshiba_acpi_dev *dev)
pr_cont(" usb3");
if (dev->wwan_supported)
pr_cont(" wwan");
if (dev->cooling_method_supported)
pr_cont(" cooling-method");
pr_cont("\n");
}
......@@ -2963,6 +3076,8 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
if (dev->wwan_supported)
toshiba_acpi_setup_wwan_rfkill(dev);
toshiba_cooling_method_available(dev);
print_supported_features(dev);
ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment