1 /* 2 * Backlight Lowlevel Control Abstraction 3 * 4 * Copyright (C) 2003,2004 Hewlett-Packard Company 5 * 6 */ 7 8 #include <linux/module.h> 9 #include <linux/init.h> 10 #include <linux/device.h> 11 #include <linux/backlight.h> 12 #include <linux/notifier.h> 13 #include <linux/ctype.h> 14 #include <linux/err.h> 15 #include <linux/fb.h> 16 #include <linux/slab.h> 17 18 #ifdef CONFIG_PMAC_BACKLIGHT 19 #include <asm/backlight.h> 20 #endif 21 22 #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ 23 defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) 24 /* This callback gets called when something important happens inside a 25 * framebuffer driver. We're looking if that important event is blanking, 26 * and if it is, we're switching backlight power as well ... 27 */ 28 static int fb_notifier_callback(struct notifier_block *self, 29 unsigned long event, void *data) 30 { 31 struct backlight_device *bd; 32 struct fb_event *evdata = data; 33 34 /* If we aren't interested in this event, skip it immediately ... */ 35 if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK) 36 return 0; 37 38 bd = container_of(self, struct backlight_device, fb_notif); 39 mutex_lock(&bd->ops_lock); 40 if (bd->ops) 41 if (!bd->ops->check_fb || 42 bd->ops->check_fb(bd, evdata->info)) { 43 bd->props.fb_blank = *(int *)evdata->data; 44 if (bd->props.fb_blank == FB_BLANK_UNBLANK) 45 bd->props.state &= ~BL_CORE_FBBLANK; 46 else 47 bd->props.state |= BL_CORE_FBBLANK; 48 backlight_update_status(bd); 49 } 50 mutex_unlock(&bd->ops_lock); 51 return 0; 52 } 53 54 static int backlight_register_fb(struct backlight_device *bd) 55 { 56 memset(&bd->fb_notif, 0, sizeof(bd->fb_notif)); 57 bd->fb_notif.notifier_call = fb_notifier_callback; 58 59 return fb_register_client(&bd->fb_notif); 60 } 61 62 static void backlight_unregister_fb(struct backlight_device *bd) 63 { 64 fb_unregister_client(&bd->fb_notif); 65 } 66 #else 67 static inline int backlight_register_fb(struct backlight_device *bd) 68 { 69 return 0; 70 } 71 72 static inline void backlight_unregister_fb(struct backlight_device *bd) 73 { 74 } 75 #endif /* CONFIG_FB */ 76 77 static void backlight_generate_event(struct backlight_device *bd, 78 enum backlight_update_reason reason) 79 { 80 char *envp[2]; 81 82 switch (reason) { 83 case BACKLIGHT_UPDATE_SYSFS: 84 envp[0] = "SOURCE=sysfs"; 85 break; 86 case BACKLIGHT_UPDATE_HOTKEY: 87 envp[0] = "SOURCE=hotkey"; 88 break; 89 default: 90 envp[0] = "SOURCE=unknown"; 91 break; 92 } 93 envp[1] = NULL; 94 kobject_uevent_env(&bd->dev.kobj, KOBJ_CHANGE, envp); 95 sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness"); 96 } 97 98 static ssize_t backlight_show_power(struct device *dev, 99 struct device_attribute *attr,char *buf) 100 { 101 struct backlight_device *bd = to_backlight_device(dev); 102 103 return sprintf(buf, "%d\n", bd->props.power); 104 } 105 106 static ssize_t backlight_store_power(struct device *dev, 107 struct device_attribute *attr, const char *buf, size_t count) 108 { 109 int rc; 110 struct backlight_device *bd = to_backlight_device(dev); 111 unsigned long power; 112 113 rc = strict_strtoul(buf, 0, &power); 114 if (rc) 115 return rc; 116 117 rc = -ENXIO; 118 mutex_lock(&bd->ops_lock); 119 if (bd->ops) { 120 pr_debug("backlight: set power to %lu\n", power); 121 if (bd->props.power != power) { 122 bd->props.power = power; 123 backlight_update_status(bd); 124 } 125 rc = count; 126 } 127 mutex_unlock(&bd->ops_lock); 128 129 return rc; 130 } 131 132 static ssize_t backlight_show_brightness(struct device *dev, 133 struct device_attribute *attr, char *buf) 134 { 135 struct backlight_device *bd = to_backlight_device(dev); 136 137 return sprintf(buf, "%d\n", bd->props.brightness); 138 } 139 140 static ssize_t backlight_store_brightness(struct device *dev, 141 struct device_attribute *attr, const char *buf, size_t count) 142 { 143 int rc; 144 struct backlight_device *bd = to_backlight_device(dev); 145 unsigned long brightness; 146 147 rc = strict_strtoul(buf, 0, &brightness); 148 if (rc) 149 return rc; 150 151 rc = -ENXIO; 152 153 mutex_lock(&bd->ops_lock); 154 if (bd->ops) { 155 if (brightness > bd->props.max_brightness) 156 rc = -EINVAL; 157 else { 158 pr_debug("backlight: set brightness to %lu\n", 159 brightness); 160 bd->props.brightness = brightness; 161 backlight_update_status(bd); 162 rc = count; 163 } 164 } 165 mutex_unlock(&bd->ops_lock); 166 167 backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS); 168 169 return rc; 170 } 171 172 static ssize_t backlight_show_max_brightness(struct device *dev, 173 struct device_attribute *attr, char *buf) 174 { 175 struct backlight_device *bd = to_backlight_device(dev); 176 177 return sprintf(buf, "%d\n", bd->props.max_brightness); 178 } 179 180 static ssize_t backlight_show_actual_brightness(struct device *dev, 181 struct device_attribute *attr, char *buf) 182 { 183 int rc = -ENXIO; 184 struct backlight_device *bd = to_backlight_device(dev); 185 186 mutex_lock(&bd->ops_lock); 187 if (bd->ops && bd->ops->get_brightness) 188 rc = sprintf(buf, "%d\n", bd->ops->get_brightness(bd)); 189 mutex_unlock(&bd->ops_lock); 190 191 return rc; 192 } 193 194 static struct class *backlight_class; 195 196 static int backlight_suspend(struct device *dev, pm_message_t state) 197 { 198 struct backlight_device *bd = to_backlight_device(dev); 199 200 mutex_lock(&bd->ops_lock); 201 if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) { 202 bd->props.state |= BL_CORE_SUSPENDED; 203 backlight_update_status(bd); 204 } 205 mutex_unlock(&bd->ops_lock); 206 207 return 0; 208 } 209 210 static int backlight_resume(struct device *dev) 211 { 212 struct backlight_device *bd = to_backlight_device(dev); 213 214 mutex_lock(&bd->ops_lock); 215 if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) { 216 bd->props.state &= ~BL_CORE_SUSPENDED; 217 backlight_update_status(bd); 218 } 219 mutex_unlock(&bd->ops_lock); 220 221 return 0; 222 } 223 224 static void bl_device_release(struct device *dev) 225 { 226 struct backlight_device *bd = to_backlight_device(dev); 227 kfree(bd); 228 } 229 230 static struct device_attribute bl_device_attributes[] = { 231 __ATTR(bl_power, 0644, backlight_show_power, backlight_store_power), 232 __ATTR(brightness, 0644, backlight_show_brightness, 233 backlight_store_brightness), 234 __ATTR(actual_brightness, 0444, backlight_show_actual_brightness, 235 NULL), 236 __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL), 237 __ATTR_NULL, 238 }; 239 240 /** 241 * backlight_force_update - tell the backlight subsystem that hardware state 242 * has changed 243 * @bd: the backlight device to update 244 * 245 * Updates the internal state of the backlight in response to a hardware event, 246 * and generate a uevent to notify userspace 247 */ 248 void backlight_force_update(struct backlight_device *bd, 249 enum backlight_update_reason reason) 250 { 251 mutex_lock(&bd->ops_lock); 252 if (bd->ops && bd->ops->get_brightness) 253 bd->props.brightness = bd->ops->get_brightness(bd); 254 mutex_unlock(&bd->ops_lock); 255 backlight_generate_event(bd, reason); 256 } 257 EXPORT_SYMBOL(backlight_force_update); 258 259 /** 260 * backlight_device_register - create and register a new object of 261 * backlight_device class. 262 * @name: the name of the new object(must be the same as the name of the 263 * respective framebuffer device). 264 * @parent: a pointer to the parent device 265 * @devdata: an optional pointer to be stored for private driver use. The 266 * methods may retrieve it by using bl_get_data(bd). 267 * @ops: the backlight operations structure. 268 * 269 * Creates and registers new backlight device. Returns either an 270 * ERR_PTR() or a pointer to the newly allocated device. 271 */ 272 struct backlight_device *backlight_device_register(const char *name, 273 struct device *parent, void *devdata, const struct backlight_ops *ops, 274 const struct backlight_properties *props) 275 { 276 struct backlight_device *new_bd; 277 int rc; 278 279 pr_debug("backlight_device_register: name=%s\n", name); 280 281 new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL); 282 if (!new_bd) 283 return ERR_PTR(-ENOMEM); 284 285 mutex_init(&new_bd->update_lock); 286 mutex_init(&new_bd->ops_lock); 287 288 new_bd->dev.class = backlight_class; 289 new_bd->dev.parent = parent; 290 new_bd->dev.release = bl_device_release; 291 dev_set_name(&new_bd->dev, name); 292 dev_set_drvdata(&new_bd->dev, devdata); 293 294 /* Set default properties */ 295 if (props) 296 memcpy(&new_bd->props, props, 297 sizeof(struct backlight_properties)); 298 299 rc = device_register(&new_bd->dev); 300 if (rc) { 301 kfree(new_bd); 302 return ERR_PTR(rc); 303 } 304 305 rc = backlight_register_fb(new_bd); 306 if (rc) { 307 device_unregister(&new_bd->dev); 308 return ERR_PTR(rc); 309 } 310 311 new_bd->ops = ops; 312 313 #ifdef CONFIG_PMAC_BACKLIGHT 314 mutex_lock(&pmac_backlight_mutex); 315 if (!pmac_backlight) 316 pmac_backlight = new_bd; 317 mutex_unlock(&pmac_backlight_mutex); 318 #endif 319 320 return new_bd; 321 } 322 EXPORT_SYMBOL(backlight_device_register); 323 324 /** 325 * backlight_device_unregister - unregisters a backlight device object. 326 * @bd: the backlight device object to be unregistered and freed. 327 * 328 * Unregisters a previously registered via backlight_device_register object. 329 */ 330 void backlight_device_unregister(struct backlight_device *bd) 331 { 332 if (!bd) 333 return; 334 335 #ifdef CONFIG_PMAC_BACKLIGHT 336 mutex_lock(&pmac_backlight_mutex); 337 if (pmac_backlight == bd) 338 pmac_backlight = NULL; 339 mutex_unlock(&pmac_backlight_mutex); 340 #endif 341 mutex_lock(&bd->ops_lock); 342 bd->ops = NULL; 343 mutex_unlock(&bd->ops_lock); 344 345 backlight_unregister_fb(bd); 346 device_unregister(&bd->dev); 347 } 348 EXPORT_SYMBOL(backlight_device_unregister); 349 350 static void __exit backlight_class_exit(void) 351 { 352 class_destroy(backlight_class); 353 } 354 355 static int __init backlight_class_init(void) 356 { 357 backlight_class = class_create(THIS_MODULE, "backlight"); 358 if (IS_ERR(backlight_class)) { 359 printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n", 360 PTR_ERR(backlight_class)); 361 return PTR_ERR(backlight_class); 362 } 363 364 backlight_class->dev_attrs = bl_device_attributes; 365 backlight_class->suspend = backlight_suspend; 366 backlight_class->resume = backlight_resume; 367 return 0; 368 } 369 370 /* 371 * if this is compiled into the kernel, we need to ensure that the 372 * class is registered before users of the class try to register lcd's 373 */ 374 postcore_initcall(backlight_class_init); 375 module_exit(backlight_class_exit); 376 377 MODULE_LICENSE("GPL"); 378 MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>"); 379 MODULE_DESCRIPTION("Backlight Lowlevel Control Abstraction"); 380