diff options
| author | Takashi Iwai <tiwai@suse.de> | 2011-08-08 14:30:29 +0200 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2011-08-08 14:30:29 +0200 | 
| commit | 0a2d31b62dba9b5b92a38c67c9cc42630513662a (patch) | |
| tree | f755d74ec85248de645e10c45ed1a2ed467530f6 /drivers/platform | |
| parent | 8039290a91c5dc4414093c086987a5d7738fe2fd (diff) | |
| parent | df944f66784e6d4f2f50739263a4947885d8b6ae (diff) | |
Merge branch 'fix/kconfig' into for-linus
Diffstat (limited to 'drivers/platform')
25 files changed, 873 insertions, 148 deletions
| diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 45e0191c35dd..1e88d4785321 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -769,4 +769,12 @@ config INTEL_OAKTRAIL  	  enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y  	  here; it will only load on supported platforms. +config SAMSUNG_Q10 +	tristate "Samsung Q10 Extras" +	depends on SERIO_I8042 +	select BACKLIGHT_CLASS_DEVICE +	---help--- +	  This driver provides support for backlight control on Samsung Q10 +	  and related laptops, including Dell Latitude X200. +  endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index afc1f832aa67..293a320d9faa 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -44,3 +44,4 @@ obj-$(CONFIG_SAMSUNG_LAPTOP)	+= samsung-laptop.o  obj-$(CONFIG_MXM_WMI)		+= mxm-wmi.o  obj-$(CONFIG_INTEL_MID_POWER_BUTTON)	+= intel_mid_powerbtn.o  obj-$(CONFIG_INTEL_OAKTRAIL)	+= intel_oaktrail.o +obj-$(CONFIG_SAMSUNG_Q10)	+= samsung-q10.o diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 005417bd429e..af2bb20cb2fb 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -99,6 +99,7 @@ enum acer_wmi_event_ids {  static const struct key_entry acer_wmi_keymap[] = {  	{KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */  	{KE_KEY, 0x03, {KEY_WLAN} },     /* WiFi */ +	{KE_KEY, 0x04, {KEY_WLAN} },     /* WiFi */  	{KE_KEY, 0x12, {KEY_BLUETOOTH} },	/* BT */  	{KE_KEY, 0x21, {KEY_PROG1} },    /* Backup */  	{KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */ @@ -304,6 +305,10 @@ static struct quirk_entry quirk_fujitsu_amilo_li_1718 = {  	.wireless = 2,  }; +static struct quirk_entry quirk_lenovo_ideapad_s205 = { +	.wireless = 3, +}; +  /* The Aspire One has a dummy ACPI-WMI interface - disable it */  static struct dmi_system_id __devinitdata acer_blacklist[] = {  	{ @@ -450,6 +455,15 @@ static struct dmi_system_id acer_quirks[] = {  		},  		.driver_data = &quirk_medion_md_98300,  	}, +	{ +		.callback = dmi_matched, +		.ident = "Lenovo Ideapad S205", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +			DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"), +		}, +		.driver_data = &quirk_lenovo_ideapad_s205, +	},  	{}  }; @@ -542,6 +556,12 @@ struct wmi_interface *iface)  				return AE_ERROR;  			*value = result & 0x1;  			return AE_OK; +		case 3: +			err = ec_read(0x78, &result); +			if (err) +				return AE_ERROR; +			*value = result & 0x1; +			return AE_OK;  		default:  			err = ec_read(0xA, &result);  			if (err) @@ -1156,9 +1176,9 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)  	struct wmid3_gds_input_param params = {  		.function_num = 0x1,  		.hotkey_number = 0x01, -		.devices = ACER_WMID3_GDS_WIRELESS & -				ACER_WMID3_GDS_THREEG & -				ACER_WMID3_GDS_WIMAX & +		.devices = ACER_WMID3_GDS_WIRELESS | +				ACER_WMID3_GDS_THREEG | +				ACER_WMID3_GDS_WIMAX |  				ACER_WMID3_GDS_BLUETOOTH,  	};  	struct acpi_buffer input = { @@ -1266,8 +1286,13 @@ static void acer_rfkill_update(struct work_struct *ignored)  	acpi_status status;  	status = get_u32(&state, ACER_CAP_WIRELESS); -	if (ACPI_SUCCESS(status)) -		rfkill_set_sw_state(wireless_rfkill, !state); +	if (ACPI_SUCCESS(status)) { +		if (quirks->wireless == 3) { +			rfkill_set_hw_state(wireless_rfkill, !state); +		} else { +			rfkill_set_sw_state(wireless_rfkill, !state); +		} +	}  	if (has_cap(ACER_CAP_BLUETOOTH)) {  		status = get_u32(&state, ACER_CAP_BLUETOOTH); @@ -1400,6 +1425,9 @@ static ssize_t show_bool_threeg(struct device *dev,  {  	u32 result; \  	acpi_status status; + +	pr_info("This threeg sysfs will be removed in 2012" +		" - used by: %s\n", current->comm);  	if (wmi_has_guid(WMID_GUID3))  		status = wmid3_get_device_status(&result,  				ACER_WMID3_GDS_THREEG); @@ -1415,8 +1443,10 @@ static ssize_t set_bool_threeg(struct device *dev,  {  	u32 tmp = simple_strtoul(buf, NULL, 10);  	acpi_status status = set_u32(tmp, ACER_CAP_THREEG); -		if (ACPI_FAILURE(status)) -			return -EINVAL; +	pr_info("This threeg sysfs will be removed in 2012" +		" - used by: %s\n", current->comm); +	if (ACPI_FAILURE(status)) +		return -EINVAL;  	return count;  }  static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg, @@ -1425,6 +1455,8 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,  static ssize_t show_interface(struct device *dev, struct device_attribute *attr,  	char *buf)  { +	pr_info("This interface sysfs will be removed in 2012" +		" - used by: %s\n", current->comm);  	switch (interface->type) {  	case ACER_AMW0:  		return sprintf(buf, "AMW0\n"); @@ -1445,6 +1477,8 @@ static void acer_wmi_notify(u32 value, void *context)  	union acpi_object *obj;  	struct event_return_value return_value;  	acpi_status status; +	u16 device_state; +	const struct key_entry *key;  	status = wmi_get_event_data(value, &response);  	if (status != AE_OK) { @@ -1472,23 +1506,32 @@ static void acer_wmi_notify(u32 value, void *context)  	switch (return_value.function) {  	case WMID_HOTKEY_EVENT: -		if (return_value.device_state) { -			u16 device_state = return_value.device_state; -			pr_debug("device state: 0x%x\n", device_state); -			if (has_cap(ACER_CAP_WIRELESS)) -				rfkill_set_sw_state(wireless_rfkill, -				!(device_state & ACER_WMID3_GDS_WIRELESS)); -			if (has_cap(ACER_CAP_BLUETOOTH)) -				rfkill_set_sw_state(bluetooth_rfkill, -				!(device_state & ACER_WMID3_GDS_BLUETOOTH)); -			if (has_cap(ACER_CAP_THREEG)) -				rfkill_set_sw_state(threeg_rfkill, -				!(device_state & ACER_WMID3_GDS_THREEG)); -		} -		if (!sparse_keymap_report_event(acer_wmi_input_dev, -				return_value.key_num, 1, true)) +		device_state = return_value.device_state; +		pr_debug("device state: 0x%x\n", device_state); + +		key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev, +							return_value.key_num); +		if (!key) {  			pr_warn("Unknown key number - 0x%x\n",  				return_value.key_num); +		} else { +			switch (key->keycode) { +			case KEY_WLAN: +			case KEY_BLUETOOTH: +				if (has_cap(ACER_CAP_WIRELESS)) +					rfkill_set_sw_state(wireless_rfkill, +						!(device_state & ACER_WMID3_GDS_WIRELESS)); +				if (has_cap(ACER_CAP_THREEG)) +					rfkill_set_sw_state(threeg_rfkill, +						!(device_state & ACER_WMID3_GDS_THREEG)); +				if (has_cap(ACER_CAP_BLUETOOTH)) +					rfkill_set_sw_state(bluetooth_rfkill, +						!(device_state & ACER_WMID3_GDS_BLUETOOTH)); +				break; +			} +			sparse_keymap_report_entry(acer_wmi_input_dev, key, +						   1, true); +		}  		break;  	default:  		pr_warn("Unknown function number - %d - %d\n", diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index fca3489218b7..760c6d7624fe 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -182,6 +182,7 @@ static const struct bios_settings_t bios_tbl[] = {  	{"Acer", "Aspire 1810T",  "v1.3308", 0x55, 0x58, {0x9e, 0x00} },  	{"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00} },  	{"Acer", "Aspire 1810T",  "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, +	{"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00} },  	/* Acer 531 */  	{"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00} },  	/* Gateway */ @@ -703,15 +704,15 @@ MODULE_LICENSE("GPL");  MODULE_AUTHOR("Peter Feuerer");  MODULE_DESCRIPTION("Aspire One temperature and fan driver");  MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:"); -MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:"); -MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:"); +MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1410*:"); +MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1810*:");  MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:");  MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:");  MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:"); -MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:"); -MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:"); -MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:"); -MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMA*:"); +MODULE_ALIAS("dmi:*:*Packard*Bell*:pnAOA*:"); +MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOA*:"); +MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMU*:"); +MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMA*:");  module_init(acerhdf_init);  module_exit(acerhdf_exit); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index d65df92e2acc..fa6d7ec68b26 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -70,11 +70,10 @@ MODULE_LICENSE("GPL");   * WAPF defines the behavior of the Fn+Fx wlan key   * The significance of values is yet to be found, but   * most of the time: - * 0x0 will do nothing - * 0x1 will allow to control the device with Fn+Fx key. - * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key - * 0x5 like 0x1 or 0x4 - * So, if something doesn't work as you want, just try other values =) + * Bit | Bluetooth | WLAN + *  0  | Hardware  | Hardware + *  1  | Hardware  | Software + *  4  | Software  | Software   */  static uint wapf = 1;  module_param(wapf, uint, 0444); diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 0580d99b0798..b0859d4183e8 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -38,6 +38,24 @@ MODULE_LICENSE("GPL");  MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); +/* + * WAPF defines the behavior of the Fn+Fx wlan key + * The significance of values is yet to be found, but + * most of the time: + * Bit | Bluetooth | WLAN + *  0  | Hardware  | Hardware + *  1  | Hardware  | Software + *  4  | Software  | Software + */ +static uint wapf; +module_param(wapf, uint, 0444); +MODULE_PARM_DESC(wapf, "WAPF value"); + +static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) +{ +	driver->wapf = wapf; +} +  static const struct key_entry asus_nb_wmi_keymap[] = {  	{ KE_KEY, 0x30, { KEY_VOLUMEUP } },  	{ KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, @@ -53,16 +71,16 @@ static const struct key_entry asus_nb_wmi_keymap[] = {  	{ KE_KEY, 0x51, { KEY_WWW } },  	{ KE_KEY, 0x55, { KEY_CALC } },  	{ KE_KEY, 0x5C, { KEY_F15 } },  /* Power Gear key */ -	{ KE_KEY, 0x5D, { KEY_WLAN } }, -	{ KE_KEY, 0x5E, { KEY_WLAN } }, -	{ KE_KEY, 0x5F, { KEY_WLAN } }, +	{ KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */ +	{ KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */ +	{ KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */  	{ KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },  	{ KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },  	{ KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },  	{ KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },  	{ KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, -	{ KE_KEY, 0x7E, { KEY_BLUETOOTH } },  	{ KE_KEY, 0x7D, { KEY_BLUETOOTH } }, +	{ KE_KEY, 0x7E, { KEY_BLUETOOTH } },  	{ KE_KEY, 0x82, { KEY_CAMERA } },  	{ KE_KEY, 0x88, { KEY_RFKILL  } },  	{ KE_KEY, 0x8A, { KEY_PROG1 } }, @@ -81,6 +99,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = {  	.keymap = asus_nb_wmi_keymap,  	.input_name = "Asus WMI hotkeys",  	.input_phys = ASUS_NB_WMI_FILE "/input0", +	.quirks = asus_nb_wmi_quirks,  }; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 00460cb9587b..95cba9ebf6c0 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -44,6 +44,7 @@  #include <linux/debugfs.h>  #include <linux/seq_file.h>  #include <linux/platform_device.h> +#include <linux/thermal.h>  #include <acpi/acpi_bus.h>  #include <acpi/acpi_drivers.h> @@ -66,6 +67,8 @@ MODULE_LICENSE("GPL");  #define NOTIFY_BRNUP_MAX		0x1f  #define NOTIFY_BRNDOWN_MIN		0x20  #define NOTIFY_BRNDOWN_MAX		0x2e +#define NOTIFY_KBD_BRTUP		0xc4 +#define NOTIFY_KBD_BRTDWN		0xc5  /* WMI Methods */  #define ASUS_WMI_METHODID_SPEC	        0x43455053 /* BIOS SPECification */ @@ -93,6 +96,7 @@ MODULE_LICENSE("GPL");  /* Wireless */  #define ASUS_WMI_DEVID_HW_SWITCH	0x00010001  #define ASUS_WMI_DEVID_WIRELESS_LED	0x00010002 +#define ASUS_WMI_DEVID_CWAP		0x00010003  #define ASUS_WMI_DEVID_WLAN		0x00010011  #define ASUS_WMI_DEVID_BLUETOOTH	0x00010013  #define ASUS_WMI_DEVID_GPS		0x00010015 @@ -102,6 +106,12 @@ MODULE_LICENSE("GPL");  /* Leds */  /* 0x000200XX and 0x000400XX */ +#define ASUS_WMI_DEVID_LED1		0x00020011 +#define ASUS_WMI_DEVID_LED2		0x00020012 +#define ASUS_WMI_DEVID_LED3		0x00020013 +#define ASUS_WMI_DEVID_LED4		0x00020014 +#define ASUS_WMI_DEVID_LED5		0x00020015 +#define ASUS_WMI_DEVID_LED6		0x00020016  /* Backlight and Brightness */  #define ASUS_WMI_DEVID_BACKLIGHT	0x00050011 @@ -174,13 +184,18 @@ struct asus_wmi {  	struct led_classdev tpd_led;  	int tpd_led_wk; +	struct led_classdev kbd_led; +	int kbd_led_wk;  	struct workqueue_struct *led_workqueue;  	struct work_struct tpd_led_work; +	struct work_struct kbd_led_work;  	struct asus_rfkill wlan;  	struct asus_rfkill bluetooth;  	struct asus_rfkill wimax;  	struct asus_rfkill wwan3g; +	struct asus_rfkill gps; +	struct asus_rfkill uwb;  	struct hotplug_slot *hotplug_slot;  	struct mutex hotplug_lock; @@ -205,6 +220,7 @@ static int asus_wmi_input_init(struct asus_wmi *asus)  	asus->inputdev->phys = asus->driver->input_phys;  	asus->inputdev->id.bustype = BUS_HOST;  	asus->inputdev->dev.parent = &asus->platform_device->dev; +	set_bit(EV_REP, asus->inputdev->evbit);  	err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL);  	if (err) @@ -359,30 +375,80 @@ static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)  	return read_tpd_led_state(asus);  } -static int asus_wmi_led_init(struct asus_wmi *asus) +static void kbd_led_update(struct work_struct *work)  { -	int rv; +	int ctrl_param = 0; +	struct asus_wmi *asus; -	if (read_tpd_led_state(asus) < 0) -		return 0; +	asus = container_of(work, struct asus_wmi, kbd_led_work); -	asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); -	if (!asus->led_workqueue) -		return -ENOMEM; -	INIT_WORK(&asus->tpd_led_work, tpd_led_update); +	/* +	 * bits 0-2: level +	 * bit 7: light on/off +	 */ +	if (asus->kbd_led_wk > 0) +		ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); -	asus->tpd_led.name = "asus::touchpad"; -	asus->tpd_led.brightness_set = tpd_led_set; -	asus->tpd_led.brightness_get = tpd_led_get; -	asus->tpd_led.max_brightness = 1; +	asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL); +} -	rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led); -	if (rv) { -		destroy_workqueue(asus->led_workqueue); -		return rv; +static int kbd_led_read(struct asus_wmi *asus, int *level, int *env) +{ +	int retval; + +	/* +	 * bits 0-2: level +	 * bit 7: light on/off +	 * bit 8-10: environment (0: dark, 1: normal, 2: light) +	 * bit 17: status unknown +	 */ +	retval = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_KBD_BACKLIGHT, +					    0xFFFF); + +	/* Unknown status is considered as off */ +	if (retval == 0x8000) +		retval = 0; + +	if (retval >= 0) { +		if (level) +			*level = retval & 0x80 ? retval & 0x7F : 0; +		if (env) +			*env = (retval >> 8) & 0x7F; +		retval = 0;  	} -	return 0; +	return retval; +} + +static void kbd_led_set(struct led_classdev *led_cdev, +			enum led_brightness value) +{ +	struct asus_wmi *asus; + +	asus = container_of(led_cdev, struct asus_wmi, kbd_led); + +	if (value > asus->kbd_led.max_brightness) +		value = asus->kbd_led.max_brightness; +	else if (value < 0) +		value = 0; + +	asus->kbd_led_wk = value; +	queue_work(asus->led_workqueue, &asus->kbd_led_work); +} + +static enum led_brightness kbd_led_get(struct led_classdev *led_cdev) +{ +	struct asus_wmi *asus; +	int retval, value; + +	asus = container_of(led_cdev, struct asus_wmi, kbd_led); + +	retval = kbd_led_read(asus, &value, NULL); + +	if (retval < 0) +		return retval; + +	return value;  }  static void asus_wmi_led_exit(struct asus_wmi *asus) @@ -393,6 +459,48 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)  		destroy_workqueue(asus->led_workqueue);  } +static int asus_wmi_led_init(struct asus_wmi *asus) +{ +	int rv = 0; + +	asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); +	if (!asus->led_workqueue) +		return -ENOMEM; + +	if (read_tpd_led_state(asus) >= 0) { +		INIT_WORK(&asus->tpd_led_work, tpd_led_update); + +		asus->tpd_led.name = "asus::touchpad"; +		asus->tpd_led.brightness_set = tpd_led_set; +		asus->tpd_led.brightness_get = tpd_led_get; +		asus->tpd_led.max_brightness = 1; + +		rv = led_classdev_register(&asus->platform_device->dev, +					   &asus->tpd_led); +		if (rv) +			goto error; +	} + +	if (kbd_led_read(asus, NULL, NULL) >= 0) { +		INIT_WORK(&asus->kbd_led_work, kbd_led_update); + +		asus->kbd_led.name = "asus::kbd_backlight"; +		asus->kbd_led.brightness_set = kbd_led_set; +		asus->kbd_led.brightness_get = kbd_led_get; +		asus->kbd_led.max_brightness = 3; + +		rv = led_classdev_register(&asus->platform_device->dev, +					   &asus->kbd_led); +	} + +error: +	if (rv) +		asus_wmi_led_exit(asus); + +	return rv; +} + +  /*   * PCI hotplug (for wlan rfkill)   */ @@ -729,6 +837,16 @@ static void asus_wmi_rfkill_exit(struct asus_wmi *asus)  		rfkill_destroy(asus->wwan3g.rfkill);  		asus->wwan3g.rfkill = NULL;  	} +	if (asus->gps.rfkill) { +		rfkill_unregister(asus->gps.rfkill); +		rfkill_destroy(asus->gps.rfkill); +		asus->gps.rfkill = NULL; +	} +	if (asus->uwb.rfkill) { +		rfkill_unregister(asus->uwb.rfkill); +		rfkill_destroy(asus->uwb.rfkill); +		asus->uwb.rfkill = NULL; +	}  }  static int asus_wmi_rfkill_init(struct asus_wmi *asus) @@ -763,6 +881,18 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)  	if (result && result != -ENODEV)  		goto exit; +	result = asus_new_rfkill(asus, &asus->gps, "asus-gps", +				 RFKILL_TYPE_GPS, ASUS_WMI_DEVID_GPS); + +	if (result && result != -ENODEV) +		goto exit; + +	result = asus_new_rfkill(asus, &asus->uwb, "asus-uwb", +				 RFKILL_TYPE_UWB, ASUS_WMI_DEVID_UWB); + +	if (result && result != -ENODEV) +		goto exit; +  	if (!asus->driver->hotplug_wireless)  		goto exit; @@ -797,8 +927,8 @@ exit:   * Hwmon device   */  static ssize_t asus_hwmon_pwm1(struct device *dev, -			    struct device_attribute *attr, -			    char *buf) +			       struct device_attribute *attr, +			       char *buf)  {  	struct asus_wmi *asus = dev_get_drvdata(dev);  	u32 value; @@ -809,7 +939,7 @@ static ssize_t asus_hwmon_pwm1(struct device *dev,  	if (err < 0)  		return err; -	value |= 0xFF; +	value &= 0xFF;  	if (value == 1) /* Low Speed */  		value = 85; @@ -825,7 +955,26 @@ static ssize_t asus_hwmon_pwm1(struct device *dev,  	return sprintf(buf, "%d\n", value);  } +static ssize_t asus_hwmon_temp1(struct device *dev, +				struct device_attribute *attr, +				char *buf) +{ +	struct asus_wmi *asus = dev_get_drvdata(dev); +	u32 value; +	int err; + +	err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_THERMAL_CTRL, &value); + +	if (err < 0) +		return err; + +	value = KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000; + +	return sprintf(buf, "%d\n", value); +} +  static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL, 0);  static ssize_t  show_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -836,12 +985,13 @@ static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);  static struct attribute *hwmon_attributes[] = {  	&sensor_dev_attr_pwm1.dev_attr.attr, +	&sensor_dev_attr_temp1_input.dev_attr.attr,  	&sensor_dev_attr_name.dev_attr.attr,  	NULL  };  static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, -				    struct attribute *attr, int idx) +					  struct attribute *attr, int idx)  {  	struct device *dev = container_of(kobj, struct device, kobj);  	struct platform_device *pdev = to_platform_device(dev->parent); @@ -852,12 +1002,14 @@ static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,  	if (attr == &sensor_dev_attr_pwm1.dev_attr.attr)  		dev_id = ASUS_WMI_DEVID_FAN_CTRL; +	else if (attr == &sensor_dev_attr_temp1_input.dev_attr.attr) +		dev_id = ASUS_WMI_DEVID_THERMAL_CTRL;  	if (dev_id != -1) {  		int err = asus_wmi_get_devstate(asus, dev_id, &value);  		if (err < 0) -			return err; +			return 0; /* can't return negative here */  	}  	if (dev_id == ASUS_WMI_DEVID_FAN_CTRL) { @@ -869,9 +1021,13 @@ static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,  		 * - reverved bits are non-zero  		 * - sfun and presence bit are not set  		 */ -		if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 +		if (value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000  		    || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT)))  			ok = false; +	} else if (dev_id == ASUS_WMI_DEVID_THERMAL_CTRL) { +		/* If value is zero, something is clearly wrong */ +		if (value == 0) +			ok = false;  	}  	return ok ? attr->mode : 0; @@ -904,6 +1060,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)  		pr_err("Could not register asus hwmon device\n");  		return PTR_ERR(hwmon);  	} +	dev_set_drvdata(hwmon, asus);  	asus->hwmon_device = hwmon;  	result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group);  	if (result) @@ -1025,6 +1182,7 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)  		return power;  	memset(&props, 0, sizeof(struct backlight_properties)); +	props.type = BACKLIGHT_PLATFORM;  	props.max_brightness = max;  	bd = backlight_device_register(asus->driver->name,  				       &asus->platform_device->dev, asus, @@ -1059,6 +1217,8 @@ static void asus_wmi_notify(u32 value, void *context)  	acpi_status status;  	int code;  	int orig_code; +	unsigned int key_value = 1; +	bool autorelease = 1;  	status = wmi_get_event_data(value, &response);  	if (status != AE_OK) { @@ -1074,6 +1234,13 @@ static void asus_wmi_notify(u32 value, void *context)  	code = obj->integer.value;  	orig_code = code; +	if (asus->driver->key_filter) { +		asus->driver->key_filter(asus->driver, &code, &key_value, +					 &autorelease); +		if (code == ASUS_WMI_KEY_IGNORE) +			goto exit; +	} +  	if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)  		code = NOTIFY_BRNUP_MIN;  	else if (code >= NOTIFY_BRNDOWN_MIN && @@ -1083,7 +1250,8 @@ static void asus_wmi_notify(u32 value, void *context)  	if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {  		if (!acpi_video_backlight_support())  			asus_wmi_backlight_notify(asus, orig_code); -	} else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true)) +	} else if (!sparse_keymap_report_event(asus->inputdev, code, +					       key_value, autorelease))  		pr_info("Unknown key %x pressed\n", code);  exit: @@ -1163,14 +1331,18 @@ ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER);  static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,  			   const char *buf, size_t count)  { -	int value; +	int value, rv;  	if (!count || sscanf(buf, "%i", &value) != 1)  		return -EINVAL;  	if (value < 0 || value > 2)  		return -EINVAL; -	return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); +	rv = asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); +	if (rv < 0) +		return rv; + +	return count;  }  static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); @@ -1233,7 +1405,7 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)  	/* We don't know yet what to do with this version... */  	if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) { -		pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF); +		pr_info("BIOS WMI version: %d.%d", rv >> 16, rv & 0xFF);  		asus->spec = rv;  	} @@ -1265,6 +1437,12 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)  		return -ENODEV;  	} +	/* CWAP allow to define the behavior of the Fn+F2 key, +	 * this method doesn't seems to be present on Eee PCs */ +	if (asus->driver->wapf >= 0) +		asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP, +				      asus->driver->wapf, NULL); +  	return asus_wmi_sysfs_init(asus->platform_device);  } @@ -1567,6 +1745,14 @@ static int asus_hotk_restore(struct device *device)  		bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G);  		rfkill_set_sw_state(asus->wwan3g.rfkill, bl);  	} +	if (asus->gps.rfkill) { +		bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPS); +		rfkill_set_sw_state(asus->gps.rfkill, bl); +	} +	if (asus->uwb.rfkill) { +		bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB); +		rfkill_set_sw_state(asus->uwb.rfkill, bl); +	}  	return 0;  } @@ -1603,7 +1789,7 @@ static int asus_wmi_probe(struct platform_device *pdev)  static bool used; -int asus_wmi_register_driver(struct asus_wmi_driver *driver) +int __init_or_module asus_wmi_register_driver(struct asus_wmi_driver *driver)  {  	struct platform_driver *platform_driver;  	struct platform_device *platform_device; diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index c044522c8766..8147c10161cc 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -29,12 +29,15 @@  #include <linux/platform_device.h> +#define ASUS_WMI_KEY_IGNORE (-1) +  struct module;  struct key_entry;  struct asus_wmi;  struct asus_wmi_driver {  	bool			hotplug_wireless; +	int			wapf;  	const char		*name;  	struct module		*owner; @@ -44,6 +47,10 @@ struct asus_wmi_driver {  	const struct key_entry	*keymap;  	const char		*input_name;  	const char		*input_phys; +	/* Returns new code, value, and autorelease values in arguments. +	 * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */ +	void (*key_filter) (struct asus_wmi_driver *driver, int *code, +			    unsigned int *value, bool *autorelease);  	int (*probe) (struct platform_device *device);  	void (*quirks) (struct asus_wmi_driver *driver); diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 3f204fde1b02..8877b836d27c 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -1030,8 +1030,10 @@ static int __devinit compal_probe(struct platform_device *pdev)  	initialize_fan_control_data(data);  	err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group); -	if (err) +	if (err) { +		kfree(data);  		return err; +	}  	data->hwmon_dev = hwmon_device_register(&pdev->dev);  	if (IS_ERR(data->hwmon_dev)) { diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index d3841de6a8cf..f31fa4efa725 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -292,12 +292,9 @@ static int dell_rfkill_set(void *data, bool blocked)  	dell_send_request(buffer, 17, 11);  	/* If the hardware switch controls this radio, and the hardware -	   switch is disabled, don't allow changing the software state. -	   If the hardware switch is reported as not supported, always -	   fire the SMI to toggle the killswitch. */ +	   switch is disabled, don't allow changing the software state */  	if ((hwswitch_state & BIT(hwswitch_bit)) && -	    !(buffer->output[1] & BIT(16)) && -	    (buffer->output[1] & BIT(0))) { +	    !(buffer->output[1] & BIT(16))) {  		ret = -EINVAL;  		goto out;  	} @@ -403,23 +400,6 @@ static const struct file_operations dell_debugfs_fops = {  static void dell_update_rfkill(struct work_struct *ignored)  { -	int status; - -	get_buffer(); -	dell_send_request(buffer, 17, 11); -	status = buffer->output[1]; -	release_buffer(); - -	/* if hardware rfkill is not supported, set it explicitly */ -	if (!(status & BIT(0))) { -		if (wifi_rfkill) -			dell_rfkill_set((void *)1, !((status & BIT(17)) >> 17)); -		if (bluetooth_rfkill) -			dell_rfkill_set((void *)2, !((status & BIT(18)) >> 18)); -		if (wwan_rfkill) -			dell_rfkill_set((void *)3, !((status & BIT(19)) >> 19)); -	} -  	if (wifi_rfkill)  		dell_rfkill_query(wifi_rfkill, (void *)1);  	if (bluetooth_rfkill) @@ -560,11 +540,11 @@ static int dell_get_intensity(struct backlight_device *bd)  	else  		dell_send_request(buffer, 0, 1); +	ret = buffer->output[1]; +  out:  	release_buffer(); -	if (ret) -		return ret; -	return buffer->output[1]; +	return ret;  }  static const struct backlight_ops dell_ops = { @@ -632,7 +612,6 @@ static int __init dell_init(void)  	if (!bufferpage)  		goto fail_buffer;  	buffer = page_address(bufferpage); -	mutex_init(&buffer_mutex);  	ret = dell_setup_rfkill(); diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index ce790827e199..fa9a2171cc13 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -54,6 +54,8 @@ MODULE_ALIAS("wmi:"DELL_EVENT_GUID);   */  static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { +	{ KE_IGNORE, 0x003a, { KEY_CAPSLOCK } }, +  	{ KE_KEY, 0xe045, { KEY_PROG1 } },  	{ KE_KEY, 0xe009, { KEY_EJECTCD } }, @@ -85,6 +87,11 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {  	{ KE_IGNORE, 0xe013, { KEY_RESERVED } },  	{ KE_IGNORE, 0xe020, { KEY_MUTE } }, + +	/* Shortcut and audio panel keys */ +	{ KE_IGNORE, 0xe025, { KEY_RESERVED } }, +	{ KE_IGNORE, 0xe026, { KEY_RESERVED } }, +  	{ KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },  	{ KE_IGNORE, 0xe030, { KEY_VOLUMEUP } },  	{ KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } }, @@ -92,6 +99,9 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {  	{ KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } },  	{ KE_IGNORE, 0xe045, { KEY_NUMLOCK } },  	{ KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } }, +	{ KE_IGNORE, 0xe0f7, { KEY_MUTE } }, +	{ KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } }, +	{ KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } },  	{ KE_END, 0 }  }; diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 4aa867a9b88b..9f6e64302b45 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -56,6 +56,11 @@ MODULE_PARM_DESC(hotplug_wireless,  		 "If your laptop needs that, please report to "  		 "acpi4asus-user@lists.sourceforge.net."); +/* Values for T101MT "Home" key */ +#define HOME_PRESS	0xe4 +#define HOME_HOLD	0xea +#define HOME_RELEASE	0xe5 +  static const struct key_entry eeepc_wmi_keymap[] = {  	/* Sleep already handled via generic ACPI code */  	{ KE_KEY, 0x30, { KEY_VOLUMEUP } }, @@ -71,6 +76,7 @@ static const struct key_entry eeepc_wmi_keymap[] = {  	{ KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },  	{ KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */  	{ KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ +	{ KE_KEY, HOME_PRESS, { KEY_CONFIG } }, /* Home/Express gate key */  	{ KE_KEY, 0xe8, { KEY_SCREENLOCK } },  	{ KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } },  	{ KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, @@ -81,6 +87,25 @@ static const struct key_entry eeepc_wmi_keymap[] = {  	{ KE_END, 0},  }; +static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, +				 unsigned int *value, bool *autorelease) +{ +	switch (*code) { +	case HOME_PRESS: +		*value = 1; +		*autorelease = 0; +		break; +	case HOME_HOLD: +		*code = ASUS_WMI_KEY_IGNORE; +		break; +	case HOME_RELEASE: +		*code = HOME_PRESS; +		*value = 0; +		*autorelease = 0; +		break; +	} +} +  static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level,  						 void *context, void **retval)  { @@ -141,6 +166,7 @@ static void eeepc_dmi_check(struct asus_wmi_driver *driver)  static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)  {  	driver->hotplug_wireless = hotplug_wireless; +	driver->wapf = -1;  	eeepc_dmi_check(driver);  } @@ -151,6 +177,7 @@ static struct asus_wmi_driver asus_wmi_driver = {  	.keymap = eeepc_wmi_keymap,  	.input_name = "Eee PC WMI hotkeys",  	.input_phys = EEEPC_WMI_FILE "/input0", +	.key_filter = eeepc_wmi_key_filter,  	.probe = eeepc_wmi_probe,  	.quirks = eeepc_wmi_quirks,  }; diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index f94017bcdd6e..e2faa3cbb792 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -207,6 +207,7 @@ static int hp_wmi_perform_query(int query, int write, void *buffer,  	};  	struct acpi_buffer input = { sizeof(struct bios_args), &args };  	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; +	u32 rc;  	if (WARN_ON(insize > sizeof(args.data)))  		return -EINVAL; @@ -224,13 +225,13 @@ static int hp_wmi_perform_query(int query, int write, void *buffer,  	}  	bios_return = (struct bios_return *)obj->buffer.pointer; +	rc = bios_return->return_code; -	if (bios_return->return_code) { -		if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE) -			pr_warn("query 0x%x returned error 0x%x\n", -				query, bios_return->return_code); +	if (rc) { +		if (rc != HPWMI_RET_UNKNOWN_CMDTYPE) +			pr_warn("query 0x%x returned error 0x%x\n", query, rc);  		kfree(obj); -		return bios_return->return_code; +		return rc;  	}  	if (!outsize) { diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index bfdda33feb26..0c595410e788 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -32,13 +32,22 @@  #include <linux/platform_device.h>  #include <linux/input.h>  #include <linux/input/sparse-keymap.h> +#include <linux/backlight.h> +#include <linux/fb.h>  #define IDEAPAD_RFKILL_DEV_NUM	(3) +#define CFG_BT_BIT	(16) +#define CFG_3G_BIT	(17) +#define CFG_WIFI_BIT	(18) +#define CFG_CAMERA_BIT	(19) +  struct ideapad_private {  	struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];  	struct platform_device *platform_device;  	struct input_dev *inputdev; +	struct backlight_device *blightdev; +	unsigned long cfg;  };  static acpi_handle ideapad_handle; @@ -155,7 +164,7 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)  }  /* - * camera power + * sysfs   */  static ssize_t show_ideapad_cam(struct device *dev,  				struct device_attribute *attr, @@ -186,6 +195,44 @@ static ssize_t store_ideapad_cam(struct device *dev,  static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); +static ssize_t show_ideapad_cfg(struct device *dev, +				struct device_attribute *attr, +				char *buf) +{ +	struct ideapad_private *priv = dev_get_drvdata(dev); + +	return sprintf(buf, "0x%.8lX\n", priv->cfg); +} + +static DEVICE_ATTR(cfg, 0444, show_ideapad_cfg, NULL); + +static struct attribute *ideapad_attributes[] = { +	&dev_attr_camera_power.attr, +	&dev_attr_cfg.attr, +	NULL +}; + +static mode_t ideapad_is_visible(struct kobject *kobj, +				 struct attribute *attr, +				 int idx) +{ +	struct device *dev = container_of(kobj, struct device, kobj); +	struct ideapad_private *priv = dev_get_drvdata(dev); +	bool supported; + +	if (attr == &dev_attr_camera_power.attr) +		supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg)); +	else +		supported = true; + +	return supported ? attr->mode : 0; +} + +static struct attribute_group ideapad_attribute_group = { +	.is_visible = ideapad_is_visible, +	.attrs = ideapad_attributes +}; +  /*   * Rfkill   */ @@ -197,9 +244,9 @@ struct ideapad_rfk_data {  };  const struct ideapad_rfk_data ideapad_rfk_data[] = { -	{ "ideapad_wlan",	18, 0x15, RFKILL_TYPE_WLAN }, -	{ "ideapad_bluetooth",	16, 0x17, RFKILL_TYPE_BLUETOOTH }, -	{ "ideapad_3g",		17, 0x20, RFKILL_TYPE_WWAN }, +	{ "ideapad_wlan",      CFG_WIFI_BIT, 0x15, RFKILL_TYPE_WLAN }, +	{ "ideapad_bluetooth", CFG_BT_BIT,   0x17, RFKILL_TYPE_BLUETOOTH }, +	{ "ideapad_3g",        CFG_3G_BIT,   0x20, RFKILL_TYPE_WWAN },  };  static int ideapad_rfk_set(void *data, bool blocked) @@ -265,8 +312,7 @@ static int __devinit ideapad_register_rfkill(struct acpi_device *adevice,  	return 0;  } -static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice, -						int dev) +static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)  {  	struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); @@ -280,15 +326,6 @@ static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice,  /*   * Platform device   */ -static struct attribute *ideapad_attributes[] = { -	&dev_attr_camera_power.attr, -	NULL -}; - -static struct attribute_group ideapad_attribute_group = { -	.attrs = ideapad_attributes -}; -  static int __devinit ideapad_platform_init(struct ideapad_private *priv)  {  	int result; @@ -369,7 +406,7 @@ err_free_dev:  	return error;  } -static void __devexit ideapad_input_exit(struct ideapad_private *priv) +static void ideapad_input_exit(struct ideapad_private *priv)  {  	sparse_keymap_free(priv->inputdev);  	input_unregister_device(priv->inputdev); @@ -383,6 +420,98 @@ static void ideapad_input_report(struct ideapad_private *priv,  }  /* + * backlight + */ +static int ideapad_backlight_get_brightness(struct backlight_device *blightdev) +{ +	unsigned long now; + +	if (read_ec_data(ideapad_handle, 0x12, &now)) +		return -EIO; +	return now; +} + +static int ideapad_backlight_update_status(struct backlight_device *blightdev) +{ +	if (write_ec_cmd(ideapad_handle, 0x13, blightdev->props.brightness)) +		return -EIO; +	if (write_ec_cmd(ideapad_handle, 0x33, +			 blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1)) +		return -EIO; + +	return 0; +} + +static const struct backlight_ops ideapad_backlight_ops = { +	.get_brightness = ideapad_backlight_get_brightness, +	.update_status = ideapad_backlight_update_status, +}; + +static int ideapad_backlight_init(struct ideapad_private *priv) +{ +	struct backlight_device *blightdev; +	struct backlight_properties props; +	unsigned long max, now, power; + +	if (read_ec_data(ideapad_handle, 0x11, &max)) +		return -EIO; +	if (read_ec_data(ideapad_handle, 0x12, &now)) +		return -EIO; +	if (read_ec_data(ideapad_handle, 0x18, &power)) +		return -EIO; + +	memset(&props, 0, sizeof(struct backlight_properties)); +	props.max_brightness = max; +	props.type = BACKLIGHT_PLATFORM; +	blightdev = backlight_device_register("ideapad", +					      &priv->platform_device->dev, +					      priv, +					      &ideapad_backlight_ops, +					      &props); +	if (IS_ERR(blightdev)) { +		pr_err("Could not register backlight device\n"); +		return PTR_ERR(blightdev); +	} + +	priv->blightdev = blightdev; +	blightdev->props.brightness = now; +	blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; +	backlight_update_status(blightdev); + +	return 0; +} + +static void ideapad_backlight_exit(struct ideapad_private *priv) +{ +	if (priv->blightdev) +		backlight_device_unregister(priv->blightdev); +	priv->blightdev = NULL; +} + +static void ideapad_backlight_notify_power(struct ideapad_private *priv) +{ +	unsigned long power; +	struct backlight_device *blightdev = priv->blightdev; + +	if (read_ec_data(ideapad_handle, 0x18, &power)) +		return; +	blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; +} + +static void ideapad_backlight_notify_brightness(struct ideapad_private *priv) +{ +	unsigned long now; + +	/* if we control brightness via acpi video driver */ +	if (priv->blightdev == NULL) { +		read_ec_data(ideapad_handle, 0x12, &now); +		return; +	} + +	backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY); +} + +/*   * module init/exit   */  static const struct acpi_device_id ideapad_device_ids[] = { @@ -393,10 +522,11 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);  static int __devinit ideapad_acpi_add(struct acpi_device *adevice)  { -	int ret, i, cfg; +	int ret, i; +	unsigned long cfg;  	struct ideapad_private *priv; -	if (read_method_int(adevice->handle, "_CFG", &cfg)) +	if (read_method_int(adevice->handle, "_CFG", (int *)&cfg))  		return -ENODEV;  	priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -404,6 +534,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)  		return -ENOMEM;  	dev_set_drvdata(&adevice->dev, priv);  	ideapad_handle = adevice->handle; +	priv->cfg = cfg;  	ret = ideapad_platform_init(priv);  	if (ret) @@ -414,15 +545,25 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)  		goto input_failed;  	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) { -		if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg)) +		if (test_bit(ideapad_rfk_data[i].cfgbit, &cfg))  			ideapad_register_rfkill(adevice, i);  		else  			priv->rfk[i] = NULL;  	}  	ideapad_sync_rfk_state(adevice); +	if (!acpi_video_backlight_support()) { +		ret = ideapad_backlight_init(priv); +		if (ret && ret != -ENODEV) +			goto backlight_failed; +	} +  	return 0; +backlight_failed: +	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) +		ideapad_unregister_rfkill(adevice, i); +	ideapad_input_exit(priv);  input_failed:  	ideapad_platform_exit(priv);  platform_failed: @@ -435,6 +576,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type)  	struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);  	int i; +	ideapad_backlight_exit(priv);  	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)  		ideapad_unregister_rfkill(adevice, i);  	ideapad_input_exit(priv); @@ -459,12 +601,19 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)  	vpc1 = (vpc2 << 8) | vpc1;  	for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {  		if (test_bit(vpc_bit, &vpc1)) { -			if (vpc_bit == 9) +			switch (vpc_bit) { +			case 9:  				ideapad_sync_rfk_state(adevice); -			else if (vpc_bit == 4) -				read_ec_data(handle, 0x12, &vpc2); -			else +				break; +			case 4: +				ideapad_backlight_notify_brightness(priv); +				break; +			case 2: +				ideapad_backlight_notify_power(priv); +				break; +			default:  				ideapad_input_report(priv, vpc_bit); +			}  		}  	}  } diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index 5ffe7c398148..809a3ae943c6 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -403,7 +403,7 @@ static void ips_cpu_raise(struct ips_driver *ips)  	thm_writew(THM_MPCPC, (new_tdp_limit * 10) / 8); -	turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN; +	turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN;  	wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);  	turbo_override &= ~TURBO_TDP_MASK; @@ -438,7 +438,7 @@ static void ips_cpu_lower(struct ips_driver *ips)  	thm_writew(THM_MPCPC, (new_limit * 10) / 8); -	turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN; +	turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN;  	wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);  	turbo_override &= ~TURBO_TDP_MASK; diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c index 809adea4965f..abddc83e9fd7 100644 --- a/drivers/platform/x86/intel_menlow.c +++ b/drivers/platform/x86/intel_menlow.c @@ -477,6 +477,8 @@ static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,  		return AE_ERROR;  	} +	return AE_OK; +   aux1_not_found:  	if (status == AE_NOT_FOUND)  		return AE_OK; diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index 3a578323122b..ccd7b1f83519 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -493,20 +493,30 @@ static int mid_thermal_probe(struct platform_device *pdev)  	/* Register each sensor with the generic thermal framework*/  	for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { +		struct thermal_device_info *td_info = initialize_sensor(i); + +		if (!td_info) { +			ret = -ENOMEM; +			goto err; +		}  		pinfo->tzd[i] = thermal_zone_device_register(name[i], -				0, initialize_sensor(i), &tzd_ops, 0, 0, 0, 0); -		if (IS_ERR(pinfo->tzd[i])) -			goto reg_fail; +				0, td_info, &tzd_ops, 0, 0, 0, 0); +		if (IS_ERR(pinfo->tzd[i])) { +			kfree(td_info); +			ret = PTR_ERR(pinfo->tzd[i]); +			goto err; +		}  	}  	pinfo->pdev = pdev;  	platform_set_drvdata(pdev, pinfo);  	return 0; -reg_fail: -	ret = PTR_ERR(pinfo->tzd[i]); -	while (--i >= 0) +err: +	while (--i >= 0) { +		kfree(pinfo->tzd[i]->devdata);  		thermal_zone_device_unregister(pinfo->tzd[i]); +	}  	configure_adc(0);  	kfree(pinfo);  	return ret; @@ -524,8 +534,10 @@ static int mid_thermal_remove(struct platform_device *pdev)  	int i;  	struct platform_info *pinfo = platform_get_drvdata(pdev); -	for (i = 0; i < MSIC_THERMAL_SENSORS; i++) +	for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { +		kfree(pinfo->tzd[i]->devdata);  		thermal_zone_device_unregister(pinfo->tzd[i]); +	}  	kfree(pinfo);  	platform_set_drvdata(pdev, NULL); diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c index e936364a609d..7f88c7923fc6 100644 --- a/drivers/platform/x86/intel_oaktrail.c +++ b/drivers/platform/x86/intel_oaktrail.c @@ -250,6 +250,7 @@ static int oaktrail_backlight_init(void)  	struct backlight_properties props;  	memset(&props, 0, sizeof(struct backlight_properties)); +	props.type = BACKLIGHT_PLATFORM;  	props.max_brightness = OT_EC_BL_BRIGHTNESS_MAX;  	bd = backlight_device_register(DRIVER_NAME,  				       &oaktrail_device->dev, NULL, diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c index bde47e9080cd..c8a6aed45277 100644 --- a/drivers/platform/x86/intel_rar_register.c +++ b/drivers/platform/x86/intel_rar_register.c @@ -637,15 +637,13 @@ end_function:  	return error;  } -const struct pci_device_id rar_pci_id_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(rar_pci_id_tbl) = {  	{ PCI_VDEVICE(INTEL, 0x4110) },  	{ 0 }  };  MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl); -const struct pci_device_id *my_id_table = rar_pci_id_tbl; -  /* field for registering driver to PCI device */  static struct pci_driver rar_pci_driver = {  	.name = "rar_register_driver", diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 940accbe28d3..c86665369a22 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -725,7 +725,7 @@ static void ipc_remove(struct pci_dev *pdev)  	intel_scu_devices_destroy();  } -static const struct pci_device_id pci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)},  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},  	{ 0,} diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 3ff629df9f01..f204643c5052 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -538,6 +538,15 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {  		},  		.callback = dmi_check_cb  	}, +	{ +		.ident = "MSI U270", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, +				"Micro-Star International Co., Ltd."), +			DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"), +		}, +		.callback = dmi_check_cb +	},  	{ }  }; @@ -996,3 +1005,4 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*");  MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*");  MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*");  MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*"); +MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*"); diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c index c832e3356cd6..6f40bf202dc7 100644 --- a/drivers/platform/x86/msi-wmi.c +++ b/drivers/platform/x86/msi-wmi.c @@ -272,6 +272,7 @@ static int __init msi_wmi_init(void)  err_free_backlight:  	backlight_device_unregister(backlight);  err_free_input: +	sparse_keymap_free(msi_wmi_input_dev);  	input_unregister_device(msi_wmi_input_dev);  err_uninstall_notifier:  	wmi_remove_notify_handler(MSIWMI_EVENT_GUID); diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index d347116d150e..359163011044 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -521,6 +521,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {  		.callback = dmi_check_cb,  	},  	{ +		.ident = "N510", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, +					"SAMSUNG ELECTRONICS CO., LTD."), +			DMI_MATCH(DMI_PRODUCT_NAME, "N510"), +			DMI_MATCH(DMI_BOARD_NAME, "N510"), +		}, +		.callback = dmi_check_cb, +	}, +	{  		.ident = "X125",  		.matches = {  			DMI_MATCH(DMI_SYS_VENDOR, @@ -601,6 +611,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {  		.callback = dmi_check_cb,  	},  	{ +		.ident = "N150/N210/N220", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, +					"SAMSUNG ELECTRONICS CO., LTD."), +			DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), +			DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), +		}, +		.callback = dmi_check_cb, +	}, +	{  		.ident = "N150/N210/N220/N230",  		.matches = {  			DMI_MATCH(DMI_SYS_VENDOR, diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c new file mode 100644 index 000000000000..1e54ae74274c --- /dev/null +++ b/drivers/platform/x86/samsung-q10.c @@ -0,0 +1,196 @@ +/* + *  Driver for Samsung Q10 and related laptops: controls the backlight + * + *  Copyright (c) 2011 Frederick van der Wyck <fvanderwyck@gmail.com> + * + *  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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/backlight.h> +#include <linux/i8042.h> +#include <linux/dmi.h> + +#define SAMSUNGQ10_BL_MAX_INTENSITY      255 +#define SAMSUNGQ10_BL_DEFAULT_INTENSITY  185 + +#define SAMSUNGQ10_BL_8042_CMD           0xbe +#define SAMSUNGQ10_BL_8042_DATA          { 0x89, 0x91 } + +static int samsungq10_bl_brightness; + +static bool force; +module_param(force, bool, 0); +MODULE_PARM_DESC(force, +		"Disable the DMI check and force the driver to be loaded"); + +static int samsungq10_bl_set_intensity(struct backlight_device *bd) +{ + +	int brightness = bd->props.brightness; +	unsigned char c[3] = SAMSUNGQ10_BL_8042_DATA; + +	c[2] = (unsigned char)brightness; +	i8042_lock_chip(); +	i8042_command(c, (0x30 << 8) | SAMSUNGQ10_BL_8042_CMD); +	i8042_unlock_chip(); +	samsungq10_bl_brightness = brightness; + +	return 0; +} + +static int samsungq10_bl_get_intensity(struct backlight_device *bd) +{ +	return samsungq10_bl_brightness; +} + +static const struct backlight_ops samsungq10_bl_ops = { +	.get_brightness = samsungq10_bl_get_intensity, +	.update_status	= samsungq10_bl_set_intensity, +}; + +#ifdef CONFIG_PM_SLEEP +static int samsungq10_suspend(struct device *dev) +{ +	return 0; +} + +static int samsungq10_resume(struct device *dev) +{ + +	struct backlight_device *bd = dev_get_drvdata(dev); + +	samsungq10_bl_set_intensity(bd); +	return 0; +} +#else +#define samsungq10_suspend NULL +#define samsungq10_resume  NULL +#endif + +static SIMPLE_DEV_PM_OPS(samsungq10_pm_ops, +			  samsungq10_suspend, samsungq10_resume); + +static int __devinit samsungq10_probe(struct platform_device *pdev) +{ + +	struct backlight_properties props; +	struct backlight_device *bd; + +	memset(&props, 0, sizeof(struct backlight_properties)); +	props.type = BACKLIGHT_PLATFORM; +	props.max_brightness = SAMSUNGQ10_BL_MAX_INTENSITY; +	bd = backlight_device_register("samsung", &pdev->dev, NULL, +				       &samsungq10_bl_ops, &props); +	if (IS_ERR(bd)) +		return PTR_ERR(bd); + +	platform_set_drvdata(pdev, bd); + +	bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY; +	samsungq10_bl_set_intensity(bd); + +	return 0; +} + +static int __devexit samsungq10_remove(struct platform_device *pdev) +{ + +	struct backlight_device *bd = platform_get_drvdata(pdev); + +	bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY; +	samsungq10_bl_set_intensity(bd); + +	backlight_device_unregister(bd); + +	return 0; +} + +static struct platform_driver samsungq10_driver = { +	.driver		= { +		.name	= KBUILD_MODNAME, +		.owner	= THIS_MODULE, +		.pm	= &samsungq10_pm_ops, +	}, +	.probe		= samsungq10_probe, +	.remove		= __devexit_p(samsungq10_remove), +}; + +static struct platform_device *samsungq10_device; + +static int __init dmi_check_callback(const struct dmi_system_id *id) +{ +	printk(KERN_INFO KBUILD_MODNAME ": found model '%s'\n", id->ident); +	return 1; +} + +static struct dmi_system_id __initdata samsungq10_dmi_table[] = { +	{ +		.ident = "Samsung Q10", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Samsung"), +			DMI_MATCH(DMI_PRODUCT_NAME, "SQ10"), +		}, +		.callback = dmi_check_callback, +	}, +	{ +		.ident = "Samsung Q20", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"), +			DMI_MATCH(DMI_PRODUCT_NAME, "SENS Q20"), +		}, +		.callback = dmi_check_callback, +	}, +	{ +		.ident = "Samsung Q25", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"), +			DMI_MATCH(DMI_PRODUCT_NAME, "NQ25"), +		}, +		.callback = dmi_check_callback, +	}, +	{ +		.ident = "Dell Latitude X200", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), +			DMI_MATCH(DMI_PRODUCT_NAME, "X200"), +		}, +		.callback = dmi_check_callback, +	}, +	{ }, +}; +MODULE_DEVICE_TABLE(dmi, samsungq10_dmi_table); + +static int __init samsungq10_init(void) +{ +	if (!force && !dmi_check_system(samsungq10_dmi_table)) +		return -ENODEV; + +	samsungq10_device = platform_create_bundle(&samsungq10_driver, +						   samsungq10_probe, +						   NULL, 0, NULL, 0); + +	if (IS_ERR(samsungq10_device)) +		return PTR_ERR(samsungq10_device); + +	return 0; +} + +static void __exit samsungq10_exit(void) +{ +	platform_device_unregister(samsungq10_device); +	platform_driver_unregister(&samsungq10_driver); +} + +module_init(samsungq10_init); +module_exit(samsungq10_exit); + +MODULE_AUTHOR("Frederick van der Wyck <fvanderwyck@gmail.com>"); +MODULE_DESCRIPTION("Samsung Q10 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 77f6e707a2a9..7bd829f247eb 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -184,6 +184,10 @@ enum tpacpi_hkey_event_t {  	/* Misc bay events */  	TP_HKEY_EV_OPTDRV_EJ		= 0x3006, /* opt. drive tray ejected */ +	TP_HKEY_EV_HOTPLUG_DOCK		= 0x4010, /* docked into hotplug dock +						     or port replicator */ +	TP_HKEY_EV_HOTPLUG_UNDOCK	= 0x4011, /* undocked from hotplug +						     dock or port replicator */  	/* User-interface events */  	TP_HKEY_EV_LID_CLOSE		= 0x5001, /* laptop lid closed */ @@ -194,6 +198,10 @@ enum tpacpi_hkey_event_t {  	TP_HKEY_EV_PEN_REMOVED		= 0x500c, /* tablet pen removed */  	TP_HKEY_EV_BRGHT_CHANGED	= 0x5010, /* backlight control event */ +	/* Key-related user-interface events */ +	TP_HKEY_EV_KEY_NUMLOCK		= 0x6000, /* NumLock key pressed */ +	TP_HKEY_EV_KEY_FN		= 0x6005, /* Fn key pressed? E420 */ +  	/* Thermal events */  	TP_HKEY_EV_ALARM_BAT_HOT	= 0x6011, /* battery too hot */  	TP_HKEY_EV_ALARM_BAT_XHOT	= 0x6012, /* battery critically hot */ @@ -201,6 +209,10 @@ enum tpacpi_hkey_event_t {  	TP_HKEY_EV_ALARM_SENSOR_XHOT	= 0x6022, /* sensor critically hot */  	TP_HKEY_EV_THM_TABLE_CHANGED	= 0x6030, /* thermal table changed */ +	TP_HKEY_EV_UNK_6040		= 0x6040, /* Related to AC change? +						     some sort of APM hint, +						     W520 */ +  	/* Misc */  	TP_HKEY_EV_RFKILL_CHANGED	= 0x7000, /* rfkill switch changed */  }; @@ -3174,8 +3186,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)  		KEY_VENDOR,	/* 0x17: Thinkpad/AccessIBM/Lenovo */  		/* (assignments unknown, please report if found) */ +		KEY_UNKNOWN, KEY_UNKNOWN, + +		/* +		 * The mic mute button only sends 0x1a.  It does not +		 * automatically mute the mic or change the mute light. +		 */ +		KEY_MICMUTE,	/* 0x1a: Mic mute (since ?400 or so) */ + +		/* (assignments unknown, please report if found) */  		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, -		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, +		KEY_UNKNOWN,  		},  	}; @@ -3513,6 +3534,34 @@ static bool hotkey_notify_wakeup(const u32 hkey,  	return true;  } +static bool hotkey_notify_dockevent(const u32 hkey, +				 bool *send_acpi_ev, +				 bool *ignore_acpi_ev) +{ +	/* 0x4000-0x4FFF: dock-related events */ +	*send_acpi_ev = true; +	*ignore_acpi_ev = false; + +	switch (hkey) { +	case TP_HKEY_EV_UNDOCK_ACK: +		/* ACPI undock operation completed after wakeup */ +		hotkey_autosleep_ack = 1; +		pr_info("undocked\n"); +		hotkey_wakeup_hotunplug_complete_notify_change(); +		return true; + +	case TP_HKEY_EV_HOTPLUG_DOCK: /* docked to port replicator */ +		pr_info("docked into hotplug port replicator\n"); +		return true; +	case TP_HKEY_EV_HOTPLUG_UNDOCK: /* undocked from port replicator */ +		pr_info("undocked from hotplug port replicator\n"); +		return true; + +	default: +		return false; +	} +} +  static bool hotkey_notify_usrevent(const u32 hkey,  				 bool *send_acpi_ev,  				 bool *ignore_acpi_ev) @@ -3547,13 +3596,13 @@ static bool hotkey_notify_usrevent(const u32 hkey,  static void thermal_dump_all_sensors(void); -static bool hotkey_notify_thermal(const u32 hkey, +static bool hotkey_notify_6xxx(const u32 hkey,  				 bool *send_acpi_ev,  				 bool *ignore_acpi_ev)  {  	bool known = true; -	/* 0x6000-0x6FFF: thermal alarms */ +	/* 0x6000-0x6FFF: thermal alarms/notices and keyboard events */  	*send_acpi_ev = true;  	*ignore_acpi_ev = false; @@ -3582,8 +3631,17 @@ static bool hotkey_notify_thermal(const u32 hkey,  			 "a sensor reports something is extremely hot!\n");  		/* recommended action: immediate sleep/hibernate */  		break; + +	case TP_HKEY_EV_KEY_NUMLOCK: +	case TP_HKEY_EV_KEY_FN: +		/* key press events, we just ignore them as long as the EC +		 * is still reporting them in the normal keyboard stream */ +		*send_acpi_ev = false; +		*ignore_acpi_ev = true; +		return true; +  	default: -		pr_alert("THERMAL ALERT: unknown thermal alarm received\n"); +		pr_warn("unknown possible thermal alarm or keyboard event received\n");  		known = false;  	} @@ -3652,15 +3710,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)  			}  			break;  		case 4: -			/* 0x4000-0x4FFF: dock-related wakeups */ -			if (hkey == TP_HKEY_EV_UNDOCK_ACK) { -				hotkey_autosleep_ack = 1; -				pr_info("undocked\n"); -				hotkey_wakeup_hotunplug_complete_notify_change(); -				known_ev = true; -			} else { -				known_ev = false; -			} +			/* 0x4000-0x4FFF: dock-related events */ +			known_ev = hotkey_notify_dockevent(hkey, &send_acpi_ev, +						&ignore_acpi_ev);  			break;  		case 5:  			/* 0x5000-0x5FFF: human interface helpers */ @@ -3668,8 +3720,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)  						 &ignore_acpi_ev);  			break;  		case 6: -			/* 0x6000-0x6FFF: thermal alarms */ -			known_ev = hotkey_notify_thermal(hkey, &send_acpi_ev, +			/* 0x6000-0x6FFF: thermal alarms/notices and +			 *                keyboard events */ +			known_ev = hotkey_notify_6xxx(hkey, &send_acpi_ev,  						 &ignore_acpi_ev);  			break;  		case 7: | 
