advantechwdt.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Advantech Single Board Computer WDT driver for Linux 2.4.x
  3.  *
  4.  * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
  5.  *
  6.  * Based on acquirewdt.c which is based on wdt.c.
  7.  * Original copyright messages:
  8.  *
  9.  * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
  10.  * http://www.redhat.com
  11.  *
  12.  * This program is free software; you can redistribute it and/or
  13.  * modify it under the terms of the GNU General Public License
  14.  * as published by the Free Software Foundation; either version
  15.  * 2 of the License, or (at your option) any later version.
  16.  *
  17.  * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
  18.  * warranty for any of this software. This material is provided 
  19.  * "AS-IS" and at no charge.
  20.  *
  21.  * (c) Copyright 1995    Alan Cox <alan@redhat.com>
  22.  *
  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 advwdt_is_open;
  45. static spinlock_t advwdt_lock;
  46. /*
  47.  * You must set these - there is no sane way to probe for this board.
  48.  *
  49.  * To enable or restart, write the timeout value in seconds (1 to 63)
  50.  * to I/O port WDT_START.  To disable, read I/O port WDT_STOP.
  51.  * Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but
  52.  * check your manual (at least the PCA-6159 seems to be different -
  53.  * the manual says WDT_STOP is 0x43, not 0x443).
  54.  * (0x43 is also a write-only control register for the 8254 timer!)
  55.  *
  56.  * TODO: module parameters to set the I/O port addresses and NOWAYOUT
  57.  * option at load time.
  58.  */
  59.  
  60. #define WDT_STOP 0x443
  61. #define WDT_START 0x443
  62. #define WD_TIMO 60 /* 1 minute */
  63. static int wd_margin = WD_TIMO;
  64. /*
  65.  * Kernel methods.
  66.  */
  67.  
  68. static void
  69. advwdt_ping(void)
  70. {
  71. /* Write a watchdog value */
  72. outb_p(wd_margin, WDT_START);
  73. }
  74. static ssize_t
  75. advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
  76. {
  77. /*  Can't seek (pwrite) on this device  */
  78. if (ppos != &file->f_pos)
  79. return -ESPIPE;
  80. if (count) {
  81. advwdt_ping();
  82. return 1;
  83. }
  84. return 0;
  85. }
  86. static ssize_t
  87. advwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos)
  88. {
  89. return -EINVAL;
  90. }
  91. static int
  92. advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
  93.   unsigned long arg)
  94. {
  95. int new_margin;
  96. static struct watchdog_info ident = {
  97. WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, 1, "Advantech WDT"
  98. };
  99. switch (cmd) {
  100. case WDIOC_GETSUPPORT:
  101.   if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
  102.     return -EFAULT;
  103.   break;
  104.   
  105. case WDIOC_GETSTATUS:
  106.   if (copy_to_user((int *)arg, &advwdt_is_open,  sizeof(int)))
  107.     return -EFAULT;
  108.   break;
  109. case WDIOC_KEEPALIVE:
  110.   advwdt_ping();
  111.   break;
  112. case WDIOC_SETTIMEOUT:
  113.   if (get_user(new_margin, (int *)arg))
  114.   return -EFAULT;
  115.   if ((new_margin < 1) || (new_margin > 63))
  116.   return -EINVAL;
  117.   wd_margin = new_margin;
  118.   advwdt_ping();
  119.   /* Fall */
  120. case WDIOC_GETTIMEOUT:
  121.   return put_user(wd_margin, (int *)arg);
  122.   break;
  123. default:
  124.   return -ENOTTY;
  125. }
  126. return 0;
  127. }
  128. static int
  129. advwdt_open(struct inode *inode, struct file *file)
  130. {
  131. switch (MINOR(inode->i_rdev)) {
  132. case WATCHDOG_MINOR:
  133. spin_lock(&advwdt_lock);
  134. if (advwdt_is_open) {
  135. spin_unlock(&advwdt_lock);
  136. return -EBUSY;
  137. }
  138. /*
  139.  * Activate 
  140.  */
  141.  
  142. advwdt_is_open = 1;
  143. advwdt_ping();
  144. spin_unlock(&advwdt_lock);
  145. return 0;
  146. default:
  147. return -ENODEV;
  148. }
  149. }
  150. static int
  151. advwdt_close(struct inode *inode, struct file *file)
  152. {
  153. lock_kernel();
  154. if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
  155. spin_lock(&advwdt_lock);
  156. #ifndef CONFIG_WATCHDOG_NOWAYOUT
  157. inb_p(WDT_STOP);
  158. #endif
  159. advwdt_is_open = 0;
  160. spin_unlock(&advwdt_lock);
  161. }
  162. unlock_kernel();
  163. return 0;
  164. }
  165. /*
  166.  * Notifier for system down
  167.  */
  168. static int
  169. advwdt_notify_sys(struct notifier_block *this, unsigned long code,
  170. void *unused)
  171. {
  172. if (code == SYS_DOWN || code == SYS_HALT) {
  173. /* Turn the WDT off */
  174. inb_p(WDT_STOP);
  175. }
  176. return NOTIFY_DONE;
  177. }
  178.  
  179. /*
  180.  * Kernel Interfaces
  181.  */
  182.  
  183. static struct file_operations advwdt_fops = {
  184. owner: THIS_MODULE,
  185. read: advwdt_read,
  186. write: advwdt_write,
  187. ioctl: advwdt_ioctl,
  188. open: advwdt_open,
  189. release: advwdt_close,
  190. };
  191. static struct miscdevice advwdt_miscdev = {
  192. WATCHDOG_MINOR,
  193. "watchdog",
  194. &advwdt_fops
  195. };
  196. /*
  197.  * The WDT needs to learn about soft shutdowns in order to
  198.  * turn the timebomb registers off. 
  199.  */
  200.  
  201. static struct notifier_block advwdt_notifier = {
  202. advwdt_notify_sys,
  203. NULL,
  204. 0
  205. };
  206. static int __init
  207. advwdt_init(void)
  208. {
  209. printk("WDT driver for Advantech single board computer initialising.n");
  210. spin_lock_init(&advwdt_lock);
  211. misc_register(&advwdt_miscdev);
  212. #if WDT_START != WDT_STOP
  213. request_region(WDT_STOP, 1, "Advantech WDT");
  214. #endif
  215. request_region(WDT_START, 1, "Advantech WDT");
  216. register_reboot_notifier(&advwdt_notifier);
  217. return 0;
  218. }
  219. static void __exit
  220. advwdt_exit(void)
  221. {
  222. misc_deregister(&advwdt_miscdev);
  223. unregister_reboot_notifier(&advwdt_notifier);
  224. #if WDT_START != WDT_STOP
  225. release_region(WDT_STOP,1);
  226. #endif
  227. release_region(WDT_START,1);
  228. }
  229. module_init(advwdt_init);
  230. module_exit(advwdt_exit);
  231. MODULE_LICENSE("GPL");
  232. /* end of advantechwdt.c */