From c72a1d608dd0eb3d553a08bfdf1c0041bebaa8a0 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Fri, 31 Mar 2006 02:31:04 -0800 Subject: [PATCH] LED: add LED class Add the foundations of a new LEDs subsystem. This patch adds a class which presents LED devices within sysfs and allows their brightness to be controlled. Signed-off-by: Richard Purdie Cc: Russell King Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/leds/Kconfig | 18 ++++++ drivers/leds/Makefile | 4 ++ drivers/leds/led-class.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/leds/led-core.c | 25 ++++++++ drivers/leds/leds.h | 31 ++++++++++ 7 files changed, 228 insertions(+) create mode 100644 drivers/leds/Kconfig create mode 100644 drivers/leds/Makefile create mode 100644 drivers/leds/led-class.c create mode 100644 drivers/leds/led-core.c create mode 100644 drivers/leds/leds.h (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index 9f5c0da57c90..5c91d6afb117 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -64,6 +64,8 @@ source "drivers/usb/Kconfig" source "drivers/mmc/Kconfig" +source "drivers/leds/Kconfig" + source "drivers/infiniband/Kconfig" source "drivers/sn/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 424955274e60..d6e8ffbd8132 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_MMC) += mmc/ +obj-$(CONFIG_NEW_LEDS) += leds/ obj-$(CONFIG_INFINIBAND) += infiniband/ obj-$(CONFIG_SGI_SN) += sn/ obj-y += firmware/ diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig new file mode 100644 index 000000000000..106f9aeca04f --- /dev/null +++ b/drivers/leds/Kconfig @@ -0,0 +1,18 @@ + +menu "LED devices" + +config NEW_LEDS + bool "LED Support" + help + Say Y to enable Linux LED support. This is not related to standard + keyboard LEDs which are controlled via the input system. + +config LEDS_CLASS + tristate "LED Class Support" + depends NEW_LEDS + help + This option enables the led sysfs class in /sys/class/leds. You'll + need this to do anything useful with LEDs. If unsure, say N. + +endmenu + diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile new file mode 100644 index 000000000000..8a62871437fa --- /dev/null +++ b/drivers/leds/Makefile @@ -0,0 +1,4 @@ + +# LED Core +obj-$(CONFIG_NEW_LEDS) += led-core.o +obj-$(CONFIG_LEDS_CLASS) += led-class.o diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c new file mode 100644 index 000000000000..0292df4101ba --- /dev/null +++ b/drivers/leds/led-class.c @@ -0,0 +1,147 @@ +/* + * LED Class Core + * + * Copyright (C) 2005 John Lenz + * Copyright (C) 2005-2006 Richard Purdie + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "leds.h" + +static struct class *leds_class; + +static ssize_t led_brightness_show(struct class_device *dev, char *buf) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + ssize_t ret = 0; + + /* no lock needed for this */ + sprintf(buf, "%u\n", led_cdev->brightness); + ret = strlen(buf) + 1; + + return ret; +} + +static ssize_t led_brightness_store(struct class_device *dev, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + ssize_t ret = -EINVAL; + char *after; + unsigned long state = simple_strtoul(buf, &after, 10); + + if (after - buf > 0) { + ret = after - buf; + led_set_brightness(led_cdev, state); + } + + return ret; +} + +static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show, + led_brightness_store); + +/** + * 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) +{ + led_cdev->class_dev = class_device_create(leds_class, NULL, 0, + parent, "%s", led_cdev->name); + if (unlikely(IS_ERR(led_cdev->class_dev))) + return PTR_ERR(led_cdev->class_dev); + + class_set_devdata(led_cdev->class_dev, led_cdev); + + /* register the attributes */ + class_device_create_file(led_cdev->class_dev, + &class_device_attr_brightness); + + /* add to the list of leds */ + write_lock(&leds_list_lock); + list_add_tail(&led_cdev->node, &leds_list); + write_unlock(&leds_list_lock); + + printk(KERN_INFO "Registered led device: %s\n", + led_cdev->class_dev->class_id); + + return 0; +} +EXPORT_SYMBOL_GPL(led_classdev_register); + +/** + * led_classdev_unregister - unregisters a object of led_properties class. + * @led_cdev: the led device to unreigister + * + * Unregisters a previously registered via led_classdev_register object. + */ +void led_classdev_unregister(struct led_classdev *led_cdev) +{ + class_device_remove_file(led_cdev->class_dev, + &class_device_attr_brightness); + + class_device_unregister(led_cdev->class_dev); + + write_lock(&leds_list_lock); + list_del(&led_cdev->node); + write_unlock(&leds_list_lock); +} +EXPORT_SYMBOL_GPL(led_classdev_unregister); + +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"); diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c new file mode 100644 index 000000000000..fe6541326c71 --- /dev/null +++ b/drivers/leds/led-core.c @@ -0,0 +1,25 @@ +/* + * LED Class Core + * + * Copyright 2005-2006 Openedhand Ltd. + * + * Author: Richard Purdie + * + * 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 +#include +#include +#include +#include +#include "leds.h" + +rwlock_t leds_list_lock = RW_LOCK_UNLOCKED; +LIST_HEAD(leds_list); + +EXPORT_SYMBOL_GPL(leds_list); +EXPORT_SYMBOL_GPL(leds_list_lock); diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h new file mode 100644 index 000000000000..d26ca2f7e722 --- /dev/null +++ b/drivers/leds/leds.h @@ -0,0 +1,31 @@ +/* + * LED Core + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * 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. + * + */ +#ifndef __LEDS_H_INCLUDED +#define __LEDS_H_INCLUDED + +#include + +static inline void led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + if (value > LED_FULL) + value = LED_FULL; + led_cdev->brightness = value; + if (!(led_cdev->flags & LED_SUSPENDED)) + led_cdev->brightness_set(led_cdev, value); +} + +extern rwlock_t leds_list_lock; +extern struct list_head leds_list; + +#endif /* __LEDS_H_INCLUDED */ -- cgit v1.2.3