mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
LEDs for 4.11
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJYq0qJAAoJEL1qUBy3i3wmPCgP/3XMatJDziwedPfs1qZXNXPM LLFGsmCtSC79TXyWYg9jgDoLKbt2G8Rb1KAvfhhPd7H/HRQD0YjwEHEzYv6BYE7O yns6t1ea1pZUGtqwPjSwvVybdZZgOsDI8T6OxIv2Tj7m4sI9w26undFPnWF7dIyG Kv14fLncXh1q4iwaXSfjFokI3V+o1xUH/fvLaLQ7w0EgbQn6VTgdn+fJr6aM1LH5 tcMyBnmaRg4D++erXPeqYxhRtG+Fn3NGolFjDWAXAxyxooVcyD9zJpdx65I2T03U eVUI7gIpB/niOnskVTwJsd/hKI/aow3lDU+tRWgZvicuM6Sj7GI1zKuVU13aoKFw TwcAnEE7oQJFuU4AmbDlHjso31cWcOOStKNFQXjOP1qbU6O5Q3SWaYET5cWaUNWM hanY/hoU3U40x7m64HM67TT6frz6jEbNorY/bUvVX+JHrJcKTFFReBeIMgrIT/St 0wZNHptYeOjkLHB+jURgnBVm6bTc4DJjtjnCTFQ/kOOiPgo6CikXFzzBzJHgPI9L /NfOsT13v2R6BJlvHgjNqIbj1gRCFHSYGloI5PBWAG5hk5z38GcJPlqvWxCQWOXs NSfzLPUiavkfOW1U/OQTNHeeDZXKBuWMui1QlpTX3XkGPviDwtoGxezzgSAltdMo LxIt/v0G4q5xJV3nDR19 =amlj -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
7aa7d60811
@ -23,6 +23,23 @@ Description:
|
|||||||
If the LED does not support different brightness levels, this
|
If the LED does not support different brightness levels, this
|
||||||
should be 1.
|
should be 1.
|
||||||
|
|
||||||
|
What: /sys/class/leds/<led>/brightness_hw_changed
|
||||||
|
Date: January 2017
|
||||||
|
KernelVersion: 4.11
|
||||||
|
Description:
|
||||||
|
Last hardware set brightness level for this LED. Some LEDs
|
||||||
|
may be changed autonomously by hardware/firmware. Only LEDs
|
||||||
|
where this happens and the driver can detect this, will have
|
||||||
|
this file.
|
||||||
|
|
||||||
|
This file supports poll() to detect when the hardware changes
|
||||||
|
the brightness.
|
||||||
|
|
||||||
|
Reading this file will return the last brightness level set
|
||||||
|
by the hardware, this may be different from the current
|
||||||
|
brightness. Reading this file when no hw brightness change
|
||||||
|
event has happened will return an ENODATA error.
|
||||||
|
|
||||||
What: /sys/class/leds/<led>/trigger
|
What: /sys/class/leds/<led>/trigger
|
||||||
Date: March 2006
|
Date: March 2006
|
||||||
KernelVersion: 2.6.17
|
KernelVersion: 2.6.17
|
||||||
|
@ -61,16 +61,24 @@ property can be omitted.
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
system-status {
|
gpio-leds {
|
||||||
label = "Status";
|
compatible = "gpio-leds";
|
||||||
linux,default-trigger = "heartbeat";
|
|
||||||
...
|
system-status {
|
||||||
|
label = "Status";
|
||||||
|
linux,default-trigger = "heartbeat";
|
||||||
|
gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
camera-flash {
|
max77693-led {
|
||||||
label = "Flash";
|
compatible = "maxim,max77693-led";
|
||||||
led-sources = <0>, <1>;
|
|
||||||
led-max-microamp = <50000>;
|
camera-flash {
|
||||||
flash-max-microamp = <320000>;
|
label = "Flash";
|
||||||
flash-max-timeout-us = <500000>;
|
led-sources = <0>, <1>;
|
||||||
|
led-max-microamp = <50000>;
|
||||||
|
flash-max-microamp = <320000>;
|
||||||
|
flash-max-timeout-us = <500000>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -65,6 +65,21 @@ LED subsystem core exposes following API for setting brightness:
|
|||||||
blinking, returns -EBUSY if software blink fallback is enabled.
|
blinking, returns -EBUSY if software blink fallback is enabled.
|
||||||
|
|
||||||
|
|
||||||
|
LED registration API
|
||||||
|
====================
|
||||||
|
|
||||||
|
A driver wanting to register a LED classdev for use by other drivers /
|
||||||
|
userspace needs to allocate and fill a led_classdev struct and then call
|
||||||
|
[devm_]led_classdev_register. If the non devm version is used the driver
|
||||||
|
must call led_classdev_unregister from its remove function before
|
||||||
|
free-ing the led_classdev struct.
|
||||||
|
|
||||||
|
If the driver can detect hardware initiated brightness changes and thus
|
||||||
|
wants to have a brightness_hw_changed attribute then the LED_BRIGHT_HW_CHANGED
|
||||||
|
flag must be set in flags before registering. Calling
|
||||||
|
led_classdev_notify_brightness_hw_changed on a classdev not registered with
|
||||||
|
the LED_BRIGHT_HW_CHANGED flag is a bug and will trigger a WARN_ON.
|
||||||
|
|
||||||
Hardware accelerated blink of LEDs
|
Hardware accelerated blink of LEDs
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
|
@ -29,6 +29,15 @@ config LEDS_CLASS_FLASH
|
|||||||
for the flash related features of a LED device. It can be built
|
for the flash related features of a LED device. It can be built
|
||||||
as a module.
|
as a module.
|
||||||
|
|
||||||
|
config LEDS_BRIGHTNESS_HW_CHANGED
|
||||||
|
bool "LED Class brightness_hw_changed attribute support"
|
||||||
|
depends on LEDS_CLASS
|
||||||
|
help
|
||||||
|
This option enables support for the brightness_hw_changed attribute
|
||||||
|
for led sysfs class devices under /sys/class/leds.
|
||||||
|
|
||||||
|
See Documentation/ABI/testing/sysfs-class-led for details.
|
||||||
|
|
||||||
comment "LED drivers"
|
comment "LED drivers"
|
||||||
|
|
||||||
config LEDS_88PM860X
|
config LEDS_88PM860X
|
||||||
|
@ -103,6 +103,68 @@ static const struct attribute_group *led_groups[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
|
||||||
|
static ssize_t brightness_hw_changed_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (led_cdev->brightness_hw_changed == -1)
|
||||||
|
return -ENODATA;
|
||||||
|
|
||||||
|
return sprintf(buf, "%u\n", led_cdev->brightness_hw_changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RO(brightness_hw_changed);
|
||||||
|
|
||||||
|
static int led_add_brightness_hw_changed(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
struct device *dev = led_cdev->dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = device_create_file(dev, &dev_attr_brightness_hw_changed);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Error creating brightness_hw_changed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
led_cdev->brightness_hw_changed_kn =
|
||||||
|
sysfs_get_dirent(dev->kobj.sd, "brightness_hw_changed");
|
||||||
|
if (!led_cdev->brightness_hw_changed_kn) {
|
||||||
|
dev_err(dev, "Error getting brightness_hw_changed kn\n");
|
||||||
|
device_remove_file(dev, &dev_attr_brightness_hw_changed);
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
sysfs_put(led_cdev->brightness_hw_changed_kn);
|
||||||
|
device_remove_file(led_cdev->dev, &dev_attr_brightness_hw_changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void led_classdev_notify_brightness_hw_changed(struct led_classdev *led_cdev,
|
||||||
|
enum led_brightness brightness)
|
||||||
|
{
|
||||||
|
if (WARN_ON(!led_cdev->brightness_hw_changed_kn))
|
||||||
|
return;
|
||||||
|
|
||||||
|
led_cdev->brightness_hw_changed = brightness;
|
||||||
|
sysfs_notify_dirent(led_cdev->brightness_hw_changed_kn);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(led_classdev_notify_brightness_hw_changed);
|
||||||
|
#else
|
||||||
|
static int led_add_brightness_hw_changed(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* led_classdev_suspend - suspend an led_classdev.
|
* led_classdev_suspend - suspend an led_classdev.
|
||||||
* @led_cdev: the led_classdev to suspend.
|
* @led_cdev: the led_classdev to suspend.
|
||||||
@ -204,9 +266,20 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
|
|||||||
dev_warn(parent, "Led %s renamed to %s due to name collision",
|
dev_warn(parent, "Led %s renamed to %s due to name collision",
|
||||||
led_cdev->name, dev_name(led_cdev->dev));
|
led_cdev->name, dev_name(led_cdev->dev));
|
||||||
|
|
||||||
|
if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) {
|
||||||
|
ret = led_add_brightness_hw_changed(led_cdev);
|
||||||
|
if (ret) {
|
||||||
|
device_unregister(led_cdev->dev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
led_cdev->work_flags = 0;
|
led_cdev->work_flags = 0;
|
||||||
#ifdef CONFIG_LEDS_TRIGGERS
|
#ifdef CONFIG_LEDS_TRIGGERS
|
||||||
init_rwsem(&led_cdev->trigger_lock);
|
init_rwsem(&led_cdev->trigger_lock);
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
|
||||||
|
led_cdev->brightness_hw_changed = -1;
|
||||||
#endif
|
#endif
|
||||||
mutex_init(&led_cdev->led_access);
|
mutex_init(&led_cdev->led_access);
|
||||||
/* add to the list of leds */
|
/* add to the list of leds */
|
||||||
@ -256,6 +329,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
|
|||||||
|
|
||||||
flush_work(&led_cdev->set_brightness_work);
|
flush_work(&led_cdev->set_brightness_work);
|
||||||
|
|
||||||
|
if (led_cdev->flags & LED_BRIGHT_HW_CHANGED)
|
||||||
|
led_remove_brightness_hw_changed(led_cdev);
|
||||||
|
|
||||||
device_unregister(led_cdev->dev);
|
device_unregister(led_cdev->dev);
|
||||||
|
|
||||||
down_write(&leds_list_lock);
|
down_write(&leds_list_lock);
|
||||||
|
@ -270,15 +270,15 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
|
|||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
|
led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
|
||||||
if (IS_ERR(led->ctrl_gpio)) {
|
ret = PTR_ERR_OR_ZERO(led->ctrl_gpio);
|
||||||
ret = PTR_ERR(led->ctrl_gpio);
|
if (ret) {
|
||||||
dev_err(dev, "cannot get ctrl-gpios %d\n", ret);
|
dev_err(dev, "cannot get ctrl-gpios %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
led->aux_gpio = devm_gpiod_get(dev, "aux", GPIOD_ASIS);
|
led->aux_gpio = devm_gpiod_get(dev, "aux", GPIOD_ASIS);
|
||||||
if (IS_ERR(led->aux_gpio)) {
|
ret = PTR_ERR_OR_ZERO(led->aux_gpio);
|
||||||
ret = PTR_ERR(led->aux_gpio);
|
if (ret) {
|
||||||
dev_err(dev, "cannot get aux-gpios %d\n", ret);
|
dev_err(dev, "cannot get aux-gpios %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,9 @@ static void led_heartbeat_function(unsigned long data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (test_and_clear_bit(LED_BLINK_BRIGHTNESS_CHANGE, &led_cdev->work_flags))
|
||||||
|
led_cdev->blink_brightness = led_cdev->new_blink_brightness;
|
||||||
|
|
||||||
/* acts like an actual heart beat -- ie thump-thump-pause... */
|
/* acts like an actual heart beat -- ie thump-thump-pause... */
|
||||||
switch (heartbeat_data->phase) {
|
switch (heartbeat_data->phase) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -59,26 +62,26 @@ static void led_heartbeat_function(unsigned long data)
|
|||||||
delay = msecs_to_jiffies(70);
|
delay = msecs_to_jiffies(70);
|
||||||
heartbeat_data->phase++;
|
heartbeat_data->phase++;
|
||||||
if (!heartbeat_data->invert)
|
if (!heartbeat_data->invert)
|
||||||
brightness = led_cdev->max_brightness;
|
brightness = led_cdev->blink_brightness;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
|
delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
|
||||||
heartbeat_data->phase++;
|
heartbeat_data->phase++;
|
||||||
if (heartbeat_data->invert)
|
if (heartbeat_data->invert)
|
||||||
brightness = led_cdev->max_brightness;
|
brightness = led_cdev->blink_brightness;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
delay = msecs_to_jiffies(70);
|
delay = msecs_to_jiffies(70);
|
||||||
heartbeat_data->phase++;
|
heartbeat_data->phase++;
|
||||||
if (!heartbeat_data->invert)
|
if (!heartbeat_data->invert)
|
||||||
brightness = led_cdev->max_brightness;
|
brightness = led_cdev->blink_brightness;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
delay = heartbeat_data->period - heartbeat_data->period / 4 -
|
delay = heartbeat_data->period - heartbeat_data->period / 4 -
|
||||||
msecs_to_jiffies(70);
|
msecs_to_jiffies(70);
|
||||||
heartbeat_data->phase = 0;
|
heartbeat_data->phase = 0;
|
||||||
if (heartbeat_data->invert)
|
if (heartbeat_data->invert)
|
||||||
brightness = led_cdev->max_brightness;
|
brightness = led_cdev->blink_brightness;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +136,10 @@ static void heartbeat_trig_activate(struct led_classdev *led_cdev)
|
|||||||
setup_timer(&heartbeat_data->timer,
|
setup_timer(&heartbeat_data->timer,
|
||||||
led_heartbeat_function, (unsigned long) led_cdev);
|
led_heartbeat_function, (unsigned long) led_cdev);
|
||||||
heartbeat_data->phase = 0;
|
heartbeat_data->phase = 0;
|
||||||
|
if (!led_cdev->blink_brightness)
|
||||||
|
led_cdev->blink_brightness = led_cdev->max_brightness;
|
||||||
led_heartbeat_function(heartbeat_data->timer.data);
|
led_heartbeat_function(heartbeat_data->timer.data);
|
||||||
|
set_bit(LED_BLINK_SW, &led_cdev->work_flags);
|
||||||
led_cdev->activated = true;
|
led_cdev->activated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +151,7 @@ static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
|
|||||||
del_timer_sync(&heartbeat_data->timer);
|
del_timer_sync(&heartbeat_data->timer);
|
||||||
device_remove_file(led_cdev->dev, &dev_attr_invert);
|
device_remove_file(led_cdev->dev, &dev_attr_invert);
|
||||||
kfree(heartbeat_data);
|
kfree(heartbeat_data);
|
||||||
|
clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
|
||||||
led_cdev->activated = false;
|
led_cdev->activated = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#define __LINUX_LEDS_H_INCLUDED
|
#define __LINUX_LEDS_H_INCLUDED
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/kernfs.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/rwsem.h>
|
#include <linux/rwsem.h>
|
||||||
@ -27,6 +28,7 @@ struct device;
|
|||||||
|
|
||||||
enum led_brightness {
|
enum led_brightness {
|
||||||
LED_OFF = 0,
|
LED_OFF = 0,
|
||||||
|
LED_ON = 1,
|
||||||
LED_HALF = 127,
|
LED_HALF = 127,
|
||||||
LED_FULL = 255,
|
LED_FULL = 255,
|
||||||
};
|
};
|
||||||
@ -46,6 +48,7 @@ struct led_classdev {
|
|||||||
#define LED_DEV_CAP_FLASH (1 << 18)
|
#define LED_DEV_CAP_FLASH (1 << 18)
|
||||||
#define LED_HW_PLUGGABLE (1 << 19)
|
#define LED_HW_PLUGGABLE (1 << 19)
|
||||||
#define LED_PANIC_INDICATOR (1 << 20)
|
#define LED_PANIC_INDICATOR (1 << 20)
|
||||||
|
#define LED_BRIGHT_HW_CHANGED (1 << 21)
|
||||||
|
|
||||||
/* set_brightness_work / blink_timer flags, atomic, private. */
|
/* set_brightness_work / blink_timer flags, atomic, private. */
|
||||||
unsigned long work_flags;
|
unsigned long work_flags;
|
||||||
@ -110,6 +113,11 @@ struct led_classdev {
|
|||||||
bool activated;
|
bool activated;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
|
||||||
|
int brightness_hw_changed;
|
||||||
|
struct kernfs_node *brightness_hw_changed_kn;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Ensures consistent access to the LED Flash Class device */
|
/* Ensures consistent access to the LED Flash Class device */
|
||||||
struct mutex led_access;
|
struct mutex led_access;
|
||||||
};
|
};
|
||||||
@ -422,4 +430,12 @@ static inline void ledtrig_cpu(enum cpu_led_event evt)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
|
||||||
|
extern void led_classdev_notify_brightness_hw_changed(
|
||||||
|
struct led_classdev *led_cdev, enum led_brightness brightness);
|
||||||
|
#else
|
||||||
|
static inline void led_classdev_notify_brightness_hw_changed(
|
||||||
|
struct led_classdev *led_cdev, enum led_brightness brightness) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __LINUX_LEDS_H_INCLUDED */
|
#endif /* __LINUX_LEDS_H_INCLUDED */
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
CC = $(CROSS_COMPILE)gcc
|
CC = $(CROSS_COMPILE)gcc
|
||||||
CFLAGS = -Wall -Wextra -g -I../../include/uapi
|
CFLAGS = -Wall -Wextra -g -I../../include/uapi
|
||||||
|
|
||||||
all: uledmon
|
all: uledmon led_hw_brightness_mon
|
||||||
%: %.c
|
%: %.c
|
||||||
$(CC) $(CFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) uledmon
|
$(RM) uledmon led_hw_brightness_mon
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
84
tools/leds/led_hw_brightness_mon.c
Normal file
84
tools/leds/led_hw_brightness_mon.c
Normal file
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user