Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 27a3353a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for_linus' of...

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86: (32 commits)
  Move N014, N051 and CR620 dmi information to load scm dmi table
  drivers/platform/x86/eeepc-wmi.c: fix build warning
  X86 platfrom wmi: Add debug facility to dump WMI data in a readable way
  X86 platform wmi: Also log GUID string when an event happens and debug is set
  X86 platform wmi: Introduce debug param to log all WMI events
  Clean up all objects used by scm model when driver initial fail or exit
  msi-laptop: fix up some coding style issues found by checkpatch
  msi-laptop: Add i8042 filter to sync sw state with BIOS when function key pressed
  msi-laptop: Set rfkill init state when msi-laptop intiial
  msi-laptop: Add MSI CR620 notebook dmi information to scm models table
  msi-laptop: Add N014 N051 dmi information to scm models table
  drivers/platform/x86: Use kmemdup
  drivers/platform/x86: Use kzalloc
  drivers/platform/x86: Clarify the MRST IPC driver description slightly
  eeepc-wmi: depends on BACKLIGHT_CLASS_DEVICE
  IPC driver for Intel Mobile Internet Device (MID) platforms
  classmate-laptop: Add RFKILL support.
  thinkpad-acpi: document backlight level writeback at driver init
  thinkpad-acpi: clean up ACPI handles handling
  thinkpad-acpi: don't depend on led_path for led firmware type (v2)
  ...
parents 6f68fbaa 785cfc03
Loading
Loading
Loading
Loading
+49 −17
Original line number Diff line number Diff line
@@ -292,13 +292,13 @@ sysfs notes:

		Warning: when in NVRAM mode, the volume up/down/mute
		keys are synthesized according to changes in the mixer,
		so you have to use volume up or volume down to unmute,
		as per the ThinkPad volume mixer user interface.  When
		in ACPI event mode, volume up/down/mute are reported as
		separate events, but this behaviour may be corrected in
		future releases of this driver, in which case the
		ThinkPad volume mixer user interface semantics will be
		enforced.
		which uses a single volume up or volume down hotkey
		press to unmute, as per the ThinkPad volume mixer user
		interface.  When in ACPI event mode, volume up/down/mute
		events are reported by the firmware and can behave
		differently (and that behaviour changes with firmware
		version -- not just with firmware models -- as well as
		OSI(Linux) state).

	hotkey_poll_freq:
		frequency in Hz for hot key polling. It must be between
@@ -309,7 +309,7 @@ sysfs notes:
		will cause hot key presses that require NVRAM polling
		to never be reported.

		Setting hotkey_poll_freq too low will cause repeated
		Setting hotkey_poll_freq too low may cause repeated
		pressings of the same hot key to be misreported as a
		single key press, or to not even be detected at all.
		The recommended polling frequency is 10Hz.
@@ -397,6 +397,7 @@ ACPI Scan
event	code	Key		Notes

0x1001	0x00	FN+F1		-

0x1002	0x01	FN+F2		IBM: battery (rare)
				Lenovo: Screen lock

@@ -404,7 +405,8 @@ event code Key Notes
				this hot key, even with hot keys
				disabled or with Fn+F3 masked
				off
				IBM: screen lock
				IBM: screen lock, often turns
				off the ThinkLight as side-effect
				Lenovo: battery

0x1004	0x03	FN+F4		Sleep button (ACPI sleep button
@@ -433,7 +435,8 @@ event code Key Notes
				Do you feel lucky today?

0x1008	0x07	FN+F8		IBM: toggle screen expand
				Lenovo: configure UltraNav
				Lenovo: configure UltraNav,
				or toggle screen expand

0x1009	0x08	FN+F9		-
	..	..		..
@@ -444,7 +447,7 @@ event code Key Notes
				either through the ACPI event,
				or through a hotkey event.
				The firmware may refuse to
				generate further FN+F4 key
				generate further FN+F12 key
				press events until a S3 or S4
				ACPI sleep cycle is performed,
				or some time passes.
@@ -512,15 +515,19 @@ events for switches:
SW_RFKILL_ALL	T60 and later hardware rfkill rocker switch
SW_TABLET_MODE	Tablet ThinkPads HKEY events 0x5009 and 0x500A

Non hot-key ACPI HKEY event map:
Non hotkey ACPI HKEY event map:
-------------------------------

Events that are not propagated by the driver, except for legacy
compatibility purposes when hotkey_report_mode is set to 1:

0x5001		Lid closed
0x5002		Lid opened
0x5009		Tablet swivel: switched to tablet mode
0x500A		Tablet swivel: switched to normal mode
0x7000		Radio Switch may have changed state

The above events are not propagated by the driver, except for legacy
compatibility purposes when hotkey_report_mode is set to 1.
Events that are never propagated by the driver:

0x2304		System is waking up from suspend to undock
0x2305		System is waking up from suspend to eject bay
@@ -528,14 +535,39 @@ compatibility purposes when hotkey_report_mode is set to 1.
0x2405		System is waking up from hibernation to eject bay
0x5010		Brightness level changed/control event

The above events are never propagated by the driver.
Events that are propagated by the driver to userspace:

0x2313		ALARM: System is waking up from suspend because
		the battery is nearly empty
0x2413		ALARM: System is waking up from hibernation because
		the battery is nearly empty
0x3003		Bay ejection (see 0x2x05) complete, can sleep again
0x3006		Bay hotplug request (hint to power up SATA link when
		the optical drive tray is ejected)
0x4003		Undocked (see 0x2x04), can sleep again
0x500B		Tablet pen inserted into its storage bay
0x500C		Tablet pen removed from its storage bay

The above events are propagated by the driver.
0x6011		ALARM: battery is too hot
0x6012		ALARM: battery is extremely hot
0x6021		ALARM: a sensor is too hot
0x6022		ALARM: a sensor is extremely hot
0x6030		System thermal table changed

Battery nearly empty alarms are a last resort attempt to get the
operating system to hibernate or shutdown cleanly (0x2313), or shutdown
cleanly (0x2413) before power is lost.  They must be acted upon, as the
wake up caused by the firmware will have negated most safety nets...

When any of the "too hot" alarms happen, according to Lenovo the user
should suspend or hibernate the laptop (and in the case of battery
alarms, unplug the AC adapter) to let it cool down.  These alarms do
signal that something is wrong, they should never happen on normal
operating conditions.

The "extremely hot" alarms are emergencies.  According to Lenovo, the
operating system is to force either an immediate suspend or hibernate
cycle, or a system shutdown.  Obviously, something is very wrong if this
happens.

Compatibility notes:

+55 −0
Original line number Diff line number Diff line
#ifndef _ASM_X86_INTEL_SCU_IPC_H_
#define  _ASM_X86_INTEL_SCU_IPC_H_

/* Read single register */
int intel_scu_ipc_ioread8(u16 addr, u8 *data);

/* Read two sequential registers */
int intel_scu_ipc_ioread16(u16 addr, u16 *data);

/* Read four sequential registers */
int intel_scu_ipc_ioread32(u16 addr, u32 *data);

/* Read a vector */
int intel_scu_ipc_readv(u16 *addr, u8 *data, int len);

/* Write single register */
int intel_scu_ipc_iowrite8(u16 addr, u8 data);

/* Write two sequential registers */
int intel_scu_ipc_iowrite16(u16 addr, u16 data);

/* Write four sequential registers */
int intel_scu_ipc_iowrite32(u16 addr, u32 data);

/* Write a vector */
int intel_scu_ipc_writev(u16 *addr, u8 *data, int len);

/* Update single register based on the mask */
int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);

/*
 * Indirect register read
 * Can be used when SCCB(System Controller Configuration Block) register
 * HRIM(Honor Restricted IPC Messages) is set (bit 23)
 */
int intel_scu_ipc_register_read(u32 addr, u32 *data);

/*
 * Indirect register write
 * Can be used when SCCB(System Controller Configuration Block) register
 * HRIM(Honor Restricted IPC Messages) is set (bit 23)
 */
int intel_scu_ipc_register_write(u32 addr, u32 data);

/* Issue commands to the SCU with or without data */
int intel_scu_ipc_simple_command(int cmd, int sub);
int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
							u32 *out, int outlen);
/* I2C control api */
int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data);

/* Update FW version */
int intel_scu_ipc_fw_update(u8 *buffer, u32 length);

#endif
+10 −0
Original line number Diff line number Diff line
@@ -390,6 +390,7 @@ config EEEPC_WMI
	depends on ACPI_WMI
	depends on INPUT
	depends on EXPERIMENTAL
	depends on BACKLIGHT_CLASS_DEVICE
	select INPUT_SPARSEKMAP
	---help---
	  Say Y here if you want to support WMI-based hotkeys on Eee PC laptops.
@@ -527,4 +528,13 @@ config ACPI_CMPC
	  keys as input device, backlight device, tablet and accelerometer
	  devices.

config INTEL_SCU_IPC
	bool "Intel SCU IPC Support"
	depends on X86_MRST
	default y
	---help---
	  IPC is used to bridge the communications between kernel and SCU on
	  some embedded Intel x86 platforms. This is not needed for PC-type
	  machines.

endif # X86_PLATFORM_DEVICES
+1 −0
Original line number Diff line number Diff line
@@ -25,3 +25,4 @@ obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
obj-$(CONFIG_TOPSTAR_LAPTOP)	+= topstar-laptop.o
obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
obj-$(CONFIG_TOSHIBA_BT_RFKILL)	+= toshiba_bluetooth.o
obj-$(CONFIG_INTEL_SCU_IPC)	+= intel_scu_ipc.o
+148 −22
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <acpi/acpi_drivers.h>
#include <linux/backlight.h>
#include <linux/input.h>
#include <linux/rfkill.h>

MODULE_LICENSE("GPL");

@@ -37,7 +38,7 @@ struct cmpc_accel {

#define CMPC_ACCEL_HID		"ACCE0000"
#define CMPC_TABLET_HID		"TBLT0000"
#define CMPC_BL_HID		"IPML200"
#define CMPC_IPML_HID	"IPML200"
#define CMPC_KEYS_HID		"FnBT0000"

/*
@@ -461,43 +462,168 @@ static const struct backlight_ops cmpc_bl_ops = {
	.update_status = cmpc_bl_update_status
};

static int cmpc_bl_add(struct acpi_device *acpi)
/*
 * RFKILL code.
 */

static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
					unsigned long long *value)
{
	struct backlight_properties props;
	union acpi_object param;
	struct acpi_object_list input;
	unsigned long long output;
	acpi_status status;

	param.type = ACPI_TYPE_INTEGER;
	param.integer.value = 0xC1;
	input.count = 1;
	input.pointer = &param;
	status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
	if (ACPI_SUCCESS(status))
		*value = output;
	return status;
}

static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
					unsigned long long value)
{
	union acpi_object param[2];
	struct acpi_object_list input;
	acpi_status status;
	unsigned long long output;

	param[0].type = ACPI_TYPE_INTEGER;
	param[0].integer.value = 0xC1;
	param[1].type = ACPI_TYPE_INTEGER;
	param[1].integer.value = value;
	input.count = 2;
	input.pointer = param;
	status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
	return status;
}

static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
{
	acpi_status status;
	acpi_handle handle;
	unsigned long long state;
	bool blocked;

	handle = data;
	status = cmpc_get_rfkill_wlan(handle, &state);
	if (ACPI_SUCCESS(status)) {
		blocked = state & 1 ? false : true;
		rfkill_set_sw_state(rfkill, blocked);
	}
}

static int cmpc_rfkill_block(void *data, bool blocked)
{
	acpi_status status;
	acpi_handle handle;
	unsigned long long state;

	handle = data;
	status = cmpc_get_rfkill_wlan(handle, &state);
	if (ACPI_FAILURE(status))
		return -ENODEV;
	if (blocked)
		state &= ~1;
	else
		state |= 1;
	status = cmpc_set_rfkill_wlan(handle, state);
	if (ACPI_FAILURE(status))
		return -ENODEV;
	return 0;
}

static const struct rfkill_ops cmpc_rfkill_ops = {
	.query = cmpc_rfkill_query,
	.set_block = cmpc_rfkill_block,
};

/*
 * Common backlight and rfkill code.
 */

struct ipml200_dev {
	struct backlight_device *bd;
	struct rfkill *rf;
};

static int cmpc_ipml_add(struct acpi_device *acpi)
{
	int retval;
	struct ipml200_dev *ipml;
	struct backlight_properties props;

	ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
	if (ipml == NULL)
		return -ENOMEM;

	memset(&props, 0, sizeof(struct backlight_properties));
	props.max_brightness = 7;
	bd = backlight_device_register("cmpc_bl", &acpi->dev, acpi->handle,
				       &cmpc_bl_ops, &props);
	if (IS_ERR(bd))
		return PTR_ERR(bd);
	dev_set_drvdata(&acpi->dev, bd);
	ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
					     acpi->handle, &cmpc_bl_ops,
					     &props);
	if (IS_ERR(ipml->bd)) {
		retval = PTR_ERR(ipml->bd);
		goto out_bd;
	}

	ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
				&cmpc_rfkill_ops, acpi->handle);
	/* rfkill_alloc may fail if RFKILL is disabled. We should still work
	 * anyway. */
	if (!IS_ERR(ipml->rf)) {
		retval = rfkill_register(ipml->rf);
		if (retval) {
			rfkill_destroy(ipml->rf);
			ipml->rf = NULL;
		}
	} else {
		ipml->rf = NULL;
	}

	dev_set_drvdata(&acpi->dev, ipml);
	return 0;

out_bd:
	kfree(ipml);
	return retval;
}

static int cmpc_bl_remove(struct acpi_device *acpi, int type)
static int cmpc_ipml_remove(struct acpi_device *acpi, int type)
{
	struct backlight_device *bd;
	struct ipml200_dev *ipml;

	ipml = dev_get_drvdata(&acpi->dev);

	backlight_device_unregister(ipml->bd);

	if (ipml->rf) {
		rfkill_unregister(ipml->rf);
		rfkill_destroy(ipml->rf);
	}

	kfree(ipml);

	bd = dev_get_drvdata(&acpi->dev);
	backlight_device_unregister(bd);
	return 0;
}

static const struct acpi_device_id cmpc_bl_device_ids[] = {
	{CMPC_BL_HID, 0},
static const struct acpi_device_id cmpc_ipml_device_ids[] = {
	{CMPC_IPML_HID, 0},
	{"", 0}
};

static struct acpi_driver cmpc_bl_acpi_driver = {
static struct acpi_driver cmpc_ipml_acpi_driver = {
	.owner = THIS_MODULE,
	.name = "cmpc",
	.class = "cmpc",
	.ids = cmpc_bl_device_ids,
	.ids = cmpc_ipml_device_ids,
	.ops = {
		.add = cmpc_bl_add,
		.remove = cmpc_bl_remove
		.add = cmpc_ipml_add,
		.remove = cmpc_ipml_remove
	}
};

@@ -580,7 +706,7 @@ static int cmpc_init(void)
	if (r)
		goto failed_keys;

	r = acpi_bus_register_driver(&cmpc_bl_acpi_driver);
	r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
	if (r)
		goto failed_bl;

@@ -598,7 +724,7 @@ static int cmpc_init(void)
	acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);

failed_tablet:
	acpi_bus_unregister_driver(&cmpc_bl_acpi_driver);
	acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);

failed_bl:
	acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
@@ -611,7 +737,7 @@ static void cmpc_exit(void)
{
	acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
	acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
	acpi_bus_unregister_driver(&cmpc_bl_acpi_driver);
	acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
	acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
}

@@ -621,7 +747,7 @@ module_exit(cmpc_exit);
static const struct acpi_device_id cmpc_device_ids[] = {
	{CMPC_ACCEL_HID, 0},
	{CMPC_TABLET_HID, 0},
	{CMPC_BL_HID, 0},
	{CMPC_IPML_HID, 0},
	{CMPC_KEYS_HID, 0},
	{"", 0}
};
Loading