|
@@ -1911,6 +1911,17 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */
|
|
|
TP_ACPI_HOTKEYSCAN_VOLUMEDOWN,
|
|
|
TP_ACPI_HOTKEYSCAN_MUTE,
|
|
|
TP_ACPI_HOTKEYSCAN_THINKPAD,
|
|
|
+ TP_ACPI_HOTKEYSCAN_UNK1,
|
|
|
+ TP_ACPI_HOTKEYSCAN_UNK2,
|
|
|
+ TP_ACPI_HOTKEYSCAN_UNK3,
|
|
|
+ TP_ACPI_HOTKEYSCAN_UNK4,
|
|
|
+ TP_ACPI_HOTKEYSCAN_UNK5,
|
|
|
+ TP_ACPI_HOTKEYSCAN_UNK6,
|
|
|
+ TP_ACPI_HOTKEYSCAN_UNK7,
|
|
|
+ TP_ACPI_HOTKEYSCAN_UNK8,
|
|
|
+
|
|
|
+ /* Hotkey keymap size */
|
|
|
+ TPACPI_HOTKEY_MAP_LEN
|
|
|
};
|
|
|
|
|
|
enum { /* Keys/events available through NVRAM polling */
|
|
@@ -3082,6 +3093,8 @@ static const struct tpacpi_quirk tpacpi_hotkey_qtable[] __initconst = {
|
|
|
TPACPI_Q_IBM('1', 'D', TPACPI_HK_Q_INIMASK), /* X22, X23, X24 */
|
|
|
};
|
|
|
|
|
|
+typedef u16 tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN];
|
|
|
+
|
|
|
static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|
|
{
|
|
|
/* Requirements for changing the default keymaps:
|
|
@@ -3113,9 +3126,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|
|
* If the above is too much to ask, don't change the keymap.
|
|
|
* Ask the thinkpad-acpi maintainer to do it, instead.
|
|
|
*/
|
|
|
- static u16 ibm_keycode_map[] __initdata = {
|
|
|
+
|
|
|
+ enum keymap_index {
|
|
|
+ TPACPI_KEYMAP_IBM_GENERIC = 0,
|
|
|
+ TPACPI_KEYMAP_LENOVO_GENERIC,
|
|
|
+ };
|
|
|
+
|
|
|
+ static const tpacpi_keymap_t tpacpi_keymaps[] __initconst = {
|
|
|
+ /* Generic keymap for IBM ThinkPads */
|
|
|
+ [TPACPI_KEYMAP_IBM_GENERIC] = {
|
|
|
/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
|
|
|
- KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP,
|
|
|
+ KEY_FN_F1, KEY_BATTERY, KEY_COFFEE, KEY_SLEEP,
|
|
|
KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
|
|
|
KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
|
|
|
|
|
@@ -3146,11 +3167,13 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|
|
/* (assignments unknown, please report if found) */
|
|
|
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
|
|
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
|
|
- };
|
|
|
- static u16 lenovo_keycode_map[] __initdata = {
|
|
|
+ },
|
|
|
+
|
|
|
+ /* Generic keymap for Lenovo ThinkPads */
|
|
|
+ [TPACPI_KEYMAP_LENOVO_GENERIC] = {
|
|
|
/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
|
|
|
KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP,
|
|
|
- KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
|
|
|
+ KEY_WLAN, KEY_CAMERA, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
|
|
|
KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
|
|
|
|
|
|
/* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */
|
|
@@ -3189,11 +3212,25 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|
|
/* (assignments unknown, please report if found) */
|
|
|
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
|
|
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ static const struct tpacpi_quirk tpacpi_keymap_qtable[] __initconst = {
|
|
|
+ /* Generic maps (fallback) */
|
|
|
+ {
|
|
|
+ .vendor = PCI_VENDOR_ID_IBM,
|
|
|
+ .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
|
|
|
+ .quirks = TPACPI_KEYMAP_IBM_GENERIC,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .vendor = PCI_VENDOR_ID_LENOVO,
|
|
|
+ .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
|
|
|
+ .quirks = TPACPI_KEYMAP_LENOVO_GENERIC,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
-#define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map)
|
|
|
-#define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map)
|
|
|
-#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0])
|
|
|
+#define TPACPI_HOTKEY_MAP_SIZE sizeof(tpacpi_keymap_t)
|
|
|
+#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(tpacpi_keymap_t[0])
|
|
|
|
|
|
int res, i;
|
|
|
int status;
|
|
@@ -3202,6 +3239,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|
|
bool tabletsw_state = false;
|
|
|
|
|
|
unsigned long quirks;
|
|
|
+ unsigned long keymap_id;
|
|
|
|
|
|
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
|
|
|
"initializing hotkey subdriver\n");
|
|
@@ -3342,7 +3380,6 @@ 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) {
|
|
@@ -3352,17 +3389,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|
|
goto err_exit;
|
|
|
}
|
|
|
|
|
|
- if (tpacpi_is_lenovo()) {
|
|
|
- dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
|
|
|
- "using Lenovo default hot key map\n");
|
|
|
- memcpy(hotkey_keycode_map, &lenovo_keycode_map,
|
|
|
- TPACPI_HOTKEY_MAP_SIZE);
|
|
|
- } else {
|
|
|
- dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
|
|
|
- "using IBM default hot key map\n");
|
|
|
- memcpy(hotkey_keycode_map, &ibm_keycode_map,
|
|
|
- TPACPI_HOTKEY_MAP_SIZE);
|
|
|
- }
|
|
|
+ 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);
|
|
|
|
|
|
input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN);
|
|
|
tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
|
|
@@ -3469,7 +3503,8 @@ static bool hotkey_notify_hotkey(const u32 hkey,
|
|
|
*send_acpi_ev = true;
|
|
|
*ignore_acpi_ev = false;
|
|
|
|
|
|
- if (scancode > 0 && scancode < 0x21) {
|
|
|
+ /* HKEY event 0x1001 is scancode 0x00 */
|
|
|
+ if (scancode > 0 && scancode <= TPACPI_HOTKEY_MAP_LEN) {
|
|
|
scancode--;
|
|
|
if (!(hotkey_source_mask & (1 << scancode))) {
|
|
|
tpacpi_input_send_key_masked(scancode);
|
|
@@ -6080,13 +6115,18 @@ static struct backlight_ops ibm_backlight_data = {
|
|
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
|
|
+/*
|
|
|
+ * Call _BCL method of video device. On some ThinkPads this will
|
|
|
+ * switch the firmware to the ACPI brightness control mode.
|
|
|
+ */
|
|
|
+
|
|
|
static int __init tpacpi_query_bcl_levels(acpi_handle handle)
|
|
|
{
|
|
|
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
|
union acpi_object *obj;
|
|
|
int rc;
|
|
|
|
|
|
- if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
|
|
|
+ if (ACPI_SUCCESS(acpi_evaluate_object(handle, "_BCL", NULL, &buffer))) {
|
|
|
obj = (union acpi_object *)buffer.pointer;
|
|
|
if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
|
|
|
printk(TPACPI_ERR "Unknown _BCL data, "
|
|
@@ -6103,55 +6143,22 @@ static int __init tpacpi_query_bcl_levels(acpi_handle handle)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle,
|
|
|
- u32 lvl, void *context, void **rv)
|
|
|
-{
|
|
|
- char name[ACPI_PATH_SEGMENT_LENGTH];
|
|
|
- struct acpi_buffer buffer = { sizeof(name), &name };
|
|
|
-
|
|
|
- if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
|
|
|
- !strncmp("_BCL", name, sizeof(name) - 1)) {
|
|
|
- BUG_ON(!rv || !*rv);
|
|
|
- **(int **)rv = tpacpi_query_bcl_levels(handle);
|
|
|
- return AE_CTRL_TERMINATE;
|
|
|
- } else {
|
|
|
- return AE_OK;
|
|
|
- }
|
|
|
-}
|
|
|
|
|
|
/*
|
|
|
* Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map
|
|
|
*/
|
|
|
static unsigned int __init tpacpi_check_std_acpi_brightness_support(void)
|
|
|
{
|
|
|
- int status;
|
|
|
+ acpi_handle video_device;
|
|
|
int bcl_levels = 0;
|
|
|
- void *bcl_ptr = &bcl_levels;
|
|
|
-
|
|
|
- if (!vid_handle)
|
|
|
- TPACPI_ACPIHANDLE_INIT(vid);
|
|
|
-
|
|
|
- if (!vid_handle)
|
|
|
- return 0;
|
|
|
-
|
|
|
- /*
|
|
|
- * Search for a _BCL method, and execute it. This is safe on all
|
|
|
- * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista
|
|
|
- * BIOS in ACPI backlight control mode. We do NOT have to care
|
|
|
- * about calling the _BCL method in an enabled video device, any
|
|
|
- * will do for our purposes.
|
|
|
- */
|
|
|
|
|
|
- status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
|
|
|
- tpacpi_acpi_walk_find_bcl, NULL, NULL,
|
|
|
- &bcl_ptr);
|
|
|
+ tpacpi_acpi_handle_locate("video", ACPI_VIDEO_HID, &video_device);
|
|
|
+ if (video_device)
|
|
|
+ bcl_levels = tpacpi_query_bcl_levels(video_device);
|
|
|
|
|
|
- if (ACPI_SUCCESS(status) && bcl_levels > 2) {
|
|
|
- tp_features.bright_acpimode = 1;
|
|
|
- return bcl_levels - 2;
|
|
|
- }
|
|
|
+ tp_features.bright_acpimode = (bcl_levels > 0);
|
|
|
|
|
|
- return 0;
|
|
|
+ return (bcl_levels > 2) ? (bcl_levels - 2) : 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -6244,28 +6251,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|
|
if (tp_features.bright_unkfw)
|
|
|
return 1;
|
|
|
|
|
|
- if (tp_features.bright_acpimode) {
|
|
|
- if (acpi_video_backlight_support()) {
|
|
|
- if (brightness_enable > 1) {
|
|
|
- printk(TPACPI_NOTICE
|
|
|
- "Standard ACPI backlight interface "
|
|
|
- "available, not loading native one.\n");
|
|
|
- return 1;
|
|
|
- } else if (brightness_enable == 1) {
|
|
|
- printk(TPACPI_NOTICE
|
|
|
- "Backlight control force enabled, even if standard "
|
|
|
- "ACPI backlight interface is available\n");
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (brightness_enable > 1) {
|
|
|
- printk(TPACPI_NOTICE
|
|
|
- "Standard ACPI backlight interface not "
|
|
|
- "available, thinkpad_acpi native "
|
|
|
- "brightness control enabled\n");
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
if (!brightness_enable) {
|
|
|
dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
|
|
|
"brightness support disabled by "
|
|
@@ -6273,6 +6258,26 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+ if (acpi_video_backlight_support()) {
|
|
|
+ if (brightness_enable > 1) {
|
|
|
+ printk(TPACPI_INFO
|
|
|
+ "Standard ACPI backlight interface "
|
|
|
+ "available, not loading native one.\n");
|
|
|
+ return 1;
|
|
|
+ } else if (brightness_enable == 1) {
|
|
|
+ printk(TPACPI_WARN
|
|
|
+ "Cannot enable backlight brightness support, "
|
|
|
+ "ACPI is already handling it. Refer to the "
|
|
|
+ "acpi_backlight kernel parameter\n");
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ } else if (tp_features.bright_acpimode && brightness_enable > 1) {
|
|
|
+ printk(TPACPI_NOTICE
|
|
|
+ "Standard ACPI backlight interface not "
|
|
|
+ "available, thinkpad_acpi native "
|
|
|
+ "brightness control enabled\n");
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Check for module parameter bogosity, note that we
|
|
|
* init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be
|