From: John Lenz <lenz@cs.wisc.edu>
To: Russell King <rmk+lkml@arm.linux.org.uk>
Cc: linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2.6.8.1 0/2] leds: new class for led devices
Date: Fri, 03 Sep 2004 20:35:21 +0000 [thread overview]
Message-ID: <1094243721l.7429l.3l@hydra> (raw)
In-Reply-To: <20040903205115.E15620@flint.arm.linux.org.uk>
[-- Attachment #1: Type: text/plain, Size: 301 bytes --]
On 09/03/04 14:51:15, Russell King wrote:
>
> You missed the point. The above scenarios I was describing are _not_
> debugging.
Ok, so we get rid of the function thing, but still provide a
heartbeat_enabled entry in sysfs. Something like this patch
Signed-off-by: John Lenz <lenz@cs.wisc.edu>
[-- Attachment #2: leds_sysfs.patch --]
[-- Type: text/x-patch, Size: 9728 bytes --]
#
# Patch managed by http://www.holgerschurig.de/patcher.html
#
--- /dev/null
+++ linux/drivers/leds/ledscore.c
@@ -0,0 +1,281 @@
+/*
+ * linux/drivers/leds/ledscore.c
+ *
+ * Copyright (C) 2004 John Lenz <lenz@cs.wisc.edu>
+ *
+ * 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/config.h>
+#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/leds.h>
+
+#define LEDS_TIMER_INTERVAL (HZ * 5)
+
+struct led_device {
+ /* This protects the props field.*/
+ spinlock_t lock;
+ /* If props is NULL, the driver that registered this device has been unloaded */
+ struct led_properties *props;
+ struct class_device class_dev;
+ struct list_head list;
+};
+
+#define to_led_device(d) container_of(d, struct led_device, class_dev)
+
+static rwlock_t leds_list_lock = RW_LOCK_UNLOCKED;
+static LIST_HEAD(leds_list);
+static atomic_t leds_count = ATOMIC_INIT(0);
+
+static void leds_class_release(struct class_device *dev)
+{
+ struct led_device *d = to_led_device(dev);
+
+ write_lock(&leds_list_lock);
+ list_del(&d->list);
+ write_unlock(&leds_list_lock);
+
+ kfree(d);
+}
+
+static struct class leds_class = {
+ .name = "leds",
+ .release = leds_class_release,
+};
+
+static ssize_t leds_show_color(struct class_device *dev, char *buf)
+{
+ struct led_device *led_dev = to_led_device(dev);
+ ssize_t ret = 0;
+
+ spin_lock(&led_dev->lock);
+ if (likely(led_dev->props)) {
+ sprintf(buf, "%s\n", led_dev->props->color);
+ ret = strlen(buf) + 1;
+ }
+ spin_unlock(&led_dev->lock);
+
+ return ret;
+}
+
+static CLASS_DEVICE_ATTR(color, 0444, leds_show_color, NULL);
+
+static ssize_t leds_show_light(struct class_device *dev, char *buf)
+{
+ struct led_device *led_dev = to_led_device(dev);
+ ssize_t ret = 0;
+
+ spin_lock(&led_dev->lock);
+ if (likely(led_dev->props)) {
+ sprintf(buf, "%lu\n", led_dev->props->light_state);
+ ret = strlen(buf) + 1;
+ }
+ spin_unlock(&led_dev->lock);
+
+ return ret;
+}
+
+static ssize_t leds_store_light(struct class_device *dev, const char *buf, size_t size)
+{
+ struct led_device *led_dev = to_led_device(dev);
+ int ret = -EINVAL;
+ char *after;
+
+ unsigned long state = simple_strtoul(buf, &after, 10);
+ if (after - buf > 0) {
+ ret = after - buf;
+ spin_lock(&led_dev->lock);
+ if (likely(led_dev->props)) {
+ if (!led_dev->props->heartbeat_enabled) {
+ led_dev->props->light_state = state;
+ if (led_dev->props->light)
+ led_dev->props->light(led_dev->class_dev.dev, led_dev->props);
+ }
+ }
+ spin_unlock(&led_dev->lock);
+ }
+
+ return ret;
+}
+
+static CLASS_DEVICE_ATTR(light, 0644, leds_show_light, leds_store_light);
+
+static ssize_t leds_show_heartbeat(struct class_device *dev, char *buf)
+{
+ struct led_device *led_dev = to_led_device(dev);
+ ssize_t ret = 0;
+
+ spin_lock(&led_dev->lock);
+ if (likely(led_dev->props)) {
+ sprintf(buf, "%lu\n", led_dev->props->heartbeat_enabled);
+ ret = strlen(buf) + 1;
+ }
+ spin_unlock(&led_dev->lock);
+
+ return ret;
+}
+
+static ssize_t leds_store_heartbeat(struct class_device *dev, const char *buf, size_t size)
+{
+ struct led_device *led_dev = to_led_device(dev);
+ int ret = -EINVAL;
+
+ spin_lock(&led_dev->lock);
+ if (likely(led_dev->props)) {
+ if (buf[0] == '1') {
+ led_dev->props->heartbeat_enabled = 1;
+ } else {
+ led_dev->props->heartbeat_enabled = 0;
+ }
+ }
+ spin_unlock(&led_dev->lock);
+
+ return ret;
+}
+
+static CLASS_DEVICE_ATTR(heartbeat_enabled, 0644, leds_show_heartbeat, leds_store_heartbeat);
+
+/**
+ * leds_device_register - register a new object of led_device class.
+ * @dev: The device to register.
+ * @prop: the led properties structure for this device.
+ */
+int leds_device_register(struct device *dev, struct led_properties *props)
+{
+ int rc, num;
+ struct led_device *new_led;
+
+ new_led = kmalloc (sizeof (struct led_device), GFP_KERNEL);
+ if (unlikely (!new_led))
+ return -ENOMEM;
+
+ spin_lock_init(&new_led->lock);
+ new_led->props = props;
+ props->led_dev = new_led;
+
+ memset (&new_led->class_dev, 0, sizeof (new_led->class_dev));
+ new_led->class_dev.class = &leds_class;
+ new_led->class_dev.dev = dev;
+
+ /* assign this led a number */
+ num = atomic_add_return(1, &leds_count);
+ sprintf(new_led->class_dev.class_id, "%i", num);
+
+ rc = class_device_register (&new_led->class_dev);
+ if (unlikely (rc)) {
+ kfree (new_led);
+ return rc;
+ }
+
+ /* register the attributes */
+ class_device_create_file(&new_led->class_dev, &class_device_attr_color);
+ class_device_create_file(&new_led->class_dev, &class_device_attr_light);
+ class_device_create_file(&new_led->class_dev, &class_device_attr_heartbeat_enabled);
+
+ /* add to the list of leds */
+ write_lock(&leds_list_lock);
+ list_add_tail(&new_led->list, &leds_list);
+ write_unlock(&leds_list_lock);
+
+ printk(KERN_INFO "Registered led device: number=%s, color=%s\n", new_led->class_dev.class_id, props->color);
+
+ return 0;
+}
+EXPORT_SYMBOL(leds_device_register);
+
+/**
+ * led_device_unregister - unregisters a object of led_properties class.
+ * @props: the property to unreigister
+ *
+ * Unregisters a previously registered via led_device_register object.
+ */
+void leds_device_unregister(struct led_properties *props)
+{
+ struct led_device *led_dev;
+ if (!props)
+ return;
+
+ pr_debug("led_device_unregister: color=%s\n", props->color);
+
+ led_dev = props->led_dev;
+
+ class_device_remove_file (&led_dev->class_dev, &class_device_attr_heartbeat_enabled);
+ class_device_remove_file (&led_dev->class_dev, &class_device_attr_light);
+ class_device_remove_file (&led_dev->class_dev, &class_device_attr_color);
+
+ spin_lock(&led_dev->lock);
+ led_dev->props = NULL;
+ props->led_dev = NULL;
+ spin_unlock(&led_dev->lock);
+
+ class_device_unregister(&led_dev->class_dev);
+}
+EXPORT_SYMBOL(leds_device_unregister);
+
+/* set up a kernel timer */
+static struct timer_list leds_ktimer;
+static atomic_t leds_stop_timer = ATOMIC_INIT(0);
+
+static void leds_timer_function(unsigned long data)
+{
+ struct led_device *led_dev;
+
+ read_lock(&leds_list_lock);
+ list_for_each_entry(led_dev, &leds_list, list) {
+ spin_lock(&led_dev->lock);
+ if (likely(led_dev->props)) {
+ if (led_dev->props->heartbeat_enabled) {
+ led_dev->props->light_state = !led_dev->props->light_state;
+ if (led_dev->props->light)
+ led_dev->props->light(led_dev->class_dev.dev, led_dev->props);
+ }
+ }
+ spin_unlock(&led_dev->lock);
+ }
+ read_unlock(&leds_list_lock);
+
+ if (!atomic_read(&leds_stop_timer))
+ mod_timer(&leds_ktimer, jiffies + LEDS_TIMER_INTERVAL);
+}
+
+static int __init leds_init(void)
+{
+ int ret = 0;
+
+ /* initialize the class device */
+ class_register(&leds_class);
+
+ /* register the timer */
+ init_timer(&leds_ktimer);
+ leds_ktimer.function = leds_timer_function;
+ leds_ktimer.data = 0;
+ leds_ktimer.expires = jiffies + LEDS_TIMER_INTERVAL;
+ add_timer(&leds_ktimer);
+
+ return ret;
+}
+subsys_initcall(leds_init);
+
+static void __exit leds_exit(void)
+{
+ class_unregister(&leds_class);
+
+ atomic_set(&leds_stop_timer, 1);
+
+ del_timer_sync(&leds_ktimer);
+}
+module_exit(leds_exit);
+
+MODULE_AUTHOR("John Lenz");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LED core class interface");
+
--- /dev/null
+++ linux/include/linux/leds.h
@@ -0,0 +1,46 @@
+/*
+ * linux/include/leds.h
+ *
+ * Copyright (C) 2004 John Lenz <lenz@cs.wisc.edu>
+ *
+ * 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.
+ *
+ * Driver model for leds
+ */
+#ifndef ASM_ARM_LEDS_H
+#define ASM_ARM_LEDS_H
+
+#include <linux/device.h>
+
+struct led_device;
+
+struct led_properties {
+ struct module *owner;
+
+ /* Color of the led. For multiple color leds, the color names should
+ * be seperated by a "/". For example, "amber/green".
+ */
+ char *color;
+
+ /* current state of this led.
+ * 0 = off, 1,2,3,... = on, where the number is the posision in the list
+ * of colors given above.
+ */
+ unsigned long light_state;
+
+ /* heartbeat enabled on this led */
+ int heartbeat_enabled;
+
+ /* This function is called after the light_state property is changed. */
+ void (*light)(struct device *, struct led_properties *props);
+
+ /* private structure */
+ struct led_device *led_dev;
+};
+
+int leds_device_register(struct device *dev, struct led_properties *props);
+void leds_device_unregister(struct led_properties *props);
+
+#endif
--- /dev/null
+++ linux/drivers/leds/Kconfig
@@ -0,0 +1,11 @@
+
+menu "LED devices"
+
+config CLASS_LEDS
+ tristate "LED support"
+ help
+ This option provides the generic support for the leds class.
+ LEDs can be accessed from /sys/class/leds. It will also allow you
+ to select individual drivers for LED devices. If unsure, say N.
+
+endmenu
--- /dev/null
+++ linux/drivers/leds/Makefile
@@ -0,0 +1,3 @@
+
+# Core functionality.
+obj-$(CONFIG_CLASS_LEDS) += ledscore.o
--- linux/drivers/Kconfig~leds_sysfs
+++ linux/drivers/Kconfig
@@ -48,6 +48,8 @@
source "drivers/media/Kconfig"
+source "drivers/leds/Kconfig"
+
source "drivers/video/Kconfig"
source "sound/Kconfig"
--- linux/drivers/Makefile~leds_sysfs
+++ linux/drivers/Makefile
@@ -50,4 +50,5 @@
obj-$(CONFIG_MCA) += mca/
obj-$(CONFIG_EISA) += eisa/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
+obj-$(CONFIG_CLASS_LEDS) += leds/
obj-y += firmware/
next prev parent reply other threads:[~2004-09-03 20:42 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-09-02 20:33 [PATCH 2.6.8.1 0/2] leds: new class for led devices John Lenz
2004-09-02 20:34 ` [PATCH 2.6.8.1 1/2] " John Lenz
2004-09-02 20:38 ` [PATCH 2.6.8.1 2/2] " John Lenz
2004-09-03 4:54 ` [PATCH 2.6.8.1 0/2] " Kalin KOZHUHAROV
2004-09-03 11:32 ` Geert Uytterhoeven
2004-09-03 12:06 ` Jan-Benedict Glaw
2004-09-03 18:47 ` John Lenz
2004-09-03 22:25 ` Russell King
2004-09-03 23:19 ` John Lenz
2004-09-04 11:12 ` Pavel Machek
2004-09-04 20:53 ` Russell King
2004-09-04 21:41 ` Pavel Machek
2004-09-06 7:36 ` John Lenz
2004-09-03 13:17 ` Robert Schwebel
2004-09-03 13:31 ` Robert Schwebel
2004-09-03 8:00 ` Oliver Neukum
2004-09-03 13:51 ` Pavel Machek
2004-09-03 18:38 ` John Lenz
2004-09-03 18:55 ` Russell King
2004-09-03 19:09 ` John Lenz
2004-09-03 19:51 ` Russell King
2004-09-03 20:35 ` John Lenz [this message]
2004-09-04 11:09 ` Pavel Machek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1094243721l.7429l.3l@hydra \
--to=lenz@cs.wisc.edu \
--cc=linux-kernel@vger.kernel.org \
--cc=rmk+lkml@arm.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.