/drivers/char/watchdog/indydog.c

https://bitbucket.org/evzijst/gittest · C · 221 lines · 163 code · 39 blank · 19 comment · 15 complexity · 6ae3ebedcc508134534ac44724b95443 MD5 · raw file

  1. /*
  2. * IndyDog 0.3 A Hardware Watchdog Device for SGI IP22
  3. *
  4. * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. *
  11. * based on softdog.c by Alan Cox <alan@redhat.com>
  12. */
  13. #include <linux/module.h>
  14. #include <linux/moduleparam.h>
  15. #include <linux/config.h>
  16. #include <linux/types.h>
  17. #include <linux/kernel.h>
  18. #include <linux/fs.h>
  19. #include <linux/mm.h>
  20. #include <linux/miscdevice.h>
  21. #include <linux/watchdog.h>
  22. #include <linux/notifier.h>
  23. #include <linux/reboot.h>
  24. #include <linux/init.h>
  25. #include <asm/uaccess.h>
  26. #include <asm/sgi/mc.h>
  27. #define PFX "indydog: "
  28. static int indydog_alive;
  29. #ifdef CONFIG_WATCHDOG_NOWAYOUT
  30. static int nowayout = 1;
  31. #else
  32. static int nowayout = 0;
  33. #endif
  34. #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
  35. module_param(nowayout, int, 0);
  36. MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
  37. static void indydog_start(void)
  38. {
  39. u32 mc_ctrl0 = sgimc->cpuctrl0;
  40. mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
  41. sgimc->cpuctrl0 = mc_ctrl0;
  42. }
  43. static void indydog_stop(void)
  44. {
  45. u32 mc_ctrl0 = sgimc->cpuctrl0;
  46. mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
  47. sgimc->cpuctrl0 = mc_ctrl0;
  48. printk(KERN_INFO PFX "Stopped watchdog timer.\n");
  49. }
  50. static void indydog_ping(void)
  51. {
  52. sgimc->watchdogt = 0;
  53. }
  54. /*
  55. * Allow only one person to hold it open
  56. */
  57. static int indydog_open(struct inode *inode, struct file *file)
  58. {
  59. if (indydog_alive)
  60. return -EBUSY;
  61. if (nowayout)
  62. __module_get(THIS_MODULE);
  63. /* Activate timer */
  64. indydog_start();
  65. indydog_ping();
  66. indydog_alive = 1;
  67. printk(KERN_INFO "Started watchdog timer.\n");
  68. return nonseekable_open(inode, file);
  69. }
  70. static int indydog_release(struct inode *inode, struct file *file)
  71. {
  72. /* Shut off the timer.
  73. * Lock it in if it's a module and we defined ...NOWAYOUT */
  74. if (!nowayout)
  75. indydog_stop(); /* Turn the WDT off */
  76. indydog_alive = 0;
  77. return 0;
  78. }
  79. static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
  80. {
  81. /* Refresh the timer. */
  82. if (len) {
  83. indydog_ping();
  84. }
  85. return len;
  86. }
  87. static int indydog_ioctl(struct inode *inode, struct file *file,
  88. unsigned int cmd, unsigned long arg)
  89. {
  90. int options, retval = -EINVAL;
  91. static struct watchdog_info ident = {
  92. .options = WDIOF_KEEPALIVEPING |
  93. WDIOF_MAGICCLOSE,
  94. .firmware_version = 0,
  95. .identity = "Hardware Watchdog for SGI IP22",
  96. };
  97. switch (cmd) {
  98. default:
  99. return -ENOIOCTLCMD;
  100. case WDIOC_GETSUPPORT:
  101. if (copy_to_user((struct watchdog_info *)arg,
  102. &ident, sizeof(ident)))
  103. return -EFAULT;
  104. return 0;
  105. case WDIOC_GETSTATUS:
  106. case WDIOC_GETBOOTSTATUS:
  107. return put_user(0,(int *)arg);
  108. case WDIOC_KEEPALIVE:
  109. indydog_ping();
  110. return 0;
  111. case WDIOC_GETTIMEOUT:
  112. return put_user(WATCHDOG_TIMEOUT,(int *)arg);
  113. case WDIOC_SETOPTIONS:
  114. {
  115. if (get_user(options, (int *)arg))
  116. return -EFAULT;
  117. if (options & WDIOS_DISABLECARD) {
  118. indydog_stop();
  119. retval = 0;
  120. }
  121. if (options & WDIOS_ENABLECARD) {
  122. indydog_start();
  123. retval = 0;
  124. }
  125. return retval;
  126. }
  127. }
  128. }
  129. static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
  130. {
  131. if (code == SYS_DOWN || code == SYS_HALT)
  132. indydog_stop(); /* Turn the WDT off */
  133. return NOTIFY_DONE;
  134. }
  135. static struct file_operations indydog_fops = {
  136. .owner = THIS_MODULE,
  137. .llseek = no_llseek,
  138. .write = indydog_write,
  139. .ioctl = indydog_ioctl,
  140. .open = indydog_open,
  141. .release = indydog_release,
  142. };
  143. static struct miscdevice indydog_miscdev = {
  144. .minor = WATCHDOG_MINOR,
  145. .name = "watchdog",
  146. .fops = &indydog_fops,
  147. };
  148. static struct notifier_block indydog_notifier = {
  149. .notifier_call = indydog_notify_sys,
  150. };
  151. static char banner[] __initdata =
  152. KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
  153. static int __init watchdog_init(void)
  154. {
  155. int ret;
  156. ret = register_reboot_notifier(&indydog_notifier);
  157. if (ret) {
  158. printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
  159. ret);
  160. return ret;
  161. }
  162. ret = misc_register(&indydog_miscdev);
  163. if (ret) {
  164. printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
  165. WATCHDOG_MINOR, ret);
  166. unregister_reboot_notifier(&indydog_notifier);
  167. return ret;
  168. }
  169. printk(banner);
  170. return 0;
  171. }
  172. static void __exit watchdog_exit(void)
  173. {
  174. misc_deregister(&indydog_miscdev);
  175. unregister_reboot_notifier(&indydog_notifier);
  176. }
  177. module_init(watchdog_init);
  178. module_exit(watchdog_exit);
  179. MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
  180. MODULE_DESCRIPTION("Hardware Watchdog Device for SGI IP22");
  181. MODULE_LICENSE("GPL");
  182. MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);