From 36ac0d439b795e8f395e3aa46434d79a5626219f Mon Sep 17 00:00:00 2001 From: Ritesh Raj Sarraf Date: Sat, 18 Feb 2017 00:17:56 +0530 Subject: platform/x86: ideapad-laptop: Add sysfs interface for touchpad state Lenovo Yoga (many variants: Yoga, Yoga2 Pro, Yoga2 13, Yoga3 Pro, Yoga 3 14, etc) has multiple modles that are a hybrid laptop, working in laptop mode as well as tablet mode. Currently, there is no easy interface to determine the touchpad status, which in case of the Yoga family of machines, can also be useful to assume tablet mode status. Note: The ideapad-laptop driver does not provide a SW_TABLET_MODE either. For a detailed discussion on why we want either of the interfaces, please see: https://bugs.launchpad.net/onboard/+bug/1366421/comments/43 This patch adds a sysfs interface for read/write access under: /sys/bus/platform/devices/VPC2004\:00/touchpad_mode Signed-off-by: Ritesh Raj Sarraf Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 24ca9fbe31cc..933668e48f87 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -423,9 +423,42 @@ static ssize_t store_ideapad_fan(struct device *dev, static DEVICE_ATTR(fan_mode, 0644, show_ideapad_fan, store_ideapad_fan); +static ssize_t touchpad_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ideapad_private *priv = dev_get_drvdata(dev); + unsigned long result; + + if (read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result)) + return sprintf(buf, "-1\n"); + return sprintf(buf, "%lu\n", result); +} + +static ssize_t touchpad_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ideapad_private *priv = dev_get_drvdata(dev); + bool state; + int ret; + + ret = kstrtobool(buf, &state); + if (ret) + return ret; + + ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state); + if (ret < 0) + return -EIO; + return count; +} + +static DEVICE_ATTR_RW(touchpad); + static struct attribute *ideapad_attributes[] = { &dev_attr_camera_power.attr, &dev_attr_fan_mode.attr, + &dev_attr_touchpad.attr, NULL }; -- cgit v1.2.3 From 7f363145992cebf4ea760447f1cfdf6f81459683 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 7 May 2017 14:28:30 +0300 Subject: platform/x86: ideapad-laptop: Switch touchpad attribute to be RO For now let's restrict touchpad attribute to be read only. We might revisit this in the future though. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 933668e48f87..f7a4608cc60b 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -453,7 +453,8 @@ static ssize_t touchpad_store(struct device *dev, return count; } -static DEVICE_ATTR_RW(touchpad); +/* Switch to RO for now: It might be revisited in the future */ +static DEVICE_ATTR_RO(touchpad); static struct attribute *ideapad_attributes[] = { &dev_attr_camera_power.attr, -- cgit v1.2.3 From f0ee1a6d319df56e49ca8308c5e9b69a9017f69d Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sat, 6 May 2017 23:40:19 +0800 Subject: platform/x86: toshiba_acpi: use memdup_user_nul Use memdup_user_nul() helper instead of open-coding to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Andy Shevchenko --- drivers/platform/x86/toshiba_acpi.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index d0daf75cbed1..88f9f79a7cf6 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1502,14 +1502,9 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, int ret; u32 video_out; - cmd = kmalloc(count + 1, GFP_KERNEL); - if (!cmd) - return -ENOMEM; - if (copy_from_user(cmd, buf, count)) { - kfree(cmd); - return -EFAULT; - } - cmd[count] = '\0'; + cmd = memdup_user_nul(buf, count); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); buffer = cmd; -- cgit v1.2.3 From d9ca30b87e6c9b4982bbda0362212500d5c5d5d7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 May 2017 14:35:15 +0200 Subject: platform/x86: silead_dmi: Add touchscreen info for GP-electronic T701 Add touchscreen info for the GP-electronic T701 tablet. Signed-off-by: Hans de Goede Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/silead_dmi.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index a3a57d93cf06..db3a877d2160 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -80,6 +80,19 @@ static const struct silead_ts_dmi_data surftab_wintron70_st70416_6_data = { .properties = surftab_wintron70_st70416_6_props, }; +static const struct property_entry gp_electronic_t701_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 960), + PROPERTY_ENTRY_U32("touchscreen-size-y", 640), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1680-gp-electronic-t701.fw"), + { } +}; + +static const struct silead_ts_dmi_data gp_electronic_t701_data = { + .acpi_name = "MSSL1680:00", + .properties = gp_electronic_t701_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -117,6 +130,15 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"), }, }, + { + /* GP-electronic T701 */ + .driver_data = (void *)&gp_electronic_t701_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "T701"), + DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), + }, + }, { }, }; -- cgit v1.2.3 From 5cac62ac92689e361ef6b83c1984e3fdf76b6766 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 May 2017 17:17:20 +0300 Subject: platform/x86: thinkpad_acpi: Join string literals back There is no point to keep string literal split. It even makes slightly harder to maintain and debug. Join string literals back to be oneliners. While here, print negative error without changing a sign as it is a common pattern in the kernel. Other than above there were no functional changes intended. Signed-off-by: Andy Shevchenko Acked-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 182 +++++++++++++---------------------- 1 file changed, 65 insertions(+), 117 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 7b6cb0c69b02..d2f67a8071a6 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -590,8 +590,8 @@ static int acpi_evalf(acpi_handle handle, break; /* add more types as needed */ default: - pr_err("acpi_evalf() called " - "with invalid format character '%c'\n", c); + pr_err("acpi_evalf() called with invalid format character '%c'\n", + c); va_end(ap); return 0; } @@ -619,8 +619,8 @@ static int acpi_evalf(acpi_handle handle, break; /* add more types as needed */ default: - pr_err("acpi_evalf() called " - "with invalid format character '%c'\n", res_type); + pr_err("acpi_evalf() called with invalid format character '%c'\n", + res_type); return 0; } @@ -790,8 +790,8 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm) ibm->acpi->type, dispatch_acpi_notify, ibm); if (ACPI_FAILURE(status)) { if (status == AE_ALREADY_EXISTS) { - pr_notice("another device driver is already " - "handling %s events\n", ibm->name); + pr_notice("another device driver is already handling %s events\n", + ibm->name); } else { pr_err("acpi_install_notify_handler(%s) failed: %s\n", ibm->name, acpi_format_exception(status)); @@ -1095,8 +1095,7 @@ static void printk_deprecated_attribute(const char * const what, const char * const details) { tpacpi_log_usertask("deprecated sysfs attribute"); - pr_warn("WARNING: sysfs attribute %s is deprecated and " - "will be removed. %s\n", + pr_warn("WARNING: sysfs attribute %s is deprecated and will be removed. %s\n", what, details); } @@ -1828,8 +1827,7 @@ static void __init tpacpi_check_outdated_fw(void) * best if the user upgrades the firmware anyway. */ pr_warn("WARNING: Outdated ThinkPad BIOS/EC firmware\n"); - pr_warn("WARNING: This firmware may be missing critical bug " - "fixes and/or important features\n"); + pr_warn("WARNING: This firmware may be missing critical bug fixes and/or important features\n"); } } @@ -2198,8 +2196,7 @@ static int hotkey_mask_set(u32 mask) * a given event. */ if (!hotkey_mask_get() && !rc && (fwmask & ~hotkey_acpi_mask)) { - pr_notice("asked for hotkey mask 0x%08x, but " - "firmware forced it to 0x%08x\n", + pr_notice("asked for hotkey mask 0x%08x, but firmware forced it to 0x%08x\n", fwmask, hotkey_acpi_mask); } @@ -2224,11 +2221,9 @@ static int hotkey_user_mask_set(const u32 mask) (mask == 0xffff || mask == 0xffffff || mask == 0xffffffff)) { tp_warned.hotkey_mask_ff = 1; - pr_notice("setting the hotkey mask to 0x%08x is likely " - "not the best way to go about it\n", mask); - pr_notice("please consider using the driver defaults, " - "and refer to up-to-date thinkpad-acpi " - "documentation\n"); + pr_notice("setting the hotkey mask to 0x%08x is likely not the best way to go about it\n", + mask); + pr_notice("please consider using the driver defaults, and refer to up-to-date thinkpad-acpi documentation\n"); } /* Try to enable what the user asked for, plus whatever we need. @@ -2603,17 +2598,14 @@ static void hotkey_poll_setup(const bool may_warn) NULL, TPACPI_NVRAM_KTHREAD_NAME); if (IS_ERR(tpacpi_hotkey_task)) { tpacpi_hotkey_task = NULL; - pr_err("could not create kernel thread " - "for hotkey polling\n"); + pr_err("could not create kernel thread for hotkey polling\n"); } } } else { hotkey_poll_stop_sync(); if (may_warn && (poll_driver_mask || poll_user_mask) && hotkey_poll_freq == 0) { - pr_notice("hot keys 0x%08x and/or events 0x%08x " - "require polling, which is currently " - "disabled\n", + pr_notice("hot keys 0x%08x and/or events 0x%08x require polling, which is currently disabled\n", poll_user_mask, poll_driver_mask); } } @@ -2840,12 +2832,10 @@ static ssize_t hotkey_source_mask_store(struct device *dev, mutex_unlock(&hotkey_mutex); if (rc < 0) - pr_err("hotkey_source_mask: " - "failed to update the firmware event mask!\n"); + pr_err("hotkey_source_mask: failed to update the firmware event mask!\n"); if (r_ev) - pr_notice("hotkey_source_mask: " - "some important events were disabled: 0x%04x\n", + pr_notice("hotkey_source_mask: some important events were disabled: 0x%04x\n", r_ev); tpacpi_disclose_usertask("hotkey_source_mask", "set to 0x%08lx\n", t); @@ -3106,8 +3096,7 @@ static void hotkey_exit(void) if (((tp_features.hotkey_mask && hotkey_mask_set(hotkey_orig_mask)) | hotkey_status_set(false)) != 0) - pr_err("failed to restore hot key mask " - "to BIOS defaults\n"); + pr_err("failed to restore hot key mask to BIOS defaults\n"); } static void __init hotkey_unmap(const unsigned int scancode) @@ -3619,11 +3608,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) * userspace. tpacpi_detect_brightness_capabilities() must have * been called before this point */ if (acpi_video_get_backlight_type() != acpi_backlight_vendor) { - pr_info("This ThinkPad has standard ACPI backlight " - "brightness control, supported by the ACPI " - "video driver\n"); - pr_notice("Disabling thinkpad-acpi brightness events " - "by default...\n"); + pr_info("This ThinkPad has standard ACPI backlight brightness control, supported by the ACPI video driver\n"); + pr_notice("Disabling thinkpad-acpi brightness events by default...\n"); /* Disable brightness up/down on Lenovo thinkpads when * ACPI is handling them, otherwise it is plain impossible @@ -3792,7 +3778,7 @@ static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode) TP_ACPI_HOTKEYSCAN_EXTENDED_START - TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) { pr_info("Unhandled adaptive keyboard key: 0x%x\n", - scancode); + scancode); return false; } keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY + @@ -3989,14 +3975,12 @@ static bool hotkey_notify_6xxx(const u32 hkey, /* recommended action: immediate sleep/hibernate */ break; case TP_HKEY_EV_ALARM_SENSOR_HOT: - pr_crit("THERMAL ALARM: " - "a sensor reports something is too hot!\n"); + pr_crit("THERMAL ALARM: a sensor reports something is too hot!\n"); /* recommended action: warn user through gui, that */ /* some internal component is too hot */ break; case TP_HKEY_EV_ALARM_SENSOR_XHOT: - pr_alert("THERMAL EMERGENCY: " - "a sensor reports something is extremely hot!\n"); + pr_alert("THERMAL EMERGENCY: a sensor reports something is extremely hot!\n"); /* recommended action: immediate sleep/hibernate */ break; case TP_HKEY_EV_AC_CHANGED: @@ -4121,8 +4105,8 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) } if (!known_ev) { pr_notice("unhandled HKEY event 0x%04x\n", hkey); - pr_notice("please report the conditions when this " - "event happened to %s\n", TPACPI_MAIL); + pr_notice("please report the conditions when this event happened to %s\n", + TPACPI_MAIL); } /* netlink events */ @@ -4156,8 +4140,7 @@ static void hotkey_resume(void) if (hotkey_status_set(true) < 0 || hotkey_mask_set(hotkey_acpi_mask) < 0) - pr_err("error while attempting to reset the event " - "firmware interface\n"); + pr_err("error while attempting to reset the event firmware interface\n"); tpacpi_send_radiosw_update(); hotkey_tablet_mode_notify_change(); @@ -4209,12 +4192,8 @@ static void hotkey_enabledisable_warn(bool enable) { tpacpi_log_usertask("procfs hotkey enable/disable"); if (!WARN((tpacpi_lifecycle == TPACPI_LIFE_RUNNING || !enable), - pr_fmt("hotkey enable/disable functionality has been " - "removed from the driver. " - "Hotkeys are always enabled.\n"))) - pr_err("Please remove the hotkey=enable module " - "parameter, it is deprecated. " - "Hotkeys are always enabled.\n"); + pr_fmt("hotkey enable/disable functionality has been removed from the driver. Hotkeys are always enabled.\n"))) + pr_err("Please remove the hotkey=enable module parameter, it is deprecated. Hotkeys are always enabled.\n"); } static int hotkey_write(char *buf) @@ -4872,8 +4851,7 @@ static void video_exit(void) dbg_printk(TPACPI_DBG_EXIT, "restoring original video autoswitch mode\n"); if (video_autosw_set(video_orig_autosw)) - pr_err("error while trying to restore original " - "video autoswitch mode\n"); + pr_err("error while trying to restore original video autoswitch mode\n"); } static int video_outputsw_get(void) @@ -5963,8 +5941,7 @@ static int __init led_init(struct ibm_init_struct *iibm) } #ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS - pr_notice("warning: userspace override of important " - "firmware LEDs is enabled\n"); + pr_notice("warning: userspace override of important firmware LEDs is enabled\n"); #endif return 0; } @@ -5993,8 +5970,7 @@ static int led_read(struct seq_file *m) } } - seq_printf(m, "commands:\t" - " on, off, blink ( is 0-15)\n"); + seq_printf(m, "commands:\t on, off, blink ( is 0-15)\n"); return 0; } @@ -6367,13 +6343,10 @@ static int __init thermal_init(struct ibm_init_struct *iibm) if (ta1 == 0) { /* This is sheer paranoia, but we handle it anyway */ if (acpi_tmp7) { - pr_err("ThinkPad ACPI EC access misbehaving, " - "falling back to ACPI TMPx access " - "mode\n"); + pr_err("ThinkPad ACPI EC access misbehaving, falling back to ACPI TMPx access mode\n"); thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; } else { - pr_err("ThinkPad ACPI EC access misbehaving, " - "disabling thermal sensors access\n"); + pr_err("ThinkPad ACPI EC access misbehaving, disabling thermal sensors access\n"); thermal_read_mode = TPACPI_THERMAL_NONE; } } else { @@ -6852,26 +6825,20 @@ static int __init brightness_init(struct ibm_init_struct *iibm) if (!brightness_enable) { dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, - "brightness support disabled by " - "module parameter\n"); + "brightness support disabled by module parameter\n"); return 1; } if (acpi_video_get_backlight_type() != acpi_backlight_vendor) { if (brightness_enable > 1) { - pr_info("Standard ACPI backlight interface " - "available, not loading native one\n"); + pr_info("Standard ACPI backlight interface available, not loading native one\n"); return 1; } else if (brightness_enable == 1) { - pr_warn("Cannot enable backlight brightness support, " - "ACPI is already handling it. Refer to the " - "acpi_backlight kernel parameter.\n"); + pr_warn("Cannot enable backlight brightness support, ACPI is already handling it. Refer to the acpi_backlight kernel parameter.\n"); return 1; } } else if (tp_features.bright_acpimode && brightness_enable > 1) { - pr_notice("Standard ACPI backlight interface not " - "available, thinkpad_acpi native " - "brightness control enabled\n"); + pr_notice("Standard ACPI backlight interface not available, thinkpad_acpi native brightness control enabled\n"); } /* @@ -6922,10 +6889,10 @@ static int __init brightness_init(struct ibm_init_struct *iibm) "brightness is supported\n"); if (quirks & TPACPI_BRGHT_Q_ASK) { - pr_notice("brightness: will use unverified default: " - "brightness_mode=%d\n", brightness_mode); - pr_notice("brightness: please report to %s whether it works well " - "or not on your ThinkPad\n", TPACPI_MAIL); + pr_notice("brightness: will use unverified default: brightness_mode=%d\n", + brightness_mode); + pr_notice("brightness: please report to %s whether it works well or not on your ThinkPad\n", + TPACPI_MAIL); } /* Added by mistake in early 2007. Probably useless, but it could @@ -6935,8 +6902,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) backlight_update_status(ibm_backlight_device); vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, - "brightness: registering brightness hotkeys " - "as change notification\n"); + "brightness: registering brightness hotkeys as change notification\n"); tpacpi_hotkey_driver_mask_set(hotkey_driver_mask | TP_ACPI_HKEY_BRGHTUP_MASK | TP_ACPI_HKEY_BRGHTDWN_MASK); @@ -7599,8 +7565,8 @@ static int __init volume_init(struct ibm_init_struct *iibm) return -EINVAL; if (volume_mode == TPACPI_VOL_MODE_UCMS_STEP) { - pr_err("UCMS step volume mode not implemented, " - "please contact %s\n", TPACPI_MAIL); + pr_err("UCMS step volume mode not implemented, please contact %s\n", + TPACPI_MAIL); return 1; } @@ -7613,8 +7579,7 @@ static int __init volume_init(struct ibm_init_struct *iibm) */ if (!alsa_enable) { vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, - "ALSA mixer disabled by parameter, " - "not loading volume subdriver...\n"); + "ALSA mixer disabled by parameter, not loading volume subdriver...\n"); return 1; } @@ -7706,12 +7671,9 @@ static int volume_read(struct seq_file *m) if (volume_control_allowed) { seq_printf(m, "commands:\tunmute, mute\n"); if (!tp_features.mixer_no_level_control) { - seq_printf(m, - "commands:\tup, down\n"); - seq_printf(m, - "commands:\tlevel " - " ( is 0-%d)\n", - TP_EC_VOLUME_MAX); + seq_printf(m, "commands:\tup, down\n"); + seq_printf(m, "commands:\tlevel ( is 0-%d)\n", + TP_EC_VOLUME_MAX); } } } @@ -7734,10 +7696,8 @@ static int volume_write(char *buf) if (!volume_control_allowed && tpacpi_lifecycle != TPACPI_LIFE_INIT) { if (unlikely(!tp_warned.volume_ctrl_forbidden)) { tp_warned.volume_ctrl_forbidden = 1; - pr_notice("Console audio control in monitor mode, " - "changes are not allowed\n"); - pr_notice("Use the volume_control=1 module parameter " - "to enable volume control\n"); + pr_notice("Console audio control in monitor mode, changes are not allowed\n"); + pr_notice("Use the volume_control=1 module parameter to enable volume control\n"); } return -EPERM; } @@ -8019,8 +7979,7 @@ TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */ static void fan_quirk1_setup(void) { if (fan_control_initial_status == 0x07) { - pr_notice("fan_init: initial fan status is unknown, " - "assuming it is in auto mode\n"); + pr_notice("fan_init: initial fan status is unknown, assuming it is in auto mode\n"); tp_features.fan_ctrl_status_undef = 1; } } @@ -8417,8 +8376,8 @@ static void fan_watchdog_fire(struct work_struct *ignored) pr_notice("fan watchdog: enabling fan\n"); rc = fan_set_enable(); if (rc < 0) { - pr_err("fan watchdog: error %d while enabling fan, " - "will try again later...\n", -rc); + pr_err("fan watchdog: error %d while enabling fan, will try again later...\n", + rc); /* reschedule for later */ fan_watchdog_reset(); } @@ -8715,8 +8674,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) "secondary fan support enabled\n"); } } else { - pr_err("ThinkPad ACPI EC access misbehaving, " - "fan status and control unavailable\n"); + pr_err("ThinkPad ACPI EC access misbehaving, fan status and control unavailable\n"); return 1; } } @@ -8815,8 +8773,8 @@ static void fan_suspend(void) fan_control_resume_level = 0; rc = fan_get_status_safe(&fan_control_resume_level); if (rc < 0) - pr_notice("failed to read fan level for later " - "restore during resume: %d\n", rc); + pr_notice("failed to read fan level for later restore during resume: %d\n", + rc); /* if it is undefined, don't attempt to restore it. * KEEP THIS LAST */ @@ -8935,20 +8893,17 @@ static int fan_read(struct seq_file *m) break; default: - seq_printf(m, " ( is 0-7, " - "auto, disengaged, full-speed)\n"); + seq_printf(m, " ( is 0-7, auto, disengaged, full-speed)\n"); break; } } if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) seq_printf(m, "commands:\tenable, disable\n" - "commands:\twatchdog ( " - "is 0 (off), 1-120 (seconds))\n"); + "commands:\twatchdog ( is 0 (off), 1-120 (seconds))\n"); if (fan_control_commands & TPACPI_FAN_CMD_SPEED) - seq_printf(m, "commands:\tspeed " - " ( is 0-65535)\n"); + seq_printf(m, "commands:\tspeed ( is 0-65535)\n"); return 0; } @@ -9474,8 +9429,7 @@ static int __must_check __init get_thinkpad_model_data( tp->ec_release = (ec_fw_string[4] << 8) | ec_fw_string[5]; } else { - pr_notice("ThinkPad firmware release %s " - "doesn't match the known patterns\n", + pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n", ec_fw_string); pr_notice("please report this to %s\n", TPACPI_MAIL); @@ -9670,8 +9624,7 @@ MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); module_param(force_load, bool, 0444); MODULE_PARM_DESC(force_load, - "Attempts to load the driver even on a " - "mis-identified ThinkPad when true"); + "Attempts to load the driver even on a mis-identified ThinkPad when true"); module_param_named(fan_control, fan_control_allowed, bool, 0444); MODULE_PARM_DESC(fan_control, @@ -9679,8 +9632,7 @@ MODULE_PARM_DESC(fan_control, module_param_named(brightness_mode, brightness_mode, uint, 0444); MODULE_PARM_DESC(brightness_mode, - "Selects brightness control strategy: " - "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM"); + "Selects brightness control strategy: 0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM"); module_param(brightness_enable, uint, 0444); MODULE_PARM_DESC(brightness_enable, @@ -9689,18 +9641,15 @@ MODULE_PARM_DESC(brightness_enable, #ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT module_param_named(volume_mode, volume_mode, uint, 0444); MODULE_PARM_DESC(volume_mode, - "Selects volume control strategy: " - "0=auto, 1=EC, 2=N/A, 3=EC+NVRAM"); + "Selects volume control strategy: 0=auto, 1=EC, 2=N/A, 3=EC+NVRAM"); module_param_named(volume_capabilities, volume_capabilities, uint, 0444); MODULE_PARM_DESC(volume_capabilities, - "Selects the mixer capabilites: " - "0=auto, 1=volume and mute, 2=mute only"); + "Selects the mixer capabilites: 0=auto, 1=volume and mute, 2=mute only"); module_param_named(volume_control, volume_control_allowed, bool, 0444); MODULE_PARM_DESC(volume_control, - "Enables software override for the console audio " - "control when true"); + "Enables software override for the console audio control when true"); module_param_named(software_mute, software_mute_requested, bool, 0444); MODULE_PARM_DESC(software_mute, @@ -9717,8 +9666,7 @@ MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer"); #define TPACPI_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ - MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \ - "at module load, see documentation") + MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command at module load, see documentation") TPACPI_PARAM(hotkey); TPACPI_PARAM(bluetooth); -- cgit v1.2.3 From 9b4bbbd2aebb2630c587faae911463198172a7e0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 May 2017 17:17:21 +0300 Subject: platform/x86: thinkpad_acpi: Add a comment about 0 in module_param_call() As per discussion [1] there are only few users of module_param_call() in kernel which prevent to read module parameters back. It thinkpad_acpi driver there is even no method do so. Thus, for now, add just a comment to explain why 0 is used as permissions in module_param_call(). [1]: https://patchwork.ozlabs.org/patch/713245/ Cc: Richard Weinberger Signed-off-by: Andy Shevchenko Acked-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d2f67a8071a6..cab115bece15 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9664,6 +9664,7 @@ module_param_named(enable, alsa_enable, bool, 0444); MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer"); #endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */ +/* The module parameter can't be read back, that's why 0 is used here */ #define TPACPI_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command at module load, see documentation") -- cgit v1.2.3 From 13bb0fd5519db658860ce3b3c89a7631a3ed1077 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 12 May 2017 17:11:54 +0200 Subject: platform/x86: peaq-wmi: Add new peaq-wmi driver PEAQ is a new European OEM, I've bought one of their 2-in-1 x86 devices, which is actually quite a nice device. Under Windows it has Dolby software for "better" sound and you can select different equalizer presets using a special button. This WMI interface for this button is not really nice, as it does not do notifies (it really does not I triple checked), but since I had already figured out the entire WMI interface for this I decided to go the full mile anyway and implement a WMI based input driver for this using input_polldev since, well, we need to poll. This commit adds support for this button making it report KEY_SOUND input events. KEY_SOUND is already used in various places to switch sound into theatre mode and things like that so it seems appropriate here. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Reviewed-by: Dmitry Torokhov [dvhart: minor declaration ordering and commit log typo fixes] Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/Kconfig | 7 +++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/peaq-wmi.c | 100 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 drivers/platform/x86/peaq-wmi.c (limited to 'drivers/platform') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 8489020ecf44..49a1d012f025 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -669,6 +669,13 @@ config MSI_WMI To compile this driver as a module, choose M here: the module will be called msi-wmi. +config PEAQ_WMI + tristate "PEAQ 2-in-1 WMI hotkey driver" + depends on ACPI_WMI + depends on INPUT + help + Say Y here if you want to support WMI-based hotkeys on PEAQ 2-in-1s. + config TOPSTAR_LAPTOP tristate "Topstar Laptop Extras" depends on ACPI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 182a3ed6605a..652d7c8a2e58 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_ACPI_WMI) += wmi.o obj-$(CONFIG_MSI_WMI) += msi-wmi.o +obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o diff --git a/drivers/platform/x86/peaq-wmi.c b/drivers/platform/x86/peaq-wmi.c new file mode 100644 index 000000000000..ca75b4dc437e --- /dev/null +++ b/drivers/platform/x86/peaq-wmi.c @@ -0,0 +1,100 @@ +/* + * PEAQ 2-in-1 WMI hotkey driver + * Copyright (C) 2017 Hans de Goede + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#define PEAQ_DOLBY_BUTTON_GUID "ABBC0F6F-8EA1-11D1-00A0-C90629100000" +#define PEAQ_DOLBY_BUTTON_METHOD_ID 5 +#define PEAQ_POLL_INTERVAL_MS 250 +#define PEAQ_POLL_IGNORE_MS 500 +#define PEAQ_POLL_MAX_MS 1000 + +MODULE_ALIAS("wmi:"PEAQ_DOLBY_BUTTON_GUID); + +static unsigned int peaq_ignore_events_counter; +static struct input_polled_dev *peaq_poll_dev; + +/* + * The Dolby button (yes really a Dolby button) causes an ACPI variable to get + * set on both press and release. The WMI method checks and clears that flag. + * So for a press + release we will get back One from the WMI method either once + * (if polling after the release) or twice (polling between press and release). + * We ignore events for 0.5s after the first event to avoid reporting 2 presses. + */ +static void peaq_wmi_poll(struct input_polled_dev *dev) +{ + union acpi_object obj; + acpi_status status; + u32 dummy = 0; + + struct acpi_buffer input = { sizeof(dummy), &dummy }; + struct acpi_buffer output = { sizeof(obj), &obj }; + + status = wmi_evaluate_method(PEAQ_DOLBY_BUTTON_GUID, 1, + PEAQ_DOLBY_BUTTON_METHOD_ID, + &input, &output); + if (ACPI_FAILURE(status)) + return; + + if (obj.type != ACPI_TYPE_INTEGER) { + dev_err(&peaq_poll_dev->input->dev, + "Error WMBC did not return an integer\n"); + return; + } + + if (peaq_ignore_events_counter && --peaq_ignore_events_counter > 0) + return; + + if (obj.integer.value) { + input_event(peaq_poll_dev->input, EV_KEY, KEY_SOUND, 1); + input_sync(peaq_poll_dev->input); + input_event(peaq_poll_dev->input, EV_KEY, KEY_SOUND, 0); + input_sync(peaq_poll_dev->input); + peaq_ignore_events_counter = max(1u, + PEAQ_POLL_IGNORE_MS / peaq_poll_dev->poll_interval); + } +} + +static int __init peaq_wmi_init(void) +{ + if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID)) + return -ENODEV; + + peaq_poll_dev = input_allocate_polled_device(); + if (!peaq_poll_dev) + return -ENOMEM; + + peaq_poll_dev->poll = peaq_wmi_poll; + peaq_poll_dev->poll_interval = PEAQ_POLL_INTERVAL_MS; + peaq_poll_dev->poll_interval_max = PEAQ_POLL_MAX_MS; + peaq_poll_dev->input->name = "PEAQ WMI hotkeys"; + peaq_poll_dev->input->phys = "wmi/input0"; + peaq_poll_dev->input->id.bustype = BUS_HOST; + input_set_capability(peaq_poll_dev->input, EV_KEY, KEY_SOUND); + + return input_register_polled_device(peaq_poll_dev); +} + +static void __exit peaq_wmi_exit(void) +{ + if (!wmi_has_guid(PEAQ_DOLBY_BUTTON_GUID)) + return; + + input_unregister_polled_device(peaq_poll_dev); +} + +module_init(peaq_wmi_init); +module_exit(peaq_wmi_exit); + +MODULE_DESCRIPTION("PEAQ 2-in-1 WMI hotkey driver"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 23ccd0363c9b1fbe7bbba3123cf2c1bc870f584a Mon Sep 17 00:00:00 2001 From: Guillaume Douézan-Grard Date: Mon, 15 May 2017 18:22:08 +0200 Subject: platform/x86: topstar-laptop: Add new device id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The latest Topstar BIOS updates (109_931P) advertise the "TPS0001" device id by default, preventing the topstar-laptop module from being loaded automatically. Signed-off-by: Guillaume Douézan-Grard Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/topstar-laptop.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c index 70205d222da9..1032c00b907b 100644 --- a/drivers/platform/x86/topstar-laptop.c +++ b/drivers/platform/x86/topstar-laptop.c @@ -162,6 +162,7 @@ static int acpi_topstar_remove(struct acpi_device *device) } static const struct acpi_device_id topstar_device_ids[] = { + { "TPS0001", 0 }, { "TPSACPI01", 0 }, { "", 0 }, }; -- cgit v1.2.3 From 46936fd65c107ed935e21bfa6fc00b4f510b1714 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 May 2017 15:07:03 +0200 Subject: platform/x86: ideapad-laptop: hide unused 'touchpad_store' A readonly sysfs property must not have a 'store' function: drivers/platform/x86/ideapad-laptop.c:438:16: error: 'touchpad_store' defined but not used [-Werror=unused-function] We can either comment it out or remove the function entirely, without a good reason one or or another I picked the second option. Fixes: 7f363145992c ("platform/x86: ideapad-laptop: Switch touchpad attribute to be RO") Signed-off-by: Arnd Bergmann Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index f7a4608cc60b..e4c83c15587d 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -435,9 +435,10 @@ static ssize_t touchpad_show(struct device *dev, return sprintf(buf, "%lu\n", result); } -static ssize_t touchpad_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +/* Switch to RO for now: It might be revisited in the future */ +static ssize_t __maybe_unused touchpad_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct ideapad_private *priv = dev_get_drvdata(dev); bool state; @@ -453,7 +454,6 @@ static ssize_t touchpad_store(struct device *dev, return count; } -/* Switch to RO for now: It might be revisited in the future */ static DEVICE_ATTR_RO(touchpad); static struct attribute *ideapad_attributes[] = { -- cgit v1.2.3 From 3cfd956b02ac7a9fb5f2414171f834871931fbd0 Mon Sep 17 00:00:00 2001 From: Hao Wei Tee Date: Mon, 22 May 2017 18:38:55 +0800 Subject: platform/x86: ideapad-laptop: Squelch ACPI event 1 Don't simply throw this to userspace via the sparse_keymap (which does not have a mapping for scancode 1), as this causes KEY_UNKNOWN to be emitted, which is a nuisance and of no use at all (it is not the right way to expose this ACPI event to userspace, anyway, and the original intention of the commit which added this (cfee5d63767b2e7997c1f36420d008abbe61565c) was only to suppress an unhandled event log message). Signed-off-by: Hao Wei Tee Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index e4c83c15587d..d48962569364 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -844,7 +844,6 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) case 8: case 7: case 6: - case 1: ideapad_input_report(priv, vpc_bit); break; case 5: @@ -862,6 +861,13 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) case 0: ideapad_check_special_buttons(priv); break; + case 1: + /* Some IdeaPads report event 1 every ~20 + * seconds while on battery power; some + * report this when changing to/from tablet + * mode. Squelch this event. + */ + break; default: pr_info("Unknown event: %lu\n", vpc_bit); } -- cgit v1.2.3 From 6bee1af9dcaa05c2b9289ec26ed121039dfea251 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 25 May 2017 15:15:10 -0700 Subject: platform/x86: intel_pmc_ipc: Mark ipc_data_readb() as __maybe_unused The function is currently not used, however it is part of the API and might be used in the future. Adding the attribute fixes the following warning when building with clang: drivers/platform/x86/intel_pmc_ipc.c:189:18: error: unused function 'ipc_data_readb' [-Werror,-Wunused-function] Signed-off-by: Matthias Kaehlcke Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index e4d4dfe3e1d1..bb792a52248b 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -186,7 +186,7 @@ static inline void ipc_data_writel(u32 data, u32 offset) writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset); } -static inline u8 ipc_data_readb(u32 offset) +static inline u8 __maybe_unused ipc_data_readb(u32 offset) { return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset); } -- cgit v1.2.3 From 251ebd0334835b7e8613067fd063d38c1eaddebd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 26 May 2017 12:53:48 +0200 Subject: platform/x86: intel_cht_int33fe: Set supplied-from property on max17047 dev Devices with the intel_cht_int33fe ACPI device use a max17047 fuel-gauge combined with a bq24272i charger, in order for the fuel-gauge driver to correctly display charging / discharging status it needs to know which charger is supplying the battery. This commit sets the supplied-from device property to the name of the bq24272i charger for this. Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_cht_int33fe.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 6a1b2ca5b6fe..da706e2c4232 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -34,6 +34,13 @@ struct cht_int33fe_data { struct i2c_client *pi3usb30532; }; +static const char * const max17047_suppliers[] = { "bq24190-charger" }; + +static const struct property_entry max17047_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", max17047_suppliers), + { } +}; + static int cht_int33fe_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -70,6 +77,7 @@ static int cht_int33fe_probe(struct i2c_client *client) memset(&board_info, 0, sizeof(board_info)); strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); + board_info.properties = max17047_props; data->max17047 = i2c_acpi_new_device(dev, 1, &board_info); if (!data->max17047) -- cgit v1.2.3 From 7ec3b54d162f5f1794a153e038b3940497579599 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 19 May 2017 09:44:41 +0200 Subject: platform/x86: fujitsu-laptop: distinguish current uses of device-specific data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In portions of the driver which use device-specific data, rename local variables from fujitsu_bl and fujitsu_laptop to priv in order to clearly distinguish these parts from code that uses module-wide data. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 48 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 7f49d92914c9..024ef339179a 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -348,26 +348,26 @@ static const struct key_entry keymap_backlight[] = { static int acpi_fujitsu_bl_input_setup(struct acpi_device *device) { - struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device); + struct fujitsu_bl *priv = acpi_driver_data(device); int ret; - fujitsu_bl->input = devm_input_allocate_device(&device->dev); - if (!fujitsu_bl->input) + priv->input = devm_input_allocate_device(&device->dev); + if (!priv->input) return -ENOMEM; - snprintf(fujitsu_bl->phys, sizeof(fujitsu_bl->phys), - "%s/video/input0", acpi_device_hid(device)); + snprintf(priv->phys, sizeof(priv->phys), "%s/video/input0", + acpi_device_hid(device)); - fujitsu_bl->input->name = acpi_device_name(device); - fujitsu_bl->input->phys = fujitsu_bl->phys; - fujitsu_bl->input->id.bustype = BUS_HOST; - fujitsu_bl->input->id.product = 0x06; + priv->input->name = acpi_device_name(device); + priv->input->phys = priv->phys; + priv->input->id.bustype = BUS_HOST; + priv->input->id.product = 0x06; - ret = sparse_keymap_setup(fujitsu_bl->input, keymap_backlight, NULL); + ret = sparse_keymap_setup(priv->input, keymap_backlight, NULL); if (ret) return ret; - return input_register_device(fujitsu_bl->input); + return input_register_device(priv->input); } static int fujitsu_backlight_register(struct acpi_device *device) @@ -541,27 +541,27 @@ static const struct dmi_system_id fujitsu_laptop_dmi_table[] = { static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) { - struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device); + struct fujitsu_laptop *priv = acpi_driver_data(device); int ret; - fujitsu_laptop->input = devm_input_allocate_device(&device->dev); - if (!fujitsu_laptop->input) + priv->input = devm_input_allocate_device(&device->dev); + if (!priv->input) return -ENOMEM; - snprintf(fujitsu_laptop->phys, sizeof(fujitsu_laptop->phys), - "%s/video/input0", acpi_device_hid(device)); + snprintf(priv->phys, sizeof(priv->phys), "%s/video/input0", + acpi_device_hid(device)); - fujitsu_laptop->input->name = acpi_device_name(device); - fujitsu_laptop->input->phys = fujitsu_laptop->phys; - fujitsu_laptop->input->id.bustype = BUS_HOST; - fujitsu_laptop->input->id.product = 0x06; + priv->input->name = acpi_device_name(device); + priv->input->phys = priv->phys; + priv->input->id.bustype = BUS_HOST; + priv->input->id.product = 0x06; dmi_check_system(fujitsu_laptop_dmi_table); - ret = sparse_keymap_setup(fujitsu_laptop->input, keymap, NULL); + ret = sparse_keymap_setup(priv->input, keymap, NULL); if (ret) return ret; - return input_register_device(fujitsu_laptop->input); + return input_register_device(priv->input); } static int fujitsu_laptop_platform_add(void) @@ -863,11 +863,11 @@ err_stop: static int acpi_fujitsu_laptop_remove(struct acpi_device *device) { - struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device); + struct fujitsu_laptop *priv = acpi_driver_data(device); fujitsu_laptop_platform_remove(); - kfifo_free(&fujitsu_laptop->fifo); + kfifo_free(&priv->fifo); return 0; } -- cgit v1.2.3 From 679374e49c6f6691f5b19751b3a2e36cba0c4a4d Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 19 May 2017 09:44:42 +0200 Subject: platform/x86: fujitsu-laptop: allocate fujitsu_bl in acpi_fujitsu_bl_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only allocate memory for struct fujitsu_bl when the FUJ02B1 ACPI device is present. Use devm_kzalloc() for allocating memory to simplify cleanup. Due to the fact that the power property of the backlight device created by the backlight driver is accessed from acpi_fujitsu_laptop_add(), pointer to the allocated memory will remain stored in a module-wide variable until the backlight driver is extracted into a separate module. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 024ef339179a..63a9b98967fa 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -392,6 +392,7 @@ static int fujitsu_backlight_register(struct acpi_device *device) static int acpi_fujitsu_bl_add(struct acpi_device *device) { + struct fujitsu_bl *priv; int state = 0; int error; @@ -401,10 +402,15 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) if (!device) return -EINVAL; + priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + fujitsu_bl = priv; fujitsu_bl->acpi_handle = device->handle; sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_BL_DEVICE_NAME); sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); - device->driver_data = fujitsu_bl; + device->driver_data = priv; error = acpi_fujitsu_bl_input_setup(device); if (error) @@ -837,7 +843,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); /* Sync backlight power status */ - if (fujitsu_bl->bl_device && + if (fujitsu_bl && fujitsu_bl->bl_device && acpi_video_get_backlight_type() == acpi_backlight_vendor) { if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN; @@ -995,13 +1001,9 @@ static int __init fujitsu_init(void) if (acpi_disabled) return -ENODEV; - fujitsu_bl = kzalloc(sizeof(struct fujitsu_bl), GFP_KERNEL); - if (!fujitsu_bl) - return -ENOMEM; - ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver); if (ret) - goto err_free_fujitsu_bl; + return ret; /* Register platform stuff */ @@ -1031,8 +1033,6 @@ err_unregister_platform_driver: platform_driver_unregister(&fujitsu_pf_driver); err_unregister_acpi: acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); -err_free_fujitsu_bl: - kfree(fujitsu_bl); return ret; } @@ -1047,8 +1047,6 @@ static void __exit fujitsu_cleanup(void) acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); - kfree(fujitsu_bl); - pr_info("driver unloaded\n"); } -- cgit v1.2.3 From f2db7c646b716160dbb8832c24d47a35e9ac299a Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 19 May 2017 09:44:43 +0200 Subject: platform/x86: fujitsu-laptop: use device-specific data in backlight code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To prevent using module-wide data in backlight-related code, employ acpi_driver_data() and bl_get_data() where possible to fetch device-specific data to work on in each function. This makes the input local variable in acpi_fujitsu_bl_notify() and the acpi_handle field of struct fujitsu_bl redundant, so remove them. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 75 ++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 63a9b98967fa..1124070aad2d 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -130,7 +130,6 @@ /* Device controlling the backlight and associated keys */ struct fujitsu_bl { - acpi_handle acpi_handle; struct input_dev *input; char phys[32]; struct backlight_device *bl_device; @@ -189,14 +188,15 @@ static int call_fext_func(int func, int op, int feature, int state) /* Hardware access for LCD brightness control */ -static int set_lcd_level(int level) +static int set_lcd_level(struct acpi_device *device, int level) { + struct fujitsu_bl *priv = acpi_driver_data(device); acpi_status status; char *method; switch (use_alt_lcd_levels) { case -1: - if (acpi_has_method(fujitsu_bl->acpi_handle, "SBL2")) + if (acpi_has_method(device->handle, "SBL2")) method = "SBL2"; else method = "SBLL"; @@ -212,71 +212,74 @@ static int set_lcd_level(int level) vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via %s [%d]\n", method, level); - if (level < 0 || level >= fujitsu_bl->max_brightness) + if (level < 0 || level >= priv->max_brightness) return -EINVAL; - status = acpi_execute_simple_method(fujitsu_bl->acpi_handle, method, - level); + status = acpi_execute_simple_method(device->handle, method, level); if (ACPI_FAILURE(status)) { vdbg_printk(FUJLAPTOP_DBG_ERROR, "Failed to evaluate %s\n", method); return -ENODEV; } - fujitsu_bl->brightness_level = level; + priv->brightness_level = level; return 0; } -static int get_lcd_level(void) +static int get_lcd_level(struct acpi_device *device) { + struct fujitsu_bl *priv = acpi_driver_data(device); unsigned long long state = 0; acpi_status status = AE_OK; vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n"); - status = acpi_evaluate_integer(fujitsu_bl->acpi_handle, "GBLL", NULL, - &state); + status = acpi_evaluate_integer(device->handle, "GBLL", NULL, &state); if (ACPI_FAILURE(status)) return 0; - fujitsu_bl->brightness_level = state & 0x0fffffff; + priv->brightness_level = state & 0x0fffffff; - return fujitsu_bl->brightness_level; + return priv->brightness_level; } -static int get_max_brightness(void) +static int get_max_brightness(struct acpi_device *device) { + struct fujitsu_bl *priv = acpi_driver_data(device); unsigned long long state = 0; acpi_status status = AE_OK; vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n"); - status = acpi_evaluate_integer(fujitsu_bl->acpi_handle, "RBLL", NULL, - &state); + status = acpi_evaluate_integer(device->handle, "RBLL", NULL, &state); if (ACPI_FAILURE(status)) return -1; - fujitsu_bl->max_brightness = state; + priv->max_brightness = state; - return fujitsu_bl->max_brightness; + return priv->max_brightness; } /* Backlight device stuff */ static int bl_get_brightness(struct backlight_device *b) { - return b->props.power == FB_BLANK_POWERDOWN ? 0 : get_lcd_level(); + struct acpi_device *device = bl_get_data(b); + + return b->props.power == FB_BLANK_POWERDOWN ? 0 : get_lcd_level(device); } static int bl_update_status(struct backlight_device *b) { + struct acpi_device *device = bl_get_data(b); + if (b->props.power == FB_BLANK_POWERDOWN) call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); else call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); - return set_lcd_level(b->props.brightness); + return set_lcd_level(device, b->props.brightness); } static const struct backlight_ops fujitsu_bl_ops = { @@ -372,20 +375,21 @@ static int acpi_fujitsu_bl_input_setup(struct acpi_device *device) static int fujitsu_backlight_register(struct acpi_device *device) { + struct fujitsu_bl *priv = acpi_driver_data(device); const struct backlight_properties props = { - .brightness = fujitsu_bl->brightness_level, - .max_brightness = fujitsu_bl->max_brightness - 1, + .brightness = priv->brightness_level, + .max_brightness = priv->max_brightness - 1, .type = BACKLIGHT_PLATFORM }; struct backlight_device *bd; bd = devm_backlight_device_register(&device->dev, "fujitsu-laptop", - &device->dev, NULL, + &device->dev, device, &fujitsu_bl_ops, &props); if (IS_ERR(bd)) return PTR_ERR(bd); - fujitsu_bl->bl_device = bd; + priv->bl_device = bd; return 0; } @@ -407,7 +411,6 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) return -ENOMEM; fujitsu_bl = priv; - fujitsu_bl->acpi_handle = device->handle; sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_BL_DEVICE_NAME); sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); device->driver_data = priv; @@ -416,7 +419,7 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) if (error) return error; - error = acpi_bus_update_power(fujitsu_bl->acpi_handle, &state); + error = acpi_bus_update_power(device->handle, &state); if (error) { pr_err("Error reading power state\n"); return error; @@ -434,9 +437,9 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) pr_err("_INI Method failed\n"); } - if (get_max_brightness() <= 0) - fujitsu_bl->max_brightness = FUJITSU_LCD_N_LEVELS; - get_lcd_level(); + if (get_max_brightness(device) <= 0) + priv->max_brightness = FUJITSU_LCD_N_LEVELS; + get_lcd_level(device); error = fujitsu_backlight_register(device); if (error) @@ -449,21 +452,19 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) { - struct input_dev *input; + struct fujitsu_bl *priv = acpi_driver_data(device); int oldb, newb; - input = fujitsu_bl->input; - if (event != ACPI_FUJITSU_NOTIFY_CODE1) { vdbg_printk(FUJLAPTOP_DBG_WARN, "unsupported event [0x%x]\n", event); - sparse_keymap_report_event(input, -1, 1, true); + sparse_keymap_report_event(priv->input, -1, 1, true); return; } - oldb = fujitsu_bl->brightness_level; - get_lcd_level(); - newb = fujitsu_bl->brightness_level; + oldb = priv->brightness_level; + get_lcd_level(device); + newb = priv->brightness_level; vdbg_printk(FUJLAPTOP_DBG_TRACE, "brightness button event [%i -> %i]\n", oldb, newb); @@ -472,9 +473,9 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) return; if (!disable_brightness_adjust) - set_lcd_level(newb); + set_lcd_level(device, newb); - sparse_keymap_report_event(input, oldb < newb, 1, true); + sparse_keymap_report_event(priv->input, oldb < newb, 1, true); } /* ACPI device for hotkey handling */ -- cgit v1.2.3 From a4b176ea9ab8b10d976dde61972ac884f888ba56 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 19 May 2017 09:44:44 +0200 Subject: platform/x86: fujitsu-laptop: allocate fujitsu_laptop in acpi_fujitsu_laptop_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only allocate memory for struct fujitsu_laptop when the FUJ02E3 ACPI device is present. Use devm_kzalloc() for allocating memory to simplify cleanup. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 1124070aad2d..3916f0ae59f3 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -776,6 +776,7 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) static int acpi_fujitsu_laptop_add(struct acpi_device *device) { + struct fujitsu_laptop *priv; int state = 0; int error; int i; @@ -783,11 +784,16 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) if (!device) return -EINVAL; + priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + fujitsu_laptop = priv; fujitsu_laptop->acpi_handle = device->handle; sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_LAPTOP_DEVICE_NAME); sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); - device->driver_data = fujitsu_laptop; + device->driver_data = priv; /* kfifo */ spin_lock_init(&fujitsu_laptop->fifo_lock); @@ -1014,22 +1020,14 @@ static int __init fujitsu_init(void) /* Register laptop driver */ - fujitsu_laptop = kzalloc(sizeof(struct fujitsu_laptop), GFP_KERNEL); - if (!fujitsu_laptop) { - ret = -ENOMEM; - goto err_unregister_platform_driver; - } - ret = acpi_bus_register_driver(&acpi_fujitsu_laptop_driver); if (ret) - goto err_free_fujitsu_laptop; + goto err_unregister_platform_driver; pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n"); return 0; -err_free_fujitsu_laptop: - kfree(fujitsu_laptop); err_unregister_platform_driver: platform_driver_unregister(&fujitsu_pf_driver); err_unregister_acpi: @@ -1042,8 +1040,6 @@ static void __exit fujitsu_cleanup(void) { acpi_bus_unregister_driver(&acpi_fujitsu_laptop_driver); - kfree(fujitsu_laptop); - platform_driver_unregister(&fujitsu_pf_driver); acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); -- cgit v1.2.3 From ca0d9eab0fb5b92c94de049241d639c2db66c3a6 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 19 May 2017 09:44:45 +0200 Subject: platform/x86: fujitsu-laptop: track the last instantiated FUJ02E3 ACPI device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fujitsu-laptop registers two ACPI drivers: one for ACPI device FUJ02B1 enabling backlight control and another for ACPI device FUJ02E3 which handles various other stuff (hotkeys, LEDs, etc.) In a perfect world, private data used by each of these drivers would be neatly encapsulated in a structure specific to a given driver instance. Sadly, firmware present on some Fujitsu laptops makes that impossible by exposing backlight power control (which is what the FUJ02B1 ACPI device should take care of) through the FUJ02E3 ACPI device. This means the backlight driver needs a way to access an ACPI device it is not bound to. When the backlight driver is extracted into a separate module, it will not be able to rely on a module-wide variable any more and such access will happen through an API exposed by fujitsu-laptop. For all known firmwares out in the wild, it seems that whenever the FUJ02B1 ACPI device is present, it is always accompanied by a single instance of the FUJ02E3 ACPI device. We could independently grab an ACPI handle to the FUJ02E3 ACPI device from the backlight driver, but that would require using a hardcoded absolute path to that ACPI device, which is subject to change. It is easier to simply store a module-wide pointer to the last (most likely only) FUJ02E3 ACPI device found, make the aforementioned API use it and cover our bases by warning the user if firmware exposes multiple FUJ02E3 ACPI devices. Introducing this pointer in advance allows us to get rid of the acpi_handle field of struct fujitsu_bl and also enables a bit more step-by-step migration to a device-specific implementation of call_fext_func(). Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 3916f0ae59f3..21bd60afea75 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -155,6 +155,7 @@ struct fujitsu_laptop { }; static struct fujitsu_laptop *fujitsu_laptop; +static struct acpi_device *fext; #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG static u32 dbg_level = 0x03; @@ -788,6 +789,9 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) if (!priv) return -ENOMEM; + WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended."); + fext = device; + fujitsu_laptop = priv; fujitsu_laptop->acpi_handle = device->handle; sprintf(acpi_device_name(device), "%s", -- cgit v1.2.3 From 84631e0c8b90411b424682eec4084006fae3f2cc Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 19 May 2017 09:44:46 +0200 Subject: platform/x86: fujitsu-laptop: explicitly pass ACPI device to call_fext_func() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for not using module-wide data in call_fext_func() by explicitly passing it a pointer to struct acpi_device while still using a module-wide pointer in each call. Doing this enables call_fext_func() to fetch the ACPI handle from its argument, making the acpi_handle field of struct fujitsu_laptop useless, so remove that field. While we are at it, the dev field of the same structure is assigned in acpi_fujitsu_laptop_add() but not used for anything, so remove it as well. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 81 ++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 39 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 21bd60afea75..b78c97ebfee4 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -143,8 +143,6 @@ static bool disable_brightness_adjust; /* Device used to access hotkeys and other features on the laptop */ struct fujitsu_laptop { - acpi_handle acpi_handle; - struct acpi_device *dev; struct input_dev *input; char phys[32]; struct platform_device *pf_device; @@ -163,7 +161,8 @@ static u32 dbg_level = 0x03; /* Fujitsu ACPI interface function */ -static int call_fext_func(int func, int op, int feature, int state) +static int call_fext_func(struct acpi_device *device, + int func, int op, int feature, int state) { union acpi_object params[4] = { { .integer.type = ACPI_TYPE_INTEGER, .integer.value = func }, @@ -175,8 +174,8 @@ static int call_fext_func(int func, int op, int feature, int state) unsigned long long value; acpi_status status; - status = acpi_evaluate_integer(fujitsu_laptop->acpi_handle, "FUNC", - &arg_list, &value); + status = acpi_evaluate_integer(device->handle, "FUNC", &arg_list, + &value); if (ACPI_FAILURE(status)) { vdbg_printk(FUJLAPTOP_DBG_ERROR, "Failed to evaluate FUNC\n"); return -ENODEV; @@ -276,9 +275,9 @@ static int bl_update_status(struct backlight_device *b) struct acpi_device *device = bl_get_data(b); if (b->props.power == FB_BLANK_POWERDOWN) - call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); + call_fext_func(fext, FUNC_BACKLIGHT, 0x1, 0x4, 0x3); else - call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); + call_fext_func(fext, FUNC_BACKLIGHT, 0x1, 0x4, 0x0); return set_lcd_level(device, b->props.brightness); } @@ -618,22 +617,22 @@ static int logolamp_set(struct led_classdev *cdev, if (brightness < LED_FULL) always = FUNC_LED_OFF; - ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); + ret = call_fext_func(fext, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); if (ret < 0) return ret; - return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always); + return call_fext_func(fext, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always); } static enum led_brightness logolamp_get(struct led_classdev *cdev) { int ret; - ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); + ret = call_fext_func(fext, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); if (ret == FUNC_LED_ON) return LED_FULL; - ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); + ret = call_fext_func(fext, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); if (ret == FUNC_LED_ON) return LED_HALF; @@ -650,10 +649,10 @@ static int kblamps_set(struct led_classdev *cdev, enum led_brightness brightness) { if (brightness >= LED_FULL) - return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, + return call_fext_func(fext, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); else - return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, + return call_fext_func(fext, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF); } @@ -661,7 +660,8 @@ static enum led_brightness kblamps_get(struct led_classdev *cdev) { enum led_brightness brightness = LED_OFF; - if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) + if (call_fext_func(fext, + FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) brightness = LED_FULL; return brightness; @@ -677,17 +677,18 @@ static int radio_led_set(struct led_classdev *cdev, enum led_brightness brightness) { if (brightness >= LED_FULL) - return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, + return call_fext_func(fext, FUNC_FLAGS, 0x5, RADIO_LED_ON, RADIO_LED_ON); else - return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, 0x0); + return call_fext_func(fext, FUNC_FLAGS, 0x5, RADIO_LED_ON, + 0x0); } static enum led_brightness radio_led_get(struct led_classdev *cdev) { enum led_brightness brightness = LED_OFF; - if (call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON) + if (call_fext_func(fext, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON) brightness = LED_FULL; return brightness; @@ -705,12 +706,12 @@ static int eco_led_set(struct led_classdev *cdev, { int curr; - curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0); + curr = call_fext_func(fext, FUNC_LEDS, 0x2, ECO_LED, 0x0); if (brightness >= LED_FULL) - return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, + return call_fext_func(fext, FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON); else - return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, + return call_fext_func(fext, FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON); } @@ -718,7 +719,7 @@ static enum led_brightness eco_led_get(struct led_classdev *cdev) { enum led_brightness brightness = LED_OFF; - if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) + if (call_fext_func(fext, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) brightness = LED_FULL; return brightness; @@ -734,15 +735,17 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) { int result; - if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { + if (call_fext_func(fext, + FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { result = devm_led_classdev_register(&device->dev, &logolamp_led); if (result) return result; } - if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && - (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { + if ((call_fext_func(fext, + FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && + (call_fext_func(fext, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { result = devm_led_classdev_register(&device->dev, &kblamps_led); if (result) return result; @@ -754,7 +757,7 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) * to also have an RF LED. Therefore use bit 24 as an indicator * that an RF LED is present. */ - if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { + if (call_fext_func(fext, FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { result = devm_led_classdev_register(&device->dev, &radio_led); if (result) return result; @@ -765,8 +768,9 @@ 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(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && - (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { + if ((call_fext_func(fext, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && + (call_fext_func(fext, + FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { result = devm_led_classdev_register(&device->dev, &eco_led); if (result) return result; @@ -793,7 +797,6 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) fext = device; fujitsu_laptop = priv; - fujitsu_laptop->acpi_handle = device->handle; sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_LAPTOP_DEVICE_NAME); sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); @@ -812,7 +815,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) if (error) goto err_free_fifo; - error = acpi_bus_update_power(fujitsu_laptop->acpi_handle, &state); + error = acpi_bus_update_power(device->handle, &state); if (error) { pr_err("Error reading power state\n"); goto err_free_fifo; @@ -822,8 +825,6 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) acpi_device_name(device), acpi_device_bid(device), !device->power.state ? "on" : "off"); - fujitsu_laptop->dev = device; - if (acpi_has_method(device->handle, METHOD_NAME__INI)) { vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); if (ACPI_FAILURE @@ -833,13 +834,13 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) } i = 0; - while (call_fext_func(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 */ vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); fujitsu_laptop->flags_supported = - call_fext_func(FUNC_FLAGS, 0x0, 0x0, 0x0); + 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. */ @@ -848,15 +849,16 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) if (fujitsu_laptop->flags_supported) fujitsu_laptop->flags_state = - call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0); + call_fext_func(fext, FUNC_FLAGS, 0x4, 0x0, 0x0); /* Suspect this is a keymap of the application panel, print it */ - pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); + pr_info("BTNI: [0x%x]\n", call_fext_func(fext, + FUNC_BUTTONS, 0x0, 0x0, 0x0)); /* Sync backlight power status */ if (fujitsu_bl && fujitsu_bl->bl_device && acpi_video_get_backlight_type() == acpi_backlight_vendor) { - if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) + if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN; else fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK; @@ -942,9 +944,10 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) if (fujitsu_laptop->flags_supported) fujitsu_laptop->flags_state = - call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0); + call_fext_func(fext, FUNC_FLAGS, 0x4, 0x0, 0x0); - while ((irb = call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 && + while ((irb = call_fext_func(fext, + FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 && i++ < MAX_HOTKEY_RINGBUFFER_SIZE) { scancode = irb & 0x4ff; if (sparse_keymap_entry_from_scancode(input, scancode)) @@ -961,7 +964,7 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) * handled in software; its state is queried using FUNC_FLAGS */ if ((fujitsu_laptop->flags_supported & BIT(26)) && - (call_fext_func(FUNC_FLAGS, 0x1, 0x0, 0x0) & BIT(26))) + (call_fext_func(fext, FUNC_FLAGS, 0x1, 0x0, 0x0) & BIT(26))) sparse_keymap_report_event(input, BIT(26), 1, true); } -- cgit v1.2.3 From a823f8e757a90ff5697fd9346c2dd0ede0083e89 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 19 May 2017 09:44:47 +0200 Subject: platform/x86: fujitsu-laptop: use device-specific data in LED-related code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to perform their duties, all LED callbacks need a pointer to the struct acpi_device representing the FUJ02E3 ACPI device. To limit the use of the module-wide pointer, the same pointer should be extracted from data that gets passed to LED callbacks as arguments. However, LED core does not currently support supplying driver-specific pointers to struct led_classdev callbacks, so the latter have to be implemented a bit differently than backlight device callbacks and platform device attribute callbacks. As the FUJ02E3 ACPI device is the parent device of all LED class devices registered by fujitsu-laptop, struct acpi_device representing the former can be extracted by following the parent link present inside the struct device belonging to the struct led_classdev passed as an argument to each LED callback. To get rid of module-wide structures defining LED class devices, allocate them dynamically using devm_kzalloc() and initialize them in acpi_fujitsu_laptop_leds_register(). Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 102 +++++++++++++++++----------------- 1 file changed, 52 insertions(+), 50 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index b78c97ebfee4..3d33be9f88f6 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -608,6 +608,7 @@ static void fujitsu_laptop_platform_remove(void) static int logolamp_set(struct led_classdev *cdev, enum led_brightness brightness) { + struct acpi_device *device = to_acpi_device(cdev->dev->parent); int poweron = FUNC_LED_ON, always = FUNC_LED_ON; int ret; @@ -617,136 +618,128 @@ static int logolamp_set(struct led_classdev *cdev, if (brightness < LED_FULL) always = FUNC_LED_OFF; - ret = call_fext_func(fext, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); + ret = call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); if (ret < 0) return ret; - return call_fext_func(fext, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always); + return call_fext_func(device, 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); int ret; - ret = call_fext_func(fext, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); + ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); if (ret == FUNC_LED_ON) return LED_FULL; - ret = call_fext_func(fext, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); + ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); if (ret == FUNC_LED_ON) return LED_HALF; return LED_OFF; } -static struct led_classdev logolamp_led = { - .name = "fujitsu::logolamp", - .brightness_set_blocking = logolamp_set, - .brightness_get = logolamp_get -}; - static int kblamps_set(struct led_classdev *cdev, enum led_brightness brightness) { + struct acpi_device *device = to_acpi_device(cdev->dev->parent); + if (brightness >= LED_FULL) - return call_fext_func(fext, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, + return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); else - return call_fext_func(fext, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, + return call_fext_func(device, 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(fext, + if (call_fext_func(device, FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) brightness = LED_FULL; return brightness; } -static struct led_classdev kblamps_led = { - .name = "fujitsu::kblamps", - .brightness_set_blocking = kblamps_set, - .brightness_get = kblamps_get -}; - static int radio_led_set(struct led_classdev *cdev, enum led_brightness brightness) { + struct acpi_device *device = to_acpi_device(cdev->dev->parent); + if (brightness >= LED_FULL) - return call_fext_func(fext, FUNC_FLAGS, 0x5, RADIO_LED_ON, + return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON, RADIO_LED_ON); else - return call_fext_func(fext, FUNC_FLAGS, 0x5, RADIO_LED_ON, + return call_fext_func(device, 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); enum led_brightness brightness = LED_OFF; - if (call_fext_func(fext, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON) + if (call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON) brightness = LED_FULL; return brightness; } -static struct led_classdev radio_led = { - .name = "fujitsu::radio_led", - .brightness_set_blocking = radio_led_set, - .brightness_get = radio_led_get, - .default_trigger = "rfkill-any" -}; - static int eco_led_set(struct led_classdev *cdev, enum led_brightness brightness) { + struct acpi_device *device = to_acpi_device(cdev->dev->parent); int curr; - curr = call_fext_func(fext, FUNC_LEDS, 0x2, ECO_LED, 0x0); + curr = call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0); if (brightness >= LED_FULL) - return call_fext_func(fext, FUNC_LEDS, 0x1, ECO_LED, + return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON); else - return call_fext_func(fext, FUNC_LEDS, 0x1, ECO_LED, + return call_fext_func(device, 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); enum led_brightness brightness = LED_OFF; - if (call_fext_func(fext, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) + if (call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) brightness = LED_FULL; return brightness; } -static struct led_classdev eco_led = { - .name = "fujitsu::eco_led", - .brightness_set_blocking = eco_led_set, - .brightness_get = eco_led_get -}; - static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) { + struct led_classdev *led; int result; - if (call_fext_func(fext, + if (call_fext_func(device, FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { - result = devm_led_classdev_register(&device->dev, - &logolamp_led); + led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); + led->name = "fujitsu::logolamp"; + led->brightness_set_blocking = logolamp_set; + led->brightness_get = logolamp_get; + result = devm_led_classdev_register(&device->dev, led); if (result) return result; } - if ((call_fext_func(fext, + if ((call_fext_func(device, FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && - (call_fext_func(fext, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { - result = devm_led_classdev_register(&device->dev, &kblamps_led); + (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { + led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); + led->name = "fujitsu::kblamps"; + led->brightness_set_blocking = kblamps_set; + led->brightness_get = kblamps_get; + result = devm_led_classdev_register(&device->dev, led); if (result) return result; } @@ -757,8 +750,13 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) * to also have an RF LED. Therefore use bit 24 as an indicator * that an RF LED is present. */ - if (call_fext_func(fext, FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { - result = devm_led_classdev_register(&device->dev, &radio_led); + if (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { + led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); + led->name = "fujitsu::radio_led"; + led->brightness_set_blocking = radio_led_set; + led->brightness_get = radio_led_get; + led->default_trigger = "rfkill-any"; + result = devm_led_classdev_register(&device->dev, led); if (result) return result; } @@ -768,10 +766,14 @@ 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(fext, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && - (call_fext_func(fext, + if ((call_fext_func(device, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && + (call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { - result = devm_led_classdev_register(&device->dev, &eco_led); + led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); + led->name = "fujitsu::eco_led"; + led->brightness_set_blocking = eco_led_set; + led->brightness_get = eco_led_get; + result = devm_led_classdev_register(&device->dev, led); if (result) return result; } -- cgit v1.2.3 From d659d11ad37b2bfa8192fdf0ca2850eba955fee5 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 19 May 2017 09:44:48 +0200 Subject: platform/x86: fujitsu-laptop: use device-specific data in remaining module code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid using module-wide data in remaining module code, employ acpi_driver_data() and dev_get_drvdata() to fetch device-specific data to work on in each function. This makes the input local variables in hotkey-related callbacks and the module-wide struct fujitsu_laptop redundant, so remove them. Adjust whitespace to make checkpatch happy. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 123 ++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 59 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 3d33be9f88f6..1c6fdd952c75 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -152,7 +152,6 @@ struct fujitsu_laptop { int flags_state; }; -static struct fujitsu_laptop *fujitsu_laptop; static struct acpi_device *fext; #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG @@ -290,9 +289,11 @@ static const struct backlight_ops fujitsu_bl_ops = { static ssize_t lid_show(struct device *dev, struct device_attribute *attr, char *buf) { - if (!(fujitsu_laptop->flags_supported & FLAG_LID)) + struct fujitsu_laptop *priv = dev_get_drvdata(dev); + + if (!(priv->flags_supported & FLAG_LID)) return sprintf(buf, "unknown\n"); - if (fujitsu_laptop->flags_state & FLAG_LID) + if (priv->flags_state & FLAG_LID) return sprintf(buf, "open\n"); else return sprintf(buf, "closed\n"); @@ -301,9 +302,11 @@ static ssize_t lid_show(struct device *dev, struct device_attribute *attr, static ssize_t dock_show(struct device *dev, struct device_attribute *attr, char *buf) { - if (!(fujitsu_laptop->flags_supported & FLAG_DOCK)) + struct fujitsu_laptop *priv = dev_get_drvdata(dev); + + if (!(priv->flags_supported & FLAG_DOCK)) return sprintf(buf, "unknown\n"); - if (fujitsu_laptop->flags_state & FLAG_DOCK) + if (priv->flags_state & FLAG_DOCK) return sprintf(buf, "docked\n"); else return sprintf(buf, "undocked\n"); @@ -312,9 +315,11 @@ static ssize_t dock_show(struct device *dev, struct device_attribute *attr, static ssize_t radios_show(struct device *dev, struct device_attribute *attr, char *buf) { - if (!(fujitsu_laptop->flags_supported & FLAG_RFKILL)) + struct fujitsu_laptop *priv = dev_get_drvdata(dev); + + if (!(priv->flags_supported & FLAG_RFKILL)) return sprintf(buf, "unknown\n"); - if (fujitsu_laptop->flags_state & FLAG_RFKILL) + if (priv->flags_state & FLAG_RFKILL) return sprintf(buf, "on\n"); else return sprintf(buf, "killed\n"); @@ -571,19 +576,22 @@ static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) return input_register_device(priv->input); } -static int fujitsu_laptop_platform_add(void) +static int fujitsu_laptop_platform_add(struct acpi_device *device) { + struct fujitsu_laptop *priv = acpi_driver_data(device); int ret; - fujitsu_laptop->pf_device = platform_device_alloc("fujitsu-laptop", -1); - if (!fujitsu_laptop->pf_device) + priv->pf_device = platform_device_alloc("fujitsu-laptop", -1); + if (!priv->pf_device) return -ENOMEM; - ret = platform_device_add(fujitsu_laptop->pf_device); + platform_set_drvdata(priv->pf_device, priv); + + ret = platform_device_add(priv->pf_device); if (ret) goto err_put_platform_device; - ret = sysfs_create_group(&fujitsu_laptop->pf_device->dev.kobj, + ret = sysfs_create_group(&priv->pf_device->dev.kobj, &fujitsu_pf_attribute_group); if (ret) goto err_del_platform_device; @@ -591,18 +599,20 @@ static int fujitsu_laptop_platform_add(void) return 0; err_del_platform_device: - platform_device_del(fujitsu_laptop->pf_device); + platform_device_del(priv->pf_device); err_put_platform_device: - platform_device_put(fujitsu_laptop->pf_device); + platform_device_put(priv->pf_device); return ret; } -static void fujitsu_laptop_platform_remove(void) +static void fujitsu_laptop_platform_remove(struct acpi_device *device) { - sysfs_remove_group(&fujitsu_laptop->pf_device->dev.kobj, + struct fujitsu_laptop *priv = acpi_driver_data(device); + + sysfs_remove_group(&priv->pf_device->dev.kobj, &fujitsu_pf_attribute_group); - platform_device_unregister(fujitsu_laptop->pf_device); + platform_device_unregister(priv->pf_device); } static int logolamp_set(struct led_classdev *cdev, @@ -798,16 +808,15 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended."); fext = device; - fujitsu_laptop = priv; sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_LAPTOP_DEVICE_NAME); sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); device->driver_data = priv; /* kfifo */ - spin_lock_init(&fujitsu_laptop->fifo_lock); - error = kfifo_alloc(&fujitsu_laptop->fifo, RINGBUFFERSIZE * sizeof(int), - GFP_KERNEL); + spin_lock_init(&priv->fifo_lock); + error = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int), + GFP_KERNEL); if (error) { pr_err("kfifo_alloc failed\n"); goto err_stop; @@ -836,25 +845,25 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) } i = 0; - while (call_fext_func(fext, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 + while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ; /* No action, result is discarded */ vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); - fujitsu_laptop->flags_supported = - call_fext_func(fext, FUNC_FLAGS, 0x0, 0x0, 0x0); + priv->flags_supported = call_fext_func(device, 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. */ - if (fujitsu_laptop->flags_supported == UNSUPPORTED_CMD) - fujitsu_laptop->flags_supported = 0; + if (priv->flags_supported == UNSUPPORTED_CMD) + priv->flags_supported = 0; - if (fujitsu_laptop->flags_supported) - fujitsu_laptop->flags_state = - call_fext_func(fext, FUNC_FLAGS, 0x4, 0x0, 0x0); + if (priv->flags_supported) + priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, + 0x0); /* Suspect this is a keymap of the application panel, print it */ - pr_info("BTNI: [0x%x]\n", call_fext_func(fext, + pr_info("BTNI: [0x%x]\n", call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0)); /* Sync backlight power status */ @@ -870,14 +879,14 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) if (error) goto err_free_fifo; - error = fujitsu_laptop_platform_add(); + error = fujitsu_laptop_platform_add(device); if (error) goto err_free_fifo; return 0; err_free_fifo: - kfifo_free(&fujitsu_laptop->fifo); + kfifo_free(&priv->fifo); err_stop: return error; } @@ -886,44 +895,42 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device) { struct fujitsu_laptop *priv = acpi_driver_data(device); - fujitsu_laptop_platform_remove(); + fujitsu_laptop_platform_remove(device); kfifo_free(&priv->fifo); return 0; } -static void acpi_fujitsu_laptop_press(int scancode) +static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode) { - struct input_dev *input = fujitsu_laptop->input; + struct fujitsu_laptop *priv = acpi_driver_data(device); int status; - status = kfifo_in_locked(&fujitsu_laptop->fifo, - (unsigned char *)&scancode, sizeof(scancode), - &fujitsu_laptop->fifo_lock); + status = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode, + sizeof(scancode), &priv->fifo_lock); if (status != sizeof(scancode)) { vdbg_printk(FUJLAPTOP_DBG_WARN, "Could not push scancode [0x%x]\n", scancode); return; } - sparse_keymap_report_event(input, scancode, 1, false); + sparse_keymap_report_event(priv->input, scancode, 1, false); vdbg_printk(FUJLAPTOP_DBG_TRACE, "Push scancode into ringbuffer [0x%x]\n", scancode); } -static void acpi_fujitsu_laptop_release(void) +static void acpi_fujitsu_laptop_release(struct acpi_device *device) { - struct input_dev *input = fujitsu_laptop->input; + struct fujitsu_laptop *priv = acpi_driver_data(device); int scancode, status; while (true) { - status = kfifo_out_locked(&fujitsu_laptop->fifo, + status = kfifo_out_locked(&priv->fifo, (unsigned char *)&scancode, - sizeof(scancode), - &fujitsu_laptop->fifo_lock); + sizeof(scancode), &priv->fifo_lock); if (status != sizeof(scancode)) return; - sparse_keymap_report_event(input, scancode, 0, false); + sparse_keymap_report_event(priv->input, scancode, 0, false); vdbg_printk(FUJLAPTOP_DBG_TRACE, "Pop scancode from ringbuffer [0x%x]\n", scancode); } @@ -931,31 +938,29 @@ static void acpi_fujitsu_laptop_release(void) static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) { - struct input_dev *input; + struct fujitsu_laptop *priv = acpi_driver_data(device); int scancode, i = 0; unsigned int irb; - input = fujitsu_laptop->input; - if (event != ACPI_FUJITSU_NOTIFY_CODE1) { vdbg_printk(FUJLAPTOP_DBG_WARN, "Unsupported event [0x%x]\n", event); - sparse_keymap_report_event(input, -1, 1, true); + sparse_keymap_report_event(priv->input, -1, 1, true); return; } - if (fujitsu_laptop->flags_supported) - fujitsu_laptop->flags_state = - call_fext_func(fext, FUNC_FLAGS, 0x4, 0x0, 0x0); + if (priv->flags_supported) + priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, + 0x0); - while ((irb = call_fext_func(fext, + 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(input, scancode)) - acpi_fujitsu_laptop_press(scancode); + if (sparse_keymap_entry_from_scancode(priv->input, scancode)) + acpi_fujitsu_laptop_press(device, scancode); else if (scancode == 0) - acpi_fujitsu_laptop_release(); + acpi_fujitsu_laptop_release(device); else vdbg_printk(FUJLAPTOP_DBG_WARN, "Unknown GIRB result [%x]\n", irb); @@ -965,9 +970,9 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is * handled in software; its state is queried using FUNC_FLAGS */ - if ((fujitsu_laptop->flags_supported & BIT(26)) && - (call_fext_func(fext, FUNC_FLAGS, 0x1, 0x0, 0x0) & BIT(26))) - sparse_keymap_report_event(input, BIT(26), 1, true); + if ((priv->flags_supported & BIT(26)) && + (call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0) & BIT(26))) + sparse_keymap_report_event(priv->input, BIT(26), 1, true); } /* Initialization */ -- cgit v1.2.3 From 074df51ca84d321f4d259b097d80ebca6a3ee9fe Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 17 Feb 2016 12:34:34 -0800 Subject: platform/x86: dell-wmi: Add a comment explaining the 0xb2 magic number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hotkey table is 0xb2, add a comment for clarity. Suggested-by: Darren Hart Signed-off-by: Andy Lutomirski Cc: Matthew Garrett Reviewed-by: Pali Rohár Reviewed-by: Andy Shevchenko Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-wmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 8a64c7967753..24467b1f0f21 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -449,6 +449,7 @@ static void __init handle_dmi_entry(const struct dmi_header *dm, if (results->err || results->keymap) return; /* We already found the hotkey table. */ + /* The Dell hotkey table is type 0xB2. Scan until we find it. */ if (dm->type != 0xb2) return; -- cgit v1.2.3 From e4f2e3f0ea13cf3424c0f23d01424c68a428333b Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 17 Feb 2016 12:38:07 -0800 Subject: platform/x86: dell-wmi: Add a better description for "stealth mode" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is based on Mario's explanation and observation of my laptop. Suggested-by: "Pali Rohár" Signed-off-by: Andy Lutomirski Cc: Mario Limonciello Cc: Matthew Garrett Reviewed-by: Andy Shevchenko Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-wmi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 24467b1f0f21..73aee0d1aea4 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -272,7 +272,12 @@ static const struct key_entry dell_wmi_keymap_type_0010[] __initconst = { /* RGB keyboard backlight control */ { KE_IGNORE, 0x154, { KEY_RESERVED } }, - /* Stealth mode toggle */ + /* + * Stealth mode toggle. This will "disable all lights and sounds". + * The action is performed by the BIOS and EC; the WMI event is just + * a notification. On the XPS 13 9350, this is Fn+F7, and there's + * a BIOS setting to enable and disable the hotkey. + */ { KE_IGNORE, 0x155, { KEY_RESERVED } }, /* Rugged magnetic dock attach/detach events */ -- cgit v1.2.3 From 5d4be5f2b1f1919ffbf1ca5c9c014692848bafd1 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 17 Feb 2016 12:43:06 -0800 Subject: platform/x86: dell-rbtn: Improve explanation about DELLABC6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to Mario at Dell, the DELLABC6 device should not be used on a Linux system. It also conflicts with Intel-HID and its interactions with Network Manager. Document that we are aware of the device, but that we are intentionally ignoring it. Signed-off-by: Andy Lutomirski [dvhart: New commit message and minor comment wording fixes] Cc: Mario Limonciello Cc: "Pali Rohár" Reviewed-by: Andy Shevchenko Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-rbtn.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/dell-rbtn.c b/drivers/platform/x86/dell-rbtn.c index dcd9f40a4b18..f5c53ea87158 100644 --- a/drivers/platform/x86/dell-rbtn.c +++ b/drivers/platform/x86/dell-rbtn.c @@ -221,16 +221,27 @@ static const struct acpi_device_id rbtn_ids[] = { /* * This driver can also handle the "DELLABC6" device that - * appears on the XPS 13 9350, but that device is disabled - * by the DSDT unless booted with acpi_osi="!Windows 2012" - * acpi_osi="!Windows 2013". Even if we boot that and bind - * the driver, we seem to have inconsistent behavior in - * which NetworkManager can get out of sync with the rfkill - * state. + * appears on the XPS 13 9350, but that device is disabled by + * the DSDT unless booted with acpi_osi="!Windows 2012" + * acpi_osi="!Windows 2013". * - * On the XPS 13 9350 and similar laptops, we're not supposed to - * use DELLABC6 at all. Instead, we handle the rfkill button - * via the intel-hid driver. + * According to Mario at Dell: + * + * DELLABC6 is a custom interface that was created solely to + * have airplane mode support for Windows 7. For Windows 10 + * the proper interface is to use that which is handled by + * intel-hid. A OEM airplane mode driver is not used. + * + * Since the kernel doesn't identify as Windows 7 it would be + * incorrect to do attempt to use that interface. + * + * Even if we override _OSI and bind to DELLABC6, we end up with + * inconsistent behavior in which userspace can get out of sync + * with the rfkill state as it conflicts with events from + * intel-hid. + * + * The upshot is that it is better to just ignore DELLABC6 + * devices. */ { "", 0 }, -- cgit v1.2.3 From 0f97ebd1bcc408fe1820e83e6e11b06ce041018f Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 24 Nov 2015 20:15:48 -0800 Subject: platform/x86: wmi: Drop "Mapper (un)loaded" messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WMI is just a driver. There is no need to announce when it is loaded. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index ceeb8c188ef3..004358140239 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -836,7 +836,6 @@ static int __init acpi_wmi_init(void) return error; } - pr_info("Mapper loaded\n"); return 0; } @@ -844,8 +843,6 @@ static void __exit acpi_wmi_exit(void) { acpi_bus_unregister_driver(&acpi_wmi_driver); class_unregister(&wmi_class); - - pr_info("Mapper unloaded\n"); } subsys_initcall(acpi_wmi_init); -- cgit v1.2.3 From 7f5809bf6e2e43953e48e86cb039736a6448e070 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 19 Nov 2015 14:44:46 -0800 Subject: platform/x86: wmi: Pass the acpi_device through to parse_wdg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will need the device to convert to a bus architecture and bind WMI to the platform device. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 004358140239..c6e11b573ef3 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -606,7 +606,8 @@ static struct class wmi_class = { }; static int wmi_create_device(const struct guid_block *gblock, - struct wmi_block *wblock, acpi_handle handle) + struct wmi_block *wblock, + struct acpi_device *device) { wblock->dev.class = &wmi_class; @@ -645,7 +646,7 @@ static bool guid_already_parsed(const char *guid_string) /* * Parse the _WDG method for the GUID data blocks */ -static int parse_wdg(acpi_handle handle) +static int parse_wdg(struct acpi_device *device) { struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; union acpi_object *obj; @@ -655,7 +656,7 @@ static int parse_wdg(acpi_handle handle) int retval; u32 i, total; - status = acpi_evaluate_object(handle, "_WDG", NULL, &out); + status = acpi_evaluate_object(device->handle, "_WDG", NULL, &out); if (ACPI_FAILURE(status)) return -ENXIO; @@ -679,7 +680,7 @@ static int parse_wdg(acpi_handle handle) if (!wblock) return -ENOMEM; - wblock->handle = handle; + wblock->handle = device->handle; wblock->gblock = gblock[i]; /* @@ -689,7 +690,7 @@ static int parse_wdg(acpi_handle handle) for device creation. */ if (!guid_already_parsed(gblock[i].guid)) { - retval = wmi_create_device(&gblock[i], wblock, handle); + retval = wmi_create_device(&gblock[i], wblock, device); if (retval) { wmi_free_devices(); goto out_free_pointer; @@ -806,7 +807,7 @@ static int acpi_wmi_add(struct acpi_device *device) return -ENODEV; } - error = parse_wdg(device->handle); + error = parse_wdg(device); if (error) { acpi_remove_address_space_handler(device->handle, ACPI_ADR_SPACE_EC, -- cgit v1.2.3 From 46492ee4a6ca82e878218059c0f8539c8f9ac14e Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 24 Nov 2015 19:54:46 -0800 Subject: platform/x86: wmi: Clean up acpi_wmi_add MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rearrange acpi_wmi_add to use Linux's error handling conventions. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index c6e11b573ef3..ac60a5119751 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -803,20 +803,24 @@ static int acpi_wmi_add(struct acpi_device *device) &acpi_wmi_ec_space_handler, NULL, NULL); if (ACPI_FAILURE(status)) { - pr_err("Error installing EC region handler\n"); + dev_err(&device->dev, "Error installing EC region handler\n"); return -ENODEV; } error = parse_wdg(device); if (error) { - acpi_remove_address_space_handler(device->handle, - ACPI_ADR_SPACE_EC, - &acpi_wmi_ec_space_handler); pr_err("Failed to parse WDG method\n"); - return error; + goto err_remove_handler; } return 0; + +err_remove_handler: + acpi_remove_address_space_handler(device->handle, + ACPI_ADR_SPACE_EC, + &acpi_wmi_ec_space_handler); + + return error; } static int __init acpi_wmi_init(void) -- cgit v1.2.3 From b0e86302973d9e710c722a8436cc7e099d2a5b0d Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 24 Nov 2015 19:50:01 -0800 Subject: platform/x86: wmi: Track wmi devices per ACPI device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we free all devices when we detach from any ACPI node. Instead, keep track of which node WMI devices are attached to and free them only as needed. While we are at it, match up notifications with the device they came from correctly. This will make our behavior more straightforward on systems with more than one WMI node in the ACPI tables (e.g. the Dell XPS 13 9350). This also adds a warning when GUIDs are not unique. NB: The guid_string parameter in guid_already_parsed was a little-endian binary GUID, not a string. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 58 ++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 22 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index ac60a5119751..faaa9a7c9c2e 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -64,7 +64,7 @@ struct guid_block { struct wmi_block { struct list_head list; struct guid_block gblock; - acpi_handle handle; + struct acpi_device *acpi_device; wmi_notify_handler handler; void *handler_data; struct device dev; @@ -147,7 +147,7 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable) acpi_handle handle; block = &wblock->gblock; - handle = wblock->handle; + handle = wblock->acpi_device->handle; snprintf(method, 5, "WE%02X", block->notify_id); status = acpi_execute_simple_method(handle, method, enable); @@ -186,7 +186,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) return AE_ERROR; block = &wblock->gblock; - handle = wblock->handle; + handle = wblock->acpi_device->handle; if (!(block->flags & ACPI_WMI_METHOD)) return AE_BAD_DATA; @@ -248,7 +248,7 @@ struct acpi_buffer *out) return AE_ERROR; block = &wblock->gblock; - handle = wblock->handle; + handle = wblock->acpi_device->handle; if (block->instance_count < instance) return AE_BAD_PARAMETER; @@ -321,7 +321,7 @@ const struct acpi_buffer *in) return AE_ERROR; block = &wblock->gblock; - handle = wblock->handle; + handle = wblock->acpi_device->handle; if (block->instance_count < instance) return AE_BAD_PARAMETER; @@ -525,8 +525,8 @@ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) if ((gblock->flags & ACPI_WMI_EVENT) && (gblock->notify_id == event)) - return acpi_evaluate_object(wblock->handle, "_WED", - &input, out); + return acpi_evaluate_object(wblock->acpi_device->handle, + "_WED", &input, out); } return AE_NOT_FOUND; @@ -618,27 +618,40 @@ static int wmi_create_device(const struct guid_block *gblock, return device_register(&wblock->dev); } -static void wmi_free_devices(void) +static void wmi_free_devices(struct acpi_device *device) { struct wmi_block *wblock, *next; /* Delete devices for all the GUIDs */ list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { - list_del(&wblock->list); - if (wblock->dev.class) - device_unregister(&wblock->dev); - else - kfree(wblock); + if (wblock->acpi_device == device) { + list_del(&wblock->list); + if (wblock->dev.class) + device_unregister(&wblock->dev); + else + kfree(wblock); + } } } -static bool guid_already_parsed(const char *guid_string) +static bool guid_already_parsed(struct acpi_device *device, + const u8 *guid) { struct wmi_block *wblock; - list_for_each_entry(wblock, &wmi_block_list, list) - if (memcmp(wblock->gblock.guid, guid_string, 16) == 0) + list_for_each_entry(wblock, &wmi_block_list, list) { + if (memcmp(wblock->gblock.guid, guid, 16) == 0) { + /* + * Because we historically didn't track the relationship + * between GUIDs and ACPI nodes, we don't know whether + * we need to suppress GUIDs that are unique on a + * given node but duplicated across nodes. + */ + dev_warn(&device->dev, "duplicate WMI GUID %pUL (first instance was on %s)\n", + guid, dev_name(&wblock->acpi_device->dev)); return true; + } + } return false; } @@ -680,7 +693,7 @@ static int parse_wdg(struct acpi_device *device) if (!wblock) return -ENOMEM; - wblock->handle = device->handle; + wblock->acpi_device = device; wblock->gblock = gblock[i]; /* @@ -689,10 +702,10 @@ static int parse_wdg(struct acpi_device *device) case yet, so for now, we'll just ignore the duplicate for device creation. */ - if (!guid_already_parsed(gblock[i].guid)) { + if (!guid_already_parsed(device, gblock[i].guid)) { retval = wmi_create_device(&gblock[i], wblock, device); if (retval) { - wmi_free_devices(); + wmi_free_devices(device); goto out_free_pointer; } } @@ -767,8 +780,9 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event) wblock = list_entry(p, struct wmi_block, list); block = &wblock->gblock; - if ((block->flags & ACPI_WMI_EVENT) && - (block->notify_id == event)) { + if (wblock->acpi_device == device && + (block->flags & ACPI_WMI_EVENT) && + (block->notify_id == event)) { if (wblock->handler) wblock->handler(event, wblock->handler_data); if (debug_event) { @@ -788,7 +802,7 @@ static int acpi_wmi_remove(struct acpi_device *device) { acpi_remove_address_space_handler(device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); - wmi_free_devices(); + wmi_free_devices(device); return 0; } -- cgit v1.2.3 From 844af950da946cfab227a04b950614da04cb6275 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 24 Nov 2015 19:49:23 -0800 Subject: platform/x86: wmi: Turn WMI into a bus driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WMI is logically a bus: the WMI driver binds to an ACPI node (or more than one), and each instance of the WMI driver enumerates its children and hopes that drivers will attach to the children that are useful. This patch gives WMI a driver model bus type and the ability to match to drivers. The bus itself is a device in the new "wmi_bus" class, and all of the individual WMI devices are slotted into the device hierarchy correctly. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 197 +++++++++++++++++++++++++++++++++++---------- include/linux/wmi.h | 47 +++++++++++ 2 files changed, 201 insertions(+), 43 deletions(-) create mode 100644 include/linux/wmi.h (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index faaa9a7c9c2e..f06b7c00339d 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -37,6 +37,7 @@ #include #include #include +#include #include ACPI_MODULE_NAME("wmi"); @@ -44,8 +45,6 @@ MODULE_AUTHOR("Carlos Corbacho"); MODULE_DESCRIPTION("ACPI-WMI Mapping Driver"); MODULE_LICENSE("GPL"); -#define ACPI_WMI_CLASS "wmi" - static LIST_HEAD(wmi_block_list); struct guid_block { @@ -62,12 +61,12 @@ struct guid_block { }; struct wmi_block { + struct wmi_device dev; struct list_head list; struct guid_block gblock; struct acpi_device *acpi_device; wmi_notify_handler handler; void *handler_data; - struct device dev; }; @@ -102,8 +101,8 @@ static const struct acpi_device_id wmi_device_ids[] = { MODULE_DEVICE_TABLE(acpi, wmi_device_ids); static struct acpi_driver acpi_wmi_driver = { - .name = "wmi", - .class = ACPI_WMI_CLASS, + .name = "acpi-wmi", + .owner = THIS_MODULE, .ids = wmi_device_ids, .ops = { .add = acpi_wmi_add, @@ -545,77 +544,146 @@ bool wmi_has_guid(const char *guid_string) } EXPORT_SYMBOL_GPL(wmi_has_guid); +static struct wmi_block *dev_to_wblock(struct device *dev) +{ + return container_of(dev, struct wmi_block, dev.dev); +} + +static struct wmi_device *dev_to_wdev(struct device *dev) +{ + return container_of(dev, struct wmi_device, dev); +} + /* * sysfs interface */ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct wmi_block *wblock; - - wblock = dev_get_drvdata(dev); - if (!wblock) { - strcat(buf, "\n"); - return strlen(buf); - } + struct wmi_block *wblock = dev_to_wblock(dev); return sprintf(buf, "wmi:%pUL\n", wblock->gblock.guid); } static DEVICE_ATTR_RO(modalias); +static ssize_t guid_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wmi_block *wblock = dev_to_wblock(dev); + + return sprintf(buf, "%pUL\n", wblock->gblock.guid); +} +static DEVICE_ATTR_RO(guid); + static struct attribute *wmi_attrs[] = { &dev_attr_modalias.attr, + &dev_attr_guid.attr, NULL, }; ATTRIBUTE_GROUPS(wmi); static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { - char guid_string[37]; - - struct wmi_block *wblock; + struct wmi_block *wblock = dev_to_wblock(dev); - if (add_uevent_var(env, "MODALIAS=")) + if (add_uevent_var(env, "MODALIAS=wmi:%pUL", wblock->gblock.guid)) return -ENOMEM; - wblock = dev_get_drvdata(dev); - if (!wblock) + if (add_uevent_var(env, "WMI_GUID=%pUL", wblock->gblock.guid)) return -ENOMEM; - sprintf(guid_string, "%pUL", wblock->gblock.guid); + return 0; +} + +static void wmi_dev_release(struct device *dev) +{ + struct wmi_block *wblock = dev_to_wblock(dev); + + kfree(wblock); +} + +static int wmi_dev_match(struct device *dev, struct device_driver *driver) +{ + struct wmi_driver *wmi_driver = + container_of(driver, struct wmi_driver, driver); + struct wmi_block *wblock = dev_to_wblock(dev); + const struct wmi_device_id *id = wmi_driver->id_table; - strcpy(&env->buf[env->buflen - 1], "wmi:"); - memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36); - env->buflen += 40; + while (id->guid_string) { + uuid_le driver_guid; + + if (WARN_ON(uuid_le_to_bin(id->guid_string, &driver_guid))) + continue; + if (!memcmp(&driver_guid, wblock->gblock.guid, 16)) + return 1; + + id++; + } return 0; } -static void wmi_dev_free(struct device *dev) +static int wmi_dev_probe(struct device *dev) { - struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev); + struct wmi_block *wblock = dev_to_wblock(dev); + struct wmi_driver *wdriver = + container_of(dev->driver, struct wmi_driver, driver); + int ret = 0; + + if (ACPI_FAILURE(wmi_method_enable(wblock, 1))) + dev_warn(dev, "failed to enable device -- probing anyway\n"); + + if (wdriver->probe) { + ret = wdriver->probe(dev_to_wdev(dev)); + if (ret != 0 && ACPI_FAILURE(wmi_method_enable(wblock, 0))) + dev_warn(dev, "failed to disable device\n"); + } + + return ret; +} + +static int wmi_dev_remove(struct device *dev) +{ + struct wmi_block *wblock = dev_to_wblock(dev); + struct wmi_driver *wdriver = + container_of(dev->driver, struct wmi_driver, driver); + int ret = 0; + + if (wdriver->remove) + ret = wdriver->remove(dev_to_wdev(dev)); + + if (ACPI_FAILURE(wmi_method_enable(wblock, 0))) + dev_warn(dev, "failed to disable device\n"); - kfree(wmi_block); + return ret; } -static struct class wmi_class = { +static struct class wmi_bus_class = { + .name = "wmi_bus", +}; + +static struct bus_type wmi_bus_type = { .name = "wmi", - .dev_release = wmi_dev_free, - .dev_uevent = wmi_dev_uevent, .dev_groups = wmi_groups, + .match = wmi_dev_match, + .uevent = wmi_dev_uevent, + .probe = wmi_dev_probe, + .remove = wmi_dev_remove, }; -static int wmi_create_device(const struct guid_block *gblock, +static int wmi_create_device(struct device *wmi_bus_dev, + const struct guid_block *gblock, struct wmi_block *wblock, struct acpi_device *device) { - wblock->dev.class = &wmi_class; + wblock->dev.dev.bus = &wmi_bus_type; + wblock->dev.dev.parent = wmi_bus_dev; - dev_set_name(&wblock->dev, "%pUL", gblock->guid); + dev_set_name(&wblock->dev.dev, "%pUL", gblock->guid); - dev_set_drvdata(&wblock->dev, wblock); + wblock->dev.dev.release = wmi_dev_release; - return device_register(&wblock->dev); + return device_register(&wblock->dev.dev); } static void wmi_free_devices(struct acpi_device *device) @@ -626,8 +694,8 @@ static void wmi_free_devices(struct acpi_device *device) list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { if (wblock->acpi_device == device) { list_del(&wblock->list); - if (wblock->dev.class) - device_unregister(&wblock->dev); + if (wblock->dev.dev.bus) + device_unregister(&wblock->dev.dev); else kfree(wblock); } @@ -659,7 +727,7 @@ static bool guid_already_parsed(struct acpi_device *device, /* * Parse the _WDG method for the GUID data blocks */ -static int parse_wdg(struct acpi_device *device) +static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) { struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; union acpi_object *obj; @@ -703,7 +771,8 @@ static int parse_wdg(struct acpi_device *device) for device creation. */ if (!guid_already_parsed(device, gblock[i].guid)) { - retval = wmi_create_device(&gblock[i], wblock, device); + retval = wmi_create_device(wmi_bus_dev, &gblock[i], + wblock, device); if (retval) { wmi_free_devices(device); goto out_free_pointer; @@ -803,12 +872,15 @@ static int acpi_wmi_remove(struct acpi_device *device) acpi_remove_address_space_handler(device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); wmi_free_devices(device); + device_unregister((struct device *)acpi_driver_data(device)); + device->driver_data = NULL; return 0; } static int acpi_wmi_add(struct acpi_device *device) { + struct device *wmi_bus_dev; acpi_status status; int error; @@ -821,14 +893,25 @@ static int acpi_wmi_add(struct acpi_device *device) return -ENODEV; } - error = parse_wdg(device); + wmi_bus_dev = device_create(&wmi_bus_class, &device->dev, MKDEV(0, 0), + NULL, "wmi_bus-%s", dev_name(&device->dev)); + if (IS_ERR(wmi_bus_dev)) { + error = PTR_ERR(wmi_bus_dev); + goto err_remove_handler; + } + device->driver_data = wmi_bus_dev; + + error = parse_wdg(wmi_bus_dev, device); if (error) { pr_err("Failed to parse WDG method\n"); - goto err_remove_handler; + goto err_remove_busdev; } return 0; +err_remove_busdev: + device_unregister(wmi_bus_dev); + err_remove_handler: acpi_remove_address_space_handler(device->handle, ACPI_ADR_SPACE_EC, @@ -837,6 +920,22 @@ err_remove_handler: return error; } +int __must_check __wmi_driver_register(struct wmi_driver *driver, + struct module *owner) +{ + driver->driver.owner = owner; + driver->driver.bus = &wmi_bus_type; + + return driver_register(&driver->driver); +} +EXPORT_SYMBOL(__wmi_driver_register); + +void wmi_driver_unregister(struct wmi_driver *driver) +{ + driver_unregister(&driver->driver); +} +EXPORT_SYMBOL(wmi_driver_unregister); + static int __init acpi_wmi_init(void) { int error; @@ -844,24 +943,36 @@ static int __init acpi_wmi_init(void) if (acpi_disabled) return -ENODEV; - error = class_register(&wmi_class); + error = class_register(&wmi_bus_class); if (error) return error; + error = bus_register(&wmi_bus_type); + if (error) + goto err_unreg_class; + error = acpi_bus_register_driver(&acpi_wmi_driver); if (error) { pr_err("Error loading mapper\n"); - class_unregister(&wmi_class); - return error; + goto err_unreg_bus; } return 0; + +err_unreg_class: + class_unregister(&wmi_bus_class); + +err_unreg_bus: + bus_unregister(&wmi_bus_type); + + return error; } static void __exit acpi_wmi_exit(void) { acpi_bus_unregister_driver(&acpi_wmi_driver); - class_unregister(&wmi_class); + class_unregister(&wmi_bus_class); + bus_unregister(&wmi_bus_type); } subsys_initcall(acpi_wmi_init); diff --git a/include/linux/wmi.h b/include/linux/wmi.h new file mode 100644 index 000000000000..29ed34b4dae1 --- /dev/null +++ b/include/linux/wmi.h @@ -0,0 +1,47 @@ +/* + * wmi.h - ACPI WMI interface + * + * Copyright (c) 2015 Andrew Lutomirski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _LINUX_WMI_H +#define _LINUX_WMI_H + +#include +#include + +struct wmi_device { + struct device dev; +}; + +struct wmi_device_id { + const char *guid_string; +}; + +struct wmi_driver { + struct device_driver driver; + const struct wmi_device_id *id_table; + + int (*probe)(struct wmi_device *wdev); + int (*remove)(struct wmi_device *wdev); +}; + +extern int __must_check __wmi_driver_register(struct wmi_driver *driver, + struct module *owner); +extern void wmi_driver_unregister(struct wmi_driver *driver); +#define wmi_driver_register(driver) __wmi_driver_register((driver), THIS_MODULE) + +#define module_wmi_driver(__wmi_driver) \ + module_driver(__wmi_driver, wmi_driver_register, \ + wmi_driver_unregister) + +#endif -- cgit v1.2.3 From a1c31bcd5772b13b39b028126fa9de918c36cf26 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 25 Nov 2015 08:24:42 -0800 Subject: platform/x86: wmi: Fix error handling when creating devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have two memory leaks. If guid_already_parsed returned true, we leak the wmi_block. If wmi_create_device failed, we leak the device. Simplify the logic and fix both of them. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index f06b7c00339d..31c317fb65dc 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -757,6 +757,15 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) if (debug_dump_wdg) wmi_dump_wdg(&gblock[i]); + /* + * Some WMI devices, like those for nVidia hooks, have a + * duplicate GUID. It's not clear what we should do in this + * case yet, so for now, we'll just ignore the duplicate + * for device creation. + */ + if (guid_already_parsed(device, gblock[i].guid)) + continue; + wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); if (!wblock) return -ENOMEM; @@ -764,19 +773,12 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) wblock->acpi_device = device; wblock->gblock = gblock[i]; - /* - Some WMI devices, like those for nVidia hooks, have a - duplicate GUID. It's not clear what we should do in this - case yet, so for now, we'll just ignore the duplicate - for device creation. - */ - if (!guid_already_parsed(device, gblock[i].guid)) { - retval = wmi_create_device(wmi_bus_dev, &gblock[i], - wblock, device); - if (retval) { - wmi_free_devices(device); - goto out_free_pointer; - } + retval = wmi_create_device(wmi_bus_dev, &gblock[i], + wblock, device); + if (retval) { + put_device(&wblock->dev.dev); + wmi_free_devices(device); + goto out_free_pointer; } list_add_tail(&wblock->list, &wmi_block_list); -- cgit v1.2.3 From d79b10740210c6c686a9256b801e08f7679e04e2 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 25 Nov 2015 10:01:37 -0800 Subject: platform/x86: wmi: Split devices into types and add basic sysfs attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Divide the "data", "method" and "event" types. All devices get "instance_count" and "expensive" attributes, data and method devices get "object_id" attributes, and event devices get "notify_id" attributes. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 78 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 31c317fb65dc..33a3609d54db 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -575,13 +575,65 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(guid); +static ssize_t instance_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct wmi_block *wblock = dev_to_wblock(dev); + + return sprintf(buf, "%d\n", (int)wblock->gblock.instance_count); +} +static DEVICE_ATTR_RO(instance_count); + +static ssize_t expensive_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct wmi_block *wblock = dev_to_wblock(dev); + + return sprintf(buf, "%d\n", + (wblock->gblock.flags & ACPI_WMI_EXPENSIVE) != 0); +} +static DEVICE_ATTR_RO(expensive); + static struct attribute *wmi_attrs[] = { &dev_attr_modalias.attr, &dev_attr_guid.attr, + &dev_attr_instance_count.attr, + &dev_attr_expensive.attr, NULL, }; ATTRIBUTE_GROUPS(wmi); +static ssize_t notify_id_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wmi_block *wblock = dev_to_wblock(dev); + + return sprintf(buf, "%02X\n", (unsigned int)wblock->gblock.notify_id); +} +static DEVICE_ATTR_RO(notify_id); + +static struct attribute *wmi_event_attrs[] = { + &dev_attr_notify_id.attr, + NULL, +}; +ATTRIBUTE_GROUPS(wmi_event); + +static ssize_t object_id_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wmi_block *wblock = dev_to_wblock(dev); + + return sprintf(buf, "%c%c\n", wblock->gblock.object_id[0], + wblock->gblock.object_id[1]); +} +static DEVICE_ATTR_RO(object_id); + +static struct attribute *wmi_data_or_method_attrs[] = { + &dev_attr_object_id.attr, + NULL, +}; +ATTRIBUTE_GROUPS(wmi_data_or_method); + static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { struct wmi_block *wblock = dev_to_wblock(dev); @@ -671,6 +723,24 @@ static struct bus_type wmi_bus_type = { .remove = wmi_dev_remove, }; +static struct device_type wmi_type_event = { + .name = "event", + .groups = wmi_event_groups, + .release = wmi_dev_release, +}; + +static struct device_type wmi_type_method = { + .name = "method", + .groups = wmi_data_or_method_groups, + .release = wmi_dev_release, +}; + +static struct device_type wmi_type_data = { + .name = "data", + .groups = wmi_data_or_method_groups, + .release = wmi_dev_release, +}; + static int wmi_create_device(struct device *wmi_bus_dev, const struct guid_block *gblock, struct wmi_block *wblock, @@ -681,7 +751,13 @@ static int wmi_create_device(struct device *wmi_bus_dev, dev_set_name(&wblock->dev.dev, "%pUL", gblock->guid); - wblock->dev.dev.release = wmi_dev_release; + if (gblock->flags & ACPI_WMI_EVENT) { + wblock->dev.dev.type = &wmi_type_event; + } else if (gblock->flags & ACPI_WMI_METHOD) { + wblock->dev.dev.type = &wmi_type_method; + } else { + wblock->dev.dev.type = &wmi_type_data; + } return device_register(&wblock->dev.dev); } -- cgit v1.2.3 From d4fc91adfde11c41295d1cf001bdbec5d6879016 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 25 Nov 2015 14:03:43 -0800 Subject: platform/x86: wmi: Probe data objects for read and write capabilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Dell XPS 13 9350 has one RW data object, one RO data object, and one totally inaccessible data object. Check for the existence of the accessor methods and report in sysfs. The docs also permit WQxx getters for single-instance objects to take no parameters. Probe for that as well to avoid ACPICA warnings about mismatched signatures. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 101 +++++++++++++++++++++++++++++++++++++++++++-- include/linux/wmi.h | 6 +++ 2 files changed, 103 insertions(+), 4 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 33a3609d54db..651693a5e0ea 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -67,6 +67,8 @@ struct wmi_block { struct acpi_device *acpi_device; wmi_notify_handler handler; void *handler_data; + + bool read_takes_no_args; /* only defined if readable */ }; @@ -138,6 +140,30 @@ static bool find_guid(const char *guid_string, struct wmi_block **out) return false; } +static int get_subobj_info(acpi_handle handle, const char *pathname, + struct acpi_device_info **info) +{ + struct acpi_device_info *dummy_info, **info_ptr; + acpi_handle subobj_handle; + acpi_status status; + + status = acpi_get_handle(handle, (char *)pathname, &subobj_handle); + if (status == AE_NOT_FOUND) + return -ENOENT; + else if (ACPI_FAILURE(status)) + return -EIO; + + info_ptr = info ? info : &dummy_info; + status = acpi_get_object_info(subobj_handle, info_ptr); + if (ACPI_FAILURE(status)) + return -EIO; + + if (!info) + kfree(dummy_info); + + return 0; +} + static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable) { struct guid_block *block = NULL; @@ -261,6 +287,9 @@ struct acpi_buffer *out) wq_params[0].type = ACPI_TYPE_INTEGER; wq_params[0].integer.value = instance; + if (instance == 0 && wblock->read_takes_no_args) + input.count = 0; + /* * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to * enable collection. @@ -628,11 +657,37 @@ static ssize_t object_id_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(object_id); -static struct attribute *wmi_data_or_method_attrs[] = { +static ssize_t readable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wmi_device *wdev = dev_to_wdev(dev); + + return sprintf(buf, "%d\n", (int)wdev->readable); +} +static DEVICE_ATTR_RO(readable); + +static ssize_t writeable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wmi_device *wdev = dev_to_wdev(dev); + + return sprintf(buf, "%d\n", (int)wdev->writeable); +} +static DEVICE_ATTR_RO(writeable); + +static struct attribute *wmi_data_attrs[] = { + &dev_attr_object_id.attr, + &dev_attr_readable.attr, + &dev_attr_writeable.attr, + NULL, +}; +ATTRIBUTE_GROUPS(wmi_data); + +static struct attribute *wmi_method_attrs[] = { &dev_attr_object_id.attr, NULL, }; -ATTRIBUTE_GROUPS(wmi_data_or_method); +ATTRIBUTE_GROUPS(wmi_method); static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { @@ -731,13 +786,13 @@ static struct device_type wmi_type_event = { static struct device_type wmi_type_method = { .name = "method", - .groups = wmi_data_or_method_groups, + .groups = wmi_method_groups, .release = wmi_dev_release, }; static struct device_type wmi_type_data = { .name = "data", - .groups = wmi_data_or_method_groups, + .groups = wmi_data_groups, .release = wmi_dev_release, }; @@ -756,7 +811,45 @@ static int wmi_create_device(struct device *wmi_bus_dev, } else if (gblock->flags & ACPI_WMI_METHOD) { wblock->dev.dev.type = &wmi_type_method; } else { + struct acpi_device_info *info; + char method[5]; + int result; + wblock->dev.dev.type = &wmi_type_data; + + strcpy(method, "WQ"); + strncat(method, wblock->gblock.object_id, 2); + result = get_subobj_info(device->handle, method, &info); + + if (result == 0) { + wblock->dev.readable = true; + + /* + * The Microsoft documentation specifically states: + * + * Data blocks registered with only a single instance + * can ignore the parameter. + * + * ACPICA will get mad at us if we call the method + * with the wrong number of arguments, so check what + * our method expects. (On some Dell laptops, WQxx + * may not be a method at all.) + */ + if (info->type != ACPI_TYPE_METHOD || + info->param_count == 0) + wblock->read_takes_no_args = true; + + kfree(info); + } + + strcpy(method, "WS"); + strncat(method, wblock->gblock.object_id, 2); + result = get_subobj_info(device->handle, method, NULL); + + if (result == 0) { + wblock->dev.writeable = true; + } + } return device_register(&wblock->dev.dev); diff --git a/include/linux/wmi.h b/include/linux/wmi.h index 29ed34b4dae1..53095006821e 100644 --- a/include/linux/wmi.h +++ b/include/linux/wmi.h @@ -21,6 +21,12 @@ struct wmi_device { struct device dev; + + /* + * These are true for data objects that support reads and writes, + * respectively. + */ + bool readable, writeable; }; struct wmi_device_id { -- cgit v1.2.3 From 6ee50aaa9a20c7c11c964c249440857ab58ece36 Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Tue, 6 Jun 2017 10:13:49 -0700 Subject: platform/x86: wmi: Instantiate all devices before adding them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At some point, we will want sub-drivers to get references to other devices on the same WMI bus. This change is needed to avoid races. This ends up simplifying the setup code and fixing some leaks, too. This is based on the original work of Andy Lutomirski , but includes several modifications, many in response to review from Michał Kępień : https://www.spinics.net/lists/platform-driver-x86/msg08201.html Signed-off-by: Darren Hart (VMware) Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki --- drivers/platform/x86/wmi.c | 49 +++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 20 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 651693a5e0ea..fbce8765e222 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -796,7 +796,7 @@ static struct device_type wmi_type_data = { .release = wmi_dev_release, }; -static int wmi_create_device(struct device *wmi_bus_dev, +static void wmi_create_device(struct device *wmi_bus_dev, const struct guid_block *gblock, struct wmi_block *wblock, struct acpi_device *device) @@ -852,7 +852,7 @@ static int wmi_create_device(struct device *wmi_bus_dev, } - return device_register(&wblock->dev.dev); + device_initialize(&wblock->dev.dev); } static void wmi_free_devices(struct acpi_device *device) @@ -863,10 +863,7 @@ static void wmi_free_devices(struct acpi_device *device) list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { if (wblock->acpi_device == device) { list_del(&wblock->list); - if (wblock->dev.dev.bus) - device_unregister(&wblock->dev.dev); - else - kfree(wblock); + device_unregister(&wblock->dev.dev); } } } @@ -899,11 +896,11 @@ static bool guid_already_parsed(struct acpi_device *device, static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) { struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *obj; const struct guid_block *gblock; - struct wmi_block *wblock; + struct wmi_block *wblock, *next; + union acpi_object *obj; acpi_status status; - int retval; + int retval = 0; u32 i, total; status = acpi_evaluate_object(device->handle, "_WDG", NULL, &out); @@ -936,19 +933,15 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) continue; wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); - if (!wblock) - return -ENOMEM; + if (!wblock) { + retval = -ENOMEM; + break; + } wblock->acpi_device = device; wblock->gblock = gblock[i]; - retval = wmi_create_device(wmi_bus_dev, &gblock[i], - wblock, device); - if (retval) { - put_device(&wblock->dev.dev); - wmi_free_devices(device); - goto out_free_pointer; - } + wmi_create_device(wmi_bus_dev, &gblock[i], wblock, device); list_add_tail(&wblock->list, &wmi_block_list); @@ -958,11 +951,27 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) } } - retval = 0; + /* + * Now that all of the devices are created, add them to the + * device tree and probe subdrivers. + */ + list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { + if (wblock->acpi_device != device) + continue; + + retval = device_add(&wblock->dev.dev); + if (retval) { + dev_err(wmi_bus_dev, "failed to register %pULL\n", + wblock->gblock.guid); + if (debug_event) + wmi_method_enable(wblock, 0); + list_del(&wblock->list); + put_device(&wblock->dev.dev); + } + } out_free_pointer: kfree(out.pointer); - return retval; } -- cgit v1.2.3 From 1686f5444546c3b53547aa8736afcf05833ed31a Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 25 Nov 2015 17:33:25 -0800 Subject: platform/x86: wmi: Incorporate acpi_install_notify_handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a platform driver, acpi_driver.notify will not be available, so use acpi_install_notify_handler as we will be converting to a platform driver. This gives event drivers a simple way to handle events. It also seems closer to what the Windows docs suggest that Windows does: it sounds like, in Windows, the mapper is responsible for called _WED before dispatching to the subdriver. Signed-off-by: Andy Lutomirski [dvhart: merge two development commits and update commit message] Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 89 +++++++++++++++++++++++++++++++++++++--------- include/linux/wmi.h | 1 + 2 files changed, 73 insertions(+), 17 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index fbce8765e222..4395d83ba9cc 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -93,7 +93,6 @@ MODULE_PARM_DESC(debug_dump_wdg, static int acpi_wmi_remove(struct acpi_device *device); static int acpi_wmi_add(struct acpi_device *device); -static void acpi_wmi_notify(struct acpi_device *device, u32 event); static const struct acpi_device_id wmi_device_ids[] = { {"PNP0C14", 0}, @@ -109,7 +108,6 @@ static struct acpi_driver acpi_wmi_driver = { .ops = { .add = acpi_wmi_add, .remove = acpi_wmi_remove, - .notify = acpi_wmi_notify, }, }; @@ -1019,36 +1017,80 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address, } } -static void acpi_wmi_notify(struct acpi_device *device, u32 event) +static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, + void *context) { struct guid_block *block; struct wmi_block *wblock; struct list_head *p; + bool found_it = false; list_for_each(p, &wmi_block_list) { wblock = list_entry(p, struct wmi_block, list); block = &wblock->gblock; - if (wblock->acpi_device == device && + if (wblock->acpi_device->handle == handle && (block->flags & ACPI_WMI_EVENT) && - (block->notify_id == event)) { - if (wblock->handler) - wblock->handler(event, wblock->handler_data); - if (debug_event) { - pr_info("DEBUG Event GUID: %pUL\n", - wblock->gblock.guid); - } - - acpi_bus_generate_netlink_event( - device->pnp.device_class, dev_name(&device->dev), - event, 0); + (block->notify_id == event)) + { + found_it = true; break; } } + + if (!found_it) + return; + + /* If a driver is bound, then notify the driver. */ + if (wblock->dev.dev.driver) { + struct wmi_driver *driver; + struct acpi_object_list input; + union acpi_object params[1]; + struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status; + + driver = container_of(wblock->dev.dev.driver, + struct wmi_driver, driver); + + input.count = 1; + input.pointer = params; + params[0].type = ACPI_TYPE_INTEGER; + params[0].integer.value = event; + + status = acpi_evaluate_object(wblock->acpi_device->handle, + "_WED", &input, &evdata); + if (ACPI_FAILURE(status)) { + dev_warn(&wblock->dev.dev, + "failed to get event data\n"); + return; + } + + if (driver->notify) + driver->notify(&wblock->dev, + (union acpi_object *)evdata.pointer); + + kfree(evdata.pointer); + } else if (wblock->handler) { + /* Legacy handler */ + wblock->handler(event, wblock->handler_data); + } + + if (debug_event) { + pr_info("DEBUG Event GUID: %pUL\n", + wblock->gblock.guid); + } + + acpi_bus_generate_netlink_event( + wblock->acpi_device->pnp.device_class, + dev_name(&wblock->dev.dev), + event, 0); + } static int acpi_wmi_remove(struct acpi_device *device) { + acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + acpi_wmi_notify_handler); acpi_remove_address_space_handler(device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); wmi_free_devices(device); @@ -1073,11 +1115,20 @@ static int acpi_wmi_add(struct acpi_device *device) return -ENODEV; } + status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + acpi_wmi_notify_handler, + NULL); + if (ACPI_FAILURE(status)) { + dev_err(&device->dev, "Error installing notify handler\n"); + error = -ENODEV; + goto err_remove_ec_handler; + } + wmi_bus_dev = device_create(&wmi_bus_class, &device->dev, MKDEV(0, 0), NULL, "wmi_bus-%s", dev_name(&device->dev)); if (IS_ERR(wmi_bus_dev)) { error = PTR_ERR(wmi_bus_dev); - goto err_remove_handler; + goto err_remove_notify_handler; } device->driver_data = wmi_bus_dev; @@ -1092,7 +1143,11 @@ static int acpi_wmi_add(struct acpi_device *device) err_remove_busdev: device_unregister(wmi_bus_dev); -err_remove_handler: +err_remove_notify_handler: + acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + acpi_wmi_notify_handler); + +err_remove_ec_handler: acpi_remove_address_space_handler(device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); diff --git a/include/linux/wmi.h b/include/linux/wmi.h index 53095006821e..c6eedfd94e7d 100644 --- a/include/linux/wmi.h +++ b/include/linux/wmi.h @@ -39,6 +39,7 @@ struct wmi_driver { int (*probe)(struct wmi_device *wdev); int (*remove)(struct wmi_device *wdev); + void (*notify)(struct wmi_device *device, union acpi_object *data); }; extern int __must_check __wmi_driver_register(struct wmi_driver *driver, -- cgit v1.2.3 From 56a370259db4f6204d3514431d1629e0a7135b53 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 25 Nov 2015 18:19:26 -0800 Subject: platform/x86: wmi: Add a new interface to read block data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wmi_query_block is unnecessarily indirect. Add a straightforward method for wmi bus drivers to use to read block data. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 54 ++++++++++++++++++++++++++++++++-------------- include/linux/wmi.h | 4 ++++ 2 files changed, 42 insertions(+), 16 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 4395d83ba9cc..f8fdd48b78c4 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -244,19 +244,10 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) } EXPORT_SYMBOL_GPL(wmi_evaluate_method); -/** - * wmi_query_block - Return contents of a WMI block - * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba - * @instance: Instance index - * &out: Empty buffer to return the contents of the data block to - * - * Return the contents of an ACPI-WMI data block to a buffer - */ -acpi_status wmi_query_block(const char *guid_string, u8 instance, -struct acpi_buffer *out) +static acpi_status __query_block(struct wmi_block *wblock, u8 instance, + struct acpi_buffer *out) { struct guid_block *block = NULL; - struct wmi_block *wblock = NULL; acpi_handle handle; acpi_status status, wc_status = AE_ERROR; struct acpi_object_list input; @@ -264,12 +255,9 @@ struct acpi_buffer *out) char method[5]; char wc_method[5] = "WC"; - if (!guid_string || !out) + if (!out) return AE_BAD_PARAMETER; - if (!find_guid(guid_string, &wblock)) - return AE_ERROR; - block = &wblock->gblock; handle = wblock->acpi_device->handle; @@ -320,8 +308,42 @@ struct acpi_buffer *out) return status; } + +/** + * wmi_query_block - Return contents of a WMI block (deprecated) + * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba + * @instance: Instance index + * &out: Empty buffer to return the contents of the data block to + * + * Return the contents of an ACPI-WMI data block to a buffer + */ +acpi_status wmi_query_block(const char *guid_string, u8 instance, + struct acpi_buffer *out) +{ + struct wmi_block *wblock; + + if (!guid_string) + return AE_BAD_PARAMETER; + + if (!find_guid(guid_string, &wblock)) + return AE_ERROR; + + return __query_block(wblock, instance, out); +} EXPORT_SYMBOL_GPL(wmi_query_block); +union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance) +{ + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; + struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev); + + if (ACPI_FAILURE(__query_block(wblock, instance, &out))) + return NULL; + + return (union acpi_object *)out.pointer; +} +EXPORT_SYMBOL_GPL(wmidev_block_query); + /** * wmi_set_block - Write to a WMI block * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba @@ -331,7 +353,7 @@ EXPORT_SYMBOL_GPL(wmi_query_block); * Write the contents of the input buffer to an ACPI-WMI data block */ acpi_status wmi_set_block(const char *guid_string, u8 instance, -const struct acpi_buffer *in) + const struct acpi_buffer *in) { struct guid_block *block = NULL; struct wmi_block *wblock = NULL; diff --git a/include/linux/wmi.h b/include/linux/wmi.h index c6eedfd94e7d..0ab254019488 100644 --- a/include/linux/wmi.h +++ b/include/linux/wmi.h @@ -29,6 +29,10 @@ struct wmi_device { bool readable, writeable; }; +/* Caller must kfree the result. */ +extern union acpi_object *wmidev_block_query(struct wmi_device *wdev, + u8 instance); + struct wmi_device_id { const char *guid_string; }; -- cgit v1.2.3 From 9599ed919f9bc42ea0bdd49745bc8451019e0447 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 27 Nov 2015 11:56:02 -0800 Subject: platform/x86: wmi: Bind the platform device, not the ACPI node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have the PNP glue to instantiate platform devices for the ACPI devices that WMI drives. WMI should therefore attach to the platform device, not the ACPI node. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 57 +++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 24 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index f8fdd48b78c4..52452ec5099b 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -91,8 +92,8 @@ module_param(debug_dump_wdg, bool, 0444); MODULE_PARM_DESC(debug_dump_wdg, "Dump available WMI interfaces [0/1]"); -static int acpi_wmi_remove(struct acpi_device *device); -static int acpi_wmi_add(struct acpi_device *device); +static int acpi_wmi_remove(struct platform_device *device); +static int acpi_wmi_probe(struct platform_device *device); static const struct acpi_device_id wmi_device_ids[] = { {"PNP0C14", 0}, @@ -101,14 +102,13 @@ static const struct acpi_device_id wmi_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, wmi_device_ids); -static struct acpi_driver acpi_wmi_driver = { - .name = "acpi-wmi", - .owner = THIS_MODULE, - .ids = wmi_device_ids, - .ops = { - .add = acpi_wmi_add, - .remove = acpi_wmi_remove, +static struct platform_driver acpi_wmi_driver = { + .driver = { + .name = "acpi-wmi", + .acpi_match_table = wmi_device_ids, }, + .probe = acpi_wmi_probe, + .remove = acpi_wmi_remove, }; /* @@ -1109,26 +1109,34 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, } -static int acpi_wmi_remove(struct acpi_device *device) +static int acpi_wmi_remove(struct platform_device *device) { - acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + struct acpi_device *acpi_device = ACPI_COMPANION(&device->dev); + + acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler); - acpi_remove_address_space_handler(device->handle, + acpi_remove_address_space_handler(acpi_device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); - wmi_free_devices(device); - device_unregister((struct device *)acpi_driver_data(device)); - device->driver_data = NULL; + wmi_free_devices(acpi_device); + device_unregister((struct device *)dev_get_drvdata(&device->dev)); return 0; } -static int acpi_wmi_add(struct acpi_device *device) +static int acpi_wmi_probe(struct platform_device *device) { + struct acpi_device *acpi_device; struct device *wmi_bus_dev; acpi_status status; int error; - status = acpi_install_address_space_handler(device->handle, + acpi_device = ACPI_COMPANION(&device->dev); + if (!acpi_device) { + dev_err(&device->dev, "ACPI companion is missing\n"); + return -ENODEV; + } + + status = acpi_install_address_space_handler(acpi_device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler, NULL, NULL); @@ -1137,7 +1145,8 @@ static int acpi_wmi_add(struct acpi_device *device) return -ENODEV; } - status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + status = acpi_install_notify_handler(acpi_device->handle, + ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler, NULL); if (ACPI_FAILURE(status)) { @@ -1152,9 +1161,9 @@ static int acpi_wmi_add(struct acpi_device *device) error = PTR_ERR(wmi_bus_dev); goto err_remove_notify_handler; } - device->driver_data = wmi_bus_dev; + dev_set_drvdata(&device->dev, wmi_bus_dev); - error = parse_wdg(wmi_bus_dev, device); + error = parse_wdg(wmi_bus_dev, acpi_device); if (error) { pr_err("Failed to parse WDG method\n"); goto err_remove_busdev; @@ -1166,11 +1175,11 @@ err_remove_busdev: device_unregister(wmi_bus_dev); err_remove_notify_handler: - acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler); err_remove_ec_handler: - acpi_remove_address_space_handler(device->handle, + acpi_remove_address_space_handler(acpi_device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); @@ -1208,7 +1217,7 @@ static int __init acpi_wmi_init(void) if (error) goto err_unreg_class; - error = acpi_bus_register_driver(&acpi_wmi_driver); + error = platform_driver_register(&acpi_wmi_driver); if (error) { pr_err("Error loading mapper\n"); goto err_unreg_bus; @@ -1227,7 +1236,7 @@ err_unreg_bus: static void __exit acpi_wmi_exit(void) { - acpi_bus_unregister_driver(&acpi_wmi_driver); + platform_driver_unregister(&acpi_wmi_driver); class_unregister(&wmi_bus_class); bus_unregister(&wmi_bus_type); } -- cgit v1.2.3 From f63019861cd1192e546397b13f926876a93450fd Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 29 Dec 2015 22:53:51 -0800 Subject: platform/x86: wmi: Add an interface for subdrivers to access sibling devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some subdrivers need to access sibling devices. This gives them a clean way to do so. Signed-off-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 17 +++++++++++++++++ include/linux/wmi.h | 4 ++++ 2 files changed, 21 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 52452ec5099b..250d7b2398b4 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -344,6 +344,23 @@ union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance) } EXPORT_SYMBOL_GPL(wmidev_block_query); +struct wmi_device *wmidev_get_other_guid(struct wmi_device *wdev, + const char *guid_string) +{ + struct wmi_block *this_wb = container_of(wdev, struct wmi_block, dev); + struct wmi_block *other_wb; + + if (!find_guid(guid_string, &other_wb)) + return NULL; + + if (other_wb->acpi_device != this_wb->acpi_device) + return NULL; + + get_device(&other_wb->dev.dev); + return &other_wb->dev; +} +EXPORT_SYMBOL_GPL(wmidev_get_other_guid); + /** * wmi_set_block - Write to a WMI block * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba diff --git a/include/linux/wmi.h b/include/linux/wmi.h index 0ab254019488..a283768afb7e 100644 --- a/include/linux/wmi.h +++ b/include/linux/wmi.h @@ -33,6 +33,10 @@ struct wmi_device { extern union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance); +/* Gets another device on the same bus. Caller must put_device the result. */ +extern struct wmi_device *wmidev_get_other_guid(struct wmi_device *wdev, + const char *guid_string); + struct wmi_device_id { const char *guid_string; }; -- cgit v1.2.3 From fd70da6a6267c91fbdda9c560f098cfd52fba00f Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Fri, 19 May 2017 19:28:36 -0700 Subject: platform/x86: wmi: Require query for data blocks, rename writable to setable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Microsoft WMI documentation requires all data blocks to implement the Query Control Method (WQxx). If we encounter a data block not implementing this control method, issue a warning, and ignore the data block. Remove the "readable" attribute as all data blocks must be readable (query-able). Be consistent with the language in the documentation, replace the "writable" attribute with "setable". Simplify (flatten) the control flow of wmi_create_device a bit while we are updating it for the above changes. Signed-off-by: Darren Hart (VMware) Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki --- drivers/platform/x86/wmi.c | 117 +++++++++++++++++++++++---------------------- include/linux/wmi.h | 7 +-- 2 files changed, 63 insertions(+), 61 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 250d7b2398b4..37f6651d1bf7 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -69,7 +69,7 @@ struct wmi_block { wmi_notify_handler handler; void *handler_data; - bool read_takes_no_args; /* only defined if readable */ + bool read_takes_no_args; }; @@ -694,28 +694,18 @@ static ssize_t object_id_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(object_id); -static ssize_t readable_show(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t setable_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct wmi_device *wdev = dev_to_wdev(dev); - return sprintf(buf, "%d\n", (int)wdev->readable); + return sprintf(buf, "%d\n", (int)wdev->setable); } -static DEVICE_ATTR_RO(readable); - -static ssize_t writeable_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct wmi_device *wdev = dev_to_wdev(dev); - - return sprintf(buf, "%d\n", (int)wdev->writeable); -} -static DEVICE_ATTR_RO(writeable); +static DEVICE_ATTR_RO(setable); static struct attribute *wmi_data_attrs[] = { &dev_attr_object_id.attr, - &dev_attr_readable.attr, - &dev_attr_writeable.attr, + &dev_attr_setable.attr, NULL, }; ATTRIBUTE_GROUPS(wmi_data); @@ -833,63 +823,74 @@ static struct device_type wmi_type_data = { .release = wmi_dev_release, }; -static void wmi_create_device(struct device *wmi_bus_dev, +static int wmi_create_device(struct device *wmi_bus_dev, const struct guid_block *gblock, struct wmi_block *wblock, struct acpi_device *device) { - wblock->dev.dev.bus = &wmi_bus_type; - wblock->dev.dev.parent = wmi_bus_dev; - - dev_set_name(&wblock->dev.dev, "%pUL", gblock->guid); + struct acpi_device_info *info; + char method[5]; + int result; if (gblock->flags & ACPI_WMI_EVENT) { wblock->dev.dev.type = &wmi_type_event; - } else if (gblock->flags & ACPI_WMI_METHOD) { + goto out_init; + } + + if (gblock->flags & ACPI_WMI_METHOD) { wblock->dev.dev.type = &wmi_type_method; - } else { - struct acpi_device_info *info; - char method[5]; - int result; + goto out_init; + } - wblock->dev.dev.type = &wmi_type_data; + /* + * Data Block Query Control Method (WQxx by convention) is + * required per the WMI documentation. If it is not present, + * we ignore this data block. + */ + strcpy(method, "WQ"); + strncat(method, wblock->gblock.object_id, 2); + result = get_subobj_info(device->handle, method, &info); + + if (result) { + dev_warn(wmi_bus_dev, + "%s data block query control method not found", + method); + return result; + } - strcpy(method, "WQ"); - strncat(method, wblock->gblock.object_id, 2); - result = get_subobj_info(device->handle, method, &info); + wblock->dev.dev.type = &wmi_type_data; - if (result == 0) { - wblock->dev.readable = true; + /* + * The Microsoft documentation specifically states: + * + * Data blocks registered with only a single instance + * can ignore the parameter. + * + * ACPICA will get mad at us if we call the method with the wrong number + * of arguments, so check what our method expects. (On some Dell + * laptops, WQxx may not be a method at all.) + */ + if (info->type != ACPI_TYPE_METHOD || info->param_count == 0) + wblock->read_takes_no_args = true; - /* - * The Microsoft documentation specifically states: - * - * Data blocks registered with only a single instance - * can ignore the parameter. - * - * ACPICA will get mad at us if we call the method - * with the wrong number of arguments, so check what - * our method expects. (On some Dell laptops, WQxx - * may not be a method at all.) - */ - if (info->type != ACPI_TYPE_METHOD || - info->param_count == 0) - wblock->read_takes_no_args = true; + kfree(info); - kfree(info); - } + strcpy(method, "WS"); + strncat(method, wblock->gblock.object_id, 2); + result = get_subobj_info(device->handle, method, NULL); - strcpy(method, "WS"); - strncat(method, wblock->gblock.object_id, 2); - result = get_subobj_info(device->handle, method, NULL); + if (result == 0) + wblock->dev.setable = true; - if (result == 0) { - wblock->dev.writeable = true; - } + out_init: + wblock->dev.dev.bus = &wmi_bus_type; + wblock->dev.dev.parent = wmi_bus_dev; - } + dev_set_name(&wblock->dev.dev, "%pUL", gblock->guid); device_initialize(&wblock->dev.dev); + + return 0; } static void wmi_free_devices(struct acpi_device *device) @@ -978,7 +979,11 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) wblock->acpi_device = device; wblock->gblock = gblock[i]; - wmi_create_device(wmi_bus_dev, &gblock[i], wblock, device); + retval = wmi_create_device(wmi_bus_dev, &gblock[i], wblock, device); + if (retval) { + kfree(wblock); + continue; + } list_add_tail(&wblock->list, &wmi_block_list); diff --git a/include/linux/wmi.h b/include/linux/wmi.h index a283768afb7e..cd0d7734dc49 100644 --- a/include/linux/wmi.h +++ b/include/linux/wmi.h @@ -22,11 +22,8 @@ struct wmi_device { struct device dev; - /* - * These are true for data objects that support reads and writes, - * respectively. - */ - bool readable, writeable; + /* True for data blocks implementing the Set Control Method */ + bool setable; }; /* Caller must kfree the result. */ -- cgit v1.2.3 From f9dd82c0ea5588bac5f9ba284c8e609ffd9dfbe5 Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Tue, 6 Jun 2017 10:07:32 -0700 Subject: platform/x86: wmi-bmof: New driver to expose embedded Binary WMI MOF metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many laptops (and maybe servers?) have embedded WMI Binary MOF metadata. We do not yet have open-source tools for processing the data, although one is in the works thanks to Pali: https://github.com/pali/bmfdec There is currently no interface to get the data in the first place. By exposing it, we facilitate the development of new tools. This is based on the original work of Andy Lutomirski , but contains several modifications in response to various reviews. Signed-off-by: Darren Hart (VMware) Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/platform/x86/Kconfig | 12 ++++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/wmi-bmof.c | 124 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 drivers/platform/x86/wmi-bmof.c (limited to 'drivers/platform') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 49a1d012f025..32cfeeca3ecc 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -656,6 +656,18 @@ config ACPI_WMI It is safe to enable this driver even if your DSDT doesn't define any ACPI-WMI devices. +config WMI_BMOF + tristate "WMI embedded Binary MOF driver" + depends on ACPI_WMI + default ACPI_WMI + ---help--- + Say Y here if you want to be able to read a firmware-embedded + WMI Binary MOF data. Using this requires userspace tools and may be + rather tedious. + + To compile this driver as a module, choose M here: the module will + be called wmi-bmof. + config MSI_WMI tristate "MSI WMI extras" depends on ACPI_WMI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 652d7c8a2e58..6a1063edc6dc 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_MSI_WMI) += msi-wmi.o obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o +obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o # toshiba_acpi must link after wmi to ensure that wmi devices are found # before toshiba_acpi initializes diff --git a/drivers/platform/x86/wmi-bmof.c b/drivers/platform/x86/wmi-bmof.c new file mode 100644 index 000000000000..94922b9342ce --- /dev/null +++ b/drivers/platform/x86/wmi-bmof.c @@ -0,0 +1,124 @@ +/* + * WMI embedded Binary MOF driver + * + * Copyright (c) 2015 Andrew Lutomirski + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WMI_BMOF_GUID "05901221-D566-11D1-B2F0-00A0C9062910" + +struct bmof_priv { + union acpi_object *bmofdata; + struct bin_attribute bmof_bin_attr; +}; + +static ssize_t +read_bmof(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct bmof_priv *priv = + container_of(attr, struct bmof_priv, bmof_bin_attr); + + if (off < 0) + return -EINVAL; + + if (off >= priv->bmofdata->buffer.length) + return 0; + + if (count > priv->bmofdata->buffer.length - off) + count = priv->bmofdata->buffer.length - off; + + memcpy(buf, priv->bmofdata->buffer.pointer + off, count); + return count; +} + +static int wmi_bmof_probe(struct wmi_device *wdev) +{ + struct bmof_priv *priv; + int ret; + + priv = devm_kzalloc(&wdev->dev, sizeof(struct bmof_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(&wdev->dev, priv); + + priv->bmofdata = wmidev_block_query(wdev, 0); + if (!priv->bmofdata) { + dev_err(&wdev->dev, "failed to read Binary MOF\n"); + return -EIO; + } + + if (priv->bmofdata->type != ACPI_TYPE_BUFFER) { + dev_err(&wdev->dev, "Binary MOF is not a buffer\n"); + ret = -EIO; + goto err_free; + } + + sysfs_bin_attr_init(&priv->bmof_bin_attr); + priv->bmof_bin_attr.attr.name = "bmof"; + priv->bmof_bin_attr.attr.mode = 0400; + priv->bmof_bin_attr.read = read_bmof; + priv->bmof_bin_attr.size = priv->bmofdata->buffer.length; + + ret = sysfs_create_bin_file(&wdev->dev.kobj, &priv->bmof_bin_attr); + if (ret) + goto err_free; + + return 0; + + err_free: + kfree(priv->bmofdata); + return ret; +} + +static int wmi_bmof_remove(struct wmi_device *wdev) +{ + struct bmof_priv *priv = dev_get_drvdata(&wdev->dev); + + sysfs_remove_bin_file(&wdev->dev.kobj, &priv->bmof_bin_attr); + kfree(priv->bmofdata); + return 0; +} + +static const struct wmi_device_id wmi_bmof_id_table[] = { + { .guid_string = WMI_BMOF_GUID }, + { }, +}; + +static struct wmi_driver wmi_bmof_driver = { + .driver = { + .name = "wmi-bmof", + }, + .probe = wmi_bmof_probe, + .remove = wmi_bmof_remove, + .id_table = wmi_bmof_id_table, +}; + +module_wmi_driver(wmi_bmof_driver); + +MODULE_ALIAS("wmi:" WMI_BMOF_GUID); +MODULE_AUTHOR("Andrew Lutomirski "); +MODULE_DESCRIPTION("WMI embedded Binary MOF driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From bff589be59c50924a9715951160578e570cba5c6 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 25 Nov 2015 07:53:13 -0800 Subject: platform/x86: dell-wmi: Convert to the WMI bus infrastructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move some initialization out of _init and into _probe. Update signatures and logic to use the wmi bus and device structures. Signed-off-by: Andy Lutomirski [dvhart: drop deprecated sparse_keymap_free, order declarations, add commit msg] Cc: Andy Lutomirski Cc: Mario Limonciello Cc: Pali Rohár Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-wmi.c | 136 +++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 66 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 73aee0d1aea4..f8978464df31 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "dell-smbios.h" @@ -53,6 +54,10 @@ static bool wmi_requires_smbios_request; MODULE_ALIAS("wmi:"DELL_EVENT_GUID); MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID); +struct dell_wmi_priv { + struct input_dev *input_dev; +}; + static int __init dmi_matched(const struct dmi_system_id *dmi) { wmi_requires_smbios_request = 1; @@ -86,7 +91,7 @@ static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = { * notifications (rather than requests for change) or are also sent * via the keyboard controller so should not be sent again. */ -static const struct key_entry dell_wmi_keymap_type_0000[] __initconst = { +static const struct key_entry dell_wmi_keymap_type_0000[] = { { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } }, /* Key code is followed by brightness level */ @@ -207,7 +212,7 @@ struct dell_dmi_results { }; /* Uninitialized entries here are KEY_RESERVED == 0. */ -static const u16 bios_to_linux_keycode[256] __initconst = { +static const u16 bios_to_linux_keycode[256] = { [0] = KEY_MEDIA, [1] = KEY_NEXTSONG, [2] = KEY_PLAYPAUSE, @@ -256,7 +261,7 @@ static const u16 bios_to_linux_keycode[256] __initconst = { * These are applied if the 0xB2 DMI hotkey table is present and doesn't * override them. */ -static const struct key_entry dell_wmi_keymap_type_0010[] __initconst = { +static const struct key_entry dell_wmi_keymap_type_0010[] = { /* Fn-lock */ { KE_IGNORE, 0x151, { KEY_RESERVED } }, @@ -294,7 +299,7 @@ static const struct key_entry dell_wmi_keymap_type_0010[] __initconst = { /* * Keymap for WMI events of type 0x0011 */ -static const struct key_entry dell_wmi_keymap_type_0011[] __initconst = { +static const struct key_entry dell_wmi_keymap_type_0011[] = { /* Battery unplugged */ { KE_IGNORE, 0xfff0, { KEY_RESERVED } }, @@ -309,13 +314,12 @@ static const struct key_entry dell_wmi_keymap_type_0011[] __initconst = { { KE_IGNORE, 0x02f6, { KEY_RESERVED } }, }; -static struct input_dev *dell_wmi_input_dev; - -static void dell_wmi_process_key(int type, int code) +static void dell_wmi_process_key(struct wmi_device *wdev, int type, int code) { + struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev); const struct key_entry *key; - key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, + key = sparse_keymap_entry_from_scancode(priv->input_dev, (type << 16) | code); if (!key) { pr_info("Unknown key with type 0x%04x and code 0x%04x pressed\n", @@ -338,33 +342,18 @@ static void dell_wmi_process_key(int type, int code) dell_laptop_call_notifier( DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED, NULL); - sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); + sparse_keymap_report_entry(priv->input_dev, key, 1, true); } -static void dell_wmi_notify(u32 value, void *context) +static void dell_wmi_notify(struct wmi_device *wdev, + union acpi_object *obj) { - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - acpi_status status; - acpi_size buffer_size; u16 *buffer_entry, *buffer_end; + acpi_size buffer_size; int len, i; - status = wmi_get_event_data(value, &response); - if (status != AE_OK) { - pr_warn("bad event status 0x%x\n", status); - return; - } - - obj = (union acpi_object *)response.pointer; - if (!obj) { - pr_warn("no response\n"); - return; - } - if (obj->type != ACPI_TYPE_BUFFER) { pr_warn("bad response type %x\n", obj->type); - kfree(obj); return; } @@ -409,13 +398,14 @@ static void dell_wmi_notify(u32 value, void *context) switch (buffer_entry[1]) { case 0x0000: /* One key pressed or event occurred */ if (len > 2) - dell_wmi_process_key(0x0000, buffer_entry[2]); + dell_wmi_process_key(wdev, 0x0000, + buffer_entry[2]); /* Other entries could contain additional information */ break; case 0x0010: /* Sequence of keys pressed */ case 0x0011: /* Sequence of events occurred */ for (i = 2; i < len; ++i) - dell_wmi_process_key(buffer_entry[1], + dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[i]); break; default: /* Unknown event */ @@ -428,7 +418,6 @@ static void dell_wmi_notify(u32 value, void *context) } - kfree(obj); } static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len) @@ -442,9 +431,7 @@ static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len) return false; } -static void __init handle_dmi_entry(const struct dmi_header *dm, - void *opaque) - +static void handle_dmi_entry(const struct dmi_header *dm, void *opaque) { struct dell_dmi_results *results = opaque; struct dell_bios_hotkey_table *table; @@ -515,19 +502,20 @@ static void __init handle_dmi_entry(const struct dmi_header *dm, results->keymap_size = pos; } -static int __init dell_wmi_input_setup(void) +static int dell_wmi_input_setup(struct wmi_device *wdev) { + struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev); struct dell_dmi_results dmi_results = {}; struct key_entry *keymap; int err, i, pos = 0; - dell_wmi_input_dev = input_allocate_device(); - if (!dell_wmi_input_dev) + priv->input_dev = input_allocate_device(); + if (!priv->input_dev) return -ENOMEM; - dell_wmi_input_dev->name = "Dell WMI hotkeys"; - dell_wmi_input_dev->phys = "wmi/input0"; - dell_wmi_input_dev->id.bustype = BUS_HOST; + priv->input_dev->name = "Dell WMI hotkeys"; + priv->input_dev->id.bustype = BUS_HOST; + priv->input_dev->dev.parent = &wdev->dev; if (dmi_walk(handle_dmi_entry, &dmi_results)) { /* @@ -602,7 +590,7 @@ static int __init dell_wmi_input_setup(void) keymap[pos].type = KE_END; - err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL); + err = sparse_keymap_setup(priv->input_dev, keymap, NULL); /* * Sparse keymap library makes a copy of keymap so we don't need the * original one that was allocated. @@ -611,17 +599,24 @@ static int __init dell_wmi_input_setup(void) if (err) goto err_free_dev; - err = input_register_device(dell_wmi_input_dev); + err = input_register_device(priv->input_dev); if (err) goto err_free_dev; return 0; err_free_dev: - input_free_device(dell_wmi_input_dev); + input_free_device(priv->input_dev); return err; } +static void dell_wmi_input_destroy(struct wmi_device *wdev) +{ + struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev); + + input_unregister_device(priv->input_dev); +} + /* * Descriptor buffer is 128 byte long and contains: * @@ -720,46 +715,55 @@ static int dell_wmi_events_set_enabled(bool enable) return dell_smbios_error(ret); } +static int dell_wmi_probe(struct wmi_device *wdev) +{ + struct dell_wmi_priv *priv = devm_kzalloc( + &wdev->dev, sizeof(struct dell_wmi_priv), GFP_KERNEL); + + dev_set_drvdata(&wdev->dev, priv); + + return dell_wmi_input_setup(wdev); +} + +static int dell_wmi_remove(struct wmi_device *wdev) +{ + dell_wmi_input_destroy(wdev); + return 0; +} +static const struct wmi_device_id dell_wmi_id_table[] = { + { .guid_string = DELL_EVENT_GUID }, + { }, +}; + +static struct wmi_driver dell_wmi_driver = { + .driver = { + .name = "dell-wmi", + }, + .id_table = dell_wmi_id_table, + .probe = dell_wmi_probe, + .remove = dell_wmi_remove, + .notify = dell_wmi_notify, +}; + static int __init dell_wmi_init(void) { int err; - acpi_status status; - - if (!wmi_has_guid(DELL_EVENT_GUID) || - !wmi_has_guid(DELL_DESCRIPTOR_GUID)) { - pr_warn("Dell WMI GUID were not found\n"); - return -ENODEV; - } err = dell_wmi_check_descriptor_buffer(); if (err) return err; - err = dell_wmi_input_setup(); - if (err) - return err; - - status = wmi_install_notify_handler(DELL_EVENT_GUID, - dell_wmi_notify, NULL); - if (ACPI_FAILURE(status)) { - input_unregister_device(dell_wmi_input_dev); - pr_err("Unable to register notify handler - %d\n", status); - return -ENODEV; - } - dmi_check_system(dell_wmi_smbios_list); if (wmi_requires_smbios_request) { err = dell_wmi_events_set_enabled(true); if (err) { pr_err("Failed to enable WMI events\n"); - wmi_remove_notify_handler(DELL_EVENT_GUID); - input_unregister_device(dell_wmi_input_dev); return err; } } - return 0; + return wmi_driver_register(&dell_wmi_driver); } module_init(dell_wmi_init); @@ -767,7 +771,7 @@ static void __exit dell_wmi_exit(void) { if (wmi_requires_smbios_request) dell_wmi_events_set_enabled(false); - wmi_remove_notify_handler(DELL_EVENT_GUID); - input_unregister_device(dell_wmi_input_dev); + + wmi_driver_unregister(&dell_wmi_driver); } module_exit(dell_wmi_exit); -- cgit v1.2.3 From 0d2c95354a3b63256e92d9fb865c08902d2c9b0b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 7 Jun 2017 16:56:15 +0300 Subject: platform/x86: samsung-laptop: Initialize loca variable The variable is used uninitialized which might come into unexpected behaviour on some Samsung laptops. Initialize it to 0xffff which seems a proper value for non-supported feature. Reported-by: Geert Uytterhoeven Signed-off-by: Andy Shevchenko --- drivers/platform/x86/samsung-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 8c146e2b6727..1aa11732f48c 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -1446,9 +1446,9 @@ static int __init samsung_sabi_init(struct samsung_laptop *samsung) const struct sabi_config *config = NULL; const struct sabi_commands *commands; unsigned int ifaceP; + int loca = 0xffff; int ret = 0; int i; - int loca; samsung->f0000_segment = ioremap_nocache(0xf0000, 0xffff); if (!samsung->f0000_segment) { -- cgit v1.2.3 From feb4ec1412ab948c30dbf98cd9326825e8d49513 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 31 May 2017 16:17:48 -0700 Subject: platform/x86: panasonic-laptop: remove unused code The struct pcc_keyinput is not used in panasonic-laptop and in anywhere in kernel, and it can be removed. Signed-off-by: Alex Hung Acked-by: Harald Welte Signed-off-by: Andy Shevchenko --- drivers/platform/x86/panasonic-laptop.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 975f4e100dbd..76b0a58e205b 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -228,10 +228,6 @@ struct pcc_acpi { struct backlight_device *backlight; }; -struct pcc_keyinput { - struct acpi_hotkey *hotkey; -}; - /* method access functions */ static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val) { -- cgit v1.2.3 From 3e2bc5c5b3274ec7402fabbfba557ea58084985e Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Tue, 6 Jun 2017 13:07:22 -0700 Subject: platform/x86: acer-wmi: Detect RF Button capability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a machine reports a RF Button in the communication button device bitmap, we need to remove it before calling Get Device Status otherwise it will return the "Undefined device" (0xE2) error code. Although this may be a BIOS bug, we don't really need to get or set the RF Button status. The status indicator LED embedded in the button is controlled by firmware logic, depending on the status of the wireless radios present on the machine (WiFi || WWAN). This commit fixes the wireless status indicator LED on the Acer TravelMate P648-G2-MG, and cleans the following message from the kernel log: "Get Current Device Status failed: 0xe2 - 0x0". Signed-off-by: João Paulo Rechi Vita Reviewed-by: "Lee, Chun-Yi" Signed-off-by: Andy Shevchenko --- drivers/platform/x86/acer-wmi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 79fa5ab3fd00..3b381178039b 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -149,6 +149,8 @@ struct event_return_value { #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ #define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */ #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ +#define ACER_WMID3_GDS_RFBTN (1<<14) /* RF Button */ + #define ACER_WMID3_GDS_TOUCHPAD (1<<1) /* Touchpad */ /* Hotkey Customized Setting and Acer Application Status. @@ -221,6 +223,7 @@ struct hotkey_function_type_aa { #define ACER_CAP_BRIGHTNESS (1<<3) #define ACER_CAP_THREEG (1<<4) #define ACER_CAP_ACCEL (1<<5) +#define ACER_CAP_RFBTN (1<<6) #define ACER_CAP_ANY (0xFFFFFFFF) /* @@ -1264,6 +1267,10 @@ static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d) interface->capability |= ACER_CAP_THREEG; if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH) interface->capability |= ACER_CAP_BLUETOOTH; + if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN) { + interface->capability |= ACER_CAP_RFBTN; + commun_func_bitmap &= ~ACER_WMID3_GDS_RFBTN; + } commun_fn_key_number = type_aa->commun_fn_key_number; } -- cgit v1.2.3 From 2c9c56645f46c6be4e3303cf1dd25d69c674d293 Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Tue, 6 Jun 2017 16:40:56 -0700 Subject: platform/x86: wmi*: Add recent copyright statements Add copyright statements for Andy Lutomirski and Darren Hart (VMware) for their contributions to the WMI bus infrastructure and the creation of the wmi-bmof driver. Signed-off-by: Darren Hart (VMware) Cc: Andy Lutomirski --- drivers/platform/x86/wmi-bmof.c | 1 + drivers/platform/x86/wmi.c | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi-bmof.c b/drivers/platform/x86/wmi-bmof.c index 94922b9342ce..c4530ba715e8 100644 --- a/drivers/platform/x86/wmi-bmof.c +++ b/drivers/platform/x86/wmi-bmof.c @@ -2,6 +2,7 @@ * WMI embedded Binary MOF driver * * Copyright (c) 2015 Andrew Lutomirski + * Copyright (C) 2017 VMware, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 37f6651d1bf7..4bfc3b04e26a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -8,6 +8,10 @@ * Copyright (c) 2001-2007 Anton Altaparmakov * Copyright (C) 2001,2002 Jakob Kemi * + * WMI bus infrastructure by Andrew Lutomirski and Darren Hart: + * Copyright (C) 2015 Andrew Lutomirski + * Copyright (C) 2017 VMware, Inc. All Rights Reserved. + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This program is free software; you can redistribute it and/or modify -- cgit v1.2.3 From 8314a1c8dd183e36342bd00c1e46b6c7e38939b1 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Fri, 9 Jun 2017 11:31:44 +0530 Subject: platform/x86: samsung-laptop: constify rfkill_ops structures Add const to rfkill_ops structures that are only passed as an argument to the functions rfkill_alloc or samsung_new_rfkill. These arguments are of type const, so such structures can be annotated with const. Signed-off-by: Bhumika Goyal Signed-off-by: Andy Shevchenko --- drivers/platform/x86/samsung-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 1aa11732f48c..5c4dfe48f03d 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -591,7 +591,7 @@ static int seclinux_rfkill_set(void *data, bool blocked) !blocked); } -static struct rfkill_ops seclinux_rfkill_ops = { +static const struct rfkill_ops seclinux_rfkill_ops = { .set_block = seclinux_rfkill_set, }; @@ -651,7 +651,7 @@ static void swsmi_rfkill_query(struct rfkill *rfkill, void *priv) rfkill_set_sw_state(rfkill, !ret); } -static struct rfkill_ops swsmi_rfkill_ops = { +static const struct rfkill_ops swsmi_rfkill_ops = { .set_block = swsmi_rfkill_set, .query = swsmi_rfkill_query, }; -- cgit v1.2.3 From 3d59dfcd1f2610d26da2cf19646ace6692c521dc Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Fri, 9 Jun 2017 11:38:18 +0530 Subject: platform/x86: ideapad-laptop: constify rfkill_ops structure Add const to rfkill_ops structure as it is only passed as an argument to the functions rfkill_alloc. This argument is of type const, so annotate the structure with const. Signed-off-by: Bhumika Goyal Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index d48962569364..4bf93c0c7e36 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -512,7 +512,7 @@ static int ideapad_rfk_set(void *data, bool blocked) return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked); } -static struct rfkill_ops ideapad_rfk_ops = { +static const struct rfkill_ops ideapad_rfk_ops = { .set_block = ideapad_rfk_set, }; -- cgit v1.2.3 From a63693a0e617636bd786c7d6bd114b37435e14ef Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Fri, 9 Jun 2017 11:27:40 +0530 Subject: platform/x86: dell-rbtn: constify rfkill_ops structures Add const to rfkill_ops structures that are only passed as an argument to the functions rfkill_alloc or samsung_new_rfkill. These arguments are of type const, so such structures can be annotated with const. Signed-off-by: Bhumika Goyal Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-rbtn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/dell-rbtn.c b/drivers/platform/x86/dell-rbtn.c index f5c53ea87158..f3afe778001e 100644 --- a/drivers/platform/x86/dell-rbtn.c +++ b/drivers/platform/x86/dell-rbtn.c @@ -110,7 +110,7 @@ static int rbtn_rfkill_set_block(void *data, bool blocked) return -EINVAL; } -static struct rfkill_ops rbtn_ops = { +static const struct rfkill_ops rbtn_ops = { .query = rbtn_rfkill_query, .set_block = rbtn_rfkill_set_block, }; -- cgit v1.2.3 From cd3921f88b82f1c89057b964338f6d10204c7abc Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Sat, 10 Jun 2017 12:57:11 +0200 Subject: platform/x86: wmi: Fix printing info about WDG structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit object_id and notify_id are in one union structure and their meaning is defined by flags. Therefore do not print notify_id for non-event block and do not print object_id for event block. Remove also reserved member as it does not have any defined meaning or type yet. As object_id and notify_id union members overlaps and have different types, it caused that kernel print to dmesg binary data. This patch eliminates it. Signed-off-by: Pali Rohár Reviewed-by: Andy Shevchenko Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/wmi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 4bfc3b04e26a..1a764e311e11 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -421,9 +421,10 @@ EXPORT_SYMBOL_GPL(wmi_set_block); static void wmi_dump_wdg(const struct guid_block *g) { pr_info("%pUL:\n", g->guid); - pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]); - pr_info("\tnotify_id: %02X\n", g->notify_id); - pr_info("\treserved: %02X\n", g->reserved); + if (g->flags & ACPI_WMI_EVENT) + pr_info("\tnotify_id: 0x%02X\n", g->notify_id); + else + pr_info("\tobject_id: %2pE\n", g->object_id); pr_info("\tinstance_count: %d\n", g->instance_count); pr_info("\tflags: %#x", g->flags); if (g->flags) { -- cgit v1.2.3 From 13fadfa75c7c08111ef142439b94e463bef6dfb5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 15 Jun 2017 08:48:32 +0200 Subject: platform/x86: silead_dmi: Add touchscreen info for Pipo W2S tablet Add touchscreen info for Pipo W2S tablet. Signed-off-by: Hans de Goede Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/silead_dmi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index db3a877d2160..1bdf15f19c26 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -93,6 +93,21 @@ static const struct silead_ts_dmi_data gp_electronic_t701_data = { .properties = gp_electronic_t701_props, }; +static const struct property_entry pipo_w2s_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), + PROPERTY_ENTRY_U32("touchscreen-size-y", 880), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1680-pipo-w2s.fw"), + { } +}; + +static const struct silead_ts_dmi_data pipo_w2s_data = { + .acpi_name = "MSSL1680:00", + .properties = pipo_w2s_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -139,6 +154,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), }, }, + { + /* Pipo W2S */ + .driver_data = (void *)&pipo_w2s_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "PIPO"), + DMI_MATCH(DMI_PRODUCT_NAME, "W2S"), + }, + }, { }, }; -- cgit v1.2.3 From f4d342cf900a95907a8b5aa84bbe9898160eb497 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 15 Jun 2017 08:48:31 +0200 Subject: platform/x86: silead_dmi: Add touchscreen info for PoV mobii wintab p800w Add touchscreen info for the Point of View mobii wintab p800w tablet. Signed-off-by: Hans de Goede Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/silead_dmi.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 1bdf15f19c26..3cd3bdfe51df 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -108,6 +108,20 @@ static const struct silead_ts_dmi_data pipo_w2s_data = { .properties = pipo_w2s_props, }; +static const struct property_entry pov_mobii_wintab_p800w_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1800), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl3692-pov-mobii-wintab-p800w.fw"), + { } +}; + +static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_data = { + .acpi_name = "MSSL1680:00", + .properties = pov_mobii_wintab_p800w_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -162,6 +176,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "W2S"), }, }, + { + /* Point of View mobii wintab p800w */ + .driver_data = (void *)&pov_mobii_wintab_p800w_data, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"), + }, + }, { }, }; -- cgit v1.2.3 From 5d9f40b56630a8702b5f7a61a770f9b73aa07464 Mon Sep 17 00:00:00 2001 From: Olle Liljenzin Date: Sun, 18 Jun 2017 13:09:31 +0200 Subject: platform/x86: ideapad-laptop: Add Y520-15IKBN to no_hw_rfkill Lenovo Legion Y520-15IKBN is yet another Lenovo model that does not have an hw rfkill switch, resulting in wifi always reported as hard blocked. Add the model to the list of models without rfkill switch. Signed-off-by: Olle Liljenzin Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 4bf93c0c7e36..f929bf12b506 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -950,6 +950,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"), }, }, + { + .ident = "Lenovo Legion Y520-15IKBN", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"), + }, + }, { .ident = "Lenovo Yoga 2 11 / 13 / Pro", .matches = { -- cgit v1.2.3 From b2f2fe205c3b9b595dc50ee431230a45d03f9c2c Mon Sep 17 00:00:00 2001 From: Olle Liljenzin Date: Sun, 18 Jun 2017 14:37:58 +0200 Subject: platform/x86: ideapad-laptop: Add Y720-15IKBN to no_hw_rfkill Lenovo Legion Y720-15IKBN is yet another Lenovo model that does not have an hw rfkill switch, resulting in wifi always reported as hard blocked. Add the model to the list of models without rfkill switch. Signed-off-by: Olle Liljenzin Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index f929bf12b506..527e5d9ab9bf 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -957,6 +957,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"), }, }, + { + .ident = "Lenovo Legion Y720-15IKBN", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBN"), + }, + }, { .ident = "Lenovo Yoga 2 11 / 13 / Pro", .matches = { -- cgit v1.2.3 From 62fc743cafd07e134292d510827a80b3c01df784 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Tue, 20 Jun 2017 17:06:23 +0800 Subject: platform/x86: acer-wmi: Using zero as first WMI instance number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pali Rohár found that there have some wmi query/evaluation code that they used 'one' as the first WMI instance number. But the number is indexed from zero that it's must less than the instance_count in _WDG. This patch changes those instance number from one to zero. Cc: Darren Hart Cc: Andy Shevchenko Reviewed-by: Pali Rohár Signed-off-by: "Lee, Chun-Yi" Signed-off-by: Andy Shevchenko --- drivers/platform/x86/acer-wmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 3b381178039b..1be71f956d5c 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -703,7 +703,7 @@ struct acpi_buffer *result) input.length = sizeof(struct wmab_args); input.pointer = (u8 *)regbuf; - status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result); + status = wmi_evaluate_method(AMW0_GUID1, 0, 1, &input, result); return status; } @@ -968,7 +968,7 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out) u32 tmp = 0; acpi_status status; - status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); + status = wmi_evaluate_method(WMID_GUID1, 0, method_id, &input, &result); if (ACPI_FAILURE(status)) return status; @@ -1282,7 +1282,7 @@ static acpi_status __init WMID_set_capabilities(void) acpi_status status; u32 devices; - status = wmi_query_block(WMID_GUID2, 1, &out); + status = wmi_query_block(WMID_GUID2, 0, &out); if (ACPI_FAILURE(status)) return status; @@ -2025,7 +2025,7 @@ static u32 get_wmid_devices(void) acpi_status status; u32 devices = 0; - status = wmi_query_block(WMID_GUID2, 1, &out); + status = wmi_query_block(WMID_GUID2, 0, &out); if (ACPI_FAILURE(status)) return 0; -- cgit v1.2.3 From 1b1ffc57a1b2edf58e803e463980b326765a237f Mon Sep 17 00:00:00 2001 From: Kai Heng Feng Date: Tue, 20 Jun 2017 11:05:19 +0800 Subject: platform/x86: dell-laptop: Fix bogus keyboard backlight sysfs interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dell Latitude 3160 does not have keyboard backlight, but there is a sysfs interface for it, which does nothing at all. KBD_LED_ON_TOKEN is the only token can be found. Since it doesn't have KBD_LED_OFF_TOKEN or KBD_LED_AUTO_*_TOKEN, it should be safe to assume at least two tokens should be present to support keyboard backlight. Not all models have ON token - they may have multiple AUTO tokens instead. Models which do not use SMBIOS token to control keyboard backlight, also have this issue. Brightness level is 0 on these models. Verified on Dell Inspiron 3565. Reports keyboard backlight is supported only when at least two modes are present. Signed-off-by: Kai-Heng Feng Reviewed-by: Pali Rohár Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-laptop.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index ec202094bd50..f42159fd2031 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -1510,7 +1510,11 @@ static void kbd_init(void) ret = kbd_init_info(); kbd_init_tokens(); - if (kbd_token_bits != 0 || ret == 0) + /* + * Only supports keyboard backlight when it has at least two modes. + */ + if ((ret == 0 && (kbd_info.levels != 0 || kbd_mode_levels_count >= 2)) + || kbd_get_valid_token_counts() >= 2) kbd_led_present = true; } -- cgit v1.2.3 From adee455112190a4a1ed5d01badcac59278c55d9c Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 21 Jun 2017 12:34:16 +0530 Subject: platform/x86: acerhdf: Add const to thermal_cooling_device_ops structure Declare thermal_cooling_device_ops structure as const as it is only passed as an argument to the function thermal_cooling_device_register and this argument is of type const. So, declare the structure as const. Signed-off-by: Bhumika Goyal Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/acerhdf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index 2acdb0d6ea89..ea22591ee66f 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -557,7 +557,7 @@ err_out: } /* bind fan callbacks to fan device */ -static struct thermal_cooling_device_ops acerhdf_cooling_ops = { +static const struct thermal_cooling_device_ops acerhdf_cooling_ops = { .get_max_state = acerhdf_get_max_state, .get_cur_state = acerhdf_get_cur_state, .set_cur_state = acerhdf_set_cur_state, -- cgit v1.2.3 From 20485a565de73c58d39b74501b451b40bd817195 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 21 Jun 2017 12:34:17 +0530 Subject: platform/x86: intel_menlow: Add const to thermal_cooling_device_ops structure Declare thermal_cooling_device_ops structure as const as it is only passed as an argument to the function thermal_cooling_device_register and this argument is of type const. So, declare the structure as const. Signed-off-by: Bhumika Goyal Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel_menlow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c index cbe01021c939..ef9b0af8cdd3 100644 --- a/drivers/platform/x86/intel_menlow.c +++ b/drivers/platform/x86/intel_menlow.c @@ -142,7 +142,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev, return 0; } -static struct thermal_cooling_device_ops memory_cooling_ops = { +static const struct thermal_cooling_device_ops memory_cooling_ops = { .get_max_state = memory_get_max_bandwidth, .get_cur_state = memory_get_cur_bandwidth, .set_cur_state = memory_set_cur_bandwidth, -- cgit v1.2.3 From c0e4aa78716401e8d7d5434b69bbf6596b55a936 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 21 Jun 2017 17:01:35 -0500 Subject: platform/x86: alienware-wmi: Adjust instance of wmi_evaluate_method calls to 0 Pali recently noticed that WMI instances are zero indexed. The only reason that these calls all worked properly is because the ASL didn't verify the instance number. Signed-off-by: Mario Limonciello Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/alienware-wmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index d6b34923fb4e..9866fec78c1c 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -303,7 +303,7 @@ static int alienware_update_led(struct platform_zone *zone) } pr_debug("alienware-wmi: guid %s method %d\n", guid, method_id); - status = wmi_evaluate_method(guid, 1, method_id, &input, NULL); + status = wmi_evaluate_method(guid, 0, method_id, &input, NULL); if (ACPI_FAILURE(status)) pr_err("alienware-wmi: zone set failure: %u\n", status); return ACPI_FAILURE(status); @@ -352,7 +352,7 @@ static int wmax_brightness(int brightness) }; input.length = (acpi_size) sizeof(args); input.pointer = &args; - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, + status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, WMAX_METHOD_BRIGHTNESS, &input, NULL); if (ACPI_FAILURE(status)) pr_err("alienware-wmi: brightness set failure: %u\n", status); @@ -506,10 +506,10 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, if (out_data != NULL) { output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, + status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, command, &input, &output); } else - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, + status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, command, &input, NULL); if (ACPI_SUCCESS(status) && out_data != NULL) { -- cgit v1.2.3 From 71596f5b0e4a0071394d425d7cbcd2bfca655c61 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 23 Jun 2017 09:35:21 -0500 Subject: platform/x86: dell-wmi-led: Adjust instance of wmi_evaluate_method calls to 0 Pali recently noticed that WMI instances are zero indexed. The only reason that these calls all worked properly is because the ASL didn't verify the instance number. Signed-off-by: Louis Davis Signed-off-by: Mario Limonciello Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-wmi-led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/dell-wmi-led.c b/drivers/platform/x86/dell-wmi-led.c index a0c7e99530ef..5bedaf7f0633 100644 --- a/drivers/platform/x86/dell-wmi-led.c +++ b/drivers/platform/x86/dell-wmi-led.c @@ -68,7 +68,7 @@ static int dell_led_perform_fn(u8 length, u8 result_code, u8 device_id, input.length = sizeof(struct bios_args); input.pointer = &args; - status = wmi_evaluate_method(DELL_LED_BIOS_GUID, 1, 1, &input, &output); + status = wmi_evaluate_method(DELL_LED_BIOS_GUID, 0, 1, &input, &output); if (ACPI_FAILURE(status)) return status; -- cgit v1.2.3 From 36a1f2c607fe3f196bd15a0f4cd3d727b2c9c399 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 23 Jun 2017 14:05:56 +0530 Subject: platform/x86: toshiba_haps: constify haps_attr_group File size before: text data bss dec hex filename 1471 528 8 2007 7d7 drivers/platform/x86/toshiba_haps.o File size After adding 'const': text data bss dec hex filename 1519 464 8 1991 7c7 drivers/platform/x86/toshiba_haps.o Signed-off-by: Arvind Yadav Signed-off-by: Andy Shevchenko --- drivers/platform/x86/toshiba_haps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c index b3dec521e2b6..fb2736602558 100644 --- a/drivers/platform/x86/toshiba_haps.c +++ b/drivers/platform/x86/toshiba_haps.c @@ -132,7 +132,7 @@ static struct attribute *haps_attributes[] = { NULL, }; -static struct attribute_group haps_attr_group = { +static const struct attribute_group haps_attr_group = { .attrs = haps_attributes, }; -- cgit v1.2.3 From 130bbe6328c9edec37f59e4582cec5e43512b8e6 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 23 Jun 2017 14:40:51 +0530 Subject: platform/x86: eeepc-laptop: constify platform_attribute_group File size before: text data bss dec hex filename 9934 1136 2 11072 2b40 drivers/platform/x86/eeepc-laptop.o File size After adding 'const': text data bss dec hex filename 9998 1072 2 11072 2b40 drivers/platform/x86/eeepc-laptop.o Signed-off-by: Arvind Yadav Signed-off-by: Andy Shevchenko --- drivers/platform/x86/eeepc-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 2426399e1e04..5a681962899c 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -445,7 +445,7 @@ static struct attribute *platform_attributes[] = { NULL }; -static struct attribute_group platform_attribute_group = { +static const struct attribute_group platform_attribute_group = { .attrs = platform_attributes }; -- cgit v1.2.3 From 79e19ab5421b2d4f30901594aeee8180ee7a99ab Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 23 Jun 2017 16:06:30 +0530 Subject: platform/x86: msi-laptop: constify msipf*_attribute_group File size before: text data bss dec hex filename 5396 5016 85 10497 2901 drivers/platform/x86/msi-laptop.o File size After adding 'const': text data bss dec hex filename 5524 4888 85 10497 2901 drivers/platform/x86/msi-laptop.o Signed-off-by: Arvind Yadav Signed-off-by: Andy Shevchenko --- drivers/platform/x86/msi-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 9e90827c176a..61b9014d2610 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -563,11 +563,11 @@ static struct attribute *msipf_old_attributes[] = { NULL }; -static struct attribute_group msipf_attribute_group = { +static const struct attribute_group msipf_attribute_group = { .attrs = msipf_attributes }; -static struct attribute_group msipf_old_attribute_group = { +static const struct attribute_group msipf_old_attribute_group = { .attrs = msipf_old_attributes }; -- cgit v1.2.3 From 08df5d476fa817ff9c4a5a194a171e43f27a91c1 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 16 Jun 2017 06:40:53 +0200 Subject: platform/x86: fujitsu-laptop: remove redundant safety checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not check whether the pointer passed to ACPI add callbacks is NULL as it is earlier dereferenced anyway in the bus-level probe callback, acpi_device_probe(). Do not check the value of acpi_disabled in fujitsu_init(), because it is already done by acpi_bus_register_driver(), which is the first function called by fujitsu_init(). Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 1c6fdd952c75..04796b27a4f0 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -408,9 +408,6 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) if (acpi_video_get_backlight_type() != acpi_backlight_vendor) return -ENODEV; - if (!device) - return -EINVAL; - priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -798,9 +795,6 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) int error; int i; - if (!device) - return -EINVAL; - priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -1019,9 +1013,6 @@ static int __init fujitsu_init(void) { int ret; - if (acpi_disabled) - return -ENODEV; - ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver); if (ret) return ret; -- cgit v1.2.3 From d6a298aea319c794fd7ae976836fe5f71a649407 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 16 Jun 2017 06:40:54 +0200 Subject: platform/x86: fujitsu-laptop: use strcpy to set ACPI device names and classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No formatting is needed when setting ACPI device name and class, so switch to using strcpy() for this purpose. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 04796b27a4f0..b4e7a93c9877 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -413,8 +413,8 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) return -ENOMEM; fujitsu_bl = priv; - sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_BL_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); + strcpy(acpi_device_name(device), ACPI_FUJITSU_BL_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_FUJITSU_CLASS); device->driver_data = priv; error = acpi_fujitsu_bl_input_setup(device); @@ -802,9 +802,8 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended."); fext = device; - sprintf(acpi_device_name(device), "%s", - ACPI_FUJITSU_LAPTOP_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); + strcpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_FUJITSU_CLASS); device->driver_data = priv; /* kfifo */ -- cgit v1.2.3 From c1f51f1c4906f2551e21451228dcbb3b9dfc7008 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 16 Jun 2017 06:40:55 +0200 Subject: platform/x86: fujitsu-laptop: sanitize hotkey input device identification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the case of brightness-related FUJ02B1 ACPI device, initializing the input device associated with it identically as acpi-video initializes its input device makes sense. However, using the same data for the input device associated with the FUJ02E3 ACPI device makes little sense, because the latter has nothing to do with video and assigning an arbitrary product ID to it is redundant. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index b4e7a93c9877..c01b8ed99478 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -557,13 +557,12 @@ static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) if (!priv->input) return -ENOMEM; - snprintf(priv->phys, sizeof(priv->phys), "%s/video/input0", + snprintf(priv->phys, sizeof(priv->phys), "%s/input0", acpi_device_hid(device)); priv->input->name = acpi_device_name(device); priv->input->phys = priv->phys; priv->input->id.bustype = BUS_HOST; - priv->input->id.product = 0x06; dmi_check_system(fujitsu_laptop_dmi_table); ret = sparse_keymap_setup(priv->input, keymap, NULL); -- cgit v1.2.3 From 1c1946269f6a7b3c96a7164f0c9b48854ac8a6e2 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 16 Jun 2017 06:40:56 +0200 Subject: platform/x86: fujitsu-laptop: do not update ACPI device power status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling acpi_bus_update_power() for ACPI devices FUJ02B1 and FUJ02E3 is pointless as they are not power manageable (neither _PS0 nor _PR0 is defined for any of them), which causes their power state to be inherited from their parent devices. Given the ACPI paths of these two devices (\_SB.PCI0.LPCB.FJEX, \_SB.FEXT), their parent devices are also not power manageable. These parent devices will thus have their power state initialized to ACPI_STATE_D0, which in turn causes the power state for both FUJ02B1 and FUJ02E3 to always be ACPI_STATE_D0 ("on"). Remove relevant acpi_bus_update_power() calls along with parts of debug messages that they were supposed to have an effect on. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index c01b8ed99478..1ab7a115094b 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -402,7 +402,6 @@ static int fujitsu_backlight_register(struct acpi_device *device) static int acpi_fujitsu_bl_add(struct acpi_device *device) { struct fujitsu_bl *priv; - int state = 0; int error; if (acpi_video_get_backlight_type() != acpi_backlight_vendor) @@ -421,15 +420,8 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) if (error) return error; - error = acpi_bus_update_power(device->handle, &state); - if (error) { - pr_err("Error reading power state\n"); - return error; - } - - pr_info("ACPI: %s [%s] (%s)\n", - acpi_device_name(device), acpi_device_bid(device), - !device->power.state ? "on" : "off"); + pr_info("ACPI: %s [%s]\n", + acpi_device_name(device), acpi_device_bid(device)); if (acpi_has_method(device->handle, METHOD_NAME__INI)) { vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); @@ -790,7 +782,6 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) static int acpi_fujitsu_laptop_add(struct acpi_device *device) { struct fujitsu_laptop *priv; - int state = 0; int error; int i; @@ -818,15 +809,8 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) if (error) goto err_free_fifo; - error = acpi_bus_update_power(device->handle, &state); - if (error) { - pr_err("Error reading power state\n"); - goto err_free_fifo; - } - - pr_info("ACPI: %s [%s] (%s)\n", - acpi_device_name(device), acpi_device_bid(device), - !device->power.state ? "on" : "off"); + pr_info("ACPI: %s [%s]\n", + acpi_device_name(device), acpi_device_bid(device)); if (acpi_has_method(device->handle, METHOD_NAME__INI)) { vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); -- cgit v1.2.3 From 32c28f1f431f1c1c6db3491820a0086ddcd317c6 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 16 Jun 2017 06:40:57 +0200 Subject: platform/x86: fujitsu-laptop: do not evaluate ACPI _INI methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit acpi_ns_initialize_devices(), which is called during system-wide ACPI initialization, already detects and calls all _INI methods belonging to objects present in ACPI tables. There is no need to call these methods again every time the module is loaded because they only initialize status flags and hotkey-related variables; status flags are effectively constants, hotkey-related variables may be assigned non-zero values before acpi_fujitsu_laptop_add() is called, but that does not really matter as we drain the scancodes queued in the firmware's ring buffer before doing anything else. Remove sections of code which invoke and check evaluation status of the _INI methods belonging to the ACPI devices handled by the driver. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 1ab7a115094b..5c80bcb81451 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -423,14 +423,6 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) pr_info("ACPI: %s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); - if (acpi_has_method(device->handle, METHOD_NAME__INI)) { - vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); - if (ACPI_FAILURE - (acpi_evaluate_object - (device->handle, METHOD_NAME__INI, NULL, NULL))) - pr_err("_INI Method failed\n"); - } - if (get_max_brightness(device) <= 0) priv->max_brightness = FUJITSU_LCD_N_LEVELS; get_lcd_level(device); @@ -812,14 +804,6 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) pr_info("ACPI: %s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); - if (acpi_has_method(device->handle, METHOD_NAME__INI)) { - vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); - if (ACPI_FAILURE - (acpi_evaluate_object - (device->handle, METHOD_NAME__INI, NULL, NULL))) - pr_err("_INI Method failed\n"); - } - i = 0; while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) -- cgit v1.2.3 From eee77da1a7f02fd114288c4c379fed3d2ca4593d Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 16 Jun 2017 06:40:58 +0200 Subject: platform/x86: fujitsu-laptop: rework debugging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using a dedicated Kconfig option for enabling debugging means the user may be forced to recompile their kernel in order to gather debugging information, which is inconvenient. Replace custom debugging infrastructure with standard logging functions, taking advantage of dynamic debug. Replace a pr_info() call inside an ACPI callback with an acpi_handle_info() call. The following mapping was used: - FUJLAPTOP_DBG_ERROR -> acpi_handle_err() - FUJLAPTOP_DBG_WARN -> acpi_handle_info() / dev_info() - FUJLAPTOP_DBG_INFO -> acpi_handle_debug() - FUJLAPTOP_DBG_TRACE -> acpi_handle_debug() / dev_dbg() This means that some events which used to only be logged when the user explicitly requested it will now be logged by default: - ACPI method evaluation errors, - unknown ACPI notification codes, - unknown hotkey scancodes. The first type of events should happen rarely, if ever at all. The rest is interesting from driver development perspective as their presence in the logs will mean the driver is unaware of certain events, handling of which should be implemented. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/Kconfig | 10 ----- drivers/platform/x86/fujitsu-laptop.c | 78 +++++++++++++---------------------- 2 files changed, 28 insertions(+), 60 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 32cfeeca3ecc..c30f159353fd 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -195,16 +195,6 @@ config FUJITSU_LAPTOP If you have a Fujitsu laptop, say Y or M here. -config FUJITSU_LAPTOP_DEBUG - bool "Verbose debug mode for Fujitsu Laptop Extras" - depends on FUJITSU_LAPTOP - default n - ---help--- - Enables extra debug output from the fujitsu extras driver, at the - expense of a slight increase in driver size. - - If you are not sure, say N here. - config FUJITSU_TABLET tristate "Fujitsu Tablet Extras" depends on ACPI diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 5c80bcb81451..c1a852847d02 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -112,22 +112,6 @@ #define MAX_HOTKEY_RINGBUFFER_SIZE 100 #define RINGBUFFERSIZE 40 -/* Debugging */ -#define FUJLAPTOP_DBG_ERROR 0x0001 -#define FUJLAPTOP_DBG_WARN 0x0002 -#define FUJLAPTOP_DBG_INFO 0x0004 -#define FUJLAPTOP_DBG_TRACE 0x0008 - -#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG -#define vdbg_printk(a_dbg_level, format, arg...) \ - do { if (dbg_level & a_dbg_level) \ - printk(KERN_DEBUG pr_fmt("%s: " format), __func__, ## arg); \ - } while (0) -#else -#define vdbg_printk(a_dbg_level, format, arg...) \ - do { } while (0) -#endif - /* Device controlling the backlight and associated keys */ struct fujitsu_bl { struct input_dev *input; @@ -154,10 +138,6 @@ struct fujitsu_laptop { static struct acpi_device *fext; -#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG -static u32 dbg_level = 0x03; -#endif - /* Fujitsu ACPI interface function */ static int call_fext_func(struct acpi_device *device, @@ -176,12 +156,13 @@ static int call_fext_func(struct acpi_device *device, status = acpi_evaluate_integer(device->handle, "FUNC", &arg_list, &value); if (ACPI_FAILURE(status)) { - vdbg_printk(FUJLAPTOP_DBG_ERROR, "Failed to evaluate FUNC\n"); + acpi_handle_err(device->handle, "Failed to evaluate FUNC\n"); return -ENODEV; } - vdbg_printk(FUJLAPTOP_DBG_TRACE, "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", - func, op, feature, state, (int)value); + acpi_handle_debug(device->handle, + "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", + func, op, feature, state, (int)value); return value; } @@ -208,16 +189,16 @@ static int set_lcd_level(struct acpi_device *device, int level) break; } - vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via %s [%d]\n", - method, level); + acpi_handle_debug(device->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); if (ACPI_FAILURE(status)) { - vdbg_printk(FUJLAPTOP_DBG_ERROR, "Failed to evaluate %s\n", - method); + acpi_handle_err(device->handle, "Failed to evaluate %s\n", + method); return -ENODEV; } @@ -232,7 +213,7 @@ static int get_lcd_level(struct acpi_device *device) unsigned long long state = 0; acpi_status status = AE_OK; - vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n"); + acpi_handle_debug(device->handle, "get lcd level via GBLL\n"); status = acpi_evaluate_integer(device->handle, "GBLL", NULL, &state); if (ACPI_FAILURE(status)) @@ -249,7 +230,7 @@ static int get_max_brightness(struct acpi_device *device) unsigned long long state = 0; acpi_status status = AE_OK; - vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n"); + acpi_handle_debug(device->handle, "get max lcd level via RBLL\n"); status = acpi_evaluate_integer(device->handle, "RBLL", NULL, &state); if (ACPI_FAILURE(status)) @@ -442,8 +423,8 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) int oldb, newb; if (event != ACPI_FUJITSU_NOTIFY_CODE1) { - vdbg_printk(FUJLAPTOP_DBG_WARN, - "unsupported event [0x%x]\n", event); + acpi_handle_info(device->handle, "unsupported event [0x%x]\n", + event); sparse_keymap_report_event(priv->input, -1, 1, true); return; } @@ -452,8 +433,8 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) get_lcd_level(device); newb = priv->brightness_level; - vdbg_printk(FUJLAPTOP_DBG_TRACE, "brightness button event [%i -> %i]\n", - oldb, newb); + acpi_handle_debug(device->handle, + "brightness button event [%i -> %i]\n", oldb, newb); if (oldb == newb) return; @@ -808,7 +789,8 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ; /* No action, result is discarded */ - vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); + acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n", + i); priv->flags_supported = call_fext_func(device, FUNC_FLAGS, 0x0, 0x0, 0x0); @@ -823,8 +805,8 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) 0x0); /* Suspect this is a keymap of the application panel, print it */ - pr_info("BTNI: [0x%x]\n", call_fext_func(device, - FUNC_BUTTONS, 0x0, 0x0, 0x0)); + acpi_handle_info(device->handle, "BTNI: [0x%x]\n", + call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0)); /* Sync backlight power status */ if (fujitsu_bl && fujitsu_bl->bl_device && @@ -870,13 +852,13 @@ static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode) status = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode, sizeof(scancode), &priv->fifo_lock); if (status != sizeof(scancode)) { - vdbg_printk(FUJLAPTOP_DBG_WARN, - "Could not push scancode [0x%x]\n", scancode); + dev_info(&priv->input->dev, "Could not push scancode [0x%x]\n", + scancode); return; } sparse_keymap_report_event(priv->input, scancode, 1, false); - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "Push scancode into ringbuffer [0x%x]\n", scancode); + dev_dbg(&priv->input->dev, "Push scancode into ringbuffer [0x%x]\n", + scancode); } static void acpi_fujitsu_laptop_release(struct acpi_device *device) @@ -891,8 +873,8 @@ static void acpi_fujitsu_laptop_release(struct acpi_device *device) if (status != sizeof(scancode)) return; sparse_keymap_report_event(priv->input, scancode, 0, false); - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "Pop scancode from ringbuffer [0x%x]\n", scancode); + dev_dbg(&priv->input->dev, + "Pop scancode from ringbuffer [0x%x]\n", scancode); } } @@ -903,8 +885,8 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) unsigned int irb; if (event != ACPI_FUJITSU_NOTIFY_CODE1) { - vdbg_printk(FUJLAPTOP_DBG_WARN, - "Unsupported event [0x%x]\n", event); + acpi_handle_info(device->handle, "Unsupported event [0x%x]\n", + event); sparse_keymap_report_event(priv->input, -1, 1, true); return; } @@ -922,8 +904,8 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) else if (scancode == 0) acpi_fujitsu_laptop_release(device); else - vdbg_printk(FUJLAPTOP_DBG_WARN, - "Unknown GIRB result [%x]\n", irb); + acpi_handle_info(device->handle, + "Unknown GIRB result [%x]\n", irb); } /* On some models (first seen on the Skylake-based Lifebook @@ -1025,10 +1007,6 @@ module_param(use_alt_lcd_levels, int, 0644); MODULE_PARM_DESC(use_alt_lcd_levels, "Interface used for setting LCD brightness level (-1 = auto, 0 = force SBLL, 1 = force SBL2)"); module_param(disable_brightness_adjust, bool, 0644); MODULE_PARM_DESC(disable_brightness_adjust, "Disable LCD brightness adjustment"); -#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG -module_param_named(debug, dbg_level, uint, 0644); -MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); -#endif MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon"); MODULE_DESCRIPTION("Fujitsu laptop extras support"); -- cgit v1.2.3 From d791db9a57ab7f390916dce0fa1315130bb6664c Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 30 Jun 2017 10:39:47 +0530 Subject: platform/x86: sony-laptop: constify attribute_group and input index array attribute_groups are not supposed to change at runtime. All functions working with attribute_groups provided by work with const attribute_group. The content of sony_laptop_input_index does not change and is declared as a static global array. Constify spic_attribute_group and sony_laptop_input_index. File size before: text data bss dec hex filename 31273 5176 372 36821 8fd5 drivers/platform/x86/sony-laptop.o File size After adding 'const': text data bss dec hex filename 31337 5112 372 36821 8fd5 drivers/platform/x86/sony-laptop.o Signed-off-by: Arvind Yadav [dvhart: updated commit message, includes fix suggested by Arnd Bergmann] Signed-off-by: Andy Shevchenko Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/sony-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index aa2ee51d3547..bfae79534f44 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -222,7 +222,7 @@ struct sony_laptop_keypress { /* Correspondance table between sonypi events * and input layer indexes in the keymap */ -static int sony_laptop_input_index[] = { +static const int sony_laptop_input_index[] = { -1, /* 0 no event */ -1, /* 1 SONYPI_EVENT_JOGDIAL_DOWN */ -1, /* 2 SONYPI_EVENT_JOGDIAL_UP */ @@ -4032,7 +4032,7 @@ static struct attribute *spic_attributes[] = { NULL }; -static struct attribute_group spic_attribute_group = { +static const struct attribute_group spic_attribute_group = { .attrs = spic_attributes }; -- cgit v1.2.3