2005-04-16 15:20:36 -07:00
/* -*- mode: c; c-basic-offset: 8 -*- */
/* Copyright (C) 2001
*
* Author : J . E . J . Bottomley @ HansenPartnership . com
*
* linux / arch / i386 / kernel / voyager_thread . c
*
* This module provides the machine status monitor thread for the
* voyager architecture . This allows us to monitor the machine
* environment ( temp , voltage , fan function ) and the front panel and
* internal UPS . If a fault is detected , this thread takes corrective
* action ( usually just informing init )
* */
# include <linux/module.h>
# include <linux/mm.h>
# include <linux/kernel_stat.h>
# include <linux/delay.h>
# include <linux/mc146818rtc.h>
# include <linux/init.h>
# include <linux/bootmem.h>
# include <linux/kmod.h>
# include <linux/completion.h>
# include <linux/sched.h>
2007-04-22 20:30:43 +01:00
# include <linux/kthread.h>
2005-04-16 15:20:36 -07:00
# include <asm/desc.h>
# include <asm/voyager.h>
# include <asm/vic.h>
# include <asm/mtrr.h>
# include <asm/msr.h>
2007-04-22 20:30:43 +01:00
struct task_struct * voyager_thread ;
static __u8 set_timeout ;
2005-04-16 15:20:36 -07:00
2008-01-30 13:30:10 +01:00
static int execute ( const char * string )
2005-04-16 15:20:36 -07:00
{
int ret ;
char * envp [ ] = {
" HOME=/ " ,
" TERM=linux " ,
" PATH=/sbin:/usr/sbin:/bin:/usr/bin " ,
NULL ,
} ;
char * argv [ ] = {
" /bin/bash " ,
" -c " ,
( char * ) string ,
NULL ,
} ;
2008-01-30 13:30:10 +01:00
if ( ( ret =
call_usermodehelper ( argv [ 0 ] , argv , envp , UMH_WAIT_PROC ) ) ! = 0 ) {
printk ( KERN_ERR " Voyager failed to run \" %s \" : %i \n " , string ,
ret ) ;
2005-04-16 15:20:36 -07:00
}
return ret ;
}
2008-01-30 13:30:10 +01:00
static void check_from_kernel ( void )
2005-04-16 15:20:36 -07:00
{
2008-01-30 13:30:10 +01:00
if ( voyager_status . switch_off ) {
2007-10-20 01:13:56 +02:00
/* FIXME: This should be configurable via proc */
2005-04-16 15:20:36 -07:00
execute ( " umask 600; echo 0 > /etc/initrunlvl; kill -HUP 1 " ) ;
2008-01-30 13:30:10 +01:00
} else if ( voyager_status . power_fail ) {
2005-04-16 15:20:36 -07:00
VDEBUG ( ( " Voyager daemon detected AC power failure \n " ) ) ;
2008-01-30 13:30:10 +01:00
2005-04-16 15:20:36 -07:00
/* FIXME: This should be configureable via proc */
execute ( " umask 600; echo F > /etc/powerstatus; kill -PWR 1 " ) ;
set_timeout = 1 ;
}
}
2008-01-30 13:30:10 +01:00
static void check_continuing_condition ( void )
2005-04-16 15:20:36 -07:00
{
2008-01-30 13:30:10 +01:00
if ( voyager_status . power_fail ) {
2005-04-16 15:20:36 -07:00
__u8 data ;
2008-01-30 13:30:10 +01:00
voyager_cat_psi ( VOYAGER_PSI_SUBREAD ,
2005-04-16 15:20:36 -07:00
VOYAGER_PSI_AC_FAIL_REG , & data ) ;
2008-01-30 13:30:10 +01:00
if ( ( data & 0x1f ) = = 0 ) {
2005-04-16 15:20:36 -07:00
/* all power restored */
2008-01-30 13:30:10 +01:00
printk ( KERN_NOTICE
" VOYAGER AC power restored, cancelling shutdown \n " ) ;
2005-04-16 15:20:36 -07:00
/* FIXME: should be user configureable */
2008-01-30 13:30:10 +01:00
execute
( " umask 600; echo O > /etc/powerstatus; kill -PWR 1 " ) ;
2005-04-16 15:20:36 -07:00
set_timeout = 0 ;
}
}
}
2008-01-30 13:30:10 +01:00
static int thread ( void * unused )
2005-04-16 15:20:36 -07:00
{
printk ( KERN_NOTICE " Voyager starting monitor thread \n " ) ;
2007-04-22 20:30:43 +01:00
for ( ; ; ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule_timeout ( set_timeout ? HZ : MAX_SCHEDULE_TIMEOUT ) ;
2005-04-16 15:20:36 -07:00
VDEBUG ( ( " Voyager Daemon awoken \n " ) ) ;
2008-01-30 13:30:10 +01:00
if ( voyager_status . request_from_kernel = = 0 ) {
2005-04-16 15:20:36 -07:00
/* probably awoken from timeout */
check_continuing_condition ( ) ;
} else {
check_from_kernel ( ) ;
voyager_status . request_from_kernel = 0 ;
}
}
}
2008-01-30 13:30:10 +01:00
static int __init voyager_thread_start ( void )
2007-04-22 20:30:43 +01:00
{
voyager_thread = kthread_run ( thread , NULL , " kvoyagerd " ) ;
if ( IS_ERR ( voyager_thread ) ) {
2008-01-30 13:30:10 +01:00
printk ( KERN_ERR
" Voyager: Failed to create system monitor thread. \n " ) ;
2007-04-22 20:30:43 +01:00
return PTR_ERR ( voyager_thread ) ;
}
return 0 ;
}
2008-01-30 13:30:10 +01:00
static void __exit voyager_thread_stop ( void )
2005-04-16 15:20:36 -07:00
{
2007-04-22 20:30:43 +01:00
kthread_stop ( voyager_thread ) ;
2005-04-16 15:20:36 -07:00
}
module_init ( voyager_thread_start ) ;
2007-04-22 20:30:43 +01:00
module_exit ( voyager_thread_stop ) ;