This source file includes following definitions.
- sbc8360_activate
- sbc8360_ping
- sbc8360_stop
- sbc8360_write
- sbc8360_open
- sbc8360_close
- sbc8360_notify_sys
- sbc8360_init
- sbc8360_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
31
32
33
34
35 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
36
37 #include <linux/module.h>
38 #include <linux/types.h>
39 #include <linux/miscdevice.h>
40 #include <linux/watchdog.h>
41 #include <linux/ioport.h>
42 #include <linux/delay.h>
43 #include <linux/notifier.h>
44 #include <linux/fs.h>
45 #include <linux/reboot.h>
46 #include <linux/init.h>
47 #include <linux/spinlock.h>
48 #include <linux/moduleparam.h>
49 #include <linux/io.h>
50 #include <linux/uaccess.h>
51
52
53 static unsigned long sbc8360_is_open;
54 static char expect_close;
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 static int wd_times[64][2] = {
123 {0, 1},
124 {1, 1},
125 {2, 1},
126 {3, 1},
127 {4, 1},
128 {5, 1},
129 {6, 1},
130 {7, 1},
131 {8, 1},
132 {9, 1},
133 {0xA, 1},
134 {0xB, 1},
135 {0xC, 1},
136 {0xD, 1},
137 {0xE, 1},
138 {0xF, 1},
139 {0, 2},
140 {1, 2},
141 {2, 2},
142 {3, 2},
143 {4, 2},
144 {5, 2},
145 {6, 2},
146 {7, 2},
147 {8, 2},
148 {9, 2},
149 {0xA, 2},
150 {0xB, 2},
151 {0xC, 2},
152 {0xD, 2},
153 {0xE, 2},
154 {0xF, 2},
155 {0, 3},
156 {1, 3},
157 {2, 3},
158 {3, 3},
159 {4, 3},
160 {5, 3},
161 {6, 3},
162 {7, 3},
163 {8, 3},
164 {9, 3},
165 {0xA, 3},
166 {0xB, 3},
167 {0xC, 3},
168 {0xD, 3},
169 {0xE, 3},
170 {0xF, 3},
171 {0, 4},
172 {1, 4},
173 {2, 4},
174 {3, 4},
175 {4, 4},
176 {5, 4},
177 {6, 4},
178 {7, 4},
179 {8, 4},
180 {9, 4},
181 {0xA, 4},
182 {0xB, 4},
183 {0xC, 4},
184 {0xD, 4},
185 {0xE, 4},
186 {0xF, 4}
187 };
188
189 #define SBC8360_ENABLE 0x120
190 #define SBC8360_BASETIME 0x121
191
192 static int timeout = 27;
193 static int wd_margin = 0xB;
194 static int wd_multiplier = 2;
195 static bool nowayout = WATCHDOG_NOWAYOUT;
196
197 module_param(timeout, int, 0);
198 MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
199 module_param(nowayout, bool, 0);
200 MODULE_PARM_DESC(nowayout,
201 "Watchdog cannot be stopped once started (default="
202 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
203
204
205
206
207
208
209 static void sbc8360_activate(void)
210 {
211
212 outb(0x0A, SBC8360_ENABLE);
213 msleep_interruptible(100);
214 outb(0x0B, SBC8360_ENABLE);
215 msleep_interruptible(100);
216
217 outb(wd_multiplier, SBC8360_ENABLE);
218 msleep_interruptible(100);
219
220 }
221
222
223 static void sbc8360_ping(void)
224 {
225
226 outb(wd_margin, SBC8360_BASETIME);
227 }
228
229
230 static void sbc8360_stop(void)
231 {
232
233 outb(0, SBC8360_ENABLE);
234 }
235
236
237 static ssize_t sbc8360_write(struct file *file, const char __user *buf,
238 size_t count, loff_t *ppos)
239 {
240 if (count) {
241 if (!nowayout) {
242 size_t i;
243
244
245 expect_close = 0;
246
247 for (i = 0; i != count; i++) {
248 char c;
249 if (get_user(c, buf + i))
250 return -EFAULT;
251 if (c == 'V')
252 expect_close = 42;
253 }
254 }
255 sbc8360_ping();
256 }
257 return count;
258 }
259
260 static int sbc8360_open(struct inode *inode, struct file *file)
261 {
262 if (test_and_set_bit(0, &sbc8360_is_open))
263 return -EBUSY;
264 if (nowayout)
265 __module_get(THIS_MODULE);
266
267
268 sbc8360_activate();
269 sbc8360_ping();
270 return stream_open(inode, file);
271 }
272
273 static int sbc8360_close(struct inode *inode, struct file *file)
274 {
275 if (expect_close == 42)
276 sbc8360_stop();
277 else
278 pr_crit("SBC8360 device closed unexpectedly. SBC8360 will not stop!\n");
279
280 clear_bit(0, &sbc8360_is_open);
281 expect_close = 0;
282 return 0;
283 }
284
285
286
287
288
289 static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code,
290 void *unused)
291 {
292 if (code == SYS_DOWN || code == SYS_HALT)
293 sbc8360_stop();
294
295 return NOTIFY_DONE;
296 }
297
298
299
300
301
302 static const struct file_operations sbc8360_fops = {
303 .owner = THIS_MODULE,
304 .llseek = no_llseek,
305 .write = sbc8360_write,
306 .open = sbc8360_open,
307 .release = sbc8360_close,
308 };
309
310 static struct miscdevice sbc8360_miscdev = {
311 .minor = WATCHDOG_MINOR,
312 .name = "watchdog",
313 .fops = &sbc8360_fops,
314 };
315
316
317
318
319
320
321 static struct notifier_block sbc8360_notifier = {
322 .notifier_call = sbc8360_notify_sys,
323 };
324
325 static int __init sbc8360_init(void)
326 {
327 int res;
328 unsigned long int mseconds = 60000;
329
330 if (timeout < 0 || timeout > 63) {
331 pr_err("Invalid timeout index (must be 0-63)\n");
332 res = -EINVAL;
333 goto out;
334 }
335
336 if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
337 pr_err("ENABLE method I/O %X is not available\n",
338 SBC8360_ENABLE);
339 res = -EIO;
340 goto out;
341 }
342 if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
343 pr_err("BASETIME method I/O %X is not available\n",
344 SBC8360_BASETIME);
345 res = -EIO;
346 goto out_nobasetimereg;
347 }
348
349 res = register_reboot_notifier(&sbc8360_notifier);
350 if (res) {
351 pr_err("Failed to register reboot notifier\n");
352 goto out_noreboot;
353 }
354
355 res = misc_register(&sbc8360_miscdev);
356 if (res) {
357 pr_err("failed to register misc device\n");
358 goto out_nomisc;
359 }
360
361 wd_margin = wd_times[timeout][0];
362 wd_multiplier = wd_times[timeout][1];
363
364 if (wd_multiplier == 1)
365 mseconds = (wd_margin + 1) * 500;
366 else if (wd_multiplier == 2)
367 mseconds = (wd_margin + 1) * 5000;
368 else if (wd_multiplier == 3)
369 mseconds = (wd_margin + 1) * 50000;
370 else if (wd_multiplier == 4)
371 mseconds = (wd_margin + 1) * 100000;
372
373
374 pr_info("Timeout set at %ld ms\n", mseconds);
375
376 return 0;
377
378 out_nomisc:
379 unregister_reboot_notifier(&sbc8360_notifier);
380 out_noreboot:
381 release_region(SBC8360_BASETIME, 1);
382 out_nobasetimereg:
383 release_region(SBC8360_ENABLE, 1);
384 out:
385 return res;
386 }
387
388 static void __exit sbc8360_exit(void)
389 {
390 misc_deregister(&sbc8360_miscdev);
391 unregister_reboot_notifier(&sbc8360_notifier);
392 release_region(SBC8360_ENABLE, 1);
393 release_region(SBC8360_BASETIME, 1);
394 }
395
396 module_init(sbc8360_init);
397 module_exit(sbc8360_exit);
398
399 MODULE_AUTHOR("Ian E. Morgan <imorgan@webcon.ca>");
400 MODULE_DESCRIPTION("SBC8360 watchdog driver");
401 MODULE_LICENSE("GPL");
402 MODULE_VERSION("1.01");
403
404