Hello Hans , >-----Original Message----- >From: Hans de Goede <hdegoede@xxxxxxxxxx> >Sent: Tuesday, January 26, 2021 5:34 AM >To: Nitin Joshi <nitjoshi@xxxxxxxxx> >Cc: bberg@xxxxxxxxxx; peter.hutterer@xxxxxxxxxx; Tomoki Maruichi ><maruichit@xxxxxxxxxx>; Mark Pearson <mpearson@xxxxxxxxxx>; >platform-driver-x86@xxxxxxxxxxxxxxx; Nitin Joshi1 <njoshi1@xxxxxxxxxx> >Subject: [External] Re: [PATCH] [v2] platform/x86: thinkpad_acpi: set keyboard >language > >Hi, > >On 1/25/21 3:59 AM, Nitin Joshi wrote: >> From: Nitin Joshi <njoshi1@xxxxxxxxxx> >> >> 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@xxxxxxxxxx> >> --- >> Changes in v2: >> - used sysfs_streq() API instead of strcmp >> - used ARRAY_SIZE() API instead of strlen >> - addressed typo > >Thank you for your patch, I've applied this patch to my review-hans >branch: >https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers- >x86.git/log/?h=review-hans > >Nitn, I did not notice one small issue while testing this on a X1C8 I will send out >a follow-up patch addressing that. If you can test the follow-up patch on one >of the affected models >(T580 , T590 , T15 Gen 1, etc.) that would be great. Yes , sure . I will test it . Thank you > >Note this patch will show up in my review-hans branch once I've pushed my >local branch there, which might take a while. > >Once I've run some tests on this branch the patches there will be added to the >platform-drivers-x86/for-next branch and eventually will be included in the >pdx86 pull-request to Linus for the next merge-window. > >Regards, > >Hans > Thanks & Regards, Nitin Joshi > >> --- >> .../admin-guide/laptops/thinkpad-acpi.rst | 24 +++ >> drivers/platform/x86/thinkpad_acpi.c | 182 ++++++++++++++++++ >> 2 files changed, 206 insertions(+) >> >> diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst >> b/Documentation/admin-guide/laptops/thinkpad-acpi.rst >> index 5fe1ade88c17..b1188f05a99a 100644 >> --- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst >> +++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst >> @@ -51,6 +51,7 @@ detailed description): >> - UWB enable and disable >> - LCD Shadow (PrivacyGuard) enable and disable >> - Lap mode sensor >> + - Setting keyboard language >> >> A compatibility table by model and feature is maintained on the web >> 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 >> 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 >> ----------------- >> >> diff --git a/drivers/platform/x86/thinkpad_acpi.c >> b/drivers/platform/x86/thinkpad_acpi.c >> index e03df2881dc6..3cfc4a872c2d 100644 >> --- a/drivers/platform/x86/thinkpad_acpi.c >> +++ b/drivers/platform/x86/thinkpad_acpi.c >> @@ -9982,6 +9982,183 @@ static struct ibm_struct proxsensor_driver_data >= { >> .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, >> +}; >> + >> >/**************************************************************** >************ >> >***************************************************************** >*********** >> * >> @@ -10474,6 +10651,11 @@ static struct ibm_init_struct ibms_init[] >__initdata = { >> .init = tpacpi_proxsensor_init, >> .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) >>