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

[PATCH] backlight: Backlight Class Improvements

Backlight class attributes are currently easy to implement incorrectly.
Moving certain handling into the backlight core prevents this whilst at the
same time makes the drivers simpler and consistent. The following changes are
included:

The brightness attribute only sets and reads the brightness variable in the
backlight_properties structure.

The power attribute only sets and reads the power variable in the
backlight_properties structure.

Any framebuffer blanking events change a variable fb_blank in the
backlight_properties structure.

The backlight driver has only two functions to implement. One function is
called when any of the above properties change (to update the backlight
brightness), the second is called to return the current backlight brightness
value. A new attribute "actual_brightness" is added to return this brightness
as determined by the driver having combined all the above factors (and any
driver/device specific factors).

Additionally, the backlight core takes care of checking the maximum brightness
is not exceeded and of turning off the backlight before device removal.

The corgi backlight driver is updated to reflect these changes.

Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Richard Purdie and committed by
Linus Torvalds
6ca01765 9b0e1c5d

+110 -104
+56 -28
drivers/video/backlight/backlight.c
··· 16 16 17 17 static ssize_t backlight_show_power(struct class_device *cdev, char *buf) 18 18 { 19 - int rc; 19 + int rc = -ENXIO; 20 20 struct backlight_device *bd = to_backlight_device(cdev); 21 21 22 22 down(&bd->sem); 23 - if (likely(bd->props && bd->props->get_power)) 24 - rc = sprintf(buf, "%d\n", bd->props->get_power(bd)); 25 - else 26 - rc = -ENXIO; 23 + if (likely(bd->props)) 24 + rc = sprintf(buf, "%d\n", bd->props->power); 27 25 up(&bd->sem); 28 26 29 27 return rc; ··· 29 31 30 32 static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count) 31 33 { 32 - int rc, power; 34 + int rc = -ENXIO, power; 33 35 char *endp; 34 36 struct backlight_device *bd = to_backlight_device(cdev); 35 37 ··· 38 40 return -EINVAL; 39 41 40 42 down(&bd->sem); 41 - if (likely(bd->props && bd->props->set_power)) { 43 + if (likely(bd->props)) { 42 44 pr_debug("backlight: set power to %d\n", power); 43 - bd->props->set_power(bd, power); 45 + bd->props->power = power; 46 + if (likely(bd->props->update_status)) 47 + bd->props->update_status(bd); 44 48 rc = count; 45 - } else 46 - rc = -ENXIO; 49 + } 47 50 up(&bd->sem); 48 51 49 52 return rc; ··· 52 53 53 54 static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf) 54 55 { 55 - int rc; 56 + int rc = -ENXIO; 56 57 struct backlight_device *bd = to_backlight_device(cdev); 57 58 58 59 down(&bd->sem); 59 - if (likely(bd->props && bd->props->get_brightness)) 60 - rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd)); 61 - else 62 - rc = -ENXIO; 60 + if (likely(bd->props)) 61 + rc = sprintf(buf, "%d\n", bd->props->brightness); 63 62 up(&bd->sem); 64 63 65 64 return rc; ··· 65 68 66 69 static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count) 67 70 { 68 - int rc, brightness; 71 + int rc = -ENXIO, brightness; 69 72 char *endp; 70 73 struct backlight_device *bd = to_backlight_device(cdev); 71 74 ··· 74 77 return -EINVAL; 75 78 76 79 down(&bd->sem); 77 - if (likely(bd->props && bd->props->set_brightness)) { 78 - pr_debug("backlight: set brightness to %d\n", brightness); 79 - bd->props->set_brightness(bd, brightness); 80 - rc = count; 81 - } else 82 - rc = -ENXIO; 80 + if (likely(bd->props)) { 81 + if (brightness > bd->props->max_brightness) 82 + rc = -EINVAL; 83 + else { 84 + pr_debug("backlight: set brightness to %d\n", 85 + brightness); 86 + bd->props->brightness = brightness; 87 + if (likely(bd->props->update_status)) 88 + bd->props->update_status(bd); 89 + rc = count; 90 + } 91 + } 83 92 up(&bd->sem); 84 93 85 94 return rc; ··· 93 90 94 91 static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf) 95 92 { 96 - int rc; 93 + int rc = -ENXIO; 97 94 struct backlight_device *bd = to_backlight_device(cdev); 98 95 99 96 down(&bd->sem); 100 97 if (likely(bd->props)) 101 98 rc = sprintf(buf, "%d\n", bd->props->max_brightness); 102 - else 103 - rc = -ENXIO; 99 + up(&bd->sem); 100 + 101 + return rc; 102 + } 103 + 104 + static ssize_t backlight_show_actual_brightness(struct class_device *cdev, 105 + char *buf) 106 + { 107 + int rc = -ENXIO; 108 + struct backlight_device *bd = to_backlight_device(cdev); 109 + 110 + down(&bd->sem); 111 + if (likely(bd->props && bd->props->get_brightness)) 112 + rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd)); 104 113 up(&bd->sem); 105 114 106 115 return rc; ··· 138 123 139 124 static struct class_device_attribute bl_class_device_attributes[] = { 140 125 DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power), 141 - DECLARE_ATTR(brightness, 0644, backlight_show_brightness, backlight_store_brightness), 126 + DECLARE_ATTR(brightness, 0644, backlight_show_brightness, 127 + backlight_store_brightness), 128 + DECLARE_ATTR(actual_brightness, 0444, backlight_show_actual_brightness, 129 + NULL), 142 130 DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL), 143 131 }; 144 132 ··· 162 144 bd = container_of(self, struct backlight_device, fb_notif); 163 145 down(&bd->sem); 164 146 if (bd->props) 165 - if (!bd->props->check_fb || bd->props->check_fb(evdata->info)) 166 - bd->props->set_power(bd, *(int *)evdata->data); 147 + if (!bd->props->check_fb || 148 + bd->props->check_fb(evdata->info)) { 149 + bd->props->fb_blank = *(int *)evdata->data; 150 + if (likely(bd->props && bd->props->update_status)) 151 + bd->props->update_status(bd); 152 + } 167 153 up(&bd->sem); 168 154 return 0; 169 155 } ··· 253 231 &bl_class_device_attributes[i]); 254 232 255 233 down(&bd->sem); 234 + if (likely(bd->props && bd->props->update_status)) { 235 + bd->props->brightness = 0; 236 + bd->props->power = 0; 237 + bd->props->update_status(bd); 238 + } 239 + 256 240 bd->props = NULL; 257 241 up(&bd->sem); 258 242
+39 -66
drivers/video/backlight/corgi_bl.c
··· 25 25 #define CORGI_DEFAULT_INTENSITY 0x1f 26 26 #define CORGI_LIMIT_MASK 0x0b 27 27 28 - static int corgibl_powermode = FB_BLANK_UNBLANK; 29 - static int current_intensity = 0; 30 - static int corgibl_limit = 0; 28 + static int corgibl_intensity; 31 29 static void (*corgibl_mach_set_intensity)(int intensity); 32 30 static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED; 33 31 static struct backlight_properties corgibl_data; 32 + static struct backlight_device *corgi_backlight_device; 34 33 35 - static void corgibl_send_intensity(int intensity) 34 + static unsigned long corgibl_flags; 35 + #define CORGIBL_SUSPENDED 0x01 36 + #define CORGIBL_BATTLOW 0x02 37 + 38 + static int corgibl_send_intensity(struct backlight_device *bd) 36 39 { 37 40 unsigned long flags; 38 41 void (*corgi_kick_batt)(void); 42 + int intensity = bd->props->brightness; 39 43 40 - if (corgibl_powermode != FB_BLANK_UNBLANK) { 44 + if (bd->props->power != FB_BLANK_UNBLANK) 41 45 intensity = 0; 42 - } else { 43 - if (corgibl_limit) 44 - intensity &= CORGI_LIMIT_MASK; 45 - } 46 + if (bd->props->fb_blank != FB_BLANK_UNBLANK) 47 + intensity = 0; 48 + if (corgibl_flags & CORGIBL_SUSPENDED) 49 + intensity = 0; 50 + if (corgibl_flags & CORGIBL_BATTLOW) 51 + intensity &= CORGI_LIMIT_MASK; 46 52 47 53 spin_lock_irqsave(&bl_lock, flags); 48 54 ··· 56 50 57 51 spin_unlock_irqrestore(&bl_lock, flags); 58 52 53 + corgibl_intensity = intensity; 54 + 59 55 corgi_kick_batt = symbol_get(sharpsl_battery_kick); 60 56 if (corgi_kick_batt) { 61 57 corgi_kick_batt(); 62 58 symbol_put(sharpsl_battery_kick); 63 59 } 64 - } 65 60 66 - static void corgibl_blank(int blank) 67 - { 68 - switch(blank) { 69 - 70 - case FB_BLANK_NORMAL: 71 - case FB_BLANK_VSYNC_SUSPEND: 72 - case FB_BLANK_HSYNC_SUSPEND: 73 - case FB_BLANK_POWERDOWN: 74 - if (corgibl_powermode == FB_BLANK_UNBLANK) { 75 - corgibl_send_intensity(0); 76 - corgibl_powermode = blank; 77 - } 78 - break; 79 - case FB_BLANK_UNBLANK: 80 - if (corgibl_powermode != FB_BLANK_UNBLANK) { 81 - corgibl_powermode = blank; 82 - corgibl_send_intensity(current_intensity); 83 - } 84 - break; 85 - } 61 + return 0; 86 62 } 87 63 88 64 #ifdef CONFIG_PM 89 65 static int corgibl_suspend(struct platform_device *dev, pm_message_t state) 90 66 { 91 - corgibl_blank(FB_BLANK_POWERDOWN); 67 + corgibl_flags |= CORGIBL_SUSPENDED; 68 + corgibl_send_intensity(corgi_backlight_device); 92 69 return 0; 93 70 } 94 71 95 72 static int corgibl_resume(struct platform_device *dev) 96 73 { 97 - corgibl_blank(FB_BLANK_UNBLANK); 74 + corgibl_flags &= ~CORGIBL_SUSPENDED; 75 + corgibl_send_intensity(corgi_backlight_device); 98 76 return 0; 99 77 } 100 78 #else ··· 86 96 #define corgibl_resume NULL 87 97 #endif 88 98 89 - 90 - static int corgibl_set_power(struct backlight_device *bd, int state) 91 - { 92 - corgibl_blank(state); 93 - return 0; 94 - } 95 - 96 - static int corgibl_get_power(struct backlight_device *bd) 97 - { 98 - return corgibl_powermode; 99 - } 100 - 101 - static int corgibl_set_intensity(struct backlight_device *bd, int intensity) 102 - { 103 - if (intensity > corgibl_data.max_brightness) 104 - intensity = corgibl_data.max_brightness; 105 - corgibl_send_intensity(intensity); 106 - current_intensity=intensity; 107 - return 0; 108 - } 109 - 110 99 static int corgibl_get_intensity(struct backlight_device *bd) 111 100 { 112 - return current_intensity; 101 + return corgibl_intensity; 102 + } 103 + 104 + static int corgibl_set_intensity(struct backlight_device *bd) 105 + { 106 + corgibl_send_intensity(corgi_backlight_device); 107 + return 0; 113 108 } 114 109 115 110 /* ··· 103 128 */ 104 129 void corgibl_limit_intensity(int limit) 105 130 { 106 - corgibl_limit = (limit ? 1 : 0); 107 - corgibl_send_intensity(current_intensity); 131 + if (limit) 132 + corgibl_flags |= CORGIBL_BATTLOW; 133 + else 134 + corgibl_flags &= ~CORGIBL_BATTLOW; 135 + corgibl_send_intensity(corgi_backlight_device); 108 136 } 109 137 EXPORT_SYMBOL(corgibl_limit_intensity); 110 138 111 139 112 140 static struct backlight_properties corgibl_data = { 113 - .owner = THIS_MODULE, 114 - .get_power = corgibl_get_power, 115 - .set_power = corgibl_set_power, 141 + .owner = THIS_MODULE, 116 142 .get_brightness = corgibl_get_intensity, 117 - .set_brightness = corgibl_set_intensity, 143 + .update_status = corgibl_set_intensity, 118 144 }; 119 - 120 - static struct backlight_device *corgi_backlight_device; 121 145 122 146 static int __init corgibl_probe(struct platform_device *pdev) 123 147 { ··· 130 156 if (IS_ERR (corgi_backlight_device)) 131 157 return PTR_ERR (corgi_backlight_device); 132 158 133 - corgibl_set_intensity(NULL, CORGI_DEFAULT_INTENSITY); 134 - corgibl_limit_intensity(0); 159 + corgibl_data.power = FB_BLANK_UNBLANK; 160 + corgibl_data.brightness = CORGI_DEFAULT_INTENSITY; 161 + corgibl_send_intensity(corgi_backlight_device); 135 162 136 163 printk("Corgi Backlight Driver Initialized.\n"); 137 164 return 0; ··· 141 166 static int corgibl_remove(struct platform_device *dev) 142 167 { 143 168 backlight_device_unregister(corgi_backlight_device); 144 - 145 - corgibl_set_intensity(NULL, 0); 146 169 147 170 printk("Corgi Backlight Driver Unloaded\n"); 148 171 return 0;
+15 -10
include/linux/backlight.h
··· 19 19 struct backlight_properties { 20 20 /* Owner module */ 21 21 struct module *owner; 22 - /* Get the backlight power status (0: full on, 1..3: power saving 23 - modes; 4: full off), see FB_BLANK_XXX */ 24 - int (*get_power)(struct backlight_device *); 25 - /* Enable or disable power to the LCD (0: on; 4: off, see FB_BLANK_XXX) */ 26 - int (*set_power)(struct backlight_device *, int power); 27 - /* Maximal value for brightness (read-only) */ 28 - int max_brightness; 29 - /* Get current backlight brightness */ 22 + 23 + /* Notify the backlight driver some property has changed */ 24 + int (*update_status)(struct backlight_device *); 25 + /* Return the current backlight brightness (accounting for power, 26 + fb_blank etc.) */ 30 27 int (*get_brightness)(struct backlight_device *); 31 - /* Set backlight brightness (0..max_brightness) */ 32 - int (*set_brightness)(struct backlight_device *, int brightness); 33 28 /* Check if given framebuffer device is the one bound to this backlight; 34 29 return 0 if not, !=0 if it is. If NULL, backlight always matches the fb. */ 35 30 int (*check_fb)(struct fb_info *); 31 + 32 + /* Current User requested brightness (0 - max_brightness) */ 33 + int brightness; 34 + /* Maximal value for brightness (read-only) */ 35 + int max_brightness; 36 + /* Current FB Power mode (0: full on, 1..3: power saving 37 + modes; 4: full off), see FB_BLANK_XXX */ 38 + int power; 39 + /* FB Blanking active? (values as for power) */ 40 + int fb_blank; 36 41 }; 37 42 38 43 struct backlight_device {