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 17 18 #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ 19 defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) 20 /* This callback gets called when something important happens inside a 21 * framebuffer driver. We're looking if that important event is blanking, 22 * and if it is, we're switching backlight power as well ... 23 */ 24 static int fb_notifier_callback(struct notifier_block *self, 25 unsigned long event, void *data) 26 { 27 struct backlight_device *bd; 28 struct fb_event *evdata = data; 29 30 /* If we aren't interested in this event, skip it immediately ... */ 31 if (event != FB_EVENT_BLANK) 32 return 0; 33 34 bd = container_of(self, struct backlight_device, fb_notif); 35 down(&bd->sem); 36 if (bd->props) 37 if (!bd->props->check_fb || 38 bd->props->check_fb(evdata->info)) { 39 bd->props->fb_blank = *(int *)evdata->data; 40 if (likely(bd->props && bd->props->update_status)) 41 bd->props->update_status(bd); 42 } 43 up(&bd->sem); 44 return 0; 45 } 46 47 static int backlight_register_fb(struct backlight_device *bd) 48 { 49 memset(&bd->fb_notif, 0, sizeof(bd->fb_notif)); 50 bd->fb_notif.notifier_call = fb_notifier_callback; 51 52 return fb_register_client(&bd->fb_notif); 53 } 54 55 static void backlight_unregister_fb(struct backlight_device *bd) 56 { 57 fb_unregister_client(&bd->fb_notif); 58 } 59 #else 60 static inline int backlight_register_fb(struct backlight_device *bd) 61 { 62 return 0; 63 } 64 65 static inline void backlight_unregister_fb(struct backlight_device *bd) 66 { 67 } 68 #endif /* CONFIG_FB */ 69 70 static ssize_t backlight_show_power(struct class_device *cdev, char *buf) 71 { 72 int rc = -ENXIO; 73 struct backlight_device *bd = to_backlight_device(cdev); 74 75 down(&bd->sem); 76 if (likely(bd->props)) 77 rc = sprintf(buf, "%d\n", bd->props->power); 78 up(&bd->sem); 79 80 return rc; 81 } 82 83 static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count) 84 { 85 int rc = -ENXIO; 86 char *endp; 87 struct backlight_device *bd = to_backlight_device(cdev); 88 int power = simple_strtoul(buf, &endp, 0); 89 size_t size = endp - buf; 90 91 if (*endp && isspace(*endp)) 92 size++; 93 if (size != count) 94 return -EINVAL; 95 96 down(&bd->sem); 97 if (likely(bd->props)) { 98 pr_debug("backlight: set power to %d\n", power); 99 bd->props->power = power; 100 if (likely(bd->props->update_status)) 101 bd->props->update_status(bd); 102 rc = count; 103 } 104 up(&bd->sem); 105 106 return rc; 107 } 108 109 static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf) 110 { 111 int rc = -ENXIO; 112 struct backlight_device *bd = to_backlight_device(cdev); 113 114 down(&bd->sem); 115 if (likely(bd->props)) 116 rc = sprintf(buf, "%d\n", bd->props->brightness); 117 up(&bd->sem); 118 119 return rc; 120 } 121 122 static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count) 123 { 124 int rc = -ENXIO; 125 char *endp; 126 struct backlight_device *bd = to_backlight_device(cdev); 127 int brightness = simple_strtoul(buf, &endp, 0); 128 size_t size = endp - buf; 129 130 if (*endp && isspace(*endp)) 131 size++; 132 if (size != count) 133 return -EINVAL; 134 135 down(&bd->sem); 136 if (likely(bd->props)) { 137 if (brightness > bd->props->max_brightness) 138 rc = -EINVAL; 139 else { 140 pr_debug("backlight: set brightness to %d\n", 141 brightness); 142 bd->props->brightness = brightness; 143 if (likely(bd->props->update_status)) 144 bd->props->update_status(bd); 145 rc = count; 146 } 147 } 148 up(&bd->sem); 149 150 return rc; 151 } 152 153 static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf) 154 { 155 int rc = -ENXIO; 156 struct backlight_device *bd = to_backlight_device(cdev); 157 158 down(&bd->sem); 159 if (likely(bd->props)) 160 rc = sprintf(buf, "%d\n", bd->props->max_brightness); 161 up(&bd->sem); 162 163 return rc; 164 } 165 166 static ssize_t backlight_show_actual_brightness(struct class_device *cdev, 167 char *buf) 168 { 169 int rc = -ENXIO; 170 struct backlight_device *bd = to_backlight_device(cdev); 171 172 down(&bd->sem); 173 if (likely(bd->props && bd->props->get_brightness)) 174 rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd)); 175 up(&bd->sem); 176 177 return rc; 178 } 179 180 static void backlight_class_release(struct class_device *dev) 181 { 182 struct backlight_device *bd = to_backlight_device(dev); 183 kfree(bd); 184 } 185 186 static struct class backlight_class = { 187 .name = "backlight", 188 .release = backlight_class_release, 189 }; 190 191 #define DECLARE_ATTR(_name,_mode,_show,_store) \ 192 { \ 193 .attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ 194 .show = _show, \ 195 .store = _store, \ 196 } 197 198 static const struct class_device_attribute bl_class_device_attributes[] = { 199 DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power), 200 DECLARE_ATTR(brightness, 0644, backlight_show_brightness, 201 backlight_store_brightness), 202 DECLARE_ATTR(actual_brightness, 0444, backlight_show_actual_brightness, 203 NULL), 204 DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL), 205 }; 206 207 /** 208 * backlight_device_register - create and register a new object of 209 * backlight_device class. 210 * @name: the name of the new object(must be the same as the name of the 211 * respective framebuffer device). 212 * @devdata: an optional pointer to be stored in the class_device. The 213 * methods may retrieve it by using class_get_devdata(&bd->class_dev). 214 * @bp: the backlight properties structure. 215 * 216 * Creates and registers new backlight class_device. Returns either an 217 * ERR_PTR() or a pointer to the newly allocated device. 218 */ 219 struct backlight_device *backlight_device_register(const char *name, 220 struct device *dev, 221 void *devdata, 222 struct backlight_properties *bp) 223 { 224 int i, rc; 225 struct backlight_device *new_bd; 226 227 pr_debug("backlight_device_alloc: name=%s\n", name); 228 229 new_bd = kmalloc(sizeof(struct backlight_device), GFP_KERNEL); 230 if (unlikely(!new_bd)) 231 return ERR_PTR(-ENOMEM); 232 233 init_MUTEX(&new_bd->sem); 234 new_bd->props = bp; 235 memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev)); 236 new_bd->class_dev.class = &backlight_class; 237 new_bd->class_dev.dev = dev; 238 strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN); 239 class_set_devdata(&new_bd->class_dev, devdata); 240 241 rc = class_device_register(&new_bd->class_dev); 242 if (unlikely(rc)) { 243 error: kfree(new_bd); 244 return ERR_PTR(rc); 245 } 246 247 rc = backlight_register_fb(new_bd); 248 if (unlikely(rc)) 249 goto error; 250 251 for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) { 252 rc = class_device_create_file(&new_bd->class_dev, 253 &bl_class_device_attributes[i]); 254 if (unlikely(rc)) { 255 while (--i >= 0) 256 class_device_remove_file(&new_bd->class_dev, 257 &bl_class_device_attributes[i]); 258 class_device_unregister(&new_bd->class_dev); 259 /* No need to kfree(new_bd) since release() method was called */ 260 return ERR_PTR(rc); 261 } 262 } 263 264 return new_bd; 265 } 266 EXPORT_SYMBOL(backlight_device_register); 267 268 /** 269 * backlight_device_unregister - unregisters a backlight device object. 270 * @bd: the backlight device object to be unregistered and freed. 271 * 272 * Unregisters a previously registered via backlight_device_register object. 273 */ 274 void backlight_device_unregister(struct backlight_device *bd) 275 { 276 int i; 277 278 if (!bd) 279 return; 280 281 pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id); 282 283 for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) 284 class_device_remove_file(&bd->class_dev, 285 &bl_class_device_attributes[i]); 286 287 down(&bd->sem); 288 bd->props = NULL; 289 up(&bd->sem); 290 291 backlight_unregister_fb(bd); 292 293 class_device_unregister(&bd->class_dev); 294 } 295 EXPORT_SYMBOL(backlight_device_unregister); 296 297 static void __exit backlight_class_exit(void) 298 { 299 class_unregister(&backlight_class); 300 } 301 302 static int __init backlight_class_init(void) 303 { 304 return class_register(&backlight_class); 305 } 306 307 /* 308 * if this is compiled into the kernel, we need to ensure that the 309 * class is registered before users of the class try to register lcd's 310 */ 311 postcore_initcall(backlight_class_init); 312 module_exit(backlight_class_exit); 313 314 MODULE_LICENSE("GPL"); 315 MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>"); 316 MODULE_DESCRIPTION("Backlight Lowlevel Control Abstraction"); 317