linux/drivers/platform/x86/think-lmi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Think LMI BIOS configuration driver
   4 *
   5 * Copyright(C) 2019-2021 Lenovo
   6 *
   7 * Original code from Thinkpad-wmi project https://github.com/iksaif/thinkpad-wmi
   8 * Copyright(C) 2017 Corentin Chary <corentin.chary@gmail.com>
   9 * Distributed under the GPL-2.0 license
  10 */
  11
  12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13
  14#include <linux/acpi.h>
  15#include <linux/errno.h>
  16#include <linux/fs.h>
  17#include <linux/string.h>
  18#include <linux/types.h>
  19#include <linux/wmi.h>
  20#include "firmware_attributes_class.h"
  21#include "think-lmi.h"
  22
  23static bool debug_support;
  24module_param(debug_support, bool, 0444);
  25MODULE_PARM_DESC(debug_support, "Enable debug command support");
  26
  27/*
  28 * Name:
  29 *  Lenovo_BiosSetting
  30 * Description:
  31 *  Get item name and settings for current LMI instance.
  32 * Type:
  33 *  Query
  34 * Returns:
  35 *  "Item,Value"
  36 * Example:
  37 *  "WakeOnLAN,Enable"
  38 */
  39#define LENOVO_BIOS_SETTING_GUID "51F5230E-9677-46CD-A1CF-C0B23EE34DB7"
  40
  41/*
  42 * Name:
  43 *  Lenovo_SetBiosSetting
  44 * Description:
  45 *  Change the BIOS setting to the desired value using the Lenovo_SetBiosSetting
  46 *  class. To save the settings, use the Lenovo_SaveBiosSetting class.
  47 *  BIOS settings and values are case sensitive.
  48 *  After making changes to the BIOS settings, you must reboot the computer
  49 *  before the changes will take effect.
  50 * Type:
  51 *  Method
  52 * Arguments:
  53 *  "Item,Value,Password,Encoding,KbdLang;"
  54 * Example:
  55 *  "WakeOnLAN,Disable,pa55w0rd,ascii,us;"
  56 */
  57#define LENOVO_SET_BIOS_SETTINGS_GUID "98479A64-33F5-4E33-A707-8E251EBBC3A1"
  58
  59/*
  60 * Name:
  61 *  Lenovo_SaveBiosSettings
  62 * Description:
  63 *  Save any pending changes in settings.
  64 * Type:
  65 *  Method
  66 * Arguments:
  67 *  "Password,Encoding,KbdLang;"
  68 * Example:
  69 * "pa55w0rd,ascii,us;"
  70 */
  71#define LENOVO_SAVE_BIOS_SETTINGS_GUID "6A4B54EF-A5ED-4D33-9455-B0D9B48DF4B3"
  72
  73/*
  74 * Name:
  75 *  Lenovo_BiosPasswordSettings
  76 * Description:
  77 *  Return BIOS Password settings
  78 * Type:
  79 *  Query
  80 * Returns:
  81 *  PasswordMode, PasswordState, MinLength, MaxLength,
  82 *  SupportedEncoding, SupportedKeyboard
  83 */
  84#define LENOVO_BIOS_PASSWORD_SETTINGS_GUID "8ADB159E-1E32-455C-BC93-308A7ED98246"
  85
  86/*
  87 * Name:
  88 *  Lenovo_SetBiosPassword
  89 * Description:
  90 *  Change a specific password.
  91 *  - BIOS settings cannot be changed at the same boot as power-on
  92 *    passwords (POP) and hard disk passwords (HDP). If you want to change
  93 *    BIOS settings and POP or HDP, you must reboot the system after changing
  94 *    one of them.
  95 *  - A password cannot be set using this method when one does not already
  96 *    exist. Passwords can only be updated or cleared.
  97 * Type:
  98 *  Method
  99 * Arguments:
 100 *  "PasswordType,CurrentPassword,NewPassword,Encoding,KbdLang;"
 101 * Example:
 102 *  "pop,pa55w0rd,newpa55w0rd,ascii,us;”
 103 */
 104#define LENOVO_SET_BIOS_PASSWORD_GUID "2651D9FD-911C-4B69-B94E-D0DED5963BD7"
 105
 106/*
 107 * Name:
 108 *  Lenovo_GetBiosSelections
 109 * Description:
 110 *  Return a list of valid settings for a given item.
 111 * Type:
 112 *  Method
 113 * Arguments:
 114 *  "Item"
 115 * Returns:
 116 *  "Value1,Value2,Value3,..."
 117 * Example:
 118 *  -> "FlashOverLAN"
 119 *  <- "Enabled,Disabled"
 120 */
 121#define LENOVO_GET_BIOS_SELECTIONS_GUID "7364651A-132F-4FE7-ADAA-40C6C7EE2E3B"
 122
 123/*
 124 * Name:
 125 *  Lenovo_DebugCmdGUID
 126 * Description
 127 *  Debug entry GUID method for entering debug commands to the BIOS
 128 */
 129#define LENOVO_DEBUG_CMD_GUID "7FF47003-3B6C-4E5E-A227-E979824A85D1"
 130
 131#define TLMI_POP_PWD (1 << 0)
 132#define TLMI_PAP_PWD (1 << 1)
 133#define to_tlmi_pwd_setting(kobj)  container_of(kobj, struct tlmi_pwd_setting, kobj)
 134#define to_tlmi_attr_setting(kobj)  container_of(kobj, struct tlmi_attr_setting, kobj)
 135
 136static const struct tlmi_err_codes tlmi_errs[] = {
 137        {"Success", 0},
 138        {"Not Supported", -EOPNOTSUPP},
 139        {"Invalid Parameter", -EINVAL},
 140        {"Access Denied", -EACCES},
 141        {"System Busy", -EBUSY},
 142};
 143
 144static const char * const encoding_options[] = {
 145        [TLMI_ENCODING_ASCII] = "ascii",
 146        [TLMI_ENCODING_SCANCODE] = "scancode",
 147};
 148static struct think_lmi tlmi_priv;
 149static struct class *fw_attr_class;
 150
 151/* ------ Utility functions ------------*/
 152/* Convert BIOS WMI error string to suitable error code */
 153static int tlmi_errstr_to_err(const char *errstr)
 154{
 155        int i;
 156
 157        for (i = 0; i < sizeof(tlmi_errs)/sizeof(struct tlmi_err_codes); i++) {
 158                if (!strcmp(tlmi_errs[i].err_str, errstr))
 159                        return tlmi_errs[i].err_code;
 160        }
 161        return -EPERM;
 162}
 163
 164/* Extract error string from WMI return buffer */
 165static int tlmi_extract_error(const struct acpi_buffer *output)
 166{
 167        const union acpi_object *obj;
 168
 169        obj = output->pointer;
 170        if (!obj)
 171                return -ENOMEM;
 172        if (obj->type != ACPI_TYPE_STRING || !obj->string.pointer)
 173                return -EIO;
 174
 175        return tlmi_errstr_to_err(obj->string.pointer);
 176}
 177
 178/* Utility function to execute WMI call to BIOS */
 179static int tlmi_simple_call(const char *guid, const char *arg)
 180{
 181        const struct acpi_buffer input = { strlen(arg), (char *)arg };
 182        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 183        acpi_status status;
 184        int i, err;
 185
 186        /*
 187         * Duplicated call required to match BIOS workaround for behavior
 188         * seen when WMI accessed via scripting on other OS.
 189         */
 190        for (i = 0; i < 2; i++) {
 191                /* (re)initialize output buffer to default state */
 192                output.length = ACPI_ALLOCATE_BUFFER;
 193                output.pointer = NULL;
 194
 195                status = wmi_evaluate_method(guid, 0, 0, &input, &output);
 196                if (ACPI_FAILURE(status)) {
 197                        kfree(output.pointer);
 198                        return -EIO;
 199                }
 200                err = tlmi_extract_error(&output);
 201                kfree(output.pointer);
 202                if (err)
 203                        return err;
 204        }
 205        return 0;
 206}
 207
 208/* Extract output string from WMI return buffer */
 209static int tlmi_extract_output_string(const struct acpi_buffer *output,
 210                                      char **string)
 211{
 212        const union acpi_object *obj;
 213        char *s;
 214
 215        obj = output->pointer;
 216        if (!obj)
 217                return -ENOMEM;
 218        if (obj->type != ACPI_TYPE_STRING || !obj->string.pointer)
 219                return -EIO;
 220
 221        s = kstrdup(obj->string.pointer, GFP_KERNEL);
 222        if (!s)
 223                return -ENOMEM;
 224        *string = s;
 225        return 0;
 226}
 227
 228/* ------ Core interface functions ------------*/
 229
 230/* Get password settings from BIOS */
 231static int tlmi_get_pwd_settings(struct tlmi_pwdcfg *pwdcfg)
 232{
 233        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 234        const union acpi_object *obj;
 235        acpi_status status;
 236
 237        if (!tlmi_priv.can_get_password_settings)
 238                return -EOPNOTSUPP;
 239
 240        status = wmi_query_block(LENOVO_BIOS_PASSWORD_SETTINGS_GUID, 0,
 241                                 &output);
 242        if (ACPI_FAILURE(status))
 243                return -EIO;
 244
 245        obj = output.pointer;
 246        if (!obj)
 247                return -ENOMEM;
 248        if (obj->type != ACPI_TYPE_BUFFER || !obj->buffer.pointer) {
 249                kfree(obj);
 250                return -EIO;
 251        }
 252        /*
 253         * The size of thinkpad_wmi_pcfg on ThinkStation is larger than ThinkPad.
 254         * To make the driver compatible on different brands, we permit it to get
 255         * the data in below case.
 256         */
 257        if (obj->buffer.length < sizeof(struct tlmi_pwdcfg)) {
 258                pr_warn("Unknown pwdcfg buffer length %d\n", obj->buffer.length);
 259                kfree(obj);
 260                return -EIO;
 261        }
 262        memcpy(pwdcfg, obj->buffer.pointer, sizeof(struct tlmi_pwdcfg));
 263        kfree(obj);
 264        return 0;
 265}
 266
 267static int tlmi_save_bios_settings(const char *password)
 268{
 269        return tlmi_simple_call(LENOVO_SAVE_BIOS_SETTINGS_GUID,
 270                                password);
 271}
 272
 273static int tlmi_setting(int item, char **value, const char *guid_string)
 274{
 275        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 276        acpi_status status;
 277        int ret;
 278
 279        status = wmi_query_block(guid_string, item, &output);
 280        if (ACPI_FAILURE(status)) {
 281                kfree(output.pointer);
 282                return -EIO;
 283        }
 284
 285        ret = tlmi_extract_output_string(&output, value);
 286        kfree(output.pointer);
 287        return ret;
 288}
 289
 290static int tlmi_get_bios_selections(const char *item, char **value)
 291{
 292        const struct acpi_buffer input = { strlen(item), (char *)item };
 293        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 294        acpi_status status;
 295        int ret;
 296
 297        status = wmi_evaluate_method(LENOVO_GET_BIOS_SELECTIONS_GUID,
 298                                     0, 0, &input, &output);
 299
 300        if (ACPI_FAILURE(status)) {
 301                kfree(output.pointer);
 302                return -EIO;
 303        }
 304
 305        ret = tlmi_extract_output_string(&output, value);
 306        kfree(output.pointer);
 307        return ret;
 308}
 309
 310/* ---- Authentication sysfs --------------------------------------------------------- */
 311static ssize_t is_enabled_show(struct kobject *kobj, struct kobj_attribute *attr,
 312                                          char *buf)
 313{
 314        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 315
 316        return sysfs_emit(buf, "%d\n", setting->valid);
 317}
 318
 319static struct kobj_attribute auth_is_pass_set = __ATTR_RO(is_enabled);
 320
 321static ssize_t current_password_store(struct kobject *kobj,
 322                                      struct kobj_attribute *attr,
 323                                      const char *buf, size_t count)
 324{
 325        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 326        size_t pwdlen;
 327        char *p;
 328
 329        pwdlen = strlen(buf);
 330        /* pwdlen == 0 is allowed to clear the password */
 331        if (pwdlen && ((pwdlen < setting->minlen) || (pwdlen > setting->maxlen)))
 332                return -EINVAL;
 333
 334        strscpy(setting->password, buf, setting->maxlen);
 335        /* Strip out CR if one is present, setting password won't work if it is present */
 336        p = strchrnul(setting->password, '\n');
 337        *p = '\0';
 338        return count;
 339}
 340
 341static struct kobj_attribute auth_current_password = __ATTR_WO(current_password);
 342
 343static ssize_t new_password_store(struct kobject *kobj,
 344                                  struct kobj_attribute *attr,
 345                                  const char *buf, size_t count)
 346{
 347        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 348        char *auth_str, *new_pwd, *p;
 349        size_t pwdlen;
 350        int ret;
 351
 352        if (!capable(CAP_SYS_ADMIN))
 353                return -EPERM;
 354
 355        if (!tlmi_priv.can_set_bios_password)
 356                return -EOPNOTSUPP;
 357
 358        new_pwd = kstrdup(buf, GFP_KERNEL);
 359        if (!new_pwd)
 360                return -ENOMEM;
 361
 362        /* Strip out CR if one is present, setting password won't work if it is present */
 363        p = strchrnul(new_pwd, '\n');
 364        *p = '\0';
 365
 366        pwdlen = strlen(new_pwd);
 367        /* pwdlen == 0 is allowed to clear the password */
 368        if (pwdlen && ((pwdlen < setting->minlen) || (pwdlen > setting->maxlen))) {
 369                ret = -EINVAL;
 370                goto out;
 371        }
 372
 373        /* Format: 'PasswordType,CurrentPw,NewPw,Encoding,KbdLang;' */
 374        auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s,%s,%s;",
 375                 setting->pwd_type, setting->password, new_pwd,
 376                 encoding_options[setting->encoding], setting->kbdlang);
 377        if (!auth_str) {
 378                ret = -ENOMEM;
 379                goto out;
 380        }
 381        ret = tlmi_simple_call(LENOVO_SET_BIOS_PASSWORD_GUID, auth_str);
 382        kfree(auth_str);
 383out:
 384        kfree(new_pwd);
 385        return ret ?: count;
 386}
 387
 388static struct kobj_attribute auth_new_password = __ATTR_WO(new_password);
 389
 390static ssize_t min_password_length_show(struct kobject *kobj, struct kobj_attribute *attr,
 391                         char *buf)
 392{
 393        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 394
 395        return sysfs_emit(buf, "%d\n", setting->minlen);
 396}
 397
 398static struct kobj_attribute auth_min_pass_length = __ATTR_RO(min_password_length);
 399
 400static ssize_t max_password_length_show(struct kobject *kobj, struct kobj_attribute *attr,
 401                         char *buf)
 402{
 403        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 404
 405        return sysfs_emit(buf, "%d\n", setting->maxlen);
 406}
 407static struct kobj_attribute auth_max_pass_length = __ATTR_RO(max_password_length);
 408
 409static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
 410                         char *buf)
 411{
 412        return sysfs_emit(buf, "password\n");
 413}
 414static struct kobj_attribute auth_mechanism = __ATTR_RO(mechanism);
 415
 416static ssize_t encoding_show(struct kobject *kobj, struct kobj_attribute *attr,
 417                         char *buf)
 418{
 419        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 420
 421        return sysfs_emit(buf, "%s\n", encoding_options[setting->encoding]);
 422}
 423
 424static ssize_t encoding_store(struct kobject *kobj,
 425                                  struct kobj_attribute *attr,
 426                                  const char *buf, size_t count)
 427{
 428        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 429        int i;
 430
 431        /* Scan for a matching profile */
 432        i = sysfs_match_string(encoding_options, buf);
 433        if (i < 0)
 434                return -EINVAL;
 435
 436        setting->encoding = i;
 437        return count;
 438}
 439
 440static struct kobj_attribute auth_encoding = __ATTR_RW(encoding);
 441
 442static ssize_t kbdlang_show(struct kobject *kobj, struct kobj_attribute *attr,
 443                         char *buf)
 444{
 445        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 446
 447        return sysfs_emit(buf, "%s\n", setting->kbdlang);
 448}
 449
 450static ssize_t kbdlang_store(struct kobject *kobj,
 451                                  struct kobj_attribute *attr,
 452                                  const char *buf, size_t count)
 453{
 454        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 455        int length;
 456
 457        /* Calculate length till '\n' or terminating 0 */
 458        length = strchrnul(buf, '\n') - buf;
 459        if (!length || length >= TLMI_LANG_MAXLEN)
 460                return -EINVAL;
 461
 462        memcpy(setting->kbdlang, buf, length);
 463        setting->kbdlang[length] = '\0';
 464        return count;
 465}
 466
 467static struct kobj_attribute auth_kbdlang = __ATTR_RW(kbdlang);
 468
 469static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr,
 470                         char *buf)
 471{
 472        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 473
 474        return sysfs_emit(buf, "%s\n", setting->role);
 475}
 476static struct kobj_attribute auth_role = __ATTR_RO(role);
 477
 478static struct attribute *auth_attrs[] = {
 479        &auth_is_pass_set.attr,
 480        &auth_min_pass_length.attr,
 481        &auth_max_pass_length.attr,
 482        &auth_current_password.attr,
 483        &auth_new_password.attr,
 484        &auth_role.attr,
 485        &auth_mechanism.attr,
 486        &auth_encoding.attr,
 487        &auth_kbdlang.attr,
 488        NULL
 489};
 490
 491static const struct attribute_group auth_attr_group = {
 492        .attrs = auth_attrs,
 493};
 494
 495/* ---- Attributes sysfs --------------------------------------------------------- */
 496static ssize_t display_name_show(struct kobject *kobj, struct kobj_attribute *attr,
 497                char *buf)
 498{
 499        struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
 500
 501        return sysfs_emit(buf, "%s\n", setting->display_name);
 502}
 503
 504static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 505{
 506        struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
 507        char *item, *value;
 508        int ret;
 509
 510        ret = tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID);
 511        if (ret)
 512                return ret;
 513
 514        /* validate and split from `item,value` -> `value` */
 515        value = strpbrk(item, ",");
 516        if (!value || value == item || !strlen(value + 1))
 517                return -EINVAL;
 518
 519        ret = sysfs_emit(buf, "%s\n", value + 1);
 520        kfree(item);
 521        return ret;
 522}
 523
 524static ssize_t possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 525{
 526        struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
 527
 528        if (!tlmi_priv.can_get_bios_selections)
 529                return -EOPNOTSUPP;
 530
 531        return sysfs_emit(buf, "%s\n", setting->possible_values);
 532}
 533
 534static ssize_t current_value_store(struct kobject *kobj,
 535                struct kobj_attribute *attr,
 536                const char *buf, size_t count)
 537{
 538        struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
 539        char *set_str = NULL, *new_setting = NULL;
 540        char *auth_str = NULL;
 541        char *p;
 542        int ret;
 543
 544        if (!tlmi_priv.can_set_bios_settings)
 545                return -EOPNOTSUPP;
 546
 547        new_setting = kstrdup(buf, GFP_KERNEL);
 548        if (!new_setting)
 549                return -ENOMEM;
 550
 551        /* Strip out CR if one is present */
 552        p = strchrnul(new_setting, '\n');
 553        *p = '\0';
 554
 555        if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
 556                auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
 557                                tlmi_priv.pwd_admin->password,
 558                                encoding_options[tlmi_priv.pwd_admin->encoding],
 559                                tlmi_priv.pwd_admin->kbdlang);
 560                if (!auth_str) {
 561                        ret = -ENOMEM;
 562                        goto out;
 563                }
 564        }
 565
 566        if (auth_str)
 567                set_str = kasprintf(GFP_KERNEL, "%s,%s,%s", setting->display_name,
 568                                new_setting, auth_str);
 569        else
 570                set_str = kasprintf(GFP_KERNEL, "%s,%s;", setting->display_name,
 571                                new_setting);
 572        if (!set_str) {
 573                ret = -ENOMEM;
 574                goto out;
 575        }
 576
 577        ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTINGS_GUID, set_str);
 578        if (ret)
 579                goto out;
 580
 581        if (auth_str)
 582                ret = tlmi_save_bios_settings(auth_str);
 583        else
 584                ret = tlmi_save_bios_settings("");
 585
 586        if (!ret && !tlmi_priv.pending_changes) {
 587                tlmi_priv.pending_changes = true;
 588                /* let userland know it may need to check reboot pending again */
 589                kobject_uevent(&tlmi_priv.class_dev->kobj, KOBJ_CHANGE);
 590        }
 591out:
 592        kfree(auth_str);
 593        kfree(set_str);
 594        kfree(new_setting);
 595        return ret ?: count;
 596}
 597
 598static struct kobj_attribute attr_displ_name = __ATTR_RO(display_name);
 599
 600static struct kobj_attribute attr_possible_values = __ATTR_RO(possible_values);
 601
 602static struct kobj_attribute attr_current_val = __ATTR_RW_MODE(current_value, 0600);
 603
 604static struct attribute *tlmi_attrs[] = {
 605        &attr_displ_name.attr,
 606        &attr_current_val.attr,
 607        &attr_possible_values.attr,
 608        NULL
 609};
 610
 611static const struct attribute_group tlmi_attr_group = {
 612        .attrs = tlmi_attrs,
 613};
 614
 615static ssize_t tlmi_attr_show(struct kobject *kobj, struct attribute *attr,
 616                                    char *buf)
 617{
 618        struct kobj_attribute *kattr;
 619
 620        kattr = container_of(attr, struct kobj_attribute, attr);
 621        if (kattr->show)
 622                return kattr->show(kobj, kattr, buf);
 623        return -EIO;
 624}
 625
 626static ssize_t tlmi_attr_store(struct kobject *kobj, struct attribute *attr,
 627                                     const char *buf, size_t count)
 628{
 629        struct kobj_attribute *kattr;
 630
 631        kattr = container_of(attr, struct kobj_attribute, attr);
 632        if (kattr->store)
 633                return kattr->store(kobj, kattr, buf, count);
 634        return -EIO;
 635}
 636
 637static const struct sysfs_ops tlmi_kobj_sysfs_ops = {
 638        .show   = tlmi_attr_show,
 639        .store  = tlmi_attr_store,
 640};
 641
 642static void tlmi_attr_setting_release(struct kobject *kobj)
 643{
 644        struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
 645
 646        kfree(setting->possible_values);
 647        kfree(setting);
 648}
 649
 650static void tlmi_pwd_setting_release(struct kobject *kobj)
 651{
 652        struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 653
 654        kfree(setting);
 655}
 656
 657static struct kobj_type tlmi_attr_setting_ktype = {
 658        .release        = &tlmi_attr_setting_release,
 659        .sysfs_ops      = &tlmi_kobj_sysfs_ops,
 660};
 661
 662static struct kobj_type tlmi_pwd_setting_ktype = {
 663        .release        = &tlmi_pwd_setting_release,
 664        .sysfs_ops      = &tlmi_kobj_sysfs_ops,
 665};
 666
 667static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr,
 668                                   char *buf)
 669{
 670        return sprintf(buf, "%d\n", tlmi_priv.pending_changes);
 671}
 672
 673static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
 674
 675/* ---- Debug interface--------------------------------------------------------- */
 676static ssize_t debug_cmd_store(struct kobject *kobj, struct kobj_attribute *attr,
 677                                const char *buf, size_t count)
 678{
 679        char *set_str = NULL, *new_setting = NULL;
 680        char *auth_str = NULL;
 681        char *p;
 682        int ret;
 683
 684        if (!tlmi_priv.can_debug_cmd)
 685                return -EOPNOTSUPP;
 686
 687        new_setting = kstrdup(buf, GFP_KERNEL);
 688        if (!new_setting)
 689                return -ENOMEM;
 690
 691        /* Strip out CR if one is present */
 692        p = strchrnul(new_setting, '\n');
 693        *p = '\0';
 694
 695        if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
 696                auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
 697                                tlmi_priv.pwd_admin->password,
 698                                encoding_options[tlmi_priv.pwd_admin->encoding],
 699                                tlmi_priv.pwd_admin->kbdlang);
 700                if (!auth_str) {
 701                        ret = -ENOMEM;
 702                        goto out;
 703                }
 704        }
 705
 706        if (auth_str)
 707                set_str = kasprintf(GFP_KERNEL, "%s,%s", new_setting, auth_str);
 708        else
 709                set_str = kasprintf(GFP_KERNEL, "%s;", new_setting);
 710        if (!set_str) {
 711                ret = -ENOMEM;
 712                goto out;
 713        }
 714
 715        ret = tlmi_simple_call(LENOVO_DEBUG_CMD_GUID, set_str);
 716        if (ret)
 717                goto out;
 718
 719        if (!ret && !tlmi_priv.pending_changes) {
 720                tlmi_priv.pending_changes = true;
 721                /* let userland know it may need to check reboot pending again */
 722                kobject_uevent(&tlmi_priv.class_dev->kobj, KOBJ_CHANGE);
 723        }
 724out:
 725        kfree(auth_str);
 726        kfree(set_str);
 727        kfree(new_setting);
 728        return ret ?: count;
 729}
 730
 731static struct kobj_attribute debug_cmd = __ATTR_WO(debug_cmd);
 732
 733/* ---- Initialisation --------------------------------------------------------- */
 734static void tlmi_release_attr(void)
 735{
 736        int i;
 737
 738        /* Attribute structures */
 739        for (i = 0; i < TLMI_SETTINGS_COUNT; i++) {
 740                if (tlmi_priv.setting[i]) {
 741                        sysfs_remove_group(&tlmi_priv.setting[i]->kobj, &tlmi_attr_group);
 742                        kobject_put(&tlmi_priv.setting[i]->kobj);
 743                }
 744        }
 745        sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr);
 746        if (tlmi_priv.can_debug_cmd && debug_support)
 747                sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr);
 748        kset_unregister(tlmi_priv.attribute_kset);
 749
 750        /* Authentication structures */
 751        sysfs_remove_group(&tlmi_priv.pwd_admin->kobj, &auth_attr_group);
 752        kobject_put(&tlmi_priv.pwd_admin->kobj);
 753        sysfs_remove_group(&tlmi_priv.pwd_power->kobj, &auth_attr_group);
 754        kobject_put(&tlmi_priv.pwd_power->kobj);
 755        kset_unregister(tlmi_priv.authentication_kset);
 756}
 757
 758static int tlmi_sysfs_init(void)
 759{
 760        int i, ret;
 761
 762        ret = fw_attributes_class_get(&fw_attr_class);
 763        if (ret)
 764                return ret;
 765
 766        tlmi_priv.class_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0),
 767                        NULL, "%s", "thinklmi");
 768        if (IS_ERR(tlmi_priv.class_dev)) {
 769                ret = PTR_ERR(tlmi_priv.class_dev);
 770                goto fail_class_created;
 771        }
 772
 773        tlmi_priv.attribute_kset = kset_create_and_add("attributes", NULL,
 774                        &tlmi_priv.class_dev->kobj);
 775        if (!tlmi_priv.attribute_kset) {
 776                ret = -ENOMEM;
 777                goto fail_device_created;
 778        }
 779
 780        for (i = 0; i < TLMI_SETTINGS_COUNT; i++) {
 781                /* Check if index is a valid setting - skip if it isn't */
 782                if (!tlmi_priv.setting[i])
 783                        continue;
 784
 785                /* check for duplicate or reserved values */
 786                if (kset_find_obj(tlmi_priv.attribute_kset, tlmi_priv.setting[i]->display_name) ||
 787                    !strcmp(tlmi_priv.setting[i]->display_name, "Reserved")) {
 788                        pr_debug("duplicate or reserved attribute name found - %s\n",
 789                                tlmi_priv.setting[i]->display_name);
 790                        kfree(tlmi_priv.setting[i]->possible_values);
 791                        kfree(tlmi_priv.setting[i]);
 792                        tlmi_priv.setting[i] = NULL;
 793                        continue;
 794                }
 795
 796                /* Build attribute */
 797                tlmi_priv.setting[i]->kobj.kset = tlmi_priv.attribute_kset;
 798                ret = kobject_add(&tlmi_priv.setting[i]->kobj, NULL,
 799                                  "%s", tlmi_priv.setting[i]->display_name);
 800                if (ret)
 801                        goto fail_create_attr;
 802
 803                ret = sysfs_create_group(&tlmi_priv.setting[i]->kobj, &tlmi_attr_group);
 804                if (ret)
 805                        goto fail_create_attr;
 806        }
 807
 808        ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr);
 809        if (ret)
 810                goto fail_create_attr;
 811
 812        if (tlmi_priv.can_debug_cmd && debug_support) {
 813                ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr);
 814                if (ret)
 815                        goto fail_create_attr;
 816        }
 817        /* Create authentication entries */
 818        tlmi_priv.authentication_kset = kset_create_and_add("authentication", NULL,
 819                                                                &tlmi_priv.class_dev->kobj);
 820        if (!tlmi_priv.authentication_kset) {
 821                ret = -ENOMEM;
 822                goto fail_create_attr;
 823        }
 824        tlmi_priv.pwd_admin->kobj.kset = tlmi_priv.authentication_kset;
 825        ret = kobject_add(&tlmi_priv.pwd_admin->kobj, NULL, "%s", "Admin");
 826        if (ret)
 827                goto fail_create_attr;
 828
 829        ret = sysfs_create_group(&tlmi_priv.pwd_admin->kobj, &auth_attr_group);
 830        if (ret)
 831                goto fail_create_attr;
 832
 833        tlmi_priv.pwd_power->kobj.kset = tlmi_priv.authentication_kset;
 834        ret = kobject_add(&tlmi_priv.pwd_power->kobj, NULL, "%s", "System");
 835        if (ret)
 836                goto fail_create_attr;
 837
 838        ret = sysfs_create_group(&tlmi_priv.pwd_power->kobj, &auth_attr_group);
 839        if (ret)
 840                goto fail_create_attr;
 841
 842        return ret;
 843
 844fail_create_attr:
 845        tlmi_release_attr();
 846fail_device_created:
 847        device_destroy(fw_attr_class, MKDEV(0, 0));
 848fail_class_created:
 849        fw_attributes_class_put();
 850        return ret;
 851}
 852
 853/* ---- Base Driver -------------------------------------------------------- */
 854static int tlmi_analyze(void)
 855{
 856        struct tlmi_pwdcfg pwdcfg;
 857        acpi_status status;
 858        int i, ret;
 859
 860        if (wmi_has_guid(LENOVO_SET_BIOS_SETTINGS_GUID) &&
 861            wmi_has_guid(LENOVO_SAVE_BIOS_SETTINGS_GUID))
 862                tlmi_priv.can_set_bios_settings = true;
 863
 864        if (wmi_has_guid(LENOVO_GET_BIOS_SELECTIONS_GUID))
 865                tlmi_priv.can_get_bios_selections = true;
 866
 867        if (wmi_has_guid(LENOVO_SET_BIOS_PASSWORD_GUID))
 868                tlmi_priv.can_set_bios_password = true;
 869
 870        if (wmi_has_guid(LENOVO_BIOS_PASSWORD_SETTINGS_GUID))
 871                tlmi_priv.can_get_password_settings = true;
 872
 873        if (wmi_has_guid(LENOVO_DEBUG_CMD_GUID))
 874                tlmi_priv.can_debug_cmd = true;
 875
 876        /*
 877         * Try to find the number of valid settings of this machine
 878         * and use it to create sysfs attributes.
 879         */
 880        for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) {
 881                struct tlmi_attr_setting *setting;
 882                char *item = NULL;
 883                char *p;
 884
 885                tlmi_priv.setting[i] = NULL;
 886                status = tlmi_setting(i, &item, LENOVO_BIOS_SETTING_GUID);
 887                if (ACPI_FAILURE(status))
 888                        break;
 889                if (!item)
 890                        break;
 891                if (!*item)
 892                        continue;
 893
 894                /* It is not allowed to have '/' for file name. Convert it into '\'. */
 895                strreplace(item, '/', '\\');
 896
 897                /* Remove the value part */
 898                p = strchrnul(item, ',');
 899                *p = '\0';
 900
 901                /* Create a setting entry */
 902                setting = kzalloc(sizeof(*setting), GFP_KERNEL);
 903                if (!setting) {
 904                        ret = -ENOMEM;
 905                        goto fail_clear_attr;
 906                }
 907                setting->index = i;
 908                strscpy(setting->display_name, item, TLMI_SETTINGS_MAXLEN);
 909                /* If BIOS selections supported, load those */
 910                if (tlmi_priv.can_get_bios_selections) {
 911                        ret = tlmi_get_bios_selections(setting->display_name,
 912                                        &setting->possible_values);
 913                        if (ret || !setting->possible_values)
 914                                pr_info("Error retrieving possible values for %d : %s\n",
 915                                                i, setting->display_name);
 916                }
 917                kobject_init(&setting->kobj, &tlmi_attr_setting_ktype);
 918                tlmi_priv.setting[i] = setting;
 919                tlmi_priv.settings_count++;
 920                kfree(item);
 921        }
 922
 923        /* Create password setting structure */
 924        ret = tlmi_get_pwd_settings(&pwdcfg);
 925        if (ret)
 926                goto fail_clear_attr;
 927
 928        tlmi_priv.pwd_admin = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL);
 929        if (!tlmi_priv.pwd_admin) {
 930                ret = -ENOMEM;
 931                goto fail_clear_attr;
 932        }
 933        strscpy(tlmi_priv.pwd_admin->kbdlang, "us", TLMI_LANG_MAXLEN);
 934        tlmi_priv.pwd_admin->encoding = TLMI_ENCODING_ASCII;
 935        tlmi_priv.pwd_admin->pwd_type = "pap";
 936        tlmi_priv.pwd_admin->role = "bios-admin";
 937        tlmi_priv.pwd_admin->minlen = pwdcfg.min_length;
 938        if (WARN_ON(pwdcfg.max_length >= TLMI_PWD_BUFSIZE))
 939                pwdcfg.max_length = TLMI_PWD_BUFSIZE - 1;
 940        tlmi_priv.pwd_admin->maxlen = pwdcfg.max_length;
 941        if (pwdcfg.password_state & TLMI_PAP_PWD)
 942                tlmi_priv.pwd_admin->valid = true;
 943
 944        kobject_init(&tlmi_priv.pwd_admin->kobj, &tlmi_pwd_setting_ktype);
 945
 946        tlmi_priv.pwd_power = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL);
 947        if (!tlmi_priv.pwd_power) {
 948                ret = -ENOMEM;
 949                goto fail_free_pwd_admin;
 950        }
 951        strscpy(tlmi_priv.pwd_power->kbdlang, "us", TLMI_LANG_MAXLEN);
 952        tlmi_priv.pwd_power->encoding = TLMI_ENCODING_ASCII;
 953        tlmi_priv.pwd_power->pwd_type = "pop";
 954        tlmi_priv.pwd_power->role = "power-on";
 955        tlmi_priv.pwd_power->minlen = pwdcfg.min_length;
 956        tlmi_priv.pwd_power->maxlen = pwdcfg.max_length;
 957
 958        if (pwdcfg.password_state & TLMI_POP_PWD)
 959                tlmi_priv.pwd_power->valid = true;
 960
 961        kobject_init(&tlmi_priv.pwd_power->kobj, &tlmi_pwd_setting_ktype);
 962
 963        return 0;
 964
 965fail_free_pwd_admin:
 966        kfree(tlmi_priv.pwd_admin);
 967fail_clear_attr:
 968        for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) {
 969                if (tlmi_priv.setting[i]) {
 970                        kfree(tlmi_priv.setting[i]->possible_values);
 971                        kfree(tlmi_priv.setting[i]);
 972                }
 973        }
 974        return ret;
 975}
 976
 977static void tlmi_remove(struct wmi_device *wdev)
 978{
 979        tlmi_release_attr();
 980        device_destroy(fw_attr_class, MKDEV(0, 0));
 981        fw_attributes_class_put();
 982}
 983
 984static int tlmi_probe(struct wmi_device *wdev, const void *context)
 985{
 986        tlmi_analyze();
 987        return tlmi_sysfs_init();
 988}
 989
 990static const struct wmi_device_id tlmi_id_table[] = {
 991        { .guid_string = LENOVO_BIOS_SETTING_GUID },
 992        { }
 993};
 994MODULE_DEVICE_TABLE(wmi, tlmi_id_table);
 995
 996static struct wmi_driver tlmi_driver = {
 997        .driver = {
 998                .name = "think-lmi",
 999        },
1000        .id_table = tlmi_id_table,
1001        .probe = tlmi_probe,
1002        .remove = tlmi_remove,
1003};
1004
1005MODULE_AUTHOR("Sugumaran L <slacshiminar@lenovo.com>");
1006MODULE_AUTHOR("Mark Pearson <markpearson@lenovo.com>");
1007MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>");
1008MODULE_DESCRIPTION("ThinkLMI Driver");
1009MODULE_LICENSE("GPL");
1010
1011module_wmi_driver(tlmi_driver);
1012