diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-20 12:02:24 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-20 12:02:24 -0700 |
| commit | da6b5aae84beb0917ecb0c9fbc71169d145397ff (patch) | |
| tree | 20d39405eb2d710a2beae5a51ff9d4c92009a554 /drivers | |
| parent | b69e478512080f9bb03ed3e812b759bb73e2837b (diff) | |
| parent | 344bf523d441d44c75c429ea6cdcfa8f12efde4d (diff) | |
Merge tag 'platform-drivers-x86-v7.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver updates from Ilpo Järvinen:
"asus-wmi:
- Retain battery charge threshold during boot which avoids
unsolicited change to 100%. Return -ENODATA when the limit
is not yet known
- Improve screenpad power/brightness handling consistency
- Fix screenpad brightness range
barco-p50-gpio:
- Normalize gpio_get return values
bitland-mifs-wmi:
- Add driver for Bitland laptops (supports platform profile,
hwmon, kbd backlight, gpu mode, hotkeys, and fan boost)
dell_rbu:
- Fix using uninitialized value in sysfs write function
dell-wmi-sysman:
- Respect destination length when constructing enum strings
hp-wmi:
- Propagate fan setting apply failures and log an error
- Fix sysfs write vs work handler cancel_delayed_work_sync() deadlock
- Correct keepalive schedule_delayed_work() to mod_delayed_work()
- Fix u8 underflows in GPU delta calculation
- Use mutex to protect fan pwm/mode
- Ignore kbd backlight and FnLock key events that are handled by FW
- Fix fan table parsing (use correct field)
- Add support for Omen 14-fb0xxx, 16-n0xxx, 16-wf1xxx, and
Omen MAX 16-ak0xxxx
input: trackpoint & thinkpad_acpi:
- Enable doubletap by default and add sysfs enable/disable
int3472:
- Add support for GPIO type 0x02 (IR flood LED)
intel-speed-select: (updated to v1.26)
- Avoid using current base frequency as maximum
- Fix CPU extended family ID decoding
- Fix exit code
- Improve error reporting
intel/vsec:
- Refactor to support ACPI-enumerated PMT endpoints.
pcengines-apuv2:
- Attach software node to the gpiochip
uniwill:
- Refactor hwmon to smaller parts to accomodate HW diversity
- Support USB-C power/performance priority switch through sysfs
- Add another XMG Fusion 15 (L19) DMI vendor
- Enable fine-grained features to device lineup mapping
wmi:
- Perform output size check within WMI core to allow simpler WMI
drivers
misc:
- acpi_driver -> platform driver conversions (a large number of
changes from Rafael J. Wysocki)
- cleanups / refactoring / improvements"
* tag 'platform-drivers-x86-v7.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (106 commits)
platform/x86: hp-wmi: Add support for Omen 16-wf1xxx (8C77)
platform/x86: hp-wmi: Add support for Omen 16-n0xxx (8A44)
platform/x86: hp-wmi: Add support for OMEN MAX 16-ak0xxx (8D87)
platform/x86: hp-wmi: fix fan table parsing
platform/x86: hp-wmi: add Omen 14-fb0xxx (board 8C58) support
platform/wmi: Replace .no_notify_data with .min_event_size
platform/wmi: Extend wmidev_query_block() to reject undersized data
platform/wmi: Extend wmidev_invoke_method() to reject undersized data
platform/wmi: Prepare to reject undersized unmarshalling results
platform/wmi: Convert drivers to use wmidev_invoke_procedure()
platform/wmi: Add wmidev_invoke_procedure()
platform/x86: int3472: Add support for GPIO type 0x02 (IR flood LED)
platform/x86: int3472: Parameterize LED con_id in registration
platform/x86: int3472: Rename pled to led in LED registration code
platform/x86: int3472: Use local variable for LED struct access
platform/x86: thinkpad_acpi: remove obsolete TODO comment
platform/x86: dell-wmi-sysman: bound enumeration string aggregation
platform/x86: hp-wmi: Ignore backlight and FnLock events
platform/x86: uniwill-laptop: Fix signedness bug
platform/x86: dell_rbu: avoid uninit value usage in packet_size_write()
...
Diffstat (limited to 'drivers')
69 files changed, 2727 insertions, 1270 deletions
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, |
