lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20220824114927.79231-1-mmkurbanov@sberdevices.ru>
Date:   Wed, 24 Aug 2022 14:49:27 +0300
From:   Martin Kurbanov <mmkurbanov@...rdevices.ru>
To:     Pavel Machek <pavel@....cz>,
        Raphael Teysseyre <rteysseyre@...il.com>,
        Baolin Wang <baolin.wang@...aro.org>
CC:     <linux-leds@...r.kernel.org>, <linux-kernel@...r.kernel.org>,
        <kernel@...rdevices.ru>,
        Martin Kurbanov <mmkurbanov@...rdevices.ru>
Subject: [PATCH v1] leds: trigger: pattern: notify userpace if pattern finished

In the current moment, userspace caller can schedule led pattern with
appropriate parameters, but it doesn't have ability to listen any events
indicated pattern finished. This patch implements such an event using
sysfs node and sysfs_notify_dirent() call.

Signed-off-by: Martin Kurbanov <mmkurbanov@...rdevices.ru>
---
 drivers/leds/trigger/ledtrig-pattern.c | 64 +++++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/drivers/leds/trigger/ledtrig-pattern.c b/drivers/leds/trigger/ledtrig-pattern.c
index 43a265dc4696..54c4b957052f 100644
--- a/drivers/leds/trigger/ledtrig-pattern.c
+++ b/drivers/leds/trigger/ledtrig-pattern.c
@@ -33,7 +33,9 @@ struct pattern_trig_data {
 	int delta_t;
 	bool is_indefinite;
 	bool is_hw_pattern;
+	bool running;
 	struct timer_list timer;
+	struct kernfs_node *pattern_ended;
 };

 static void pattern_trig_update_patterns(struct pattern_trig_data *data)
@@ -76,8 +78,14 @@ static void pattern_trig_timer_function(struct timer_list *t)
 	struct pattern_trig_data *data = from_timer(data, t, timer);

 	for (;;) {
-		if (!data->is_indefinite && !data->repeat)
+		if (!data->is_indefinite && !data->repeat) {
+			data->running = false;
+
+			if (data->pattern_ended)
+				sysfs_notify_dirent(data->pattern_ended);
+
 			break;
+		}

 		if (data->curr->brightness == data->next->brightness) {
 			/* Step change of brightness */
@@ -137,6 +145,7 @@ static int pattern_trig_start_pattern(struct led_classdev *led_cdev)
 	data->curr = data->patterns;
 	data->next = data->patterns + 1;
 	data->timer.expires = jiffies;
+	data->running = true;
 	add_timer(&data->timer);

 	return 0;
@@ -176,6 +185,7 @@ static ssize_t repeat_store(struct device *dev, struct device_attribute *attr,
 	mutex_lock(&data->lock);

 	del_timer_sync(&data->timer);
+	data->running = false;

 	if (data->is_hw_pattern)
 		led_cdev->pattern_clear(led_cdev);
@@ -268,6 +278,7 @@ static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev,
 	mutex_lock(&data->lock);

 	del_timer_sync(&data->timer);
+	data->running = false;

 	if (data->is_hw_pattern)
 		led_cdev->pattern_clear(led_cdev);
@@ -330,6 +341,17 @@ static ssize_t hw_pattern_store(struct device *dev,

 static DEVICE_ATTR_RW(hw_pattern);

+static ssize_t pattern_ended_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct pattern_trig_data *data = led_get_trigger_data(led_cdev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", !data->running);
+}
+
+static DEVICE_ATTR_RO(pattern_ended);
+
 static umode_t pattern_trig_attrs_mode(struct kobject *kobj,
 				       struct attribute *attr, int index)
 {
@@ -385,9 +407,41 @@ static void pattern_init(struct led_classdev *led_cdev)
 	kfree(pattern);
 }

+static int pattern_trig_add_pattern_ended(struct led_classdev *led_cdev)
+{
+	struct pattern_trig_data *data = led_get_trigger_data(led_cdev);
+	struct device *dev = led_cdev->dev;
+	int ret;
+
+	ret = device_create_file(dev, &dev_attr_pattern_ended);
+	if (ret) {
+		dev_err(dev,
+			"Error creating pattern_ended (%pe)\n", ERR_PTR(ret));
+		return ret;
+	}
+
+	data->pattern_ended = sysfs_get_dirent(dev->kobj.sd, "pattern_ended");
+	if (!data->pattern_ended) {
+		dev_err(dev, "Error getting pattern_ended kernelfs\n");
+		device_remove_file(dev, &dev_attr_pattern_ended);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void pattern_trig_remove_pattern_ended(struct led_classdev *led_cdev)
+{
+	struct pattern_trig_data *data = led_get_trigger_data(led_cdev);
+
+	sysfs_put(data->pattern_ended);
+	device_remove_file(led_cdev->dev, &dev_attr_pattern_ended);
+}
+
 static int pattern_trig_activate(struct led_classdev *led_cdev)
 {
 	struct pattern_trig_data *data;
+	int err;

 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
@@ -406,6 +460,13 @@ static int pattern_trig_activate(struct led_classdev *led_cdev)
 	data->led_cdev = led_cdev;
 	led_set_trigger_data(led_cdev, data);
 	timer_setup(&data->timer, pattern_trig_timer_function, 0);
+
+	err = pattern_trig_add_pattern_ended(led_cdev);
+	if (err)
+		dev_warn(led_cdev->dev,
+			 "pattern ended notifications disabled (%pe)\n",
+			 ERR_PTR(err));
+
 	led_cdev->activated = true;

 	if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) {
@@ -431,6 +492,7 @@ static void pattern_trig_deactivate(struct led_classdev *led_cdev)
 		led_cdev->pattern_clear(led_cdev);

 	del_timer_sync(&data->timer);
+	pattern_trig_remove_pattern_ended(led_cdev);

 	led_set_brightness(led_cdev, LED_OFF);
 	kfree(data);
--
2.37.2

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ