Diff markup
1 /* 1 /*
2 * Advantech Single Board Computer WDT dr 2 * Advantech Single Board Computer WDT driver
3 * 3 *
4 * (c) Copyright 2000-2001 Marek Michalki 4 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
5 * 5 *
6 * Based on acquirewdt.c which is based o 6 * Based on acquirewdt.c which is based on wdt.c.
7 * Original copyright messages: 7 * Original copyright messages:
8 * 8 *
9 * (c) Copyright 1996 Alan Cox <alan@lxor !! 9 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
10 * !! 10 * http://www.redhat.com
11 * 11 *
12 * This program is free software; you can 12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU G 13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foun 14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) 15 * 2 of the License, or (at your option) any later version.
16 * 16 *
17 * Neither Alan Cox nor CymruNet Ltd. adm 17 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
18 * warranty for any of this software. Thi 18 * warranty for any of this software. This material is provided
19 * "AS-IS" and at no charge. 19 * "AS-IS" and at no charge.
20 * 20 *
21 * (c) Copyright 1995 Alan Cox <alan@l !! 21 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
22 * 22 *
23 * 14-Dec-2001 Matt Domsch <Matt_Domsch@d 23 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
24 * Added nowayout module option to ov 24 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
25 * 25 *
26 * 16-Oct-2002 Rob Radez <rob@osinvestor. 26 * 16-Oct-2002 Rob Radez <rob@osinvestor.com>
27 * Clean up ioctls, clean up init + e 27 * Clean up ioctls, clean up init + exit, add expect close support,
28 * add wdt_start and wdt_stop as para 28 * add wdt_start and wdt_stop as parameters.
29 */ 29 */
30 30
31 #include <linux/module.h> 31 #include <linux/module.h>
32 #include <linux/moduleparam.h> 32 #include <linux/moduleparam.h>
33 #include <linux/types.h> 33 #include <linux/types.h>
34 #include <linux/miscdevice.h> 34 #include <linux/miscdevice.h>
35 #include <linux/watchdog.h> 35 #include <linux/watchdog.h>
36 #include <linux/fs.h> 36 #include <linux/fs.h>
37 #include <linux/ioport.h> 37 #include <linux/ioport.h>
38 #include <linux/platform_device.h> 38 #include <linux/platform_device.h>
39 #include <linux/init.h> 39 #include <linux/init.h>
40 #include <linux/io.h> <<
41 #include <linux/uaccess.h> <<
42 40
>> 41 #include <asm/io.h>
>> 42 #include <asm/uaccess.h>
43 #include <asm/system.h> 43 #include <asm/system.h>
44 44
45 #define DRV_NAME "advantechwdt" 45 #define DRV_NAME "advantechwdt"
46 #define PFX DRV_NAME ": " 46 #define PFX DRV_NAME ": "
47 #define WATCHDOG_NAME "Advantech WDT" 47 #define WATCHDOG_NAME "Advantech WDT"
48 #define WATCHDOG_TIMEOUT 60 /* 60 48 #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
49 49
50 /* the watchdog platform device */ !! 50 static struct platform_device *advwdt_platform_device; /* the watchdog platform device */
51 static struct platform_device *advwdt_platform <<
52 static unsigned long advwdt_is_open; 51 static unsigned long advwdt_is_open;
53 static char adv_expect_close; 52 static char adv_expect_close;
54 53
55 /* 54 /*
56 * You must set these - there is no sane 55 * You must set these - there is no sane way to probe for this board.
57 * 56 *
58 * To enable or restart, write the timeou 57 * To enable or restart, write the timeout value in seconds (1 to 63)
59 * to I/O port wdt_start. To disable, re 58 * to I/O port wdt_start. To disable, read I/O port wdt_stop.
60 * Both are 0x443 for most boards (tested 59 * Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but
61 * check your manual (at least the PCA-61 60 * check your manual (at least the PCA-6159 seems to be different -
62 * the manual says wdt_stop is 0x43, not 61 * the manual says wdt_stop is 0x43, not 0x443).
63 * (0x43 is also a write-only control reg 62 * (0x43 is also a write-only control register for the 8254 timer!)
64 */ 63 */
65 64
66 static int wdt_stop = 0x443; 65 static int wdt_stop = 0x443;
67 module_param(wdt_stop, int, 0); 66 module_param(wdt_stop, int, 0);
68 MODULE_PARM_DESC(wdt_stop, "Advantech WDT 'sto 67 MODULE_PARM_DESC(wdt_stop, "Advantech WDT 'stop' io port (default 0x443)");
69 68
70 static int wdt_start = 0x443; 69 static int wdt_start = 0x443;
71 module_param(wdt_start, int, 0); 70 module_param(wdt_start, int, 0);
72 MODULE_PARM_DESC(wdt_start, "Advantech WDT 'st 71 MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)");
73 72
74 static int timeout = WATCHDOG_TIMEOUT; /* in 73 static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
75 module_param(timeout, int, 0); 74 module_param(timeout, int, 0);
76 MODULE_PARM_DESC(timeout, !! 75 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
77 "Watchdog timeout in seconds. 1<= time <<
78 __MODULE_STRING(WATCHDOG_TIMEO <<
79 76
80 static int nowayout = WATCHDOG_NOWAYOUT; 77 static int nowayout = WATCHDOG_NOWAYOUT;
81 module_param(nowayout, int, 0); 78 module_param(nowayout, int, 0);
82 MODULE_PARM_DESC(nowayout, !! 79 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
83 "Watchdog cannot be stopped once start <<
84 __MODULE_STRING(WATCHDOG_NOWAY <<
85 80
86 /* 81 /*
87 * Watchdog Operations 82 * Watchdog Operations
88 */ 83 */
89 84
90 static void advwdt_ping(void) !! 85 static void
>> 86 advwdt_ping(void)
91 { 87 {
92 /* Write a watchdog value */ 88 /* Write a watchdog value */
93 outb_p(timeout, wdt_start); 89 outb_p(timeout, wdt_start);
94 } 90 }
95 91
96 static void advwdt_disable(void) !! 92 static void
>> 93 advwdt_disable(void)
97 { 94 {
98 inb_p(wdt_stop); 95 inb_p(wdt_stop);
99 } 96 }
100 97
101 static int advwdt_set_heartbeat(int t) !! 98 static int
>> 99 advwdt_set_heartbeat(int t)
102 { 100 {
103 if (t < 1 || t > 63) !! 101 if ((t < 1) || (t > 63))
104 return -EINVAL; 102 return -EINVAL;
>> 103
105 timeout = t; 104 timeout = t;
106 return 0; 105 return 0;
107 } 106 }
108 107
109 /* 108 /*
110 * /dev/watchdog handling 109 * /dev/watchdog handling
111 */ 110 */
112 111
113 static ssize_t advwdt_write(struct file *file, !! 112 static ssize_t
114 !! 113 advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
115 { 114 {
116 if (count) { 115 if (count) {
117 if (!nowayout) { 116 if (!nowayout) {
118 size_t i; 117 size_t i;
119 118
120 adv_expect_close = 0; 119 adv_expect_close = 0;
121 120
122 for (i = 0; i != count 121 for (i = 0; i != count; i++) {
123 char c; 122 char c;
124 if (get_user(c !! 123 if (get_user(c, buf+i))
125 return 124 return -EFAULT;
126 if (c == 'V') 125 if (c == 'V')
127 adv_ex 126 adv_expect_close = 42;
128 } 127 }
129 } 128 }
130 advwdt_ping(); 129 advwdt_ping();
131 } 130 }
132 return count; 131 return count;
133 } 132 }
134 133
135 static long advwdt_ioctl(struct file *file, un !! 134 static int
>> 135 advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
>> 136 unsigned long arg)
136 { 137 {
137 int new_timeout; 138 int new_timeout;
138 void __user *argp = (void __user *)arg 139 void __user *argp = (void __user *)arg;
139 int __user *p = argp; 140 int __user *p = argp;
140 static struct watchdog_info ident = { 141 static struct watchdog_info ident = {
141 .options = WDIOF_KEEPALIVEPING !! 142 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
142 WDIOF_SETTIMEOUT | <<
143 WDIOF_MAGICCLOSE, <<
144 .firmware_version = 1, 143 .firmware_version = 1,
145 .identity = WATCHDOG_NAME, 144 .identity = WATCHDOG_NAME,
146 }; 145 };
147 146
148 switch (cmd) { 147 switch (cmd) {
149 case WDIOC_GETSUPPORT: 148 case WDIOC_GETSUPPORT:
150 if (copy_to_user(argp, &ident, !! 149 if (copy_to_user(argp, &ident, sizeof(ident)))
151 return -EFAULT; !! 150 return -EFAULT;
152 break; !! 151 break;
153 152
154 case WDIOC_GETSTATUS: 153 case WDIOC_GETSTATUS:
155 case WDIOC_GETBOOTSTATUS: 154 case WDIOC_GETBOOTSTATUS:
156 return put_user(0, p); !! 155 return put_user(0, p);
>> 156
>> 157 case WDIOC_KEEPALIVE:
>> 158 advwdt_ping();
>> 159 break;
>> 160
>> 161 case WDIOC_SETTIMEOUT:
>> 162 if (get_user(new_timeout, p))
>> 163 return -EFAULT;
>> 164 if (advwdt_set_heartbeat(new_timeout))
>> 165 return -EINVAL;
>> 166 advwdt_ping();
>> 167 /* Fall */
>> 168
>> 169 case WDIOC_GETTIMEOUT:
>> 170 return put_user(timeout, p);
157 171
158 case WDIOC_SETOPTIONS: 172 case WDIOC_SETOPTIONS:
159 { 173 {
160 int options, retval = -EINVAL; !! 174 int options, retval = -EINVAL;
161 175
162 if (get_user(options, p)) !! 176 if (get_user(options, p))
163 return -EFAULT; !! 177 return -EFAULT;
164 if (options & WDIOS_DISABLECAR !! 178
165 advwdt_disable(); !! 179 if (options & WDIOS_DISABLECARD) {
166 retval = 0; !! 180 advwdt_disable();
167 } !! 181 retval = 0;
168 if (options & WDIOS_ENABLECARD !! 182 }
169 advwdt_ping(); !! 183
170 retval = 0; !! 184 if (options & WDIOS_ENABLECARD) {
171 } !! 185 advwdt_ping();
172 return retval; !! 186 retval = 0;
>> 187 }
>> 188
>> 189 return retval;
173 } 190 }
174 case WDIOC_KEEPALIVE: <<
175 advwdt_ping(); <<
176 break; <<
177 191
178 case WDIOC_SETTIMEOUT: <<
179 if (get_user(new_timeout, p)) <<
180 return -EFAULT; <<
181 if (advwdt_set_heartbeat(new_t <<
182 return -EINVAL; <<
183 advwdt_ping(); <<
184 /* Fall */ <<
185 case WDIOC_GETTIMEOUT: <<
186 return put_user(timeout, p); <<
187 default: 192 default:
188 return -ENOTTY; !! 193 return -ENOTTY;
189 } 194 }
190 return 0; 195 return 0;
191 } 196 }
192 197
193 static int advwdt_open(struct inode *inode, st !! 198 static int
>> 199 advwdt_open(struct inode *inode, struct file *file)
194 { 200 {
195 if (test_and_set_bit(0, &advwdt_is_ope 201 if (test_and_set_bit(0, &advwdt_is_open))
196 return -EBUSY; 202 return -EBUSY;
197 /* 203 /*
198 * Activate 204 * Activate
199 */ 205 */
200 206
201 advwdt_ping(); 207 advwdt_ping();
202 return nonseekable_open(inode, file); 208 return nonseekable_open(inode, file);
203 } 209 }
204 210
205 static int advwdt_close(struct inode *inode, s !! 211 static int
>> 212 advwdt_close(struct inode *inode, struct file *file)
206 { 213 {
207 if (adv_expect_close == 42) { 214 if (adv_expect_close == 42) {
208 advwdt_disable(); 215 advwdt_disable();
209 } else { 216 } else {
210 printk(KERN_CRIT PFX !! 217 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
211 "Unexpected cl <<
212 advwdt_ping(); 218 advwdt_ping();
213 } 219 }
214 clear_bit(0, &advwdt_is_open); 220 clear_bit(0, &advwdt_is_open);
215 adv_expect_close = 0; 221 adv_expect_close = 0;
216 return 0; 222 return 0;
217 } 223 }
218 224
219 /* 225 /*
220 * Kernel Interfaces 226 * Kernel Interfaces
221 */ 227 */
222 228
223 static const struct file_operations advwdt_fop 229 static const struct file_operations advwdt_fops = {
224 .owner = THIS_MODULE, 230 .owner = THIS_MODULE,
225 .llseek = no_llseek, 231 .llseek = no_llseek,
226 .write = advwdt_write, 232 .write = advwdt_write,
227 .unlocked_ioctl = advwdt_ioctl, !! 233 .ioctl = advwdt_ioctl,
228 .open = advwdt_open, 234 .open = advwdt_open,
229 .release = advwdt_close, 235 .release = advwdt_close,
230 }; 236 };
231 237
232 static struct miscdevice advwdt_miscdev = { 238 static struct miscdevice advwdt_miscdev = {
233 .minor = WATCHDOG_MINOR, 239 .minor = WATCHDOG_MINOR,
234 .name = "watchdog", 240 .name = "watchdog",
235 .fops = &advwdt_fops, 241 .fops = &advwdt_fops,
236 }; 242 };
237 243
238 /* 244 /*
239 * Init & exit routines 245 * Init & exit routines
240 */ 246 */
241 247
242 static int __devinit advwdt_probe(struct platf !! 248 static int __devinit
>> 249 advwdt_probe(struct platform_device *dev)
243 { 250 {
244 int ret; 251 int ret;
245 252
246 if (wdt_stop != wdt_start) { 253 if (wdt_stop != wdt_start) {
247 if (!request_region(wdt_stop, 254 if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
248 printk(KERN_ERR PFX !! 255 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
249 "I/O address 0 !! 256 wdt_stop);
250 <<
251 ret = -EIO; 257 ret = -EIO;
252 goto out; 258 goto out;
253 } 259 }
254 } 260 }
255 261
256 if (!request_region(wdt_start, 1, WATC 262 if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
257 printk(KERN_ERR PFX !! 263 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
258 "I/O address 0 !! 264 wdt_start);
259 <<
260 ret = -EIO; 265 ret = -EIO;
261 goto unreg_stop; 266 goto unreg_stop;
262 } 267 }
263 268
264 /* Check that the heartbeat value is w !! 269 /* Check that the heartbeat value is within it's range ; if not reset to the default */
265 * if not reset to the default */ <<
266 if (advwdt_set_heartbeat(timeout)) { 270 if (advwdt_set_heartbeat(timeout)) {
267 advwdt_set_heartbeat(WATCHDOG_ 271 advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
268 printk(KERN_INFO PFX !! 272 printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n",
269 "timeout value must be !! 273 timeout);
270 } 274 }
271 275
272 ret = misc_register(&advwdt_miscdev); 276 ret = misc_register(&advwdt_miscdev);
273 if (ret != 0) { 277 if (ret != 0) {
274 printk(KERN_ERR PFX !! 278 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
275 "cannot register miscd !! 279 WATCHDOG_MINOR, ret);
276 <<
277 goto unreg_regions; 280 goto unreg_regions;
278 } 281 }
279 printk(KERN_INFO PFX "initialized. tim !! 282
>> 283 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
280 timeout, nowayout); 284 timeout, nowayout);
>> 285
281 out: 286 out:
282 return ret; 287 return ret;
283 unreg_regions: 288 unreg_regions:
284 release_region(wdt_start, 1); 289 release_region(wdt_start, 1);
285 unreg_stop: 290 unreg_stop:
286 if (wdt_stop != wdt_start) 291 if (wdt_stop != wdt_start)
287 release_region(wdt_stop, 1); 292 release_region(wdt_stop, 1);
288 goto out; 293 goto out;
289 } 294 }
290 295
291 static int __devexit advwdt_remove(struct plat !! 296 static int __devexit
>> 297 advwdt_remove(struct platform_device *dev)
292 { 298 {
293 misc_deregister(&advwdt_miscdev); 299 misc_deregister(&advwdt_miscdev);
294 release_region(wdt_start, 1); !! 300 release_region(wdt_start,1);
295 if (wdt_stop != wdt_start) !! 301 if(wdt_stop != wdt_start)
296 release_region(wdt_stop, 1); !! 302 release_region(wdt_stop,1);
297 303
298 return 0; 304 return 0;
299 } 305 }
300 306
301 static void advwdt_shutdown(struct platform_de !! 307 static void
>> 308 advwdt_shutdown(struct platform_device *dev)
302 { 309 {
303 /* Turn the WDT off if we have a soft 310 /* Turn the WDT off if we have a soft shutdown */
304 advwdt_disable(); 311 advwdt_disable();
305 } 312 }
306 313
307 static struct platform_driver advwdt_driver = 314 static struct platform_driver advwdt_driver = {
308 .probe = advwdt_probe, 315 .probe = advwdt_probe,
309 .remove = __devexit_p(advwdt_r 316 .remove = __devexit_p(advwdt_remove),
310 .shutdown = advwdt_shutdown, 317 .shutdown = advwdt_shutdown,
311 .driver = { 318 .driver = {
312 .owner = THIS_MODULE, 319 .owner = THIS_MODULE,
313 .name = DRV_NAME, 320 .name = DRV_NAME,
314 }, 321 },
315 }; 322 };
316 323
317 static int __init advwdt_init(void) !! 324 static int __init
>> 325 advwdt_init(void)
318 { 326 {
319 int err; 327 int err;
320 328
321 printk(KERN_INFO !! 329 printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
322 "WDT driver for Advantech single <<
323 330
324 err = platform_driver_register(&advwdt 331 err = platform_driver_register(&advwdt_driver);
325 if (err) 332 if (err)
326 return err; 333 return err;
327 334
328 advwdt_platform_device = platform_devi !! 335 advwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
329 <<
330 if (IS_ERR(advwdt_platform_device)) { 336 if (IS_ERR(advwdt_platform_device)) {
331 err = PTR_ERR(advwdt_platform_ 337 err = PTR_ERR(advwdt_platform_device);
332 goto unreg_platform_driver; 338 goto unreg_platform_driver;
333 } 339 }
334 340
335 return 0; 341 return 0;
336 342
337 unreg_platform_driver: 343 unreg_platform_driver:
338 platform_driver_unregister(&advwdt_dri 344 platform_driver_unregister(&advwdt_driver);
339 return err; 345 return err;
340 } 346 }
341 347
342 static void __exit advwdt_exit(void) !! 348 static void __exit
>> 349 advwdt_exit(void)
343 { 350 {
344 platform_device_unregister(advwdt_plat 351 platform_device_unregister(advwdt_platform_device);
345 platform_driver_unregister(&advwdt_dri 352 platform_driver_unregister(&advwdt_driver);
346 printk(KERN_INFO PFX "Watchdog Module 353 printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
347 } 354 }
348 355
349 module_init(advwdt_init); 356 module_init(advwdt_init);
350 module_exit(advwdt_exit); 357 module_exit(advwdt_exit);
351 358
352 MODULE_LICENSE("GPL"); 359 MODULE_LICENSE("GPL");
353 MODULE_AUTHOR("Marek Michalkiewicz <marekm@lin 360 MODULE_AUTHOR("Marek Michalkiewicz <marekm@linux.org.pl>");
354 MODULE_DESCRIPTION("Advantech Single Board Com 361 MODULE_DESCRIPTION("Advantech Single Board Computer WDT driver");
355 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 362 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
356 363
|
This page was automatically generated by the
LXR engine.
|