Commit a8df7b1ab70bfd6f261fa5e96985fca638299acc
Committed by
Bryan Wu
1 parent
5cce0105c8
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
leds: add led_trigger_rename function
Implements a "led_trigger_rename" function to rename a trigger with proper locking. This assumes that led name was originally allocated in non-constant storage. Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com> Cc: Kurt Van Dijck <kurt.van.dijck@eia.be> Signed-off-by: Bryan Wu <cooloney@gmail.com>
Showing 2 changed files with 31 additions and 0 deletions Inline Diff
drivers/leds/led-triggers.c
1 | /* | 1 | /* |
2 | * LED Triggers Core | 2 | * LED Triggers Core |
3 | * | 3 | * |
4 | * Copyright 2005-2007 Openedhand Ltd. | 4 | * Copyright 2005-2007 Openedhand Ltd. |
5 | * | 5 | * |
6 | * Author: Richard Purdie <rpurdie@openedhand.com> | 6 | * Author: Richard Purdie <rpurdie@openedhand.com> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/list.h> | 17 | #include <linux/list.h> |
18 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
19 | #include <linux/device.h> | 19 | #include <linux/device.h> |
20 | #include <linux/timer.h> | 20 | #include <linux/timer.h> |
21 | #include <linux/rwsem.h> | 21 | #include <linux/rwsem.h> |
22 | #include <linux/leds.h> | 22 | #include <linux/leds.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include "leds.h" | 24 | #include "leds.h" |
25 | 25 | ||
26 | /* | 26 | /* |
27 | * Nests outside led_cdev->trigger_lock | 27 | * Nests outside led_cdev->trigger_lock |
28 | */ | 28 | */ |
29 | static DECLARE_RWSEM(triggers_list_lock); | 29 | static DECLARE_RWSEM(triggers_list_lock); |
30 | static LIST_HEAD(trigger_list); | 30 | static LIST_HEAD(trigger_list); |
31 | 31 | ||
32 | /* Used by LED Class */ | 32 | /* Used by LED Class */ |
33 | 33 | ||
34 | ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, | 34 | ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, |
35 | const char *buf, size_t count) | 35 | const char *buf, size_t count) |
36 | { | 36 | { |
37 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | 37 | struct led_classdev *led_cdev = dev_get_drvdata(dev); |
38 | char trigger_name[TRIG_NAME_MAX]; | 38 | char trigger_name[TRIG_NAME_MAX]; |
39 | struct led_trigger *trig; | 39 | struct led_trigger *trig; |
40 | size_t len; | 40 | size_t len; |
41 | 41 | ||
42 | trigger_name[sizeof(trigger_name) - 1] = '\0'; | 42 | trigger_name[sizeof(trigger_name) - 1] = '\0'; |
43 | strncpy(trigger_name, buf, sizeof(trigger_name) - 1); | 43 | strncpy(trigger_name, buf, sizeof(trigger_name) - 1); |
44 | len = strlen(trigger_name); | 44 | len = strlen(trigger_name); |
45 | 45 | ||
46 | if (len && trigger_name[len - 1] == '\n') | 46 | if (len && trigger_name[len - 1] == '\n') |
47 | trigger_name[len - 1] = '\0'; | 47 | trigger_name[len - 1] = '\0'; |
48 | 48 | ||
49 | if (!strcmp(trigger_name, "none")) { | 49 | if (!strcmp(trigger_name, "none")) { |
50 | led_trigger_remove(led_cdev); | 50 | led_trigger_remove(led_cdev); |
51 | return count; | 51 | return count; |
52 | } | 52 | } |
53 | 53 | ||
54 | down_read(&triggers_list_lock); | 54 | down_read(&triggers_list_lock); |
55 | list_for_each_entry(trig, &trigger_list, next_trig) { | 55 | list_for_each_entry(trig, &trigger_list, next_trig) { |
56 | if (!strcmp(trigger_name, trig->name)) { | 56 | if (!strcmp(trigger_name, trig->name)) { |
57 | down_write(&led_cdev->trigger_lock); | 57 | down_write(&led_cdev->trigger_lock); |
58 | led_trigger_set(led_cdev, trig); | 58 | led_trigger_set(led_cdev, trig); |
59 | up_write(&led_cdev->trigger_lock); | 59 | up_write(&led_cdev->trigger_lock); |
60 | 60 | ||
61 | up_read(&triggers_list_lock); | 61 | up_read(&triggers_list_lock); |
62 | return count; | 62 | return count; |
63 | } | 63 | } |
64 | } | 64 | } |
65 | up_read(&triggers_list_lock); | 65 | up_read(&triggers_list_lock); |
66 | 66 | ||
67 | return -EINVAL; | 67 | return -EINVAL; |
68 | } | 68 | } |
69 | EXPORT_SYMBOL_GPL(led_trigger_store); | 69 | EXPORT_SYMBOL_GPL(led_trigger_store); |
70 | 70 | ||
71 | ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, | 71 | ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, |
72 | char *buf) | 72 | char *buf) |
73 | { | 73 | { |
74 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | 74 | struct led_classdev *led_cdev = dev_get_drvdata(dev); |
75 | struct led_trigger *trig; | 75 | struct led_trigger *trig; |
76 | int len = 0; | 76 | int len = 0; |
77 | 77 | ||
78 | down_read(&triggers_list_lock); | 78 | down_read(&triggers_list_lock); |
79 | down_read(&led_cdev->trigger_lock); | 79 | down_read(&led_cdev->trigger_lock); |
80 | 80 | ||
81 | if (!led_cdev->trigger) | 81 | if (!led_cdev->trigger) |
82 | len += sprintf(buf+len, "[none] "); | 82 | len += sprintf(buf+len, "[none] "); |
83 | else | 83 | else |
84 | len += sprintf(buf+len, "none "); | 84 | len += sprintf(buf+len, "none "); |
85 | 85 | ||
86 | list_for_each_entry(trig, &trigger_list, next_trig) { | 86 | list_for_each_entry(trig, &trigger_list, next_trig) { |
87 | if (led_cdev->trigger && !strcmp(led_cdev->trigger->name, | 87 | if (led_cdev->trigger && !strcmp(led_cdev->trigger->name, |
88 | trig->name)) | 88 | trig->name)) |
89 | len += sprintf(buf+len, "[%s] ", trig->name); | 89 | len += sprintf(buf+len, "[%s] ", trig->name); |
90 | else | 90 | else |
91 | len += sprintf(buf+len, "%s ", trig->name); | 91 | len += sprintf(buf+len, "%s ", trig->name); |
92 | } | 92 | } |
93 | up_read(&led_cdev->trigger_lock); | 93 | up_read(&led_cdev->trigger_lock); |
94 | up_read(&triggers_list_lock); | 94 | up_read(&triggers_list_lock); |
95 | 95 | ||
96 | len += sprintf(len+buf, "\n"); | 96 | len += sprintf(len+buf, "\n"); |
97 | return len; | 97 | return len; |
98 | } | 98 | } |
99 | EXPORT_SYMBOL_GPL(led_trigger_show); | 99 | EXPORT_SYMBOL_GPL(led_trigger_show); |
100 | 100 | ||
101 | /* Caller must ensure led_cdev->trigger_lock held */ | 101 | /* Caller must ensure led_cdev->trigger_lock held */ |
102 | void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) | 102 | void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) |
103 | { | 103 | { |
104 | unsigned long flags; | 104 | unsigned long flags; |
105 | char *event = NULL; | 105 | char *event = NULL; |
106 | char *envp[2]; | 106 | char *envp[2]; |
107 | const char *name; | 107 | const char *name; |
108 | 108 | ||
109 | name = trig ? trig->name : "none"; | 109 | name = trig ? trig->name : "none"; |
110 | event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name); | 110 | event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name); |
111 | 111 | ||
112 | /* Remove any existing trigger */ | 112 | /* Remove any existing trigger */ |
113 | if (led_cdev->trigger) { | 113 | if (led_cdev->trigger) { |
114 | write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); | 114 | write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); |
115 | list_del(&led_cdev->trig_list); | 115 | list_del(&led_cdev->trig_list); |
116 | write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, | 116 | write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, |
117 | flags); | 117 | flags); |
118 | cancel_work_sync(&led_cdev->set_brightness_work); | 118 | cancel_work_sync(&led_cdev->set_brightness_work); |
119 | led_stop_software_blink(led_cdev); | 119 | led_stop_software_blink(led_cdev); |
120 | if (led_cdev->trigger->deactivate) | 120 | if (led_cdev->trigger->deactivate) |
121 | led_cdev->trigger->deactivate(led_cdev); | 121 | led_cdev->trigger->deactivate(led_cdev); |
122 | led_cdev->trigger = NULL; | 122 | led_cdev->trigger = NULL; |
123 | led_set_brightness(led_cdev, LED_OFF); | 123 | led_set_brightness(led_cdev, LED_OFF); |
124 | } | 124 | } |
125 | if (trig) { | 125 | if (trig) { |
126 | write_lock_irqsave(&trig->leddev_list_lock, flags); | 126 | write_lock_irqsave(&trig->leddev_list_lock, flags); |
127 | list_add_tail(&led_cdev->trig_list, &trig->led_cdevs); | 127 | list_add_tail(&led_cdev->trig_list, &trig->led_cdevs); |
128 | write_unlock_irqrestore(&trig->leddev_list_lock, flags); | 128 | write_unlock_irqrestore(&trig->leddev_list_lock, flags); |
129 | led_cdev->trigger = trig; | 129 | led_cdev->trigger = trig; |
130 | if (trig->activate) | 130 | if (trig->activate) |
131 | trig->activate(led_cdev); | 131 | trig->activate(led_cdev); |
132 | } | 132 | } |
133 | 133 | ||
134 | if (event) { | 134 | if (event) { |
135 | envp[0] = event; | 135 | envp[0] = event; |
136 | envp[1] = NULL; | 136 | envp[1] = NULL; |
137 | kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp); | 137 | kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp); |
138 | kfree(event); | 138 | kfree(event); |
139 | } | 139 | } |
140 | } | 140 | } |
141 | EXPORT_SYMBOL_GPL(led_trigger_set); | 141 | EXPORT_SYMBOL_GPL(led_trigger_set); |
142 | 142 | ||
143 | void led_trigger_remove(struct led_classdev *led_cdev) | 143 | void led_trigger_remove(struct led_classdev *led_cdev) |
144 | { | 144 | { |
145 | down_write(&led_cdev->trigger_lock); | 145 | down_write(&led_cdev->trigger_lock); |
146 | led_trigger_set(led_cdev, NULL); | 146 | led_trigger_set(led_cdev, NULL); |
147 | up_write(&led_cdev->trigger_lock); | 147 | up_write(&led_cdev->trigger_lock); |
148 | } | 148 | } |
149 | EXPORT_SYMBOL_GPL(led_trigger_remove); | 149 | EXPORT_SYMBOL_GPL(led_trigger_remove); |
150 | 150 | ||
151 | void led_trigger_set_default(struct led_classdev *led_cdev) | 151 | void led_trigger_set_default(struct led_classdev *led_cdev) |
152 | { | 152 | { |
153 | struct led_trigger *trig; | 153 | struct led_trigger *trig; |
154 | 154 | ||
155 | if (!led_cdev->default_trigger) | 155 | if (!led_cdev->default_trigger) |
156 | return; | 156 | return; |
157 | 157 | ||
158 | down_read(&triggers_list_lock); | 158 | down_read(&triggers_list_lock); |
159 | down_write(&led_cdev->trigger_lock); | 159 | down_write(&led_cdev->trigger_lock); |
160 | list_for_each_entry(trig, &trigger_list, next_trig) { | 160 | list_for_each_entry(trig, &trigger_list, next_trig) { |
161 | if (!strcmp(led_cdev->default_trigger, trig->name)) | 161 | if (!strcmp(led_cdev->default_trigger, trig->name)) |
162 | led_trigger_set(led_cdev, trig); | 162 | led_trigger_set(led_cdev, trig); |
163 | } | 163 | } |
164 | up_write(&led_cdev->trigger_lock); | 164 | up_write(&led_cdev->trigger_lock); |
165 | up_read(&triggers_list_lock); | 165 | up_read(&triggers_list_lock); |
166 | } | 166 | } |
167 | EXPORT_SYMBOL_GPL(led_trigger_set_default); | 167 | EXPORT_SYMBOL_GPL(led_trigger_set_default); |
168 | 168 | ||
169 | void led_trigger_rename_static(const char *name, struct led_trigger *trig) | ||
170 | { | ||
171 | /* new name must be on a temporary string to prevent races */ | ||
172 | BUG_ON(name == trig->name); | ||
173 | |||
174 | down_write(&triggers_list_lock); | ||
175 | /* this assumes that trig->name was originaly allocated to | ||
176 | * non constant storage */ | ||
177 | strcpy((char *)trig->name, name); | ||
178 | up_write(&triggers_list_lock); | ||
179 | } | ||
180 | EXPORT_SYMBOL_GPL(led_trigger_rename_static); | ||
181 | |||
169 | /* LED Trigger Interface */ | 182 | /* LED Trigger Interface */ |
170 | 183 | ||
171 | int led_trigger_register(struct led_trigger *trig) | 184 | int led_trigger_register(struct led_trigger *trig) |
172 | { | 185 | { |
173 | struct led_classdev *led_cdev; | 186 | struct led_classdev *led_cdev; |
174 | struct led_trigger *_trig; | 187 | struct led_trigger *_trig; |
175 | 188 | ||
176 | rwlock_init(&trig->leddev_list_lock); | 189 | rwlock_init(&trig->leddev_list_lock); |
177 | INIT_LIST_HEAD(&trig->led_cdevs); | 190 | INIT_LIST_HEAD(&trig->led_cdevs); |
178 | 191 | ||
179 | down_write(&triggers_list_lock); | 192 | down_write(&triggers_list_lock); |
180 | /* Make sure the trigger's name isn't already in use */ | 193 | /* Make sure the trigger's name isn't already in use */ |
181 | list_for_each_entry(_trig, &trigger_list, next_trig) { | 194 | list_for_each_entry(_trig, &trigger_list, next_trig) { |
182 | if (!strcmp(_trig->name, trig->name)) { | 195 | if (!strcmp(_trig->name, trig->name)) { |
183 | up_write(&triggers_list_lock); | 196 | up_write(&triggers_list_lock); |
184 | return -EEXIST; | 197 | return -EEXIST; |
185 | } | 198 | } |
186 | } | 199 | } |
187 | /* Add to the list of led triggers */ | 200 | /* Add to the list of led triggers */ |
188 | list_add_tail(&trig->next_trig, &trigger_list); | 201 | list_add_tail(&trig->next_trig, &trigger_list); |
189 | up_write(&triggers_list_lock); | 202 | up_write(&triggers_list_lock); |
190 | 203 | ||
191 | /* Register with any LEDs that have this as a default trigger */ | 204 | /* Register with any LEDs that have this as a default trigger */ |
192 | down_read(&leds_list_lock); | 205 | down_read(&leds_list_lock); |
193 | list_for_each_entry(led_cdev, &leds_list, node) { | 206 | list_for_each_entry(led_cdev, &leds_list, node) { |
194 | down_write(&led_cdev->trigger_lock); | 207 | down_write(&led_cdev->trigger_lock); |
195 | if (!led_cdev->trigger && led_cdev->default_trigger && | 208 | if (!led_cdev->trigger && led_cdev->default_trigger && |
196 | !strcmp(led_cdev->default_trigger, trig->name)) | 209 | !strcmp(led_cdev->default_trigger, trig->name)) |
197 | led_trigger_set(led_cdev, trig); | 210 | led_trigger_set(led_cdev, trig); |
198 | up_write(&led_cdev->trigger_lock); | 211 | up_write(&led_cdev->trigger_lock); |
199 | } | 212 | } |
200 | up_read(&leds_list_lock); | 213 | up_read(&leds_list_lock); |
201 | 214 | ||
202 | return 0; | 215 | return 0; |
203 | } | 216 | } |
204 | EXPORT_SYMBOL_GPL(led_trigger_register); | 217 | EXPORT_SYMBOL_GPL(led_trigger_register); |
205 | 218 | ||
206 | void led_trigger_unregister(struct led_trigger *trig) | 219 | void led_trigger_unregister(struct led_trigger *trig) |
207 | { | 220 | { |
208 | struct led_classdev *led_cdev; | 221 | struct led_classdev *led_cdev; |
209 | 222 | ||
210 | /* Remove from the list of led triggers */ | 223 | /* Remove from the list of led triggers */ |
211 | down_write(&triggers_list_lock); | 224 | down_write(&triggers_list_lock); |
212 | list_del(&trig->next_trig); | 225 | list_del(&trig->next_trig); |
213 | up_write(&triggers_list_lock); | 226 | up_write(&triggers_list_lock); |
214 | 227 | ||
215 | /* Remove anyone actively using this trigger */ | 228 | /* Remove anyone actively using this trigger */ |
216 | down_read(&leds_list_lock); | 229 | down_read(&leds_list_lock); |
217 | list_for_each_entry(led_cdev, &leds_list, node) { | 230 | list_for_each_entry(led_cdev, &leds_list, node) { |
218 | down_write(&led_cdev->trigger_lock); | 231 | down_write(&led_cdev->trigger_lock); |
219 | if (led_cdev->trigger == trig) | 232 | if (led_cdev->trigger == trig) |
220 | led_trigger_set(led_cdev, NULL); | 233 | led_trigger_set(led_cdev, NULL); |
221 | up_write(&led_cdev->trigger_lock); | 234 | up_write(&led_cdev->trigger_lock); |
222 | } | 235 | } |
223 | up_read(&leds_list_lock); | 236 | up_read(&leds_list_lock); |
224 | } | 237 | } |
225 | EXPORT_SYMBOL_GPL(led_trigger_unregister); | 238 | EXPORT_SYMBOL_GPL(led_trigger_unregister); |
226 | 239 | ||
227 | /* Simple LED Tigger Interface */ | 240 | /* Simple LED Tigger Interface */ |
228 | 241 | ||
229 | void led_trigger_event(struct led_trigger *trig, | 242 | void led_trigger_event(struct led_trigger *trig, |
230 | enum led_brightness brightness) | 243 | enum led_brightness brightness) |
231 | { | 244 | { |
232 | struct list_head *entry; | 245 | struct list_head *entry; |
233 | 246 | ||
234 | if (!trig) | 247 | if (!trig) |
235 | return; | 248 | return; |
236 | 249 | ||
237 | read_lock(&trig->leddev_list_lock); | 250 | read_lock(&trig->leddev_list_lock); |
238 | list_for_each(entry, &trig->led_cdevs) { | 251 | list_for_each(entry, &trig->led_cdevs) { |
239 | struct led_classdev *led_cdev; | 252 | struct led_classdev *led_cdev; |
240 | 253 | ||
241 | led_cdev = list_entry(entry, struct led_classdev, trig_list); | 254 | led_cdev = list_entry(entry, struct led_classdev, trig_list); |
242 | led_set_brightness(led_cdev, brightness); | 255 | led_set_brightness(led_cdev, brightness); |
243 | } | 256 | } |
244 | read_unlock(&trig->leddev_list_lock); | 257 | read_unlock(&trig->leddev_list_lock); |
245 | } | 258 | } |
246 | EXPORT_SYMBOL_GPL(led_trigger_event); | 259 | EXPORT_SYMBOL_GPL(led_trigger_event); |
247 | 260 | ||
248 | static void led_trigger_blink_setup(struct led_trigger *trig, | 261 | static void led_trigger_blink_setup(struct led_trigger *trig, |
249 | unsigned long *delay_on, | 262 | unsigned long *delay_on, |
250 | unsigned long *delay_off, | 263 | unsigned long *delay_off, |
251 | int oneshot, | 264 | int oneshot, |
252 | int invert) | 265 | int invert) |
253 | { | 266 | { |
254 | struct list_head *entry; | 267 | struct list_head *entry; |
255 | 268 | ||
256 | if (!trig) | 269 | if (!trig) |
257 | return; | 270 | return; |
258 | 271 | ||
259 | read_lock(&trig->leddev_list_lock); | 272 | read_lock(&trig->leddev_list_lock); |
260 | list_for_each(entry, &trig->led_cdevs) { | 273 | list_for_each(entry, &trig->led_cdevs) { |
261 | struct led_classdev *led_cdev; | 274 | struct led_classdev *led_cdev; |
262 | 275 | ||
263 | led_cdev = list_entry(entry, struct led_classdev, trig_list); | 276 | led_cdev = list_entry(entry, struct led_classdev, trig_list); |
264 | if (oneshot) | 277 | if (oneshot) |
265 | led_blink_set_oneshot(led_cdev, delay_on, delay_off, | 278 | led_blink_set_oneshot(led_cdev, delay_on, delay_off, |
266 | invert); | 279 | invert); |
267 | else | 280 | else |
268 | led_blink_set(led_cdev, delay_on, delay_off); | 281 | led_blink_set(led_cdev, delay_on, delay_off); |
269 | } | 282 | } |
270 | read_unlock(&trig->leddev_list_lock); | 283 | read_unlock(&trig->leddev_list_lock); |
271 | } | 284 | } |
272 | 285 | ||
273 | void led_trigger_blink(struct led_trigger *trig, | 286 | void led_trigger_blink(struct led_trigger *trig, |
274 | unsigned long *delay_on, | 287 | unsigned long *delay_on, |
275 | unsigned long *delay_off) | 288 | unsigned long *delay_off) |
276 | { | 289 | { |
277 | led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0); | 290 | led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0); |
278 | } | 291 | } |
279 | EXPORT_SYMBOL_GPL(led_trigger_blink); | 292 | EXPORT_SYMBOL_GPL(led_trigger_blink); |
280 | 293 | ||
281 | void led_trigger_blink_oneshot(struct led_trigger *trig, | 294 | void led_trigger_blink_oneshot(struct led_trigger *trig, |
282 | unsigned long *delay_on, | 295 | unsigned long *delay_on, |
283 | unsigned long *delay_off, | 296 | unsigned long *delay_off, |
284 | int invert) | 297 | int invert) |
285 | { | 298 | { |
286 | led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert); | 299 | led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert); |
287 | } | 300 | } |
288 | EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot); | 301 | EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot); |
289 | 302 | ||
290 | void led_trigger_register_simple(const char *name, struct led_trigger **tp) | 303 | void led_trigger_register_simple(const char *name, struct led_trigger **tp) |
291 | { | 304 | { |
292 | struct led_trigger *trig; | 305 | struct led_trigger *trig; |
293 | int err; | 306 | int err; |
294 | 307 | ||
295 | trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | 308 | trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); |
296 | 309 | ||
297 | if (trig) { | 310 | if (trig) { |
298 | trig->name = name; | 311 | trig->name = name; |
299 | err = led_trigger_register(trig); | 312 | err = led_trigger_register(trig); |
300 | if (err < 0) { | 313 | if (err < 0) { |
301 | kfree(trig); | 314 | kfree(trig); |
302 | trig = NULL; | 315 | trig = NULL; |
303 | printk(KERN_WARNING "LED trigger %s failed to register" | 316 | printk(KERN_WARNING "LED trigger %s failed to register" |
304 | " (%d)\n", name, err); | 317 | " (%d)\n", name, err); |
305 | } | 318 | } |
306 | } else | 319 | } else |
307 | printk(KERN_WARNING "LED trigger %s failed to register" | 320 | printk(KERN_WARNING "LED trigger %s failed to register" |
308 | " (no memory)\n", name); | 321 | " (no memory)\n", name); |
309 | 322 | ||
310 | *tp = trig; | 323 | *tp = trig; |
311 | } | 324 | } |
312 | EXPORT_SYMBOL_GPL(led_trigger_register_simple); | 325 | EXPORT_SYMBOL_GPL(led_trigger_register_simple); |
313 | 326 | ||
314 | void led_trigger_unregister_simple(struct led_trigger *trig) | 327 | void led_trigger_unregister_simple(struct led_trigger *trig) |
315 | { | 328 | { |
316 | if (trig) | 329 | if (trig) |
317 | led_trigger_unregister(trig); | 330 | led_trigger_unregister(trig); |
318 | kfree(trig); | 331 | kfree(trig); |
319 | } | 332 | } |
320 | EXPORT_SYMBOL_GPL(led_trigger_unregister_simple); | 333 | EXPORT_SYMBOL_GPL(led_trigger_unregister_simple); |
321 | 334 | ||
322 | MODULE_AUTHOR("Richard Purdie"); | 335 | MODULE_AUTHOR("Richard Purdie"); |
323 | MODULE_LICENSE("GPL"); | 336 | MODULE_LICENSE("GPL"); |
324 | MODULE_DESCRIPTION("LED Triggers Core"); | 337 | MODULE_DESCRIPTION("LED Triggers Core"); |
325 | 338 |
include/linux/leds.h
1 | /* | 1 | /* |
2 | * Driver model for leds and led triggers | 2 | * Driver model for leds and led triggers |
3 | * | 3 | * |
4 | * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu> | 4 | * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu> |
5 | * Copyright (C) 2005 Richard Purdie <rpurdie@openedhand.com> | 5 | * Copyright (C) 2005 Richard Purdie <rpurdie@openedhand.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 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 | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | #ifndef __LINUX_LEDS_H_INCLUDED | 12 | #ifndef __LINUX_LEDS_H_INCLUDED |
13 | #define __LINUX_LEDS_H_INCLUDED | 13 | #define __LINUX_LEDS_H_INCLUDED |
14 | 14 | ||
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
17 | #include <linux/rwsem.h> | 17 | #include <linux/rwsem.h> |
18 | #include <linux/timer.h> | 18 | #include <linux/timer.h> |
19 | #include <linux/workqueue.h> | 19 | #include <linux/workqueue.h> |
20 | 20 | ||
21 | struct device; | 21 | struct device; |
22 | /* | 22 | /* |
23 | * LED Core | 23 | * LED Core |
24 | */ | 24 | */ |
25 | 25 | ||
26 | enum led_brightness { | 26 | enum led_brightness { |
27 | LED_OFF = 0, | 27 | LED_OFF = 0, |
28 | LED_HALF = 127, | 28 | LED_HALF = 127, |
29 | LED_FULL = 255, | 29 | LED_FULL = 255, |
30 | }; | 30 | }; |
31 | 31 | ||
32 | struct led_classdev { | 32 | struct led_classdev { |
33 | const char *name; | 33 | const char *name; |
34 | int brightness; | 34 | int brightness; |
35 | int max_brightness; | 35 | int max_brightness; |
36 | int flags; | 36 | int flags; |
37 | 37 | ||
38 | /* Lower 16 bits reflect status */ | 38 | /* Lower 16 bits reflect status */ |
39 | #define LED_SUSPENDED (1 << 0) | 39 | #define LED_SUSPENDED (1 << 0) |
40 | /* Upper 16 bits reflect control information */ | 40 | /* Upper 16 bits reflect control information */ |
41 | #define LED_CORE_SUSPENDRESUME (1 << 16) | 41 | #define LED_CORE_SUSPENDRESUME (1 << 16) |
42 | #define LED_BLINK_ONESHOT (1 << 17) | 42 | #define LED_BLINK_ONESHOT (1 << 17) |
43 | #define LED_BLINK_ONESHOT_STOP (1 << 18) | 43 | #define LED_BLINK_ONESHOT_STOP (1 << 18) |
44 | #define LED_BLINK_INVERT (1 << 19) | 44 | #define LED_BLINK_INVERT (1 << 19) |
45 | 45 | ||
46 | /* Set LED brightness level */ | 46 | /* Set LED brightness level */ |
47 | /* Must not sleep, use a workqueue if needed */ | 47 | /* Must not sleep, use a workqueue if needed */ |
48 | void (*brightness_set)(struct led_classdev *led_cdev, | 48 | void (*brightness_set)(struct led_classdev *led_cdev, |
49 | enum led_brightness brightness); | 49 | enum led_brightness brightness); |
50 | /* Get LED brightness level */ | 50 | /* Get LED brightness level */ |
51 | enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); | 51 | enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); |
52 | 52 | ||
53 | /* | 53 | /* |
54 | * Activate hardware accelerated blink, delays are in milliseconds | 54 | * Activate hardware accelerated blink, delays are in milliseconds |
55 | * and if both are zero then a sensible default should be chosen. | 55 | * and if both are zero then a sensible default should be chosen. |
56 | * The call should adjust the timings in that case and if it can't | 56 | * The call should adjust the timings in that case and if it can't |
57 | * match the values specified exactly. | 57 | * match the values specified exactly. |
58 | * Deactivate blinking again when the brightness is set to a fixed | 58 | * Deactivate blinking again when the brightness is set to a fixed |
59 | * value via the brightness_set() callback. | 59 | * value via the brightness_set() callback. |
60 | */ | 60 | */ |
61 | int (*blink_set)(struct led_classdev *led_cdev, | 61 | int (*blink_set)(struct led_classdev *led_cdev, |
62 | unsigned long *delay_on, | 62 | unsigned long *delay_on, |
63 | unsigned long *delay_off); | 63 | unsigned long *delay_off); |
64 | 64 | ||
65 | struct device *dev; | 65 | struct device *dev; |
66 | struct list_head node; /* LED Device list */ | 66 | struct list_head node; /* LED Device list */ |
67 | const char *default_trigger; /* Trigger to use */ | 67 | const char *default_trigger; /* Trigger to use */ |
68 | 68 | ||
69 | unsigned long blink_delay_on, blink_delay_off; | 69 | unsigned long blink_delay_on, blink_delay_off; |
70 | struct timer_list blink_timer; | 70 | struct timer_list blink_timer; |
71 | int blink_brightness; | 71 | int blink_brightness; |
72 | 72 | ||
73 | struct work_struct set_brightness_work; | 73 | struct work_struct set_brightness_work; |
74 | int delayed_set_value; | 74 | int delayed_set_value; |
75 | 75 | ||
76 | #ifdef CONFIG_LEDS_TRIGGERS | 76 | #ifdef CONFIG_LEDS_TRIGGERS |
77 | /* Protects the trigger data below */ | 77 | /* Protects the trigger data below */ |
78 | struct rw_semaphore trigger_lock; | 78 | struct rw_semaphore trigger_lock; |
79 | 79 | ||
80 | struct led_trigger *trigger; | 80 | struct led_trigger *trigger; |
81 | struct list_head trig_list; | 81 | struct list_head trig_list; |
82 | void *trigger_data; | 82 | void *trigger_data; |
83 | /* true if activated - deactivate routine uses it to do cleanup */ | 83 | /* true if activated - deactivate routine uses it to do cleanup */ |
84 | bool activated; | 84 | bool activated; |
85 | #endif | 85 | #endif |
86 | }; | 86 | }; |
87 | 87 | ||
88 | extern int led_classdev_register(struct device *parent, | 88 | extern int led_classdev_register(struct device *parent, |
89 | struct led_classdev *led_cdev); | 89 | struct led_classdev *led_cdev); |
90 | extern void led_classdev_unregister(struct led_classdev *led_cdev); | 90 | extern void led_classdev_unregister(struct led_classdev *led_cdev); |
91 | extern void led_classdev_suspend(struct led_classdev *led_cdev); | 91 | extern void led_classdev_suspend(struct led_classdev *led_cdev); |
92 | extern void led_classdev_resume(struct led_classdev *led_cdev); | 92 | extern void led_classdev_resume(struct led_classdev *led_cdev); |
93 | 93 | ||
94 | /** | 94 | /** |
95 | * led_blink_set - set blinking with software fallback | 95 | * led_blink_set - set blinking with software fallback |
96 | * @led_cdev: the LED to start blinking | 96 | * @led_cdev: the LED to start blinking |
97 | * @delay_on: the time it should be on (in ms) | 97 | * @delay_on: the time it should be on (in ms) |
98 | * @delay_off: the time it should ble off (in ms) | 98 | * @delay_off: the time it should ble off (in ms) |
99 | * | 99 | * |
100 | * This function makes the LED blink, attempting to use the | 100 | * This function makes the LED blink, attempting to use the |
101 | * hardware acceleration if possible, but falling back to | 101 | * hardware acceleration if possible, but falling back to |
102 | * software blinking if there is no hardware blinking or if | 102 | * software blinking if there is no hardware blinking or if |
103 | * the LED refuses the passed values. | 103 | * the LED refuses the passed values. |
104 | * | 104 | * |
105 | * Note that if software blinking is active, simply calling | 105 | * Note that if software blinking is active, simply calling |
106 | * led_cdev->brightness_set() will not stop the blinking, | 106 | * led_cdev->brightness_set() will not stop the blinking, |
107 | * use led_classdev_brightness_set() instead. | 107 | * use led_classdev_brightness_set() instead. |
108 | */ | 108 | */ |
109 | extern void led_blink_set(struct led_classdev *led_cdev, | 109 | extern void led_blink_set(struct led_classdev *led_cdev, |
110 | unsigned long *delay_on, | 110 | unsigned long *delay_on, |
111 | unsigned long *delay_off); | 111 | unsigned long *delay_off); |
112 | /** | 112 | /** |
113 | * led_blink_set_oneshot - do a oneshot software blink | 113 | * led_blink_set_oneshot - do a oneshot software blink |
114 | * @led_cdev: the LED to start blinking | 114 | * @led_cdev: the LED to start blinking |
115 | * @delay_on: the time it should be on (in ms) | 115 | * @delay_on: the time it should be on (in ms) |
116 | * @delay_off: the time it should ble off (in ms) | 116 | * @delay_off: the time it should ble off (in ms) |
117 | * @invert: blink off, then on, leaving the led on | 117 | * @invert: blink off, then on, leaving the led on |
118 | * | 118 | * |
119 | * This function makes the LED blink one time for delay_on + | 119 | * This function makes the LED blink one time for delay_on + |
120 | * delay_off time, ignoring the request if another one-shot | 120 | * delay_off time, ignoring the request if another one-shot |
121 | * blink is already in progress. | 121 | * blink is already in progress. |
122 | * | 122 | * |
123 | * If invert is set, led blinks for delay_off first, then for | 123 | * If invert is set, led blinks for delay_off first, then for |
124 | * delay_on and leave the led on after the on-off cycle. | 124 | * delay_on and leave the led on after the on-off cycle. |
125 | */ | 125 | */ |
126 | extern void led_blink_set_oneshot(struct led_classdev *led_cdev, | 126 | extern void led_blink_set_oneshot(struct led_classdev *led_cdev, |
127 | unsigned long *delay_on, | 127 | unsigned long *delay_on, |
128 | unsigned long *delay_off, | 128 | unsigned long *delay_off, |
129 | int invert); | 129 | int invert); |
130 | /** | 130 | /** |
131 | * led_set_brightness - set LED brightness | 131 | * led_set_brightness - set LED brightness |
132 | * @led_cdev: the LED to set | 132 | * @led_cdev: the LED to set |
133 | * @brightness: the brightness to set it to | 133 | * @brightness: the brightness to set it to |
134 | * | 134 | * |
135 | * Set an LED's brightness, and, if necessary, cancel the | 135 | * Set an LED's brightness, and, if necessary, cancel the |
136 | * software blink timer that implements blinking when the | 136 | * software blink timer that implements blinking when the |
137 | * hardware doesn't. | 137 | * hardware doesn't. |
138 | */ | 138 | */ |
139 | extern void led_set_brightness(struct led_classdev *led_cdev, | 139 | extern void led_set_brightness(struct led_classdev *led_cdev, |
140 | enum led_brightness brightness); | 140 | enum led_brightness brightness); |
141 | 141 | ||
142 | /** | ||
143 | * led_trigger_rename_static - rename a trigger | ||
144 | * @name: the new trigger name | ||
145 | * @trig: the LED trigger to rename | ||
146 | * | ||
147 | * Change a LED trigger name by copying the string passed in | ||
148 | * name into current trigger name, which MUST be large | ||
149 | * enough for the new string. | ||
150 | * | ||
151 | * Note that name must NOT point to the same string used | ||
152 | * during LED registration, as that could lead to races. | ||
153 | * | ||
154 | * This is meant to be used on triggers with statically | ||
155 | * allocated name. | ||
156 | */ | ||
157 | extern void led_trigger_rename_static(const char *name, | ||
158 | struct led_trigger *trig); | ||
159 | |||
142 | /* | 160 | /* |
143 | * LED Triggers | 161 | * LED Triggers |
144 | */ | 162 | */ |
145 | #ifdef CONFIG_LEDS_TRIGGERS | 163 | #ifdef CONFIG_LEDS_TRIGGERS |
146 | 164 | ||
147 | #define TRIG_NAME_MAX 50 | 165 | #define TRIG_NAME_MAX 50 |
148 | 166 | ||
149 | struct led_trigger { | 167 | struct led_trigger { |
150 | /* Trigger Properties */ | 168 | /* Trigger Properties */ |
151 | const char *name; | 169 | const char *name; |
152 | void (*activate)(struct led_classdev *led_cdev); | 170 | void (*activate)(struct led_classdev *led_cdev); |
153 | void (*deactivate)(struct led_classdev *led_cdev); | 171 | void (*deactivate)(struct led_classdev *led_cdev); |
154 | 172 | ||
155 | /* LEDs under control by this trigger (for simple triggers) */ | 173 | /* LEDs under control by this trigger (for simple triggers) */ |
156 | rwlock_t leddev_list_lock; | 174 | rwlock_t leddev_list_lock; |
157 | struct list_head led_cdevs; | 175 | struct list_head led_cdevs; |
158 | 176 | ||
159 | /* Link to next registered trigger */ | 177 | /* Link to next registered trigger */ |
160 | struct list_head next_trig; | 178 | struct list_head next_trig; |
161 | }; | 179 | }; |
162 | 180 | ||
163 | /* Registration functions for complex triggers */ | 181 | /* Registration functions for complex triggers */ |
164 | extern int led_trigger_register(struct led_trigger *trigger); | 182 | extern int led_trigger_register(struct led_trigger *trigger); |
165 | extern void led_trigger_unregister(struct led_trigger *trigger); | 183 | extern void led_trigger_unregister(struct led_trigger *trigger); |
166 | 184 | ||
167 | /* Registration functions for simple triggers */ | 185 | /* Registration functions for simple triggers */ |
168 | #define DEFINE_LED_TRIGGER(x) static struct led_trigger *x; | 186 | #define DEFINE_LED_TRIGGER(x) static struct led_trigger *x; |
169 | #define DEFINE_LED_TRIGGER_GLOBAL(x) struct led_trigger *x; | 187 | #define DEFINE_LED_TRIGGER_GLOBAL(x) struct led_trigger *x; |
170 | extern void led_trigger_register_simple(const char *name, | 188 | extern void led_trigger_register_simple(const char *name, |
171 | struct led_trigger **trigger); | 189 | struct led_trigger **trigger); |
172 | extern void led_trigger_unregister_simple(struct led_trigger *trigger); | 190 | extern void led_trigger_unregister_simple(struct led_trigger *trigger); |
173 | extern void led_trigger_event(struct led_trigger *trigger, | 191 | extern void led_trigger_event(struct led_trigger *trigger, |
174 | enum led_brightness event); | 192 | enum led_brightness event); |
175 | extern void led_trigger_blink(struct led_trigger *trigger, | 193 | extern void led_trigger_blink(struct led_trigger *trigger, |
176 | unsigned long *delay_on, | 194 | unsigned long *delay_on, |
177 | unsigned long *delay_off); | 195 | unsigned long *delay_off); |
178 | extern void led_trigger_blink_oneshot(struct led_trigger *trigger, | 196 | extern void led_trigger_blink_oneshot(struct led_trigger *trigger, |
179 | unsigned long *delay_on, | 197 | unsigned long *delay_on, |
180 | unsigned long *delay_off, | 198 | unsigned long *delay_off, |
181 | int invert); | 199 | int invert); |
182 | 200 | ||
183 | #else | 201 | #else |
184 | 202 | ||
185 | /* Triggers aren't active - null macros */ | 203 | /* Triggers aren't active - null macros */ |
186 | #define DEFINE_LED_TRIGGER(x) | 204 | #define DEFINE_LED_TRIGGER(x) |
187 | #define DEFINE_LED_TRIGGER_GLOBAL(x) | 205 | #define DEFINE_LED_TRIGGER_GLOBAL(x) |
188 | #define led_trigger_register_simple(x, y) do {} while(0) | 206 | #define led_trigger_register_simple(x, y) do {} while(0) |
189 | #define led_trigger_unregister_simple(x) do {} while(0) | 207 | #define led_trigger_unregister_simple(x) do {} while(0) |
190 | #define led_trigger_event(x, y) do {} while(0) | 208 | #define led_trigger_event(x, y) do {} while(0) |
191 | 209 | ||
192 | #endif | 210 | #endif |
193 | 211 | ||
194 | /* Trigger specific functions */ | 212 | /* Trigger specific functions */ |
195 | #ifdef CONFIG_LEDS_TRIGGER_IDE_DISK | 213 | #ifdef CONFIG_LEDS_TRIGGER_IDE_DISK |
196 | extern void ledtrig_ide_activity(void); | 214 | extern void ledtrig_ide_activity(void); |
197 | #else | 215 | #else |
198 | #define ledtrig_ide_activity() do {} while(0) | 216 | #define ledtrig_ide_activity() do {} while(0) |
199 | #endif | 217 | #endif |
200 | 218 | ||
201 | /* | 219 | /* |
202 | * Generic LED platform data for describing LED names and default triggers. | 220 | * Generic LED platform data for describing LED names and default triggers. |
203 | */ | 221 | */ |
204 | struct led_info { | 222 | struct led_info { |
205 | const char *name; | 223 | const char *name; |
206 | const char *default_trigger; | 224 | const char *default_trigger; |
207 | int flags; | 225 | int flags; |
208 | }; | 226 | }; |
209 | 227 | ||
210 | struct led_platform_data { | 228 | struct led_platform_data { |
211 | int num_leds; | 229 | int num_leds; |
212 | struct led_info *leds; | 230 | struct led_info *leds; |
213 | }; | 231 | }; |
214 | 232 | ||
215 | /* For the leds-gpio driver */ | 233 | /* For the leds-gpio driver */ |
216 | struct gpio_led { | 234 | struct gpio_led { |
217 | const char *name; | 235 | const char *name; |
218 | const char *default_trigger; | 236 | const char *default_trigger; |
219 | unsigned gpio; | 237 | unsigned gpio; |
220 | unsigned active_low : 1; | 238 | unsigned active_low : 1; |
221 | unsigned retain_state_suspended : 1; | 239 | unsigned retain_state_suspended : 1; |
222 | unsigned default_state : 2; | 240 | unsigned default_state : 2; |
223 | /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */ | 241 | /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */ |
224 | }; | 242 | }; |
225 | #define LEDS_GPIO_DEFSTATE_OFF 0 | 243 | #define LEDS_GPIO_DEFSTATE_OFF 0 |
226 | #define LEDS_GPIO_DEFSTATE_ON 1 | 244 | #define LEDS_GPIO_DEFSTATE_ON 1 |
227 | #define LEDS_GPIO_DEFSTATE_KEEP 2 | 245 | #define LEDS_GPIO_DEFSTATE_KEEP 2 |
228 | 246 | ||
229 | struct gpio_led_platform_data { | 247 | struct gpio_led_platform_data { |
230 | int num_leds; | 248 | int num_leds; |
231 | const struct gpio_led *leds; | 249 | const struct gpio_led *leds; |
232 | 250 | ||
233 | #define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */ | 251 | #define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */ |
234 | #define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */ | 252 | #define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */ |
235 | #define GPIO_LED_BLINK 2 /* Please, blink */ | 253 | #define GPIO_LED_BLINK 2 /* Please, blink */ |
236 | int (*gpio_blink_set)(unsigned gpio, int state, | 254 | int (*gpio_blink_set)(unsigned gpio, int state, |
237 | unsigned long *delay_on, | 255 | unsigned long *delay_on, |
238 | unsigned long *delay_off); | 256 | unsigned long *delay_off); |
239 | }; | 257 | }; |
240 | 258 | ||
241 | struct platform_device *gpio_led_register_device( | 259 | struct platform_device *gpio_led_register_device( |
242 | int id, const struct gpio_led_platform_data *pdata); | 260 | int id, const struct gpio_led_platform_data *pdata); |
243 | 261 | ||
244 | enum cpu_led_event { | 262 | enum cpu_led_event { |
245 | CPU_LED_IDLE_START, /* CPU enters idle */ | 263 | CPU_LED_IDLE_START, /* CPU enters idle */ |
246 | CPU_LED_IDLE_END, /* CPU idle ends */ | 264 | CPU_LED_IDLE_END, /* CPU idle ends */ |
247 | CPU_LED_START, /* Machine starts, especially resume */ | 265 | CPU_LED_START, /* Machine starts, especially resume */ |
248 | CPU_LED_STOP, /* Machine stops, especially suspend */ | 266 | CPU_LED_STOP, /* Machine stops, especially suspend */ |
249 | CPU_LED_HALTED, /* Machine shutdown */ | 267 | CPU_LED_HALTED, /* Machine shutdown */ |
250 | }; | 268 | }; |
251 | #ifdef CONFIG_LEDS_TRIGGER_CPU | 269 | #ifdef CONFIG_LEDS_TRIGGER_CPU |
252 | extern void ledtrig_cpu(enum cpu_led_event evt); | 270 | extern void ledtrig_cpu(enum cpu_led_event evt); |
253 | #else | 271 | #else |
254 | static inline void ledtrig_cpu(enum cpu_led_event evt) | 272 | static inline void ledtrig_cpu(enum cpu_led_event evt) |
255 | { | 273 | { |
256 | return; | 274 | return; |
257 | } | 275 | } |
258 | #endif | 276 | #endif |
259 | 277 | ||
260 | #endif /* __LINUX_LEDS_H_INCLUDED */ | 278 | #endif /* __LINUX_LEDS_H_INCLUDED */ |
261 | 279 |