1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <sys/ioctl.h>
28 #include <linux/input.h>
29 #include <sys/epoll.h>
31 #include "conf-parser.h"
33 #include "logind-button.h"
35 #include "dbus-common.h"
37 Button* button_new(Manager *m, const char *name) {
47 b->name = strdup(name);
53 if (hashmap_put(m->buttons, b->name, b) < 0) {
65 void button_free(Button *b) {
68 hashmap_remove(b->manager->buttons, b->name);
71 hashmap_remove(b->manager->button_fds, INT_TO_PTR(b->fd + 1));
72 assert_se(epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_DEL, b->fd, NULL) == 0);
73 close_nointr_nofail(b->fd);
81 int button_set_seat(Button *b, const char *sn) {
97 int button_open(Button *b) {
99 struct epoll_event ev;
105 close_nointr_nofail(b->fd);
109 p = strappend("/dev/input/", b->name);
113 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
116 log_warning("Failed to open %s: %m", b->name);
120 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
121 log_error("Failed to get input name: %m");
128 ev.data.u32 = FD_OTHER_BASE + b->fd;
130 if (epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_ADD, b->fd, &ev) < 0) {
131 log_error("Failed to add to epoll: %m");
136 r = hashmap_put(b->manager->button_fds, INT_TO_PTR(b->fd + 1), b);
138 log_error("Failed to add to hash map: %s", strerror(-r));
139 assert_se(epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_DEL, b->fd, NULL) == 0);
143 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
148 close_nointr_nofail(b->fd);
153 static int button_handle(
155 InhibitWhat inhibit_key,
157 bool ignore_inhibited,
164 r = manager_handle_action(b->manager, inhibit_key, handle, ignore_inhibited, is_edge);
166 /* We are executing the operation, so make sure we don't
167 * execute another one until the lid is opened/closed again */
168 b->lid_close_queued = false;
173 int button_process(Button *b) {
174 struct input_event ev;
179 l = read(b->fd, &ev, sizeof(ev));
181 return errno != EAGAIN ? -errno : 0;
182 if ((size_t) l < sizeof(ev))
185 if (ev.type == EV_KEY && ev.value > 0) {
191 log_info("Power key pressed.");
192 return button_handle(b, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
194 /* The kernel is a bit confused here:
196 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
197 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
201 log_info("Suspend key pressed.");
202 return button_handle(b, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
205 log_info("Hibernate key pressed.");
206 return button_handle(b, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
209 } else if (ev.type == EV_SW && ev.value > 0) {
214 log_info("Lid closed.");
215 b->lid_close_queued = true;
217 return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true);
220 } else if (ev.type == EV_SW && ev.value == 0) {
225 log_info("Lid opened.");
226 b->lid_close_queued = false;
234 int button_recheck(Button *b) {
237 if (!b->lid_close_queued)
240 return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false);