Version:  2.0.40 2.2.26 2.4.37 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10

Linux/drivers/acpi/button.c

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us