Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <fcntl.h>
5 : : #include <string.h>
6 : : #include <sys/ioctl.h>
7 : : #include <unistd.h>
8 : : #include <linux/input.h>
9 : :
10 : : #include "sd-messages.h"
11 : :
12 : : #include "alloc-util.h"
13 : : #include "fd-util.h"
14 : : #include "logind-button.h"
15 : : #include "missing_input.h"
16 : : #include "string-util.h"
17 : : #include "util.h"
18 : :
19 : : #define CONST_MAX4(a, b, c, d) CONST_MAX(CONST_MAX(a, b), CONST_MAX(c, d))
20 : :
21 : : #define ULONG_BITS (sizeof(unsigned long)*8)
22 : :
23 : 0 : static bool bitset_get(const unsigned long *bits, unsigned i) {
24 : 0 : return (bits[i / ULONG_BITS] >> (i % ULONG_BITS)) & 1UL;
25 : : }
26 : :
27 : 0 : static void bitset_put(unsigned long *bits, unsigned i) {
28 : 0 : bits[i / ULONG_BITS] |= (unsigned long) 1 << (i % ULONG_BITS);
29 : 0 : }
30 : :
31 : 0 : Button* button_new(Manager *m, const char *name) {
32 : : Button *b;
33 : :
34 [ # # ]: 0 : assert(m);
35 [ # # ]: 0 : assert(name);
36 : :
37 : 0 : b = new0(Button, 1);
38 [ # # ]: 0 : if (!b)
39 : 0 : return NULL;
40 : :
41 : 0 : b->name = strdup(name);
42 [ # # ]: 0 : if (!b->name)
43 : 0 : return mfree(b);
44 : :
45 [ # # ]: 0 : if (hashmap_put(m->buttons, b->name, b) < 0) {
46 : 0 : free(b->name);
47 : 0 : return mfree(b);
48 : : }
49 : :
50 : 0 : b->manager = m;
51 : 0 : b->fd = -1;
52 : :
53 : 0 : return b;
54 : : }
55 : :
56 : 0 : void button_free(Button *b) {
57 [ # # ]: 0 : assert(b);
58 : :
59 : 0 : hashmap_remove(b->manager->buttons, b->name);
60 : :
61 : 0 : sd_event_source_unref(b->io_event_source);
62 : 0 : sd_event_source_unref(b->check_event_source);
63 : :
64 [ # # ]: 0 : if (b->fd >= 0)
65 : : /* If the device has been unplugged close() returns
66 : : * ENODEV, let's ignore this, hence we don't use
67 : : * safe_close() */
68 : 0 : (void) close(b->fd);
69 : :
70 : 0 : free(b->name);
71 : 0 : free(b->seat);
72 : 0 : free(b);
73 : 0 : }
74 : :
75 : 0 : int button_set_seat(Button *b, const char *sn) {
76 : : char *s;
77 : :
78 [ # # ]: 0 : assert(b);
79 [ # # ]: 0 : assert(sn);
80 : :
81 : 0 : s = strdup(sn);
82 [ # # ]: 0 : if (!s)
83 : 0 : return -ENOMEM;
84 : :
85 : 0 : free(b->seat);
86 : 0 : b->seat = s;
87 : :
88 : 0 : return 0;
89 : : }
90 : :
91 : 0 : static void button_lid_switch_handle_action(Manager *manager, bool is_edge) {
92 : : HandleAction handle_action;
93 : :
94 [ # # ]: 0 : assert(manager);
95 : :
96 : : /* If we are docked or on external power, handle the lid switch
97 : : * differently */
98 [ # # ]: 0 : if (manager_is_docked_or_external_displays(manager))
99 : 0 : handle_action = manager->handle_lid_switch_docked;
100 [ # # # # ]: 0 : else if (manager->handle_lid_switch_ep != _HANDLE_ACTION_INVALID &&
101 : 0 : manager_is_on_external_power())
102 : 0 : handle_action = manager->handle_lid_switch_ep;
103 : : else
104 : 0 : handle_action = manager->handle_lid_switch;
105 : :
106 : 0 : manager_handle_action(manager, INHIBIT_HANDLE_LID_SWITCH, handle_action, manager->lid_switch_ignore_inhibited, is_edge);
107 : 0 : }
108 : :
109 : 0 : static int button_recheck(sd_event_source *e, void *userdata) {
110 : 0 : Button *b = userdata;
111 : :
112 [ # # ]: 0 : assert(b);
113 [ # # ]: 0 : assert(b->lid_closed);
114 : :
115 : 0 : button_lid_switch_handle_action(b->manager, false);
116 : 0 : return 1;
117 : : }
118 : :
119 : 0 : static int button_install_check_event_source(Button *b) {
120 : : int r;
121 [ # # ]: 0 : assert(b);
122 : :
123 : : /* Install a post handler, so that we keep rechecking as long as the lid is closed. */
124 : :
125 [ # # ]: 0 : if (b->check_event_source)
126 : 0 : return 0;
127 : :
128 : 0 : r = sd_event_add_post(b->manager->event, &b->check_event_source, button_recheck, b);
129 [ # # ]: 0 : if (r < 0)
130 : 0 : return r;
131 : :
132 : 0 : return sd_event_source_set_priority(b->check_event_source, SD_EVENT_PRIORITY_IDLE+1);
133 : : }
134 : :
135 : 0 : static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
136 : 0 : Button *b = userdata;
137 : : struct input_event ev;
138 : : ssize_t l;
139 : :
140 [ # # ]: 0 : assert(s);
141 [ # # ]: 0 : assert(fd == b->fd);
142 [ # # ]: 0 : assert(b);
143 : :
144 : 0 : l = read(b->fd, &ev, sizeof(ev));
145 [ # # ]: 0 : if (l < 0)
146 [ # # ]: 0 : return errno != EAGAIN ? -errno : 0;
147 [ # # ]: 0 : if ((size_t) l < sizeof(ev))
148 : 0 : return -EIO;
149 : :
150 [ # # # # ]: 0 : if (ev.type == EV_KEY && ev.value > 0) {
151 : :
152 [ # # # # ]: 0 : switch (ev.code) {
153 : :
154 : 0 : case KEY_POWER:
155 : : case KEY_POWER2:
156 : 0 : log_struct(LOG_INFO,
157 : : LOG_MESSAGE("Power key pressed."),
158 : : "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_STR);
159 : :
160 : 0 : manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
161 : 0 : break;
162 : :
163 : : /* The kernel is a bit confused here:
164 : :
165 : : KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
166 : : KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
167 : : */
168 : :
169 : 0 : case KEY_SLEEP:
170 : 0 : log_struct(LOG_INFO,
171 : : LOG_MESSAGE("Suspend key pressed."),
172 : : "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_STR);
173 : :
174 : 0 : manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
175 : 0 : break;
176 : :
177 : 0 : case KEY_SUSPEND:
178 : 0 : log_struct(LOG_INFO,
179 : : LOG_MESSAGE("Hibernate key pressed."),
180 : : "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_STR);
181 : :
182 : 0 : manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
183 : 0 : break;
184 : : }
185 : :
186 [ # # # # ]: 0 : } else if (ev.type == EV_SW && ev.value > 0) {
187 : :
188 [ # # ]: 0 : if (ev.code == SW_LID) {
189 : 0 : log_struct(LOG_INFO,
190 : : LOG_MESSAGE("Lid closed."),
191 : : "MESSAGE_ID=" SD_MESSAGE_LID_CLOSED_STR);
192 : :
193 : 0 : b->lid_closed = true;
194 : 0 : button_lid_switch_handle_action(b->manager, true);
195 : 0 : button_install_check_event_source(b);
196 : :
197 [ # # ]: 0 : } else if (ev.code == SW_DOCK) {
198 : 0 : log_struct(LOG_INFO,
199 : : LOG_MESSAGE("System docked."),
200 : : "MESSAGE_ID=" SD_MESSAGE_SYSTEM_DOCKED_STR);
201 : :
202 : 0 : b->docked = true;
203 : : }
204 : :
205 [ # # # # ]: 0 : } else if (ev.type == EV_SW && ev.value == 0) {
206 : :
207 [ # # ]: 0 : if (ev.code == SW_LID) {
208 : 0 : log_struct(LOG_INFO,
209 : : LOG_MESSAGE("Lid opened."),
210 : : "MESSAGE_ID=" SD_MESSAGE_LID_OPENED_STR);
211 : :
212 : 0 : b->lid_closed = false;
213 : 0 : b->check_event_source = sd_event_source_unref(b->check_event_source);
214 : :
215 [ # # ]: 0 : } else if (ev.code == SW_DOCK) {
216 : 0 : log_struct(LOG_INFO,
217 : : LOG_MESSAGE("System undocked."),
218 : : "MESSAGE_ID=" SD_MESSAGE_SYSTEM_UNDOCKED_STR);
219 : :
220 : 0 : b->docked = false;
221 : : }
222 : : }
223 : :
224 : 0 : return 0;
225 : : }
226 : :
227 : 0 : static int button_suitable(int fd) {
228 : : unsigned long types[CONST_MAX(EV_KEY, EV_SW)/ULONG_BITS+1];
229 : :
230 [ # # ]: 0 : assert(fd >= 0);
231 : :
232 [ # # ]: 0 : if (ioctl(fd, EVIOCGBIT(EV_SYN, sizeof types), types) < 0)
233 : 0 : return -errno;
234 : :
235 [ # # ]: 0 : if (bitset_get(types, EV_KEY)) {
236 : : unsigned long keys[CONST_MAX4(KEY_POWER, KEY_POWER2, KEY_SLEEP, KEY_SUSPEND)/ULONG_BITS+1];
237 : :
238 [ # # ]: 0 : if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof keys), keys) < 0)
239 : 0 : return -errno;
240 : :
241 [ # # # # ]: 0 : if (bitset_get(keys, KEY_POWER) ||
242 [ # # ]: 0 : bitset_get(keys, KEY_POWER2) ||
243 [ # # ]: 0 : bitset_get(keys, KEY_SLEEP) ||
244 : 0 : bitset_get(keys, KEY_SUSPEND))
245 : 0 : return true;
246 : : }
247 : :
248 [ # # ]: 0 : if (bitset_get(types, EV_SW)) {
249 : : unsigned long switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1];
250 : :
251 [ # # ]: 0 : if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof switches), switches) < 0)
252 : 0 : return -errno;
253 : :
254 [ # # # # ]: 0 : if (bitset_get(switches, SW_LID) ||
255 : 0 : bitset_get(switches, SW_DOCK))
256 : 0 : return true;
257 : : }
258 : :
259 : 0 : return false;
260 : : }
261 : :
262 : 0 : static int button_set_mask(const char *name, int fd) {
263 : : unsigned long
264 : 0 : types[CONST_MAX(EV_KEY, EV_SW)/ULONG_BITS+1] = {},
265 : 0 : keys[CONST_MAX4(KEY_POWER, KEY_POWER2, KEY_SLEEP, KEY_SUSPEND)/ULONG_BITS+1] = {},
266 : 0 : switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1] = {};
267 : : struct input_mask mask;
268 : :
269 [ # # ]: 0 : assert(name);
270 [ # # ]: 0 : assert(fd >= 0);
271 : :
272 : 0 : bitset_put(types, EV_KEY);
273 : 0 : bitset_put(types, EV_SW);
274 : :
275 : 0 : mask = (struct input_mask) {
276 : : .type = EV_SYN,
277 : : .codes_size = sizeof(types),
278 : 0 : .codes_ptr = PTR_TO_UINT64(types),
279 : : };
280 : :
281 [ # # ]: 0 : if (ioctl(fd, EVIOCSMASK, &mask) < 0)
282 : : /* Log only at debug level if the kernel doesn't do EVIOCSMASK yet */
283 [ # # # # : 0 : return log_full_errno(IN_SET(errno, ENOTTY, EOPNOTSUPP, EINVAL) ? LOG_DEBUG : LOG_WARNING,
# # ]
284 : : errno, "Failed to set EV_SYN event mask on /dev/input/%s: %m", name);
285 : :
286 : 0 : bitset_put(keys, KEY_POWER);
287 : 0 : bitset_put(keys, KEY_POWER2);
288 : 0 : bitset_put(keys, KEY_SLEEP);
289 : 0 : bitset_put(keys, KEY_SUSPEND);
290 : :
291 : 0 : mask = (struct input_mask) {
292 : : .type = EV_KEY,
293 : : .codes_size = sizeof(keys),
294 : 0 : .codes_ptr = PTR_TO_UINT64(keys),
295 : : };
296 : :
297 [ # # ]: 0 : if (ioctl(fd, EVIOCSMASK, &mask) < 0)
298 [ # # ]: 0 : return log_warning_errno(errno, "Failed to set EV_KEY event mask on /dev/input/%s: %m", name);
299 : :
300 : 0 : bitset_put(switches, SW_LID);
301 : 0 : bitset_put(switches, SW_DOCK);
302 : :
303 : 0 : mask = (struct input_mask) {
304 : : .type = EV_SW,
305 : : .codes_size = sizeof(switches),
306 : 0 : .codes_ptr = PTR_TO_UINT64(switches),
307 : : };
308 : :
309 [ # # ]: 0 : if (ioctl(fd, EVIOCSMASK, &mask) < 0)
310 [ # # ]: 0 : return log_warning_errno(errno, "Failed to set EV_SW event mask on /dev/input/%s: %m", name);
311 : :
312 : 0 : return 0;
313 : : }
314 : :
315 : 0 : int button_open(Button *b) {
316 : 0 : _cleanup_close_ int fd = -1;
317 : : const char *p;
318 : : char name[256];
319 : : int r;
320 : :
321 [ # # ]: 0 : assert(b);
322 : :
323 : 0 : b->fd = safe_close(b->fd);
324 : :
325 [ # # # # : 0 : p = strjoina("/dev/input/", b->name);
# # # # #
# # # ]
326 : :
327 : 0 : fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
328 [ # # ]: 0 : if (fd < 0)
329 [ # # ]: 0 : return log_warning_errno(errno, "Failed to open %s: %m", p);
330 : :
331 : 0 : r = button_suitable(fd);
332 [ # # ]: 0 : if (r < 0)
333 [ # # ]: 0 : return log_warning_errno(r, "Failed to determine whether input device %s is relevant to us: %m", p);
334 [ # # ]: 0 : if (r == 0)
335 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL),
336 : : "Device %s does not expose keys or switches relevant to us, ignoring.", p);
337 : :
338 [ # # ]: 0 : if (ioctl(fd, EVIOCGNAME(sizeof name), name) < 0)
339 [ # # ]: 0 : return log_error_errno(errno, "Failed to get input name for %s: %m", p);
340 : :
341 : 0 : (void) button_set_mask(b->name, fd);
342 : :
343 : 0 : b->io_event_source = sd_event_source_unref(b->io_event_source);
344 : 0 : r = sd_event_add_io(b->manager->event, &b->io_event_source, fd, EPOLLIN, button_dispatch, b);
345 [ # # ]: 0 : if (r < 0)
346 [ # # ]: 0 : return log_error_errno(r, "Failed to add button event for %s: %m", p);
347 : :
348 : 0 : b->fd = TAKE_FD(fd);
349 [ # # ]: 0 : log_info("Watching system buttons on %s (%s)", p, name);
350 : 0 : return 0;
351 : : }
352 : :
353 : 0 : int button_check_switches(Button *b) {
354 : 0 : unsigned long switches[CONST_MAX(SW_LID, SW_DOCK)/ULONG_BITS+1] = {};
355 [ # # ]: 0 : assert(b);
356 : :
357 [ # # ]: 0 : if (b->fd < 0)
358 : 0 : return -EINVAL;
359 : :
360 [ # # ]: 0 : if (ioctl(b->fd, EVIOCGSW(sizeof(switches)), switches) < 0)
361 : 0 : return -errno;
362 : :
363 : 0 : b->lid_closed = bitset_get(switches, SW_LID);
364 : 0 : b->docked = bitset_get(switches, SW_DOCK);
365 : :
366 [ # # ]: 0 : if (b->lid_closed)
367 : 0 : button_install_check_event_source(b);
368 : :
369 : 0 : return 0;
370 : : }
|