mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-15 22:31:47 -04:00
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>
This commit is contained in:
committed by
Lee Jones
parent
e98696cea7
commit
bc70cc84f5
@@ -15,9 +15,11 @@
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static DEFINE_MUTEX(lcd_dev_list_mutex);
|
||||
static LIST_HEAD(lcd_dev_list);
|
||||
|
||||
static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev,
|
||||
int power)
|
||||
{
|
||||
@@ -31,6 +33,17 @@ static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev,
|
||||
ld->ops->set_power(ld, power);
|
||||
}
|
||||
|
||||
void lcd_notify_blank_all(struct device *display_dev, int power)
|
||||
{
|
||||
struct lcd_device *ld;
|
||||
|
||||
guard(mutex)(&lcd_dev_list_mutex);
|
||||
|
||||
list_for_each_entry(ld, &lcd_dev_list, entry)
|
||||
lcd_notify_blank(ld, display_dev, power);
|
||||
}
|
||||
EXPORT_SYMBOL(lcd_notify_blank_all);
|
||||
|
||||
static void lcd_notify_mode_change(struct lcd_device *ld, struct device *display_dev,
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
@@ -44,75 +57,17 @@ static void lcd_notify_mode_change(struct lcd_device *ld, struct device *display
|
||||
ld->ops->set_mode(ld, width, height);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
|
||||
defined(CONFIG_LCD_CLASS_DEVICE_MODULE))
|
||||
static int to_lcd_power(int fb_blank)
|
||||
void lcd_notify_mode_change_all(struct device *display_dev,
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
switch (fb_blank) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
return LCD_POWER_ON;
|
||||
/* deprecated; TODO: should become 'off' */
|
||||
case FB_BLANK_NORMAL:
|
||||
return LCD_POWER_REDUCED;
|
||||
case FB_BLANK_VSYNC_SUSPEND:
|
||||
return LCD_POWER_REDUCED_VSYNC_SUSPEND;
|
||||
/* 'off' */
|
||||
case FB_BLANK_HSYNC_SUSPEND:
|
||||
case FB_BLANK_POWERDOWN:
|
||||
default:
|
||||
return LCD_POWER_OFF;
|
||||
}
|
||||
struct lcd_device *ld;
|
||||
|
||||
guard(mutex)(&lcd_dev_list_mutex);
|
||||
|
||||
list_for_each_entry(ld, &lcd_dev_list, entry)
|
||||
lcd_notify_mode_change(ld, display_dev, width, height);
|
||||
}
|
||||
|
||||
/* This callback gets called when something important happens inside a
|
||||
* framebuffer driver. We're looking if that important event is blanking,
|
||||
* and if it is, we're switching lcd power as well ...
|
||||
*/
|
||||
static int fb_notifier_callback(struct notifier_block *self,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct lcd_device *ld = container_of(self, struct lcd_device, fb_notif);
|
||||
struct fb_event *evdata = data;
|
||||
struct fb_info *info = evdata->info;
|
||||
struct lcd_device *fb_lcd = fb_lcd_device(info);
|
||||
|
||||
if (fb_lcd && fb_lcd != ld)
|
||||
return 0;
|
||||
|
||||
if (event == FB_EVENT_BLANK) {
|
||||
int power = to_lcd_power(*(int *)evdata->data);
|
||||
|
||||
lcd_notify_blank(ld, info->device, power);
|
||||
} else {
|
||||
const struct fb_videomode *videomode = evdata->data;
|
||||
|
||||
lcd_notify_mode_change(ld, info->device, videomode->xres, videomode->yres);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lcd_register_fb(struct lcd_device *ld)
|
||||
{
|
||||
memset(&ld->fb_notif, 0, sizeof(ld->fb_notif));
|
||||
ld->fb_notif.notifier_call = fb_notifier_callback;
|
||||
return fb_register_client(&ld->fb_notif);
|
||||
}
|
||||
|
||||
static void lcd_unregister_fb(struct lcd_device *ld)
|
||||
{
|
||||
fb_unregister_client(&ld->fb_notif);
|
||||
}
|
||||
#else
|
||||
static int lcd_register_fb(struct lcd_device *ld)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void lcd_unregister_fb(struct lcd_device *ld)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_FB */
|
||||
EXPORT_SYMBOL(lcd_notify_mode_change_all);
|
||||
|
||||
static ssize_t lcd_power_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@@ -263,11 +218,8 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent,
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
rc = lcd_register_fb(new_ld);
|
||||
if (rc) {
|
||||
device_unregister(&new_ld->dev);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
guard(mutex)(&lcd_dev_list_mutex);
|
||||
list_add(&new_ld->entry, &lcd_dev_list);
|
||||
|
||||
return new_ld;
|
||||
}
|
||||
@@ -284,10 +236,12 @@ void lcd_device_unregister(struct lcd_device *ld)
|
||||
if (!ld)
|
||||
return;
|
||||
|
||||
guard(mutex)(&lcd_dev_list_mutex);
|
||||
list_del(&ld->entry);
|
||||
|
||||
mutex_lock(&ld->ops_lock);
|
||||
ld->ops = NULL;
|
||||
mutex_unlock(&ld->ops_lock);
|
||||
lcd_unregister_fb(ld);
|
||||
|
||||
device_unregister(&ld->dev);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fbcon.h>
|
||||
#include <linux/lcd.h>
|
||||
|
||||
#include <video/nomodeset.h>
|
||||
|
||||
@@ -220,6 +221,12 @@ static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
|
||||
return err;
|
||||
}
|
||||
|
||||
static void fb_lcd_notify_mode_change(struct fb_info *info,
|
||||
struct fb_videomode *mode)
|
||||
{
|
||||
lcd_notify_mode_change_all(info->device, mode->xres, mode->yres);
|
||||
}
|
||||
|
||||
int
|
||||
fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
|
||||
{
|
||||
@@ -227,7 +234,6 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
|
||||
u32 activate;
|
||||
struct fb_var_screeninfo old_var;
|
||||
struct fb_videomode mode;
|
||||
struct fb_event event;
|
||||
u32 unused;
|
||||
|
||||
if (var->activate & FB_ACTIVATE_INV_MODE) {
|
||||
@@ -331,14 +337,38 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
event.info = info;
|
||||
event.data = &mode;
|
||||
fb_notifier_call_chain(FB_EVENT_MODE_CHANGE, &event);
|
||||
fb_lcd_notify_mode_change(info, &mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fb_set_var);
|
||||
|
||||
static void fb_lcd_notify_blank(struct fb_info *info)
|
||||
{
|
||||
int power;
|
||||
|
||||
switch (info->blank) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
power = LCD_POWER_ON;
|
||||
break;
|
||||
/* deprecated; TODO: should become 'off' */
|
||||
case FB_BLANK_NORMAL:
|
||||
power = LCD_POWER_REDUCED;
|
||||
break;
|
||||
case FB_BLANK_VSYNC_SUSPEND:
|
||||
power = LCD_POWER_REDUCED_VSYNC_SUSPEND;
|
||||
break;
|
||||
/* 'off' */
|
||||
case FB_BLANK_HSYNC_SUSPEND:
|
||||
case FB_BLANK_POWERDOWN:
|
||||
default:
|
||||
power = LCD_POWER_OFF;
|
||||
break;
|
||||
}
|
||||
|
||||
lcd_notify_blank_all(info->device, power);
|
||||
}
|
||||
|
||||
int fb_blank(struct fb_info *info, int blank)
|
||||
{
|
||||
int old_blank = info->blank;
|
||||
@@ -364,6 +394,7 @@ int fb_blank(struct fb_info *info, int blank)
|
||||
goto err;
|
||||
|
||||
fb_bl_notify_blank(info, old_blank);
|
||||
fb_lcd_notify_blank(info);
|
||||
|
||||
fb_notifier_call_chain(FB_EVENT_BLANK, &event);
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#define LCD_POWER_ON (0)
|
||||
#define LCD_POWER_REDUCED (1) // deprecated; don't use in new code
|
||||
@@ -79,8 +78,11 @@ struct lcd_device {
|
||||
const struct lcd_ops *ops;
|
||||
/* Serialise access to set_power method */
|
||||
struct mutex update_lock;
|
||||
/* The framebuffer notifier block */
|
||||
struct notifier_block fb_notif;
|
||||
|
||||
/**
|
||||
* @entry: List entry of all registered lcd devices
|
||||
*/
|
||||
struct list_head entry;
|
||||
|
||||
struct device dev;
|
||||
};
|
||||
@@ -125,6 +127,19 @@ extern void lcd_device_unregister(struct lcd_device *ld);
|
||||
extern void devm_lcd_device_unregister(struct device *dev,
|
||||
struct lcd_device *ld);
|
||||
|
||||
#if IS_REACHABLE(CONFIG_LCD_CLASS_DEVICE)
|
||||
void lcd_notify_blank_all(struct device *display_dev, int power);
|
||||
void lcd_notify_mode_change_all(struct device *display_dev,
|
||||
unsigned int width, unsigned int height);
|
||||
#else
|
||||
static inline void lcd_notify_blank_all(struct device *display_dev, int power)
|
||||
{}
|
||||
|
||||
static inline void lcd_notify_mode_change_all(struct device *display_dev,
|
||||
unsigned int width, unsigned int height)
|
||||
{}
|
||||
#endif
|
||||
|
||||
#define to_lcd_device(obj) container_of(obj, struct lcd_device, dev)
|
||||
|
||||
static inline void * lcd_get_data(struct lcd_device *ld_dev)
|
||||
|
||||
Reference in New Issue
Block a user