From a71fd7d4709b47564cc647c2cb50ba050963b7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 13 Jun 2024 15:29:09 +0200 Subject: [PATCH 1/7] manager: Move schema name to header This makes it available to other compilation units --- src/fbd-feedback-manager.c | 1 - src/fbd.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fbd-feedback-manager.c b/src/fbd-feedback-manager.c index 4560a95..2188969 100644 --- a/src/fbd-feedback-manager.c +++ b/src/fbd-feedback-manager.c @@ -22,7 +22,6 @@ #include #include -#define FEEDBACKD_SCHEMA_ID "org.sigxcpu.feedbackd" #define FEEDBACKD_KEY_PROFILE "profile" #define FEEDBACKD_KEY_THEME "theme" #define FEEDBACKD_KEY_ALLOW_IMPORTANT "allow-important" diff --git a/src/fbd.h b/src/fbd.h index 82da4e2..be68808 100644 --- a/src/fbd.h +++ b/src/fbd.h @@ -11,6 +11,8 @@ G_BEGIN_DECLS #define FEEDBACKD_UDEV_ATTR "FEEDBACKD_TYPE" #define FEEDBACKD_UDEV_VAL_LED "led" +#define FEEDBACKD_SCHEMA_ID "org.sigxcpu.feedbackd" + typedef enum { FBD_ERROR_FAILED = 0, FBD_ERROR_THEME_EXPAND = 1, From 417b34be89bf284f185496a790ab6ac82b378697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 13 Jun 2024 15:29:11 +0200 Subject: [PATCH 2/7] led: Drop FBD_FEEDBACK_LED_COLOR_LAST With new led types we might not loop over all of them. This makes it a bit more obvious. --- src/fbd-dev-led.c | 2 +- src/fbd-feedback-led.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fbd-dev-led.c b/src/fbd-dev-led.c index 1ec0812..c70b5eb 100644 --- a/src/fbd-dev-led.c +++ b/src/fbd-dev-led.c @@ -52,7 +52,7 @@ fbd_dev_led_probe_default (FbdDevLed *led, GError **error) gboolean success = FALSE; name = g_udev_device_get_name (priv->dev); - for (int i = 0; i <= FBD_FEEDBACK_LED_COLOR_LAST; i++) { + for (int i = 0; i <= FBD_FEEDBACK_LED_COLOR_RGB; i++) { g_autofree char *color = NULL; g_autofree char *enum_name = NULL; gchar *c; diff --git a/src/fbd-feedback-led.h b/src/fbd-feedback-led.h index f67af6c..f05c683 100644 --- a/src/fbd-feedback-led.h +++ b/src/fbd-feedback-led.h @@ -25,7 +25,6 @@ typedef enum _FbdFeedbackLedColor { FBD_FEEDBACK_LED_COLOR_GREEN = 2, FBD_FEEDBACK_LED_COLOR_BLUE = 3, FBD_FEEDBACK_LED_COLOR_RGB = 4, - FBD_FEEDBACK_LED_COLOR_LAST = FBD_FEEDBACK_LED_COLOR_RGB, } FbdFeedbackLedColor; typedef struct { From e16dc3cdab4db194e895534313b86eca21baab67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 13 Jun 2024 15:29:11 +0200 Subject: [PATCH 3/7] feedback-led: Check if at least one LED is available So far we didn't create any FbdDevLeds if there wasn't at least one usable LED. Once we introduce flash LEDs we might probe the LED but the LED might not be usable as the user hasn't enabled using it. Prepare for that scenario. --- src/fbd-dev-leds.c | 29 ++++++++++++++++++++++++++--- src/fbd-dev-leds.h | 4 ++-- src/fbd-feedback-led.c | 5 ++++- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/fbd-dev-leds.c b/src/fbd-dev-leds.c index f0eb1df..ae9c278 100644 --- a/src/fbd-dev-leds.c +++ b/src/fbd-dev-leds.c @@ -48,7 +48,7 @@ find_led_by_color (FbdDevLeds *self, FbdFeedbackLedColor color) g_return_val_if_fail (self->leds, NULL); for (GSList *l = self->leds; l != NULL; l = l->next) { - FbdDevLed *led = l->data; + FbdDevLed *led = FBD_DEV_LED (l->data); if (fbd_dev_led_supports_color (led, color)) return led; } @@ -199,7 +199,10 @@ fbd_dev_leds_start_periodic (FbdDevLeds *self, g_return_val_if_fail (FBD_IS_DEV_LEDS (self), FALSE); g_return_val_if_fail (max_brightness_percentage <= 100.0, FALSE); led = find_led_by_color (self, color); - g_return_val_if_fail (led, FALSE); + if (!led) { + g_warning_once ("No usable led found"); + return FALSE; + } fbd_dev_led_set_color (led, color, rgb); @@ -214,7 +217,27 @@ fbd_dev_leds_stop (FbdDevLeds *self, FbdFeedbackLedColor color) g_return_val_if_fail (FBD_IS_DEV_LEDS (self), FALSE); led = find_led_by_color (self, color); - g_return_val_if_fail (led, FALSE); + if (!led) { + g_warning_once ("No usable led found"); + return FALSE; + } return fbd_dev_led_set_brightness (led, 0); } + +/** + * fbd_dev_leds_has_led: + * @self: The FbdDevLeds + * @color: The color type to check + * + * Whether there's a usable LED of the given type + * + * Returns: `TRUE` if there's a at least one usable LED, otherwise `FALSE` + */ +gboolean +fbd_dev_leds_has_led (FbdDevLeds *self, FbdFeedbackLedColor color) +{ + g_return_val_if_fail (FBD_IS_DEV_LEDS (self), FALSE); + + return !!find_led_by_color (self, color); +} diff --git a/src/fbd-dev-leds.h b/src/fbd-dev-leds.h index 6387882..368ec2c 100644 --- a/src/fbd-dev-leds.h +++ b/src/fbd-dev-leds.h @@ -22,7 +22,7 @@ gboolean fbd_dev_leds_start_periodic (FbdDevLeds *self, FbdLedRgbColor *rgb, guint max_brighness, guint freq); -gboolean fbd_dev_leds_stop (FbdDevLeds *self, - FbdFeedbackLedColor color); +gboolean fbd_dev_leds_stop (FbdDevLeds *self, FbdFeedbackLedColor color); +gboolean fbd_dev_leds_has_led (FbdDevLeds *self, FbdFeedbackLedColor color); G_END_DECLS diff --git a/src/fbd-feedback-led.c b/src/fbd-feedback-led.c index dc297b7..f9fd408 100644 --- a/src/fbd-feedback-led.c +++ b/src/fbd-feedback-led.c @@ -250,7 +250,10 @@ fbd_feedback_led_is_available (FbdFeedbackBase *base) FbdFeedbackManager *manager = fbd_feedback_manager_get_default (); FbdDevLeds *dev = fbd_feedback_manager_get_dev_leds (manager); - return FBD_IS_DEV_LEDS (dev); + if (!FBD_IS_DEV_LEDS (dev)) + return FALSE; + + return fbd_dev_leds_has_led (dev, FBD_FEEDBACK_LED_COLOR_WHITE); } From e47ce8e09eb8d2484ebf7c6ac6f9e971ae34132b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 13 Jun 2024 15:29:12 +0200 Subject: [PATCH 4/7] led: Add flash LED type Camera flashes are also exported via the LED subsystem. We use a separate LED type so they're not picked by default. We don't use them as fallbacks either. --- src/fbd-dev-led-flash.c | 81 ++++++++++++++++ src/fbd-dev-led-flash.h | 18 ++++ src/fbd-dev-leds.c | 11 ++- src/fbd-feedback-led.h | 3 + src/meson.build | 1 + tests/data/umockdev/led-flash.umockdev | 128 +++++++++++++++++++++++++ tests/test-fbd-dev-led.c | 32 +++++++ 7 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 src/fbd-dev-led-flash.c create mode 100644 src/fbd-dev-led-flash.h create mode 100644 tests/data/umockdev/led-flash.umockdev diff --git a/src/fbd-dev-led-flash.c b/src/fbd-dev-led-flash.c new file mode 100644 index 0000000..32653cb --- /dev/null +++ b/src/fbd-dev-led-flash.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2024 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0+ + * Author: Guido Günther + * + * See Documentation/ABI/testing/sysfs-class-led-trigger-pattern + */ + +#define G_LOG_DOMAIN "fbd-dev-led-flash" + +#include "fbd-dev-led-priv.h" +#include "fbd-dev-led-flash.h" +#include "fbd-enums.h" +#include "fbd-udev.h" + +#include + +/** + * fbd-dev-led-flash: + * + * The LED of a camera flash + */ +typedef struct _FbdDevLedFlash { + FbdDevLed parent; +} FbdDevLedFlash; + + +G_DEFINE_TYPE (FbdDevLedFlash, fbd_dev_led_flash, FBD_TYPE_DEV_LED) + + +static gboolean +fbd_dev_led_flash_probe (FbdDevLed *led, GError **error) +{ + GUdevDevice *dev = fbd_dev_led_get_device (led); + const gchar *name, *path; + guint max_brightness; + + name = g_udev_device_get_name (dev); + if (!g_udev_device_get_sysfs_attr (dev, "flash_strobe") || + !g_udev_device_get_sysfs_attr (dev, "flash_brightness")) { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s is no flash LED", name); + return FALSE; + } + + max_brightness = g_udev_device_get_sysfs_attr_as_int (dev, LED_MAX_BRIGHTNESS_ATTR); + if (!max_brightness) { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s has no max_brightness", name); + return FALSE; + } + + fbd_dev_led_set_max_brightness (led, max_brightness); + fbd_dev_led_set_supported_color (led, FBD_FEEDBACK_LED_COLOR_FLASH); + + path = g_udev_device_get_sysfs_path (dev); + g_debug ("LED at '%s' usable as flash", path); + + return TRUE; +} + + +static void +fbd_dev_led_flash_class_init (FbdDevLedFlashClass *klass) +{ + FbdDevLedClass *fbd_dev_led_class = FBD_DEV_LED_CLASS (klass); + + fbd_dev_led_class->probe = fbd_dev_led_flash_probe; +} + + +static void +fbd_dev_led_flash_init (FbdDevLedFlash *self) +{ +} + + +FbdDevLed * +fbd_dev_led_flash_new (GUdevDevice *dev, GError **err) +{ + return g_initable_new (FBD_TYPE_DEV_LED_FLASH, NULL, err, "dev", dev, NULL); +} diff --git a/src/fbd-dev-led-flash.h b/src/fbd-dev-led-flash.h new file mode 100644 index 0000000..fea66f7 --- /dev/null +++ b/src/fbd-dev-led-flash.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2024 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0+ + */ +#pragma once + +#include "fbd-dev-led.h" + +G_BEGIN_DECLS + +#define FBD_TYPE_DEV_LED_FLASH fbd_dev_led_flash_get_type() + +G_DECLARE_FINAL_TYPE (FbdDevLedFlash, fbd_dev_led_flash, FBD, DEV_LED_FLASH, FbdDevLed) + +FbdDevLed *fbd_dev_led_flash_new (GUdevDevice *dev, GError **err); + +G_END_DECLS diff --git a/src/fbd-dev-leds.c b/src/fbd-dev-leds.c index ae9c278..12a0b08 100644 --- a/src/fbd-dev-leds.c +++ b/src/fbd-dev-leds.c @@ -53,8 +53,15 @@ find_led_by_color (FbdDevLeds *self, FbdFeedbackLedColor color) return led; } - /* If we did not match a color pick the first */ - return self->leds->data; + /* If we did not match a color pick the first non flash LED */ + for (GSList *l = self->leds; l != NULL; l = l->next) { + FbdDevLed *led = FBD_DEV_LED (l->data); + + if (!fbd_dev_led_supports_color (led, FBD_FEEDBACK_LED_COLOR_FLASH)) + return led; + } + + return NULL; } diff --git a/src/fbd-feedback-led.h b/src/fbd-feedback-led.h index f05c683..84733a2 100644 --- a/src/fbd-feedback-led.h +++ b/src/fbd-feedback-led.h @@ -16,6 +16,7 @@ G_BEGIN_DECLS * @FBD_FEEDBACK_LED_COLOR_GREEN: A green LED * @FBD_FEEDBACK_LED_COLOR_BLUE: A blue LED * @FBD_FEEDBACK_LED_COLOR_RGB: A multicolor LED that can display arbitrary RGB values + * @FBD_FEEDBACK_LED_COLOR_FLASH: A flash (usually white) * * The color of a hardware LED. */ @@ -25,6 +26,8 @@ typedef enum _FbdFeedbackLedColor { FBD_FEEDBACK_LED_COLOR_GREEN = 2, FBD_FEEDBACK_LED_COLOR_BLUE = 3, FBD_FEEDBACK_LED_COLOR_RGB = 4, + /* Keep this last in the list */ + FBD_FEEDBACK_LED_COLOR_FLASH = 5, } FbdFeedbackLedColor; typedef struct { diff --git a/src/meson.build b/src/meson.build index f538ef1..3b3f945 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,6 +16,7 @@ sources = [ 'fbd-dev-vibra.c', 'fbd-dev-sound.c', 'fbd-dev-led.c', + 'fbd-dev-led-flash.c', 'fbd-dev-led-multicolor.c', 'fbd-dev-led-qcom.c', 'fbd-dev-led-qcom-multicolor.c', diff --git a/tests/data/umockdev/led-flash.umockdev b/tests/data/umockdev/led-flash.umockdev new file mode 100644 index 0000000..440243d --- /dev/null +++ b/tests/data/umockdev/led-flash.umockdev @@ -0,0 +1,128 @@ +P: /devices/platform/soc@0/c440000.spmi/spmi-0/0-03/c440000.spmi:pmic@3:led-controller@d300/leds/white:flash +E: FEEDBACKD_TYPE=led +E: CURRENT_TAGS=:seat: +E: ID_FOR_SEAT=leds-platform-c440000_spmi-platform-c440000_spmi_pmic_3_led-controller_d300 +E: ID_PATH=platform-c440000.spmi-platform-c440000.spmi:pmic@3:led-controller@d300 +E: ID_PATH_TAG=platform-c440000_spmi-platform-c440000_spmi_pmic_3_led-controller_d300 +E: OF_COMPATIBLE_N=0 +E: OF_FULLNAME=/soc@0/spmi@c440000/pmic@3/led-controller@d300/led-0 +E: OF_NAME=led-0 +E: SUBSYSTEM=leds +E: TAGS=:seat: +A: brightness=0\n +L: device=../../../c440000.spmi:pmic@3:led-controller@d300 +A: flash_brightness=12500\n +A: flash_fault=flash-timeout-exceeded \n +A: flash_strobe=1\n +A: flash_timeout=10000\n +A: max_brightness=255\n +A: max_flash_brightness=1500000\n +A: max_flash_timeout=1280000\n +A: pattern= +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n +A: repeat=-1\n +A: trigger=none usb-gadget usb-host kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock usbport timer oneshot heartbeat backlight cpu cpu0 cpu1 cpu2 cpu3 cpu4 cpu5 cpu6 cpu7 activity default-on transient flash torch panic netdev [pattern] audio-mute audio-micmute rfkill-any rfkill-none bq27411-0-charging-or-full bq27411-0-charging bq27411-0-full bq27411-0-charging-blink-full-solid pmi8998-charger-online bluetooth-power hci0-power rfkill0 phy0rx phy0tx phy0assoc phy0radio rfkill1\n + +P: /devices/platform/soc@0/c440000.spmi/spmi-0/0-03/c440000.spmi:pmic@3:led-controller@d300 +E: DRIVER=leds-qcom-flash +E: ID_PATH=platform-c440000.spmi-platform-c440000.spmi:pmic@3:led-controller@d300 +E: ID_PATH_TAG=platform-c440000_spmi-platform-c440000_spmi_pmic_3_led-controller_d300 +E: MODALIAS=of:Nled-controllerT(null)Cqcom,pmi8998-flash-ledCqcom,spmi-flash-led +E: OF_COMPATIBLE_0=qcom,pmi8998-flash-led +E: OF_COMPATIBLE_1=qcom,spmi-flash-led +E: OF_COMPATIBLE_N=2 +E: OF_FULLNAME=/soc@0/spmi@c440000/pmic@3/led-controller@d300 +E: OF_NAME=led-controller +E: SUBSYSTEM=platform +L: driver=../../../../../../../bus/platform/drivers/leds-qcom-flash +A: driver_override=(null)\n +A: modalias=of:Nled-controllerT(null)Cqcom,pmi8998-flash-ledCqcom,spmi-flash-led\n +L: of_node=../../../../../../../firmware/devicetree/base/soc@0/spmi@c440000/pmic@3/led-controller@d300 +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0/c440000.spmi/spmi-0/0-03 +E: DRIVER=pmic-spmi +E: MODALIAS=of:NpmicT(null)Cqcom,pmi8998Cqcom,spmi-pmic +E: OF_COMPATIBLE_0=qcom,pmi8998 +E: OF_COMPATIBLE_1=qcom,spmi-pmic +E: OF_COMPATIBLE_N=2 +E: OF_FULLNAME=/soc@0/spmi@c440000/pmic@3 +E: OF_NAME=pmic +E: SUBSYSTEM=spmi +L: driver=../../../../../../bus/spmi/drivers/pmic-spmi +L: of_node=../../../../../../firmware/devicetree/base/soc@0/spmi@c440000/pmic@3 +A: power/control=auto\n +A: power/runtime_active_time=132131678\n +A: power/runtime_status=active\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0/c440000.spmi/spmi-0 +E: MODALIAS=of:NspmiT(null)Cqcom,spmi-pmic-arb +E: OF_COMPATIBLE_0=qcom,spmi-pmic-arb +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0/spmi@c440000 +E: OF_NAME=spmi +E: SUBSYSTEM=spmi +L: of_node=../../../../../firmware/devicetree/base/soc@0/spmi@c440000 +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0/c440000.spmi +E: DRIVER=spmi_pmic_arb +E: ID_PATH=platform-c440000.spmi +E: ID_PATH_TAG=platform-c440000_spmi +E: MODALIAS=of:NspmiT(null)Cqcom,spmi-pmic-arb +E: OF_COMPATIBLE_0=qcom,spmi-pmic-arb +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0/spmi@c440000 +E: OF_NAME=spmi +E: SUBSYSTEM=platform +L: consumer:platform:c440000.spmi:pmic@0:adc@3100=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:adc@3100 +L: consumer:platform:c440000.spmi:pmic@0:pon@800:pwrkey=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:pon@800:pwrkey +L: consumer:platform:c440000.spmi:pmic@0:rtc@6000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:rtc@6000 +L: consumer:platform:c440000.spmi:pmic@0:temp-alarm@2400=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@0:temp-alarm@2400 +L: consumer:platform:c440000.spmi:pmic@2:charger@1000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@2:charger@1000 +L: consumer:platform:c440000.spmi:pmic@3:haptics@c000=../../../virtual/devlink/platform:c440000.spmi--platform:c440000.spmi:pmic@3:haptics@c000 +L: driver=../../../../bus/platform/drivers/spmi_pmic_arb +A: driver_override=(null)\n +A: modalias=of:NspmiT(null)Cqcom,spmi-pmic-arb\n +L: of_node=../../../../firmware/devicetree/base/soc@0/spmi@c440000 +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + +P: /devices/platform/soc@0 +E: DRIVER=simple-pm-bus +E: ID_PATH=platform-soc@0 +E: ID_PATH_TAG=platform-soc_0 +E: MODALIAS=of:NsocT(null)Csimple-bus +E: OF_COMPATIBLE_0=simple-bus +E: OF_COMPATIBLE_N=1 +E: OF_FULLNAME=/soc@0 +E: OF_NAME=soc +E: SUBSYSTEM=platform +L: consumer:platform:17c90000.timer=../../virtual/devlink/platform:soc@0--platform:17c90000.timer +L: consumer:platform:890000.i2c=../../virtual/devlink/platform:soc@0--platform:890000.i2c +L: consumer:platform:898000.serial=../../virtual/devlink/platform:soc@0--platform:898000.serial +L: consumer:platform:a600000.usb=../../virtual/devlink/platform:soc@0--platform:a600000.usb +L: consumer:platform:a84000.serial=../../virtual/devlink/platform:soc@0--platform:a84000.serial +L: consumer:platform:a88000.i2c=../../virtual/devlink/platform:soc@0--platform:a88000.i2c +L: consumer:platform:a90000.i2c=../../virtual/devlink/platform:soc@0--platform:a90000.i2c +L: driver=../../../bus/platform/drivers/simple-pm-bus +A: driver_override=(null)\n +A: modalias=of:NsocT(null)Csimple-bus\n +L: of_node=../../../firmware/devicetree/base/soc@0 +A: power/control=auto\n +A: power/runtime_active_time=0\n +A: power/runtime_status=unsupported\n +A: power/runtime_suspended_time=0\n + diff --git a/tests/test-fbd-dev-led.c b/tests/test-fbd-dev-led.c index 93f64a9..4cc0a1e 100644 --- a/tests/test-fbd-dev-led.c +++ b/tests/test-fbd-dev-led.c @@ -7,6 +7,7 @@ #include "fbd-feedback-led.h" #include "fbd-dev-led.h" +#include "fbd-dev-led-flash.h" #include "fbd-dev-led-multicolor.h" #include "fbd-dev-led-qcom.h" #include "fbd-dev-led-qcom-multicolor.h" @@ -69,6 +70,34 @@ test_fbd_dev_led_multicolor (FbdUmockdevFixture *fixture, gconstpointer unused) } +static void +test_fbd_dev_led_flash (FbdUmockdevFixture *fixture, gconstpointer unused) +{ + GUdevClient *client; + g_autolist (GUdevDevice) leds = NULL; + FbdDevLed *led; + g_autoptr (GError) err = NULL; + GUdevDevice *dev; + + client = g_udev_client_new ((const char *const []){ "leds", NULL}); + leds = g_udev_client_query_by_subsystem (client, "leds"); + + /* There should be a single device only */ + g_assert_cmpint (g_list_length (leds), ==, 1); + dev = G_UDEV_DEVICE (leds->data); + + g_assert_cmpstr (g_udev_device_get_property (dev, "FEEDBACKD_TYPE"), ==, "led"); + + led = fbd_dev_led_flash_new (dev, &err); + g_assert_no_error (err); + g_assert_cmpint (fbd_dev_led_get_max_brightness (led), ==, 255); + g_assert_true (fbd_dev_led_supports_color (led, FBD_FEEDBACK_LED_COLOR_FLASH)); + g_assert_true (fbd_dev_led_start_periodic (led, 50, 50)); + + g_assert_finalize_object (led); +} + + static void test_fbd_dev_led_qcom_simple (FbdUmockdevFixture *fixture, gconstpointer unused) { @@ -135,6 +164,9 @@ main (gint argc, gchar *argv[]) FBD_UMOCKDEV_TEST_ADD ("/feedbackd/fbd/dev/led/multicolor", test_fbd_dev_led_multicolor, "led-multicolor"); + FBD_UMOCKDEV_TEST_ADD ("/feedbackd/fbd/dev/led/flash", + test_fbd_dev_led_flash, + "led-flash"); FBD_UMOCKDEV_TEST_ADD ("/feedbackd/fbd/dev/led/qcom/simple", test_fbd_dev_led_qcom_simple, "led-qcom-simple"); From ffd939c53652251fa816a987a5b439c454e81906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 13 Jun 2024 15:29:12 +0200 Subject: [PATCH 5/7] leds: Probe flash LED --- src/fbd-dev-leds.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/fbd-dev-leds.c b/src/fbd-dev-leds.c index 12a0b08..0d856e8 100644 --- a/src/fbd-dev-leds.c +++ b/src/fbd-dev-leds.c @@ -11,6 +11,7 @@ #include "fbd.h" #include "fbd-enums.h" #include "fbd-dev-led.h" +#include "fbd-dev-led-flash.h" #include "fbd-dev-led-multicolor.h" #include "fbd-dev-led-qcom.h" #include "fbd-dev-led-qcom-multicolor.h" @@ -90,6 +91,13 @@ probe_led (GUdevDevice *dev, GError **error) { } g_clear_error (error); + led = fbd_dev_led_flash_new (dev, error); + if (led != NULL) { + g_debug ("Discovered flash LED"); + return led; + } + g_clear_error (error); + led = fbd_dev_led_new (dev, error); if (led != NULL) { g_debug ("Discovered single color LED"); From 8f67dbd120dcf963227a5347119e0261d65e5e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 13 Jun 2024 15:29:13 +0200 Subject: [PATCH 6/7] feedback-led: Allow to prefer flash LEDs over notification LEDs --- data/org.sigxcpu.feedbackd.gschema.xml | 8 ++++ src/fbd-dev-leds.c | 2 +- src/fbd-feedback-led.c | 61 +++++++++++++++++++++----- tests/test-fbd-feedback-led.c | 11 +++-- 4 files changed, 66 insertions(+), 16 deletions(-) diff --git a/data/org.sigxcpu.feedbackd.gschema.xml b/data/org.sigxcpu.feedbackd.gschema.xml index 462e6c7..c70da2a 100644 --- a/data/org.sigxcpu.feedbackd.gschema.xml +++ b/data/org.sigxcpu.feedbackd.gschema.xml @@ -24,6 +24,14 @@ + + false + Prefer camera flash LED over notification LED + + Prefer the (camera) flash LED over other notifiction LEDs. + + + [] List of apps that can override the feedback level diff --git a/src/fbd-dev-leds.c b/src/fbd-dev-leds.c index 0d856e8..467d1f9 100644 --- a/src/fbd-dev-leds.c +++ b/src/fbd-dev-leds.c @@ -28,7 +28,7 @@ * * LED device interface * - * #FbdDevLeds is used to interface with LEDS via sysfs + * #FbdDevLeds is used to interface with all LEDs detected in sysfs * It currently only supports one pattern per led at a time. */ typedef struct _FbdDevLeds { diff --git a/src/fbd-feedback-led.c b/src/fbd-feedback-led.c index f9fd408..b713690 100644 --- a/src/fbd-feedback-led.c +++ b/src/fbd-feedback-led.c @@ -8,6 +8,7 @@ #define G_LOG_DOMAIN "fbd-feedback-led" +#include "fbd.h" #include "fbd-enums.h" #include "fbd-dev-leds.h" #include "fbd-feedback-led.h" @@ -39,6 +40,9 @@ typedef struct _FbdFeedbackLed { guint priority; guint max_brightness; char *color; + gboolean prefer_flash; + + GSettings *settings; } FbdFeedbackLed; G_DEFINE_TYPE (FbdFeedbackLed, fbd_feedback_led, FBD_TYPE_FEEDBACK_BASE) @@ -120,34 +124,52 @@ parse_hex_color (const char *color, FbdLedRgbColor *rgb) static FbdFeedbackLedColor -color_string_to_color (const char *color, FbdLedRgbColor *rgb) +color_string_to_color (const char *color, gboolean prefer_flash, FbdLedRgbColor *rgb) { + FbdFeedbackLedColor type; + g_return_val_if_fail (!gm_str_is_null_or_empty (color), FBD_FEEDBACK_LED_COLOR_WHITE); if (g_strcmp0 (color, "red") == 0) { if (rgb) rgb->r = 255; - return FBD_FEEDBACK_LED_COLOR_RED; + type = FBD_FEEDBACK_LED_COLOR_RED; } else if (g_strcmp0 (color, "green") == 0) { if (rgb) rgb->g = 255; - return FBD_FEEDBACK_LED_COLOR_GREEN; + type = FBD_FEEDBACK_LED_COLOR_GREEN; } else if (g_strcmp0 (color, "blue") == 0) { if (rgb) rgb->b = 255; - return FBD_FEEDBACK_LED_COLOR_BLUE; + type = FBD_FEEDBACK_LED_COLOR_BLUE; } else if (g_strcmp0 (color, "white") == 0) { if (rgb) rgb->r = rgb->g = rgb->b = 255; - return FBD_FEEDBACK_LED_COLOR_WHITE; + type = FBD_FEEDBACK_LED_COLOR_WHITE; } else if (parse_hex_color (color, rgb)) { - return FBD_FEEDBACK_LED_COLOR_RGB; + type = FBD_FEEDBACK_LED_COLOR_RGB; + } else { + g_warning_once ("Can't parse color '%s' using white", color); + if (rgb) + rgb->r = rgb->g = rgb->b = 255; + type = FBD_FEEDBACK_LED_COLOR_WHITE; } - g_warning_once ("Can't parse color '%s' using white", color); - if (rgb) - rgb->r = rgb->g = rgb->b = 255; - return FBD_FEEDBACK_LED_COLOR_WHITE; + /* Override the LED color type at the very end as we want rgb filled + * in so it can be used in case we need to fall back to non flash + * LED */ + if (prefer_flash) + type = FBD_FEEDBACK_LED_COLOR_FLASH; + + return type; +} + + +static void +on_prefer_flash_changed (FbdFeedbackLed *self) +{ + self->prefer_flash = g_settings_get_boolean (self->settings, "prefer-flash"); + g_debug ("Prefer flash: %d", self->prefer_flash); } @@ -219,7 +241,7 @@ fbd_feedback_led_run (FbdFeedbackBase *base) g_return_if_fail (FBD_IS_DEV_LEDS (dev)); g_debug ("Periodic led feedback: max brightness: %d, freq: %d", self->max_brightness, self->frequency); - color = color_string_to_color (self->color, &rgb); + color = color_string_to_color (self->color, self->prefer_flash, &rgb); /* FIXME: handle priority */ fbd_dev_leds_start_periodic (dev, color, @@ -237,7 +259,7 @@ fbd_feedback_led_end (FbdFeedbackBase *base) FbdDevLeds *dev = fbd_feedback_manager_get_dev_leds (manager); FbdFeedbackLedColor color; - color = color_string_to_color (self->color, NULL); + color = color_string_to_color (self->color, self->prefer_flash, NULL); if (dev) fbd_dev_leds_stop (dev, color); fbd_feedback_base_done (FBD_FEEDBACK_BASE (self)); @@ -247,12 +269,18 @@ fbd_feedback_led_end (FbdFeedbackBase *base) static gboolean fbd_feedback_led_is_available (FbdFeedbackBase *base) { + FbdFeedbackLed *self = FBD_FEEDBACK_LED (base); FbdFeedbackManager *manager = fbd_feedback_manager_get_default (); FbdDevLeds *dev = fbd_feedback_manager_get_dev_leds (manager); if (!FBD_IS_DEV_LEDS (dev)) return FALSE; + if (self->prefer_flash && + fbd_dev_leds_has_led (dev, FBD_FEEDBACK_LED_COLOR_FLASH)) { + return TRUE; + } + return fbd_dev_leds_has_led (dev, FBD_FEEDBACK_LED_COLOR_WHITE); } @@ -262,6 +290,7 @@ fbd_feedback_led_finalize (GObject *object) { FbdFeedbackLed *self = FBD_FEEDBACK_LED (object); + g_clear_object (&self->settings); g_clear_pointer (&self->color, g_free); G_OBJECT_CLASS (fbd_feedback_led_parent_class)->finalize (object); @@ -331,4 +360,12 @@ static void fbd_feedback_led_init (FbdFeedbackLed *self) { self->max_brightness = 100; + self->settings = g_settings_new (FEEDBACKD_SCHEMA_ID); + + g_signal_connect_object (self->settings, + "changed::prefer-flash", + G_CALLBACK (on_prefer_flash_changed), + self, + G_CONNECT_SWAPPED); + on_prefer_flash_changed (self); } diff --git a/tests/test-fbd-feedback-led.c b/tests/test-fbd-feedback-led.c index 2b7bb0e..8be5853 100644 --- a/tests/test-fbd-feedback-led.c +++ b/tests/test-fbd-feedback-led.c @@ -38,14 +38,19 @@ test_fbd_feedback_led_color_string_to_color (void) { FbdLedRgbColor rgb = { 0 }; - g_assert_cmpint (color_string_to_color ("red", NULL), ==, FBD_FEEDBACK_LED_COLOR_RED); + g_assert_cmpint (color_string_to_color ("red", FALSE, NULL), ==, FBD_FEEDBACK_LED_COLOR_RED); - g_assert_cmpint (color_string_to_color ("#11aaBB", &rgb), ==, FBD_FEEDBACK_LED_COLOR_RGB); + g_assert_cmpint (color_string_to_color ("#11aaBB", FALSE, &rgb), ==, FBD_FEEDBACK_LED_COLOR_RGB); g_assert_cmpint (rgb.r, ==, 0x11); g_assert_cmpint (rgb.g, ==, 0xaa); g_assert_cmpint (rgb.b, ==, 0xbb); - g_assert_cmpint (color_string_to_color ("#00FF00", &rgb), ==, FBD_FEEDBACK_LED_COLOR_RGB); + g_assert_cmpint (color_string_to_color ("#00FF00", FALSE, &rgb), ==, FBD_FEEDBACK_LED_COLOR_RGB); + g_assert_cmpint (rgb.r, ==, 0x00); + g_assert_cmpint (rgb.g, ==, 0xFF); + g_assert_cmpint (rgb.b, ==, 0x00); + + g_assert_cmpint (color_string_to_color ("#00FF00", TRUE, &rgb), ==, FBD_FEEDBACK_LED_COLOR_FLASH); g_assert_cmpint (rgb.r, ==, 0x00); g_assert_cmpint (rgb.g, ==, 0xFF); g_assert_cmpint (rgb.b, ==, 0x00); From 6622444c78b8b57c6c81c7cd224eda8b8effa519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 13 Jun 2024 15:29:14 +0200 Subject: [PATCH 7/7] udev: Allow to use flash devices --- debian/feedbackd.udev | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/feedbackd.udev b/debian/feedbackd.udev index 4c88fa5..511b914 100644 --- a/debian/feedbackd.udev +++ b/debian/feedbackd.udev @@ -6,8 +6,14 @@ ACTION=="remove", GOTO="feedbackd_end" SUBSYSTEM=="input", KERNEL=="event*", ENV{ID_INPUT}=="1", ENV{ID_PATH}=="platform-vibrator", TAG+="uaccess", ENV{FEEDBACKD_TYPE}="vibra" +# # See include/dt-bindings/leds/common.h in the linux kernel +# +# Status LEDs SUBSYSTEM=="leds", DEVPATH=="*/*:status", 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=="*/*:indicator", ENV{FEEDBACKD_TYPE}="led", RUN{builtin}+="kmod load ledtrig-pattern", RUN+="/usr/libexec/fbd-ledctrl -p %S%p -t pattern -G feedbackd" +# Camera Flash +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" LABEL="feedbackd_end"