Skip to content

Commit bc70cc8

Browse files
Thomas Zimmermannlag-linaro
authored andcommitted
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>
1 parent e98696c commit bc70cc8

File tree

3 files changed

+79
-79
lines changed

3 files changed

+79
-79
lines changed

drivers/video/backlight/lcd.c

Lines changed: 26 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
#include <linux/notifier.h>
1616
#include <linux/ctype.h>
1717
#include <linux/err.h>
18-
#include <linux/fb.h>
1918
#include <linux/slab.h>
2019

20+
static DEFINE_MUTEX(lcd_dev_list_mutex);
21+
static LIST_HEAD(lcd_dev_list);
22+
2123
static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev,
2224
int power)
2325
{
@@ -31,6 +33,17 @@ static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev,
3133
ld->ops->set_power(ld, power);
3234
}
3335

36+
void lcd_notify_blank_all(struct device *display_dev, int power)
37+
{
38+
struct lcd_device *ld;
39+
40+
guard(mutex)(&lcd_dev_list_mutex);
41+
42+
list_for_each_entry(ld, &lcd_dev_list, entry)
43+
lcd_notify_blank(ld, display_dev, power);
44+
}
45+
EXPORT_SYMBOL(lcd_notify_blank_all);
46+
3447
static void lcd_notify_mode_change(struct lcd_device *ld, struct device *display_dev,
3548
unsigned int width, unsigned int height)
3649
{
@@ -44,75 +57,17 @@ static void lcd_notify_mode_change(struct lcd_device *ld, struct device *display
4457
ld->ops->set_mode(ld, width, height);
4558
}
4659

47-
#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
48-
defined(CONFIG_LCD_CLASS_DEVICE_MODULE))
49-
static int to_lcd_power(int fb_blank)
60+
void lcd_notify_mode_change_all(struct device *display_dev,
61+
unsigned int width, unsigned int height)
5062
{
51-
switch (fb_blank) {
52-
case FB_BLANK_UNBLANK:
53-
return LCD_POWER_ON;
54-
/* deprecated; TODO: should become 'off' */
55-
case FB_BLANK_NORMAL:
56-
return LCD_POWER_REDUCED;
57-
case FB_BLANK_VSYNC_SUSPEND:
58-
return LCD_POWER_REDUCED_VSYNC_SUSPEND;
59-
/* 'off' */
60-
case FB_BLANK_HSYNC_SUSPEND:
61-
case FB_BLANK_POWERDOWN:
62-
default:
63-
return LCD_POWER_OFF;
64-
}
65-
}
63+
struct lcd_device *ld;
6664

67-
/* This callback gets called when something important happens inside a
68-
* framebuffer driver. We're looking if that important event is blanking,
69-
* and if it is, we're switching lcd power as well ...
70-
*/
71-
static int fb_notifier_callback(struct notifier_block *self,
72-
unsigned long event, void *data)
73-
{
74-
struct lcd_device *ld = container_of(self, struct lcd_device, fb_notif);
75-
struct fb_event *evdata = data;
76-
struct fb_info *info = evdata->info;
77-
struct lcd_device *fb_lcd = fb_lcd_device(info);
78-
79-
if (fb_lcd && fb_lcd != ld)
80-
return 0;
81-
82-
if (event == FB_EVENT_BLANK) {
83-
int power = to_lcd_power(*(int *)evdata->data);
84-
85-
lcd_notify_blank(ld, info->device, power);
86-
} else {
87-
const struct fb_videomode *videomode = evdata->data;
88-
89-
lcd_notify_mode_change(ld, info->device, videomode->xres, videomode->yres);
90-
}
65+
guard(mutex)(&lcd_dev_list_mutex);
9166

92-
return 0;
67+
list_for_each_entry(ld, &lcd_dev_list, entry)
68+
lcd_notify_mode_change(ld, display_dev, width, height);
9369
}
94-
95-
static int lcd_register_fb(struct lcd_device *ld)
96-
{
97-
memset(&ld->fb_notif, 0, sizeof(ld->fb_notif));
98-
ld->fb_notif.notifier_call = fb_notifier_callback;
99-
return fb_register_client(&ld->fb_notif);
100-
}
101-
102-
static void lcd_unregister_fb(struct lcd_device *ld)
103-
{
104-
fb_unregister_client(&ld->fb_notif);
105-
}
106-
#else
107-
static int lcd_register_fb(struct lcd_device *ld)
108-
{
109-
return 0;
110-
}
111-
112-
static inline void lcd_unregister_fb(struct lcd_device *ld)
113-
{
114-
}
115-
#endif /* CONFIG_FB */
70+
EXPORT_SYMBOL(lcd_notify_mode_change_all);
11671

11772
static ssize_t lcd_power_show(struct device *dev, struct device_attribute *attr,
11873
char *buf)
@@ -263,11 +218,8 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent,
263218
return ERR_PTR(rc);
264219
}
265220

266-
rc = lcd_register_fb(new_ld);
267-
if (rc) {
268-
device_unregister(&new_ld->dev);
269-
return ERR_PTR(rc);
270-
}
221+
guard(mutex)(&lcd_dev_list_mutex);
222+
list_add(&new_ld->entry, &lcd_dev_list);
271223

272224
return new_ld;
273225
}
@@ -284,10 +236,12 @@ void lcd_device_unregister(struct lcd_device *ld)
284236
if (!ld)
285237
return;
286238

239+
guard(mutex)(&lcd_dev_list_mutex);
240+
list_del(&ld->entry);
241+
287242
mutex_lock(&ld->ops_lock);
288243
ld->ops = NULL;
289244
mutex_unlock(&ld->ops_lock);
290-
lcd_unregister_fb(ld);
291245

292246
device_unregister(&ld->dev);
293247
}

drivers/video/fbdev/core/fbmem.c

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/export.h>
1616
#include <linux/fb.h>
1717
#include <linux/fbcon.h>
18+
#include <linux/lcd.h>
1819

1920
#include <video/nomodeset.h>
2021

@@ -220,14 +221,19 @@ static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
220221
return err;
221222
}
222223

224+
static void fb_lcd_notify_mode_change(struct fb_info *info,
225+
struct fb_videomode *mode)
226+
{
227+
lcd_notify_mode_change_all(info->device, mode->xres, mode->yres);
228+
}
229+
223230
int
224231
fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
225232
{
226233
int ret = 0;
227234
u32 activate;
228235
struct fb_var_screeninfo old_var;
229236
struct fb_videomode mode;
230-
struct fb_event event;
231237
u32 unused;
232238

233239
if (var->activate & FB_ACTIVATE_INV_MODE) {
@@ -331,14 +337,38 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
331337
if (ret)
332338
return ret;
333339

334-
event.info = info;
335-
event.data = &mode;
336-
fb_notifier_call_chain(FB_EVENT_MODE_CHANGE, &event);
340+
fb_lcd_notify_mode_change(info, &mode);
337341

338342
return 0;
339343
}
340344
EXPORT_SYMBOL(fb_set_var);
341345

346+
static void fb_lcd_notify_blank(struct fb_info *info)
347+
{
348+
int power;
349+
350+
switch (info->blank) {
351+
case FB_BLANK_UNBLANK:
352+
power = LCD_POWER_ON;
353+
break;
354+
/* deprecated; TODO: should become 'off' */
355+
case FB_BLANK_NORMAL:
356+
power = LCD_POWER_REDUCED;
357+
break;
358+
case FB_BLANK_VSYNC_SUSPEND:
359+
power = LCD_POWER_REDUCED_VSYNC_SUSPEND;
360+
break;
361+
/* 'off' */
362+
case FB_BLANK_HSYNC_SUSPEND:
363+
case FB_BLANK_POWERDOWN:
364+
default:
365+
power = LCD_POWER_OFF;
366+
break;
367+
}
368+
369+
lcd_notify_blank_all(info->device, power);
370+
}
371+
342372
int fb_blank(struct fb_info *info, int blank)
343373
{
344374
int old_blank = info->blank;
@@ -364,6 +394,7 @@ int fb_blank(struct fb_info *info, int blank)
364394
goto err;
365395

366396
fb_bl_notify_blank(info, old_blank);
397+
fb_lcd_notify_blank(info);
367398

368399
fb_notifier_call_chain(FB_EVENT_BLANK, &event);
369400

include/linux/lcd.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
#include <linux/device.h>
1313
#include <linux/mutex.h>
14-
#include <linux/notifier.h>
1514

1615
#define LCD_POWER_ON (0)
1716
#define LCD_POWER_REDUCED (1) // deprecated; don't use in new code
@@ -79,8 +78,11 @@ struct lcd_device {
7978
const struct lcd_ops *ops;
8079
/* Serialise access to set_power method */
8180
struct mutex update_lock;
82-
/* The framebuffer notifier block */
83-
struct notifier_block fb_notif;
81+
82+
/**
83+
* @entry: List entry of all registered lcd devices
84+
*/
85+
struct list_head entry;
8486

8587
struct device dev;
8688
};
@@ -125,6 +127,19 @@ extern void lcd_device_unregister(struct lcd_device *ld);
125127
extern void devm_lcd_device_unregister(struct device *dev,
126128
struct lcd_device *ld);
127129

130+
#if IS_REACHABLE(CONFIG_LCD_CLASS_DEVICE)
131+
void lcd_notify_blank_all(struct device *display_dev, int power);
132+
void lcd_notify_mode_change_all(struct device *display_dev,
133+
unsigned int width, unsigned int height);
134+
#else
135+
static inline void lcd_notify_blank_all(struct device *display_dev, int power)
136+
{}
137+
138+
static inline void lcd_notify_mode_change_all(struct device *display_dev,
139+
unsigned int width, unsigned int height)
140+
{}
141+
#endif
142+
128143
#define to_lcd_device(obj) container_of(obj, struct lcd_device, dev)
129144

130145
static inline void * lcd_get_data(struct lcd_device *ld_dev)

0 commit comments

Comments
 (0)