Skip to content

Commit a9dfb7d

Browse files
committed
Merge tag 'backlight-next-6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight
Pull backlight updates from Lee Jones: "Framebuffer Subsystem (fbdev): - The display's blanking status is now tracked in 'struct fb_info' - 'framebuffer_alloc()' initializes the blank state to FB_BLANK_UNBLANK - 'register_framebuffer()' sets the state to 'FB_BLANK_POWERDOWN' if an 'fb_blank' callback exists, ensuring 'FB_EVENT_BLANK' listeners correctly see the display being turned on during the first modeset - The 'FB_EVENT_BLANK' event data now includes both the new and the old blank states - 'fb_blank()' has been reworked to return early on errors, without functional changes, in preparation for further state tracking improvements - Fbdev now calls dedicated functions in the backlight subsystems to notify them of blank state changes, instead of relying on fbdev event notifiers - For LCDs, fbdev also calls a dedicated function to notify of mode changes - Removed the definitions for the unused fbdev event constants 'FB_EVENT_MODE_CHANGE' and 'FB_EVENT_BLANK' from the header file Backlight Subsystem: - Implemented fbdev blank state tracking using the (newly enhanced) blank state information provided directly by 'FB_EVENT_BLANK' - Removed internal blank state tracking fields ('fb_bl_on') from 'struct backlight_device' - Moved the handling of blank-state updates into a separate internal helper function, 'backlight_notify_blank()' - Removed support for fbdev events and replaced it with a dedicated function call interface ('backlight_notify_blank()' and 'backlight_notify_blank_all()') for display drivers to update backlight status LCD Subsystem: - Moved the handling of display updates (blank events and mode changes) from fbdev event notifiers to separate internal helper functions ('lcd_notify_blank', 'lcd_notify_mode_change') - Removed support for fbdev events and replaced it with dedicated function call interfaces ('lcd_notify_blank_all()', 'lcd_notify_mode_change_all()') - The LCD subsystem now maintains its own internal list of LCD devices instead of relying on fbdev notifiers LED Backlight Trigger: - Moved the handling of blank-state updates into a separate internal helper, 'ledtrig_backlight_notify_blank()' - Removed support for fbdev events and replaced it with a dedicated function call, 'ledtrig_backlight_blank()', for fbdev to notify trigger of blank state changes - The LED backlight trigger now maintains its own internal list of triggers instead of relying on fbdev notifiers Qualcomm WLED Backlight: - Added a NULL check after 'devm_kasprintf()' in 'wled_configure()' to prevent a potential NULL pointer dereference if memory allocation fails" * tag 'backlight-next-6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight: backlight: pm8941: Add NULL check in wled_configure() fbdev: Remove constants of unused events leds: backlight trigger: Replace fb events with a dedicated function call leds: backlight trigger: Move blank-state handling into helper backlight: lcd: Replace fb events with a dedicated function call backlight: lcd: Move event handling into helpers backlight: Replace fb events with a dedicated function call backlight: Move blank-state handling into helper backlight: Implement fbdev tracking with blank state from event fbdev: Send old blank state in FB_EVENT_BLANK fbdev: Track display blanking state fbdev: Rework fb_blank()
2 parents b546608 + e12d3e1 commit a9dfb7d

File tree

12 files changed

+219
-210
lines changed

12 files changed

+219
-210
lines changed

drivers/leds/trigger/ledtrig-backlight.c

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include <linux/kernel.h>
1111
#include <linux/slab.h>
1212
#include <linux/init.h>
13-
#include <linux/fb.h>
1413
#include <linux/leds.h>
1514
#include "../leds.h"
1615

@@ -21,29 +20,20 @@ struct bl_trig_notifier {
2120
struct led_classdev *led;
2221
int brightness;
2322
int old_status;
24-
struct notifier_block notifier;
2523
unsigned invert;
24+
25+
struct list_head entry;
2626
};
2727

28-
static int fb_notifier_callback(struct notifier_block *p,
29-
unsigned long event, void *data)
28+
static DEFINE_MUTEX(ledtrig_backlight_list_mutex);
29+
static LIST_HEAD(ledtrig_backlight_list);
30+
31+
static void ledtrig_backlight_notify_blank(struct bl_trig_notifier *n, int new_status)
3032
{
31-
struct bl_trig_notifier *n = container_of(p,
32-
struct bl_trig_notifier, notifier);
3333
struct led_classdev *led = n->led;
34-
struct fb_event *fb_event = data;
35-
int *blank;
36-
int new_status;
37-
38-
/* If we aren't interested in this event, skip it immediately ... */
39-
if (event != FB_EVENT_BLANK)
40-
return 0;
41-
42-
blank = fb_event->data;
43-
new_status = *blank ? BLANK : UNBLANK;
4434

4535
if (new_status == n->old_status)
46-
return 0;
36+
return;
4737

4838
if ((n->old_status == UNBLANK) ^ n->invert) {
4939
n->brightness = led->brightness;
@@ -53,9 +43,19 @@ static int fb_notifier_callback(struct notifier_block *p,
5343
}
5444

5545
n->old_status = new_status;
46+
}
5647

57-
return 0;
48+
void ledtrig_backlight_blank(bool blank)
49+
{
50+
struct bl_trig_notifier *n;
51+
int new_status = blank ? BLANK : UNBLANK;
52+
53+
guard(mutex)(&ledtrig_backlight_list_mutex);
54+
55+
list_for_each_entry(n, &ledtrig_backlight_list, entry)
56+
ledtrig_backlight_notify_blank(n, new_status);
5857
}
58+
EXPORT_SYMBOL(ledtrig_backlight_blank);
5959

6060
static ssize_t bl_trig_invert_show(struct device *dev,
6161
struct device_attribute *attr, char *buf)
@@ -100,8 +100,6 @@ ATTRIBUTE_GROUPS(bl_trig);
100100

101101
static int bl_trig_activate(struct led_classdev *led)
102102
{
103-
int ret;
104-
105103
struct bl_trig_notifier *n;
106104

107105
n = kzalloc(sizeof(struct bl_trig_notifier), GFP_KERNEL);
@@ -112,11 +110,9 @@ static int bl_trig_activate(struct led_classdev *led)
112110
n->led = led;
113111
n->brightness = led->brightness;
114112
n->old_status = UNBLANK;
115-
n->notifier.notifier_call = fb_notifier_callback;
116113

117-
ret = fb_register_client(&n->notifier);
118-
if (ret)
119-
dev_err(led->dev, "unable to register backlight trigger\n");
114+
guard(mutex)(&ledtrig_backlight_list_mutex);
115+
list_add(&n->entry, &ledtrig_backlight_list);
120116

121117
return 0;
122118
}
@@ -125,7 +121,9 @@ static void bl_trig_deactivate(struct led_classdev *led)
125121
{
126122
struct bl_trig_notifier *n = led_get_trigger_data(led);
127123

128-
fb_unregister_client(&n->notifier);
124+
guard(mutex)(&ledtrig_backlight_list_mutex);
125+
list_del(&n->entry);
126+
129127
kfree(n);
130128
}
131129

drivers/video/backlight/backlight.c

Lines changed: 20 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
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

2120
#ifdef CONFIG_PMAC_BACKLIGHT
@@ -57,10 +56,10 @@
5756
* a hot-key to adjust backlight, the driver must notify the backlight
5857
* core that brightness has changed using backlight_force_update().
5958
*
60-
* The backlight driver core receives notifications from fbdev and
61-
* if the event is FB_EVENT_BLANK and if the value of blank, from the
62-
* FBIOBLANK ioctrl, results in a change in the backlight state the
63-
* update_status() operation is called.
59+
* Display drives can control the backlight device's status using
60+
* backlight_notify_blank() and backlight_notify_blank_all(). If this
61+
* results in a change in the backlight state the functions call the
62+
* update_status() operation.
6463
*/
6564

6665
static struct list_head backlight_dev_list;
@@ -78,85 +77,40 @@ static const char *const backlight_scale_types[] = {
7877
[BACKLIGHT_SCALE_NON_LINEAR] = "non-linear",
7978
};
8079

81-
#if defined(CONFIG_FB_CORE) || (defined(CONFIG_FB_CORE_MODULE) && \
82-
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
83-
/*
84-
* fb_notifier_callback
85-
*
86-
* This callback gets called when something important happens inside a
87-
* framebuffer driver. The backlight core only cares about FB_BLANK_UNBLANK
88-
* which is reported to the driver using backlight_update_status()
89-
* as a state change.
90-
*
91-
* There may be several fbdev's connected to the backlight device,
92-
* in which case they are kept track of. A state change is only reported
93-
* if there is a change in backlight for the specified fbdev.
94-
*/
95-
static int fb_notifier_callback(struct notifier_block *self,
96-
unsigned long event, void *data)
80+
void backlight_notify_blank(struct backlight_device *bd, struct device *display_dev,
81+
bool fb_on, bool prev_fb_on)
9782
{
98-
struct backlight_device *bd;
99-
struct fb_event *evdata = data;
100-
struct fb_info *info = evdata->info;
101-
struct backlight_device *fb_bd = fb_bl_device(info);
102-
int node = info->node;
103-
int fb_blank = 0;
104-
105-
/* If we aren't interested in this event, skip it immediately ... */
106-
if (event != FB_EVENT_BLANK)
107-
return 0;
108-
109-
bd = container_of(self, struct backlight_device, fb_notif);
110-
mutex_lock(&bd->ops_lock);
83+
guard(mutex)(&bd->ops_lock);
11184

11285
if (!bd->ops)
113-
goto out;
114-
if (bd->ops->controls_device && !bd->ops->controls_device(bd, info->device))
115-
goto out;
116-
if (fb_bd && fb_bd != bd)
117-
goto out;
118-
119-
fb_blank = *(int *)evdata->data;
120-
if (fb_blank == FB_BLANK_UNBLANK && !bd->fb_bl_on[node]) {
121-
bd->fb_bl_on[node] = true;
86+
return;
87+
if (bd->ops->controls_device && !bd->ops->controls_device(bd, display_dev))
88+
return;
89+
90+
if (fb_on && (!prev_fb_on || !bd->use_count)) {
12291
if (!bd->use_count++) {
12392
bd->props.state &= ~BL_CORE_FBBLANK;
12493
backlight_update_status(bd);
12594
}
126-
} else if (fb_blank != FB_BLANK_UNBLANK && bd->fb_bl_on[node]) {
127-
bd->fb_bl_on[node] = false;
95+
} else if (!fb_on && prev_fb_on && bd->use_count) {
12896
if (!(--bd->use_count)) {
12997
bd->props.state |= BL_CORE_FBBLANK;
13098
backlight_update_status(bd);
13199
}
132100
}
133-
out:
134-
mutex_unlock(&bd->ops_lock);
135-
return 0;
136101
}
102+
EXPORT_SYMBOL(backlight_notify_blank);
137103

138-
static int backlight_register_fb(struct backlight_device *bd)
104+
void backlight_notify_blank_all(struct device *display_dev, bool fb_on, bool prev_fb_on)
139105
{
140-
memset(&bd->fb_notif, 0, sizeof(bd->fb_notif));
141-
bd->fb_notif.notifier_call = fb_notifier_callback;
106+
struct backlight_device *bd;
142107

143-
return fb_register_client(&bd->fb_notif);
144-
}
108+
guard(mutex)(&backlight_dev_list_mutex);
145109

146-
static void backlight_unregister_fb(struct backlight_device *bd)
147-
{
148-
fb_unregister_client(&bd->fb_notif);
149-
}
150-
#else
151-
static inline int backlight_register_fb(struct backlight_device *bd)
152-
{
153-
return 0;
110+
list_for_each_entry(bd, &backlight_dev_list, entry)
111+
backlight_notify_blank(bd, display_dev, fb_on, prev_fb_on);
154112
}
155-
156-
static inline void backlight_unregister_fb(struct backlight_device *bd)
157-
{
158-
}
159-
#endif /* CONFIG_FB_CORE */
113+
EXPORT_SYMBOL(backlight_notify_blank_all);
160114

161115
static void backlight_generate_event(struct backlight_device *bd,
162116
enum backlight_update_reason reason)
@@ -447,12 +401,6 @@ struct backlight_device *backlight_device_register(const char *name,
447401
return ERR_PTR(rc);
448402
}
449403

450-
rc = backlight_register_fb(new_bd);
451-
if (rc) {
452-
device_unregister(&new_bd->dev);
453-
return ERR_PTR(rc);
454-
}
455-
456404
new_bd->ops = ops;
457405

458406
#ifdef CONFIG_PMAC_BACKLIGHT
@@ -539,7 +487,6 @@ void backlight_device_unregister(struct backlight_device *bd)
539487
bd->ops = NULL;
540488
mutex_unlock(&bd->ops_lock);
541489

542-
backlight_unregister_fb(bd);
543490
device_unregister(&bd->dev);
544491
}
545492
EXPORT_SYMBOL(backlight_device_unregister);

drivers/video/backlight/lcd.c

Lines changed: 40 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -15,86 +15,59 @@
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

21-
#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
22-
defined(CONFIG_LCD_CLASS_DEVICE_MODULE))
23-
static int to_lcd_power(int fb_blank)
24-
{
25-
switch (fb_blank) {
26-
case FB_BLANK_UNBLANK:
27-
return LCD_POWER_ON;
28-
/* deprecated; TODO: should become 'off' */
29-
case FB_BLANK_NORMAL:
30-
return LCD_POWER_REDUCED;
31-
case FB_BLANK_VSYNC_SUSPEND:
32-
return LCD_POWER_REDUCED_VSYNC_SUSPEND;
33-
/* 'off' */
34-
case FB_BLANK_HSYNC_SUSPEND:
35-
case FB_BLANK_POWERDOWN:
36-
default:
37-
return LCD_POWER_OFF;
38-
}
39-
}
20+
static DEFINE_MUTEX(lcd_dev_list_mutex);
21+
static LIST_HEAD(lcd_dev_list);
4022

41-
/* This callback gets called when something important happens inside a
42-
* framebuffer driver. We're looking if that important event is blanking,
43-
* and if it is, we're switching lcd power as well ...
44-
*/
45-
static int fb_notifier_callback(struct notifier_block *self,
46-
unsigned long event, void *data)
23+
static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev,
24+
int power)
4725
{
48-
struct lcd_device *ld = container_of(self, struct lcd_device, fb_notif);
49-
struct fb_event *evdata = data;
50-
struct fb_info *info = evdata->info;
51-
struct lcd_device *fb_lcd = fb_lcd_device(info);
52-
5326
guard(mutex)(&ld->ops_lock);
5427

55-
if (!ld->ops)
56-
return 0;
57-
if (ld->ops->controls_device && !ld->ops->controls_device(ld, info->device))
58-
return 0;
59-
if (fb_lcd && fb_lcd != ld)
60-
return 0;
28+
if (!ld->ops || !ld->ops->set_power)
29+
return;
30+
if (ld->ops->controls_device && !ld->ops->controls_device(ld, display_dev))
31+
return;
6132

62-
if (event == FB_EVENT_BLANK) {
63-
int power = to_lcd_power(*(int *)evdata->data);
33+
ld->ops->set_power(ld, power);
34+
}
6435

65-
if (ld->ops->set_power)
66-
ld->ops->set_power(ld, power);
67-
} else {
68-
const struct fb_videomode *videomode = evdata->data;
36+
void lcd_notify_blank_all(struct device *display_dev, int power)
37+
{
38+
struct lcd_device *ld;
6939

70-
if (ld->ops->set_mode)
71-
ld->ops->set_mode(ld, videomode->xres, videomode->yres);
72-
}
40+
guard(mutex)(&lcd_dev_list_mutex);
7341

74-
return 0;
42+
list_for_each_entry(ld, &lcd_dev_list, entry)
43+
lcd_notify_blank(ld, display_dev, power);
7544
}
45+
EXPORT_SYMBOL(lcd_notify_blank_all);
7646

77-
static int lcd_register_fb(struct lcd_device *ld)
47+
static void lcd_notify_mode_change(struct lcd_device *ld, struct device *display_dev,
48+
unsigned int width, unsigned int height)
7849
{
79-
memset(&ld->fb_notif, 0, sizeof(ld->fb_notif));
80-
ld->fb_notif.notifier_call = fb_notifier_callback;
81-
return fb_register_client(&ld->fb_notif);
82-
}
50+
guard(mutex)(&ld->ops_lock);
8351

84-
static void lcd_unregister_fb(struct lcd_device *ld)
85-
{
86-
fb_unregister_client(&ld->fb_notif);
87-
}
88-
#else
89-
static int lcd_register_fb(struct lcd_device *ld)
90-
{
91-
return 0;
52+
if (!ld->ops || !ld->ops->set_mode)
53+
return;
54+
if (ld->ops->controls_device && !ld->ops->controls_device(ld, display_dev))
55+
return;
56+
57+
ld->ops->set_mode(ld, width, height);
9258
}
9359

94-
static inline void lcd_unregister_fb(struct lcd_device *ld)
60+
void lcd_notify_mode_change_all(struct device *display_dev,
61+
unsigned int width, unsigned int height)
9562
{
63+
struct lcd_device *ld;
64+
65+
guard(mutex)(&lcd_dev_list_mutex);
66+
67+
list_for_each_entry(ld, &lcd_dev_list, entry)
68+
lcd_notify_mode_change(ld, display_dev, width, height);
9669
}
97-
#endif /* CONFIG_FB */
70+
EXPORT_SYMBOL(lcd_notify_mode_change_all);
9871

9972
static ssize_t lcd_power_show(struct device *dev, struct device_attribute *attr,
10073
char *buf)
@@ -245,11 +218,8 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent,
245218
return ERR_PTR(rc);
246219
}
247220

248-
rc = lcd_register_fb(new_ld);
249-
if (rc) {
250-
device_unregister(&new_ld->dev);
251-
return ERR_PTR(rc);
252-
}
221+
guard(mutex)(&lcd_dev_list_mutex);
222+
list_add(&new_ld->entry, &lcd_dev_list);
253223

254224
return new_ld;
255225
}
@@ -266,10 +236,12 @@ void lcd_device_unregister(struct lcd_device *ld)
266236
if (!ld)
267237
return;
268238

239+
guard(mutex)(&lcd_dev_list_mutex);
240+
list_del(&ld->entry);
241+
269242
mutex_lock(&ld->ops_lock);
270243
ld->ops = NULL;
271244
mutex_unlock(&ld->ops_lock);
272-
lcd_unregister_fb(ld);
273245

274246
device_unregister(&ld->dev);
275247
}

0 commit comments

Comments
 (0)