diff options
| author | Jacek Anaszewski <jacek.anaszewski@gmail.com> | 2017-01-29 06:52:31 -0500 |
|---|---|---|
| committer | Jacek Anaszewski <jacek.anaszewski@gmail.com> | 2017-02-14 16:20:23 -0500 |
| commit | ae3473231e77a3f1909d48cd144cebe5e1d049b3 (patch) | |
| tree | 8541d32cc0a4e7b426bb1b962de504fd1f0e02fc | |
| parent | 0cb8eb30d425d2d2ae28ab630596c44a158784c4 (diff) | |
tools/leds: Add led_hw_brightness_mon program
LED subsystem supports POLLPRI on "brightness_hw_changed" sysfs file
of LED class devices. This tool demonstrates how to use the feature.
Signed-off-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
Acked-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
| -rw-r--r-- | tools/leds/Makefile | 4 | ||||
| -rw-r--r-- | tools/leds/led_hw_brightness_mon.c | 84 |
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 @@ | |||
| 3 | CC = $(CROSS_COMPILE)gcc | 3 | CC = $(CROSS_COMPILE)gcc |
| 4 | CFLAGS = -Wall -Wextra -g -I../../include/uapi | 4 | CFLAGS = -Wall -Wextra -g -I../../include/uapi |
| 5 | 5 | ||
| 6 | all: uledmon | 6 | all: uledmon led_hw_brightness_mon |
| 7 | %: %.c | 7 | %: %.c |
| 8 | $(CC) $(CFLAGS) -o $@ $^ | 8 | $(CC) $(CFLAGS) -o $@ $^ |
| 9 | 9 | ||
| 10 | clean: | 10 | clean: |
| 11 | $(RM) uledmon | 11 | $(RM) uledmon led_hw_brightness_mon |
| 12 | 12 | ||
| 13 | .PHONY: all clean | 13 | .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 @@ | |||
| 1 | /* | ||
| 2 | * led_hw_brightness_mon.c | ||
| 3 | * | ||
| 4 | * This program monitors LED brightness level changes having its origin | ||
| 5 | * in hardware/firmware, i.e. outside of kernel control. | ||
| 6 | * A timestamp and brightness value is printed each time the brightness changes. | ||
| 7 | * | ||
| 8 | * Usage: led_hw_brightness_mon <device-name> | ||
| 9 | * | ||
| 10 | * <device-name> is the name of the LED class device to be monitored. Pressing | ||
| 11 | * CTRL+C will exit. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <errno.h> | ||
| 15 | #include <fcntl.h> | ||
| 16 | #include <poll.h> | ||
| 17 | #include <stdio.h> | ||
| 18 | #include <stdlib.h> | ||
| 19 | #include <string.h> | ||
| 20 | #include <time.h> | ||
| 21 | #include <unistd.h> | ||
| 22 | |||
| 23 | #include <linux/uleds.h> | ||
| 24 | |||
| 25 | int main(int argc, char const *argv[]) | ||
| 26 | { | ||
| 27 | int fd, ret; | ||
| 28 | char brightness_file_path[LED_MAX_NAME_SIZE + 11]; | ||
| 29 | struct pollfd pollfd; | ||
| 30 | struct timespec ts; | ||
| 31 | char buf[11]; | ||
| 32 | |||
| 33 | if (argc != 2) { | ||
| 34 | fprintf(stderr, "Requires <device-name> argument\n"); | ||
| 35 | return 1; | ||
| 36 | } | ||
| 37 | |||
| 38 | snprintf(brightness_file_path, LED_MAX_NAME_SIZE, | ||
| 39 | "/sys/class/leds/%s/brightness_hw_changed", argv[1]); | ||
| 40 | |||
| 41 | fd = open(brightness_file_path, O_RDONLY); | ||
| 42 | if (fd == -1) { | ||
| 43 | printf("Failed to open %s file\n", brightness_file_path); | ||
| 44 | return 1; | ||
| 45 | } | ||
| 46 | |||
| 47 | /* | ||
| 48 | * read may fail if no hw brightness change has occurred so far, | ||
| 49 | * but it is required to avoid spurious poll notifications in | ||
| 50 | * the opposite case. | ||
| 51 | */ | ||
| 52 | read(fd, buf, sizeof(buf)); | ||
| 53 | |||
| 54 | pollfd.fd = fd; | ||
| 55 | pollfd.events = POLLPRI; | ||
| 56 | |||
| 57 | while (1) { | ||
| 58 | ret = poll(&pollfd, 1, -1); | ||
| 59 | if (ret == -1) { | ||
| 60 | printf("Failed to poll %s file (%d)\n", | ||
| 61 | brightness_file_path, ret); | ||
| 62 | ret = 1; | ||
| 63 | break; | ||
| 64 | } | ||
| 65 | |||
| 66 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
| 67 | |||
| 68 | ret = read(fd, buf, sizeof(buf)); | ||
| 69 | if (ret < 0) | ||
| 70 | break; | ||
| 71 | |||
| 72 | ret = lseek(pollfd.fd, 0, SEEK_SET); | ||
| 73 | if (ret < 0) { | ||
| 74 | printf("lseek failed (%d)\n", ret); | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | |||
| 78 | printf("[%ld.%09ld] %d\n", ts.tv_sec, ts.tv_nsec, atoi(buf)); | ||
| 79 | } | ||
| 80 | |||
| 81 | close(fd); | ||
| 82 | |||
| 83 | return ret; | ||
| 84 | } | ||
