Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

leds: backlight trigger: Replace fb events with a dedicated function call

Remove support for fb events from the led backlight trigger. Provide
the helper ledtrig_backlight_blank() instead. Call it from fbdev to
inform the trigger of changes to a display's blank state.

Fbdev maintains a list of all installed notifiers. Instead of the fbdev
notifiers, maintain an internal list of led backlight triggers.

v3:
- export ledtrig_backlight_blank()
v2:
- maintain global list of led backlight triggers (Lee)
- avoid IS_REACHABLE() in source file (Lee)
- notify on changes to blank state instead of display state
- use lock guards
- initialize led list and list mutex

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Simona Vetter <simona.vetter@ffwll.ch>
Link: https://lore.kernel.org/r/20250321095517.313713-11-tzimmermann@suse.de
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Thomas Zimmermann and committed by
Lee Jones
dc2139c0 28f8bab7

+33 -34
+17 -25
drivers/leds/trigger/ledtrig-backlight.c
··· 10 10 #include <linux/kernel.h> 11 11 #include <linux/slab.h> 12 12 #include <linux/init.h> 13 - #include <linux/fb.h> 14 13 #include <linux/leds.h> 15 14 #include "../leds.h" 16 15 ··· 20 21 struct led_classdev *led; 21 22 int brightness; 22 23 int old_status; 23 - struct notifier_block notifier; 24 24 unsigned invert; 25 + 26 + struct list_head entry; 25 27 }; 28 + 29 + static DEFINE_MUTEX(ledtrig_backlight_list_mutex); 30 + static LIST_HEAD(ledtrig_backlight_list); 26 31 27 32 static void ledtrig_backlight_notify_blank(struct bl_trig_notifier *n, int new_status) 28 33 { ··· 45 42 n->old_status = new_status; 46 43 } 47 44 48 - static int fb_notifier_callback(struct notifier_block *p, 49 - unsigned long event, void *data) 45 + void ledtrig_backlight_blank(bool blank) 50 46 { 51 - struct bl_trig_notifier *n = container_of(p, 52 - struct bl_trig_notifier, notifier); 53 - struct fb_event *fb_event = data; 54 - int *blank; 55 - int new_status; 47 + struct bl_trig_notifier *n; 48 + int new_status = blank ? BLANK : UNBLANK; 56 49 57 - /* If we aren't interested in this event, skip it immediately ... */ 58 - if (event != FB_EVENT_BLANK) 59 - return 0; 50 + guard(mutex)(&ledtrig_backlight_list_mutex); 60 51 61 - blank = fb_event->data; 62 - new_status = *blank ? BLANK : UNBLANK; 63 - 64 - ledtrig_backlight_notify_blank(n, new_status); 65 - 66 - return 0; 52 + list_for_each_entry(n, &ledtrig_backlight_list, entry) 53 + ledtrig_backlight_notify_blank(n, new_status); 67 54 } 55 + EXPORT_SYMBOL(ledtrig_backlight_blank); 68 56 69 57 static ssize_t bl_trig_invert_show(struct device *dev, 70 58 struct device_attribute *attr, char *buf) ··· 100 106 101 107 static int bl_trig_activate(struct led_classdev *led) 102 108 { 103 - int ret; 104 - 105 109 struct bl_trig_notifier *n; 106 110 107 111 n = kzalloc(sizeof(struct bl_trig_notifier), GFP_KERNEL); ··· 110 118 n->led = led; 111 119 n->brightness = led->brightness; 112 120 n->old_status = UNBLANK; 113 - n->notifier.notifier_call = fb_notifier_callback; 114 121 115 - ret = fb_register_client(&n->notifier); 116 - if (ret) 117 - dev_err(led->dev, "unable to register backlight trigger\n"); 122 + guard(mutex)(&ledtrig_backlight_list_mutex); 123 + list_add(&n->entry, &ledtrig_backlight_list); 118 124 119 125 return 0; 120 126 } ··· 121 131 { 122 132 struct bl_trig_notifier *n = led_get_trigger_data(led); 123 133 124 - fb_unregister_client(&n->notifier); 134 + guard(mutex)(&ledtrig_backlight_list_mutex); 135 + list_del(&n->entry); 136 + 125 137 kfree(n); 126 138 } 127 139
+10 -9
drivers/video/fbdev/core/fbmem.c
··· 16 16 #include <linux/fb.h> 17 17 #include <linux/fbcon.h> 18 18 #include <linux/lcd.h> 19 + #include <linux/leds.h> 19 20 20 21 #include <video/nomodeset.h> 21 22 ··· 370 369 lcd_notify_blank_all(info->device, power); 371 370 } 372 371 372 + static void fb_ledtrig_backlight_notify_blank(struct fb_info *info) 373 + { 374 + if (info->blank == FB_BLANK_UNBLANK) 375 + ledtrig_backlight_blank(false); 376 + else 377 + ledtrig_backlight_blank(true); 378 + } 379 + 373 380 int fb_blank(struct fb_info *info, int blank) 374 381 { 375 382 int old_blank = info->blank; 376 - struct fb_event event; 377 - int data[2]; 378 383 int ret; 379 384 380 385 if (!info->fbops->fb_blank) ··· 388 381 389 382 if (blank > FB_BLANK_POWERDOWN) 390 383 blank = FB_BLANK_POWERDOWN; 391 - 392 - data[0] = blank; 393 - data[1] = old_blank; 394 - event.info = info; 395 - event.data = data; 396 384 397 385 info->blank = blank; 398 386 ··· 397 395 398 396 fb_bl_notify_blank(info, old_blank); 399 397 fb_lcd_notify_blank(info); 400 - 401 - fb_notifier_call_chain(FB_EVENT_BLANK, &event); 398 + fb_ledtrig_backlight_notify_blank(info); 402 399 403 400 return 0; 404 401
+6
include/linux/leds.h
··· 640 640 static inline void ledtrig_torch_ctrl(bool on) {} 641 641 #endif 642 642 643 + #if IS_REACHABLE(CONFIG_LEDS_TRIGGER_BACKLIGHT) 644 + void ledtrig_backlight_blank(bool blank); 645 + #else 646 + static inline void ledtrig_backlight_blank(bool blank) {} 647 + #endif 648 + 643 649 /* 644 650 * Generic LED platform data for describing LED names and default triggers. 645 651 */