2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/*
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  drivers / char / watchdog / shwdt . c 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Watchdog  driver  for  integrated  watchdog  in  the  SuperH  processors . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Copyright  ( C )  2001 ,  2002 ,  2003  Paul  Mundt  < lethal @ linux - sh . org > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  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  of  the  License ,  or  ( at  your 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  option )  any  later  version . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  14 - Dec - 2001  Matt  Domsch  < Matt_Domsch @ dell . com > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *      Added  nowayout  module  option  to  override  CONFIG_WATCHDOG_NOWAYOUT 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  19 - Apr - 2002  Rob  Radez  < rob @ osinvestor . com > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *      Added  expect  close  support ,  made  emulated  timeout  runtime  changeable 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *      general  cleanups ,  add  some  ioctls 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <linux/module.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <linux/moduleparam.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <linux/init.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <linux/types.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <linux/miscdevice.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <linux/watchdog.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <linux/reboot.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <linux/notifier.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <linux/ioport.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <linux/fs.h> 
  
						 
					
						
							
								
									
										
										
										
											2006-09-27 17:53:59 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <linux/mm.h> 
  
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								# include  <asm/io.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <asm/uaccess.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <asm/watchdog.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define PFX "shwdt: " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Default  clock  division  ratio  is  5.25  msecs .  For  an  additional  table  of 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  values ,  consult  the  asm - sh / watchdog . h .  Overload  this  at  module  load 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  time . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  In  order  for  this  to  work  reliably  we  need  to  have  HZ  set  to  1000  or 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  something  quite  higher  than  100  ( or  we  need  a  proper  high - res  timer 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  implementation  that  will  deal  with  this  properly ) ,  otherwise  the  10 ms 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  resolution  of  a  jiffy  is  enough  to  trigger  the  overflow .  For  things  like 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  the  SH - 4  and  SH - 5 ,  this  isn ' t  necessarily  that  big  of  a  problem ,  though 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  for  the  SH - 2  and  SH - 3 ,  this  isn ' t  recommended  unless  the  WDT  is  absolutely 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  necssary . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  As  a  result  of  this  timing  problem ,  the  only  modes  that  are  particularly 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  feasible  are  the  4096  and  the  2048  divisors ,  which  yeild  5.25  and  2.62 ms 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  overflow  periods  respectively . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Also ,  since  we  can ' t  really  expect  userspace  to  be  responsive  enough 
							 
						 
					
						
							
								
									
										
										
										
											2008-02-03 17:32:52 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  before  the  overflow  happens ,  we  maintain  two  separate  timers  . .  One  in 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								 *  the  kernel  for  clearing  out  WOVF  every  2 ms  or  so  ( again ,  this  depends  on 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  HZ  = =  1000 ) ,  and  another  for  monitoring  userspace  writes  to  the  WDT  device . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  As  such ,  we  currently  use  a  configurable  heartbeat  interval  which  defaults 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  to  30 s .  In  this  case ,  the  userspace  daemon  is  only  responsible  for  periodic 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  writes  to  the  device  before  the  next  heartbeat  is  scheduled .  If  the  daemon 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  misses  its  deadline ,  the  kernel  timer  will  allow  the  WDT  to  overflow . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  clock_division_ratio  =  WTCSR_CKS_4096 ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define next_ping_period(cks)	msecs_to_jiffies(cks - 4) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2007-02-08 18:39:36 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  sh_wdt_ping ( unsigned  long  data ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								static  unsigned  long  shwdt_is_open ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  watchdog_info  sh_wdt_info ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  char  shwdt_expect_close ;  
						 
					
						
							
								
									
										
										
										
											2007-02-08 18:39:36 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  DEFINE_TIMER ( timer ,  sh_wdt_ping ,  0 ,  0 ) ;  
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								static  unsigned  long  next_heartbeat ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# define WATCHDOG_HEARTBEAT 30			 /* 30 sec default heartbeat */ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  heartbeat  =  WATCHDOG_HEARTBEAT ; 	/* in seconds */  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2005-07-27 11:43:58 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  nowayout  =  WATCHDOG_NOWAYOUT ;  
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_start  -  Start  the  Watchdog 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Starts  the  watchdog . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  sh_wdt_start ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									__u8  csr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									next_heartbeat  =  jiffies  +  ( heartbeat  *  HZ ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									mod_timer ( & timer ,  next_ping_period ( clock_division_ratio ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									csr  =  sh_wdt_read_csr ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									csr  | =  WTCSR_WT  |  clock_division_ratio ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sh_wdt_write_csr ( csr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sh_wdt_write_cnt ( 0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  These  processors  have  a  bit  of  an  inconsistent  initialization 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  process . .  starting  with  SH - 3 ,  RSTS  was  moved  to  WTCSR ,  and  the 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  RSTCSR  register  was  removed . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  On  the  SH - 2  however ,  in  addition  with  bits  being  in  different 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  locations ,  we  must  deal  with  RSTCSR  outright . . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									csr  =  sh_wdt_read_csr ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									csr  | =  WTCSR_TME ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									csr  & =  ~ WTCSR_RSTS ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sh_wdt_write_csr ( csr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# ifdef CONFIG_CPU_SH2 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  Whoever  came  up  with  the  RSTCSR  semantics  must ' ve  been  smoking 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  some  of  the  good  stuff ,  since  in  addition  to  the  WTCSR / WTCNT  write 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  brain - damage ,  it ' s  managed  to  fuck  things  up  one  step  further . . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  If  we  need  to  clear  the  WOVF  bit ,  the  upper  byte  has  to  be  0xa5 . . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  but  if  we  want  to  touch  RSTE  or  RSTS ,  the  upper  byte  has  to  be 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  0x5a . . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									csr  =  sh_wdt_read_rstcsr ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									csr  & =  ~ RSTCSR_RSTS ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sh_wdt_write_rstcsr ( csr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# endif 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_stop  -  Stop  the  Watchdog 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Stops  the  watchdog . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  sh_wdt_stop ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									__u8  csr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									del_timer ( & timer ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									csr  =  sh_wdt_read_csr ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									csr  & =  ~ WTCSR_TME ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sh_wdt_write_csr ( csr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_keepalive  -  Keep  the  Userspace  Watchdog  Alive 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	The  Userspace  watchdog  got  a  KeepAlive :  schedule  the  next  heartbeat . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  inline  void  sh_wdt_keepalive ( void )  
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									next_heartbeat  =  jiffies  +  ( heartbeat  *  HZ ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_set_heartbeat  -  Set  the  Userspace  Watchdog  heartbeat 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Set  the  Userspace  Watchdog  heartbeat 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  sh_wdt_set_heartbeat ( int  t )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( unlikely ( ( t  <  1 )  | |  ( t  >  3600 ) ) )  /* arbitrary upper limit */ 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  - EINVAL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									heartbeat  =  t ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_ping  -  Ping  the  Watchdog 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 	@ data :  Unused 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Clears  overflow  bit ,  resets  timer  counter . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  sh_wdt_ping ( unsigned  long  data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( time_before ( jiffies ,  next_heartbeat ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										__u8  csr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										csr  =  sh_wdt_read_csr ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										csr  & =  ~ WTCSR_IOVF ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										sh_wdt_write_csr ( csr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										sh_wdt_write_cnt ( 0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										mod_timer ( & timer ,  next_ping_period ( clock_division_ratio ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									}  else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										printk ( KERN_WARNING  PFX  " Heartbeat lost! Will not ping  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										       " the watchdog \n " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_open  -  Open  the  Device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ inode :  inode  of  device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ file :  file  handle  of  device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Watchdog  device  is  opened  and  started . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  sh_wdt_open ( struct  inode  * inode ,  struct  file  * file )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( test_and_set_bit ( 0 ,  & shwdt_is_open ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - EBUSY ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( nowayout ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										__module_get ( THIS_MODULE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sh_wdt_start ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nonseekable_open ( inode ,  file ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_close  -  Close  the  Device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ inode :  inode  of  device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ file :  file  handle  of  device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Watchdog  device  is  closed  and  stopped . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  sh_wdt_close ( struct  inode  * inode ,  struct  file  * file )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( shwdt_expect_close  = =  42 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										sh_wdt_stop ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										printk ( KERN_CRIT  PFX  " Unexpected close, not  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										       " stopping watchdog! \n " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										sh_wdt_keepalive ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									clear_bit ( 0 ,  & shwdt_is_open ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									shwdt_expect_close  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_write  -  Write  to  Device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ file :  file  handle  of  device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ buf :  buffer  to  write 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ count :  length  of  buffer 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ ppos :  offset 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Pings  the  watchdog  on  write . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  ssize_t  sh_wdt_write ( struct  file  * file ,  const  char  * buf ,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											    size_t  count ,  loff_t  * ppos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( count )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! nowayout )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											size_t  i ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											shwdt_expect_close  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											for  ( i  =  0 ;  i  ! =  count ;  i + + )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												char  c ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ( get_user ( c ,  buf  +  i ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													return  - EFAULT ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ( c  = =  ' V ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													shwdt_expect_close  =  42 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										sh_wdt_keepalive ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  count ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-09-27 17:53:59 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_mmap  -  map  WDT / CPG  registers  into  userspace 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ file :  file  structure  for  the  device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ vma :  VMA  to  map  the  registers  into 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	A  simple  mmap ( )  implementation  for  the  corner  cases  where  the  counter 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	needs  to  be  mapped  in  userspace  directly .  Due  to  the  relatively  small 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	size  of  the  area ,  neighbouring  registers  not  necessarily  tied  to  the 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	CPG  will  also  be  accessible  through  the  register  page ,  so  this  remains 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	configurable  for  users  that  really  know  what  they ' re  doing . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 	Additionaly ,  the  register  page  maps  in  the  CPG  register  base  relative 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 	to  the  nearest  page - aligned  boundary ,  which  requires  that  userspace  do 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 	the  appropriate  CPU  subtype  math  for  calculating  the  page  offset  for 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 	the  counter  value . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  sh_wdt_mmap ( struct  file  * file ,  struct  vm_area_struct  * vma )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  ret  =  - ENOSYS ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# ifdef CONFIG_SH_WDT_MMAP 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  long  addr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Only support the simple cases where we map in a register page. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( ( vma - > vm_end  -  vma - > vm_start )  ! =  PAGE_SIZE )  | |  vma - > vm_pgoff ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - EINVAL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  Pick  WTCNT  as  the  start ,  it ' s  usually  the  first  register  after  the 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  FRQCR ,  and  neither  one  are  generally  page - aligned  out  of  the  box . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									addr  =  WTCNT  &  ~ ( PAGE_SIZE  -  1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									vma - > vm_flags  | =  VM_IO ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									vma - > vm_page_prot  =  pgprot_noncached ( vma - > vm_page_prot ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( io_remap_pfn_range ( vma ,  vma - > vm_start ,  addr  > >  PAGE_SHIFT , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											       PAGE_SIZE ,  vma - > vm_page_prot ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										printk ( KERN_ERR  PFX  " %s: io_remap_pfn_range failed \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										       __FUNCTION__ ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - EAGAIN ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ret  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# endif 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ret ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_ioctl  -  Query  Device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ inode :  inode  of  device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ file :  file  handle  of  device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ cmd :  watchdog  command 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ arg :  argument 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Query  basic  information  from  the  device  or  ping  it ,  as  outlined  by  the 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	watchdog  API . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  sh_wdt_ioctl ( struct  inode  * inode ,  struct  file  * file ,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											unsigned  int  cmd ,  unsigned  long  arg ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  new_heartbeat ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  options ,  retval  =  - EINVAL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									switch  ( cmd )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  WDIOC_GETSUPPORT : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  copy_to_user ( ( struct  watchdog_info  * ) arg , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													  & sh_wdt_info , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													  sizeof ( sh_wdt_info ) )  ?  - EFAULT  :  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  WDIOC_GETSTATUS : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  WDIOC_GETBOOTSTATUS : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  put_user ( 0 ,  ( int  * ) arg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  WDIOC_KEEPALIVE : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											sh_wdt_keepalive ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  WDIOC_SETTIMEOUT : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( get_user ( new_heartbeat ,  ( int  * ) arg ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  - EFAULT ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( sh_wdt_set_heartbeat ( new_heartbeat ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  - EINVAL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											sh_wdt_keepalive ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* Fall */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  WDIOC_GETTIMEOUT : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  put_user ( heartbeat ,  ( int  * ) arg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  WDIOC_SETOPTIONS : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( get_user ( options ,  ( int  * ) arg ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  - EFAULT ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( options  &  WDIOS_DISABLECARD )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												sh_wdt_stop ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												retval  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( options  &  WDIOS_ENABLECARD )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												sh_wdt_start ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												retval  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  retval ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										default : 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-09 17:34:31 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  - ENOTTY ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_notify_sys  -  Notifier  Handler 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ this :  notifier  block 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ code :  notifier  event 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	@ unused :  unused 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Handles  specific  events ,  such  as  turning  off  the  watchdog  during  a 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	shutdown  event . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  sh_wdt_notify_sys ( struct  notifier_block  * this ,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											     unsigned  long  code ,  void  * unused ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( code  = =  SYS_DOWN  | |  code  = =  SYS_HALT ) 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										sh_wdt_stop ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  NOTIFY_DONE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-07-03 00:24:21 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  const  struct  file_operations  sh_wdt_fops  =  {  
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									. owner 		=  THIS_MODULE , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. llseek 		=  no_llseek , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. write 		=  sh_wdt_write , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. ioctl 		=  sh_wdt_ioctl , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. open 		=  sh_wdt_open , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. release 	=  sh_wdt_close , 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-27 17:53:59 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									. mmap 		=  sh_wdt_mmap , 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  watchdog_info  sh_wdt_info  =  {  
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									. options 		=  WDIOF_KEEPALIVEPING  |  WDIOF_SETTIMEOUT  | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												  WDIOF_MAGICCLOSE , 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									. firmware_version 	=  1 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. identity 		=  " SH WDT " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  notifier_block  sh_wdt_notifier  =  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. notifier_call 		=  sh_wdt_notify_sys , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  struct  miscdevice  sh_wdt_miscdev  =  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. minor 		=  WATCHDOG_MINOR , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. name 		=  " watchdog " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. fops 		=  & sh_wdt_fops , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_init  -  Initialize  module 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Registers  the  device  and  notifier  handler .  Actual  device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	initialization  is  handled  by  sh_wdt_open ( ) . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  __init  sh_wdt_init ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  rc ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( clock_division_ratio  <  0x5 )  | |  ( clock_division_ratio  >  0x7 ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										clock_division_ratio  =  WTCSR_CKS_4096 ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										printk ( KERN_INFO  PFX  " clock_division_ratio value must  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										       " be 0x5<=x<=0x7, using %d \n " ,  clock_division_ratio ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									rc  =  sh_wdt_set_heartbeat ( heartbeat ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( unlikely ( rc ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										heartbeat  =  WATCHDOG_HEARTBEAT ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										printk ( KERN_INFO  PFX  " heartbeat value must  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										       " be 1<=x<=3600, using %d \n " ,  heartbeat ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									rc  =  register_reboot_notifier ( & sh_wdt_notifier ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( unlikely ( rc ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										printk ( KERN_ERR  PFX  " Can't register reboot notifier (err=%d) \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										       rc ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  rc ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									rc  =  misc_register ( & sh_wdt_miscdev ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( unlikely ( rc ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										printk ( KERN_ERR  PFX  " Can't register miscdev on  " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										       " minor=%d (err=%d) \n " ,  sh_wdt_miscdev . minor ,  rc ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										unregister_reboot_notifier ( & sh_wdt_notifier ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  rc ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									printk ( KERN_INFO  PFX  " initialized. heartbeat=%d sec (nowayout=%d) \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										heartbeat ,  nowayout ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/**
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	sh_wdt_exit  -  Deinitialize  module 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	Unregisters  the  device  and  notifier  handler .  Actual  device 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  	deinitialization  is  handled  by  sh_wdt_close ( ) . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  __exit  sh_wdt_exit ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									misc_deregister ( & sh_wdt_miscdev ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unregister_reboot_notifier ( & sh_wdt_notifier ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								MODULE_AUTHOR ( " Paul Mundt <lethal@linux-sh.org> " ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								MODULE_DESCRIPTION ( " SuperH watchdog driver " ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								MODULE_LICENSE ( " GPL " ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								MODULE_ALIAS_MISCDEV ( WATCHDOG_MINOR ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								module_param ( clock_division_ratio ,  int ,  0 ) ;  
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								MODULE_PARM_DESC ( clock_division_ratio ,  " Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default= "  __MODULE_STRING ( clock_division_ratio )  " ) " ) ;  
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								module_param ( heartbeat ,  int ,  0 ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								MODULE_PARM_DESC ( heartbeat ,  " Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default= "  __MODULE_STRING ( WATCHDOG_HEARTBEAT )  " ) " ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								module_param ( nowayout ,  int ,  0 ) ;  
						 
					
						
							
								
									
										
										
										
											2006-09-27 12:31:01 +09:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								MODULE_PARM_DESC ( nowayout ,  " Watchdog cannot be stopped once started (default= "  __MODULE_STRING ( WATCHDOG_NOWAYOUT )  " ) " ) ;  
						 
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								module_init ( sh_wdt_init ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								module_exit ( sh_wdt_exit ) ;