| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * LED Class Core | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu> | 
|  | 5 | * Copyright (C) 2005-2006 Richard Purdie <rpurdie@openedhand.com> | 
|  | 6 | * | 
|  | 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 | 
|  | 9 | * published by the Free Software Foundation. | 
|  | 10 | */ | 
|  | 11 |  | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 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/err.h> | 
| Richard Purdie | 3dc7b82 | 2006-05-15 09:44:17 -0700 | [diff] [blame] | 21 | #include <linux/ctype.h> | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 22 | #include <linux/leds.h> | 
|  | 23 | #include "leds.h" | 
|  | 24 |  | 
|  | 25 | static struct class *leds_class; | 
|  | 26 |  | 
|  | 27 | static ssize_t led_brightness_show(struct class_device *dev, char *buf) | 
|  | 28 | { | 
|  | 29 | struct led_classdev *led_cdev = class_get_devdata(dev); | 
|  | 30 | ssize_t ret = 0; | 
|  | 31 |  | 
|  | 32 | /* no lock needed for this */ | 
|  | 33 | sprintf(buf, "%u\n", led_cdev->brightness); | 
|  | 34 | ret = strlen(buf) + 1; | 
|  | 35 |  | 
|  | 36 | return ret; | 
|  | 37 | } | 
|  | 38 |  | 
|  | 39 | static ssize_t led_brightness_store(struct class_device *dev, | 
|  | 40 | const char *buf, size_t size) | 
|  | 41 | { | 
|  | 42 | struct led_classdev *led_cdev = class_get_devdata(dev); | 
|  | 43 | ssize_t ret = -EINVAL; | 
|  | 44 | char *after; | 
|  | 45 | unsigned long state = simple_strtoul(buf, &after, 10); | 
| Richard Purdie | 3dc7b82 | 2006-05-15 09:44:17 -0700 | [diff] [blame] | 46 | size_t count = after - buf; | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 47 |  | 
| Richard Purdie | 3dc7b82 | 2006-05-15 09:44:17 -0700 | [diff] [blame] | 48 | if (*after && isspace(*after)) | 
|  | 49 | count++; | 
|  | 50 |  | 
|  | 51 | if (count == size) { | 
|  | 52 | ret = count; | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 53 | led_set_brightness(led_cdev, state); | 
|  | 54 | } | 
|  | 55 |  | 
|  | 56 | return ret; | 
|  | 57 | } | 
|  | 58 |  | 
|  | 59 | static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show, | 
|  | 60 | led_brightness_store); | 
| Richard Purdie | c3bc995 | 2006-03-31 02:31:05 -0800 | [diff] [blame] | 61 | #ifdef CONFIG_LEDS_TRIGGERS | 
|  | 62 | static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store); | 
|  | 63 | #endif | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 64 |  | 
|  | 65 | /** | 
|  | 66 | * led_classdev_suspend - suspend an led_classdev. | 
|  | 67 | * @led_cdev: the led_classdev to suspend. | 
|  | 68 | */ | 
|  | 69 | void led_classdev_suspend(struct led_classdev *led_cdev) | 
|  | 70 | { | 
|  | 71 | led_cdev->flags |= LED_SUSPENDED; | 
|  | 72 | led_cdev->brightness_set(led_cdev, 0); | 
|  | 73 | } | 
|  | 74 | EXPORT_SYMBOL_GPL(led_classdev_suspend); | 
|  | 75 |  | 
|  | 76 | /** | 
|  | 77 | * led_classdev_resume - resume an led_classdev. | 
|  | 78 | * @led_cdev: the led_classdev to resume. | 
|  | 79 | */ | 
|  | 80 | void led_classdev_resume(struct led_classdev *led_cdev) | 
|  | 81 | { | 
|  | 82 | led_cdev->brightness_set(led_cdev, led_cdev->brightness); | 
|  | 83 | led_cdev->flags &= ~LED_SUSPENDED; | 
|  | 84 | } | 
|  | 85 | EXPORT_SYMBOL_GPL(led_classdev_resume); | 
|  | 86 |  | 
|  | 87 | /** | 
|  | 88 | * led_classdev_register - register a new object of led_classdev class. | 
|  | 89 | * @dev: The device to register. | 
|  | 90 | * @led_cdev: the led_classdev structure for this device. | 
|  | 91 | */ | 
|  | 92 | int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) | 
|  | 93 | { | 
| Jeff Garzik | 12fda16 | 2006-10-17 00:10:20 -0700 | [diff] [blame] | 94 | int rc; | 
|  | 95 |  | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 96 | led_cdev->class_dev = class_device_create(leds_class, NULL, 0, | 
|  | 97 | parent, "%s", led_cdev->name); | 
|  | 98 | if (unlikely(IS_ERR(led_cdev->class_dev))) | 
|  | 99 | return PTR_ERR(led_cdev->class_dev); | 
|  | 100 |  | 
|  | 101 | class_set_devdata(led_cdev->class_dev, led_cdev); | 
|  | 102 |  | 
|  | 103 | /* register the attributes */ | 
| Jeff Garzik | 12fda16 | 2006-10-17 00:10:20 -0700 | [diff] [blame] | 104 | rc = class_device_create_file(led_cdev->class_dev, | 
|  | 105 | &class_device_attr_brightness); | 
|  | 106 | if (rc) | 
|  | 107 | goto err_out; | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 108 |  | 
|  | 109 | /* add to the list of leds */ | 
|  | 110 | write_lock(&leds_list_lock); | 
|  | 111 | list_add_tail(&led_cdev->node, &leds_list); | 
|  | 112 | write_unlock(&leds_list_lock); | 
|  | 113 |  | 
| Richard Purdie | c3bc995 | 2006-03-31 02:31:05 -0800 | [diff] [blame] | 114 | #ifdef CONFIG_LEDS_TRIGGERS | 
|  | 115 | rwlock_init(&led_cdev->trigger_lock); | 
|  | 116 |  | 
| Jeff Garzik | 12fda16 | 2006-10-17 00:10:20 -0700 | [diff] [blame] | 117 | rc = class_device_create_file(led_cdev->class_dev, | 
|  | 118 | &class_device_attr_trigger); | 
|  | 119 | if (rc) | 
|  | 120 | goto err_out_led_list; | 
| Richard Purdie | c3bc995 | 2006-03-31 02:31:05 -0800 | [diff] [blame] | 121 |  | 
| Jeff Garzik | 12fda16 | 2006-10-17 00:10:20 -0700 | [diff] [blame] | 122 | led_trigger_set_default(led_cdev); | 
| Richard Purdie | c3bc995 | 2006-03-31 02:31:05 -0800 | [diff] [blame] | 123 | #endif | 
|  | 124 |  | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 125 | printk(KERN_INFO "Registered led device: %s\n", | 
|  | 126 | led_cdev->class_dev->class_id); | 
|  | 127 |  | 
|  | 128 | return 0; | 
| Jeff Garzik | 12fda16 | 2006-10-17 00:10:20 -0700 | [diff] [blame] | 129 |  | 
|  | 130 | #ifdef CONFIG_LEDS_TRIGGERS | 
|  | 131 | err_out_led_list: | 
|  | 132 | class_device_remove_file(led_cdev->class_dev, | 
|  | 133 | &class_device_attr_brightness); | 
|  | 134 | list_del(&led_cdev->node); | 
|  | 135 | #endif | 
|  | 136 | err_out: | 
|  | 137 | class_device_unregister(led_cdev->class_dev); | 
|  | 138 | return rc; | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 139 | } | 
|  | 140 | EXPORT_SYMBOL_GPL(led_classdev_register); | 
|  | 141 |  | 
|  | 142 | /** | 
|  | 143 | * led_classdev_unregister - unregisters a object of led_properties class. | 
| Henrik Kretzschmar | 70d63cc | 2006-10-03 23:31:30 +0200 | [diff] [blame] | 144 | * @led_cdev: the led device to unregister | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 145 | * | 
|  | 146 | * Unregisters a previously registered via led_classdev_register object. | 
|  | 147 | */ | 
|  | 148 | void led_classdev_unregister(struct led_classdev *led_cdev) | 
|  | 149 | { | 
|  | 150 | class_device_remove_file(led_cdev->class_dev, | 
|  | 151 | &class_device_attr_brightness); | 
| Richard Purdie | c3bc995 | 2006-03-31 02:31:05 -0800 | [diff] [blame] | 152 | #ifdef CONFIG_LEDS_TRIGGERS | 
|  | 153 | class_device_remove_file(led_cdev->class_dev, | 
|  | 154 | &class_device_attr_trigger); | 
|  | 155 | write_lock(&led_cdev->trigger_lock); | 
|  | 156 | if (led_cdev->trigger) | 
|  | 157 | led_trigger_set(led_cdev, NULL); | 
|  | 158 | write_unlock(&led_cdev->trigger_lock); | 
|  | 159 | #endif | 
| Richard Purdie | c72a1d6 | 2006-03-31 02:31:04 -0800 | [diff] [blame] | 160 |  | 
|  | 161 | class_device_unregister(led_cdev->class_dev); | 
|  | 162 |  | 
|  | 163 | write_lock(&leds_list_lock); | 
|  | 164 | list_del(&led_cdev->node); | 
|  | 165 | write_unlock(&leds_list_lock); | 
|  | 166 | } | 
|  | 167 | EXPORT_SYMBOL_GPL(led_classdev_unregister); | 
|  | 168 |  | 
|  | 169 | static int __init leds_init(void) | 
|  | 170 | { | 
|  | 171 | leds_class = class_create(THIS_MODULE, "leds"); | 
|  | 172 | if (IS_ERR(leds_class)) | 
|  | 173 | return PTR_ERR(leds_class); | 
|  | 174 | return 0; | 
|  | 175 | } | 
|  | 176 |  | 
|  | 177 | static void __exit leds_exit(void) | 
|  | 178 | { | 
|  | 179 | class_destroy(leds_class); | 
|  | 180 | } | 
|  | 181 |  | 
|  | 182 | subsys_initcall(leds_init); | 
|  | 183 | module_exit(leds_exit); | 
|  | 184 |  | 
|  | 185 | MODULE_AUTHOR("John Lenz, Richard Purdie"); | 
|  | 186 | MODULE_LICENSE("GPL"); | 
|  | 187 | MODULE_DESCRIPTION("LED Class Interface"); |