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 or on external power, handle the lid switch
115 if (manager_is_docked_or_external_displays(manager
))
116 handle_action
= manager
->handle_lid_switch_docked
;
117 else if (manager
->handle_lid_switch_ep
!= _HANDLE_ACTION_INVALID
&&
118 manager_is_on_external_power())
119 handle_action
= manager
->handle_lid_switch_ep
;
121 handle_action
= manager
->handle_lid_switch
;
123 manager_handle_action(manager
, INHIBIT_HANDLE_LID_SWITCH
, handle_action
, manager
->lid_switch_ignore_inhibited
, is_edge
);
126 static int button_recheck(sd_event_source
*e
, void *userdata
) {
127 Button
*b
= userdata
;
130 assert(b
->lid_closed
);
132 button_lid_switch_handle_action(b
->manager
, false);
136 static int button_install_check_event_source(Button
*b
) {
140 /* Install a post handler, so that we keep rechecking as long as the lid is closed. */
142 if (b
->check_event_source
)
145 r
= sd_event_add_post(b
->manager
->event
, &b
->check_event_source
, button_recheck
, b
);
149 return sd_event_source_set_priority(b
->check_event_source
, SD_EVENT_PRIORITY_IDLE
+1);
152 static int button_dispatch(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
153 Button
*b
= userdata
;
154 struct input_event ev
;
161 l
= read(b
->fd
, &ev
, sizeof(ev
));
163 return errno
!= EAGAIN
? -errno
: 0;
164 if ((size_t) l
< sizeof(ev
))
167 if (ev
.type
== EV_KEY
&& ev
.value
> 0) {
174 LOG_MESSAGE("Power key pressed."),
175 "MESSAGE_ID=" SD_MESSAGE_POWER_KEY_STR
,
178 manager_handle_action(b
->manager
, INHIBIT_HANDLE_POWER_KEY
, b
->manager
->handle_power_key
, b
->manager
->power_key_ignore_inhibited
, true);
181 /* The kernel is a bit confused here:
183 KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend"
184 KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
189 LOG_MESSAGE("Suspend key pressed."),
190 "MESSAGE_ID=" SD_MESSAGE_SUSPEND_KEY_STR
,
193 manager_handle_action(b
->manager
, INHIBIT_HANDLE_SUSPEND_KEY
, b
->manager
->handle_suspend_key
, b
->manager
->suspend_key_ignore_inhibited
, true);
198 LOG_MESSAGE("Hibernate key pressed."),
199 "MESSAGE_ID=" SD_MESSAGE_HIBERNATE_KEY_STR
,
202 manager_handle_action(b
->manager
, INHIBIT_HANDLE_HIBERNATE_KEY
, b
->manager
->handle_hibernate_key
, b
->manager
->hibernate_key_ignore_inhibited
, true);
206 } else if (ev
.type
== EV_SW
&& ev
.value
> 0) {
208 if (ev
.code
== SW_LID
) {
210 LOG_MESSAGE("Lid closed."),
211 "MESSAGE_ID=" SD_MESSAGE_LID_CLOSED_STR
,
214 b
->lid_closed
= true;
215 button_lid_switch_handle_action(b
->manager
, true);
216 button_install_check_event_source(b
);
218 } else if (ev
.code
== SW_DOCK
) {
220 LOG_MESSAGE("System docked."),
221 "MESSAGE_ID=" SD_MESSAGE_SYSTEM_DOCKED_STR
,
227 } else if (ev
.type
== EV_SW
&& ev
.value
== 0) {
229 if (ev
.code
== SW_LID
) {
231 LOG_MESSAGE("Lid opened."),
232 "MESSAGE_ID=" SD_MESSAGE_LID_OPENED_STR
,
235 b
->lid_closed
= false;
236 b
->check_event_source
= sd_event_source_unref(b
->check_event_source
);
238 } else if (ev
.code
== SW_DOCK
) {
240 LOG_MESSAGE("System undocked."),
241 "MESSAGE_ID=" SD_MESSAGE_SYSTEM_UNDOCKED_STR
,
251 static int button_suitable(Button
*b
) {
252 unsigned long types
[CONST_MAX(EV_KEY
, EV_SW
)/ULONG_BITS
+1];
257 if (ioctl(b
->fd
, EVIOCGBIT(EV_SYN
, sizeof(types
)), types
) < 0)
260 if (bitset_get(types
, EV_KEY
)) {
261 unsigned long keys
[CONST_MAX4(KEY_POWER
, KEY_POWER2
, KEY_SLEEP
, KEY_SUSPEND
)/ULONG_BITS
+1];
263 if (ioctl(b
->fd
, EVIOCGBIT(EV_KEY
, sizeof(keys
)), keys
) < 0)
266 if (bitset_get(keys
, KEY_POWER
) ||
267 bitset_get(keys
, KEY_POWER2
) ||
268 bitset_get(keys
, KEY_SLEEP
) ||
269 bitset_get(keys
, KEY_SUSPEND
))
273 if (bitset_get(types
, EV_SW
)) {
274 unsigned long switches
[CONST_MAX(SW_LID
, SW_DOCK
)/ULONG_BITS
+1];
276 if (ioctl(b
->fd
, EVIOCGBIT(EV_SW
, sizeof(switches
)), switches
) < 0)
279 if (bitset_get(switches
, SW_LID
) ||
280 bitset_get(switches
, SW_DOCK
))
287 static int button_set_mask(Button
*b
) {
289 types
[CONST_MAX(EV_KEY
, EV_SW
)/ULONG_BITS
+1] = {},
290 keys
[CONST_MAX4(KEY_POWER
, KEY_POWER2
, KEY_SLEEP
, KEY_SUSPEND
)/ULONG_BITS
+1] = {},
291 switches
[CONST_MAX(SW_LID
, SW_DOCK
)/ULONG_BITS
+1] = {};
292 struct input_mask mask
;
297 bitset_put(types
, EV_KEY
);
298 bitset_put(types
, EV_SW
);
300 mask
= (struct input_mask
) {
302 .codes_size
= sizeof(types
),
303 .codes_ptr
= PTR_TO_UINT64(types
),
306 if (ioctl(b
->fd
, EVIOCSMASK
, &mask
) < 0)
307 /* Log only at debug level if the kernel doesn't do EVIOCSMASK yet */
308 return log_full_errno(IN_SET(errno
, ENOTTY
, EOPNOTSUPP
, EINVAL
) ? LOG_DEBUG
: LOG_WARNING
,
309 errno
, "Failed to set EV_SYN event mask on /dev/input/%s: %m", b
->name
);
311 bitset_put(keys
, KEY_POWER
);
312 bitset_put(keys
, KEY_POWER2
);
313 bitset_put(keys
, KEY_SLEEP
);
314 bitset_put(keys
, KEY_SUSPEND
);
316 mask
= (struct input_mask
) {
318 .codes_size
= sizeof(keys
),
319 .codes_ptr
= PTR_TO_UINT64(keys
),
322 if (ioctl(b
->fd
, EVIOCSMASK
, &mask
) < 0)
323 return log_warning_errno(errno
, "Failed to set EV_KEY event mask on /dev/input/%s: %m", b
->name
);
325 bitset_put(switches
, SW_LID
);
326 bitset_put(switches
, SW_DOCK
);
328 mask
= (struct input_mask
) {
330 .codes_size
= sizeof(switches
),
331 .codes_ptr
= PTR_TO_UINT64(switches
),
334 if (ioctl(b
->fd
, EVIOCSMASK
, &mask
) < 0)
335 return log_warning_errno(errno
, "Failed to set EV_SW event mask on /dev/input/%s: %m", b
->name
);
340 int button_open(Button
*b
) {
346 b
->fd
= safe_close(b
->fd
);
348 p
= strjoina("/dev/input/", b
->name
);
350 b
->fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
352 return log_warning_errno(errno
, "Failed to open %s: %m", p
);
354 r
= button_suitable(b
);
356 return log_warning_errno(r
, "Failed to determine whether input device is relevant to us: %m");
358 log_debug("Device %s does not expose keys or switches relevant to us, ignoring.", p
);
359 return -EADDRNOTAVAIL
;
362 if (ioctl(b
->fd
, EVIOCGNAME(sizeof(name
)), name
) < 0) {
363 r
= log_error_errno(errno
, "Failed to get input name: %m");
367 (void) button_set_mask(b
);
369 r
= sd_event_add_io(b
->manager
->event
, &b
->io_event_source
, b
->fd
, EPOLLIN
, button_dispatch
, b
);
371 log_error_errno(r
, "Failed to add button event: %m");
375 log_info("Watching system buttons on /dev/input/%s (%s)", b
->name
, name
);
380 b
->fd
= safe_close(b
->fd
);
384 int button_check_switches(Button
*b
) {
385 unsigned long switches
[CONST_MAX(SW_LID
, SW_DOCK
)/ULONG_BITS
+1] = {};
391 if (ioctl(b
->fd
, EVIOCGSW(sizeof(switches
)), switches
) < 0)
394 b
->lid_closed
= bitset_get(switches
, SW_LID
);
395 b
->docked
= bitset_get(switches
, SW_DOCK
);
398 button_install_check_event_source(b
);