Commit a8df7b1ab70bfd6f261fa5e96985fca638299acc

Authored by Fabio Baltieri
Committed by Bryan Wu
1 parent 5cce0105c8

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