Root/
1 | /* |
2 | * SBC EPX C3 0.1 A Hardware Watchdog Device for the Winsystems EPX-C3 |
3 | * single board computer |
4 | * |
5 | * (c) Copyright 2006 Calin A. Culianu <calin@ajvar.org>, All Rights |
6 | * Reserved. |
7 | * |
8 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License |
10 | * as published by the Free Software Foundation; either version |
11 | * 2 of the License, or (at your option) any later version. |
12 | * |
13 | * based on softdog.c by Alan Cox <alan@lxorguk.ukuu.org.uk> |
14 | */ |
15 | |
16 | #include <linux/module.h> |
17 | #include <linux/moduleparam.h> |
18 | #include <linux/types.h> |
19 | #include <linux/kernel.h> |
20 | #include <linux/fs.h> |
21 | #include <linux/mm.h> |
22 | #include <linux/miscdevice.h> |
23 | #include <linux/watchdog.h> |
24 | #include <linux/notifier.h> |
25 | #include <linux/reboot.h> |
26 | #include <linux/init.h> |
27 | #include <linux/ioport.h> |
28 | #include <linux/uaccess.h> |
29 | #include <linux/io.h> |
30 | |
31 | #define PFX "epx_c3: " |
32 | static int epx_c3_alive; |
33 | |
34 | #define WATCHDOG_TIMEOUT 1 /* 1 sec default timeout */ |
35 | |
36 | static int nowayout = WATCHDOG_NOWAYOUT; |
37 | module_param(nowayout, int, 0); |
38 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
39 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
40 | |
41 | #define EPXC3_WATCHDOG_CTL_REG 0x1ee /* write 1 to enable, 0 to disable */ |
42 | #define EPXC3_WATCHDOG_PET_REG 0x1ef /* write anything to pet once enabled */ |
43 | |
44 | static void epx_c3_start(void) |
45 | { |
46 | outb(1, EPXC3_WATCHDOG_CTL_REG); |
47 | } |
48 | |
49 | static void epx_c3_stop(void) |
50 | { |
51 | |
52 | outb(0, EPXC3_WATCHDOG_CTL_REG); |
53 | |
54 | printk(KERN_INFO PFX "Stopped watchdog timer.\n"); |
55 | } |
56 | |
57 | static void epx_c3_pet(void) |
58 | { |
59 | outb(1, EPXC3_WATCHDOG_PET_REG); |
60 | } |
61 | |
62 | /* |
63 | * Allow only one person to hold it open |
64 | */ |
65 | static int epx_c3_open(struct inode *inode, struct file *file) |
66 | { |
67 | if (epx_c3_alive) |
68 | return -EBUSY; |
69 | |
70 | if (nowayout) |
71 | __module_get(THIS_MODULE); |
72 | |
73 | /* Activate timer */ |
74 | epx_c3_start(); |
75 | epx_c3_pet(); |
76 | |
77 | epx_c3_alive = 1; |
78 | printk(KERN_INFO "Started watchdog timer.\n"); |
79 | |
80 | return nonseekable_open(inode, file); |
81 | } |
82 | |
83 | static int epx_c3_release(struct inode *inode, struct file *file) |
84 | { |
85 | /* Shut off the timer. |
86 | * Lock it in if it's a module and we defined ...NOWAYOUT */ |
87 | if (!nowayout) |
88 | epx_c3_stop(); /* Turn the WDT off */ |
89 | |
90 | epx_c3_alive = 0; |
91 | |
92 | return 0; |
93 | } |
94 | |
95 | static ssize_t epx_c3_write(struct file *file, const char __user *data, |
96 | size_t len, loff_t *ppos) |
97 | { |
98 | /* Refresh the timer. */ |
99 | if (len) |
100 | epx_c3_pet(); |
101 | return len; |
102 | } |
103 | |
104 | static long epx_c3_ioctl(struct file *file, unsigned int cmd, |
105 | unsigned long arg) |
106 | { |
107 | int options, retval = -EINVAL; |
108 | int __user *argp = (void __user *)arg; |
109 | static const struct watchdog_info ident = { |
110 | .options = WDIOF_KEEPALIVEPING, |
111 | .firmware_version = 0, |
112 | .identity = "Winsystems EPX-C3 H/W Watchdog", |
113 | }; |
114 | |
115 | switch (cmd) { |
116 | case WDIOC_GETSUPPORT: |
117 | if (copy_to_user(argp, &ident, sizeof(ident))) |
118 | return -EFAULT; |
119 | return 0; |
120 | case WDIOC_GETSTATUS: |
121 | case WDIOC_GETBOOTSTATUS: |
122 | return put_user(0, argp); |
123 | case WDIOC_SETOPTIONS: |
124 | if (get_user(options, argp)) |
125 | return -EFAULT; |
126 | |
127 | if (options & WDIOS_DISABLECARD) { |
128 | epx_c3_stop(); |
129 | retval = 0; |
130 | } |
131 | |
132 | if (options & WDIOS_ENABLECARD) { |
133 | epx_c3_start(); |
134 | retval = 0; |
135 | } |
136 | |
137 | return retval; |
138 | case WDIOC_KEEPALIVE: |
139 | epx_c3_pet(); |
140 | return 0; |
141 | case WDIOC_GETTIMEOUT: |
142 | return put_user(WATCHDOG_TIMEOUT, argp); |
143 | default: |
144 | return -ENOTTY; |
145 | } |
146 | } |
147 | |
148 | static int epx_c3_notify_sys(struct notifier_block *this, unsigned long code, |
149 | void *unused) |
150 | { |
151 | if (code == SYS_DOWN || code == SYS_HALT) |
152 | epx_c3_stop(); /* Turn the WDT off */ |
153 | |
154 | return NOTIFY_DONE; |
155 | } |
156 | |
157 | static const struct file_operations epx_c3_fops = { |
158 | .owner = THIS_MODULE, |
159 | .llseek = no_llseek, |
160 | .write = epx_c3_write, |
161 | .unlocked_ioctl = epx_c3_ioctl, |
162 | .open = epx_c3_open, |
163 | .release = epx_c3_release, |
164 | }; |
165 | |
166 | static struct miscdevice epx_c3_miscdev = { |
167 | .minor = WATCHDOG_MINOR, |
168 | .name = "watchdog", |
169 | .fops = &epx_c3_fops, |
170 | }; |
171 | |
172 | static struct notifier_block epx_c3_notifier = { |
173 | .notifier_call = epx_c3_notify_sys, |
174 | }; |
175 | |
176 | static const char banner[] __initdata = KERN_INFO PFX |
177 | "Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n"; |
178 | |
179 | static int __init watchdog_init(void) |
180 | { |
181 | int ret; |
182 | |
183 | if (!request_region(EPXC3_WATCHDOG_CTL_REG, 2, "epxc3_watchdog")) |
184 | return -EBUSY; |
185 | |
186 | ret = register_reboot_notifier(&epx_c3_notifier); |
187 | if (ret) { |
188 | printk(KERN_ERR PFX "cannot register reboot notifier " |
189 | "(err=%d)\n", ret); |
190 | goto out; |
191 | } |
192 | |
193 | ret = misc_register(&epx_c3_miscdev); |
194 | if (ret) { |
195 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d " |
196 | "(err=%d)\n", WATCHDOG_MINOR, ret); |
197 | unregister_reboot_notifier(&epx_c3_notifier); |
198 | goto out; |
199 | } |
200 | |
201 | printk(banner); |
202 | |
203 | return 0; |
204 | |
205 | out: |
206 | release_region(EPXC3_WATCHDOG_CTL_REG, 2); |
207 | return ret; |
208 | } |
209 | |
210 | static void __exit watchdog_exit(void) |
211 | { |
212 | misc_deregister(&epx_c3_miscdev); |
213 | unregister_reboot_notifier(&epx_c3_notifier); |
214 | release_region(EPXC3_WATCHDOG_CTL_REG, 2); |
215 | } |
216 | |
217 | module_init(watchdog_init); |
218 | module_exit(watchdog_exit); |
219 | |
220 | MODULE_AUTHOR("Calin A. Culianu <calin@ajvar.org>"); |
221 | MODULE_DESCRIPTION("Hardware Watchdog Device for Winsystems EPX-C3 SBC. " |
222 | "Note that there is no way to probe for this device -- " |
223 | "so only use it if you are *sure* you are runnning on this specific " |
224 | "SBC system from Winsystems! It writes to IO ports 0x1ee and 0x1ef!"); |
225 | MODULE_LICENSE("GPL"); |
226 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
227 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9