Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
led-triggers.c
Go to the documentation of this file.
1 /*
2  * LED Triggers Core
3  *
4  * Copyright 2005-2007 Openedhand Ltd.
5  *
6  * Author: Richard Purdie <[email protected]>
7  *
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
10  * published by the Free Software Foundation.
11  *
12  */
13 
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/list.h>
18 #include <linux/spinlock.h>
19 #include <linux/device.h>
20 #include <linux/timer.h>
21 #include <linux/rwsem.h>
22 #include <linux/leds.h>
23 #include <linux/slab.h>
24 #include "leds.h"
25 
26 /*
27  * Nests outside led_cdev->trigger_lock
28  */
29 static DECLARE_RWSEM(triggers_list_lock);
30 static LIST_HEAD(trigger_list);
31 
32  /* Used by LED Class */
33 
35  const char *buf, size_t count)
36 {
37  struct led_classdev *led_cdev = dev_get_drvdata(dev);
38  char trigger_name[TRIG_NAME_MAX];
39  struct led_trigger *trig;
40  size_t len;
41 
42  trigger_name[sizeof(trigger_name) - 1] = '\0';
43  strncpy(trigger_name, buf, sizeof(trigger_name) - 1);
44  len = strlen(trigger_name);
45 
46  if (len && trigger_name[len - 1] == '\n')
47  trigger_name[len - 1] = '\0';
48 
49  if (!strcmp(trigger_name, "none")) {
50  led_trigger_remove(led_cdev);
51  return count;
52  }
53 
54  down_read(&triggers_list_lock);
55  list_for_each_entry(trig, &trigger_list, next_trig) {
56  if (!strcmp(trigger_name, trig->name)) {
57  down_write(&led_cdev->trigger_lock);
58  led_trigger_set(led_cdev, trig);
59  up_write(&led_cdev->trigger_lock);
60 
61  up_read(&triggers_list_lock);
62  return count;
63  }
64  }
65  up_read(&triggers_list_lock);
66 
67  return -EINVAL;
68 }
70 
72  char *buf)
73 {
74  struct led_classdev *led_cdev = dev_get_drvdata(dev);
75  struct led_trigger *trig;
76  int len = 0;
77 
78  down_read(&triggers_list_lock);
79  down_read(&led_cdev->trigger_lock);
80 
81  if (!led_cdev->trigger)
82  len += sprintf(buf+len, "[none] ");
83  else
84  len += sprintf(buf+len, "none ");
85 
86  list_for_each_entry(trig, &trigger_list, next_trig) {
87  if (led_cdev->trigger && !strcmp(led_cdev->trigger->name,
88  trig->name))
89  len += sprintf(buf+len, "[%s] ", trig->name);
90  else
91  len += sprintf(buf+len, "%s ", trig->name);
92  }
93  up_read(&led_cdev->trigger_lock);
94  up_read(&triggers_list_lock);
95 
96  len += sprintf(len+buf, "\n");
97  return len;
98 }
100 
101 /* Caller must ensure led_cdev->trigger_lock held */
102 void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
103 {
104  unsigned long flags;
105  char *event = NULL;
106  char *envp[2];
107  const char *name;
108 
109  name = trig ? trig->name : "none";
110  event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
111 
112  /* Remove any existing trigger */
113  if (led_cdev->trigger) {
114  write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
115  list_del(&led_cdev->trig_list);
116  write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
117  flags);
119  led_stop_software_blink(led_cdev);
120  if (led_cdev->trigger->deactivate)
121  led_cdev->trigger->deactivate(led_cdev);
122  led_cdev->trigger = NULL;
123  led_set_brightness(led_cdev, LED_OFF);
124  }
125  if (trig) {
126  write_lock_irqsave(&trig->leddev_list_lock, flags);
127  list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
128  write_unlock_irqrestore(&trig->leddev_list_lock, flags);
129  led_cdev->trigger = trig;
130  if (trig->activate)
131  trig->activate(led_cdev);
132  }
133 
134  if (event) {
135  envp[0] = event;
136  envp[1] = NULL;
137  kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp);
138  kfree(event);
139  }
140 }
142 
143 void led_trigger_remove(struct led_classdev *led_cdev)
144 {
145  down_write(&led_cdev->trigger_lock);
146  led_trigger_set(led_cdev, NULL);
147  up_write(&led_cdev->trigger_lock);
148 }
150 
151 void led_trigger_set_default(struct led_classdev *led_cdev)
152 {
153  struct led_trigger *trig;
154 
155  if (!led_cdev->default_trigger)
156  return;
157 
158  down_read(&triggers_list_lock);
159  down_write(&led_cdev->trigger_lock);
160  list_for_each_entry(trig, &trigger_list, next_trig) {
161  if (!strcmp(led_cdev->default_trigger, trig->name))
162  led_trigger_set(led_cdev, trig);
163  }
164  up_write(&led_cdev->trigger_lock);
165  up_read(&triggers_list_lock);
166 }
168 
169 /* LED Trigger Interface */
170 
171 int led_trigger_register(struct led_trigger *trig)
172 {
173  struct led_classdev *led_cdev;
174  struct led_trigger *_trig;
175 
176  rwlock_init(&trig->leddev_list_lock);
177  INIT_LIST_HEAD(&trig->led_cdevs);
178 
179  down_write(&triggers_list_lock);
180  /* Make sure the trigger's name isn't already in use */
181  list_for_each_entry(_trig, &trigger_list, next_trig) {
182  if (!strcmp(_trig->name, trig->name)) {
183  up_write(&triggers_list_lock);
184  return -EEXIST;
185  }
186  }
187  /* Add to the list of led triggers */
188  list_add_tail(&trig->next_trig, &trigger_list);
189  up_write(&triggers_list_lock);
190 
191  /* Register with any LEDs that have this as a default trigger */
193  list_for_each_entry(led_cdev, &leds_list, node) {
194  down_write(&led_cdev->trigger_lock);
195  if (!led_cdev->trigger && led_cdev->default_trigger &&
196  !strcmp(led_cdev->default_trigger, trig->name))
197  led_trigger_set(led_cdev, trig);
198  up_write(&led_cdev->trigger_lock);
199  }
201 
202  return 0;
203 }
205 
206 void led_trigger_unregister(struct led_trigger *trig)
207 {
208  struct led_classdev *led_cdev;
209 
210  /* Remove from the list of led triggers */
211  down_write(&triggers_list_lock);
212  list_del(&trig->next_trig);
213  up_write(&triggers_list_lock);
214 
215  /* Remove anyone actively using this trigger */
217  list_for_each_entry(led_cdev, &leds_list, node) {
218  down_write(&led_cdev->trigger_lock);
219  if (led_cdev->trigger == trig)
220  led_trigger_set(led_cdev, NULL);
221  up_write(&led_cdev->trigger_lock);
222  }
224 }
226 
227 /* Simple LED Tigger Interface */
228 
229 void led_trigger_event(struct led_trigger *trig,
231 {
232  struct list_head *entry;
233 
234  if (!trig)
235  return;
236 
237  read_lock(&trig->leddev_list_lock);
238  list_for_each(entry, &trig->led_cdevs) {
239  struct led_classdev *led_cdev;
240 
241  led_cdev = list_entry(entry, struct led_classdev, trig_list);
242  led_set_brightness(led_cdev, brightness);
243  }
244  read_unlock(&trig->leddev_list_lock);
245 }
247 
248 static void led_trigger_blink_setup(struct led_trigger *trig,
249  unsigned long *delay_on,
250  unsigned long *delay_off,
251  int oneshot,
252  int invert)
253 {
254  struct list_head *entry;
255 
256  if (!trig)
257  return;
258 
259  read_lock(&trig->leddev_list_lock);
260  list_for_each(entry, &trig->led_cdevs) {
261  struct led_classdev *led_cdev;
262 
263  led_cdev = list_entry(entry, struct led_classdev, trig_list);
264  if (oneshot)
265  led_blink_set_oneshot(led_cdev, delay_on, delay_off,
266  invert);
267  else
268  led_blink_set(led_cdev, delay_on, delay_off);
269  }
270  read_unlock(&trig->leddev_list_lock);
271 }
272 
273 void led_trigger_blink(struct led_trigger *trig,
274  unsigned long *delay_on,
275  unsigned long *delay_off)
276 {
277  led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
278 }
280 
281 void led_trigger_blink_oneshot(struct led_trigger *trig,
282  unsigned long *delay_on,
283  unsigned long *delay_off,
284  int invert)
285 {
286  led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
287 }
289 
290 void led_trigger_register_simple(const char *name, struct led_trigger **tp)
291 {
292  struct led_trigger *trig;
293  int err;
294 
295  trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
296 
297  if (trig) {
298  trig->name = name;
299  err = led_trigger_register(trig);
300  if (err < 0) {
301  kfree(trig);
302  trig = NULL;
303  printk(KERN_WARNING "LED trigger %s failed to register"
304  " (%d)\n", name, err);
305  }
306  } else
307  printk(KERN_WARNING "LED trigger %s failed to register"
308  " (no memory)\n", name);
309 
310  *tp = trig;
311 }
313 
314 void led_trigger_unregister_simple(struct led_trigger *trig)
315 {
316  if (trig)
318  kfree(trig);
319 }
321 
322 MODULE_AUTHOR("Richard Purdie");
323 MODULE_LICENSE("GPL");
324 MODULE_DESCRIPTION("LED Triggers Core");