summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-02-20 17:31:23 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-20 17:31:23 -0800
commit7aa7d608112baf63a0b1278955f9619427373807 (patch)
treeb6a7ed4233ddf3a6760bd72aed93d4b83b1f7c45 /tools
parent85adbcd54f0982040c8cc7a086f01554b8f64427 (diff)
parentfb3d769173d26268d7bf068094a599bb28b2ac63 (diff)
Merge tag 'leds_for_4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds
Pull LED updates from Jacek Anaszewski: "New features and improvements: - add new optional brightness_hw_changed attribute for the LEDs that may have their brightness level changed autonomously (outside of kernel control) by hardware / firmware. The attribute supports userspace notifications through POLLPRI events - add led_brightness_hw_mon tool that demonstrates how to use the aforementioned feature - add LED_ON enum for LEDs that can be only turned on/off, and don't allow setting other brightness levels - allow for adjusting heartbeat trigger blink brightness level Fixes and cleanups: - avoid harmless maybe-uninitialized warning in leds-ktd2692.c - add context to the existing example entries in common LED bindings to make the documentation more clear" * tag 'leds_for_4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds: leds: ledtrig-heartbeat: Make top brightness adjustable tools/leds: Add led_hw_brightness_mon program leds: class: Add new optional brightness_hw_changed attribute leds: ktd2692: avoid harmless maybe-uninitialized warning leds: add LED_ON brightness as boolean value DT: leds: Improve examples by adding some context
Diffstat (limited to 'tools')
-rw-r--r--tools/leds/Makefile4
-rw-r--r--tools/leds/led_hw_brightness_mon.c84
2 files changed, 86 insertions, 2 deletions
diff --git a/tools/leds/Makefile b/tools/leds/Makefile
index c03a79ebf9c8..078b666fd78b 100644
--- a/tools/leds/Makefile
+++ b/tools/leds/Makefile
@@ -3,11 +3,11 @@
CC = $(CROSS_COMPILE)gcc
CFLAGS = -Wall -Wextra -g -I../../include/uapi
-all: uledmon
+all: uledmon led_hw_brightness_mon
%: %.c
$(CC) $(CFLAGS) -o $@ $^
clean:
- $(RM) uledmon
+ $(RM) uledmon led_hw_brightness_mon
.PHONY: all clean
diff --git a/tools/leds/led_hw_brightness_mon.c b/tools/leds/led_hw_brightness_mon.c
new file mode 100644
index 000000000000..64642ccfe442
--- /dev/null
+++ b/tools/leds/led_hw_brightness_mon.c
@@ -0,0 +1,84 @@
+/*
+ * led_hw_brightness_mon.c
+ *
+ * This program monitors LED brightness level changes having its origin
+ * in hardware/firmware, i.e. outside of kernel control.
+ * A timestamp and brightness value is printed each time the brightness changes.
+ *
+ * Usage: led_hw_brightness_mon <device-name>
+ *
+ * <device-name> is the name of the LED class device to be monitored. Pressing
+ * CTRL+C will exit.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/uleds.h>
+
+int main(int argc, char const *argv[])
+{
+ int fd, ret;
+ char brightness_file_path[LED_MAX_NAME_SIZE + 11];
+ struct pollfd pollfd;
+ struct timespec ts;
+ char buf[11];
+
+ if (argc != 2) {
+ fprintf(stderr, "Requires <device-name> argument\n");
+ return 1;
+ }
+
+ snprintf(brightness_file_path, LED_MAX_NAME_SIZE,
+ "/sys/class/leds/%s/brightness_hw_changed", argv[1]);
+
+ fd = open(brightness_file_path, O_RDONLY);
+ if (fd == -1) {
+ printf("Failed to open %s file\n", brightness_file_path);
+ return 1;
+ }
+
+ /*
+ * read may fail if no hw brightness change has occurred so far,
+ * but it is required to avoid spurious poll notifications in
+ * the opposite case.
+ */
+ read(fd, buf, sizeof(buf));
+
+ pollfd.fd = fd;
+ pollfd.events = POLLPRI;
+
+ while (1) {
+ ret = poll(&pollfd, 1, -1);
+ if (ret == -1) {
+ printf("Failed to poll %s file (%d)\n",
+ brightness_file_path, ret);
+ ret = 1;
+ break;
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ ret = read(fd, buf, sizeof(buf));
+ if (ret < 0)
+ break;
+
+ ret = lseek(pollfd.fd, 0, SEEK_SET);
+ if (ret < 0) {
+ printf("lseek failed (%d)\n", ret);
+ break;
+ }
+
+ printf("[%ld.%09ld] %d\n", ts.tv_sec, ts.tv_nsec, atoi(buf));
+ }
+
+ close(fd);
+
+ return ret;
+}