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