1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * led_hw_brightness_mon.c 4 * 5 * This program monitors LED brightness level changes having its origin 6 * in hardware/firmware, i.e. outside of kernel control. 7 * A timestamp and brightness value is printed each time the brightness changes. 8 * 9 * Usage: led_hw_brightness_mon <device-name> 10 * 11 * <device-name> is the name of the LED class device to be monitored. Pressing 12 * CTRL+C will exit. 13 */ 14 15 #include <errno.h> 16 #include <fcntl.h> 17 #include <poll.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <time.h> 22 #include <unistd.h> 23 24 #include <linux/uleds.h> 25 26 int main(int argc, char const *argv[]) 27 { 28 int fd, ret; 29 char brightness_file_path[LED_MAX_NAME_SIZE + 11]; 30 struct pollfd pollfd; 31 struct timespec ts; 32 char buf[11]; 33 34 if (argc != 2) { 35 fprintf(stderr, "Requires <device-name> argument\n"); 36 return 1; 37 } 38 39 snprintf(brightness_file_path, LED_MAX_NAME_SIZE, 40 "/sys/class/leds/%s/brightness_hw_changed", argv[1]); 41 42 fd = open(brightness_file_path, O_RDONLY); 43 if (fd == -1) { 44 printf("Failed to open %s file\n", brightness_file_path); 45 return 1; 46 } 47 48 /* 49 * read may fail if no hw brightness change has occurred so far, 50 * but it is required to avoid spurious poll notifications in 51 * the opposite case. 52 */ 53 read(fd, buf, sizeof(buf)); 54 55 pollfd.fd = fd; 56 pollfd.events = POLLPRI; 57 58 while (1) { 59 ret = poll(&pollfd, 1, -1); 60 if (ret == -1) { 61 printf("Failed to poll %s file (%d)\n", 62 brightness_file_path, ret); 63 ret = 1; 64 break; 65 } 66 67 clock_gettime(CLOCK_MONOTONIC, &ts); 68 69 ret = read(fd, buf, sizeof(buf)); 70 if (ret < 0) 71 break; 72 73 ret = lseek(pollfd.fd, 0, SEEK_SET); 74 if (ret < 0) { 75 printf("lseek failed (%d)\n", ret); 76 break; 77 } 78 79 printf("[%ld.%09ld] %d\n", ts.tv_sec, ts.tv_nsec, atoi(buf)); 80 } 81 82 close(fd); 83 84 return ret; 85 } 86