diff options
Diffstat (limited to 'drivers/platform/x86/thinkpad_acpi.c')
| -rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 122 | 
1 files changed, 112 insertions, 10 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 7bde4640ef34..da794dcfdd92 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3647,22 +3647,19 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)  		goto err_exit;  	/* Set up key map */ -	hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, -					GFP_KERNEL); -	if (!hotkey_keycode_map) { -		pr_err("failed to allocate memory for key map\n"); -		res = -ENOMEM; -		goto err_exit; -	} -  	keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable,  					ARRAY_SIZE(tpacpi_keymap_qtable));  	BUG_ON(keymap_id >= ARRAY_SIZE(tpacpi_keymaps));  	dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,  		   "using keymap number %lu\n", keymap_id); -	memcpy(hotkey_keycode_map, &tpacpi_keymaps[keymap_id], -		TPACPI_HOTKEY_MAP_SIZE); +	hotkey_keycode_map = kmemdup(&tpacpi_keymaps[keymap_id], +			TPACPI_HOTKEY_MAP_SIZE,	GFP_KERNEL); +	if (!hotkey_keycode_map) { +		pr_err("failed to allocate memory for key map\n"); +		res = -ENOMEM; +		goto err_exit; +	}  	input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN);  	tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; @@ -9714,6 +9711,107 @@ static struct ibm_struct battery_driver_data = {  	.exit = tpacpi_battery_exit,  }; +/************************************************************************* + * LCD Shadow subdriver, for the Lenovo PrivacyGuard feature + */ + +static int lcdshadow_state; + +static int lcdshadow_on_off(bool state) +{ +	acpi_handle set_shadow_handle; +	int output; + +	if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "SSSS", &set_shadow_handle))) { +		pr_warn("Thinkpad ACPI has no %s interface.\n", "SSSS"); +		return -EIO; +	} + +	if (!acpi_evalf(set_shadow_handle, &output, NULL, "dd", (int)state)) +		return -EIO; + +	lcdshadow_state = state; +	return 0; +} + +static int lcdshadow_set(bool on) +{ +	if (lcdshadow_state < 0) +		return lcdshadow_state; +	if (lcdshadow_state == on) +		return 0; +	return lcdshadow_on_off(on); +} + +static int tpacpi_lcdshadow_init(struct ibm_init_struct *iibm) +{ +	acpi_handle get_shadow_handle; +	int output; + +	if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "GSSS", &get_shadow_handle))) { +		lcdshadow_state = -ENODEV; +		return 0; +	} + +	if (!acpi_evalf(get_shadow_handle, &output, NULL, "dd", 0)) { +		lcdshadow_state = -EIO; +		return -EIO; +	} +	if (!(output & 0x10000)) { +		lcdshadow_state = -ENODEV; +		return 0; +	} +	lcdshadow_state = output & 0x1; + +	return 0; +} + +static void lcdshadow_resume(void) +{ +	if (lcdshadow_state >= 0) +		lcdshadow_on_off(lcdshadow_state); +} + +static int lcdshadow_read(struct seq_file *m) +{ +	if (lcdshadow_state < 0) { +		seq_puts(m, "status:\t\tnot supported\n"); +	} else { +		seq_printf(m, "status:\t\t%d\n", lcdshadow_state); +		seq_puts(m, "commands:\t0, 1\n"); +	} + +	return 0; +} + +static int lcdshadow_write(char *buf) +{ +	char *cmd; +	int state = -1; + +	if (lcdshadow_state < 0) +		return -ENODEV; + +	while ((cmd = next_cmd(&buf))) { +		if (strlencmp(cmd, "0") == 0) +			state = 0; +		else if (strlencmp(cmd, "1") == 0) +			state = 1; +	} + +	if (state == -1) +		return -EINVAL; + +	return lcdshadow_set(state); +} + +static struct ibm_struct lcdshadow_driver_data = { +	.name = "lcdshadow", +	.resume = lcdshadow_resume, +	.read = lcdshadow_read, +	.write = lcdshadow_write, +}; +  /****************************************************************************   ****************************************************************************   * @@ -10195,6 +10293,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {  		.init = tpacpi_battery_init,  		.data = &battery_driver_data,  	}, +	{ +		.init = tpacpi_lcdshadow_init, +		.data = &lcdshadow_driver_data, +	},  };  static int __init set_ibm_param(const char *val, const struct kernel_param *kp)  |