led-class.c 4.6 KB
Newer Older
R
Richard Purdie 已提交
1 2 3 4
/*
 * LED Class Core
 *
 * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
5
 * Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.com>
R
Richard Purdie 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/timer.h>
#include <linux/err.h>
21
#include <linux/ctype.h>
R
Richard Purdie 已提交
22 23 24 25 26
#include <linux/leds.h>
#include "leds.h"

static struct class *leds_class;

27 28 29 30 31 32
static void led_update_brightness(struct led_classdev *led_cdev)
{
	if (led_cdev->brightness_get)
		led_cdev->brightness = led_cdev->brightness_get(led_cdev);
}

33 34
static ssize_t led_brightness_show(struct device *dev, 
		struct device_attribute *attr, char *buf)
R
Richard Purdie 已提交
35
{
36
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
R
Richard Purdie 已提交
37 38 39
	ssize_t ret = 0;

	/* no lock needed for this */
40
	led_update_brightness(led_cdev);
R
Richard Purdie 已提交
41 42 43 44 45 46
	sprintf(buf, "%u\n", led_cdev->brightness);
	ret = strlen(buf) + 1;

	return ret;
}

47 48
static ssize_t led_brightness_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
R
Richard Purdie 已提交
49
{
50
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
R
Richard Purdie 已提交
51 52 53
	ssize_t ret = -EINVAL;
	char *after;
	unsigned long state = simple_strtoul(buf, &after, 10);
54
	size_t count = after - buf;
R
Richard Purdie 已提交
55

56 57 58 59 60
	if (*after && isspace(*after))
		count++;

	if (count == size) {
		ret = count;
61 62 63

		if (state == LED_OFF)
			led_trigger_remove(led_cdev);
R
Richard Purdie 已提交
64 65 66 67 68 69
		led_set_brightness(led_cdev, state);
	}

	return ret;
}

70
static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
71
#ifdef CONFIG_LEDS_TRIGGERS
72
static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
73
#endif
R
Richard Purdie 已提交
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

/**
 * led_classdev_suspend - suspend an led_classdev.
 * @led_cdev: the led_classdev to suspend.
 */
void led_classdev_suspend(struct led_classdev *led_cdev)
{
	led_cdev->flags |= LED_SUSPENDED;
	led_cdev->brightness_set(led_cdev, 0);
}
EXPORT_SYMBOL_GPL(led_classdev_suspend);

/**
 * led_classdev_resume - resume an led_classdev.
 * @led_cdev: the led_classdev to resume.
 */
void led_classdev_resume(struct led_classdev *led_cdev)
{
	led_cdev->brightness_set(led_cdev, led_cdev->brightness);
	led_cdev->flags &= ~LED_SUSPENDED;
}
EXPORT_SYMBOL_GPL(led_classdev_resume);

/**
 * led_classdev_register - register a new object of led_classdev class.
 * @dev: The device to register.
 * @led_cdev: the led_classdev structure for this device.
 */
int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
104 105
	int rc;

106 107
	led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,
				      "%s", led_cdev->name);
108
	if (IS_ERR(led_cdev->dev))
109
		return PTR_ERR(led_cdev->dev);
R
Richard Purdie 已提交
110 111

	/* register the attributes */
112
	rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
113 114
	if (rc)
		goto err_out;
R
Richard Purdie 已提交
115 116

	/* add to the list of leds */
117
	down_write(&leds_list_lock);
R
Richard Purdie 已提交
118
	list_add_tail(&led_cdev->node, &leds_list);
119
	up_write(&leds_list_lock);
R
Richard Purdie 已提交
120

121 122
	led_update_brightness(led_cdev);

123
#ifdef CONFIG_LEDS_TRIGGERS
124
	init_rwsem(&led_cdev->trigger_lock);
125

126
	rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
127 128
	if (rc)
		goto err_out_led_list;
129

130
	led_trigger_set_default(led_cdev);
131 132
#endif

R
Richard Purdie 已提交
133
	printk(KERN_INFO "Registered led device: %s\n",
134
			led_cdev->name);
R
Richard Purdie 已提交
135 136

	return 0;
137 138 139

#ifdef CONFIG_LEDS_TRIGGERS
err_out_led_list:
140
	device_remove_file(led_cdev->dev, &dev_attr_brightness);
141 142 143
	list_del(&led_cdev->node);
#endif
err_out:
144
	device_unregister(led_cdev->dev);
145
	return rc;
R
Richard Purdie 已提交
146 147 148 149
}
EXPORT_SYMBOL_GPL(led_classdev_register);

/**
150
 * __led_classdev_unregister - unregisters a object of led_properties class.
H
Henrik Kretzschmar 已提交
151
 * @led_cdev: the led device to unregister
R
Richard Purdie 已提交
152 153 154
 *
 * Unregisters a previously registered via led_classdev_register object.
 */
155
void led_classdev_unregister(struct led_classdev *led_cdev)
R
Richard Purdie 已提交
156
{
157
	device_remove_file(led_cdev->dev, &dev_attr_brightness);
158
#ifdef CONFIG_LEDS_TRIGGERS
159
	device_remove_file(led_cdev->dev, &dev_attr_trigger);
160
	down_write(&led_cdev->trigger_lock);
161 162
	if (led_cdev->trigger)
		led_trigger_set(led_cdev, NULL);
163
	up_write(&led_cdev->trigger_lock);
164
#endif
R
Richard Purdie 已提交
165

166
	device_unregister(led_cdev->dev);
R
Richard Purdie 已提交
167

168
	down_write(&leds_list_lock);
R
Richard Purdie 已提交
169
	list_del(&led_cdev->node);
170
	up_write(&leds_list_lock);
R
Richard Purdie 已提交
171
}
172
EXPORT_SYMBOL_GPL(led_classdev_unregister);
R
Richard Purdie 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

static int __init leds_init(void)
{
	leds_class = class_create(THIS_MODULE, "leds");
	if (IS_ERR(leds_class))
		return PTR_ERR(leds_class);
	return 0;
}

static void __exit leds_exit(void)
{
	class_destroy(leds_class);
}

subsys_initcall(leds_init);
module_exit(leds_exit);

MODULE_AUTHOR("John Lenz, Richard Purdie");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("LED Class Interface");