diff -urN i8kutils-1.25/i8kctl.c i8kutils-1.25-spb/i8kctl.c
--- i8kutils-1.25/i8kctl.c	2003-12-29 16:50:02.000000000 +0100
+++ i8kutils-1.25-spb/i8kctl.c	2008-08-22 09:57:38.000000000 +0200
@@ -3,6 +3,9 @@
  *
  * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>
  *
+ * fand daemon: ported to i8k by Christian Ostheimer 2008 from
+ * Copyright (C) 2006 Lee Wilmot <dellfand.lee@dinglisch.net>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2, or (at your option) any
@@ -23,6 +26,10 @@
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 
+/* used by fand code */
+#include <unistd.h>
+#include <signal.h>
+
 #include "i8k.h"
 
 #define PROG_VERSION "v1.5 10/11/2001"
@@ -143,6 +150,201 @@
     return args[0];
 }
 
+/* ported from dellfand (2006 Lee Wilmot <dellfand.lee@dinglisch.net>) */
+#define FAND_VERSION 0.9
+#define FAND_ARG_ERROR 2
+#define FAND_FORK_ERROR 3
+#define FAND_SID_ERROR 4
+#define FAND_CHDIR_ERROR 5
+
+enum fand_mode_type { foreground = 0, background, info };
+enum fand_mode_type fand_modeG = info;
+
+int fand_check_args( float sleep_seconds, int off, int low, int high )
+{
+   if ( sleep_seconds < 0.2 ) {
+	   puts(" <sleep_seconds> must be >= 0.2 "); 
+	   return FAND_ARG_ERROR; 
+   }
+   else if( off < 25 || off > 60 ) { 
+	   puts(" <off> must be in range 25..60 "); 
+	   return FAND_ARG_ERROR; 
+   }
+   else if ( low < off || low > 60 ) { 
+	   puts(" <low> must be in range <off>..60 "); 
+	   return FAND_ARG_ERROR;
+   } 
+   else if ( high < low || high > 70 ) { 
+	   puts(" <high> must be in range <low>..70) "); 
+	   return FAND_ARG_ERROR;
+   }
+   else if ( fand_modeG != background && fand_modeG != foreground ) {
+	   puts( "<mode> must be in range 0..1" ); 
+	   return FAND_ARG_ERROR;
+   }
+   return 0;
+}
+
+int fand_do_daemon_setup( void )
+{
+	umask(0);
+         
+	pid_t sid = setsid();
+	if (sid < 0)
+	       return FAND_SID_ERROR;
+
+	if ( (chdir("/")) < 0 )
+		return FAND_CHDIR_ERROR;
+
+	close(STDIN_FILENO);
+	close(STDOUT_FILENO);
+	close(STDERR_FILENO);
+
+	return 0;
+}
+
+void fand_do_main_loop( float sleep_seconds, int off, int low, int high )
+{
+	int done = 0;
+	int last_set_status = -1;
+
+	while ( done == 0 ) {
+		int old_status = i8k_get_fan_status(I8K_FAN_RIGHT);
+		int speed = i8k_get_fan_speed(I8K_FAN_RIGHT);
+		int temp = i8k_get_cpu_temp();
+
+		// Print data in info mode
+		if ( fand_modeG == info ) {
+			printf( "Fan 0 Status %d Speed %d CPU Temp %dC\n", old_status, speed, temp );
+
+			done = 1;
+		}
+		// Amend fan if not mode 2
+		else {
+			int desired_status = old_status;
+	
+   			if ( temp <= off ) 
+				desired_status = 0;
+			else if ( temp >= low && temp < high) 
+				desired_status = 1;
+			else if ( temp >= high )
+				desired_status = 2;
+
+			// Little check it got/stayed set to what we asked last time
+
+			if ( 
+				( last_set_status >= 0 ) &&
+				( last_set_status != old_status )
+			) {
+				fprintf( stderr, "i8kfand: warning: set fan 0 status to %d last cycle, it's now %d (BIOS interference ?)\n", last_set_status, old_status );
+				last_set_status = -2;
+			}
+
+			// Only set fan if it's not what we already want (duh...)
+			//
+			if ( old_status != desired_status )
+				i8k_set_fan( I8K_FAN_RIGHT, desired_status );
+
+			printf( "Fan 0 Status %d->%d Speed %d CPU Temp %dC\n", old_status, desired_status, speed, temp );
+
+			// Record status, unless we've warned once already
+
+			if ( last_set_status != -2 )
+				last_set_status = desired_status;
+
+  			usleep( (long) ( sleep_seconds * (float) 1000000 ) );
+		}
+	}
+}
+
+void fand_prepare_to_exit( void )
+{
+	// If fan is off, set it to low since it will
+	// stay off and laptop will overheat
+	// If it was low or high, leave as is
+	
+	if ( i8k_get_fan_status(I8K_FAN_RIGHT) == 0 )
+		i8k_set_fan( I8K_FAN_RIGHT, I8K_FAN_LOW );
+}
+
+void fand_int_handler( int sig )
+{
+	// Never adjust fan if we only wanted stats
+	if ( fand_modeG != info )
+		fand_prepare_to_exit();
+
+	exit( 0 );
+}
+
+
+
+int
+fand(int argc, char **argv)
+{
+	// register int handler
+	// we want to leave the fan on low when we
+	// get INT in case it was an accidental term
+	
+	(void) signal( SIGINT, fand_int_handler );
+
+	// Process args
+	
+	float sleep_seconds;
+	int off, low, high;
+
+	if ( argc == 1 ) {
+        	// Don't need set mode here for info, it's the default
+		printf("v%.1f: ", FAND_VERSION ); 
+	}
+	else if ( argc == 6 ) {
+		fand_modeG = (enum fand_mode_type) atoi(argv[1]);
+		sscanf( argv[2], "%f", &sleep_seconds );
+		off = atoi(argv[3]);
+		low = atoi(argv[4]);
+		high = atoi(argv[5]);
+	}
+	else { 
+		puts(" usage: i8kfand [<is_daemon=[0|1]> <sleep seconds> <off °C> <low °C> <high °C>]"); 
+		return FAND_ARG_ERROR;
+	}
+
+	// Check args (if there were any)
+  
+	int err;
+	if ( fand_modeG != info ) {
+		err = fand_check_args( sleep_seconds, off, low, high );
+		if ( err != 0 ) 
+			return err;
+	}
+   
+	pid_t pid = 0;
+
+	// Fork if requested
+	if ( fand_modeG == background )
+		pid = fork();
+  
+	// Fork failure
+	if ( pid < 0 )
+	   return FAND_FORK_ERROR;
+
+	// Child, or 'parent' if no fork requested
+	else if ( pid == 0 ) {
+
+		if ( fand_modeG == background ) {
+			err = fand_do_daemon_setup();
+			if ( err != 0 )
+				return err;
+		}
+
+		fand_do_main_loop( sleep_seconds, off, low, high );
+	}
+
+	if ( fand_modeG != info )
+		fand_prepare_to_exit();
+
+	return 0;
+}
+
 int
 fan(int argc, char **argv)
 {
@@ -272,9 +474,10 @@
 void
 usage(char *progname)
 {
-    printf("Usage: %s [-v] "
-	   "[fan [<l> <r>] | speed | version | bios | id | temp | ac | fn]\n",
-	   progname);
+    printf("Usage:\n"
+	   "%s [-v] [fan [<l> <r>] | speed | version | bios | id | temp | ac | fn]\n"
+	   "%s fand [ -h | is_daemon sleep temp_off temp_low temp_high]\n",
+	   progname, progname);
 }
 
 int
@@ -307,6 +510,11 @@
 	exit(1);
     }
 
+    /* If called as i8kfand emulate dellfand program */
+    if (strcmp(progname,"i8kfand")==0) {
+	return fand(argc,argv);
+    }
+
     /* If called as i8kfan emulate the old program */
     if (strcmp(progname,"i8kfan")==0) {
 	return fan(argc,argv);
@@ -317,6 +525,11 @@
 	return status();
     }
 
+    if (strcmp(argv[1],"fand")==0) {
+	argc--; argv++;
+	return fand(argc,argv);
+    }
+
     if (strcmp(argv[1],"fan")==0) {
 	argc--; argv++;
 	return fan(argc,argv);
diff -urN i8kutils-1.25/Makefile i8kutils-1.25-spb/Makefile
--- i8kutils-1.25/Makefile	2003-01-21 19:03:20.000000000 +0100
+++ i8kutils-1.25-spb/Makefile	2008-08-22 09:43:47.000000000 +0200
@@ -43,6 +43,7 @@
 i8kctl:		i8kctl.c
 		$(CC) -g $(CFLAGS) -I. -o $@ $<
 		ln -fs $@ i8kfan
+		ln -fs $@ i8kfand
 
 install:	i8kbuttons i8kctl i8kmon
 		cp -fp i8kbuttons i8kctl i8kmon $(DESTDIR)/$(BINDIR)/
diff -urN i8kutils-1.25/README.i8kfand i8kutils-1.25-spb/README.i8kfand
--- i8kutils-1.25/README.i8kfand	1970-01-01 01:00:00.000000000 +0100
+++ i8kutils-1.25-spb/README.i8kfand	2008-08-22 10:20:52.000000000 +0200
@@ -0,0 +1,29 @@
+i8kfand (i8kctl fand)
+
+This is dellfand, (c) 2006 Lee Wilmot, ported to i8kutils
+
+- dellfand uses assembler io call to access smm bios
+  (included assembler code not properly licensed:
+  i386 instructions are taken verbatim from i8kutils smm.c but are not under gpl)
+- i8kfand uses /proc/i8k interface (i8k.ko) to access smm bios
+  (module i8k.ko is part of recent linux 2.6 kernel tree, 
+  in kernel/drivers/char)
+
+usage example:
+
+# Interval (seconds) between polls of the CPU temperature and
+# adjustment of the fan speed accordingly
+SLEEP_TIME="2"
+
+# When the fan is on, at what temperature (°C) or below to turn it off
+FAN_OFF="30"
+
+# When the fan is off, at what temperature to turn it to the low
+# speed setting
+FAN_LOW="38"
+
+# When the fan is on low, at what temperature to turn it to the
+# higher setting
+FAN_HIGH="48"
+
+i8kctl fand 1 $SLEEP_TIME $FAN_OFF $FAN_LOW $FAN_HIGH
