mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: John Lenz <lenz@cs.wisc.edu>
To: linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2.6.8.1 1/2] leds: new class for led devices
Date: Thu, 02 Sep 2004 20:34:36 +0000	[thread overview]
Message-ID: <1094157276l.4235l.3l@hydra> (raw)
In-Reply-To: <1094157190l.4235l.2l@hydra>

[-- Attachment #1: Type: text/plain, Size: 88 bytes --]

This provides the base ledscore.c support.

Signed-off-by: John Lenz <lenz@cs.wisc.edu>

[-- Attachment #2: leds_sysfs.patch --]
[-- Type: text/x-patch, Size: 10908 bytes --]


#
# Patch managed by http://www.holgerschurig.de/patcher.html
#

--- /dev/null
+++ linux/drivers/leds/ledscore.c
@@ -0,0 +1,314 @@
+/*
+ * 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);
+
+struct leds_function_name {
+	const char *		name;
+	enum led_functions	function;
+};
+static const struct leds_function_name leds_function_names[] = {
+	{ "user",	leds_user },
+	{ "timer",	leds_timer },
+	{ "idle",	leds_idle },
+	{ "power",	leds_power },
+};
+
+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->function == leds_user) {
+				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_function(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", leds_function_names[(int)led_dev->props->function].name);
+		ret = strlen(buf) + 1;
+	}
+	spin_unlock(&led_dev->lock);
+
+	return ret;
+}
+
+static ssize_t leds_store_function(struct class_device *dev, const char *buf, size_t size)
+{
+	struct led_device *led_dev = to_led_device(dev);
+	int ret = -EINVAL;
+	int i;
+	
+	for (i = 0; i < ARRAY_SIZE(leds_function_names); i++) {
+		if (strncmp(buf, leds_function_names[i].name, strlen(leds_function_names[i].name)) == 0) {
+			ret = size;
+			spin_lock(&led_dev->lock);
+			if (likely(led_dev->props)) {
+				led_dev->props->function = leds_function_names[i].function;
+			}
+			spin_unlock(&led_dev->lock);
+		}
+	}
+
+	return ret;
+}
+
+static CLASS_DEVICE_ATTR(function, 0644, leds_show_function, leds_store_function);
+
+/**
+ * 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_function);
+
+	/* 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_function);
+	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->function == leds_timer) {
+				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);
+}
+
+/* arch code should call this function from the idle thread */
+void leds_idle_function(int state)
+{
+	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->function == leds_idle) {
+				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);
+	}
+	read_unlock(&leds_list_lock);
+}
+
+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 <lenz@cs.wisc.edu>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LED core class interface");
+
--- /dev/null
+++ linux/include/linux/leds.h
@@ -0,0 +1,53 @@
+/*
+ *  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>
+
+enum led_functions {
+	leds_user = 0,	/* user has control of this led through sysfs */
+	leds_timer,	/* led blinks on a timer */
+	leds_idle,	/* led is on when the system is not idle */
+	leds_power,
+};
+
+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;
+
+	/* current function of this led */
+	enum led_functions function;
+
+	/* 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/


  reply	other threads:[~2004-09-03  3:01 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] " John Lenz
2004-09-02 20:34 ` John Lenz [this message]
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
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=1094157276l.4235l.3l@hydra \
    --to=lenz@cs.wisc.edu \
    --cc=linux-kernel@vger.kernel.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome