mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-22 12:14:01 +08:00
platform/x86: thinkpad_acpi: set keyboard language
This patch is to create sysfs entry for setting keyboard language using ASL method. Some thinkpads models like T580 , T590 , T15 Gen 1 etc. has "=", "(',")" numeric keys, which are not displaying correctly, when keyboard language is other than "english". This patch fixes this issue by setting keyboard language to ECFW. Signed-off-by: Nitin Joshi <njoshi1@lenovo.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Link: https://lore.kernel.org/r/20210125025916.180831-1-nitjoshi@gmail.com Signed-off-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
parent
aecb925db7
commit
d7cbe2773a
@ -51,6 +51,7 @@ detailed description):
|
|||||||
- UWB enable and disable
|
- UWB enable and disable
|
||||||
- LCD Shadow (PrivacyGuard) enable and disable
|
- LCD Shadow (PrivacyGuard) enable and disable
|
||||||
- Lap mode sensor
|
- Lap mode sensor
|
||||||
|
- Setting keyboard language
|
||||||
|
|
||||||
A compatibility table by model and feature is maintained on the web
|
A compatibility table by model and feature is maintained on the web
|
||||||
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
|
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
|
||||||
@ -1466,6 +1467,29 @@ Sysfs notes
|
|||||||
rfkill controller switch "tpacpi_uwb_sw": refer to
|
rfkill controller switch "tpacpi_uwb_sw": refer to
|
||||||
Documentation/driver-api/rfkill.rst for details.
|
Documentation/driver-api/rfkill.rst for details.
|
||||||
|
|
||||||
|
|
||||||
|
Setting keyboard language
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
sysfs: keyboard_lang
|
||||||
|
|
||||||
|
This feature is used to set keyboard language to ECFW using ASL interface.
|
||||||
|
Fewer thinkpads models like T580 , T590 , T15 Gen 1 etc.. has "=", "(',
|
||||||
|
")" numeric keys, which are not displaying correctly, when keyboard language
|
||||||
|
is other than "english". This is because of default keyboard language in ECFW
|
||||||
|
is set as "english". Hence using this sysfs, user can set correct keyboard
|
||||||
|
language to ECFW and then these key's will work correctly .
|
||||||
|
|
||||||
|
Example of command to set keyboard language is mentioned below::
|
||||||
|
|
||||||
|
echo jp > /sys/devices/platform/thinkpad_acpi/keyboard_lang
|
||||||
|
|
||||||
|
Text corresponding to keyboard layout to be set in sysfs are : jp (Japan), be(Belgian),
|
||||||
|
cz(Czech), en(English), da(Danish), de(German), es(Spain) , et(Estonian),
|
||||||
|
fr(French) , fr-ch (French(Switzerland)), pl(Polish), sl(Slovenian), hu
|
||||||
|
(Hungarian), nl(Dutch), tr(Turkey), it(Italy), sv(Sweden), pt(portugese)
|
||||||
|
|
||||||
|
|
||||||
Adaptive keyboard
|
Adaptive keyboard
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
@ -9983,6 +9983,183 @@ static struct ibm_struct proxsensor_driver_data = {
|
|||||||
.exit = proxsensor_exit,
|
.exit = proxsensor_exit,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Keyboard language interface
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct keyboard_lang_data {
|
||||||
|
const char *lang_str;
|
||||||
|
int lang_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When adding new entries to keyboard_lang_data, please check that
|
||||||
|
* the select_lang[] buffer in keyboard_lang_show() is still large enough.
|
||||||
|
*/
|
||||||
|
struct keyboard_lang_data keyboard_lang_data[] = {
|
||||||
|
{"en", 0},
|
||||||
|
{"be", 0x080c},
|
||||||
|
{"cz", 0x0405},
|
||||||
|
{"da", 0x0406},
|
||||||
|
{"de", 0x0c07},
|
||||||
|
{"es", 0x2c0a},
|
||||||
|
{"et", 0x0425},
|
||||||
|
{"fr", 0x040c},
|
||||||
|
{"fr-ch", 0x100c},
|
||||||
|
{"hu", 0x040e},
|
||||||
|
{"it", 0x0410},
|
||||||
|
{"jp", 0x0411},
|
||||||
|
{"nl", 0x0413},
|
||||||
|
{"nn", 0x0414},
|
||||||
|
{"pl", 0x0415},
|
||||||
|
{"pt", 0x0816},
|
||||||
|
{"sl", 0x041b},
|
||||||
|
{"sv", 0x081d},
|
||||||
|
{"tr", 0x041f},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int set_keyboard_lang_command(int command)
|
||||||
|
{
|
||||||
|
acpi_handle sskl_handle;
|
||||||
|
int output;
|
||||||
|
|
||||||
|
if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "SSKL", &sskl_handle))) {
|
||||||
|
/* Platform doesn't support SSKL */
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acpi_evalf(sskl_handle, &output, NULL, "dd", command))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_keyboard_lang(int *output)
|
||||||
|
{
|
||||||
|
acpi_handle gskl_handle;
|
||||||
|
int kbd_lang;
|
||||||
|
|
||||||
|
if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "GSKL", &gskl_handle))) {
|
||||||
|
/* Platform doesn't support GSKL */
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acpi_evalf(gskl_handle, &kbd_lang, NULL, "dd", 0x02000000))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
*output = kbd_lang;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sysfs keyboard language entry */
|
||||||
|
static ssize_t keyboard_lang_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
int output, err, i;
|
||||||
|
char select_lang[80] = "";
|
||||||
|
char lang[8] = "";
|
||||||
|
|
||||||
|
err = get_keyboard_lang(&output);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(keyboard_lang_data); i++) {
|
||||||
|
if (i)
|
||||||
|
strcat(select_lang, " ");
|
||||||
|
|
||||||
|
if (output == keyboard_lang_data[i].lang_code) {
|
||||||
|
strcat(lang, "[");
|
||||||
|
strcat(lang, keyboard_lang_data[i].lang_str);
|
||||||
|
strcat(lang, "]");
|
||||||
|
strcat(select_lang, lang);
|
||||||
|
} else {
|
||||||
|
strcat(select_lang, keyboard_lang_data[i].lang_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sysfs_emit(buf, "%s\n", select_lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t keyboard_lang_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int err, i;
|
||||||
|
bool lang_found = false;
|
||||||
|
int lang_code = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(keyboard_lang_data); i++) {
|
||||||
|
if (sysfs_streq(buf, keyboard_lang_data[i].lang_str)) {
|
||||||
|
lang_code = keyboard_lang_data[i].lang_code;
|
||||||
|
lang_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lang_found) {
|
||||||
|
lang_code = lang_code | 1 << 24;
|
||||||
|
|
||||||
|
/* Set language code */
|
||||||
|
err = set_keyboard_lang_command(lang_code);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
} else {
|
||||||
|
pr_err("Unknown Keyboard language. Ignoring\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tpacpi_disclose_usertask(attr->attr.name,
|
||||||
|
"keyboard language is set to %s\n", buf);
|
||||||
|
|
||||||
|
sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "keyboard_lang");
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(keyboard_lang);
|
||||||
|
|
||||||
|
static struct attribute *kbdlang_attributes[] = {
|
||||||
|
&dev_attr_keyboard_lang.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group kbdlang_attr_group = {
|
||||||
|
.attrs = kbdlang_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tpacpi_kbdlang_init(struct ibm_init_struct *iibm)
|
||||||
|
{
|
||||||
|
int err, output;
|
||||||
|
|
||||||
|
err = get_keyboard_lang(&output);
|
||||||
|
/*
|
||||||
|
* If support isn't available (ENODEV) then don't return an error
|
||||||
|
* just don't create the sysfs group
|
||||||
|
*/
|
||||||
|
if (err == -ENODEV)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Platform supports this feature - create the sysfs file */
|
||||||
|
err = sysfs_create_group(&tpacpi_pdev->dev.kobj, &kbdlang_attr_group);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kbdlang_exit(void)
|
||||||
|
{
|
||||||
|
sysfs_remove_group(&tpacpi_pdev->dev.kobj, &kbdlang_attr_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ibm_struct kbdlang_driver_data = {
|
||||||
|
.name = "kbdlang",
|
||||||
|
.exit = kbdlang_exit,
|
||||||
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
****************************************************************************
|
****************************************************************************
|
||||||
*
|
*
|
||||||
@ -10475,6 +10652,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
|
|||||||
.init = tpacpi_proxsensor_init,
|
.init = tpacpi_proxsensor_init,
|
||||||
.data = &proxsensor_driver_data,
|
.data = &proxsensor_driver_data,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.init = tpacpi_kbdlang_init,
|
||||||
|
.data = &kbdlang_driver_data,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
|
static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
|
||||||
|
Loading…
Reference in New Issue
Block a user