sync hh.org
[hh.org.git] / drivers / leds / ledscore.c
blobe4abc63f6129fd1b193347c2debc5bc9211d0302
1 /*
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.
9 */
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>
22 struct led_device {
23 /* This protects the props field.*/
24 spinlock_t lock;
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);
48 list_del(&d->node);
49 write_unlock(&leds_list_lock);
51 kfree(d);
54 static struct class leds_class = {
55 .name = "leds",
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)) {
68 unsigned long value;
69 if (led_dev->props->brightness_get(led_dev->class_dev.dev, led_dev->props))
70 value = 0;
71 else
72 value = 100;
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);
79 if (delay)
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);
98 } else {
99 led_dev->frequency = 0;
100 return -ENOMEM;
104 return 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);
111 ssize_t ret = 0;
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);
118 return ret;
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);
126 ssize_t ret = 0;
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);
135 return ret;
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);
143 ssize_t ret = 0;
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);
154 return ret;
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;
161 char *after;
163 unsigned long state = simple_strtoul(buf, &after, 10);
164 if (after - buf > 0) {
165 ret = after - buf;
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);
174 return ret;
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);
182 ssize_t ret = 0;
184 spin_lock(&led_dev->lock);
185 if (likely(led_dev->props)) {
186 if (likely(led_dev->props->brightness_get)) {
187 sprintf(buf, "%u\n",
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);
194 return ret;
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;
201 char *after;
203 unsigned long state = simple_strtoul(buf, &after, 10);
204 if (after - buf > 0) {
205 ret = after - buf;
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);
215 return ret;
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);
223 ssize_t ret = 0;
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));
230 else
231 sprintf(buf, "%lu\n", led_dev->frequency);
232 ret = strlen(buf) + 1;
234 spin_unlock(&led_dev->lock);
236 return ret;
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;
243 char *after;
245 unsigned long state = simple_strtoul(buf, &after, 10);
246 if (after - buf > 0) {
247 ret = after - buf;
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);
253 } else {
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);
264 return ret;
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)
276 int rc;
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))
282 return -ENOMEM;
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;
294 new_led->in_use = 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);
300 if (unlikely (rc)) {
301 kfree (new_led);
302 return rc;
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) {
320 if (interface->add)
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);
327 return 0;
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)
343 return;
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)
378 int ret = -EBUSY;
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;
385 ret = 0;
387 spin_unlock(&led->led_dev->lock);
389 return ret;
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)
408 int ret = 0;
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);
414 } else {
415 if (!led->led_dev->in_use)
416 return -EINVAL;
418 led->led_dev->frequency = frequency;
419 ret = leds_enable_timer(led->led_dev);
422 spin_unlock(&led->led_dev->lock);
424 return ret;
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);
447 return 0;
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");