root/drivers/acpi/button.c

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

DEFINITIONS

This source file includes following definitions.
  1. acpi_lid_evaluate_state
  2. acpi_lid_notify_state
  3. acpi_button_state_seq_show
  4. acpi_button_add_fs
  5. acpi_button_remove_fs
  6. acpi_lid_notifier_register
  7. acpi_lid_notifier_unregister
  8. acpi_lid_open
  9. acpi_lid_update_state
  10. acpi_lid_initialize_state
  11. acpi_button_notify
  12. acpi_button_suspend
  13. acpi_button_resume
  14. acpi_lid_input_open
  15. acpi_button_add
  16. acpi_button_remove
  17. param_set_lid_init_state
  18. param_get_lid_init_state
  19. acpi_button_register_driver
  20. acpi_button_unregister_driver

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  button.c - ACPI Button Driver
   4  *
   5  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
   6  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
   7  */
   8 
   9 #define pr_fmt(fmt) "ACPI: button: " fmt
  10 
  11 #include <linux/compiler.h>
  12 #include <linux/kernel.h>
  13 #include <linux/module.h>
  14 #include <linux/init.h>
  15 #include <linux/types.h>
  16 #include <linux/proc_fs.h>
  17 #include <linux/seq_file.h>
  18 #include <linux/input.h>
  19 #include <linux/slab.h>
  20 #include <linux/acpi.h>
  21 #include <linux/dmi.h>
  22 #include <acpi/button.h>
  23 
  24 #define PREFIX "ACPI: "
  25 
  26 #define ACPI_BUTTON_CLASS               "button"
  27 #define ACPI_BUTTON_FILE_INFO           "info"
  28 #define ACPI_BUTTON_FILE_STATE          "state"
  29 #define ACPI_BUTTON_TYPE_UNKNOWN        0x00
  30 #define ACPI_BUTTON_NOTIFY_STATUS       0x80
  31 
  32 #define ACPI_BUTTON_SUBCLASS_POWER      "power"
  33 #define ACPI_BUTTON_HID_POWER           "PNP0C0C"
  34 #define ACPI_BUTTON_DEVICE_NAME_POWER   "Power Button"
  35 #define ACPI_BUTTON_TYPE_POWER          0x01
  36 
  37 #define ACPI_BUTTON_SUBCLASS_SLEEP      "sleep"
  38 #define ACPI_BUTTON_HID_SLEEP           "PNP0C0E"
  39 #define ACPI_BUTTON_DEVICE_NAME_SLEEP   "Sleep Button"
  40 #define ACPI_BUTTON_TYPE_SLEEP          0x03
  41 
  42 #define ACPI_BUTTON_SUBCLASS_LID        "lid"
  43 #define ACPI_BUTTON_HID_LID             "PNP0C0D"
  44 #define ACPI_BUTTON_DEVICE_NAME_LID     "Lid Switch"
  45 #define ACPI_BUTTON_TYPE_LID            0x05
  46 
  47 #define ACPI_BUTTON_LID_INIT_IGNORE     0x00
  48 #define ACPI_BUTTON_LID_INIT_OPEN       0x01
  49 #define ACPI_BUTTON_LID_INIT_METHOD     0x02
  50 
  51 #define _COMPONENT              ACPI_BUTTON_COMPONENT
  52 ACPI_MODULE_NAME("button");
  53 
  54 MODULE_AUTHOR("Paul Diefenbaugh");
  55 MODULE_DESCRIPTION("ACPI Button Driver");
  56 MODULE_LICENSE("GPL");
  57 
  58 static const struct acpi_device_id button_device_ids[] = {
  59         {ACPI_BUTTON_HID_LID,    0},
  60         {ACPI_BUTTON_HID_SLEEP,  0},
  61         {ACPI_BUTTON_HID_SLEEPF, 0},
  62         {ACPI_BUTTON_HID_POWER,  0},
  63         {ACPI_BUTTON_HID_POWERF, 0},
  64         {"", 0},
  65 };
  66 MODULE_DEVICE_TABLE(acpi, button_device_ids);
  67 
  68 /*
  69  * Some devices which don't even have a lid in anyway have a broken _LID
  70  * method (e.g. pointing to a floating gpio pin) causing spurious LID events.
  71  */
  72 static const struct dmi_system_id lid_blacklst[] = {
  73         {
  74                 /* GP-electronic T701 */
  75                 .matches = {
  76                         DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
  77                         DMI_MATCH(DMI_PRODUCT_NAME, "T701"),
  78                         DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"),
  79                 },
  80         },
  81         {
  82                 /*
  83                  * Medion Akoya E2215T, notification of the LID device only
  84                  * happens on close, not on open and _LID always returns closed.
  85                  */
  86                 .matches = {
  87                         DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
  88                         DMI_MATCH(DMI_PRODUCT_NAME, "E2215T MD60198"),
  89                 },
  90                 .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
  91         },
  92         {
  93                 /*
  94                  * Razer Blade Stealth 13 late 2019, notification of the LID device
  95                  * only happens on close, not on open and _LID always returns closed.
  96                  */
  97                 .matches = {
  98                         DMI_MATCH(DMI_SYS_VENDOR, "Razer"),
  99                         DMI_MATCH(DMI_PRODUCT_NAME, "Razer Blade Stealth 13 Late 2019"),
 100                 },
 101                 .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
 102         },
 103         {}
 104 };
 105 
 106 static int acpi_button_add(struct acpi_device *device);
 107 static int acpi_button_remove(struct acpi_device *device);
 108 static void acpi_button_notify(struct acpi_device *device, u32 event);
 109 
 110 #ifdef CONFIG_PM_SLEEP
 111 static int acpi_button_suspend(struct device *dev);
 112 static int acpi_button_resume(struct device *dev);
 113 #else
 114 #define acpi_button_suspend NULL
 115 #define acpi_button_resume NULL
 116 #endif
 117 static SIMPLE_DEV_PM_OPS(acpi_button_pm, acpi_button_suspend, acpi_button_resume);
 118 
 119 static struct acpi_driver acpi_button_driver = {
 120         .name = "button",
 121         .class = ACPI_BUTTON_CLASS,
 122         .ids = button_device_ids,
 123         .ops = {
 124                 .add = acpi_button_add,
 125                 .remove = acpi_button_remove,
 126                 .notify = acpi_button_notify,
 127         },
 128         .drv.pm = &acpi_button_pm,
 129 };
 130 
 131 struct acpi_button {
 132         unsigned int type;
 133         struct input_dev *input;
 134         char phys[32];                  /* for input device */
 135         unsigned long pushed;
 136         int last_state;
 137         ktime_t last_time;
 138         bool suspended;
 139 };
 140 
 141 static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
 142 static struct acpi_device *lid_device;
 143 static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
 144 
 145 static unsigned long lid_report_interval __read_mostly = 500;
 146 module_param(lid_report_interval, ulong, 0644);
 147 MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events");
 148 
 149 /* --------------------------------------------------------------------------
 150                               FS Interface (/proc)
 151    -------------------------------------------------------------------------- */
 152 
 153 static struct proc_dir_entry *acpi_button_dir;
 154 static struct proc_dir_entry *acpi_lid_dir;
 155 
 156 static int acpi_lid_evaluate_state(struct acpi_device *device)
 157 {
 158         unsigned long long lid_state;
 159         acpi_status status;
 160 
 161         status = acpi_evaluate_integer(device->handle, "_LID", NULL, &lid_state);
 162         if (ACPI_FAILURE(status))
 163                 return -ENODEV;
 164 
 165         return lid_state ? 1 : 0;
 166 }
 167 
 168 static int acpi_lid_notify_state(struct acpi_device *device, int state)
 169 {
 170         struct acpi_button *button = acpi_driver_data(device);
 171         int ret;
 172         ktime_t next_report;
 173         bool do_update;
 174 
 175         /*
 176          * In lid_init_state=ignore mode, if user opens/closes lid
 177          * frequently with "open" missing, and "last_time" is also updated
 178          * frequently, "close" cannot be delivered to the userspace.
 179          * So "last_time" is only updated after a timeout or an actual
 180          * switch.
 181          */
 182         if (lid_init_state != ACPI_BUTTON_LID_INIT_IGNORE ||
 183             button->last_state != !!state)
 184                 do_update = true;
 185         else
 186                 do_update = false;
 187 
 188         next_report = ktime_add(button->last_time,
 189                                 ms_to_ktime(lid_report_interval));
 190         if (button->last_state == !!state &&
 191             ktime_after(ktime_get(), next_report)) {
 192                 /* Complain the buggy firmware */
 193                 pr_warn_once("The lid device is not compliant to SW_LID.\n");
 194 
 195                 /*
 196                  * Send the unreliable complement switch event:
 197                  *
 198                  * On most platforms, the lid device is reliable. However
 199                  * there are exceptions:
 200                  * 1. Platforms returning initial lid state as "close" by
 201                  *    default after booting/resuming:
 202                  *     https://bugzilla.kernel.org/show_bug.cgi?id=89211
 203                  *     https://bugzilla.kernel.org/show_bug.cgi?id=106151
 204                  * 2. Platforms never reporting "open" events:
 205                  *     https://bugzilla.kernel.org/show_bug.cgi?id=106941
 206                  * On these buggy platforms, the usage model of the ACPI
 207                  * lid device actually is:
 208                  * 1. The initial returning value of _LID may not be
 209                  *    reliable.
 210                  * 2. The open event may not be reliable.
 211                  * 3. The close event is reliable.
 212                  *
 213                  * But SW_LID is typed as input switch event, the input
 214                  * layer checks if the event is redundant. Hence if the
 215                  * state is not switched, the userspace cannot see this
 216                  * platform triggered reliable event. By inserting a
 217                  * complement switch event, it then is guaranteed that the
 218                  * platform triggered reliable one can always be seen by
 219                  * the userspace.
 220                  */
 221                 if (lid_init_state == ACPI_BUTTON_LID_INIT_IGNORE) {
 222                         do_update = true;
 223                         /*
 224                          * Do generate complement switch event for "close"
 225                          * as "close" is reliable and wrong "open" won't
 226                          * trigger unexpected behaviors.
 227                          * Do not generate complement switch event for
 228                          * "open" as "open" is not reliable and wrong
 229                          * "close" will trigger unexpected behaviors.
 230                          */
 231                         if (!state) {
 232                                 input_report_switch(button->input,
 233                                                     SW_LID, state);
 234                                 input_sync(button->input);
 235                         }
 236                 }
 237         }
 238         /* Send the platform triggered reliable event */
 239         if (do_update) {
 240                 acpi_handle_debug(device->handle, "ACPI LID %s\n",
 241                                   state ? "open" : "closed");
 242                 input_report_switch(button->input, SW_LID, !state);
 243                 input_sync(button->input);
 244                 button->last_state = !!state;
 245                 button->last_time = ktime_get();
 246         }
 247 
 248         ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
 249         if (ret == NOTIFY_DONE)
 250                 ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
 251                                                    device);
 252         if (ret == NOTIFY_DONE || ret == NOTIFY_OK) {
 253                 /*
 254                  * It is also regarded as success if the notifier_chain
 255                  * returns NOTIFY_OK or NOTIFY_DONE.
 256                  */
 257                 ret = 0;
 258         }
 259         return ret;
 260 }
 261 
 262 static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq,
 263                                                      void *offset)
 264 {
 265         struct acpi_device *device = seq->private;
 266         int state;
 267 
 268         state = acpi_lid_evaluate_state(device);
 269         seq_printf(seq, "state:      %s\n",
 270                    state < 0 ? "unsupported" : (state ? "open" : "closed"));
 271         return 0;
 272 }
 273 
 274 static int acpi_button_add_fs(struct acpi_device *device)
 275 {
 276         struct acpi_button *button = acpi_driver_data(device);
 277         struct proc_dir_entry *entry = NULL;
 278         int ret = 0;
 279 
 280         /* procfs I/F for ACPI lid device only */
 281         if (button->type != ACPI_BUTTON_TYPE_LID)
 282                 return 0;
 283 
 284         if (acpi_button_dir || acpi_lid_dir) {
 285                 printk(KERN_ERR PREFIX "More than one Lid device found!\n");
 286                 return -EEXIST;
 287         }
 288 
 289         /* create /proc/acpi/button */
 290         acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
 291         if (!acpi_button_dir)
 292                 return -ENODEV;
 293 
 294         /* create /proc/acpi/button/lid */
 295         acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
 296         if (!acpi_lid_dir) {
 297                 ret = -ENODEV;
 298                 goto remove_button_dir;
 299         }
 300 
 301         /* create /proc/acpi/button/lid/LID/ */
 302         acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_lid_dir);
 303         if (!acpi_device_dir(device)) {
 304                 ret = -ENODEV;
 305                 goto remove_lid_dir;
 306         }
 307 
 308         /* create /proc/acpi/button/lid/LID/state */
 309         entry = proc_create_single_data(ACPI_BUTTON_FILE_STATE, S_IRUGO,
 310                         acpi_device_dir(device), acpi_button_state_seq_show,
 311                         device);
 312         if (!entry) {
 313                 ret = -ENODEV;
 314                 goto remove_dev_dir;
 315         }
 316 
 317 done:
 318         return ret;
 319 
 320 remove_dev_dir:
 321         remove_proc_entry(acpi_device_bid(device),
 322                           acpi_lid_dir);
 323         acpi_device_dir(device) = NULL;
 324 remove_lid_dir:
 325         remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
 326         acpi_lid_dir = NULL;
 327 remove_button_dir:
 328         remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
 329         acpi_button_dir = NULL;
 330         goto done;
 331 }
 332 
 333 static int acpi_button_remove_fs(struct acpi_device *device)
 334 {
 335         struct acpi_button *button = acpi_driver_data(device);
 336 
 337         if (button->type != ACPI_BUTTON_TYPE_LID)
 338                 return 0;
 339 
 340         remove_proc_entry(ACPI_BUTTON_FILE_STATE,
 341                           acpi_device_dir(device));
 342         remove_proc_entry(acpi_device_bid(device),
 343                           acpi_lid_dir);
 344         acpi_device_dir(device) = NULL;
 345         remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
 346         acpi_lid_dir = NULL;
 347         remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
 348         acpi_button_dir = NULL;
 349 
 350         return 0;
 351 }
 352 
 353 /* --------------------------------------------------------------------------
 354                                 Driver Interface
 355    -------------------------------------------------------------------------- */
 356 int acpi_lid_notifier_register(struct notifier_block *nb)
 357 {
 358         return blocking_notifier_chain_register(&acpi_lid_notifier, nb);
 359 }
 360 EXPORT_SYMBOL(acpi_lid_notifier_register);
 361 
 362 int acpi_lid_notifier_unregister(struct notifier_block *nb)
 363 {
 364         return blocking_notifier_chain_unregister(&acpi_lid_notifier, nb);
 365 }
 366 EXPORT_SYMBOL(acpi_lid_notifier_unregister);
 367 
 368 int acpi_lid_open(void)
 369 {
 370         if (!lid_device)
 371                 return -ENODEV;
 372 
 373         return acpi_lid_evaluate_state(lid_device);
 374 }
 375 EXPORT_SYMBOL(acpi_lid_open);
 376 
 377 static int acpi_lid_update_state(struct acpi_device *device,
 378                                  bool signal_wakeup)
 379 {
 380         int state;
 381 
 382         state = acpi_lid_evaluate_state(device);
 383         if (state < 0)
 384                 return state;
 385 
 386         if (state && signal_wakeup)
 387                 acpi_pm_wakeup_event(&device->dev);
 388 
 389         return acpi_lid_notify_state(device, state);
 390 }
 391 
 392 static void acpi_lid_initialize_state(struct acpi_device *device)
 393 {
 394         switch (lid_init_state) {
 395         case ACPI_BUTTON_LID_INIT_OPEN:
 396                 (void)acpi_lid_notify_state(device, 1);
 397                 break;
 398         case ACPI_BUTTON_LID_INIT_METHOD:
 399                 (void)acpi_lid_update_state(device, false);
 400                 break;
 401         case ACPI_BUTTON_LID_INIT_IGNORE:
 402         default:
 403                 break;
 404         }
 405 }
 406 
 407 static void acpi_button_notify(struct acpi_device *device, u32 event)
 408 {
 409         struct acpi_button *button = acpi_driver_data(device);
 410         struct input_dev *input;
 411         int users;
 412 
 413         switch (event) {
 414         case ACPI_FIXED_HARDWARE_EVENT:
 415                 event = ACPI_BUTTON_NOTIFY_STATUS;
 416                 /* fall through */
 417         case ACPI_BUTTON_NOTIFY_STATUS:
 418                 input = button->input;
 419                 if (button->type == ACPI_BUTTON_TYPE_LID) {
 420                         mutex_lock(&button->input->mutex);
 421                         users = button->input->users;
 422                         mutex_unlock(&button->input->mutex);
 423                         if (users)
 424                                 acpi_lid_update_state(device, true);
 425                 } else {
 426                         int keycode;
 427 
 428                         acpi_pm_wakeup_event(&device->dev);
 429                         if (button->suspended)
 430                                 break;
 431 
 432                         keycode = test_bit(KEY_SLEEP, input->keybit) ?
 433                                                 KEY_SLEEP : KEY_POWER;
 434                         input_report_key(input, keycode, 1);
 435                         input_sync(input);
 436                         input_report_key(input, keycode, 0);
 437                         input_sync(input);
 438 
 439                         acpi_bus_generate_netlink_event(
 440                                         device->pnp.device_class,
 441                                         dev_name(&device->dev),
 442                                         event, ++button->pushed);
 443                 }
 444                 break;
 445         default:
 446                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 447                                   "Unsupported event [0x%x]\n", event));
 448                 break;
 449         }
 450 }
 451 
 452 #ifdef CONFIG_PM_SLEEP
 453 static int acpi_button_suspend(struct device *dev)
 454 {
 455         struct acpi_device *device = to_acpi_device(dev);
 456         struct acpi_button *button = acpi_driver_data(device);
 457 
 458         button->suspended = true;
 459         return 0;
 460 }
 461 
 462 static int acpi_button_resume(struct device *dev)
 463 {
 464         struct acpi_device *device = to_acpi_device(dev);
 465         struct acpi_button *button = acpi_driver_data(device);
 466 
 467         button->suspended = false;
 468         if (button->type == ACPI_BUTTON_TYPE_LID && button->input->users) {
 469                 button->last_state = !!acpi_lid_evaluate_state(device);
 470                 button->last_time = ktime_get();
 471                 acpi_lid_initialize_state(device);
 472         }
 473         return 0;
 474 }
 475 #endif
 476 
 477 static int acpi_lid_input_open(struct input_dev *input)
 478 {
 479         struct acpi_device *device = input_get_drvdata(input);
 480         struct acpi_button *button = acpi_driver_data(device);
 481 
 482         button->last_state = !!acpi_lid_evaluate_state(device);
 483         button->last_time = ktime_get();
 484         acpi_lid_initialize_state(device);
 485 
 486         return 0;
 487 }
 488 
 489 static int acpi_button_add(struct acpi_device *device)
 490 {
 491         struct acpi_button *button;
 492         struct input_dev *input;
 493         const char *hid = acpi_device_hid(device);
 494         char *name, *class;
 495         int error;
 496 
 497         if (!strcmp(hid, ACPI_BUTTON_HID_LID) && dmi_check_system(lid_blacklst))
 498                 return -ENODEV;
 499 
 500         button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
 501         if (!button)
 502                 return -ENOMEM;
 503 
 504         device->driver_data = button;
 505 
 506         button->input = input = input_allocate_device();
 507         if (!input) {
 508                 error = -ENOMEM;
 509                 goto err_free_button;
 510         }
 511 
 512         name = acpi_device_name(device);
 513         class = acpi_device_class(device);
 514 
 515         if (!strcmp(hid, ACPI_BUTTON_HID_POWER) ||
 516             !strcmp(hid, ACPI_BUTTON_HID_POWERF)) {
 517                 button->type = ACPI_BUTTON_TYPE_POWER;
 518                 strcpy(name, ACPI_BUTTON_DEVICE_NAME_POWER);
 519                 sprintf(class, "%s/%s",
 520                         ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
 521         } else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEP) ||
 522                    !strcmp(hid, ACPI_BUTTON_HID_SLEEPF)) {
 523                 button->type = ACPI_BUTTON_TYPE_SLEEP;
 524                 strcpy(name, ACPI_BUTTON_DEVICE_NAME_SLEEP);
 525                 sprintf(class, "%s/%s",
 526                         ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
 527         } else if (!strcmp(hid, ACPI_BUTTON_HID_LID)) {
 528                 button->type = ACPI_BUTTON_TYPE_LID;
 529                 strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID);
 530                 sprintf(class, "%s/%s",
 531                         ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
 532                 input->open = acpi_lid_input_open;
 533         } else {
 534                 printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid);
 535                 error = -ENODEV;
 536                 goto err_free_input;
 537         }
 538 
 539         error = acpi_button_add_fs(device);
 540         if (error)
 541                 goto err_free_input;
 542 
 543         snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
 544 
 545         input->name = name;
 546         input->phys = button->phys;
 547         input->id.bustype = BUS_HOST;
 548         input->id.product = button->type;
 549         input->dev.parent = &device->dev;
 550 
 551         switch (button->type) {
 552         case ACPI_BUTTON_TYPE_POWER:
 553                 input_set_capability(input, EV_KEY, KEY_POWER);
 554                 break;
 555 
 556         case ACPI_BUTTON_TYPE_SLEEP:
 557                 input_set_capability(input, EV_KEY, KEY_SLEEP);
 558                 break;
 559 
 560         case ACPI_BUTTON_TYPE_LID:
 561                 input_set_capability(input, EV_SW, SW_LID);
 562                 break;
 563         }
 564 
 565         input_set_drvdata(input, device);
 566         error = input_register_device(input);
 567         if (error)
 568                 goto err_remove_fs;
 569         if (button->type == ACPI_BUTTON_TYPE_LID) {
 570                 /*
 571                  * This assumes there's only one lid device, or if there are
 572                  * more we only care about the last one...
 573                  */
 574                 lid_device = device;
 575         }
 576 
 577         device_init_wakeup(&device->dev, true);
 578         printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
 579         return 0;
 580 
 581  err_remove_fs:
 582         acpi_button_remove_fs(device);
 583  err_free_input:
 584         input_free_device(input);
 585  err_free_button:
 586         kfree(button);
 587         return error;
 588 }
 589 
 590 static int acpi_button_remove(struct acpi_device *device)
 591 {
 592         struct acpi_button *button = acpi_driver_data(device);
 593 
 594         acpi_button_remove_fs(device);
 595         input_unregister_device(button->input);
 596         kfree(button);
 597         return 0;
 598 }
 599 
 600 static int param_set_lid_init_state(const char *val,
 601                                     const struct kernel_param *kp)
 602 {
 603         int result = 0;
 604 
 605         if (!strncmp(val, "open", sizeof("open") - 1)) {
 606                 lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
 607                 pr_info("Notify initial lid state as open\n");
 608         } else if (!strncmp(val, "method", sizeof("method") - 1)) {
 609                 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
 610                 pr_info("Notify initial lid state with _LID return value\n");
 611         } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) {
 612                 lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;
 613                 pr_info("Do not notify initial lid state\n");
 614         } else
 615                 result = -EINVAL;
 616         return result;
 617 }
 618 
 619 static int param_get_lid_init_state(char *buffer,
 620                                     const struct kernel_param *kp)
 621 {
 622         switch (lid_init_state) {
 623         case ACPI_BUTTON_LID_INIT_OPEN:
 624                 return sprintf(buffer, "open");
 625         case ACPI_BUTTON_LID_INIT_METHOD:
 626                 return sprintf(buffer, "method");
 627         case ACPI_BUTTON_LID_INIT_IGNORE:
 628                 return sprintf(buffer, "ignore");
 629         default:
 630                 return sprintf(buffer, "invalid");
 631         }
 632         return 0;
 633 }
 634 
 635 module_param_call(lid_init_state,
 636                   param_set_lid_init_state, param_get_lid_init_state,
 637                   NULL, 0644);
 638 MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state");
 639 
 640 static int acpi_button_register_driver(struct acpi_driver *driver)
 641 {
 642         /*
 643          * Modules such as nouveau.ko and i915.ko have a link time dependency
 644          * on acpi_lid_open(), and would therefore not be loadable on ACPI
 645          * capable kernels booted in non-ACPI mode if the return value of
 646          * acpi_bus_register_driver() is returned from here with ACPI disabled
 647          * when this driver is built as a module.
 648          */
 649         if (acpi_disabled)
 650                 return 0;
 651 
 652         return acpi_bus_register_driver(driver);
 653 }
 654 
 655 static void acpi_button_unregister_driver(struct acpi_driver *driver)
 656 {
 657         if (!acpi_disabled)
 658                 acpi_bus_unregister_driver(driver);
 659 }
 660 
 661 module_driver(acpi_button_driver, acpi_button_register_driver,
 662                acpi_button_unregister_driver);

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