1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2012 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/ioctl.h>
26 #include <linux/input.h>
28 #include "sd-messages.h"
30 #include "alloc-util.h"
32 #include "logind-button.h"
33 #include "string-util.h"
36 #define CONST_MAX4(a, b, c, d) CONST_MAX(CONST_MAX(a, b), CONST_MAX(c, d))
38 #define ULONG_BITS (sizeof(unsigned long)*8)
40 static bool bitset_get(const unsigned long *bits
, unsigned i
) {
41 return (bits
[i
/ ULONG_BITS
] >> (i
% ULONG_BITS
)) & 1UL;
44 static void bitset_put(unsigned long *bits
, unsigned i
) {
45 bits
[i
/ ULONG_BITS
] |= (unsigned long) 1 << (i
% ULONG_BITS
);
48 Button
* button_new(Manager
*m
, const char *name
) {
58 b
->name
= strdup(name
);
62 if (hashmap_put(m
->buttons
, b
->name
, b
) < 0) {
73 void button_free(Button
*b
) {
76 hashmap_remove(b
->manager
->buttons
, b
->name
);
78 sd_event_source_unref(b
->io_event_source
);
79 sd_event_source_unref(b
->check_event_source
);
82 /* If the device has been unplugged close() returns
83 * ENODEV, let's ignore this, hence we don't use
92 int button_set_seat(Button
*b
, const char *sn
) {
108 static void button_lid_switch_handle_action(Manager
*manager
, bool is_edge
) {
109 HandleAction handle_action
;
113 /* If we are docked, handle the lid switch differently */
114 if (manager_is_docked_or_external_displays(manager
))
115 handle_action
= manager
->handle_lid_switch_docked
;
117 handle_action
= manager
->handle_lid_switch
;
119 manager_handle_action(manager
, INHIBIT_HANDLE_LID_SWITCH
, handle_action
, manager
->lid_switch_ignore_inhibited
, is_edge
);
122 static int button_recheck(sd_event_source
*e
, void *userdata
) {
123 Button
*b
= userdata
;
126 assert(b
->lid_closed
);
128 button_lid_switch_handle_action(b
->manager
, false);
132 static int button_install_check_event_source(Button
*b
) {
136 /* Install a post handler, so that we keep rechecking as long as the lid is closed. */
138 if (b
->check_event_source
)
141 r
= sd_event_add_post(b
->manager
->event
, &b
->check_event_source
, button_recheck
, b
);
145 return sd_event_source_set_priority(b
->check_event_source
, SD_EVENT_PRIORITY_IDLE
+1);
148 static int button_dispatch(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
149 Button
*b
= userdata
;
150 struct input_event ev
;
157 l
= read(b
->fd
, &ev
, sizeof(ev
));
159 return errno
!= EAGAIN
? -errno
: 0;
160 if ((size_t) l
< sizeof(ev
))
163 if (ev
.type
== EV_KEY
&& ev
.value
> 0) {
170 LOG_MESSAGE("Power key pressed."),
171 "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_STR
,
174 manager_handle_action(b
->manager
, INHIBIT_HANDLE_POWER_KEY
, b
->manager
->handle_power_key
, b
->manager
->power_key_ignore_inhibited
, true);
177 /* The kernel is a bit confused here:
179 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
180 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
185 LOG_MESSAGE("Suspend key pressed."),
186 "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_STR
,
189 manager_handle_action(b
->manager
, INHIBIT_HANDLE_SUSPEND_KEY
, b
->manager
->handle_suspend_key
, b
->manager
->suspend_key_ignore_inhibited
, true);
194 LOG_MESSAGE("Hibernate key pressed."),
195 "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_STR
,
198 manager_handle_action(b
->manager
, INHIBIT_HANDLE_HIBERNATE_KEY
, b
->manager
->handle_hibernate_key
, b
->manager
->hibernate_key_ignore_inhibited
, true);
202 } else if (ev
.type
== EV_SW
&& ev
.value
> 0) {
204 if (ev
.code
== SW_LID
) {
206 LOG_MESSAGE("Lid closed."),
207 "MESSAGE_ID=" SD_MESSAGE_LID_CLOSED_STR
,
210 b
->lid_closed
= true;
211 button_lid_switch_handle_action(b
->manager
, true);
212 button_install_check_event_source(b
);
214 } else if (ev
.code
== SW_DOCK
) {
216 LOG_MESSAGE("System docked."),
217 "MESSAGE_ID=" SD_MESSAGE_SYSTEM_DOCKED_STR
,
223 } else if (ev
.type
== EV_SW
&& ev
.value
== 0) {
225 if (ev
.code
== SW_LID
) {
227 LOG_MESSAGE("Lid opened."),
228 "MESSAGE_ID=" SD_MESSAGE_LID_OPENED_STR
,
231 b
->lid_closed
= false;
232 b
->check_event_source
= sd_event_source_unref(b
->check_event_source
);
234 } else if (ev
.code
== SW_DOCK
) {
236 LOG_MESSAGE("System undocked."),
237 "MESSAGE_ID=" SD_MESSAGE_SYSTEM_UNDOCKED_STR
,
247 static int button_suitable(Button
*b
) {
248 unsigned long types
[CONST_MAX(EV_KEY
, EV_SW
)/ULONG_BITS
+1];
253 if (ioctl(b
->fd
, EVIOCGBIT(EV_SYN
, sizeof(types
)), types
) < 0)
256 if (bitset_get(types
, EV_KEY
)) {
257 unsigned long keys
[CONST_MAX4(KEY_POWER
, KEY_POWER2
, KEY_SLEEP
, KEY_SUSPEND
)/ULONG_BITS
+1];
259 if (ioctl(b
->fd
, EVIOCGBIT(EV_KEY
, sizeof(keys
)), keys
) < 0)
262 if (bitset_get(keys
, KEY_POWER
) ||
263 bitset_get(keys
, KEY_POWER2
) ||
264 bitset_get(keys
, KEY_SLEEP
) ||
265 bitset_get(keys
, KEY_SUSPEND
))
269 if (bitset_get(types
, EV_SW
)) {
270 unsigned long switches
[CONST_MAX(SW_LID
, SW_DOCK
)/ULONG_BITS
+1];
272 if (ioctl(b
->fd
, EVIOCGBIT(EV_SW
, sizeof(switches
)), switches
) < 0)
275 if (bitset_get(switches
, SW_LID
) ||
276 bitset_get(switches
, SW_DOCK
))
283 static int button_set_mask(Button
*b
) {
285 types
[CONST_MAX(EV_KEY
, EV_SW
)/ULONG_BITS
+1] = {},
286 keys
[CONST_MAX4(KEY_POWER
, KEY_POWER2
, KEY_SLEEP
, KEY_SUSPEND
)/ULONG_BITS
+1] = {},
287 switches
[CONST_MAX(SW_LID
, SW_DOCK
)/ULONG_BITS
+1] = {};
288 struct input_mask mask
;
293 bitset_put(types
, EV_KEY
);
294 bitset_put(types
, EV_SW
);
296 mask
= (struct input_mask
) {
298 .codes_size
= sizeof(types
),
299 .codes_ptr
= PTR_TO_UINT64(types
),
302 if (ioctl(b
->fd
, EVIOCSMASK
, &mask
) < 0)
303 /* Log only at debug level if the kernel doesn't do EVIOCSMASK yet */
304 return log_full_errno(IN_SET(errno
, ENOTTY
, EOPNOTSUPP
, EINVAL
) ? LOG_DEBUG
: LOG_WARNING
,
305 errno
, "Failed to set EV_SYN event mask on /dev/input/%s: %m", b
->name
);
307 bitset_put(keys
, KEY_POWER
);
308 bitset_put(keys
, KEY_POWER2
);
309 bitset_put(keys
, KEY_SLEEP
);
310 bitset_put(keys
, KEY_SUSPEND
);
312 mask
= (struct input_mask
) {
314 .codes_size
= sizeof(keys
),
315 .codes_ptr
= PTR_TO_UINT64(keys
),
318 if (ioctl(b
->fd
, EVIOCSMASK
, &mask
) < 0)
319 return log_warning_errno(errno
, "Failed to set EV_KEY event mask on /dev/input/%s: %m", b
->name
);
321 bitset_put(switches
, SW_LID
);
322 bitset_put(switches
, SW_DOCK
);
324 mask
= (struct input_mask
) {
326 .codes_size
= sizeof(switches
),
327 .codes_ptr
= PTR_TO_UINT64(switches
),
330 if (ioctl(b
->fd
, EVIOCSMASK
, &mask
) < 0)
331 return log_warning_errno(errno
, "Failed to set EV_SW event mask on /dev/input/%s: %m", b
->name
);
336 int button_open(Button
*b
) {
342 b
->fd
= safe_close(b
->fd
);
344 p
= strjoina("/dev/input/", b
->name
);
346 b
->fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
348 return log_warning_errno(errno
, "Failed to open %s: %m", p
);
350 r
= button_suitable(b
);
352 return log_warning_errno(r
, "Failed to determine whether input device is relevant to us: %m");
354 log_debug("Device %s does not expose keys or switches relevant to us, ignoring.", p
);
355 return -EADDRNOTAVAIL
;
358 if (ioctl(b
->fd
, EVIOCGNAME(sizeof(name
)), name
) < 0) {
359 r
= log_error_errno(errno
, "Failed to get input name: %m");
363 (void) button_set_mask(b
);
365 r
= sd_event_add_io(b
->manager
->event
, &b
->io_event_source
, b
->fd
, EPOLLIN
, button_dispatch
, b
);
367 log_error_errno(r
, "Failed to add button event: %m");
371 log_info("Watching system buttons on /dev/input/%s (%s)", b
->name
, name
);
376 b
->fd
= safe_close(b
->fd
);
380 int button_check_switches(Button
*b
) {
381 unsigned long switches
[CONST_MAX(SW_LID
, SW_DOCK
)/ULONG_BITS
+1] = {};
387 if (ioctl(b
->fd
, EVIOCGSW(sizeof(switches
)), switches
) < 0)
390 b
->lid_closed
= bitset_get(switches
, SW_LID
);
391 b
->docked
= bitset_get(switches
, SW_DOCK
);
394 button_install_check_event_source(b
);