diff options
78 files changed, 3073 insertions, 1309 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop index 2df70792968f..2397c65c969a 100644 --- a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop +++ b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop @@ -51,3 +51,30 @@ Description: Reading this file returns the current status of the breathing animation functionality. + +What: /sys/bus/platform/devices/INOU0000:XX/ctgp_offset +Date: January 2026 +KernelVersion: 7.0 +Contact: Werner Sembach <wse@tuxedocomputers.com> +Description: + Allows userspace applications to set the configurable TGP offset on top of the base + TGP. Base TGP and max TGP and therefore the max cTGP offset are device specific. + Note that setting the maximum cTGP leaves no window open for Dynamic Boost as + Dynamic Boost also can not go over max TGP. Setting the cTGP to maximum is + effectively disabling Dynamic Boost and telling the device to always prioritize the + GPU over the CPU. + + Reading this file returns the current configurable TGP offset. + +What: /sys/bus/platform/devices/INOU0000:XX/usb_c_power_priority +Date: February 2026 +KernelVersion: 7.1 +Contact: Werner Sembach <wse@tuxedocomputers.com> +Description: + Allows userspace applications to choose the USB-C power distribution profile between + one that offers a bigger share of the power to the battery and one that offers more + of it to the CPU. Writing "charging"/"performance" into this file selects the + respective profile. + + Reading this file returns the profile names with the currently active one in + brackets. diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst index 03951ed6b628..f874db31801d 100644 --- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst +++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst @@ -1522,6 +1522,27 @@ Currently 2 antenna types are supported as mentioned below: The property is read-only. If the platform doesn't have support the sysfs class is not created. +doubletap_enable +---------------- + +sysfs: doubletap_enable + +Controls whether TrackPoint doubletap events are filtered out. Doubletap is a +feature where quickly tapping the TrackPoint twice triggers a special function key event. + +The available commands are:: + + cat /sys/devices/platform/thinkpad_acpi/doubletap_enable + echo 1 | sudo tee /sys/devices/platform/thinkpad_acpi/doubletap_enable + echo 0 | sudo tee /sys/devices/platform/thinkpad_acpi/doubletap_enable + +Values: + + * 1 - doubletap events are processed (default) + * 0 - doubletap events are filtered out (ignored) + + This setting can also be toggled via the Fn+doubletap hotkey. + Auxmac ------ diff --git a/Documentation/admin-guide/laptops/uniwill-laptop.rst b/Documentation/admin-guide/laptops/uniwill-laptop.rst index aff5f57a6bd4..561334865feb 100644 --- a/Documentation/admin-guide/laptops/uniwill-laptop.rst +++ b/Documentation/admin-guide/laptops/uniwill-laptop.rst @@ -50,6 +50,10 @@ between 1 and 100 percent are supported. Additionally the driver signals the presence of battery charging issues through the standard ``health`` power supply sysfs attribute. +It also lets you set whether a USB-C power source should prioritise charging the battery or +delivering immediate power to the cpu. See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for +details. + Lightbar -------- @@ -58,3 +62,11 @@ LED class device. The default name of this LED class device is ``uniwill:multico See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details on how to control the various animation modes of the lightbar. + +Configurable TGP +---------------- + +The ``uniwill-laptop`` driver allows to set the configurable TGP for devices with NVIDIA GPUs that +allow it. + +See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details. diff --git a/Documentation/wmi/devices/bitland-mifs-wmi.rst b/Documentation/wmi/devices/bitland-mifs-wmi.rst new file mode 100644 index 000000000000..9e86ecc2993c --- /dev/null +++ b/Documentation/wmi/devices/bitland-mifs-wmi.rst @@ -0,0 +1,207 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +======================================== +Bitland MIFS driver (bitland-mifs-wmi) +======================================== + +Introduction +============ + + +EC WMI interface description +============================ + +The EC WMI interface description can be decoded from the embedded binary MOF (bmof) +data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility: + +:: + + class WMIEvent : __ExtrinsicEvent { + }; + + [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT20"), guid("{46c93e13-ee9b-4262-8488-563bca757fef}")] + class HID_EVENT20 : WmiEvent { + [key, read] string InstanceName; + [read] boolean Active; + [WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8]; + }; + + [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT21"), guid("{fa78e245-2c0f-4ca1-91cf-15f34e474850}")] + class HID_EVENT21 : WmiEvent { + [key, read] string InstanceName; + [read] boolean Active; + [WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8]; + }; + + [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT22"), guid("{1dceaf0a-4d63-44bb-bd0c-0d6281bfddc5}")] + class HID_EVENT22 : WmiEvent { + [key, read] string InstanceName; + [read] boolean Active; + [WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8]; + }; + + [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x40A"), Description("Root WMI HID_EVENT23"), guid("{3f9e3c26-b077-4f86-91f5-37ff64d8c7ed}")] + class HID_EVENT23 : WmiEvent { + [key, read] string InstanceName; + [read] boolean Active; + [WmiDataId(1), read, write, Description("Package Data")] uint8 EventDetail[8]; + }; + + [WMI, Dynamic, provider("WmiProv"), Locale("MS\\0x409"), Description("Class used to operate firmware interface"), guid("{b60bfb48-3e5b-49e4-a0e9-8cffe1b3434b}")] + class MICommonInterface { + [key, read] string InstanceName; + [read] boolean Active; + + [WmiMethodId(1), Implemented, read, write, Description("Method used to support system functions.")] void MiInterface([in, Description("WMI Interface")] uint8 InData[32], [out] uint8 OutData[30], [out] uint16 Reserved); + }; + +Reverse-Engineering the EC WMI interface +======================================== + +The OEM software can be download from `this link <https://iknow.lenovo.com.cn/detail/429447>`_ + +Nothing is obfuscated, In this case, `ILSpy <https://github.com/icsharpcode/ILSpy>`_ could be helpful. + +WMI Methods (MICommonInterface) +======================================== + +The ``MICommonInterface`` class (GUID: ``{b60bfb48-3e5b-49e4-a0e9-8cffe1b3434b}``) +is the primary control interface. It uses a 32-byte buffer for both input +(``InData``) and output (``OutData``). + +Method Structure +---------------- + +The data packet follows a standardized format: + ++----------+------------------------------------------------------------------+ +| Byte | Description | ++==========+==================================================================+ +| 1 | Method Type: Get (0xFA / 250) or Set (0xFB / 251) | ++----------+------------------------------------------------------------------+ +| 3 | Command ID (Method Name) | ++----------+------------------------------------------------------------------+ +| 4 - 31 | Arguments (for Set) or Return Data (for Get) | ++----------+------------------------------------------------------------------+ + + +Command IDs +----------- + +The following Command IDs are used in the third byte of the buffer: + ++----------+-----------------------+------------------------------------------+ +| ID | Name | Values / Description | ++==========+=======================+==========================================+ +| 8 | SystemPerMode | 0: Balance, 1: Performance, 2: Quiet, | +| | | 3: Full-speed | ++----------+-----------------------+------------------------------------------+ +| 9 | GPUMode | 0: Hybrid, 1: Discrete, 2: UMA | ++----------+-----------------------+------------------------------------------+ +| 10 | KeyboardType | 0: White, 1: Single RGB, 2: Zone RGB | ++----------+-----------------------+------------------------------------------+ +| 11 | FnLock | 0: Off, 1: On | ++----------+-----------------------+------------------------------------------+ +| 12 | TPLock | 0: Unlock, 1: Lock (Touchpad) | ++----------+-----------------------+------------------------------------------+ +| 13 | CPUGPUSYSFanSpeed | Returns 12 bytes of fan data: | +| | | Bytes 4-5: CPU Fan RPM (Little Endian) | +| | | Bytes 6-7: GPU Fan RPM (Little Endian) | +| | | Bytes 10-11: SYS Fan RPM (Little Endian) | ++----------+-----------------------+------------------------------------------+ +| 16 | RGBKeyboardMode | 0: Off, 1: Auto Cyclic, 2: Fixed, | +| | | 3: Custom | ++----------+-----------------------+------------------------------------------+ +| 17 | RGBKeyboardColor | Bytes 4, 5, 6: Red, Green, Blue values | ++----------+-----------------------+------------------------------------------+ +| 18 | RGBKeyboardBrightness | 0-10: Brightness Levels, 128: Auto | ++----------+-----------------------+------------------------------------------+ +| 19 | SystemAcType | 1: Type-C, 2: Circular Hole (DC) | ++----------+-----------------------+------------------------------------------+ +| 20 | MaxFanSpeedSwitch | Byte 4: Fan Type (0: CPU/GPU, 1: SYS) | +| | | Byte 5: State (0: Off, 1: On) | ++----------+-----------------------+------------------------------------------+ +| 21 | MaxFanSpeed | Sets manual fan speed duty cycle | ++----------+-----------------------+------------------------------------------+ +| 22 | CPUThermometer | Returns CPU Temperature | ++----------+-----------------------+------------------------------------------+ + +WMI Events (HID_EVENT20) +======================== + +The driver listens for events from the ``HID_EVENT20`` class +(GUID: ``{46c93e13-ee9b-4262-8488-563bca757fef}``). These events are triggered +by hotkeys or system state changes (e.g., plugging in AC power). + +Event Structure +--------------- + +The event data is provided in an 8-byte array (``EventDetail``): + ++----------+------------------------------------------------------------------+ +| Byte | Description | ++==========+==================================================================+ +| 0 | Event Type (Always 0x01 for HotKey/Notification) | ++----------+------------------------------------------------------------------+ +| 1 | Event ID (Corresponds to the Command IDs above) | ++----------+------------------------------------------------------------------+ +| 2 | Value (The new state or value of the feature) | ++----------+------------------------------------------------------------------+ + +Common Event IDs: +----------------- + +Note: reserved event ids are not listed there + ++----------+------------------------------------------------------------------+ +| Event Id | Description | ++==========+==================================================================+ +| 4 | AirPlane mode change | ++----------+------------------------------------------------------------------+ +| 5 | Keyboard brightness change | ++----------+------------------------------------------------------------------+ +| 6 | Touchpad state (enabled/disabled) change | ++----------+------------------------------------------------------------------+ +| 7 | FnLock state (enabled/disabled) change | ++----------+------------------------------------------------------------------+ +| 8 | Keyboard mode change | ++----------+------------------------------------------------------------------+ +| 9 | CapsLock state change | ++----------+------------------------------------------------------------------+ +| 13 | NumLock state change | ++----------+------------------------------------------------------------------+ +| 14 | ScrollLock state change | ++----------+------------------------------------------------------------------+ +| 15 | Performance plan change | ++----------+------------------------------------------------------------------+ +| 25 | Display refresh rate change | ++----------+------------------------------------------------------------------+ +| 33 | Super key lock state (enabled/disabled) change | ++----------+------------------------------------------------------------------+ +| 35 | Open control center key | ++----------+------------------------------------------------------------------+ + +Implementation Details +====================== + +Performance Modes +----------------- +Changing the performance mode via Command ID 0x08 (SystemPerMode) affects the +power limits (PL1/PL2) and fan curves managed by the Embedded Controller (EC). +Note that the "Full-speed" and "Performance" mode (1, 3) is typically only +available when the system is connected to a DC power source (not USB-C/PD). + +In the driver implementation, switch to performance/full-speed mode without +DC power connected will throw the EOPNOTSUPP error. + +Graphics Switching +------------------ +The ``GPUMode`` (0x09) allows switching between Hybrid (Muxless) and Discrete +(Muxed) graphics. Changing this value usually requires a system reboot to +take effect in the BIOS/Firmware. + +Fan Control +----------- +The system supports both automatic EC control and manual overrides. Command ID +0x14 (``MaxFanSpeedSwitch``) is used to toggle manual control, while ID 0x15 +sets the actual PWM duty cycle. diff --git a/Documentation/wmi/driver-development-guide.rst b/Documentation/wmi/driver-development-guide.rst index fbc2d9b12fe9..387f508d57ad 100644 --- a/Documentation/wmi/driver-development-guide.rst +++ b/Documentation/wmi/driver-development-guide.rst @@ -71,7 +71,7 @@ to matching WMI devices using a struct wmi_device_id table: .remove = foo_remove, /* optional, devres is preferred */ .shutdown = foo_shutdown, /* optional, called during shutdown */ .notify_new = foo_notify, /* optional, for event handling */ - .no_notify_data = true, /* optional, enables events containing no additional data */ + .min_event_size = X, /* optional, simplifies event payload size verification */ .no_singleton = true, /* required for new WMI drivers */ }; module_wmi_driver(foo_driver); @@ -106,7 +106,8 @@ WMI method drivers WMI drivers can call WMI device methods using wmidev_invoke_method(). For each WMI method invocation the WMI driver needs to provide the instance number and the method ID, as well as -a buffer with the method arguments and optionally a buffer for the results. +a buffer with the method arguments and optionally a buffer for the results. When calling WMI +methods that do not return any values, wmidev_invoke_procedure() should be used instead. The layout of said buffers is device-specific and described by the Binary MOF data associated with a given WMI device. Said Binary MOF data also describes the method ID of a given WMI method @@ -141,8 +142,10 @@ right before and after calling its remove() or shutdown() callback. However WMI driver developers should be aware that multiple WMI events can be received concurrently, so any locking (if necessary) needs to be provided by the WMI driver itself. -In order to be able to receive WMI events containing no additional event data, -the ``no_notify_data`` flag inside struct wmi_driver should be set to ``true``. +The WMI driver can furthermore instruct the WMI driver core to automatically reject WMI events +that contain a undersized event payload by populating the ``min_event_size`` field inside +struct wmi_driver. Setting this field to 0 will thus enable the WMI driver to receive WMI events +without any event payload. Take a look at drivers/platform/x86/xiaomi-wmi.c for an example WMI event driver. diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index 844cfafe1ec7..ad2d8f179eb6 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -45,7 +45,7 @@ static void read_residency_counter(struct xe_device *xe, struct xe_mmio *mmio, u64 residency = 0; int ret; - ret = xe_pmt_telem_read(to_pci_dev(xe->drm.dev), + ret = xe_pmt_telem_read(xe->drm.dev, xe_mmio_read32(mmio, PUNIT_TELEMETRY_GUID), &residency, offset, sizeof(residency)); if (ret != sizeof(residency)) { diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c index 0fd4d4f1014a..92e423a339f1 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -506,7 +506,7 @@ xe_hwmon_energy_get(struct xe_hwmon *hwmon, int channel, long *energy) if (hwmon->xe->info.platform == XE_BATTLEMAGE) { u64 pmt_val; - ret = xe_pmt_telem_read(to_pci_dev(hwmon->xe->drm.dev), + ret = xe_pmt_telem_read(hwmon->xe->drm.dev, xe_mmio_read32(mmio, PUNIT_TELEMETRY_GUID), &pmt_val, BMG_ENERGY_STATUS_PMT_OFFSET, sizeof(pmt_val)); if (ret != sizeof(pmt_val)) { diff --git a/drivers/gpu/drm/xe/xe_vsec.c b/drivers/gpu/drm/xe/xe_vsec.c index 4ebb4dbe1c9b..a9baf0bfe572 100644 --- a/drivers/gpu/drm/xe/xe_vsec.c +++ b/drivers/gpu/drm/xe/xe_vsec.c @@ -140,10 +140,10 @@ static int xe_guid_decode(u32 guid, int *index, u32 *offset) return 0; } -int xe_pmt_telem_read(struct pci_dev *pdev, u32 guid, u64 *data, loff_t user_offset, +int xe_pmt_telem_read(struct device *dev, u32 guid, u64 *data, loff_t user_offset, u32 count) { - struct xe_device *xe = pdev_to_xe_device(pdev); + struct xe_device *xe = kdev_to_xe_device(dev); void __iomem *telem_addr = xe->mmio.regs + BMG_TELEMETRY_OFFSET; u32 mem_region; u32 offset; @@ -198,7 +198,6 @@ void xe_vsec_init(struct xe_device *xe) { struct intel_vsec_platform_info *info; struct device *dev = xe->drm.dev; - struct pci_dev *pdev = to_pci_dev(dev); enum xe_vsec platform; platform = get_platform_info(xe); @@ -221,6 +220,6 @@ void xe_vsec_init(struct xe_device *xe) * Register a VSEC. Cleanup is handled using device managed * resources. */ - intel_vsec_register(pdev, info); + intel_vsec_register(dev, info); } MODULE_IMPORT_NS("INTEL_VSEC"); diff --git a/drivers/gpu/drm/xe/xe_vsec.h b/drivers/gpu/drm/xe/xe_vsec.h index dabfb4e02d70..a25b4e6e681b 100644 --- a/drivers/gpu/drm/xe/xe_vsec.h +++ b/drivers/gpu/drm/xe/xe_vsec.h @@ -6,10 +6,10 @@ #include <linux/types.h> -struct pci_dev; +struct device; struct xe_device; void xe_vsec_init(struct xe_device *xe); -int xe_pmt_telem_read(struct pci_dev *pdev, u32 guid, u64 *data, loff_t user_offset, u32 count); +int xe_pmt_telem_read(struct device *dev, u32 guid, u64 *data, loff_t user_offset, u32 count); #endif diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index b06c7ad721fe..3bd8fdf56cd3 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -5,6 +5,7 @@ * Trademarks are the property of their respective owners. */ +#include <linux/array_size.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/serio.h> @@ -12,6 +13,7 @@ #include <linux/input.h> #include <linux/libps2.h> #include <linux/proc_fs.h> +#include <linux/string.h> #include <linux/uaccess.h> #include "psmouse.h" #include "trackpoint.h" @@ -393,6 +395,44 @@ static int trackpoint_reconnect(struct psmouse *psmouse) return 0; } +/* List of known incapable device PNP IDs */ +static const char * const dt_incompatible_devices[] = { + "LEN0304", + "LEN0306", + "LEN0317", + "LEN031A", + "LEN031B", + "LEN031C", + "LEN031D", +}; + +/* + * Checks if it's a doubletap capable device. + * The PNP ID format is "PNP: LEN030d PNP0f13". + */ +static bool trackpoint_is_dt_capable(const char *pnp_id) +{ + size_t i; + + if (!pnp_id) + return false; + + /* Must start with "PNP: LEN03" */ + if (!strstarts(pnp_id, "PNP: LEN03")) + return false; + + /* Ensure enough length before comparing */ + if (strlen(pnp_id) < 12) + return false; + + /* Check deny-list */ + for (i = 0; i < ARRAY_SIZE(dt_incompatible_devices); i++) { + if (!strncmp(pnp_id + 5, dt_incompatible_devices[i], 7)) + return false; + } + return true; +} + int trackpoint_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; @@ -470,6 +510,12 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) psmouse->vendor, firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f); + if (trackpoint_is_dt_capable(ps2dev->serio->firmware_id)) { + error = trackpoint_write(ps2dev, TP_DOUBLETAP, TP_DOUBLETAP_ENABLE); + if (error) + psmouse_warn(psmouse, "Failed to enable doubletap: %d\n", error); + } + return 0; } diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h index eb5412904fe0..3e03cdb39449 100644 --- a/drivers/input/mouse/trackpoint.h +++ b/drivers/input/mouse/trackpoint.h @@ -69,6 +69,8 @@ /* (how hard it is to drag */ /* with Z-axis pressed) */ +#define TP_DOUBLETAP 0x58 /* TrackPoint doubletap register */ + #define TP_MINDRAG 0x59 /* Minimum amount of force needed */ /* to trigger dragging */ @@ -110,6 +112,9 @@ external device will be forced to 1 */ #define TP_MASK_EXT_TAG 0x04 +/* Doubletap register values */ +#define TP_DOUBLETAP_ENABLE 0xFF /* Enable value */ +#define TP_DOUBLETAP_DISABLE 0xFE /* Disable value */ /* Power on Self Test Results */ #define TP_POR_SUCCESS 0x3B diff --git a/drivers/platform/mellanox/nvsw-sn2201.c b/drivers/platform/mellanox/nvsw-sn2201.c index 51504113c17e..92b58ba8f97b 100644 --- a/drivers/platform/mellanox/nvsw-sn2201.c +++ b/drivers/platform/mellanox/nvsw-sn2201.c @@ -10,7 +10,6 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/gpio.h> #include <linux/module.h> #include <linux/platform_data/mlxcpld.h> #include <linux/platform_data/mlxreg.h> diff --git a/drivers/platform/surface/surface_hotplug.c b/drivers/platform/surface/surface_hotplug.c index c0d83ed5a208..33a8a9d41900 100644 --- a/drivers/platform/surface/surface_hotplug.c +++ b/drivers/platform/surface/surface_hotplug.c @@ -14,7 +14,7 @@ */ #include <linux/acpi.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c index 9bd39f09c7db..0293bc517b54 100644 --- a/drivers/platform/surface/surfacepro3_button.c +++ b/drivers/platform/surface/surfacepro3_button.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/input.h> #include <linux/acpi.h> +#include <linux/platform_device.h> #include <acpi/button.h> #define SURFACE_PRO3_BUTTON_HID "MSHW0028" @@ -72,9 +73,10 @@ struct surface_button { bool suspended; }; -static void surface_button_notify(struct acpi_device *device, u32 event) +static void surface_button_notify(acpi_handle handle, u32 event, void *data) { - struct surface_button *button = acpi_driver_data(device); + struct device *dev = data; + struct surface_button *button = dev_get_drvdata(dev); struct input_dev *input; int key_code = KEY_RESERVED; bool pressed = false; @@ -109,18 +111,17 @@ static void surface_button_notify(struct acpi_device *device, u32 event) key_code = KEY_VOLUMEDOWN; break; case SURFACE_BUTTON_NOTIFY_TABLET_MODE: - dev_warn_once(&device->dev, "Tablet mode is not supported\n"); + dev_warn_once(dev, "Tablet mode is not supported\n"); break; default: - dev_info_ratelimited(&device->dev, - "Unsupported event [0x%x]\n", event); + dev_info_ratelimited(dev, "Unsupported event [0x%x]\n", event); break; } input = button->input; if (key_code == KEY_RESERVED) return; if (pressed) - pm_wakeup_dev_event(&device->dev, 0, button->suspended); + pm_wakeup_dev_event(dev, 0, button->suspended); if (button->suspended) return; input_report_key(input, key_code, pressed?1:0); @@ -130,8 +131,7 @@ static void surface_button_notify(struct acpi_device *device, u32 event) #ifdef CONFIG_PM_SLEEP static int surface_button_suspend(struct device *dev) { - struct acpi_device *device = to_acpi_device(dev); - struct surface_button *button = acpi_driver_data(device); + struct surface_button *button = dev_get_drvdata(dev); button->suspended = true; return 0; @@ -139,8 +139,7 @@ static int surface_button_suspend(struct device *dev) static int surface_button_resume(struct device *dev) { - struct acpi_device *device = to_acpi_device(dev); - struct surface_button *button = acpi_driver_data(device); + struct surface_button *button = dev_get_drvdata(dev); button->suspended = false; return 0; @@ -155,9 +154,8 @@ static int surface_button_resume(struct device *dev) * Returns true if the driver should bind to this device, i.e. the device is * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. */ -static bool surface_button_check_MSHW0040(struct acpi_device *dev) +static bool surface_button_check_MSHW0040(struct device *dev, acpi_handle handle) { - acpi_handle handle = dev->handle; union acpi_object *result; u64 oem_platform_rev = 0; // valid revisions are nonzero @@ -179,14 +177,15 @@ static bool surface_button_check_MSHW0040(struct acpi_device *dev) ACPI_FREE(result); } - dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); + dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev); return oem_platform_rev == 0; } -static int surface_button_add(struct acpi_device *device) +static int surface_button_probe(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct surface_button *button; struct input_dev *input; const char *hid = acpi_device_hid(device); @@ -196,14 +195,14 @@ static int surface_button_add(struct acpi_device *device) strlen(SURFACE_BUTTON_OBJ_NAME))) return -ENODEV; - if (!surface_button_check_MSHW0040(device)) + if (!surface_button_check_MSHW0040(&pdev->dev, device->handle)) return -ENODEV; button = kzalloc_obj(struct surface_button); if (!button) return -ENOMEM; - device->driver_data = button; + platform_set_drvdata(pdev, button); button->input = input = input_allocate_device(); if (!input) { error = -ENOMEM; @@ -216,7 +215,7 @@ static int surface_button_add(struct acpi_device *device) input->name = acpi_device_name(device); input->phys = button->phys; input->id.bustype = BUS_HOST; - input->dev.parent = &device->dev; + input->dev.parent = &pdev->dev; input_set_capability(input, EV_KEY, KEY_POWER); input_set_capability(input, EV_KEY, KEY_LEFTMETA); input_set_capability(input, EV_KEY, KEY_VOLUMEUP); @@ -226,8 +225,17 @@ static int surface_button_add(struct acpi_device *device) if (error) goto err_free_input; - device_init_wakeup(&device->dev, true); - dev_info(&device->dev, "%s [%s]\n", acpi_device_name(device), + device_init_wakeup(&pdev->dev, true); + + error = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + surface_button_notify, &pdev->dev); + if (error) { + device_init_wakeup(&pdev->dev, false); + input_unregister_device(input); + goto err_free_button; + } + + dev_info(&pdev->dev, "%s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); return 0; @@ -238,10 +246,13 @@ static int surface_button_add(struct acpi_device *device) return error; } -static void surface_button_remove(struct acpi_device *device) +static void surface_button_remove(struct platform_device *pdev) { - struct surface_button *button = acpi_driver_data(device); + struct surface_button *button = platform_get_drvdata(pdev); + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, surface_button_notify); + device_init_wakeup(&pdev->dev, false); input_unregister_device(button->input); kfree(button); } @@ -249,16 +260,14 @@ static void surface_button_remove(struct acpi_device *device) static SIMPLE_DEV_PM_OPS(surface_button_pm, surface_button_suspend, surface_button_resume); -static struct acpi_driver surface_button_driver = { - .name = "surface_pro3_button", - .class = "SurfacePro3", - .ids = surface_button_device_ids, - .ops = { - .add = surface_button_add, - .remove = surface_button_remove, - .notify = surface_button_notify, +static struct platform_driver surface_button_driver = { + .probe = surface_button_probe, + .remove = surface_button_remove, + .driver = { + .name = "surface_pro3_button", + .acpi_match_table = surface_button_device_ids, + .pm = &surface_button_pm, }, - .drv.pm = &surface_button_pm, }; -module_acpi_driver(surface_button_driver); +module_platform_driver(surface_button_driver); diff --git a/drivers/platform/wmi/core.c b/drivers/platform/wmi/core.c index 750e3619724e..7aa40dab6145 100644 --- a/drivers/platform/wmi/core.c +++ b/drivers/platform/wmi/core.c @@ -364,20 +364,23 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 met EXPORT_SYMBOL_GPL(wmidev_evaluate_method); /** - * wmidev_invoke_method - Invoke a WMI method + * wmidev_invoke_method - Invoke a WMI method that returns values * @wdev: A wmi bus device from a driver * @instance: Instance index * @method_id: Method ID to call * @in: Mandatory WMI buffer containing input for the method call - * @out: Optional WMI buffer to return the method results + * @out: Mandatory WMI buffer to return the method results + * @min_size: Minimum size of the method result data in bytes * - * Invoke a WMI method, the caller must free the resulting data inside @out. - * Said data is guaranteed to be aligned on a 8-byte boundary. + * Invoke a WMI method that returns values, the caller must free the resulting + * data inside @out using kfree(). Said data is guaranteed to be aligned on a + * 8-byte boundary. Use wmidev_invoke_procedure() for WMI methods that + * return no values. * * Return: 0 on success or negative error code on failure. */ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id, - const struct wmi_buffer *in, struct wmi_buffer *out) + const struct wmi_buffer *in, struct wmi_buffer *out, size_t min_size) { struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev); struct acpi_buffer aout = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -398,10 +401,7 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id, ain.pointer = in->data; } - if (out) - status = wmidev_evaluate_method(wdev, instance, method_id, &ain, &aout); - else - status = wmidev_evaluate_method(wdev, instance, method_id, &ain, NULL); + status = wmidev_evaluate_method(wdev, instance, method_id, &ain, &aout); if (wblock->gblock.flags & ACPI_WMI_STRING) kfree(ain.pointer); @@ -409,9 +409,6 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id, if (ACPI_FAILURE(status)) return -EIO; - if (!out) - return 0; - obj = aout.pointer; if (!obj) { out->length = 0; @@ -420,13 +417,57 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id, return 0; } - ret = wmi_unmarshal_acpi_object(obj, out); + ret = wmi_unmarshal_acpi_object(obj, out, min_size); kfree(obj); return ret; } EXPORT_SYMBOL_GPL(wmidev_invoke_method); +/** + * wmidev_invoke_procedure - Invoke a WMI method that does not return values + * @wdev: A wmi bus device from a driver + * @instance: Instance index + * @method_id: Method ID to call + * @in: Mandatory WMI buffer containing input for the method call + * + * Invoke a WMI method that does not return any values. Use wmidev_invoke_method() + * for WMI methods that do return values. + * + * Return: 0 on success or negative error code on failure. + */ +int wmidev_invoke_procedure(struct wmi_device *wdev, u8 instance, u32 method_id, + const struct wmi_buffer *in) +{ + struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev); + struct acpi_buffer ain; + acpi_status status; + int ret; + + if (wblock->gblock.flags & ACPI_WMI_STRING) { + ret = wmi_marshal_string(in, &ain); + if (ret < 0) + return ret; + } else { + if (in->length > U32_MAX) + return -E2BIG; + + ain.length = in->length; + ain.pointer = in->data; + } + + status = wmidev_evaluate_method(wdev, instance, method_id, &ain, NULL); + + if (wblock->gblock.flags & ACPI_WMI_STRING) + kfree(ain.pointer); + + if (ACPI_FAILURE(status)) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(wmidev_invoke_procedure); + static acpi_status __query_block(struct wmi_block *wblock, u8 instance, struct acpi_buffer *out) { @@ -524,13 +565,15 @@ EXPORT_SYMBOL_GPL(wmidev_block_query); * @wdev: A wmi bus device from a driver * @instance: Instance index * @out: WMI buffer to fill + * @min_size: Minimum size of the result data in bytes * - * Query a WMI data block, the caller must free the resulting data inside @out. - * Said data is guaranteed to be aligned on a 8-byte boundary. + * Query a WMI data block, the caller must free the resulting data inside @out + * using kfree(). Said data is guaranteed to be aligned on a 8-byte boundary. * * Return: 0 on success or a negative error code on failure. */ -int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *out) +int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *out, + size_t min_size) { union acpi_object *obj; int ret; @@ -539,7 +582,7 @@ int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer * if (!obj) return -EIO; - ret = wmi_unmarshal_acpi_object(obj, out); + ret = wmi_unmarshal_acpi_object(obj, out, min_size); kfree(obj); return ret; @@ -970,7 +1013,7 @@ static int wmi_dev_probe(struct device *dev) } if (wdriver->notify || wdriver->notify_new) { - if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags) && !wdriver->no_notify_data) + if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags) && wdriver->min_event_size) return -ENODEV; } @@ -1329,10 +1372,14 @@ static int wmi_get_notify_data(struct wmi_block *wblock, union acpi_object **obj static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj) { struct wmi_driver *driver = to_wmi_driver(wblock->dev.dev.driver); + struct wmi_buffer dummy = { + .length = 0, + .data = ZERO_SIZE_PTR, + }; struct wmi_buffer buffer; int ret; - if (!obj && !driver->no_notify_data) { + if (!obj && driver->min_event_size) { dev_warn(&wblock->dev.dev, "Event contains no event data\n"); return; } @@ -1342,11 +1389,11 @@ static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj) if (driver->notify_new) { if (!obj) { - driver->notify_new(&wblock->dev, NULL); + driver->notify_new(&wblock->dev, &dummy); return; } - ret = wmi_unmarshal_acpi_object(obj, &buffer); + ret = wmi_unmarshal_acpi_object(obj, &buffer, driver->min_event_size); if (ret < 0) { dev_warn(&wblock->dev.dev, "Failed to unmarshal event data: %d\n", ret); return; diff --git a/drivers/platform/wmi/internal.h b/drivers/platform/wmi/internal.h index 9a39ffa31ad1..c02908694563 100644 --- a/drivers/platform/wmi/internal.h +++ b/drivers/platform/wmi/internal.h @@ -11,7 +11,8 @@ union acpi_object; struct wmi_buffer; -int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer); +int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer, + size_t min_size); int wmi_marshal_string(const struct wmi_buffer *buffer, struct acpi_buffer *out); #endif /* _WMI_INTERNAL_H_ */ diff --git a/drivers/platform/wmi/marshalling.c b/drivers/platform/wmi/marshalling.c index 63a92c4ebab5..87091832568e 100644 --- a/drivers/platform/wmi/marshalling.c +++ b/drivers/platform/wmi/marshalling.c @@ -151,7 +151,8 @@ static int wmi_obj_transform(const union acpi_object *obj, u8 *buffer) return 0; } -int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer) +int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer, + size_t min_size) { size_t length, alloc_length; u8 *data; @@ -161,6 +162,9 @@ int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *b if (ret < 0) return ret; + if (length < min_size) + return -ENODATA; + if (ARCH_KMALLOC_MINALIGN < 8) { /* * kmalloc() guarantees that the alignment of the resulting memory allocation is at diff --git a/drivers/platform/wmi/tests/marshalling_kunit.c b/drivers/platform/wmi/tests/marshalling_kunit.c index 0c7cd8774aa3..471963076d58 100644 --- a/drivers/platform/wmi/tests/marshalling_kunit.c +++ b/drivers/platform/wmi/tests/marshalling_kunit.c @@ -372,7 +372,7 @@ static void wmi_unmarshal_acpi_object_test(struct kunit *test) struct wmi_buffer result; int ret; - ret = wmi_unmarshal_acpi_object(¶m->obj, &result); + ret = wmi_unmarshal_acpi_object(¶m->obj, &result, param->buffer.length); if (ret < 0) KUNIT_FAIL_AND_ABORT(test, "Unmarshalling of ACPI object failed\n"); @@ -389,7 +389,7 @@ static void wmi_unmarshal_acpi_object_failure_test(struct kunit *test) struct wmi_buffer result; int ret; - ret = wmi_unmarshal_acpi_object(¶m->obj, &result); + ret = wmi_unmarshal_acpi_object(¶m->obj, &result, 0); if (ret < 0) return; @@ -427,6 +427,25 @@ static void wmi_marshal_string_failure_test(struct kunit *test) KUNIT_FAIL(test, "Invalid string was not rejected\n"); } +static void wmi_unmarshal_acpi_object_undersized_test(struct kunit *test) +{ + const union acpi_object obj = { + .integer = { + .type = ACPI_TYPE_INTEGER, + .value = 0xdeadbeef, + }, + }; + struct wmi_buffer result; + int ret; + + ret = wmi_unmarshal_acpi_object(&obj, &result, sizeof(expected_single_integer) + 1); + if (ret < 0) + return; + + kfree(result.data); + KUNIT_FAIL(test, "Undersized unmarshalling result was not rejected\n"); +} + static struct kunit_case wmi_marshalling_test_cases[] = { KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_test, wmi_unmarshal_acpi_object_gen_params), @@ -436,6 +455,7 @@ static struct kunit_case wmi_marshalling_test_cases[] = { wmi_unmarshal_acpi_object_failure_gen_params), KUNIT_CASE_PARAM(wmi_marshal_string_failure_test, wmi_marshal_string_failure_gen_params), + KUNIT_CASE(wmi_unmarshal_acpi_object_undersized_test), {} }; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 4cb7d97a9fcc..2ffa4ecf65b0 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -113,6 +113,24 @@ config GIGABYTE_WMI To compile this driver as a module, choose M here: the module will be called gigabyte-wmi. +config BITLAND_MIFS_WMI + tristate "Bitland MIFS (MiInterface) WMI driver" + depends on ACPI_WMI + depends on HWMON + depends on INPUT + depends on POWER_SUPPLY + select ACPI_PLATFORM_PROFILE + select INPUT_SPARSEKMAP + help + This is a driver for Bitland MiInterface based laptops. + + It provides the access to the temperature, fan speed, gpu + control, keyboard backlight brightness and platform profile + via hwmon and sysfs. + + To compile this driver as a module, choose M here: the module will + be called bitland-mifs-wmi. + config ACERHDF tristate "Acer Aspire One temperature and fan driver" depends on ACPI_EC && THERMAL diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index d25762f7114f..872ac3842391 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_NVIDIA_WMI_EC_BACKLIGHT) += nvidia-wmi-ec-backlight.o obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o obj-$(CONFIG_REDMI_WMI) += redmi-wmi.o obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o +obj-$(CONFIG_BITLAND_MIFS_WMI) += bitland-mifs-wmi.o # Acer obj-$(CONFIG_ACERHDF) += acerhdf.o diff --git a/drivers/platform/x86/acer-wireless.c b/drivers/platform/x86/acer-wireless.c index 1b5d935d085a..f464b13a58af 100644 --- a/drivers/platform/x86/acer-wireless.c +++ b/drivers/platform/x86/acer-wireless.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci_ids.h> +#include <linux/platform_device.h> #include <linux/types.h> static const struct acpi_device_id acer_wireless_acpi_ids[] = { @@ -18,13 +19,14 @@ static const struct acpi_device_id acer_wireless_acpi_ids[] = { }; MODULE_DEVICE_TABLE(acpi, acer_wireless_acpi_ids); -static void acer_wireless_notify(struct acpi_device *adev, u32 event) +static void acer_wireless_notify(acpi_handle handle, u32 event, void *data) { - struct input_dev *idev = acpi_driver_data(adev); + struct device *dev = data; + struct input_dev *idev = dev_get_drvdata(dev); - dev_dbg(&adev->dev, "event=%#x\n", event); + dev_dbg(dev, "event=%#x\n", event); if (event != 0x80) { - dev_notice(&adev->dev, "Unknown SMKB event: %#x\n", event); + dev_notice(dev, "Unknown SMKB event: %#x\n", event); return; } input_report_key(idev, KEY_RFKILL, 1); @@ -33,15 +35,16 @@ static void acer_wireless_notify(struct acpi_device *adev, u32 event) input_sync(idev); } -static int acer_wireless_add(struct acpi_device *adev) +static int acer_wireless_probe(struct platform_device *pdev) { struct input_dev *idev; + int ret; - idev = devm_input_allocate_device(&adev->dev); + idev = devm_input_allocate_device(&pdev->dev); if (!idev) return -ENOMEM; - adev->driver_data = idev; + platform_set_drvdata(pdev, idev); idev->name = "Acer Wireless Radio Control"; idev->phys = "acer-wireless/input0"; idev->id.bustype = BUS_HOST; @@ -50,19 +53,32 @@ static int acer_wireless_add(struct acpi_device *adev) set_bit(EV_KEY, idev->evbit); set_bit(KEY_RFKILL, idev->keybit); - return input_register_device(idev); + ret = input_register_device(idev); + if (ret) + return ret; + + return acpi_dev_install_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, + acer_wireless_notify, + &pdev->dev); +} + +static void acer_wireless_remove(struct platform_device *pdev) +{ + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, + acer_wireless_notify); } -static struct acpi_driver acer_wireless_driver = { - .name = "Acer Wireless Radio Control Driver", - .class = "hotkey", - .ids = acer_wireless_acpi_ids, - .ops = { - .add = acer_wireless_add, - .notify = acer_wireless_notify, +static struct platform_driver acer_wireless_driver = { + .probe = acer_wireless_probe, + .remove = acer_wireless_remove, + .driver = { + .name = "Acer Wireless Radio Control Driver", + .acpi_match_table = acer_wireless_acpi_ids, }, }; -module_acpi_driver(acer_wireless_driver); +module_platform_driver(acer_wireless_driver); MODULE_DESCRIPTION("Acer Wireless Radio Control Driver"); MODULE_AUTHOR("Chris Chiu <chiu@gmail.com>"); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index d96f6af26ff7..dbbb6292cd11 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1517,9 +1517,9 @@ static void asus_input_exit(struct asus_laptop *asus) /* * ACPI driver */ -static void asus_acpi_notify(struct acpi_device *device, u32 event) +static void asus_acpi_notify(acpi_handle handle, u32 event, void *data) { - struct asus_laptop *asus = acpi_driver_data(device); + struct asus_laptop *asus = data; u16 count; /* TODO Find a better way to handle events count. */ @@ -1824,8 +1824,9 @@ static void asus_dmi_check(void) static bool asus_device_present; -static int asus_acpi_add(struct acpi_device *device) +static int asus_acpi_probe(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct asus_laptop *asus; int result; @@ -1837,7 +1838,6 @@ static int asus_acpi_add(struct acpi_device *device) asus->handle = device->handle; strscpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME); strscpy(acpi_device_class(device), ASUS_LAPTOP_CLASS); - device->driver_data = asus; asus->device = device; asus_dmi_check(); @@ -1846,6 +1846,8 @@ static int asus_acpi_add(struct acpi_device *device) if (result) goto fail_platform; + platform_set_drvdata(pdev, asus); + /* * Need platform type detection first, then the platform * device. It is used as a parent for the sub-devices below. @@ -1881,6 +1883,11 @@ static int asus_acpi_add(struct acpi_device *device) if (result && result != -ENODEV) goto fail_pega_rfkill; + result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + asus_acpi_notify, asus); + if (result) + goto fail_pega_rfkill; + asus_device_present = true; return 0; @@ -1902,10 +1909,12 @@ fail_platform: return result; } -static void asus_acpi_remove(struct acpi_device *device) +static void asus_acpi_remove(struct platform_device *pdev) { - struct asus_laptop *asus = acpi_driver_data(device); + struct asus_laptop *asus = platform_get_drvdata(pdev); + acpi_dev_remove_notify_handler(asus->device, ACPI_DEVICE_NOTIFY, + asus_acpi_notify); asus_backlight_exit(asus); asus_rfkill_exit(asus); asus_led_exit(asus); @@ -1924,16 +1933,13 @@ static const struct acpi_device_id asus_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, asus_device_ids); -static struct acpi_driver asus_acpi_driver = { - .name = ASUS_LAPTOP_NAME, - .class = ASUS_LAPTOP_CLASS, - .ids = asus_device_ids, - .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, - .ops = { - .add = asus_acpi_add, - .remove = asus_acpi_remove, - .notify = asus_acpi_notify, - }, +static struct platform_driver asus_acpi_driver = { + .probe = asus_acpi_probe, + .remove = asus_acpi_remove, + .driver = { + .name = ASUS_LAPTOP_NAME, + .acpi_match_table = asus_device_ids, + }, }; static int __init asus_laptop_init(void) @@ -1944,7 +1950,7 @@ static int __init asus_laptop_init(void) if (result < 0) return result; - result = acpi_bus_register_driver(&asus_acpi_driver); + result = platform_driver_register(&asus_acpi_driver); if (result < 0) goto fail_acpi_driver; if (!asus_device_present) { @@ -1954,7 +1960,7 @@ static int __init asus_laptop_init(void) return 0; fail_no_device: - acpi_bus_unregister_driver(&asus_acpi_driver); + platform_driver_unregister(&asus_acpi_driver); fail_acpi_driver: platform_driver_unregister(&platform_driver); return result; @@ -1962,7 +1968,7 @@ fail_acpi_driver: static void __exit asus_laptop_exit(void) { - acpi_bus_unregister_driver(&asus_acpi_driver); + platform_driver_unregister(&asus_acpi_driver); platform_driver_unregister(&platform_driver); } diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index 41227bf95878..2b494bf3cba8 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -12,6 +12,7 @@ #include <linux/acpi.h> #include <linux/input.h> #include <linux/pci_ids.h> +#include <linux/platform_device.h> #include <linux/leds.h> struct hswc_params { @@ -108,9 +109,10 @@ static void led_state_set(struct led_classdev *led, enum led_brightness value) queue_work(data->wq, &data->led_work); } -static void asus_wireless_notify(struct acpi_device *adev, u32 event) +static void asus_wireless_notify(acpi_handle handle, u32 event, void *context) { - struct asus_wireless_data *data = acpi_driver_data(adev); + struct asus_wireless_data *data = context; + struct acpi_device *adev = data->adev; dev_dbg(&adev->dev, "event=%#x\n", event); if (event != 0x88) { @@ -123,19 +125,22 @@ static void asus_wireless_notify(struct acpi_device *adev, u32 event) input_sync(data->idev); } -static int asus_wireless_add(struct acpi_device *adev) +static int asus_wireless_probe(struct platform_device *pdev) { + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); struct asus_wireless_data *data; const struct acpi_device_id *id; int err; - data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - adev->driver_data = data; + + platform_set_drvdata(pdev, data); + data->adev = adev; - data->idev = devm_input_allocate_device(&adev->dev); + data->idev = devm_input_allocate_device(&pdev->dev); if (!data->idev) return -ENOMEM; data->idev->name = "Asus Wireless Radio Control"; @@ -164,34 +169,44 @@ static int asus_wireless_add(struct acpi_device *adev) data->led.flags = LED_CORE_SUSPENDRESUME; data->led.max_brightness = 1; data->led.default_trigger = "rfkill-none"; - err = devm_led_classdev_register(&adev->dev, &data->led); + err = devm_led_classdev_register(&pdev->dev, &data->led); if (err) - destroy_workqueue(data->wq); + goto err; + + err = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY, + asus_wireless_notify, data); + if (err) { + devm_led_classdev_unregister(&pdev->dev, &data->led); + goto err; + } + return 0; +err: + destroy_workqueue(data->wq); return err; } -static void asus_wireless_remove(struct acpi_device *adev) +static void asus_wireless_remove(struct platform_device *pdev) { - struct asus_wireless_data *data = acpi_driver_data(adev); + struct asus_wireless_data *data = platform_get_drvdata(pdev); + acpi_dev_remove_notify_handler(data->adev, ACPI_DEVICE_NOTIFY, + asus_wireless_notify); if (data->wq) { - devm_led_classdev_unregister(&adev->dev, &data->led); + devm_led_classdev_unregister(&pdev->dev, &data->led); destroy_workqueue(data->wq); } } -static struct acpi_driver asus_wireless_driver = { - .name = "Asus Wireless Radio Control Driver", - .class = "hotkey", - .ids = device_ids, - .ops = { - .add = asus_wireless_add, - .remove = asus_wireless_remove, - .notify = asus_wireless_notify, +static struct platform_driver asus_wireless_driver = { + .probe = asus_wireless_probe, + .remove = asus_wireless_remove, + .driver = { + .name = "Asus Wireless Radio Control Driver", + .acpi_match_table = device_ids, }, }; -module_acpi_driver(asus_wireless_driver); +module_platform_driver(asus_wireless_driver); MODULE_DESCRIPTION("Asus Wireless Radio Control Driver"); MODULE_AUTHOR("João Paulo Rechi Vita <jprvita@gmail.com>"); diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 7c0915e097ba..80144c412b90 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -125,7 +125,6 @@ module_param(fnlock_default, bool, 0444); #define NVIDIA_TEMP_MIN 75 #define NVIDIA_TEMP_MAX 87 -#define ASUS_SCREENPAD_BRIGHT_MIN 20 #define ASUS_SCREENPAD_BRIGHT_MAX 255 #define ASUS_SCREENPAD_BRIGHT_DEFAULT 60 @@ -1557,7 +1556,10 @@ static ssize_t charge_control_end_threshold_show(struct device *device, struct device_attribute *attr, char *buf) { - return sysfs_emit(buf, "%d\n", charge_end_threshold); + if ((charge_end_threshold >= 0) && (charge_end_threshold <= 100)) + return sysfs_emit(buf, "%d\n", charge_end_threshold); + + return -ENODATA; } static DEVICE_ATTR_RW(charge_control_end_threshold); @@ -1580,11 +1582,11 @@ static int asus_wmi_battery_add(struct power_supply *battery, struct acpi_batter return -ENODEV; /* The charge threshold is only reset when the system is power cycled, - * and we can't get the current threshold so let set it to 100% when - * a battery is added. + * and we can't read the current threshold, however the majority of + * platforms retains it, therefore signal the threshold as unknown + * until user explicitly sets it to a new value. */ - asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, 100, NULL); - charge_end_threshold = 100; + charge_end_threshold = -1; return 0; } @@ -4408,43 +4410,35 @@ static int read_screenpad_brightness(struct backlight_device *bd) return err; /* The device brightness can only be read if powered, so return stored */ if (err == BACKLIGHT_POWER_OFF) - return asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; + return bd->props.brightness; err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval); if (err < 0) return err; - return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) - ASUS_SCREENPAD_BRIGHT_MIN; + return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; } static int update_screenpad_bl_status(struct backlight_device *bd) { - struct asus_wmi *asus = bl_get_data(bd); - int power, err = 0; - u32 ctrl_param; + u32 ctrl_param = bd->props.brightness; + int err = 0; - power = read_screenpad_backlight_power(asus); - if (power < 0) - return power; + if (bd->props.power) { + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 1, NULL); + if (err < 0) + return err; - if (bd->props.power != power) { - if (power != BACKLIGHT_POWER_ON) { - /* Only brightness > 0 can power it back on */ - ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, - ctrl_param, NULL); - } else { - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); - } - } else if (power == BACKLIGHT_POWER_ON) { - /* Only set brightness if powered on or we get invalid/unsync state */ - ctrl_param = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL); + if (err < 0) + return err; } - /* Ensure brightness is stored to turn back on with */ - if (err == 0) - asus->driver->screenpad_brightness = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; + if (!bd->props.power) { + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); + if (err < 0) + return err; + } return err; } @@ -4462,22 +4456,19 @@ static int asus_screenpad_init(struct asus_wmi *asus) int err, power; int brightness = 0; - power = read_screenpad_backlight_power(asus); + power = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); if (power < 0) return power; - if (power != BACKLIGHT_POWER_OFF) { + if (power) { err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness); if (err < 0) return err; } - /* default to an acceptable min brightness on boot if too low */ - if (brightness < ASUS_SCREENPAD_BRIGHT_MIN) - brightness = ASUS_SCREENPAD_BRIGHT_DEFAULT; memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */ - props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX - ASUS_SCREENPAD_BRIGHT_MIN; + props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX; bd = backlight_device_register("asus_screenpad", &asus->platform_device->dev, asus, &asus_screenpad_bl_ops, &props); @@ -4488,7 +4479,7 @@ static int asus_screenpad_init(struct asus_wmi *asus) asus->screenpad_backlight_device = bd; asus->driver->screenpad_brightness = brightness; - bd->props.brightness = brightness - ASUS_SCREENPAD_BRIGHT_MIN; + bd->props.brightness = brightness; bd->props.power = power; backlight_update_status(bd); @@ -5413,17 +5404,3 @@ void asus_wmi_unregister_driver(struct asus_wmi_driver *driver) used = false; } EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver); - -static int __init asus_wmi_init(void) -{ - pr_info("ASUS WMI generic driver loaded\n"); - return 0; -} - -static void __exit asus_wmi_exit(void) -{ - pr_info("ASUS WMI generic driver unloaded\n"); -} - -module_init(asus_wmi_init); -module_exit(asus_wmi_exit); diff --git a/drivers/platform/x86/barco-p50-gpio.c b/drivers/platform/x86/barco-p50-gpio.c index 6f13e81f98fb..2a6d8607c402 100644 --- a/drivers/platform/x86/barco-p50-gpio.c +++ b/drivers/platform/x86/barco-p50-gpio.c @@ -272,30 +272,27 @@ static int p50_gpio_get(struct gpio_chip *gc, unsigned int offset) struct p50_gpio *p50 = gpiochip_get_data(gc); int ret; - mutex_lock(&p50->lock); + guard(mutex)(&p50->lock); ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_READ_GPIO, gpio_params[offset], 0); - if (ret == 0) - ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA); + if (ret < 0) + return ret; - mutex_unlock(&p50->lock); + ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA); + if (ret < 0) + return ret; - return ret; + return !!ret; } static int p50_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) { struct p50_gpio *p50 = gpiochip_get_data(gc); - int ret; - - mutex_lock(&p50->lock); - ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO, - gpio_params[offset], value); + guard(mutex)(&p50->lock); - mutex_unlock(&p50->lock); - - return ret; + return p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO, + gpio_params[offset], value); } static int p50_gpio_probe(struct platform_device *pdev) diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c new file mode 100644 index 000000000000..b0d06a80e89e --- /dev/null +++ b/drivers/platform/x86/bitland-mifs-wmi.c @@ -0,0 +1,837 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Linux driver for Bitland notebooks. + * + * Copyright (C) 2026 2 Mingyou Chen <qby140326@gmail.com> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/acpi.h> +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/container_of.h> +#include <linux/dev_printk.h> +#include <linux/device.h> +#include <linux/device/devres.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/init.h> +#include <linux/input-event-codes.h> +#include <linux/input.h> +#include <linux/input/sparse-keymap.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/platform_profile.h> +#include <linux/pm.h> +#include <linux/power_supply.h> +#include <linux/stddef.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/unaligned.h> +#include <linux/units.h> +#include <linux/wmi.h> + +#define DRV_NAME "bitland-mifs-wmi" +#define BITLAND_MIFS_GUID "B60BFB48-3E5B-49E4-A0E9-8CFFE1B3434B" +#define BITLAND_EVENT_GUID "46C93E13-EE9B-4262-8488-563BCA757FEF" + +enum bitland_mifs_operation { + WMI_METHOD_GET = 250, + WMI_METHOD_SET = 251, +}; + +enum bitland_mifs_function { + WMI_FN_SYSTEM_PER_MODE = 8, + WMI_FN_GPU_MODE = 9, + WMI_FN_KBD_TYPE = 10, + WMI_FN_FN_LOCK = 11, + WMI_FN_TP_LOCK = 12, + WMI_FN_FAN_SPEEDS = 13, + WMI_FN_RGB_KB_MODE = 16, + WMI_FN_RGB_KB_COLOR = 17, + WMI_FN_RGB_KB_BRIGHTNESS = 18, + WMI_FN_SYSTEM_AC_TYPE = 19, + WMI_FN_MAX_FAN_SWITCH = 20, + WMI_FN_MAX_FAN_SPEED = 21, + WMI_FN_CPU_THERMOMETER = 22, + WMI_FN_CPU_POWER = 23, +}; + +enum bitland_system_ac_mode { + WMI_SYSTEM_AC_TYPEC = 1, + /* Unknown type, this is unused in the original driver */ + WMI_SYSTEM_AC_CIRCULARHOLE = 2, +}; + +enum bitland_mifs_power_profile { + WMI_PP_BALANCED = 0, + WMI_PP_PERFORMANCE = 1, + WMI_PP_QUIET = 2, + WMI_PP_FULL_SPEED = 3, +}; + +enum bitland_mifs_event_id { + WMI_EVENT_RESERVED_1 = 1, + WMI_EVENT_RESERVED_2 = 2, + WMI_EVENT_RESERVED_3 = 3, + WMI_EVENT_AIRPLANE_MODE = 4, + WMI_EVENT_KBD_BRIGHTNESS = 5, + WMI_EVENT_TOUCHPAD_STATE = 6, + WMI_EVENT_FNLOCK_STATE = 7, + WMI_EVENT_KBD_MODE = 8, + WMI_EVENT_CAPSLOCK_STATE = 9, + WMI_EVENT_CALCULATOR_START = 11, + WMI_EVENT_BROWSER_START = 12, + WMI_EVENT_NUMLOCK_STATE = 13, + WMI_EVENT_SCROLLLOCK_STATE = 14, + WMI_EVENT_PERFORMANCE_PLAN = 15, + WMI_EVENT_FN_J = 16, + WMI_EVENT_FN_F = 17, + WMI_EVENT_FN_0 = 18, + WMI_EVENT_FN_1 = 19, + WMI_EVENT_FN_2 = 20, + WMI_EVENT_FN_3 = 21, + WMI_EVENT_FN_4 = 22, + WMI_EVENT_FN_5 = 24, + WMI_EVENT_REFRESH_RATE = 25, + WMI_EVENT_CPU_FAN_SPEED = 26, + WMI_EVENT_GPU_FAN_SPEED = 32, + WMI_EVENT_WIN_KEY_LOCK = 33, + WMI_EVENT_RESERVED_23 = 34, + WMI_EVENT_OPEN_APP = 35, +}; + +enum bitland_mifs_event_type { + WMI_EVENT_TYPE_HOTKEY = 1, +}; + +enum bitland_wmi_device_type { + BITLAND_WMI_CONTROL = 0, + BITLAND_WMI_EVENT = 1, +}; + +struct bitland_mifs_input { + u8 reserved1; + u8 operation; + u8 reserved2; + u8 function; + u8 payload[28]; +} __packed; + +struct bitland_mifs_output { + u8 reserved1; + u8 operation; + u8 reserved2; + u8 function; + u8 data[28]; +} __packed; + +struct bitland_mifs_event { + u8 event_type; + u8 event_id; + u8 value_low; /* For most events, this is the value */ + u8 value_high; /* For fan speed events, combined with value_low */ + u8 reserved[4]; +} __packed; + +static BLOCKING_NOTIFIER_HEAD(bitland_notifier_list); + +enum bitland_notifier_actions { + BITLAND_NOTIFY_KBD_BRIGHTNESS, + BITLAND_NOTIFY_PLATFORM_PROFILE, + BITLAND_NOTIFY_HWMON, +}; + +struct bitland_fan_notify_data { + int channel; /* 0 = CPU, 1 = GPU */ + u16 speed; +}; + +struct bitland_mifs_wmi_data { + struct wmi_device *wdev; + struct mutex lock; /* Protects WMI calls */ + struct led_classdev kbd_led; + struct notifier_block notifier; + struct input_dev *input_dev; + struct device *hwmon_dev; + struct device *pp_dev; + enum platform_profile_option saved_profile; +}; + +static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data, + const struct bitland_mifs_input *input, + struct bitland_mifs_output *output) +{ + struct wmi_buffer in_buf = { .length = sizeof(*input), .data = (void *)input }; + struct wmi_buffer out_buf = { 0 }; + int ret; + + guard(mutex)(&data->lock); + + if (!output) + return wmidev_invoke_procedure(data->wdev, 0, 1, &in_buf); + + ret = wmidev_invoke_method(data->wdev, 0, 1, &in_buf, &out_buf, sizeof(*output)); + if (ret) + return ret; + + memcpy(output, out_buf.data, sizeof(*output)); + kfree(out_buf.data); + + return 0; +} + +static int laptop_profile_get(struct device *dev, + enum platform_profile_option *profile) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); + struct bitland_mifs_input input = { + .reserved1 = 0, + .operation = WMI_METHOD_GET, + .reserved2 = 0, + .function = WMI_FN_SYSTEM_PER_MODE, + }; + struct bitland_mifs_output result; + int ret; + + ret = bitland_mifs_wmi_call(data, &input, &result); + if (ret) + return ret; + + switch (result.data[0]) { + case WMI_PP_BALANCED: + *profile = PLATFORM_PROFILE_BALANCED; + break; + case WMI_PP_PERFORMANCE: + *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE; + break; + case WMI_PP_QUIET: + *profile = PLATFORM_PROFILE_LOW_POWER; + break; + case WMI_PP_FULL_SPEED: + *profile = PLATFORM_PROFILE_PERFORMANCE; + break; + default: + return -EINVAL; + } + return 0; +} + +static int bitland_check_performance_capability(struct bitland_mifs_wmi_data *data) +{ + struct bitland_mifs_input input = { + .operation = WMI_METHOD_GET, + .function = WMI_FN_SYSTEM_AC_TYPE, + }; + struct bitland_mifs_output output; + int ret; + + /* Full-speed/performance mode requires DC power (not USB-C) */ + if (!power_supply_is_system_supplied()) + return -EOPNOTSUPP; + + ret = bitland_mifs_wmi_call(data, &input, &output); + if (ret) + return ret; + + if (output.data[0] != WMI_SYSTEM_AC_CIRCULARHOLE) + return -EOPNOTSUPP; + + return 0; +} + +static int laptop_profile_set(struct device *dev, + enum platform_profile_option profile) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); + struct bitland_mifs_input input = { + .reserved1 = 0, + .operation = WMI_METHOD_SET, + .reserved2 = 0, + .function = WMI_FN_SYSTEM_PER_MODE, + }; + int ret; + u8 val; + + switch (profile) { + case PLATFORM_PROFILE_LOW_POWER: + val = WMI_PP_QUIET; + break; + case PLATFORM_PROFILE_BALANCED: + val = WMI_PP_BALANCED; + break; + case PLATFORM_PROFILE_BALANCED_PERFORMANCE: + ret = bitland_check_performance_capability(data); + if (ret) + return ret; + val = WMI_PP_PERFORMANCE; + break; + case PLATFORM_PROFILE_PERFORMANCE: + ret = bitland_check_performance_capability(data); + if (ret) + return ret; + val = WMI_PP_FULL_SPEED; + break; + default: + return -EOPNOTSUPP; + } + + input.payload[0] = val; + + return bitland_mifs_wmi_call(data, &input, NULL); +} + +static int platform_profile_probe(void *drvdata, unsigned long *choices) +{ + set_bit(PLATFORM_PROFILE_LOW_POWER, choices); + set_bit(PLATFORM_PROFILE_BALANCED, choices); + set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices); + set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); + + return 0; +} + +static int bitland_mifs_wmi_suspend(struct device *dev) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); + enum platform_profile_option profile; + int ret; + + ret = laptop_profile_get(data->pp_dev, &profile); + if (ret == 0) + data->saved_profile = profile; + + return ret; +} + +static int bitland_mifs_wmi_resume(struct device *dev) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); + + dev_dbg(dev, "Resuming, restoring profile %d\n", data->saved_profile); + return laptop_profile_set(dev, data->saved_profile); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(bitland_mifs_wmi_pm_ops, + bitland_mifs_wmi_suspend, + bitland_mifs_wmi_resume); + +static const struct platform_profile_ops laptop_profile_ops = { + .probe = platform_profile_probe, + .profile_get = laptop_profile_get, + .profile_set = laptop_profile_set, +}; + +static const char *const fan_labels[] = { + "CPU", /* 0 */ + "GPU", /* 1 */ + "SYS", /* 2 */ +}; + +static int laptop_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); + struct bitland_mifs_input input = { + .reserved1 = 0, + .operation = WMI_METHOD_GET, + .reserved2 = 0, + }; + struct bitland_mifs_output res; + int ret; + + switch (type) { + case hwmon_temp: + input.function = WMI_FN_CPU_THERMOMETER; + ret = bitland_mifs_wmi_call(data, &input, &res); + if (!ret) + *val = res.data[0] * MILLIDEGREE_PER_DEGREE; + return ret; + case hwmon_fan: + input.function = WMI_FN_FAN_SPEEDS; + ret = bitland_mifs_wmi_call(data, &input, &res); + if (ret) + return ret; + + switch (channel) { + case 0: /* CPU */ + *val = get_unaligned_le16(&res.data[0]); + return 0; + case 1: /* GPU */ + *val = get_unaligned_le16(&res.data[2]); + return 0; + case 2: /* SYS */ + *val = get_unaligned_le16(&res.data[6]); + return 0; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int laptop_hwmon_read_string(struct device *dev, + enum hwmon_sensor_types type, u32 attr, + int channel, const char **str) +{ + if (type == hwmon_fan && attr == hwmon_fan_label) { + if (channel >= 0 && channel < ARRAY_SIZE(fan_labels)) { + *str = fan_labels[channel]; + return 0; + } + } + return -EINVAL; +} + +static const struct hwmon_channel_info *laptop_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL), + NULL +}; + +static const struct hwmon_ops laptop_hwmon_ops = { + .visible = 0444, + .read = laptop_hwmon_read, + .read_string = laptop_hwmon_read_string, +}; + +static const struct hwmon_chip_info laptop_chip_info = { + .ops = &laptop_hwmon_ops, + .info = laptop_hwmon_info, +}; + +static int laptop_kbd_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct bitland_mifs_wmi_data *data = + container_of(led_cdev, struct bitland_mifs_wmi_data, kbd_led); + struct bitland_mifs_input input = { + .reserved1 = 0, + .operation = WMI_METHOD_SET, + .reserved2 = 0, + .function = WMI_FN_RGB_KB_BRIGHTNESS, + }; + + input.payload[0] = (u8)value; + + return bitland_mifs_wmi_call(data, &input, NULL); +} + +static enum led_brightness laptop_kbd_led_get(struct led_classdev *led_cdev) +{ + struct bitland_mifs_wmi_data *data = + container_of(led_cdev, struct bitland_mifs_wmi_data, kbd_led); + struct bitland_mifs_input input = { + .reserved1 = 0, + .operation = WMI_METHOD_GET, + .reserved2 = 0, + .function = WMI_FN_RGB_KB_BRIGHTNESS, + }; + struct bitland_mifs_output res; + int ret; + + ret = bitland_mifs_wmi_call(data, &input, &res); + if (ret) + return ret; + + return res.data[0]; +} + +static const char *const gpu_mode_strings[] = { + "hybrid", + "discrete", + "uma", +}; + +/* GPU Mode: 0:Hybrid, 1:Discrete, 2:UMA */ +static ssize_t gpu_mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); + struct bitland_mifs_input input = { + .reserved1 = 0, + .operation = WMI_METHOD_GET, + .reserved2 = 0, + .function = WMI_FN_GPU_MODE, + }; + struct bitland_mifs_output res; + u8 mode_val; + int ret; + + ret = bitland_mifs_wmi_call(data, &input, &res); + if (ret) + return ret; + + mode_val = res.data[0]; + if (mode_val >= ARRAY_SIZE(gpu_mode_strings)) + return -EPROTO; + + return sysfs_emit(buf, "%s\n", gpu_mode_strings[mode_val]); +} + +static ssize_t gpu_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); + struct bitland_mifs_input input = { + .reserved1 = 0, + .operation = WMI_METHOD_SET, + .reserved2 = 0, + .function = WMI_FN_GPU_MODE, + }; + int val; + int ret; + + val = sysfs_match_string(gpu_mode_strings, buf); + if (val < 0) + return -EINVAL; + + input.payload[0] = (u8)val; + + ret = bitland_mifs_wmi_call(data, &input, NULL); + if (ret) + return ret; + + return count; +} + +static const char *const kb_mode_strings[] = { + "off", /* 0 */ + "cyclic", /* 1 */ + "fixed", /* 2 */ + "custom", /* 3 */ +}; + +static ssize_t kb_mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); + struct bitland_mifs_input input = { + .reserved1 = 0, + .operation = WMI_METHOD_GET, + .reserved2 = 0, + .function = WMI_FN_RGB_KB_MODE, + }; + struct bitland_mifs_output res; + u8 mode_val; + int ret; + + ret = bitland_mifs_wmi_call(data, &input, &res); + if (ret) + return ret; + + mode_val = res.data[0]; + if (mode_val >= ARRAY_SIZE(kb_mode_strings)) + return -EPROTO; + + return sysfs_emit(buf, "%s\n", kb_mode_strings[mode_val]); +} + +static ssize_t kb_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); + struct bitland_mifs_input input = { + .reserved1 = 0, + .operation = WMI_METHOD_SET, + .reserved2 = 0, + .function = WMI_FN_RGB_KB_MODE, + }; + // the wmi value (0, 1, 2 or 3) + int val; + int ret; + + val = sysfs_match_string(kb_mode_strings, buf); + if (val < 0) + return -EINVAL; + + input.payload[0] = (u8)val; + + ret = bitland_mifs_wmi_call(data, &input, NULL); + if (ret) + return ret; + + return count; +} + +/* Fan Boost: 0:Normal, 1:Max Speed */ +static ssize_t fan_boost_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); + struct bitland_mifs_input input = { + .reserved1 = 0, + .operation = WMI_METHOD_SET, + .reserved2 = 0, + .function = WMI_FN_MAX_FAN_SWITCH, + }; + bool val; + int ret; + + if (kstrtobool(buf, &val)) + return -EINVAL; + + input.payload[0] = 0; /* CPU/GPU Fan */ + input.payload[1] = val; + + ret = bitland_mifs_wmi_call(data, &input, NULL); + if (ret) + return ret; + + return count; +} + +static const DEVICE_ATTR_RW(gpu_mode); +static const DEVICE_ATTR_RW(kb_mode); +static const DEVICE_ATTR_WO(fan_boost); + +static const struct attribute *const laptop_attrs[] = { + &dev_attr_gpu_mode.attr, + &dev_attr_kb_mode.attr, + &dev_attr_fan_boost.attr, + NULL, +}; +ATTRIBUTE_GROUPS(laptop); + +static const struct key_entry bitland_mifs_wmi_keymap[] = { + { KE_KEY, WMI_EVENT_OPEN_APP, { KEY_PROG1 } }, + { KE_KEY, WMI_EVENT_CALCULATOR_START, { KEY_CALC } }, + { KE_KEY, WMI_EVENT_BROWSER_START, { KEY_WWW } }, + { KE_IGNORE, WMI_EVENT_FN_J, { KEY_RESERVED } }, + { KE_IGNORE, WMI_EVENT_FN_F, { KEY_RESERVED } }, + { KE_IGNORE, WMI_EVENT_FN_0, { KEY_RESERVED } }, + { KE_IGNORE, WMI_EVENT_FN_1, { KEY_RESERVED } }, + { KE_IGNORE, WMI_EVENT_FN_2, { KEY_RESERVED } }, + { KE_IGNORE, WMI_EVENT_FN_3, { KEY_RESERVED } }, + { KE_IGNORE, WMI_EVENT_FN_4, { KEY_RESERVED } }, + { KE_IGNORE, WMI_EVENT_FN_5, { KEY_RESERVED } }, + { KE_END, 0 } +}; + +static void bitland_notifier_unregister(void *data) +{ + struct notifier_block *nb = data; + + blocking_notifier_chain_unregister(&bitland_notifier_list, nb); +} + +static int bitland_notifier_callback(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct bitland_mifs_wmi_data *data_ctx = + container_of(nb, struct bitland_mifs_wmi_data, notifier); + struct bitland_fan_notify_data *fan_info; + u8 *brightness; + + switch (action) { + case BITLAND_NOTIFY_KBD_BRIGHTNESS: + brightness = data; + led_classdev_notify_brightness_hw_changed(&data_ctx->kbd_led, + *brightness); + break; + case BITLAND_NOTIFY_PLATFORM_PROFILE: + platform_profile_notify(data_ctx->pp_dev); + break; + case BITLAND_NOTIFY_HWMON: + fan_info = data; + + hwmon_notify_event(data_ctx->hwmon_dev, hwmon_fan, + hwmon_fan_input, fan_info->channel); + break; + } + + return NOTIFY_OK; +} + +static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context) +{ + struct bitland_mifs_wmi_data *drv_data; + enum bitland_wmi_device_type dev_type = + (enum bitland_wmi_device_type)(unsigned long)context; + struct led_init_data init_data = { + .devicename = DRV_NAME, + .default_label = ":" LED_FUNCTION_KBD_BACKLIGHT, + .devname_mandatory = true, + }; + int ret; + + drv_data = devm_kzalloc(&wdev->dev, sizeof(*drv_data), GFP_KERNEL); + if (!drv_data) + return -ENOMEM; + + drv_data->wdev = wdev; + + ret = devm_mutex_init(&wdev->dev, &drv_data->lock); + if (ret) + return ret; + + dev_set_drvdata(&wdev->dev, drv_data); + + if (dev_type == BITLAND_WMI_EVENT) { + /* Register input device for hotkeys */ + drv_data->input_dev = devm_input_allocate_device(&wdev->dev); + if (!drv_data->input_dev) + return -ENOMEM; + + drv_data->input_dev->name = "Bitland MIFS WMI hotkeys"; + drv_data->input_dev->phys = "wmi/input0"; + drv_data->input_dev->id.bustype = BUS_HOST; + drv_data->input_dev->dev.parent = &wdev->dev; + + ret = sparse_keymap_setup(drv_data->input_dev, + bitland_mifs_wmi_keymap, NULL); + if (ret) + return ret; + + return input_register_device(drv_data->input_dev); + } + + /* Register platform profile */ + drv_data->pp_dev = devm_platform_profile_register(&wdev->dev, DRV_NAME, drv_data, + &laptop_profile_ops); + if (IS_ERR(drv_data->pp_dev)) + return PTR_ERR(drv_data->pp_dev); + + /* Register hwmon */ + drv_data->hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev, + "bitland_mifs", + drv_data, + &laptop_chip_info, + NULL); + if (IS_ERR(drv_data->hwmon_dev)) + return PTR_ERR(drv_data->hwmon_dev); + + /* Register keyboard LED */ + drv_data->kbd_led.max_brightness = 3; + drv_data->kbd_led.brightness_set_blocking = laptop_kbd_led_set; + drv_data->kbd_led.brightness_get = laptop_kbd_led_get; + drv_data->kbd_led.brightness = laptop_kbd_led_get(&drv_data->kbd_led); + drv_data->kbd_led.flags = LED_CORE_SUSPENDRESUME | + LED_BRIGHT_HW_CHANGED | + LED_REJECT_NAME_CONFLICT; + ret = devm_led_classdev_register_ext(&wdev->dev, &drv_data->kbd_led, &init_data); + if (ret) + return ret; + + drv_data->notifier.notifier_call = bitland_notifier_callback; + ret = blocking_notifier_chain_register(&bitland_notifier_list, &drv_data->notifier); + if (ret) + return ret; + + return devm_add_action_or_reset(&wdev->dev, + bitland_notifier_unregister, + &drv_data->notifier); +} + +static void bitland_mifs_wmi_notify(struct wmi_device *wdev, + const struct wmi_buffer *buffer) +{ + struct bitland_mifs_wmi_data *data = dev_get_drvdata(&wdev->dev); + const struct bitland_mifs_event *event = buffer->data; + struct bitland_fan_notify_data fan_data; + u8 brightness; + + /* Validate event type */ + if (event->event_type != WMI_EVENT_TYPE_HOTKEY) + return; + + dev_dbg(&wdev->dev, + "WMI event: id=0x%02x value_low=0x%02x value_high=0x%02x\n", + event->event_id, event->value_low, event->value_high); + + switch (event->event_id) { + case WMI_EVENT_KBD_BRIGHTNESS: + brightness = event->value_low; + blocking_notifier_call_chain(&bitland_notifier_list, + BITLAND_NOTIFY_KBD_BRIGHTNESS, + &brightness); + break; + + case WMI_EVENT_PERFORMANCE_PLAN: + blocking_notifier_call_chain(&bitland_notifier_list, + BITLAND_NOTIFY_PLATFORM_PROFILE, + NULL); + break; + + case WMI_EVENT_OPEN_APP: + case WMI_EVENT_CALCULATOR_START: + case WMI_EVENT_BROWSER_START: { + guard(mutex)(&data->lock); + if (!sparse_keymap_report_event(data->input_dev, + event->event_id, 1, true)) + dev_warn(&wdev->dev, "Unknown key pressed: 0x%02x\n", + event->event_id); + break; + } + + /* + * The device has 3 fans (CPU, GPU, SYS), + * but there are only the CPU and GPU fan has events + */ + case WMI_EVENT_CPU_FAN_SPEED: + case WMI_EVENT_GPU_FAN_SPEED: + if (event->event_id == WMI_EVENT_CPU_FAN_SPEED) + fan_data.channel = 0; + else + fan_data.channel = 1; + + /* Fan speed is 16-bit value (value_low is LSB, value_high is MSB) */ + fan_data.speed = (event->value_high << 8) | event->value_low; + blocking_notifier_call_chain(&bitland_notifier_list, + BITLAND_NOTIFY_HWMON, + &fan_data); + break; + + case WMI_EVENT_AIRPLANE_MODE: + case WMI_EVENT_TOUCHPAD_STATE: + case WMI_EVENT_FNLOCK_STATE: + case WMI_EVENT_KBD_MODE: + case WMI_EVENT_CAPSLOCK_STATE: + case WMI_EVENT_NUMLOCK_STATE: + case WMI_EVENT_SCROLLLOCK_STATE: + case WMI_EVENT_REFRESH_RATE: + case WMI_EVENT_WIN_KEY_LOCK: + /* These events are informational or handled by firmware */ + dev_dbg(&wdev->dev, "State change event: id=%d value=%d\n", + event->event_id, event->value_low); + break; + + default: + dev_dbg(&wdev->dev, "Unknown event: id=0x%02x value=0x%02x\n", + event->event_id, event->value_low); + break; + } +} + +static const struct wmi_device_id bitland_mifs_wmi_id_table[] = { + { BITLAND_MIFS_GUID, (void *)BITLAND_WMI_CONTROL }, + { BITLAND_EVENT_GUID, (void *)BITLAND_WMI_EVENT }, + {} +}; +MODULE_DEVICE_TABLE(wmi, bitland_mifs_wmi_id_table); + +static struct wmi_driver bitland_mifs_wmi_driver = { + .no_singleton = true, + .driver = { + .name = DRV_NAME, + .dev_groups = laptop_groups, + .pm = pm_sleep_ptr(&bitland_mifs_wmi_pm_ops), + }, + .id_table = bitland_mifs_wmi_id_table, + .min_event_size = sizeof(struct bitland_mifs_event), + .probe = bitland_mifs_wmi_probe, + .notify_new = bitland_mifs_wmi_notify, +}; + +module_wmi_driver(bitland_mifs_wmi_driver); + +MODULE_AUTHOR("Mingyou Chen <qby140326@gmail.com>"); +MODULE_DESCRIPTION("Bitland MIFS (MiInterface) WMI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/dell/dell-rbtn.c b/drivers/platform/x86/dell/dell-rbtn.c index a415c432d4c3..34af9f4ff741 100644 --- a/drivers/platform/x86/dell/dell-rbtn.c +++ b/drivers/platform/x86/dell/dell-rbtn.c @@ -9,6 +9,7 @@ #include <linux/acpi.h> #include <linux/rfkill.h> #include <linux/input.h> +#include <linux/platform_device.h> #include "dell-rbtn.h" @@ -109,9 +110,9 @@ static const struct rfkill_ops rbtn_ops = { .set_block = rbtn_rfkill_set_block, }; -static int rbtn_rfkill_init(struct acpi_device *device) +static int rbtn_rfkill_init(struct device *dev) { - struct rbtn_data *rbtn_data = device->driver_data; + struct rbtn_data *rbtn_data = dev_get_drvdata(dev); int ret; if (rbtn_data->rfkill) @@ -122,8 +123,8 @@ static int rbtn_rfkill_init(struct acpi_device *device) * but rfkill interface does not support "ANY" type * so "WLAN" type is used */ - rbtn_data->rfkill = rfkill_alloc("dell-rbtn", &device->dev, - RFKILL_TYPE_WLAN, &rbtn_ops, device); + rbtn_data->rfkill = rfkill_alloc("dell-rbtn", dev, RFKILL_TYPE_WLAN, + &rbtn_ops, ACPI_COMPANION(dev)); if (!rbtn_data->rfkill) return -ENOMEM; @@ -137,9 +138,9 @@ static int rbtn_rfkill_init(struct acpi_device *device) return 0; } -static void rbtn_rfkill_exit(struct acpi_device *device) +static void rbtn_rfkill_exit(struct device *dev) { - struct rbtn_data *rbtn_data = device->driver_data; + struct rbtn_data *rbtn_data = dev_get_drvdata(dev); if (!rbtn_data->rfkill) return; @@ -149,12 +150,12 @@ static void rbtn_rfkill_exit(struct acpi_device *device) rbtn_data->rfkill = NULL; } -static void rbtn_rfkill_event(struct acpi_device *device) +static void rbtn_rfkill_event(struct device *dev) { - struct rbtn_data *rbtn_data = device->driver_data; + struct rbtn_data *rbtn_data = dev_get_drvdata(dev); if (rbtn_data->rfkill) - rbtn_rfkill_query(rbtn_data->rfkill, device); + rbtn_rfkill_query(rbtn_data->rfkill, ACPI_COMPANION(dev)); } @@ -205,9 +206,9 @@ static void rbtn_input_event(struct rbtn_data *rbtn_data) * acpi driver */ -static int rbtn_add(struct acpi_device *device); -static void rbtn_remove(struct acpi_device *device); -static void rbtn_notify(struct acpi_device *device, u32 event); +static int rbtn_probe(struct platform_device *pdev); +static void rbtn_remove(struct platform_device *pdev); +static void rbtn_notify(acpi_handle handle, u32 event, void *data); static const struct acpi_device_id rbtn_ids[] = { { "DELRBTN", 0 }, @@ -251,8 +252,7 @@ static void ACPI_SYSTEM_XFACE rbtn_clear_suspended_flag(void *context) static int rbtn_suspend(struct device *dev) { - struct acpi_device *device = to_acpi_device(dev); - struct rbtn_data *rbtn_data = acpi_driver_data(device); + struct rbtn_data *rbtn_data = dev_get_drvdata(dev); rbtn_data->suspended = true; @@ -261,8 +261,7 @@ static int rbtn_suspend(struct device *dev) static int rbtn_resume(struct device *dev) { - struct acpi_device *device = to_acpi_device(dev); - struct rbtn_data *rbtn_data = acpi_driver_data(device); + struct rbtn_data *rbtn_data = dev_get_drvdata(dev); acpi_status status; /* @@ -286,14 +285,13 @@ static int rbtn_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(rbtn_pm_ops, rbtn_suspend, rbtn_resume); -static struct acpi_driver rbtn_driver = { - .name = "dell-rbtn", - .ids = rbtn_ids, - .drv.pm = &rbtn_pm_ops, - .ops = { - .add = rbtn_add, - .remove = rbtn_remove, - .notify = rbtn_notify, +static struct platform_driver rbtn_driver = { + .probe = rbtn_probe, + .remove = rbtn_remove, + .driver = { + .name = "dell-rbtn", + .acpi_match_table = rbtn_ids, + .pm = &rbtn_pm_ops, }, }; @@ -308,8 +306,7 @@ static ATOMIC_NOTIFIER_HEAD(rbtn_chain_head); static int rbtn_inc_count(struct device *dev, void *data) { - struct acpi_device *device = to_acpi_device(dev); - struct rbtn_data *rbtn_data = device->driver_data; + struct rbtn_data *rbtn_data = dev_get_drvdata(dev); int *count = data; if (rbtn_data->type == RBTN_SLIDER) @@ -320,17 +317,16 @@ static int rbtn_inc_count(struct device *dev, void *data) static int rbtn_switch_dev(struct device *dev, void *data) { - struct acpi_device *device = to_acpi_device(dev); - struct rbtn_data *rbtn_data = device->driver_data; + struct rbtn_data *rbtn_data = dev_get_drvdata(dev); bool enable = data; if (rbtn_data->type != RBTN_SLIDER) return 0; if (enable) - rbtn_rfkill_init(device); + rbtn_rfkill_init(dev); else - rbtn_rfkill_exit(device); + rbtn_rfkill_exit(dev); return 0; } @@ -342,7 +338,7 @@ int dell_rbtn_notifier_register(struct notifier_block *nb) int ret; count = 0; - ret = driver_for_each_device(&rbtn_driver.drv, NULL, &count, + ret = driver_for_each_device(&rbtn_driver.driver, NULL, &count, rbtn_inc_count); if (ret || count == 0) return -ENODEV; @@ -354,7 +350,7 @@ int dell_rbtn_notifier_register(struct notifier_block *nb) return ret; if (auto_remove_rfkill && first) - ret = driver_for_each_device(&rbtn_driver.drv, NULL, + ret = driver_for_each_device(&rbtn_driver.driver, NULL, (void *)false, rbtn_switch_dev); return ret; @@ -370,7 +366,7 @@ int dell_rbtn_notifier_unregister(struct notifier_block *nb) return ret; if (auto_remove_rfkill && !rbtn_chain_head.head) - ret = driver_for_each_device(&rbtn_driver.drv, NULL, + ret = driver_for_each_device(&rbtn_driver.driver, NULL, (void *)true, rbtn_switch_dev); return ret; @@ -382,30 +378,48 @@ EXPORT_SYMBOL_GPL(dell_rbtn_notifier_unregister); * acpi driver functions */ -static int rbtn_add(struct acpi_device *device) +static void rbtn_cleanup(struct device *dev) { + struct rbtn_data *rbtn_data = dev_get_drvdata(dev); + + switch (rbtn_data->type) { + case RBTN_TOGGLE: + rbtn_input_exit(rbtn_data); + break; + case RBTN_SLIDER: + rbtn_rfkill_exit(dev); + break; + default: + break; + } +} + +static int rbtn_probe(struct platform_device *pdev) +{ + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct rbtn_data *rbtn_data; enum rbtn_type type; int ret = 0; type = rbtn_check(device); if (type == RBTN_UNKNOWN) { - dev_info(&device->dev, "Unknown device type\n"); + dev_info(&pdev->dev, "Unknown device type\n"); return -EINVAL; } - rbtn_data = devm_kzalloc(&device->dev, sizeof(*rbtn_data), GFP_KERNEL); + rbtn_data = devm_kzalloc(&pdev->dev, sizeof(*rbtn_data), GFP_KERNEL); if (!rbtn_data) return -ENOMEM; ret = rbtn_acquire(device, true); if (ret < 0) { - dev_err(&device->dev, "Cannot enable device\n"); + dev_err(&pdev->dev, "Cannot enable device\n"); return ret; } + platform_set_drvdata(pdev, rbtn_data); + rbtn_data->type = type; - device->driver_data = rbtn_data; switch (rbtn_data->type) { case RBTN_TOGGLE: @@ -415,51 +429,54 @@ static int rbtn_add(struct acpi_device *device) if (auto_remove_rfkill && rbtn_chain_head.head) ret = 0; else - ret = rbtn_rfkill_init(device); + ret = rbtn_rfkill_init(&pdev->dev); break; default: ret = -EINVAL; break; } if (ret) - rbtn_acquire(device, false); + goto err; + + ret = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + rbtn_notify, &pdev->dev); + if (ret) + goto err_cleanup; + return 0; + +err_cleanup: + rbtn_cleanup(&pdev->dev); +err: + rbtn_acquire(device, false); return ret; } -static void rbtn_remove(struct acpi_device *device) +static void rbtn_remove(struct platform_device *pdev) { - struct rbtn_data *rbtn_data = device->driver_data; - - switch (rbtn_data->type) { - case RBTN_TOGGLE: - rbtn_input_exit(rbtn_data); - break; - case RBTN_SLIDER: - rbtn_rfkill_exit(device); - break; - default: - break; - } + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, rbtn_notify); + rbtn_cleanup(&pdev->dev); rbtn_acquire(device, false); } -static void rbtn_notify(struct acpi_device *device, u32 event) +static void rbtn_notify(acpi_handle handle, u32 event, void *data) { - struct rbtn_data *rbtn_data = device->driver_data; + struct device *dev = data; + struct rbtn_data *rbtn_data = dev_get_drvdata(dev); /* * Some BIOSes send a notification at resume. * Ignore it to prevent unwanted input events. */ if (rbtn_data->suspended) { - dev_dbg(&device->dev, "ACPI notification ignored\n"); + dev_dbg(dev, "ACPI notification ignored\n"); return; } if (event != 0x80) { - dev_info(&device->dev, "Received unknown event (0x%x)\n", + dev_info(dev, "Received unknown event (0x%x)\n", event); return; } @@ -469,20 +486,15 @@ static void rbtn_notify(struct acpi_device *device, u32 event) rbtn_input_event(rbtn_data); break; case RBTN_SLIDER: - rbtn_rfkill_event(device); - atomic_notifier_call_chain(&rbtn_chain_head, event, device); + rbtn_rfkill_event(dev); + atomic_notifier_call_chain(&rbtn_chain_head, event, NULL); break; default: break; } } - -/* - * module functions - */ - -module_acpi_driver(rbtn_driver); +module_platform_driver(rbtn_driver); module_param(auto_remove_rfkill, bool, 0444); diff --git a/drivers/platform/x86/dell/dell-wmi-base.c b/drivers/platform/x86/dell/dell-wmi-base.c index e7a411ae9ca1..2a5804efd3ea 100644 --- a/drivers/platform/x86/dell/dell-wmi-base.c +++ b/drivers/platform/x86/dell/dell-wmi-base.c @@ -825,6 +825,7 @@ static struct wmi_driver dell_wmi_driver = { .name = "dell-wmi", }, .id_table = dell_wmi_id_table, + .min_event_size = sizeof(u16), .probe = dell_wmi_probe, .remove = dell_wmi_remove, .notify = dell_wmi_notify, diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h b/drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h index 817ee7ba07ca..5278a93fdaf7 100644 --- a/drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h +++ b/drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h @@ -189,8 +189,8 @@ void exit_bios_attr_set_interface(void); int init_bios_attr_set_interface(void); int map_wmi_error(int error_code); size_t calculate_string_buffer(const char *str); -size_t calculate_security_buffer(char *authentication); -void populate_security_buffer(char *buffer, char *authentication); +size_t calculate_security_buffer(const char *authentication); +void populate_security_buffer(char *buffer, const char *authentication); ssize_t populate_string_buffer(char *buffer, size_t buffer_len, const char *str); int set_new_password(const char *password_type, const char *new); int init_bios_attr_pass_interface(void); diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c index 09996fbdc707..a85639d8a076 100644 --- a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +++ b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c @@ -6,10 +6,32 @@ * Copyright (c) 2020 Dell Inc. */ +#include <linux/bug.h> + #include "dell-wmi-sysman.h" get_instance_id(enumeration); +static int append_enum_string(char *dest, const char *src) +{ + size_t dest_len = strlen(dest); + ssize_t copied; + + if (WARN_ON_ONCE(dest_len >= MAX_BUFF)) + return -EINVAL; + + copied = strscpy(dest + dest_len, src, MAX_BUFF - dest_len); + if (copied < 0) + return -EINVAL; + + dest_len += copied; + copied = strscpy(dest + dest_len, ";", MAX_BUFF - dest_len); + if (copied < 0) + return -EINVAL; + + return 0; +} + static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int instance_id = get_enumeration_instance_id(kobj); @@ -176,9 +198,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, return -EINVAL; if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) return -EINVAL; - strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, - enumeration_obj[next_obj++].string.pointer); - strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";"); + if (append_enum_string(wmi_priv.enumeration_data[instance_id].dell_value_modifier, + enumeration_obj[next_obj++].string.pointer)) + return -EINVAL; } if (next_obj >= enum_property_count) @@ -193,9 +215,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, return -EINVAL; if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) return -EINVAL; - strcat(wmi_priv.enumeration_data[instance_id].possible_values, - enumeration_obj[next_obj++].string.pointer); - strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";"); + if (append_enum_string(wmi_priv.enumeration_data[instance_id].possible_values, + enumeration_obj[next_obj++].string.pointer)) + return -EINVAL; } return sysfs_create_group(attr_name_kobj, &enumeration_attr_group); diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c index 9dddab6c9397..51d25fdc1389 100644 --- a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c +++ b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c @@ -7,10 +7,13 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/align.h> #include <linux/fs.h> #include <linux/dmi.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/string.h> +#include <linux/sysfs.h> #include <linux/wmi.h> #include "dell-wmi-sysman.h" #include "../../firmware_attributes_class.h" @@ -72,13 +75,9 @@ size_t calculate_string_buffer(const char *str) * * Currently only supported type is Admin password */ -size_t calculate_security_buffer(char *authentication) +size_t calculate_security_buffer(const char *authentication) { - if (strlen(authentication) > 0) { - return (sizeof(u32) * 2) + strlen(authentication) + - strlen(authentication) % 2; - } - return sizeof(u32) * 2; + return sizeof(u32) * 2 + ALIGN(strlen(authentication), 2); } /** @@ -88,18 +87,18 @@ size_t calculate_security_buffer(char *authentication) * * Currently only supported type is PLAIN TEXT */ -void populate_security_buffer(char *buffer, char *authentication) +void populate_security_buffer(char *buffer, const char *authentication) { + size_t seclen = strlen(authentication); char *auth = buffer + sizeof(u32) * 2; u32 *sectype = (u32 *) buffer; - u32 *seclen = sectype + 1; + u32 *seclenp = sectype + 1; - *sectype = strlen(authentication) > 0 ? 1 : 0; - *seclen = strlen(authentication); + *sectype = !!seclen; + *seclenp = seclen; /* plain text */ - if (strlen(authentication) > 0) - memcpy(auth, authentication, *seclen); + memcpy(auth, authentication, seclen); } /** @@ -143,17 +142,17 @@ int map_wmi_error(int error_code) */ static ssize_t reset_bios_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - char *start = buf; + ssize_t len = 0; int i; for (i = 0; i < MAX_TYPES; i++) { if (i == reset_option) - buf += sprintf(buf, "[%s] ", reset_types[i]); + len += sysfs_emit_at(buf, len, "[%s] ", reset_types[i]); else - buf += sprintf(buf, "%s ", reset_types[i]); + len += sysfs_emit_at(buf, len, "%s ", reset_types[i]); } - buf += sprintf(buf, "\n"); - return buf-start; + len += sysfs_emit_at(buf, len, "\n"); + return len; } /** @@ -194,7 +193,7 @@ static ssize_t reset_bios_store(struct kobject *kobj, static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", wmi_priv.pending_changes); + return sysfs_emit(buf, "%d\n", wmi_priv.pending_changes); } static struct kobj_attribute reset_bios = __ATTR_RW(reset_bios); @@ -220,35 +219,6 @@ static int create_attributes_level_sysfs_files(void) return 0; } -static ssize_t wmi_sysman_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct kobj_attribute *kattr; - ssize_t ret = -EIO; - - kattr = container_of(attr, struct kobj_attribute, attr); - if (kattr->show) - ret = kattr->show(kobj, kattr, buf); - return ret; -} - -static ssize_t wmi_sysman_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ - struct kobj_attribute *kattr; - ssize_t ret = -EIO; - - kattr = container_of(attr, struct kobj_attribute, attr); - if (kattr->store) - ret = kattr->store(kobj, kattr, buf, count); - return ret; -} - -static const struct sysfs_ops wmi_sysman_kobj_sysfs_ops = { - .show = wmi_sysman_attr_show, - .store = wmi_sysman_attr_store, -}; - static void attr_name_release(struct kobject *kobj) { kfree(kobj); @@ -256,7 +226,7 @@ static void attr_name_release(struct kobject *kobj) static const struct kobj_type attr_name_ktype = { .release = attr_name_release, - .sysfs_ops = &wmi_sysman_kobj_sysfs_ops, + .sysfs_ops = &kobj_sysfs_ops, }; /** @@ -343,7 +313,7 @@ static int alloc_attributes_data(int attr_type) * destroy_attribute_objs() - Free a kset of kobjects * @kset: The kset to destroy * - * Fress kobjects created for each attribute_name under attribute type kset + * Frees kobjects created for each attribute_name under attribute type kset. */ static void destroy_attribute_objs(struct kset *kset) { diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c index eb50f1d75d0c..3fa9de9aa47b 100644 --- a/drivers/platform/x86/dell/dell_rbu.c +++ b/drivers/platform/x86/dell/dell_rbu.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/init.h> +#include <linux/kstrtox.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/string.h> @@ -619,9 +620,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj, char *buffer, loff_t pos, size_t count) { unsigned long temp; + + if (kstrtoul(buffer, 10, &temp)) + return -EINVAL; + spin_lock(&rbu_data.lock); packet_empty_list(); - sscanf(buffer, "%lu", &temp); if (temp < 0xffffffff) rbu_data.packetsize = temp; diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 974f55e0b36f..02a71095920e 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1204,9 +1204,10 @@ static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event) pr_info("Unknown key %x pressed\n", event); } -static void eeepc_acpi_notify(struct acpi_device *device, u32 event) +static void eeepc_acpi_notify(acpi_handle handle, u32 event, void *data) { - struct eeepc_laptop *eeepc = acpi_driver_data(device); + struct eeepc_laptop *eeepc = data; + struct acpi_device *device = eeepc->device; int old_brightness, new_brightness; u16 count; @@ -1360,8 +1361,9 @@ static void eeepc_enable_camera(struct eeepc_laptop *eeepc) static bool eeepc_device_present; -static int eeepc_acpi_add(struct acpi_device *device) +static int eeepc_acpi_probe(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct eeepc_laptop *eeepc; int result; @@ -1372,9 +1374,10 @@ static int eeepc_acpi_add(struct acpi_device *device) eeepc->handle = device->handle; strscpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME); strscpy(acpi_device_class(device), EEEPC_ACPI_CLASS); - device->driver_data = eeepc; eeepc->device = device; + platform_set_drvdata(pdev, eeepc); + eeepc->hotplug_disabled = hotplug_disabled; eeepc_dmi_check(eeepc); @@ -1422,9 +1425,16 @@ static int eeepc_acpi_add(struct acpi_device *device) if (result) goto fail_rfkill; + result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY, + eeepc_acpi_notify, eeepc); + if (result) + goto fail_acpi_notifier; + eeepc_device_present = true; return 0; +fail_acpi_notifier: + eeepc_rfkill_exit(eeepc); fail_rfkill: eeepc_led_exit(eeepc); fail_led: @@ -1440,10 +1450,12 @@ fail_platform: return result; } -static void eeepc_acpi_remove(struct acpi_device *device) +static void eeepc_acpi_remove(struct platform_device *pdev) { - struct eeepc_laptop *eeepc = acpi_driver_data(device); + struct eeepc_laptop *eeepc = platform_get_drvdata(pdev); + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_ALL_NOTIFY, eeepc_acpi_notify); eeepc_backlight_exit(eeepc); eeepc_rfkill_exit(eeepc); eeepc_input_exit(eeepc); @@ -1460,15 +1472,12 @@ static const struct acpi_device_id eeepc_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, eeepc_device_ids); -static struct acpi_driver eeepc_acpi_driver = { - .name = EEEPC_LAPTOP_NAME, - .class = EEEPC_ACPI_CLASS, - .ids = eeepc_device_ids, - .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, - .ops = { - .add = eeepc_acpi_add, - .remove = eeepc_acpi_remove, - .notify = eeepc_acpi_notify, +static struct platform_driver eeepc_acpi_driver = { + .probe = eeepc_acpi_probe, + .remove = eeepc_acpi_remove, + .driver = { + .name = EEEPC_LAPTOP_NAME, + .acpi_match_table = eeepc_device_ids, }, }; @@ -1481,7 +1490,7 @@ static int __init eeepc_laptop_init(void) if (result < 0) return result; - result = acpi_bus_register_driver(&eeepc_acpi_driver); + result = platform_driver_register(&eeepc_acpi_driver); if (result < 0) goto fail_acpi_driver; @@ -1493,7 +1502,7 @@ static int __init eeepc_laptop_init(void) return 0; fail_no_device: - acpi_bus_unregister_driver(&eeepc_acpi_driver); + platform_driver_unregister(&eeepc_acpi_driver); fail_acpi_driver: platform_driver_unregister(&platform_driver); return result; @@ -1501,7 +1510,7 @@ fail_acpi_driver: static void __exit eeepc_laptop_exit(void) { - acpi_bus_unregister_driver(&eeepc_acpi_driver); + platform_driver_unregister(&eeepc_acpi_driver); platform_driver_unregister(&platform_driver); } diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 931fbcdd21b8..2e265be2267e 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -144,11 +144,11 @@ struct fujitsu_laptop { bool charge_control_supported; }; -static struct acpi_device *fext; +static struct device *fext; /* Fujitsu ACPI interface function */ -static int call_fext_func(struct acpi_device *device, +static int call_fext_func(struct device *dev, int func, int op, int feature, int state) { union acpi_object params[4] = { @@ -158,18 +158,17 @@ static int call_fext_func(struct acpi_device *device, { .integer.type = ACPI_TYPE_INTEGER, .integer.value = state } }; struct acpi_object_list arg_list = { 4, params }; + acpi_handle handle = ACPI_HANDLE(dev); unsigned long long value; acpi_status status; - status = acpi_evaluate_integer(device->handle, "FUNC", &arg_list, - &value); + status = acpi_evaluate_integer(handle, "FUNC", &arg_list, &value); if (ACPI_FAILURE(status)) { - acpi_handle_err(device->handle, "Failed to evaluate FUNC\n"); + acpi_handle_err(handle, "Failed to evaluate FUNC\n"); return -ENODEV; } - acpi_handle_debug(device->handle, - "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", + acpi_handle_debug(handle, "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", func, op, feature, state, (int)value); return value; } @@ -251,9 +250,9 @@ static struct acpi_battery_hook battery_hook = { * These functions are intended to be called from acpi_fujitsu_laptop_add and * acpi_fujitsu_laptop_remove. */ -static int fujitsu_battery_charge_control_add(struct acpi_device *device) +static int fujitsu_battery_charge_control_add(struct device *dev) { - struct fujitsu_laptop *priv = acpi_driver_data(device); + struct fujitsu_laptop *priv = dev_get_drvdata(dev); int s006_cc_return; priv->charge_control_supported = false; @@ -274,9 +273,9 @@ static int fujitsu_battery_charge_control_add(struct acpi_device *device) return 0; } -static void fujitsu_battery_charge_control_remove(struct acpi_device *device) +static void fujitsu_battery_charge_control_remove(struct device *dev) { - struct fujitsu_laptop *priv = acpi_driver_data(device); + struct fujitsu_laptop *priv = dev_get_drvdata(dev); if (priv->charge_control_supported) battery_hook_unregister(&battery_hook); @@ -284,15 +283,16 @@ static void fujitsu_battery_charge_control_remove(struct acpi_device *device) /* Hardware access for LCD brightness control */ -static int set_lcd_level(struct acpi_device *device, int level) +static int set_lcd_level(struct device *dev, int level) { - struct fujitsu_bl *priv = acpi_driver_data(device); + struct fujitsu_bl *priv = dev_get_drvdata(dev); + acpi_handle handle = ACPI_HANDLE(dev); acpi_status status; char *method; switch (use_alt_lcd_levels) { case -1: - if (acpi_has_method(device->handle, "SBL2")) + if (acpi_has_method(handle, "SBL2")) method = "SBL2"; else method = "SBLL"; @@ -305,16 +305,14 @@ static int set_lcd_level(struct acpi_device *device, int level) break; } - acpi_handle_debug(device->handle, "set lcd level via %s [%d]\n", method, - level); + acpi_handle_debug(handle, "set lcd level via %s [%d]\n", method, level); if (level < 0 || level >= priv->max_brightness) return -EINVAL; - status = acpi_execute_simple_method(device->handle, method, level); + status = acpi_execute_simple_method(handle, method, level); if (ACPI_FAILURE(status)) { - acpi_handle_err(device->handle, "Failed to evaluate %s\n", - method); + acpi_handle_err(handle, "Failed to evaluate %s\n", method); return -ENODEV; } @@ -323,15 +321,16 @@ static int set_lcd_level(struct acpi_device *device, int level) return 0; } -static int get_lcd_level(struct acpi_device *device) +static int get_lcd_level(struct device *dev) { - struct fujitsu_bl *priv = acpi_driver_data(device); + struct fujitsu_bl *priv = dev_get_drvdata(dev); + acpi_handle handle = ACPI_HANDLE(dev); unsigned long long state = 0; acpi_status status = AE_OK; - acpi_handle_debug(device->handle, "get lcd level via GBLL\n"); + acpi_handle_debug(handle, "get lcd level via GBLL\n"); - status = acpi_evaluate_integer(device->handle, "GBLL", NULL, &state); + status = acpi_evaluate_integer(handle, "GBLL", NULL, &state); if (ACPI_FAILURE(status)) return 0; @@ -340,15 +339,16 @@ static int get_lcd_level(struct acpi_device *device) return priv->brightness_level; } -static int get_max_brightness(struct acpi_device *device) +static int get_max_brightness(struct device *dev) { - struct fujitsu_bl *priv = acpi_driver_data(device); + struct fujitsu_bl *priv = dev_get_drvdata(dev); + acpi_handle handle = ACPI_HANDLE(dev); unsigned long long state = 0; acpi_status status = AE_OK; - acpi_handle_debug(device->handle, "get max lcd level via RBLL\n"); + acpi_handle_debug(handle, "get max lcd level via RBLL\n"); - status = acpi_evaluate_integer(device->handle, "RBLL", NULL, &state); + status = acpi_evaluate_integer(handle, "RBLL", NULL, &state); if (ACPI_FAILURE(status)) return -1; @@ -361,15 +361,13 @@ static int get_max_brightness(struct acpi_device *device) static int bl_get_brightness(struct backlight_device *b) { - struct acpi_device *device = bl_get_data(b); + struct device *dev = bl_get_data(b); - return b->props.power == BACKLIGHT_POWER_OFF ? 0 : get_lcd_level(device); + return b->props.power == BACKLIGHT_POWER_OFF ? 0 : get_lcd_level(dev); } static int bl_update_status(struct backlight_device *b) { - struct acpi_device *device = bl_get_data(b); - if (fext) { if (b->props.power == BACKLIGHT_POWER_OFF) call_fext_func(fext, FUNC_BACKLIGHT, 0x1, @@ -379,7 +377,7 @@ static int bl_update_status(struct backlight_device *b) BACKLIGHT_PARAM_POWER, BACKLIGHT_ON); } - return set_lcd_level(device, b->props.brightness); + return set_lcd_level(bl_get_data(b), b->props.brightness); } static const struct backlight_ops fujitsu_bl_ops = { @@ -455,12 +453,13 @@ static const struct key_entry keymap_backlight[] = { { KE_END, 0 } }; -static int acpi_fujitsu_bl_input_setup(struct acpi_device *device) +static int acpi_fujitsu_bl_input_setup(struct device *dev) { - struct fujitsu_bl *priv = acpi_driver_data(device); + struct fujitsu_bl *priv = dev_get_drvdata(dev); + struct acpi_device *device = ACPI_COMPANION(dev); int ret; - priv->input = devm_input_allocate_device(&device->dev); + priv->input = devm_input_allocate_device(dev); if (!priv->input) return -ENOMEM; @@ -479,9 +478,9 @@ static int acpi_fujitsu_bl_input_setup(struct acpi_device *device) return input_register_device(priv->input); } -static int fujitsu_backlight_register(struct acpi_device *device) +static int fujitsu_backlight_register(struct device *dev) { - struct fujitsu_bl *priv = acpi_driver_data(device); + struct fujitsu_bl *priv = dev_get_drvdata(dev); const struct backlight_properties props = { .brightness = priv->brightness_level, .max_brightness = priv->max_brightness - 1, @@ -489,9 +488,8 @@ static int fujitsu_backlight_register(struct acpi_device *device) }; struct backlight_device *bd; - bd = devm_backlight_device_register(&device->dev, "fujitsu-laptop", - &device->dev, device, - &fujitsu_bl_ops, &props); + bd = devm_backlight_device_register(dev, "fujitsu-laptop", + dev, dev, &fujitsu_bl_ops, &props); if (IS_ERR(bd)) return PTR_ERR(bd); @@ -500,65 +498,78 @@ static int fujitsu_backlight_register(struct acpi_device *device) return 0; } -static int acpi_fujitsu_bl_add(struct acpi_device *device) +/* Brightness notify */ + +static void acpi_fujitsu_bl_notify(acpi_handle handle, u32 event, void *data) { + struct device *dev = data; + struct fujitsu_bl *priv = dev_get_drvdata(dev); + int oldb, newb; + + if (event != ACPI_FUJITSU_NOTIFY_CODE) { + acpi_handle_info(handle, "unsupported event [0x%x]\n", event); + sparse_keymap_report_event(priv->input, -1, 1, true); + return; + } + + oldb = priv->brightness_level; + get_lcd_level(dev); + newb = priv->brightness_level; + + acpi_handle_debug(handle, "brightness button event [%i -> %i]\n", + oldb, newb); + + if (oldb == newb) + return; + + if (!disable_brightness_adjust) + set_lcd_level(dev, newb); + + sparse_keymap_report_event(priv->input, oldb < newb, 1, true); +} + +static int acpi_fujitsu_bl_probe(struct platform_device *pdev) +{ + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct fujitsu_bl *priv; int ret; if (acpi_video_get_backlight_type() != acpi_backlight_vendor) return -ENODEV; - priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; fujitsu_bl = priv; strscpy(acpi_device_name(device), ACPI_FUJITSU_BL_DEVICE_NAME); strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS); - device->driver_data = priv; + + platform_set_drvdata(pdev, priv); pr_info("ACPI: %s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); - if (get_max_brightness(device) <= 0) + if (get_max_brightness(&pdev->dev) <= 0) priv->max_brightness = FUJITSU_LCD_N_LEVELS; - get_lcd_level(device); + get_lcd_level(&pdev->dev); - ret = acpi_fujitsu_bl_input_setup(device); + ret = acpi_fujitsu_bl_input_setup(&pdev->dev); if (ret) return ret; - return fujitsu_backlight_register(device); -} + ret = fujitsu_backlight_register(&pdev->dev); + if (ret) + return ret; -/* Brightness notify */ + return acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_fujitsu_bl_notify, &pdev->dev); +} -static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) +static void acpi_fujitsu_bl_remove(struct platform_device *pdev) { - struct fujitsu_bl *priv = acpi_driver_data(device); - int oldb, newb; - - if (event != ACPI_FUJITSU_NOTIFY_CODE) { - acpi_handle_info(device->handle, "unsupported event [0x%x]\n", - event); - sparse_keymap_report_event(priv->input, -1, 1, true); - return; - } - - oldb = priv->brightness_level; - get_lcd_level(device); - newb = priv->brightness_level; - - acpi_handle_debug(device->handle, - "brightness button event [%i -> %i]\n", oldb, newb); - - if (oldb == newb) - return; - - if (!disable_brightness_adjust) - set_lcd_level(device, newb); - - sparse_keymap_report_event(priv->input, oldb < newb, 1, true); + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, acpi_fujitsu_bl_notify); } /* ACPI device for hotkey handling */ @@ -653,12 +664,13 @@ static const struct dmi_system_id fujitsu_laptop_dmi_table[] = { {} }; -static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) +static int acpi_fujitsu_laptop_input_setup(struct device *dev) { - struct fujitsu_laptop *priv = acpi_driver_data(device); + struct fujitsu_laptop *priv = dev_get_drvdata(dev); + struct acpi_device *device = ACPI_COMPANION(dev); int ret; - priv->input = devm_input_allocate_device(&device->dev); + priv->input = devm_input_allocate_device(dev); if (!priv->input) return -ENOMEM; @@ -677,9 +689,9 @@ static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) return input_register_device(priv->input); } -static int fujitsu_laptop_platform_add(struct acpi_device *device) +static int fujitsu_laptop_platform_add(struct device *dev) { - struct fujitsu_laptop *priv = acpi_driver_data(device); + struct fujitsu_laptop *priv = dev_get_drvdata(dev); int ret; priv->pf_device = platform_device_alloc("fujitsu-laptop", PLATFORM_DEVID_NONE); @@ -707,9 +719,9 @@ err_put_platform_device: return ret; } -static void fujitsu_laptop_platform_remove(struct acpi_device *device) +static void fujitsu_laptop_platform_remove(struct device *dev) { - struct fujitsu_laptop *priv = acpi_driver_data(device); + struct fujitsu_laptop *priv = dev_get_drvdata(dev); sysfs_remove_group(&priv->pf_device->dev.kobj, &fujitsu_pf_attribute_group); @@ -719,7 +731,7 @@ static void fujitsu_laptop_platform_remove(struct acpi_device *device) static int logolamp_set(struct led_classdev *cdev, enum led_brightness brightness) { - struct acpi_device *device = to_acpi_device(cdev->dev->parent); + struct device *parent = cdev->dev->parent; int poweron = FUNC_LED_ON, always = FUNC_LED_ON; int ret; @@ -729,23 +741,23 @@ static int logolamp_set(struct led_classdev *cdev, if (brightness < LED_FULL) always = FUNC_LED_OFF; - ret = call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); + ret = call_fext_func(parent, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); if (ret < 0) return ret; - return call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always); + return call_fext_func(parent, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always); } static enum led_brightness logolamp_get(struct led_classdev *cdev) { - struct acpi_device *device = to_acpi_device(cdev->dev->parent); + struct device *parent = cdev->dev->parent; int ret; - ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); + ret = call_fext_func(parent, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); if (ret == FUNC_LED_ON) return LED_FULL; - ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); + ret = call_fext_func(parent, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); if (ret == FUNC_LED_ON) return LED_HALF; @@ -755,22 +767,21 @@ static enum led_brightness logolamp_get(struct led_classdev *cdev) static int kblamps_set(struct led_classdev *cdev, enum led_brightness brightness) { - struct acpi_device *device = to_acpi_device(cdev->dev->parent); + struct device *parent = cdev->dev->parent; if (brightness >= LED_FULL) - return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, + return call_fext_func(parent, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); else - return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, + return call_fext_func(parent, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF); } static enum led_brightness kblamps_get(struct led_classdev *cdev) { - struct acpi_device *device = to_acpi_device(cdev->dev->parent); enum led_brightness brightness = LED_OFF; - if (call_fext_func(device, + if (call_fext_func(cdev->dev->parent, FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) brightness = LED_FULL; @@ -780,22 +791,22 @@ static enum led_brightness kblamps_get(struct led_classdev *cdev) static int radio_led_set(struct led_classdev *cdev, enum led_brightness brightness) { - struct acpi_device *device = to_acpi_device(cdev->dev->parent); + struct device *parent = cdev->dev->parent; if (brightness >= LED_FULL) - return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON, + return call_fext_func(parent, FUNC_FLAGS, 0x5, RADIO_LED_ON, RADIO_LED_ON); else - return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON, + return call_fext_func(parent, FUNC_FLAGS, 0x5, RADIO_LED_ON, 0x0); } static enum led_brightness radio_led_get(struct led_classdev *cdev) { - struct acpi_device *device = to_acpi_device(cdev->dev->parent); + struct device *parent = cdev->dev->parent; enum led_brightness brightness = LED_OFF; - if (call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON) + if (call_fext_func(parent, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON) brightness = LED_FULL; return brightness; @@ -804,60 +815,58 @@ static enum led_brightness radio_led_get(struct led_classdev *cdev) static int eco_led_set(struct led_classdev *cdev, enum led_brightness brightness) { - struct acpi_device *device = to_acpi_device(cdev->dev->parent); + struct device *parent = cdev->dev->parent; int curr; - curr = call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0); + curr = call_fext_func(parent, FUNC_LEDS, 0x2, ECO_LED, 0x0); if (brightness >= LED_FULL) - return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED, + return call_fext_func(parent, FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON); else - return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED, + return call_fext_func(parent, FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON); } static enum led_brightness eco_led_get(struct led_classdev *cdev) { - struct acpi_device *device = to_acpi_device(cdev->dev->parent); + struct device *parent = cdev->dev->parent; enum led_brightness brightness = LED_OFF; - if (call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) + if (call_fext_func(parent, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) brightness = LED_FULL; return brightness; } -static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) +static int acpi_fujitsu_laptop_leds_register(struct device *dev) { - struct fujitsu_laptop *priv = acpi_driver_data(device); + struct fujitsu_laptop *priv = dev_get_drvdata(dev); struct led_classdev *led; int ret; - if (call_fext_func(device, - FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { - led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); + if (call_fext_func(dev, FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; led->name = "fujitsu::logolamp"; led->brightness_set_blocking = logolamp_set; led->brightness_get = logolamp_get; - ret = devm_led_classdev_register(&device->dev, led); + ret = devm_led_classdev_register(dev, led); if (ret) return ret; } - if ((call_fext_func(device, - FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && - (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { - led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); + if ((call_fext_func(dev, FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && + (call_fext_func(dev, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; led->name = "fujitsu::kblamps"; led->brightness_set_blocking = kblamps_set; led->brightness_get = kblamps_get; - ret = devm_led_classdev_register(&device->dev, led); + ret = devm_led_classdev_register(dev, led); if (ret) return ret; } @@ -872,7 +881,7 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) * whether given model has a radio toggle button. */ if (priv->flags_supported & BIT(17)) { - led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; @@ -880,7 +889,7 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) led->brightness_set_blocking = radio_led_set; led->brightness_get = radio_led_get; led->default_trigger = "rfkill-any"; - ret = devm_led_classdev_register(&device->dev, led); + ret = devm_led_classdev_register(dev, led); if (ret) return ret; } @@ -890,17 +899,16 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) * bit 14 seems to indicate presence of said led as well. * Confirm by testing the status. */ - if ((call_fext_func(device, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && - (call_fext_func(device, - FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { - led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); + if ((call_fext_func(dev, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && + (call_fext_func(dev, FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; led->name = "fujitsu::eco_led"; led->brightness_set_blocking = eco_led_set; led->brightness_get = eco_led_get; - ret = devm_led_classdev_register(&device->dev, led); + ret = devm_led_classdev_register(dev, led); if (ret) return ret; } @@ -908,21 +916,98 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) return 0; } -static int acpi_fujitsu_laptop_add(struct acpi_device *device) +static void acpi_fujitsu_laptop_press(struct device *dev, int scancode) +{ + struct fujitsu_laptop *priv = dev_get_drvdata(dev); + int ret; + + ret = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode, + sizeof(scancode), &priv->fifo_lock); + if (ret != sizeof(scancode)) { + dev_info(&priv->input->dev, "Could not push scancode [0x%x]\n", + scancode); + return; + } + sparse_keymap_report_event(priv->input, scancode, 1, false); + dev_dbg(&priv->input->dev, "Push scancode into ringbuffer [0x%x]\n", + scancode); +} + +static void acpi_fujitsu_laptop_release(struct device *dev) +{ + struct fujitsu_laptop *priv = dev_get_drvdata(dev); + int scancode, ret; + + while (true) { + ret = kfifo_out_locked(&priv->fifo, (unsigned char *)&scancode, + sizeof(scancode), &priv->fifo_lock); + if (ret != sizeof(scancode)) + return; + sparse_keymap_report_event(priv->input, scancode, 0, false); + dev_dbg(&priv->input->dev, + "Pop scancode from ringbuffer [0x%x]\n", scancode); + } +} + +static void acpi_fujitsu_laptop_notify(acpi_handle handle, u32 event, void *data) +{ + struct device *dev = data; + struct fujitsu_laptop *priv = dev_get_drvdata(dev); + unsigned long flags; + int scancode, i = 0; + unsigned int irb; + + if (event != ACPI_FUJITSU_NOTIFY_CODE) { + acpi_handle_info(handle, "Unsupported event [0x%x]\n", event); + sparse_keymap_report_event(priv->input, -1, 1, true); + return; + } + + if (priv->flags_supported) + priv->flags_state = call_fext_func(dev, FUNC_FLAGS, 0x4, 0x0, 0x0); + + while ((irb = call_fext_func(dev, FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 && + i++ < MAX_HOTKEY_RINGBUFFER_SIZE) { + scancode = irb & 0x4ff; + if (sparse_keymap_entry_from_scancode(priv->input, scancode)) + acpi_fujitsu_laptop_press(dev, scancode); + else if (scancode == 0) + acpi_fujitsu_laptop_release(dev); + else + acpi_handle_info(handle, "Unknown GIRB result [%x]\n", irb); + } + + /* + * First seen on the Skylake-based Lifebook E736/E746/E756), the + * touchpad toggle hotkey (Fn+F4) is handled in software. Other models + * have since added additional "soft keys". These are reported in the + * status flags queried using FUNC_FLAGS. + */ + if (priv->flags_supported & (FLAG_SOFTKEYS)) { + flags = call_fext_func(dev, FUNC_FLAGS, 0x1, 0x0, 0x0); + flags &= (FLAG_SOFTKEYS); + for_each_set_bit(i, &flags, BITS_PER_LONG) + sparse_keymap_report_event(priv->input, BIT(i), 1, true); + } +} + +static int acpi_fujitsu_laptop_probe(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct fujitsu_laptop *priv; int ret, i = 0; - priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended."); - fext = device; + fext = &pdev->dev; strscpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME); strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS); - device->driver_data = priv; + + platform_set_drvdata(pdev, priv); /* kfifo */ spin_lock_init(&priv->fifo_lock); @@ -934,14 +1019,13 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) pr_info("ACPI: %s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); - while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 && + while (call_fext_func(fext, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 && i++ < MAX_HOTKEY_RINGBUFFER_SIZE) ; /* No action, result is discarded */ acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n", i); - priv->flags_supported = call_fext_func(device, FUNC_FLAGS, 0x0, 0x0, - 0x0); + priv->flags_supported = call_fext_func(fext, FUNC_FLAGS, 0x0, 0x0, 0x0); /* Make sure our bitmask of supported functions is cleared if the RFKILL function block is not implemented, like on the S7020. */ @@ -949,12 +1033,12 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) priv->flags_supported = 0; if (priv->flags_supported) - priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, + priv->flags_state = call_fext_func(fext, FUNC_FLAGS, 0x4, 0x0, 0x0); /* Suspect this is a keymap of the application panel, print it */ acpi_handle_info(device->handle, "BTNI: [0x%x]\n", - call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0)); + call_fext_func(fext, FUNC_BUTTONS, 0x0, 0x0, 0x0)); /* Sync backlight power status */ if (fujitsu_bl && fujitsu_bl->bl_device && @@ -966,117 +1050,49 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_ON; } - ret = acpi_fujitsu_laptop_input_setup(device); + ret = acpi_fujitsu_laptop_input_setup(fext); if (ret) goto err_free_fifo; - ret = acpi_fujitsu_laptop_leds_register(device); + ret = acpi_fujitsu_laptop_leds_register(fext); if (ret) goto err_free_fifo; - ret = fujitsu_laptop_platform_add(device); + ret = fujitsu_laptop_platform_add(fext); if (ret) goto err_free_fifo; - ret = fujitsu_battery_charge_control_add(device); + ret = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_fujitsu_laptop_notify, fext); + if (ret) + goto err_platform_remove; + + ret = fujitsu_battery_charge_control_add(fext); if (ret < 0) pr_warn("Unable to register battery charge control: %d\n", ret); return 0; +err_platform_remove: + fujitsu_laptop_platform_remove(fext); err_free_fifo: kfifo_free(&priv->fifo); return ret; } -static void acpi_fujitsu_laptop_remove(struct acpi_device *device) -{ - struct fujitsu_laptop *priv = acpi_driver_data(device); - - fujitsu_battery_charge_control_remove(device); - - fujitsu_laptop_platform_remove(device); - - kfifo_free(&priv->fifo); -} - -static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode) -{ - struct fujitsu_laptop *priv = acpi_driver_data(device); - int ret; - - ret = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode, - sizeof(scancode), &priv->fifo_lock); - if (ret != sizeof(scancode)) { - dev_info(&priv->input->dev, "Could not push scancode [0x%x]\n", - scancode); - return; - } - sparse_keymap_report_event(priv->input, scancode, 1, false); - dev_dbg(&priv->input->dev, "Push scancode into ringbuffer [0x%x]\n", - scancode); -} - -static void acpi_fujitsu_laptop_release(struct acpi_device *device) +static void acpi_fujitsu_laptop_remove(struct platform_device *pdev) { - struct fujitsu_laptop *priv = acpi_driver_data(device); - int scancode, ret; - - while (true) { - ret = kfifo_out_locked(&priv->fifo, (unsigned char *)&scancode, - sizeof(scancode), &priv->fifo_lock); - if (ret != sizeof(scancode)) - return; - sparse_keymap_report_event(priv->input, scancode, 0, false); - dev_dbg(&priv->input->dev, - "Pop scancode from ringbuffer [0x%x]\n", scancode); - } -} + struct fujitsu_laptop *priv = platform_get_drvdata(pdev); -static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) -{ - struct fujitsu_laptop *priv = acpi_driver_data(device); - unsigned long flags; - int scancode, i = 0; - unsigned int irb; + fujitsu_battery_charge_control_remove(&pdev->dev); - if (event != ACPI_FUJITSU_NOTIFY_CODE) { - acpi_handle_info(device->handle, "Unsupported event [0x%x]\n", - event); - sparse_keymap_report_event(priv->input, -1, 1, true); - return; - } + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), ACPI_DEVICE_NOTIFY, + acpi_fujitsu_laptop_notify); - if (priv->flags_supported) - priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, - 0x0); + fujitsu_laptop_platform_remove(&pdev->dev); - while ((irb = call_fext_func(device, - FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 && - i++ < MAX_HOTKEY_RINGBUFFER_SIZE) { - scancode = irb & 0x4ff; - if (sparse_keymap_entry_from_scancode(priv->input, scancode)) - acpi_fujitsu_laptop_press(device, scancode); - else if (scancode == 0) - acpi_fujitsu_laptop_release(device); - else - acpi_handle_info(device->handle, - "Unknown GIRB result [%x]\n", irb); - } - - /* - * First seen on the Skylake-based Lifebook E736/E746/E756), the - * touchpad toggle hotkey (Fn+F4) is handled in software. Other models - * have since added additional "soft keys". These are reported in the - * status flags queried using FUNC_FLAGS. - */ - if (priv->flags_supported & (FLAG_SOFTKEYS)) { - flags = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0); - flags &= (FLAG_SOFTKEYS); - for_each_set_bit(i, &flags, BITS_PER_LONG) - sparse_keymap_report_event(priv->input, BIT(i), 1, true); - } + kfifo_free(&priv->fifo); } /* Initialization */ @@ -1086,14 +1102,13 @@ static const struct acpi_device_id fujitsu_bl_device_ids[] = { {"", 0}, }; -static struct acpi_driver acpi_fujitsu_bl_driver = { - .name = ACPI_FUJITSU_BL_DRIVER_NAME, - .class = ACPI_FUJITSU_CLASS, - .ids = fujitsu_bl_device_ids, - .ops = { - .add = acpi_fujitsu_bl_add, - .notify = acpi_fujitsu_bl_notify, - }, +static struct platform_driver acpi_fujitsu_bl_driver = { + .probe = acpi_fujitsu_bl_probe, + .remove = acpi_fujitsu_bl_remove, + .driver = { + .name = ACPI_FUJITSU_BL_DRIVER_NAME, + .acpi_match_table = fujitsu_bl_device_ids, + }, }; static const struct acpi_device_id fujitsu_laptop_device_ids[] = { @@ -1101,15 +1116,13 @@ static const struct acpi_device_id fujitsu_laptop_device_ids[] = { {"", 0}, }; -static struct acpi_driver acpi_fujitsu_laptop_driver = { - .name = ACPI_FUJITSU_LAPTOP_DRIVER_NAME, - .class = ACPI_FUJITSU_CLASS, - .ids = fujitsu_laptop_device_ids, - .ops = { - .add = acpi_fujitsu_laptop_add, - .remove = acpi_fujitsu_laptop_remove, - .notify = acpi_fujitsu_laptop_notify, - }, +static struct platform_driver acpi_fujitsu_laptop_driver = { + .probe = acpi_fujitsu_laptop_probe, + .remove = acpi_fujitsu_laptop_remove, + .driver = { + .name = ACPI_FUJITSU_LAPTOP_DRIVER_NAME, + .acpi_match_table = fujitsu_laptop_device_ids, + }, }; static const struct acpi_device_id fujitsu_ids[] __used = { @@ -1123,7 +1136,7 @@ static int __init fujitsu_init(void) { int ret; - ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver); + ret = platform_driver_register(&acpi_fujitsu_bl_driver); if (ret) return ret; @@ -1135,7 +1148,7 @@ static int __init fujitsu_init(void) /* Register laptop driver */ - ret = acpi_bus_register_driver(&acpi_fujitsu_laptop_driver); + ret = platform_driver_register(&acpi_fujitsu_laptop_driver); if (ret) goto err_unregister_platform_driver; @@ -1146,18 +1159,18 @@ static int __init fujitsu_init(void) err_unregister_platform_driver: platform_driver_unregister(&fujitsu_pf_driver); err_unregister_acpi: - acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); + platform_driver_unregister(&acpi_fujitsu_bl_driver); return ret; } static void __exit fujitsu_cleanup(void) { - acpi_bus_unregister_driver(&acpi_fujitsu_laptop_driver); + platform_driver_unregister(&acpi_fujitsu_laptop_driver); platform_driver_unregister(&fujitsu_pf_driver); - acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); + platform_driver_unregister(&acpi_fujitsu_bl_driver); pr_info("driver unloaded\n"); } diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c index 17f08ce7552d..8319df28e9b8 100644 --- a/drivers/platform/x86/fujitsu-tablet.c +++ b/drivers/platform/x86/fujitsu-tablet.c @@ -18,6 +18,7 @@ #include <linux/input.h> #include <linux/delay.h> #include <linux/dmi.h> +#include <linux/platform_device.h> #define MODULENAME "fujitsu-tablet" @@ -442,14 +443,12 @@ static acpi_status fujitsu_walk_resources(struct acpi_resource *res, void *data) } } -static int acpi_fujitsu_add(struct acpi_device *adev) +static int acpi_fujitsu_probe(struct platform_device *pdev) { + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); acpi_status status; int error; - if (!adev) - return -EINVAL; - status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, fujitsu_walk_resources, NULL); if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base) @@ -461,7 +460,7 @@ static int acpi_fujitsu_add(struct acpi_device *adev) snprintf(fujitsu.phys, sizeof(fujitsu.phys), "%s/input0", acpi_device_hid(adev)); - error = input_fujitsu_setup(&adev->dev, + error = input_fujitsu_setup(&pdev->dev, acpi_device_name(adev), fujitsu.phys); if (error) return error; @@ -484,7 +483,7 @@ static int acpi_fujitsu_add(struct acpi_device *adev) return 0; } -static void acpi_fujitsu_remove(struct acpi_device *adev) +static void acpi_fujitsu_remove(struct platform_device *pdev) { free_irq(fujitsu.irq, fujitsu_interrupt); release_region(fujitsu.io_base, fujitsu.io_length); @@ -501,15 +500,14 @@ static int acpi_fujitsu_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume); -static struct acpi_driver acpi_fujitsu_driver = { - .name = MODULENAME, - .class = "hotkey", - .ids = fujitsu_ids, - .ops = { - .add = acpi_fujitsu_add, - .remove = acpi_fujitsu_remove, +static struct platform_driver acpi_fujitsu_driver = { + .probe = acpi_fujitsu_probe, + .remove = acpi_fujitsu_remove, + .driver = { + .name = MODULENAME, + .acpi_match_table = fujitsu_ids, + .pm = &acpi_fujitsu_pm, }, - .drv.pm = &acpi_fujitsu_pm, }; static int __init fujitsu_module_init(void) @@ -518,7 +516,7 @@ static int __init fujitsu_module_init(void) dmi_check_system(dmi_ids); - error = acpi_bus_register_driver(&acpi_fujitsu_driver); + error = platform_driver_register(&acpi_fujitsu_driver); if (error) return error; @@ -527,7 +525,7 @@ static int __init fujitsu_module_init(void) static void __exit fujitsu_module_exit(void) { - acpi_bus_unregister_driver(&acpi_fujitsu_driver); + platform_driver_unregister(&acpi_fujitsu_driver); } module_init(fujitsu_module_init); diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index 7df00447bba4..d1cc6e7d176c 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -48,6 +48,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45E9-BE91-3D44E2C707E4"); enum hp_ec_offsets { HP_EC_OFFSET_UNKNOWN = 0x00, + HP_NO_THERMAL_PROFILE_OFFSET = 0x01, HP_VICTUS_S_EC_THERMAL_PROFILE_OFFSET = 0x59, HP_OMEN_EC_THERMAL_PROFILE_FLAGS_OFFSET = 0x62, HP_OMEN_EC_THERMAL_PROFILE_TIMER_OFFSET = 0x63, @@ -125,6 +126,13 @@ static const struct thermal_profile_params omen_v1_legacy_thermal_params = { .ec_tp_offset = HP_OMEN_EC_THERMAL_PROFILE_OFFSET, }; +static const struct thermal_profile_params omen_v1_no_ec_thermal_params = { + .performance = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE, + .balanced = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT, + .low_power = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT, + .ec_tp_offset = HP_NO_THERMAL_PROFILE_OFFSET, +}; + /* * A generic pointer for the currently-active board's thermal profile * parameters. @@ -151,6 +159,7 @@ static const char * const omen_thermal_profile_boards[] = { "8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB", "8A15", "8A42", "8BAD", + "8C58", "8E41", }; @@ -181,6 +190,10 @@ static const char * const victus_thermal_profile_boards[] = { /* DMI Board names of Victus 16-r and Victus 16-s laptops */ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = { { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "8A44") }, + .driver_data = (void *)&omen_v1_legacy_thermal_params, + }, + { .matches = { DMI_MATCH(DMI_BOARD_NAME, "8A4D") }, .driver_data = (void *)&omen_v1_legacy_thermal_params, }, @@ -213,6 +226,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst .driver_data = (void *)&omen_v1_thermal_params, }, { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C77") }, + .driver_data = (void *)&omen_v1_thermal_params, + }, + { .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C78") }, .driver_data = (void *)&omen_v1_thermal_params, }, @@ -228,6 +245,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst .matches = { DMI_MATCH(DMI_BOARD_NAME, "8D41") }, .driver_data = (void *)&victus_s_thermal_params, }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "8D87") }, + .driver_data = (void *)&omen_v1_no_ec_thermal_params, + }, {}, }; @@ -397,6 +418,11 @@ static const struct key_entry hp_wmi_keymap[] = { { KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } }, { KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } }, { KE_KEY, 0x231b, { KEY_HELP } }, + { KE_IGNORE, 0x21ab, }, /* FnLock on */ + { KE_IGNORE, 0x121ab, }, /* FnLock off */ + { KE_IGNORE, 0x30021aa, }, /* kbd backlight: level 2 -> off */ + { KE_IGNORE, 0x33221aa, }, /* kbd backlight: off -> level 1 */ + { KE_IGNORE, 0x36421aa, }, /* kbd backlight: level 1 -> level 2*/ { KE_END, 0 } }; @@ -451,23 +477,24 @@ enum pwm_modes { }; struct hp_wmi_hwmon_priv { + struct mutex lock; /* protects mode, pwm */ u8 min_rpm; u8 max_rpm; - u8 gpu_delta; + int gpu_delta; u8 mode; u8 pwm; struct delayed_work keep_alive_dwork; }; struct victus_s_fan_table_header { + u8 num_fans; u8 unknown; - u8 num_entries; } __packed; struct victus_s_fan_table_entry { u8 cpu_rpm; u8 gpu_rpm; - u8 unknown; + u8 noise_db; } __packed; struct victus_s_fan_table { @@ -1828,7 +1855,8 @@ static int platform_profile_victus_s_get_ec(enum platform_profile_option *profil const struct thermal_profile_params *params; params = active_thermal_profile_params; - if (params->ec_tp_offset == HP_EC_OFFSET_UNKNOWN) { + if (params->ec_tp_offset == HP_EC_OFFSET_UNKNOWN || + params->ec_tp_offset == HP_NO_THERMAL_PROFILE_OFFSET) { *profile = active_platform_profile; return 0; } @@ -2183,7 +2211,8 @@ static int thermal_profile_setup(struct platform_device *device) * behaves like a wrapper around active_platform_profile, to avoid using * uninitialized data, we default to PLATFORM_PROFILE_BALANCED. */ - if (active_thermal_profile_params->ec_tp_offset == HP_EC_OFFSET_UNKNOWN) { + if (active_thermal_profile_params->ec_tp_offset == HP_EC_OFFSET_UNKNOWN || + active_thermal_profile_params->ec_tp_offset == HP_NO_THERMAL_PROFILE_OFFSET) { active_platform_profile = PLATFORM_PROFILE_BALANCED; } else { err = platform_profile_victus_s_get_ec(&active_platform_profile); @@ -2351,13 +2380,16 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv) switch (priv->mode) { case PWM_MODE_MAX: - if (is_victus_s_thermal_profile()) - hp_wmi_get_fan_count_userdefine_trigger(); + if (is_victus_s_thermal_profile()) { + ret = hp_wmi_get_fan_count_userdefine_trigger(); + if (ret < 0) + return ret; + } ret = hp_wmi_fan_speed_max_set(1); if (ret < 0) return ret; - schedule_delayed_work(&priv->keep_alive_dwork, - secs_to_jiffies(KEEP_ALIVE_DELAY_SECS)); + mod_delayed_work(system_wq, &priv->keep_alive_dwork, + secs_to_jiffies(KEEP_ALIVE_DELAY_SECS)); return 0; case PWM_MODE_MANUAL: if (!is_victus_s_thermal_profile()) @@ -2365,26 +2397,26 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv) ret = hp_wmi_fan_speed_set(priv, pwm_to_rpm(priv->pwm, priv)); if (ret < 0) return ret; - schedule_delayed_work(&priv->keep_alive_dwork, - secs_to_jiffies(KEEP_ALIVE_DELAY_SECS)); + mod_delayed_work(system_wq, &priv->keep_alive_dwork, + secs_to_jiffies(KEEP_ALIVE_DELAY_SECS)); return 0; case PWM_MODE_AUTO: if (is_victus_s_thermal_profile()) { - hp_wmi_get_fan_count_userdefine_trigger(); + ret = hp_wmi_get_fan_count_userdefine_trigger(); + if (ret < 0) + return ret; ret = hp_wmi_fan_speed_max_reset(priv); } else { ret = hp_wmi_fan_speed_max_set(0); } if (ret < 0) return ret; - cancel_delayed_work_sync(&priv->keep_alive_dwork); + cancel_delayed_work(&priv->keep_alive_dwork); return 0; default: /* shouldn't happen */ return -EINVAL; } - - return 0; } static umode_t hp_wmi_hwmon_is_visible(const void *data, @@ -2417,6 +2449,7 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, { struct hp_wmi_hwmon_priv *priv; int rpm, ret; + u8 mode; priv = dev_get_drvdata(dev); switch (type) { @@ -2440,11 +2473,13 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, *val = rpm_to_pwm(rpm / 100, priv); return 0; } - switch (priv->mode) { + scoped_guard(mutex, &priv->lock) + mode = priv->mode; + switch (mode) { case PWM_MODE_MAX: case PWM_MODE_MANUAL: case PWM_MODE_AUTO: - *val = priv->mode; + *val = mode; return 0; default: /* shouldn't happen */ @@ -2462,6 +2497,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, int rpm; priv = dev_get_drvdata(dev); + guard(mutex)(&priv->lock); switch (type) { case hwmon_pwm: if (attr == hwmon_pwm_input) { @@ -2526,22 +2562,30 @@ static void hp_wmi_hwmon_keep_alive_handler(struct work_struct *work) { struct delayed_work *dwork; struct hp_wmi_hwmon_priv *priv; + int ret; dwork = to_delayed_work(work); priv = container_of(dwork, struct hp_wmi_hwmon_priv, keep_alive_dwork); + + guard(mutex)(&priv->lock); /* * Re-apply the current hwmon context settings. * NOTE: hp_wmi_apply_fan_settings will handle the re-scheduling. */ - hp_wmi_apply_fan_settings(priv); + ret = hp_wmi_apply_fan_settings(priv); + if (ret) + pr_warn_ratelimited("keep-alive failed to refresh fan settings: %d\n", + ret); } static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv) { u8 fan_data[128] = { 0 }; struct victus_s_fan_table *fan_table; - u8 min_rpm, max_rpm, gpu_delta; - int ret; + u8 min_rpm, max_rpm; + u8 cpu_rpm, gpu_rpm, noise_db; + int gpu_delta, i, num_entries, ret; + size_t header_size, entry_size; /* Default behaviour on hwmon init is automatic mode */ priv->mode = PWM_MODE_AUTO; @@ -2556,13 +2600,36 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv) return ret; fan_table = (struct victus_s_fan_table *)fan_data; - if (fan_table->header.num_entries == 0 || - sizeof(struct victus_s_fan_table_header) + - sizeof(struct victus_s_fan_table_entry) * fan_table->header.num_entries > sizeof(fan_data)) + if (fan_table->header.num_fans == 0) + return -EINVAL; + + header_size = sizeof(struct victus_s_fan_table_header); + entry_size = sizeof(struct victus_s_fan_table_entry); + num_entries = (sizeof(fan_data) - header_size) / entry_size; + min_rpm = U8_MAX; + max_rpm = 0; + + for (i = 0 ; i < num_entries ; i++) { + cpu_rpm = fan_table->entries[i].cpu_rpm; + gpu_rpm = fan_table->entries[i].gpu_rpm; + noise_db = fan_table->entries[i].noise_db; + + /* + * On some devices, the fan table is truncated with an all-zero row, + * hence we stop parsing here. + */ + if (cpu_rpm == 0 && gpu_rpm == 0 && noise_db == 0) + break; + + if (cpu_rpm < min_rpm) + min_rpm = cpu_rpm; + if (cpu_rpm > max_rpm) + max_rpm = cpu_rpm; + } + + if (min_rpm == U8_MAX || max_rpm == 0) return -EINVAL; - min_rpm = fan_table->entries[0].cpu_rpm; - max_rpm = fan_table->entries[fan_table->header.num_entries - 1].cpu_rpm; gpu_delta = fan_table->entries[0].gpu_rpm - fan_table->entries[0].cpu_rpm; priv->min_rpm = min_rpm; priv->max_rpm = max_rpm; @@ -2582,6 +2649,10 @@ static int hp_wmi_hwmon_init(void) if (!priv) return -ENOMEM; + ret = devm_mutex_init(dev, &priv->lock); + if (ret) + return ret; + ret = hp_wmi_setup_fan_settings(priv); if (ret) return ret; @@ -2595,7 +2666,9 @@ static int hp_wmi_hwmon_init(void) INIT_DELAYED_WORK(&priv->keep_alive_dwork, hp_wmi_hwmon_keep_alive_handler); platform_set_drvdata(hp_wmi_platform_dev, priv); - hp_wmi_apply_fan_settings(priv); + ret = hp_wmi_apply_fan_settings(priv); + if (ret) + dev_warn(dev, "Failed to apply initial fan settings: %d\n", ret); return 0; } diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 1c65ce87cde0..115bb37577a1 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -212,7 +212,11 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 *gpio_flags = GPIO_ACTIVE_HIGH; break; case INT3472_GPIO_TYPE_PRIVACY_LED: - *con_id = "privacy-led"; + *con_id = "privacy"; + *gpio_flags = GPIO_ACTIVE_HIGH; + break; + case INT3472_GPIO_TYPE_STROBE: + *con_id = "ir_flood"; *gpio_flags = GPIO_ACTIVE_HIGH; break; case INT3472_GPIO_TYPE_HOTPLUG_DETECT: @@ -252,6 +256,7 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 * * 0x00 Reset * 0x01 Power down + * 0x02 Strobe * 0x0b Power enable * 0x0c Clock enable * 0x0d Privacy LED @@ -336,6 +341,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, break; case INT3472_GPIO_TYPE_CLK_ENABLE: case INT3472_GPIO_TYPE_PRIVACY_LED: + case INT3472_GPIO_TYPE_STROBE: case INT3472_GPIO_TYPE_POWER_ENABLE: case INT3472_GPIO_TYPE_DOVDD: case INT3472_GPIO_TYPE_HANDSHAKE: @@ -354,7 +360,8 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, break; case INT3472_GPIO_TYPE_PRIVACY_LED: - ret = skl_int3472_register_pled(int3472, gpio); + case INT3472_GPIO_TYPE_STROBE: + ret = skl_int3472_register_led(int3472, gpio, con_id); if (ret) err_msg = "Failed to register LED\n"; @@ -429,7 +436,7 @@ void int3472_discrete_cleanup(struct int3472_discrete_device *int3472) gpiod_remove_lookup_table(&int3472->gpios); skl_int3472_unregister_clock(int3472); - skl_int3472_unregister_pled(int3472); + skl_int3472_unregister_leds(int3472); skl_int3472_unregister_regulator(int3472); } EXPORT_SYMBOL_NS_GPL(int3472_discrete_cleanup, "INTEL_INT3472_DISCRETE"); diff --git a/drivers/platform/x86/intel/int3472/led.c b/drivers/platform/x86/intel/int3472/led.c index b1d84b968112..9b2573cc347b 100644 --- a/drivers/platform/x86/intel/int3472/led.c +++ b/drivers/platform/x86/intel/int3472/led.c @@ -6,55 +6,58 @@ #include <linux/leds.h> #include <linux/platform_data/x86/int3472.h> -static int int3472_pled_set(struct led_classdev *led_cdev, - enum led_brightness brightness) +static int int3472_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct int3472_discrete_device *int3472 = - container_of(led_cdev, struct int3472_discrete_device, pled.classdev); + struct int3472_led *led = container_of(led_cdev, struct int3472_led, classdev); - gpiod_set_value_cansleep(int3472->pled.gpio, brightness); + gpiod_set_value_cansleep(led->gpio, brightness); return 0; } -int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio) +int skl_int3472_register_led(struct int3472_discrete_device *int3472, struct gpio_desc *gpio, + const char *con_id) { + struct int3472_led *led; char *p; int ret; - if (int3472->pled.classdev.dev) - return -EBUSY; + if (int3472->n_leds >= INT3472_MAX_LEDS) + return -ENOSPC; - int3472->pled.gpio = gpio; + led = &int3472->leds[int3472->n_leds]; + led->gpio = gpio; /* Generate the name, replacing the ':' in the ACPI devname with '_' */ - snprintf(int3472->pled.name, sizeof(int3472->pled.name), - "%s::privacy_led", acpi_dev_name(int3472->sensor)); - p = strchr(int3472->pled.name, ':'); + snprintf(led->name, sizeof(led->name), + "%s::%s_led", acpi_dev_name(int3472->sensor), con_id); + p = strchr(led->name, ':'); if (p) *p = '_'; - int3472->pled.classdev.name = int3472->pled.name; - int3472->pled.classdev.max_brightness = 1; - int3472->pled.classdev.brightness_set_blocking = int3472_pled_set; + led->classdev.name = led->name; + led->classdev.max_brightness = 1; + led->classdev.brightness_set_blocking = int3472_led_set; - ret = led_classdev_register(int3472->dev, &int3472->pled.classdev); + ret = led_classdev_register(int3472->dev, &led->classdev); if (ret) return ret; - int3472->pled.lookup.provider = int3472->pled.name; - int3472->pled.lookup.dev_id = int3472->sensor_name; - int3472->pled.lookup.con_id = "privacy"; - led_add_lookup(&int3472->pled.lookup); + led->lookup.provider = led->name; + led->lookup.dev_id = int3472->sensor_name; + led->lookup.con_id = con_id; + led_add_lookup(&led->lookup); + int3472->n_leds++; return 0; } -void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472) +void skl_int3472_unregister_leds(struct int3472_discrete_device *int3472) { - if (IS_ERR_OR_NULL(int3472->pled.classdev.dev)) - return; + for (unsigned int i = 0; i < int3472->n_leds; i++) { + struct int3472_led *led = &int3472->leds[i]; - led_remove_lookup(&int3472->pled.lookup); - led_classdev_unregister(&int3472->pled.classdev); - gpiod_put(int3472->pled.gpio); + led_remove_lookup(&led->lookup); + led_classdev_unregister(&led->classdev); + gpiod_put(led->gpio); + } } diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index 02b303418d18..d91e1ab842d6 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -1315,7 +1315,7 @@ static struct telem_endpoint *pmc_core_register_endpoint(struct pci_dev *pcidev, unsigned int i; for (i = 0; guids[i]; i++) { - ep = pmt_telem_find_and_register_endpoint(pcidev, guids[i], 0); + ep = pmt_telem_find_and_register_endpoint(&pcidev->dev, guids[i], 0); if (!IS_ERR(ep)) return ep; } @@ -1600,7 +1600,7 @@ static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, struct pmc_dev_info * if (!pmc->map->lpm_req_guid) return -ENXIO; - ep = pmt_telem_find_and_register_endpoint(pcidev, pmc->map->lpm_req_guid, 0); + ep = pmt_telem_find_and_register_endpoint(&pcidev->dev, pmc->map->lpm_req_guid, 0); if (IS_ERR(ep)) { dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %pe", ep); return -EPROBE_DEFER; diff --git a/drivers/platform/x86/intel/pmc/ssram_telemetry.c b/drivers/platform/x86/intel/pmc/ssram_telemetry.c index 03fad9331fc0..6f6e83e70fc5 100644 --- a/drivers/platform/x86/intel/pmc/ssram_telemetry.c +++ b/drivers/platform/x86/intel/pmc/ssram_telemetry.c @@ -60,7 +60,7 @@ pmc_ssram_telemetry_add_pmt(struct pci_dev *pcidev, u64 ssram_base, void __iomem info.base_addr = ssram_base; info.parent = &pcidev->dev; - return intel_vsec_register(pcidev, &info); + return intel_vsec_register(&pcidev->dev, &info); } static inline u64 get_base(void __iomem *addr, u32 offset) diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c index be3c8d9e4fff..b4c9964df807 100644 --- a/drivers/platform/x86/intel/pmt/class.c +++ b/drivers/platform/x86/intel/pmt/class.c @@ -60,11 +60,11 @@ pmt_memcpy64_fromio(void *to, const u64 __iomem *from, size_t count) return count; } -int pmt_telem_read_mmio(struct pci_dev *pdev, struct pmt_callbacks *cb, u32 guid, void *buf, +int pmt_telem_read_mmio(struct device *dev, struct pmt_callbacks *cb, u32 guid, void *buf, void __iomem *addr, loff_t off, u32 count) { if (cb && cb->read_telem) - return cb->read_telem(pdev, guid, buf, off, count); + return cb->read_telem(dev, guid, buf, off, count); addr += off; @@ -99,7 +99,7 @@ intel_pmt_read(struct file *filp, struct kobject *kobj, if (count > entry->size - off) count = entry->size - off; - count = pmt_telem_read_mmio(entry->pcidev, entry->cb, entry->header.guid, buf, + count = pmt_telem_read_mmio(entry->ep->dev, entry->cb, entry->header.guid, buf, entry->base, off, count); return count; @@ -208,7 +208,7 @@ static int intel_pmt_populate_entry(struct intel_pmt_entry *entry, struct intel_vsec_device *ivdev, struct resource *disc_res) { - struct pci_dev *pci_dev = ivdev->pcidev; + struct pci_dev *pci_dev = to_pci_dev(ivdev->dev); struct device *dev = &ivdev->auxdev.dev; struct intel_pmt_header *header = &entry->header; u8 bir; diff --git a/drivers/platform/x86/intel/pmt/class.h b/drivers/platform/x86/intel/pmt/class.h index 3c5ad5f52bca..1ae56a5baad2 100644 --- a/drivers/platform/x86/intel/pmt/class.h +++ b/drivers/platform/x86/intel/pmt/class.h @@ -19,11 +19,12 @@ #define GET_BIR(v) ((v) & GENMASK(2, 0)) #define GET_ADDRESS(v) ((v) & GENMASK(31, 3)) +struct device; struct pci_dev; extern struct class intel_pmt_class; struct telem_endpoint { - struct pci_dev *pcidev; + struct device *dev; struct telem_header header; struct pmt_callbacks *cb; void __iomem *base; @@ -65,7 +66,7 @@ struct intel_pmt_namespace { struct intel_pmt_entry *entry); }; -int pmt_telem_read_mmio(struct pci_dev *pdev, struct pmt_callbacks *cb, u32 guid, void *buf, +int pmt_telem_read_mmio(struct device *dev, struct pmt_callbacks *cb, u32 guid, void *buf, void __iomem *addr, loff_t off, u32 count); bool intel_pmt_is_early_client_hw(struct device *dev); int intel_pmt_dev_create(struct intel_pmt_entry *entry, diff --git a/drivers/platform/x86/intel/pmt/discovery.c b/drivers/platform/x86/intel/pmt/discovery.c index e500aa327d23..c482368bfaae 100644 --- a/drivers/platform/x86/intel/pmt/discovery.c +++ b/drivers/platform/x86/intel/pmt/discovery.c @@ -542,7 +542,7 @@ static int pmt_features_probe(struct auxiliary_device *auxdev, const struct auxi if (!priv) return -ENOMEM; - priv->parent = &ivdev->pcidev->dev; + priv->parent = ivdev->dev; auxiliary_set_drvdata(auxdev, priv); priv->dev = device_create(&intel_pmt_class, &auxdev->dev, MKDEV(0, 0), priv, @@ -609,7 +609,7 @@ void intel_pmt_get_features(struct intel_pmt_entry *entry) mutex_lock(&feature_list_lock); list_for_each_entry(feature, &pmt_feature_list, list) { - if (feature->priv->parent != &entry->ep->pcidev->dev) + if (feature->priv->parent != entry->ep->dev) continue; pmt_get_features(entry, feature); diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c index a52803bfe124..bdc7c24a3678 100644 --- a/drivers/platform/x86/intel/pmt/telemetry.c +++ b/drivers/platform/x86/intel/pmt/telemetry.c @@ -112,7 +112,7 @@ static int pmt_telem_add_endpoint(struct intel_vsec_device *ivdev, return -ENOMEM; ep = entry->ep; - ep->pcidev = ivdev->pcidev; + ep->dev = ivdev->dev; ep->header.access_type = entry->header.access_type; ep->header.guid = entry->header.guid; ep->header.base_offset = entry->header.base_offset; @@ -204,7 +204,7 @@ int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info) goto unlock; } - info->pdev = entry->ep->pcidev; + info->dev = entry->ep->dev; info->header = entry->ep->header; unlock: @@ -218,9 +218,10 @@ static int pmt_copy_region(struct telemetry_region *region, struct intel_pmt_entry *entry) { + struct pci_dev *pdev = to_pci_dev(entry->ep->dev); struct oobmsm_plat_info *plat_info; - plat_info = intel_vsec_get_mapping(entry->ep->pcidev); + plat_info = intel_vsec_get_mapping(pdev); if (IS_ERR(plat_info)) return PTR_ERR(plat_info); @@ -308,7 +309,7 @@ int pmt_telem_read(struct telem_endpoint *ep, u32 id, u64 *data, u32 count) if (offset + NUM_BYTES_QWORD(count) > size) return -EINVAL; - pmt_telem_read_mmio(ep->pcidev, ep->cb, ep->header.guid, data, ep->base, offset, + pmt_telem_read_mmio(ep->dev, ep->cb, ep->header.guid, data, ep->base, offset, NUM_BYTES_QWORD(count)); return ep->present ? 0 : -EPIPE; @@ -335,7 +336,7 @@ int pmt_telem_read32(struct telem_endpoint *ep, u32 id, u32 *data, u32 count) EXPORT_SYMBOL_NS_GPL(pmt_telem_read32, "INTEL_PMT_TELEMETRY"); struct telem_endpoint * -pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev, u32 guid, u16 pos) +pmt_telem_find_and_register_endpoint(struct device *dev, u32 guid, u16 pos) { int devid = 0; int inst = 0; @@ -348,7 +349,7 @@ pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev, u32 guid, u16 pos) if (err) return ERR_PTR(err); - if (ep_info.header.guid == guid && ep_info.pdev == pcidev) { + if (ep_info.header.guid == guid && ep_info.dev == dev) { if (inst == pos) return pmt_telem_register_endpoint(devid); ++inst; diff --git a/drivers/platform/x86/intel/pmt/telemetry.h b/drivers/platform/x86/intel/pmt/telemetry.h index d45af5512b4e..0f88c5e7d90e 100644 --- a/drivers/platform/x86/intel/pmt/telemetry.h +++ b/drivers/platform/x86/intel/pmt/telemetry.h @@ -6,8 +6,8 @@ #define PMT_TELEM_TELEMETRY 0 #define PMT_TELEM_CRASHLOG 1 +struct device; struct telem_endpoint; -struct pci_dev; struct telem_header { u8 access_type; @@ -17,7 +17,7 @@ struct telem_header { }; struct telem_endpoint_info { - struct pci_dev *pdev; + struct device *dev; struct telem_header header; }; @@ -71,8 +71,8 @@ int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info); /** * pmt_telem_find_and_register_endpoint() - Get a telemetry endpoint from - * pci_dev device, guid and pos - * @pdev: PCI device inside the Intel vsec + * device, guid and pos + * @dev: device inside the Intel vsec * @guid: GUID of the telemetry space * @pos: Instance of the guid * @@ -80,8 +80,8 @@ int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info); * * endpoint - On success returns pointer to the telemetry endpoint * * -ENXIO - telemetry endpoint not found */ -struct telem_endpoint *pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev, - u32 guid, u16 pos); +struct telem_endpoint * +pmt_telem_find_and_register_endpoint(struct device *dev, u32 guid, u16 pos); /** * pmt_telem_read() - Read qwords from counter sram using sample id diff --git a/drivers/platform/x86/intel/rst.c b/drivers/platform/x86/intel/rst.c index f3a60e14d4c1..4bd10927aad9 100644 --- a/drivers/platform/x86/intel/rst.c +++ b/drivers/platform/x86/intel/rst.c @@ -5,6 +5,7 @@ #include <linux/acpi.h> #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/slab.h> MODULE_DESCRIPTION("Intel Rapid Start Technology Driver"); @@ -99,8 +100,9 @@ static struct device_attribute irst_timeout_attr = { .store = irst_store_wakeup_time }; -static int irst_add(struct acpi_device *acpi) +static int irst_probe(struct platform_device *pdev) { + struct acpi_device *acpi = ACPI_COMPANION(&pdev->dev); int error; error = device_create_file(&acpi->dev, &irst_timeout_attr); @@ -114,8 +116,10 @@ static int irst_add(struct acpi_device *acpi) return error; } -static void irst_remove(struct acpi_device *acpi) +static void irst_remove(struct platform_device *pdev) { + struct acpi_device *acpi = ACPI_COMPANION(&pdev->dev); + device_remove_file(&acpi->dev, &irst_wakeup_attr); device_remove_file(&acpi->dev, &irst_timeout_attr); } @@ -125,16 +129,15 @@ static const struct acpi_device_id irst_ids[] = { {"", 0} }; -static struct acpi_driver irst_driver = { - .name = "intel_rapid_start", - .class = "intel_rapid_start", - .ids = irst_ids, - .ops = { - .add = irst_add, - .remove = irst_remove, +static struct platform_driver irst_driver = { + .probe = irst_probe, + .remove = irst_remove, + .driver = { + .name = "intel_rapid_start", + .acpi_match_table = irst_ids, }, }; -module_acpi_driver(irst_driver); +module_platform_driver(irst_driver); MODULE_DEVICE_TABLE(acpi, irst_ids); diff --git a/drivers/platform/x86/intel/sdsi.c b/drivers/platform/x86/intel/sdsi.c index da75f53d0bcc..d7e37d4ace23 100644 --- a/drivers/platform/x86/intel/sdsi.c +++ b/drivers/platform/x86/intel/sdsi.c @@ -599,13 +599,14 @@ static int sdsi_get_layout(struct sdsi_priv *priv, struct disc_table *table) return 0; } -static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *parent, +static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct device *dev, struct disc_table *disc_table, struct resource *disc_res) { u32 access_type = FIELD_GET(DT_ACCESS_TYPE, disc_table->access_info); u32 size = FIELD_GET(DT_SIZE, disc_table->access_info); u32 tbir = FIELD_GET(DT_TBIR, disc_table->offset); u32 offset = DT_OFFSET(disc_table->offset); + struct pci_dev *parent = to_pci_dev(dev); struct resource res = {}; /* Starting location of SDSi MMIO region based on access type */ @@ -681,7 +682,7 @@ static int sdsi_probe(struct auxiliary_device *auxdev, const struct auxiliary_de return ret; /* Map the SDSi mailbox registers */ - ret = sdsi_map_mbox_registers(priv, intel_cap_dev->pcidev, &disc_table, disc_res); + ret = sdsi_map_mbox_registers(priv, intel_cap_dev->dev, &disc_table, disc_res); if (ret) return ret; diff --git a/drivers/platform/x86/intel/smartconnect.c b/drivers/platform/x86/intel/smartconnect.c index 31019a1a6d5e..4d866b6366d6 100644 --- a/drivers/platform/x86/intel/smartconnect.c +++ b/drivers/platform/x86/intel/smartconnect.c @@ -5,22 +5,24 @@ #include <linux/acpi.h> #include <linux/module.h> +#include <linux/platform_device.h> MODULE_DESCRIPTION("Intel Smart Connect disabling driver"); MODULE_LICENSE("GPL"); -static int smartconnect_acpi_init(struct acpi_device *acpi) +static int smartconnect_acpi_probe(struct platform_device *pdev) { + acpi_handle handle = ACPI_HANDLE(&pdev->dev); unsigned long long value; acpi_status status; - status = acpi_evaluate_integer(acpi->handle, "GAOS", NULL, &value); + status = acpi_evaluate_integer(handle, "GAOS", NULL, &value); if (ACPI_FAILURE(status)) return -EINVAL; if (value & 0x1) { - dev_info(&acpi->dev, "Disabling Intel Smart Connect\n"); - status = acpi_execute_simple_method(acpi->handle, "SAOS", 0); + dev_info(&pdev->dev, "Disabling Intel Smart Connect\n"); + status = acpi_execute_simple_method(handle, "SAOS", 0); } return 0; @@ -32,13 +34,12 @@ static const struct acpi_device_id smartconnect_ids[] = { }; MODULE_DEVICE_TABLE(acpi, smartconnect_ids); -static struct acpi_driver smartconnect_driver = { - .name = "intel_smart_connect", - .class = "intel_smart_connect", - .ids = smartconnect_ids, - .ops = { - .add = smartconnect_acpi_init, +static struct platform_driver smartconnect_driver = { + .probe = smartconnect_acpi_probe, + .driver = { + .name = "intel_smart_connect", + .acpi_match_table = smartconnect_ids, }, }; -module_acpi_driver(smartconnect_driver); +module_platform_driver(smartconnect_driver); diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index 5059d320edf8..7d5dbc1c1d05 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -24,7 +24,9 @@ #include <linux/intel_vsec.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/overflow.h> #include <linux/pci.h> +#include <linux/string.h> #include <linux/types.h> #define PMT_XA_START 0 @@ -42,7 +44,7 @@ enum vsec_device_state { }; struct vsec_priv { - struct intel_vsec_platform_info *info; + const struct intel_vsec_platform_info *info; struct device *suppliers[VSEC_FEATURE_COUNT]; struct oobmsm_plat_info plat_info; enum vsec_device_state state[VSEC_FEATURE_COUNT]; @@ -109,6 +111,7 @@ static void intel_vsec_dev_release(struct device *dev) ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id); + kfree(intel_vsec_dev->acpi_disc); kfree(intel_vsec_dev->resource); kfree(intel_vsec_dev); } @@ -158,18 +161,23 @@ static bool vsec_driver_present(int cap_id) */ static const struct pci_device_id intel_vsec_pci_ids[]; -static int intel_vsec_link_devices(struct pci_dev *pdev, struct device *dev, +static int intel_vsec_link_devices(struct device *parent, struct device *dev, int consumer_id) { const struct vsec_feature_dependency *deps; enum vsec_device_state *state; struct device **suppliers; struct vsec_priv *priv; + struct pci_dev *pdev; int supplier_id; if (!consumer_id) return 0; + if (!dev_is_pci(parent)) + return 0; + + pdev = to_pci_dev(parent); if (!pci_match_id(intel_vsec_pci_ids, pdev)) return 0; @@ -204,7 +212,7 @@ static int intel_vsec_link_devices(struct pci_dev *pdev, struct device *dev, return 0; } -int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, +int intel_vsec_add_aux(struct device *parent, struct intel_vsec_device *intel_vsec_dev, const char *name) { @@ -252,7 +260,7 @@ int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, if (ret) goto cleanup_aux; - ret = intel_vsec_link_devices(pdev, &auxdev->dev, intel_vsec_dev->cap_id); + ret = intel_vsec_link_devices(parent, &auxdev->dev, intel_vsec_dev->cap_id); if (ret) goto cleanup_aux; @@ -269,33 +277,32 @@ cleanup_aux: } EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, "INTEL_VSEC"); -static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header, - struct intel_vsec_platform_info *info, - unsigned long cap_id) +static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *header, + const struct intel_vsec_platform_info *info, + unsigned long cap_id, u64 base_addr) { struct intel_vsec_device __free(kfree) *intel_vsec_dev = NULL; struct resource __free(kfree) *res = NULL; struct resource *tmp; struct device *parent; unsigned long quirks = info->quirks; - u64 base_addr; int i; if (info->parent) parent = info->parent; else - parent = &pdev->dev; + parent = dev; if (!intel_vsec_supported(header->id, info->caps)) return -EINVAL; if (!header->num_entries) { - dev_dbg(&pdev->dev, "Invalid 0 entry count for header id %d\n", header->id); + dev_dbg(dev, "Invalid 0 entry count for header id %d\n", header->id); return -EINVAL; } if (!header->entry_size) { - dev_dbg(&pdev->dev, "Invalid 0 entry size for header id %d\n", header->id); + dev_dbg(dev, "Invalid 0 entry size for header id %d\n", header->id); return -EINVAL; } @@ -310,17 +317,19 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he if (quirks & VSEC_QUIRK_TABLE_SHIFT) header->offset >>= TABLE_OFFSET_SHIFT; - if (info->base_addr) - base_addr = info->base_addr; - else - base_addr = pdev->resource[header->tbir].start; - /* * The DVSEC/VSEC contains the starting offset and count for a block of * discovery tables. Create a resource array of these tables to the * auxiliary device driver. */ for (i = 0, tmp = res; i < header->num_entries; i++, tmp++) { + /* + * Skip resource mapping check for ACPI-based discovery + * since those tables are read from _DSD, not MMIO. + */ + if (info->src == INTEL_VSEC_DISC_ACPI) + break; + tmp->start = base_addr + header->offset + i * (header->entry_size * sizeof(u32)); tmp->end = tmp->start + (header->entry_size * sizeof(u32)) - 1; tmp->flags = IORESOURCE_MEM; @@ -332,13 +341,26 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he release_mem_region(tmp->start, resource_size(tmp)); } - intel_vsec_dev->pcidev = pdev; + intel_vsec_dev->dev = dev; intel_vsec_dev->resource = no_free_ptr(res); intel_vsec_dev->num_resources = header->num_entries; intel_vsec_dev->quirks = info->quirks; intel_vsec_dev->base_addr = info->base_addr; intel_vsec_dev->priv_data = info->priv_data; intel_vsec_dev->cap_id = cap_id; + intel_vsec_dev->src = info->src; + + if (info->src == INTEL_VSEC_DISC_ACPI) { + size_t bytes; + + if (check_mul_overflow(intel_vsec_dev->num_resources, + sizeof(*info->acpi_disc), &bytes)) + return -EOVERFLOW; + + intel_vsec_dev->acpi_disc = kmemdup(info->acpi_disc, bytes, GFP_KERNEL); + if (!intel_vsec_dev->acpi_disc) + return -ENOMEM; + } if (header->id == VSEC_ID_SDSI) intel_vsec_dev->ida = &intel_vsec_sdsi_ida; @@ -349,7 +371,7 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he * Pass the ownership of intel_vsec_dev and resource within it to * intel_vsec_add_aux() */ - return intel_vsec_add_aux(pdev, parent, no_free_ptr(intel_vsec_dev), + return intel_vsec_add_aux(parent, no_free_ptr(intel_vsec_dev), intel_vsec_name(header->id)); } @@ -410,12 +432,14 @@ static int get_cap_id(u32 header_id, unsigned long *cap_id) return 0; } -static int intel_vsec_register_device(struct pci_dev *pdev, +static int intel_vsec_register_device(struct device *dev, struct intel_vsec_header *header, - struct intel_vsec_platform_info *info) + const struct intel_vsec_platform_info *info, + u64 base_addr) { const struct vsec_feature_dependency *consumer_deps; struct vsec_priv *priv; + struct pci_dev *pdev; unsigned long cap_id; int ret; @@ -427,8 +451,12 @@ static int intel_vsec_register_device(struct pci_dev *pdev, * Only track dependencies for devices probed by the VSEC driver. * For others using the exported APIs, add the device directly. */ + if (!dev_is_pci(dev)) + return intel_vsec_add_dev(dev, header, info, cap_id, base_addr); + + pdev = to_pci_dev(dev); if (!pci_match_id(intel_vsec_pci_ids, pdev)) - return intel_vsec_add_dev(pdev, header, info, cap_id); + return intel_vsec_add_dev(dev, header, info, cap_id, base_addr); priv = pci_get_drvdata(pdev); if (priv->state[cap_id] == STATE_REGISTERED || @@ -444,7 +472,7 @@ static int intel_vsec_register_device(struct pci_dev *pdev, consumer_deps = get_consumer_dependencies(priv, cap_id); if (!consumer_deps || suppliers_ready(priv, consumer_deps, cap_id)) { - ret = intel_vsec_add_dev(pdev, header, info, cap_id); + ret = intel_vsec_add_dev(dev, header, info, cap_id, base_addr); if (ret) priv->state[cap_id] = STATE_SKIP; else @@ -456,24 +484,23 @@ static int intel_vsec_register_device(struct pci_dev *pdev, return -EAGAIN; } -static bool intel_vsec_walk_header(struct pci_dev *pdev, - struct intel_vsec_platform_info *info) +static int intel_vsec_walk_header(struct device *dev, + const struct intel_vsec_platform_info *info) { struct intel_vsec_header **header = info->headers; - bool have_devices = false; int ret; for ( ; *header; header++) { - ret = intel_vsec_register_device(pdev, *header, info); - if (!ret) - have_devices = true; + ret = intel_vsec_register_device(dev, *header, info, info->base_addr); + if (ret) + return ret; } - return have_devices; + return 0; } static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, - struct intel_vsec_platform_info *info) + const struct intel_vsec_platform_info *info) { bool have_devices = false; int pos = 0; @@ -512,7 +539,8 @@ static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER2, &hdr); header.id = PCI_DVSEC_HEADER2_ID(hdr); - ret = intel_vsec_register_device(pdev, &header, info); + ret = intel_vsec_register_device(&pdev->dev, &header, info, + pci_resource_start(pdev, header.tbir)); if (ret) continue; @@ -523,7 +551,7 @@ static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, } static bool intel_vsec_walk_vsec(struct pci_dev *pdev, - struct intel_vsec_platform_info *info) + const struct intel_vsec_platform_info *info) { bool have_devices = false; int pos = 0; @@ -557,7 +585,8 @@ static bool intel_vsec_walk_vsec(struct pci_dev *pdev, header.tbir = INTEL_DVSEC_TABLE_BAR(table); header.offset = INTEL_DVSEC_TABLE_OFFSET(table); - ret = intel_vsec_register_device(pdev, &header, info); + ret = intel_vsec_register_device(&pdev->dev, &header, info, + pci_resource_start(pdev, header.tbir)); if (ret) continue; @@ -567,21 +596,18 @@ static bool intel_vsec_walk_vsec(struct pci_dev *pdev, return have_devices; } -int intel_vsec_register(struct pci_dev *pdev, - struct intel_vsec_platform_info *info) +int intel_vsec_register(struct device *dev, + const struct intel_vsec_platform_info *info) { - if (!pdev || !info || !info->headers) + if (!dev || !info || !info->headers) return -EINVAL; - if (!intel_vsec_walk_header(pdev, info)) - return -ENODEV; - else - return 0; + return intel_vsec_walk_header(dev, info); } EXPORT_SYMBOL_NS_GPL(intel_vsec_register, "INTEL_VSEC"); static bool intel_vsec_get_features(struct pci_dev *pdev, - struct intel_vsec_platform_info *info) + const struct intel_vsec_platform_info *info) { bool found = false; @@ -599,7 +625,7 @@ static bool intel_vsec_get_features(struct pci_dev *pdev, found = true; if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) && - intel_vsec_walk_header(pdev, info)) + intel_vsec_walk_header(&pdev->dev, info)) found = true; return found; @@ -625,7 +651,7 @@ static void intel_vsec_skip_missing_dependencies(struct pci_dev *pdev) static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct intel_vsec_platform_info *info; + const struct intel_vsec_platform_info *info; struct vsec_priv *priv; int num_caps, ret; int run_once = 0; @@ -636,7 +662,7 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id return ret; pci_save_state(pdev); - info = (struct intel_vsec_platform_info *)id->driver_data; + info = (const struct intel_vsec_platform_info *)id->driver_data; if (!info) return -EINVAL; @@ -671,7 +697,10 @@ int intel_vsec_set_mapping(struct oobmsm_plat_info *plat_info, { struct vsec_priv *priv; - priv = pci_get_drvdata(vsec_dev->pcidev); + if (!dev_is_pci(vsec_dev->dev)) + return -ENODEV; + + priv = pci_get_drvdata(to_pci_dev(vsec_dev->dev)); if (!priv) return -EINVAL; @@ -819,7 +848,7 @@ static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev) xa_for_each(&auxdev_array, index, intel_vsec_dev) { /* check if pdev doesn't match */ - if (pdev != intel_vsec_dev->pcidev) + if (&pdev->dev != intel_vsec_dev->dev) continue; devm_release_action(&pdev->dev, intel_vsec_remove_aux, &intel_vsec_dev->auxdev); diff --git a/drivers/platform/x86/intel/vsec_tpmi.c b/drivers/platform/x86/intel/vsec_tpmi.c index 98846e88d3d0..7fc6ff8d1040 100644 --- a/drivers/platform/x86/intel/vsec_tpmi.c +++ b/drivers/platform/x86/intel/vsec_tpmi.c @@ -46,6 +46,7 @@ * provided by the Intel VSEC driver. */ +#include <linux/align.h> #include <linux/auxiliary_bus.h> #include <linux/bitfield.h> #include <linux/debugfs.h> @@ -479,6 +480,9 @@ static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t l addr = array[2]; value = array[3]; + if (!IS_ALIGNED(addr, sizeof(u32))) + return -EINVAL; + if (punit >= pfs->pfs_header.num_entries) { ret = -EINVAL; goto exit_write; @@ -530,7 +534,7 @@ static const struct file_operations mem_write_ops = { .release = single_release, }; -#define tpmi_to_dev(info) (&info->vsec_dev->pcidev->dev) +#define tpmi_to_dev(info) ((info)->vsec_dev->dev) static void tpmi_dbgfs_register(struct intel_tpmi_info *tpmi_info) { @@ -642,7 +646,7 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info, tmp->flags = IORESOURCE_MEM; } - feature_vsec_dev->pcidev = vsec_dev->pcidev; + feature_vsec_dev->dev = vsec_dev->dev; feature_vsec_dev->resource = res; feature_vsec_dev->num_resources = pfs->pfs_header.num_entries; feature_vsec_dev->priv_data = &tpmi_info->plat_info; @@ -655,7 +659,7 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info, * feature_vsec_dev and res memory are also freed as part of * device deletion. */ - return intel_vsec_add_aux(vsec_dev->pcidev, &vsec_dev->auxdev.dev, + return intel_vsec_add_aux(&vsec_dev->auxdev.dev, feature_vsec_dev, feature_id_name); } @@ -742,7 +746,7 @@ static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, i static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev) { struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); - struct pci_dev *pci_dev = vsec_dev->pcidev; + struct pci_dev *pci_dev = to_pci_dev(vsec_dev->dev); struct intel_tpmi_info *tpmi_info; u64 pfs_start = 0; int ret, i; diff --git a/drivers/platform/x86/intel/wmi/sbl-fw-update.c b/drivers/platform/x86/intel/wmi/sbl-fw-update.c index 3716ccaaed6a..62c9c7f1842b 100644 --- a/drivers/platform/x86/intel/wmi/sbl-fw-update.c +++ b/drivers/platform/x86/intel/wmi/sbl-fw-update.c @@ -28,15 +28,10 @@ static int get_fwu_request(struct device *dev, u32 *out) __le32 *result; int ret; - ret = wmidev_query_block(to_wmi_device(dev), 0, &buffer); + ret = wmidev_query_block(to_wmi_device(dev), 0, &buffer, sizeof(*result)); if (ret < 0) return ret; - if (buffer.length < sizeof(*result)) { - kfree(buffer.data); - return -ENODATA; - } - result = buffer.data; *out = le32_to_cpu(*result); kfree(result); diff --git a/drivers/platform/x86/intel/wmi/thunderbolt.c b/drivers/platform/x86/intel/wmi/thunderbolt.c index 47017f2d7597..9b1920d61674 100644 --- a/drivers/platform/x86/intel/wmi/thunderbolt.c +++ b/drivers/platform/x86/intel/wmi/thunderbolt.c @@ -34,7 +34,7 @@ static ssize_t force_power_store(struct device *dev, if (mode > 1) return -EINVAL; - ret = wmidev_invoke_method(to_wmi_device(dev), 0, 1, &buffer, NULL); + ret = wmidev_invoke_procedure(to_wmi_device(dev), 0, 1, &buffer); if (ret < 0) return ret; diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c index ae1ebb071fab..4fbc904f1fc3 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -2340,6 +2340,7 @@ static struct wmi_driver ideapad_wmi_driver = { .name = "ideapad_wmi", }, .id_table = ideapad_wmi_ids, + .min_event_size = sizeof(u32), .probe = ideapad_wmi_probe, .notify = ideapad_wmi_notify, }; diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c index 8982d92dfd97..e1cee42a1683 100644 --- a/drivers/platform/x86/lenovo/thinkpad_acpi.c +++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c @@ -299,7 +299,6 @@ struct ibm_struct; struct tp_acpi_drv_struct { const struct acpi_device_id *hid; - struct acpi_driver *driver; void (*notify) (struct ibm_struct *, u32); acpi_handle *handle; @@ -322,7 +321,6 @@ struct ibm_struct { struct tp_acpi_drv_struct *acpi; struct { - u8 acpi_driver_registered:1; u8 acpi_notify_installed:1; u8 proc_created:1; u8 init_called:1; @@ -374,7 +372,7 @@ static struct { u32 hotkey_poll_active:1; u32 has_adaptive_kbd:1; u32 kbd_lang:1; - u32 trackpoint_doubletap:1; + u32 trackpoint_doubletap_enable:1; struct quirk_entry *quirks; } tp_features; @@ -832,9 +830,9 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm) vdbg_printk(TPACPI_DBG_INIT, "setting up ACPI notify for %s\n", ibm->name); - ibm->acpi->device = acpi_fetch_acpi_dev(*ibm->acpi->handle); + ibm->acpi->device = acpi_get_acpi_dev(*ibm->acpi->handle); if (!ibm->acpi->device) { - pr_err("acpi_fetch_acpi_dev(%s) failed\n", ibm->name); + pr_err("acpi_get_acpi_dev(%s) failed\n", ibm->name); return -ENODEV; } @@ -859,44 +857,6 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm) return 0; } -static int __init tpacpi_device_add(struct acpi_device *device) -{ - return 0; -} - -static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) -{ - int rc; - - dbg_printk(TPACPI_DBG_INIT, - "registering %s as an ACPI driver\n", ibm->name); - - BUG_ON(!ibm->acpi); - - ibm->acpi->driver = kzalloc_obj(struct acpi_driver); - if (!ibm->acpi->driver) { - pr_err("failed to allocate memory for ibm->acpi->driver\n"); - return -ENOMEM; - } - - sprintf(ibm->acpi->driver->name, "%s_%s", TPACPI_NAME, ibm->name); - ibm->acpi->driver->ids = ibm->acpi->hid; - - ibm->acpi->driver->ops.add = &tpacpi_device_add; - - rc = acpi_bus_register_driver(ibm->acpi->driver); - if (rc < 0) { - pr_err("acpi_bus_register_driver(%s) failed: %d\n", - ibm->name, rc); - kfree(ibm->acpi->driver); - ibm->acpi->driver = NULL; - } else if (!rc) - ibm->flags.acpi_driver_registered = 1; - - return rc; -} - - /**************************************************************************** **************************************************************************** * @@ -1315,7 +1275,7 @@ static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id, static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, struct seq_file *m) { if (id >= TPACPI_RFK_SW_MAX) - seq_printf(m, "status:\t\tnot supported\n"); + seq_puts(m, "status:\t\tnot supported\n"); else { int status; @@ -1330,7 +1290,7 @@ static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, struct seq_file * } seq_printf(m, "status:\t\t%s\n", str_enabled_disabled(status == TPACPI_RFK_RADIO_ON)); - seq_printf(m, "commands:\tenable, disable\n"); + seq_puts(m, "commands:\tenable, disable\n"); } return 0; @@ -3019,6 +2979,31 @@ static const struct attribute_group adaptive_kbd_attr_group = { .attrs = adaptive_kbd_attributes, }; +/* sysfs doubletap enable --------------------------------------------- */ +static ssize_t doubletap_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%d\n", tp_features.trackpoint_doubletap_enable); +} + +static ssize_t doubletap_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + bool enable; + int err; + + err = kstrtobool(buf, &enable); + if (err) + return err; + + tp_features.trackpoint_doubletap_enable = enable; + return count; +} + +static DEVICE_ATTR_RW(doubletap_enable); + /* --------------------------------------------------------------------- */ static struct attribute *hotkey_attributes[] = { @@ -3033,6 +3018,7 @@ static struct attribute *hotkey_attributes[] = { &dev_attr_hotkey_recommended_mask.attr, &dev_attr_hotkey_tablet_mode.attr, &dev_attr_hotkey_radio_sw.attr, + &dev_attr_doubletap_enable.attr, #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL &dev_attr_hotkey_source_mask.attr, &dev_attr_hotkey_poll_freq.attr, @@ -3558,8 +3544,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) hotkey_poll_setup_safe(true); - /* Enable doubletap by default */ - tp_features.trackpoint_doubletap = 1; + /* Enable TrackPoint doubletap event reporting by default. */ + tp_features.trackpoint_doubletap_enable = 1; return 0; } @@ -3864,9 +3850,9 @@ static bool hotkey_notify_8xxx(const u32 hkey, bool *send_acpi_ev) { switch (hkey) { case TP_HKEY_EV_TRACK_DOUBLETAP: - if (tp_features.trackpoint_doubletap) - tpacpi_input_send_key(hkey, send_acpi_ev); - + /* Only send event if doubletap is enabled */ + if (!tp_features.trackpoint_doubletap_enable) + *send_acpi_ev = false; return true; default: return false; @@ -4017,7 +4003,7 @@ static int hotkey_read(struct seq_file *m) int res, status; if (!tp_features.hotkey) { - seq_printf(m, "status:\t\tnot supported\n"); + seq_puts(m, "status:\t\tnot supported\n"); return 0; } @@ -4033,10 +4019,10 @@ static int hotkey_read(struct seq_file *m) seq_printf(m, "status:\t\t%s\n", str_enabled_disabled(status & BIT(0))); if (hotkey_all_mask) { seq_printf(m, "mask:\t\t0x%08x\n", hotkey_user_mask); - seq_printf(m, "commands:\tenable, disable, reset, <mask>\n"); + seq_puts(m, "commands:\tenable, disable, reset, <mask>\n"); } else { - seq_printf(m, "mask:\t\tnot supported\n"); - seq_printf(m, "commands:\tenable, disable, reset\n"); + seq_puts(m, "mask:\t\tnot supported\n"); + seq_puts(m, "commands:\tenable, disable, reset\n"); } return 0; @@ -4933,7 +4919,7 @@ static int video_read(struct seq_file *m) int status, autosw; if (video_supported == TPACPI_VIDEO_NONE) { - seq_printf(m, "status:\t\tnot supported\n"); + seq_puts(m, "status:\t\tnot supported\n"); return 0; } @@ -4949,18 +4935,18 @@ static int video_read(struct seq_file *m) if (autosw < 0) return autosw; - seq_printf(m, "status:\t\tsupported\n"); + seq_puts(m, "status:\t\tsupported\n"); seq_printf(m, "lcd:\t\t%s\n", str_enabled_disabled(status & BIT(0))); seq_printf(m, "crt:\t\t%s\n", str_enabled_disabled(status & BIT(1))); if (video_supported == TPACPI_VIDEO_NEW) seq_printf(m, "dvi:\t\t%s\n", str_enabled_disabled(status & BIT(3))); seq_printf(m, "auto:\t\t%s\n", str_enabled_disabled(autosw & BIT(0))); - seq_printf(m, "commands:\tlcd_enable, lcd_disable\n"); - seq_printf(m, "commands:\tcrt_enable, crt_disable\n"); + seq_puts(m, "commands:\tlcd_enable, lcd_disable\n"); + seq_puts(m, "commands:\tcrt_enable, crt_disable\n"); if (video_supported == TPACPI_VIDEO_NEW) - seq_printf(m, "commands:\tdvi_enable, dvi_disable\n"); - seq_printf(m, "commands:\tauto_enable, auto_disable\n"); - seq_printf(m, "commands:\tvideo_switch, expand_toggle\n"); + seq_puts(m, "commands:\tdvi_enable, dvi_disable\n"); + seq_puts(m, "commands:\tauto_enable, auto_disable\n"); + seq_puts(m, "commands:\tvideo_switch, expand_toggle\n"); return 0; } @@ -5204,14 +5190,14 @@ static int kbdlight_read(struct seq_file *m) int level; if (!tp_features.kbdlight) { - seq_printf(m, "status:\t\tnot supported\n"); + seq_puts(m, "status:\t\tnot supported\n"); } else { level = kbdlight_get_level(); if (level < 0) seq_printf(m, "status:\t\terror %d\n", level); else seq_printf(m, "status:\t\t%d\n", level); - seq_printf(m, "commands:\t0, 1, 2\n"); + seq_puts(m, "commands:\t0, 1, 2\n"); } return 0; @@ -5378,16 +5364,16 @@ static int light_read(struct seq_file *m) int status; if (!tp_features.light) { - seq_printf(m, "status:\t\tnot supported\n"); + seq_puts(m, "status:\t\tnot supported\n"); } else if (!tp_features.light_status) { - seq_printf(m, "status:\t\tunknown\n"); - seq_printf(m, "commands:\ton, off\n"); + seq_puts(m, "status:\t\tunknown\n"); + seq_puts(m, "commands:\ton, off\n"); } else { status = light_get_status(); if (status < 0) return status; seq_printf(m, "status:\t\t%s\n", str_on_off(status & BIT(0))); - seq_printf(m, "commands:\ton, off\n"); + seq_puts(m, "commands:\ton, off\n"); } return 0; @@ -5477,10 +5463,10 @@ static int cmos_read(struct seq_file *m) /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, R30, R31, T20-22, X20-21 */ if (!cmos_handle) - seq_printf(m, "status:\t\tnot supported\n"); + seq_puts(m, "status:\t\tnot supported\n"); else { - seq_printf(m, "status:\t\tsupported\n"); - seq_printf(m, "commands:\t<cmd> (<cmd> is 0-21)\n"); + seq_puts(m, "status:\t\tsupported\n"); + seq_puts(m, "commands:\t<cmd> (<cmd> is 0-21)\n"); } return 0; @@ -5846,10 +5832,10 @@ static int __init led_init(struct ibm_init_struct *iibm) static int led_read(struct seq_file *m) { if (!led_supported) { - seq_printf(m, "status:\t\tnot supported\n"); + seq_puts(m, "status:\t\tnot supported\n"); return 0; } - seq_printf(m, "status:\t\tsupported\n"); + seq_puts(m, "status:\t\tsupported\n"); if (led_supported == TPACPI_LED_570) { /* 570 */ @@ -5862,7 +5848,7 @@ static int led_read(struct seq_file *m) } } - seq_printf(m, "commands:\t<led> on, <led> off, <led> blink (<led> is 0-15)\n"); + seq_puts(m, "commands:\t<led> on, <led> off, <led> blink (<led> is 0-15)\n"); return 0; } @@ -5946,10 +5932,10 @@ static int __init beep_init(struct ibm_init_struct *iibm) static int beep_read(struct seq_file *m) { if (!beep_handle) - seq_printf(m, "status:\t\tnot supported\n"); + seq_puts(m, "status:\t\tnot supported\n"); else { - seq_printf(m, "status:\t\tsupported\n"); - seq_printf(m, "commands:\t<cmd> (<cmd> is 0-17)\n"); + seq_puts(m, "status:\t\tsupported\n"); + seq_puts(m, "commands:\t<cmd> (<cmd> is 0-17)\n"); } return 0; @@ -6398,14 +6384,14 @@ static int thermal_read(struct seq_file *m) if (unlikely(n < 0)) return n; - seq_printf(m, "temperatures:\t"); + seq_puts(m, "temperatures:\t"); if (n > 0) { for (i = 0; i < (n - 1); i++) seq_printf(m, "%d ", t.temp[i] / 1000); seq_printf(m, "%d\n", t.temp[i] / 1000); } else - seq_printf(m, "not supported\n"); + seq_puts(m, "not supported\n"); return 0; } @@ -6918,10 +6904,10 @@ static int brightness_read(struct seq_file *m) level = brightness_get(NULL); if (level < 0) { - seq_printf(m, "level:\t\tunreadable\n"); + seq_puts(m, "level:\t\tunreadable\n"); } else { seq_printf(m, "level:\t\t%d\n", level); - seq_printf(m, "commands:\tup, down\n"); + seq_puts(m, "commands:\tup, down\n"); seq_printf(m, "commands:\tlevel <level> (<level> is 0-%d)\n", bright_maxlvl); } @@ -7637,10 +7623,10 @@ static int volume_read(struct seq_file *m) u8 status; if (volume_get_status(&status) < 0) { - seq_printf(m, "level:\t\tunreadable\n"); + seq_puts(m, "level:\t\tunreadable\n"); } else { if (tp_features.mixer_no_level_control) - seq_printf(m, "level:\t\tunsupported\n"); + seq_puts(m, "level:\t\tunsupported\n"); else seq_printf(m, "level:\t\t%d\n", status & TP_EC_AUDIO_LVL_MSK); @@ -7648,9 +7634,9 @@ static int volume_read(struct seq_file *m) seq_printf(m, "mute:\t\t%s\n", str_on_off(status & BIT(TP_EC_AUDIO_MUTESW))); if (volume_control_allowed) { - seq_printf(m, "commands:\tunmute, mute\n"); + seq_puts(m, "commands:\tunmute, mute\n"); if (!tp_features.mixer_no_level_control) { - seq_printf(m, "commands:\tup, down\n"); + seq_puts(m, "commands:\tup, down\n"); seq_printf(m, "commands:\tlevel <level> (<level> is 0-%d)\n", TP_EC_VOLUME_MAX); } @@ -9156,9 +9142,9 @@ static int fan_read(struct seq_file *m) } else if (fan_status_access_mode == TPACPI_FAN_RD_TPEC) { if (status & TP_EC_FAN_FULLSPEED) /* Disengaged mode takes precedence */ - seq_printf(m, "level:\t\tdisengaged\n"); + seq_puts(m, "level:\t\tdisengaged\n"); else if (status & TP_EC_FAN_AUTO) - seq_printf(m, "level:\t\tauto\n"); + seq_puts(m, "level:\t\tauto\n"); else seq_printf(m, "level:\t\t%d\n", status); } @@ -9166,19 +9152,19 @@ static int fan_read(struct seq_file *m) case TPACPI_FAN_NONE: default: - seq_printf(m, "status:\t\tnot supported\n"); + seq_puts(m, "status:\t\tnot supported\n"); } if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { - seq_printf(m, "commands:\tlevel <level>"); + seq_puts(m, "commands:\tlevel <level>"); switch (fan_control_access_mode) { case TPACPI_FAN_WR_ACPI_SFAN: - seq_printf(m, " (<level> is 0-7)\n"); + seq_puts(m, " (<level> is 0-7)\n"); break; default: - seq_printf(m, " (<level> is 0-7, auto, disengaged, full-speed)\n"); + seq_puts(m, " (<level> is 0-7, auto, disengaged, full-speed)\n"); break; } } @@ -9188,7 +9174,7 @@ static int fan_read(struct seq_file *m) "commands:\twatchdog <timeout> (<timeout> is 0 (off), 1-120 (seconds))\n"); if (fan_control_commands & TPACPI_FAN_CMD_SPEED) - seq_printf(m, "commands:\tspeed <speed> (<speed> is 0-65535)\n"); + seq_puts(m, "commands:\tspeed <speed> (<speed> is 0-65535)\n"); return 0; } @@ -9249,9 +9235,6 @@ static int fan_write_cmd_speed(const char *cmd, int *rc) { int speed; - /* TODO: - * Support speed <low> <medium> <high> ? */ - if (sscanf(cmd, "speed %d", &speed) != 1) return 0; @@ -11488,7 +11471,9 @@ static bool tpacpi_driver_event(const unsigned int hkey_event) mutex_unlock(&tpacpi_inputdev_send_mutex); return true; case TP_HKEY_EV_DOUBLETAP_TOGGLE: - tp_features.trackpoint_doubletap = !tp_features.trackpoint_doubletap; + /* Toggle kernel-level doubletap event filtering */ + tp_features.trackpoint_doubletap_enable = + !tp_features.trackpoint_doubletap_enable; return true; case TP_HKEY_EV_PROFILE_TOGGLE: case TP_HKEY_EV_PROFILE_TOGGLE2: @@ -11532,6 +11517,8 @@ static void ibm_exit(struct ibm_struct *ibm) acpi_remove_notify_handler(*ibm->acpi->handle, ibm->acpi->type, dispatch_acpi_notify); + ibm->acpi->device->driver_data = NULL; + acpi_dev_put(ibm->acpi->device); ibm->flags.acpi_notify_installed = 0; } @@ -11542,16 +11529,6 @@ static void ibm_exit(struct ibm_struct *ibm) ibm->flags.proc_created = 0; } - if (ibm->flags.acpi_driver_registered) { - dbg_printk(TPACPI_DBG_EXIT, - "%s: acpi_bus_unregister_driver\n", ibm->name); - BUG_ON(!ibm->acpi); - acpi_bus_unregister_driver(ibm->acpi->driver); - kfree(ibm->acpi->driver); - ibm->acpi->driver = NULL; - ibm->flags.acpi_driver_registered = 0; - } - if (ibm->flags.init_called && ibm->exit) { ibm->exit(); ibm->flags.init_called = 0; @@ -11587,12 +11564,6 @@ static int __init ibm_init(struct ibm_init_struct *iibm) } if (ibm->acpi) { - if (ibm->acpi->hid) { - ret = register_tpacpi_subdriver(ibm); - if (ret) - goto err_out; - } - if (ibm->acpi->notify) { ret = setup_acpi_notify(ibm); if (ret == -ENODEV) { diff --git a/drivers/platform/x86/lenovo/wmi-camera.c b/drivers/platform/x86/lenovo/wmi-camera.c index eb60fb9a5b3f..89ecbce60bf4 100644 --- a/drivers/platform/x86/lenovo/wmi-camera.c +++ b/drivers/platform/x86/lenovo/wmi-camera.c @@ -134,6 +134,7 @@ static struct wmi_driver lenovo_wmi_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .id_table = lenovo_wmi_id_table, + .min_event_size = sizeof(u8), .no_singleton = true, .probe = lenovo_wmi_probe, .notify = lenovo_wmi_notify, diff --git a/drivers/platform/x86/lenovo/wmi-events.c b/drivers/platform/x86/lenovo/wmi-events.c index 0994cd7dd504..4a6a2c82413a 100644 --- a/drivers/platform/x86/lenovo/wmi-events.c +++ b/drivers/platform/x86/lenovo/wmi-events.c @@ -183,6 +183,7 @@ static struct wmi_driver lwmi_events_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .id_table = lwmi_events_id_table, + .min_event_size = sizeof(u32), .probe = lwmi_events_probe, .notify = lwmi_events_notify, .no_singleton = true, diff --git a/drivers/platform/x86/lenovo/ymc.c b/drivers/platform/x86/lenovo/ymc.c index 470d53e3c9d2..1b73a55f1b89 100644 --- a/drivers/platform/x86/lenovo/ymc.c +++ b/drivers/platform/x86/lenovo/ymc.c @@ -153,6 +153,7 @@ static struct wmi_driver lenovo_ymc_driver = { .name = "lenovo-ymc", }, .id_table = lenovo_ymc_wmi_id_table, + .min_event_size = sizeof(u32), .probe = lenovo_ymc_probe, .notify = lenovo_ymc_notify, }; diff --git a/drivers/platform/x86/lenovo/yogabook.c b/drivers/platform/x86/lenovo/yogabook.c index 69887de36c9b..1a4b2ab1f35d 100644 --- a/drivers/platform/x86/lenovo/yogabook.c +++ b/drivers/platform/x86/lenovo/yogabook.c @@ -411,8 +411,8 @@ static struct wmi_driver yogabook_wmi_driver = { .name = "yogabook-wmi", .pm = pm_sleep_ptr(&yogabook_pm_ops), }, - .no_notify_data = true, .id_table = yogabook_wmi_id_table, + .min_event_size = 0, .probe = yogabook_wmi_probe, .remove = yogabook_wmi_remove, .notify = yogabook_wmi_notify, diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c index 61ef7a218a80..9681412d694b 100644 --- a/drivers/platform/x86/lg-laptop.c +++ b/drivers/platform/x86/lg-laptop.c @@ -271,11 +271,6 @@ static void wmi_input_setup(void) } } -static void acpi_notify(struct acpi_device *device, u32 event) -{ - acpi_handle_debug(device->handle, "notify: %d\n", event); -} - static ssize_t fan_mode_store(struct device *dev, struct device_attribute *attr, const char *buffer, size_t count) @@ -764,8 +759,9 @@ static void lg_laptop_remove_address_space_handler(void *data) &lg_laptop_address_space_handler); } -static int acpi_add(struct acpi_device *device) +static int acpi_probe(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct platform_device_info pdev_info = { .fwnode = acpi_fwnode_handle(device), .name = PLATFORM_NAME, @@ -781,11 +777,11 @@ static int acpi_add(struct acpi_device *device) status = acpi_install_address_space_handler(device->handle, LG_ADDRESS_SPACE_ID, &lg_laptop_address_space_handler, - NULL, &device->dev); + NULL, &pdev->dev); if (ACPI_FAILURE(status)) return -ENODEV; - ret = devm_add_action_or_reset(&device->dev, lg_laptop_remove_address_space_handler, + ret = devm_add_action_or_reset(&pdev->dev, lg_laptop_remove_address_space_handler, device); if (ret < 0) return ret; @@ -879,7 +875,7 @@ out_platform_registered: return ret; } -static void acpi_remove(struct acpi_device *device) +static void acpi_remove(struct platform_device *pdev) { sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group); @@ -899,34 +895,13 @@ static const struct acpi_device_id device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, device_ids); -static struct acpi_driver acpi_driver = { - .name = "LG Gram Laptop Support", - .class = "lg-laptop", - .ids = device_ids, - .ops = { - .add = acpi_add, - .remove = acpi_remove, - .notify = acpi_notify, - }, +static struct platform_driver acpi_driver = { + .probe = acpi_probe, + .remove = acpi_remove, + .driver = { + .name = "LG Gram Laptop Support", + .acpi_match_table = device_ids, + }, }; -static int __init acpi_init(void) -{ - int result; - - result = acpi_bus_register_driver(&acpi_driver); - if (result < 0) { - pr_debug("Error registering driver\n"); - return -ENODEV; - } - - return 0; -} - -static void __exit acpi_exit(void) -{ - acpi_bus_unregister_driver(&acpi_driver); -} - -module_init(acpi_init); -module_exit(acpi_exit); +module_platform_driver(acpi_driver); diff --git a/drivers/platform/x86/mxm-wmi.c b/drivers/platform/x86/mxm-wmi.c index 9a457956025a..dbc5e35ec38b 100644 --- a/drivers/platform/x86/mxm-wmi.c +++ b/drivers/platform/x86/mxm-wmi.c @@ -80,15 +80,3 @@ bool mxm_wmi_supported(void) return guid_valid; } EXPORT_SYMBOL_GPL(mxm_wmi_supported); - -static int __init mxm_wmi_init(void) -{ - return 0; -} - -static void __exit mxm_wmi_exit(void) -{ -} - -module_init(mxm_wmi_init); -module_exit(mxm_wmi_exit); diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index d923ddaa4849..1337f7c49805 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -183,9 +183,9 @@ enum SINF_BITS { SINF_NUM_BATTERIES = 0, }; /* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */ -static int acpi_pcc_hotkey_add(struct acpi_device *device); -static void acpi_pcc_hotkey_remove(struct acpi_device *device); -static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event); +static int acpi_pcc_hotkey_probe(struct platform_device *pdev); +static void acpi_pcc_hotkey_remove(struct platform_device *pdev); +static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data); static const struct acpi_device_id pcc_device_ids[] = { { "MAT0012", 0}, @@ -201,16 +201,14 @@ static int acpi_pcc_hotkey_resume(struct device *dev); #endif static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume); -static struct acpi_driver acpi_pcc_driver = { - .name = ACPI_PCC_DRIVER_NAME, - .class = ACPI_PCC_CLASS, - .ids = pcc_device_ids, - .ops = { - .add = acpi_pcc_hotkey_add, - .remove = acpi_pcc_hotkey_remove, - .notify = acpi_pcc_hotkey_notify, - }, - .drv.pm = &acpi_pcc_hotkey_pm, +static struct platform_driver acpi_pcc_driver = { + .probe = acpi_pcc_hotkey_probe, + .remove = acpi_pcc_hotkey_remove, + .driver = { + .name = ACPI_PCC_DRIVER_NAME, + .acpi_match_table = pcc_device_ids, + .pm = &acpi_pcc_hotkey_pm, + }, }; static const struct key_entry panasonic_keymap[] = { @@ -869,9 +867,9 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) pr_err("Unknown hotkey event: 0x%04llx\n", result); } -static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event) +static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data) { - struct pcc_acpi *pcc = acpi_driver_data(device); + struct pcc_acpi *pcc = data; switch (event) { case HKEY_NOTIFY: @@ -891,7 +889,7 @@ static void pcc_optd_notify(acpi_handle handle, u32 event, void *data) set_optd_power_state(0); } -static int pcc_register_optd_notifier(struct pcc_acpi *pcc, char *node) +static void pcc_register_optd_notifier(struct pcc_acpi *pcc, char *node) { acpi_status status; acpi_handle handle; @@ -904,10 +902,7 @@ static int pcc_register_optd_notifier(struct pcc_acpi *pcc, char *node) pcc_optd_notify, pcc); if (ACPI_FAILURE(status)) pr_err("Failed to register notify on %s\n", node); - } else - return -ENODEV; - - return 0; + } } static void pcc_unregister_optd_notifier(struct pcc_acpi *pcc, char *node) @@ -968,14 +963,7 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc) #ifdef CONFIG_PM_SLEEP static int acpi_pcc_hotkey_resume(struct device *dev) { - struct pcc_acpi *pcc; - - if (!dev) - return -EINVAL; - - pcc = acpi_driver_data(to_acpi_device(dev)); - if (!pcc) - return -EINVAL; + struct pcc_acpi *pcc = acpi_driver_data(ACPI_COMPANION(dev)); if (pcc->num_sifr > SINF_MUTE) acpi_pcc_write_sset(pcc, SINF_MUTE, pcc->mute); @@ -991,15 +979,13 @@ static int acpi_pcc_hotkey_resume(struct device *dev) } #endif -static int acpi_pcc_hotkey_add(struct acpi_device *device) +static int acpi_pcc_hotkey_probe(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct backlight_properties props; struct pcc_acpi *pcc; int num_sifr, result; - if (!device) - return -EINVAL; - num_sifr = acpi_pcc_get_sqty(device); /* @@ -1083,19 +1069,25 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) if (result) goto out_backlight; + result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_pcc_hotkey_notify, pcc); + if (result) + goto out_sysfs; + /* optical drive initialization */ if (ACPI_SUCCESS(check_optd_present())) { pcc->platform = platform_device_register_simple("panasonic", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(pcc->platform)) { result = PTR_ERR(pcc->platform); - goto out_sysfs; + goto out_notify_handler; } result = device_create_file(&pcc->platform->dev, &dev_attr_cdpower); - pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); if (result) goto out_platform; + + pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); } else { pcc->platform = NULL; } @@ -1105,6 +1097,9 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) out_platform: platform_device_unregister(pcc->platform); +out_notify_handler: + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_pcc_hotkey_notify); out_sysfs: sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); out_backlight: @@ -1112,6 +1107,7 @@ out_backlight: out_input: input_unregister_device(pcc->input_dev); out_sinf: + device->driver_data = NULL; kfree(pcc->sinf); out_hotkey: kfree(pcc); @@ -1119,20 +1115,21 @@ out_hotkey: return result; } -static void acpi_pcc_hotkey_remove(struct acpi_device *device) +static void acpi_pcc_hotkey_remove(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct pcc_acpi *pcc = acpi_driver_data(device); - if (!device || !pcc) - return; - i8042_remove_filter(panasonic_i8042_filter); if (pcc->platform) { + pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); platform_device_unregister(pcc->platform); } - pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_pcc_hotkey_notify); sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); @@ -1140,8 +1137,10 @@ static void acpi_pcc_hotkey_remove(struct acpi_device *device) input_unregister_device(pcc->input_dev); + device->driver_data = NULL; + kfree(pcc->sinf); kfree(pcc); } -module_acpi_driver(acpi_pcc_driver); +module_platform_driver(acpi_pcc_driver); diff --git a/drivers/platform/x86/pcengines-apuv2.c b/drivers/platform/x86/pcengines-apuv2.c index 3b086863c6ac..3f19589d1ba0 100644 --- a/drivers/platform/x86/pcengines-apuv2.c +++ b/drivers/platform/x86/pcengines-apuv2.c @@ -294,7 +294,8 @@ static int __init apu_board_init(void) } apu_gpio_pdev = apu_create_pdev(AMD_FCH_GPIO_DRIVER_NAME, - id->driver_data, sizeof(struct amd_fch_gpio_pdata), NULL); + id->driver_data, sizeof(struct amd_fch_gpio_pdata), + &apu2_gpiochip_node); err = PTR_ERR_OR_ZERO(apu_gpio_pdev); if (err) goto err_unregister_swnodes; diff --git a/drivers/platform/x86/redmi-wmi.c b/drivers/platform/x86/redmi-wmi.c index e5cb348e3a39..58898630eda6 100644 --- a/drivers/platform/x86/redmi-wmi.c +++ b/drivers/platform/x86/redmi-wmi.c @@ -141,6 +141,7 @@ static struct wmi_driver redmi_wmi_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .id_table = redmi_wmi_id_table, + .min_event_size = 32, .probe = redmi_wmi_probe, .notify = redmi_wmi_notify, .no_singleton = true, diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index d3e7a52c22a7..b18f00e9082f 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -178,8 +178,7 @@ enum sony_nc_rfkill { static int sony_rfkill_handle; static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; -static int sony_nc_rfkill_setup(struct acpi_device *device, - unsigned int handle); +static int sony_nc_rfkill_setup(struct device *dev, unsigned int handle); static void sony_nc_rfkill_cleanup(void); static void sony_nc_rfkill_update(void); @@ -435,7 +434,7 @@ static void sony_laptop_report_input_event(u8 event) dprintk("unknown input event %.2x\n", event); } -static int sony_laptop_setup_input(struct acpi_device *acpi_device) +static int sony_laptop_setup_input(struct device *parent) { struct input_dev *jog_dev; struct input_dev *key_dev; @@ -468,7 +467,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device) key_dev->name = "Sony Vaio Keys"; key_dev->id.bustype = BUS_ISA; key_dev->id.vendor = PCI_VENDOR_ID_SONY; - key_dev->dev.parent = &acpi_device->dev; + key_dev->dev.parent = parent; /* Initialize the Input Drivers: special keys */ input_set_capability(key_dev, EV_MSC, MSC_SCAN); @@ -497,7 +496,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device) jog_dev->name = "Sony Vaio Jogdial"; jog_dev->id.bustype = BUS_ISA; jog_dev->id.vendor = PCI_VENDOR_ID_SONY; - jog_dev->dev.parent = &acpi_device->dev; + jog_dev->dev.parent = parent; input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE); input_set_capability(jog_dev, EV_REL, REL_WHEEL); @@ -1176,7 +1175,7 @@ enum event_types { KILLSWITCH, GFX_SWITCH }; -static void sony_nc_notify(struct acpi_device *device, u32 event) +static void sony_nc_notify(acpi_handle ah, u32 event, void *data) { u32 real_ev = event; u8 ev_type = 0; @@ -1287,7 +1286,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level, /* * ACPI device */ -static void sony_nc_function_setup(struct acpi_device *device, +static void sony_nc_function_setup(struct device *dev, struct platform_device *pf_device) { unsigned int i, result, bitmask, arg; @@ -1360,7 +1359,7 @@ static void sony_nc_function_setup(struct acpi_device *device, break; case 0x0124: case 0x0135: - result = sony_nc_rfkill_setup(device, handle); + result = sony_nc_rfkill_setup(dev, handle); if (result) pr_err("couldn't set up rfkill support (%d)\n", result); @@ -1600,8 +1599,7 @@ static const struct rfkill_ops sony_rfkill_ops = { .set_block = sony_nc_rfkill_set, }; -static int sony_nc_setup_rfkill(struct acpi_device *device, - enum sony_nc_rfkill nc_type) +static int sony_nc_setup_rfkill(struct device *parent, enum sony_nc_rfkill nc_type) { int err; struct rfkill *rfk; @@ -1631,8 +1629,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device, return -EINVAL; } - rfk = rfkill_alloc(name, &device->dev, type, - &sony_rfkill_ops, (void *)nc_type); + rfk = rfkill_alloc(name, parent, type, &sony_rfkill_ops, (void *)nc_type); if (!rfk) return -ENOMEM; @@ -1692,8 +1689,7 @@ static void sony_nc_rfkill_update(void) } } -static int sony_nc_rfkill_setup(struct acpi_device *device, - unsigned int handle) +static int sony_nc_rfkill_setup(struct device *parent, unsigned int handle) { u64 offset; int i; @@ -1734,18 +1730,18 @@ static int sony_nc_rfkill_setup(struct acpi_device *device, dprintk("Radio devices, found 0x%.2x\n", buffer[i]); if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI]) - sony_nc_setup_rfkill(device, SONY_WIFI); + sony_nc_setup_rfkill(parent, SONY_WIFI); if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) - sony_nc_setup_rfkill(device, SONY_BLUETOOTH); + sony_nc_setup_rfkill(parent, SONY_BLUETOOTH); if (((0xf0 & buffer[i]) == 0x20 || (0xf0 & buffer[i]) == 0x50) && !sony_rfkill_devices[SONY_WWAN]) - sony_nc_setup_rfkill(device, SONY_WWAN); + sony_nc_setup_rfkill(parent, SONY_WWAN); if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) - sony_nc_setup_rfkill(device, SONY_WIMAX); + sony_nc_setup_rfkill(parent, SONY_WIMAX); } return 0; } @@ -3149,8 +3145,9 @@ static void sony_nc_backlight_cleanup(void) backlight_device_unregister(sony_bl_props.dev); } -static int sony_nc_add(struct acpi_device *device) +static int sony_nc_probe(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); acpi_status status; int result = 0; struct sony_nc_value *item; @@ -3184,7 +3181,7 @@ static int sony_nc_add(struct acpi_device *device) } } - result = sony_laptop_setup_input(device); + result = sony_laptop_setup_input(&pdev->dev); if (result) { pr_err("Unable to create input devices\n"); goto outplatform; @@ -3201,7 +3198,7 @@ static int sony_nc_add(struct acpi_device *device) /* retrieve the available handles */ result = sony_nc_handles_setup(sony_pf_device); if (!result) - sony_nc_function_setup(device, sony_pf_device); + sony_nc_function_setup(&pdev->dev, sony_pf_device); } if (acpi_video_get_backlight_type() == acpi_backlight_vendor) @@ -3244,6 +3241,11 @@ static int sony_nc_add(struct acpi_device *device) } } + result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + sony_nc_notify, NULL); + if (result) + goto out_sysfs; + pr_info("SNC setup done.\n"); return 0; @@ -3266,10 +3268,13 @@ outwalk: return result; } -static void sony_nc_remove(struct acpi_device *device) +static void sony_nc_remove(struct platform_device *pdev) { struct sony_nc_value *item; + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, sony_nc_notify); + sony_nc_backlight_cleanup(); sony_nc_acpi_device = NULL; @@ -3297,16 +3302,14 @@ static const struct acpi_device_id sony_nc_device_ids[] = { {"", 0}, }; -static struct acpi_driver sony_nc_driver = { - .name = SONY_NC_DRIVER_NAME, - .class = SONY_NC_CLASS, - .ids = sony_nc_device_ids, - .ops = { - .add = sony_nc_add, - .remove = sony_nc_remove, - .notify = sony_nc_notify, - }, - .drv.pm = &sony_nc_pm, +static struct platform_driver sony_nc_driver = { + .probe = sony_nc_probe, + .remove = sony_nc_remove, + .driver = { + .name = SONY_NC_DRIVER_NAME, + .acpi_match_table = sony_nc_device_ids, + .pm = &sony_nc_pm, + }, }; /*********** SPIC (SNY6001) Device ***********/ @@ -4276,9 +4279,9 @@ end: /* * Disable the spic device by calling its _DIS method */ -static int sony_pic_disable(struct acpi_device *device) +static int sony_pic_disable(struct device *dev) { - acpi_status ret = acpi_evaluate_object(device->handle, "_DIS", NULL, + acpi_status ret = acpi_evaluate_object(ACPI_HANDLE(dev), "_DIS", NULL, NULL); if (ACPI_FAILURE(ret) && ret != AE_NOT_FOUND) @@ -4294,7 +4297,7 @@ static int sony_pic_disable(struct acpi_device *device) * * Call _SRS to set current resources */ -static int sony_pic_enable(struct acpi_device *device, +static int sony_pic_enable(struct device *dev, struct sony_pic_ioport *ioport, struct sony_pic_irq *irq) { acpi_status status; @@ -4376,7 +4379,7 @@ static int sony_pic_enable(struct acpi_device *device, /* Attempt to set the resource */ dprintk("Evaluating _SRS\n"); - status = acpi_set_current_resources(device->handle, &buffer); + status = acpi_set_current_resources(ACPI_HANDLE(dev), &buffer); /* check for total failure */ if (ACPI_FAILURE(status)) { @@ -4465,12 +4468,12 @@ found: * ACPI driver * *****************/ -static void sony_pic_remove(struct acpi_device *device) +static void sony_pic_remove(struct platform_device *pdev) { struct sony_pic_ioport *io, *tmp_io; struct sony_pic_irq *irq, *tmp_irq; - if (sony_pic_disable(device)) { + if (sony_pic_disable(&pdev->dev)) { pr_err("Couldn't disable device\n"); return; } @@ -4504,11 +4507,12 @@ static void sony_pic_remove(struct acpi_device *device) dprintk(SONY_PIC_DRIVER_NAME " removed.\n"); } -static int sony_pic_add(struct acpi_device *device) +static int sony_pic_probe(struct platform_device *pdev) { - int result; + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct sony_pic_ioport *io, *tmp_io; struct sony_pic_irq *irq, *tmp_irq; + int result; spic_dev.acpi_dev = device; strscpy(acpi_device_class(device), "sony/hotkey"); @@ -4523,7 +4527,7 @@ static int sony_pic_add(struct acpi_device *device) } /* setup input devices and helper fifo */ - result = sony_laptop_setup_input(device); + result = sony_laptop_setup_input(&pdev->dev); if (result) { pr_err("Unable to create input devices\n"); goto err_free_resources; @@ -4593,7 +4597,7 @@ static int sony_pic_add(struct acpi_device *device) } /* set resource status _SRS */ - result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); + result = sony_pic_enable(&pdev->dev, spic_dev.cur_ioport, spic_dev.cur_irq); if (result) { pr_err("Couldn't enable device\n"); goto err_free_irq; @@ -4616,7 +4620,7 @@ err_remove_pf: sony_pf_remove(); err_disable_device: - sony_pic_disable(device); + sony_pic_disable(&pdev->dev); err_free_irq: free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); @@ -4652,15 +4656,14 @@ err_free_resources: #ifdef CONFIG_PM_SLEEP static int sony_pic_suspend(struct device *dev) { - if (sony_pic_disable(to_acpi_device(dev))) + if (sony_pic_disable(dev)) return -ENXIO; return 0; } static int sony_pic_resume(struct device *dev) { - sony_pic_enable(to_acpi_device(dev), - spic_dev.cur_ioport, spic_dev.cur_irq); + sony_pic_enable(dev, spic_dev.cur_ioport, spic_dev.cur_irq); return 0; } #endif @@ -4672,15 +4675,14 @@ static const struct acpi_device_id sony_pic_device_ids[] = { {"", 0}, }; -static struct acpi_driver sony_pic_driver = { - .name = SONY_PIC_DRIVER_NAME, - .class = SONY_PIC_CLASS, - .ids = sony_pic_device_ids, - .ops = { - .add = sony_pic_add, - .remove = sony_pic_remove, - }, - .drv.pm = &sony_pic_pm, +static struct platform_driver sony_pic_driver = { + .probe = sony_pic_probe, + .remove = sony_pic_remove, + .driver = { + .name = SONY_PIC_DRIVER_NAME, + .acpi_match_table = sony_pic_device_ids, + .pm = &sony_pic_pm, + }, }; static const struct dmi_system_id sonypi_dmi_table[] __initconst = { @@ -4706,7 +4708,7 @@ static int __init sony_laptop_init(void) int result; if (!no_spic && dmi_check_system(sonypi_dmi_table)) { - result = acpi_bus_register_driver(&sony_pic_driver); + result = platform_driver_register(&sony_pic_driver); if (result) { pr_err("Unable to register SPIC driver\n"); goto out; @@ -4714,7 +4716,7 @@ static int __init sony_laptop_init(void) spic_drv_registered = 1; } - result = acpi_bus_register_driver(&sony_nc_driver); + result = platform_driver_register(&sony_nc_driver); if (result) { pr_err("Unable to register SNC driver\n"); goto out_unregister_pic; @@ -4724,16 +4726,16 @@ static int __init sony_laptop_init(void) out_unregister_pic: if (spic_drv_registered) - acpi_bus_unregister_driver(&sony_pic_driver); + platform_driver_unregister(&sony_pic_driver); out: return result; } static void __exit sony_laptop_exit(void) { - acpi_bus_unregister_driver(&sony_nc_driver); + platform_driver_unregister(&sony_nc_driver); if (spic_drv_registered) - acpi_bus_unregister_driver(&sony_pic_driver); + platform_driver_unregister(&sony_pic_driver); } module_init(sony_laptop_init); diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c index 3da753b3d00d..693cbb461382 100644 --- a/drivers/platform/x86/system76_acpi.c +++ b/drivers/platform/x86/system76_acpi.c @@ -18,6 +18,7 @@ #include <linux/leds.h> #include <linux/module.h> #include <linux/pci_ids.h> +#include <linux/platform_device.h> #include <linux/power_supply.h> #include <linux/sysfs.h> #include <linux/types.h> @@ -644,11 +645,10 @@ static void input_key(struct system76_data *data, unsigned int code) } // Handle ACPI notification -static void system76_notify(struct acpi_device *acpi_dev, u32 event) +static void system76_notify(acpi_handle handle, u32 event, void *context) { - struct system76_data *data; + struct system76_data *data = context; - data = acpi_driver_data(acpi_dev); switch (event) { case 0x80: kb_led_hotkey_hardware(data); @@ -671,16 +671,19 @@ static void system76_notify(struct acpi_device *acpi_dev, u32 event) } } -// Add a System76 ACPI device -static int system76_add(struct acpi_device *acpi_dev) +// Probe a System76 platform device +static int system76_probe(struct platform_device *pdev) { + struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev); struct system76_data *data; int err; - data = devm_kzalloc(&acpi_dev->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - acpi_dev->driver_data = data; + + platform_set_drvdata(pdev, data); + data->acpi_dev = acpi_dev; // Some models do not run open EC firmware. Check for an ACPI method @@ -696,7 +699,7 @@ static int system76_add(struct acpi_device *acpi_dev) data->ap_led.brightness_set_blocking = ap_led_set; data->ap_led.max_brightness = 1; data->ap_led.default_trigger = "rfkill-none"; - err = devm_led_classdev_register(&acpi_dev->dev, &data->ap_led); + err = devm_led_classdev_register(&pdev->dev, &data->ap_led); if (err) return err; @@ -740,24 +743,29 @@ static int system76_add(struct acpi_device *acpi_dev) } if (data->kbled_type != KBLED_NONE) { - err = devm_led_classdev_register(&acpi_dev->dev, &data->kb_led); + err = devm_led_classdev_register(&pdev->dev, &data->kb_led); if (err) return err; } - data->input = devm_input_allocate_device(&acpi_dev->dev); + data->input = devm_input_allocate_device(&pdev->dev); if (!data->input) return -ENOMEM; data->input->name = "System76 ACPI Hotkeys"; data->input->phys = "system76_acpi/input0"; data->input->id.bustype = BUS_HOST; - data->input->dev.parent = &acpi_dev->dev; + data->input->dev.parent = &pdev->dev; input_set_capability(data->input, EV_KEY, KEY_SCREENLOCK); err = input_register_device(data->input); if (err) - goto error; + return err; + + err = acpi_dev_install_notify_handler(acpi_dev, ACPI_DEVICE_NOTIFY, + system76_notify, data); + if (err) + return err; if (data->has_open_ec) { err = system76_get_object(data, "NFAN", &data->nfan); @@ -768,7 +776,7 @@ static int system76_add(struct acpi_device *acpi_dev) if (err) goto error; - data->therm = devm_hwmon_device_register_with_info(&acpi_dev->dev, + data->therm = devm_hwmon_device_register_with_info(&pdev->dev, "system76_acpi", data, &thermal_chip_info, NULL); err = PTR_ERR_OR_ZERO(data->therm); if (err) @@ -784,15 +792,14 @@ error: kfree(data->ntmp); kfree(data->nfan); } + acpi_dev_remove_notify_handler(acpi_dev, ACPI_DEVICE_NOTIFY, system76_notify); return err; } -// Remove a System76 ACPI device -static void system76_remove(struct acpi_device *acpi_dev) +// Remove a System76 platform device +static void system76_remove(struct platform_device *pdev) { - struct system76_data *data; - - data = acpi_driver_data(acpi_dev); + struct system76_data *data = platform_get_drvdata(pdev); if (data->has_open_ec) { system76_battery_exit(); @@ -800,23 +807,21 @@ static void system76_remove(struct acpi_device *acpi_dev) kfree(data->ntmp); } - devm_led_classdev_unregister(&acpi_dev->dev, &data->ap_led); - devm_led_classdev_unregister(&acpi_dev->dev, &data->kb_led); + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, system76_notify); system76_get(data, "FINI"); } -static struct acpi_driver system76_driver = { - .name = "System76 ACPI Driver", - .class = "hotkey", - .ids = device_ids, - .ops = { - .add = system76_add, - .remove = system76_remove, - .notify = system76_notify, +static struct platform_driver system76_driver = { + .probe = system76_probe, + .remove = system76_remove, + .driver = { + .name = "System76 ACPI Driver", + .acpi_match_table = device_ids, }, }; -module_acpi_driver(system76_driver); +module_platform_driver(system76_driver); MODULE_DESCRIPTION("System76 ACPI Driver"); MODULE_AUTHOR("Jeremy Soller <jeremy@system76.com>"); diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c index a7b4b6c8e549..e09d7f8ce45f 100644 --- a/drivers/platform/x86/topstar-laptop.c +++ b/drivers/platform/x86/topstar-laptop.c @@ -232,9 +232,9 @@ static int topstar_acpi_fncx_switch(struct acpi_device *device, bool state) return 0; } -static void topstar_acpi_notify(struct acpi_device *device, u32 event) +static void topstar_acpi_notify(acpi_handle handle, u32 event, void *data) { - struct topstar_laptop *topstar = acpi_driver_data(device); + struct topstar_laptop *topstar = data; static bool dup_evnt[2]; bool *dup; @@ -285,8 +285,9 @@ static const struct dmi_system_id topstar_dmi_ids[] = { {} }; -static int topstar_acpi_add(struct acpi_device *device) +static int topstar_acpi_probe(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct topstar_laptop *topstar; int err; @@ -296,9 +297,10 @@ static int topstar_acpi_add(struct acpi_device *device) if (!topstar) return -ENOMEM; + platform_set_drvdata(pdev, topstar); + strscpy(acpi_device_name(device), "Topstar TPSACPI"); strscpy(acpi_device_class(device), TOPSTAR_LAPTOP_CLASS); - device->driver_data = topstar; topstar->device = device; err = topstar_acpi_init(topstar); @@ -313,14 +315,21 @@ static int topstar_acpi_add(struct acpi_device *device) if (err) goto err_platform_exit; + err = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + topstar_acpi_notify, topstar); + if (err) + goto err_input_exit; + if (led_workaround) { err = topstar_led_init(topstar); if (err) - goto err_input_exit; + goto err_notify_handler_exit; } return 0; +err_notify_handler_exit: + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, topstar_acpi_notify); err_input_exit: topstar_input_exit(topstar); err_platform_exit: @@ -332,13 +341,15 @@ err_free: return err; } -static void topstar_acpi_remove(struct acpi_device *device) +static void topstar_acpi_remove(struct platform_device *pdev) { - struct topstar_laptop *topstar = acpi_driver_data(device); + struct topstar_laptop *topstar = platform_get_drvdata(pdev); if (led_workaround) topstar_led_exit(topstar); + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, topstar_acpi_notify); topstar_input_exit(topstar); topstar_platform_exit(topstar); topstar_acpi_exit(topstar); @@ -353,14 +364,12 @@ static const struct acpi_device_id topstar_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, topstar_device_ids); -static struct acpi_driver topstar_acpi_driver = { - .name = "Topstar laptop ACPI driver", - .class = TOPSTAR_LAPTOP_CLASS, - .ids = topstar_device_ids, - .ops = { - .add = topstar_acpi_add, - .remove = topstar_acpi_remove, - .notify = topstar_acpi_notify, +static struct platform_driver topstar_acpi_driver = { + .probe = topstar_acpi_probe, + .remove = topstar_acpi_remove, + .driver = { + .name = "Topstar laptop ACPI driver", + .acpi_match_table = topstar_device_ids, }, }; @@ -372,7 +381,7 @@ static int __init topstar_laptop_init(void) if (ret < 0) return ret; - ret = acpi_bus_register_driver(&topstar_acpi_driver); + ret = platform_driver_register(&topstar_acpi_driver); if (ret < 0) goto err_driver_unreg; @@ -386,7 +395,7 @@ err_driver_unreg: static void __exit topstar_laptop_exit(void) { - acpi_bus_unregister_driver(&topstar_acpi_driver); + platform_driver_unregister(&topstar_acpi_driver); platform_driver_unregister(&topstar_platform_driver); } diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 18fb558115aa..35d899c01740 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -44,6 +44,7 @@ #include <linux/rfkill.h> #include <linux/hwmon.h> #include <linux/iio/iio.h> +#include <linux/platform_device.h> #include <linux/toshiba.h> #include <acpi/battery.h> #include <acpi/video.h> @@ -223,6 +224,7 @@ struct toshiba_acpi_dev { unsigned int cooling_method_supported:1; unsigned int battery_charge_mode_supported:1; unsigned int sysfs_created:1; + unsigned int notify_handler_installed:1; unsigned int special_functions; bool kbd_event_generated; @@ -3193,14 +3195,80 @@ static void print_supported_features(struct toshiba_acpi_dev *dev) pr_cont("\n"); } -static void toshiba_acpi_remove(struct acpi_device *acpi_dev) +static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *data) { - struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); + struct toshiba_acpi_dev *dev = data; + struct acpi_device *acpi_dev = dev->acpi_dev; + + switch (event) { + case 0x80: /* Hotkeys and some system events */ + /* + * Machines with this WMI GUID aren't supported due to bugs in + * their AML. + * + * Return silently to avoid triggering a netlink event. + */ + if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) + return; + toshiba_acpi_process_hotkeys(dev); + break; + case 0x81: /* Dock events */ + case 0x82: + case 0x83: + pr_info("Dock event received %x\n", event); + break; + case 0x88: /* Thermal events */ + pr_info("Thermal event received\n"); + break; + case 0x8f: /* LID closed */ + case 0x90: /* LID is closed and Dock has been ejected */ + break; + case 0x8c: /* SATA power events */ + case 0x8b: + pr_info("SATA power event received %x\n", event); + break; + case 0x92: /* Keyboard backlight mode changed */ + dev->kbd_event_generated = true; + /* Update sysfs entries */ + if (sysfs_update_group(&acpi_dev->dev.kobj, + &toshiba_attr_group)) + pr_err("Unable to update sysfs entries\n"); + /* Notify LED subsystem about keyboard backlight change */ + if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO) + led_classdev_notify_brightness_hw_changed(&dev->kbd_led, + (dev->kbd_mode == SCI_KBD_MODE_ON) ? + LED_FULL : LED_OFF); + break; + case 0x8e: /* Power button pressed */ + break; + case 0x85: /* Unknown */ + case 0x8d: /* Unknown */ + case 0x94: /* Unknown */ + case 0x95: /* Unknown */ + default: + pr_info("Unknown event received %x\n", event); + break; + } + + acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, + dev_name(&acpi_dev->dev), + event, (event == 0x80) ? + dev->last_key_event : 0); +} + +static void toshiba_acpi_remove(struct platform_device *pdev) +{ + struct toshiba_acpi_dev *dev = platform_get_drvdata(pdev); misc_deregister(&dev->miscdev); remove_toshiba_proc_entries(dev); + if (dev->notify_handler_installed) + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, + toshiba_acpi_notify); + #if IS_ENABLED(CONFIG_HWMON) if (dev->hwmon_device) hwmon_device_unregister(dev->hwmon_device); @@ -3240,6 +3308,8 @@ static void toshiba_acpi_remove(struct acpi_device *acpi_dev) if (toshiba_acpi) toshiba_acpi = NULL; + dev_set_drvdata(&dev->acpi_dev->dev, NULL); + kfree(dev); } @@ -3302,8 +3372,9 @@ static const struct dmi_system_id toshiba_dmi_quirks[] __initconst = { { } }; -static int toshiba_acpi_add(struct acpi_device *acpi_dev) +static int toshiba_acpi_probe(struct platform_device *pdev) { + struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev); struct toshiba_acpi_dev *dev; const char *hci_method; u32 dummy; @@ -3337,7 +3408,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) return ret; } - acpi_dev->driver_data = dev; + platform_set_drvdata(pdev, dev); dev_set_drvdata(&acpi_dev->dev, dev); /* Query the BIOS for supported features */ @@ -3368,7 +3439,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) dev->led_dev.max_brightness = 1; dev->led_dev.brightness_set = toshiba_illumination_set; dev->led_dev.brightness_get = toshiba_illumination_get; - led_classdev_register(&acpi_dev->dev, &dev->led_dev); + led_classdev_register(&pdev->dev, &dev->led_dev); } toshiba_eco_mode_available(dev); @@ -3377,7 +3448,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) dev->eco_led.max_brightness = 1; dev->eco_led.brightness_set = toshiba_eco_mode_set_status; dev->eco_led.brightness_get = toshiba_eco_mode_get_status; - led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led); + led_classdev_register(&pdev->dev, &dev->eco_led); } toshiba_kbd_illum_available(dev); @@ -3393,7 +3464,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) dev->kbd_led.max_brightness = 1; dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; - led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led); + led_classdev_register(&pdev->dev, &dev->kbd_led); } ret = toshiba_touchpad_get(dev, &dummy); @@ -3401,7 +3472,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) toshiba_accelerometer_available(dev); if (dev->accelerometer_supported) { - dev->indio_dev = iio_device_alloc(&acpi_dev->dev, sizeof(*dev)); + dev->indio_dev = iio_device_alloc(&pdev->dev, sizeof(*dev)); if (!dev->indio_dev) { pr_err("Unable to allocate iio device\n"); goto iio_error; @@ -3450,7 +3521,7 @@ iio_error: #if IS_ENABLED(CONFIG_HWMON) if (dev->fan_rpm_supported) { dev->hwmon_device = hwmon_device_register_with_info( - &dev->acpi_dev->dev, "toshiba_acpi_sensors", NULL, + &pdev->dev, "toshiba_acpi_sensors", NULL, &toshiba_acpi_hwmon_chip_info, NULL); if (IS_ERR(dev->hwmon_device)) { dev->hwmon_device = NULL; @@ -3477,6 +3548,13 @@ iio_error: } dev->sysfs_created = !ret; + ret = acpi_dev_install_notify_handler(acpi_dev, ACPI_DEVICE_NOTIFY, + toshiba_acpi_notify, dev); + if (ret) + goto error; + + dev->notify_handler_installed = 1; + create_toshiba_proc_entries(dev); toshiba_acpi = dev; @@ -3491,74 +3569,14 @@ iio_error: return 0; error: - toshiba_acpi_remove(acpi_dev); + toshiba_acpi_remove(pdev); return ret; } -static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) -{ - struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); - - switch (event) { - case 0x80: /* Hotkeys and some system events */ - /* - * Machines with this WMI GUID aren't supported due to bugs in - * their AML. - * - * Return silently to avoid triggering a netlink event. - */ - if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) - return; - toshiba_acpi_process_hotkeys(dev); - break; - case 0x81: /* Dock events */ - case 0x82: - case 0x83: - pr_info("Dock event received %x\n", event); - break; - case 0x88: /* Thermal events */ - pr_info("Thermal event received\n"); - break; - case 0x8f: /* LID closed */ - case 0x90: /* LID is closed and Dock has been ejected */ - break; - case 0x8c: /* SATA power events */ - case 0x8b: - pr_info("SATA power event received %x\n", event); - break; - case 0x92: /* Keyboard backlight mode changed */ - dev->kbd_event_generated = true; - /* Update sysfs entries */ - if (sysfs_update_group(&acpi_dev->dev.kobj, - &toshiba_attr_group)) - pr_err("Unable to update sysfs entries\n"); - /* Notify LED subsystem about keyboard backlight change */ - if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO) - led_classdev_notify_brightness_hw_changed(&dev->kbd_led, - (dev->kbd_mode == SCI_KBD_MODE_ON) ? - LED_FULL : LED_OFF); - break; - case 0x8e: /* Power button pressed */ - break; - case 0x85: /* Unknown */ - case 0x8d: /* Unknown */ - case 0x94: /* Unknown */ - case 0x95: /* Unknown */ - default: - pr_info("Unknown event received %x\n", event); - break; - } - - acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, - dev_name(&acpi_dev->dev), - event, (event == 0x80) ? - dev->last_key_event : 0); -} - #ifdef CONFIG_PM_SLEEP static int toshiba_acpi_suspend(struct device *device) { - struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); + struct toshiba_acpi_dev *dev = dev_get_drvdata(device); if (dev->hotkey_dev) { u32 result; @@ -3573,7 +3591,7 @@ static int toshiba_acpi_suspend(struct device *device) static int toshiba_acpi_resume(struct device *device) { - struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); + struct toshiba_acpi_dev *dev = dev_get_drvdata(device); if (dev->hotkey_dev) { if (toshiba_acpi_enable_hotkeys(dev)) @@ -3595,16 +3613,14 @@ static int toshiba_acpi_resume(struct device *device) static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, toshiba_acpi_suspend, toshiba_acpi_resume); -static struct acpi_driver toshiba_acpi_driver = { - .name = "Toshiba ACPI driver", - .ids = toshiba_device_ids, - .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, - .ops = { - .add = toshiba_acpi_add, - .remove = toshiba_acpi_remove, - .notify = toshiba_acpi_notify, +static struct platform_driver toshiba_acpi_driver = { + .probe = toshiba_acpi_probe, + .remove = toshiba_acpi_remove, + .driver = { + .name = "Toshiba ACPI driver", + .acpi_match_table = toshiba_device_ids, + .pm = &toshiba_acpi_pm, }, - .drv.pm = &toshiba_acpi_pm, }; static void __init toshiba_dmi_init(void) @@ -3634,7 +3650,7 @@ static int __init toshiba_acpi_init(void) return -ENODEV; } - ret = acpi_bus_register_driver(&toshiba_acpi_driver); + ret = platform_driver_register(&toshiba_acpi_driver); if (ret) { pr_err("Failed to register ACPI driver: %d\n", ret); remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); @@ -3645,7 +3661,7 @@ static int __init toshiba_acpi_init(void) static void __exit toshiba_acpi_exit(void) { - acpi_bus_unregister_driver(&toshiba_acpi_driver); + platform_driver_unregister(&toshiba_acpi_driver); if (toshiba_proc_dir) remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); } diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c index e587beef05b9..e50d4fc1e603 100644 --- a/drivers/platform/x86/toshiba_bluetooth.c +++ b/drivers/platform/x86/toshiba_bluetooth.c @@ -17,6 +17,7 @@ #include <linux/types.h> #include <linux/acpi.h> #include <linux/rfkill.h> +#include <linux/platform_device.h> #define BT_KILLSWITCH_MASK 0x01 #define BT_PLUGGED_MASK 0x40 @@ -35,9 +36,9 @@ struct toshiba_bluetooth_dev { bool powered; }; -static int toshiba_bt_rfkill_add(struct acpi_device *device); -static void toshiba_bt_rfkill_remove(struct acpi_device *device); -static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event); +static int toshiba_bt_rfkill_probe(struct platform_device *pdev); +static void toshiba_bt_rfkill_remove(struct platform_device *pdev); +static void toshiba_bt_rfkill_notify(acpi_handle handle, u32 event, void *data); static const struct acpi_device_id bt_device_ids[] = { { "TOS6205", 0}, @@ -50,16 +51,14 @@ static int toshiba_bt_resume(struct device *dev); #endif static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume); -static struct acpi_driver toshiba_bt_rfkill_driver = { - .name = "Toshiba BT", - .class = "Toshiba", - .ids = bt_device_ids, - .ops = { - .add = toshiba_bt_rfkill_add, - .remove = toshiba_bt_rfkill_remove, - .notify = toshiba_bt_rfkill_notify, - }, - .drv.pm = &toshiba_bt_pm, +static struct platform_driver toshiba_bt_rfkill_driver = { + .probe = toshiba_bt_rfkill_probe, + .remove = toshiba_bt_rfkill_remove, + .driver = { + .name = "Toshiba BT", + .acpi_match_table = bt_device_ids, + .pm = &toshiba_bt_pm, + }, }; static int toshiba_bluetooth_present(acpi_handle handle) @@ -203,9 +202,9 @@ static const struct rfkill_ops rfk_ops = { }; /* ACPI driver functions */ -static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) +static void toshiba_bt_rfkill_notify(acpi_handle handle, u32 event, void *data) { - struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device); + struct toshiba_bluetooth_dev *bt_dev = data; if (toshiba_bluetooth_sync_status(bt_dev)) return; @@ -216,11 +215,9 @@ static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) #ifdef CONFIG_PM_SLEEP static int toshiba_bt_resume(struct device *dev) { - struct toshiba_bluetooth_dev *bt_dev; + struct toshiba_bluetooth_dev *bt_dev = dev_get_drvdata(dev); int ret; - bt_dev = acpi_driver_data(to_acpi_device(dev)); - ret = toshiba_bluetooth_sync_status(bt_dev); if (ret) return ret; @@ -231,8 +228,9 @@ static int toshiba_bt_resume(struct device *dev) } #endif -static int toshiba_bt_rfkill_add(struct acpi_device *device) +static int toshiba_bt_rfkill_probe(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct toshiba_bluetooth_dev *bt_dev; int result; @@ -246,8 +244,8 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device) if (!bt_dev) return -ENOMEM; bt_dev->acpi_dev = device; - device->driver_data = bt_dev; - dev_set_drvdata(&device->dev, bt_dev); + + platform_set_drvdata(pdev, bt_dev); result = toshiba_bluetooth_sync_status(bt_dev); if (result) { @@ -256,14 +254,14 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device) } bt_dev->rfk = rfkill_alloc("Toshiba Bluetooth", - &device->dev, + &pdev->dev, RFKILL_TYPE_BLUETOOTH, &rfk_ops, bt_dev); if (!bt_dev->rfk) { pr_err("Unable to allocate rfkill device\n"); - kfree(bt_dev); - return -ENOMEM; + result = -ENOMEM; + goto err_free_bt_dev; } rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch); @@ -271,18 +269,36 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device) result = rfkill_register(bt_dev->rfk); if (result) { pr_err("Unable to register rfkill device\n"); - rfkill_destroy(bt_dev->rfk); - kfree(bt_dev); + goto err_rfkill_destroy; } + result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + toshiba_bt_rfkill_notify, bt_dev); + if (result) { + pr_err("Unable to register ACPI notify handler\n"); + goto err_rfkill_unregister; + } + + return 0; + +err_rfkill_unregister: + rfkill_unregister(bt_dev->rfk); +err_rfkill_destroy: + rfkill_destroy(bt_dev->rfk); +err_free_bt_dev: + kfree(bt_dev); return result; } -static void toshiba_bt_rfkill_remove(struct acpi_device *device) +static void toshiba_bt_rfkill_remove(struct platform_device *pdev) { - struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device); + struct toshiba_bluetooth_dev *bt_dev = platform_get_drvdata(pdev); + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); /* clean up */ + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, + toshiba_bt_rfkill_notify); + if (bt_dev->rfk) { rfkill_unregister(bt_dev->rfk); rfkill_destroy(bt_dev->rfk); @@ -293,4 +309,4 @@ static void toshiba_bt_rfkill_remove(struct acpi_device *device) toshiba_bluetooth_disable(device->handle); } -module_acpi_driver(toshiba_bt_rfkill_driver); +module_platform_driver(toshiba_bt_rfkill_driver); diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c index e9324bf16aea..1486252b5983 100644 --- a/drivers/platform/x86/toshiba_haps.c +++ b/drivers/platform/x86/toshiba_haps.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/acpi.h> +#include <linux/platform_device.h> MODULE_AUTHOR("Azael Avalos <coproscefalo@gmail.com>"); MODULE_DESCRIPTION("Toshiba HDD Active Protection Sensor"); @@ -129,8 +130,10 @@ static const struct attribute_group haps_attr_group = { /* * ACPI stuff */ -static void toshiba_haps_notify(struct acpi_device *device, u32 event) +static void toshiba_haps_notify(acpi_handle handle, u32 event, void *data) { + struct acpi_device *device = data; + pr_debug("Received event: 0x%x\n", event); acpi_bus_generate_netlink_event(device->pnp.device_class, @@ -138,12 +141,19 @@ static void toshiba_haps_notify(struct acpi_device *device, u32 event) event, 0); } -static void toshiba_haps_remove(struct acpi_device *device) +static void toshiba_haps_remove(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); + + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, + toshiba_haps_notify); + sysfs_remove_group(&device->dev.kobj, &haps_attr_group); if (toshiba_haps) toshiba_haps = NULL; + + dev_set_drvdata(&device->dev, NULL); } /* Helper function */ @@ -170,8 +180,9 @@ static int toshiba_haps_available(acpi_handle handle) return 1; } -static int toshiba_haps_add(struct acpi_device *acpi_dev) +static int toshiba_haps_probe(struct platform_device *pdev) { + struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev); struct toshiba_haps_dev *haps; int ret; @@ -183,14 +194,15 @@ static int toshiba_haps_add(struct acpi_device *acpi_dev) pr_info("Toshiba HDD Active Protection Sensor device\n"); - haps = devm_kzalloc(&acpi_dev->dev, sizeof(*haps), GFP_KERNEL); + haps = devm_kzalloc(&pdev->dev, sizeof(*haps), GFP_KERNEL); if (!haps) return -ENOMEM; haps->acpi_dev = acpi_dev; haps->protection_level = 2; - acpi_dev->driver_data = haps; + dev_set_drvdata(&acpi_dev->dev, haps); + platform_set_drvdata(pdev, haps); /* Set the protection level, currently at level 2 (Medium) */ ret = toshiba_haps_protection_level(acpi_dev->handle, 2); @@ -201,19 +213,26 @@ static int toshiba_haps_add(struct acpi_device *acpi_dev) if (ret) return ret; + ret = acpi_dev_install_notify_handler(acpi_dev, ACPI_DEVICE_NOTIFY, + toshiba_haps_notify, acpi_dev); + if (ret) + goto err; + toshiba_haps = haps; return 0; + +err: + sysfs_remove_group(&acpi_dev->dev.kobj, &haps_attr_group); + return ret; } #ifdef CONFIG_PM_SLEEP static int toshiba_haps_suspend(struct device *device) { - struct toshiba_haps_dev *haps; + struct toshiba_haps_dev *haps = dev_get_drvdata(device); int ret; - haps = acpi_driver_data(to_acpi_device(device)); - /* Deactivate the protection on suspend */ ret = toshiba_haps_protection_level(haps->acpi_dev->handle, 0); @@ -222,11 +241,9 @@ static int toshiba_haps_suspend(struct device *device) static int toshiba_haps_resume(struct device *device) { - struct toshiba_haps_dev *haps; + struct toshiba_haps_dev *haps = dev_get_drvdata(device); int ret; - haps = acpi_driver_data(to_acpi_device(device)); - /* Set the stored protection level */ ret = toshiba_haps_protection_level(haps->acpi_dev->handle, haps->protection_level); @@ -249,16 +266,14 @@ static const struct acpi_device_id haps_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, haps_device_ids); -static struct acpi_driver toshiba_haps_driver = { - .name = "Toshiba HAPS", - .ids = haps_device_ids, - .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, - .ops = { - .add = toshiba_haps_add, - .remove = toshiba_haps_remove, - .notify = toshiba_haps_notify, +static struct platform_driver toshiba_haps_driver = { + .probe = toshiba_haps_probe, + .remove = toshiba_haps_remove, + .driver = { + .name = "Toshiba HAPS", + .acpi_match_table = haps_device_ids, + .pm = &toshiba_haps_pm, }, - .drv.pm = &toshiba_haps_pm, }; -module_acpi_driver(toshiba_haps_driver); +module_platform_driver(toshiba_haps_driver); diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c index 6341dca20b76..945df5092637 100644 --- a/drivers/platform/x86/uniwill/uniwill-acpi.c +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c @@ -110,6 +110,8 @@ #define EC_ADDR_BAT_CYCLE_COUNT_2 0x04A7 #define EC_ADDR_PROJECT_ID 0x0740 +#define PROJECT_ID_PH4TRX1 0x12 +#define PROJECT_ID_PH6TRX1 0x15 #define EC_ADDR_AP_OEM 0x0741 #define ENABLE_MANUAL_CTRL BIT(0) @@ -266,8 +268,8 @@ #define BATTERY_CHARGE_FULL_OVER_24H BIT(3) #define BATTERY_ERM_STATUS_REACHED BIT(4) -#define EC_ADDR_CHARGE_PRIO 0x07CC -#define CHARGING_PERFORMANCE BIT(7) +#define EC_ADDR_USB_C_POWER_PRIORITY 0x07CC +#define USB_C_POWER_PRIORITY BIT(7) /* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */ #define EC_ADDR_LIGHTBAR_BAT_CTRL 0x07E2 @@ -319,8 +321,17 @@ #define UNIWILL_FEATURE_TOUCHPAD_TOGGLE BIT(2) #define UNIWILL_FEATURE_LIGHTBAR BIT(3) #define UNIWILL_FEATURE_BATTERY BIT(4) -#define UNIWILL_FEATURE_HWMON BIT(5) -#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL BIT(6) +#define UNIWILL_FEATURE_CPU_TEMP BIT(5) +#define UNIWILL_FEATURE_GPU_TEMP BIT(6) +#define UNIWILL_FEATURE_PRIMARY_FAN BIT(7) +#define UNIWILL_FEATURE_SECONDARY_FAN BIT(8) +#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL BIT(9) +#define UNIWILL_FEATURE_USB_C_POWER_PRIORITY BIT(10) + +enum usb_c_power_priority_options { + USB_C_POWER_PRIORITY_CHARGING = 0, + USB_C_POWER_PRIORITY_PERFORMANCE, +}; struct uniwill_data { struct device *dev; @@ -340,6 +351,8 @@ struct uniwill_data { struct mutex input_lock; /* Protects input sequence during notify */ struct input_dev *input_device; struct notifier_block nb; + struct mutex usb_c_power_priority_lock; /* Protects dependent bit write and state safe */ + enum usb_c_power_priority_options last_usb_c_power_priority_option; }; struct uniwill_battery_entry { @@ -427,7 +440,7 @@ static const struct key_entry uniwill_keymap[] = { { KE_END } }; -static inline bool uniwill_device_supports(struct uniwill_data *data, +static inline bool uniwill_device_supports(const struct uniwill_data *data, unsigned int features) { return (data->features & features) == features; @@ -524,6 +537,7 @@ static bool uniwill_writeable_reg(struct device *dev, unsigned int reg) case EC_ADDR_CTGP_DB_CTGP_OFFSET: case EC_ADDR_CTGP_DB_TPP_OFFSET: case EC_ADDR_CTGP_DB_DB_OFFSET: + case EC_ADDR_USB_C_POWER_PRIORITY: return true; default: return false; @@ -562,6 +576,7 @@ static bool uniwill_readable_reg(struct device *dev, unsigned int reg) case EC_ADDR_CTGP_DB_CTGP_OFFSET: case EC_ADDR_CTGP_DB_TPP_OFFSET: case EC_ADDR_CTGP_DB_DB_OFFSET: + case EC_ADDR_USB_C_POWER_PRIORITY: return true; default: return false; @@ -584,6 +599,7 @@ static bool uniwill_volatile_reg(struct device *dev, unsigned int reg) case EC_ADDR_TRIGGER: case EC_ADDR_SWITCH_STATUS: case EC_ADDR_CHARGE_CTRL: + case EC_ADDR_USB_C_POWER_PRIORITY: return true; default: return false; @@ -880,6 +896,105 @@ static int uniwill_nvidia_ctgp_init(struct uniwill_data *data) return 0; } +static const char * const usb_c_power_priority_text[] = { + [USB_C_POWER_PRIORITY_CHARGING] = "charging", + [USB_C_POWER_PRIORITY_PERFORMANCE] = "performance", +}; + +static const u8 usb_c_power_priority_value[] = { + [USB_C_POWER_PRIORITY_CHARGING] = 0, + [USB_C_POWER_PRIORITY_PERFORMANCE] = USB_C_POWER_PRIORITY, +}; + +static ssize_t usb_c_power_priority_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + enum usb_c_power_priority_options option; + unsigned int value; + int ret; + + ret = sysfs_match_string(usb_c_power_priority_text, buf); + if (ret < 0) + return ret; + + option = ret; + value = usb_c_power_priority_value[option]; + + guard(mutex)(&data->usb_c_power_priority_lock); + + ret = regmap_update_bits(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, + USB_C_POWER_PRIORITY, value); + if (ret < 0) + return ret; + + data->last_usb_c_power_priority_option = option; + + return count; +} + +static ssize_t usb_c_power_priority_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct uniwill_data *data = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value); + if (ret < 0) + return ret; + + value &= USB_C_POWER_PRIORITY; + + if (usb_c_power_priority_value[USB_C_POWER_PRIORITY_PERFORMANCE] == value) + return sysfs_emit(buf, "%s\n", + usb_c_power_priority_text[USB_C_POWER_PRIORITY_PERFORMANCE]); + + return sysfs_emit(buf, "%s\n", usb_c_power_priority_text[USB_C_POWER_PRIORITY_CHARGING]); +} + +static DEVICE_ATTR_RW(usb_c_power_priority); + +static int usb_c_power_priority_restore(struct uniwill_data *data) +{ + unsigned int value; + + value = usb_c_power_priority_value[data->last_usb_c_power_priority_option]; + + guard(mutex)(&data->usb_c_power_priority_lock); + + return regmap_update_bits(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, + USB_C_POWER_PRIORITY, value); +} + +static int usb_c_power_priority_init(struct uniwill_data *data) +{ + unsigned int value; + int ret; + + if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY)) + return 0; + + ret = devm_mutex_init(data->dev, &data->usb_c_power_priority_lock); + if (ret < 0) + return ret; + + ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value); + if (ret < 0) + return ret; + + value &= USB_C_POWER_PRIORITY; + + data->last_usb_c_power_priority_option = + usb_c_power_priority_value[USB_C_POWER_PRIORITY_PERFORMANCE] == value ? + USB_C_POWER_PRIORITY_PERFORMANCE : + USB_C_POWER_PRIORITY_CHARGING; + + return 0; +} + static struct attribute *uniwill_attrs[] = { /* Keyboard-related */ &dev_attr_fn_lock.attr, @@ -890,6 +1005,7 @@ static struct attribute *uniwill_attrs[] = { &dev_attr_breathing_in_suspend.attr, /* Power-management-related */ &dev_attr_ctgp_offset.attr, + &dev_attr_usb_c_power_priority.attr, NULL }; @@ -924,6 +1040,11 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a return attr->mode; } + if (attr == &dev_attr_usb_c_power_priority.attr) { + if (uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY)) + return attr->mode; + } + return 0; } @@ -937,6 +1058,48 @@ static const struct attribute_group *uniwill_groups[] = { NULL }; +static umode_t uniwill_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, + int channel) +{ + const struct uniwill_data *data = drvdata; + unsigned int feature; + + switch (type) { + case hwmon_temp: + switch (channel) { + case 0: + feature = UNIWILL_FEATURE_CPU_TEMP; + break; + case 1: + feature = UNIWILL_FEATURE_GPU_TEMP; + break; + default: + return 0; + } + break; + case hwmon_fan: + case hwmon_pwm: + switch (channel) { + case 0: + feature = UNIWILL_FEATURE_PRIMARY_FAN; + break; + case 1: + feature = UNIWILL_FEATURE_SECONDARY_FAN; + break; + default: + return 0; + } + break; + default: + return 0; + } + + if (uniwill_device_supports(data, feature)) + return 0444; + + return 0; +} + static int uniwill_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { @@ -1020,7 +1183,7 @@ static int uniwill_read_string(struct device *dev, enum hwmon_sensor_types type, } static const struct hwmon_ops uniwill_ops = { - .visible = 0444, + .is_visible = uniwill_is_visible, .read = uniwill_read, .read_string = uniwill_read_string, }; @@ -1048,7 +1211,10 @@ static int uniwill_hwmon_init(struct uniwill_data *data) { struct device *hdev; - if (!uniwill_device_supports(data, UNIWILL_FEATURE_HWMON)) + if (!uniwill_device_supports(data, UNIWILL_FEATURE_CPU_TEMP) && + !uniwill_device_supports(data, UNIWILL_FEATURE_GPU_TEMP) && + !uniwill_device_supports(data, UNIWILL_FEATURE_PRIMARY_FAN) && + !uniwill_device_supports(data, UNIWILL_FEATURE_SECONDARY_FAN)) return 0; hdev = devm_hwmon_device_register_with_info(data->dev, "uniwill", data, @@ -1369,11 +1535,10 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action return NOTIFY_OK; case UNIWILL_OSD_DC_ADAPTER_CHANGED: - /* noop for the time being, will change once charging priority - * gets implemented. - */ + if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY)) + return NOTIFY_DONE; - return NOTIFY_OK; + return notifier_from_errno(usb_c_power_priority_restore(data)); case UNIWILL_OSD_FN_LOCK: if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK)) return NOTIFY_DONE; @@ -1467,6 +1632,7 @@ static int uniwill_probe(struct platform_device *pdev) return PTR_ERR(regmap); data->regmap = regmap; + ret = devm_mutex_init(&pdev->dev, &data->super_key_lock); if (ret < 0) return ret; @@ -1504,6 +1670,10 @@ static int uniwill_probe(struct platform_device *pdev) if (ret < 0) return ret; + ret = usb_c_power_priority_init(data); + if (ret < 0) + return ret; + return uniwill_input_init(data); } @@ -1633,6 +1803,14 @@ static int uniwill_resume_nvidia_ctgp(struct uniwill_data *data) CTGP_DB_DB_ENABLE | CTGP_DB_CTGP_ENABLE); } +static int uniwill_resume_usb_c_power_priority(struct uniwill_data *data) +{ + if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY)) + return 0; + + return usb_c_power_priority_restore(data); +} + static int uniwill_resume(struct device *dev) { struct uniwill_data *data = dev_get_drvdata(dev); @@ -1656,7 +1834,11 @@ static int uniwill_resume(struct device *dev) if (ret < 0) return ret; - return uniwill_resume_nvidia_ctgp(data); + ret = uniwill_resume_nvidia_ctgp(data); + if (ret < 0) + return ret; + + return uniwill_resume_usb_c_power_priority(data); } static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_resume); @@ -1682,12 +1864,24 @@ static struct platform_driver uniwill_driver = { .shutdown = uniwill_shutdown, }; +static struct uniwill_device_descriptor lapqc71a_lapqc71b_descriptor __initdata = { + .features = UNIWILL_FEATURE_SUPER_KEY | + UNIWILL_FEATURE_BATTERY | + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_GPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN | + UNIWILL_FEATURE_SECONDARY_FAN, +}; + static struct uniwill_device_descriptor lapac71h_descriptor __initdata = { .features = UNIWILL_FEATURE_FN_LOCK | UNIWILL_FEATURE_SUPER_KEY | UNIWILL_FEATURE_TOUCHPAD_TOGGLE | UNIWILL_FEATURE_BATTERY | - UNIWILL_FEATURE_HWMON, + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_GPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN | + UNIWILL_FEATURE_SECONDARY_FAN, }; static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = { @@ -1696,7 +1890,89 @@ static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = { UNIWILL_FEATURE_TOUCHPAD_TOGGLE | UNIWILL_FEATURE_LIGHTBAR | UNIWILL_FEATURE_BATTERY | - UNIWILL_FEATURE_HWMON, + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_GPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN | + UNIWILL_FEATURE_SECONDARY_FAN, +}; + +/* + * The featuresets below reflect somewhat chronological changes: + * 1 -> 2: UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL is added to the EC firmware. + * 2 -> 3: UNIWILL_FEATURE_USB_C_POWER_PRIORITY is removed from the EC firmware. + * Some devices might divert from this timeline. + */ + +static struct uniwill_device_descriptor tux_featureset_1_descriptor __initdata = { + .features = UNIWILL_FEATURE_FN_LOCK | + UNIWILL_FEATURE_SUPER_KEY | + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN | + UNIWILL_FEATURE_SECONDARY_FAN | + UNIWILL_FEATURE_USB_C_POWER_PRIORITY, +}; + +static struct uniwill_device_descriptor tux_featureset_1_nvidia_descriptor __initdata = { + .features = UNIWILL_FEATURE_FN_LOCK | + UNIWILL_FEATURE_SUPER_KEY | + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_GPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN | + UNIWILL_FEATURE_SECONDARY_FAN | + UNIWILL_FEATURE_USB_C_POWER_PRIORITY, +}; + +static struct uniwill_device_descriptor tux_featureset_2_nvidia_descriptor __initdata = { + .features = UNIWILL_FEATURE_FN_LOCK | + UNIWILL_FEATURE_SUPER_KEY | + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_GPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN | + UNIWILL_FEATURE_SECONDARY_FAN | + UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL | + UNIWILL_FEATURE_USB_C_POWER_PRIORITY, +}; + +static struct uniwill_device_descriptor tux_featureset_3_descriptor __initdata = { + .features = UNIWILL_FEATURE_FN_LOCK | + UNIWILL_FEATURE_SUPER_KEY | + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN | + UNIWILL_FEATURE_SECONDARY_FAN, +}; + +static struct uniwill_device_descriptor tux_featureset_3_nvidia_descriptor __initdata = { + .features = UNIWILL_FEATURE_FN_LOCK | + UNIWILL_FEATURE_SUPER_KEY | + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_GPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN | + UNIWILL_FEATURE_SECONDARY_FAN | + UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL, +}; + +static int phxtxx1_probe(struct uniwill_data *data) +{ + unsigned int value; + int ret; + + ret = regmap_read(data->regmap, EC_ADDR_PROJECT_ID, &value); + if (ret < 0) + return ret; + + if (value == PROJECT_ID_PH4TRX1 || value == PROJECT_ID_PH6TRX1) + data->features |= UNIWILL_FEATURE_SECONDARY_FAN; + + return 0; +}; + +static struct uniwill_device_descriptor phxtxx1_descriptor __initdata = { + .features = UNIWILL_FEATURE_FN_LOCK | + UNIWILL_FEATURE_SUPER_KEY | + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN | + UNIWILL_FEATURE_USB_C_POWER_PRIORITY, + .probe = phxtxx1_probe, }; static int phxarx1_phxaqf1_probe(struct uniwill_data *data) @@ -1709,37 +1985,61 @@ static int phxarx1_phxaqf1_probe(struct uniwill_data *data) return ret; if (value & HAS_GPU) - data->features |= UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL; + data->features |= UNIWILL_FEATURE_GPU_TEMP | + UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL; return 0; }; static struct uniwill_device_descriptor phxarx1_phxaqf1_descriptor __initdata = { + .features = UNIWILL_FEATURE_FN_LOCK | + UNIWILL_FEATURE_SUPER_KEY | + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN | + UNIWILL_FEATURE_SECONDARY_FAN | + UNIWILL_FEATURE_USB_C_POWER_PRIORITY, .probe = phxarx1_phxaqf1_probe, }; -static struct uniwill_device_descriptor tux_featureset_1_descriptor __initdata = { - .features = UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL, +static struct uniwill_device_descriptor pf5pu1g_descriptor __initdata = { + .features = UNIWILL_FEATURE_FN_LOCK | + UNIWILL_FEATURE_SUPER_KEY | + UNIWILL_FEATURE_CPU_TEMP | + UNIWILL_FEATURE_PRIMARY_FAN, }; -static struct uniwill_device_descriptor empty_descriptor __initdata = {}; - static const struct dmi_system_id uniwill_dmi_table[] __initconst = { { - .ident = "XMG FUSION 15", + .ident = "XMG FUSION 15 (L19)", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"), }, - .driver_data = &empty_descriptor, + .driver_data = &lapqc71a_lapqc71b_descriptor, }, { - .ident = "XMG FUSION 15", + .ident = "XMG FUSION 15 (L19)", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"), }, - .driver_data = &empty_descriptor, + .driver_data = &lapqc71a_lapqc71b_descriptor, + }, + { + .ident = "XMG FUSION 15 (L19)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"), + }, + .driver_data = &lapqc71a_lapqc71b_descriptor, + }, + { + .ident = "XMG FUSION 15 (L19)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"), + }, + .driver_data = &lapqc71a_lapqc71b_descriptor, }, { .ident = "Intel NUC x15", @@ -1763,7 +2063,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTxX1"), }, - .driver_data = &empty_descriptor, + .driver_data = &phxtxx1_descriptor, }, { .ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel", @@ -1771,7 +2071,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_2_nvidia_descriptor, }, { .ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel", @@ -1787,7 +2087,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_2_nvidia_descriptor, }, { .ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8", @@ -1795,7 +2095,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PRX1_PH6PRX1"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_descriptor, }, { .ident = "TUXEDO InfinityBook Pro 14 Gen8 Intel/Commodore Omnia-Book Pro Gen 8", @@ -1803,7 +2103,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_2_nvidia_descriptor, }, { .ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel", @@ -1811,7 +2111,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_2_nvidia_descriptor, }, { .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD", @@ -1819,7 +2119,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_3_descriptor, }, { .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore Omnia-Book 15 Gen9", @@ -1827,7 +2127,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_3_descriptor, }, { .ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD", @@ -1835,7 +2135,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_3_descriptor, }, { .ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD", @@ -1843,7 +2143,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_3_descriptor, }, { .ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel", @@ -1851,7 +2151,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_3_descriptor, }, { .ident = "TUXEDO InfinityBook Max 15 Gen10 AMD", @@ -1859,7 +2159,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO InfinityBook Max 16 Gen10 AMD", @@ -1867,7 +2167,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6HP45xU"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO InfinityBook Max 16 Gen10 AMD", @@ -1875,7 +2175,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO InfinityBook Max 15 Gen10 Intel", @@ -1883,7 +2183,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5AR45xS"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO InfinityBook Max 16 Gen10 Intel", @@ -1891,7 +2191,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR55xU"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 15 Gen1 AMD", @@ -1899,7 +2199,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 15 Gen1 AMD", @@ -1907,7 +2207,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 17 Gen1 AMD", @@ -1915,7 +2215,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 17 Gen1 AMD", @@ -1923,7 +2223,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 15 Gen1 Intel", @@ -1931,7 +2231,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I1650TI"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 15 Gen1 Intel", @@ -1939,7 +2239,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I2060"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 17 Gen1 Intel", @@ -1947,7 +2247,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I1650TI"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 17 Gen1 Intel", @@ -1955,7 +2255,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I2060"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_nvidia_descriptor, }, { .ident = "TUXEDO Trinity 15 Intel Gen1", @@ -1963,7 +2263,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1501I"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_nvidia_descriptor, }, { .ident = "TUXEDO Trinity 17 Intel Gen1", @@ -1971,7 +2271,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1701I"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 15/17 Gen2 AMD", @@ -1979,7 +2279,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_2_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 15/17 Gen2 Intel", @@ -1987,7 +2287,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_2_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD", @@ -1995,7 +2295,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_2_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel", @@ -2003,7 +2303,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_2_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD", @@ -2011,7 +2311,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris 15 Gen4 Intel", @@ -2019,7 +2319,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Polaris 15/17 Gen5 AMD", @@ -2027,7 +2327,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_2_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris 16 Gen5 AMD", @@ -2035,7 +2335,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5", @@ -2043,7 +2343,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris Slim 15 Gen6 AMD", @@ -2051,7 +2351,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6", @@ -2059,7 +2359,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6", @@ -2067,7 +2367,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6", @@ -2075,7 +2375,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6", @@ -2083,7 +2383,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris 16 Gen7 AMD", @@ -2091,7 +2391,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris 16 Gen7 Intel", @@ -2099,7 +2399,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Stellaris 16 Gen7 Intel", @@ -2107,7 +2407,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"), }, - .driver_data = &tux_featureset_1_descriptor, + .driver_data = &tux_featureset_3_nvidia_descriptor, }, { .ident = "TUXEDO Book BA15 Gen10 AMD", @@ -2115,7 +2415,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5PU1G"), }, - .driver_data = &empty_descriptor, + .driver_data = &pf5pu1g_descriptor, }, { .ident = "TUXEDO Pulse 14 Gen1 AMD", @@ -2123,7 +2423,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1401"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_descriptor, }, { .ident = "TUXEDO Pulse 15 Gen1 AMD", @@ -2131,7 +2431,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1501"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_descriptor, }, { .ident = "TUXEDO Pulse 15 Gen2 AMD", @@ -2139,7 +2439,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5LUXG"), }, - .driver_data = &empty_descriptor, + .driver_data = &tux_featureset_1_descriptor, }, { } }; diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.c b/drivers/platform/x86/uniwill/uniwill-wmi.c index 31d9c39f14ab..097882f10b1e 100644 --- a/drivers/platform/x86/uniwill/uniwill-wmi.c +++ b/drivers/platform/x86/uniwill/uniwill-wmi.c @@ -77,6 +77,7 @@ static struct wmi_driver uniwill_wmi_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .id_table = uniwill_wmi_id_table, + .min_event_size = sizeof(u32), .notify = uniwill_wmi_notify, .no_singleton = true, }; diff --git a/drivers/platform/x86/wireless-hotkey.c b/drivers/platform/x86/wireless-hotkey.c index e5083c0e1515..f680d8ff8e87 100644 --- a/drivers/platform/x86/wireless-hotkey.c +++ b/drivers/platform/x86/wireless-hotkey.c @@ -35,16 +35,17 @@ static const struct acpi_device_id wl_ids[] = { {"", 0}, }; -static int wireless_input_setup(struct acpi_device *device) +static int wireless_input_setup(struct device *dev) { - struct wl_button *button = acpi_driver_data(device); + struct wl_button *button = dev_get_drvdata(dev); int err; button->input_dev = input_allocate_device(); if (!button->input_dev) return -ENOMEM; - snprintf(button->phys, sizeof(button->phys), "%s/input0", acpi_device_hid(device)); + snprintf(button->phys, sizeof(button->phys), "%s/input0", + acpi_device_hid(ACPI_COMPANION(dev))); button->input_dev->name = "Wireless hotkeys"; button->input_dev->phys = button->phys; @@ -63,17 +64,17 @@ err_free_dev: return err; } -static void wireless_input_destroy(struct acpi_device *device) +static void wireless_input_destroy(struct device *dev) { - struct wl_button *button = acpi_driver_data(device); + struct wl_button *button = dev_get_drvdata(dev); input_unregister_device(button->input_dev); kfree(button); } -static void wl_notify(struct acpi_device *acpi_dev, u32 event) +static void wl_notify(acpi_handle handle, u32 event, void *data) { - struct wl_button *button = acpi_driver_data(acpi_dev); + struct wl_button *button = data; if (event != 0x80) { pr_info("Received unknown event (0x%x)\n", event); @@ -86,7 +87,7 @@ static void wl_notify(struct acpi_device *acpi_dev, u32 event) input_sync(button->input_dev); } -static int wl_add(struct acpi_device *device) +static int wl_probe(struct platform_device *pdev) { struct wl_button *button; int err; @@ -95,30 +96,38 @@ static int wl_add(struct acpi_device *device) if (!button) return -ENOMEM; - device->driver_data = button; + platform_set_drvdata(pdev, button); - err = wireless_input_setup(device); + err = wireless_input_setup(&pdev->dev); if (err) { pr_err("Failed to setup wireless hotkeys\n"); kfree(button); + return err; + } + err = acpi_dev_install_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, wl_notify, button); + if (err) { + pr_err("Failed to install ACPI notify handler\n"); + wireless_input_destroy(&pdev->dev); } return err; } -static void wl_remove(struct acpi_device *device) +static void wl_remove(struct platform_device *pdev) { - wireless_input_destroy(device); + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, wl_notify); + wireless_input_destroy(&pdev->dev); } -static struct acpi_driver wl_driver = { - .name = "wireless-hotkey", - .ids = wl_ids, - .ops = { - .add = wl_add, - .remove = wl_remove, - .notify = wl_notify, +static struct platform_driver wl_driver = { + .probe = wl_probe, + .remove = wl_remove, + .driver = { + .name = "wireless-hotkey", + .acpi_match_table = wl_ids, }, }; -module_acpi_driver(wl_driver); +module_platform_driver(wl_driver); diff --git a/drivers/platform/x86/wmi-bmof.c b/drivers/platform/x86/wmi-bmof.c index e3a126de421b..6623cf60e4b4 100644 --- a/drivers/platform/x86/wmi-bmof.c +++ b/drivers/platform/x86/wmi-bmof.c @@ -62,7 +62,7 @@ static int wmi_bmof_probe(struct wmi_device *wdev, const void *context) if (!buffer) return -ENOMEM; - ret = wmidev_query_block(wdev, 0, buffer); + ret = wmidev_query_block(wdev, 0, buffer, 0); if (ret < 0) return ret; diff --git a/drivers/platform/x86/xiaomi-wmi.c b/drivers/platform/x86/xiaomi-wmi.c index badf9e42e015..3874f3336a0d 100644 --- a/drivers/platform/x86/xiaomi-wmi.c +++ b/drivers/platform/x86/xiaomi-wmi.c @@ -83,6 +83,7 @@ static struct wmi_driver xiaomi_wmi_driver = { .name = "xiaomi-wmi", }, .id_table = xiaomi_wmi_id_table, + .min_event_size = 0, .probe = xiaomi_wmi_probe, .notify_new = xiaomi_wmi_notify, .no_singleton = true, diff --git a/include/linux/intel_vsec.h b/include/linux/intel_vsec.h index 1a0f357c2427..1fe5665a9d02 100644 --- a/include/linux/intel_vsec.h +++ b/include/linux/intel_vsec.h @@ -29,9 +29,15 @@ #define INTEL_DVSEC_TABLE_OFFSET(x) ((x) & GENMASK(31, 3)) #define TABLE_OFFSET_SHIFT 3 +struct device; struct pci_dev; struct resource; +enum intel_vsec_disc_source { + INTEL_VSEC_DISC_PCI, /* PCI, default */ + INTEL_VSEC_DISC_ACPI, /* ACPI */ +}; + enum intel_vsec_id { VSEC_ID_TELEMETRY = 2, VSEC_ID_WATCHER = 3, @@ -82,14 +88,14 @@ enum intel_vsec_quirks { * struct pmt_callbacks - Callback infrastructure for PMT devices * @read_telem: when specified, called by client driver to access PMT * data (instead of direct copy). - * * pdev: PCI device reference for the callback's use + * * dev: device reference for the callback's use * * guid: ID of data to acccss * * data: buffer for the data to be copied * * off: offset into the requested buffer * * count: size of buffer */ struct pmt_callbacks { - int (*read_telem)(struct pci_dev *pdev, u32 guid, u64 *data, loff_t off, u32 count); + int (*read_telem)(struct device *dev, u32 guid, u64 *data, loff_t off, u32 count); }; struct vsec_feature_dependency { @@ -102,6 +108,10 @@ struct vsec_feature_dependency { * @parent: parent device in the auxbus chain * @headers: list of headers to define the PMT client devices to create * @deps: array of feature dependencies + * @acpi_disc: ACPI discovery tables, each entry is two QWORDs + * in little-endian format as defined by the PMT ACPI spec. + * Valid only when @provider == INTEL_VSEC_DISC_ACPI. + * @src: source of discovery table data * @priv_data: private data, usable by parent devices, currently a callback * @caps: bitmask of PMT capabilities for the given headers * @quirks: bitmask of VSEC device quirks @@ -112,6 +122,8 @@ struct intel_vsec_platform_info { struct device *parent; struct intel_vsec_header **headers; const struct vsec_feature_dependency *deps; + u32 (*acpi_disc)[4]; + enum intel_vsec_disc_source src; void *priv_data; unsigned long caps; unsigned long quirks; @@ -122,8 +134,13 @@ struct intel_vsec_platform_info { /** * struct intel_vsec_device - Auxbus specific device information * @auxdev: auxbus device struct for auxbus access - * @pcidev: pci device associated with the device - * @resource: any resources shared by the parent + * @dev: struct device associated with the device + * @resource: PCI discovery resources (BAR windows), one per discovery + * instance. Valid only when @src == INTEL_VSEC_DISC_PCI + * @acpi_disc: ACPI discovery tables, each entry is two QWORDs + * in little-endian format as defined by the PMT ACPI spec. + * Valid only when @src == INTEL_VSEC_DISC_ACPI. + * @src: source of discovery table data * @ida: id reference * @num_resources: number of resources * @id: xarray id @@ -135,8 +152,10 @@ struct intel_vsec_platform_info { */ struct intel_vsec_device { struct auxiliary_device auxdev; - struct pci_dev *pcidev; + struct device *dev; struct resource *resource; + u32 (*acpi_disc)[4]; + enum intel_vsec_disc_source src; struct ida *ida; int num_resources; int id; /* xa */ @@ -184,7 +203,7 @@ struct pmt_feature_group { struct telemetry_region regions[]; }; -int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, +int intel_vsec_add_aux(struct device *parent, struct intel_vsec_device *intel_vsec_dev, const char *name); @@ -199,14 +218,14 @@ static inline struct intel_vsec_device *auxdev_to_ivdev(struct auxiliary_device } #if IS_ENABLED(CONFIG_INTEL_VSEC) -int intel_vsec_register(struct pci_dev *pdev, - struct intel_vsec_platform_info *info); +int intel_vsec_register(struct device *dev, + const struct intel_vsec_platform_info *info); int intel_vsec_set_mapping(struct oobmsm_plat_info *plat_info, struct intel_vsec_device *vsec_dev); struct oobmsm_plat_info *intel_vsec_get_mapping(struct pci_dev *pdev); #else -static inline int intel_vsec_register(struct pci_dev *pdev, - struct intel_vsec_platform_info *info) +static inline int intel_vsec_register(struct device *dev, + const struct intel_vsec_platform_info *info) { return -ENODEV; } diff --git a/include/linux/platform_data/x86/int3472.h b/include/linux/platform_data/x86/int3472.h index dbe745dc88d5..93f1e1fe09b4 100644 --- a/include/linux/platform_data/x86/int3472.h +++ b/include/linux/platform_data/x86/int3472.h @@ -23,6 +23,7 @@ /* PMIC GPIO Types */ #define INT3472_GPIO_TYPE_RESET 0x00 #define INT3472_GPIO_TYPE_POWERDOWN 0x01 +#define INT3472_GPIO_TYPE_STROBE 0x02 #define INT3472_GPIO_TYPE_POWER_ENABLE 0x0b #define INT3472_GPIO_TYPE_CLK_ENABLE 0x0c #define INT3472_GPIO_TYPE_PRIVACY_LED 0x0d @@ -32,6 +33,7 @@ #define INT3472_PDEV_MAX_NAME_LEN 23 #define INT3472_MAX_SENSOR_GPIOS 3 +#define INT3472_MAX_LEDS 2 #define INT3472_MAX_REGULATORS 3 /* E.g. "dovdd\0" */ @@ -122,16 +124,17 @@ struct int3472_discrete_device { u8 imgclk_index; } clock; - struct int3472_pled { + struct int3472_led { struct led_classdev classdev; struct led_lookup_data lookup; char name[INT3472_LED_MAX_NAME_LEN]; struct gpio_desc *gpio; - } pled; + } leds[INT3472_MAX_LEDS]; struct int3472_discrete_quirks quirks; unsigned int ngpios; /* how many GPIOs have we seen */ + unsigned int n_leds; /* how many LEDs have we registered */ unsigned int n_sensor_gpios; /* how many have we mapped to sensor */ unsigned int n_regulator_gpios; /* how many have we mapped to a regulator */ struct gpiod_lookup_table gpios; @@ -161,7 +164,8 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, const char *second_sensor); void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472); -int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio); -void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472); +int skl_int3472_register_led(struct int3472_discrete_device *int3472, struct gpio_desc *gpio, + const char *con_id); +void skl_int3472_unregister_leds(struct int3472_discrete_device *int3472); #endif diff --git a/include/linux/wmi.h b/include/linux/wmi.h index 14fb644e1701..d723e4b1cafb 100644 --- a/include/linux/wmi.h +++ b/include/linux/wmi.h @@ -64,9 +64,13 @@ ssize_t wmi_string_from_utf8s(struct wmi_string *str, size_t max_chars, const u8 size_t src_length); int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id, - const struct wmi_buffer *in, struct wmi_buffer *out); + const struct wmi_buffer *in, struct wmi_buffer *out, size_t min_size); -int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *out); +int wmidev_invoke_procedure(struct wmi_device *wdev, u8 instance, u32 method_id, + const struct wmi_buffer *in); + +int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer *out, + size_t min_size); int wmidev_set_block(struct wmi_device *wdev, u8 instance, const struct wmi_buffer *in); @@ -83,7 +87,7 @@ u8 wmidev_instance_count(struct wmi_device *wdev); * struct wmi_driver - WMI driver structure * @driver: Driver model structure * @id_table: List of WMI GUIDs supported by this driver - * @no_notify_data: Driver supports WMI events which provide no event data + * @min_event_size: Minimum event payload size supported by this driver * @no_singleton: Driver can be instantiated multiple times * @probe: Callback for device binding * @remove: Callback for device unbinding @@ -93,11 +97,14 @@ u8 wmidev_instance_count(struct wmi_device *wdev); * * This represents WMI drivers which handle WMI devices. The data inside the buffer * passed to the @notify_new callback is guaranteed to be aligned on a 8-byte boundary. + * The minimum supported size for said buffer can be specified using @min_event_size. + * WMI drivers that still use the deprecated @notify callback can still set @min_event_size + * to 0 in order to signal that they support WMI events which provide no event data. */ struct wmi_driver { struct device_driver driver; const struct wmi_device_id *id_table; - bool no_notify_data; + size_t min_event_size; bool no_singleton; int (*probe)(struct wmi_device *wdev, const void *context); diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index dd9056ddb016..2faff1aead52 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -16,7 +16,7 @@ struct process_cmd_struct { int arg; }; -static const char *version_str = "v1.25"; +static const char *version_str = "v1.26"; static const int supported_api_ver = 3; static struct isst_if_platform_info isst_platform_info; @@ -26,7 +26,7 @@ static FILE *outf; static int cpu_model; static int cpu_stepping; -static int extended_family; +static int cpu_family; #define MAX_CPUS_IN_ONE_REQ 512 static short max_target_cpus; @@ -82,6 +82,11 @@ struct cpu_topology { static int read_only; +static void print_version(void) +{ + fprintf(outf, "Version %s\n", version_str); +} + static void check_privilege(void) { if (!read_only) @@ -158,7 +163,7 @@ int is_icx_platform(void) static int is_dmr_plus_platform(void) { - if (extended_family == 0x04) + if (cpu_family == 19) return 1; return 0; @@ -167,13 +172,14 @@ static int is_dmr_plus_platform(void) static int update_cpu_model(void) { unsigned int ebx, ecx, edx; - unsigned int fms, family; + unsigned int fms; __cpuid(1, fms, ebx, ecx, edx); - family = (fms >> 8) & 0xf; - extended_family = (fms >> 20) & 0x0f; + cpu_family = (fms >> 8) & 0xf; + if (cpu_family == 0xf) + cpu_family += (fms >> 20) & 0xff; cpu_model = (fms >> 4) & 0xf; - if (family == 6 || family == 0xf) + if (cpu_family == 6 || cpu_family == 0xf) cpu_model += ((fms >> 16) & 0xf) << 4; cpu_stepping = fms & 0xf; @@ -1137,8 +1143,9 @@ static int isst_fill_platform_info(void) close(fd); if (isst_platform_info.api_version > supported_api_ver) { + print_version(); printf("Incompatible API versions; Upgrade of tool is required\n"); - return -1; + exit(1); } set_platform_ops: @@ -1744,6 +1751,9 @@ static int no_turbo(void) return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); } +#define U32_MAX ((unsigned int)~0U) +#define S32_MAX ((int)(U32_MAX >> 1)) + static void adjust_scaling_max_from_base_freq(int cpu) { int base_freq, scaling_max_freq; @@ -1751,7 +1761,7 @@ static void adjust_scaling_max_from_base_freq(int cpu) scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); base_freq = get_cpufreq_base_freq(cpu); if (scaling_max_freq < base_freq || no_turbo()) - set_cpufreq_scaling_min_max(cpu, 1, base_freq); + set_cpufreq_scaling_min_max(cpu, 1, S32_MAX); } static void adjust_scaling_min_from_base_freq(int cpu) @@ -3191,12 +3201,6 @@ static void usage(void) printf("\tTo get full turbo-freq information dump:\n"); printf("\t\tintel-speed-select turbo-freq info -l 0\n"); } - exit(1); -} - -static void print_version(void) -{ - fprintf(outf, "Version %s\n", version_str); exit(0); } @@ -3246,8 +3250,10 @@ static void cmdline(int argc, char **argv) } ret = update_cpu_model(); - if (ret) - err(-1, "Invalid CPU model (%d)\n", cpu_model); + if (ret) { + fprintf(stderr, "Invalid CPU model (%d)\n", cpu_model); + exit(1); + } printf("Intel(R) Speed Select Technology\n"); printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model); @@ -3311,6 +3317,7 @@ static void cmdline(int argc, char **argv) break; case 'v': print_version(); + exit(0); break; case 'b': oob_mode = 1; |
