浏览代码

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:
  hp-wmi: fix use after free
  dell-laptop - using buffer without mutex_lock
  Revert: "dell-laptop: Toggle the unsupported hardware killswitch"
  platform-drivers-x86: set backlight type to BACKLIGHT_PLATFORM
  thinkpad-acpi: handle HKEY 0x4010, 0x4011 events
  drivers/platform/x86: Fix memory leak
  thinkpad-acpi: handle some new HKEY 0x60xx events
  acer-wmi: fix bitwise bug when set device state
  acer-wmi: Only update rfkill status for associated hotkey events
Linus Torvalds 14 年之前
父节点
当前提交
145628130b

+ 5 - 0
Documentation/laptops/thinkpad-acpi.txt

@@ -534,6 +534,8 @@ Events that are never propagated by the driver:
 0x2404		System is waking up from hibernation to undock
 0x2404		System is waking up from hibernation to undock
 0x2405		System is waking up from hibernation to eject bay
 0x2405		System is waking up from hibernation to eject bay
 0x5010		Brightness level changed/control event
 0x5010		Brightness level changed/control event
+0x6000		KEYBOARD: Numlock key pressed
+0x6005		KEYBOARD: Fn key pressed (TO BE VERIFIED)
 
 
 Events that are propagated by the driver to userspace:
 Events that are propagated by the driver to userspace:
 
 
@@ -545,6 +547,8 @@ Events that are propagated by the driver to userspace:
 0x3006		Bay hotplug request (hint to power up SATA link when
 0x3006		Bay hotplug request (hint to power up SATA link when
 		the optical drive tray is ejected)
 		the optical drive tray is ejected)
 0x4003		Undocked (see 0x2x04), can sleep again
 0x4003		Undocked (see 0x2x04), can sleep again
+0x4010		Docked into hotplug port replicator (non-ACPI dock)
+0x4011		Undocked from hotplug port replicator (non-ACPI dock)
 0x500B		Tablet pen inserted into its storage bay
 0x500B		Tablet pen inserted into its storage bay
 0x500C		Tablet pen removed from its storage bay
 0x500C		Tablet pen removed from its storage bay
 0x6011		ALARM: battery is too hot
 0x6011		ALARM: battery is too hot
@@ -552,6 +556,7 @@ Events that are propagated by the driver to userspace:
 0x6021		ALARM: a sensor is too hot
 0x6021		ALARM: a sensor is too hot
 0x6022		ALARM: a sensor is extremely hot
 0x6022		ALARM: a sensor is extremely hot
 0x6030		System thermal table changed
 0x6030		System thermal table changed
+0x6040		Nvidia Optimus/AC adapter related (TO BE VERIFIED)
 
 
 Battery nearly empty alarms are a last resort attempt to get the
 Battery nearly empty alarms are a last resort attempt to get the
 operating system to hibernate or shutdown cleanly (0x2313), or shutdown
 operating system to hibernate or shutdown cleanly (0x2313), or shutdown

+ 29 - 18
drivers/platform/x86/acer-wmi.c

@@ -1156,9 +1156,9 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
 	struct wmid3_gds_input_param params = {
 	struct wmid3_gds_input_param params = {
 		.function_num = 0x1,
 		.function_num = 0x1,
 		.hotkey_number = 0x01,
 		.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,
 				ACER_WMID3_GDS_BLUETOOTH,
 	};
 	};
 	struct acpi_buffer input = {
 	struct acpi_buffer input = {
@@ -1445,6 +1445,8 @@ static void acer_wmi_notify(u32 value, void *context)
 	union acpi_object *obj;
 	union acpi_object *obj;
 	struct event_return_value return_value;
 	struct event_return_value return_value;
 	acpi_status status;
 	acpi_status status;
+	u16 device_state;
+	const struct key_entry *key;
 
 
 	status = wmi_get_event_data(value, &response);
 	status = wmi_get_event_data(value, &response);
 	if (status != AE_OK) {
 	if (status != AE_OK) {
@@ -1472,23 +1474,32 @@ static void acer_wmi_notify(u32 value, void *context)
 
 
 	switch (return_value.function) {
 	switch (return_value.function) {
 	case WMID_HOTKEY_EVENT:
 	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",
 			pr_warn("Unknown key number - 0x%x\n",
 				return_value.key_num);
 				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;
 		break;
 	default:
 	default:
 		pr_warn("Unknown function number - %d - %d\n",
 		pr_warn("Unknown function number - %d - %d\n",

+ 1 - 0
drivers/platform/x86/asus-wmi.c

@@ -1025,6 +1025,7 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
 		return power;
 		return power;
 
 
 	memset(&props, 0, sizeof(struct backlight_properties));
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = max;
 	props.max_brightness = max;
 	bd = backlight_device_register(asus->driver->name,
 	bd = backlight_device_register(asus->driver->name,
 				       &asus->platform_device->dev, asus,
 				       &asus->platform_device->dev, asus,

+ 3 - 1
drivers/platform/x86/compal-laptop.c

@@ -1030,8 +1030,10 @@ static int __devinit compal_probe(struct platform_device *pdev)
 	initialize_fan_control_data(data);
 	initialize_fan_control_data(data);
 
 
 	err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group);
 	err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group);
-	if (err)
+	if (err) {
+		kfree(data);
 		return err;
 		return err;
+	}
 
 
 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
 	if (IS_ERR(data->hwmon_dev)) {
 	if (IS_ERR(data->hwmon_dev)) {

+ 5 - 25
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);
 	dell_send_request(buffer, 17, 11);
 
 
 	/* If the hardware switch controls this radio, and the hardware
 	/* 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)) &&
 	if ((hwswitch_state & BIT(hwswitch_bit)) &&
-	    !(buffer->output[1] & BIT(16)) &&
-	    (buffer->output[1] & BIT(0))) {
+	    !(buffer->output[1] & BIT(16))) {
 		ret = -EINVAL;
 		ret = -EINVAL;
 		goto out;
 		goto out;
 	}
 	}
@@ -403,23 +400,6 @@ static const struct file_operations dell_debugfs_fops = {
 
 
 static void dell_update_rfkill(struct work_struct *ignored)
 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)
 	if (wifi_rfkill)
 		dell_rfkill_query(wifi_rfkill, (void *)1);
 		dell_rfkill_query(wifi_rfkill, (void *)1);
 	if (bluetooth_rfkill)
 	if (bluetooth_rfkill)
@@ -560,11 +540,11 @@ static int dell_get_intensity(struct backlight_device *bd)
 	else
 	else
 		dell_send_request(buffer, 0, 1);
 		dell_send_request(buffer, 0, 1);
 
 
+	ret = buffer->output[1];
+
 out:
 out:
 	release_buffer();
 	release_buffer();
-	if (ret)
-		return ret;
-	return buffer->output[1];
+	return ret;
 }
 }
 
 
 static const struct backlight_ops dell_ops = {
 static const struct backlight_ops dell_ops = {

+ 6 - 5
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 input = { sizeof(struct bios_args), &args };
 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+	u32 rc;
 
 
 	if (WARN_ON(insize > sizeof(args.data)))
 	if (WARN_ON(insize > sizeof(args.data)))
 		return -EINVAL;
 		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;
 	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);
 		kfree(obj);
-		return bios_return->return_code;
+		return rc;
 	}
 	}
 
 
 	if (!outsize) {
 	if (!outsize) {

+ 1 - 0
drivers/platform/x86/intel_oaktrail.c

@@ -250,6 +250,7 @@ static int oaktrail_backlight_init(void)
 	struct backlight_properties props;
 	struct backlight_properties props;
 
 
 	memset(&props, 0, sizeof(struct backlight_properties));
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = OT_EC_BL_BRIGHTNESS_MAX;
 	props.max_brightness = OT_EC_BL_BRIGHTNESS_MAX;
 	bd = backlight_device_register(DRIVER_NAME,
 	bd = backlight_device_register(DRIVER_NAME,
 				       &oaktrail_device->dev, NULL,
 				       &oaktrail_device->dev, NULL,

+ 58 - 14
drivers/platform/x86/thinkpad_acpi.c

@@ -184,6 +184,10 @@ enum tpacpi_hkey_event_t {
 
 
 	/* Misc bay events */
 	/* Misc bay events */
 	TP_HKEY_EV_OPTDRV_EJ		= 0x3006, /* opt. drive tray ejected */
 	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 */
 	/* User-interface events */
 	TP_HKEY_EV_LID_CLOSE		= 0x5001, /* laptop lid closed */
 	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_PEN_REMOVED		= 0x500c, /* tablet pen removed */
 	TP_HKEY_EV_BRGHT_CHANGED	= 0x5010, /* backlight control event */
 	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 */
 	/* Thermal events */
 	TP_HKEY_EV_ALARM_BAT_HOT	= 0x6011, /* battery too hot */
 	TP_HKEY_EV_ALARM_BAT_HOT	= 0x6011, /* battery too hot */
 	TP_HKEY_EV_ALARM_BAT_XHOT	= 0x6012, /* battery critically 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_ALARM_SENSOR_XHOT	= 0x6022, /* sensor critically hot */
 	TP_HKEY_EV_THM_TABLE_CHANGED	= 0x6030, /* thermal table changed */
 	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 */
 	/* Misc */
 	TP_HKEY_EV_RFKILL_CHANGED	= 0x7000, /* rfkill switch changed */
 	TP_HKEY_EV_RFKILL_CHANGED	= 0x7000, /* rfkill switch changed */
 };
 };
@@ -3513,6 +3525,34 @@ static bool hotkey_notify_wakeup(const u32 hkey,
 	return true;
 	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,
 static bool hotkey_notify_usrevent(const u32 hkey,
 				 bool *send_acpi_ev,
 				 bool *send_acpi_ev,
 				 bool *ignore_acpi_ev)
 				 bool *ignore_acpi_ev)
@@ -3547,13 +3587,13 @@ static bool hotkey_notify_usrevent(const u32 hkey,
 
 
 static void thermal_dump_all_sensors(void);
 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 *send_acpi_ev,
 				 bool *ignore_acpi_ev)
 				 bool *ignore_acpi_ev)
 {
 {
 	bool known = true;
 	bool known = true;
 
 
-	/* 0x6000-0x6FFF: thermal alarms */
+	/* 0x6000-0x6FFF: thermal alarms/notices and keyboard events */
 	*send_acpi_ev = true;
 	*send_acpi_ev = true;
 	*ignore_acpi_ev = false;
 	*ignore_acpi_ev = false;
 
 
@@ -3582,8 +3622,17 @@ static bool hotkey_notify_thermal(const u32 hkey,
 			 "a sensor reports something is extremely hot!\n");
 			 "a sensor reports something is extremely hot!\n");
 		/* recommended action: immediate sleep/hibernate */
 		/* recommended action: immediate sleep/hibernate */
 		break;
 		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:
 	default:
-		pr_alert("THERMAL ALERT: unknown thermal alarm received\n");
+		pr_warn("unknown possible thermal alarm or keyboard event received\n");
 		known = false;
 		known = false;
 	}
 	}
 
 
@@ -3652,15 +3701,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
 			}
 			}
 			break;
 			break;
 		case 4:
 		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;
 			break;
 		case 5:
 		case 5:
 			/* 0x5000-0x5FFF: human interface helpers */
 			/* 0x5000-0x5FFF: human interface helpers */
@@ -3668,8 +3711,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
 						 &ignore_acpi_ev);
 						 &ignore_acpi_ev);
 			break;
 			break;
 		case 6:
 		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);
 						 &ignore_acpi_ev);
 			break;
 			break;
 		case 7:
 		case 7: