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"
36 #include "sd-messages.h"
38 Button* button_new(Manager *m, const char *name) {
48 b->name = strdup(name);
54 if (hashmap_put(m->buttons, b->name, b) < 0) {
66 void button_free(Button *b) {
69 hashmap_remove(b->manager->buttons, b->name);
72 hashmap_remove(b->manager->button_fds, INT_TO_PTR(b->fd + 1));
73 assert_se(epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_DEL, b->fd, NULL) == 0);
74 close_nointr_nofail(b->fd);
82 int button_set_seat(Button *b, const char *sn) {
98 int button_open(Button *b) {
100 struct epoll_event ev;
106 close_nointr_nofail(b->fd);
110 p = strappend("/dev/input/", b->name);
114 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
117 log_warning("Failed to open %s: %m", b->name);
121 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
122 log_error("Failed to get input name: %m");
129 ev.data.u32 = FD_OTHER_BASE + b->fd;
131 if (epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_ADD, b->fd, &ev) < 0) {
132 log_error("Failed to add to epoll: %m");
137 r = hashmap_put(b->manager->button_fds, INT_TO_PTR(b->fd + 1), b);
139 log_error("Failed to add to hash map: %s", strerror(-r));
140 assert_se(epoll_ctl(b->manager->epoll_fd, EPOLL_CTL_DEL, b->fd, NULL) == 0);
144 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
149 close_nointr_nofail(b->fd);
154 static int button_handle(
156 InhibitWhat inhibit_key,
158 bool ignore_inhibited,
165 r = manager_handle_action(b->manager, inhibit_key, handle, ignore_inhibited, is_edge);
167 /* We are executing the operation, so make sure we don't
168 * execute another one until the lid is opened/closed again */
169 b->lid_close_queued = false;
174 int button_process(Button *b) {
175 struct input_event ev;
180 l = read(b->fd, &ev, sizeof(ev));
182 return errno != EAGAIN ? -errno : 0;
183 if ((size_t) l < sizeof(ev))
186 if (ev.type == EV_KEY && ev.value > 0) {
193 "MESSAGE=Power key pressed.",
194 MESSAGE_ID(SD_MESSAGE_POWER_KEY),
196 return button_handle(b, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
198 /* The kernel is a bit confused here:
200 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
201 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
206 "MESSAGE=Suspend key pressed.",
207 MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
209 return button_handle(b, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
213 "MESSAGE=Hibernate key pressed.",
214 MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
216 return button_handle(b, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
219 } else if (ev.type == EV_SW && ev.value > 0) {
225 "MESSAGE=Lid closed.",
226 MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
228 b->lid_close_queued = true;
230 return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true);
233 } else if (ev.type == EV_SW && ev.value == 0) {
239 "MESSAGE=Lid opened.",
240 MESSAGE_ID(SD_MESSAGE_LID_OPENED),
242 b->lid_close_queued = false;
250 int button_recheck(Button *b) {
253 if (!b->lid_close_queued)
256 return button_handle(b, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false);