18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * led_hw_brightness_mon.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This program monitors LED brightness level changes having its origin 68c2ecf20Sopenharmony_ci * in hardware/firmware, i.e. outside of kernel control. 78c2ecf20Sopenharmony_ci * A timestamp and brightness value is printed each time the brightness changes. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Usage: led_hw_brightness_mon <device-name> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * <device-name> is the name of the LED class device to be monitored. Pressing 128c2ecf20Sopenharmony_ci * CTRL+C will exit. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <errno.h> 168c2ecf20Sopenharmony_ci#include <fcntl.h> 178c2ecf20Sopenharmony_ci#include <poll.h> 188c2ecf20Sopenharmony_ci#include <stdio.h> 198c2ecf20Sopenharmony_ci#include <stdlib.h> 208c2ecf20Sopenharmony_ci#include <string.h> 218c2ecf20Sopenharmony_ci#include <time.h> 228c2ecf20Sopenharmony_ci#include <unistd.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/uleds.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciint main(int argc, char const *argv[]) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci int fd, ret; 298c2ecf20Sopenharmony_ci char brightness_file_path[LED_MAX_NAME_SIZE + 11]; 308c2ecf20Sopenharmony_ci struct pollfd pollfd; 318c2ecf20Sopenharmony_ci struct timespec ts; 328c2ecf20Sopenharmony_ci char buf[11]; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (argc != 2) { 358c2ecf20Sopenharmony_ci fprintf(stderr, "Requires <device-name> argument\n"); 368c2ecf20Sopenharmony_ci return 1; 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci snprintf(brightness_file_path, LED_MAX_NAME_SIZE, 408c2ecf20Sopenharmony_ci "/sys/class/leds/%s/brightness_hw_changed", argv[1]); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci fd = open(brightness_file_path, O_RDONLY); 438c2ecf20Sopenharmony_ci if (fd == -1) { 448c2ecf20Sopenharmony_ci printf("Failed to open %s file\n", brightness_file_path); 458c2ecf20Sopenharmony_ci return 1; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * read may fail if no hw brightness change has occurred so far, 508c2ecf20Sopenharmony_ci * but it is required to avoid spurious poll notifications in 518c2ecf20Sopenharmony_ci * the opposite case. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci read(fd, buf, sizeof(buf)); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci pollfd.fd = fd; 568c2ecf20Sopenharmony_ci pollfd.events = POLLPRI; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci while (1) { 598c2ecf20Sopenharmony_ci ret = poll(&pollfd, 1, -1); 608c2ecf20Sopenharmony_ci if (ret == -1) { 618c2ecf20Sopenharmony_ci printf("Failed to poll %s file (%d)\n", 628c2ecf20Sopenharmony_ci brightness_file_path, ret); 638c2ecf20Sopenharmony_ci ret = 1; 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &ts); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci ret = read(fd, buf, sizeof(buf)); 708c2ecf20Sopenharmony_ci if (ret < 0) 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci ret = lseek(pollfd.fd, 0, SEEK_SET); 748c2ecf20Sopenharmony_ci if (ret < 0) { 758c2ecf20Sopenharmony_ci printf("lseek failed (%d)\n", ret); 768c2ecf20Sopenharmony_ci break; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci printf("[%ld.%09ld] %d\n", ts.tv_sec, ts.tv_nsec, atoi(buf)); 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci close(fd); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return ret; 858c2ecf20Sopenharmony_ci} 86