led: core: RfC - add RGB LED handling to the core
PATCH 1/1 led: core: RfC - add RGB LED handling to the core
When playing with a ThingM Blink(1) USB RGB LED device I found that there are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.
Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one led_classdev per RGB LED. Also userspace should be able to change the color with one call -> therefore only one sysfs attribute for the RGB values.
Also the current brightness-related functionality should not be effected by the RGB extension.
This patch is intended to demonstrate the idea of the extension. Most likely it's not ready yet for submission.
Main idea is to base the effective RGB value on a combination of brightness and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags bitmap.
Experimentally I changed the thingm driver to use this extension and it works quite well. As one result the driver could be very much simplified.
Any feedback is appreciated.
--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)
drivers/leds/led-class.c +62 -0
@@ -64,6 +64,47 @@ unlock: }static DEVICE_ATTR_RW (brightness); +static ssize_t rgb_show (struct device *dev,struct device_attribute *attr, +char *buf) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +u32 rgb_val; + +mutex_lock (&led_cdev->led_access); +led_update_rgb_val (led_cdev); + rgb_val =led_get_rgb_val (led_cdev); +mutex_unlock (&led_cdev->led_access); + +return sprintf (buf,"0x%06x\n" , rgb_val); +} + +static ssize_t rgb_store (struct device *dev,struct device_attribute *attr, +const char *buf,size_t size) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +unsigned long state; +ssize_t ret; + +mutex_lock (&led_cdev->led_access); + +if (led_sysfs_is_disabled (led_cdev)) { + ret = -EBUSY ; + goto unlock; + } + + ret =kstrtoul (buf,0 , &state); +if (ret) + goto unlock; + +led_set_rgb_val (led_cdev, state); + + ret = size; +unlock: +mutex_unlock (&led_cdev->led_access); +return ret; +} +static DEVICE_ATTR_RW (rgb); +static ssize_t max_brightness_show (struct device *dev,struct device_attribute *attr,char *buf) {
@@ -190,6 +231,16 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)char name[64 ];int ret; +/* FLASH is not supported for RGB LEDs so far +* and RGB enforces max_brightness = LED_FULL. +* Initialize the color as white. +*/ +if (led_isRGB (led_cdev)) { + led_cdev->flags &= ~LED_DEV_CAP_FLASH ; + led_cdev->max_brightness =LED_FULL ; + led_cdev->rgb_val =0xffffff ; + } + ret =led_classdev_next_name (led_cdev->name, name,sizeof (name));if (ret <0 )return ret;
@@ -203,6 +254,14 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)dev_warn (parent,"Led %s renamed to %s due to name collision" , led_cdev->name,dev_name (led_cdev->dev)); +if (led_isRGB (led_cdev)) { + ret =device_create_file (led_cdev->dev, &dev_attr_rgb); +if (ret) { +device_unregister (led_cdev->dev); +return ret; + } + } +#ifdef CONFIG_LEDS_TRIGGERS init_rwsem (&led_cdev->trigger_lock);#endif
@@ -252,6 +311,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)flush_work (&led_cdev->set_brightness_work); +if (led_isRGB (led_cdev)) +device_remove_file (led_cdev->dev, &dev_attr_rgb); +device_unregister (led_cdev->dev);down_write (&leds_list_lock);
drivers/leds/led-core.c +106 -0
145 lines not on this page · raw message
drivers/leds/leds.h +12 -0
@@ -16,17 +16,29 @@#include <linux/rwsem.h> #include <linux/leds.h> +static inline bool led_isRGB (struct led_classdev *led_cdev) +{ +return (led_cdev->flags &LED_RGB ) !=0 ; +} +static inline int led_get_brightness (struct led_classdev *led_cdev) {return led_cdev->brightness; } +static inline u32 led_get_rgb_val (struct led_classdev *led_cdev) +{ +return led_cdev->rgb_val; +} +void led_init_core (struct led_classdev *led_cdev);void led_stop_software_blink (struct led_classdev *led_cdev);void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value);void led_set_brightness_nosleep (struct led_classdev *led_cdev,enum led_brightness value); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val); +int led_update_rgb_val (struct led_classdev *led_cdev);extern struct rw_semaphore leds_list_lock;extern struct list_head leds_list;
include/linux/leds.h +13 -0
@@ -35,6 +35,7 @@ struct led_classdev {const char *name;enum led_brightness brightness;enum led_brightness max_brightness; +u32 rgb_val;int flags;/* Lower 16 bits reflect status */
@@ -48,6 +49,7 @@ struct led_classdev {#define LED_BLINK_DISABLE (1 << 21)#define LED_SYSFS_DISABLE (1 << 22)#define LED_DEV_CAP_FLASH (1 << 23) +#define LED_RGB (1 << 24)/* Set LED brightness level */ /* Must not sleep. If no non-blocking version can be provided
@@ -56,15 +58,25 @@ struct led_classdev {*/ void (*brightness_set)(struct led_classdev *led_cdev,enum led_brightness brightness); + +void (*rgb_set)(struct led_classdev *led_cdev, +u32 rgb_val);/* * Set LED brightness level immediately - it can block the caller for * the time required for accessing a LED device register. */ int (*brightness_set_blocking)(struct led_classdev *led_cdev,enum led_brightness brightness); + +int (*rgb_set_blocking)(struct led_classdev *led_cdev, +u32 rgb_val); +/* Get LED brightness level */ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); +/* Get LED RGB val */ +s32 (*rgb_get)(struct led_classdev *led_cdev); +/* * Activate hardware accelerated blink, delays are in milliseconds * and if both are zero then a sensible default should be chosen.
@@ -90,6 +102,7 @@ struct led_classdev {struct work_struct set_brightness_work;int delayed_set_value; +u32 delayed_rgb_value;#ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */
Signature · 1 line
2.7.0
Hi Heiner,
Thank you for the patch. We have to ask a question here - what benefits these modifications bring about. Isn't all of this achievable in the user space? And I think that RGB LED problem can be boiled down to even more generic one, namely: how to make all the sub-LEDs controllable with a single LED class device. This subject pops out from time to time and it'd be good to have it tackled finally. Please refer to [1] and follow the links.
[1] http://www.spinics.net/lists/linux-leds/msg04508.html
Best Regards,
Jacek Anaszewski
Quoted 381 lines · Heiner Kallweit
When playing with a ThingM Blink(1) USB RGB LED device I found that there are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdevper RGB LED. Also userspace should be able to change the color with one call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected by the RGB extension.
This patch is intended to demonstrate the idea of the extension. Most likely it's not ready yet for submission.
Main idea is to base the effective RGB value on a combination of brightness and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags bitmap.Experimentally I changed the thingm driver to use this extension and it works quite well. As one result the driver could be very much simplified.
Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)drivers/leds/led-class.c +62
-0@@ -64,6 +64,47 @@ unlock: }static DEVICE_ATTR_RW (brightness); +static ssize_t rgb_show (struct device *dev,struct device_attribute *attr, +char *buf) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +u32 rgb_val; + +mutex_lock (&led_cdev->led_access); +led_update_rgb_val (led_cdev); + rgb_val =led_get_rgb_val (led_cdev); +mutex_unlock (&led_cdev->led_access); + +return sprintf (buf,"0x%06x\n" , rgb_val); +} + +static ssize_t rgb_store (struct device *dev,struct device_attribute *attr, +const char *buf,size_t size) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +unsigned long state; +ssize_t ret; + +mutex_lock (&led_cdev->led_access); + +if (led_sysfs_is_disabled (led_cdev)) { + ret = -EBUSY ; + goto unlock; + } + + ret =kstrtoul (buf,0 , &state); +if (ret) + goto unlock; + +led_set_rgb_val (led_cdev, state); + + ret = size; +unlock: +mutex_unlock (&led_cdev->led_access); +return ret; +} +static DEVICE_ATTR_RW (rgb); +static ssize_t max_brightness_show (struct device *dev,struct device_attribute *attr,char *buf) {@@ -190,6 +231,16 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)char name[64 ];int ret; +/* FLASH is not supported for RGB LEDs so far +* and RGB enforces max_brightness = LED_FULL. +* Initialize the color as white. +*/ +if (led_isRGB (led_cdev)) { + led_cdev->flags &= ~LED_DEV_CAP_FLASH ; + led_cdev->max_brightness =LED_FULL ; + led_cdev->rgb_val =0xffffff ; + } + ret =led_classdev_next_name (led_cdev->name, name,sizeof (name));if (ret <0 )return ret;@@ -203,6 +254,14 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)dev_warn (parent,"Led %s renamed to %s due to name collision" , led_cdev->name,dev_name (led_cdev->dev)); +if (led_isRGB (led_cdev)) { + ret =device_create_file (led_cdev->dev, &dev_attr_rgb); +if (ret) { +device_unregister (led_cdev->dev); +return ret; + } + } +#ifdef CONFIG_LEDS_TRIGGERS init_rwsem (&led_cdev->trigger_lock);#endif @@ -252,6 +311,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)flush_work (&led_cdev->set_brightness_work); +if (led_isRGB (led_cdev)) +device_remove_file (led_cdev->dev, &dev_attr_rgb); +device_unregister (led_cdev->dev);down_write (&leds_list_lock);drivers/leds/led-core.c +106
-0@@ -25,6 +25,48 @@ EXPORT_SYMBOL_GPL(leds_list_lock);LIST_HEAD (leds_list);EXPORT_SYMBOL_GPL (leds_list); +static void led_set_rgb_raw (struct led_classdev *cdev,u32 rgb) +{ +u32 red_raw = (rgb >>16 ) &0xff ; +u32 green_raw = (rgb >>8 ) &0xff ; +u32 blue_raw = rgb &0xff ; +u32 max_raw, red, green, blue; + + max_raw =max (red_raw, green_raw); +if (blue_raw > max_raw) + max_raw = blue_raw; + +if (!max_raw) { + cdev->brightness =0 ; + cdev->rgb_val =0 ; +return ; + } + + red =DIV_ROUND_CLOSEST (red_raw *LED_FULL , max_raw); + green =DIV_ROUND_CLOSEST (green_raw *LED_FULL , max_raw); + blue =DIV_ROUND_CLOSEST (blue_raw *LED_FULL , max_raw); + + cdev->brightness = max_raw; + cdev->rgb_val = (red <<16 ) + (green <<8 ) + blue; +} + +static u32 led_get_rgb_raw (struct led_classdev *cdev,bool delayed) +{ +u32 rgb = delayed ? cdev->delayed_rgb_value : cdev->rgb_val; +u32 brightness = delayed ? cdev->delayed_set_value : + cdev->brightness; +u32 red = (rgb >>16 ) &0xff ; +u32 green = (rgb >>8 ) &0xff ; +u32 blue = rgb &0xff ; +u32 red_raw, green_raw, blue_raw; + + red_raw =DIV_ROUND_CLOSEST (red * brightness,LED_FULL ); + green_raw =DIV_ROUND_CLOSEST (green * brightness,LED_FULL ); + blue_raw =DIV_ROUND_CLOSEST (blue * brightness,LED_FULL ); + +return (red_raw <<16 ) + (green_raw <<8 ) + blue_raw; +} +static void led_timer_function (unsigned long data) {struct led_classdev *led_cdev = (void *)data;@@ -91,6 +133,21 @@ static void set_brightness_delayed(struct work_struct *ws) led_cdev->flags &= ~LED_BLINK_DISABLE ; } +if (led_isRGB (led_cdev)) { +u32 rgb =led_get_rgb_raw (led_cdev, true); + +if (led_cdev->rgb_set) + led_cdev->rgb_set (led_cdev, rgb); +else if (led_cdev->rgb_set_blocking) + ret = led_cdev->rgb_set_blocking (led_cdev, rgb); +else + ret = -EOPNOTSUPP ; +if (ret <0 ) +dev_err (led_cdev->dev, +"Setting LED RGB value failed (%d)\n" , ret); +return ; + } +if (led_cdev->brightness_set) led_cdev->brightness_set (led_cdev, led_cdev->delayed_set_value);else if (led_cdev->brightness_set_blocking)@@ -229,9 +286,35 @@ void led_set_brightness(struct led_classdev *led_cdev, }EXPORT_SYMBOL_GPL (led_set_brightness); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val) +{ +if (!led_isRGB (led_cdev) || (led_cdev->flags &LED_SUSPENDED )) +return ; + +led_set_rgb_raw (led_cdev, rgb_val); + +if (led_cdev->rgb_set) { + led_cdev->rgb_set (led_cdev, rgb_val); +return ; + } + +/* If RGB setting can sleep, delegate it to a work queue task */ + led_cdev->delayed_set_value = led_cdev->brightness; + led_cdev->delayed_rgb_value = led_cdev->rgb_val; +schedule_work (&led_cdev->set_brightness_work); +} +EXPORT_SYMBOL_GPL (led_set_rgb_val); +void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value) { +if (led_isRGB (led_cdev) && led_cdev->rgb_set) { +u32 rgb =led_get_rgb_raw (led_cdev, false); + + led_cdev->rgb_set (led_cdev, rgb); +return ; + } +/* Use brightness_set op if available, it is guaranteed not to sleep */ if (led_cdev->brightness_set) { led_cdev->brightness_set (led_cdev, value);@@ -240,6 +323,7 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,/* If brightness setting can sleep, delegate it to a work queue task */ led_cdev->delayed_set_value = value; + led_cdev->delayed_rgb_value = led_cdev->rgb_val;schedule_work (&led_cdev->set_brightness_work); }EXPORT_SYMBOL_GPL (led_set_brightness_nopm);@@ -267,6 +351,12 @@ int led_set_brightness_sync(struct led_classdev *led_cdev,if (led_cdev->flags &LED_SUSPENDED )return 0 ; +if (led_isRGB (led_cdev) && led_cdev->rgb_set_blocking) { +u32 rgb =led_get_rgb_raw (led_cdev, false); + +return led_cdev->rgb_set_blocking (led_cdev, rgb); + } +if (led_cdev->brightness_set_blocking)return led_cdev->brightness_set_blocking (led_cdev, led_cdev->brightness);@@ -290,6 +380,22 @@ int led_update_brightness(struct led_classdev *led_cdev) }EXPORT_SYMBOL_GPL (led_update_brightness); +int led_update_rgb_val (struct led_classdev *led_cdev) +{ +s32 ret =0 ; + +if (led_isRGB (led_cdev) && led_cdev->rgb_get) { + ret = led_cdev->rgb_get (led_cdev); +if (ret >=0 ) { +led_set_rgb_raw (led_cdev, ret); +return 0 ; + } + } + +return ret; +} +EXPORT_SYMBOL_GPL (led_update_rgb_val); +/* Caller must ensure led_cdev->led_access held */ void led_sysfs_disable (struct led_classdev *led_cdev) {drivers/leds/leds.h +12
-0@@ -16,17 +16,29 @@#include <linux/rwsem.h> #include <linux/leds.h> +static inline bool led_isRGB (struct led_classdev *led_cdev) +{ +return (led_cdev->flags &LED_RGB ) !=0 ; +} +static inline int led_get_brightness (struct led_classdev *led_cdev) {return led_cdev->brightness; } +static inline u32 led_get_rgb_val (struct led_classdev *led_cdev) +{ +return led_cdev->rgb_val; +} +void led_init_core (struct led_classdev *led_cdev);void led_stop_software_blink (struct led_classdev *led_cdev);void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value);void led_set_brightness_nosleep (struct led_classdev *led_cdev,enum led_brightness value); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val); +int led_update_rgb_val (struct led_classdev *led_cdev);extern struct rw_semaphore leds_list_lock;extern struct list_head leds_list;include/linux/leds.h +13
-0@@ -35,6 +35,7 @@ struct led_classdev {const char *name;enum led_brightness brightness;enum led_brightness max_brightness; +u32 rgb_val;int flags;/* Lower 16 bits reflect status */ @@ -48,6 +49,7 @@ struct led_classdev {#define LED_BLINK_DISABLE (1 << 21)#define LED_SYSFS_DISABLE (1 << 22)#define LED_DEV_CAP_FLASH (1 << 23) +#define LED_RGB (1 << 24)/* Set LED brightness level */ /* Must not sleep. If no non-blocking version can be provided @@ -56,15 +58,25 @@ struct led_classdev {*/ void (*brightness_set)(struct led_classdev *led_cdev,enum led_brightness brightness); + +void (*rgb_set)(struct led_classdev *led_cdev, +u32 rgb_val);/* * Set LED brightness level immediately - it can block the caller for * the time required for accessing a LED device register. */ int (*brightness_set_blocking)(struct led_classdev *led_cdev,enum led_brightness brightness); + +int (*rgb_set_blocking)(struct led_classdev *led_cdev, +u32 rgb_val); +/* Get LED brightness level */ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); +/* Get LED RGB val */ +s32 (*rgb_get)(struct led_classdev *led_cdev); +/* * Activate hardware accelerated blink, delays are in milliseconds * and if both are zero then a sensible default should be chosen. @@ -90,6 +102,7 @@ struct led_classdev {struct work_struct set_brightness_work;int delayed_set_value; +u32 delayed_rgb_value;#ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */
Am 13.01.2016 um 10:42 schrieb Jacek Anaszewski:
Quoted 10 lines
Hi Heiner,
Thank you for the patch. We have to ask a question here - what benefits these modifications bring about. Isn't all of this achievable in the user space? And I think that RGB LED problem can be boiled down to even more generic one, namely: how to make all the sub-LEDs controllable with a single LED class device. This subject pops out from time to time and it'd be good to have it tackled finally. Please refer to [1] and follow the links.
Quoted 5 lines
[1] http://www.spinics.net/lists/linux-leds/msg04508.html
Best Regards,
Jacek Anaszewski
Thanks for the prompt feedback, Jacek.
Regarding RGB support I also think of eventually making setting the color available via triggers. This would allow kernel events to use colors. I think of use cases like:
- add RGB support to heartbeat trigger: Then, with increasing load, the color can change from green to red.
- combine temperature monitoring with a RGB LED trigger.
- in general visualizing parameters in the kernel with >2 states or a range of possible values
Therefore I think having RGB LED support in the kernel makes sense. And we have it anyway also as of today, just in different forms in different corners of the kernel code.
Prerequiste for RGB-based triggers is one central API for controlling RGB LEDs.
When we come to sub-LEDs:
I'd define sub-LEDs as LEDs which are somehow grouped but basically independent. I don't think this definition applies to a RGB LED as the three LEDs are not independent.
I had a look at the referenced mail thread, however the usecase wasn't clear to me. I understand that it's about making LEDs blink synchronously but there was no example what it could be good for. Can you list some usecases? Maybe once I see some usecases for sub-LEDs it becomes clearer what they have in common with RGB LEDs.
The primary question with sub-LEDs most likely is:
Which properties can be controlled on a per-LED basis and which ones only on a LED group basis?
(Or should it be supported that I can fiddle with properties on a per-LED and on a group basis in parallel?)
I'd assume that the following idea is not brand-new: I could imagine to have sysfs nodes for LED groups under /sys/class/leds including:
- attributes for the LED properties delegated to the group
- links to the led_classdev nodes of the respective LEDs in the group
Kind Regards, Heiner
Quoted 39 lines · Heiner Kallweit
Quoted 35 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdevper RGB LED. Also userspace should be able to change the color with one call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected by the RGB extension.
This patch is intended to demonstrate the idea of the extension. Most likely it's not ready yet for submission.
Main idea is to base the effective RGB value on a combination of brightness and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags bitmap.Experimentally I changed the thingm driver to use this extension and it works quite well. As one result the driver could be very much simplified.
Any feedback is appreciated.
[...]
Quoted 17 lines · Heiner Kallweit
Am 13.01.2016 um 10:42 schrieb Jacek Anaszewski:
Quoted 10 lines
Hi Heiner,
Thank you for the patch. We have to ask a question here - what benefits these modifications bring about. Isn't all of this achievable in the user space? And I think that RGB LED problem can be boiled down to even more generic one, namely: how to make all the sub-LEDs controllable with a single LED class device. This subject pops out from time to time and it'd be good to have it tackled finally. Please refer to [1] and follow the links.
Quoted 5 lines
[1] http://www.spinics.net/lists/linux-leds/msg04508.html
Best Regards,
Jacek Anaszewski
Quoted 6 lines
Thanks for the prompt feedback, Jacek.
Regarding RGB support I also think of eventually making setting the color available via triggers. This would allow kernel events to use colors. I think of use cases like:
- add RGB support to heartbeat trigger: Then, with increasing load, the color can change from green to red.
What do you mean by increasing load? Heartbeat is just blinking with specific time intervals and fixed brightness.
Quoted 9 lines
- combine temperature monitoring with a RGB LED trigger.
- in general visualizing parameters in the kernel with >2 states or a range of possible valuesTherefore I think having RGB LED support in the kernel makes sense. And we have it anyway also as of today, just in different forms in different corners of the kernel code.
Prerequiste for RGB-based triggers is one central API for controlling RGB LEDs.
Quoted 9 lines
When we come to sub-LEDs:
I'd define sub-LEDs as LEDs which are somehow grouped but basically independent. I don't think this definition applies to a RGB LED as the three LEDs are not independent.
I had a look at the referenced mail thread, however the usecase wasn't clear to me. I understand that it's about making LEDs blink synchronously but there was no example what it could be good for. Can you list some usecases? Maybe once I see some usecases for sub-LEDs it becomes clearer what they have in common with RGB LEDs.
I got influenced by the fact that led-blinkm driver exposes separate LED class devices per each color component. It automatically brought sync subLEDs problem to my mind. The main benefit of synchronizing subLEDs would be possibility of setting a trigger per group of subLEDs, but current API doesn't allow for setting different brightness per triggered subLED, so it wouldn't work properly for RGB LEDs.
It was not an issue in case of flash LEDs, from which the subject arose originally. Only strobe operation was to be synchronized then and brightness could had been set in one of the previous steps.
max77693-flash device driver was being developed then
(drivers/leds/leds-max77693.c), which exposes two current outputs, that are controlled separately, but can be joint to double the maximum current for the flash strobe of a single LED.
Synchronization would be beneficial for the case when two separate
LEDs are connected to both outputs and we'd like to synchronize the
flash strobe. Strobing both LEDs required accessing a single register.
All the above seem to be irrelevant for RGB LEDs case.
Nonetheless, one straightforward idea came to my mind - we could expose RGB LED as a single LED class device and control the intensity of each color as usual with brightness attribute.
It is of enum type (i.e. at least 4 bytes), so each color component could be stored in one byte. With this approach no changes would be needed to the LED core to meet requirements from your RFC. Please let me know if I missed something?
Quoted 57 lines
The primary question with sub-LEDs most likely is:
Which properties can be controlled on a per-LED basis and which ones only on a LED group basis?(Or should it be supported that I can fiddle with properties on a per-LED and on a group basis in parallel?)
I'd assume that the following idea is not brand-new: I could imagine to have sysfs nodes for LED groups under/sys/class/ledsincluding:
- attributes for the LED properties delegated to the group
- links to theled_classdevnodes of the respective LEDs in the groupKind Regards, Heiner
Quoted 39 lines · Heiner Kallweit
Quoted 35 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdevper RGB LED. Also userspace should be able to change the color with one call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected by the RGB extension.
This patch is intended to demonstrate the idea of the extension. Most likely it's not ready yet for submission.
Main idea is to base the effective RGB value on a combination of brightness and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags bitmap.Experimentally I changed the thingm driver to use this extension and it works quite well. As one result the driver could be very much simplified.
Any feedback is appreciated.
[...]
Signature · 2 lines
Best Regards, Jacek Anaszewski
Quoted 76 lines · Jacek Anaszewski
Quoted 17 lines · Heiner Kallweit
Am 13.01.2016 um 10:42 schrieb Jacek Anaszewski:
Quoted 10 lines
Hi Heiner,
Thank you for the patch. We have to ask a question here - what benefits these modifications bring about. Isn't all of this achievable in the user space? And I think that RGB LED problem can be boiled down to even more generic one, namely: how to make all the sub-LEDs controllable with a single LED class device. This subject pops out from time to time and it'd be good to have it tackled finally. Please refer to [1] and follow the links.
Quoted 5 lines
[1] http://www.spinics.net/lists/linux-leds/msg04508.html
Best Regards,
Jacek AnaszewskiQuoted 6 lines
Thanks for the prompt feedback, Jacek.
Regarding RGB support I also think of eventually making setting the color available via triggers. This would allow kernel events to use colors. I think of use cases like:
- add RGB support to heartbeat trigger: Then, with increasing load, the color can change from green to red.What do you mean by increasing load? Heartbeat is just blinking with specific time intervals and fixed brightness.
Quoted 12 lines
- combine temperature monitoring with a RGB LED trigger.
- in general visualizing parameters in the kernel with >2 states or a range
of possible valuesTherefore I think having RGB LED support in the kernel makes sense. And we have it anyway also as of today, just in different forms in different
corners of the kernel code.
Prerequiste for RGB-based triggers is one central API for controlling RGB LEDs.Quoted 14 lines
When we come to sub-LEDs:
I'd define sub-LEDs as LEDs which are somehow grouped but basically independent.
I don't think this definition applies to a RGB LED as the three LEDs are not
independent.
I had a look at the referenced mail thread, however the usecase wasn't clear
to me. I understand that it's about making LEDs blink synchronously but there was no example what it could be good for. Can you list some usecases?
Maybe once I see some usecases for sub-LEDs it becomes clearer what they have
in common with RGB LEDs.I got influenced by the fact that led-blinkm driver exposes separate LED class devices per each color component. It automatically brought sync subLEDs problem to my mind. The main benefit of synchronizing subLEDs would be possibility of setting a trigger per group of subLEDs, but current API doesn't allow for setting different brightness per triggered subLED, so it wouldn't work properly for RGB LEDs.
It was not an issue in case of flash LEDs, from which the subject arose originally. Only strobe operation was to be synchronized then and brightness could had been set in one of the previous steps.
max77693-flash device driver was being developed then (
drivers/leds/leds-max77693.c), which exposes two current outputs, that are controlled separately, but can be joint to double the maximum current for the flash strobe of a single LED. Synchronization would be beneficial for the case when two separate LEDs are connected to both outputs and we'd like to synchronize the flash strobe. Strobing both LEDs required accessing a single register.All the above seem to be irrelevant for RGB LEDs case.
Quoted 8 lines
Nonetheless, one straightforward idea came to my mind - we could expose RGB LED as a single LED class device and control the intensity of each color as usual with brightness attribute.
It is of enum type (i.e. at least 4 bytes), so each color component could be stored in one byte. With this approach no changes would be needed to the LED core to meet requirements from your RFC. Please let me know if I missed something?
Of course I missed that we need both brightness and rgb value. In this case, some of changes you proposed by are indeed required. I'll add more comments in the response to your RFC.
Signature · 2 lines
Best Regards, Jacek Anaszewski
Quoted 74 lines · Heiner Kallweit
When playing with a ThingM Blink(1) USB RGB LED device I found that there are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdevper RGB LED. Also userspace should be able to change the color with one call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected by the RGB extension.
This patch is intended to demonstrate the idea of the extension. Most likely it's not ready yet for submission.
Main idea is to base the effective RGB value on a combination of brightness and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags bitmap.Experimentally I changed the thingm driver to use this extension and it works quite well. As one result the driver could be very much simplified.
Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)drivers/leds/led-class.c +23
-0@@ -64,6 +64,47 @@ unlock: }static DEVICE_ATTR_RW (brightness); +static ssize_t rgb_show (struct device *dev,struct device_attribute *attr, +char *buf) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +u32 rgb_val; + +mutex_lock (&led_cdev->led_access); +led_update_rgb_val (led_cdev); + rgb_val =led_get_rgb_val (led_cdev); +mutex_unlock (&led_cdev->led_access); + +return sprintf (buf,"0x%06x\n" , rgb_val); +} + +static ssize_t rgb_store (struct device *dev,struct device_attribute *attr, +const char *buf,size_t size) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +unsigned long state; +ssize_t ret; + +mutex_lock (&led_cdev->led_access); +
drivers/leds/led-class.c unlock: · line 99
Quoted 10 lines
drivers/leds/led-class.c +10
-0+if (led_sysfs_is_disabled (led_cdev)) { + ret = -EBUSY ; + goto unlock; + } + + ret =kstrtoul (buf,0 , &state); +if (ret) + goto unlock; + +led_set_rgb_val (led_cdev, state);
Please adhere to the current LED API naming style: led_rgb_set.
Quoted 12 lines
drivers/leds/led-class.c +8
-0+ + ret = size; +unlock: +mutex_unlock (&led_cdev->led_access); +return ret; +} +static DEVICE_ATTR_RW (rgb); +static ssize_t max_brightness_show (struct device *dev,struct device_attribute *attr,char *buf) {
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 238
Quoted 8 lines
drivers/leds/led-class.c +5
-0@@ -190,6 +231,16 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)char name[64 ];int ret; +/* FLASH is not supported for RGB LEDs so far +* and RGB enforces max_brightness = LED_FULL. +* Initialize the color as white. +*/ +if (led_isRGB (led_cdev)) {
Don't use camel case. Change it to led_is_rgb or check the flag directly.
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 239
Quoted 1 line
drivers/leds/led-class.c +1
-0+ led_cdev->flags &= ~LED_DEV_CAP_FLASH ;
I'd rather check whether both FLASH and RGB flag are set and return error in this case.
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 258
Quoted 13 lines
drivers/leds/led-class.c +6
-0+ led_cdev->max_brightness =LED_FULL ; + led_cdev->rgb_val =0xffffff ; + } + ret =led_classdev_next_name (led_cdev->name, name,sizeof (name));if (ret <0 )return ret;@@ -203,6 +254,14 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)dev_warn (parent,"Led %s renamed to %s due to name collision" , led_cdev->name,dev_name (led_cdev->dev)); +if (led_isRGB (led_cdev)) { + ret =device_create_file (led_cdev->dev, &dev_attr_rgb);
Please use led_cdev->groups for this. You can refer to drivers/leds/led-class-flash.c.
Quoted 41 lines
drivers/leds/led-class.c +9
-0+if (ret) { +device_unregister (led_cdev->dev); +return ret; + } + } +#ifdef CONFIG_LEDS_TRIGGERS init_rwsem (&led_cdev->trigger_lock);#endif @@ -252,6 +311,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)flush_work (&led_cdev->set_brightness_work); +if (led_isRGB (led_cdev)) +device_remove_file (led_cdev->dev, &dev_attr_rgb); +device_unregister (led_cdev->dev);down_write (&leds_list_lock);drivers/leds/led-core.c +14
-0@@ -25,6 +25,48 @@ EXPORT_SYMBOL_GPL(leds_list_lock);LIST_HEAD (leds_list);EXPORT_SYMBOL_GPL (leds_list); +static void led_set_rgb_raw (struct led_classdev *cdev,u32 rgb) +{ +u32 red_raw = (rgb >>16 ) &0xff ; +u32 green_raw = (rgb >>8 ) &0xff ; +u32 blue_raw = rgb &0xff ; +u32 max_raw, red, green, blue; + + max_raw =max (red_raw, green_raw); +if (blue_raw > max_raw) + max_raw = blue_raw; + +if (!max_raw) { + cdev->brightness =0 ; + cdev->rgb_val =0 ;
drivers/leds/led-core.c EXPORT_SYMBOL_GPL(leds_list_lock); · line 51
Quoted 10 lines
drivers/leds/led-core.c +10
-0+return ; + } + + red =DIV_ROUND_CLOSEST (red_raw *LED_FULL , max_raw); + green =DIV_ROUND_CLOSEST (green_raw *LED_FULL , max_raw); + blue =DIV_ROUND_CLOSEST (blue_raw *LED_FULL , max_raw); + + cdev->brightness = max_raw; + cdev->rgb_val = (red <<16 ) + (green <<8 ) + blue; +}
I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace to the driver.
Quoted 29 lines
drivers/leds/led-core.c +22
-0+static u32 led_get_rgb_raw (struct led_classdev *cdev,bool delayed) +{ +u32 rgb = delayed ? cdev->delayed_rgb_value : cdev->rgb_val; +u32 brightness = delayed ? cdev->delayed_set_value : + cdev->brightness; +u32 red = (rgb >>16 ) &0xff ; +u32 green = (rgb >>8 ) &0xff ; +u32 blue = rgb &0xff ; +u32 red_raw, green_raw, blue_raw; + + red_raw =DIV_ROUND_CLOSEST (red * brightness,LED_FULL ); + green_raw =DIV_ROUND_CLOSEST (green * brightness,LED_FULL ); + blue_raw =DIV_ROUND_CLOSEST (blue * brightness,LED_FULL ); + +return (red_raw <<16 ) + (green_raw <<8 ) + blue_raw; +} +static void led_timer_function (unsigned long data) {struct led_classdev *led_cdev = (void *)data;@@ -91,6 +133,21 @@ static void set_brightness_delayed(struct work_struct *ws) led_cdev->flags &= ~LED_BLINK_DISABLE ; } +if (led_isRGB (led_cdev)) { +u32 rgb =led_get_rgb_raw (led_cdev, true); + +if (led_cdev->rgb_set) + led_cdev->rgb_set (led_cdev, rgb);
drivers/leds/led-core.c static void set_brightness_delayed(struct work_struct *ws) · line 150
Quoted 10 lines
drivers/leds/led-core.c +10
-0+else if (led_cdev->rgb_set_blocking) + ret = led_cdev->rgb_set_blocking (led_cdev, rgb); +else + ret = -EOPNOTSUPP ; +if (ret <0 ) +dev_err (led_cdev->dev, +"Setting LED RGB value failed (%d)\n" , ret); +return ; + } +
Why this is needed? Could you share a use case?
Quoted 13 lines
drivers/leds/led-core.c +6
-0if (led_cdev->brightness_set) led_cdev->brightness_set (led_cdev, led_cdev->delayed_set_value);else if (led_cdev->brightness_set_blocking)@@ -229,9 +286,35 @@ void led_set_brightness(struct led_classdev *led_cdev, }EXPORT_SYMBOL_GPL (led_set_brightness); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val) +{ +if (!led_isRGB (led_cdev) || (led_cdev->flags &LED_SUSPENDED )) +return ; + +led_set_rgb_raw (led_cdev, rgb_val);
drivers/leds/led-core.c void led_set_brightness(struct led_classdev *led_cdev, · line 304
Quoted 10 lines
drivers/leds/led-core.c +10
-0+ +if (led_cdev->rgb_set) { + led_cdev->rgb_set (led_cdev, rgb_val); +return ; + } + +/* If RGB setting can sleep, delegate it to a work queue task */ + led_cdev->delayed_set_value = led_cdev->brightness; + led_cdev->delayed_rgb_value = led_cdev->rgb_val; +schedule_work (&led_cdev->set_brightness_work);
I think that settings should be written to the device only in the brightness_set op. We wouldn't need additional rgb op then.
Quoted 107 lines
drivers/leds/led-core.c +33
-0+} +EXPORT_SYMBOL_GPL (led_set_rgb_val); +void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value) { +if (led_isRGB (led_cdev) && led_cdev->rgb_set) { +u32 rgb =led_get_rgb_raw (led_cdev, false); + + led_cdev->rgb_set (led_cdev, rgb); +return ; + } +/* Use brightness_set op if available, it is guaranteed not to sleep */ if (led_cdev->brightness_set) { led_cdev->brightness_set (led_cdev, value);@@ -240,6 +323,7 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,/* If brightness setting can sleep, delegate it to a work queue task */ led_cdev->delayed_set_value = value; + led_cdev->delayed_rgb_value = led_cdev->rgb_val;schedule_work (&led_cdev->set_brightness_work); }EXPORT_SYMBOL_GPL (led_set_brightness_nopm);@@ -267,6 +351,12 @@ int led_set_brightness_sync(struct led_classdev *led_cdev,if (led_cdev->flags &LED_SUSPENDED )return 0 ; +if (led_isRGB (led_cdev) && led_cdev->rgb_set_blocking) { +u32 rgb =led_get_rgb_raw (led_cdev, false); + +return led_cdev->rgb_set_blocking (led_cdev, rgb); + } +if (led_cdev->brightness_set_blocking)return led_cdev->brightness_set_blocking (led_cdev, led_cdev->brightness);@@ -290,6 +380,22 @@ int led_update_brightness(struct led_classdev *led_cdev) }EXPORT_SYMBOL_GPL (led_update_brightness); +int led_update_rgb_val (struct led_classdev *led_cdev) +{ +s32 ret =0 ; + +if (led_isRGB (led_cdev) && led_cdev->rgb_get) { + ret = led_cdev->rgb_get (led_cdev); +if (ret >=0 ) { +led_set_rgb_raw (led_cdev, ret); +return 0 ; + } + } + +return ret; +} +EXPORT_SYMBOL_GPL (led_update_rgb_val); +/* Caller must ensure led_cdev->led_access held */ void led_sysfs_disable (struct led_classdev *led_cdev) {drivers/leds/leds.h +12
-0@@ -16,17 +16,29 @@#include <linux/rwsem.h> #include <linux/leds.h> +static inline bool led_isRGB (struct led_classdev *led_cdev) +{ +return (led_cdev->flags &LED_RGB ) !=0 ; +} +static inline int led_get_brightness (struct led_classdev *led_cdev) {return led_cdev->brightness; } +static inline u32 led_get_rgb_val (struct led_classdev *led_cdev) +{ +return led_cdev->rgb_val; +} +void led_init_core (struct led_classdev *led_cdev);void led_stop_software_blink (struct led_classdev *led_cdev);void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value);void led_set_brightness_nosleep (struct led_classdev *led_cdev,enum led_brightness value); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val); +int led_update_rgb_val (struct led_classdev *led_cdev);extern struct rw_semaphore leds_list_lock;extern struct list_head leds_list;include/linux/leds.h +1
-0@@ -35,6 +35,7 @@ struct led_classdev {const char *name;enum led_brightness brightness;enum led_brightness max_brightness; +u32 rgb_val;int flags;/* Lower 16 bits reflect status */
include/linux/leds.h struct led_classdev { · line 52
Quoted 4 lines
include/linux/leds.h +1
-0@@ -48,6 +49,7 @@ struct led_classdev {#define LED_BLINK_DISABLE (1 << 21)#define LED_SYSFS_DISABLE (1 << 22)#define LED_DEV_CAP_FLASH (1 << 23) +#define LED_RGB (1 << 24)
Please rename it to LED_DEV_CAP_RGB.
include/linux/leds.h struct led_classdev { · line 63
Quoted 10 lines
include/linux/leds.h +3
-0/* Set LED brightness level */ /* Must not sleep. If no non-blocking version can be provided @@ -56,15 +58,25 @@ struct led_classdev {*/ void (*brightness_set)(struct led_classdev *led_cdev,enum led_brightness brightness); + +void (*rgb_set)(struct led_classdev *led_cdev, +u32 rgb_val);
Without this everything would be much simpler.
If we wanted to change the color and intensity we would need to:
1. Set rgb (value only cached in the LED core)
2. Set brightness (write both brightness and rgb settings to the hw)
Current brightness can always be obtained with led_get_brightness in case only rgb is to be set.
include/linux/leds.h struct led_classdev { · line 73
Quoted 10 lines
include/linux/leds.h +4
-0/* * Set LED brightness level immediately - it can block the caller for * the time required for accessing a LED device register. */ int (*brightness_set_blocking)(struct led_classdev *led_cdev,enum led_brightness brightness); + +int (*rgb_set_blocking)(struct led_classdev *led_cdev, +u32 rgb_val); +
This is also not needed.
include/linux/leds.h struct led_classdev { · line 79
Quoted 6 lines
include/linux/leds.h +3
-0/* Get LED brightness level */ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); +/* Get LED RGB val */ +s32 (*rgb_get)(struct led_classdev *led_cdev); +
Ditto.
include/linux/leds.h struct led_classdev { · line 105
Quoted 8 lines
include/linux/leds.h +1
-0/* * Activate hardware accelerated blink, delays are in milliseconds * and if both are zero then a sensible default should be chosen. @@ -90,6 +102,7 @@ struct led_classdev {struct work_struct set_brightness_work;int delayed_set_value; +u32 delayed_rgb_value;
Ditto.
Quoted 4 lines
include/linux/leds.h +0
-0#ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */
Signature · 2 lines
Best Regards, Jacek Anaszewski
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 79 lines · Heiner Kallweit
Quoted 78 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdevper RGB LED. Also userspace should be able to change the color with one call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected by the RGB extension.
This patch is intended to demonstrate the idea of the extension. Most likely it's not ready yet for submission.
Main idea is to base the effective RGB value on a combination of brightness and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags bitmap.Experimentally I changed the thingm driver to use this extension and it works quite well. As one result the driver could be very much simplified.
Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)drivers/leds/led-class.c +27
-0@@ -64,6 +64,47 @@ unlock: }static DEVICE_ATTR_RW (brightness); +static ssize_t rgb_show (struct device *dev,struct device_attribute *attr, +char *buf) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +u32 rgb_val; + +mutex_lock (&led_cdev->led_access); +led_update_rgb_val (led_cdev); + rgb_val =led_get_rgb_val (led_cdev); +mutex_unlock (&led_cdev->led_access); + +return sprintf (buf,"0x%06x\n" , rgb_val); +} + +static ssize_t rgb_store (struct device *dev,struct device_attribute *attr, +const char *buf,size_t size) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +unsigned long state; +ssize_t ret; + +mutex_lock (&led_cdev->led_access); + +if (led_sysfs_is_disabled (led_cdev)) { + ret = -EBUSY ; + goto unlock; + }
Quoted 9 lines
drivers/leds/led-class.c unlock: · line 99
Quoted 6 lines
drivers/leds/led-class.c +6
-0+ + ret =kstrtoul (buf,0 , &state); +if (ret) + goto unlock; + +led_set_rgb_val (led_cdev, state);Please adhere to the current LED API naming style:
led_rgb_set.
Seems like currently two naming styles are use in the LED core. We have e.g. led_blink_set and led_set_brightness. However I'm fine with the suggested led_rgb_set.
Quoted 15 lines
Quoted 15 lines
drivers/leds/led-class.c +8
-0+ + ret = size; +unlock: +mutex_unlock (&led_cdev->led_access); +return ret; +} +static DEVICE_ATTR_RW (rgb); +static ssize_t max_brightness_show (struct device *dev,struct device_attribute *attr,char *buf) {@@ -190,6 +231,16 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)char name[64 ];int ret;
Quoted 9 lines
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 238
Quoted 5 lines
drivers/leds/led-class.c +5
-0+/* FLASH is not supported for RGB LEDs so far +* and RGB enforces max_brightness = LED_FULL. +* Initialize the color as white. +*/ +if (led_isRGB (led_cdev)) {Don't use camel case. Change it to
led_is_rgbor check the flag directly.
OK, will change it to led_is_rgb.
Quoted 5 lines
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 239
Quoted 1 line
drivers/leds/led-class.c +1
-0+ led_cdev->flags &= ~LED_DEV_CAP_FLASH ;I'd rather check whether both FLASH and RGB flag are set and return error in this case.
OK
Quoted 11 lines
Quoted 11 lines
drivers/leds/led-class.c +4
-0+ led_cdev->max_brightness =LED_FULL ; + led_cdev->rgb_val =0xffffff ; + } + ret =led_classdev_next_name (led_cdev->name, name,sizeof (name));if (ret <0 )return ret;@@ -203,6 +254,14 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)dev_warn (parent,"Led %s renamed to %s due to name collision" , led_cdev->name,dev_name (led_cdev->dev));
Quoted 5 lines
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 258
Quoted 2 lines
drivers/leds/led-class.c +2
-0+if (led_isRGB (led_cdev)) { + ret =device_create_file (led_cdev->dev, &dev_attr_rgb);Please use
led_cdev->groupsfor this. You can refer todrivers/leds/led-class-flash.c.
OK
Quoted 47 lines
Quoted 47 lines
drivers/leds/led-class.c +9
-0+if (ret) { +device_unregister (led_cdev->dev); +return ret; + } + } +#ifdef CONFIG_LEDS_TRIGGERS init_rwsem (&led_cdev->trigger_lock);#endif @@ -252,6 +311,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)flush_work (&led_cdev->set_brightness_work); +if (led_isRGB (led_cdev)) +device_remove_file (led_cdev->dev, &dev_attr_rgb); +device_unregister (led_cdev->dev);down_write (&leds_list_lock);drivers/leds/led-core.c +20
-0@@ -25,6 +25,48 @@ EXPORT_SYMBOL_GPL(leds_list_lock);LIST_HEAD (leds_list);EXPORT_SYMBOL_GPL (leds_list); +static void led_set_rgb_raw (struct led_classdev *cdev,u32 rgb) +{ +u32 red_raw = (rgb >>16 ) &0xff ; +u32 green_raw = (rgb >>8 ) &0xff ; +u32 blue_raw = rgb &0xff ; +u32 max_raw, red, green, blue; + + max_raw =max (red_raw, green_raw); +if (blue_raw > max_raw) + max_raw = blue_raw; + +if (!max_raw) { + cdev->brightness =0 ; + cdev->rgb_val =0 ; +return ; + } + + red =DIV_ROUND_CLOSEST (red_raw *LED_FULL , max_raw); + green =DIV_ROUND_CLOSEST (green_raw *LED_FULL , max_raw); + blue =DIV_ROUND_CLOSEST (blue_raw *LED_FULL , max_raw);
Quoted 9 lines
drivers/leds/led-core.c EXPORT_SYMBOL_GPL(leds_list_lock); · line 51
Quoted 4 lines
drivers/leds/led-core.c +4
-0+ + cdev->brightness = max_raw; + cdev->rgb_val = (red <<16 ) + (green <<8 ) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace to the driver.
Right, setting brightness from userspace is no problem.
But how about led_update_brightness? It's supposed to update the brightness value in led_cdev with the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values. Or do you see a better way?
This leads me to another question: What do we need led_update_brightness for in general? The cached and the actual value should always be in sync, except the actual brightness can be changed from outside the driver.
Do we have such cases?
Last but not least I saw that led_update_brightness is called in led_classdev_register.
Instead of updating our cached value with the actual value shouldn't we initialize cached and actual value (most likely to 0)?
The actual value theoretically could be uninitialized.
Seems like we rely on BIOS / boot loader to initialize LEDs.
Quoted 33 lines
Quoted 33 lines
drivers/leds/led-core.c +26
-0+static u32 led_get_rgb_raw (struct led_classdev *cdev,bool delayed) +{ +u32 rgb = delayed ? cdev->delayed_rgb_value : cdev->rgb_val; +u32 brightness = delayed ? cdev->delayed_set_value : + cdev->brightness; +u32 red = (rgb >>16 ) &0xff ; +u32 green = (rgb >>8 ) &0xff ; +u32 blue = rgb &0xff ; +u32 red_raw, green_raw, blue_raw; + + red_raw =DIV_ROUND_CLOSEST (red * brightness,LED_FULL ); + green_raw =DIV_ROUND_CLOSEST (green * brightness,LED_FULL ); + blue_raw =DIV_ROUND_CLOSEST (blue * brightness,LED_FULL ); + +return (red_raw <<16 ) + (green_raw <<8 ) + blue_raw; +} +static void led_timer_function (unsigned long data) {struct led_classdev *led_cdev = (void *)data;@@ -91,6 +133,21 @@ static void set_brightness_delayed(struct work_struct *ws) led_cdev->flags &= ~LED_BLINK_DISABLE ; } +if (led_isRGB (led_cdev)) { +u32 rgb =led_get_rgb_raw (led_cdev, true); + +if (led_cdev->rgb_set) + led_cdev->rgb_set (led_cdev, rgb); +else if (led_cdev->rgb_set_blocking) + ret = led_cdev->rgb_set_blocking (led_cdev, rgb); +else + ret = -EOPNOTSUPP ;
Quoted 9 lines
drivers/leds/led-core.c static void set_brightness_delayed(struct work_struct *ws) · line 150
Quoted 6 lines
drivers/leds/led-core.c +6
-0+if (ret <0 ) +dev_err (led_cdev->dev, +"Setting LED RGB value failed (%d)\n" , ret); +return ; + } +Why this is needed? Could you share a use case?
If we re-use the existing brightness ops as suggested by you then most of this code isn't needed.
Quoted 132 lines
Quoted 13 lines
drivers/leds/led-core.c +6
-0if (led_cdev->brightness_set) led_cdev->brightness_set (led_cdev, led_cdev->delayed_set_value);else if (led_cdev->brightness_set_blocking)@@ -229,9 +286,35 @@ void led_set_brightness(struct led_classdev *led_cdev, }EXPORT_SYMBOL_GPL (led_set_brightness); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val) +{ +if (!led_isRGB (led_cdev) || (led_cdev->flags &LED_SUSPENDED )) +return ; + +led_set_rgb_raw (led_cdev, rgb_val);drivers/leds/led-core.c void led_set_brightness(struct led_classdev *led_cdev, · line 304
Quoted 10 lines
drivers/leds/led-core.c +10
-0+ +if (led_cdev->rgb_set) { + led_cdev->rgb_set (led_cdev, rgb_val); +return ; + } + +/* If RGB setting can sleep, delegate it to a work queue task */ + led_cdev->delayed_set_value = led_cdev->brightness; + led_cdev->delayed_rgb_value = led_cdev->rgb_val; +schedule_work (&led_cdev->set_brightness_work);I think that settings should be written to the device only in the
brightness_setop. We wouldn't need additional rgb op then.Quoted 105 lines
drivers/leds/led-core.c +33
-0+} +EXPORT_SYMBOL_GPL (led_set_rgb_val); +void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value) { +if (led_isRGB (led_cdev) && led_cdev->rgb_set) { +u32 rgb =led_get_rgb_raw (led_cdev, false); + + led_cdev->rgb_set (led_cdev, rgb); +return ; + } +/* Use brightness_set op if available, it is guaranteed not to sleep */ if (led_cdev->brightness_set) { led_cdev->brightness_set (led_cdev, value);@@ -240,6 +323,7 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,/* If brightness setting can sleep, delegate it to a work queue task */ led_cdev->delayed_set_value = value; + led_cdev->delayed_rgb_value = led_cdev->rgb_val;schedule_work (&led_cdev->set_brightness_work); }EXPORT_SYMBOL_GPL (led_set_brightness_nopm);@@ -267,6 +351,12 @@ int led_set_brightness_sync(struct led_classdev *led_cdev,if (led_cdev->flags &LED_SUSPENDED )return 0 ; +if (led_isRGB (led_cdev) && led_cdev->rgb_set_blocking) { +u32 rgb =led_get_rgb_raw (led_cdev, false); + +return led_cdev->rgb_set_blocking (led_cdev, rgb); + } +if (led_cdev->brightness_set_blocking)return led_cdev->brightness_set_blocking (led_cdev, led_cdev->brightness);@@ -290,6 +380,22 @@ int led_update_brightness(struct led_classdev *led_cdev) }EXPORT_SYMBOL_GPL (led_update_brightness); +int led_update_rgb_val (struct led_classdev *led_cdev) +{ +s32 ret =0 ; + +if (led_isRGB (led_cdev) && led_cdev->rgb_get) { + ret = led_cdev->rgb_get (led_cdev); +if (ret >=0 ) { +led_set_rgb_raw (led_cdev, ret); +return 0 ; + } + } + +return ret; +} +EXPORT_SYMBOL_GPL (led_update_rgb_val); +/* Caller must ensure led_cdev->led_access held */ void led_sysfs_disable (struct led_classdev *led_cdev) {drivers/leds/leds.h +12
-0@@ -16,17 +16,29 @@#include <linux/rwsem.h> #include <linux/leds.h> +static inline bool led_isRGB (struct led_classdev *led_cdev) +{ +return (led_cdev->flags &LED_RGB ) !=0 ; +} +static inline int led_get_brightness (struct led_classdev *led_cdev) {return led_cdev->brightness; } +static inline u32 led_get_rgb_val (struct led_classdev *led_cdev) +{ +return led_cdev->rgb_val; +} +void led_init_core (struct led_classdev *led_cdev);void led_stop_software_blink (struct led_classdev *led_cdev);void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value);void led_set_brightness_nosleep (struct led_classdev *led_cdev,enum led_brightness value); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val); +int led_update_rgb_val (struct led_classdev *led_cdev);extern struct rw_semaphore leds_list_lock;extern struct list_head leds_list;include/linux/leds.h +1
-0@@ -35,6 +35,7 @@ struct led_classdev {const char *name;enum led_brightness brightness;enum led_brightness max_brightness; +u32 rgb_val;int flags;
Quoted 9 lines
include/linux/leds.h struct led_classdev { · line 52
Quoted 6 lines
include/linux/leds.h +1
-0/* Lower 16 bits reflect status */ @@ -48,6 +49,7 @@ struct led_classdev {#define LED_BLINK_DISABLE (1 << 21)#define LED_SYSFS_DISABLE (1 << 22)#define LED_DEV_CAP_FLASH (1 << 23) +#define LED_RGB (1 << 24)Please rename it to
LED_DEV_CAP_RGB.
OK
Quoted 13 lines
include/linux/leds.h struct led_classdev { · line 63
Quoted 10 lines
include/linux/leds.h +3
-0/* Set LED brightness level */ /* Must not sleep. If no non-blocking version can be provided @@ -56,15 +58,25 @@ struct led_classdev {*/ void (*brightness_set)(struct led_classdev *led_cdev,enum led_brightness brightness); + +void (*rgb_set)(struct led_classdev *led_cdev, +u32 rgb_val);Without this everything would be much simpler.
Sure, we can re-use the existing ops. I just thought it would be a little ugly to misuse enum led_brightness for RGB values. But as it internally is an int we can also do it this way.
Quoted 34 lines
If we wanted to change the color and intensity we would need to:
1. Set rgb (value only cached in the LED core)
2. Set brightness (write both brightness and rgb settings to the hw)Current brightness can always be obtained with
led_get_brightnessin case only rgb is to be set.include/linux/leds.h struct led_classdev { · line 73
Quoted 10 lines
include/linux/leds.h +4
-0/* * Set LED brightness level immediately - it can block the caller for * the time required for accessing a LED device register. */ int (*brightness_set_blocking)(struct led_classdev *led_cdev,enum led_brightness brightness); + +int (*rgb_set_blocking)(struct led_classdev *led_cdev, +u32 rgb_val); +This is also not needed.
include/linux/leds.h struct led_classdev { · line 79
Quoted 6 lines
include/linux/leds.h +3
-0/* Get LED brightness level */ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); +/* Get LED RGB val */ +s32 (*rgb_get)(struct led_classdev *led_cdev); +Ditto.
Quoted 5 lines
include/linux/leds.h +0
-0/* * Activate hardware accelerated blink, delays are in milliseconds * and if both are zero then a sensible default should be chosen. @@ -90,6 +102,7 @@ struct led_classdev {
Quoted 6 lines
include/linux/leds.h struct led_classdev { · line 105
Quoted 3 lines
include/linux/leds.h +1
-0struct work_struct set_brightness_work;int delayed_set_value; +u32 delayed_rgb_value;Ditto.
If we have a blocking set callback then we have to set a RGB value from the workqueue. And we need brightness + RGB to calculate the effective RGB values in the worker func. Therefore I think delayed_rgb_val is needed.
Quoted 6 lines
include/linux/leds.h struct led_classdev {
Quoted 4 lines
include/linux/leds.h +0
-0#ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */
Thanks for the review, Heiner
Quoted 89 lines · Heiner Kallweit
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 79 lines · Heiner Kallweit
Quoted 78 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdevper RGB LED. Also userspace should be able to change the color with one call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected by the RGB extension.
This patch is intended to demonstrate the idea of the extension. Most likely it's not ready yet for submission.
Main idea is to base the effective RGB value on a combination of brightness and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags bitmap.Experimentally I changed the thingm driver to use this extension and it works quite well. As one result the driver could be very much simplified.
Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)drivers/leds/led-class.c +27
-0@@ -64,6 +64,47 @@ unlock: }static DEVICE_ATTR_RW (brightness); +static ssize_t rgb_show (struct device *dev,struct device_attribute *attr, +char *buf) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +u32 rgb_val; + +mutex_lock (&led_cdev->led_access); +led_update_rgb_val (led_cdev); + rgb_val =led_get_rgb_val (led_cdev); +mutex_unlock (&led_cdev->led_access); + +return sprintf (buf,"0x%06x\n" , rgb_val); +} + +static ssize_t rgb_store (struct device *dev,struct device_attribute *attr, +const char *buf,size_t size) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +unsigned long state; +ssize_t ret; + +mutex_lock (&led_cdev->led_access); + +if (led_sysfs_is_disabled (led_cdev)) { + ret = -EBUSY ; + goto unlock; + }Quoted 9 lines
drivers/leds/led-class.c unlock: · line 99
Quoted 6 lines
drivers/leds/led-class.c +6
-0+ + ret =kstrtoul (buf,0 , &state); +if (ret) + goto unlock; + +led_set_rgb_val (led_cdev, state);Please adhere to the current LED API naming style:
led_rgb_set.
Quoted 3 lines
Seems like currently two naming styles are use in the LED core. We have e.g.
led_blink_setandled_set_brightness. However I'm fine with the suggestedled_rgb_set.
Indeed. Your version would be preferable in this case. I wanted this to match led_set_brightness style, but had been too lazy to double check that :-/
Quoted 107 lines
Quoted 15 lines
Quoted 15 lines
drivers/leds/led-class.c +8
-0+ + ret = size; +unlock: +mutex_unlock (&led_cdev->led_access); +return ret; +} +static DEVICE_ATTR_RW (rgb); +static ssize_t max_brightness_show (struct device *dev,struct device_attribute *attr,char *buf) {@@ -190,6 +231,16 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)char name[64 ];int ret;Quoted 9 lines
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 238
Quoted 5 lines
drivers/leds/led-class.c +5
-0+/* FLASH is not supported for RGB LEDs so far +* and RGB enforces max_brightness = LED_FULL. +* Initialize the color as white. +*/ +if (led_isRGB (led_cdev)) {Don't use camel case. Change it to
led_is_rgbor check the flag directly.OK, will change it to
led_is_rgb.Quoted 5 lines
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 239
Quoted 1 line
drivers/leds/led-class.c +1
-0+ led_cdev->flags &= ~LED_DEV_CAP_FLASH ;I'd rather check whether both FLASH and RGB flag are set and return error in this case.
OK
Quoted 11 lines
Quoted 11 lines
drivers/leds/led-class.c +4
-0+ led_cdev->max_brightness =LED_FULL ; + led_cdev->rgb_val =0xffffff ; + } + ret =led_classdev_next_name (led_cdev->name, name,sizeof (name));if (ret <0 )return ret;@@ -203,6 +254,14 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)dev_warn (parent,"Led %s renamed to %s due to name collision" , led_cdev->name,dev_name (led_cdev->dev));Quoted 5 lines
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 258
Quoted 2 lines
drivers/leds/led-class.c +2
-0+if (led_isRGB (led_cdev)) { + ret =device_create_file (led_cdev->dev, &dev_attr_rgb);Please use
led_cdev->groupsfor this. You can refer todrivers/leds/led-class-flash.c.OK
Quoted 47 lines
Quoted 47 lines
drivers/leds/led-class.c +9
-0+if (ret) { +device_unregister (led_cdev->dev); +return ret; + } + } +#ifdef CONFIG_LEDS_TRIGGERS init_rwsem (&led_cdev->trigger_lock);#endif @@ -252,6 +311,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)flush_work (&led_cdev->set_brightness_work); +if (led_isRGB (led_cdev)) +device_remove_file (led_cdev->dev, &dev_attr_rgb); +device_unregister (led_cdev->dev);down_write (&leds_list_lock);drivers/leds/led-core.c +20
-0@@ -25,6 +25,48 @@ EXPORT_SYMBOL_GPL(leds_list_lock);LIST_HEAD (leds_list);EXPORT_SYMBOL_GPL (leds_list); +static void led_set_rgb_raw (struct led_classdev *cdev,u32 rgb) +{ +u32 red_raw = (rgb >>16 ) &0xff ; +u32 green_raw = (rgb >>8 ) &0xff ; +u32 blue_raw = rgb &0xff ; +u32 max_raw, red, green, blue; + + max_raw =max (red_raw, green_raw); +if (blue_raw > max_raw) + max_raw = blue_raw; + +if (!max_raw) { + cdev->brightness =0 ; + cdev->rgb_val =0 ; +return ; + } + + red =DIV_ROUND_CLOSEST (red_raw *LED_FULL , max_raw); + green =DIV_ROUND_CLOSEST (green_raw *LED_FULL , max_raw); + blue =DIV_ROUND_CLOSEST (blue_raw *LED_FULL , max_raw);Quoted 9 lines
drivers/leds/led-core.c EXPORT_SYMBOL_GPL(leds_list_lock); · line 51
Quoted 4 lines
drivers/leds/led-core.c +4
-0+ + cdev->brightness = max_raw; + cdev->rgb_val = (red <<16 ) + (green <<8 ) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace to the driver.
Quoted 5 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values. Or do you see a better way?
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with LED_DEV_CAP_RGB flags set?
Quoted 5 lines
This leads me to another question: What do we need
led_update_brightnessfor in general? The cached and the actual value should always be in sync, except the actual brightness can be changed from outside the driver.
Do we have such cases?
It is possible that hardware will limit the brightness, e.g. due to the low battery voltage level.
Quoted 7 lines
Last but not least I saw that
led_update_brightnessis called inled_classdev_register.
Instead of updating our cached value with the actual value shouldn't we initialize cached and actual value (most likely to 0)?
The actual value theoretically could be uninitialized.
Seems like we rely on BIOS / boot loader to initialize LEDs.
Drivers are generally expected to initialize brightness to what they deem valid initial value. If a driver implements brightness_get op then brightness will be synchronized with device settings upon registering automatically thanks to this call.
Quoted 201 lines
Quoted 33 lines
Quoted 33 lines
drivers/leds/led-core.c +26
-0+static u32 led_get_rgb_raw (struct led_classdev *cdev,bool delayed) +{ +u32 rgb = delayed ? cdev->delayed_rgb_value : cdev->rgb_val; +u32 brightness = delayed ? cdev->delayed_set_value : + cdev->brightness; +u32 red = (rgb >>16 ) &0xff ; +u32 green = (rgb >>8 ) &0xff ; +u32 blue = rgb &0xff ; +u32 red_raw, green_raw, blue_raw; + + red_raw =DIV_ROUND_CLOSEST (red * brightness,LED_FULL ); + green_raw =DIV_ROUND_CLOSEST (green * brightness,LED_FULL ); + blue_raw =DIV_ROUND_CLOSEST (blue * brightness,LED_FULL ); + +return (red_raw <<16 ) + (green_raw <<8 ) + blue_raw; +} +static void led_timer_function (unsigned long data) {struct led_classdev *led_cdev = (void *)data;@@ -91,6 +133,21 @@ static void set_brightness_delayed(struct work_struct *ws) led_cdev->flags &= ~LED_BLINK_DISABLE ; } +if (led_isRGB (led_cdev)) { +u32 rgb =led_get_rgb_raw (led_cdev, true); + +if (led_cdev->rgb_set) + led_cdev->rgb_set (led_cdev, rgb); +else if (led_cdev->rgb_set_blocking) + ret = led_cdev->rgb_set_blocking (led_cdev, rgb); +else + ret = -EOPNOTSUPP ;Quoted 9 lines
drivers/leds/led-core.c static void set_brightness_delayed(struct work_struct *ws) · line 150
Quoted 6 lines
drivers/leds/led-core.c +6
-0+if (ret <0 ) +dev_err (led_cdev->dev, +"Setting LED RGB value failed (%d)\n" , ret); +return ; + } +Why this is needed? Could you share a use case?
If we re-use the existing brightness ops as suggested by you then most of this code isn't needed.
Quoted 132 lines
Quoted 13 lines
drivers/leds/led-core.c +6
-0if (led_cdev->brightness_set) led_cdev->brightness_set (led_cdev, led_cdev->delayed_set_value);else if (led_cdev->brightness_set_blocking)@@ -229,9 +286,35 @@ void led_set_brightness(struct led_classdev *led_cdev, }EXPORT_SYMBOL_GPL (led_set_brightness); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val) +{ +if (!led_isRGB (led_cdev) || (led_cdev->flags &LED_SUSPENDED )) +return ; + +led_set_rgb_raw (led_cdev, rgb_val);drivers/leds/led-core.c void led_set_brightness(struct led_classdev *led_cdev, · line 304
Quoted 10 lines
drivers/leds/led-core.c +10
-0+ +if (led_cdev->rgb_set) { + led_cdev->rgb_set (led_cdev, rgb_val); +return ; + } + +/* If RGB setting can sleep, delegate it to a work queue task */ + led_cdev->delayed_set_value = led_cdev->brightness; + led_cdev->delayed_rgb_value = led_cdev->rgb_val; +schedule_work (&led_cdev->set_brightness_work);I think that settings should be written to the device only in the
brightness_setop. We wouldn't need additional rgb op then.Quoted 105 lines
drivers/leds/led-core.c +33
-0+} +EXPORT_SYMBOL_GPL (led_set_rgb_val); +void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value) { +if (led_isRGB (led_cdev) && led_cdev->rgb_set) { +u32 rgb =led_get_rgb_raw (led_cdev, false); + + led_cdev->rgb_set (led_cdev, rgb); +return ; + } +/* Use brightness_set op if available, it is guaranteed not to sleep */ if (led_cdev->brightness_set) { led_cdev->brightness_set (led_cdev, value);@@ -240,6 +323,7 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,/* If brightness setting can sleep, delegate it to a work queue task */ led_cdev->delayed_set_value = value; + led_cdev->delayed_rgb_value = led_cdev->rgb_val;schedule_work (&led_cdev->set_brightness_work); }EXPORT_SYMBOL_GPL (led_set_brightness_nopm);@@ -267,6 +351,12 @@ int led_set_brightness_sync(struct led_classdev *led_cdev,if (led_cdev->flags &LED_SUSPENDED )return 0 ; +if (led_isRGB (led_cdev) && led_cdev->rgb_set_blocking) { +u32 rgb =led_get_rgb_raw (led_cdev, false); + +return led_cdev->rgb_set_blocking (led_cdev, rgb); + } +if (led_cdev->brightness_set_blocking)return led_cdev->brightness_set_blocking (led_cdev, led_cdev->brightness);@@ -290,6 +380,22 @@ int led_update_brightness(struct led_classdev *led_cdev) }EXPORT_SYMBOL_GPL (led_update_brightness); +int led_update_rgb_val (struct led_classdev *led_cdev) +{ +s32 ret =0 ; + +if (led_isRGB (led_cdev) && led_cdev->rgb_get) { + ret = led_cdev->rgb_get (led_cdev); +if (ret >=0 ) { +led_set_rgb_raw (led_cdev, ret); +return 0 ; + } + } + +return ret; +} +EXPORT_SYMBOL_GPL (led_update_rgb_val); +/* Caller must ensure led_cdev->led_access held */ void led_sysfs_disable (struct led_classdev *led_cdev) {drivers/leds/leds.h +12
-0@@ -16,17 +16,29 @@#include <linux/rwsem.h> #include <linux/leds.h> +static inline bool led_isRGB (struct led_classdev *led_cdev) +{ +return (led_cdev->flags &LED_RGB ) !=0 ; +} +static inline int led_get_brightness (struct led_classdev *led_cdev) {return led_cdev->brightness; } +static inline u32 led_get_rgb_val (struct led_classdev *led_cdev) +{ +return led_cdev->rgb_val; +} +void led_init_core (struct led_classdev *led_cdev);void led_stop_software_blink (struct led_classdev *led_cdev);void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value);void led_set_brightness_nosleep (struct led_classdev *led_cdev,enum led_brightness value); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val); +int led_update_rgb_val (struct led_classdev *led_cdev);extern struct rw_semaphore leds_list_lock;extern struct list_head leds_list;include/linux/leds.h +1
-0@@ -35,6 +35,7 @@ struct led_classdev {const char *name;enum led_brightness brightness;enum led_brightness max_brightness; +u32 rgb_val;int flags;Quoted 9 lines
include/linux/leds.h struct led_classdev { · line 52
Quoted 6 lines
include/linux/leds.h +1
-0/* Lower 16 bits reflect status */ @@ -48,6 +49,7 @@ struct led_classdev {#define LED_BLINK_DISABLE (1 << 21)#define LED_SYSFS_DISABLE (1 << 22)#define LED_DEV_CAP_FLASH (1 << 23) +#define LED_RGB (1 << 24)Please rename it to
LED_DEV_CAP_RGB.OK
Quoted 13 lines
include/linux/leds.h struct led_classdev { · line 63
Quoted 10 lines
include/linux/leds.h +3
-0/* Set LED brightness level */ /* Must not sleep. If no non-blocking version can be provided @@ -56,15 +58,25 @@ struct led_classdev {*/ void (*brightness_set)(struct led_classdev *led_cdev,enum led_brightness brightness); + +void (*rgb_set)(struct led_classdev *led_cdev, +u32 rgb_val);Without this everything would be much simpler.
Quoted 3 lines
Sure, we can re-use the existing ops. I just thought it would be a little ugly to misuse enum
led_brightnessfor RGB values. But as it internally is an int we can also do it this way.
I think that this is a good idea. It would require only addition of one flag and maybe we could think of some new sysfs attribute which would allow to detect if a LED is of RGB type.
Quoted 58 lines
Quoted 35 lines
If we wanted to change the color and intensity we would need to:
1. Set rgb (value only cached in the LED core)
2. Set brightness (write both brightness and rgb settings to the hw)Current brightness can always be obtained with
led_get_brightnessin case only rgb is to be set.include/linux/leds.h struct led_classdev { · line 73
Quoted 10 lines
include/linux/leds.h +4
-0/* * Set LED brightness level immediately - it can block the caller for * the time required for accessing a LED device register. */ int (*brightness_set_blocking)(struct led_classdev *led_cdev,enum led_brightness brightness); + +int (*rgb_set_blocking)(struct led_classdev *led_cdev, +u32 rgb_val); +This is also not needed.
include/linux/leds.h struct led_classdev { · line 79
Quoted 6 lines
include/linux/leds.h +3
-0/* Get LED brightness level */ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); +/* Get LED RGB val */ +s32 (*rgb_get)(struct led_classdev *led_cdev); +Ditto.
Quoted 5 lines
include/linux/leds.h +0
-0/* * Activate hardware accelerated blink, delays are in milliseconds * and if both are zero then a sensible default should be chosen. @@ -90,6 +102,7 @@ struct led_classdev {Quoted 6 lines
include/linux/leds.h struct led_classdev { · line 105
Quoted 3 lines
include/linux/leds.h +1
-0struct work_struct set_brightness_work;int delayed_set_value; +u32 delayed_rgb_value;Ditto.
If we have a blocking set callback then we have to set a RGB value from the workqueue. And we need brightness + RGB to calculate the effective RGB values in the worker func. Therefore I think
delayed_rgb_valis needed.Quoted 6 lines
include/linux/leds.h struct led_classdev {
Quoted 4 lines
include/linux/leds.h +0
-0#ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */ Thanks for the review, Heiner
--
To unsubscribe from this list: send the line "unsubscribe linux-leds" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best Regards, Jacek Anaszewski
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 211 lines · Heiner Kallweit
Quoted 89 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 79 lines · Heiner Kallweit
Quoted 78 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdevper RGB LED. Also userspace should be able to change the color with one call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected by the RGB extension.
This patch is intended to demonstrate the idea of the extension. Most likely it's not ready yet for submission.
Main idea is to base the effective RGB value on a combination of brightness and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags bitmap.Experimentally I changed the thingm driver to use this extension and it works quite well. As one result the driver could be very much simplified.
Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)drivers/leds/led-class.c +27
-0@@ -64,6 +64,47 @@ unlock: }static DEVICE_ATTR_RW (brightness); +static ssize_t rgb_show (struct device *dev,struct device_attribute *attr, +char *buf) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +u32 rgb_val; + +mutex_lock (&led_cdev->led_access); +led_update_rgb_val (led_cdev); + rgb_val =led_get_rgb_val (led_cdev); +mutex_unlock (&led_cdev->led_access); + +return sprintf (buf,"0x%06x\n" , rgb_val); +} + +static ssize_t rgb_store (struct device *dev,struct device_attribute *attr, +const char *buf,size_t size) +{ +struct led_classdev *led_cdev =dev_get_drvdata (dev); +unsigned long state; +ssize_t ret; + +mutex_lock (&led_cdev->led_access); + +if (led_sysfs_is_disabled (led_cdev)) { + ret = -EBUSY ; + goto unlock; + }Quoted 9 lines
drivers/leds/led-class.c unlock: · line 99
Quoted 6 lines
drivers/leds/led-class.c +6
-0+ + ret =kstrtoul (buf,0 , &state); +if (ret) + goto unlock; + +led_set_rgb_val (led_cdev, state);Please adhere to the current LED API naming style:
led_rgb_set.Quoted 3 lines
Seems like currently two naming styles are use in the LED core. We have e.g.
led_blink_setandled_set_brightness. However I'm fine with the suggestedled_rgb_set.Indeed. Your version would be preferable in this case. I wanted this to match
led_set_brightnessstyle, but had been too lazy to double check that :-/Quoted 107 lines
Quoted 15 lines
Quoted 15 lines
drivers/leds/led-class.c +8
-0+ + ret = size; +unlock: +mutex_unlock (&led_cdev->led_access); +return ret; +} +static DEVICE_ATTR_RW (rgb); +static ssize_t max_brightness_show (struct device *dev,struct device_attribute *attr,char *buf) {@@ -190,6 +231,16 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)char name[64 ];int ret;Quoted 9 lines
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 238
Quoted 5 lines
drivers/leds/led-class.c +5
-0+/* FLASH is not supported for RGB LEDs so far +* and RGB enforces max_brightness = LED_FULL. +* Initialize the color as white. +*/ +if (led_isRGB (led_cdev)) {Don't use camel case. Change it to
led_is_rgbor check the flag directly.OK, will change it to
led_is_rgb.Quoted 5 lines
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 239
Quoted 1 line
drivers/leds/led-class.c +1
-0+ led_cdev->flags &= ~LED_DEV_CAP_FLASH ;I'd rather check whether both FLASH and RGB flag are set and return error in this case.
OK
Quoted 11 lines
Quoted 11 lines
drivers/leds/led-class.c +4
-0+ led_cdev->max_brightness =LED_FULL ; + led_cdev->rgb_val =0xffffff ; + } + ret =led_classdev_next_name (led_cdev->name, name,sizeof (name));if (ret <0 )return ret;@@ -203,6 +254,14 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)dev_warn (parent,"Led %s renamed to %s due to name collision" , led_cdev->name,dev_name (led_cdev->dev));Quoted 5 lines
drivers/leds/led-class.c int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) · line 258
Quoted 2 lines
drivers/leds/led-class.c +2
-0+if (led_isRGB (led_cdev)) { + ret =device_create_file (led_cdev->dev, &dev_attr_rgb);Please use
led_cdev->groupsfor this. You can refer todrivers/leds/led-class-flash.c.OK
Quoted 47 lines
Quoted 47 lines
drivers/leds/led-class.c +9
-0+if (ret) { +device_unregister (led_cdev->dev); +return ret; + } + } +#ifdef CONFIG_LEDS_TRIGGERS init_rwsem (&led_cdev->trigger_lock);#endif @@ -252,6 +311,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)flush_work (&led_cdev->set_brightness_work); +if (led_isRGB (led_cdev)) +device_remove_file (led_cdev->dev, &dev_attr_rgb); +device_unregister (led_cdev->dev);down_write (&leds_list_lock);drivers/leds/led-core.c +20
-0@@ -25,6 +25,48 @@ EXPORT_SYMBOL_GPL(leds_list_lock);LIST_HEAD (leds_list);EXPORT_SYMBOL_GPL (leds_list); +static void led_set_rgb_raw (struct led_classdev *cdev,u32 rgb) +{ +u32 red_raw = (rgb >>16 ) &0xff ; +u32 green_raw = (rgb >>8 ) &0xff ; +u32 blue_raw = rgb &0xff ; +u32 max_raw, red, green, blue; + + max_raw =max (red_raw, green_raw); +if (blue_raw > max_raw) + max_raw = blue_raw; + +if (!max_raw) { + cdev->brightness =0 ; + cdev->rgb_val =0 ; +return ; + } + + red =DIV_ROUND_CLOSEST (red_raw *LED_FULL , max_raw); + green =DIV_ROUND_CLOSEST (green_raw *LED_FULL , max_raw); + blue =DIV_ROUND_CLOSEST (blue_raw *LED_FULL , max_raw);Quoted 9 lines
drivers/leds/led-core.c EXPORT_SYMBOL_GPL(leds_list_lock); · line 51
Quoted 4 lines
drivers/leds/led-core.c +4
-0+ + cdev->brightness = max_raw; + cdev->rgb_val = (red <<16 ) + (green <<8 ) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace to the driver.
Quoted 5 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values. Or do you see a better way?
Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.
I pepared a new verion of the patch covering your review comments and will submit it shortly.
Regards, Heiner
Quoted 290 lines
Quoted 5 lines
This leads me to another question: What do we need
led_update_brightnessfor in general? The cached and the actual value should always be in sync, except the actual brightness can be changed from outside the driver.
Do we have such cases?It is possible that hardware will limit the brightness, e.g. due to the low battery voltage level.
Quoted 7 lines
Last but not least I saw that
led_update_brightnessis called inled_classdev_register.
Instead of updating our cached value with the actual value shouldn't we initialize cached and actual value (most likely to 0)?
The actual value theoretically could be uninitialized.
Seems like we rely on BIOS / boot loader to initialize LEDs.Drivers are generally expected to initialize brightness to what they deem valid initial value. If a driver implements
brightness_getop then brightness will be synchronized with device settings upon registering automatically thanks to this call.Quoted 201 lines
Quoted 33 lines
Quoted 33 lines
drivers/leds/led-core.c +26
-0+static u32 led_get_rgb_raw (struct led_classdev *cdev,bool delayed) +{ +u32 rgb = delayed ? cdev->delayed_rgb_value : cdev->rgb_val; +u32 brightness = delayed ? cdev->delayed_set_value : + cdev->brightness; +u32 red = (rgb >>16 ) &0xff ; +u32 green = (rgb >>8 ) &0xff ; +u32 blue = rgb &0xff ; +u32 red_raw, green_raw, blue_raw; + + red_raw =DIV_ROUND_CLOSEST (red * brightness,LED_FULL ); + green_raw =DIV_ROUND_CLOSEST (green * brightness,LED_FULL ); + blue_raw =DIV_ROUND_CLOSEST (blue * brightness,LED_FULL ); + +return (red_raw <<16 ) + (green_raw <<8 ) + blue_raw; +} +static void led_timer_function (unsigned long data) {struct led_classdev *led_cdev = (void *)data;@@ -91,6 +133,21 @@ static void set_brightness_delayed(struct work_struct *ws) led_cdev->flags &= ~LED_BLINK_DISABLE ; } +if (led_isRGB (led_cdev)) { +u32 rgb =led_get_rgb_raw (led_cdev, true); + +if (led_cdev->rgb_set) + led_cdev->rgb_set (led_cdev, rgb); +else if (led_cdev->rgb_set_blocking) + ret = led_cdev->rgb_set_blocking (led_cdev, rgb); +else + ret = -EOPNOTSUPP ;Quoted 9 lines
drivers/leds/led-core.c static void set_brightness_delayed(struct work_struct *ws) · line 150
Quoted 6 lines
drivers/leds/led-core.c +6
-0+if (ret <0 ) +dev_err (led_cdev->dev, +"Setting LED RGB value failed (%d)\n" , ret); +return ; + } +Why this is needed? Could you share a use case?
If we re-use the existing brightness ops as suggested by you then most of this code isn't needed.
Quoted 132 lines
Quoted 13 lines
drivers/leds/led-core.c +6
-0if (led_cdev->brightness_set) led_cdev->brightness_set (led_cdev, led_cdev->delayed_set_value);else if (led_cdev->brightness_set_blocking)@@ -229,9 +286,35 @@ void led_set_brightness(struct led_classdev *led_cdev, }EXPORT_SYMBOL_GPL (led_set_brightness); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val) +{ +if (!led_isRGB (led_cdev) || (led_cdev->flags &LED_SUSPENDED )) +return ; + +led_set_rgb_raw (led_cdev, rgb_val);drivers/leds/led-core.c void led_set_brightness(struct led_classdev *led_cdev, · line 304
Quoted 10 lines
drivers/leds/led-core.c +10
-0+ +if (led_cdev->rgb_set) { + led_cdev->rgb_set (led_cdev, rgb_val); +return ; + } + +/* If RGB setting can sleep, delegate it to a work queue task */ + led_cdev->delayed_set_value = led_cdev->brightness; + led_cdev->delayed_rgb_value = led_cdev->rgb_val; +schedule_work (&led_cdev->set_brightness_work);I think that settings should be written to the device only in the
brightness_setop. We wouldn't need additional rgb op then.Quoted 105 lines
drivers/leds/led-core.c +33
-0+} +EXPORT_SYMBOL_GPL (led_set_rgb_val); +void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value) { +if (led_isRGB (led_cdev) && led_cdev->rgb_set) { +u32 rgb =led_get_rgb_raw (led_cdev, false); + + led_cdev->rgb_set (led_cdev, rgb); +return ; + } +/* Use brightness_set op if available, it is guaranteed not to sleep */ if (led_cdev->brightness_set) { led_cdev->brightness_set (led_cdev, value);@@ -240,6 +323,7 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,/* If brightness setting can sleep, delegate it to a work queue task */ led_cdev->delayed_set_value = value; + led_cdev->delayed_rgb_value = led_cdev->rgb_val;schedule_work (&led_cdev->set_brightness_work); }EXPORT_SYMBOL_GPL (led_set_brightness_nopm);@@ -267,6 +351,12 @@ int led_set_brightness_sync(struct led_classdev *led_cdev,if (led_cdev->flags &LED_SUSPENDED )return 0 ; +if (led_isRGB (led_cdev) && led_cdev->rgb_set_blocking) { +u32 rgb =led_get_rgb_raw (led_cdev, false); + +return led_cdev->rgb_set_blocking (led_cdev, rgb); + } +if (led_cdev->brightness_set_blocking)return led_cdev->brightness_set_blocking (led_cdev, led_cdev->brightness);@@ -290,6 +380,22 @@ int led_update_brightness(struct led_classdev *led_cdev) }EXPORT_SYMBOL_GPL (led_update_brightness); +int led_update_rgb_val (struct led_classdev *led_cdev) +{ +s32 ret =0 ; + +if (led_isRGB (led_cdev) && led_cdev->rgb_get) { + ret = led_cdev->rgb_get (led_cdev); +if (ret >=0 ) { +led_set_rgb_raw (led_cdev, ret); +return 0 ; + } + } + +return ret; +} +EXPORT_SYMBOL_GPL (led_update_rgb_val); +/* Caller must ensure led_cdev->led_access held */ void led_sysfs_disable (struct led_classdev *led_cdev) {drivers/leds/leds.h +12
-0@@ -16,17 +16,29 @@#include <linux/rwsem.h> #include <linux/leds.h> +static inline bool led_isRGB (struct led_classdev *led_cdev) +{ +return (led_cdev->flags &LED_RGB ) !=0 ; +} +static inline int led_get_brightness (struct led_classdev *led_cdev) {return led_cdev->brightness; } +static inline u32 led_get_rgb_val (struct led_classdev *led_cdev) +{ +return led_cdev->rgb_val; +} +void led_init_core (struct led_classdev *led_cdev);void led_stop_software_blink (struct led_classdev *led_cdev);void led_set_brightness_nopm (struct led_classdev *led_cdev,enum led_brightness value);void led_set_brightness_nosleep (struct led_classdev *led_cdev,enum led_brightness value); +void led_set_rgb_val (struct led_classdev *led_cdev,u32 rgb_val); +int led_update_rgb_val (struct led_classdev *led_cdev);extern struct rw_semaphore leds_list_lock;extern struct list_head leds_list;include/linux/leds.h +1
-0@@ -35,6 +35,7 @@ struct led_classdev {const char *name;enum led_brightness brightness;enum led_brightness max_brightness; +u32 rgb_val;int flags;Quoted 9 lines
include/linux/leds.h struct led_classdev { · line 52
Quoted 6 lines
include/linux/leds.h +1
-0/* Lower 16 bits reflect status */ @@ -48,6 +49,7 @@ struct led_classdev {#define LED_BLINK_DISABLE (1 << 21)#define LED_SYSFS_DISABLE (1 << 22)#define LED_DEV_CAP_FLASH (1 << 23) +#define LED_RGB (1 << 24)Please rename it to
LED_DEV_CAP_RGB.OK
Quoted 13 lines
include/linux/leds.h struct led_classdev { · line 63
Quoted 10 lines
include/linux/leds.h +3
-0/* Set LED brightness level */ /* Must not sleep. If no non-blocking version can be provided @@ -56,15 +58,25 @@ struct led_classdev {*/ void (*brightness_set)(struct led_classdev *led_cdev,enum led_brightness brightness); + +void (*rgb_set)(struct led_classdev *led_cdev, +u32 rgb_val);Without this everything would be much simpler.
Quoted 3 lines
Sure, we can re-use the existing ops. I just thought it would be a little ugly to misuse enum
led_brightnessfor RGB values. But as it internally is an int we can also do it this way.I think that this is a good idea. It would require only addition of one flag and maybe we could think of some new sysfs attribute which would allow to detect if a LED is of RGB type.
Quoted 58 lines
Quoted 35 lines
If we wanted to change the color and intensity we would need to:
1. Set rgb (value only cached in the LED core)
2. Set brightness (write both brightness and rgb settings to the hw)Current brightness can always be obtained with
led_get_brightnessin case only rgb is to be set.include/linux/leds.h struct led_classdev { · line 73
Quoted 10 lines
include/linux/leds.h +4
-0/* * Set LED brightness level immediately - it can block the caller for * the time required for accessing a LED device register. */ int (*brightness_set_blocking)(struct led_classdev *led_cdev,enum led_brightness brightness); + +int (*rgb_set_blocking)(struct led_classdev *led_cdev, +u32 rgb_val); +This is also not needed.
include/linux/leds.h struct led_classdev { · line 79
Quoted 6 lines
include/linux/leds.h +3
-0/* Get LED brightness level */ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); +/* Get LED RGB val */ +s32 (*rgb_get)(struct led_classdev *led_cdev); +Ditto.
Quoted 5 lines
include/linux/leds.h +0
-0/* * Activate hardware accelerated blink, delays are in milliseconds * and if both are zero then a sensible default should be chosen. @@ -90,6 +102,7 @@ struct led_classdev {Quoted 6 lines
include/linux/leds.h struct led_classdev { · line 105
Quoted 3 lines
include/linux/leds.h +1
-0struct work_struct set_brightness_work;int delayed_set_value; +u32 delayed_rgb_value;Ditto.
If we have a blocking set callback then we have to set a RGB value from the workqueue. And we need brightness + RGB to calculate the effective RGB values in the worker func. Therefore I think
delayed_rgb_valis needed.Quoted 6 lines
include/linux/leds.h struct led_classdev {
Quoted 4 lines
include/linux/leds.h +0
-0#ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */ Thanks for the review, Heiner
Signature · 3 lines
To unsubscribe from this list: send the line "unsubscribe linux-leds" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Heiner,
Quoted 47 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 46 lines · Heiner Kallweit
Quoted 45 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 44 lines · Heiner Kallweit
Quoted 43 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdevper RGB LED. Also userspace should be able to change the color with one call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected by the RGB extension.
This patch is intended to demonstrate the idea of the extension. Most likely it's not ready yet for submission.
Main idea is to base the effective RGB value on a combination of brightness and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags bitmap.Experimentally I changed the thingm driver to use this extension and it works quite well. As one result the driver could be very much simplified.
Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)
[...]
Quoted 41 lines
Quoted 35 lines
Quoted 29 lines
Quoted 20 lines
Quoted 20 lines
drivers/leds/led-core.c +20
-0+static void led_set_rgb_raw (struct led_classdev *cdev,u32 rgb) +{ +u32 red_raw = (rgb >>16 ) &0xff ; +u32 green_raw = (rgb >>8 ) &0xff ; +u32 blue_raw = rgb &0xff ; +u32 max_raw, red, green, blue; + + max_raw =max (red_raw, green_raw); +if (blue_raw > max_raw) + max_raw = blue_raw; + +if (!max_raw) { + cdev->brightness =0 ; + cdev->rgb_val =0 ; +return ; + } + + red =DIV_ROUND_CLOSEST (red_raw *LED_FULL , max_raw); + green =DIV_ROUND_CLOSEST (green_raw *LED_FULL , max_raw); + blue =DIV_ROUND_CLOSEST (blue_raw *LED_FULL , max_raw);Quoted 9 lines
drivers/leds/led-core.c EXPORT_SYMBOL_GPL(leds_list_lock); · line 51
Quoted 4 lines
drivers/leds/led-core.c +4
-0+ + cdev->brightness = max_raw; + cdev->rgb_val = (red <<16 ) + (green <<8 ) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace to the driver.
Quoted 5 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values. Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?
Quoted 7 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.
Currently blinking works properly and brightness value isn't being lost. We store it in the led_cdev->blink_brightness property. Could you present exact use case you'd like to support and which is not feasible with current LED core design?
Signature · 2 lines
Best Regards, Jacek Anaszewski
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Quoted 58 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 56 lines · Heiner Kallweit
Quoted 54 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there
are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdev
per RGB LED. Also userspace should be able to change the color with one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 40 lines
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
drivers/leds/led-core.c +22
-0+static void led_set_rgb_raw (struct led_classdev *cdev,u32 rgb) +{ +u32 red_raw = (rgb >>16 ) &0xff ; +u32 green_raw = (rgb >>8 ) &0xff ; +u32 blue_raw = rgb &0xff ; +u32 max_raw, red, green, blue; + + max_raw =max (red_raw, green_raw); +if (blue_raw > max_raw) + max_raw = blue_raw; + +if (!max_raw) { + cdev->brightness =0 ; + cdev->rgb_val =0 ; +return ; + } + + red =DIV_ROUND_CLOSEST (red_raw *LED_FULL , max_raw); + green =DIV_ROUND_CLOSEST (green_raw *LED_FULL , max_raw); + blue =DIV_ROUND_CLOSEST (blue_raw *LED_FULL , max_raw); + + cdev->brightness = max_raw;Quoted 9 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ cdev->rgb_val = (red << 16) + (green << 8) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace
to the driver.Quoted 7 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness
value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values.
Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.
Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?
I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.
So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set to LED_OFF by the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose? That's why I'm saying we should store color and brightness separately to avoid losing the color information information even if the brightness is set to zero.
Regards, Heiner
Quoted 3 lines
--
Best Regards,
Jacek Anaszewski
Quoted 137 lines · Heiner Kallweit
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Quoted 58 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 56 lines · Heiner Kallweit
Quoted 54 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there
are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdev
per RGB LED. Also userspace should be able to change the color with one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 40 lines
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
(quoted diff) +22
-0+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb) +{ + u32 red_raw = (rgb >> 16) & 0xff; + u32 green_raw = (rgb >> 8) & 0xff; + u32 blue_raw = rgb & 0xff; + u32 max_raw, red, green, blue; + + max_raw = max(red_raw, green_raw); + if (blue_raw > max_raw) + max_raw = blue_raw; + + if (!max_raw) { + cdev->brightness = 0; + cdev->rgb_val = 0; + return; + } + + red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw); + green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw); + blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw); + + cdev->brightness = max_raw;Quoted 9 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ cdev->rgb_val = (red << 16) + (green << 8) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace
to the driver.Quoted 7 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness
value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values.
Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.
Quoted 5 lines
So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?
The one stored in blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.
Quoted 5 lines
That's why I'm saying we should store color and brightness separately to avoid losing the color information information even if the brightness is set to zero.
Regards, Heiner
Signature · 2 lines
Best Regards, Jacek Anaszewski
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 138 lines · Heiner Kallweit
Quoted 137 lines
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Quoted 58 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 56 lines · Heiner Kallweit
Quoted 54 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there
are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdev
per RGB LED. Also userspace should be able to change the color with one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 40 lines
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
(quoted diff) +22
-0+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb) +{ + u32 red_raw = (rgb >> 16) & 0xff; + u32 green_raw = (rgb >> 8) & 0xff; + u32 blue_raw = rgb & 0xff; + u32 max_raw, red, green, blue; + + max_raw = max(red_raw, green_raw); + if (blue_raw > max_raw) + max_raw = blue_raw; + + if (!max_raw) { + cdev->brightness = 0; + cdev->rgb_val = 0; + return; + } + + red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw); + green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw); + blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw); + + cdev->brightness = max_raw;Quoted 9 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ cdev->rgb_val = (red << 16) + (green << 8) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace
to the driver.Quoted 7 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness
value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values.
Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.
Quoted 9 lines
Quoted 5 lines
So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.
But blink_brightness is used in case of soft blink only.
If a trigger or userspace sets the brightness to zero then blink_brightness isn't used.
I agreed that soft blink was a bad example.
Quoted 8 lines
Quoted 5 lines
That's why I'm saying we should store color and brightness separately to avoid losing the color information information even if the brightness is set to zero.
Regards, Heiner
Quoted 145 lines · Heiner Kallweit
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Quoted 58 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 56 lines · Heiner Kallweit
Quoted 54 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there
are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdev
per RGB LED. Also userspace should be able to change the color with one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 40 lines
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
(quoted diff) +22
-0+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb) +{ + u32 red_raw = (rgb >> 16) & 0xff; + u32 green_raw = (rgb >> 8) & 0xff; + u32 blue_raw = rgb & 0xff; + u32 max_raw, red, green, blue; + + max_raw = max(red_raw, green_raw); + if (blue_raw > max_raw) + max_raw = blue_raw; + + if (!max_raw) { + cdev->brightness = 0; + cdev->rgb_val = 0; + return; + } + + red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw); + green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw); + blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw); + + cdev->brightness = max_raw;Quoted 9 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ cdev->rgb_val = (red << 16) + (green << 8) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace
to the driver.Quoted 7 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness
value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values.
Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?
Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.
In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.
Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to LED_OFF it will also disable the timer trigger."
Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to LED_OFF disables any trigger only when set from sysfs (in drivers/leds/led-class.c brightness_store calls led_trigger_remove if passed brightness is LED_OFF).
However, when setting brightness to LED_OFF directly through LED API, and not through sysfs, only blink_timer is being disabled, but trigger isn't being removed. Probably we'd have to remove trigger from set_brightness_delayed(), in case LED_BLINK_DISABLE is set, to make implementation in line with the documentation.
Quoted 12 lines
I agreed that soft blink was a bad example.
Quoted 8 lines
Quoted 5 lines
That's why I'm saying we should store color and brightness separately to avoid losing the color information information even if the brightness is set to zero.
Regards, Heiner
Signature · 2 lines
Best Regards, Jacek Anaszewski
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Quoted 58 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 56 lines · Heiner Kallweit
Quoted 54 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there
are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdev
per RGB LED. Also userspace should be able to change the color with one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 40 lines
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
(quoted diff) +22
-0+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb) +{ + u32 red_raw = (rgb >> 16) & 0xff; + u32 green_raw = (rgb >> 8) & 0xff; + u32 blue_raw = rgb & 0xff; + u32 max_raw, red, green, blue; + + max_raw = max(red_raw, green_raw); + if (blue_raw > max_raw) + max_raw = blue_raw; + + if (!max_raw) { + cdev->brightness = 0; + cdev->rgb_val = 0; + return; + } + + red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw); + green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw); + blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw); + + cdev->brightness = max_raw;Quoted 9 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ cdev->rgb_val = (red << 16) + (green << 8) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace
to the driver.Quoted 7 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness
value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values.
Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).
Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.
Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member of led_classdev to store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Regards, Heiner
Quoted 14 lines
Quoted 12 lines
I agreed that soft blink was a bad example.
Quoted 8 lines
Quoted 5 lines
That's why I'm saying we should store color and brightness separately to avoid losing the color information information even if the brightness is set to zero.
Regards, Heiner
Quoted 186 lines · Heiner Kallweit
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Quoted 58 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 56 lines · Heiner Kallweit
Quoted 54 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there
are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdev
per RGB LED. Also userspace should be able to change the color with one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 40 lines
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
(quoted diff) +22
-0+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb) +{ + u32 red_raw = (rgb >> 16) & 0xff; + u32 green_raw = (rgb >> 8) & 0xff; + u32 blue_raw = rgb & 0xff; + u32 max_raw, red, green, blue; + + max_raw = max(red_raw, green_raw); + if (blue_raw > max_raw) + max_raw = blue_raw; + + if (!max_raw) { + cdev->brightness = 0; + cdev->rgb_val = 0; + return; + } + + red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw); + green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw); + blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw); + + cdev->brightness = max_raw;Quoted 9 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ cdev->rgb_val = (red << 16) + (green << 8) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace
to the driver.Quoted 7 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness
value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values.
Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)
Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Signature · 2 lines
Best Regards, Jacek Anaszewski
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 194 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Quoted 58 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 56 lines · Heiner Kallweit
Quoted 54 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that there
are few drivers for RGB LED's spread across the kernel and each one implements the RGB functionality in its own way.
Some examples:
-drivers/hid/hid-thingm.c
-drivers/usb/misc/usbled.c
-drivers/leds/leds-bd2802.c
-drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED core.Things I didn't like too much in other driver implementations:
- oneled_classdevper color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer oneled_classdev
per RGB LED. Also userspace should be able to change the color with one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness. RGB functionally can be switched on with a new flag in the led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by Heiner Kallweit <[email protected]>--- drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++ drivers/leds/led-core.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds.h | 12 ++++++ include/linux/leds.h | 13 ++++++ 4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 40 lines
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
(quoted diff) +22
-0+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb) +{ + u32 red_raw = (rgb >> 16) & 0xff; + u32 green_raw = (rgb >> 8) & 0xff; + u32 blue_raw = rgb & 0xff; + u32 max_raw, red, green, blue; + + max_raw = max(red_raw, green_raw); + if (blue_raw > max_raw) + max_raw = blue_raw; + + if (!max_raw) { + cdev->brightness = 0; + cdev->rgb_val = 0; + return; + } + + red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw); + green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw); + blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw); + + cdev->brightness = max_raw;Quoted 9 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ cdev->rgb_val = (red << 16) + (green << 8) + blue; +}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace
to the driver.Quoted 7 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness
value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values.
Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
Quoted 9 lines
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.
Regards, Heiner
Quoted 200 lines · Heiner Kallweit
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 199 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Quoted 58 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 56 lines · Heiner Kallweit
Quoted 54 lines
When playing with a ThingM Blink(1) USB RGB LED device I found that
there
are few drivers for RGB LED's spread across the kernel and each one
implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED
core.Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one
led_classdev
per RGB LED. Also userspace should be able to change the color with
one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be
effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most
likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of
brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness.
RGB functionally can be switched on with a new flag in the
led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and
it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by: Heiner Kallweit <[email protected]>
---
drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++
drivers/leds/led-core.c | 106
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/leds/leds.h | 12 ++++++
include/linux/leds.h | 13 ++++++
4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 40 lines
Quoted 31 lines
Quoted 22 lines
Quoted 22 lines
+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb)
+{
+ u32 red_raw = (rgb >> 16) & 0xff;
+ u32 green_raw = (rgb >> 8) & 0xff;
+ u32 blue_raw = rgb & 0xff;
+ u32 max_raw, red, green, blue;
+
+ max_raw = max(red_raw, green_raw);
+ if (blue_raw > max_raw)
+ max_raw = blue_raw;
+
+ if (!max_raw) {
+ cdev->brightness = 0;
+ cdev->rgb_val = 0;
+ return;
+ }
+
+ red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw);
+ green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw);
+ blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw);
+
+ cdev->brightness = max_raw;Quoted 9 lines
Quoted 2 lines
+ cdev->rgb_val = (red << 16) + (green << 8) + blue;
+}I think that we shouldn't impose specific way of calculating brightness depending on the rgb value set. We should just pass value from userspace
to the driver.Quoted 7 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness
value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values.
Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
Quoted 8 lines
Quoted 4 lines
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
It is possible even now - brightness can be changed during blinking, but it is applied from the next transition to "on" state.
Quoted 4 lines
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.
It would suffice to implement dedicated trigger for this. IMO it would be an over engineering, though. We can support what you want by exposing each color as a separate LED class device and adding a means for LED class device synchronization, I was proposing in the beginning.
It would be convenient because it would allow to avoid code duplication in the LED core. I think that gathering all the colors in the single functionality could be a task for the user space.
Signature · 2 lines
Best Regards, Jacek Anaszewski
Am 29.01.2016 um 09:24 schrieb Jacek Anaszewski:
Quoted 218 lines · Heiner Kallweit
Quoted 200 lines
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 199 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Quoted 58 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
Quoted 56 lines · Heiner Kallweit
When playing with a ThingM Blink(1) USB RGB LED device I found that
there
are few drivers for RGB LED's spread across the kernel and each one
implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED
core.Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one
led_classdev
per RGB LED. Also userspace should be able to change the color with
one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be
effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most
likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of
brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness.
RGB functionally can be switched on with a new flag in the
led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and
it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by: Heiner Kallweit <[email protected]>
---
drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++
drivers/leds/led-core.c | 106
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/leds/leds.h | 12 ++++++
include/linux/leds.h | 13 ++++++
4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 40 lines
Quoted 31 lines
Quoted 31 lines
+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb)
+{
+ u32 red_raw = (rgb >> 16) & 0xff;
+ u32 green_raw = (rgb >> 8) & 0xff;
+ u32 blue_raw = rgb & 0xff;
+ u32 max_raw, red, green, blue;
+
+ max_raw = max(red_raw, green_raw);
+ if (blue_raw > max_raw)
+ max_raw = blue_raw;
+
+ if (!max_raw) {
+ cdev->brightness = 0;
+ cdev->rgb_val = 0;
+ return;
+ }
+
+ red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw);
+ green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw);
+ blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw);
+
+ cdev->brightness = max_raw;
+ cdev->rgb_val = (red << 16) + (green << 8) + blue;
+}I think that we shouldn't impose specific way of calculating brightness
depending on the rgb value set. We should just pass value from
userspace
to the driver.Quoted 7 lines
Right, setting brightness from userspace is no problem.
But how aboutled_update_brightness? It's supposed to update the brightness
value inled_cdevwith the actual value. And for a RGB LED we have only the RGB values, so we need to calculate the brightness based on RGB values.
Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
Quoted 8 lines
Quoted 4 lines
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
It is possible even now - brightness can be changed during blinking, but it is applied from the next transition to "on" state.
Quoted 4 lines
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.
Quoted 9 lines
It would suffice to implement dedicated trigger for this. IMO it would be an over engineering, though. We can support what you want by exposing each color as a separate LED class device and adding a means for LED class device synchronization, I was proposing in the beginning.
It would be convenient because it would allow to avoid code duplication in the LED core. I think that gathering all the colors in the single functionality could be a task for the user space.
By chance I had to deal with HSV color scheme in another project and using this color scheme core-internally for color LED's might help us to facilitate backwards compatibility and reduce the needed changes to the core. It would also allow to easily solve the question we're discussing here.
The brightness is part of the HSV model anyway so we would just have to add hue / saturation. Conversion to / from RGB would be done on demand. I have a small prototype that needs much less changes to the core logic. I'll come up with a re-worked proposal for handling color LED's.
Regards, Heiner
Quoted 233 lines · Heiner Kallweit
Am 29.01.2016 um 09:24 schrieb Jacek Anaszewski:
Quoted 218 lines · Heiner Kallweit
Quoted 200 lines
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 199 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Quoted 58 lines
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
On 01/10/2016 09:27 PM, Heiner Kallweit wrote:
When playing with a ThingM Blink(1) USB RGB LED device I found that
there
are few drivers for RGB LED's spread across the kernel and each one
implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED
core.Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one
led_classdev
per RGB LED. Also userspace should be able to change the color with
one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be
effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most
likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of
brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness.
RGB functionally can be switched on with a new flag in the
led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and
it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by: Heiner Kallweit <[email protected]>
---
drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++
drivers/leds/led-core.c | 106
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/leds/leds.h | 12 ++++++
include/linux/leds.h | 13 ++++++
4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 40 lines
Quoted 38 lines
+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb)
+{
+ u32 red_raw = (rgb >> 16) & 0xff;
+ u32 green_raw = (rgb >> 8) & 0xff;
+ u32 blue_raw = rgb & 0xff;
+ u32 max_raw, red, green, blue;
+
+ max_raw = max(red_raw, green_raw);
+ if (blue_raw > max_raw)
+ max_raw = blue_raw;
+
+ if (!max_raw) {
+ cdev->brightness = 0;
+ cdev->rgb_val = 0;
+ return;
+ }
+
+ red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw);
+ green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw);
+ blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw);
+
+ cdev->brightness = max_raw;
+ cdev->rgb_val = (red << 16) + (green << 8) + blue;
+}I think that we shouldn't impose specific way of calculating brightness
depending on the rgb value set. We should just pass value from
userspace
to the driver.Right, setting brightness from userspace is no problem.
But how about led_update_brightness? It's supposed to update the
brightness
value in led_cdev with the actual value. And for a RGB LED we have only
the RGB values, so we need to calculate the brightness based on RGB
values.
Or do you see a better way?Quoted 6 lines
I thought that you had some device using both brightness and rgb components settings (no idea if this could be sane in any way). If there are only three color components, then why not just redefine brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGBflags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
Quoted 8 lines
Quoted 4 lines
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
It is possible even now - brightness can be changed during blinking, but it is applied from the next transition to "on" state.
Quoted 4 lines
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.Quoted 9 lines
It would suffice to implement dedicated trigger for this. IMO it would be an over engineering, though. We can support what you want by exposing each color as a separate LED class device and adding a means for LED class device synchronization, I was proposing in the beginning.
It would be convenient because it would allow to avoid code duplication in the LED core. I think that gathering all the colors in the single functionality could be a task for the user space.
By chance I had to deal with HSV color scheme in another project and using this color scheme core-internally for color LED's might help us to facilitate backwards compatibility and reduce the needed changes to the core. It would also allow to easily solve the question we're discussing here.
Quoted 4 lines
The brightness is part of the HSV model anyway so we would just have to add hue / saturation. Conversion to / from RGB would be done on demand. I have a small prototype that needs much less changes to the core logic. I'll come up with a re-worked proposal for handling color LED's.
At first let's consider if LED synchronization doesn't fit your needs. I am very much in favour of this solution since it would address also other use cases. On the other hand I am opposed to adding any mechanisms for color scheme conversion to the LED core since it can be covered by the user space.
Drivers should expose device capabilities and not impose the policy on how those capabilities can be used. If with slight modifications we could stick to this rule, we should go in this direction.
Signature · 2 lines
Best Regards, Jacek Anaszewski
Am 01.02.2016 um 09:26 schrieb Jacek Anaszewski:
Quoted 239 lines · Heiner Kallweit
Quoted 233 lines
Am 29.01.2016 um 09:24 schrieb Jacek Anaszewski:
Quoted 218 lines · Heiner Kallweit
Quoted 200 lines
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 199 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
Quoted 60 lines · Heiner Kallweit
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
On 01/10/2016 09:27 PM, Heiner Kallweit wrote:
When playing with a ThingM Blink(1) USB RGB LED device I found that
there
are few drivers for RGB LED's spread across the kernel and each one
implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED
core.Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one
led_classdev
per RGB LED. Also userspace should be able to change the color with
one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be
effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most
likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of
brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness.
RGB functionally can be switched on with a new flag in the
led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and
it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by: Heiner Kallweit <[email protected]>
---
drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++
drivers/leds/led-core.c | 106
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/leds/leds.h | 12 ++++++
include/linux/leds.h | 13 ++++++
4 files changed, 193 insertions(+)[...]
Quoted 46 lines
Quoted 46 lines
+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb)
+{
+ u32 red_raw = (rgb >> 16) & 0xff;
+ u32 green_raw = (rgb >> 8) & 0xff;
+ u32 blue_raw = rgb & 0xff;
+ u32 max_raw, red, green, blue;
+
+ max_raw = max(red_raw, green_raw);
+ if (blue_raw > max_raw)
+ max_raw = blue_raw;
+
+ if (!max_raw) {
+ cdev->brightness = 0;
+ cdev->rgb_val = 0;
+ return;
+ }
+
+ red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw);
+ green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw);
+ blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw);
+
+ cdev->brightness = max_raw;
+ cdev->rgb_val = (red << 16) + (green << 8) + blue;
+}I think that we shouldn't impose specific way of calculating brightness
depending on the rgb value set. We should just pass value from
userspace
to the driver.Right, setting brightness from userspace is no problem.
But how about led_update_brightness? It's supposed to update the
brightness
value in led_cdev with the actual value. And for a RGB LED we have only
the RGB values, so we need to calculate the brightness based on RGB
values.
Or do you see a better way?I thought that you had some device using both brightness and rgb
components settings (no idea if this could be sane in any way).
If there are only three color components, then why not just redefine
brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGB flags set?Quoted 8 lines
My devices just have the three color components (normal 8 bits per color). Even in the new RGB mode I don't want to break the current brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store brightness and color separately.
Just one argument: If we store the color components only then we'll lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
Quoted 8 lines
Quoted 4 lines
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
It is possible even now - brightness can be changed during blinking, but it is applied from the next transition to "on" state.
Quoted 4 lines
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.Quoted 9 lines
It would suffice to implement dedicated trigger for this. IMO it would be an over engineering, though. We can support what you want by exposing each color as a separate LED class device and adding a means for LED class device synchronization, I was proposing in the beginning.
It would be convenient because it would allow to avoid code duplication in the LED core. I think that gathering all the colors in the single functionality could be a task for the user space.
By chance I had to deal with HSV color scheme in another project and using this color scheme core-internally for color LED's might help us to facilitate backwards compatibility and reduce the needed changes to the core. It would also allow to easily solve the question we're discussing here.
Quoted 4 lines
The brightness is part of the HSV model anyway so we would just have to add hue / saturation. Conversion to / from RGB would be done on demand. I have a small prototype that needs much less changes to the core logic. I'll come up with a re-worked proposal for handling color LED's.
Quoted 6 lines
At first let's consider if LED synchronization doesn't fit your needs. I am very much in favour of this solution since it would address also other use cases. On the other hand I am opposed to adding any mechanisms for color scheme conversion to the LED core since it can be covered by the user space.
LED synchronization would be an option. So far I've seen it being implemented directly in drivers like hid-thingm.
Where I see potential issues with LED synchronization:
- It changes the semantics of the entries /sys/class/leds from physical LED's to logical LED's. The grouping of LED's might be recognizable by the name. However a sub-structure like /sys/class/leds/<group>/<member> might be desirable.
- Users of the LED core (userspace + kernel triggers) may need more than one call to set a LED to a requested state.
What would need to be synchronized at a first glance:
- assigning triggers to a LED
- brightness_set/_get
- blinking
- ..
What "other use cases" are you thinking of?
Quoted 4 lines
Drivers should expose device capabilities and not impose the policy on how those capabilities can be used. If with slight modifications we could stick to this rule, we should go in this direction.
With regard to my HSV proposal I agree that having HSV/RGB conversion in the kernel is not necessarily desirable. HSV just fits very well into the current implementation of the LED core.
Color LED's might have different native color schemes (although so far I know no color LED using another than RGB). If the LED core wants to provide a unified interface to its users some transformation between core color scheme and native color scheme (as exposed by the driver) might be needed eventually?
Regards, Heiner
Quoted 246 lines · Heiner Kallweit
Am 01.02.2016 um 09:26 schrieb Jacek Anaszewski:
Quoted 239 lines · Heiner Kallweit
Quoted 233 lines
Am 29.01.2016 um 09:24 schrieb Jacek Anaszewski:
Quoted 218 lines · Heiner Kallweit
Quoted 200 lines
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 199 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
Quoted 124 lines · Jacek Anaszewski
Hi Heiner,
Quoted 62 lines · Heiner Kallweit
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
On 01/15/2016 09:16 PM, Heiner Kallweit wrote:
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
On 01/10/2016 09:27 PM, Heiner Kallweit wrote:
When playing with a ThingM Blink(1) USB RGB LED device I found that
there
are few drivers for RGB LED's spread across the kernel and each one
implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED
core.Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one
led_classdev
per RGB LED. Also userspace should be able to change the color with
one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be
effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most
likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of
brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness.
RGB functionally can be switched on with a new flag in the
led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and
it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by: Heiner Kallweit <[email protected]>
---
drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++
drivers/leds/led-core.c | 106
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/leds/leds.h | 12 ++++++
include/linux/leds.h | 13 ++++++
4 files changed, 193 insertions(+)[...]
Quoted 54 lines
+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb)
+{
+ u32 red_raw = (rgb >> 16) & 0xff;
+ u32 green_raw = (rgb >> 8) & 0xff;
+ u32 blue_raw = rgb & 0xff;
+ u32 max_raw, red, green, blue;
+
+ max_raw = max(red_raw, green_raw);
+ if (blue_raw > max_raw)
+ max_raw = blue_raw;
+
+ if (!max_raw) {
+ cdev->brightness = 0;
+ cdev->rgb_val = 0;
+ return;
+ }
+
+ red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw);
+ green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw);
+ blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw);
+
+ cdev->brightness = max_raw;
+ cdev->rgb_val = (red << 16) + (green << 8) + blue;
+}I think that we shouldn't impose specific way of calculating brightness
depending on the rgb value set. We should just pass value from
userspace
to the driver.Right, setting brightness from userspace is no problem.
But how about led_update_brightness? It's supposed to update the
brightness
value in led_cdev with the actual value. And for a RGB LED we have only
the RGB values, so we need to calculate the brightness based on RGB
values.
Or do you see a better way?I thought that you had some device using both brightness and rgb
components settings (no idea if this could be sane in any way).
If there are only three color components, then why not just redefine
brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGB flags set?My devices just have the three color components (normal 8 bits per color).
Even in the new RGB mode I don't want to break the current
brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store
brightness and color separately.
Just one argument: If we store the color components only then we'll
lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Quoted 5 lines
Currently blinking works properly and brightness value isn't being lost. We store it in the
led_cdev->blink_brightnessproperty. Could you present exact use case you'd like to support and which is not feasible with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
Quoted 8 lines
Quoted 4 lines
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
It is possible even now - brightness can be changed during blinking, but it is applied from the next transition to "on" state.
Quoted 4 lines
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.Quoted 9 lines
It would suffice to implement dedicated trigger for this. IMO it would be an over engineering, though. We can support what you want by exposing each color as a separate LED class device and adding a means for LED class device synchronization, I was proposing in the beginning.
It would be convenient because it would allow to avoid code duplication in the LED core. I think that gathering all the colors in the single functionality could be a task for the user space.
By chance I had to deal with HSV color scheme in another project and using this color scheme core-internally for color LED's might help us to facilitate backwards compatibility and reduce the needed changes to the core. It would also allow to easily solve the question we're discussing here.
Quoted 4 lines
The brightness is part of the HSV model anyway so we would just have to add hue / saturation. Conversion to / from RGB would be done on demand. I have a small prototype that needs much less changes to the core logic. I'll come up with a re-worked proposal for handling color LED's.
Quoted 6 lines
At first let's consider if LED synchronization doesn't fit your needs. I am very much in favour of this solution since it would address also other use cases. On the other hand I am opposed to adding any mechanisms for color scheme conversion to the LED core since it can be covered by the user space.
Quoted 7 lines
LED synchronization would be an option. So far I've seen it being implemented directly in drivers like hid-thingm.
Where I see potential issues with LED synchronization:
- It changes the semantics of the entries/sys/class/ledsfrom physical LED's to logical LED's. The grouping of LED's might be recognizable by the name. However a sub-structure like /sys/class/leds/<group>/<member> might be desirable.
Not necessarily. Actually similar functionality was present in the mainline for a short time, but was reverted [1], due to the objections raised in the discussion [2].
The idea to follow is to have a sysfs attribute which would indicate the other LED class device to synchronize with. This way it is possible to define a chain of LEDs to synchronize and whole chain could be driven with any of chain's elements. On the led-class side we would need only two additional sysfs attributes - one for defining the LED class device to synchronize with and the other one for listing LED class devices available for synchronization.
The rest of synchronization job will be done by the LED class driver, basing on the sysfs settings of the LED class devices it exposes per sub-LED.
Quoted 2 lines
- Users of the LED core (userspace + kernel triggers) may need more than one call to set a LED to a requested state.
Not necessarily as stated above.
Quoted 4 lines
What would need to be synchronized at a first glance:
- assigning triggers to a LED
- brightness_set/_get
- blinking
Any change of a single LED chain element state would propagate to all other elements (LED class devices).
Quoted 2 lines
What "other use cases" are you thinking of?
E.g. synchronous blinking of a number of sub-LEDs.
Quoted 11 lines
Quoted 4 lines
Drivers should expose device capabilities and not impose the policy on how those capabilities can be used. If with slight modifications we could stick to this rule, we should go in this direction.
With regard to my HSV proposal I agree that having HSV/RGB conversion in the kernel is not necessarily desirable. HSV just fits very well into the current implementation of the LED core.
Color LED's might have different native color schemes (although so far I know no color LED using another than RGB). If the LED core wants to provide a unified interface to its users some transformation between core color scheme and native color scheme (as exposed by the driver) might be needed eventually?
IMO the synchronization mechanism design I described above is much neater. The design of sysfs synchronization API seems to be the only vital problem here. To be more precise the problem is: how to represent, in an unambiguous and easy to parse way, the LED class devices available for synchronization. The list of space separated LED class device names is not an option since we cannot guarantee names without spaces. The design requiring more complicated parsing was refused [2].
As a last resort we'd probably need to consult linux-api guys.
[1] https://lkml.org/lkml/2015/3/4/952
[2] http://www.spinics.net/lists/linux-leds/msg02995.html
Signature · 2 lines
Best Regards, Jacek Anaszewski
Am 02.02.2016 um 09:58 schrieb Jacek Anaszewski:
Quoted 267 lines · Heiner Kallweit
Quoted 246 lines
Am 01.02.2016 um 09:26 schrieb Jacek Anaszewski:
Quoted 239 lines · Heiner Kallweit
Quoted 233 lines
Am 29.01.2016 um 09:24 schrieb Jacek Anaszewski:
Quoted 218 lines · Heiner Kallweit
Quoted 200 lines
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 199 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
Quoted 129 lines · Jacek Anaszewski
Hi Heiner,
On 01/24/2016 02:38 PM, Heiner Kallweit wrote:
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
On 01/15/2016 09:16 PM, Heiner Kallweit wrote:
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
On 01/10/2016 09:27 PM, Heiner Kallweit wrote:
When playing with a ThingM Blink(1) USB RGB LED device I found that
there
are few drivers for RGB LED's spread across the kernel and each one
implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED
core.Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one
led_classdev
per RGB LED. Also userspace should be able to change the color with
one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be
effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most
likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of
brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness.
RGB functionally can be switched on with a new flag in the
led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and
it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by: Heiner Kallweit <[email protected]>
---
drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++
drivers/leds/led-core.c | 106
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/leds/leds.h | 12 ++++++
include/linux/leds.h | 13 ++++++
4 files changed, 193 insertions(+)[...]
+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb)
+{
+ u32 red_raw = (rgb >> 16) & 0xff;
+ u32 green_raw = (rgb >> 8) & 0xff;
+ u32 blue_raw = rgb & 0xff;
+ u32 max_raw, red, green, blue;
+
+ max_raw = max(red_raw, green_raw);
+ if (blue_raw > max_raw)
+ max_raw = blue_raw;
+
+ if (!max_raw) {
+ cdev->brightness = 0;
+ cdev->rgb_val = 0;
+ return;
+ }
+
+ red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw);
+ green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw);
+ blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw);
+
+ cdev->brightness = max_raw;
+ cdev->rgb_val = (red << 16) + (green << 8) + blue;
+}I think that we shouldn't impose specific way of calculating brightness
depending on the rgb value set. We should just pass value from
userspace
to the driver.Right, setting brightness from userspace is no problem.
But how about led_update_brightness? It's supposed to update the
brightness
value in led_cdev with the actual value. And for a RGB LED we have only
the RGB values, so we need to calculate the brightness based on RGB
values.
Or do you see a better way?I thought that you had some device using both brightness and rgb
components settings (no idea if this could be sane in any way).
If there are only three color components, then why not just redefine
brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGB flags set?My devices just have the three color components (normal 8 bits per color).
Even in the new RGB mode I don't want to break the current
brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store
brightness and color separately.
Just one argument: If we store the color components only then we'll
lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Currently blinking works properly and brightness value isn't being lost.
We store it in the led_cdev->blink_brightness property. Could you
present exact use case you'd like to support and which is not feasible
with current LED core design?I didn't have a closer look on how soft blinking works and you're right, this was a bad example.
It's not about that something is wrong with the current LED core design but that IMHO storing just the raw RGB values wouldn't be a good idea and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED brightness is set toLED_OFFby the trigger and e.g. a sysfs read triggers an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
Quoted 8 lines
Quoted 4 lines
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
It is possible even now - brightness can be changed during blinking, but it is applied from the next transition to "on" state.
Quoted 4 lines
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.Quoted 9 lines
It would suffice to implement dedicated trigger for this. IMO it would be an over engineering, though. We can support what you want by exposing each color as a separate LED class device and adding a means for LED class device synchronization, I was proposing in the beginning.
It would be convenient because it would allow to avoid code duplication in the LED core. I think that gathering all the colors in the single functionality could be a task for the user space.
By chance I had to deal with HSV color scheme in another project and using this color scheme core-internally for color LED's might help us to facilitate backwards compatibility and reduce the needed changes to the core. It would also allow to easily solve the question we're discussing here.
Quoted 4 lines
The brightness is part of the HSV model anyway so we would just have to add hue / saturation. Conversion to / from RGB would be done on demand. I have a small prototype that needs much less changes to the core logic. I'll come up with a re-worked proposal for handling color LED's.
Quoted 6 lines
At first let's consider if LED synchronization doesn't fit your needs. I am very much in favour of this solution since it would address also other use cases. On the other hand I am opposed to adding any mechanisms for color scheme conversion to the LED core since it can be covered by the user space.
Quoted 7 lines
LED synchronization would be an option. So far I've seen it being implemented directly in drivers like hid-thingm.
Where I see potential issues with LED synchronization:
- It changes the semantics of the entries/sys/class/ledsfrom physical LED's to logical LED's. The grouping of LED's might be recognizable by the name. However a sub-structure like /sys/class/leds/<group>/<member> might be desirable.Not necessarily. Actually similar functionality was present in the mainline for a short time, but was reverted [1], due to the objections raised in the discussion [2].
The idea to follow is to have a sysfs attribute which would indicate the other LED class device to synchronize with. This way it is possible to define a chain of LEDs to synchronize and whole chain could be driven with any of chain's elements. On the led-class side we would need only two additional sysfs attributes - one for defining the LED class device to synchronize with and the other one for listing LED class devices available for synchronization.
Quoted 9 lines
The rest of synchronization job will be done by the LED class driver, basing on the sysfs settings of the LED class devices it exposes per sub-LED.
Quoted 2 lines
- Users of the LED core (userspace + kernel triggers) may need more than one call to set a LED to a requested state.
Not necessarily as stated above.
In the case of RGB LED's the brightness can't be synchronized and the caller needs three calls to set the R/G/B values.
Quoted 5 lines
Quoted 4 lines
What would need to be synchronized at a first glance:
- assigning triggers to a LED
- brightness_set/_get
- blinking
Quoted 8 lines
Any change of a single LED chain element state would propagate to all other elements (LED class devices).
Quoted 2 lines
What "other use cases" are you thinking of?
E.g. synchronous blinking of a number of sub-LEDs.
Do you mean that just the blinking frequency is synchronized in case the respective LED is switched on and that it still should be possible to switch on / off LEDs individually?
If not than what's the benefit of x LED's doing something synchronously? The information I get from it is the same as from one LED.
As the original synchronization idea was intended for the flash functionality, I assume it could primarily make sense there.
(But I have to admit that I have no real idea of the flash functionality.)
Quoted 20 lines
Quoted 11 lines
Quoted 4 lines
Drivers should expose device capabilities and not impose the policy on how those capabilities can be used. If with slight modifications we could stick to this rule, we should go in this direction.
With regard to my HSV proposal I agree that having HSV/RGB conversion in the kernel is not necessarily desirable. HSV just fits very well into the current implementation of the LED core.
Color LED's might have different native color schemes (although so far I know no color LED using another than RGB). If the LED core wants to provide a unified interface to its users some transformation between core color scheme and native color scheme (as exposed by the driver) might be needed eventually?IMO the synchronization mechanism design I described above is much neater. The design of sysfs synchronization API seems to be the only vital problem here. To be more precise the problem is: how to represent, in an unambiguous and easy to parse way, the LED class devices available for synchronization. The list of space separated LED class device names is not an option since we cannot guarantee names without spaces. The design requiring more complicated parsing was refused [2].
Quoted 6 lines
As a last resort we'd probably need to consult linux-api guys.
[1] https://lkml.org/lkml/2015/3/4/952
[2] http://www.spinics.net/lists/linux-leds/msg02995.html
Thanks for the links. Let me try to summarize some requirements + some inquiries:
- By synchronizing LEDs all main properties are synchronized
- Should it be configurable which properties should be synchronized? E.g. in case of RGB LED's the brightness should not be synchronized, however there might be use cases where synchronizing brightness makes sense.
- Should defining and changing groups of synchronized LEDs be possible dynamically? Based on the history of this synchronization proposal I guess so. Alternatively it could be possible only when registering the led_classdev's, e.g. by passing a reference to a "master LED" which acts as group id. (But this might restrict the mechanism to LED's created by the same driver instance.) Or both methods ..
Regards, Heiner
Quoted 272 lines · Heiner Kallweit
Am 02.02.2016 um 09:58 schrieb Jacek Anaszewski:
Quoted 271 lines · Heiner Kallweit
Quoted 246 lines
Am 01.02.2016 um 09:26 schrieb Jacek Anaszewski:
Quoted 239 lines · Heiner Kallweit
Quoted 233 lines
Am 29.01.2016 um 09:24 schrieb Jacek Anaszewski:
Quoted 218 lines · Heiner Kallweit
Quoted 200 lines
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 199 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
Quoted 142 lines
On Mon, Jan 25, 2016 at 9:41 AM, Jacek Anaszewski
<[email protected]> wrote:
Hi Heiner,On 01/24/2016 02:38 PM, Heiner Kallweit wrote:
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
On 01/15/2016 09:16 PM, Heiner Kallweit wrote:
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
On 01/10/2016 09:27 PM, Heiner Kallweit wrote:
When playing with a ThingM Blink(1) USB RGB LED device I found that
there
are few drivers for RGB LED's spread across the kernel and each one
implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED
core.Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one
led_classdev
per RGB LED. Also userspace should be able to change the color with
one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be
effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most
likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of
brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness.
RGB functionally can be switched on with a new flag in the
led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and
it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by: Heiner Kallweit <[email protected]>
---
drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++
drivers/leds/led-core.c | 106
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/leds/leds.h | 12 ++++++
include/linux/leds.h | 13 ++++++
4 files changed, 193 insertions(+)[...]
+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb)
+{
+ u32 red_raw = (rgb >> 16) & 0xff;
+ u32 green_raw = (rgb >> 8) & 0xff;
+ u32 blue_raw = rgb & 0xff;
+ u32 max_raw, red, green, blue;
+
+ max_raw = max(red_raw, green_raw);
+ if (blue_raw > max_raw)
+ max_raw = blue_raw;
+
+ if (!max_raw) {
+ cdev->brightness = 0;
+ cdev->rgb_val = 0;
+ return;
+ }
+
+ red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw);
+ green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw);
+ blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw);
+
+ cdev->brightness = max_raw;
+ cdev->rgb_val = (red << 16) + (green << 8) + blue;
+}I think that we shouldn't impose specific way of calculating brightness
depending on the rgb value set. We should just pass value from
userspace
to the driver.Right, setting brightness from userspace is no problem.
But how about led_update_brightness? It's supposed to update the
brightness
value in led_cdev with the actual value. And for a RGB LED we have only
the RGB values, so we need to calculate the brightness based on RGB
values.
Or do you see a better way?I thought that you had some device using both brightness and rgb
components settings (no idea if this could be sane in any way).
If there are only three color components, then why not just redefine
brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGB flags set?My devices just have the three color components (normal 8 bits per color).
Even in the new RGB mode I don't want to break the current
brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store
brightness and color separately.
Just one argument: If we store the color components only then we'll
lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Currently blinking works properly and brightness value isn't being lost.
We store it in the led_cdev->blink_brightness property. Could you
present exact use case you'd like to support and which is not feasible
with current LED core design?I didn't have a closer look on how soft blinking works and you're right,
this was a bad example.
It's not about that something is wrong with the current LED core design
but that IMHO storing just the raw RGB values wouldn't be a good idea
and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED
brightness is set to LED_OFF by the trigger and e.g. a sysfs read triggers
an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in
blink_brightness. I don't get how changing the interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
Quoted 8 lines
Quoted 4 lines
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
It is possible even now - brightness can be changed during blinking, but it is applied from the next transition to "on" state.
Quoted 4 lines
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.Quoted 9 lines
It would suffice to implement dedicated trigger for this. IMO it would be an over engineering, though. We can support what you want by exposing each color as a separate LED class device and adding a means for LED class device synchronization, I was proposing in the beginning.
It would be convenient because it would allow to avoid code duplication in the LED core. I think that gathering all the colors in the single functionality could be a task for the user space.
By chance I had to deal with HSV color scheme in another project and using this color scheme core-internally for color LED's might help us to facilitate backwards compatibility and reduce the needed changes to the core. It would also allow to easily solve the question we're discussing here.
Quoted 4 lines
The brightness is part of the HSV model anyway so we would just have to add hue / saturation. Conversion to / from RGB would be done on demand. I have a small prototype that needs much less changes to the core logic. I'll come up with a re-worked proposal for handling color LED's.
Quoted 6 lines
At first let's consider if LED synchronization doesn't fit your needs. I am very much in favour of this solution since it would address also other use cases. On the other hand I am opposed to adding any mechanisms for color scheme conversion to the LED core since it can be covered by the user space.
Quoted 7 lines
LED synchronization would be an option. So far I've seen it being implemented directly in drivers like hid-thingm.
Where I see potential issues with LED synchronization:
- It changes the semantics of the entries/sys/class/ledsfrom physical LED's to logical LED's. The grouping of LED's might be recognizable by the name. However a sub-structure like /sys/class/leds/<group>/<member> might be desirable.Not necessarily. Actually similar functionality was present in the mainline for a short time, but was reverted [1], due to the objections raised in the discussion [2].
The idea to follow is to have a sysfs attribute which would indicate the other LED class device to synchronize with. This way it is possible to define a chain of LEDs to synchronize and whole chain could be driven with any of chain's elements. On the led-class side we would need only two additional sysfs attributes - one for defining the LED class device to synchronize with and the other one for listing LED class devices available for synchronization.
The rest of synchronization job will be done by the LED class driver, basing on the sysfs settings of the LED class devices it exposes per sub-LED.
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
- Users of the LED core (userspace + kernel triggers) may need more than one call to set a LED to a requested state.
Not necessarily as stated above.
In the case of RGB LED's the brightness can't be synchronized and the caller needs three calls to set the R/G/B values.
Right. But this is not a big problem I think. It is just a part of user space work that needs to be done to configure the device. In case of V4L2 media controllers we also have to configure connections between platform sub-devices.
One thing could be improved - we'd have to add a reservation to the brightness attribute semantics. saying that any transition of brightness attribute value from 0 to non-zero turns the LED on only if it isn't synchronized with any other LED class device, i.e. it is a master LED or a single LED. It would allow to avoid the risk of noticeable delays between activation of a number of synchronized LEDs.
Effectively, the whole group would have to be controlled by a single master sub-LED and all group members would have to synchronize with the master.
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
What would need to be synchronized at a first glance:
- assigning triggers to a LED
- brightness_set/_get
- blinkingAny change of a single LED chain element state would propagate to all other elements (LED class devices).
In view of the above let's forget about this "chain" approach.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
What "other use cases" are you thinking of?
E.g. synchronous blinking of a number of sub-LEDs.
Do you mean that just the blinking frequency is synchronized in case the respective LED is switched on and that it still should be possible to switch on / off LEDs individually?
This is how I see it:
1. LED1 selects LED4 as a master LED
2. LED1 sets brightness to 10
3. LED2 selects LED4 as a master LED
4. LED2 sets brightness to 150
5. LED3 selects LED4 as a master LED
6. LED3 sets brightness to 255
7. LED4 sets brightness to 200
//which turns LED1, LED2, LED3 and LED4 on, //each of them with their own brightness
8. LED4 enables timer triger
//LED1, LED2, LED3 and LED4 blink simultaneously //of course some devices may introduce little delays //due to the I2C transmission delays, it depends on //the particular device register design
9. LED2 sets brightness to 100
//LED2 brightness is changed upon next transition //to "LED on" state
10. LED2 sets brightness to 0
//LED2 is turned off and removed from the group
11. LED4 sets brightness to 0
//LED1, LED3 and LED4 are turned offQuoted 30 lines
If not than what's the benefit of x LED's doing something synchronously? The information I get from it is the same as from one LED.
As the original synchronization idea was intended for the flash functionality, I assume it could primarily make sense there.
(But I have to admit that I have no real idea of the flash functionality.)Quoted 23 lines
Quoted 11 lines
Quoted 4 lines
Drivers should expose device capabilities and not impose the policy on how those capabilities can be used. If with slight modifications we could stick to this rule, we should go in this direction.
With regard to my HSV proposal I agree that having HSV/RGB conversion in the kernel is not necessarily desirable. HSV just fits very well into the current implementation of the LED core.
Color LED's might have different native color schemes (although so far I know no color LED using another than RGB). If the LED core wants to provide a unified interface to its users some transformation between core color scheme and native color scheme (as exposed by the driver) might be needed eventually?IMO the synchronization mechanism design I described above is much neater. The design of sysfs synchronization API seems to be the only vital problem here. To be more precise the problem is: how to represent, in an unambiguous and easy to parse way, the LED class devices available for synchronization. The list of space separated LED class device names is not an option since we cannot guarantee names without spaces. The design requiring more complicated parsing was refused [2].
As a last resort we'd probably need to consult linux-api guys.
Quoted 8 lines
Quoted 3 lines
[1] https://lkml.org/lkml/2015/3/4/952
[2] http://www.spinics.net/lists/linux-leds/msg02995.htmlThanks for the links. Let me try to summarize some requirements + some inquiries:
- By synchronizing LEDs all main properties are synchronized
- Should it be configurable which properties should be synchronized? E.g. in case of RGB LED's the brightness should not be synchronized, however there might be use cases where synchronizing brightness makes sense.
I think that synchronization should apply to simultaneous activation/deactivation and triggers.
Quoted 6 lines
- Should defining and changing groups of synchronized LEDs be possible dynamically? Based on the history of this synchronization proposal I guess so. Alternatively it could be possible only when registering the led_classdev's, e.g. by passing a reference to a "master LED" which acts as group id. (But this might restrict the mechanism to LED's created by the same driver instance.) Or both methods ..
Reliable synchronization is possible only for the sub-LEDs of the same device. All LED class devices exposed by an instance of a driver should register with the predefined scope of the LED class devices available for synchronization, the devices exposed by this driver.
Signature · 2 lines
Best Regards, Jacek Anaszewski
Am 03.02.2016 um 09:28 schrieb Jacek Anaszewski:
Quoted 276 lines · Heiner Kallweit
Quoted 275 lines
Am 02.02.2016 um 09:58 schrieb Jacek Anaszewski:
Quoted 274 lines · Heiner Kallweit
Quoted 246 lines
Am 01.02.2016 um 09:26 schrieb Jacek Anaszewski:
Quoted 239 lines · Heiner Kallweit
Quoted 233 lines
Am 29.01.2016 um 09:24 schrieb Jacek Anaszewski:
Quoted 218 lines · Heiner Kallweit
Quoted 200 lines
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 199 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 145 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
Quoted 144 lines · Heiner Kallweit
On Mon, Jan 25, 2016 at 9:41 AM, Jacek Anaszewski
<[email protected]> wrote:
Hi Heiner,On 01/24/2016 02:38 PM, Heiner Kallweit wrote:
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
On 01/15/2016 09:16 PM, Heiner Kallweit wrote:
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
On 01/10/2016 09:27 PM, Heiner Kallweit wrote:
When playing with a ThingM Blink(1) USB RGB LED device I found that
there
are few drivers for RGB LED's spread across the kernel and each one
implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED
core.Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one
led_classdev
per RGB LED. Also userspace should be able to change the color with
one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be
effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most
likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of
brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness.
RGB functionally can be switched on with a new flag in the
led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and
it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by: Heiner Kallweit <[email protected]>
---
drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++
drivers/leds/led-core.c | 106
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/leds/leds.h | 12 ++++++
include/linux/leds.h | 13 ++++++
4 files changed, 193 insertions(+)[...]
+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb)
+{
+ u32 red_raw = (rgb >> 16) & 0xff;
+ u32 green_raw = (rgb >> 8) & 0xff;
+ u32 blue_raw = rgb & 0xff;
+ u32 max_raw, red, green, blue;
+
+ max_raw = max(red_raw, green_raw);
+ if (blue_raw > max_raw)
+ max_raw = blue_raw;
+
+ if (!max_raw) {
+ cdev->brightness = 0;
+ cdev->rgb_val = 0;
+ return;
+ }
+
+ red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw);
+ green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw);
+ blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw);
+
+ cdev->brightness = max_raw;
+ cdev->rgb_val = (red << 16) + (green << 8) + blue;
+}I think that we shouldn't impose specific way of calculating brightness
depending on the rgb value set. We should just pass value from
userspace
to the driver.Right, setting brightness from userspace is no problem.
But how about led_update_brightness? It's supposed to update the
brightness
value in led_cdev with the actual value. And for a RGB LED we have only
the RGB values, so we need to calculate the brightness based on RGB
values.
Or do you see a better way?I thought that you had some device using both brightness and rgb
components settings (no idea if this could be sane in any way).
If there are only three color components, then why not just redefine
brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGB flags set?My devices just have the three color components (normal 8 bits per color).
Even in the new RGB mode I don't want to break the current
brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store
brightness and color separately.
Just one argument: If we store the color components only then we'll
lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Currently blinking works properly and brightness value isn't being lost.
We store it in the led_cdev->blink_brightness property. Could you
present exact use case you'd like to support and which is not feasible
with current LED core design?I didn't have a closer look on how soft blinking works and you're right,
this was a bad example.
It's not about that something is wrong with the current LED core design
but that IMHO storing just the raw RGB values wouldn't be a good idea
and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED
brightness is set to LED_OFF by the trigger and e.g. a sysfs read triggers
an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?Quoted 4 lines
Quoted 3 lines
The one stored in blink_brightness. I don't get how changing the
interpretation of brightness value can affect anything here.But
blink_brightnessis used in case of soft blink only.In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then
blink_brightnessisn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
Quoted 8 lines
Quoted 4 lines
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
It is possible even now - brightness can be changed during blinking, but it is applied from the next transition to "on" state.
Quoted 4 lines
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.Quoted 9 lines
It would suffice to implement dedicated trigger for this. IMO it would be an over engineering, though. We can support what you want by exposing each color as a separate LED class device and adding a means for LED class device synchronization, I was proposing in the beginning.
It would be convenient because it would allow to avoid code duplication in the LED core. I think that gathering all the colors in the single functionality could be a task for the user space.
By chance I had to deal with HSV color scheme in another project and using this color scheme core-internally for color LED's might help us to facilitate backwards compatibility and reduce the needed changes to the core. It would also allow to easily solve the question we're discussing here.
Quoted 4 lines
The brightness is part of the HSV model anyway so we would just have to add hue / saturation. Conversion to / from RGB would be done on demand. I have a small prototype that needs much less changes to the core logic. I'll come up with a re-worked proposal for handling color LED's.
Quoted 6 lines
At first let's consider if LED synchronization doesn't fit your needs. I am very much in favour of this solution since it would address also other use cases. On the other hand I am opposed to adding any mechanisms for color scheme conversion to the LED core since it can be covered by the user space.
Quoted 7 lines
LED synchronization would be an option. So far I've seen it being implemented directly in drivers like hid-thingm.
Where I see potential issues with LED synchronization:
- It changes the semantics of the entries/sys/class/ledsfrom physical LED's to logical LED's. The grouping of LED's might be recognizable by the name. However a sub-structure like /sys/class/leds/<group>/<member> might be desirable.Not necessarily. Actually similar functionality was present in the mainline for a short time, but was reverted [1], due to the objections raised in the discussion [2].
The idea to follow is to have a sysfs attribute which would indicate the other LED class device to synchronize with. This way it is possible to define a chain of LEDs to synchronize and whole chain could be driven with any of chain's elements. On the led-class side we would need only two additional sysfs attributes - one for defining the LED class device to synchronize with and the other one for listing LED class devices available for synchronization.
The rest of synchronization job will be done by the LED class driver, basing on the sysfs settings of the LED class devices it exposes per sub-LED.
Quoted 2 lines
- Users of the LED core (userspace + kernel triggers) may need more than one call to set a LED to a requested state.
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
Not necessarily as stated above.
In the case of RGB LED's the brightness can't be synchronized and the caller needs three calls to set the R/G/B values.
Right. But this is not a big problem I think. It is just a part of user space work that needs to be done to configure the device.
Fair enough for userspace.
When working on the RGB stuff one of my ideas was to support trigger actions for color LEDs in the future.
Either to signal whatever multi-state information or to visualize a value in a range (e.g. some temperature monitoring driver might want to map a temperature into the color range from green to red).
And a trigger most likely has to set a color with one call.
Quoted 52 lines
In case of V4L2 media controllers we also have to configure connections between platform sub-devices.
One thing could be improved - we'd have to add a reservation to the brightness attribute semantics. saying that any transition of brightness attribute value from 0 to non-zero turns the LED on only if it isn't synchronized with any other LED class device, i.e. it is a master LED or a single LED. It would allow to avoid the risk of noticeable delays between activation of a number of synchronized LEDs.
Effectively, the whole group would have to be controlled by a single master sub-LED and all group members would have to synchronize with the master.
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
What would need to be synchronized at a first glance:
- assigning triggers to a LED
- brightness_set/_get
- blinkingAny change of a single LED chain element state would propagate to all other elements (LED class devices).
In view of the above let's forget about this "chain" approach.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
What "other use cases" are you thinking of?
E.g. synchronous blinking of a number of sub-LEDs.
Do you mean that just the blinking frequency is synchronized in case the respective LED is switched on and that it still should be possible to switch on / off LEDs individually?
This is how I see it:
1. LED1 selects LED4 as a master LED
2. LED1 sets brightness to 10
3. LED2 selects LED4 as a master LED
4. LED2 sets brightness to 150
5. LED3 selects LED4 as a master LED
6. LED3 sets brightness to 255
7. LED4 sets brightness to 200
//which turns LED1, LED2, LED3 and LED4 on, //each of them with their own brightness
8. LED4 enables timer triger
//LED1, LED2, LED3 and LED4 blink simultaneously //of course some devices may introduce little delays //due to the I2C transmission delays, it depends on //the particular device register design
9. LED2 sets brightness to 100
//LED2 brightness is changed upon next transition //to "LED on" state
10. LED2 sets brightness to 0
Quoted 4 lines
//LED2 is turned off and removed from the group
11. LED4 sets brightness to 0
//LED1, LED3 and LED4 are turned offI understand the idea, still it's not clear to me what benefit would justify the effort to implement such a feature.
What kind of practical use case do you imagine (maybe except synchronuous blinking) ?
For sync blinking I could imagine a less flexible, but maybe simpler solution:
Set up a timer (independent of a led_classdev) that controls for every led_classdev that wants to use this feature the on/off blink transitions.
After a brief look at ledtrig-timer.c this trigger seems to provide a similar (or even equal) functionality already.
Drawback is that all LED's share the same blink frequency (globally, not only per LED group). But that may be acceptable or even desirable.
Quoted 55 lines
Quoted 31 lines
If not than what's the benefit of x LED's doing something synchronously? The information I get from it is the same as from one LED.
As the original synchronization idea was intended for the flash functionality, I assume it could primarily make sense there.
(But I have to admit that I have no real idea of the flash functionality.)Quoted 23 lines
Quoted 11 lines
Quoted 4 lines
Drivers should expose device capabilities and not impose the policy on how those capabilities can be used. If with slight modifications we could stick to this rule, we should go in this direction.
With regard to my HSV proposal I agree that having HSV/RGB conversion in the kernel is not necessarily desirable. HSV just fits very well into the current implementation of the LED core.
Color LED's might have different native color schemes (although so far I know no color LED using another than RGB). If the LED core wants to provide a unified interface to its users some transformation between core color scheme and native color scheme (as exposed by the driver) might be needed eventually?IMO the synchronization mechanism design I described above is much neater. The design of sysfs synchronization API seems to be the only vital problem here. To be more precise the problem is: how to represent, in an unambiguous and easy to parse way, the LED class devices available for synchronization. The list of space separated LED class device names is not an option since we cannot guarantee names without spaces. The design requiring more complicated parsing was refused [2].
As a last resort we'd probably need to consult linux-api guys.
Quoted 8 lines
Quoted 3 lines
[1] https://lkml.org/lkml/2015/3/4/952
[2] http://www.spinics.net/lists/linux-leds/msg02995.htmlThanks for the links. Let me try to summarize some requirements + some inquiries:
- By synchronizing LEDs all main properties are synchronized
- Should it be configurable which properties should be synchronized? E.g. in case of RGB LED's the brightness should not be synchronized, however there might be use cases where synchronizing brightness makes sense.I think that synchronization should apply to simultaneous activation/deactivation and triggers.
Quoted 6 lines
- Should defining and changing groups of synchronized LEDs be possible dynamically? Based on the history of this synchronization proposal I guess so. Alternatively it could be possible only when registering the led_classdev's, e.g. by passing a reference to a "master LED" which acts as group id. (But this might restrict the mechanism to LED's created by the same driver instance.) Or both methods ..
Reliable synchronization is possible only for the sub-LEDs of the same device. All LED class devices exposed by an instance of a driver should register with the predefined scope of the LED class devices available for synchronization, the devices exposed by this driver.
Quoted 350 lines · Heiner Kallweit
Am 03.02.2016 um 09:28 schrieb Jacek Anaszewski:
Quoted 276 lines · Heiner Kallweit
Quoted 275 lines
Am 02.02.2016 um 09:58 schrieb Jacek Anaszewski:
Quoted 274 lines · Heiner Kallweit
Quoted 246 lines
Am 01.02.2016 um 09:26 schrieb Jacek Anaszewski:
Quoted 239 lines · Heiner Kallweit
Quoted 233 lines
Am 29.01.2016 um 09:24 schrieb Jacek Anaszewski:
Quoted 218 lines · Heiner Kallweit
Quoted 200 lines
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 199 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 172 lines · Heiner Kallweit
Quoted 149 lines
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
On 01/25/2016 10:51 AM, Heiner Kallweit wrote:
On Mon, Jan 25, 2016 at 9:41 AM, Jacek Anaszewski
<[email protected]> wrote:
Hi Heiner,On 01/24/2016 02:38 PM, Heiner Kallweit wrote:
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
On 01/15/2016 09:16 PM, Heiner Kallweit wrote:
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
On 01/10/2016 09:27 PM, Heiner Kallweit wrote:
When playing with a ThingM Blink(1) USB RGB LED device I found that
there
are few drivers for RGB LED's spread across the kernel and each one
implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED
core.Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one
led_classdev
per RGB LED. Also userspace should be able to change the color with
one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be
effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most
likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of
brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness.
RGB functionally can be switched on with a new flag in the
led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and
it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by: Heiner Kallweit <[email protected]>
---
drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++
drivers/leds/led-core.c | 106
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/leds/leds.h | 12 ++++++
include/linux/leds.h | 13 ++++++
4 files changed, 193 insertions(+)[...]
+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb)
+{
+ u32 red_raw = (rgb >> 16) & 0xff;
+ u32 green_raw = (rgb >> 8) & 0xff;
+ u32 blue_raw = rgb & 0xff;
+ u32 max_raw, red, green, blue;
+
+ max_raw = max(red_raw, green_raw);
+ if (blue_raw > max_raw)
+ max_raw = blue_raw;
+
+ if (!max_raw) {
+ cdev->brightness = 0;
+ cdev->rgb_val = 0;
+ return;
+ }
+
+ red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw);
+ green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw);
+ blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw);
+
+ cdev->brightness = max_raw;
+ cdev->rgb_val = (red << 16) + (green << 8) + blue;
+}I think that we shouldn't impose specific way of calculating brightness
depending on the rgb value set. We should just pass value from
userspace
to the driver.Right, setting brightness from userspace is no problem.
But how about led_update_brightness? It's supposed to update the
brightness
value in led_cdev with the actual value. And for a RGB LED we have only
the RGB values, so we need to calculate the brightness based on RGB
values.
Or do you see a better way?I thought that you had some device using both brightness and rgb
components settings (no idea if this could be sane in any way).
If there are only three color components, then why not just redefine
brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGB flags set?My devices just have the three color components (normal 8 bits per color).
Even in the new RGB mode I don't want to break the current
brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store
brightness and color separately.
Just one argument: If we store the color components only then we'll
lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Currently blinking works properly and brightness value isn't being lost.
We store it in the led_cdev->blink_brightness property. Could you
present exact use case you'd like to support and which is not feasible
with current LED core design?I didn't have a closer look on how soft blinking works and you're right,
this was a bad example.
It's not about that something is wrong with the current LED core design
but that IMHO storing just the raw RGB values wouldn't be a good idea
and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED
brightness is set to LED_OFF by the trigger and e.g. a sysfs read triggers
an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?The one stored in blink_brightness. I don't get how changing the
interpretation of brightness value can affect anything here.But blink_brightness is used in case of soft blink only.
In case of hardware blinking it is driver's responsibility to report current brightness while blinking is on. It is hardware specific whether it allows to read current LED state during blinking. Nevertheless I don't see where is the problem here either.
Quoted 2 lines
If a trigger or userspace sets the brightness to zero then blink_brightness
isn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to
LED_OFFit will also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says about triggers, using timer trigger as an example. This trigger is specific because of the software fallback implemented in the core.
Setting brightness to
LED_OFFdisables any trigger only when set from sysfs (indrivers/leds/led-class.cbrightness_storecallsled_trigger_removeif passed brightness isLED_OFF).Quoted 6 lines
However, when setting brightness to
LED_OFFdirectly through LED API, and not through sysfs, onlyblink_timeris being disabled, but trigger isn't being removed. Probably we'd have to remove trigger fromset_brightness_delayed(), in caseLED_BLINK_DISABLEis set, to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
Quoted 8 lines
Quoted 4 lines
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
It is possible even now - brightness can be changed during blinking, but it is applied from the next transition to "on" state.
Quoted 4 lines
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.Quoted 9 lines
It would suffice to implement dedicated trigger for this. IMO it would be an over engineering, though. We can support what you want by exposing each color as a separate LED class device and adding a means for LED class device synchronization, I was proposing in the beginning.
It would be convenient because it would allow to avoid code duplication in the LED core. I think that gathering all the colors in the single functionality could be a task for the user space.
By chance I had to deal with HSV color scheme in another project and using this color scheme core-internally for color LED's might help us to facilitate backwards compatibility and reduce the needed changes to the core. It would also allow to easily solve the question we're discussing here.
Quoted 4 lines
The brightness is part of the HSV model anyway so we would just have to add hue / saturation. Conversion to / from RGB would be done on demand. I have a small prototype that needs much less changes to the core logic. I'll come up with a re-worked proposal for handling color LED's.
Quoted 6 lines
At first let's consider if LED synchronization doesn't fit your needs. I am very much in favour of this solution since it would address also other use cases. On the other hand I am opposed to adding any mechanisms for color scheme conversion to the LED core since it can be covered by the user space.
Quoted 7 lines
LED synchronization would be an option. So far I've seen it being implemented directly in drivers like hid-thingm.
Where I see potential issues with LED synchronization:
- It changes the semantics of the entries/sys/class/ledsfrom physical LED's to logical LED's. The grouping of LED's might be recognizable by the name. However a sub-structure like /sys/class/leds/<group>/<member> might be desirable.Not necessarily. Actually similar functionality was present in the mainline for a short time, but was reverted [1], due to the objections raised in the discussion [2].
The idea to follow is to have a sysfs attribute which would indicate the other LED class device to synchronize with. This way it is possible to define a chain of LEDs to synchronize and whole chain could be driven with any of chain's elements. On the led-class side we would need only two additional sysfs attributes - one for defining the LED class device to synchronize with and the other one for listing LED class devices available for synchronization.
The rest of synchronization job will be done by the LED class driver, basing on the sysfs settings of the LED class devices it exposes per sub-LED.
Quoted 2 lines
- Users of the LED core (userspace + kernel triggers) may need more than one call to set a LED to a requested state.
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
Not necessarily as stated above.
In the case of RGB LED's the brightness can't be synchronized and the caller needs three calls to set the R/G/B values.
Right. But this is not a big problem I think. It is just a part of user space work that needs to be done to configure the device.
Fair enough for userspace.
When working on the RGB stuff one of my ideas was to support trigger actions for color LEDs in the future.
Either to signal whatever multi-state information or to visualize a value in a range (e.g. some temperature monitoring driver might want to map a temperature into the color range from green to red).And a trigger most likely has to set a color with one call.
Quoted 41 lines
In case of V4L2 media controllers we also have to configure connections between platform sub-devices.
One thing could be improved - we'd have to add a reservation to the brightness attribute semantics. saying that any transition of brightness attribute value from 0 to non-zero turns the LED on only if it isn't synchronized with any other LED class device, i.e. it is a master LED or a single LED. It would allow to avoid the risk of noticeable delays between activation of a number of synchronized LEDs.
Effectively, the whole group would have to be controlled by a single master sub-LED and all group members would have to synchronize with the master.
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
What would need to be synchronized at a first glance:
- assigning triggers to a LED
- brightness_set/_get
- blinkingAny change of a single LED chain element state would propagate to all other elements (LED class devices).
In view of the above let's forget about this "chain" approach.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
What "other use cases" are you thinking of?
E.g. synchronous blinking of a number of sub-LEDs.
Do you mean that just the blinking frequency is synchronized in case the respective LED is switched on and that it still should be possible to switch on / off LEDs individually?
This is how I see it:
1. LED1 selects LED4 as a master LED
2. LED1 sets brightness to 10
3. LED2 selects LED4 as a master LED
4. LED2 sets brightness to 150
5. LED3 selects LED4 as a master LED
6. LED3 sets brightness to 255
7. LED4 sets brightness to 200Quoted 15 lines
//which turns LED1, LED2, LED3 and LED4 on, //each of them with their own brightness 8. LED4 enables timer triger //LED1, LED2, LED3 and LED4 blink simultaneously //of course some devices may introduce little delays //due to the I2C transmission delays, it depends on //the particular device register design 9. LED2 sets brightness to 100 //LED2 brightness is changed upon next transition //to "LED on" state 10. LED2 sets brightness to 0 //LED2 is turned off and removed from the group 11. LED4 sets brightness to 0 //LED1, LED3 and LED4 are turned off
Quoted 3 lines
I understand the idea, still it's not clear to me what benefit would justify the effort to implement such a feature.
What kind of practical use case do you imagine (maybe except synchronuous blinking) ?
I've just realized that the approach I proposed is based on wrong assumptions. It is not guaranteed that the instructions issued from user space will be executed in the same order by kernel, since they are different processes.
It seems that we could try your HSV approach. Nonetheless, I'd prefer to implement it as a wrapper of LED class, similarly to led-class-flash.c. It could be named led-class-hsv.c.
Quoted 5 lines
For sync blinking I could imagine a less flexible, but maybe simpler solution:
Set up a timer (independent of aled_classdev) that controls for everyled_classdevthat wants to use this feature the on/off blink transitions.
After a brief look atledtrig-timer.cthis trigger seems to provide a similar (or even equal) functionality already.
Timer trigger uses either hardware blinking feature provided by a device or software blinking based on blink_timer, where each LED class device has a separate instance thereof.
Quoted 61 lines
Drawback is that all LED's share the same blink frequency (globally, not only per LED group). But that may be acceptable or even desirable.
Quoted 55 lines
Quoted 31 lines
If not than what's the benefit of x LED's doing something synchronously? The information I get from it is the same as from one LED.
As the original synchronization idea was intended for the flash functionality, I assume it could primarily make sense there.
(But I have to admit that I have no real idea of the flash functionality.)Quoted 23 lines
Quoted 11 lines
Quoted 4 lines
Drivers should expose device capabilities and not impose the policy on how those capabilities can be used. If with slight modifications we could stick to this rule, we should go in this direction.
With regard to my HSV proposal I agree that having HSV/RGB conversion in the kernel is not necessarily desirable. HSV just fits very well into the current implementation of the LED core.
Color LED's might have different native color schemes (although so far I know no color LED using another than RGB). If the LED core wants to provide a unified interface to its users some transformation between core color scheme and native color scheme (as exposed by the driver) might be needed eventually?IMO the synchronization mechanism design I described above is much neater. The design of sysfs synchronization API seems to be the only vital problem here. To be more precise the problem is: how to represent, in an unambiguous and easy to parse way, the LED class devices available for synchronization. The list of space separated LED class device names is not an option since we cannot guarantee names without spaces. The design requiring more complicated parsing was refused [2].
As a last resort we'd probably need to consult linux-api guys.
Quoted 8 lines
Quoted 3 lines
[1] https://lkml.org/lkml/2015/3/4/952
[2] http://www.spinics.net/lists/linux-leds/msg02995.htmlThanks for the links. Let me try to summarize some requirements + some inquiries:
- By synchronizing LEDs all main properties are synchronized
- Should it be configurable which properties should be synchronized? E.g. in case of RGB LED's the brightness should not be synchronized, however there might be use cases where synchronizing brightness makes sense.I think that synchronization should apply to simultaneous activation/deactivation and triggers.
Quoted 6 lines
- Should defining and changing groups of synchronized LEDs be possible dynamically? Based on the history of this synchronization proposal I guess so. Alternatively it could be possible only when registering the led_classdev's, e.g. by passing a reference to a "master LED" which acts as group id. (But this might restrict the mechanism to LED's created by the same driver instance.) Or both methods ..
Reliable synchronization is possible only for the sub-LEDs of the same device. All LED class devices exposed by an instance of a driver should register with the predefined scope of the LED class devices available for synchronization, the devices exposed by this driver.
Signature · 2 lines
Best Regards, Jacek Anaszewski
Am 04.02.2016 um 09:30 schrieb Jacek Anaszewski:
Quoted 355 lines · Heiner Kallweit
Quoted 350 lines
Am 03.02.2016 um 09:28 schrieb Jacek Anaszewski:
Quoted 276 lines · Heiner Kallweit
Quoted 275 lines
Am 02.02.2016 um 09:58 schrieb Jacek Anaszewski:
Quoted 274 lines · Heiner Kallweit
Quoted 246 lines
Am 01.02.2016 um 09:26 schrieb Jacek Anaszewski:
Quoted 239 lines · Heiner Kallweit
Quoted 233 lines
Am 29.01.2016 um 09:24 schrieb Jacek Anaszewski:
Quoted 218 lines · Heiner Kallweit
Quoted 200 lines
Am 27.01.2016 um 09:27 schrieb Jacek Anaszewski:
Quoted 199 lines · Heiner Kallweit
Quoted 186 lines
Am 26.01.2016 um 10:37 schrieb Jacek Anaszewski:
Quoted 178 lines · Heiner Kallweit
Am 25.01.2016 um 11:52 schrieb Jacek Anaszewski:
On 01/25/2016 10:51 AM, Heiner Kallweit wrote:
On Mon, Jan 25, 2016 at 9:41 AM, Jacek Anaszewski
<[email protected]> wrote:
Hi Heiner,On 01/24/2016 02:38 PM, Heiner Kallweit wrote:
Am 17.01.2016 um 23:31 schrieb Jacek Anaszewski:
On 01/15/2016 09:16 PM, Heiner Kallweit wrote:
Am 14.01.2016 um 13:08 schrieb Jacek Anaszewski:
On 01/10/2016 09:27 PM, Heiner Kallweit wrote:
When playing with a ThingM Blink(1) USB RGB LED device I found that
there
are few drivers for RGB LED's spread across the kernel and each one
implements the RGB functionality in its own way.
Some examples:
- drivers/hid/hid-thingm.c
- drivers/usb/misc/usbled.c
- drivers/leds/leds-bd2802.c
- drivers/leds/leds-blinkm.c
...
IMHO it would make sense to add generic RGB functionality to the LED
core.Things I didn't like too much in other driver implementations:
- one led_classdev per color or at least
- one sysfs attribute per color
Colors are not really independent therefore I'd prefer one
led_classdev
per RGB LED. Also userspace should be able to change the color with
one
call -> therefore only one sysfs attribute for the RGB values.Also the current brightness-related functionality should not be
effected
by the RGB extension.This patch is intended to demonstrate the idea of the extension. Most
likely
it's not ready yet for submission.Main idea is to base the effective RGB value on a combination of
brightness
and a scaled-to-max RGB value.
The RGB-related callbacks are basically the same as for brightness.
RGB functionally can be switched on with a new flag in the
led_classdev.flags
bitmap.Experimentally I changed the thingm driver to use this extension and
it works
quite well. As one result the driver could be very much simplified.Any feedback is appreciated.
Signed-off-by: Heiner Kallweit <[email protected]>
---
drivers/leds/led-class.c | 62 +++++++++++++++++++++++++++
drivers/leds/led-core.c | 106
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/leds/leds.h | 12 ++++++
include/linux/leds.h | 13 ++++++
4 files changed, 193 insertions(+)[...]
+static void led_set_rgb_raw(struct led_classdev *cdev, u32 rgb)
+{
+ u32 red_raw = (rgb >> 16) & 0xff;
+ u32 green_raw = (rgb >> 8) & 0xff;
+ u32 blue_raw = rgb & 0xff;
+ u32 max_raw, red, green, blue;
+
+ max_raw = max(red_raw, green_raw);
+ if (blue_raw > max_raw)
+ max_raw = blue_raw;
+
+ if (!max_raw) {
+ cdev->brightness = 0;
+ cdev->rgb_val = 0;
+ return;
+ }
+
+ red = DIV_ROUND_CLOSEST(red_raw * LED_FULL, max_raw);
+ green = DIV_ROUND_CLOSEST(green_raw * LED_FULL, max_raw);
+ blue = DIV_ROUND_CLOSEST(blue_raw * LED_FULL, max_raw);
+
+ cdev->brightness = max_raw;
+ cdev->rgb_val = (red << 16) + (green << 8) + blue;
+}I think that we shouldn't impose specific way of calculating brightness
depending on the rgb value set. We should just pass value from
userspace
to the driver.Right, setting brightness from userspace is no problem.
But how about led_update_brightness? It's supposed to update the
brightness
value in led_cdev with the actual value. And for a RGB LED we have only
the RGB values, so we need to calculate the brightness based on RGB
values.
Or do you see a better way?I thought that you had some device using both brightness and rgb
components settings (no idea if this could be sane in any way).
If there are only three color components, then why not just redefine
brightness to store three components in case of the LEDs with
LED_DEV_CAP_RGB flags set?My devices just have the three color components (normal 8 bits per color).
Even in the new RGB mode I don't want to break the current
brightness-based API
but extend it with RGB functionality. Therefore I think it's best to store
brightness and color separately.
Just one argument: If we store the color components only then we'll
lose the color information if the brightness is set to 0.
And I would like to support e.g. software blink in whatever color.Currently blinking works properly and brightness value isn't being lost.
We store it in the led_cdev->blink_brightness property. Could you
present exact use case you'd like to support and which is not feasible
with current LED core design?I didn't have a closer look on how soft blinking works and you're right,
this was a bad example.
It's not about that something is wrong with the current LED core design
but that IMHO storing just the raw RGB values wouldn't be a good idea
and we should store brightness and color separately.So let's take another example:
I set a color via sysfs and a trigger is controling the LED. Once the LED
brightness is set to LED_OFF by the trigger and e.g. a sysfs read triggers
an update the stored RGB value is 0,0,0.
If the LED is switched on again, then which color to choose?The one stored in blink_brightness. I don't get how changing the
interpretation of brightness value can affect anything here.But blink_brightness is used in case of soft blink only.
In case of hardware blinking it is driver's responsibility to report
current brightness while blinking is on. It is hardware specific whether
it allows to read current LED state during blinking. Nevertheless
I don't see where is the problem here either.If a trigger or userspace sets the brightness to zero then blink_brightness
isn't used.Setting brightness to 0 disables trigger. Excerpt from leds-class.txt:
"However, if you set the brightness value to LED_OFF it will
also disable the timer trigger."Now I see that documentation is inexact here. The paragraph says
about triggers, using timer trigger as an example. This trigger
is specific because of the software fallback implemented in the core.Setting brightness to LED_OFF disables any trigger only when set from
sysfs (in drivers/leds/led-class.c brightness_store calls
led_trigger_remove if passed brightness is LED_OFF).However, when setting brightness to LED_OFF directly through LED API,
and not through sysfs, only blink_timer is being disabled, but trigger
isn't being removed. Probably we'd have to remove trigger
from set_brightness_delayed(), in case LED_BLINK_DISABLE is set,
to make implementation in line with the documentation.Sorry, I'm afraid we lost track of the original subject.
At least I'm a little lost ..
My understanding is that this discussion is about whether:
- use current brightness member ofled_classdevto store brightness and color (change semantics of brightness to hold a <00000000><RRRRRRRR><GGGGGGGG><BBBBBBBB> value) or
- store brightness and color separately (introduce a new member for the color)Quoted 2 lines
Is this also your understanding? Or are you focussing on a different aspect and I missed something?
Yes it is. I intended to explain that setting brightness to 0 is supposed to turn the trigger off. In effect the brightness information is not required afterwards because trigger is disabled.
During the analysis I realized about little discrepancy between the documentation and the implementation and proposed potential fix.
I analyzed this basing on the current interpretation of brightness. I think we need to focus on your following requirement:
Quoted 8 lines
Quoted 4 lines
"And I would like to support e.g. software blink in whatever color"
Could you provide more details?
Basically I want color and brightness to be independent.
One example: If a trigger is switching a LED on and off, then I want to be able to change the color from userspace (even if the LED is off in that moment) w/o affecting the trigger operation.
It is possible even now - brightness can be changed during blinking, but it is applied from the next transition to "on" state.
Quoted 4 lines
Or another one: If the brightness is changed from 255 to 1 and back to 255 then we'd partially lose the color information if color and brightness are stored together.
Partially because we'd not lose it if e.g. pure blue is set.
But if the RGB value was let's say (255, 240, 17) before then we'd not be able to restore this value.Quoted 9 lines
It would suffice to implement dedicated trigger for this. IMO it would be an over engineering, though. We can support what you want by exposing each color as a separate LED class device and adding a means for LED class device synchronization, I was proposing in the beginning.
It would be convenient because it would allow to avoid code duplication in the LED core. I think that gathering all the colors in the single functionality could be a task for the user space.
By chance I had to deal with HSV color scheme in another project and using this color scheme core-internally for color LED's might help us to facilitate backwards compatibility and reduce the needed changes to the core. It would also allow to easily solve the question we're discussing here.
Quoted 4 lines
The brightness is part of the HSV model anyway so we would just have to add hue / saturation. Conversion to / from RGB would be done on demand. I have a small prototype that needs much less changes to the core logic. I'll come up with a re-worked proposal for handling color LED's.
Quoted 6 lines
At first let's consider if LED synchronization doesn't fit your needs. I am very much in favour of this solution since it would address also other use cases. On the other hand I am opposed to adding any mechanisms for color scheme conversion to the LED core since it can be covered by the user space.
Quoted 7 lines
LED synchronization would be an option. So far I've seen it being implemented directly in drivers like hid-thingm.
Where I see potential issues with LED synchronization:
- It changes the semantics of the entries/sys/class/ledsfrom physical LED's to logical LED's. The grouping of LED's might be recognizable by the name. However a sub-structure like /sys/class/leds/<group>/<member> might be desirable.Not necessarily. Actually similar functionality was present in the mainline for a short time, but was reverted [1], due to the objections raised in the discussion [2].
The idea to follow is to have a sysfs attribute which would indicate the other LED class device to synchronize with. This way it is possible to define a chain of LEDs to synchronize and whole chain could be driven with any of chain's elements. On the led-class side we would need only two additional sysfs attributes - one for defining the LED class device to synchronize with and the other one for listing LED class devices available for synchronization.
The rest of synchronization job will be done by the LED class driver, basing on the sysfs settings of the LED class devices it exposes per sub-LED.
Quoted 2 lines
- Users of the LED core (userspace + kernel triggers) may need more than one call to set a LED to a requested state.
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
Not necessarily as stated above.
In the case of RGB LED's the brightness can't be synchronized and the caller needs three calls to set the R/G/B values.
Right. But this is not a big problem I think. It is just a part of user space work that needs to be done to configure the device.
Fair enough for userspace.
When working on the RGB stuff one of my ideas was to support trigger actions for color LEDs in the future.
Either to signal whatever multi-state information or to visualize a value in a range (e.g. some temperature monitoring driver might want to map a temperature into the color range from green to red).And a trigger most likely has to set a color with one call.
Quoted 41 lines
In case of V4L2 media controllers we also have to configure connections between platform sub-devices.
One thing could be improved - we'd have to add a reservation to the brightness attribute semantics. saying that any transition of brightness attribute value from 0 to non-zero turns the LED on only if it isn't synchronized with any other LED class device, i.e. it is a master LED or a single LED. It would allow to avoid the risk of noticeable delays between activation of a number of synchronized LEDs.
Effectively, the whole group would have to be controlled by a single master sub-LED and all group members would have to synchronize with the master.
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
What would need to be synchronized at a first glance:
- assigning triggers to a LED
- brightness_set/_get
- blinkingAny change of a single LED chain element state would propagate to all other elements (LED class devices).
In view of the above let's forget about this "chain" approach.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
What "other use cases" are you thinking of?
E.g. synchronous blinking of a number of sub-LEDs.
Do you mean that just the blinking frequency is synchronized in case the respective LED is switched on and that it still should be possible to switch on / off LEDs individually?
This is how I see it:
1. LED1 selects LED4 as a master LED
2. LED1 sets brightness to 10
3. LED2 selects LED4 as a master LED
4. LED2 sets brightness to 150
5. LED3 selects LED4 as a master LED
6. LED3 sets brightness to 255
7. LED4 sets brightness to 200Quoted 15 lines
//which turns LED1, LED2, LED3 and LED4 on, //each of them with their own brightness 8. LED4 enables timer triger //LED1, LED2, LED3 and LED4 blink simultaneously //of course some devices may introduce little delays //due to the I2C transmission delays, it depends on //the particular device register design 9. LED2 sets brightness to 100 //LED2 brightness is changed upon next transition //to "LED on" state 10. LED2 sets brightness to 0 //LED2 is turned off and removed from the group 11. LED4 sets brightness to 0 //LED1, LED3 and LED4 are turned offQuoted 3 lines
I understand the idea, still it's not clear to me what benefit would justify the effort to implement such a feature.
What kind of practical use case do you imagine (maybe except synchronuous blinking) ?
Quoted 9 lines
I've just realized that the approach I proposed is based on wrong assumptions. It is not guaranteed that the instructions issued from user space will be executed in the same order by kernel, since they are different processes.
It seems that we could try your HSV approach. Nonetheless, I'd prefer to implement it as a wrapper of LED class, similarly to
led-class-flash.c. It could be namedled-class-hsv.c.
I'll submit a proposal for the HSV extension. I thought about making it a wrapper but that doesn't really fit. Instead of adding code to the existing one I have to touch few parts in the existing core.
Appreciate your comments onec I send the HSV proposal.
Upfront I'll send a patch for adding helpers for brightness_set(_blocking). This makes code more readable anyway and allows to keep the HSV extension simpler.
Quoted 11 lines
Quoted 6 lines
For sync blinking I could imagine a less flexible, but maybe simpler solution:
Set up a timer (independent of aled_classdev) that controls for everyled_classdevthat wants to use this feature the on/off blink transitions.
After a brief look atledtrig-timer.cthis trigger seems to provide a similar (or even equal) functionality already.Timer trigger uses either hardware blinking feature provided by a device or software blinking based on
blink_timer, where each LED class device has a separate instance thereof.
I see, thanks for the explanation.
Quoted 63 lines
Quoted 61 lines
Drawback is that all LED's share the same blink frequency (globally, not only per LED group). But that may be acceptable or even desirable.
Quoted 55 lines
Quoted 31 lines
If not than what's the benefit of x LED's doing something synchronously? The information I get from it is the same as from one LED.
As the original synchronization idea was intended for the flash functionality, I assume it could primarily make sense there.
(But I have to admit that I have no real idea of the flash functionality.)Quoted 23 lines
Quoted 11 lines
Quoted 4 lines
Drivers should expose device capabilities and not impose the policy on how those capabilities can be used. If with slight modifications we could stick to this rule, we should go in this direction.
With regard to my HSV proposal I agree that having HSV/RGB conversion in the kernel is not necessarily desirable. HSV just fits very well into the current implementation of the LED core.
Color LED's might have different native color schemes (although so far I know no color LED using another than RGB). If the LED core wants to provide a unified interface to its users some transformation between core color scheme and native color scheme (as exposed by the driver) might be needed eventually?IMO the synchronization mechanism design I described above is much neater. The design of sysfs synchronization API seems to be the only vital problem here. To be more precise the problem is: how to represent, in an unambiguous and easy to parse way, the LED class devices available for synchronization. The list of space separated LED class device names is not an option since we cannot guarantee names without spaces. The design requiring more complicated parsing was refused [2].
As a last resort we'd probably need to consult linux-api guys.
Quoted 8 lines
Quoted 3 lines
[1] https://lkml.org/lkml/2015/3/4/952
[2] http://www.spinics.net/lists/linux-leds/msg02995.htmlThanks for the links. Let me try to summarize some requirements + some inquiries:
- By synchronizing LEDs all main properties are synchronized
- Should it be configurable which properties should be synchronized? E.g. in case of RGB LED's the brightness should not be synchronized, however there might be use cases where synchronizing brightness makes sense.I think that synchronization should apply to simultaneous activation/deactivation and triggers.
Quoted 6 lines
- Should defining and changing groups of synchronized LEDs be possible dynamically? Based on the history of this synchronization proposal I guess so. Alternatively it could be possible only when registering the led_classdev's, e.g. by passing a reference to a "master LED" which acts as group id. (But this might restrict the mechanism to LED's created by the same driver instance.) Or both methods ..
Reliable synchronization is possible only for the sub-LEDs of the same device. All LED class devices exposed by an instance of a driver should register with the predefined scope of the LED class devices available for synchronization, the devices exposed by this driver.