diff --git a/drivers/leds/trigger/ledtrig-backlight.c b/drivers/leds/trigger/ledtrig-backlight.c index 487577d22cfc..c1f0f5becaee 100644 --- a/drivers/leds/trigger/ledtrig-backlight.c +++ b/drivers/leds/trigger/ledtrig-backlight.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "../leds.h" @@ -21,29 +20,20 @@ struct bl_trig_notifier { struct led_classdev *led; int brightness; int old_status; - struct notifier_block notifier; unsigned invert; + + struct list_head entry; }; -static int fb_notifier_callback(struct notifier_block *p, - unsigned long event, void *data) +static DEFINE_MUTEX(ledtrig_backlight_list_mutex); +static LIST_HEAD(ledtrig_backlight_list); + +static void ledtrig_backlight_notify_blank(struct bl_trig_notifier *n, int new_status) { - struct bl_trig_notifier *n = container_of(p, - struct bl_trig_notifier, notifier); struct led_classdev *led = n->led; - struct fb_event *fb_event = data; - int *blank; - int new_status; - - /* If we aren't interested in this event, skip it immediately ... */ - if (event != FB_EVENT_BLANK) - return 0; - - blank = fb_event->data; - new_status = *blank ? BLANK : UNBLANK; if (new_status == n->old_status) - return 0; + return; if ((n->old_status == UNBLANK) ^ n->invert) { n->brightness = led->brightness; @@ -53,10 +43,20 @@ static int fb_notifier_callback(struct notifier_block *p, } n->old_status = new_status; - - return 0; } +void ledtrig_backlight_blank(bool blank) +{ + struct bl_trig_notifier *n; + int new_status = blank ? BLANK : UNBLANK; + + guard(mutex)(&ledtrig_backlight_list_mutex); + + list_for_each_entry(n, &ledtrig_backlight_list, entry) + ledtrig_backlight_notify_blank(n, new_status); +} +EXPORT_SYMBOL(ledtrig_backlight_blank); + static ssize_t bl_trig_invert_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -100,8 +100,6 @@ ATTRIBUTE_GROUPS(bl_trig); static int bl_trig_activate(struct led_classdev *led) { - int ret; - struct bl_trig_notifier *n; n = kzalloc(sizeof(struct bl_trig_notifier), GFP_KERNEL); @@ -112,11 +110,9 @@ static int bl_trig_activate(struct led_classdev *led) n->led = led; n->brightness = led->brightness; n->old_status = UNBLANK; - n->notifier.notifier_call = fb_notifier_callback; - ret = fb_register_client(&n->notifier); - if (ret) - dev_err(led->dev, "unable to register backlight trigger\n"); + guard(mutex)(&ledtrig_backlight_list_mutex); + list_add(&n->entry, &ledtrig_backlight_list); return 0; } @@ -125,7 +121,9 @@ static void bl_trig_deactivate(struct led_classdev *led) { struct bl_trig_notifier *n = led_get_trigger_data(led); - fb_unregister_client(&n->notifier); + guard(mutex)(&ledtrig_backlight_list_mutex); + list_del(&n->entry); + kfree(n); } diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index f699e5827ccb..9dc93c5e480b 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #ifdef CONFIG_PMAC_BACKLIGHT @@ -57,10 +56,10 @@ * a hot-key to adjust backlight, the driver must notify the backlight * core that brightness has changed using backlight_force_update(). * - * The backlight driver core receives notifications from fbdev and - * if the event is FB_EVENT_BLANK and if the value of blank, from the - * FBIOBLANK ioctrl, results in a change in the backlight state the - * update_status() operation is called. + * Display drives can control the backlight device's status using + * backlight_notify_blank() and backlight_notify_blank_all(). If this + * results in a change in the backlight state the functions call the + * update_status() operation. */ static struct list_head backlight_dev_list; @@ -78,85 +77,40 @@ static const char *const backlight_scale_types[] = { [BACKLIGHT_SCALE_NON_LINEAR] = "non-linear", }; -#if defined(CONFIG_FB_CORE) || (defined(CONFIG_FB_CORE_MODULE) && \ - defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) -/* - * fb_notifier_callback - * - * This callback gets called when something important happens inside a - * framebuffer driver. The backlight core only cares about FB_BLANK_UNBLANK - * which is reported to the driver using backlight_update_status() - * as a state change. - * - * There may be several fbdev's connected to the backlight device, - * in which case they are kept track of. A state change is only reported - * if there is a change in backlight for the specified fbdev. - */ -static int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data) +void backlight_notify_blank(struct backlight_device *bd, struct device *display_dev, + bool fb_on, bool prev_fb_on) { - struct backlight_device *bd; - struct fb_event *evdata = data; - struct fb_info *info = evdata->info; - struct backlight_device *fb_bd = fb_bl_device(info); - int node = info->node; - int fb_blank = 0; - - /* If we aren't interested in this event, skip it immediately ... */ - if (event != FB_EVENT_BLANK) - return 0; - - bd = container_of(self, struct backlight_device, fb_notif); - mutex_lock(&bd->ops_lock); + guard(mutex)(&bd->ops_lock); if (!bd->ops) - goto out; - if (bd->ops->controls_device && !bd->ops->controls_device(bd, info->device)) - goto out; - if (fb_bd && fb_bd != bd) - goto out; + return; + if (bd->ops->controls_device && !bd->ops->controls_device(bd, display_dev)) + return; - fb_blank = *(int *)evdata->data; - if (fb_blank == FB_BLANK_UNBLANK && !bd->fb_bl_on[node]) { - bd->fb_bl_on[node] = true; + if (fb_on && (!prev_fb_on || !bd->use_count)) { if (!bd->use_count++) { bd->props.state &= ~BL_CORE_FBBLANK; backlight_update_status(bd); } - } else if (fb_blank != FB_BLANK_UNBLANK && bd->fb_bl_on[node]) { - bd->fb_bl_on[node] = false; + } else if (!fb_on && prev_fb_on && bd->use_count) { if (!(--bd->use_count)) { bd->props.state |= BL_CORE_FBBLANK; backlight_update_status(bd); } } -out: - mutex_unlock(&bd->ops_lock); - return 0; } +EXPORT_SYMBOL(backlight_notify_blank); -static int backlight_register_fb(struct backlight_device *bd) +void backlight_notify_blank_all(struct device *display_dev, bool fb_on, bool prev_fb_on) { - memset(&bd->fb_notif, 0, sizeof(bd->fb_notif)); - bd->fb_notif.notifier_call = fb_notifier_callback; + struct backlight_device *bd; - return fb_register_client(&bd->fb_notif); -} + guard(mutex)(&backlight_dev_list_mutex); -static void backlight_unregister_fb(struct backlight_device *bd) -{ - fb_unregister_client(&bd->fb_notif); + list_for_each_entry(bd, &backlight_dev_list, entry) + backlight_notify_blank(bd, display_dev, fb_on, prev_fb_on); } -#else -static inline int backlight_register_fb(struct backlight_device *bd) -{ - return 0; -} - -static inline void backlight_unregister_fb(struct backlight_device *bd) -{ -} -#endif /* CONFIG_FB_CORE */ +EXPORT_SYMBOL(backlight_notify_blank_all); static void backlight_generate_event(struct backlight_device *bd, enum backlight_update_reason reason) @@ -447,12 +401,6 @@ struct backlight_device *backlight_device_register(const char *name, return ERR_PTR(rc); } - rc = backlight_register_fb(new_bd); - if (rc) { - device_unregister(&new_bd->dev); - return ERR_PTR(rc); - } - new_bd->ops = ops; #ifdef CONFIG_PMAC_BACKLIGHT @@ -539,7 +487,6 @@ void backlight_device_unregister(struct backlight_device *bd) bd->ops = NULL; mutex_unlock(&bd->ops_lock); - backlight_unregister_fb(bd); device_unregister(&bd->dev); } EXPORT_SYMBOL(backlight_device_unregister); diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 3267acf8dc5b..affe5c52471a 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -15,86 +15,59 @@ #include #include #include -#include #include -#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ - defined(CONFIG_LCD_CLASS_DEVICE_MODULE)) -static int to_lcd_power(int fb_blank) -{ - 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; - } -} +static DEFINE_MUTEX(lcd_dev_list_mutex); +static LIST_HEAD(lcd_dev_list); -/* 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) +static void lcd_notify_blank(struct lcd_device *ld, struct device *display_dev, + int power) { - 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); - guard(mutex)(&ld->ops_lock); - if (!ld->ops) - return 0; - if (ld->ops->controls_device && !ld->ops->controls_device(ld, info->device)) - return 0; - if (fb_lcd && fb_lcd != ld) - return 0; + if (!ld->ops || !ld->ops->set_power) + return; + if (ld->ops->controls_device && !ld->ops->controls_device(ld, display_dev)) + return; - if (event == FB_EVENT_BLANK) { - int power = to_lcd_power(*(int *)evdata->data); - - if (ld->ops->set_power) - ld->ops->set_power(ld, power); - } else { - const struct fb_videomode *videomode = evdata->data; - - if (ld->ops->set_mode) - ld->ops->set_mode(ld, videomode->xres, videomode->yres); - } - - return 0; + ld->ops->set_power(ld, power); } -static int lcd_register_fb(struct lcd_device *ld) +void lcd_notify_blank_all(struct device *display_dev, int power) { - memset(&ld->fb_notif, 0, sizeof(ld->fb_notif)); - ld->fb_notif.notifier_call = fb_notifier_callback; - return fb_register_client(&ld->fb_notif); + 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) +{ + guard(mutex)(&ld->ops_lock); + + if (!ld->ops || !ld->ops->set_mode) + return; + if (ld->ops->controls_device && !ld->ops->controls_device(ld, display_dev)) + return; + + ld->ops->set_mode(ld, width, height); } -static void lcd_unregister_fb(struct lcd_device *ld) +void lcd_notify_mode_change_all(struct device *display_dev, + unsigned int width, unsigned int height) { - fb_unregister_client(&ld->fb_notif); -} -#else -static int lcd_register_fb(struct lcd_device *ld) -{ - return 0; -} + struct lcd_device *ld; -static inline void lcd_unregister_fb(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); } -#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) @@ -245,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; } @@ -266,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); } diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 9afe701b2a1b..a63bb42c8f8b 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -1406,9 +1406,11 @@ static int wled_configure(struct wled *wled) wled->ctrl_addr = be32_to_cpu(*prop_addr); rc = of_property_read_string(dev->of_node, "label", &wled->name); - if (rc) + if (rc) { wled->name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node); - + if (!wled->name) + return -ENOMEM; + } switch (wled->version) { case 3: u32_opts = wled3_opts; diff --git a/drivers/video/fbdev/core/fb_backlight.c b/drivers/video/fbdev/core/fb_backlight.c index 6fdaa9f81be9..dbed9696f4c5 100644 --- a/drivers/video/fbdev/core/fb_backlight.c +++ b/drivers/video/fbdev/core/fb_backlight.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include #include @@ -36,4 +37,15 @@ struct backlight_device *fb_bl_device(struct fb_info *info) return info->bl_dev; } EXPORT_SYMBOL(fb_bl_device); + +void fb_bl_notify_blank(struct fb_info *info, int old_blank) +{ + bool on = info->blank == FB_BLANK_UNBLANK; + bool prev_on = old_blank == FB_BLANK_UNBLANK; + + if (info->bl_dev) + backlight_notify_blank(info->bl_dev, info->device, on, prev_on); + else + backlight_notify_blank_all(info->device, on, prev_on); +} #endif diff --git a/drivers/video/fbdev/core/fb_info.c b/drivers/video/fbdev/core/fb_info.c index 4847ebe50d7d..52f9bd2c5417 100644 --- a/drivers/video/fbdev/core/fb_info.c +++ b/drivers/video/fbdev/core/fb_info.c @@ -42,6 +42,7 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev) info->device = dev; info->fbcon_rotate_hint = -1; + info->blank = FB_BLANK_UNBLANK; #if IS_ENABLED(CONFIG_FB_BACKLIGHT) mutex_init(&info->bl_curve_mutex); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index eca2498f2436..dfcf5e4d1d4c 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include