linux/drivers/leds/ledtrig-backlight.c
<<
>>
Prefs
   1/*
   2 * Backlight emulation LED trigger
   3 *
   4 * Copyright 2008 (C) Rodolfo Giometti <giometti@linux.it>
   5 * Copyright 2008 (C) Eurotech S.p.A. <info@eurotech.it>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/slab.h>
  16#include <linux/init.h>
  17#include <linux/fb.h>
  18#include <linux/leds.h>
  19#include "leds.h"
  20
  21#define BLANK           1
  22#define UNBLANK         0
  23
  24struct bl_trig_notifier {
  25        struct led_classdev *led;
  26        int brightness;
  27        int old_status;
  28        struct notifier_block notifier;
  29        unsigned invert;
  30};
  31
  32static int fb_notifier_callback(struct notifier_block *p,
  33                                unsigned long event, void *data)
  34{
  35        struct bl_trig_notifier *n = container_of(p,
  36                                        struct bl_trig_notifier, notifier);
  37        struct led_classdev *led = n->led;
  38        struct fb_event *fb_event = data;
  39        int *blank = fb_event->data;
  40        int new_status = *blank ? BLANK : UNBLANK;
  41
  42        switch (event) {
  43        case FB_EVENT_BLANK:
  44                if (new_status == n->old_status)
  45                        break;
  46
  47                if ((n->old_status == UNBLANK) ^ n->invert) {
  48                        n->brightness = led->brightness;
  49                        __led_set_brightness(led, LED_OFF);
  50                } else {
  51                        __led_set_brightness(led, n->brightness);
  52                }
  53
  54                n->old_status = new_status;
  55
  56                break;
  57        }
  58
  59        return 0;
  60}
  61
  62static ssize_t bl_trig_invert_show(struct device *dev,
  63                struct device_attribute *attr, char *buf)
  64{
  65        struct led_classdev *led = dev_get_drvdata(dev);
  66        struct bl_trig_notifier *n = led->trigger_data;
  67
  68        return sprintf(buf, "%u\n", n->invert);
  69}
  70
  71static ssize_t bl_trig_invert_store(struct device *dev,
  72                struct device_attribute *attr, const char *buf, size_t num)
  73{
  74        struct led_classdev *led = dev_get_drvdata(dev);
  75        struct bl_trig_notifier *n = led->trigger_data;
  76        unsigned long invert;
  77        int ret;
  78
  79        ret = kstrtoul(buf, 10, &invert);
  80        if (ret < 0)
  81                return ret;
  82
  83        if (invert > 1)
  84                return -EINVAL;
  85
  86        n->invert = invert;
  87
  88        /* After inverting, we need to update the LED. */
  89        if ((n->old_status == BLANK) ^ n->invert)
  90                __led_set_brightness(led, LED_OFF);
  91        else
  92                __led_set_brightness(led, n->brightness);
  93
  94        return num;
  95}
  96static DEVICE_ATTR(inverted, 0644, bl_trig_invert_show, bl_trig_invert_store);
  97
  98static void bl_trig_activate(struct led_classdev *led)
  99{
 100        int ret;
 101
 102        struct bl_trig_notifier *n;
 103
 104        n = kzalloc(sizeof(struct bl_trig_notifier), GFP_KERNEL);
 105        led->trigger_data = n;
 106        if (!n) {
 107                dev_err(led->dev, "unable to allocate backlight trigger\n");
 108                return;
 109        }
 110
 111        ret = device_create_file(led->dev, &dev_attr_inverted);
 112        if (ret)
 113                goto err_invert;
 114
 115        n->led = led;
 116        n->brightness = led->brightness;
 117        n->old_status = UNBLANK;
 118        n->notifier.notifier_call = fb_notifier_callback;
 119
 120        ret = fb_register_client(&n->notifier);
 121        if (ret)
 122                dev_err(led->dev, "unable to register backlight trigger\n");
 123        led->activated = true;
 124
 125        return;
 126
 127err_invert:
 128        led->trigger_data = NULL;
 129        kfree(n);
 130}
 131
 132static void bl_trig_deactivate(struct led_classdev *led)
 133{
 134        struct bl_trig_notifier *n =
 135                (struct bl_trig_notifier *) led->trigger_data;
 136
 137        if (led->activated) {
 138                device_remove_file(led->dev, &dev_attr_inverted);
 139                fb_unregister_client(&n->notifier);
 140                kfree(n);
 141                led->activated = false;
 142        }
 143}
 144
 145static struct led_trigger bl_led_trigger = {
 146        .name           = "backlight",
 147        .activate       = bl_trig_activate,
 148        .deactivate     = bl_trig_deactivate
 149};
 150
 151static int __init bl_trig_init(void)
 152{
 153        return led_trigger_register(&bl_led_trigger);
 154}
 155
 156static void __exit bl_trig_exit(void)
 157{
 158        led_trigger_unregister(&bl_led_trigger);
 159}
 160
 161module_init(bl_trig_init);
 162module_exit(bl_trig_exit);
 163
 164MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
 165MODULE_DESCRIPTION("Backlight emulation LED trigger");
 166MODULE_LICENSE("GPL v2");
 167
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.