Skip to contentSkip to conversation

leds: add device trigger

PATCH In review Maciek Borzecki 3 participants 10 messages Oct 1, 2015 – Oct 2, 2015

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v2 cover leds: add device trigger

A series of patches that add yet another LED trigger, a device activity trigger.

The motivation is to have a LED trigger that is associated with a device and can be fired from cetrain points in the code that have been chosen by the developer. With this this device activity trigger it is possible for instance to easily hook up a tty driver for a console to blink one LED, yet another serial port to blink a second LED and writes to a block device to trigger a third LED.

The patches have been tested on Wandboard Quad.

The first patch adds the actual trigger. Each device wishing to use the trigger has to be explicitly registered by calling ledtrig_dev_add(), and passing it's dev_t. The intention is that the trigger will be used in scenarios that are impossible to foresee at this moment, and are likely to be approach in a case by case manner anyway.

The second patch adds couple of debugfs helpers.

The third patch adds documentation and notes on debugfs interface.

Example hooks into tty driver can be seen here:
https://github.com/bboozzoo/linux/commit/d8a875673e37b27d9c9066febe7633382f97d8af

Changes since v1:
- fixed debugfs user address space access
- added unregister debugfs attribute
- documentation update

Maciek Borzecki (3):
leds: add device activity LED triggers
leds: add debugfs to device trigger
Documentation: leds: document ledtrig-device trigger

 Documentation/leds/00-INDEX           |   3 +
 Documentation/leds/ledtrig-device.txt |  35 ++++
 drivers/leds/trigger/Kconfig          |   8 +
 drivers/leds/trigger/Makefile         |   1 +
 drivers/leds/trigger/ledtrig-device.c | 326 ++++++++++++++++++++++++++++++++++
 include/linux/leds.h                  |  10 ++
 6 files changed, 383 insertions(+)
 create mode 100644 Documentation/leds/ledtrig-device.txt
 create mode 100644 drivers/leds/trigger/ledtrig-device.c
Signature · 1 line
2.6.0
#1 lore raw

PATCH v2 1/3 leds: add device activity LED triggers

The patch adds LED triggers for indicating an activity on a selected device. The drivers that intend to use triggers need to register respective devices using ledtrig_dev_add(). Triggers are generated by explicitly calling ledtrig_dev_activity().

---
 drivers/leds/trigger/Kconfig          |   8 ++
 drivers/leds/trigger/Makefile         |   1 +
 drivers/leds/trigger/ledtrig-device.c | 185 ++++++++++++++++++++++++++++++++++
 include/linux/leds.h                  |  10 ++
 4 files changed, 204 insertions(+)
 create mode 100644 drivers/leds/trigger/ledtrig-device.c
drivers/leds/trigger/Kconfig +8 -0
index 5bda6a9b56bbd90b4a3749f87bc0c6fda8dd5034..c6ecfbd7c0876f21688140aa9afc7eb5b9fec3a2 100644
@@ -108,4 +108,12 @@ config LEDS_TRIGGER_CAMERA
 	  This enables direct flash/torch on/off by the driver, kernel space.
 	  If unsure, say Y.
 
+config LEDS_TRIGGER_DEVICE
+	bool "LED Device Activity Trigger"
+	depends on LEDS_TRIGGERS
+	help
+	  This allows LEDs to be triggered by an actvity on a selected
+          device.
+	  If unsure, say Y.
+
 endif # LEDS_TRIGGERS
drivers/leds/trigger/Makefile +1 -0
index 1abf48dacf7ebfcfb8208f7ae7bdf29d7c11ba32..86beeacd5403afc163873d7c3f817ee082b64e04 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_LEDS_TRIGGER_CPU)		+= ledtrig-cpu.o
 obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON)	+= ledtrig-default-on.o
 obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT)	+= ledtrig-transient.o
 obj-$(CONFIG_LEDS_TRIGGER_CAMERA)	+= ledtrig-camera.o
+obj-$(CONFIG_LEDS_TRIGGER_DEVICE)	+= ledtrig-device.o
drivers/leds/trigger/ledtrig-device.c new file +185 -0

185 lines not on this page · raw message

include/linux/leds.h +10 -0
index b122eeafb5dc17b8a8b1a1852dc1c420ecf0f8d2..e487d5b2ac556bdb2f1525d8b5e84df0c245d4c9 100644
@@ -369,4 +369,14 @@ static inline void ledtrig_cpu(enum cpu_led_event evt)
 }
 #endif
 
+#ifdef CONFIG_LEDS_TRIGGER_DEVICE
+extern void ledtrig_dev_add(dev_t dev);
+extern void ledtrig_dev_del(dev_t dev);
+extern void ledtrig_dev_activity(dev_t dev);
+#else
+static inline void ledtrig_dev_add(dev_t dev) {}
+static inline void ledtrig_dev_del(dev_t dev) {}
+static inline void ledtrig_dev_activity(dev_t dev) {}
+#endif
+
 #endif		/* __LINUX_LEDS_H_INCLUDED */
Signature · 1 line
2.6.0
#2 lore raw

Re: [PATCH v2 1/3] leds: add device activity LED triggers

Hello Maciek-

Some architectural questions below:

Quoted 7 lines · Maciek Borzecki

The patch adds LED triggers for indicating an activity on a selected device. The drivers that intend to use triggers need to register respective devices using ledtrig_dev_add(). Triggers are generated by explicitly calling ledtrig_dev_activity().

---

[..]

Quoted 4 lines
drivers/leds/trigger/ledtrig-device.c new file +4 -0
+struct ledtrig_dev_data {
+	char name[MAX_NAME_LEN];
+	dev_t dev;
+	struct led_trigger *trig;

drivers/leds/trigger/ledtrig-device.c line 41

Quoted 10 lines
drivers/leds/trigger/ledtrig-device.c new file +10 -0
+	struct list_head node;
+};
+
+/**
+ * ledtrig_dev_activity - signal activity on device
+ * @dev: device
+ *
+ * Fires a trigger assigned to @dev device.
+ */
+void ledtrig_dev_activity(dev_t dev)

It seems a bit strange to me to associate a device LED trigger with dev_t. Some devices don't expose a dev node, some devices expose multiple dev nodes...

Is there a reason why you are not tying to the device model?

Quoted 8 lines
drivers/leds/trigger/ledtrig-device.c new file +8 -0
+{
+	struct ledtrig_dev_data *dev_trig;
+
+	if (!down_read_trylock(&devs_list_lock))
+		return;
+
+	list_for_each_entry(dev_trig, &devs_list, node) {
+		if (dev_trig->dev == dev) {

drivers/leds/trigger/ledtrig-device.c line 59

Quoted 10 lines
drivers/leds/trigger/ledtrig-device.c new file +10 -0
+			led_trigger_blink_oneshot(dev_trig->trig,
+						  &blink_delay,
+						  &blink_delay,
+						  0);
+			break;
+		}
+	}
+	up_read(&devs_list_lock);
+}
+EXPORT_SYMBOL(ledtrig_dev_activity);

Not _GPL?

Josh

#3 lore raw

Re: [PATCH v2 1/3] leds: add device activity LED triggers

Quoted 32 lines · Josh Cartwright

Hello Maciek-

Some architectural questions below:

Quoted 7 lines · Maciek Borzecki

The patch adds LED triggers for indicating an activity on a selected device. The drivers that intend to use triggers need to register respective devices using ledtrig_dev_add(). Triggers are generated by explicitly calling ledtrig_dev_activity().

---

[..]

Quoted 4 lines
drivers/leds/trigger/ledtrig-device.c new file +4 -0
+struct ledtrig_dev_data {
+	char name[MAX_NAME_LEN];
+	dev_t dev;
+	struct led_trigger *trig;

drivers/leds/trigger/ledtrig-device.c line 41

Quoted 10 lines
drivers/leds/trigger/ledtrig-device.c new file +10 -0
+	struct list_head node;
+};
+
+/**
+ * ledtrig_dev_activity - signal activity on device
+ * @dev: device
+ *
+ * Fires a trigger assigned to @dev device.
+ */
+void ledtrig_dev_activity(dev_t dev)

It seems a bit strange to me to associate a device LED trigger with dev_t. Some devices don't expose a dev node, some devices expose multiple dev nodes...

Quoted 2 lines

Is there a reason why you are not tying to the device model?

Thanks for the comments.

The first proof of concept used sturct device as parameter in all API calls, but then there's a problem of naming of a trigger in a sane way. The trigger name followed the same approach as __dev_printk, and the naming was done in this fashion:

   sprintf(..., "dev-%s-%s", dev_driver_string(dev), dev_name(dev));

Then for instance on wandboard, /dev/ttymxc0 and /dev/ttymxc2 would appear as dev-serial-2020000 and dev-serial-21ec000. In my opinion this was unnecessarily complicated. Also, if I'm not mistaken, using this approach the partitions on MMC card or SATA drive would end up with the same trigger name, as it is a single device. However the the major:minor numbers assigned to respective partitions are different, and you'd still be able to say trigger the LEDS on writes to a particular partition.

Multiple dev nodes will already have different minor numbers, so their dev_t is different anyway.

As for devices that do not have a dev_t assigned to them one can still pass a custom tag in ledtrig_dev_add(). It's just a number so as long as there's no collision in numbering things should be fine.

Hopefull this clears up the things a little.

Quoted 12 lines
Quoted 12 lines
drivers/leds/trigger/ledtrig-device.c new file +12 -0
+{
+	struct ledtrig_dev_data *dev_trig;
+
+	if (!down_read_trylock(&devs_list_lock))
+		return;
+
+	list_for_each_entry(dev_trig, &devs_list, node) {
+		if (dev_trig->dev == dev) {
+			led_trigger_blink_oneshot(dev_trig->trig,
+						  &blink_delay,
+						  &blink_delay,
+						  0);
Quoted 8 lines

drivers/leds/trigger/ledtrig-device.c line 59

Quoted 6 lines
drivers/leds/trigger/ledtrig-device.c new file +6 -0
+			break;
+		}
+	}
+	up_read(&devs_list_lock);
+}
+EXPORT_SYMBOL(ledtrig_dev_activity);

Not _GPL?

I'm ok with EXPORT_SYMBOL_GPL() if that's a policy for new code. Though, I've looked at other triggers that are called from kernel code, and it seems that ledtrig-camera is the only one using _GPL.

--
Maciek Borzecki

#4 lore raw

Re: [PATCH v2 1/3] leds: add device activity LED triggers

Quoted 38 lines · Maciek Borzecki
Quoted 28 lines · Josh Cartwright
Quoted 7 lines · Maciek Borzecki

The patch adds LED triggers for indicating an activity on a selected device. The drivers that intend to use triggers need to register respective devices using ledtrig_dev_add(). Triggers are generated by explicitly calling ledtrig_dev_activity().

---

[..]

Quoted 4 lines
drivers/leds/trigger/ledtrig-device.c new file +4 -0
+struct ledtrig_dev_data {
+	char name[MAX_NAME_LEN];
+	dev_t dev;
+	struct led_trigger *trig;

drivers/leds/trigger/ledtrig-device.c line 41

Quoted 10 lines
drivers/leds/trigger/ledtrig-device.c new file +10 -0
+	struct list_head node;
+};
+
+/**
+ * ledtrig_dev_activity - signal activity on device
+ * @dev: device
+ *
+ * Fires a trigger assigned to @dev device.
+ */
+void ledtrig_dev_activity(dev_t dev)

It seems a bit strange to me to associate a device LED trigger with dev_t. Some devices don't expose a dev node, some devices expose multiple dev nodes...

Quoted 2 lines

Is there a reason why you are not tying to the device model?

Thanks for the comments.

The first proof of concept used sturct device as parameter in all API calls, but then there's a problem of naming of a trigger in a sane way. The trigger name followed the same approach as __dev_printk, and the naming was done in this fashion:

Quoted 5 lines
   sprintf(..., "dev-%s-%s", dev_driver_string(dev), dev_name(dev));

Then for instance on wandboard, /dev/ttymxc0 and /dev/ttymxc2 would appear as dev-serial-2020000 and dev-serial-21ec000. In my opinion this was unnecessarily complicated.

Hmm, maybe we're bikeshedding at this point, but LEDs with those names seem much more straightfoward to me than a "dev-<maj>:<min>" name, for devices which have done dynamic dev_t allocation.

Quoted 3 lines

Also, if I'm not mistaken, using this approach the partitions on MMC card or SATA drive would end up with the same trigger name, as it is a single device.

This would only be true if you used _just_ the struct device. I was imagining that you'd specify a (struct device, unsigned index) pair. Better, you could do a (struct device, const char *) pair.

Also, from a lifetime management perspective, it starts to feel like something that might integrate better as a managed resource (devm_*).

[..]

Quoted 2 lines

Multiple dev nodes will already have different minor numbers, so their dev_t is different anyway.

Okay, backing up I don't really see what this API really buys the consumer. The dev_t -> struct led_trigger mapping just seems like a total waste. Why not just make your ledtrig_dev_add() function return the struct led_trigger * that the consumer keeps track of?

Maybe seeing an example consumer would provide some clarification.

Quoted 3 lines

As for devices that do not have a dev_t assigned to them one can still pass a custom tag in ledtrig_dev_add(). It's just a number so as long as there's no collision in numbering things should be fine.

Ensuring no collision will be difficult, especially given that it's most common that the dynamic allocator is used. In order to guarantee no collisions, a user who doesn't expose any device nodes would need to do their own dev_t allocation...to use this interface. And that seems silly to me.

Josh

#5 lore raw

Re: [PATCH v2 1/3] leds: add device activity LED triggers

On 10/02 12:08, Josh Cartwright wrote:
<snip>

Quoted 31 lines

Hmm, maybe we're bikeshedding at this point, but LEDs with those names seem much more straightfoward to me than a "dev-<maj>:<min>" name, for devices which have done dynamic dev_t allocation.

Quoted 3 lines

Also, if I'm not mistaken, using this approach the partitions on MMC card or SATA drive would end up with the same trigger name, as it is a single device.

This would only be true if you used _just_ the struct device. I was imagining that you'd specify a (struct device, unsigned index) pair. Better, you could do a (struct device, const char *) pair.

Also, from a lifetime management perspective, it starts to feel like something that might integrate better as a managed resource (devm_*).

[..]

Quoted 2 lines

Multiple dev nodes will already have different minor numbers, so their dev_t is different anyway.

Okay, backing up I don't really see what this API really buys the consumer. The dev_t -> struct led_trigger mapping just seems like a total waste. Why not just make your ledtrig_dev_add() function return the struct led_trigger * that the consumer keeps track of?

Maybe seeing an example consumer would provide some clarification.

Quoted 3 lines

As for devices that do not have a dev_t assigned to them one can still pass a custom tag in ledtrig_dev_add(). It's just a number so as long as there's no collision in numbering things should be fine.

Quoted 5 lines

Ensuring no collision will be difficult, especially given that it's most common that the dynamic allocator is used. In order to guarantee no collisions, a user who doesn't expose any device nodes would need to do their own dev_t allocation...to use this interface. And that seems silly to me.

Thanks, I really appreciate your feedback.

--
Maciek Borzecki

#6 lore raw

PATCH v2 2/3 leds: add debugfs to device trigger

In reply to Maciek Borzecki

Add debugfs entries for device activity trigger. Three entries are created under /sys/kernel/debug/ledtrig-dev when the driver gets loaded. These are:

devices - cat'ing will produce a list of currently registered devices
in <major>:<minor> format, a line for each device.

register - echo'ing <major>:<minor> will create a trigger for this
device

unregister - echo'ing <major>:<minor> will delete a trigger for this
device

trigger - echo'ing <major>:<minor> will fire a trigger for this device

---
 drivers/leds/trigger/ledtrig-device.c | 145 +++++++++++++++++++++++++++++++++-
 1 file changed, 143 insertions(+), 2 deletions(-)
drivers/leds/trigger/ledtrig-device.c +143 -2
index dbb8d7d2b4a0258149c581a040c416d412d9ceeb..68f61fb6ebb05ceaee36c58f1a0244a66bf34847 100644
@@ -16,15 +16,19 @@
 #include <linux/list.h>
 #include <linux/rwsem.h>
 #include <linux/kdev_t.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
 
 #define BLINK_DELAY 30
 static unsigned long blink_delay = BLINK_DELAY;
 
 static DECLARE_RWSEM(devs_list_lock);
 static LIST_HEAD(devs_list);
+static struct dentry *debug_root;
 
 #define MAX_NAME_LEN 20
-
 struct ledtrig_dev_data {
 	char name[MAX_NAME_LEN];
 	dev_t dev;
@@ -114,8 +118,11 @@ void ledtrig_dev_add(dev_t dev)
 		/* register with led triggers */
 		led_trigger_register_simple(new_dev_trig->name,
 					    &new_dev_trig->trig);
-	else
+	else {
+		pr_warn("device %u:%u already registered\n",
+			MAJOR(dev), MINOR(dev));
 		kfree(new_dev_trig);
+	}
 }
 EXPORT_SYMBOL(ledtrig_dev_add);
 
@@ -167,13 +174,147 @@ static void ledtrig_dev_remove_all(void)
 	up_write(&devs_list_lock);
 }
 
+static int ledtrig_dev_devices_show(struct seq_file *s, void *unused)
+{
+	struct ledtrig_dev_data *dev_trig;
+
+	down_read(&devs_list_lock);
+	list_for_each_entry(dev_trig, &devs_list, node) {
+		seq_printf(s, "%u:%u\n", MAJOR(dev_trig->dev),
+			MINOR(dev_trig->dev));
+	}
+	up_read(&devs_list_lock);
+	return 0;
+}
+
+static int ledtrig_dev_devices_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ledtrig_dev_devices_show,
+			   &inode->i_private);
+}
+
+static const struct file_operations debug_devices_ops = {
+	.owner = THIS_MODULE,
+	.open = ledtrig_dev_devices_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release
+};
+
+static int get_dev_from_user(const char __user *buf, size_t size,
+			dev_t *dev)
+{
+	char temp[MAX_NAME_LEN];
+	unsigned int major;
+	unsigned int minor;
+	int ret;
+
+	WARN_ON(dev == NULL);
+	if (dev == NULL)
+		return -EINVAL;
+
+	if (size > sizeof(temp) || size == 0)
+		return -EINVAL;
+
+	if (copy_from_user(temp, buf, size) != 0)
+		return -EINVAL;
+
+	ret = sscanf(temp, "%u:%u", &major, &minor);
+	if (ret < 2)
+		return -EINVAL;
+
+	*dev = MKDEV(major, minor);
+	return 0;
+}
+
+static ssize_t ledtrig_dev_register_write(struct file *filp,
+					const char __user *buf,
+					size_t size, loff_t *off)
+{
+	dev_t dev;
+	int ret;
+
+	ret = get_dev_from_user(buf, size, &dev);
+	if (ret < 0)
+		return ret;
+
+	pr_debug("register device %u:%u\n", MAJOR(dev), MINOR(dev));
+	ledtrig_dev_add(dev);
+
+	return size;
+}
+
+static const struct file_operations debug_register_ops = {
+	.owner = THIS_MODULE,
+	.write = ledtrig_dev_register_write,
+};
+
+static ssize_t ledtrig_dev_unregister_write(struct file *filp,
+					    const char __user *buf,
+					    size_t size, loff_t *off)
+{
+	dev_t dev;
+	int ret;
+
+	ret = get_dev_from_user(buf, size, &dev);
+	if (ret < 0)
+		return ret;
+
+	pr_debug("unregister device %u:%u\n", MAJOR(dev), MINOR(dev));
+	ledtrig_dev_del(dev);
+
+	return size;
+}
+
+static const struct file_operations debug_unregister_ops = {
+	.owner = THIS_MODULE,
+	.write = ledtrig_dev_unregister_write,
+};
+
+static ssize_t ledtrig_dev_trigger_write(struct file *filp,
+					const char __user *buf,
+					size_t size, loff_t *off)
+{
+	dev_t dev;
+	int ret;
+
+	ret = get_dev_from_user(buf, size, &dev);
+	if (ret < 0)
+		return ret;
+
+	pr_debug("trigger device %u:%u\n", MAJOR(dev), MINOR(dev));
+	ledtrig_dev_activity(dev);
+
+	return size;
+}
+
+static const struct file_operations debug_trigger_ops = {
+	.owner = THIS_MODULE,
+	.write = ledtrig_dev_trigger_write,
+};
+
 static int __init ledtrig_dev_init(void)
 {
+	debug_root = debugfs_create_dir("ledtrig-dev", NULL);
+
+	if (debug_root) {
+		debugfs_create_file("devices", 0444, debug_root, NULL,
+				&debug_devices_ops);
+		debugfs_create_file("register", 0200, debug_root, NULL,
+				&debug_register_ops);
+		debugfs_create_file("unregister", 0200, debug_root, NULL,
+				&debug_unregister_ops);
+		debugfs_create_file("trigger", 0200, debug_root, NULL,
+				&debug_trigger_ops);
+	}
+
 	return 0;
 }
 
 static void __exit ledtrig_dev_exit(void)
 {
+	debugfs_remove_recursive(debug_root);
+
 	ledtrig_dev_remove_all();
 }
 
Signature · 1 line
2.6.0
#7 lore raw

PATCH v2 3/3 Documentation: leds: document ledtrig-device trigger

In reply to Maciek Borzecki

This patch adds documentation for ledtrig-device trigger.

---
 Documentation/leds/00-INDEX           |  3 +++
 Documentation/leds/ledtrig-device.txt | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)
 create mode 100644 Documentation/leds/ledtrig-device.txt
Documentation/leds/00-INDEX +3 -0
index b4ef1f34e25faafe544971f619019d748538e4de..7f18adaadc04756a6b52157a71f86bd131dd915c 100644
@@ -20,3 +20,6 @@ ledtrig-oneshot.txt
 	- One-shot LED trigger for both sporadic and dense events.
 ledtrig-transient.txt
 	- LED Transient Trigger, one shot timer activation.
+ledtrig-device.txt
+        - LED Device Activity Trigger for indicating an activity
+          on a device
\ No newline at end of file
Documentation/leds/ledtrig-device.txt new file +35 -0
new file mode 100644
index 0000000000000000000000000000000000000000..c13e1f3f6c1e462c9cf2f083e6f1b1c0838f86b2
@@ -0,0 +1,35 @@
+Device Activity LED Trigger
+==========================
+
+This is a LED trigger useful for signaling an activity on a given
+device identified by it's MKDEV(major, minor). A typical use case
+would be debugging of a device or a driver on an embedded board,
+patching up trivial electronic hardware design deficiencies in
+software or just plain desire to indicate activity on a certain
+device.
+
+Internally, a instance of a trigger is created and registered with LED
+triggers for every device added via ledtrig_dev_add() call. The
+triggers are named in the following manner:
+
+         `dev-<major>:<minor>`
+
+And can be selected from under /sys/class/leds/*/trigger. A device
+activity is explicitly indicated by calling ledtrig_dev_activity() for
+a registered device.
+
+The driver also creates a set of debugfs entries under
+/sys/kernel/debug/ledtrig-dev, these are:
+
+  devices - cat'ing will produce a list of currently registered
+            devices
+
+  register - echo'ing <major>:<minor> will create a trigger for this
+             device (note, you still need to add at least
+             ledtrig_dev_activity() hook)
+
+  unregister - echo'ing <major>:<minor> will delete a trigger for this
+               device
+
+  trigger - echo'ing <major>:<minor> will fire the trigger for this
+            device
Signature · 1 line
2.6.0
#8 lore raw
In reply to Maciek Borzecki

Hi Maciek,

I tested your trigger, and it works fine, but I wonder if it really improves the things.

Basically, similarly as Josh, I have doubts related to associating triggers with dev_t. It requires from user to figure out how they can obtain valid dev_t. For example, in case of v4l2 jpeg codec, I had to spend some time looking for the location of struct device containing dev_t related to the exposed encoder and decoder nodes, whereas addition of debugging instruction should be easy and intuitive.

It is much simpler to register a trigger with human readable names. What is more, use of dev_t makes the user thinking that there is some mechanism involved, that automatically associates device with trigger, and after some time of code investigation one gets disillusioned and realizes that dev_t is used only to uniquely identify registered triggers.

I tried to add trigger to the JPEG codec interrupt handler using ledtrig-oneshot, and below is the result:

drivers/media/platform/s5p-jpeg/jpeg-core.c +12 -0
index 9690f9d..af826d3 100644
@@ -28,6 +28,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-core.h>
 #include <media/videobuf2-dma-contig.h>
+#include <linux/leds.h>
 
 #include "jpeg-core.h"
 #include "jpeg-hw-s5p.h"
@@ -35,6 +36,9 @@
 #include "jpeg-hw-exynos3250.h"
 #include "jpeg-regs.h"
 
+static unsigned long blink_delay = 30;
+struct led_trigger *jpeg_led_trig;
+
 static struct s5p_jpeg_fmt sjpeg_formats[] = {
        {
                .name           = "JPEG JFIF",
@@ -2318,6 +2322,7 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+
 static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
 {
        unsigned int int_status;
@@ -2375,7 +2380,10 @@ static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
        v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
        curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
 
+       led_trigger_blink_oneshot(jpeg_led_trig, &blink_delay, &blink_delay, 0);
+
        spin_unlock(&jpeg->slock);
+
        return IRQ_HANDLED;
 }
 
@@ -2589,6 +2597,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
 
        v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
 
+       led_trigger_register_simple("jpeg-trig", &jpeg_led_trig);
+
        return 0;
 
 enc_vdev_register_rollback:
@@ -2633,6 +2643,8 @@ static int s5p_jpeg_remove(struct platform_device *pdev)
        if (!IS_ERR(jpeg->sclk))
                clk_put(jpeg->sclk);
 
+       led_trigger_unregister_simple(jpeg_led_trig);
+
        return 0;
 }
 

It needs addition of 6 lines of code versus 2 lines in case of ledtrig-device. Not a big deal, taking into account that we don't have to spend additional time looking for the suitable struct device.

Please note that in case of drivers that expose many dev nodes, there are cases like interrupt handlers, where struct device can't be automatically retrieved, but it needs additional analysis to find out which dev node given call to ISR referes to. In this case we would have to check current mode (encoding/decoding) and call either

	ledtrig_dev_activity(jpeg->vfd_encoder->dev.devt)
or
	ledtrig_dev_activity(jpeg->vfd_decoder->dev.devt).

When comparing the steps required from user space side to activate the triggers, it looks as follows:

ledtrig-oneshot (we have one trigger for encoding and decoding mode):
=================
#cd /sys/class/leds/aat1290
#cat triggers
#[none] jpeg-trig
#echo "jpeg-trig" > trigger

ledtrig-dev approach (we have to define trigger per dev_t, we choose encoder):
=====================
#grep . /sys/class/video4linux/video*/name #/sys/class/video4linux/video7/name:s5p-jpeg-enc #/sys/class/video4linux/video8/name:s5p-jpeg-dec
#ls -l /dev/video7
#crw-rw---T 1 root video 81, 8 Jan 1 03:32 /dev/video8
#echo "81:7" > /sys/kernel/debug/ledtrig-dev/register
#cd /sys/class/leds/aat1290
#cat triggers
#[none] dev-81:7
#echo "dev-81:7" > trigger

It seems that ledtrig-dev is more troublesome in use.

Please let me know if I missed something.

Quoted 46 lines · Maciek Borzecki

A series of patches that add yet another LED trigger, a device activity trigger.

The motivation is to have a LED trigger that is associated with a device and can be fired from cetrain points in the code that have been chosen by the developer. With this this device activity trigger it is possible for instance to easily hook up a tty driver for a console to blink one LED, yet another serial port to blink a second LED and writes to a block device to trigger a third LED.

The patches have been tested on Wandboard Quad.

The first patch adds the actual trigger. Each device wishing to use the trigger has to be explicitly registered by calling ledtrig_dev_add(), and passing it's dev_t. The intention is that the trigger will be used in scenarios that are impossible to foresee at this moment, and are likely to be approach in a case by case manner anyway.

The second patch adds couple of debugfs helpers.

The third patch adds documentation and notes on debugfs interface.

Example hooks into tty driver can be seen here:
https://github.com/bboozzoo/linux/commit/d8a875673e37b27d9c9066febe7633382f97d8af

Changes since v1:
- fixed debugfs user address space access
- added unregister debugfs attribute
- documentation update

Maciek Borzecki (3):
leds: add device activity LED triggers
leds: add debugfs to device trigger
Documentation: leds: document ledtrig-device trigger

  Documentation/leds/00-INDEX           |   3 +
  Documentation/leds/ledtrig-device.txt |  35 ++++
  drivers/leds/trigger/Kconfig          |   8 +
  drivers/leds/trigger/Makefile         |   1 +
  drivers/leds/trigger/ledtrig-device.c | 326 ++++++++++++++++++++++++++++++++++
  include/linux/leds.h                  |  10 ++
  6 files changed, 383 insertions(+)

create mode 100644 Documentation/leds/ledtrig-device.txt create mode 100644 drivers/leds/trigger/ledtrig-device.c

Signature · 2 lines
Best Regards,
Jacek Anaszewski
#9 lore raw
Quoted 128 lines · Jacek Anaszewski

Hi Maciek,

I tested your trigger, and it works fine, but I wonder if it really improves the things.

Basically, similarly as Josh, I have doubts related to associating triggers with dev_t. It requires from user to figure out how they can obtain valid dev_t. For example, in case of v4l2 jpeg codec, I had to spend some time looking for the location of struct device containing dev_t related to the exposed encoder and decoder nodes, whereas addition of debugging instruction should be easy and intuitive.

It is much simpler to register a trigger with human readable names. What is more, use of dev_t makes the user thinking that there is some mechanism involved, that automatically associates device with trigger, and after some time of code investigation one gets disillusioned and realizes that dev_t is used only to uniquely identify registered triggers.

I tried to add trigger to the JPEG codec interrupt handler using ledtrig-oneshot, and below is the result:

drivers/media/platform/s5p-jpeg/jpeg-core.c +8 -0
index 9690f9d..af826d3 100644
@@ -28,6 +28,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-core.h>
 #include <media/videobuf2-dma-contig.h>
+#include <linux/leds.h>
 
 #include "jpeg-core.h"
 #include "jpeg-hw-s5p.h"
@@ -35,6 +36,9 @@
 #include "jpeg-hw-exynos3250.h"
 #include "jpeg-regs.h"
 
+static unsigned long blink_delay = 30;
+struct led_trigger *jpeg_led_trig;
+
 static struct s5p_jpeg_fmt sjpeg_formats[] = {
        {
                .name           = "JPEG JFIF",
@@ -2318,6 +2322,7 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+
 static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
 {
        unsigned int int_status;
@@ -2375,7 +2380,10 @@ static irqreturn_t exynos4_jpeg_irq(int irq, void
 *priv)
        v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
        curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
 
+       led_trigger_blink_oneshot(jpeg_led_trig, &blink_delay, &blink_delay,
 0);
+
        spin_unlock(&jpeg->slock);
+
        return IRQ_HANDLED;

}

drivers/media/platform/s5p-jpeg/jpeg-core.c +2 -0
@@ -2589,6 +2597,8 @@ static int s5p_jpeg_probe(struct platform_device
 *pdev)
 
        v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
 
+       led_trigger_register_simple("jpeg-trig", &jpeg_led_trig);
+
        return 0;
 

enc_vdev_register_rollback:

drivers/media/platform/s5p-jpeg/jpeg-core.c +2 -0
@@ -2633,6 +2643,8 @@ static int s5p_jpeg_remove(struct platform_device
 *pdev)
        if (!IS_ERR(jpeg->sclk))
                clk_put(jpeg->sclk);
 
+       led_trigger_unregister_simple(jpeg_led_trig);
+
        return 0;
 }

It needs addition of 6 lines of code versus 2 lines in case of ledtrig-device. Not a big deal, taking into account that we don't have to spend additional time looking for the suitable struct device.

Please note that in case of drivers that expose many dev nodes, there are cases like interrupt handlers, where struct device can't be automatically retrieved, but it needs additional analysis to find out which dev node given call to ISR referes to. In this case we would have to check current mode (encoding/decoding) and call either

	ledtrig_dev_activity(jpeg->vfd_encoder->dev.devt)
or
	ledtrig_dev_activity(jpeg->vfd_decoder->dev.devt).

When comparing the steps required from user space side to activate the triggers, it looks as follows:

ledtrig-oneshot (we have one trigger for encoding and decoding mode):
=================
#cd /sys/class/leds/aat1290
#cat triggers
#[none] jpeg-trig
#echo "jpeg-trig" > trigger

ledtrig-dev approach (we have to define trigger per dev_t, we choose encoder):
=====================
#grep . /sys/class/video4linux/video*/name #/sys/class/video4linux/video7/name:s5p-jpeg-enc #/sys/class/video4linux/video8/name:s5p-jpeg-dec
#ls -l /dev/video7
#crw-rw---T 1 root video 81, 8 Jan 1 03:32 /dev/video8 #echo "81:7" > /sys/kernel/debug/ledtrig-dev/register
#cd /sys/class/leds/aat1290
#cat triggers
#[none] dev-81:7
#echo "dev-81:7" > trigger

Quoted 4 lines

It seems that ledtrig-dev is more troublesome in use.

Please let me know if I missed something.

Thanks for your comments. You've raised some fair points.

Although my use case is a bit different (multiple serial ports, each with a LED, port <-> LED mapping is user configurable, hooks at tty layer), I may have unnecessarily overengineered the solution. Indeed simply patching driver structures with struct led_trigger will work as well.

Regards,
--
Maciek Borzecki