patch-2.4.9 linux/drivers/sbus/char/envctrl.c

Next file: linux/drivers/sbus/char/openprom.c
Previous file: linux/drivers/sbus/char/aurora.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.8/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.22 2001/03/25 09:12:15 davem Exp $
+/* $Id: envctrl.c,v 1.23 2001/08/09 23:42:09 davem Exp $
  * envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
@@ -26,11 +26,16 @@
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/kernel.h>
 
 #include <asm/ebus.h>
 #include <asm/uaccess.h>
 #include <asm/envctrl.h>
 
+#define __KERNEL_SYSCALLS__
+static int errno;
+#include <asm/unistd.h>
+
 #define ENVCTRL_MINOR	162
 
 #define PCF8584_ADDRESS	0x55
@@ -373,7 +378,7 @@
 /* Function Description: Read cpu-related data such as cpu temperature, voltage.
  * Return: Number of read bytes. Data is stored in bufdata in ascii format.
  */
-static int envctrl_read_cpu_info(struct i2c_child_t *pchild,
+static int envctrl_read_cpu_info(int cpu, struct i2c_child_t *pchild,
 				 char mon_type, unsigned char *bufdata)
 {
 	unsigned char data;
@@ -383,13 +388,13 @@
 	/* Find the right monitor type and channel. */
 	for (i = 0; i < PCF8584_MAX_CHANNELS; i++) {
 		if (pchild->mon_type[i] == mon_type) {
-			if (++j == read_cpu) {
+			if (++j == cpu) {
 				break;
 			}
 		}
 	}
 
-	if (j != read_cpu)
+	if (j != cpu)
 		return 0;
 
         /* Read data from address and port. */
@@ -588,7 +593,7 @@
 	case ENVCTRL_RD_CPU_TEMPERATURE:
 		if (!(pchild = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON)))
 			return 0;
-		ret = envctrl_read_cpu_info(pchild, ENVCTRL_CPUTEMP_MON, data);
+		ret = envctrl_read_cpu_info(read_cpu, pchild, ENVCTRL_CPUTEMP_MON, data);
 
 		/* Reset cpu to the default cpu0. */
 		copy_to_user((unsigned char *)buf, data, ret);
@@ -597,7 +602,7 @@
 	case ENVCTRL_RD_CPU_VOLTAGE:
 		if (!(pchild = envctrl_get_i2c_child(ENVCTRL_CPUVOLTAGE_MON)))
 			return 0;
-		ret = envctrl_read_cpu_info(pchild, ENVCTRL_CPUVOLTAGE_MON, data);
+		ret = envctrl_read_cpu_info(read_cpu, pchild, ENVCTRL_CPUVOLTAGE_MON, data);
 
 		/* Reset cpu to the default cpu0. */
 		copy_to_user((unsigned char *)buf, data, ret);
@@ -976,6 +981,74 @@
 	return NULL;
 }
 
+static void envctrl_do_shutdown(void)
+{
+	static int inprog = 0;
+	static char *envp[] = {	
+		"HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+	char *argv[] = { 
+		"/sbin/shutdown", "-h", "now", NULL };	
+
+	if (inprog != 0)
+		return;
+
+	inprog = 1;
+	printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");
+	if (0 > execve("/sbin/shutdown", argv, envp)) {
+		printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); 
+		inprog = 0;  /* unlikely to succeed, but we could try again */
+	}
+}
+
+static struct task_struct *kenvctrld_task;
+
+static int kenvctrld(void *__unused)
+{
+	int poll_interval;
+	int whichcpu;
+	char tempbuf[10];
+	struct i2c_child_t *cputemp;
+
+	if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) {
+		printk(KERN_ERR 
+		       "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n");
+		return -ENODEV;
+	}
+
+	poll_interval = 5 * HZ; /* TODO env_mon_interval */
+
+	daemonize();
+	strcpy(current->comm, "kenvctrld");
+	kenvctrld_task = current;
+
+	printk(KERN_INFO "envctrl: %s starting...\n", current->comm);
+	for (;;) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(poll_interval);
+		current->state = TASK_RUNNING;
+
+		if(signal_pending(current))
+			break;
+
+		for (whichcpu = 0; whichcpu < ENVCTRL_MAX_CPU; ++whichcpu) {
+			if (0 < envctrl_read_cpu_info(whichcpu, cputemp,
+						      ENVCTRL_CPUTEMP_MON,
+						      tempbuf)) {
+				if (tempbuf[0] >= shutdown_temperature) {
+					printk(KERN_CRIT 
+						"%s: WARNING: CPU%i temperature %i C meets or exceeds "\
+						"shutdown threshold %i C\n", 
+						current->comm, whichcpu, 
+						tempbuf[0], shutdown_temperature);
+					envctrl_do_shutdown();
+				}
+			}
+		}
+	}
+	printk(KERN_INFO "envctrl: %s exiting...\n", current->comm);
+	return 0;
+}
+
 static int __init envctrl_init(void)
 {
 #ifdef CONFIG_PCI
@@ -1054,6 +1127,8 @@
 			i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));
 	}
 
+	kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES);
+
 	return 0;
 #else
 	return -ENODEV;
@@ -1063,6 +1138,31 @@
 static void __exit envctrl_cleanup(void)
 {
 	int i;
+
+	if (NULL != kenvctrld_task) {
+		force_sig(SIGKILL, kenvctrld_task);
+		for (;;) {
+			struct task_struct *p;
+			int found = 0;
+
+			read_lock(&tasklist_lock);
+			for_each_task(p) {
+				if (p == kenvctrld_task) {
+					found = 1;
+					break;
+				}
+			}
+			read_unlock(&tasklist_lock);
+
+			if (!found)
+				break;
+
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(HZ);
+			current->state = TASK_RUNNING;
+		}
+		kenvctrld_task = NULL;
+	}
 
 	iounmap(i2c);
 	misc_deregister(&envctrl_dev);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)