acquirewdt.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Acquire Single Board Computer Watchdog Timer driver for Linux 2.1.x
  3.  *
  4.  *      Based on wdt.c. Original copyright messages:
  5.  *
  6.  * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
  7.  * http://www.redhat.com
  8.  *
  9.  * This program is free software; you can redistribute it and/or
  10.  * modify it under the terms of the GNU General Public License
  11.  * as published by the Free Software Foundation; either version
  12.  * 2 of the License, or (at your option) any later version.
  13.  *
  14.  * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
  15.  * warranty for any of this software. This material is provided 
  16.  * "AS-IS" and at no charge.
  17.  *
  18.  * (c) Copyright 1995    Alan Cox <alan@redhat.com>
  19.  *
  20.  *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
  21.  *          Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  22.  *          Can't add timeout - driver doesn't allow changing value
  23.  */
  24. #include <linux/config.h>
  25. #include <linux/module.h>
  26. #include <linux/version.h>
  27. #include <linux/types.h>
  28. #include <linux/errno.h>
  29. #include <linux/kernel.h>
  30. #include <linux/sched.h>
  31. #include <linux/miscdevice.h>
  32. #include <linux/watchdog.h>
  33. #include <linux/slab.h>
  34. #include <linux/ioport.h>
  35. #include <linux/fcntl.h>
  36. #include <asm/io.h>
  37. #include <asm/uaccess.h>
  38. #include <asm/system.h>
  39. #include <linux/notifier.h>
  40. #include <linux/reboot.h>
  41. #include <linux/init.h>
  42. #include <linux/spinlock.h>
  43. #include <linux/smp_lock.h>
  44. static int acq_is_open;
  45. static spinlock_t acq_lock;
  46. static int expect_close = 0;
  47. /*
  48.  * You must set these - there is no sane way to probe for this board.
  49.  */
  50.  
  51. #define WDT_STOP 0x43
  52. #define WDT_START 0x443
  53. #ifdef CONFIG_WATCHDOG_NOWAYOUT
  54. static int nowayout = 1;
  55. #else
  56. static int nowayout = 0;
  57. #endif
  58. MODULE_PARM(nowayout,"i");
  59. MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
  60. /*
  61.  * Kernel methods.
  62.  */
  63.  
  64. static void acq_ping(void)
  65. {
  66. /* Write a watchdog value */
  67. inb_p(WDT_START);
  68. }
  69. static ssize_t acq_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
  70. {
  71. /*  Can't seek (pwrite) on this device  */
  72. if (ppos != &file->f_pos)
  73. return -ESPIPE;
  74. if(count)
  75. {
  76. if (!nowayout)
  77. {
  78. size_t i;
  79. expect_close = 0;
  80. for (i = 0; i != count; i++) {
  81. char c;
  82. if (get_user(c, buf + i))
  83. return -EFAULT;
  84. if (c == 'V')
  85. expect_close = 1;
  86. }
  87. }
  88. acq_ping();
  89. return 1;
  90. }
  91. return 0;
  92. }
  93. static ssize_t acq_read(struct file *file, char *buf, size_t count, loff_t *ppos)
  94. {
  95. return -EINVAL;
  96. }
  97. static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
  98. unsigned long arg)
  99. {
  100. static struct watchdog_info ident=
  101. {
  102. WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 1, "Acquire WDT"
  103. };
  104. switch(cmd)
  105. {
  106. case WDIOC_GETSUPPORT:
  107.   if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
  108.     return -EFAULT;
  109.   break;
  110.   
  111. case WDIOC_GETSTATUS:
  112.   if (copy_to_user((int *)arg, &acq_is_open,  sizeof(int)))
  113.     return -EFAULT;
  114.   break;
  115. case WDIOC_KEEPALIVE:
  116.   acq_ping();
  117.   break;
  118. default:
  119.   return -ENOTTY;
  120. }
  121. return 0;
  122. }
  123. static int acq_open(struct inode *inode, struct file *file)
  124. {
  125. switch(MINOR(inode->i_rdev))
  126. {
  127. case WATCHDOG_MINOR:
  128. spin_lock(&acq_lock);
  129. if(acq_is_open)
  130. {
  131. spin_unlock(&acq_lock);
  132. return -EBUSY;
  133. }
  134. if (nowayout) {
  135. MOD_INC_USE_COUNT;
  136. }
  137. /*
  138.  * Activate 
  139.  */
  140. acq_is_open=1;
  141. inb_p(WDT_START);      
  142. spin_unlock(&acq_lock);
  143. return 0;
  144. default:
  145. return -ENODEV;
  146. }
  147. }
  148. static int acq_close(struct inode *inode, struct file *file)
  149. {
  150. lock_kernel();
  151. if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
  152. {
  153. spin_lock(&acq_lock);
  154. if (expect_close)
  155. {
  156. inb_p(WDT_STOP);
  157. }
  158. else
  159. {
  160. printk(KERN_CRIT "WDT closed unexpectedly.  WDT will not stop!n");
  161. }
  162. acq_is_open=0;
  163. spin_unlock(&acq_lock);
  164. }
  165. unlock_kernel();
  166. return 0;
  167. }
  168. /*
  169.  * Notifier for system down
  170.  */
  171. static int acq_notify_sys(struct notifier_block *this, unsigned long code,
  172. void *unused)
  173. {
  174. if(code==SYS_DOWN || code==SYS_HALT)
  175. {
  176. /* Turn the card off */
  177. inb_p(WDT_STOP);
  178. }
  179. return NOTIFY_DONE;
  180. }
  181.  
  182. /*
  183.  * Kernel Interfaces
  184.  */
  185.  
  186.  
  187. static struct file_operations acq_fops = {
  188. owner: THIS_MODULE,
  189. read: acq_read,
  190. write: acq_write,
  191. ioctl: acq_ioctl,
  192. open: acq_open,
  193. release: acq_close,
  194. };
  195. static struct miscdevice acq_miscdev=
  196. {
  197. WATCHDOG_MINOR,
  198. "watchdog",
  199. &acq_fops
  200. };
  201. /*
  202.  * The WDT card needs to learn about soft shutdowns in order to
  203.  * turn the timebomb registers off. 
  204.  */
  205.  
  206. static struct notifier_block acq_notifier=
  207. {
  208. acq_notify_sys,
  209. NULL,
  210. 0
  211. };
  212. static int __init acq_init(void)
  213. {
  214. printk("WDT driver for Acquire single board computer initialising.n");
  215. spin_lock_init(&acq_lock);
  216. if (misc_register(&acq_miscdev))
  217. return -ENODEV;
  218. request_region(WDT_STOP, 1, "Acquire WDT");
  219. request_region(WDT_START, 1, "Acquire WDT");
  220. register_reboot_notifier(&acq_notifier);
  221. return 0;
  222. }
  223. static void __exit acq_exit(void)
  224. {
  225. misc_deregister(&acq_miscdev);
  226. unregister_reboot_notifier(&acq_notifier);
  227. release_region(WDT_STOP,1);
  228. release_region(WDT_START,1);
  229. }
  230. module_init(acq_init);
  231. module_exit(acq_exit);
  232. MODULE_LICENSE("GPL");
  233. EXPORT_NO_SYMBOLS;