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

backlight: lcd: Replace fb events with a dedicated function call

Remove support for fb events from the lcd subsystem. Provide the
helper lcd_notify_blank_all() instead. In fbdev, call
lcd_notify_blank_all() to inform the lcd subsystem of changes
to a display's blank state.

Fbdev maintains a list of all installed notifiers. Instead of fbdev
notifiers, maintain an internal list of lcd devices.

v3:
- export lcd_notify_mode_change_all() (kernel test robot)
v2:
- maintain global list of lcd devices
- avoid IS_REACHABLE() in source file
- use lock guards
- initialize lcd list and list mutex

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Simona Vetter <simona.vetter@ffwll.ch>
Reviewed-by: "Daniel Thompson (RISCstar)" <danielt@kernel.org>
Link: https://lore.kernel.org/r/20250321095517.313713-9-tzimmermann@suse.de
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Thomas Zimmermann and committed by
Lee Jones
bc70cc84 e98696ce

+81 -81
+28 -74
drivers/video/backlight/lcd.c
··· 15 15 #include <linux/notifier.h> 16 16 #include <linux/ctype.h> 17 17 #include <linux/err.h> 18 - #include <linux/fb.h> 19 18 #include <linux/slab.h> 19 + 20 + static DEFINE_MUTEX(lcd_dev_list_mutex); 21 + static LIST_HEAD(lcd_dev_list); 20 22 21 23 static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev, 22 24 int power) ··· 33 31 ld->ops->set_power(ld, power); 34 32 } 35 33 34 + void lcd_notify_blank_all(struct device *display_dev, int power) 35 + { 36 + struct lcd_device *ld; 37 + 38 + guard(mutex)(&lcd_dev_list_mutex); 39 + 40 + list_for_each_entry(ld, &lcd_dev_list, entry) 41 + lcd_notify_blank(ld, display_dev, power); 42 + } 43 + EXPORT_SYMBOL(lcd_notify_blank_all); 44 + 36 45 static void lcd_notify_mode_change(struct lcd_device *ld, struct device *display_dev, 37 46 unsigned int width, unsigned int height) 38 47 { ··· 57 44 ld->ops->set_mode(ld, width, height); 58 45 } 59 46 60 - #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ 61 - defined(CONFIG_LCD_CLASS_DEVICE_MODULE)) 62 - static int to_lcd_power(int fb_blank) 47 + void lcd_notify_mode_change_all(struct device *display_dev, 48 + unsigned int width, unsigned int height) 63 49 { 64 - switch (fb_blank) { 65 - case FB_BLANK_UNBLANK: 66 - return LCD_POWER_ON; 67 - /* deprecated; TODO: should become 'off' */ 68 - case FB_BLANK_NORMAL: 69 - return LCD_POWER_REDUCED; 70 - case FB_BLANK_VSYNC_SUSPEND: 71 - return LCD_POWER_REDUCED_VSYNC_SUSPEND; 72 - /* 'off' */ 73 - case FB_BLANK_HSYNC_SUSPEND: 74 - case FB_BLANK_POWERDOWN: 75 - default: 76 - return LCD_POWER_OFF; 77 - } 50 + struct lcd_device *ld; 51 + 52 + guard(mutex)(&lcd_dev_list_mutex); 53 + 54 + list_for_each_entry(ld, &lcd_dev_list, entry) 55 + lcd_notify_mode_change(ld, display_dev, width, height); 78 56 } 79 - 80 - /* This callback gets called when something important happens inside a 81 - * framebuffer driver. We're looking if that important event is blanking, 82 - * and if it is, we're switching lcd power as well ... 83 - */ 84 - static int fb_notifier_callback(struct notifier_block *self, 85 - unsigned long event, void *data) 86 - { 87 - struct lcd_device *ld = container_of(self, struct lcd_device, fb_notif); 88 - struct fb_event *evdata = data; 89 - struct fb_info *info = evdata->info; 90 - struct lcd_device *fb_lcd = fb_lcd_device(info); 91 - 92 - if (fb_lcd && fb_lcd != ld) 93 - return 0; 94 - 95 - if (event == FB_EVENT_BLANK) { 96 - int power = to_lcd_power(*(int *)evdata->data); 97 - 98 - lcd_notify_blank(ld, info->device, power); 99 - } else { 100 - const struct fb_videomode *videomode = evdata->data; 101 - 102 - lcd_notify_mode_change(ld, info->device, videomode->xres, videomode->yres); 103 - } 104 - 105 - return 0; 106 - } 107 - 108 - static int lcd_register_fb(struct lcd_device *ld) 109 - { 110 - memset(&ld->fb_notif, 0, sizeof(ld->fb_notif)); 111 - ld->fb_notif.notifier_call = fb_notifier_callback; 112 - return fb_register_client(&ld->fb_notif); 113 - } 114 - 115 - static void lcd_unregister_fb(struct lcd_device *ld) 116 - { 117 - fb_unregister_client(&ld->fb_notif); 118 - } 119 - #else 120 - static int lcd_register_fb(struct lcd_device *ld) 121 - { 122 - return 0; 123 - } 124 - 125 - static inline void lcd_unregister_fb(struct lcd_device *ld) 126 - { 127 - } 128 - #endif /* CONFIG_FB */ 57 + EXPORT_SYMBOL(lcd_notify_mode_change_all); 129 58 130 59 static ssize_t lcd_power_show(struct device *dev, struct device_attribute *attr, 131 60 char *buf) ··· 218 263 return ERR_PTR(rc); 219 264 } 220 265 221 - rc = lcd_register_fb(new_ld); 222 - if (rc) { 223 - device_unregister(&new_ld->dev); 224 - return ERR_PTR(rc); 225 - } 266 + guard(mutex)(&lcd_dev_list_mutex); 267 + list_add(&new_ld->entry, &lcd_dev_list); 226 268 227 269 return new_ld; 228 270 } ··· 236 284 if (!ld) 237 285 return; 238 286 287 + guard(mutex)(&lcd_dev_list_mutex); 288 + list_del(&ld->entry); 289 + 239 290 mutex_lock(&ld->ops_lock); 240 291 ld->ops = NULL; 241 292 mutex_unlock(&ld->ops_lock); 242 - lcd_unregister_fb(ld); 243 293 244 294 device_unregister(&ld->dev); 245 295 }
+35 -4
drivers/video/fbdev/core/fbmem.c
··· 15 15 #include <linux/export.h> 16 16 #include <linux/fb.h> 17 17 #include <linux/fbcon.h> 18 + #include <linux/lcd.h> 18 19 19 20 #include <video/nomodeset.h> 20 21 ··· 221 220 return err; 222 221 } 223 222 223 + static void fb_lcd_notify_mode_change(struct fb_info *info, 224 + struct fb_videomode *mode) 225 + { 226 + lcd_notify_mode_change_all(info->device, mode->xres, mode->yres); 227 + } 228 + 224 229 int 225 230 fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) 226 231 { ··· 234 227 u32 activate; 235 228 struct fb_var_screeninfo old_var; 236 229 struct fb_videomode mode; 237 - struct fb_event event; 238 230 u32 unused; 239 231 240 232 if (var->activate & FB_ACTIVATE_INV_MODE) { ··· 337 331 if (ret) 338 332 return ret; 339 333 340 - event.info = info; 341 - event.data = &mode; 342 - fb_notifier_call_chain(FB_EVENT_MODE_CHANGE, &event); 334 + fb_lcd_notify_mode_change(info, &mode); 343 335 344 336 return 0; 345 337 } 346 338 EXPORT_SYMBOL(fb_set_var); 339 + 340 + static void fb_lcd_notify_blank(struct fb_info *info) 341 + { 342 + int power; 343 + 344 + switch (info->blank) { 345 + case FB_BLANK_UNBLANK: 346 + power = LCD_POWER_ON; 347 + break; 348 + /* deprecated; TODO: should become 'off' */ 349 + case FB_BLANK_NORMAL: 350 + power = LCD_POWER_REDUCED; 351 + break; 352 + case FB_BLANK_VSYNC_SUSPEND: 353 + power = LCD_POWER_REDUCED_VSYNC_SUSPEND; 354 + break; 355 + /* 'off' */ 356 + case FB_BLANK_HSYNC_SUSPEND: 357 + case FB_BLANK_POWERDOWN: 358 + default: 359 + power = LCD_POWER_OFF; 360 + break; 361 + } 362 + 363 + lcd_notify_blank_all(info->device, power); 364 + } 347 365 348 366 int fb_blank(struct fb_info *info, int blank) 349 367 { ··· 394 364 goto err; 395 365 396 366 fb_bl_notify_blank(info, old_blank); 367 + fb_lcd_notify_blank(info); 397 368 398 369 fb_notifier_call_chain(FB_EVENT_BLANK, &event); 399 370
+18 -3
include/linux/lcd.h
··· 11 11 12 12 #include <linux/device.h> 13 13 #include <linux/mutex.h> 14 - #include <linux/notifier.h> 15 14 16 15 #define LCD_POWER_ON (0) 17 16 #define LCD_POWER_REDUCED (1) // deprecated; don't use in new code ··· 78 79 const struct lcd_ops *ops; 79 80 /* Serialise access to set_power method */ 80 81 struct mutex update_lock; 81 - /* The framebuffer notifier block */ 82 - struct notifier_block fb_notif; 82 + 83 + /** 84 + * @entry: List entry of all registered lcd devices 85 + */ 86 + struct list_head entry; 83 87 84 88 struct device dev; 85 89 }; ··· 126 124 extern void lcd_device_unregister(struct lcd_device *ld); 127 125 extern void devm_lcd_device_unregister(struct device *dev, 128 126 struct lcd_device *ld); 127 + 128 + #if IS_REACHABLE(CONFIG_LCD_CLASS_DEVICE) 129 + void lcd_notify_blank_all(struct device *display_dev, int power); 130 + void lcd_notify_mode_change_all(struct device *display_dev, 131 + unsigned int width, unsigned int height); 132 + #else 133 + static inline void lcd_notify_blank_all(struct device *display_dev, int power) 134 + {} 135 + 136 + static inline void lcd_notify_mode_change_all(struct device *display_dev, 137 + unsigned int width, unsigned int height) 138 + {} 139 + #endif 129 140 130 141 #define to_lcd_device(obj) container_of(obj, struct lcd_device, dev) 131 142