2 * linux/drivers/leds/ledscore.c
4 * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #warning This file is deprecated - please switch to mainline LED classdev
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/list.h>
16 #include <linux/spinlock.h>
17 #include <linux/device.h>
18 #include <linux/sysdev.h>
19 #include <linux/timer.h>
20 #include <linux/leds.h>
23 /* This protects the props field.*/
25 /* If props is NULL, the driver that registered this device has been unloaded */
26 struct led_properties
*props
;
28 unsigned long frequency
; /* frequency of blinking, in milliseconds */
29 int in_use
; /* 1 if this device is in use by the kernel somewhere */
31 struct class_device class_dev
;
32 struct timer_list
*ktimer
;
33 struct list_head node
;
36 #define to_led_device(d) container_of(d, struct led_device, class_dev)
38 static rwlock_t leds_list_lock
= RW_LOCK_UNLOCKED
;
39 static LIST_HEAD(leds_list
);
40 static rwlock_t leds_interface_list_lock
= RW_LOCK_UNLOCKED
;
41 static LIST_HEAD(leds_interface_list
);
43 static void leds_class_release(struct class_device
*dev
)
45 struct led_device
*d
= to_led_device(dev
);
47 write_lock(&leds_list_lock
);
49 write_unlock(&leds_list_lock
);
54 static struct class leds_class
= {
56 .release
= leds_class_release
,
59 static void leds_timer_function(unsigned long data
)
61 struct led_device
*led_dev
= (struct led_device
*) data
;
62 unsigned long delay
= 0;
64 spin_lock(&led_dev
->lock
);
65 if (led_dev
->frequency
) {
66 delay
= led_dev
->frequency
;
67 if (likely(led_dev
->props
->brightness_get
)) {
69 if (led_dev
->props
->brightness_get(led_dev
->class_dev
.dev
, led_dev
->props
))
73 if (likely(led_dev
->props
->brightness_set
))
74 led_dev
->props
->brightness_set(led_dev
->class_dev
.dev
, led_dev
->props
, value
);
77 spin_unlock(&led_dev
->lock
);
80 mod_timer(led_dev
->ktimer
, jiffies
+ msecs_to_jiffies(delay
));
83 /* This function MUST be called with led_dev->lock held */
84 static int leds_enable_timer(struct led_device
*led_dev
)
86 if (led_dev
->frequency
&& led_dev
->ktimer
) {
87 /* timer already created, just enable it */
88 mod_timer(led_dev
->ktimer
, jiffies
+ msecs_to_jiffies(led_dev
->frequency
));
89 } else if (led_dev
->frequency
&& led_dev
->ktimer
== NULL
) {
90 /* create a new timer */
91 led_dev
->ktimer
= kmalloc(sizeof(struct timer_list
), GFP_KERNEL
);
92 if (led_dev
->ktimer
) {
93 init_timer(led_dev
->ktimer
);
94 led_dev
->ktimer
->function
= leds_timer_function
;
95 led_dev
->ktimer
->data
= (unsigned long) led_dev
;
96 led_dev
->ktimer
->expires
= jiffies
+ msecs_to_jiffies(led_dev
->frequency
);
97 add_timer(led_dev
->ktimer
);
99 led_dev
->frequency
= 0;
108 static ssize_t
leds_show_in_use(struct class_device
*dev
, char *buf
)
110 struct led_device
*led_dev
= to_led_device(dev
);
113 spin_lock(&led_dev
->lock
);
114 sprintf(buf
, "%i\n", led_dev
->in_use
);
115 ret
= strlen(buf
) + 1;
116 spin_unlock(&led_dev
->lock
);
121 static CLASS_DEVICE_ATTR(in_use
, 0444, leds_show_in_use
, NULL
);
123 static ssize_t
leds_show_color(struct class_device
*dev
, char *buf
)
125 struct led_device
*led_dev
= to_led_device(dev
);
128 spin_lock(&led_dev
->lock
);
129 if (likely(led_dev
->props
)) {
130 sprintf(buf
, "%s\n", led_dev
->props
->color
);
131 ret
= strlen(buf
) + 1;
133 spin_unlock(&led_dev
->lock
);
138 static CLASS_DEVICE_ATTR(color
, 0444, leds_show_color
, NULL
);
140 static ssize_t
leds_show_current_color(struct class_device
*dev
, char *buf
)
142 struct led_device
*led_dev
= to_led_device(dev
);
145 spin_lock(&led_dev
->lock
);
146 if (likely(led_dev
->props
)) {
147 if (led_dev
->props
->color_get
) {
148 sprintf(buf
, "%u\n", led_dev
->props
->color_get(led_dev
->class_dev
.dev
, led_dev
->props
));
149 ret
= strlen(buf
) + 1;
152 spin_unlock(&led_dev
->lock
);
157 static ssize_t
leds_store_current_color(struct class_device
*dev
, const char *buf
, size_t size
)
159 struct led_device
*led_dev
= to_led_device(dev
);
160 ssize_t ret
= -EINVAL
;
163 unsigned long state
= simple_strtoul(buf
, &after
, 10);
164 if (after
- buf
> 0) {
166 spin_lock(&led_dev
->lock
);
167 if (led_dev
->props
&& !led_dev
->in_use
) {
168 if (led_dev
->props
->color_set
)
169 led_dev
->props
->color_set(led_dev
->class_dev
.dev
, led_dev
->props
, state
);
171 spin_unlock(&led_dev
->lock
);
177 static CLASS_DEVICE_ATTR(current_color
, 0444, leds_show_current_color
, leds_store_current_color
);
179 static ssize_t
leds_show_brightness(struct class_device
*dev
, char *buf
)
181 struct led_device
*led_dev
= to_led_device(dev
);
184 spin_lock(&led_dev
->lock
);
185 if (likely(led_dev
->props
)) {
186 if (likely(led_dev
->props
->brightness_get
)) {
188 led_dev
->props
->brightness_get(led_dev
->class_dev
.dev
, led_dev
->props
));
189 ret
= strlen(buf
) + 1;
192 spin_unlock(&led_dev
->lock
);
197 static ssize_t
leds_store_brightness(struct class_device
*dev
, const char *buf
, size_t size
)
199 struct led_device
*led_dev
= to_led_device(dev
);
200 ssize_t ret
= -EINVAL
;
203 unsigned long state
= simple_strtoul(buf
, &after
, 10);
204 if (after
- buf
> 0) {
206 spin_lock(&led_dev
->lock
);
207 if (led_dev
->props
&& !led_dev
->in_use
) {
208 if (state
> 100) state
= 100;
209 if (led_dev
->props
->brightness_set
)
210 led_dev
->props
->brightness_set(led_dev
->class_dev
.dev
, led_dev
->props
, state
);
212 spin_unlock(&led_dev
->lock
);
218 static CLASS_DEVICE_ATTR(brightness
, 0644, leds_show_brightness
, leds_store_brightness
);
220 static ssize_t
leds_show_frequency(struct class_device
*dev
, char *buf
)
222 struct led_device
*led_dev
= to_led_device(dev
);
225 spin_lock(&led_dev
->lock
);
226 if (likely(led_dev
->props
)) {
227 if (led_dev
->props
->blink_frequency_get
)
228 sprintf(buf
, "%lu\n",
229 led_dev
->props
->blink_frequency_get(led_dev
->class_dev
.dev
, led_dev
->props
));
231 sprintf(buf
, "%lu\n", led_dev
->frequency
);
232 ret
= strlen(buf
) + 1;
234 spin_unlock(&led_dev
->lock
);
239 static ssize_t
leds_store_frequency(struct class_device
*dev
, const char *buf
, size_t size
)
241 struct led_device
*led_dev
= to_led_device(dev
);
242 int ret
= -EINVAL
, ret2
;
245 unsigned long state
= simple_strtoul(buf
, &after
, 10);
246 if (after
- buf
> 0) {
248 spin_lock(&led_dev
->lock
);
249 if (led_dev
->props
) {
250 if (led_dev
->props
->blink_frequency_set
) {
251 led_dev
->props
->blink_frequency_set(
252 led_dev
->class_dev
.dev
, led_dev
->props
, state
);
254 if (!led_dev
->in_use
) {
255 led_dev
->frequency
= state
;
256 ret2
= leds_enable_timer(led_dev
);
257 if (ret2
) ret
= ret2
;
261 spin_unlock(&led_dev
->lock
);
267 static CLASS_DEVICE_ATTR(frequency
, 0644, leds_show_frequency
, leds_store_frequency
);
270 * leds_device_register - register a new object of led_device class.
271 * @dev: The device to register.
272 * @prop: the led properties structure for this device.
274 int leds_device_register(struct device
*dev
, struct led_properties
*props
)
277 struct led_device
*new_led
;
278 struct led_interface
*interface
;
280 new_led
= kmalloc (sizeof (struct led_device
), GFP_KERNEL
);
281 if (unlikely (!new_led
))
284 memset(new_led
, 0, sizeof(struct led_device
));
286 spin_lock_init(&new_led
->lock
);
287 new_led
->props
= props
;
288 props
->led_dev
= new_led
;
290 new_led
->class_dev
.class = &leds_class
;
291 new_led
->class_dev
.dev
= dev
;
293 new_led
->frequency
= 0;
296 /* assign this led its name */
297 strncpy(new_led
->class_dev
.class_id
, props
->name
, sizeof(new_led
->class_dev
.class_id
));
299 rc
= class_device_register (&new_led
->class_dev
);
305 /* register the attributes */
306 class_device_create_file(&new_led
->class_dev
, &class_device_attr_in_use
);
307 class_device_create_file(&new_led
->class_dev
, &class_device_attr_color
);
308 class_device_create_file(&new_led
->class_dev
, &class_device_attr_current_color
);
309 class_device_create_file(&new_led
->class_dev
, &class_device_attr_brightness
);
310 class_device_create_file(&new_led
->class_dev
, &class_device_attr_frequency
);
312 /* add to the list of leds */
313 write_lock(&leds_list_lock
);
314 list_add_tail(&new_led
->node
, &leds_list
);
315 write_unlock(&leds_list_lock
);
317 /* notify any interfaces */
318 read_lock(&leds_interface_list_lock
);
319 list_for_each_entry(interface
, &leds_interface_list
, node
) {
321 interface
->add(dev
, props
);
323 read_unlock(&leds_interface_list_lock
);
325 printk(KERN_INFO
"Registered led device: number=%s, color=%s\n", new_led
->class_dev
.class_id
, props
->color
);
329 EXPORT_SYMBOL(leds_device_register
);
332 * leds_device_unregister - unregisters a object of led_properties class.
333 * @props: the property to unreigister
335 * Unregisters a previously registered via leds_device_register object.
337 void leds_device_unregister(struct led_properties
*props
)
339 struct led_device
*led_dev
;
340 struct led_interface
*interface
;
342 if (!props
|| !props
->led_dev
)
345 led_dev
= props
->led_dev
;
347 /* notify interfaces device is going away */
348 read_lock(&leds_interface_list_lock
);
349 list_for_each_entry(interface
, &leds_interface_list
, node
) {
350 if (interface
->remove
)
351 interface
->remove(led_dev
->class_dev
.dev
, props
);
353 read_unlock(&leds_interface_list_lock
);
355 class_device_remove_file (&led_dev
->class_dev
, &class_device_attr_frequency
);
356 class_device_remove_file (&led_dev
->class_dev
, &class_device_attr_brightness
);
357 class_device_remove_file (&led_dev
->class_dev
, &class_device_attr_current_color
);
358 class_device_remove_file (&led_dev
->class_dev
, &class_device_attr_color
);
359 class_device_remove_file (&led_dev
->class_dev
, &class_device_attr_in_use
);
361 spin_lock(&led_dev
->lock
);
362 led_dev
->props
= NULL
;
363 props
->led_dev
= NULL
;
364 spin_unlock(&led_dev
->lock
);
366 if (led_dev
->ktimer
) {
367 del_timer_sync(led_dev
->ktimer
);
368 kfree(led_dev
->ktimer
);
369 led_dev
->ktimer
= NULL
;
372 class_device_unregister(&led_dev
->class_dev
);
374 EXPORT_SYMBOL(leds_device_unregister
);
376 int leds_acquire(struct led_properties
*led
)
380 spin_lock(&led
->led_dev
->lock
);
381 if (!led
->led_dev
->in_use
) {
382 led
->led_dev
->in_use
= 1;
383 /* Disable the userspace blinking, if any */
384 led
->led_dev
->frequency
= 0;
387 spin_unlock(&led
->led_dev
->lock
);
391 EXPORT_SYMBOL(leds_acquire
);
393 void leds_release(struct led_properties
*led
)
395 spin_lock(&led
->led_dev
->lock
);
396 led
->led_dev
->in_use
= 0;
397 /* Disable the kernel blinking, if any */
398 led
->led_dev
->frequency
= 0;
399 spin_unlock(&led
->led_dev
->lock
);
401 EXPORT_SYMBOL(leds_release
);
403 /* Sets the frequency of the led in milliseconds.
404 * Only call this function after leds_acquire returns true
406 int leds_set_frequency(struct led_properties
*led
, unsigned long frequency
)
410 spin_lock(&led
->led_dev
->lock
);
412 if (led
->blink_frequency_set
) {
413 led
->blink_frequency_set(led
->led_dev
->class_dev
.dev
, led
, frequency
);
415 if (!led
->led_dev
->in_use
)
418 led
->led_dev
->frequency
= frequency
;
419 ret
= leds_enable_timer(led
->led_dev
);
422 spin_unlock(&led
->led_dev
->lock
);
426 EXPORT_SYMBOL(leds_set_frequency
);
428 int leds_interface_register(struct led_interface
*interface
)
430 struct led_device
*led_dev
;
432 write_lock(&leds_interface_list_lock
);
433 list_add_tail(&interface
->node
, &leds_interface_list
);
435 read_lock(&leds_list
);
436 list_for_each_entry(led_dev
, &leds_list
, node
) {
437 spin_lock(&led_dev
->lock
);
438 if (led_dev
->props
) {
439 interface
->add(led_dev
->class_dev
.dev
, led_dev
->props
);
441 spin_unlock(&led_dev
->lock
);
443 read_unlock(&leds_list
);
445 write_unlock(&leds_interface_list_lock
);
449 EXPORT_SYMBOL(leds_interface_register
);
451 void leds_interface_unregister(struct led_interface
*interface
)
453 write_lock(&leds_interface_list_lock
);
454 list_del(&interface
->node
);
455 write_unlock(&leds_interface_list_lock
);
457 EXPORT_SYMBOL(leds_interface_unregister
);
459 static int __init
leds_init(void)
461 /* initialize the class device */
462 return class_register(&leds_class
);
464 subsys_initcall(leds_init
);
466 static void __exit
leds_exit(void)
468 class_unregister(&leds_class
);
470 module_exit(leds_exit
);
472 MODULE_AUTHOR("John Lenz");
473 MODULE_LICENSE("GPL");
474 MODULE_DESCRIPTION("LED core class interface");