You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'platform-drivers-x86-v4.15-1' of git://git.infradead.org/linux-platform-drivers-x86
Pull x86 platform driver updates from Andy Shevchenko: "Here is the collected material against Platform Drivers x86 subsystem. It's rather bit busy cycle for PDx86, mostly due to Dell SMBIOS driver activity For this cycle we have quite an update for the Dell SMBIOS driver including WMI work to provide an interface for SMBIOS tokens via sysfs and WMI support for 2017+ Dell laptop models. SMM dispatcher code is split into a separate driver followed by a new WMI dispatcher. The latter provides a character device interface to user space. The git history also contains a merge of immutable branch from Wolfram Sang in order to apply a dependent fix to the Intel CherryTrail Battery Management driver. Other Intel drivers got a lot of cleanups. The Turbo Boost Max 3.0 support is added for Intel Skylake. Peaq WMI hotkeys driver gets its own maintainer and white list of supported models. Silead DMI is expanded to support few additional platforms. Tablet mode via GMMS ACPI method is added to support some ThinkPad tablets. new driver: - Add driver to force WMI Thunderbolt controller power status asus-wmi: - Add lightbar led support dell-laptop: - Allocate buffer before rfkill use dell-smbios: - fix string overflow - Add filtering support - Introduce dispatcher for SMM calls - Add a sysfs interface for SMBIOS tokens - only run if proper oem string is detected - Prefix class/select with cmd_ - Add pr_fmt definition to driver dell-smbios-smm: - test for WSMT dell-smbios-wmi: - release mutex lock on WMI call failure - introduce userspace interface - Add new WMI dispatcher driver dell-smo8800: - remove redundant assignments to byte_data dell-wmi: - don't check length returned - clean up wmi descriptor check - increase severity of some failures - Do not match on descriptor GUID modalias - Label driver as handling notifications dell-*wmi*: - Relay failed initial probe to dependent drivers dell-wmi-descriptor: - check if memory was allocated - split WMI descriptor into it's own driver fujitsu-laptop: - Fix radio LED detection - Don't oops when FUJ02E3 is not presnt hp_accel: - Add quirk for HP ProBook 440 G4 hp-wmi: - Fix tablet mode detection for convertibles ideapad-laptop: - Add Lenovo Yoga 920-13IKB to no_hw_rfkill dmi list intel_cht_int33fe: - Update fusb302 type string, add properties - make a couple of local functions static - Work around BIOS bug on some devices intel-hid: - Power button suspend on Dell Latitude 7275 intel_ips: - Convert timers to use timer_setup() - Remove FSF address from GPL notice - Remove unneeded fields and label - Keep pointer to struct device - Use PCI_VDEVICE() macro - Switch to new PCI IRQ allocation API - Simplify error handling via devres API intel_pmc_ipc: - Revert Use MFD framework to create dependent devices - Use MFD framework to create dependent devices - Use spin_lock to protect GCR updates - Use devm_* calls in driver probe function intel_punit_ipc: - Fix resource ioremap warning intel_telemetry: - Remove useless default in Kconfig - Add needed inclusion - cleanup redundant headers - Fix typos - Fix load failure info intel_telemetry_debugfs: - Use standard ARRAY_SIZE() macro intel_turbo_max_3: - Add Skylake platform intel-wmi-thunderbolt: - Silence error cases mlx-platform: - make a couple of structures static peaq_wmi: - Fix missing terminating entry for peaq_dmi_table peaq-wmi: - Remove unnecessary checks from peaq_wmi_exit - Add DMI check before binding to the WMI interface - Revert Blacklist Lenovo ideapad 700-15ISK - Blacklist Lenovo ideapad 700-15ISK silead_dmi: - Add silead, home-button property to some tablets - Add entry for the Digma e200 tablet - Fix GP-electronic T701 entry - Add entry for the Chuwi Hi8 Pro tablet sony-laptop: - Drop variable assignment in sony_nc_setup_rfkill() - Fix error handling in sony_nc_setup_rfkill() thinkpad_acpi: - Implement tablet mode using GMMS method tools/wmi: - add a sample for dell smbios communication over WMI wmi: - release mutex on module acquistion failure - create userspace interface for drivers - Don't allow drivers to get each other's GUIDs - Add new method wmidev_evaluate_method - Destroy on cleanup rather than unregister - Cleanup exit routine in reverse order of init - Sort include list" * tag 'platform-drivers-x86-v4.15-1' of git://git.infradead.org/linux-platform-drivers-x86: (74 commits) platform/x86: silead_dmi: Add silead, home-button property to some tablets platform/x86: dell-laptop: Allocate buffer before rfkill use platform/x86: dell-*wmi*: Relay failed initial probe to dependent drivers platform/x86: dell-wmi-descriptor: check if memory was allocated platform/x86: Revert intel_pmc_ipc: Use MFD framework to create dependent devices platform/x86: dell-smbios-wmi: release mutex lock on WMI call failure platform/x86: wmi: release mutex on module acquistion failure platform/x86: dell-smbios: fix string overflow platform/x86: intel_pmc_ipc: Use MFD framework to create dependent devices platform/x86: intel_punit_ipc: Fix resource ioremap warning platform/x86: dell-smo8800: remove redundant assignments to byte_data platform/x86: hp-wmi: Fix tablet mode detection for convertibles platform/x86: intel_ips: Convert timers to use timer_setup() platform/x86: sony-laptop: Drop variable assignment in sony_nc_setup_rfkill() platform/x86: sony-laptop: Fix error handling in sony_nc_setup_rfkill() tools/wmi: add a sample for dell smbios communication over WMI platform/x86: dell-smbios-wmi: introduce userspace interface platform/x86: wmi: create userspace interface for drivers platform/x86: dell-smbios: Add filtering support platform/x86: dell-smbios-smm: test for WSMT ...
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
What: /dev/wmi/dell-smbios
|
||||
Date: November 2017
|
||||
KernelVersion: 4.15
|
||||
Contact: "Mario Limonciello" <mario.limonciello@dell.com>
|
||||
Description:
|
||||
Perform SMBIOS calls on supported Dell machines.
|
||||
through the Dell ACPI-WMI interface.
|
||||
|
||||
IOCTL's and buffer formats are defined in:
|
||||
<uapi/linux/wmi.h>
|
||||
|
||||
1) To perform an SMBIOS call from userspace, you'll need to
|
||||
first determine the minimum size of the calling interface
|
||||
buffer for your machine.
|
||||
Platforms that contain larger buffers can return larger
|
||||
objects from the system firmware.
|
||||
Commonly this size is either 4k or 32k.
|
||||
|
||||
To determine the size of the buffer read() a u64 dword from
|
||||
the WMI character device /dev/wmi/dell-smbios.
|
||||
|
||||
2) After you've determined the minimum size of the calling
|
||||
interface buffer, you can allocate a structure that represents
|
||||
the structure documented above.
|
||||
|
||||
3) In the 'length' object store the size of the buffer you
|
||||
determined above and allocated.
|
||||
|
||||
4) In this buffer object, prepare as necessary for the SMBIOS
|
||||
call you're interested in. Typically SMBIOS buffers have
|
||||
"class", "select", and "input" defined to values that coincide
|
||||
with the data you are interested in.
|
||||
Documenting class/select/input values is outside of the scope
|
||||
of this documentation. Check with the libsmbios project for
|
||||
further documentation on these values.
|
||||
|
||||
6) Run the call by using ioctl() as described in the header.
|
||||
|
||||
7) The output will be returned in the buffer object.
|
||||
|
||||
8) Be sure to free up your allocated object.
|
||||
@@ -0,0 +1,21 @@
|
||||
What: /sys/devices/platform/<platform>/tokens/*
|
||||
Date: November 2017
|
||||
KernelVersion: 4.15
|
||||
Contact: "Mario Limonciello" <mario.limonciello@dell.com>
|
||||
Description:
|
||||
A read-only description of Dell platform tokens
|
||||
available on the machine.
|
||||
|
||||
Each token attribute is available as a pair of
|
||||
sysfs attributes readable by a process with
|
||||
CAP_SYS_ADMIN.
|
||||
|
||||
For example the token ID "5" would be available
|
||||
as the following attributes:
|
||||
|
||||
0005_location
|
||||
0005_value
|
||||
|
||||
Tokens will vary from machine to machine, and
|
||||
only tokens available on that machine will be
|
||||
displayed.
|
||||
@@ -0,0 +1,11 @@
|
||||
What: /sys/devices/platform/<platform>/force_power
|
||||
Date: September 2017
|
||||
KernelVersion: 4.15
|
||||
Contact: "Mario Limonciello" <mario.limonciello@dell.com>
|
||||
Description:
|
||||
Modify the platform force power state, influencing
|
||||
Thunderbolt controllers to turn on or off when no
|
||||
devices are connected (write-only)
|
||||
There are two available states:
|
||||
* 0 -> Force power disabled
|
||||
* 1 -> Force power enabled
|
||||
@@ -221,3 +221,18 @@ The driver will create one virtual ethernet interface per Thunderbolt
|
||||
port which are named like ``thunderbolt0`` and so on. From this point
|
||||
you can either use standard userspace tools like ``ifconfig`` to
|
||||
configure the interface or let your GUI to handle it automatically.
|
||||
|
||||
Forcing power
|
||||
-------------
|
||||
Many OEMs include a method that can be used to force the power of a
|
||||
thunderbolt controller to an "On" state even if nothing is connected.
|
||||
If supported by your machine this will be exposed by the WMI bus with
|
||||
a sysfs attribute called "force_power".
|
||||
|
||||
For example the intel-wmi-thunderbolt driver exposes this attribute in:
|
||||
/sys/devices/platform/PNP0C14:00/wmi_bus/wmi_bus-PNP0C14:00/86CCFD48-205E-4A77-9C48-2021CBEDE341/force_power
|
||||
|
||||
To force the power to on, write 1 to this attribute file.
|
||||
To disable force power, write 0 to this attribute file.
|
||||
|
||||
Note: it's currently not possible to query the force power state of a platform.
|
||||
|
||||
+38
-1
@@ -384,6 +384,7 @@ ACPI WMI DRIVER
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Orphan
|
||||
F: drivers/platform/x86/wmi.c
|
||||
F: include/uapi/linux/wmi.h
|
||||
|
||||
AD1889 ALSA SOUND DRIVER
|
||||
M: Thibaut Varene <T-Bone@parisc-linux.org>
|
||||
@@ -4030,6 +4031,26 @@ M: "Maciej W. Rozycki" <macro@linux-mips.org>
|
||||
S: Maintained
|
||||
F: drivers/net/fddi/defxx.*
|
||||
|
||||
DELL SMBIOS DRIVER
|
||||
M: Pali Rohár <pali.rohar@gmail.com>
|
||||
M: Mario Limonciello <mario.limonciello@dell.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/dell-smbios.*
|
||||
|
||||
DELL SMBIOS SMM DRIVER
|
||||
M: Mario Limonciello <mario.limonciello@dell.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/dell-smbios-smm.c
|
||||
|
||||
DELL SMBIOS WMI DRIVER
|
||||
M: Mario Limonciello <mario.limonciello@dell.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/dell-smbios-wmi.c
|
||||
F: tools/wmi/dell-smbios-example.c
|
||||
|
||||
DELL LAPTOP DRIVER
|
||||
M: Matthew Garrett <mjg59@srcf.ucam.org>
|
||||
M: Pali Rohár <pali.rohar@gmail.com>
|
||||
@@ -4059,12 +4080,17 @@ S: Maintained
|
||||
F: Documentation/dcdbas.txt
|
||||
F: drivers/firmware/dcdbas.*
|
||||
|
||||
DELL WMI EXTRAS DRIVER
|
||||
DELL WMI NOTIFICATIONS DRIVER
|
||||
M: Matthew Garrett <mjg59@srcf.ucam.org>
|
||||
M: Pali Rohár <pali.rohar@gmail.com>
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/dell-wmi.c
|
||||
|
||||
DELL WMI DESCRIPTOR DRIVER
|
||||
M: Mario Limonciello <mario.limonciello@dell.com>
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/dell-wmi-descriptor.c
|
||||
|
||||
DELTA ST MEDIA DRIVER
|
||||
M: Hugues Fruchet <hugues.fruchet@st.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
@@ -7181,6 +7207,11 @@ F: Documentation/wimax/README.i2400m
|
||||
F: drivers/net/wimax/i2400m/
|
||||
F: include/uapi/linux/wimax/i2400m.h
|
||||
|
||||
INTEL WMI THUNDERBOLT FORCE POWER DRIVER
|
||||
M: Mario Limonciello <mario.limonciello@dell.com>
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/intel-wmi-thunderbolt.c
|
||||
|
||||
INTEL(R) TRACE HUB
|
||||
M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
|
||||
S: Supported
|
||||
@@ -10630,6 +10661,12 @@ S: Maintained
|
||||
F: crypto/pcrypt.c
|
||||
F: include/crypto/pcrypt.h
|
||||
|
||||
PEAQ WMI HOTKEYS DRIVER
|
||||
M: Hans de Goede <hdegoede@redhat.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/peaq-wmi.c
|
||||
|
||||
PER-CPU MEMORY ALLOCATOR
|
||||
M: Tejun Heo <tj@kernel.org>
|
||||
M: Christoph Lameter <cl@linux.com>
|
||||
|
||||
@@ -93,12 +93,33 @@ config ASUS_LAPTOP
|
||||
|
||||
config DELL_SMBIOS
|
||||
tristate
|
||||
select DCDBAS
|
||||
---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_SMBIOS_WMI
|
||||
tristate "Dell SMBIOS calling interface (WMI implementation)"
|
||||
depends on ACPI_WMI
|
||||
select DELL_WMI_DESCRIPTOR
|
||||
default ACPI_WMI
|
||||
select DELL_SMBIOS
|
||||
---help---
|
||||
This provides an implementation for the Dell SMBIOS calling interface
|
||||
communicated over ACPI-WMI.
|
||||
|
||||
If you have a Dell computer from >2007 you should say Y or M here.
|
||||
If you aren't sure and this module doesn't work for your computer
|
||||
it just won't load.
|
||||
|
||||
config DELL_SMBIOS_SMM
|
||||
tristate "Dell SMBIOS calling interface (SMM implementation)"
|
||||
depends on DCDBAS
|
||||
default DCDBAS
|
||||
select DELL_SMBIOS
|
||||
---help---
|
||||
This provides an implementation for the Dell SMBIOS calling interface
|
||||
communicated over SMI/SMM.
|
||||
|
||||
If you have a Dell computer from <=2017 you should say Y or M here.
|
||||
If you aren't sure and this module doesn't work for your computer
|
||||
it just won't load.
|
||||
|
||||
config DELL_LAPTOP
|
||||
tristate "Dell Laptop Extras"
|
||||
@@ -116,11 +137,12 @@ config DELL_LAPTOP
|
||||
laptops (except for some models covered by the Compal driver).
|
||||
|
||||
config DELL_WMI
|
||||
tristate "Dell WMI extras"
|
||||
tristate "Dell WMI notifications"
|
||||
depends on ACPI_WMI
|
||||
depends on DMI
|
||||
depends on INPUT
|
||||
depends on ACPI_VIDEO || ACPI_VIDEO = n
|
||||
select DELL_WMI_DESCRIPTOR
|
||||
select DELL_SMBIOS
|
||||
select INPUT_SPARSEKMAP
|
||||
---help---
|
||||
@@ -129,6 +151,10 @@ config DELL_WMI
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called dell-wmi.
|
||||
|
||||
config DELL_WMI_DESCRIPTOR
|
||||
tristate
|
||||
depends on ACPI_WMI
|
||||
|
||||
config DELL_WMI_AIO
|
||||
tristate "WMI Hotkeys for Dell All-In-One series"
|
||||
depends on ACPI_WMI
|
||||
@@ -658,6 +684,19 @@ config WMI_BMOF
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called wmi-bmof.
|
||||
|
||||
config INTEL_WMI_THUNDERBOLT
|
||||
tristate "Intel WMI thunderbolt force power driver"
|
||||
depends on ACPI_WMI
|
||||
default ACPI_WMI
|
||||
---help---
|
||||
Say Y here if you want to be able to use the WMI interface on select
|
||||
systems to force the power control of Intel Thunderbolt controllers.
|
||||
This is useful for updating the firmware when devices are not plugged
|
||||
into the controller.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called intel-wmi-thunderbolt.
|
||||
|
||||
config MSI_WMI
|
||||
tristate "MSI WMI extras"
|
||||
depends on ACPI_WMI
|
||||
@@ -793,7 +832,7 @@ config ACPI_CMPC
|
||||
|
||||
config INTEL_CHT_INT33FE
|
||||
tristate "Intel Cherry Trail ACPI INT33FE Driver"
|
||||
depends on X86 && ACPI && I2C
|
||||
depends on X86 && ACPI && I2C && REGULATOR
|
||||
---help---
|
||||
This driver add support for the INT33FE ACPI device found on
|
||||
some Intel Cherry Trail devices.
|
||||
@@ -804,6 +843,10 @@ config INTEL_CHT_INT33FE
|
||||
This driver instantiates i2c-clients for these, so that standard
|
||||
i2c drivers for these chips can bind to the them.
|
||||
|
||||
If you enable this driver it is advised to also select
|
||||
CONFIG_TYPEC_FUSB302=m, CONFIG_CHARGER_BQ24190=m and
|
||||
CONFIG_BATTERY_MAX17042=m.
|
||||
|
||||
config INTEL_INT0002_VGPIO
|
||||
tristate "Intel ACPI INT0002 Virtual GPIO driver"
|
||||
depends on GPIOLIB && ACPI
|
||||
@@ -1088,7 +1131,6 @@ config INTEL_PUNIT_IPC
|
||||
|
||||
config INTEL_TELEMETRY
|
||||
tristate "Intel SoC Telemetry Driver"
|
||||
default n
|
||||
depends on INTEL_PMC_IPC && INTEL_PUNIT_IPC && X86_64
|
||||
---help---
|
||||
This driver provides interfaces to configure and use
|
||||
|
||||
@@ -13,8 +13,11 @@ 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_SMBIOS_WMI) += dell-smbios-wmi.o
|
||||
obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o
|
||||
obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
|
||||
obj-$(CONFIG_DELL_WMI) += dell-wmi.o
|
||||
obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o
|
||||
obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
|
||||
obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
|
||||
obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
|
||||
@@ -40,6 +43,7 @@ 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
|
||||
obj-$(CONFIG_INTEL_WMI_THUNDERBOLT) += intel-wmi-thunderbolt.o
|
||||
|
||||
# toshiba_acpi must link after wmi to ensure that wmi devices are found
|
||||
# before toshiba_acpi initializes
|
||||
|
||||
@@ -119,6 +119,7 @@ MODULE_LICENSE("GPL");
|
||||
#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
|
||||
#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
|
||||
#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */
|
||||
#define ASUS_WMI_DEVID_LIGHTBAR 0x00050025
|
||||
|
||||
/* Misc */
|
||||
#define ASUS_WMI_DEVID_CAMERA 0x00060013
|
||||
@@ -148,6 +149,7 @@ MODULE_LICENSE("GPL");
|
||||
#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000
|
||||
#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
|
||||
#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
|
||||
#define ASUS_WMI_DSTS_LIGHTBAR_MASK 0x0000000F
|
||||
|
||||
#define ASUS_FAN_DESC "cpu_fan"
|
||||
#define ASUS_FAN_MFUN 0x13
|
||||
@@ -222,10 +224,13 @@ struct asus_wmi {
|
||||
int tpd_led_wk;
|
||||
struct led_classdev kbd_led;
|
||||
int kbd_led_wk;
|
||||
struct led_classdev lightbar_led;
|
||||
int lightbar_led_wk;
|
||||
struct workqueue_struct *led_workqueue;
|
||||
struct work_struct tpd_led_work;
|
||||
struct work_struct kbd_led_work;
|
||||
struct work_struct wlan_led_work;
|
||||
struct work_struct lightbar_led_work;
|
||||
|
||||
struct asus_rfkill wlan;
|
||||
struct asus_rfkill bluetooth;
|
||||
@@ -567,6 +572,48 @@ static enum led_brightness wlan_led_get(struct led_classdev *led_cdev)
|
||||
return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
|
||||
}
|
||||
|
||||
static void lightbar_led_update(struct work_struct *work)
|
||||
{
|
||||
struct asus_wmi *asus;
|
||||
int ctrl_param;
|
||||
|
||||
asus = container_of(work, struct asus_wmi, lightbar_led_work);
|
||||
|
||||
ctrl_param = asus->lightbar_led_wk;
|
||||
asus_wmi_set_devstate(ASUS_WMI_DEVID_LIGHTBAR, ctrl_param, NULL);
|
||||
}
|
||||
|
||||
static void lightbar_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct asus_wmi *asus;
|
||||
|
||||
asus = container_of(led_cdev, struct asus_wmi, lightbar_led);
|
||||
|
||||
asus->lightbar_led_wk = !!value;
|
||||
queue_work(asus->led_workqueue, &asus->lightbar_led_work);
|
||||
}
|
||||
|
||||
static enum led_brightness lightbar_led_get(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct asus_wmi *asus;
|
||||
u32 result;
|
||||
|
||||
asus = container_of(led_cdev, struct asus_wmi, lightbar_led);
|
||||
asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result);
|
||||
|
||||
return result & ASUS_WMI_DSTS_LIGHTBAR_MASK;
|
||||
}
|
||||
|
||||
static int lightbar_led_presence(struct asus_wmi *asus)
|
||||
{
|
||||
u32 result;
|
||||
|
||||
asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result);
|
||||
|
||||
return result & ASUS_WMI_DSTS_PRESENCE_BIT;
|
||||
}
|
||||
|
||||
static void asus_wmi_led_exit(struct asus_wmi *asus)
|
||||
{
|
||||
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
|
||||
@@ -575,6 +622,8 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
|
||||
led_classdev_unregister(&asus->tpd_led);
|
||||
if (!IS_ERR_OR_NULL(asus->wlan_led.dev))
|
||||
led_classdev_unregister(&asus->wlan_led);
|
||||
if (!IS_ERR_OR_NULL(asus->lightbar_led.dev))
|
||||
led_classdev_unregister(&asus->lightbar_led);
|
||||
if (asus->led_workqueue)
|
||||
destroy_workqueue(asus->led_workqueue);
|
||||
}
|
||||
@@ -630,6 +679,20 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
|
||||
|
||||
rv = led_classdev_register(&asus->platform_device->dev,
|
||||
&asus->wlan_led);
|
||||
if (rv)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (lightbar_led_presence(asus)) {
|
||||
INIT_WORK(&asus->lightbar_led_work, lightbar_led_update);
|
||||
|
||||
asus->lightbar_led.name = "asus::lightbar";
|
||||
asus->lightbar_led.brightness_set = lightbar_led_set;
|
||||
asus->lightbar_led.brightness_get = lightbar_led_get;
|
||||
asus->lightbar_led.max_brightness = 1;
|
||||
|
||||
rv = led_classdev_register(&asus->platform_device->dev,
|
||||
&asus->lightbar_led);
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
+105
-177
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* SMI methods for use with 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>
|
||||
* Copyright (c) 2017 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.
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include "../../firmware/dcdbas.h"
|
||||
#include "dell-smbios.h"
|
||||
|
||||
static int da_command_address;
|
||||
static int da_command_code;
|
||||
static struct calling_interface_buffer *buffer;
|
||||
struct platform_device *platform_device;
|
||||
static DEFINE_MUTEX(smm_mutex);
|
||||
|
||||
static const struct dmi_system_id dell_device_table[] __initconst = {
|
||||
{
|
||||
.ident = "Dell laptop",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /*Laptop*/
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Dell Computer Corporation",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
|
||||
DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dmi, dell_device_table);
|
||||
|
||||
static void __init parse_da_table(const struct dmi_header *dm)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static void __init find_cmd_address(const struct dmi_header *dm, void *dummy)
|
||||
{
|
||||
switch (dm->type) {
|
||||
case 0xda: /* Calling interface */
|
||||
parse_da_table(dm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int dell_smbios_smm_call(struct calling_interface_buffer *input)
|
||||
{
|
||||
struct smi_cmd command;
|
||||
size_t size;
|
||||
|
||||
size = sizeof(struct calling_interface_buffer);
|
||||
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;
|
||||
|
||||
mutex_lock(&smm_mutex);
|
||||
memcpy(buffer, input, size);
|
||||
dcdbas_smi_request(&command);
|
||||
memcpy(input, buffer, size);
|
||||
mutex_unlock(&smm_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* When enabled this indicates that SMM won't work */
|
||||
static bool test_wsmt_enabled(void)
|
||||
{
|
||||
struct calling_interface_token *wsmt;
|
||||
|
||||
/* if token doesn't exist, SMM will work */
|
||||
wsmt = dell_smbios_find_token(WSMT_EN_TOKEN);
|
||||
if (!wsmt)
|
||||
return false;
|
||||
|
||||
/* If token exists, try to access over SMM but set a dummy return.
|
||||
* - If WSMT disabled it will be overwritten by SMM
|
||||
* - If WSMT enabled then dummy value will remain
|
||||
*/
|
||||
buffer->cmd_class = CLASS_TOKEN_READ;
|
||||
buffer->cmd_select = SELECT_TOKEN_STD;
|
||||
memset(buffer, 0, sizeof(struct calling_interface_buffer));
|
||||
buffer->input[0] = wsmt->location;
|
||||
buffer->output[0] = 99;
|
||||
dell_smbios_smm_call(buffer);
|
||||
if (buffer->output[0] == 99)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __init dell_smbios_smm_init(void)
|
||||
{
|
||||
int ret;
|
||||
/*
|
||||
* 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)
|
||||
return -ENOMEM;
|
||||
|
||||
dmi_walk(find_cmd_address, NULL);
|
||||
|
||||
if (test_wsmt_enabled()) {
|
||||
pr_debug("Disabling due to WSMT enabled\n");
|
||||
ret = -ENODEV;
|
||||
goto fail_wsmt;
|
||||
}
|
||||
|
||||
platform_device = platform_device_alloc("dell-smbios", 1);
|
||||
if (!platform_device) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_platform_device_alloc;
|
||||
}
|
||||
|
||||
ret = platform_device_add(platform_device);
|
||||
if (ret)
|
||||
goto fail_platform_device_add;
|
||||
|
||||
ret = dell_smbios_register_device(&platform_device->dev,
|
||||
&dell_smbios_smm_call);
|
||||
if (ret)
|
||||
goto fail_register;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_register:
|
||||
platform_device_del(platform_device);
|
||||
|
||||
fail_platform_device_add:
|
||||
platform_device_put(platform_device);
|
||||
|
||||
fail_wsmt:
|
||||
fail_platform_device_alloc:
|
||||
free_page((unsigned long)buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit dell_smbios_smm_exit(void)
|
||||
{
|
||||
if (platform_device) {
|
||||
dell_smbios_unregister_device(&platform_device->dev);
|
||||
platform_device_unregister(platform_device);
|
||||
free_page((unsigned long)buffer);
|
||||
}
|
||||
}
|
||||
|
||||
subsys_initcall(dell_smbios_smm_init);
|
||||
module_exit(dell_smbios_smm_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_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
|
||||
MODULE_DESCRIPTION("Dell SMBIOS communications over SMI");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* WMI methods for use with dell-smbios
|
||||
*
|
||||
* Copyright (c) 2017 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.
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/wmi.h>
|
||||
#include "dell-smbios.h"
|
||||
#include "dell-wmi-descriptor.h"
|
||||
|
||||
static DEFINE_MUTEX(call_mutex);
|
||||
static DEFINE_MUTEX(list_mutex);
|
||||
static int wmi_supported;
|
||||
|
||||
struct misc_bios_flags_structure {
|
||||
struct dmi_header header;
|
||||
u16 flags0;
|
||||
} __packed;
|
||||
#define FLAG_HAS_ACPI_WMI 0x02
|
||||
|
||||
#define DELL_WMI_SMBIOS_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
|
||||
|
||||
struct wmi_smbios_priv {
|
||||
struct dell_wmi_smbios_buffer *buf;
|
||||
struct list_head list;
|
||||
struct wmi_device *wdev;
|
||||
struct device *child;
|
||||
u32 req_buf_size;
|
||||
};
|
||||
static LIST_HEAD(wmi_list);
|
||||
|
||||
static inline struct wmi_smbios_priv *get_first_smbios_priv(void)
|
||||
{
|
||||
return list_first_entry_or_null(&wmi_list,
|
||||
struct wmi_smbios_priv,
|
||||
list);
|
||||
}
|
||||
|
||||
static int run_smbios_call(struct wmi_device *wdev)
|
||||
{
|
||||
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
struct wmi_smbios_priv *priv;
|
||||
struct acpi_buffer input;
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
|
||||
priv = dev_get_drvdata(&wdev->dev);
|
||||
input.length = priv->req_buf_size - sizeof(u64);
|
||||
input.pointer = &priv->buf->std;
|
||||
|
||||
dev_dbg(&wdev->dev, "evaluating: %u/%u [%x,%x,%x,%x]\n",
|
||||
priv->buf->std.cmd_class, priv->buf->std.cmd_select,
|
||||
priv->buf->std.input[0], priv->buf->std.input[1],
|
||||
priv->buf->std.input[2], priv->buf->std.input[3]);
|
||||
|
||||
status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
obj = (union acpi_object *)output.pointer;
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
dev_dbg(&wdev->dev, "received type: %d\n", obj->type);
|
||||
if (obj->type == ACPI_TYPE_INTEGER)
|
||||
dev_dbg(&wdev->dev, "SMBIOS call failed: %llu\n",
|
||||
obj->integer.value);
|
||||
return -EIO;
|
||||
}
|
||||
memcpy(&priv->buf->std, obj->buffer.pointer, obj->buffer.length);
|
||||
dev_dbg(&wdev->dev, "result: [%08x,%08x,%08x,%08x]\n",
|
||||
priv->buf->std.output[0], priv->buf->std.output[1],
|
||||
priv->buf->std.output[2], priv->buf->std.output[3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dell_smbios_wmi_call(struct calling_interface_buffer *buffer)
|
||||
{
|
||||
struct wmi_smbios_priv *priv;
|
||||
size_t difference;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&call_mutex);
|
||||
priv = get_first_smbios_priv();
|
||||
if (!priv) {
|
||||
ret = -ENODEV;
|
||||
goto out_wmi_call;
|
||||
}
|
||||
|
||||
size = sizeof(struct calling_interface_buffer);
|
||||
difference = priv->req_buf_size - sizeof(u64) - size;
|
||||
|
||||
memset(&priv->buf->ext, 0, difference);
|
||||
memcpy(&priv->buf->std, buffer, size);
|
||||
ret = run_smbios_call(priv->wdev);
|
||||
memcpy(buffer, &priv->buf->std, size);
|
||||
out_wmi_call:
|
||||
mutex_unlock(&call_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long dell_smbios_wmi_filter(struct wmi_device *wdev, unsigned int cmd,
|
||||
struct wmi_ioctl_buffer *arg)
|
||||
{
|
||||
struct wmi_smbios_priv *priv;
|
||||
int ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case DELL_WMI_SMBIOS_CMD:
|
||||
mutex_lock(&call_mutex);
|
||||
priv = dev_get_drvdata(&wdev->dev);
|
||||
if (!priv) {
|
||||
ret = -ENODEV;
|
||||
goto fail_smbios_cmd;
|
||||
}
|
||||
memcpy(priv->buf, arg, priv->req_buf_size);
|
||||
if (dell_smbios_call_filter(&wdev->dev, &priv->buf->std)) {
|
||||
dev_err(&wdev->dev, "Invalid call %d/%d:%8x\n",
|
||||
priv->buf->std.cmd_class,
|
||||
priv->buf->std.cmd_select,
|
||||
priv->buf->std.input[0]);
|
||||
ret = -EFAULT;
|
||||
goto fail_smbios_cmd;
|
||||
}
|
||||
ret = run_smbios_call(priv->wdev);
|
||||
if (ret)
|
||||
goto fail_smbios_cmd;
|
||||
memcpy(arg, priv->buf, priv->req_buf_size);
|
||||
fail_smbios_cmd:
|
||||
mutex_unlock(&call_mutex);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dell_smbios_wmi_probe(struct wmi_device *wdev)
|
||||
{
|
||||
struct wmi_smbios_priv *priv;
|
||||
int count;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_get_descriptor_valid();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv = devm_kzalloc(&wdev->dev, sizeof(struct wmi_smbios_priv),
|
||||
GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
/* WMI buffer size will be either 4k or 32k depending on machine */
|
||||
if (!dell_wmi_get_size(&priv->req_buf_size))
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
/* add in the length object we will use internally with ioctl */
|
||||
priv->req_buf_size += sizeof(u64);
|
||||
ret = set_required_buffer_size(wdev, priv->req_buf_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
count = get_order(priv->req_buf_size);
|
||||
priv->buf = (void *)__get_free_pages(GFP_KERNEL, count);
|
||||
if (!priv->buf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* ID is used by dell-smbios to set priority of drivers */
|
||||
wdev->dev.id = 1;
|
||||
ret = dell_smbios_register_device(&wdev->dev, &dell_smbios_wmi_call);
|
||||
if (ret)
|
||||
goto fail_register;
|
||||
|
||||
priv->wdev = wdev;
|
||||
dev_set_drvdata(&wdev->dev, priv);
|
||||
mutex_lock(&list_mutex);
|
||||
list_add_tail(&priv->list, &wmi_list);
|
||||
mutex_unlock(&list_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_register:
|
||||
free_pages((unsigned long)priv->buf, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dell_smbios_wmi_remove(struct wmi_device *wdev)
|
||||
{
|
||||
struct wmi_smbios_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
int count;
|
||||
|
||||
mutex_lock(&call_mutex);
|
||||
mutex_lock(&list_mutex);
|
||||
list_del(&priv->list);
|
||||
mutex_unlock(&list_mutex);
|
||||
dell_smbios_unregister_device(&wdev->dev);
|
||||
count = get_order(priv->req_buf_size);
|
||||
free_pages((unsigned long)priv->buf, count);
|
||||
mutex_unlock(&call_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct wmi_device_id dell_smbios_wmi_id_table[] = {
|
||||
{ .guid_string = DELL_WMI_SMBIOS_GUID },
|
||||
{ },
|
||||
};
|
||||
|
||||
static void __init parse_b1_table(const struct dmi_header *dm)
|
||||
{
|
||||
struct misc_bios_flags_structure *flags =
|
||||
container_of(dm, struct misc_bios_flags_structure, header);
|
||||
|
||||
/* 4 bytes header, 8 bytes flags */
|
||||
if (dm->length < 12)
|
||||
return;
|
||||
if (dm->handle != 0xb100)
|
||||
return;
|
||||
if ((flags->flags0 & FLAG_HAS_ACPI_WMI))
|
||||
wmi_supported = 1;
|
||||
}
|
||||
|
||||
static void __init find_b1(const struct dmi_header *dm, void *dummy)
|
||||
{
|
||||
switch (dm->type) {
|
||||
case 0xb1: /* misc bios flags */
|
||||
parse_b1_table(dm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct wmi_driver dell_smbios_wmi_driver = {
|
||||
.driver = {
|
||||
.name = "dell-smbios",
|
||||
},
|
||||
.probe = dell_smbios_wmi_probe,
|
||||
.remove = dell_smbios_wmi_remove,
|
||||
.id_table = dell_smbios_wmi_id_table,
|
||||
.filter_callback = dell_smbios_wmi_filter,
|
||||
};
|
||||
|
||||
static int __init init_dell_smbios_wmi(void)
|
||||
{
|
||||
dmi_walk(find_b1, NULL);
|
||||
|
||||
if (!wmi_supported)
|
||||
return -ENODEV;
|
||||
|
||||
return wmi_driver_register(&dell_smbios_wmi_driver);
|
||||
}
|
||||
|
||||
static void __exit exit_dell_smbios_wmi(void)
|
||||
{
|
||||
wmi_driver_unregister(&dell_smbios_wmi_driver);
|
||||
}
|
||||
|
||||
module_init(init_dell_smbios_wmi);
|
||||
module_exit(exit_dell_smbios_wmi);
|
||||
|
||||
MODULE_ALIAS("wmi:" DELL_WMI_SMBIOS_GUID);
|
||||
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
|
||||
MODULE_DESCRIPTION("Dell SMBIOS communications over WMI");
|
||||
MODULE_LICENSE("GPL");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,18 +16,30 @@
|
||||
#ifndef _DELL_SMBIOS_H_
|
||||
#define _DELL_SMBIOS_H_
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <uapi/linux/wmi.h>
|
||||
|
||||
/* Classes and selects used only in kernel drivers */
|
||||
#define CLASS_KBD_BACKLIGHT 4
|
||||
#define SELECT_KBD_BACKLIGHT 11
|
||||
|
||||
/* Tokens used in kernel drivers, any of these
|
||||
* should be filtered from userspace access
|
||||
*/
|
||||
#define BRIGHTNESS_TOKEN 0x007d
|
||||
#define KBD_LED_AC_TOKEN 0x0451
|
||||
#define KBD_LED_OFF_TOKEN 0x01E1
|
||||
#define KBD_LED_ON_TOKEN 0x01E2
|
||||
#define KBD_LED_AUTO_TOKEN 0x01E3
|
||||
#define KBD_LED_AUTO_25_TOKEN 0x02EA
|
||||
#define KBD_LED_AUTO_50_TOKEN 0x02EB
|
||||
#define KBD_LED_AUTO_75_TOKEN 0x02EC
|
||||
#define KBD_LED_AUTO_100_TOKEN 0x02F6
|
||||
#define GLOBAL_MIC_MUTE_ENABLE 0x0364
|
||||
#define GLOBAL_MIC_MUTE_DISABLE 0x0365
|
||||
|
||||
struct notifier_block;
|
||||
|
||||
/* 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;
|
||||
@@ -37,12 +49,21 @@ struct calling_interface_token {
|
||||
};
|
||||
};
|
||||
|
||||
int dell_smbios_error(int value);
|
||||
struct calling_interface_structure {
|
||||
struct dmi_header header;
|
||||
u16 cmdIOAddress;
|
||||
u8 cmdIOCode;
|
||||
u32 supportedCmds;
|
||||
struct calling_interface_token tokens[];
|
||||
} __packed;
|
||||
|
||||
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);
|
||||
int dell_smbios_register_device(struct device *d, void *call_fn);
|
||||
void dell_smbios_unregister_device(struct device *d);
|
||||
|
||||
int dell_smbios_error(int value);
|
||||
int dell_smbios_call_filter(struct device *d,
|
||||
struct calling_interface_buffer *buffer);
|
||||
int dell_smbios_call(struct calling_interface_buffer *buffer);
|
||||
|
||||
struct calling_interface_token *dell_smbios_find_token(int tokenid);
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
|
||||
struct smo8800_device, miscdev);
|
||||
|
||||
u32 data = 0;
|
||||
unsigned char byte_data = 0;
|
||||
unsigned char byte_data;
|
||||
ssize_t retval = 1;
|
||||
|
||||
if (count < 1)
|
||||
@@ -103,7 +103,6 @@ static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
byte_data = 1;
|
||||
retval = 1;
|
||||
|
||||
if (data < 255)
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Dell WMI descriptor driver
|
||||
*
|
||||
* Copyright (C) 2017 Dell 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/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/wmi.h>
|
||||
#include "dell-wmi-descriptor.h"
|
||||
|
||||
#define DELL_WMI_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
|
||||
|
||||
struct descriptor_priv {
|
||||
struct list_head list;
|
||||
u32 interface_version;
|
||||
u32 size;
|
||||
};
|
||||
static int descriptor_valid = -EPROBE_DEFER;
|
||||
static LIST_HEAD(wmi_list);
|
||||
static DEFINE_MUTEX(list_mutex);
|
||||
|
||||
int dell_wmi_get_descriptor_valid(void)
|
||||
{
|
||||
if (!wmi_has_guid(DELL_WMI_DESCRIPTOR_GUID))
|
||||
return -ENODEV;
|
||||
|
||||
return descriptor_valid;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dell_wmi_get_descriptor_valid);
|
||||
|
||||
bool dell_wmi_get_interface_version(u32 *version)
|
||||
{
|
||||
struct descriptor_priv *priv;
|
||||
bool ret = false;
|
||||
|
||||
mutex_lock(&list_mutex);
|
||||
priv = list_first_entry_or_null(&wmi_list,
|
||||
struct descriptor_priv,
|
||||
list);
|
||||
if (priv) {
|
||||
*version = priv->interface_version;
|
||||
ret = true;
|
||||
}
|
||||
mutex_unlock(&list_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dell_wmi_get_interface_version);
|
||||
|
||||
bool dell_wmi_get_size(u32 *size)
|
||||
{
|
||||
struct descriptor_priv *priv;
|
||||
bool ret = false;
|
||||
|
||||
mutex_lock(&list_mutex);
|
||||
priv = list_first_entry_or_null(&wmi_list,
|
||||
struct descriptor_priv,
|
||||
list);
|
||||
if (priv) {
|
||||
*size = priv->size;
|
||||
ret = true;
|
||||
}
|
||||
mutex_unlock(&list_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dell_wmi_get_size);
|
||||
|
||||
/*
|
||||
* Descriptor buffer is 128 byte long and contains:
|
||||
*
|
||||
* Name Offset Length Value
|
||||
* Vendor Signature 0 4 "DELL"
|
||||
* Object Signature 4 4 " WMI"
|
||||
* WMI Interface Version 8 4 <version>
|
||||
* WMI buffer length 12 4 <length>
|
||||
*/
|
||||
static int dell_wmi_descriptor_probe(struct wmi_device *wdev)
|
||||
{
|
||||
union acpi_object *obj = NULL;
|
||||
struct descriptor_priv *priv;
|
||||
u32 *buffer;
|
||||
int ret;
|
||||
|
||||
obj = wmidev_block_query(wdev, 0);
|
||||
if (!obj) {
|
||||
dev_err(&wdev->dev, "failed to read Dell WMI descriptor\n");
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
dev_err(&wdev->dev, "Dell descriptor has wrong type\n");
|
||||
ret = -EINVAL;
|
||||
descriptor_valid = ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Although it's not technically a failure, this would lead to
|
||||
* unexpected behavior
|
||||
*/
|
||||
if (obj->buffer.length != 128) {
|
||||
dev_err(&wdev->dev,
|
||||
"Dell descriptor buffer has unexpected length (%d)\n",
|
||||
obj->buffer.length);
|
||||
ret = -EINVAL;
|
||||
descriptor_valid = ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buffer = (u32 *)obj->buffer.pointer;
|
||||
|
||||
if (strncmp(obj->string.pointer, "DELL WMI", 8) != 0) {
|
||||
dev_err(&wdev->dev, "Dell descriptor buffer has invalid signature (%8ph)\n",
|
||||
buffer);
|
||||
ret = -EINVAL;
|
||||
descriptor_valid = ret;
|
||||
goto out;
|
||||
}
|
||||
descriptor_valid = 0;
|
||||
|
||||
if (buffer[2] != 0 && buffer[2] != 1)
|
||||
dev_warn(&wdev->dev, "Dell descriptor buffer has unknown version (%lu)\n",
|
||||
(unsigned long) buffer[2]);
|
||||
|
||||
priv = devm_kzalloc(&wdev->dev, sizeof(struct descriptor_priv),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
priv->interface_version = buffer[2];
|
||||
priv->size = buffer[3];
|
||||
ret = 0;
|
||||
dev_set_drvdata(&wdev->dev, priv);
|
||||
mutex_lock(&list_mutex);
|
||||
list_add_tail(&priv->list, &wmi_list);
|
||||
mutex_unlock(&list_mutex);
|
||||
|
||||
dev_dbg(&wdev->dev, "Detected Dell WMI interface version %lu and buffer size %lu\n",
|
||||
(unsigned long) priv->interface_version,
|
||||
(unsigned long) priv->size);
|
||||
|
||||
out:
|
||||
kfree(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dell_wmi_descriptor_remove(struct wmi_device *wdev)
|
||||
{
|
||||
struct descriptor_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
|
||||
mutex_lock(&list_mutex);
|
||||
list_del(&priv->list);
|
||||
mutex_unlock(&list_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct wmi_device_id dell_wmi_descriptor_id_table[] = {
|
||||
{ .guid_string = DELL_WMI_DESCRIPTOR_GUID },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct wmi_driver dell_wmi_descriptor_driver = {
|
||||
.driver = {
|
||||
.name = "dell-wmi-descriptor",
|
||||
},
|
||||
.probe = dell_wmi_descriptor_probe,
|
||||
.remove = dell_wmi_descriptor_remove,
|
||||
.id_table = dell_wmi_descriptor_id_table,
|
||||
};
|
||||
|
||||
module_wmi_driver(dell_wmi_descriptor_driver);
|
||||
|
||||
MODULE_ALIAS("wmi:" DELL_WMI_DESCRIPTOR_GUID);
|
||||
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
|
||||
MODULE_DESCRIPTION("Dell WMI descriptor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Dell WMI descriptor driver
|
||||
*
|
||||
* Copyright (c) 2017 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_WMI_DESCRIPTOR_H_
|
||||
#define _DELL_WMI_DESCRIPTOR_H_
|
||||
|
||||
#include <linux/wmi.h>
|
||||
|
||||
/* possible return values:
|
||||
* -ENODEV: Descriptor GUID missing from WMI bus
|
||||
* -EPROBE_DEFER: probing for dell-wmi-descriptor not yet run
|
||||
* 0: valid descriptor, successfully probed
|
||||
* < 0: invalid descriptor, don't probe dependent devices
|
||||
*/
|
||||
int dell_wmi_get_descriptor_valid(void);
|
||||
|
||||
bool dell_wmi_get_interface_version(u32 *version);
|
||||
bool dell_wmi_get_size(u32 *size);
|
||||
|
||||
#endif
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <linux/wmi.h>
|
||||
#include <acpi/video.h>
|
||||
#include "dell-smbios.h"
|
||||
#include "dell-wmi-descriptor.h"
|
||||
|
||||
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
|
||||
MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
|
||||
@@ -46,12 +47,10 @@ MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
|
||||
#define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
|
||||
|
||||
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;
|
||||
@@ -618,78 +617,6 @@ static void dell_wmi_input_destroy(struct wmi_device *wdev)
|
||||
input_unregister_device(priv->input_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Descriptor buffer is 128 byte long and contains:
|
||||
*
|
||||
* Name Offset Length Value
|
||||
* Vendor Signature 0 4 "DELL"
|
||||
* Object Signature 4 4 " WMI"
|
||||
* WMI Interface Version 8 4 <version>
|
||||
* WMI buffer length 12 4 4096
|
||||
*/
|
||||
static int dell_wmi_check_descriptor_buffer(struct wmi_device *wdev)
|
||||
{
|
||||
struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
union acpi_object *obj = NULL;
|
||||
struct wmi_device *desc_dev;
|
||||
u32 *buffer;
|
||||
int ret;
|
||||
|
||||
desc_dev = wmidev_get_other_guid(wdev, DELL_DESCRIPTOR_GUID);
|
||||
if (!desc_dev) {
|
||||
dev_err(&wdev->dev, "Dell WMI descriptor does not exist\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
obj = wmidev_block_query(desc_dev, 0);
|
||||
if (!obj) {
|
||||
dev_err(&wdev->dev, "failed to read Dell WMI descriptor\n");
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
dev_err(&wdev->dev, "Dell descriptor has wrong type\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (obj->buffer.length != 128) {
|
||||
dev_err(&wdev->dev,
|
||||
"Dell descriptor buffer has invalid length (%d)\n",
|
||||
obj->buffer.length);
|
||||
if (obj->buffer.length < 16) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
buffer = (u32 *)obj->buffer.pointer;
|
||||
|
||||
if (buffer[0] != 0x4C4C4544 && buffer[1] != 0x494D5720)
|
||||
dev_warn(&wdev->dev, "Dell descriptor buffer has invalid signature (%*ph)\n",
|
||||
8, buffer);
|
||||
|
||||
if (buffer[2] != 0 && buffer[2] != 1)
|
||||
dev_warn(&wdev->dev, "Dell descriptor buffer has unknown version (%d)\n",
|
||||
buffer[2]);
|
||||
|
||||
if (buffer[3] != 4096)
|
||||
dev_warn(&wdev->dev, "Dell descriptor buffer has invalid buffer length (%d)\n",
|
||||
buffer[3]);
|
||||
|
||||
priv->interface_version = buffer[2];
|
||||
ret = 0;
|
||||
|
||||
dev_info(&wdev->dev, "Detected Dell WMI interface version %u\n",
|
||||
priv->interface_version);
|
||||
|
||||
out:
|
||||
kfree(obj);
|
||||
put_device(&desc_dev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to Dell SMBIOS documentation:
|
||||
*
|
||||
@@ -711,13 +638,16 @@ static int dell_wmi_events_set_enabled(bool enable)
|
||||
struct calling_interface_buffer *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = dell_smbios_get_buffer();
|
||||
buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL);
|
||||
buffer->cmd_class = CLASS_INFO;
|
||||
buffer->cmd_select = SELECT_APP_REGISTRATION;
|
||||
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();
|
||||
ret = dell_smbios_call(buffer);
|
||||
if (ret == 0)
|
||||
ret = buffer->output[0];
|
||||
kfree(buffer);
|
||||
|
||||
return dell_smbios_error(ret);
|
||||
}
|
||||
@@ -725,7 +655,11 @@ static int dell_wmi_events_set_enabled(bool enable)
|
||||
static int dell_wmi_probe(struct wmi_device *wdev)
|
||||
{
|
||||
struct dell_wmi_priv *priv;
|
||||
int err;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_get_descriptor_valid();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv = devm_kzalloc(
|
||||
&wdev->dev, sizeof(struct dell_wmi_priv), GFP_KERNEL);
|
||||
@@ -733,9 +667,8 @@ static int dell_wmi_probe(struct wmi_device *wdev)
|
||||
return -ENOMEM;
|
||||
dev_set_drvdata(&wdev->dev, priv);
|
||||
|
||||
err = dell_wmi_check_descriptor_buffer(wdev);
|
||||
if (err)
|
||||
return err;
|
||||
if (!dell_wmi_get_interface_version(&priv->interface_version))
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
return dell_wmi_input_setup(wdev);
|
||||
}
|
||||
|
||||
@@ -691,6 +691,7 @@ static enum led_brightness eco_led_get(struct led_classdev *cdev)
|
||||
|
||||
static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct led_classdev *led;
|
||||
int result;
|
||||
|
||||
@@ -724,12 +725,15 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
||||
}
|
||||
|
||||
/*
|
||||
* BTNI bit 24 seems to indicate the presence of a radio toggle
|
||||
* button in place of a slide switch, and all such machines appear
|
||||
* to also have an RF LED. Therefore use bit 24 as an indicator
|
||||
* that an RF LED is present.
|
||||
* Some Fujitsu laptops have a radio toggle button in place of a slide
|
||||
* switch and all such machines appear to also have an RF LED. Based on
|
||||
* comparing DSDT tables of four Fujitsu Lifebook models (E744, E751,
|
||||
* S7110, S8420; the first one has a radio toggle button, the other
|
||||
* three have slide switches), bit 17 of flags_supported (the value
|
||||
* returned by method S000 of ACPI device FUJ02E3) seems to indicate
|
||||
* whether given model has a radio toggle button.
|
||||
*/
|
||||
if (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) {
|
||||
if (priv->flags_supported & BIT(17)) {
|
||||
led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
|
||||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -297,7 +297,7 @@ static int hp_wmi_hw_state(int mask)
|
||||
if (state < 0)
|
||||
return state;
|
||||
|
||||
return state & 0x1;
|
||||
return !!(state & mask);
|
||||
}
|
||||
|
||||
static int __init hp_wmi_bios_2008_later(void)
|
||||
|
||||
@@ -240,6 +240,7 @@ static const struct dmi_system_id lis3lv02d_dmi_ids[] = {
|
||||
AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted),
|
||||
AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left),
|
||||
AXIS_DMI_MATCH("HPB440G3", "HP ProBook 440 G3", x_inverted_usd),
|
||||
AXIS_DMI_MATCH("HPB440G4", "HP ProBook 440 G4", x_inverted),
|
||||
AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left),
|
||||
AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
|
||||
AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user