Root/drivers/leds/ledtrig-backlight.c

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

Archive Download this file



interactive