diff options
Diffstat (limited to 'drivers/leds/ledtrig-backlight.c')
-rw-r--r-- | drivers/leds/ledtrig-backlight.c | 61 |
1 files changed, 57 insertions, 4 deletions
diff --git a/drivers/leds/ledtrig-backlight.c b/drivers/leds/ledtrig-backlight.c index f948e57bd9b8..2b513a2ad7de 100644 --- a/drivers/leds/ledtrig-backlight.c +++ b/drivers/leds/ledtrig-backlight.c | |||
@@ -26,6 +26,7 @@ struct bl_trig_notifier { | |||
26 | int brightness; | 26 | int brightness; |
27 | int old_status; | 27 | int old_status; |
28 | struct notifier_block notifier; | 28 | struct notifier_block notifier; |
29 | unsigned invert; | ||
29 | }; | 30 | }; |
30 | 31 | ||
31 | static int fb_notifier_callback(struct notifier_block *p, | 32 | static int fb_notifier_callback(struct notifier_block *p, |
@@ -36,23 +37,64 @@ static int fb_notifier_callback(struct notifier_block *p, | |||
36 | struct led_classdev *led = n->led; | 37 | struct led_classdev *led = n->led; |
37 | struct fb_event *fb_event = data; | 38 | struct fb_event *fb_event = data; |
38 | int *blank = fb_event->data; | 39 | int *blank = fb_event->data; |
40 | int new_status = *blank ? BLANK : UNBLANK; | ||
39 | 41 | ||
40 | switch (event) { | 42 | switch (event) { |
41 | case FB_EVENT_BLANK : | 43 | case FB_EVENT_BLANK : |
42 | if (*blank && n->old_status == UNBLANK) { | 44 | if (new_status == n->old_status) |
45 | break; | ||
46 | |||
47 | if ((n->old_status == UNBLANK) ^ n->invert) { | ||
43 | n->brightness = led->brightness; | 48 | n->brightness = led->brightness; |
44 | led_set_brightness(led, LED_OFF); | 49 | led_set_brightness(led, LED_OFF); |
45 | n->old_status = BLANK; | 50 | } else { |
46 | } else if (!*blank && n->old_status == BLANK) { | ||
47 | led_set_brightness(led, n->brightness); | 51 | led_set_brightness(led, n->brightness); |
48 | n->old_status = UNBLANK; | ||
49 | } | 52 | } |
53 | |||
54 | n->old_status = new_status; | ||
55 | |||
50 | break; | 56 | break; |
51 | } | 57 | } |
52 | 58 | ||
53 | return 0; | 59 | return 0; |
54 | } | 60 | } |
55 | 61 | ||
62 | static 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 | |||
71 | static 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 = strict_strtoul(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 | } | ||
96 | static DEVICE_ATTR(inverted, 0644, bl_trig_invert_show, bl_trig_invert_store); | ||
97 | |||
56 | static void bl_trig_activate(struct led_classdev *led) | 98 | static void bl_trig_activate(struct led_classdev *led) |
57 | { | 99 | { |
58 | int ret; | 100 | int ret; |
@@ -66,6 +108,10 @@ static void bl_trig_activate(struct led_classdev *led) | |||
66 | return; | 108 | return; |
67 | } | 109 | } |
68 | 110 | ||
111 | ret = device_create_file(led->dev, &dev_attr_inverted); | ||
112 | if (ret) | ||
113 | goto err_invert; | ||
114 | |||
69 | n->led = led; | 115 | n->led = led; |
70 | n->brightness = led->brightness; | 116 | n->brightness = led->brightness; |
71 | n->old_status = UNBLANK; | 117 | n->old_status = UNBLANK; |
@@ -74,6 +120,12 @@ static void bl_trig_activate(struct led_classdev *led) | |||
74 | ret = fb_register_client(&n->notifier); | 120 | ret = fb_register_client(&n->notifier); |
75 | if (ret) | 121 | if (ret) |
76 | dev_err(led->dev, "unable to register backlight trigger\n"); | 122 | dev_err(led->dev, "unable to register backlight trigger\n"); |
123 | |||
124 | return; | ||
125 | |||
126 | err_invert: | ||
127 | led->trigger_data = NULL; | ||
128 | kfree(n); | ||
77 | } | 129 | } |
78 | 130 | ||
79 | static void bl_trig_deactivate(struct led_classdev *led) | 131 | static void bl_trig_deactivate(struct led_classdev *led) |
@@ -82,6 +134,7 @@ static void bl_trig_deactivate(struct led_classdev *led) | |||
82 | (struct bl_trig_notifier *) led->trigger_data; | 134 | (struct bl_trig_notifier *) led->trigger_data; |
83 | 135 | ||
84 | if (n) { | 136 | if (n) { |
137 | device_remove_file(led->dev, &dev_attr_inverted); | ||
85 | fb_unregister_client(&n->notifier); | 138 | fb_unregister_client(&n->notifier); |
86 | kfree(n); | 139 | kfree(n); |
87 | } | 140 | } |