linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: PATCH : LEDs - possibly the most pointless kernel subsystem ever
@ 2003-07-29 20:38 John Bradford
  2003-07-29 20:37 ` Andries Brouwer
                   ` (2 more replies)
  0 siblings, 3 replies; 36+ messages in thread
From: John Bradford @ 2003-07-29 20:38 UTC (permalink / raw)
  To: john, linux-kernel, pgw99

> > This patch adds an abstraction layer for programmable LED devices,
> > hardware drivers for the Status LEDs found on some Intel PIIX4E based
> > server hardware (notably the ISP1100 1U rackmount server) and LEDs wired
> > to the parallel port data lines.
>
> I haven't had chance to test this yet, but I really like the idea - by
> an amasing co-incidence, I was actually thinking about the possibility
> of doing a parallel port connected front panel earlier today!
>
> Does anybody have any suggestions for recommended standard uses for
> parallel port connected LEDs?
>
> Disk spinning up/disk ready
> Root login active
>
> Any other suggestions?

Ah, I just thought, for debugging purposes we could have LEDs for:

* BKL taken
* Servicing interrupt
* Kernel stack usage > 2K

John.

^ permalink raw reply	[flat|nested] 36+ messages in thread
* Re: PATCH : LEDs - possibly the most pointless kernel subsystem ever
@ 2003-07-30 18:50 John Bradford
  0 siblings, 0 replies; 36+ messages in thread
From: John Bradford @ 2003-07-30 18:50 UTC (permalink / raw)
  To: john, pavel; +Cc: linux-kernel, pgw99

> > > But this kind of blinkenlights needed pretty fast LEDs. (At 486 time
> > > I decided that parport on ISA is fast enough..)
> > 
> > I'll buy some LEDs and build a parallel port connected LED panel
> > tomorrow...  Do you think the overhead of driving the LEDs would have
> > too much of a negative effect on system performance?  If so, or if
> > we
>
> I'm not sure. At 486 days I was pretty sure it did not matter. These
> days you might get 10% slowdown on some microbenchmark, or something
> like that. I do not think it can slow down common tasks.

OK, so no problems there...

> My construction of LED lights is extremely flaky, and I'm afraid of
> burning printer port. At 486 days ports were expected to survive such
> abuse. Not sure if todays EPP/wtf ports can handle that.

This could be a problem, though - now I've looked in to it, the
maximum recommended current drain on the parallel port seems to be
really low :-(.

I've CC'ed Alan - maybe he can offer some advice.

(Alan - basically we're thinking of using this LED-on-parallel-port
driver for a standardised 'front panel', showing things like interrupt
being serviced, BKL taken, etc, for debugging purposes.)

John.

^ permalink raw reply	[flat|nested] 36+ messages in thread
* Re: PATCH : LEDs - possibly the most pointless kernel subsystem ever
@ 2003-07-30 16:08 John Bradford
  2003-07-30 17:44 ` Pavel Machek
  2003-07-31  8:31 ` jw schultz
  0 siblings, 2 replies; 36+ messages in thread
From: John Bradford @ 2003-07-30 16:08 UTC (permalink / raw)
  To: john, pavel; +Cc: linux-kernel, pgw99

> > Does anybody have any suggestions for recommended standard uses for
> > parallel port connected LEDs?

> At one point I had 12 LEDs on parport. LEDs were fast enough to be
> drive at interrupt entry/exit.
> They were: 
> Yellow not idle task
> Green interrupt
> " bh
> " pagefault
> Red lowest 4 bits of PID
> Red, low intensity serial i/o
> " network i/o
>
> It actually looked very good. Glow of interrupt led told you
> interrupt load, pid LEDs told you about what kind of load it is
> experiencing (you could tell shell script from make and from
> computation, and if machine hard-died, you at least knew if it was
> interrupt or process context). 

Sounds like exactly what we need.  If we standardise on something like
the above, we could just have a CONFIG_FRONT_PANEL_MONITOR and ask
people to send in the LED status with bug reports.

> But this kind of blinkenlights needed pretty fast LEDs. (At 486 time
> I decided that parport on ISA is fast enough..)

I'll buy some LEDs and build a parallel port connected LED panel
tomorrow...  Do you think the overhead of driving the LEDs would have
too much of a negative effect on system performance?  If so, or if we
want more flexibility, maybe we could work out a design for a PCI
card, which could include more than 12 LEDs - 7-segment numeric
displays of pid, etc.

John.

^ permalink raw reply	[flat|nested] 36+ messages in thread
* Re: PATCH : LEDs - possibly the most pointless kernel subsystem ever
@ 2003-07-30 15:50 John Bradford
  0 siblings, 0 replies; 36+ messages in thread
From: John Bradford @ 2003-07-30 15:50 UTC (permalink / raw)
  To: aebr, cat; +Cc: linux-kernel, pgw99

> > Would this (now or in the future) by any chance let one use the keyboard
> > leds for stuff without activating their num lock, caps lock and scroll
> > lock functionality? I'd like to use one of them (at least) as a network
> > traffic indicator but so far I get the sideffects of the functionality
> > being on also. Most annoying when typing. :/
>
> The use of LEDs as random lights instead of as keyboard status indicators
> has been possible since very early times. See the kernel code, or setleds(1).

The keyboard LEDs are far too slow to access to use for 'front-panel'
type applications, though.

John.

^ permalink raw reply	[flat|nested] 36+ messages in thread
* Re: PATCH : LEDs - possibly the most pointless kernel subsystem ever
@ 2003-07-30 12:27 "Andrey Borzenkov" 
  0 siblings, 0 replies; 36+ messages in thread
From: "Andrey Borzenkov"  @ 2003-07-30 12:27 UTC (permalink / raw)
  To: linux-kernel


> This patch adds an abstraction layer for programmable LED devices,
> hardware drivers for the Status LEDs found on some Intel PIIX4E based
> server hardware (notably the ISP1100 1U rackmount server) and LEDs wired
> to the parallel port data lines.

Sorry for a bit OT but - anybody has experience with ASUS I-Panel?
It plugs into SM bus, has several buttons, diodes and LEDs. Some of
buttons are apparently programmable and LED can be used to cycle
through sensor information.

It should be accessible via normal i2c interface but I could not find
any description. Also pressing button when some sensor-aware program
runs gives funny results sometimes :)

TIA

-andrey


^ permalink raw reply	[flat|nested] 36+ messages in thread
* Re: PATCH : LEDs - possibly the most pointless kernel subsystem ever
@ 2003-07-29 19:15 John Bradford
  2003-07-29 19:51 ` Tim Hockin
                   ` (3 more replies)
  0 siblings, 4 replies; 36+ messages in thread
From: John Bradford @ 2003-07-29 19:15 UTC (permalink / raw)
  To: linux-kernel, pgw99

> This patch adds an abstraction layer for programmable LED devices,
> hardware drivers for the Status LEDs found on some Intel PIIX4E based
> server hardware (notably the ISP1100 1U rackmount server) and LEDs wired
> to the parallel port data lines.

I haven't had chance to test this yet, but I really like the idea - by
an amasing co-incidence, I was actually thinking about the possibility
of doing a parallel port connected front panel earlier today!

Does anybody have any suggestions for recommended standard uses for
parallel port connected LEDs?

Disk spinning up/disk ready
Root login active

Any other suggestions?

John.

^ permalink raw reply	[flat|nested] 36+ messages in thread
* PATCH : LEDs - possibly the most pointless kernel subsystem ever
@ 2003-07-29 15:17 Philip Graham Willoughby
  2003-07-29 18:00 ` Pavel Machek
                   ` (2 more replies)
  0 siblings, 3 replies; 36+ messages in thread
From: Philip Graham Willoughby @ 2003-07-29 15:17 UTC (permalink / raw)
  To: Linux Kernel Mailing List

Hi all,

This patch adds an abstraction layer for programmable LED devices,
hardware drivers for the Status LEDs found on some Intel PIIX4E based
server hardware (notably the ISP1100 1U rackmount server) and LEDs wired
to the parallel port data lines.

It also includes a kernel-space heartbeat module and a module to monitor
a user-space program, both of which will flash an LED while the system
is happy.

I'm sorry for not involving all of you earlier, but I had to obtain the
permission of my boss to GPL this, and he was out of the country.

This patch is against the 2.4 series (specifically 2.4.21, but it should
apply against any 2.4) -- the code part of the patch is fine on 2.[56] but
the config stuff obviously needs changing.

The user-level software for this can be downloaded from
http://csgsoft.doc.ic.ac.uk/leds/

Please cc me on replies as I'm only on the digest list...

Regards,

Philip Willoughby
Systems Programmer, Department of Computing, Imperial College, London, UK


diff -uNr linux-2.4.21.vanilla/arch/i386/config.in linux-2.4.21.patched/arch/i386/config.in
--- linux-2.4.21.vanilla/arch/i386/config.in	2003-07-17 17:06:01.000000000 +0100
+++ linux-2.4.21.patched/arch/i386/config.in	2003-07-29 15:28:17.000000000 +0100
@@ -485,3 +485,4 @@
 endmenu
 
 source lib/Config.in
+source drivers/leds/Config.in
diff -uNr linux-2.4.21.vanilla/Documentation/Configure.help linux-2.4.21.patched/Documentation/Configure.help
--- linux-2.4.21.vanilla/Documentation/Configure.help	2003-07-17 17:07:00.000000000 +0100
+++ linux-2.4.21.patched/Documentation/Configure.help	2003-07-29 15:28:17.000000000 +0100
@@ -26649,6 +26649,53 @@
 CONFIG_IPMI_WATCHDOG
   This enables the IPMI watchdog timer.
 
+LED Subsystem Support
+CONFIG_LEDS
+  Enables support for LED devices.
+
+Intel PIIX4E LED Support
+CONFIG_PIIX4E_LEDS
+  Enables support for the programmable LEDs on some Intel PIIX4E-based
+  mainboards.  One such board is contained in the Intel ISP1100
+  server.  If you don't have an Intel PIIX4E this driver will do
+  nothing.  On boards with the LEDs unconnected, this driver _should_
+  do no harm, but I have not been able to test it on all such boards.
+  It should be safe to load this driver (Y or M) on all machines, if
+  you find a problem, please contact me:
+
+  Philip Willoughby <pgw@alumni.doc.ic.ac.uk>
+
+  Put "PIIX4E LED BUG" in the subject line please.
+
+Parallel Port LED Support
+CONFIG_PARPORT_LEDS
+  Enables support for a bank of 8 LEDs connected to the parallel port.
+  These devices are extremely simple and cannot be autodetected.  I
+  recommend you do not load this driver unless you are sure you have
+  such a device attached.  Say N here unless you really know what
+  you're doing.
+
+Kernel Heartbeat LED
+CONFIG_KBEAT_LED
+  Enables a kernel-resident piece of code which will toggle the status
+  of a LED twice per second.  Useful as a liveness indicator.  This
+  will do nothing if you do not have any LED hardware drivers loaded.
+
+  If you build this code as a module, you can tune the flash interval
+  with module parameters.
+
+User Heartbeat
+CONFIG_UBEAT
+  Enables a kernel-resident piece of code which monitors a user daemon
+  (ubeatd).  While the user-level code is working fine, a LED will
+  flash.  In the event of a failure, a message will be logged through
+  the normal kernel logging facilities.
+
+  If you have no LED hardware, this code will still work -- no LEDs
+  will flash, but the failure message will still work.
+
+  ubeatd can be downloaded from http://csgsoft.doc.ic.ac.uk/leds/
+
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
diff -uNr linux-2.4.21.vanilla/drivers/leds/Config.in linux-2.4.21.patched/drivers/leds/Config.in
--- linux-2.4.21.vanilla/drivers/leds/Config.in	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.21.patched/drivers/leds/Config.in	2003-07-29 15:28:17.000000000 +0100
@@ -0,0 +1,21 @@
+#
+# LED device configuration
+#
+mainmenu_option next_comment
+comment 'LED Subsystem'
+
+tristate 'LED Subsystem Support' CONFIG_LEDS
+if [ "$CONFIG_LEDS" != "n" ]; then
+comment 'LED hardware drivers'
+  if [ "$CONFIG_X86" = "y" -a "$CONFIG_X86_64" != "y" ]; then
+    dep_tristate 'Intel PIIX4E LED Support' CONFIG_PIIX4E_LEDS $CONFIG_LEDS
+  fi
+  if [ "$CONFIG_PARPORT" != "n" ]; then
+    dep_tristate 'Parallel Port LED Support (Read Help)' CONFIG_PARPORT_LEDS $CONFIG_LEDS $CONFIG_PARPORT
+  fi
+comment 'LED-using software'
+  dep_tristate 'Kernel Heartbeat LED' CONFIG_KBEAT_LED $CONFIG_LEDS
+  dep_tristate 'User Heartbeat' CONFIG_UBEAT $CONFIG_LEDS
+fi
+
+endmenu
diff -uNr linux-2.4.21.vanilla/drivers/leds/kbeat_led.c linux-2.4.21.patched/drivers/leds/kbeat_led.c
--- linux-2.4.21.vanilla/drivers/leds/kbeat_led.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.21.patched/drivers/leds/kbeat_led.c	2003-07-22 14:05:54.000000000 +0100
@@ -0,0 +1,58 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+static unsigned int kbeat_led;
+static unsigned char kbeat_state = 0;
+
+static struct timer_list kbeat_timer;
+static unsigned int kbeat_stps __initdata = 2;
+static unsigned int kbeat_interval = HZ/2;
+
+static void
+kbeat_beat (unsigned long GoOnGccWarnMeThen)
+{
+  kbeat_state = ~kbeat_state;
+  led_set (kbeat_led, kbeat_state, THIS_MODULE);
+  /* init_timer(&kbeat_timer); */
+  kbeat_timer.expires=jiffies + kbeat_interval;
+  kbeat_timer.function=kbeat_beat;
+  add_timer(&kbeat_timer);
+}
+
+void __exit
+kbeat_exit(void)
+{
+  del_timer_sync (&kbeat_timer);
+  led_release(kbeat_led, THIS_MODULE);
+}
+
+int __init
+kbeat_init(void)
+{
+  if (led_reserve(&kbeat_led, THIS_MODULE) == 0)
+  {
+    printk(KERN_INFO "kbeat_led: got LED %.8x\n", kbeat_led);
+    if ((kbeat_stps <= 0) || ((kbeat_interval = HZ/kbeat_stps) == 0))
+      kbeat_interval = HZ/2;
+    init_timer(&kbeat_timer);
+    kbeat_timer.expires=jiffies + kbeat_interval;
+    kbeat_timer.function=kbeat_beat;
+    add_timer(&kbeat_timer);
+    return 0;
+  }
+  return -ENODEV;
+}
+
+module_init (kbeat_init);
+module_exit (kbeat_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philip Graham Willoughby <pgw@alumni.doc.ic.ac.uk>");
+MODULE_DESCRIPTION("Blinks a LED to indicate the kernel is alive and well");
+MODULE_PARM(kbeat_stps, "i");
+MODULE_PARM_DESC(kbeat_stps, "State changes per second for the kernel controlled LED.");
+EXPORT_NO_SYMBOLS;
diff -uNr linux-2.4.21.vanilla/drivers/leds/leds.c linux-2.4.21.patched/drivers/leds/leds.c
--- linux-2.4.21.vanilla/drivers/leds/leds.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.21.patched/drivers/leds/leds.c	2003-07-29 15:22:49.000000000 +0100
@@ -0,0 +1,595 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+static struct list_head led_list;
+static rwlock_t led_list_lock = RW_LOCK_UNLOCKED;
+static unsigned int leds_major_num;
+static devfs_handle_t ledsdir;
+static devfs_handle_t ledsctl;
+static int have_devfs = 0;
+
+static void
+del_all_owned_by_pid (pid_t who, struct linux_leds_info *leds)
+{
+  int i;
+  if (leds->owners == NULL)
+    return;
+  for (i = 0 ; i < leds->count ; ++i)
+    if ((leds->owners[i].ownertype == leds_user) && (leds->owners[i].ownerdata.processdata.pid == who))
+    {
+      leds->owners[i].ownertype = leds_noone;
+      leds->release(leds->data);
+    }
+}
+
+static void
+release_all_owned_by_pid (pid_t pid)
+{
+  struct list_head *hd;
+  write_lock(&led_list_lock);
+  hd = &led_list;
+  while (hd->next != &led_list)
+  {
+    hd = hd->next;
+    del_all_owned_by_pid (pid, (struct linux_leds_info *)hd);
+  }
+  write_unlock(&led_list_lock);
+}
+
+static void
+del_all_owned_by(struct led_owner *who, struct linux_leds_info *leds)
+{
+  int i;
+  if (leds->owners == NULL)
+    return;
+  for (i = 0 ; i < leds->count ; ++i)
+  {
+    switch (who->ownertype)
+    {
+      case leds_noone:
+	break;
+      case leds_kernel:
+	if (leds->owners[i].ownerdata.module == who->ownerdata.module)
+	{
+	  leds->owners[i].ownertype = leds_noone;
+	  leds->release(leds->data);
+	}
+	break;
+      case leds_user:
+	if ((leds->owners[i].ownerdata.processdata.pid == who->ownerdata.processdata.pid) && (leds->owners[i].ownerdata.processdata.uid == who->ownerdata.processdata.uid))
+	{
+	  leds->owners[i].ownertype = leds_noone;
+	  leds->release(leds->data);
+	}
+    }
+  }
+}
+
+static void
+release_all_owned_by(struct led_owner *pid)
+{
+  struct list_head *hd;
+  write_lock(&led_list_lock);
+  hd = &led_list;
+  while (hd->next != &led_list)
+  {
+    hd = hd->next;
+    del_all_owned_by (pid, (struct linux_leds_info *)hd);
+  }
+  write_unlock(&led_list_lock);
+}
+
+int leds_read_proc (char *buf, char **start, off_t offset, int count, int *eof, void *data)
+{
+  int len = 0;
+  int i;
+  int id;
+  struct list_head *hd;
+  *start=buf;
+  if (offset == 0)
+  {
+    len += sprintf (buf+len, "LED ID:           PID/Module Name:  UID:              \n");
+  }
+  else
+  {
+    offset /= 55;
+    --offset; /* The header -- almost forgot ;-) */
+  }
+  read_lock(&led_list_lock);
+  hd = &led_list;
+  while ((hd->next != &led_list) && ( len + 55 <= count))
+  {
+    hd = hd->next;
+    if (((struct linux_leds_info *)hd)->count < offset)
+    {
+      offset -=((struct linux_leds_info *)hd)->count;
+      continue;
+    }
+    for (i=0 ; i < ((struct linux_leds_info *)hd)->count ; ++i)
+    {
+      if (i >= offset)
+      {
+	if ( len + 55 > count)
+	{
+	  read_unlock(&led_list_lock);
+	  return len;
+	}
+	id = ((struct linux_leds_info *)hd)->id;
+	id <<= 24;
+	id |= i;
+	len += sprintf (buf+len, "%.16X  ", id);
+	if (((struct linux_leds_info *)hd)->owners == NULL)
+	{
+	  len += sprintf (buf+len, "Not allocated                       \n");
+	}
+	else if (((struct linux_leds_info *)hd)->owners[i].ownertype == leds_noone)
+	{
+	  len += sprintf (buf+len, "Not allocated                       \n");
+	}
+	else if (((struct linux_leds_info *)hd)->owners[i].ownertype == leds_kernel)
+	{
+	  int c;
+	  c = sprintf (buf+len, "%.36s", ((struct linux_leds_info *)hd)->owners[i].ownerdata.module->name);
+	  len += c;
+	  while (c < 36)
+	  {
+	    len += sprintf (buf+len, " ");
+	    ++c;
+	  }
+	  len += sprintf (buf+len, "\n");
+	}
+	else if (((struct linux_leds_info *)hd)->owners[i].ownertype == leds_user)
+	{
+	  int c;
+	  c = sprintf (buf+len, "%-16u", ((struct linux_leds_info *)hd)->owners[i].ownerdata.processdata.pid);
+	  len += c;
+	  while (c < 18)
+	  {
+	    len += sprintf (buf+len, " ");
+	    ++c;
+	  }
+	  c = sprintf (buf+len, "%-16u", ((struct linux_leds_info *)hd)->owners[i].ownerdata.processdata.uid);
+	  len += c;
+	  while (c < 18)
+	  {
+	    len += sprintf (buf+len, " ");
+	    ++c;
+	  }
+	  len += sprintf (buf+len, "\n");
+	}
+	else
+	{
+	  len += sprintf (buf+len,"Corrupted structure encountered     \n");
+	}
+      }
+    }
+    offset = 0;
+  }
+  read_unlock(&led_list_lock);
+  *eof = 1;
+  return len;
+}
+
+int
+leds_add (struct linux_leds_info *leds)
+{
+  struct list_head *hd;
+  MOD_INC_USE_COUNT;
+  INIT_LIST_HEAD(&leds->list);
+  leds->owners=NULL;
+  leds->id=0;
+  write_lock(&led_list_lock);
+  hd = &led_list;
+  while (hd->next != &led_list)
+  {
+    hd = hd->next;
+    if (leds->id < ((struct linux_leds_info *)hd)->id)
+    {
+      list_add_tail(&leds->list, hd);
+      write_unlock(&led_list_lock);
+      return 0;
+    }
+    ++leds->id;
+  }
+  list_add_tail(&leds->list, &led_list);
+  write_unlock(&led_list_lock);
+  return 0;
+}
+
+int
+leds_del (struct linux_leds_info *leds)
+{
+  MOD_DEC_USE_COUNT;
+  write_lock(&led_list_lock);
+  list_del (&leds->list);
+  write_unlock(&led_list_lock);
+  return 0;
+}
+
+unsigned int
+leds_count(void)
+{
+  unsigned int cnt = 0;
+  struct list_head *hd;
+  read_lock(&led_list_lock);
+  hd = &led_list;
+  while (hd->next != &led_list)
+  {
+    hd = hd->next;
+    cnt += ((struct linux_leds_info *)hd)->count;
+  }
+  read_unlock(&led_list_lock);
+  return cnt;
+}
+
+static int
+del_led_owner(struct led_owner *who, unsigned int idx, struct linux_leds_info *leds)
+{
+  if (leds->owners == NULL)
+    return -EBUSY;
+  if (leds->owners[idx].ownertype == leds_noone)
+    return -EBUSY;
+  if (leds->owners[idx].ownertype != who->ownertype)
+    return -EPERM;
+  switch (who->ownertype)
+  {
+    case leds_noone:
+      return -EBADFD;
+    case leds_user:
+      if (leds->owners[idx].ownerdata.processdata.pid != who->ownerdata.processdata.pid)
+	return -EPERM;
+      leds->owners[idx].ownertype = leds_noone;
+      return 0;
+    case leds_kernel:
+      if (leds->owners[idx].ownerdata.module != who->ownerdata.module)
+	return -EPERM;
+      leds->owners[idx].ownertype = leds_noone;
+      return 0;
+  }
+  return -EBUSY;
+}
+
+static int
+add_led_owner(struct led_owner *who, unsigned int idx, struct linux_leds_info *leds)
+{
+  if (leds->owners == NULL)
+  {
+    int i;
+    leds->owners = kmalloc (leds->count * sizeof(struct led_owner), GFP_KERNEL);
+    if (leds->owners == NULL)
+      return -ENOMEM;
+    for (i = 0 ; i < leds->count ; ++i)
+    {
+      leds->owners[i].ownertype = leds_noone;
+    }
+  }
+  if (leds->owners[idx].ownertype == leds_noone)
+  {
+    leds->owners[idx].ownertype = who->ownertype;
+    switch (who->ownertype)
+    {
+      case leds_noone:
+	return -EBADFD;
+	break;
+      case leds_user:
+	leds->owners[idx].ownerdata.processdata.pid = who->ownerdata.processdata.pid;
+	leds->owners[idx].ownerdata.processdata.uid = who->ownerdata.processdata.uid;
+	return 0;
+	break;
+      case leds_kernel:
+	leds->owners[idx].ownerdata.module = who->ownerdata.module;
+	return 0;
+    }
+  }
+  return -EBUSY;
+}
+
+static int
+is_allowed(struct led_owner *who, unsigned int idx, struct linux_leds_info *leds)
+{
+  int ret = -EBUSY;
+  read_lock(&led_list_lock);
+  if (leds->owners == NULL)
+    ret = 0;
+  if (leds->owners[idx].ownertype == who->ownertype)
+  {
+    switch (who->ownertype)
+    {
+      case leds_noone:
+	break;
+      case leds_user:
+	if (leds->owners[idx].ownerdata.processdata.pid != who->ownerdata.processdata.pid)
+	  break;
+	ret = 0;
+	break;
+      case leds_kernel:
+	if (leds->owners[idx].ownerdata.module != who->ownerdata.module)
+	  break;
+	ret = 0;
+    }
+  }
+  read_unlock(&led_list_lock);
+  return ret;
+}
+
+static int
+led_release_real(struct led_owner *who, unsigned int which)
+{
+  struct list_head *hd;
+  int tmp;
+  write_lock(&led_list_lock);
+  hd = &led_list;
+  while (hd->next != &led_list)
+  {
+    hd = hd->next;
+    if (((which >> 24) & 0xff) == ((struct linux_leds_info *)hd)->id)
+    {
+      if ((tmp = del_led_owner(who, which & 0xffffff, (struct linux_leds_info *)hd)) == 0)
+      {
+	((struct linux_leds_info *)hd)->release(((struct linux_leds_info *)hd)->data);
+      }
+      write_unlock(&led_list_lock);
+      return tmp;
+    }
+  }
+  write_unlock(&led_list_lock);
+  return -ENODEV;
+}
+
+static int
+led_reserve_real(struct led_owner *who, unsigned int *which)
+{
+  struct list_head *hd;
+  int tmp;
+  write_lock(&led_list_lock);
+  hd = &led_list;
+  while (hd->next != &led_list)
+  {
+    int i;
+    hd = hd->next;
+    for (i=0 ; i < ((struct linux_leds_info *)hd)->count ; ++i)
+    {
+      if ((tmp = add_led_owner(who, i, (struct linux_leds_info *)hd)) == 0)
+      {
+	*which = ((struct linux_leds_info *)hd)->id;
+	*which <<= 24;
+	*which |= i;
+	((struct linux_leds_info *)hd)->reserve(((struct linux_leds_info *)hd)->data);
+	write_unlock(&led_list_lock);
+	return tmp;
+      }
+    }
+  }
+  write_unlock(&led_list_lock);
+  return -ENODEV;
+}
+
+static int
+led_set_real (struct led_owner *who, unsigned int which, unsigned char state)
+{
+  struct list_head *hd;
+  int ret;
+  read_lock(&led_list_lock);
+  hd = &led_list;
+  if (state) state=~0;
+  while (hd->next != &led_list)
+  {
+    hd = hd->next;
+    if (((which >> 24) & 0xff) == ((struct linux_leds_info *)hd)->id)
+    {
+      if ((which & 0xffffff) > ((struct linux_leds_info *)hd)->count)
+      {
+	read_unlock(&led_list_lock);
+	return -ENODEV;
+      }
+      if ((ret = is_allowed(who, which & 0xffffff, (struct linux_leds_info *)hd)) == 0)
+	((struct linux_leds_info *)hd)->set_state(which & 0xffffff, state, ((struct linux_leds_info *)hd)->data);
+      read_unlock(&led_list_lock);
+      return ret;
+    }
+  }
+  read_unlock(&led_list_lock);
+  return -ENODEV;
+}
+
+int led_release (unsigned int idx, struct module *mod)
+{
+  struct led_owner a;
+  a.ownertype = leds_kernel;
+  a.ownerdata.module = mod;
+  return led_release_real(&a, idx);
+}
+
+int led_reserve (unsigned int *which, struct module *mod)
+{
+  struct led_owner a;
+  a.ownertype = leds_kernel;
+  a.ownerdata.module = mod;
+  return led_reserve_real(&a, which);
+}
+
+int
+led_set(unsigned int idx, unsigned char state, struct module *mod)
+{
+  struct led_owner a;
+  a.ownertype = leds_kernel;
+  a.ownerdata.module = mod;
+  return led_set_real(&a, idx, state);
+}
+
+int
+led_get(unsigned int which)
+{
+  struct list_head *hd;
+  unsigned char state;
+  read_lock(&led_list_lock);
+  hd = &led_list;
+  while (hd->next != &led_list)
+  {
+    hd = hd->next;
+    if (((which >> 24) & 0xff) == ((struct linux_leds_info *)hd)->id)
+    {
+      if ((which & 0xffffff) > ((struct linux_leds_info *)hd)->count)
+      {
+	read_unlock(&led_list_lock);
+	return -ENODEV;
+      }
+      state = ((struct linux_leds_info *)hd)->get_state(which & 0xffffff, ((struct linux_leds_info *)hd)->data);
+      read_unlock(&led_list_lock);
+      if (state) state=~0;
+      return state;
+    }
+  }
+  read_unlock(&led_list_lock);
+  return -ENODEV;
+}
+
+static int
+leds_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+  unsigned int idx;
+  unsigned char state;
+  signed int tmp;
+  struct led_owner a;
+  pid_t pid;
+  if (MINOR(inode->i_rdev) != 0xff) {
+    return -ENOTTY;
+  }
+  if (_IOC_TYPE(cmd) != LINUX_LEDS_IOC_MAGIC) {
+    return -ENOTTY;
+  }
+  if (_IOC_NR(cmd) > LINUX_LEDS_IOC_MAX_NR) {
+    return -ENOTTY;
+  }
+  if ((_IOC_DIR(cmd) & _IOC_READ) && (!access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd))))
+    return -EFAULT;
+  else if ((_IOC_DIR(cmd) & _IOC_WRITE) && (!access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd))))
+    return -EFAULT;
+  a.ownertype = leds_user;
+  a.ownerdata.processdata.pid = current->tgid;
+  a.ownerdata.processdata.uid = current->uid;
+  switch (cmd)
+  {
+    case LINUX_LEDS_IOC_COUNT_LEDS:
+      idx = leds_count();
+      __put_user(idx, (unsigned int *)arg);
+      return 0;
+    case LINUX_LEDS_IOC_SET_LED:
+      __get_user (idx, &(((struct linux_leds *)arg)->idx));
+      __get_user (state, &(((struct linux_leds *)arg)->state));
+      return led_set_real (&a, idx, state);
+    case LINUX_LEDS_IOC_GET_LED:
+      __get_user (idx, &(((struct linux_leds *)arg)->idx));
+      tmp = led_get(idx);
+      if (tmp < 0)
+	return tmp;
+      state = ((unsigned int)tmp) &0xff;
+      __put_user (state, &(((struct linux_leds *)arg)->state));
+      return 0;
+    case LINUX_LEDS_IOC_RESERVE_LED:
+      tmp = led_reserve_real (&a, &idx);
+      __put_user (idx, (unsigned int *)arg);
+      return tmp;
+    case LINUX_LEDS_IOC_RELEASE_LED:
+      __get_user (idx, (unsigned int *)arg);
+      return led_release_real (&a, idx);
+    case LINUX_LEDS_IOC_BREAK_LOCK:
+      __get_user (pid, (pid_t *)arg);
+      if (!capable(CAP_DAC_OVERRIDE))
+      {
+	a.ownerdata.processdata.pid = pid;
+	release_all_owned_by (&a);
+      }
+      else
+	release_all_owned_by_pid(pid);
+      return 0;
+  }
+  /* Unreachable code */
+  return -ENOTTY;
+}
+
+static int
+leds_open (struct inode *inode, struct file *filp)
+{
+  if (MINOR(inode->i_rdev) != 0xff) return -ENODEV;
+  MOD_INC_USE_COUNT;
+  return 0;
+}
+
+static int
+leds_release (struct inode *inode, struct file *filp)
+{
+  release_all_owned_by_pid (current->tgid);
+  MOD_DEC_USE_COUNT;
+  return 0;
+}
+
+struct file_operations leds_fops = {
+open: leds_open,
+release: leds_release,
+ioctl: leds_ioctl,
+owner: THIS_MODULE,
+};
+
+void __exit
+leds_exit (void)
+{
+  remove_proc_entry("leds", NULL);
+  if (have_devfs)
+  {
+    devfs_unregister (ledsctl);
+    devfs_unregister (ledsdir);
+  }
+  unregister_chrdev(leds_major_num, "leds");
+}
+
+int __init
+leds_init (void)
+{
+  int maj;
+  maj = register_chrdev(0, "leds", &leds_fops);
+  if (maj < 0) return maj;
+  leds_major_num = maj;
+  printk(KERN_NOTICE "leds: assigned major number %u\n", leds_major_num);
+  write_lock(&led_list_lock);
+  INIT_LIST_HEAD(&led_list);
+  write_unlock(&led_list_lock);
+  ledsdir = devfs_mk_dir (NULL, "leds", NULL);
+  if (ledsdir != NULL)
+  {
+    have_devfs = 1;
+    ledsctl = devfs_register (ledsdir, "ctl", DEVFS_FL_DEFAULT, leds_major_num, 0xff, S_IFCHR | 0666 , &leds_fops, NULL);
+    if (ledsctl == NULL)
+    {
+      devfs_unregister (ledsdir);
+      unregister_chrdev(leds_major_num, "leds");
+      return -EBUSY;
+    }
+  }
+  create_proc_read_entry("leds", 0, NULL, leds_read_proc, NULL);
+  return 0;
+}
+
+module_init(leds_init);
+module_exit(leds_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philip Graham Willoughby <pgw@alumni.doc.ic.ac.uk>");
+MODULE_DESCRIPTION("Provides a generic kernel interface for LED control");
+EXPORT_SYMBOL(led_get);
+EXPORT_SYMBOL(led_set);
+EXPORT_SYMBOL(led_reserve);
+EXPORT_SYMBOL(led_release);
+EXPORT_SYMBOL(leds_count);
+EXPORT_SYMBOL(leds_add);
+EXPORT_SYMBOL(leds_del);
diff -uNr linux-2.4.21.vanilla/drivers/leds/Makefile linux-2.4.21.patched/drivers/leds/Makefile
--- linux-2.4.21.vanilla/drivers/leds/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.21.patched/drivers/leds/Makefile	2003-07-29 15:29:31.000000000 +0100
@@ -0,0 +1,20 @@
+#
+# Makefile for the kernel LED device drivers.
+#
+
+obj-y:=
+
+obj-m:=
+
+# All of the (potential) objects that export symbols.
+# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
+
+export-objs:=leds.o
+
+obj-$(CONFIG_LEDS) += leds.o
+obj-$(CONFIG_PIIX4E_LEDS) += piix4e_leds.o
+obj-$(CONFIG_PARPORT_LEDS) += parport_leds.o
+obj-$(CONFIG_KBEAT_LED) += kbeat_led.o
+obj-$(CONFIG_UBEAT) += ubeat.o
+
+include $(TOPDIR)/Rules.make
diff -uNr linux-2.4.21.vanilla/drivers/leds/parport_leds.c linux-2.4.21.patched/drivers/leds/parport_leds.c
--- linux-2.4.21.vanilla/drivers/leds/parport_leds.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.21.patched/drivers/leds/parport_leds.c	2003-07-22 13:55:10.000000000 +0100
@@ -0,0 +1,144 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/errno.h>
+#include <linux/leds.h>
+#include <linux/spinlock.h>
+
+static spinlock_t parled_lock= SPIN_LOCK_UNLOCKED;
+static unsigned char parled_state = 0;
+static int parled_parport = -1;
+static struct pardevice *parleds_dev = NULL;
+
+static void
+release (void *ignore)
+{
+  MOD_DEC_USE_COUNT;
+}
+
+static void
+reserve (void *ignore)
+{
+  MOD_INC_USE_COUNT;
+}
+
+static void
+set_state (unsigned int idx, unsigned char state, void *ignore)
+{
+  spin_lock(&parled_lock);
+  parled_state &= ~(1 << idx);
+  parled_state |= state & (1 << idx);
+  parleds_dev->port->ops->write_data (parleds_dev->port, parled_state);
+  spin_unlock(&parled_lock);
+}
+
+static unsigned char
+get_state (unsigned int idx, void *ignore)
+{
+  unsigned char reg;
+  spin_lock(&parled_lock);
+  reg = parled_state;
+  spin_unlock(&parled_lock);
+  reg &= (1 << idx);
+  return reg;
+}
+
+static void
+attach (struct parport *thing)
+{
+  if (parled_parport >= 0)
+    return;
+  for (parled_parport = 0 ; parled_parport < PARPORT_MAX ; ++parled_parport)
+  {
+    if (thing == NULL)
+    {
+      printk (KERN_DEBUG "parport_leds: Moo %d\n", parled_parport);
+      continue;
+    }
+    if (thing->number == parled_parport)
+    {
+      struct pardevice *dev;
+      dev = parport_register_device (thing, "leds", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+      if (dev == NULL)
+      {
+	printk (KERN_DEBUG "parport_leds: Baa %d\n", parled_parport);
+	continue;
+      }
+      if (!parport_claim (dev) == 0)
+      {
+	parled_parport = -1;
+      }
+      else
+      {
+	parleds_dev = thing->devices;
+      }
+      return;
+    }
+  }
+  parled_parport = -1;
+  return;
+}
+
+static void
+detach (struct parport *thing)
+{
+}
+
+static struct linux_leds_info parleds = {
+get_state:get_state,
+set_state:set_state,
+reserve:reserve,
+release:release,
+count:8,
+drivername:THIS_MODULE,
+};
+
+static struct parport_driver parleds_driver = {
+name:"parleds",
+attach:attach,
+detach:detach,
+};
+
+int __init
+init_parallel_leds (void)
+{
+  int c;
+  if (parport_register_driver (&parleds_driver) != 0)
+  {
+    printk (KERN_INFO "parport_leds: parport_register_driver failed\n");
+    return -EIO;
+  }
+  if (parled_parport < 0)
+  {
+    parport_unregister_driver (&parleds_driver);
+    printk (KERN_INFO "parport_leds: couldn't claim a parallel port\n");
+    return -EIO;
+  }
+  c = leds_add (&parleds);
+  if (c != 0)
+  {
+    parport_unregister_driver (&parleds_driver);
+    printk (KERN_INFO "parport_leds: leds_add failed\n");
+    return -ENODEV;
+  }
+  return c;
+}
+
+void __exit
+cleanup_parallel_leds (void)
+{
+  leds_del (&parleds);
+  parport_release (parleds_dev);
+  parport_unregister_device (parleds_dev);
+  parport_unregister_driver (&parleds_driver);
+}
+
+module_init(init_parallel_leds);
+module_exit(cleanup_parallel_leds);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philip Graham Willoughby <pgw@alumni.doc.ic.ac.uk>");
+MODULE_DESCRIPTION("This module provides kernel control for programmable LEDs wired up to the parallel port");
+MODULE_SUPPORTED_DEVICE("Parallel port LED boxes");
+EXPORT_NO_SYMBOLS;
+
diff -uNr linux-2.4.21.vanilla/drivers/leds/piix4e_leds.c linux-2.4.21.patched/drivers/leds/piix4e_leds.c
--- linux-2.4.21.vanilla/drivers/leds/piix4e_leds.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.21.patched/drivers/leds/piix4e_leds.c	2003-07-22 13:54:46.000000000 +0100
@@ -0,0 +1,116 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/leds.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
+static const unsigned char bxled_mask[] = {0x01, 0x10};
+static const unsigned short bxled_port[] = {0x0435, 0x0437};
+static spinlock_t bxled_lock[] = {SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED};
+
+static void
+release (void * ignored)
+{
+  MOD_DEC_USE_COUNT;
+}
+
+static void
+reserve (void * ignored)
+{
+  MOD_INC_USE_COUNT;
+}
+
+static void
+set_state (unsigned int idx, unsigned char state, void *ignored)
+{
+  unsigned char reg;
+  spin_lock(&bxled_lock[idx]);
+  reg = inb(bxled_port[idx]);
+  reg &= ~bxled_mask[idx];
+  reg |= state & bxled_mask[idx];
+  outb (reg, bxled_port[idx]);
+  spin_unlock(&bxled_lock[idx]);
+}
+
+static unsigned char
+get_state (unsigned int idx, void * ignored)
+{
+  unsigned char reg;
+  spin_lock(&bxled_lock[idx]);
+  reg = inb(bxled_port[idx]);
+  spin_unlock(&bxled_lock[idx]);
+  reg &= bxled_mask[idx];
+  return reg;
+}
+
+static struct linux_leds_info bxleds = {
+get_state:get_state,
+set_state:set_state,
+reserve:reserve,
+release:release,
+count:2,
+data:NULL,
+drivername:THIS_MODULE,
+};
+
+int __init
+init_isp1100_lights (void)
+{
+  int c;
+  if (!pci_present())
+    return -ENODEV;
+  if (!(pci_find_device(PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_82371AB_3,NULL)))
+    return -ENODEV;
+  if (!request_region (bxled_port[0], 1, "Intel PIIX4E LED U1"))
+    return -EBUSY;
+  c = -EBUSY;
+  if (!request_region (bxled_port[1], 1, "Intel PIIX4E LED U2"))
+    goto cleanup_zero;
+  /* Now check if there are actually LEDs there.  Boards with them unconnected
+   * seem to lose the status of the IO port -- I therefore assume, if the bit
+   * sticks, poke it
+   */
+  c = -ENODEV;
+  set_state (0, 0, NULL);
+  set_state (1, 0, NULL);
+  if (get_state (0, NULL))
+    goto cleanup_both;
+  if (get_state (1, NULL))
+    goto cleanup_both;
+  set_state (0, ~0, NULL);
+  set_state (1, ~0, NULL);
+  if (!get_state (0, NULL))
+    goto cleanup_both;
+  if (!get_state (1, NULL))
+    goto cleanup_both;
+  c = leds_add (&bxleds);
+  if (c != 0)
+    goto cleanup_both;
+  return c;
+cleanup_both:
+  release_region (bxled_port[1], 1);
+cleanup_zero:
+  release_region (bxled_port[0], 1);
+  return c;
+}
+
+void __exit
+cleanup_isp1100_lights (void)
+{
+  leds_del (&bxleds);
+  release_region (bxled_port[1], 1);
+  release_region (bxled_port[0], 1);
+}
+
+module_init(init_isp1100_lights);
+module_exit(cleanup_isp1100_lights);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philip Graham Willoughby <pgw@alumni.doc.ic.ac.uk>");
+MODULE_DESCRIPTION("This module provides kernel control for the programmable LEDs on Intel PIIX4E Systems");
+MODULE_SUPPORTED_DEVICE("Intel PIIX4E Chipset");
+EXPORT_NO_SYMBOLS;
+
diff -uNr linux-2.4.21.vanilla/drivers/leds/ubeat.c linux-2.4.21.patched/drivers/leds/ubeat.c
--- linux-2.4.21.vanilla/drivers/leds/ubeat.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.21.patched/drivers/leds/ubeat.c	2003-07-22 14:06:38.000000000 +0100
@@ -0,0 +1,187 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ubeat.h>
+#include <linux/leds.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/ioctl.h>
+
+static unsigned int ubeat_major_num;
+static volatile int ubeat_have_led = 0;
+static int have_devfs = 0;
+static unsigned int ubeat_led;
+static volatile unsigned char ubeat_state = 0;
+static struct timer_list ubeat_timer;
+static unsigned int ubeat_interval;
+static signed int ubeat_timeout __initdata = 2;
+static devfs_handle_t ubeatdir;
+static devfs_handle_t ubeatctl;
+static spinlock_t ubeat_use_lock = SPIN_LOCK_UNLOCKED;
+static volatile int inuse = 0;
+static atomic_t ubeat_carp;
+
+static void
+ubeat_timeup (unsigned long ignored)
+{
+  if (atomic_read(&ubeat_carp) == 0)
+    return;
+  atomic_set (&ubeat_carp, 0);
+  printk(KERN_ALERT "ubeat: User heartbeat not detected - FIX ME!!!!\n");
+}
+
+static int
+ubeat_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+  if (MINOR(inode->i_rdev) != 0)
+  {
+    printk( KERN_DEBUG "ubeat: Minor number was %u\n", MINOR(inode->i_rdev));
+    return -ENODEV;
+  }
+  if (_IOC_TYPE(cmd) != LINUX_UBEAT_IOC_MAGIC)
+  {
+    printk( KERN_DEBUG "ubeat: Magic number was 0x%x\n", _IOC_TYPE(cmd));
+    return -ENOTTY;
+  }
+  if (_IOC_NR(cmd) > LINUX_UBEAT_IOC_MAX_NR)
+  {
+    printk( KERN_DEBUG "ubeat: Command number was %u\n", _IOC_NR(cmd));
+    return -ENOTTY;
+  }
+  switch (cmd)
+  {
+    case LINUX_UBEAT_IOC_POKE:
+      spin_lock(&ubeat_use_lock);
+      del_timer_sync(&ubeat_timer);
+      ubeat_timer.expires = jiffies + ubeat_interval;
+      add_timer(&ubeat_timer);
+      spin_unlock(&ubeat_use_lock);
+      if (ubeat_have_led)
+      {
+	led_set(ubeat_led, ubeat_state, THIS_MODULE);
+	ubeat_state = ~ubeat_state;
+      }
+      return 0;
+    case LINUX_UBEAT_IOC_FIXT:
+      spin_lock(&ubeat_use_lock);
+      del_timer_sync(&ubeat_timer);
+      ubeat_timer.expires = jiffies + ubeat_interval;
+      add_timer(&ubeat_timer);
+      spin_unlock(&ubeat_use_lock);
+      atomic_set (&ubeat_carp, 1);
+      return 0;
+  }
+  return -ENOTTY;
+}
+
+
+static int
+ubeat_open (struct inode *inode, struct file *filp)
+{
+  MOD_INC_USE_COUNT;
+  spin_lock(&ubeat_use_lock);
+  ++inuse;
+  del_timer_sync(&ubeat_timer);
+  ubeat_timer.expires = jiffies + ubeat_interval;
+  add_timer(&ubeat_timer);
+  spin_unlock(&ubeat_use_lock);
+  return 0;
+}
+
+static int
+ubeat_release (struct inode *inode, struct file *filp)
+{
+  MOD_DEC_USE_COUNT;
+  spin_lock(&ubeat_use_lock);
+  --inuse;
+  if (inuse == 0)
+  {
+    del_timer_sync(&ubeat_timer);
+    atomic_set (&ubeat_carp, 1);
+  }
+  spin_unlock(&ubeat_use_lock);
+  return 0;
+}
+
+
+static struct file_operations ubeat_fops = {
+open: ubeat_open,
+release: ubeat_release,
+ioctl: ubeat_ioctl,
+owner: THIS_MODULE,
+};
+
+void __exit
+ubeat_exit(void)
+{
+  del_timer_sync(&ubeat_timer);
+  if (ubeat_have_led)
+    led_release(ubeat_led, THIS_MODULE);
+  if (have_devfs)
+  {
+    devfs_unregister (ubeatctl);
+    devfs_unregister (ubeatdir);
+  }
+  unregister_chrdev(ubeat_major_num, "ubeat");
+}
+
+int __init
+ubeat_init(void)
+{
+  int maj;
+  atomic_set (&ubeat_carp, 1);
+  maj = register_chrdev(0, "ubeat", &ubeat_fops);
+  if (maj < 0) return maj;
+  ubeat_major_num = maj;
+  printk (KERN_NOTICE "ubeat: got major number %u\n", ubeat_major_num);
+  ubeatdir = devfs_mk_dir(NULL, "ubeat", NULL);
+  if (ubeatdir != NULL)
+  {
+    have_devfs = 1;
+    unregister_chrdev(ubeat_major_num, "ubeat");
+    ubeatctl = devfs_register (ubeatdir, "pokeme", DEVFS_FL_DEFAULT, ubeat_major_num, 0, S_IFCHR | 0660 , &ubeat_fops, NULL);
+    if (ubeatctl == NULL)
+    {
+      devfs_unregister (ubeatdir);
+      unregister_chrdev(ubeat_major_num, "ubeat");
+      return -EBUSY;
+    }
+  }
+  if (led_reserve(&ubeat_led, THIS_MODULE) == 0)
+  {
+    printk (KERN_INFO "ubeat_led: got led %.8x\n", ubeat_led);
+    ubeat_have_led = 1;
+  }
+  if (ubeat_timeout == 0)
+  {
+    printk (KERN_INFO "ubeat_led: timeout value '0' is invalid, using 2\n");
+    ubeat_timeout = 2;
+  }
+  if (ubeat_timeout < 0)
+  {
+    ubeat_interval = HZ / (-1 * ubeat_timeout);
+  } else {
+    ubeat_interval = HZ * ubeat_timeout;
+  }
+  if (ubeat_interval == 0)
+  {
+    printk (KERN_INFO "ubeat_led: timeout value out of range, using 2\n");
+    ubeat_interval = 2 * HZ;
+  }
+  init_timer (&ubeat_timer);
+  ubeat_timer.function = ubeat_timeup;
+  return 0;
+}
+
+module_init(ubeat_init);
+module_exit(ubeat_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philip Graham Willoughby <pgw@alumni.doc.ic.ac.uk>");
+MODULE_DESCRIPTION("Provides kernel interface to keep an eye on user programs");
+EXPORT_NO_SYMBOLS;
+MODULE_PARM(ubeat_timeout, "i");
+MODULE_PARM_DESC(ubeat_timeout, "Seconds before the kernel should alert you, fractions below 1s can be specified with -ve numbers e.g. -2 means wait 1/2 a second.");
diff -uNr linux-2.4.21.vanilla/drivers/Makefile linux-2.4.21.patched/drivers/Makefile
--- linux-2.4.21.vanilla/drivers/Makefile	2003-07-17 17:04:35.000000000 +0100
+++ linux-2.4.21.patched/drivers/Makefile	2003-07-29 15:28:17.000000000 +0100
@@ -48,5 +48,6 @@
 subdir-$(CONFIG_ACPI)		+= acpi
 
 subdir-$(CONFIG_BLUEZ)		+= bluetooth
+subdir-$(CONFIG_LEDS)		+= leds
 
 include $(TOPDIR)/Rules.make
diff -uNr linux-2.4.21.vanilla/include/linux/leds.h linux-2.4.21.patched/include/linux/leds.h
--- linux-2.4.21.vanilla/include/linux/leds.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.21.patched/include/linux/leds.h	2003-07-22 14:07:52.000000000 +0100
@@ -0,0 +1,68 @@
+#ifndef LINUX_LEDS_H__
+#define LINUX_LEDS_H__
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+
+enum ownertype
+{
+  leds_noone = 0,
+  leds_kernel,
+  leds_user,
+};
+
+struct led_owner
+{
+  enum ownertype ownertype;
+  union
+  {
+    struct module *module;
+    struct {
+      pid_t pid;
+      uid_t uid;
+    } processdata;
+  } ownerdata;
+};
+
+struct linux_leds_info
+{
+  struct list_head list;
+  unsigned int id:8;
+  unsigned int count:24;
+  unsigned char (*get_state)(unsigned int, void *);
+  void (*set_state)(unsigned int, unsigned char, void *);
+  void (*reserve)(void *);
+  void (*release)(void *);
+  void *data;
+  struct module *drivername;
+  struct led_owner *owners;
+};
+
+extern int led_get(unsigned int idx);
+extern int led_set(unsigned int idx, unsigned char state, struct module *mod);
+extern int led_reserve(unsigned int *idx, struct module *mod);
+extern int led_release(unsigned int idx, struct module *mod);
+extern unsigned int leds_count(void);
+extern int leds_add (struct linux_leds_info *);
+extern int leds_del (struct linux_leds_info *);
+
+#endif /* defined __KERNEL__ */
+
+#include <linux/ioctl.h>
+
+struct linux_leds {
+  unsigned int idx; /* LEDS are indexed from zero */
+  unsigned char state; /* 0 for off, ~0 for on */
+};
+
+#define LINUX_LEDS_IOC_MAGIC 0x81
+#define LINUX_LEDS_IOC_COUNT_LEDS _IOR(LINUX_LEDS_IOC_MAGIC, 0, unsigned int)
+#define LINUX_LEDS_IOC_SET_LED _IOW(LINUX_LEDS_IOC_MAGIC, 1, struct linux_leds)
+#define LINUX_LEDS_IOC_GET_LED _IOR(LINUX_LEDS_IOC_MAGIC, 2, struct linux_leds)
+#define LINUX_LEDS_IOC_RESERVE_LED _IOR(LINUX_LEDS_IOC_MAGIC, 3, unsigned int)
+#define LINUX_LEDS_IOC_RELEASE_LED _IOW(LINUX_LEDS_IOC_MAGIC, 4, unsigned int)
+#define LINUX_LEDS_IOC_BREAK_LOCK _IOW(LINUX_LEDS_IOC_MAGIC, 5, pid_t)
+#define LINUX_LEDS_IOC_MAX_NR 5
+
+#endif /* ! defined LINUX_LEDS_H__ */
diff -uNr linux-2.4.21.vanilla/include/linux/ubeat.h linux-2.4.21.patched/include/linux/ubeat.h
--- linux-2.4.21.vanilla/include/linux/ubeat.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.21.patched/include/linux/ubeat.h	2003-07-10 21:31:31.000000000 +0100
@@ -0,0 +1,11 @@
+#ifndef LINUX_UBEAT_H__
+#define LINUX_UBEAT_H__
+
+#include <linux/ioctl.h>
+
+#define LINUX_UBEAT_IOC_MAGIC 0x75
+#define LINUX_UBEAT_IOC_POKE _IO(LINUX_UBEAT_IOC_MAGIC, 0)
+#define LINUX_UBEAT_IOC_FIXT _IO(LINUX_UBEAT_IOC_MAGIC, 1)
+#define LINUX_UBEAT_IOC_MAX_NR 1
+
+#endif /* ! defined LINUX_UBEAT_H__ */

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

end of thread, other threads:[~2003-07-31  8:31 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-29 20:38 PATCH : LEDs - possibly the most pointless kernel subsystem ever John Bradford
2003-07-29 20:37 ` Andries Brouwer
2003-07-29 21:34   ` Philip Graham Willoughby
2003-07-29 20:40 ` Randolph Bentson
2003-07-29 21:15   ` Ryan Flowers
2003-07-29 20:43 ` Eli Carter
2003-07-30  6:09   ` Tomas Szepe
2003-07-30  6:37   ` Helge Deller
  -- strict thread matches above, loose matches on Subject: below --
2003-07-30 18:50 John Bradford
2003-07-30 16:08 John Bradford
2003-07-30 17:44 ` Pavel Machek
2003-07-30 18:50   ` Marc Giger
2003-07-30 19:05     ` Herbert Pötzl
2003-07-30 22:22     ` Brian McGroarty
2003-07-30 18:56   ` Herbert Pötzl
2003-07-30 19:02     ` Pavel Machek
2003-07-30 19:06     ` Marc Giger
2003-07-30 19:16       ` Herbert Pötzl
2003-07-31  8:31 ` jw schultz
2003-07-30 15:50 John Bradford
2003-07-30 12:27 "Andrey Borzenkov" 
2003-07-29 19:15 John Bradford
2003-07-29 19:51 ` Tim Hockin
2003-07-29 20:09 ` Joel Jaeggli
2003-07-29 21:20 ` Kent Borg
2003-07-29 21:44   ` Philip Graham Willoughby
2003-07-30 21:44     ` Mike Jagdis
2003-07-30 12:15 ` Pavel Machek
2003-07-29 15:17 Philip Graham Willoughby
2003-07-29 18:00 ` Pavel Machek
2003-07-30 11:45   ` Jamey Hicks
2003-07-30 12:27     ` Pavel Machek
2003-07-30  6:36 ` CaT
2003-07-30 13:00   ` Andries Brouwer
2003-07-30 13:20     ` CaT
2003-07-30 23:28 ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).