root/drivers/platform/x86/ideapad-laptop.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_method_int
  2. method_gbmd
  3. method_int1
  4. method_vpcr
  5. method_vpcw
  6. read_ec_data
  7. write_ec_cmd
  8. debugfs_status_show
  9. debugfs_cfg_show
  10. ideapad_debugfs_init
  11. ideapad_debugfs_exit
  12. show_ideapad_cam
  13. store_ideapad_cam
  14. show_ideapad_fan
  15. store_ideapad_fan
  16. touchpad_show
  17. touchpad_store
  18. conservation_mode_show
  19. conservation_mode_store
  20. fn_lock_show
  21. fn_lock_store
  22. ideapad_is_visible
  23. ideapad_rfk_set
  24. ideapad_sync_rfk_state
  25. ideapad_register_rfkill
  26. ideapad_unregister_rfkill
  27. ideapad_sysfs_init
  28. ideapad_sysfs_exit
  29. ideapad_input_init
  30. ideapad_input_exit
  31. ideapad_input_report
  32. ideapad_input_novokey
  33. ideapad_check_special_buttons
  34. ideapad_backlight_get_brightness
  35. ideapad_backlight_update_status
  36. ideapad_backlight_init
  37. ideapad_backlight_exit
  38. ideapad_backlight_notify_power
  39. ideapad_backlight_notify_brightness
  40. ideapad_sync_touchpad_state
  41. ideapad_acpi_notify
  42. ideapad_wmi_notify
  43. ideapad_acpi_add
  44. ideapad_acpi_remove
  45. ideapad_acpi_resume

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  ideapad-laptop.c - Lenovo IdeaPad ACPI Extras
   4  *
   5  *  Copyright © 2010 Intel Corporation
   6  *  Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
   7  */
   8 
   9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  10 
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/init.h>
  14 #include <linux/types.h>
  15 #include <linux/acpi.h>
  16 #include <linux/rfkill.h>
  17 #include <linux/platform_device.h>
  18 #include <linux/input.h>
  19 #include <linux/input/sparse-keymap.h>
  20 #include <linux/backlight.h>
  21 #include <linux/fb.h>
  22 #include <linux/debugfs.h>
  23 #include <linux/seq_file.h>
  24 #include <linux/i8042.h>
  25 #include <linux/dmi.h>
  26 #include <linux/device.h>
  27 #include <acpi/video.h>
  28 
  29 #define IDEAPAD_RFKILL_DEV_NUM  (3)
  30 
  31 #define BM_CONSERVATION_BIT (5)
  32 #define HA_FNLOCK_BIT       (10)
  33 
  34 #define CFG_BT_BIT      (16)
  35 #define CFG_3G_BIT      (17)
  36 #define CFG_WIFI_BIT    (18)
  37 #define CFG_CAMERA_BIT  (19)
  38 
  39 #if IS_ENABLED(CONFIG_ACPI_WMI)
  40 static const char *const ideapad_wmi_fnesc_events[] = {
  41         "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6", /* Yoga 3 */
  42         "56322276-8493-4CE8-A783-98C991274F5E", /* Yoga 700 */
  43 };
  44 #endif
  45 
  46 enum {
  47         BMCMD_CONSERVATION_ON = 3,
  48         BMCMD_CONSERVATION_OFF = 5,
  49         HACMD_FNLOCK_ON = 0xe,
  50         HACMD_FNLOCK_OFF = 0xf,
  51 };
  52 
  53 enum {
  54         VPCCMD_R_VPC1 = 0x10,
  55         VPCCMD_R_BL_MAX,
  56         VPCCMD_R_BL,
  57         VPCCMD_W_BL,
  58         VPCCMD_R_WIFI,
  59         VPCCMD_W_WIFI,
  60         VPCCMD_R_BT,
  61         VPCCMD_W_BT,
  62         VPCCMD_R_BL_POWER,
  63         VPCCMD_R_NOVO,
  64         VPCCMD_R_VPC2,
  65         VPCCMD_R_TOUCHPAD,
  66         VPCCMD_W_TOUCHPAD,
  67         VPCCMD_R_CAMERA,
  68         VPCCMD_W_CAMERA,
  69         VPCCMD_R_3G,
  70         VPCCMD_W_3G,
  71         VPCCMD_R_ODD, /* 0x21 */
  72         VPCCMD_W_FAN,
  73         VPCCMD_R_RF,
  74         VPCCMD_W_RF,
  75         VPCCMD_R_FAN = 0x2B,
  76         VPCCMD_R_SPECIAL_BUTTONS = 0x31,
  77         VPCCMD_W_BL_POWER = 0x33,
  78 };
  79 
  80 struct ideapad_rfk_priv {
  81         int dev;
  82         struct ideapad_private *priv;
  83 };
  84 
  85 struct ideapad_private {
  86         struct acpi_device *adev;
  87         struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
  88         struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
  89         struct platform_device *platform_device;
  90         struct input_dev *inputdev;
  91         struct backlight_device *blightdev;
  92         struct dentry *debug;
  93         unsigned long cfg;
  94         bool has_hw_rfkill_switch;
  95         const char *fnesc_guid;
  96 };
  97 
  98 static bool no_bt_rfkill;
  99 module_param(no_bt_rfkill, bool, 0444);
 100 MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
 101 
 102 /*
 103  * ACPI Helpers
 104  */
 105 #define IDEAPAD_EC_TIMEOUT (200) /* in ms */
 106 
 107 static int read_method_int(acpi_handle handle, const char *method, int *val)
 108 {
 109         acpi_status status;
 110         unsigned long long result;
 111 
 112         status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
 113         if (ACPI_FAILURE(status)) {
 114                 *val = -1;
 115                 return -1;
 116         }
 117         *val = result;
 118         return 0;
 119 
 120 }
 121 
 122 static int method_gbmd(acpi_handle handle, unsigned long *ret)
 123 {
 124         int result, val;
 125 
 126         result = read_method_int(handle, "GBMD", &val);
 127         *ret = val;
 128         return result;
 129 }
 130 
 131 static int method_int1(acpi_handle handle, char *method, int cmd)
 132 {
 133         acpi_status status;
 134 
 135         status = acpi_execute_simple_method(handle, method, cmd);
 136         return ACPI_FAILURE(status) ? -1 : 0;
 137 }
 138 
 139 static int method_vpcr(acpi_handle handle, int cmd, int *ret)
 140 {
 141         acpi_status status;
 142         unsigned long long result;
 143         struct acpi_object_list params;
 144         union acpi_object in_obj;
 145 
 146         params.count = 1;
 147         params.pointer = &in_obj;
 148         in_obj.type = ACPI_TYPE_INTEGER;
 149         in_obj.integer.value = cmd;
 150 
 151         status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
 152 
 153         if (ACPI_FAILURE(status)) {
 154                 *ret = -1;
 155                 return -1;
 156         }
 157         *ret = result;
 158         return 0;
 159 
 160 }
 161 
 162 static int method_vpcw(acpi_handle handle, int cmd, int data)
 163 {
 164         struct acpi_object_list params;
 165         union acpi_object in_obj[2];
 166         acpi_status status;
 167 
 168         params.count = 2;
 169         params.pointer = in_obj;
 170         in_obj[0].type = ACPI_TYPE_INTEGER;
 171         in_obj[0].integer.value = cmd;
 172         in_obj[1].type = ACPI_TYPE_INTEGER;
 173         in_obj[1].integer.value = data;
 174 
 175         status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
 176         if (status != AE_OK)
 177                 return -1;
 178         return 0;
 179 }
 180 
 181 static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
 182 {
 183         int val;
 184         unsigned long int end_jiffies;
 185 
 186         if (method_vpcw(handle, 1, cmd))
 187                 return -1;
 188 
 189         for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
 190              time_before(jiffies, end_jiffies);) {
 191                 schedule();
 192                 if (method_vpcr(handle, 1, &val))
 193                         return -1;
 194                 if (val == 0) {
 195                         if (method_vpcr(handle, 0, &val))
 196                                 return -1;
 197                         *data = val;
 198                         return 0;
 199                 }
 200         }
 201         pr_err("timeout in %s\n", __func__);
 202         return -1;
 203 }
 204 
 205 static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
 206 {
 207         int val;
 208         unsigned long int end_jiffies;
 209 
 210         if (method_vpcw(handle, 0, data))
 211                 return -1;
 212         if (method_vpcw(handle, 1, cmd))
 213                 return -1;
 214 
 215         for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
 216              time_before(jiffies, end_jiffies);) {
 217                 schedule();
 218                 if (method_vpcr(handle, 1, &val))
 219                         return -1;
 220                 if (val == 0)
 221                         return 0;
 222         }
 223         pr_err("timeout in %s\n", __func__);
 224         return -1;
 225 }
 226 
 227 /*
 228  * debugfs
 229  */
 230 static int debugfs_status_show(struct seq_file *s, void *data)
 231 {
 232         struct ideapad_private *priv = s->private;
 233         unsigned long value;
 234 
 235         if (!priv)
 236                 return -EINVAL;
 237 
 238         if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
 239                 seq_printf(s, "Backlight max:\t%lu\n", value);
 240         if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
 241                 seq_printf(s, "Backlight now:\t%lu\n", value);
 242         if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
 243                 seq_printf(s, "BL power value:\t%s\n", value ? "On" : "Off");
 244         seq_printf(s, "=====================\n");
 245 
 246         if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
 247                 seq_printf(s, "Radio status:\t%s(%lu)\n",
 248                            value ? "On" : "Off", value);
 249         if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
 250                 seq_printf(s, "Wifi status:\t%s(%lu)\n",
 251                            value ? "On" : "Off", value);
 252         if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
 253                 seq_printf(s, "BT status:\t%s(%lu)\n",
 254                            value ? "On" : "Off", value);
 255         if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
 256                 seq_printf(s, "3G status:\t%s(%lu)\n",
 257                            value ? "On" : "Off", value);
 258         seq_printf(s, "=====================\n");
 259 
 260         if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
 261                 seq_printf(s, "Touchpad status:%s(%lu)\n",
 262                            value ? "On" : "Off", value);
 263         if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
 264                 seq_printf(s, "Camera status:\t%s(%lu)\n",
 265                            value ? "On" : "Off", value);
 266         seq_puts(s, "=====================\n");
 267 
 268         if (!method_gbmd(priv->adev->handle, &value)) {
 269                 seq_printf(s, "Conservation mode:\t%s(%lu)\n",
 270                            test_bit(BM_CONSERVATION_BIT, &value) ? "On" : "Off",
 271                            value);
 272         }
 273 
 274         return 0;
 275 }
 276 DEFINE_SHOW_ATTRIBUTE(debugfs_status);
 277 
 278 static int debugfs_cfg_show(struct seq_file *s, void *data)
 279 {
 280         struct ideapad_private *priv = s->private;
 281 
 282         if (!priv) {
 283                 seq_printf(s, "cfg: N/A\n");
 284         } else {
 285                 seq_printf(s, "cfg: 0x%.8lX\n\nCapability: ",
 286                            priv->cfg);
 287                 if (test_bit(CFG_BT_BIT, &priv->cfg))
 288                         seq_printf(s, "Bluetooth ");
 289                 if (test_bit(CFG_3G_BIT, &priv->cfg))
 290                         seq_printf(s, "3G ");
 291                 if (test_bit(CFG_WIFI_BIT, &priv->cfg))
 292                         seq_printf(s, "Wireless ");
 293                 if (test_bit(CFG_CAMERA_BIT, &priv->cfg))
 294                         seq_printf(s, "Camera ");
 295                 seq_printf(s, "\nGraphic: ");
 296                 switch ((priv->cfg)&0x700) {
 297                 case 0x100:
 298                         seq_printf(s, "Intel");
 299                         break;
 300                 case 0x200:
 301                         seq_printf(s, "ATI");
 302                         break;
 303                 case 0x300:
 304                         seq_printf(s, "Nvidia");
 305                         break;
 306                 case 0x400:
 307                         seq_printf(s, "Intel and ATI");
 308                         break;
 309                 case 0x500:
 310                         seq_printf(s, "Intel and Nvidia");
 311                         break;
 312                 }
 313                 seq_printf(s, "\n");
 314         }
 315         return 0;
 316 }
 317 DEFINE_SHOW_ATTRIBUTE(debugfs_cfg);
 318 
 319 static void ideapad_debugfs_init(struct ideapad_private *priv)
 320 {
 321         struct dentry *dir;
 322 
 323         dir = debugfs_create_dir("ideapad", NULL);
 324         priv->debug = dir;
 325 
 326         debugfs_create_file("cfg", S_IRUGO, dir, priv, &debugfs_cfg_fops);
 327         debugfs_create_file("status", S_IRUGO, dir, priv, &debugfs_status_fops);
 328 }
 329 
 330 static void ideapad_debugfs_exit(struct ideapad_private *priv)
 331 {
 332         debugfs_remove_recursive(priv->debug);
 333         priv->debug = NULL;
 334 }
 335 
 336 /*
 337  * sysfs
 338  */
 339 static ssize_t show_ideapad_cam(struct device *dev,
 340                                 struct device_attribute *attr,
 341                                 char *buf)
 342 {
 343         unsigned long result;
 344         struct ideapad_private *priv = dev_get_drvdata(dev);
 345 
 346         if (read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result))
 347                 return sprintf(buf, "-1\n");
 348         return sprintf(buf, "%lu\n", result);
 349 }
 350 
 351 static ssize_t store_ideapad_cam(struct device *dev,
 352                                  struct device_attribute *attr,
 353                                  const char *buf, size_t count)
 354 {
 355         int ret, state;
 356         struct ideapad_private *priv = dev_get_drvdata(dev);
 357 
 358         if (!count)
 359                 return 0;
 360         if (sscanf(buf, "%i", &state) != 1)
 361                 return -EINVAL;
 362         ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
 363         if (ret < 0)
 364                 return -EIO;
 365         return count;
 366 }
 367 
 368 static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
 369 
 370 static ssize_t show_ideapad_fan(struct device *dev,
 371                                 struct device_attribute *attr,
 372                                 char *buf)
 373 {
 374         unsigned long result;
 375         struct ideapad_private *priv = dev_get_drvdata(dev);
 376 
 377         if (read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result))
 378                 return sprintf(buf, "-1\n");
 379         return sprintf(buf, "%lu\n", result);
 380 }
 381 
 382 static ssize_t store_ideapad_fan(struct device *dev,
 383                                  struct device_attribute *attr,
 384                                  const char *buf, size_t count)
 385 {
 386         int ret, state;
 387         struct ideapad_private *priv = dev_get_drvdata(dev);
 388 
 389         if (!count)
 390                 return 0;
 391         if (sscanf(buf, "%i", &state) != 1)
 392                 return -EINVAL;
 393         if (state < 0 || state > 4 || state == 3)
 394                 return -EINVAL;
 395         ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
 396         if (ret < 0)
 397                 return -EIO;
 398         return count;
 399 }
 400 
 401 static DEVICE_ATTR(fan_mode, 0644, show_ideapad_fan, store_ideapad_fan);
 402 
 403 static ssize_t touchpad_show(struct device *dev,
 404                              struct device_attribute *attr,
 405                              char *buf)
 406 {
 407         struct ideapad_private *priv = dev_get_drvdata(dev);
 408         unsigned long result;
 409 
 410         if (read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result))
 411                 return sprintf(buf, "-1\n");
 412         return sprintf(buf, "%lu\n", result);
 413 }
 414 
 415 /* Switch to RO for now: It might be revisited in the future */
 416 static ssize_t __maybe_unused touchpad_store(struct device *dev,
 417                                              struct device_attribute *attr,
 418                                              const char *buf, size_t count)
 419 {
 420         struct ideapad_private *priv = dev_get_drvdata(dev);
 421         bool state;
 422         int ret;
 423 
 424         ret = kstrtobool(buf, &state);
 425         if (ret)
 426                 return ret;
 427 
 428         ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
 429         if (ret < 0)
 430                 return -EIO;
 431         return count;
 432 }
 433 
 434 static DEVICE_ATTR_RO(touchpad);
 435 
 436 static ssize_t conservation_mode_show(struct device *dev,
 437                                 struct device_attribute *attr,
 438                                 char *buf)
 439 {
 440         struct ideapad_private *priv = dev_get_drvdata(dev);
 441         unsigned long result;
 442 
 443         if (method_gbmd(priv->adev->handle, &result))
 444                 return sprintf(buf, "-1\n");
 445         return sprintf(buf, "%u\n", test_bit(BM_CONSERVATION_BIT, &result));
 446 }
 447 
 448 static ssize_t conservation_mode_store(struct device *dev,
 449                                  struct device_attribute *attr,
 450                                  const char *buf, size_t count)
 451 {
 452         struct ideapad_private *priv = dev_get_drvdata(dev);
 453         bool state;
 454         int ret;
 455 
 456         ret = kstrtobool(buf, &state);
 457         if (ret)
 458                 return ret;
 459 
 460         ret = method_int1(priv->adev->handle, "SBMC", state ?
 461                                               BMCMD_CONSERVATION_ON :
 462                                               BMCMD_CONSERVATION_OFF);
 463         if (ret < 0)
 464                 return -EIO;
 465         return count;
 466 }
 467 
 468 static DEVICE_ATTR_RW(conservation_mode);
 469 
 470 static ssize_t fn_lock_show(struct device *dev,
 471                             struct device_attribute *attr,
 472                             char *buf)
 473 {
 474         struct ideapad_private *priv = dev_get_drvdata(dev);
 475         unsigned long result;
 476         int hals;
 477         int fail = read_method_int(priv->adev->handle, "HALS", &hals);
 478 
 479         if (fail)
 480                 return sprintf(buf, "-1\n");
 481 
 482         result = hals;
 483         return sprintf(buf, "%u\n", test_bit(HA_FNLOCK_BIT, &result));
 484 }
 485 
 486 static ssize_t fn_lock_store(struct device *dev,
 487                              struct device_attribute *attr,
 488                              const char *buf, size_t count)
 489 {
 490         struct ideapad_private *priv = dev_get_drvdata(dev);
 491         bool state;
 492         int ret;
 493 
 494         ret = kstrtobool(buf, &state);
 495         if (ret)
 496                 return ret;
 497 
 498         ret = method_int1(priv->adev->handle, "SALS", state ?
 499                           HACMD_FNLOCK_ON :
 500                           HACMD_FNLOCK_OFF);
 501         if (ret < 0)
 502                 return -EIO;
 503         return count;
 504 }
 505 
 506 static DEVICE_ATTR_RW(fn_lock);
 507 
 508 
 509 static struct attribute *ideapad_attributes[] = {
 510         &dev_attr_camera_power.attr,
 511         &dev_attr_fan_mode.attr,
 512         &dev_attr_touchpad.attr,
 513         &dev_attr_conservation_mode.attr,
 514         &dev_attr_fn_lock.attr,
 515         NULL
 516 };
 517 
 518 static umode_t ideapad_is_visible(struct kobject *kobj,
 519                                  struct attribute *attr,
 520                                  int idx)
 521 {
 522         struct device *dev = container_of(kobj, struct device, kobj);
 523         struct ideapad_private *priv = dev_get_drvdata(dev);
 524         bool supported;
 525 
 526         if (attr == &dev_attr_camera_power.attr)
 527                 supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg));
 528         else if (attr == &dev_attr_fan_mode.attr) {
 529                 unsigned long value;
 530                 supported = !read_ec_data(priv->adev->handle, VPCCMD_R_FAN,
 531                                           &value);
 532         } else if (attr == &dev_attr_conservation_mode.attr) {
 533                 supported = acpi_has_method(priv->adev->handle, "GBMD") &&
 534                             acpi_has_method(priv->adev->handle, "SBMC");
 535         } else if (attr == &dev_attr_fn_lock.attr) {
 536                 supported = acpi_has_method(priv->adev->handle, "HALS") &&
 537                         acpi_has_method(priv->adev->handle, "SALS");
 538         } else
 539                 supported = true;
 540 
 541         return supported ? attr->mode : 0;
 542 }
 543 
 544 static const struct attribute_group ideapad_attribute_group = {
 545         .is_visible = ideapad_is_visible,
 546         .attrs = ideapad_attributes
 547 };
 548 
 549 /*
 550  * Rfkill
 551  */
 552 struct ideapad_rfk_data {
 553         char *name;
 554         int cfgbit;
 555         int opcode;
 556         int type;
 557 };
 558 
 559 static const struct ideapad_rfk_data ideapad_rfk_data[] = {
 560         { "ideapad_wlan",    CFG_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
 561         { "ideapad_bluetooth", CFG_BT_BIT, VPCCMD_W_BT, RFKILL_TYPE_BLUETOOTH },
 562         { "ideapad_3g",        CFG_3G_BIT, VPCCMD_W_3G, RFKILL_TYPE_WWAN },
 563 };
 564 
 565 static int ideapad_rfk_set(void *data, bool blocked)
 566 {
 567         struct ideapad_rfk_priv *priv = data;
 568         int opcode = ideapad_rfk_data[priv->dev].opcode;
 569 
 570         return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
 571 }
 572 
 573 static const struct rfkill_ops ideapad_rfk_ops = {
 574         .set_block = ideapad_rfk_set,
 575 };
 576 
 577 static void ideapad_sync_rfk_state(struct ideapad_private *priv)
 578 {
 579         unsigned long hw_blocked = 0;
 580         int i;
 581 
 582         if (priv->has_hw_rfkill_switch) {
 583                 if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
 584                         return;
 585                 hw_blocked = !hw_blocked;
 586         }
 587 
 588         for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
 589                 if (priv->rfk[i])
 590                         rfkill_set_hw_state(priv->rfk[i], hw_blocked);
 591 }
 592 
 593 static int ideapad_register_rfkill(struct ideapad_private *priv, int dev)
 594 {
 595         int ret;
 596         unsigned long sw_blocked;
 597 
 598         if (no_bt_rfkill &&
 599             (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) {
 600                 /* Force to enable bluetooth when no_bt_rfkill=1 */
 601                 write_ec_cmd(priv->adev->handle,
 602                              ideapad_rfk_data[dev].opcode, 1);
 603                 return 0;
 604         }
 605         priv->rfk_priv[dev].dev = dev;
 606         priv->rfk_priv[dev].priv = priv;
 607 
 608         priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name,
 609                                       &priv->platform_device->dev,
 610                                       ideapad_rfk_data[dev].type,
 611                                       &ideapad_rfk_ops,
 612                                       &priv->rfk_priv[dev]);
 613         if (!priv->rfk[dev])
 614                 return -ENOMEM;
 615 
 616         if (read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode-1,
 617                          &sw_blocked)) {
 618                 rfkill_init_sw_state(priv->rfk[dev], 0);
 619         } else {
 620                 sw_blocked = !sw_blocked;
 621                 rfkill_init_sw_state(priv->rfk[dev], sw_blocked);
 622         }
 623 
 624         ret = rfkill_register(priv->rfk[dev]);
 625         if (ret) {
 626                 rfkill_destroy(priv->rfk[dev]);
 627                 return ret;
 628         }
 629         return 0;
 630 }
 631 
 632 static void ideapad_unregister_rfkill(struct ideapad_private *priv, int dev)
 633 {
 634         if (!priv->rfk[dev])
 635                 return;
 636 
 637         rfkill_unregister(priv->rfk[dev]);
 638         rfkill_destroy(priv->rfk[dev]);
 639 }
 640 
 641 /*
 642  * Platform device
 643  */
 644 static int ideapad_sysfs_init(struct ideapad_private *priv)
 645 {
 646         return sysfs_create_group(&priv->platform_device->dev.kobj,
 647                                     &ideapad_attribute_group);
 648 }
 649 
 650 static void ideapad_sysfs_exit(struct ideapad_private *priv)
 651 {
 652         sysfs_remove_group(&priv->platform_device->dev.kobj,
 653                            &ideapad_attribute_group);
 654 }
 655 
 656 /*
 657  * input device
 658  */
 659 static const struct key_entry ideapad_keymap[] = {
 660         { KE_KEY, 6,  { KEY_SWITCHVIDEOMODE } },
 661         { KE_KEY, 7,  { KEY_CAMERA } },
 662         { KE_KEY, 8,  { KEY_MICMUTE } },
 663         { KE_KEY, 11, { KEY_F16 } },
 664         { KE_KEY, 13, { KEY_WLAN } },
 665         { KE_KEY, 16, { KEY_PROG1 } },
 666         { KE_KEY, 17, { KEY_PROG2 } },
 667         { KE_KEY, 64, { KEY_PROG3 } },
 668         { KE_KEY, 65, { KEY_PROG4 } },
 669         { KE_KEY, 66, { KEY_TOUCHPAD_OFF } },
 670         { KE_KEY, 67, { KEY_TOUCHPAD_ON } },
 671         { KE_KEY, 128, { KEY_ESC } },
 672 
 673         { KE_END, 0 },
 674 };
 675 
 676 static int ideapad_input_init(struct ideapad_private *priv)
 677 {
 678         struct input_dev *inputdev;
 679         int error;
 680 
 681         inputdev = input_allocate_device();
 682         if (!inputdev)
 683                 return -ENOMEM;
 684 
 685         inputdev->name = "Ideapad extra buttons";
 686         inputdev->phys = "ideapad/input0";
 687         inputdev->id.bustype = BUS_HOST;
 688         inputdev->dev.parent = &priv->platform_device->dev;
 689 
 690         error = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
 691         if (error) {
 692                 pr_err("Unable to setup input device keymap\n");
 693                 goto err_free_dev;
 694         }
 695 
 696         error = input_register_device(inputdev);
 697         if (error) {
 698                 pr_err("Unable to register input device\n");
 699                 goto err_free_dev;
 700         }
 701 
 702         priv->inputdev = inputdev;
 703         return 0;
 704 
 705 err_free_dev:
 706         input_free_device(inputdev);
 707         return error;
 708 }
 709 
 710 static void ideapad_input_exit(struct ideapad_private *priv)
 711 {
 712         input_unregister_device(priv->inputdev);
 713         priv->inputdev = NULL;
 714 }
 715 
 716 static void ideapad_input_report(struct ideapad_private *priv,
 717                                  unsigned long scancode)
 718 {
 719         sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
 720 }
 721 
 722 static void ideapad_input_novokey(struct ideapad_private *priv)
 723 {
 724         unsigned long long_pressed;
 725 
 726         if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
 727                 return;
 728         if (long_pressed)
 729                 ideapad_input_report(priv, 17);
 730         else
 731                 ideapad_input_report(priv, 16);
 732 }
 733 
 734 static void ideapad_check_special_buttons(struct ideapad_private *priv)
 735 {
 736         unsigned long bit, value;
 737 
 738         read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value);
 739 
 740         for (bit = 0; bit < 16; bit++) {
 741                 if (test_bit(bit, &value)) {
 742                         switch (bit) {
 743                         case 0: /* Z580 */
 744                         case 6: /* Z570 */
 745                                 /* Thermal Management button */
 746                                 ideapad_input_report(priv, 65);
 747                                 break;
 748                         case 1:
 749                                 /* OneKey Theater button */
 750                                 ideapad_input_report(priv, 64);
 751                                 break;
 752                         default:
 753                                 pr_info("Unknown special button: %lu\n", bit);
 754                                 break;
 755                         }
 756                 }
 757         }
 758 }
 759 
 760 /*
 761  * backlight
 762  */
 763 static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
 764 {
 765         struct ideapad_private *priv = bl_get_data(blightdev);
 766         unsigned long now;
 767 
 768         if (!priv)
 769                 return -EINVAL;
 770 
 771         if (read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now))
 772                 return -EIO;
 773         return now;
 774 }
 775 
 776 static int ideapad_backlight_update_status(struct backlight_device *blightdev)
 777 {
 778         struct ideapad_private *priv = bl_get_data(blightdev);
 779 
 780         if (!priv)
 781                 return -EINVAL;
 782 
 783         if (write_ec_cmd(priv->adev->handle, VPCCMD_W_BL,
 784                          blightdev->props.brightness))
 785                 return -EIO;
 786         if (write_ec_cmd(priv->adev->handle, VPCCMD_W_BL_POWER,
 787                          blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1))
 788                 return -EIO;
 789 
 790         return 0;
 791 }
 792 
 793 static const struct backlight_ops ideapad_backlight_ops = {
 794         .get_brightness = ideapad_backlight_get_brightness,
 795         .update_status = ideapad_backlight_update_status,
 796 };
 797 
 798 static int ideapad_backlight_init(struct ideapad_private *priv)
 799 {
 800         struct backlight_device *blightdev;
 801         struct backlight_properties props;
 802         unsigned long max, now, power;
 803 
 804         if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &max))
 805                 return -EIO;
 806         if (read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now))
 807                 return -EIO;
 808         if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
 809                 return -EIO;
 810 
 811         memset(&props, 0, sizeof(struct backlight_properties));
 812         props.max_brightness = max;
 813         props.type = BACKLIGHT_PLATFORM;
 814         blightdev = backlight_device_register("ideapad",
 815                                               &priv->platform_device->dev,
 816                                               priv,
 817                                               &ideapad_backlight_ops,
 818                                               &props);
 819         if (IS_ERR(blightdev)) {
 820                 pr_err("Could not register backlight device\n");
 821                 return PTR_ERR(blightdev);
 822         }
 823 
 824         priv->blightdev = blightdev;
 825         blightdev->props.brightness = now;
 826         blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
 827         backlight_update_status(blightdev);
 828 
 829         return 0;
 830 }
 831 
 832 static void ideapad_backlight_exit(struct ideapad_private *priv)
 833 {
 834         backlight_device_unregister(priv->blightdev);
 835         priv->blightdev = NULL;
 836 }
 837 
 838 static void ideapad_backlight_notify_power(struct ideapad_private *priv)
 839 {
 840         unsigned long power;
 841         struct backlight_device *blightdev = priv->blightdev;
 842 
 843         if (!blightdev)
 844                 return;
 845         if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
 846                 return;
 847         blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
 848 }
 849 
 850 static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
 851 {
 852         unsigned long now;
 853 
 854         /* if we control brightness via acpi video driver */
 855         if (priv->blightdev == NULL) {
 856                 read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
 857                 return;
 858         }
 859 
 860         backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
 861 }
 862 
 863 /*
 864  * module init/exit
 865  */
 866 static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
 867 {
 868         unsigned long value;
 869 
 870         /* Without reading from EC touchpad LED doesn't switch state */
 871         if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) {
 872                 /* Some IdeaPads don't really turn off touchpad - they only
 873                  * switch the LED state. We (de)activate KBC AUX port to turn
 874                  * touchpad off and on. We send KEY_TOUCHPAD_OFF and
 875                  * KEY_TOUCHPAD_ON to not to get out of sync with LED */
 876                 unsigned char param;
 877                 i8042_command(&param, value ? I8042_CMD_AUX_ENABLE :
 878                               I8042_CMD_AUX_DISABLE);
 879                 ideapad_input_report(priv, value ? 67 : 66);
 880         }
 881 }
 882 
 883 static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
 884 {
 885         struct ideapad_private *priv = data;
 886         unsigned long vpc1, vpc2, vpc_bit;
 887 
 888         if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
 889                 return;
 890         if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
 891                 return;
 892 
 893         vpc1 = (vpc2 << 8) | vpc1;
 894         for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
 895                 if (test_bit(vpc_bit, &vpc1)) {
 896                         switch (vpc_bit) {
 897                         case 9:
 898                                 ideapad_sync_rfk_state(priv);
 899                                 break;
 900                         case 13:
 901                         case 11:
 902                         case 8:
 903                         case 7:
 904                         case 6:
 905                                 ideapad_input_report(priv, vpc_bit);
 906                                 break;
 907                         case 5:
 908                                 ideapad_sync_touchpad_state(priv);
 909                                 break;
 910                         case 4:
 911                                 ideapad_backlight_notify_brightness(priv);
 912                                 break;
 913                         case 3:
 914                                 ideapad_input_novokey(priv);
 915                                 break;
 916                         case 2:
 917                                 ideapad_backlight_notify_power(priv);
 918                                 break;
 919                         case 0:
 920                                 ideapad_check_special_buttons(priv);
 921                                 break;
 922                         case 1:
 923                                 /* Some IdeaPads report event 1 every ~20
 924                                  * seconds while on battery power; some
 925                                  * report this when changing to/from tablet
 926                                  * mode. Squelch this event.
 927                                  */
 928                                 break;
 929                         default:
 930                                 pr_info("Unknown event: %lu\n", vpc_bit);
 931                         }
 932                 }
 933         }
 934 }
 935 
 936 #if IS_ENABLED(CONFIG_ACPI_WMI)
 937 static void ideapad_wmi_notify(u32 value, void *context)
 938 {
 939         switch (value) {
 940         case 128:
 941                 ideapad_input_report(context, value);
 942                 break;
 943         default:
 944                 pr_info("Unknown WMI event %u\n", value);
 945         }
 946 }
 947 #endif
 948 
 949 /*
 950  * Some ideapads have a hardware rfkill switch, but most do not have one.
 951  * Reading VPCCMD_R_RF always results in 0 on models without a hardware rfkill,
 952  * switch causing ideapad_laptop to wrongly report all radios as hw-blocked.
 953  * There used to be a long list of DMI ids for models without a hw rfkill
 954  * switch here, but that resulted in playing whack a mole.
 955  * More importantly wrongly reporting the wifi radio as hw-blocked, results in
 956  * non working wifi. Whereas not reporting it hw-blocked, when it actually is
 957  * hw-blocked results in an empty SSID list, which is a much more benign
 958  * failure mode.
 959  * So the default now is the much safer option of assuming there is no
 960  * hardware rfkill switch. This default also actually matches most hardware,
 961  * since having a hw rfkill switch is quite rare on modern hardware, so this
 962  * also leads to a much shorter list.
 963  */
 964 static const struct dmi_system_id hw_rfkill_list[] = {
 965         {}
 966 };
 967 
 968 static int ideapad_acpi_add(struct platform_device *pdev)
 969 {
 970         int ret, i;
 971         int cfg;
 972         struct ideapad_private *priv;
 973         struct acpi_device *adev;
 974 
 975         ret = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev);
 976         if (ret)
 977                 return -ENODEV;
 978 
 979         if (read_method_int(adev->handle, "_CFG", &cfg))
 980                 return -ENODEV;
 981 
 982         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 983         if (!priv)
 984                 return -ENOMEM;
 985 
 986         dev_set_drvdata(&pdev->dev, priv);
 987         priv->cfg = cfg;
 988         priv->adev = adev;
 989         priv->platform_device = pdev;
 990         priv->has_hw_rfkill_switch = dmi_check_system(hw_rfkill_list);
 991 
 992         ret = ideapad_sysfs_init(priv);
 993         if (ret)
 994                 return ret;
 995 
 996         ideapad_debugfs_init(priv);
 997 
 998         ret = ideapad_input_init(priv);
 999         if (ret)
1000                 goto input_failed;
1001 
1002         /*
1003          * On some models without a hw-switch (the yoga 2 13 at least)
1004          * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work.
1005          */
1006         if (!priv->has_hw_rfkill_switch)
1007                 write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
1008 
1009         for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1010                 if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
1011                         ideapad_register_rfkill(priv, i);
1012 
1013         ideapad_sync_rfk_state(priv);
1014         ideapad_sync_touchpad_state(priv);
1015 
1016         if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1017                 ret = ideapad_backlight_init(priv);
1018                 if (ret && ret != -ENODEV)
1019                         goto backlight_failed;
1020         }
1021         ret = acpi_install_notify_handler(adev->handle,
1022                 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify, priv);
1023         if (ret)
1024                 goto notification_failed;
1025 
1026 #if IS_ENABLED(CONFIG_ACPI_WMI)
1027         for (i = 0; i < ARRAY_SIZE(ideapad_wmi_fnesc_events); i++) {
1028                 ret = wmi_install_notify_handler(ideapad_wmi_fnesc_events[i],
1029                                                  ideapad_wmi_notify, priv);
1030                 if (ret == AE_OK) {
1031                         priv->fnesc_guid = ideapad_wmi_fnesc_events[i];
1032                         break;
1033                 }
1034         }
1035         if (ret != AE_OK && ret != AE_NOT_EXIST)
1036                 goto notification_failed_wmi;
1037 #endif
1038 
1039         return 0;
1040 #if IS_ENABLED(CONFIG_ACPI_WMI)
1041 notification_failed_wmi:
1042         acpi_remove_notify_handler(priv->adev->handle,
1043                 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify);
1044 #endif
1045 notification_failed:
1046         ideapad_backlight_exit(priv);
1047 backlight_failed:
1048         for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1049                 ideapad_unregister_rfkill(priv, i);
1050         ideapad_input_exit(priv);
1051 input_failed:
1052         ideapad_debugfs_exit(priv);
1053         ideapad_sysfs_exit(priv);
1054         return ret;
1055 }
1056 
1057 static int ideapad_acpi_remove(struct platform_device *pdev)
1058 {
1059         struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
1060         int i;
1061 
1062 #if IS_ENABLED(CONFIG_ACPI_WMI)
1063         if (priv->fnesc_guid)
1064                 wmi_remove_notify_handler(priv->fnesc_guid);
1065 #endif
1066         acpi_remove_notify_handler(priv->adev->handle,
1067                 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify);
1068         ideapad_backlight_exit(priv);
1069         for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1070                 ideapad_unregister_rfkill(priv, i);
1071         ideapad_input_exit(priv);
1072         ideapad_debugfs_exit(priv);
1073         ideapad_sysfs_exit(priv);
1074         dev_set_drvdata(&pdev->dev, NULL);
1075 
1076         return 0;
1077 }
1078 
1079 #ifdef CONFIG_PM_SLEEP
1080 static int ideapad_acpi_resume(struct device *device)
1081 {
1082         struct ideapad_private *priv;
1083 
1084         if (!device)
1085                 return -EINVAL;
1086         priv = dev_get_drvdata(device);
1087 
1088         ideapad_sync_rfk_state(priv);
1089         ideapad_sync_touchpad_state(priv);
1090         return 0;
1091 }
1092 #endif
1093 static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume);
1094 
1095 static const struct acpi_device_id ideapad_device_ids[] = {
1096         { "VPC2004", 0},
1097         { "", 0},
1098 };
1099 MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
1100 
1101 static struct platform_driver ideapad_acpi_driver = {
1102         .probe = ideapad_acpi_add,
1103         .remove = ideapad_acpi_remove,
1104         .driver = {
1105                 .name   = "ideapad_acpi",
1106                 .pm     = &ideapad_pm,
1107                 .acpi_match_table = ACPI_PTR(ideapad_device_ids),
1108         },
1109 };
1110 
1111 module_platform_driver(ideapad_acpi_driver);
1112 
1113 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1114 MODULE_DESCRIPTION("IdeaPad ACPI Extras");
1115 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */