Merge tag 'platform-drivers-x86-v6.16-3' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

Pull x86 platform drivers fixes from Ilpo Järvinen:
 "Mostly a few lines fixed here and there except amd/isp4 which improves
  swnodes relationships but that is a new driver not in any stable
  kernels yet. The think-lmi driver changes also look relatively large
  but there are just many fixes to it.

  The i2c/piix4 change is a effectively a revert of the commit
  7e173eb82a ("i2c: piix4: Make CONFIG_I2C_PIIX4 dependent on
  CONFIG_X86") but that required moving the header out from arch/x86
  under include/linux/platform_data/

  Summary:

   - amd/isp4: Improve swnode graph (new driver exception)

   - asus-nb-wmi: Use duo keyboard quirk for Zenbook Duo UX8406CA

   - dell-lis3lv02d: Add Latitude 5500 accelerometer address

   - dell-wmi-sysman: Fix WMI data block retrieval and class dev unreg

   - hp-bioscfg: Fix class device unregistration

   - i2c: piix4: Re-enable on non-x86 + move FCH header under platform_data/

   - intel/hid: Wildcat Lake support

   - mellanox:
      - mlxbf-pmc: Fix duplicate event ID
      - mlxbf-tmfifo: Fix vring_desc.len assignment
      - mlxreg-lc: Fix bit-not-set logic check
      - nvsw-sn2201: Fix bus number in error message & spelling errors

   - portwell-ec: Move watchdog device under correct platform hierarchy

   - think-lmi: Error handling fixes (sysfs, kset, kobject, class dev unreg)

   - thinkpad_acpi: Handle HKEY 0x1402 event (2025 Thinkpads)

   - wmi: Fix WMI event enablement"

* tag 'platform-drivers-x86-v6.16-3' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (22 commits)
  platform/x86: think-lmi: Fix sysfs group cleanup
  platform/x86: think-lmi: Fix kobject cleanup
  platform/x86: think-lmi: Create ksets consecutively
  platform/mellanox: mlxreg-lc: Fix logic error in power state check
  i2c: Re-enable piix4 driver on non-x86
  Move FCH header to a location accessible by all archs
  platform/x86/intel/hid: Add Wildcat Lake support
  platform/x86: dell-wmi-sysman: Fix class device unregistration
  platform/x86: think-lmi: Fix class device unregistration
  platform/x86: hp-bioscfg: Fix class device unregistration
  platform/x86: Update swnode graph for amd isp4
  platform/x86: dell-wmi-sysman: Fix WMI data block retrieval in sysfs callbacks
  platform/x86: wmi: Update documentation of WCxx/WExx ACPI methods
  platform/x86: wmi: Fix WMI event enablement
  platform/mellanox: nvsw-sn2201: Fix bus number in adapter error message
  platform/mellanox: Fix spelling and comment clarity in Mellanox drivers
  platform/mellanox: mlxbf-pmc: Fix duplicate event ID for CACHE_DATA1
  platform/x86: thinkpad_acpi: handle HKEY 0x1402 event
  platform/x86: asus-nb-wmi: add DMI quirk for ASUS Zenbook Duo UX8406CA
  platform/x86: dell-lis3lv02d: Add Latitude 5500
  ...
This commit is contained in:
Linus Torvalds
2025-07-04 10:05:31 -07:00
26 changed files with 250 additions and 140 deletions

View File

@@ -36,7 +36,7 @@ Offset Size (in bytes) Content
The WMI object flags control whether the method or notification ID is used:
- 0x1: Data block usage is expensive and must be explicitly enabled/disabled.
- 0x1: Data block is expensive to collect.
- 0x2: Data block contains WMI methods.
- 0x4: Data block contains ASCIZ string.
- 0x8: Data block describes a WMI event, use notification ID instead
@@ -83,14 +83,18 @@ event as hexadecimal value. Their first parameter is an integer with a value
of 0 if the WMI event should be disabled, other values will enable
the WMI event.
Those ACPI methods are always called even for WMI events not registered as
being expensive to collect to match the behavior of the Windows driver.
WCxx ACPI methods
-----------------
Similar to the ``WExx`` ACPI methods, except that it controls data collection
instead of events and thus the last two characters of the ACPI method name are
the method ID of the data block to enable/disable.
Similar to the ``WExx`` ACPI methods, except that instead of WMI events it controls
data collection of data blocks registered as being expensive to collect. Thus the
last two characters of the ACPI method name are the method ID of the data block
to enable/disable.
Those ACPI methods are also called before setting data blocks to match the
behaviour of the Windows driver.
behavior of the Windows driver.
_WED ACPI method
----------------

View File

@@ -9,7 +9,7 @@
#include <linux/sched/clock.h>
#include <linux/random.h>
#include <linux/topology.h>
#include <asm/amd/fch.h>
#include <linux/platform_data/x86/amd-fch.h>
#include <asm/processor.h>
#include <asm/apic.h>
#include <asm/cacheinfo.h>

View File

@@ -200,7 +200,7 @@ config I2C_ISMT
config I2C_PIIX4
tristate "Intel PIIX4 and compatible (ATI/AMD/Serverworks/Broadcom/SMSC)"
depends on PCI && HAS_IOPORT && X86
depends on PCI && HAS_IOPORT
select I2C_SMBUS
help
If you say yes to this option, support will be included for the Intel

View File

@@ -34,7 +34,7 @@
#include <linux/dmi.h>
#include <linux/acpi.h>
#include <linux/io.h>
#include <asm/amd/fch.h>
#include <linux/platform_data/x86/amd-fch.h>
#include "i2c-piix4.h"

View File

@@ -715,7 +715,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_llt_events[] = {
{101, "GDC_BANK0_HIT_DCL_PARTIAL"},
{102, "GDC_BANK0_EVICT_DCL"},
{103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA0"},
{103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA1"},
{104, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA1"},
{105, "GDC_BANK0_ARB_STRB"},
{106, "GDC_BANK0_ARB_WAIT"},
{107, "GDC_BANK0_GGA_STRB"},

View File

@@ -281,7 +281,8 @@ static int mlxbf_tmfifo_alloc_vrings(struct mlxbf_tmfifo *fifo,
vring->align = SMP_CACHE_BYTES;
vring->index = i;
vring->vdev_id = tm_vdev->vdev.id.device;
vring->drop_desc.len = VRING_DROP_DESC_MAX_LEN;
vring->drop_desc.len = cpu_to_virtio32(&tm_vdev->vdev,
VRING_DROP_DESC_MAX_LEN);
dev = &tm_vdev->vdev.dev;
size = vring_size(vring->num, vring->align);
@@ -1287,7 +1288,7 @@ static void mlxbf_tmfifo_get_cfg_mac(u8 *mac)
ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac);
}
/* Set TmFifo thresolds which is used to trigger interrupts. */
/* Set TmFifo thresholds which is used to trigger interrupts. */
static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
{
u64 ctl;

View File

@@ -483,7 +483,7 @@ static int mlxreg_dpu_config_init(struct mlxreg_dpu *mlxreg_dpu, void *regmap,
mlxreg_dpu->io_data,
sizeof(*mlxreg_dpu->io_data));
if (IS_ERR(mlxreg_dpu->io_regs)) {
dev_err(dev, "Failed to create regio for client %s at bus %d at addr 0x%02x\n",
dev_err(dev, "Failed to create region for client %s at bus %d at addr 0x%02x\n",
data->hpdev.brdinfo->type, data->hpdev.nr,
data->hpdev.brdinfo->addr);
return PTR_ERR(mlxreg_dpu->io_regs);

View File

@@ -57,9 +57,9 @@ enum mlxreg_lc_state {
* @dev: platform device;
* @lock: line card lock;
* @par_regmap: parent device regmap handle;
* @data: pltaform core data;
* @data: platform core data;
* @io_data: register access platform data;
* @led_data: LED platform data ;
* @led_data: LED platform data;
* @mux_data: MUX platform data;
* @led: LED device;
* @io_regs: register access device;
@@ -171,7 +171,7 @@ static int mlxreg_lc_chan[] = {
0x4e, 0x4f
};
/* Defaul mux configuration. */
/* Default mux configuration. */
static struct mlxcpld_mux_plat_data mlxreg_lc_mux_data[] = {
{
.chan_ids = mlxreg_lc_chan,
@@ -181,7 +181,7 @@ static struct mlxcpld_mux_plat_data mlxreg_lc_mux_data[] = {
},
};
/* Defaul mux board info. */
/* Default mux board info. */
static struct i2c_board_info mlxreg_lc_mux_brdinfo = {
I2C_BOARD_INFO("i2c-mux-mlxcpld", 0x32),
};
@@ -688,7 +688,7 @@ static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent,
if (regval & mlxreg_lc->data->mask) {
mlxreg_lc->state |= MLXREG_LC_SYNCED;
mlxreg_lc_state_update_locked(mlxreg_lc, MLXREG_LC_SYNCED, 1);
if (mlxreg_lc->state & ~MLXREG_LC_POWERED) {
if (!(mlxreg_lc->state & MLXREG_LC_POWERED)) {
err = mlxreg_lc_power_on_off(mlxreg_lc, 1);
if (err)
goto mlxreg_lc_regmap_power_on_off_fail;
@@ -758,7 +758,7 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap,
platform_device_register_resndata(dev, "mlxreg-io", data->hpdev.nr, NULL, 0,
mlxreg_lc->io_data, sizeof(*mlxreg_lc->io_data));
if (IS_ERR(mlxreg_lc->io_regs)) {
dev_err(dev, "Failed to create regio for client %s at bus %d at addr 0x%02x\n",
dev_err(dev, "Failed to create region for client %s at bus %d at addr 0x%02x\n",
data->hpdev.brdinfo->type, data->hpdev.nr,
data->hpdev.brdinfo->addr);
err = PTR_ERR(mlxreg_lc->io_regs);

View File

@@ -1181,7 +1181,7 @@ static int nvsw_sn2201_i2c_completion_notify(void *handle, int id)
if (!nvsw_sn2201->main_mux_devs->adapter) {
err = -ENODEV;
dev_err(nvsw_sn2201->dev, "Failed to get adapter for bus %d\n",
nvsw_sn2201->cpld_devs->nr);
nvsw_sn2201->main_mux_devs->nr);
goto i2c_get_adapter_main_fail;
}

View File

@@ -21,6 +21,9 @@
#define AMDISP_OV05C10_REMOTE_EP_NAME "ov05c10_isp_4_1_1"
#define AMD_ISP_PLAT_DRV_NAME "amd-isp4"
static const struct software_node isp4_mipi1_endpoint_node;
static const struct software_node ov05c10_endpoint_node;
/*
* AMD ISP platform info definition to initialize sensor
* specific platform configuration to prepare the amdisp
@@ -43,55 +46,116 @@ struct amdisp_platform {
struct mutex lock; /* protects i2c client creation */
};
/* Top-level OV05C10 camera node property table */
/* Root AMD CAMERA SWNODE */
/* Root amd camera node definition */
static const struct software_node amd_camera_node = {
.name = "amd_camera",
};
/* ISP4 SWNODE */
/* ISP4 OV05C10 camera node definition */
static const struct software_node isp4_node = {
.name = "isp4",
.parent = &amd_camera_node,
};
/*
* ISP4 Ports node definition. No properties defined for
* ports node.
*/
static const struct software_node isp4_ports = {
.name = "ports",
.parent = &isp4_node,
};
/*
* ISP4 Port node definition. No properties defined for
* port node.
*/
static const struct software_node isp4_port_node = {
.name = "port@0",
.parent = &isp4_ports,
};
/*
* ISP4 MIPI1 remote endpoint points to OV05C10 endpoint
* node.
*/
static const struct software_node_ref_args isp4_refs[] = {
SOFTWARE_NODE_REFERENCE(&ov05c10_endpoint_node),
};
/* ISP4 MIPI1 endpoint node properties table */
static const struct property_entry isp4_mipi1_endpoint_props[] = {
PROPERTY_ENTRY_REF_ARRAY("remote-endpoint", isp4_refs),
{ }
};
/* ISP4 MIPI1 endpoint node definition */
static const struct software_node isp4_mipi1_endpoint_node = {
.name = "endpoint",
.parent = &isp4_port_node,
.properties = isp4_mipi1_endpoint_props,
};
/* I2C1 SWNODE */
/* I2C1 camera node property table */
static const struct property_entry i2c1_camera_props[] = {
PROPERTY_ENTRY_U32("clock-frequency", 1 * HZ_PER_MHZ),
{ }
};
/* I2C1 camera node definition */
static const struct software_node i2c1_node = {
.name = "i2c1",
.parent = &amd_camera_node,
.properties = i2c1_camera_props,
};
/* I2C1 camera node property table */
static const struct property_entry ov05c10_camera_props[] = {
PROPERTY_ENTRY_U32("clock-frequency", 24 * HZ_PER_MHZ),
{ }
};
/* Root AMD ISP OV05C10 camera node definition */
static const struct software_node camera_node = {
/* OV05C10 camera node definition */
static const struct software_node ov05c10_camera_node = {
.name = AMDISP_OV05C10_HID,
.parent = &i2c1_node,
.properties = ov05c10_camera_props,
};
/*
* AMD ISP OV05C10 Ports node definition. No properties defined for
* OV05C10 Ports node definition. No properties defined for
* ports node for OV05C10.
*/
static const struct software_node ports = {
static const struct software_node ov05c10_ports = {
.name = "ports",
.parent = &camera_node,
.parent = &ov05c10_camera_node,
};
/*
* AMD ISP OV05C10 Port node definition. No properties defined for
* port node for OV05C10.
* OV05C10 Port node definition.
*/
static const struct software_node port_node = {
.name = "port@",
.parent = &ports,
static const struct software_node ov05c10_port_node = {
.name = "port@0",
.parent = &ov05c10_ports,
};
/*
* Remote endpoint AMD ISP node definition. No properties defined for
* remote endpoint node for OV05C10.
*/
static const struct software_node remote_ep_isp_node = {
.name = AMDISP_OV05C10_REMOTE_EP_NAME,
};
/*
* Remote endpoint reference for isp node included in the
* OV05C10 endpoint.
* OV05C10 remote endpoint points to ISP4 MIPI1 endpoint
* node.
*/
static const struct software_node_ref_args ov05c10_refs[] = {
SOFTWARE_NODE_REFERENCE(&remote_ep_isp_node),
SOFTWARE_NODE_REFERENCE(&isp4_mipi1_endpoint_node),
};
/* OV05C10 supports one single link frequency */
static const u64 ov05c10_link_freqs[] = {
925 * HZ_PER_MHZ,
900 * HZ_PER_MHZ,
};
/* OV05C10 supports only 2-lane configuration */
@@ -111,27 +175,64 @@ static const struct property_entry ov05c10_endpoint_props[] = {
{ }
};
/* AMD ISP endpoint node definition */
static const struct software_node endpoint_node = {
/* OV05C10 endpoint node definition */
static const struct software_node ov05c10_endpoint_node = {
.name = "endpoint",
.parent = &port_node,
.parent = &ov05c10_port_node,
.properties = ov05c10_endpoint_props,
};
/*
* AMD ISP swnode graph uses 5 nodes and also its relationship is
* fixed to align with the structure that v4l2 expects for successful
* endpoint fwnode parsing.
* AMD Camera swnode graph uses 10 nodes and also its relationship is
* fixed to align with the structure that v4l2 and i2c frameworks expects
* for successful parsing of fwnodes and its properties with standard names.
*
* It is only the node property_entries that will vary for each platform
* supporting different sensor modules.
*
* AMD ISP4 SWNODE GRAPH Structure
*
* amd_camera {
* isp4 {
* ports {
* port@0 {
* isp4_mipi1_ep: endpoint {
* remote-endpoint = &OMNI5C10_ep;
* };
* };
* };
* };
*
* i2c1 {
* clock-frequency = 1 MHz;
* OMNI5C10 {
* clock-frequency = 24MHz;
* ports {
* port@0 {
* OMNI5C10_ep: endpoint {
* bus-type = 4;
* data-lanes = <1 2>;
* link-frequencies = 900MHz;
* remote-endpoint = &isp4_mipi1;
* };
* };
* };
* };
* };
* };
*
*/
static const struct software_node *ov05c10_nodes[] = {
&camera_node,
&ports,
&port_node,
&endpoint_node,
&remote_ep_isp_node,
static const struct software_node *amd_isp4_nodes[] = {
&amd_camera_node,
&isp4_node,
&isp4_ports,
&isp4_port_node,
&isp4_mipi1_endpoint_node,
&i2c1_node,
&ov05c10_camera_node,
&ov05c10_ports,
&ov05c10_port_node,
&ov05c10_endpoint_node,
NULL
};
@@ -141,7 +242,7 @@ static const struct amdisp_platform_info ov05c10_platform_config = {
.dev_name = "ov05c10",
I2C_BOARD_INFO("ov05c10", AMDISP_OV05C10_I2C_ADDR),
},
.swnodes = ov05c10_nodes,
.swnodes = amd_isp4_nodes,
};
static const struct acpi_device_id amdisp_sensor_ids[] = {
@@ -233,7 +334,8 @@ static struct amdisp_platform *prepare_amdisp_platform(struct device *dev,
if (ret)
return ERR_PTR(ret);
isp4_platform->board_info.swnode = src->swnodes[0];
/* initialize ov05c10_camera_node */
isp4_platform->board_info.swnode = src->swnodes[6];
return isp4_platform;
}
@@ -258,6 +360,7 @@ static int amd_isp_probe(struct platform_device *pdev)
{
const struct amdisp_platform_info *pinfo;
struct amdisp_platform *isp4_platform;
struct acpi_device *adev;
int ret;
pinfo = device_get_match_data(&pdev->dev);
@@ -275,6 +378,10 @@ static int amd_isp_probe(struct platform_device *pdev)
if (ret)
goto error_unregister_sw_node;
adev = ACPI_COMPANION(&pdev->dev);
/* initialize root amd_camera_node */
adev->driver_data = (void *)pinfo->swnodes[0];
/* check if adapter is already registered and create i2c client instance */
i2c_for_each_dev(isp4_platform, try_to_instantiate_i2c_client);

View File

@@ -11,7 +11,7 @@
#include <linux/dmi.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <asm/amd/fch.h>
#include <linux/platform_data/x86/amd-fch.h>
#include "pmc.h"

View File

@@ -530,6 +530,15 @@ static const struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_zenbook_duo_kbd,
},
{
.callback = dmi_matched,
.ident = "ASUS Zenbook Duo UX8406CA",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "UX8406CA"),
},
.driver_data = &quirk_asus_zenbook_duo_kbd,
},
{},
};

View File

@@ -45,6 +45,7 @@ static const struct dmi_system_id lis3lv02d_devices[] __initconst = {
* Additional individual entries were added after verification.
*/
DELL_LIS3LV02D_DMI_ENTRY("Latitude 5480", 0x29),
DELL_LIS3LV02D_DMI_ENTRY("Latitude 5500", 0x29),
DELL_LIS3LV02D_DMI_ENTRY("Latitude E6330", 0x29),
DELL_LIS3LV02D_DMI_ENTRY("Latitude E6430", 0x29),
DELL_LIS3LV02D_DMI_ENTRY("Precision 3540", 0x29),

View File

@@ -89,6 +89,11 @@ extern struct wmi_sysman_priv wmi_priv;
enum { ENUM, INT, STR, PO };
#define ENUM_MIN_ELEMENTS 8
#define INT_MIN_ELEMENTS 9
#define STR_MIN_ELEMENTS 8
#define PO_MIN_ELEMENTS 4
enum {
ATTR_NAME,
DISPL_NAME_LANG_CODE,

View File

@@ -23,9 +23,10 @@ static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *a
obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
if (!obj)
return -EIO;
if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count < ENUM_MIN_ELEMENTS ||
obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
kfree(obj);
return -EINVAL;
return -EIO;
}
ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
kfree(obj);

View File

@@ -25,9 +25,10 @@ static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *a
obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
if (!obj)
return -EIO;
if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_INTEGER) {
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count < INT_MIN_ELEMENTS ||
obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_INTEGER) {
kfree(obj);
return -EINVAL;
return -EIO;
}
ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[CURRENT_VAL].integer.value);
kfree(obj);

View File

@@ -26,9 +26,10 @@ static ssize_t is_enabled_show(struct kobject *kobj, struct kobj_attribute *attr
obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
if (!obj)
return -EIO;
if (obj->package.elements[IS_PASS_SET].type != ACPI_TYPE_INTEGER) {
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count < PO_MIN_ELEMENTS ||
obj->package.elements[IS_PASS_SET].type != ACPI_TYPE_INTEGER) {
kfree(obj);
return -EINVAL;
return -EIO;
}
ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[IS_PASS_SET].integer.value);
kfree(obj);

View File

@@ -25,9 +25,10 @@ static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *a
obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
if (!obj)
return -EIO;
if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count < STR_MIN_ELEMENTS ||
obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
kfree(obj);
return -EINVAL;
return -EIO;
}
ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
kfree(obj);

View File

@@ -407,10 +407,10 @@ static int init_bios_attributes(int attr_type, const char *guid)
return retval;
switch (attr_type) {
case ENUM: min_elements = 8; break;
case INT: min_elements = 9; break;
case STR: min_elements = 8; break;
case PO: min_elements = 4; break;
case ENUM: min_elements = ENUM_MIN_ELEMENTS; break;
case INT: min_elements = INT_MIN_ELEMENTS; break;
case STR: min_elements = STR_MIN_ELEMENTS; break;
case PO: min_elements = PO_MIN_ELEMENTS; break;
default:
pr_err("Error: Unknown attr_type: %d\n", attr_type);
return -EINVAL;
@@ -597,7 +597,7 @@ err_release_attributes_data:
release_attributes_data();
err_destroy_classdev:
device_destroy(&firmware_attributes_class, MKDEV(0, 0));
device_unregister(wmi_priv.class_dev);
err_exit_bios_attr_pass_interface:
exit_bios_attr_pass_interface();
@@ -611,7 +611,7 @@ err_exit_bios_attr_set_interface:
static void __exit sysman_exit(void)
{
release_attributes_data();
device_destroy(&firmware_attributes_class, MKDEV(0, 0));
device_unregister(wmi_priv.class_dev);
exit_bios_attr_set_interface();
exit_bios_attr_pass_interface();
}

View File

@@ -1034,7 +1034,7 @@ err_release_attributes_data:
release_attributes_data();
err_destroy_classdev:
device_destroy(&firmware_attributes_class, MKDEV(0, 0));
device_unregister(bioscfg_drv.class_dev);
err_unregister_class:
hp_exit_attr_set_interface();
@@ -1045,7 +1045,7 @@ err_unregister_class:
static void __exit hp_exit(void)
{
release_attributes_data();
device_destroy(&firmware_attributes_class, MKDEV(0, 0));
device_unregister(bioscfg_drv.class_dev);
hp_exit_attr_set_interface();
}

View File

@@ -54,6 +54,7 @@ static const struct acpi_device_id intel_hid_ids[] = {
{ "INTC107B" },
{ "INTC10CB" },
{ "INTC10CC" },
{ "INTC10F1" },
{ }
};
MODULE_DEVICE_TABLE(acpi, intel_hid_ids);

View File

@@ -236,6 +236,7 @@ static int pwec_probe(struct platform_device *pdev)
return ret;
}
ec_wdt_dev.parent = &pdev->dev;
ret = devm_watchdog_register_device(&pdev->dev, &ec_wdt_dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register Portwell EC Watchdog\n");

View File

@@ -973,6 +973,7 @@ static const struct attribute_group auth_attr_group = {
.is_visible = auth_attr_is_visible,
.attrs = auth_attrs,
};
__ATTRIBUTE_GROUPS(auth_attr);
/* ---- Attributes sysfs --------------------------------------------------------- */
static ssize_t display_name_show(struct kobject *kobj, struct kobj_attribute *attr,
@@ -1188,6 +1189,7 @@ static const struct attribute_group tlmi_attr_group = {
.is_visible = attr_is_visible,
.attrs = tlmi_attrs,
};
__ATTRIBUTE_GROUPS(tlmi_attr);
static void tlmi_attr_setting_release(struct kobject *kobj)
{
@@ -1207,11 +1209,13 @@ static void tlmi_pwd_setting_release(struct kobject *kobj)
static const struct kobj_type tlmi_attr_setting_ktype = {
.release = &tlmi_attr_setting_release,
.sysfs_ops = &kobj_sysfs_ops,
.default_groups = tlmi_attr_groups,
};
static const struct kobj_type tlmi_pwd_setting_ktype = {
.release = &tlmi_pwd_setting_release,
.sysfs_ops = &kobj_sysfs_ops,
.default_groups = auth_attr_groups,
};
static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr,
@@ -1380,21 +1384,18 @@ static struct kobj_attribute debug_cmd = __ATTR_WO(debug_cmd);
/* ---- Initialisation --------------------------------------------------------- */
static void tlmi_release_attr(void)
{
int i;
struct kobject *pos, *n;
/* Attribute structures */
for (i = 0; i < TLMI_SETTINGS_COUNT; i++) {
if (tlmi_priv.setting[i]) {
sysfs_remove_group(&tlmi_priv.setting[i]->kobj, &tlmi_attr_group);
kobject_put(&tlmi_priv.setting[i]->kobj);
}
}
sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr);
sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &save_settings.attr);
if (tlmi_priv.can_debug_cmd && debug_support)
sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr);
list_for_each_entry_safe(pos, n, &tlmi_priv.attribute_kset->list, entry)
kobject_put(pos);
kset_unregister(tlmi_priv.attribute_kset);
/* Free up any saved signatures */
@@ -1402,19 +1403,8 @@ static void tlmi_release_attr(void)
kfree(tlmi_priv.pwd_admin->save_signature);
/* Authentication structures */
sysfs_remove_group(&tlmi_priv.pwd_admin->kobj, &auth_attr_group);
kobject_put(&tlmi_priv.pwd_admin->kobj);
sysfs_remove_group(&tlmi_priv.pwd_power->kobj, &auth_attr_group);
kobject_put(&tlmi_priv.pwd_power->kobj);
if (tlmi_priv.opcode_support) {
sysfs_remove_group(&tlmi_priv.pwd_system->kobj, &auth_attr_group);
kobject_put(&tlmi_priv.pwd_system->kobj);
sysfs_remove_group(&tlmi_priv.pwd_hdd->kobj, &auth_attr_group);
kobject_put(&tlmi_priv.pwd_hdd->kobj);
sysfs_remove_group(&tlmi_priv.pwd_nvme->kobj, &auth_attr_group);
kobject_put(&tlmi_priv.pwd_nvme->kobj);
}
list_for_each_entry_safe(pos, n, &tlmi_priv.authentication_kset->list, entry)
kobject_put(pos);
kset_unregister(tlmi_priv.authentication_kset);
}
@@ -1455,6 +1445,14 @@ static int tlmi_sysfs_init(void)
goto fail_device_created;
}
tlmi_priv.authentication_kset = kset_create_and_add("authentication", NULL,
&tlmi_priv.class_dev->kobj);
if (!tlmi_priv.authentication_kset) {
kset_unregister(tlmi_priv.attribute_kset);
ret = -ENOMEM;
goto fail_device_created;
}
for (i = 0; i < TLMI_SETTINGS_COUNT; i++) {
/* Check if index is a valid setting - skip if it isn't */
if (!tlmi_priv.setting[i])
@@ -1471,12 +1469,8 @@ static int tlmi_sysfs_init(void)
/* Build attribute */
tlmi_priv.setting[i]->kobj.kset = tlmi_priv.attribute_kset;
ret = kobject_add(&tlmi_priv.setting[i]->kobj, NULL,
"%s", tlmi_priv.setting[i]->display_name);
if (ret)
goto fail_create_attr;
ret = sysfs_create_group(&tlmi_priv.setting[i]->kobj, &tlmi_attr_group);
ret = kobject_init_and_add(&tlmi_priv.setting[i]->kobj, &tlmi_attr_setting_ktype,
NULL, "%s", tlmi_priv.setting[i]->display_name);
if (ret)
goto fail_create_attr;
}
@@ -1496,55 +1490,34 @@ static int tlmi_sysfs_init(void)
}
/* Create authentication entries */
tlmi_priv.authentication_kset = kset_create_and_add("authentication", NULL,
&tlmi_priv.class_dev->kobj);
if (!tlmi_priv.authentication_kset) {
ret = -ENOMEM;
goto fail_create_attr;
}
tlmi_priv.pwd_admin->kobj.kset = tlmi_priv.authentication_kset;
ret = kobject_add(&tlmi_priv.pwd_admin->kobj, NULL, "%s", "Admin");
if (ret)
goto fail_create_attr;
ret = sysfs_create_group(&tlmi_priv.pwd_admin->kobj, &auth_attr_group);
ret = kobject_init_and_add(&tlmi_priv.pwd_admin->kobj, &tlmi_pwd_setting_ktype,
NULL, "%s", "Admin");
if (ret)
goto fail_create_attr;
tlmi_priv.pwd_power->kobj.kset = tlmi_priv.authentication_kset;
ret = kobject_add(&tlmi_priv.pwd_power->kobj, NULL, "%s", "Power-on");
if (ret)
goto fail_create_attr;
ret = sysfs_create_group(&tlmi_priv.pwd_power->kobj, &auth_attr_group);
ret = kobject_init_and_add(&tlmi_priv.pwd_power->kobj, &tlmi_pwd_setting_ktype,
NULL, "%s", "Power-on");
if (ret)
goto fail_create_attr;
if (tlmi_priv.opcode_support) {
tlmi_priv.pwd_system->kobj.kset = tlmi_priv.authentication_kset;
ret = kobject_add(&tlmi_priv.pwd_system->kobj, NULL, "%s", "System");
if (ret)
goto fail_create_attr;
ret = sysfs_create_group(&tlmi_priv.pwd_system->kobj, &auth_attr_group);
ret = kobject_init_and_add(&tlmi_priv.pwd_system->kobj, &tlmi_pwd_setting_ktype,
NULL, "%s", "System");
if (ret)
goto fail_create_attr;
tlmi_priv.pwd_hdd->kobj.kset = tlmi_priv.authentication_kset;
ret = kobject_add(&tlmi_priv.pwd_hdd->kobj, NULL, "%s", "HDD");
if (ret)
goto fail_create_attr;
ret = sysfs_create_group(&tlmi_priv.pwd_hdd->kobj, &auth_attr_group);
ret = kobject_init_and_add(&tlmi_priv.pwd_hdd->kobj, &tlmi_pwd_setting_ktype,
NULL, "%s", "HDD");
if (ret)
goto fail_create_attr;
tlmi_priv.pwd_nvme->kobj.kset = tlmi_priv.authentication_kset;
ret = kobject_add(&tlmi_priv.pwd_nvme->kobj, NULL, "%s", "NVMe");
if (ret)
goto fail_create_attr;
ret = sysfs_create_group(&tlmi_priv.pwd_nvme->kobj, &auth_attr_group);
ret = kobject_init_and_add(&tlmi_priv.pwd_nvme->kobj, &tlmi_pwd_setting_ktype,
NULL, "%s", "NVMe");
if (ret)
goto fail_create_attr;
}
@@ -1554,7 +1527,7 @@ static int tlmi_sysfs_init(void)
fail_create_attr:
tlmi_release_attr();
fail_device_created:
device_destroy(&firmware_attributes_class, MKDEV(0, 0));
device_unregister(tlmi_priv.class_dev);
fail_class_created:
return ret;
}
@@ -1577,8 +1550,6 @@ static struct tlmi_pwd_setting *tlmi_create_auth(const char *pwd_type,
new_pwd->maxlen = tlmi_priv.pwdcfg.core.max_length;
new_pwd->index = 0;
kobject_init(&new_pwd->kobj, &tlmi_pwd_setting_ktype);
return new_pwd;
}
@@ -1683,7 +1654,6 @@ static int tlmi_analyze(struct wmi_device *wdev)
if (setting->possible_values)
strreplace(setting->possible_values, ',', ';');
kobject_init(&setting->kobj, &tlmi_attr_setting_ktype);
tlmi_priv.setting[i] = setting;
kfree(item);
}
@@ -1781,7 +1751,7 @@ fail_clear_attr:
static void tlmi_remove(struct wmi_device *wdev)
{
tlmi_release_attr();
device_destroy(&firmware_attributes_class, MKDEV(0, 0));
device_unregister(tlmi_priv.class_dev);
}
static int tlmi_probe(struct wmi_device *wdev, const void *context)

View File

@@ -3295,6 +3295,7 @@ static const struct key_entry keymap_lenovo[] __initconst = {
*/
{ KE_KEY, 0x131d, { KEY_VENDOR } }, /* System debug info, similar to old ThinkPad key */
{ KE_KEY, 0x1320, { KEY_LINK_PHONE } },
{ KE_KEY, 0x1402, { KEY_LINK_PHONE } },
{ KE_KEY, TP_HKEY_EV_TRACK_DOUBLETAP /* 0x8036 */, { KEY_PROG4 } },
{ KE_END }
};

View File

@@ -177,16 +177,22 @@ static int wmi_device_enable(struct wmi_device *wdev, bool enable)
acpi_handle handle;
acpi_status status;
if (!(wblock->gblock.flags & ACPI_WMI_EXPENSIVE))
return 0;
if (wblock->dev.dev.type == &wmi_type_method)
return 0;
if (wblock->dev.dev.type == &wmi_type_event)
if (wblock->dev.dev.type == &wmi_type_event) {
/*
* Windows always enables/disables WMI events, even when they are
* not marked as being expensive. We follow this behavior for
* compatibility reasons.
*/
snprintf(method, sizeof(method), "WE%02X", wblock->gblock.notify_id);
else
} else {
if (!(wblock->gblock.flags & ACPI_WMI_EXPENSIVE))
return 0;
get_acpi_method_name(wblock, 'C', method);
}
/*
* Not all WMI devices marked as expensive actually implement the