Merge branch 'alert-slider' into 'main'

fbd-alert-slider: Small service to track alert sliders

See merge request Librem5/feedbackd!142
This commit is contained in:
Guido Günther
2024-09-27 07:35:07 +00:00
9 changed files with 308 additions and 1 deletions
+6
View File
@@ -25,4 +25,10 @@ SUBSYSTEM=="leds", DEVPATH=="*/*:indicator", ENV{FEEDBACKD_TYPE}="led", RUN{buil
SUBSYSTEM=="leds", DEVPATH=="*/*:flash", ENV{FEEDBACKD_TYPE}="led", RUN{builtin}+="kmod load ledtrig-pattern", RUN+="/usr/libexec/fbd-ledctrl -p %S%p -t pattern -G feedbackd"
SUBSYSTEM=="leds", DEVPATH=="*/*:torch", ENV{FEEDBACKD_TYPE}="led", RUN{builtin}+="kmod load ledtrig-pattern", RUN+="/usr/libexec/fbd-ledctrl -p %S%p -t pattern -G feedbackd"
#
# Alert sliders
#
# OnePlus 6,6T (DT bits not yet upstream)
SUBSYSTEM=="input", KERNEL=="event*", ENV{ID_INPUT}=="1", ENV{ID_PATH}=="platform-alert-slider", TAG+="uaccess", ENV{FEEDBACKD_TYPE}="alert-slider"
LABEL="feedbackd_end"
+11
View File
@@ -0,0 +1,11 @@
[Unit]
Description=Feedbackd Alert Slider Handler
PartOf=graphical-session.target
[Service]
ExecStart=@libexecdir@/fbd-alert-slider
Restart=on-abnormal
RestartSec=10s
[Install]
WantedBy=graphical-session.target
+20
View File
@@ -72,4 +72,24 @@ if get_option('udev')
install_data('90-feedbackd.rules', install_dir: udevdir)
endif
systemd_user_unit_dir = get_option('systemd_user_unit_dir')
systemd_dep = dependency('systemd', required: false)
if systemd_user_unit_dir == ''
if systemd_dep.found()
systemd_user_unit_dir = systemd_dep.get_variable('systemd_user_unit_dir')
else
systemd_user_unit_dir = prefix / libdir / 'systemd' / 'user'
endif
endif
# Alert slider Systemd user service
alert_slider_unit = 'fbd-alert-slider.service'
configure_file(
input : alert_slider_unit + '.in',
output : alert_slider_unit,
configuration : service_data,
install : true,
install_dir : systemd_user_unit_dir,
)
endif # daemon
+2 -1
View File
@@ -33,7 +33,8 @@
</key>
<key name="allow-important" type="as">
<default>[]</default>
<default>['org.sigxcpu.FbdAlertSlider',
'org.sigxcpu.FbdAlertSlider']</default>
<summary>List of apps that can override the feedback level</summary>
<description>
Apps listed here can override the configured feedack level by
+1
View File
@@ -1,4 +1,5 @@
usr/bin/
usr/lib/systemd/user
usr/lib/udev/
usr/libexec/
usr/share/dbus-1/
+1
View File
@@ -27,6 +27,7 @@ if get_option('daemon')
gsound = dependency('gsound')
gudev = dependency('gudev-1.0', version: '>=232')
json_glib = dependency('json-glib-1.0')
systemd_dep = dependency('systemd', required: false)
endif
prefix = get_option('prefix')
+3
View File
@@ -16,3 +16,6 @@ option('man',
option('tests',
type: 'boolean', value: true,
description: 'Whether to compile unit tests')
option('systemd_user_unit_dir',
type: 'string', value: '',
description: 'Directory for systemd user units')
+255
View File
@@ -0,0 +1,255 @@
/*
* Copyright (C) 2024 The Phosh Developers
*
* SPDX-License-Identifier: GPL-3.0+
*
* Heavily based on a shell script posted to the phosh matrix channel
* by isyourbrain foss
*
* Author: Guido Günther <agx@sigxcpu.org>
*/
#define G_LOG_DOMAIN "fbd-alert-slider"
#define LIBFEEDBACK_USE_UNSTABLE_API
#include "libfeedback.h"
#include "fbd.h"
#include <gudev/gudev.h>
#include <glib.h>
#include <gio/gio.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x) - 1) / BITS_PER_LONG) + 1)
#define OFF(x) ((x) % BITS_PER_LONG)
#define BIT(x) (1UL << OFF (x))
#define LONG(x) ((x) / BITS_PER_LONG)
#define test_bit(bit, array) ((array[LONG (bit)] >> OFF (bit)) & 1)
typedef enum {
FBD_ALERT_SLIDER_STATE_SILENT = 0,
FBD_ALERT_SLIDER_STATE_QUIET = 1,
FBD_ALERT_SLIDER_STATE_FULL = 2,
} FbdAlertSliderState;
GSettings *settings = NULL;
static void
set_level (FbdAlertSliderState state, gboolean silent)
{
g_autoptr (LfbEvent) event = NULL;
const char *profile;
switch (state) {
case FBD_ALERT_SLIDER_STATE_SILENT:
profile = "silent";
break;
case FBD_ALERT_SLIDER_STATE_QUIET:
profile = "quiet";
break;
case FBD_ALERT_SLIDER_STATE_FULL:
profile = "full";
break;
default:
g_return_if_reached ();
}
g_debug ("Setting profile to %s", profile);
lfb_set_feedback_profile (profile);
if (!silent) {
event = lfb_event_new ("button-pressed");
lfb_event_set_important (event, TRUE);
lfb_event_set_feedback_profile (event, "quiet");
lfb_event_trigger_feedback (event, NULL);
}
}
static int
get_initial_value (int fd, int axis)
{
int abs[6] = {0};
ioctl (fd, EVIOCGABS (axis), abs);
return abs[0];
}
static int
probe (FbdAlertSliderState *initial)
{
GList *l;
g_autolist (GUdevClient) devices = NULL;
g_autoptr (GUdevClient) client = NULL;
unsigned int code;
int version, fd, value = 0;
char name[256] = "Unknown";
unsigned long bit[EV_MAX][NBITS (KEY_MAX)];
const char *device_file = NULL;
const char * const subsystems[] = { "input", NULL };
client = g_udev_client_new (subsystems);
devices = g_udev_client_query_by_subsystem (client, "input");
for (l = devices; l != NULL; l = l->next) {
GUdevDevice *dev = l->data;
if (!g_strcmp0 (g_udev_device_get_property (dev, FEEDBACKD_UDEV_ATTR), "alert-slider")) {
device_file = g_udev_device_get_device_file (dev);
g_debug ("Found alert slider device: %s", device_file);
break;
}
}
if (!device_file) {
g_debug ("No matching device found");
return -ENOENT;
}
if ((fd = open (device_file, O_RDONLY)) < 0) {
g_warning ("Failed to open alert slider device: %s", strerror (errno));
return -1;
}
if (ioctl (fd, EVIOCGVERSION, &version)) {
g_warning ("Can't get version %s", strerror (errno));
return -1;
}
g_debug ("Input driver version: %d.%d.%d", version >> 16, (version >> 8) & 0xff, version & 0xff);
ioctl (fd, EVIOCGNAME (sizeof(name)), name);
g_debug ("Input device name: '%s'", name);
if (g_strcmp0 (name, "Alert slider")) {
g_critical ("Not an alert slider but '%s'", name);
return -1;
}
memset (bit, 0, sizeof(bit));
ioctl (fd, EVIOCGBIT (0, EV_MAX), bit[0]);
if (test_bit (EV_ABS, bit[0])) {
ioctl (fd, EVIOCGBIT (EV_ABS, KEY_MAX), bit[EV_ABS]);
for (code = 0; code < KEY_MAX; code++) {
if (test_bit (code, bit[EV_ABS])) {
value = get_initial_value (fd, code);
break;
}
}
} else {
g_critical ("Device doesn't support EV_ABS");
return -1;
}
if (fd >= 0) {
g_debug ("Initial value: %d", value);
*initial = value;
}
return fd;
}
static gboolean
on_input_ready (GIOChannel *source, GIOCondition cond, gpointer unused)
{
GIOError status;
struct input_event ev[64];
gsize rd;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
status = g_io_channel_read (source, (char *)ev, sizeof(ev), &rd /*, &err */);
G_GNUC_END_IGNORE_DEPRECATIONS
if (status != G_IO_ERROR_NONE ) {
g_warning ("Failed to read event: %d", status);
return TRUE;
}
if (rd < sizeof(struct input_event)) {
g_warning ("Expected %d bytes, got %zd", (int) sizeof(struct input_event), rd);
return TRUE;
}
for (int i = 0; i < rd / sizeof(struct input_event); i++) {
unsigned int type, code;
type = ev[i].type;
code = ev[i].code;
if (type == EV_SYN)
continue;
if (type != EV_ABS || code != 34) {
g_warning ("Unexpected event %d / %d", type, code);
continue;
}
g_debug ("Event: time %ld.%06ld, value: %d",
ev[i].input_event_sec,
ev[i].input_event_usec,
ev[i].value);
set_level (ev[i].value, FALSE);
}
return TRUE;
}
int
main (int argc, char *argv[])
{
g_autoptr (GError) err = NULL;
g_autoptr (GOptionContext) opt_context = NULL;
g_autoptr (GIOChannel) input = NULL;
g_autoptr (GMainLoop) loop = NULL;
FbdAlertSliderState state = 0;
int fd;
const GOptionEntry options [] = {
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
};
opt_context = g_option_context_new ("- helper to prepare sysfs for feedbackd");
g_option_context_add_main_entries (opt_context, options, NULL);
if (!g_option_context_parse (opt_context, &argc, &argv, &err)) {
g_print ("%s", err->message);
return 1;
}
fd = probe (&state);
if (fd < 0) {
if (fd == -ENOENT)
return EXIT_SUCCESS;
else
return EXIT_FAILURE;
}
if (!lfb_init ("org.sigxcpu.FbdAlertSlider", &err)) {
g_print ("Failed to init libfeedback: %s\n", err->message);
return 1;
}
set_level (state, TRUE);
input = g_io_channel_unix_new (fd);
g_io_channel_set_encoding (input, NULL, NULL);
g_io_add_watch (input, G_IO_IN | G_IO_ERR | G_IO_HUP, on_input_ready, NULL);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
g_clear_object (&settings);
return 0;
}
+9
View File
@@ -87,6 +87,15 @@ executable(
install_dir: libexecdir,
)
executable(
'fbd-alert-slider',
sources : ['fbd-alert-slider.c'],
include_directories : fbd_inc,
dependencies : [glib, gio, gio_unix, gudev, libfeedback_dep],
install : true,
install_dir: libexecdir,
)
executable(
'fbd-theme-validate',
sources : ['fbd-theme-validate.c'],