This source file includes following definitions.
- ibwdt_ping
- ibwdt_disable
- ibwdt_set_heartbeat
- ibwdt_write
- ibwdt_ioctl
- ibwdt_open
- ibwdt_close
- ibwdt_probe
- ibwdt_remove
- ibwdt_shutdown
- ibwdt_init
- ibwdt_exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31
32 #include <linux/module.h>
33 #include <linux/types.h>
34 #include <linux/miscdevice.h>
35 #include <linux/watchdog.h>
36 #include <linux/ioport.h>
37 #include <linux/fs.h>
38 #include <linux/init.h>
39 #include <linux/spinlock.h>
40 #include <linux/moduleparam.h>
41 #include <linux/platform_device.h>
42 #include <linux/io.h>
43 #include <linux/uaccess.h>
44
45
46 static struct platform_device *ibwdt_platform_device;
47 static unsigned long ibwdt_is_open;
48 static DEFINE_SPINLOCK(ibwdt_lock);
49 static char expect_close;
50
51
52 #define DRV_NAME "ib700wdt"
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 #define WDT_STOP 0x441
91 #define WDT_START 0x443
92
93
94 #define WATCHDOG_TIMEOUT 30
95 static int timeout = WATCHDOG_TIMEOUT;
96 module_param(timeout, int, 0);
97 MODULE_PARM_DESC(timeout,
98 "Watchdog timeout in seconds. 0<= timeout <=30, default="
99 __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
100
101 static bool nowayout = WATCHDOG_NOWAYOUT;
102 module_param(nowayout, bool, 0);
103 MODULE_PARM_DESC(nowayout,
104 "Watchdog cannot be stopped once started (default="
105 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
106
107
108
109
110
111
112 static void ibwdt_ping(void)
113 {
114 int wd_margin = 15 - ((timeout + 1) / 2);
115
116 spin_lock(&ibwdt_lock);
117
118
119 outb_p(wd_margin, WDT_START);
120
121 spin_unlock(&ibwdt_lock);
122 }
123
124 static void ibwdt_disable(void)
125 {
126 spin_lock(&ibwdt_lock);
127 outb_p(0, WDT_STOP);
128 spin_unlock(&ibwdt_lock);
129 }
130
131 static int ibwdt_set_heartbeat(int t)
132 {
133 if (t < 0 || t > 30)
134 return -EINVAL;
135
136 timeout = t;
137 return 0;
138 }
139
140
141
142
143
144 static ssize_t ibwdt_write(struct file *file, const char __user *buf,
145 size_t count, loff_t *ppos)
146 {
147 if (count) {
148 if (!nowayout) {
149 size_t i;
150
151
152 expect_close = 0;
153
154 for (i = 0; i != count; i++) {
155 char c;
156 if (get_user(c, buf + i))
157 return -EFAULT;
158 if (c == 'V')
159 expect_close = 42;
160 }
161 }
162 ibwdt_ping();
163 }
164 return count;
165 }
166
167 static long ibwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
168 {
169 int new_margin;
170 void __user *argp = (void __user *)arg;
171 int __user *p = argp;
172
173 static const struct watchdog_info ident = {
174 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
175 | WDIOF_MAGICCLOSE,
176 .firmware_version = 1,
177 .identity = "IB700 WDT",
178 };
179
180 switch (cmd) {
181 case WDIOC_GETSUPPORT:
182 if (copy_to_user(argp, &ident, sizeof(ident)))
183 return -EFAULT;
184 break;
185
186 case WDIOC_GETSTATUS:
187 case WDIOC_GETBOOTSTATUS:
188 return put_user(0, p);
189
190 case WDIOC_SETOPTIONS:
191 {
192 int options, retval = -EINVAL;
193
194 if (get_user(options, p))
195 return -EFAULT;
196
197 if (options & WDIOS_DISABLECARD) {
198 ibwdt_disable();
199 retval = 0;
200 }
201 if (options & WDIOS_ENABLECARD) {
202 ibwdt_ping();
203 retval = 0;
204 }
205 return retval;
206 }
207 case WDIOC_KEEPALIVE:
208 ibwdt_ping();
209 break;
210
211 case WDIOC_SETTIMEOUT:
212 if (get_user(new_margin, p))
213 return -EFAULT;
214 if (ibwdt_set_heartbeat(new_margin))
215 return -EINVAL;
216 ibwdt_ping();
217
218
219 case WDIOC_GETTIMEOUT:
220 return put_user(timeout, p);
221
222 default:
223 return -ENOTTY;
224 }
225 return 0;
226 }
227
228 static int ibwdt_open(struct inode *inode, struct file *file)
229 {
230 if (test_and_set_bit(0, &ibwdt_is_open))
231 return -EBUSY;
232 if (nowayout)
233 __module_get(THIS_MODULE);
234
235
236 ibwdt_ping();
237 return stream_open(inode, file);
238 }
239
240 static int ibwdt_close(struct inode *inode, struct file *file)
241 {
242 if (expect_close == 42) {
243 ibwdt_disable();
244 } else {
245 pr_crit("WDT device closed unexpectedly. WDT will not stop!\n");
246 ibwdt_ping();
247 }
248 clear_bit(0, &ibwdt_is_open);
249 expect_close = 0;
250 return 0;
251 }
252
253
254
255
256
257 static const struct file_operations ibwdt_fops = {
258 .owner = THIS_MODULE,
259 .llseek = no_llseek,
260 .write = ibwdt_write,
261 .unlocked_ioctl = ibwdt_ioctl,
262 .open = ibwdt_open,
263 .release = ibwdt_close,
264 };
265
266 static struct miscdevice ibwdt_miscdev = {
267 .minor = WATCHDOG_MINOR,
268 .name = "watchdog",
269 .fops = &ibwdt_fops,
270 };
271
272
273
274
275
276 static int __init ibwdt_probe(struct platform_device *dev)
277 {
278 int res;
279
280 #if WDT_START != WDT_STOP
281 if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
282 pr_err("STOP method I/O %X is not available\n", WDT_STOP);
283 res = -EIO;
284 goto out_nostopreg;
285 }
286 #endif
287
288 if (!request_region(WDT_START, 1, "IB700 WDT")) {
289 pr_err("START method I/O %X is not available\n", WDT_START);
290 res = -EIO;
291 goto out_nostartreg;
292 }
293
294
295
296 if (ibwdt_set_heartbeat(timeout)) {
297 ibwdt_set_heartbeat(WATCHDOG_TIMEOUT);
298 pr_info("timeout value must be 0<=x<=30, using %d\n", timeout);
299 }
300
301 res = misc_register(&ibwdt_miscdev);
302 if (res) {
303 pr_err("failed to register misc device\n");
304 goto out_nomisc;
305 }
306 return 0;
307
308 out_nomisc:
309 release_region(WDT_START, 1);
310 out_nostartreg:
311 #if WDT_START != WDT_STOP
312 release_region(WDT_STOP, 1);
313 #endif
314 out_nostopreg:
315 return res;
316 }
317
318 static int ibwdt_remove(struct platform_device *dev)
319 {
320 misc_deregister(&ibwdt_miscdev);
321 release_region(WDT_START, 1);
322 #if WDT_START != WDT_STOP
323 release_region(WDT_STOP, 1);
324 #endif
325 return 0;
326 }
327
328 static void ibwdt_shutdown(struct platform_device *dev)
329 {
330
331 ibwdt_disable();
332 }
333
334 static struct platform_driver ibwdt_driver = {
335 .remove = ibwdt_remove,
336 .shutdown = ibwdt_shutdown,
337 .driver = {
338 .name = DRV_NAME,
339 },
340 };
341
342 static int __init ibwdt_init(void)
343 {
344 int err;
345
346 pr_info("WDT driver for IB700 single board computer initialising\n");
347
348 ibwdt_platform_device = platform_device_register_simple(DRV_NAME,
349 -1, NULL, 0);
350 if (IS_ERR(ibwdt_platform_device))
351 return PTR_ERR(ibwdt_platform_device);
352
353 err = platform_driver_probe(&ibwdt_driver, ibwdt_probe);
354 if (err)
355 goto unreg_platform_device;
356
357 return 0;
358
359 unreg_platform_device:
360 platform_device_unregister(ibwdt_platform_device);
361 return err;
362 }
363
364 static void __exit ibwdt_exit(void)
365 {
366 platform_device_unregister(ibwdt_platform_device);
367 platform_driver_unregister(&ibwdt_driver);
368 pr_info("Watchdog Module Unloaded\n");
369 }
370
371 module_init(ibwdt_init);
372 module_exit(ibwdt_exit);
373
374 MODULE_AUTHOR("Charles Howes <chowes@vsol.net>");
375 MODULE_DESCRIPTION("IB700 SBC watchdog driver");
376 MODULE_LICENSE("GPL");
377
378