]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-button.c
update TODO
[thirdparty/systemd.git] / src / login / logind-button.c
CommitLineData
e9d21f24
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
e9d21f24
LP
22#include <string.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <sys/ioctl.h>
26#include <unistd.h>
27#include <linux/input.h>
e9d21f24 28
cc377381 29#include "sd-messages.h"
e9d21f24 30#include "util.h"
cc377381 31#include "logind-button.h"
e9d21f24
LP
32
33Button* button_new(Manager *m, const char *name) {
34 Button *b;
35
36 assert(m);
37 assert(name);
38
39 b = new0(Button, 1);
40 if (!b)
41 return NULL;
42
43 b->name = strdup(name);
44 if (!b->name) {
45 free(b);
46 return NULL;
47 }
48
49 if (hashmap_put(m->buttons, b->name, b) < 0) {
50 free(b->name);
51 free(b);
52 return NULL;
53 }
54
55 b->manager = m;
56 b->fd = -1;
57
58 return b;
59}
60
61void button_free(Button *b) {
62 assert(b);
63
64 hashmap_remove(b->manager->buttons, b->name);
65
ed4ba7e4
LP
66 sd_event_source_unref(b->io_event_source);
67 sd_event_source_unref(b->check_event_source);
c30a0c62 68
cc377381 69 if (b->fd >= 0) {
c30a0c62
LP
70 /* If the device has been unplugged close() returns
71 * ENODEV, let's ignore this, hence we don't use
03e334a1 72 * safe_close() */
c30a0c62 73 close(b->fd);
e9d21f24
LP
74 }
75
76 free(b->name);
77 free(b->seat);
78 free(b);
79}
80
81int button_set_seat(Button *b, const char *sn) {
82 char *s;
83
84 assert(b);
85 assert(sn);
86
87 s = strdup(sn);
88 if (!s)
89 return -ENOMEM;
90
91 free(b->seat);
92 b->seat = s;
93
94 return 0;
95}
96
3c56cab4
BW
97static void button_lid_switch_handle_action(Manager *manager, bool is_edge) {
98 HandleAction handle_action;
99
100 assert(manager);
101
102 /* If we are docked, handle the lid switch differently */
103 if (manager_is_docked_or_multiple_displays(manager))
104 handle_action = manager->handle_lid_switch_docked;
105 else
106 handle_action = manager->handle_lid_switch;
107
108 manager_handle_action(manager, INHIBIT_HANDLE_LID_SWITCH, handle_action, manager->lid_switch_ignore_inhibited, is_edge);
109}
110
ed4ba7e4
LP
111static int button_recheck(sd_event_source *e, void *userdata) {
112 Button *b = userdata;
beaafb2e 113
ed4ba7e4
LP
114 assert(b);
115 assert(b->lid_closed);
116
3c56cab4 117 button_lid_switch_handle_action(b->manager, false);
ed4ba7e4
LP
118 return 1;
119}
e9d21f24 120
ed4ba7e4
LP
121static int button_install_check_event_source(Button *b) {
122 int r;
e9d21f24
LP
123 assert(b);
124
ed4ba7e4 125 /* Install a post handler, so that we keep rechecking as long as the lid is closed. */
6de0e0e5 126
ed4ba7e4
LP
127 if (b->check_event_source)
128 return 0;
129
130 r = sd_event_add_post(b->manager->event, &b->check_event_source, button_recheck, b);
131 if (r < 0)
132 return r;
133
134 return sd_event_source_set_priority(b->check_event_source, SD_EVENT_PRIORITY_IDLE+1);
e9d21f24
LP
135}
136
cc377381
LP
137static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
138 Button *b = userdata;
e9d21f24
LP
139 struct input_event ev;
140 ssize_t l;
141
cc377381
LP
142 assert(s);
143 assert(fd == b->fd);
e9d21f24
LP
144 assert(b);
145
146 l = read(b->fd, &ev, sizeof(ev));
147 if (l < 0)
148 return errno != EAGAIN ? -errno : 0;
149 if ((size_t) l < sizeof(ev))
150 return -EIO;
151
e9d21f24
LP
152 if (ev.type == EV_KEY && ev.value > 0) {
153
154 switch (ev.code) {
155
156 case KEY_POWER:
157 case KEY_POWER2:
c485437f 158 log_struct(LOG_INFO,
e2cc6eca
LP
159 LOG_MESSAGE("Power key pressed."),
160 LOG_MESSAGE_ID(SD_MESSAGE_POWER_KEY),
c485437f 161 NULL);
7b77ed8c 162
ed4ba7e4 163 manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
7b77ed8c 164 break;
e9d21f24 165
8e7fd6ad
LP
166 /* The kernel is a bit confused here:
167
168 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
169 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
170 */
171
e9d21f24 172 case KEY_SLEEP:
c485437f 173 log_struct(LOG_INFO,
e2cc6eca
LP
174 LOG_MESSAGE("Suspend key pressed."),
175 LOG_MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
c485437f 176 NULL);
7b77ed8c 177
ed4ba7e4 178 manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
7b77ed8c 179 break;
e9d21f24 180
8e7fd6ad 181 case KEY_SUSPEND:
c485437f 182 log_struct(LOG_INFO,
e2cc6eca
LP
183 LOG_MESSAGE("Hibernate key pressed."),
184 LOG_MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
c485437f 185 NULL);
7b77ed8c 186
ed4ba7e4 187 manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
7b77ed8c 188 break;
e9d21f24 189 }
8e7fd6ad 190
e9d21f24
LP
191 } else if (ev.type == EV_SW && ev.value > 0) {
192
7b77ed8c 193 if (ev.code == SW_LID) {
c485437f 194 log_struct(LOG_INFO,
e2cc6eca
LP
195 LOG_MESSAGE("Lid closed."),
196 LOG_MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
c485437f 197 NULL);
65b51162 198
ed4ba7e4 199 b->lid_closed = true;
3c56cab4 200 button_lid_switch_handle_action(b->manager, true);
ed4ba7e4 201 button_install_check_event_source(b);
2d62c530
LP
202
203 } else if (ev.code == SW_DOCK) {
204 log_struct(LOG_INFO,
e2cc6eca
LP
205 LOG_MESSAGE("System docked."),
206 LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_DOCKED),
2d62c530
LP
207 NULL);
208
209 b->docked = true;
65b51162
LP
210 }
211
212 } else if (ev.type == EV_SW && ev.value == 0) {
213
7b77ed8c 214 if (ev.code == SW_LID) {
c485437f 215 log_struct(LOG_INFO,
e2cc6eca
LP
216 LOG_MESSAGE("Lid opened."),
217 LOG_MESSAGE_ID(SD_MESSAGE_LID_OPENED),
c485437f 218 NULL);
7b77ed8c 219
ed4ba7e4
LP
220 b->lid_closed = false;
221 b->check_event_source = sd_event_source_unref(b->check_event_source);
2d62c530
LP
222
223 } else if (ev.code == SW_DOCK) {
224 log_struct(LOG_INFO,
e2cc6eca
LP
225 LOG_MESSAGE("System undocked."),
226 LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_UNDOCKED),
2d62c530
LP
227 NULL);
228
229 b->docked = false;
e9d21f24
LP
230 }
231 }
232
233 return 0;
234}
235
cc377381
LP
236int button_open(Button *b) {
237 char *p, name[256];
238 int r;
239
240 assert(b);
241
242 if (b->fd >= 0) {
243 close(b->fd);
244 b->fd = -1;
245 }
246
63c372cb 247 p = strjoina("/dev/input/", b->name);
cc377381
LP
248
249 b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
4a62c710
MS
250 if (b->fd < 0)
251 return log_warning_errno(errno, "Failed to open %s: %m", b->name);
cc377381
LP
252
253 if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
56f64d95 254 log_error_errno(errno, "Failed to get input name: %m");
cc377381
LP
255 r = -errno;
256 goto fail;
257 }
258
ed4ba7e4 259 r = sd_event_add_io(b->manager->event, &b->io_event_source, b->fd, EPOLLIN, button_dispatch, b);
cc377381 260 if (r < 0) {
da927ba9 261 log_error_errno(r, "Failed to add button event: %m");
cc377381
LP
262 goto fail;
263 }
264
265 log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
266
267 return 0;
268
269fail:
270 close(b->fd);
271 b->fd = -1;
272 return r;
273}
274
2d62c530 275int button_check_switches(Button *b) {
ed4ba7e4 276 uint8_t switches[SW_MAX/8+1] = {};
65b51162
LP
277 assert(b);
278
ed4ba7e4
LP
279 if (b->fd < 0)
280 return -EINVAL;
281
282 if (ioctl(b->fd, EVIOCGSW(sizeof(switches)), switches) < 0)
283 return -errno;
65b51162 284
ed4ba7e4 285 b->lid_closed = (switches[SW_LID/8] >> (SW_LID % 8)) & 1;
2d62c530 286 b->docked = (switches[SW_DOCK/8] >> (SW_DOCK % 8)) & 1;
ed4ba7e4 287
2d62c530 288 if (b->lid_closed)
ed4ba7e4 289 button_install_check_event_source(b);
ed4ba7e4
LP
290
291 return 0;
65b51162 292}