LCOV - code coverage report
Current view: top level - drivers/acpi - button.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 52 251 20.7 %
Date: 2022-03-28 13:20:08 Functions: 4 18 22.2 %
Branches: 14 121 11.6 %

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

Generated by: LCOV version 1.14