123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- /*
- * Backlight Lowlevel Control Abstraction
- *
- * Copyright (C) 2003,2004 Hewlett-Packard Company
- *
- */
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/device.h>
- #include <linux/backlight.h>
- #include <linux/notifier.h>
- #include <linux/ctype.h>
- #include <linux/err.h>
- #include <linux/fb.h>
- static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
- {
- int rc = -ENXIO;
- struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props))
- rc = sprintf(buf, "%d\n", bd->props->power);
- up(&bd->sem);
- return rc;
- }
- static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
- {
- int rc = -ENXIO, power;
- char *endp;
- struct backlight_device *bd = to_backlight_device(cdev);
- power = simple_strtoul(buf, &endp, 0);
- if (*endp && !isspace(*endp))
- return -EINVAL;
- down(&bd->sem);
- if (likely(bd->props)) {
- pr_debug("backlight: set power to %d\n", power);
- bd->props->power = power;
- if (likely(bd->props->update_status))
- bd->props->update_status(bd);
- rc = count;
- }
- up(&bd->sem);
- return rc;
- }
- static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
- {
- int rc = -ENXIO;
- struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props))
- rc = sprintf(buf, "%d\n", bd->props->brightness);
- up(&bd->sem);
- return rc;
- }
- static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
- {
- int rc = -ENXIO, brightness;
- char *endp;
- struct backlight_device *bd = to_backlight_device(cdev);
- brightness = simple_strtoul(buf, &endp, 0);
- if (*endp && !isspace(*endp))
- return -EINVAL;
- down(&bd->sem);
- if (likely(bd->props)) {
- if (brightness > bd->props->max_brightness)
- rc = -EINVAL;
- else {
- pr_debug("backlight: set brightness to %d\n",
- brightness);
- bd->props->brightness = brightness;
- if (likely(bd->props->update_status))
- bd->props->update_status(bd);
- rc = count;
- }
- }
- up(&bd->sem);
- return rc;
- }
- static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
- {
- int rc = -ENXIO;
- struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props))
- rc = sprintf(buf, "%d\n", bd->props->max_brightness);
- up(&bd->sem);
- return rc;
- }
- static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
- char *buf)
- {
- int rc = -ENXIO;
- struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props && bd->props->get_brightness))
- rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd));
- up(&bd->sem);
- return rc;
- }
- static void backlight_class_release(struct class_device *dev)
- {
- struct backlight_device *bd = to_backlight_device(dev);
- kfree(bd);
- }
- static struct class backlight_class = {
- .name = "backlight",
- .release = backlight_class_release,
- };
- #define DECLARE_ATTR(_name,_mode,_show,_store) \
- { \
- .attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
- .show = _show, \
- .store = _store, \
- }
- static struct class_device_attribute bl_class_device_attributes[] = {
- DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power),
- DECLARE_ATTR(brightness, 0644, backlight_show_brightness,
- backlight_store_brightness),
- DECLARE_ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
- NULL),
- DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
- };
- /* This callback gets called when something important happens inside a
- * framebuffer driver. We're looking if that important event is blanking,
- * and if it is, we're switching backlight power as well ...
- */
- static int fb_notifier_callback(struct notifier_block *self,
- unsigned long event, void *data)
- {
- struct backlight_device *bd;
- struct fb_event *evdata =(struct fb_event *)data;
- /* If we aren't interested in this event, skip it immediately ... */
- if (event != FB_EVENT_BLANK)
- return 0;
- bd = container_of(self, struct backlight_device, fb_notif);
- down(&bd->sem);
- if (bd->props)
- if (!bd->props->check_fb ||
- bd->props->check_fb(evdata->info)) {
- bd->props->fb_blank = *(int *)evdata->data;
- if (likely(bd->props && bd->props->update_status))
- bd->props->update_status(bd);
- }
- up(&bd->sem);
- return 0;
- }
- /**
- * backlight_device_register - create and register a new object of
- * backlight_device class.
- * @name: the name of the new object(must be the same as the name of the
- * respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- * methods may retrieve it by using class_get_devdata(&bd->class_dev).
- * @bp: the backlight properties structure.
- *
- * Creates and registers new backlight class_device. Returns either an
- * ERR_PTR() or a pointer to the newly allocated device.
- */
- struct backlight_device *backlight_device_register(const char *name, void *devdata,
- struct backlight_properties *bp)
- {
- int i, rc;
- struct backlight_device *new_bd;
- pr_debug("backlight_device_alloc: name=%s\n", name);
- new_bd = kmalloc(sizeof(struct backlight_device), GFP_KERNEL);
- if (unlikely(!new_bd))
- return ERR_PTR(-ENOMEM);
- init_MUTEX(&new_bd->sem);
- new_bd->props = bp;
- memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev));
- new_bd->class_dev.class = &backlight_class;
- strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
- class_set_devdata(&new_bd->class_dev, devdata);
- rc = class_device_register(&new_bd->class_dev);
- if (unlikely(rc)) {
- error: kfree(new_bd);
- return ERR_PTR(rc);
- }
- memset(&new_bd->fb_notif, 0, sizeof(new_bd->fb_notif));
- new_bd->fb_notif.notifier_call = fb_notifier_callback;
- rc = fb_register_client(&new_bd->fb_notif);
- if (unlikely(rc))
- goto error;
- for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) {
- rc = class_device_create_file(&new_bd->class_dev,
- &bl_class_device_attributes[i]);
- if (unlikely(rc)) {
- while (--i >= 0)
- class_device_remove_file(&new_bd->class_dev,
- &bl_class_device_attributes[i]);
- class_device_unregister(&new_bd->class_dev);
- /* No need to kfree(new_bd) since release() method was called */
- return ERR_PTR(rc);
- }
- }
- return new_bd;
- }
- EXPORT_SYMBOL(backlight_device_register);
- /**
- * backlight_device_unregister - unregisters a backlight device object.
- * @bd: the backlight device object to be unregistered and freed.
- *
- * Unregisters a previously registered via backlight_device_register object.
- */
- void backlight_device_unregister(struct backlight_device *bd)
- {
- int i;
- if (!bd)
- return;
- pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id);
- for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++)
- class_device_remove_file(&bd->class_dev,
- &bl_class_device_attributes[i]);
- down(&bd->sem);
- if (likely(bd->props && bd->props->update_status)) {
- bd->props->brightness = 0;
- bd->props->power = 0;
- bd->props->update_status(bd);
- }
- bd->props = NULL;
- up(&bd->sem);
- fb_unregister_client(&bd->fb_notif);
- class_device_unregister(&bd->class_dev);
- }
- EXPORT_SYMBOL(backlight_device_unregister);
- static void __exit backlight_class_exit(void)
- {
- class_unregister(&backlight_class);
- }
- static int __init backlight_class_init(void)
- {
- return class_register(&backlight_class);
- }
- /*
- * if this is compiled into the kernel, we need to ensure that the
- * class is registered before users of the class try to register lcd's
- */
- postcore_initcall(backlight_class_init);
- module_exit(backlight_class_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>");
- MODULE_DESCRIPTION("Backlight Lowlevel Control Abstraction");
|