All of lore.kernel.org
 help / color / mirror / Atom feed
* [sparc32] Kernel module to control front LED
@ 2005-08-26 17:21 Metalhead
  2005-09-27 20:28 ` David S. Miller
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Metalhead @ 2005-08-26 17:21 UTC (permalink / raw)
  To: sparclinux

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

Hi all,

 I've written a kernel module that allows you to control the fron LED on
Sparcstations via /proc. It can also be compiled into the kernel, supporting
display of the system load (a la NetBSD and OpenBSD) then.

Please find the patch against a vanilla 2.4.30 tree included. The sources and
the patch can also be found at http://www.metalhead.ws/led.tar.gz.

diff -uprN linux-2.4.30-vanilla/Documentation/Configure.help linux-2.4.30-mod/Documentation/Configure.help
--- linux-2.4.30-vanilla/Documentation/Configure.help	2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.30-mod/Documentation/Configure.help	2005-08-25 20:32:22.000000000 +0000
@@ -23069,6 +23083,17 @@ CONFIG_SUN_OPENPROMFS
   <file:Documentation/modules.txt>.
   The module will be called openpromfs.o.  If unsure, say M.
 
+Control front LED on sun4m machines via /proc/led (EXPERIMENTAL)
+CONFIG_SUN_LED
+  This allows you to control the front LED on sun4m machines via /proc/led. The
+  state of the LED can also be queried.
+
+  On, off and toggle do what their names suggest, an integer number makes the
+  LED blink at this interval seconds, load makes it blink according to the
+  system load (not available when compiled as a module).
+
+  If unsure, say N.
+
 Kernel support for Linux/Sparc 32bit binary compatibility
 CONFIG_SPARC32_COMPAT
   This allows you to run 32-bit binaries on your Ultra.
diff -uprN linux-2.4.30-vanilla/arch/sparc/config.in linux-2.4.30-mod/arch/sparc/config.in
--- linux-2.4.30-vanilla/arch/sparc/config.in	2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.30-mod/arch/sparc/config.in	2005-08-25 20:32:38.000000000 +0000
@@ -64,6 +64,10 @@ else
    define_bool CONFIG_PCI n
 fi
 
+if [ "$CONFIG_PROC_FS" = "y" ]; then
+   tristate 'Control front LED on sun4m machines via /proc/led (EXPERIMENTAL)' CONFIG_SUN_LED
+fi
+
 tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
diff -uprN linux-2.4.30-vanilla/arch/sparc/kernel/Makefile linux-2.4.30-mod/arch/sparc/kernel/Makefile
--- linux-2.4.30-vanilla/arch/sparc/kernel/Makefile	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.30-mod/arch/sparc/kernel/Makefile	2005-08-25 20:32:59.000000000 +0000
@@ -33,6 +33,7 @@ obj-$(CONFIG_SMP) += trampoline.o smp.o 
 obj-$(CONFIG_SUN_AUXIO) += auxio.o
 obj-$(CONFIG_PCI) += ebus.o
 obj-$(CONFIG_SUN_PM) += apc.o pmc.o
+obj-$(CONFIG_SUN_LED) += led.o
 
 ifdef CONFIG_SUNOS_EMUL
 obj-y += sys_sunos.o sunos_ioctl.o
diff -uprN linux-2.4.30-vanilla/arch/sparc/kernel/led.c linux-2.4.30-mod/arch/sparc/kernel/led.c
--- linux-2.4.30-vanilla/arch/sparc/kernel/led.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.30-mod/arch/sparc/kernel/led.c	2005-08-25 20:32:03.000000000 +0000
@@ -0,0 +1,170 @@
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/auxio.h>
+#include <asm/uaccess.h>
+
+#define MODULE_VERSION "0.1"
+#define MODULE_NAME "led"
+
+MODULE_AUTHOR("Lars Kotthoff <metalhead@metalhead.ws>");
+MODULE_DESCRIPTION("Provides control of the front LED on SPARC systems.");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
+#define LED_MAX_LENGTH 8 /* maximum chars written to proc file */
+
+struct proc_dir_entry *led;
+struct timer_list led_blink_timer;
+
+inline void print_debug(const char *msg)
+{
+	printk(KERN_DEBUG "[%s] %s\n", MODULE_NAME, msg);
+}
+
+inline void led_toggle(void)
+{
+	/* set_auxio takes 2 arguments, first the bits to enable, second the
+	 * bits to disable (huh?) */
+	set_auxio(get_auxio() ^ AUXIO_LED, get_auxio() & AUXIO_LED);
+}
+
+void led_blink(unsigned long timeout)
+{
+	led_toggle();
+
+	/* reschedule */
+#ifndef CONFIG_SUN_LED_MODULE
+	if(!timeout) { /* blink according to load */
+		led_blink_timer.expires = jiffies +
+			((1 + (avenrun[0] >> FSHIFT)) * HZ);
+		/* avenrun isn't exported by the kernel, hence the ifndefs */
+		led_blink_timer.data = 0;
+	} else { /* blink at user specified interval */
+#endif
+		led_blink_timer.expires = jiffies + (timeout * HZ);
+		led_blink_timer.data = timeout;
+#ifndef CONFIG_SUN_LED_MODULE
+	}
+#endif
+	add_timer(&led_blink_timer);
+}
+
+int led_read_proc(char *buf, char **start, off_t offset, int count,
+		int *eof, void *data)
+{
+	int len = 0;
+
+	MOD_INC_USE_COUNT;
+
+	if(get_auxio() & AUXIO_LED) {
+		len = sprintf(buf, "on\n");
+	} else {
+		len = sprintf(buf, "off\n");
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return len;
+}
+
+int led_write_proc(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+	char *buf = NULL;
+	unsigned long l = 0;
+
+	if(count > LED_MAX_LENGTH) {
+		count = LED_MAX_LENGTH;
+	}
+
+	buf = kmalloc(sizeof(char) * (count + 1), GFP_KERNEL);
+	if(!buf) {
+		return -ENOMEM;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	if(copy_from_user(buf, buffer, count)) {
+		MOD_DEC_USE_COUNT;
+		kfree(buf);
+		return -EFAULT;
+	}
+	buf[count] = '\0';
+
+	/* work around \n when echo'ing into proc */
+	if(buf[count - 1] == '\n') {
+		buf[count - 1] = '\0';
+	}
+
+	/* before we change anything we want to stop any running timers,
+	 * otherwise calls such as on will have no persistent effect */
+	if(timer_pending(&led_blink_timer)) {
+		del_timer_sync(&led_blink_timer);
+	}
+
+	if(!strcmp(buf, "on")) {
+		print_debug("Turning LED on...");
+		auxio_set_led(AUXIO_LED_ON);
+	} else if(!strcmp(buf, "toggle")) {
+		print_debug("Toggling LED...");
+		led_toggle();
+	} else if((*buf > '0') && (*buf <= '9')) { /* 0 would cause division by
+						      zero */
+		for(l = 0; *buf != '\0'; buf++) { /* convert to number */
+			l = 10 * l + (*buf - '0');
+		}
+		print_debug("Starting to blink...");
+		led_blink(l);
+#ifndef CONFIG_SUN_LED_MODULE
+	} else if(!strcmp(buf, "load")) {
+		print_debug("Starting to display load...");
+		led_blink(0);
+#endif
+	} else {
+		print_debug("Turning LED off...");
+		auxio_set_led(AUXIO_LED_OFF);
+	}
+
+	MOD_DEC_USE_COUNT;
+	kfree(buf);
+
+	return count;
+}
+
+static int __init init_led(void)
+{
+	led = create_proc_entry(MODULE_NAME,
+			0, /* default mode */
+			NULL /* parent dir */);
+	if(!led) {
+		return -ENOMEM;
+	}
+
+	led->read_proc = led_read_proc; /* reader function */
+	led->write_proc = led_write_proc; /* writer function */
+	led->owner = THIS_MODULE;
+
+	/* initialize timer for blinking */
+	init_timer(&led_blink_timer);
+	led_blink_timer.function = led_blink; /* blinking function */
+
+	printk(KERN_INFO
+		"%s version %s, Lars Kotthoff <metalhead@metalhead.ws>\n",
+		MODULE_NAME, MODULE_VERSION);
+
+	return 0;
+}
+
+static void __exit cleanup_led(void)
+{
+	remove_proc_entry(MODULE_NAME, NULL);
+	if(timer_pending(&led_blink_timer)) { /* kill timer if necessary */
+		del_timer_sync(&led_blink_timer);
+	}
+}
+
+module_init(init_led);
+module_exit(cleanup_led);

-- 
They say that bandaging one's wounds helps to keep up one's appearance.

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2005-09-28 14:28 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-08-26 17:21 [sparc32] Kernel module to control front LED Metalhead
2005-09-27 20:28 ` David S. Miller
2005-09-27 21:18 ` Arnaldo Carvalho de Melo
2005-09-27 22:09 ` David S. Miller
2005-09-28  0:39 ` Eric Brower
2005-09-28  0:48 ` Arnaldo Carvalho de Melo
2005-09-28  4:38 ` David S. Miller
2005-09-28  7:09 ` Christian Joensson
2005-09-28 14:28 ` Metalhead

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.