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