platform-drivers-x86 for v4.17-1
Dell SMBIOS driver fixed against memory leaks. The fujitsu-laptop driver is cleaned up and now supports hotkeys for Lifebook U7x7 models. Besides that the typo introduced by one of previous clean up series has been fixed. Specific to x86-based laptops HID device now supports KEY_ROTATE_LOCK_TOGGLE event which is emitted, for example, by Wacom MobileStudio Pro 13. Turbo MAX 3 technology is enabled for the rest of platforms that support Hardware-P-States feature which have core priority described by ACPI CPPC table. Mellanox on x86 gets better support of I2C bus in use including support of hotpluggable ones. Silead touchscreen is enabled on two tablet models, i.e Yours Y8W81 and I.T.Works TW701. From now on the second fan on Thinkpad P50 is supported. The topstar-laptop driver is reworked to support new models, in particular Topstar U931. Some of the changes had been already applied during v4.16 cycle and thus have a duplication here: -027d50ccd6
platform/x86: intel-vbtn: Only activate tablet mode switch on 2-in-1's -250b044e1a
platform/x86: intel-vbtn: Reset wakeup capable flag on removal -356b57752c
platform/x86: intel-hid: Reset wakeup capable flag on removal -501f7e52de
platform/x86: wmi: Fix misuse of vsprintf extension %pULL -98c76a3904
platform/x86: dell-smbios: Correct some style warnings -ec34fe3859
platform/x86: dell-smbios: Rename dell-smbios source to dell-smbios-bae -41e36f2f85
platform/x86: dell-smbios: Link all dell-smbios-* modules together -c715e43455
platform/x86: Allow for SMBIOS backend defaults -cc69c88fbe
platform/x86: dell-smbios: Resolve dependency error on DCDBAS -4716007c23
platform/x86: dell-smbios: Resolve dependency error on ACPI_WMI -7129707ec2
platform/x86: Fix dell driver init order The following is an automated git shortlog grouped by driver: dell-smbios: - Fix memory leaks in build_tokens_sysfs() - Fix dell driver init order - Resolve dependency error on ACPI_WMI - Resolve dependency error on DCDBAS - Allow for SMBIOS backend defaults - Link all dell-smbios-* modules together - Rename dell-smbios source to dell-smbios-base - Correct some style warnings fujitsu-laptop: - Support Lifebook U7x7 hotkeys - Revert UNSUPPORTED_CMD back to an int - Clean up constants - Define constants for backlight power control - Do not include linux/slab.h - Clearly distinguish module parameters - Simplify error paths - Defer input device registration - Unify local variable naming GPD pocket fan: - fix spelling mistake: "Mill-celcius" -> "millicelsius" intel-hid: - support KEY_ROTATE_LOCK_TOGGLE - clean up and sort header files - Reset wakeup capable flag on removal intel_turbo_max_3: - Remove restriction for HWP platforms intel-vbtn: - Reset wakeup capable flag on removal - Only activate tablet mode switch on 2-in-1's mlx-platform: - Add physical bus number auto detection - Add deffered bus functionality - Use define for the channel numbers platform/mellanox: - mlxreg-hotplug: Change input for device create routine silead_dmi: - Add entry for the Yours Y8W81 tablet - Add DMI match for the I.T.Works TW701 tablet thinkpad_acpi: - Add 2nd Fan Support for Thinkpad P50 topstar-laptop: - replace licence text with SPDX tag - update copyright and fix some comments - add Topstar U931/RVP7 WLAN LED workaround - add platform device - split ACPI events and input handling - use consistent naming scheme - revert "convert to module_acpi_driver()" wmi: - Fix misuse of vsprintf extension %pULL - Replace list_for_each() by list_for_each_entry() - Replace kmalloc + sprintf() with kasprintf() -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEhiZOUlnC9oKN3n3AmT3/83c5Sy0FAlrM6icACgkQmT3/83c5 Sy0qUA//Zg1uCmqTzvTxEsj7Z6RfwPV5IKE0pl86JufNXibuvxInVQI3qMU9D7lw Fl6n0k0HDoOEce5wo8fy7pic1WmmwDrapaV977elMfv4yGNQl/eIEoT6g9VBGMhE 9ORrdjBJtVYJR2rWLNH0DzeU2WoLUL0OwTQs0e3mj/mLazIARN6lC0qPDr9P4baE yXKkLGBmeuw2m0s3BfLVP5CDSanv0oB2IFsH5Qt1/y1qVT/VQnzcqFSSwz/IENm7 ZslNKR4Msi9/lDDt5HOsTADpgUI3m1t4fUReXx3MtcvuxZb6DdrHJWIAVU86NhKk /Yxm6/HU5/zpYgLXF+980GVjT6/KfPtRjJFoBItFtNeatj/oI9YStcaPFWwt2TFV hBHgS0OjPjuQNIizsjByitKerVEdsV7dJHY7wcmfq/3CpvB4Y8xrIJAa/Hj3HR34 SNbnl8vO1EfUu1vo1W4R8GfHxkIETKXT/hLpj54GSmSCzVY9lUQydyQwLTIC2Nsr L8XPsZyZfS6mq4ZeGfy9QDFbLZ9NephjnGFBiRceWM8xZKO0l8iDYMfd2sVfOP+v 4SzoWmLMVXS+ittObRo8i26B7ISlzVwdf3XCQA2ZgYeP/E/1ilo44Ifwf7ycOgeu Q8uk0mLAs0etfV8IqKwW3U5d/KzJEkBxYI4+HdL1IcQ2tAqe0J4= =SuHR -----END PGP SIGNATURE----- Merge tag 'platform-drivers-x86-v4.17-1' of git://git.infradead.org/linux-platform-drivers-x86 Pull x86 platform driver updates from Andy Shevchenko: - Dell SMBIOS driver fixed against memory leaks. - The fujitsu-laptop driver is cleaned up and now supports hotkeys for Lifebook U7x7 models. Besides that the typo introduced by one of previous clean up series has been fixed. - Specific to x86-based laptops HID device now supports KEY_ROTATE_LOCK_TOGGLE event which is emitted, for example, by Wacom MobileStudio Pro 13. - Turbo MAX 3 technology is enabled for the rest of platforms that support Hardware-P-States feature which have core priority described by ACPI CPPC table. - Mellanox on x86 gets better support of I2C bus in use including support of hotpluggable ones. - Silead touchscreen is enabled on two tablet models, i.e Yours Y8W81 and I.T.Works TW701. - From now on the second fan on Thinkpad P50 is supported. - The topstar-laptop driver is reworked to support new models, in particular Topstar U931. * tag 'platform-drivers-x86-v4.17-1' of git://git.infradead.org/linux-platform-drivers-x86: (41 commits) platform/x86: thinkpad_acpi: Add 2nd Fan Support for Thinkpad P50 platform/x86: dell-smbios: Fix memory leaks in build_tokens_sysfs() intel-hid: support KEY_ROTATE_LOCK_TOGGLE intel-hid: clean up and sort header files platform/x86: silead_dmi: Add entry for the Yours Y8W81 tablet platform/x86: fujitsu-laptop: Support Lifebook U7x7 hotkeys platform/x86: mlx-platform: Add physical bus number auto detection platform/mellanox: mlxreg-hotplug: Change input for device create routine platform/x86: mlx-platform: Add deffered bus functionality platform/x86: mlx-platform: Use define for the channel numbers platform/x86: fujitsu-laptop: Revert UNSUPPORTED_CMD back to an int platform/x86: Fix dell driver init order platform/x86: dell-smbios: Resolve dependency error on ACPI_WMI platform/x86: dell-smbios: Resolve dependency error on DCDBAS platform/x86: Allow for SMBIOS backend defaults platform/x86: dell-smbios: Link all dell-smbios-* modules together platform/x86: dell-smbios: Rename dell-smbios source to dell-smbios-base platform/x86: dell-smbios: Correct some style warnings platform/x86: wmi: Fix misuse of vsprintf extension %pULL platform/x86: intel-hid: Reset wakeup capable flag on removal ...
This commit is contained in:
commit
a7726f6b61
|
@ -93,9 +93,11 @@ struct mlxreg_hotplug_priv_data {
|
|||
bool after_probe;
|
||||
};
|
||||
|
||||
static int mlxreg_hotplug_device_create(struct device *dev,
|
||||
static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
|
||||
struct mlxreg_core_data *data)
|
||||
{
|
||||
struct mlxreg_core_hotplug_platform_data *pdata;
|
||||
|
||||
/*
|
||||
* Return if adapter number is negative. It could be in case hotplug
|
||||
* event is not associated with hotplug device.
|
||||
|
@ -103,19 +105,21 @@ static int mlxreg_hotplug_device_create(struct device *dev,
|
|||
if (data->hpdev.nr < 0)
|
||||
return 0;
|
||||
|
||||
data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
|
||||
pdata = dev_get_platdata(&priv->pdev->dev);
|
||||
data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
|
||||
pdata->shift_nr);
|
||||
if (!data->hpdev.adapter) {
|
||||
dev_err(dev, "Failed to get adapter for bus %d\n",
|
||||
data->hpdev.nr);
|
||||
dev_err(priv->dev, "Failed to get adapter for bus %d\n",
|
||||
data->hpdev.nr + pdata->shift_nr);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
data->hpdev.client = i2c_new_device(data->hpdev.adapter,
|
||||
data->hpdev.brdinfo);
|
||||
if (!data->hpdev.client) {
|
||||
dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
|
||||
data->hpdev.brdinfo->type, data->hpdev.nr,
|
||||
data->hpdev.brdinfo->addr);
|
||||
dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
|
||||
data->hpdev.brdinfo->type, data->hpdev.nr +
|
||||
pdata->shift_nr, data->hpdev.brdinfo->addr);
|
||||
|
||||
i2c_put_adapter(data->hpdev.adapter);
|
||||
data->hpdev.adapter = NULL;
|
||||
|
@ -270,10 +274,10 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
|
|||
if (item->inversed)
|
||||
mlxreg_hotplug_device_destroy(data);
|
||||
else
|
||||
mlxreg_hotplug_device_create(priv->dev, data);
|
||||
mlxreg_hotplug_device_create(priv, data);
|
||||
} else {
|
||||
if (item->inversed)
|
||||
mlxreg_hotplug_device_create(priv->dev, data);
|
||||
mlxreg_hotplug_device_create(priv, data);
|
||||
else
|
||||
mlxreg_hotplug_device_destroy(data);
|
||||
}
|
||||
|
@ -319,7 +323,7 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
|
|||
if (regval == MLXREG_HOTPLUG_HEALTH_MASK) {
|
||||
if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) ||
|
||||
!priv->after_probe) {
|
||||
mlxreg_hotplug_device_create(priv->dev, data);
|
||||
mlxreg_hotplug_device_create(priv, data);
|
||||
data->attached = true;
|
||||
}
|
||||
} else {
|
||||
|
@ -550,6 +554,7 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct mlxreg_core_hotplug_platform_data *pdata;
|
||||
struct mlxreg_hotplug_priv_data *priv;
|
||||
struct i2c_adapter *deferred_adap;
|
||||
int err;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
@ -558,6 +563,12 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Defer probing if the necessary adapter is not configured yet. */
|
||||
deferred_adap = i2c_get_adapter(pdata->deferred_nr);
|
||||
if (!deferred_adap)
|
||||
return -EPROBE_DEFER;
|
||||
i2c_put_adapter(deferred_adap);
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -757,6 +757,8 @@ config TOPSTAR_LAPTOP
|
|||
depends on ACPI
|
||||
depends on INPUT
|
||||
select INPUT_SPARSEKMAP
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
---help---
|
||||
This driver adds support for hotkeys found on Topstar laptops.
|
||||
|
||||
|
@ -1174,6 +1176,7 @@ config INTEL_TELEMETRY
|
|||
|
||||
config MLX_PLATFORM
|
||||
tristate "Mellanox Technologies platform support"
|
||||
depends on I2C && REGMAP
|
||||
---help---
|
||||
This option enables system support for the Mellanox Technologies
|
||||
platform. The Mellanox systems provide data center networking
|
||||
|
|
|
@ -514,7 +514,7 @@ static int build_tokens_sysfs(struct platform_device *dev)
|
|||
continue;
|
||||
|
||||
loop_fail_create_value:
|
||||
kfree(value_name);
|
||||
kfree(location_name);
|
||||
goto out_unwind_strings;
|
||||
}
|
||||
smbios_attribute_group.attrs = token_attrs;
|
||||
|
@ -525,7 +525,7 @@ loop_fail_create_value:
|
|||
return 0;
|
||||
|
||||
out_unwind_strings:
|
||||
for (i = i-1; i > 0; i--) {
|
||||
while (i--) {
|
||||
kfree(token_location_attrs[i].attr.name);
|
||||
kfree(token_value_attrs[i].attr.name);
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/fb.h>
|
||||
|
@ -61,7 +62,6 @@
|
|||
#include <linux/kfifo.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <acpi/video.h>
|
||||
|
||||
#define FUJITSU_DRIVER_VERSION "0.6.0"
|
||||
|
@ -76,42 +76,52 @@
|
|||
#define ACPI_FUJITSU_LAPTOP_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
|
||||
#define ACPI_FUJITSU_LAPTOP_DEVICE_NAME "Fujitsu FUJ02E3"
|
||||
|
||||
#define ACPI_FUJITSU_NOTIFY_CODE1 0x80
|
||||
#define ACPI_FUJITSU_NOTIFY_CODE 0x80
|
||||
|
||||
/* FUNC interface - command values */
|
||||
#define FUNC_FLAGS 0x1000
|
||||
#define FUNC_LEDS 0x1001
|
||||
#define FUNC_BUTTONS 0x1002
|
||||
#define FUNC_BACKLIGHT 0x1004
|
||||
#define FUNC_FLAGS BIT(12)
|
||||
#define FUNC_LEDS (BIT(12) | BIT(0))
|
||||
#define FUNC_BUTTONS (BIT(12) | BIT(1))
|
||||
#define FUNC_BACKLIGHT (BIT(12) | BIT(2))
|
||||
|
||||
/* FUNC interface - responses */
|
||||
#define UNSUPPORTED_CMD 0x80000000
|
||||
|
||||
/* FUNC interface - status flags */
|
||||
#define FLAG_RFKILL 0x020
|
||||
#define FLAG_LID 0x100
|
||||
#define FLAG_DOCK 0x200
|
||||
#define FLAG_RFKILL BIT(5)
|
||||
#define FLAG_LID BIT(8)
|
||||
#define FLAG_DOCK BIT(9)
|
||||
|
||||
/* FUNC interface - LED control */
|
||||
#define FUNC_LED_OFF 0x1
|
||||
#define FUNC_LED_ON 0x30001
|
||||
#define KEYBOARD_LAMPS 0x100
|
||||
#define LOGOLAMP_POWERON 0x2000
|
||||
#define LOGOLAMP_ALWAYS 0x4000
|
||||
#define RADIO_LED_ON 0x20
|
||||
#define ECO_LED 0x10000
|
||||
#define ECO_LED_ON 0x80000
|
||||
#define FUNC_LED_OFF BIT(0)
|
||||
#define FUNC_LED_ON (BIT(0) | BIT(16) | BIT(17))
|
||||
#define LOGOLAMP_POWERON BIT(13)
|
||||
#define LOGOLAMP_ALWAYS BIT(14)
|
||||
#define KEYBOARD_LAMPS BIT(8)
|
||||
#define RADIO_LED_ON BIT(5)
|
||||
#define ECO_LED BIT(16)
|
||||
#define ECO_LED_ON BIT(19)
|
||||
|
||||
/* Hotkey details */
|
||||
#define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */
|
||||
/* FUNC interface - backlight power control */
|
||||
#define BACKLIGHT_PARAM_POWER BIT(2)
|
||||
#define BACKLIGHT_OFF (BIT(0) | BIT(1))
|
||||
#define BACKLIGHT_ON 0
|
||||
|
||||
/* Scancodes read from the GIRB register */
|
||||
#define KEY1_CODE 0x410
|
||||
#define KEY2_CODE 0x411
|
||||
#define KEY3_CODE 0x412
|
||||
#define KEY4_CODE 0x413
|
||||
#define KEY5_CODE 0x420
|
||||
|
||||
/* Hotkey ringbuffer limits */
|
||||
#define MAX_HOTKEY_RINGBUFFER_SIZE 100
|
||||
#define RINGBUFFERSIZE 40
|
||||
|
||||
/* Module parameters */
|
||||
static int use_alt_lcd_levels = -1;
|
||||
static bool disable_brightness_adjust;
|
||||
|
||||
/* Device controlling the backlight and associated keys */
|
||||
struct fujitsu_bl {
|
||||
struct input_dev *input;
|
||||
|
@ -122,8 +132,6 @@ struct fujitsu_bl {
|
|||
};
|
||||
|
||||
static struct fujitsu_bl *fujitsu_bl;
|
||||
static int use_alt_lcd_levels = -1;
|
||||
static bool disable_brightness_adjust;
|
||||
|
||||
/* Device used to access hotkeys and other features on the laptop */
|
||||
struct fujitsu_laptop {
|
||||
|
@ -256,9 +264,11 @@ static int bl_update_status(struct backlight_device *b)
|
|||
|
||||
if (fext) {
|
||||
if (b->props.power == FB_BLANK_POWERDOWN)
|
||||
call_fext_func(fext, FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
|
||||
call_fext_func(fext, FUNC_BACKLIGHT, 0x1,
|
||||
BACKLIGHT_PARAM_POWER, BACKLIGHT_OFF);
|
||||
else
|
||||
call_fext_func(fext, FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
|
||||
call_fext_func(fext, FUNC_BACKLIGHT, 0x1,
|
||||
BACKLIGHT_PARAM_POWER, BACKLIGHT_ON);
|
||||
}
|
||||
|
||||
return set_lcd_level(device, b->props.brightness);
|
||||
|
@ -385,7 +395,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 error;
|
||||
int ret;
|
||||
|
||||
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
|
||||
return -ENODEV;
|
||||
|
@ -399,10 +409,6 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device)
|
|||
strcpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
|
||||
device->driver_data = priv;
|
||||
|
||||
error = acpi_fujitsu_bl_input_setup(device);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
pr_info("ACPI: %s [%s]\n",
|
||||
acpi_device_name(device), acpi_device_bid(device));
|
||||
|
||||
|
@ -410,11 +416,11 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device)
|
|||
priv->max_brightness = FUJITSU_LCD_N_LEVELS;
|
||||
get_lcd_level(device);
|
||||
|
||||
error = fujitsu_backlight_register(device);
|
||||
if (error)
|
||||
return error;
|
||||
ret = acpi_fujitsu_bl_input_setup(device);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return fujitsu_backlight_register(device);
|
||||
}
|
||||
|
||||
/* Brightness notify */
|
||||
|
@ -424,7 +430,7 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event)
|
|||
struct fujitsu_bl *priv = acpi_driver_data(device);
|
||||
int oldb, newb;
|
||||
|
||||
if (event != ACPI_FUJITSU_NOTIFY_CODE1) {
|
||||
if (event != ACPI_FUJITSU_NOTIFY_CODE) {
|
||||
acpi_handle_info(device->handle, "unsupported event [0x%x]\n",
|
||||
event);
|
||||
sparse_keymap_report_event(priv->input, -1, 1, true);
|
||||
|
@ -455,7 +461,9 @@ static const struct key_entry keymap_default[] = {
|
|||
{ KE_KEY, KEY3_CODE, { KEY_PROG3 } },
|
||||
{ KE_KEY, KEY4_CODE, { KEY_PROG4 } },
|
||||
{ KE_KEY, KEY5_CODE, { KEY_RFKILL } },
|
||||
{ KE_KEY, BIT(5), { KEY_RFKILL } },
|
||||
{ KE_KEY, BIT(26), { KEY_TOUCHPAD_TOGGLE } },
|
||||
{ KE_KEY, BIT(29), { KEY_MICMUTE } },
|
||||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
|
@ -693,7 +701,7 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
|||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
struct led_classdev *led;
|
||||
int result;
|
||||
int ret;
|
||||
|
||||
if (call_fext_func(device,
|
||||
FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
|
||||
|
@ -704,9 +712,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
|||
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;
|
||||
ret = devm_led_classdev_register(&device->dev, led);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((call_fext_func(device,
|
||||
|
@ -719,9 +727,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
|||
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;
|
||||
ret = devm_led_classdev_register(&device->dev, led);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -742,9 +750,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
|||
led->brightness_set_blocking = radio_led_set;
|
||||
led->brightness_get = radio_led_get;
|
||||
led->default_trigger = "rfkill-any";
|
||||
result = devm_led_classdev_register(&device->dev, led);
|
||||
if (result)
|
||||
return result;
|
||||
ret = devm_led_classdev_register(&device->dev, led);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Support for eco led is not always signaled in bit corresponding
|
||||
|
@ -762,9 +770,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
|
|||
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;
|
||||
ret = devm_led_classdev_register(&device->dev, led);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -773,8 +781,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 error;
|
||||
int i;
|
||||
int ret, i = 0;
|
||||
|
||||
priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
|
@ -789,23 +796,16 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device)
|
|||
|
||||
/* kfifo */
|
||||
spin_lock_init(&priv->fifo_lock);
|
||||
error = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int),
|
||||
ret = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int),
|
||||
GFP_KERNEL);
|
||||
if (error) {
|
||||
pr_err("kfifo_alloc failed\n");
|
||||
goto err_stop;
|
||||
}
|
||||
|
||||
error = acpi_fujitsu_laptop_input_setup(device);
|
||||
if (error)
|
||||
goto err_free_fifo;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pr_info("ACPI: %s [%s]\n",
|
||||
acpi_device_name(device), acpi_device_bid(device));
|
||||
|
||||
i = 0;
|
||||
while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0
|
||||
&& (i++) < MAX_HOTKEY_RINGBUFFER_SIZE)
|
||||
while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 &&
|
||||
i++ < MAX_HOTKEY_RINGBUFFER_SIZE)
|
||||
; /* No action, result is discarded */
|
||||
acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n",
|
||||
i);
|
||||
|
@ -829,26 +829,31 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device)
|
|||
/* Sync backlight power status */
|
||||
if (fujitsu_bl && fujitsu_bl->bl_device &&
|
||||
acpi_video_get_backlight_type() == acpi_backlight_vendor) {
|
||||
if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
|
||||
if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2,
|
||||
BACKLIGHT_PARAM_POWER, 0x0) == BACKLIGHT_OFF)
|
||||
fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN;
|
||||
else
|
||||
fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK;
|
||||
}
|
||||
|
||||
error = acpi_fujitsu_laptop_leds_register(device);
|
||||
if (error)
|
||||
ret = acpi_fujitsu_laptop_input_setup(device);
|
||||
if (ret)
|
||||
goto err_free_fifo;
|
||||
|
||||
error = fujitsu_laptop_platform_add(device);
|
||||
if (error)
|
||||
ret = acpi_fujitsu_laptop_leds_register(device);
|
||||
if (ret)
|
||||
goto err_free_fifo;
|
||||
|
||||
ret = fujitsu_laptop_platform_add(device);
|
||||
if (ret)
|
||||
goto err_free_fifo;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_fifo:
|
||||
kfifo_free(&priv->fifo);
|
||||
err_stop:
|
||||
return error;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_fujitsu_laptop_remove(struct acpi_device *device)
|
||||
|
@ -865,11 +870,11 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device)
|
|||
static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
int status;
|
||||
int ret;
|
||||
|
||||
status = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode,
|
||||
ret = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode,
|
||||
sizeof(scancode), &priv->fifo_lock);
|
||||
if (status != sizeof(scancode)) {
|
||||
if (ret != sizeof(scancode)) {
|
||||
dev_info(&priv->input->dev, "Could not push scancode [0x%x]\n",
|
||||
scancode);
|
||||
return;
|
||||
|
@ -882,13 +887,12 @@ static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode)
|
|||
static void acpi_fujitsu_laptop_release(struct acpi_device *device)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
int scancode, status;
|
||||
int scancode, ret;
|
||||
|
||||
while (true) {
|
||||
status = kfifo_out_locked(&priv->fifo,
|
||||
(unsigned char *)&scancode,
|
||||
ret = kfifo_out_locked(&priv->fifo, (unsigned char *)&scancode,
|
||||
sizeof(scancode), &priv->fifo_lock);
|
||||
if (status != sizeof(scancode))
|
||||
if (ret != sizeof(scancode))
|
||||
return;
|
||||
sparse_keymap_report_event(priv->input, scancode, 0, false);
|
||||
dev_dbg(&priv->input->dev,
|
||||
|
@ -899,10 +903,10 @@ static void acpi_fujitsu_laptop_release(struct acpi_device *device)
|
|||
static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
|
||||
{
|
||||
struct fujitsu_laptop *priv = acpi_driver_data(device);
|
||||
int scancode, i = 0;
|
||||
int scancode, i = 0, ret;
|
||||
unsigned int irb;
|
||||
|
||||
if (event != ACPI_FUJITSU_NOTIFY_CODE1) {
|
||||
if (event != ACPI_FUJITSU_NOTIFY_CODE) {
|
||||
acpi_handle_info(device->handle, "Unsupported event [0x%x]\n",
|
||||
event);
|
||||
sparse_keymap_report_event(priv->input, -1, 1, true);
|
||||
|
@ -930,9 +934,18 @@ 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 ((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);
|
||||
if (priv->flags_supported & (BIT(5) | BIT(26) | BIT(29))) {
|
||||
ret = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0);
|
||||
if (ret & BIT(5))
|
||||
sparse_keymap_report_event(priv->input,
|
||||
BIT(5), 1, true);
|
||||
if (ret & BIT(26))
|
||||
sparse_keymap_report_event(priv->input,
|
||||
BIT(26), 1, true);
|
||||
if (ret & BIT(29))
|
||||
sparse_keymap_report_event(priv->input,
|
||||
BIT(29), 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialization */
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
static int temp_limits[3] = { 55000, 60000, 65000 };
|
||||
module_param_array(temp_limits, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(temp_limits,
|
||||
"Milli-celcius values above which the fan speed increases");
|
||||
"Millicelsius values above which the fan speed increases");
|
||||
|
||||
static int hysteresis = 3000;
|
||||
module_param(hysteresis, int, 0444);
|
||||
MODULE_PARM_DESC(hysteresis,
|
||||
"Hysteresis in milli-celcius before lowering the fan speed");
|
||||
"Hysteresis in millicelsius before lowering the fan speed");
|
||||
|
||||
static int speed_on_ac = 2;
|
||||
module_param(speed_on_ac, int, 0444);
|
||||
|
|
|
@ -16,16 +16,14 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Alex Hung");
|
||||
|
@ -67,8 +65,8 @@ static const struct key_entry intel_array_keymap[] = {
|
|||
{ KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* Release */
|
||||
{ KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* Press */
|
||||
{ KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* Release */
|
||||
{ KE_SW, 0xC8, { .sw = { SW_ROTATE_LOCK, 1 } } }, /* Press */
|
||||
{ KE_SW, 0xC9, { .sw = { SW_ROTATE_LOCK, 0 } } }, /* Release */
|
||||
{ KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } }, /* Press */
|
||||
{ KE_IGNORE, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } }, /* Release */
|
||||
{ KE_KEY, 0xCE, { KEY_POWER } }, /* Press */
|
||||
{ KE_IGNORE, 0xCF, { KEY_POWER } }, /* Release */
|
||||
{ KE_END },
|
||||
|
|
|
@ -138,9 +138,6 @@ static int __init itmt_legacy_init(void)
|
|||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_HWP))
|
||||
return -ENODEV;
|
||||
|
||||
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
|
||||
"platform/x86/turbo_max_3:online",
|
||||
itmt_legacy_cpu_online, NULL);
|
||||
|
|
|
@ -85,6 +85,15 @@
|
|||
#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
|
||||
#define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0)
|
||||
|
||||
/* Default I2C parent bus number */
|
||||
#define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1
|
||||
|
||||
/* Maximum number of possible physical buses equipped on system */
|
||||
#define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16
|
||||
|
||||
/* Number of channels in group */
|
||||
#define MLXPLAT_CPLD_GRP_CHNL_NUM 8
|
||||
|
||||
/* Start channel numbers */
|
||||
#define MLXPLAT_CPLD_CH1 2
|
||||
#define MLXPLAT_CPLD_CH2 10
|
||||
|
@ -124,7 +133,7 @@ static const struct resource mlxplat_lpc_resources[] = {
|
|||
};
|
||||
|
||||
/* Platform default channels */
|
||||
static const int mlxplat_default_channels[][8] = {
|
||||
static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = {
|
||||
{
|
||||
MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
|
||||
MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
|
||||
|
@ -694,6 +703,8 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
|
|||
ARRAY_SIZE(mlxplat_default_channels[i]);
|
||||
}
|
||||
mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
|
||||
mlxplat_hotplug->deferred_nr =
|
||||
mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
@ -708,6 +719,8 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
|
|||
ARRAY_SIZE(mlxplat_msn21xx_channels);
|
||||
}
|
||||
mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
|
||||
mlxplat_hotplug->deferred_nr =
|
||||
mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
@ -722,6 +735,8 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
|
|||
ARRAY_SIZE(mlxplat_msn21xx_channels);
|
||||
}
|
||||
mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
|
||||
mlxplat_hotplug->deferred_nr =
|
||||
mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
@ -736,6 +751,8 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
|
|||
ARRAY_SIZE(mlxplat_msn21xx_channels);
|
||||
}
|
||||
mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
|
||||
mlxplat_hotplug->deferred_nr =
|
||||
mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
@ -750,6 +767,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
|
|||
ARRAY_SIZE(mlxplat_msn21xx_channels);
|
||||
}
|
||||
mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
|
||||
mlxplat_hotplug->deferred_nr =
|
||||
mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
@ -830,10 +849,48 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
|
|||
|
||||
MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
|
||||
|
||||
static int mlxplat_mlxcpld_verify_bus_topology(int *nr)
|
||||
{
|
||||
struct i2c_adapter *search_adap;
|
||||
int shift, i;
|
||||
|
||||
/* Scan adapters from expected id to verify it is free. */
|
||||
*nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR;
|
||||
for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i <
|
||||
MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) {
|
||||
search_adap = i2c_get_adapter(i);
|
||||
if (search_adap) {
|
||||
i2c_put_adapter(search_adap);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Return if expected parent adapter is free. */
|
||||
if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return with error if free id for adapter is not found. */
|
||||
if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM)
|
||||
return -ENODEV;
|
||||
|
||||
/* Shift adapter ids, since expected parent adapter is not free. */
|
||||
*nr = i;
|
||||
for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
|
||||
shift = *nr - mlxplat_mux_data[i].parent;
|
||||
mlxplat_mux_data[i].parent = *nr;
|
||||
mlxplat_mux_data[i].base_nr += shift;
|
||||
if (shift > 0)
|
||||
mlxplat_hotplug->shift_nr = shift;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init mlxplat_init(void)
|
||||
{
|
||||
struct mlxplat_priv *priv;
|
||||
int i, err;
|
||||
int i, nr, err;
|
||||
|
||||
if (!dmi_check_system(mlxplat_dmi_table))
|
||||
return -ENODEV;
|
||||
|
@ -853,7 +910,12 @@ static int __init mlxplat_init(void)
|
|||
}
|
||||
platform_set_drvdata(mlxplat_dev, priv);
|
||||
|
||||
priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
|
||||
err = mlxplat_mlxcpld_verify_bus_topology(&nr);
|
||||
if (nr < 0)
|
||||
goto fail_alloc;
|
||||
|
||||
nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr;
|
||||
priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr,
|
||||
NULL, 0);
|
||||
if (IS_ERR(priv->pdev_i2c)) {
|
||||
err = PTR_ERR(priv->pdev_i2c);
|
||||
|
|
|
@ -446,6 +446,23 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
|
|||
DMI_MATCH(DMI_BOARD_NAME, "X3 Plus"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* I.T.Works TW701 */
|
||||
.driver_data = (void *)&surftab_wintron70_st70416_6_data,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "i71c"),
|
||||
DMI_MATCH(DMI_BIOS_VERSION, "itWORKS.G.WI71C.JGBMRB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Yours Y8W81, same case and touchscreen as Chuwi Vi8 */
|
||||
.driver_data = (void *)&chuwi_vi8_data,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "YOURS"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"),
|
||||
},
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
|
@ -8703,16 +8703,24 @@ static const struct attribute_group fan_attr_group = {
|
|||
.ec = TPID(__id1, __id2), \
|
||||
.quirks = __quirks }
|
||||
|
||||
#define TPACPI_FAN_QB(__id1, __id2, __quirks) \
|
||||
{ .vendor = PCI_VENDOR_ID_LENOVO, \
|
||||
.bios = TPID(__id1, __id2), \
|
||||
.ec = TPACPI_MATCH_ANY, \
|
||||
.quirks = __quirks }
|
||||
|
||||
static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
|
||||
TPACPI_FAN_QI('1', 'Y', TPACPI_FAN_Q1),
|
||||
TPACPI_FAN_QI('7', '8', TPACPI_FAN_Q1),
|
||||
TPACPI_FAN_QI('7', '6', TPACPI_FAN_Q1),
|
||||
TPACPI_FAN_QI('7', '0', TPACPI_FAN_Q1),
|
||||
TPACPI_FAN_QL('7', 'M', TPACPI_FAN_2FAN),
|
||||
TPACPI_FAN_QB('N', '1', TPACPI_FAN_2FAN),
|
||||
};
|
||||
|
||||
#undef TPACPI_FAN_QL
|
||||
#undef TPACPI_FAN_QI
|
||||
#undef TPACPI_FAN_QB
|
||||
|
||||
static int __init fan_init(struct ibm_init_struct *iibm)
|
||||
{
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ACPI driver for Topstar notebooks (hotkeys support only)
|
||||
* Topstar Laptop ACPI Extras driver
|
||||
*
|
||||
* Copyright (c) 2009 Herton Ronaldo Krzesinski <herton@mandriva.com.br>
|
||||
* Copyright (c) 2018 Guillaume Douézan-Grard
|
||||
*
|
||||
* Implementation inspired by existing x86 platform drivers, in special
|
||||
* asus/eepc/fujitsu-laptop, thanks to their authors
|
||||
*
|
||||
* 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.
|
||||
* asus/eepc/fujitsu-laptop, thanks to their authors.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
@ -18,15 +16,93 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define ACPI_TOPSTAR_CLASS "topstar"
|
||||
#define TOPSTAR_LAPTOP_CLASS "topstar"
|
||||
|
||||
struct topstar_hkey {
|
||||
struct input_dev *inputdev;
|
||||
struct topstar_laptop {
|
||||
struct acpi_device *device;
|
||||
struct platform_device *platform;
|
||||
struct input_dev *input;
|
||||
struct led_classdev led;
|
||||
};
|
||||
|
||||
/*
|
||||
* LED
|
||||
*/
|
||||
|
||||
static enum led_brightness topstar_led_get(struct led_classdev *led)
|
||||
{
|
||||
return led->brightness;
|
||||
}
|
||||
|
||||
static int topstar_led_set(struct led_classdev *led,
|
||||
enum led_brightness state)
|
||||
{
|
||||
struct topstar_laptop *topstar = container_of(led,
|
||||
struct topstar_laptop, led);
|
||||
|
||||
struct acpi_object_list params;
|
||||
union acpi_object in_obj;
|
||||
unsigned long long int ret;
|
||||
acpi_status status;
|
||||
|
||||
params.count = 1;
|
||||
params.pointer = &in_obj;
|
||||
in_obj.type = ACPI_TYPE_INTEGER;
|
||||
in_obj.integer.value = 0x83;
|
||||
|
||||
/*
|
||||
* Topstar ACPI returns 0x30001 when the LED is ON and 0x30000 when it
|
||||
* is OFF.
|
||||
*/
|
||||
status = acpi_evaluate_integer(topstar->device->handle,
|
||||
"GETX", ¶ms, &ret);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* FNCX(0x83) toggles the LED (more precisely, it is supposed to
|
||||
* act as an hardware switch and disconnect the WLAN adapter but
|
||||
* it seems to be faulty on some models like the Topstar U931
|
||||
* Notebook).
|
||||
*/
|
||||
if ((ret == 0x30001 && state == LED_OFF)
|
||||
|| (ret == 0x30000 && state != LED_OFF)) {
|
||||
status = acpi_execute_simple_method(topstar->device->handle,
|
||||
"FNCX", 0x83);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int topstar_led_init(struct topstar_laptop *topstar)
|
||||
{
|
||||
topstar->led = (struct led_classdev) {
|
||||
.default_trigger = "rfkill0",
|
||||
.brightness_get = topstar_led_get,
|
||||
.brightness_set_blocking = topstar_led_set,
|
||||
.name = TOPSTAR_LAPTOP_CLASS "::wlan",
|
||||
};
|
||||
|
||||
return led_classdev_register(&topstar->platform->dev, &topstar->led);
|
||||
}
|
||||
|
||||
static void topstar_led_exit(struct topstar_laptop *topstar)
|
||||
{
|
||||
led_classdev_unregister(&topstar->led);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input
|
||||
*/
|
||||
|
||||
static const struct key_entry topstar_keymap[] = {
|
||||
{ KE_KEY, 0x80, { KEY_BRIGHTNESSUP } },
|
||||
{ KE_KEY, 0x81, { KEY_BRIGHTNESSDOWN } },
|
||||
|
@ -57,11 +133,110 @@ static const struct key_entry topstar_keymap[] = {
|
|||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
static void acpi_topstar_notify(struct acpi_device *device, u32 event)
|
||||
static void topstar_input_notify(struct topstar_laptop *topstar, int event)
|
||||
{
|
||||
if (!sparse_keymap_report_event(topstar->input, event, 1, true))
|
||||
pr_info("unknown event = 0x%02x\n", event);
|
||||
}
|
||||
|
||||
static int topstar_input_init(struct topstar_laptop *topstar)
|
||||
{
|
||||
struct input_dev *input;
|
||||
int err;
|
||||
|
||||
input = input_allocate_device();
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
|
||||
input->name = "Topstar Laptop extra buttons";
|
||||
input->phys = TOPSTAR_LAPTOP_CLASS "/input0";
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->dev.parent = &topstar->platform->dev;
|
||||
|
||||
err = sparse_keymap_setup(input, topstar_keymap, NULL);
|
||||
if (err) {
|
||||
pr_err("Unable to setup input device keymap\n");
|
||||
goto err_free_dev;
|
||||
}
|
||||
|
||||
err = input_register_device(input);
|
||||
if (err) {
|
||||
pr_err("Unable to register input device\n");
|
||||
goto err_free_dev;
|
||||
}
|
||||
|
||||
topstar->input = input;
|
||||
return 0;
|
||||
|
||||
err_free_dev:
|
||||
input_free_device(input);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void topstar_input_exit(struct topstar_laptop *topstar)
|
||||
{
|
||||
input_unregister_device(topstar->input);
|
||||
}
|
||||
|
||||
/*
|
||||
* Platform
|
||||
*/
|
||||
|
||||
static struct platform_driver topstar_platform_driver = {
|
||||
.driver = {
|
||||
.name = TOPSTAR_LAPTOP_CLASS,
|
||||
},
|
||||
};
|
||||
|
||||
static int topstar_platform_init(struct topstar_laptop *topstar)
|
||||
{
|
||||
int err;
|
||||
|
||||
topstar->platform = platform_device_alloc(TOPSTAR_LAPTOP_CLASS, -1);
|
||||
if (!topstar->platform)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(topstar->platform, topstar);
|
||||
|
||||
err = platform_device_add(topstar->platform);
|
||||
if (err)
|
||||
goto err_device_put;
|
||||
|
||||
return 0;
|
||||
|
||||
err_device_put:
|
||||
platform_device_put(topstar->platform);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void topstar_platform_exit(struct topstar_laptop *topstar)
|
||||
{
|
||||
platform_device_unregister(topstar->platform);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI
|
||||
*/
|
||||
|
||||
static int topstar_acpi_fncx_switch(struct acpi_device *device, bool state)
|
||||
{
|
||||
acpi_status status;
|
||||
u64 arg = state ? 0x86 : 0x87;
|
||||
|
||||
status = acpi_execute_simple_method(device->handle, "FNCX", arg);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_err("Unable to switch FNCX notifications\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void topstar_acpi_notify(struct acpi_device *device, u32 event)
|
||||
{
|
||||
struct topstar_laptop *topstar = acpi_driver_data(device);
|
||||
static bool dup_evnt[2];
|
||||
bool *dup;
|
||||
struct topstar_hkey *hkey = acpi_driver_data(device);
|
||||
|
||||
/* 0x83 and 0x84 key events comes duplicated... */
|
||||
if (event == 0x83 || event == 0x84) {
|
||||
|
@ -73,91 +248,102 @@ static void acpi_topstar_notify(struct acpi_device *device, u32 event)
|
|||
*dup = true;
|
||||
}
|
||||
|
||||
if (!sparse_keymap_report_event(hkey->inputdev, event, 1, true))
|
||||
pr_info("unknown event = 0x%02x\n", event);
|
||||
topstar_input_notify(topstar, event);
|
||||
}
|
||||
|
||||
static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
|
||||
static int topstar_acpi_init(struct topstar_laptop *topstar)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_execute_simple_method(device->handle, "FNCX",
|
||||
state ? 0x86 : 0x87);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_err("Unable to switch FNCX notifications\n");
|
||||
return -ENODEV;
|
||||
return topstar_acpi_fncx_switch(topstar->device, true);
|
||||
}
|
||||
|
||||
static void topstar_acpi_exit(struct topstar_laptop *topstar)
|
||||
{
|
||||
topstar_acpi_fncx_switch(topstar->device, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable software-based WLAN LED control on systems with defective
|
||||
* hardware switch.
|
||||
*/
|
||||
static bool led_workaround;
|
||||
|
||||
static int dmi_led_workaround(const struct dmi_system_id *id)
|
||||
{
|
||||
led_workaround = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_topstar_init_hkey(struct topstar_hkey *hkey)
|
||||
static const struct dmi_system_id topstar_dmi_ids[] = {
|
||||
{
|
||||
struct input_dev *input;
|
||||
int error;
|
||||
.callback = dmi_led_workaround,
|
||||
.ident = "Topstar U931/RVP7",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "U931"),
|
||||
DMI_MATCH(DMI_BOARD_VERSION, "RVP7"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
input = input_allocate_device();
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
|
||||
input->name = "Topstar Laptop extra buttons";
|
||||
input->phys = "topstar/input0";
|
||||
input->id.bustype = BUS_HOST;
|
||||
|
||||
error = sparse_keymap_setup(input, topstar_keymap, NULL);
|
||||
if (error) {
|
||||
pr_err("Unable to setup input device keymap\n");
|
||||
goto err_free_dev;
|
||||
}
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
pr_err("Unable to register input device\n");
|
||||
goto err_free_dev;
|
||||
}
|
||||
|
||||
hkey->inputdev = input;
|
||||
return 0;
|
||||
|
||||
err_free_dev:
|
||||
input_free_device(input);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int acpi_topstar_add(struct acpi_device *device)
|
||||
static int topstar_acpi_add(struct acpi_device *device)
|
||||
{
|
||||
struct topstar_hkey *tps_hkey;
|
||||
struct topstar_laptop *topstar;
|
||||
int err;
|
||||
|
||||
tps_hkey = kzalloc(sizeof(struct topstar_hkey), GFP_KERNEL);
|
||||
if (!tps_hkey)
|
||||
dmi_check_system(topstar_dmi_ids);
|
||||
|
||||
topstar = kzalloc(sizeof(struct topstar_laptop), GFP_KERNEL);
|
||||
if (!topstar)
|
||||
return -ENOMEM;
|
||||
|
||||
strcpy(acpi_device_name(device), "Topstar TPSACPI");
|
||||
strcpy(acpi_device_class(device), ACPI_TOPSTAR_CLASS);
|
||||
strcpy(acpi_device_class(device), TOPSTAR_LAPTOP_CLASS);
|
||||
device->driver_data = topstar;
|
||||
topstar->device = device;
|
||||
|
||||
if (acpi_topstar_fncx_switch(device, true))
|
||||
goto add_err;
|
||||
err = topstar_acpi_init(topstar);
|
||||
if (err)
|
||||
goto err_free;
|
||||
|
||||
if (acpi_topstar_init_hkey(tps_hkey))
|
||||
goto add_err;
|
||||
err = topstar_platform_init(topstar);
|
||||
if (err)
|
||||
goto err_acpi_exit;
|
||||
|
||||
device->driver_data = tps_hkey;
|
||||
return 0;
|
||||
err = topstar_input_init(topstar);
|
||||
if (err)
|
||||
goto err_platform_exit;
|
||||
|
||||
add_err:
|
||||
kfree(tps_hkey);
|
||||
return -ENODEV;
|
||||
if (led_workaround) {
|
||||
err = topstar_led_init(topstar);
|
||||
if (err)
|
||||
goto err_input_exit;
|
||||
}
|
||||
|
||||
static int acpi_topstar_remove(struct acpi_device *device)
|
||||
return 0;
|
||||
|
||||
err_input_exit:
|
||||
topstar_input_exit(topstar);
|
||||
err_platform_exit:
|
||||
topstar_platform_exit(topstar);
|
||||
err_acpi_exit:
|
||||
topstar_acpi_exit(topstar);
|
||||
err_free:
|
||||
kfree(topstar);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int topstar_acpi_remove(struct acpi_device *device)
|
||||
{
|
||||
struct topstar_hkey *tps_hkey = acpi_driver_data(device);
|
||||
struct topstar_laptop *topstar = acpi_driver_data(device);
|
||||
|
||||
acpi_topstar_fncx_switch(device, false);
|
||||
if (led_workaround)
|
||||
topstar_led_exit(topstar);
|
||||
|
||||
input_unregister_device(tps_hkey->inputdev);
|
||||
kfree(tps_hkey);
|
||||
topstar_input_exit(topstar);
|
||||
topstar_platform_exit(topstar);
|
||||
topstar_acpi_exit(topstar);
|
||||
|
||||
kfree(topstar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -168,18 +354,47 @@ static const struct acpi_device_id topstar_device_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, topstar_device_ids);
|
||||
|
||||
static struct acpi_driver acpi_topstar_driver = {
|
||||
static struct acpi_driver topstar_acpi_driver = {
|
||||
.name = "Topstar laptop ACPI driver",
|
||||
.class = ACPI_TOPSTAR_CLASS,
|
||||
.class = TOPSTAR_LAPTOP_CLASS,
|
||||
.ids = topstar_device_ids,
|
||||
.ops = {
|
||||
.add = acpi_topstar_add,
|
||||
.remove = acpi_topstar_remove,
|
||||
.notify = acpi_topstar_notify,
|
||||
.add = topstar_acpi_add,
|
||||
.remove = topstar_acpi_remove,
|
||||
.notify = topstar_acpi_notify,
|
||||
},
|
||||
};
|
||||
module_acpi_driver(acpi_topstar_driver);
|
||||
|
||||
static int __init topstar_laptop_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&topstar_platform_driver);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = acpi_bus_register_driver(&topstar_acpi_driver);
|
||||
if (ret < 0)
|
||||
goto err_driver_unreg;
|
||||
|
||||
pr_info("ACPI extras driver loaded\n");
|
||||
return 0;
|
||||
|
||||
err_driver_unreg:
|
||||
platform_driver_unregister(&topstar_platform_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit topstar_laptop_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&topstar_acpi_driver);
|
||||
platform_driver_unregister(&topstar_platform_driver);
|
||||
}
|
||||
|
||||
module_init(topstar_laptop_init);
|
||||
module_exit(topstar_laptop_exit);
|
||||
|
||||
MODULE_AUTHOR("Herton Ronaldo Krzesinski");
|
||||
MODULE_AUTHOR("Guillaume Douézan-Grard");
|
||||
MODULE_DESCRIPTION("Topstar Laptop ACPI Extras driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -130,13 +130,11 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
|
|||
uuid_le guid_input;
|
||||
struct wmi_block *wblock;
|
||||
struct guid_block *block;
|
||||
struct list_head *p;
|
||||
|
||||
if (uuid_le_to_bin(guid_string, &guid_input))
|
||||
return false;
|
||||
|
||||
list_for_each(p, &wmi_block_list) {
|
||||
wblock = list_entry(p, struct wmi_block, list);
|
||||
list_for_each_entry(wblock, &wmi_block_list, list) {
|
||||
block = &wblock->gblock;
|
||||
|
||||
if (memcmp(block->guid, &guid_input, 16) == 0) {
|
||||
|
@ -519,7 +517,6 @@ wmi_notify_handler handler, void *data)
|
|||
struct wmi_block *block;
|
||||
acpi_status status = AE_NOT_EXIST;
|
||||
uuid_le guid_input;
|
||||
struct list_head *p;
|
||||
|
||||
if (!guid || !handler)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
@ -527,9 +524,8 @@ wmi_notify_handler handler, void *data)
|
|||
if (uuid_le_to_bin(guid, &guid_input))
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
list_for_each(p, &wmi_block_list) {
|
||||
list_for_each_entry(block, &wmi_block_list, list) {
|
||||
acpi_status wmi_status;
|
||||
block = list_entry(p, struct wmi_block, list);
|
||||
|
||||
if (memcmp(block->gblock.guid, &guid_input, 16) == 0) {
|
||||
if (block->handler &&
|
||||
|
@ -560,7 +556,6 @@ acpi_status wmi_remove_notify_handler(const char *guid)
|
|||
struct wmi_block *block;
|
||||
acpi_status status = AE_NOT_EXIST;
|
||||
uuid_le guid_input;
|
||||
struct list_head *p;
|
||||
|
||||
if (!guid)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
@ -568,9 +563,8 @@ acpi_status wmi_remove_notify_handler(const char *guid)
|
|||
if (uuid_le_to_bin(guid, &guid_input))
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
list_for_each(p, &wmi_block_list) {
|
||||
list_for_each_entry(block, &wmi_block_list, list) {
|
||||
acpi_status wmi_status;
|
||||
block = list_entry(p, struct wmi_block, list);
|
||||
|
||||
if (memcmp(block->gblock.guid, &guid_input, 16) == 0) {
|
||||
if (!block->handler ||
|
||||
|
@ -610,15 +604,13 @@ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
|
|||
union acpi_object params[1];
|
||||
struct guid_block *gblock;
|
||||
struct wmi_block *wblock;
|
||||
struct list_head *p;
|
||||
|
||||
input.count = 1;
|
||||
input.pointer = params;
|
||||
params[0].type = ACPI_TYPE_INTEGER;
|
||||
params[0].integer.value = event;
|
||||
|
||||
list_for_each(p, &wmi_block_list) {
|
||||
wblock = list_entry(p, struct wmi_block, list);
|
||||
list_for_each_entry(wblock, &wmi_block_list, list) {
|
||||
gblock = &wblock->gblock;
|
||||
|
||||
if ((gblock->flags & ACPI_WMI_EVENT) &&
|
||||
|
@ -933,12 +925,11 @@ static int wmi_dev_probe(struct device *dev)
|
|||
goto probe_failure;
|
||||
}
|
||||
|
||||
buf = kmalloc(strlen(wdriver->driver.name) + 5, GFP_KERNEL);
|
||||
buf = kasprintf(GFP_KERNEL, "wmi/%s", wdriver->driver.name);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto probe_string_failure;
|
||||
}
|
||||
sprintf(buf, "wmi/%s", wdriver->driver.name);
|
||||
wblock->char_dev.minor = MISC_DYNAMIC_MINOR;
|
||||
wblock->char_dev.name = buf;
|
||||
wblock->char_dev.fops = &wmi_fops;
|
||||
|
@ -1261,11 +1252,9 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event,
|
|||
{
|
||||
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);
|
||||
list_for_each_entry(wblock, &wmi_block_list, list) {
|
||||
block = &wblock->gblock;
|
||||
|
||||
if (wblock->acpi_device->handle == handle &&
|
||||
|
|
|
@ -129,6 +129,8 @@ struct mlxreg_core_platform_data {
|
|||
* @mask: top aggregation interrupt common mask;
|
||||
* @cell_low: location of low aggregation interrupt register;
|
||||
* @mask_low: low aggregation interrupt common mask;
|
||||
* @deferred_nr: I2C adapter number must be exist prior probing execution;
|
||||
* @shift_nr: I2C adapter numbers must be incremented by this value;
|
||||
*/
|
||||
struct mlxreg_core_hotplug_platform_data {
|
||||
struct mlxreg_core_item *items;
|
||||
|
@ -139,6 +141,8 @@ struct mlxreg_core_hotplug_platform_data {
|
|||
u32 mask;
|
||||
u32 cell_low;
|
||||
u32 mask_low;
|
||||
int deferred_nr;
|
||||
int shift_nr;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */
|
||||
|
|
Loading…
Reference in New Issue