Blame view

drivers/watchdog/wdt977.c 12 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
2
   *	Wdt977	0.04:	A Watchdog Device for Netwinder W83977AF chip
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   *
   *	(c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
   *
   *			-----------------------
   *
   *	This program is free software; you can redistribute it and/or
   *	modify it under the terms of the GNU General Public License
   *	as published by the Free Software Foundation; either version
   *	2 of the License, or (at your option) any later version.
   *
   *			-----------------------
   *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
   *           Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
   *	19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface
   *	06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts
   *				    from minutes to seconds.
   *      07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in
   *                                    nwwatchdog_init.
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
21
   *      25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
22
23
   *				    remove limitiation to be used on
   *				    Netwinders only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
   */
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/fs.h>
  #include <linux/miscdevice.h>
  #include <linux/init.h>
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
33
  #include <linux/ioport.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
  #include <linux/watchdog.h>
  #include <linux/notifier.h>
  #include <linux/reboot.h>
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
37
38
  #include <linux/io.h>
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
  #include <asm/system.h>
  #include <asm/mach-types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
43
44
45
46
47
48
49
  #define WATCHDOG_VERSION  "0.04"
  #define WATCHDOG_NAME     "Wdt977"
  #define PFX WATCHDOG_NAME ": "
  #define DRIVER_VERSION    WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "
  "
  
  #define IO_INDEX_PORT	0x370		/* on some systems it can be 0x3F0 */
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
50
  #define IO_DATA_PORT	(IO_INDEX_PORT + 1)
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
51
52
53
54
  
  #define UNLOCK_DATA	0x87
  #define LOCK_DATA	0xAA
  #define DEVICE_REGISTER	0x07
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
62
  
  #define	DEFAULT_TIMEOUT	60			/* default timeout in seconds */
  
  static	int timeout = DEFAULT_TIMEOUT;
  static	int timeoutM;				/* timeout in minutes */
  static	unsigned long timer_alive;
  static	int testmode;
  static	char expect_close;
c7dfd0cca   Alexey Dobriyan   [WATCHDOG] spin_l...
63
  static	DEFINE_SPINLOCK(spinlock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
  
  module_param(timeout, int, 0);
76550d329   Randy Dunlap   watchdog: fix sev...
66
  MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (60..15300, default="
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
67
  				__MODULE_STRING(DEFAULT_TIMEOUT) ")");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  module_param(testmode, int, 0);
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
69
  MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

4bfdf3783   Andrey Panin   [PATCH] consolida...
71
  static int nowayout = WATCHDOG_NOWAYOUT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  module_param(nowayout, int, 0);
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
73
74
75
  MODULE_PARM_DESC(nowayout,
  		"Watchdog cannot be stopped once started (default="
  				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
  
  /*
   * Start the watchdog
   */
  
  static int wdt977_start(void)
  {
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
83
84
85
  	unsigned long flags;
  
  	spin_lock_irqsave(&spinlock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  	/* unlock the SuperIO chip */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
87
88
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
94
95
  
  	/* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
  	 * F2 has the timeout in minutes
  	 * F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
  	 *   at timeout, and to reset timer on kbd/mouse activity (not impl.)
  	 * F4 is used to just clear the TIMEOUT'ed state (bit 0)
  	 */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
96
97
98
99
100
  	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  	outb_p(0x08, IO_DATA_PORT);
  	outb_p(0xF2, IO_INDEX_PORT);
  	outb_p(timeoutM, IO_DATA_PORT);
  	outb_p(0xF3, IO_INDEX_PORT);
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
101
102
  	outb_p(0x00, IO_DATA_PORT);	/* another setting is 0E for
  					   kbd/mouse/LED */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
103
104
  	outb_p(0xF4, IO_INDEX_PORT);
  	outb_p(0x00, IO_DATA_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105

f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
106
107
108
109
110
  	/* At last select device Aux1 (dev=7) and set GP16 as a
  	 * watchdog output. In test mode watch the bit 1 on F4 to
  	 * indicate "triggered"
  	 */
  	if (!testmode) {
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
111
112
113
114
  		outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  		outb_p(0x07, IO_DATA_PORT);
  		outb_p(0xE6, IO_INDEX_PORT);
  		outb_p(0x08, IO_DATA_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
  	}
  
  	/* lock the SuperIO chip */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
118
  	outb_p(LOCK_DATA, IO_INDEX_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119

4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
120
  	spin_unlock_irqrestore(&spinlock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
128
129
130
131
132
  	printk(KERN_INFO PFX "activated.
  ");
  
  	return 0;
  }
  
  /*
   * Stop the watchdog
   */
  
  static int wdt977_stop(void)
  {
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
133
134
  	unsigned long flags;
  	spin_lock_irqsave(&spinlock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  	/* unlock the SuperIO chip */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
136
137
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
141
142
143
  
  	/* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
  	* F3 is reset to its default state
  	* F4 can clear the TIMEOUT'ed state (bit 0) - back to default
  	* We can not use GP17 as a PowerLed, as we use its usage as a RedLed
  	*/
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
144
145
146
147
148
149
150
151
152
153
  	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  	outb_p(0x08, IO_DATA_PORT);
  	outb_p(0xF2, IO_INDEX_PORT);
  	outb_p(0xFF, IO_DATA_PORT);
  	outb_p(0xF3, IO_INDEX_PORT);
  	outb_p(0x00, IO_DATA_PORT);
  	outb_p(0xF4, IO_INDEX_PORT);
  	outb_p(0x00, IO_DATA_PORT);
  	outb_p(0xF2, IO_INDEX_PORT);
  	outb_p(0x00, IO_DATA_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154

f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
155
156
  	/* at last select device Aux1 (dev=7) and set
  	   GP16 as a watchdog output */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
157
158
159
160
  	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  	outb_p(0x07, IO_DATA_PORT);
  	outb_p(0xE6, IO_INDEX_PORT);
  	outb_p(0x08, IO_DATA_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
  
  	/* lock the SuperIO chip */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
163
  	outb_p(LOCK_DATA, IO_INDEX_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164

4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
165
  	spin_unlock_irqrestore(&spinlock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
169
170
171
172
173
174
175
176
177
178
  	printk(KERN_INFO PFX "shutdown.
  ");
  
  	return 0;
  }
  
  /*
   * Send a keepalive ping to the watchdog
   * This is done by simply re-writing the timeout to reg. 0xF2
   */
  
  static int wdt977_keepalive(void)
  {
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
179
180
  	unsigned long flags;
  	spin_lock_irqsave(&spinlock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  	/* unlock the SuperIO chip */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
182
183
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
  
  	/* select device Aux2 (device=8) and kicks watchdog reg F2 */
  	/* F2 has the timeout in minutes */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
187
188
189
190
  	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  	outb_p(0x08, IO_DATA_PORT);
  	outb_p(0xF2, IO_INDEX_PORT);
  	outb_p(timeoutM, IO_DATA_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
  
  	/* lock the SuperIO chip */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
193
194
  	outb_p(LOCK_DATA, IO_INDEX_PORT);
  	spin_unlock_irqrestore(&spinlock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  
  	return 0;
  }
  
  /*
   * Set the watchdog timeout value
   */
  
  static int wdt977_set_timeout(int t)
  {
  	int tmrval;
  
  	/* convert seconds to minutes, rounding up */
  	tmrval = (t + 59) / 60;
  
  	if (machine_is_netwinder()) {
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
211
212
213
  		/* we have a hw bug somewhere, so each 977 minute is actually
  		 * only 30sec. This limits the max timeout to half of device
  		 * max of 255 minutes...
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
216
  		 */
  		tmrval += tmrval;
  	}
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
217
  	if (tmrval < 1 || tmrval > 255)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  		return -EINVAL;
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
219
220
  	/* timeout is the timeout in seconds, timeoutM is
  	   the timeout in minutes) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
226
227
228
229
230
231
232
  	timeout = t;
  	timeoutM = tmrval;
  	return 0;
  }
  
  /*
   * Get the watchdog status
   */
  
  static int wdt977_get_status(int *status)
  {
  	int new_status;
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
233
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234

4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
235
  	spin_lock_irqsave(&spinlock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
  
  	/* unlock the SuperIO chip */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
238
239
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
  
  	/* select device Aux2 (device=8) and read watchdog reg F4 */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
242
243
244
245
  	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  	outb_p(0x08, IO_DATA_PORT);
  	outb_p(0xF4, IO_INDEX_PORT);
  	new_status = inb_p(IO_DATA_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
  
  	/* lock the SuperIO chip */
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
248
  	outb_p(LOCK_DATA, IO_INDEX_PORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249

4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
250
  	spin_unlock_irqrestore(&spinlock, flags);
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
251
  	*status = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  	if (new_status & 1)
  		*status |= WDIOF_CARDRESET;
  
  	return 0;
  }
  
  
  /*
   *	/dev/watchdog handling
   */
  
  static int wdt977_open(struct inode *inode, struct file *file)
  {
  	/* If the watchdog is alive we don't need to start it again */
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
266
  	if (test_and_set_bit(0, &timer_alive))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
270
271
272
273
274
275
276
277
278
279
  		return -EBUSY;
  
  	if (nowayout)
  		__module_get(THIS_MODULE);
  
  	wdt977_start();
  	return nonseekable_open(inode, file);
  }
  
  static int wdt977_release(struct inode *inode, struct file *file)
  {
  	/*
  	 *	Shut off the timer.
5f3b27569   Wim Van Sebroeck   watchdog: cleanup...
280
  	 *	Lock it in if it's a module and we set nowayout
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  	 */
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
282
  	if (expect_close == 42) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  		wdt977_stop();
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
284
  		clear_bit(0, &timer_alive);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
  		wdt977_keepalive();
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
287
288
289
  		printk(KERN_CRIT PFX
  			"Unexpected close, not stopping watchdog!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  	}
  	expect_close = 0;
  	return 0;
  }
  
  
  /*
   *      wdt977_write:
   *      @file: file handle to the watchdog
   *      @buf: buffer to write (unused as data does not matter here
   *      @count: count of bytes
   *      @ppos: pointer to the position to write. No seeks allowed
   *
   *      A write to a watchdog device is defined as a keepalive signal. Any
   *      write of data will do, as we we don't define content meaning.
   */
  
  static ssize_t wdt977_write(struct file *file, const char __user *buf,
  			    size_t count, loff_t *ppos)
  {
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
310
311
  	if (count) {
  		if (!nowayout) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
315
  			size_t i;
  
  			/* In case it was set long ago */
  			expect_close = 0;
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
316
  			for (i = 0; i != count; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
320
321
322
323
  				char c;
  				if (get_user(c, buf + i))
  					return -EFAULT;
  				if (c == 'V')
  					expect_close = 42;
  			}
  		}
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
324
  		/* someone wrote to us, we should restart timer */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
327
328
  		wdt977_keepalive();
  	}
  	return count;
  }
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
329
330
331
332
333
334
335
  static const struct watchdog_info ident = {
  	.options =		WDIOF_SETTIMEOUT |
  				WDIOF_MAGICCLOSE |
  				WDIOF_KEEPALIVEPING,
  	.firmware_version =	1,
  	.identity =		WATCHDOG_NAME,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
341
342
343
344
345
  /*
   *      wdt977_ioctl:
   *      @inode: inode of the device
   *      @file: file handle to the device
   *      @cmd: watchdog command
   *      @arg: argument pointer
   *
   *      The watchdog API defines a common set of functions for all watchdogs
   *      according to their available features.
   */
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
346
347
  static long wdt977_ioctl(struct file *file, unsigned int cmd,
  							unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
352
353
354
355
356
357
  {
  	int status;
  	int new_options, retval = -EINVAL;
  	int new_timeout;
  	union {
  		struct watchdog_info __user *ident;
  		int __user *i;
  	} uarg;
  
  	uarg.i = (int __user *)arg;
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
358
  	switch (cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
363
364
365
366
367
368
  	case WDIOC_GETSUPPORT:
  		return copy_to_user(uarg.ident, &ident,
  			sizeof(ident)) ? -EFAULT : 0;
  
  	case WDIOC_GETSTATUS:
  		wdt977_get_status(&status);
  		return put_user(status, uarg.i);
  
  	case WDIOC_GETBOOTSTATUS:
  		return put_user(0, uarg.i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  	case WDIOC_SETOPTIONS:
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
370
  		if (get_user(new_options, uarg.i))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
375
376
377
378
379
380
381
382
383
  			return -EFAULT;
  
  		if (new_options & WDIOS_DISABLECARD) {
  			wdt977_stop();
  			retval = 0;
  		}
  
  		if (new_options & WDIOS_ENABLECARD) {
  			wdt977_start();
  			retval = 0;
  		}
  
  		return retval;
0c06090c9   Wim Van Sebroeck   [WATCHDOG] Coding...
384
385
386
  	case WDIOC_KEEPALIVE:
  		wdt977_keepalive();
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
391
  	case WDIOC_SETTIMEOUT:
  		if (get_user(new_timeout, uarg.i))
  			return -EFAULT;
  
  		if (wdt977_set_timeout(new_timeout))
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
392
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
396
397
398
  
  		wdt977_keepalive();
  		/* Fall */
  
  	case WDIOC_GETTIMEOUT:
  		return put_user(timeout, uarg.i);
0c06090c9   Wim Van Sebroeck   [WATCHDOG] Coding...
399
400
  	default:
  		return -ENOTTY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
403
404
405
406
  	}
  }
  
  static int wdt977_notify_sys(struct notifier_block *this, unsigned long code,
  	void *unused)
  {
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
407
  	if (code == SYS_DOWN || code == SYS_HALT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
  		wdt977_stop();
  	return NOTIFY_DONE;
  }
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
411
  static const struct file_operations wdt977_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
  	.owner		= THIS_MODULE,
  	.llseek		= no_llseek,
  	.write		= wdt977_write,
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
415
  	.unlocked_ioctl	= wdt977_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
  	.open		= wdt977_open,
  	.release	= wdt977_release,
  };
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
419
  static struct miscdevice wdt977_miscdev = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
423
424
425
426
427
  	.minor		= WATCHDOG_MINOR,
  	.name		= "watchdog",
  	.fops		= &wdt977_fops,
  };
  
  static struct notifier_block wdt977_notifier = {
  	.notifier_call = wdt977_notify_sys,
  };
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
428
  static int __init wd977_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  {
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
430
  	int rc;
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
431
  	printk(KERN_INFO PFX DRIVER_VERSION);
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
432
433
434
  	/* Check that the timeout value is within its range;
  	   if not reset to the default */
  	if (wdt977_set_timeout(timeout)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  		wdt977_set_timeout(DEFAULT_TIMEOUT);
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
436
437
438
439
  		printk(KERN_INFO PFX
  		      "timeout value must be 60 < timeout < 15300, using %d
  ",
  							DEFAULT_TIMEOUT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  	}
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
441
442
443
  	/* on Netwinder the IOports are already reserved by
  	 * arch/arm/mach-footbridge/netwinder-hw.c
  	 */
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
444
445
446
447
448
449
  	if (!machine_is_netwinder()) {
  		if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
  			printk(KERN_ERR PFX
  				"I/O address 0x%04x already in use
  ",
  								IO_INDEX_PORT);
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
450
451
452
  			rc = -EIO;
  			goto err_out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  	}
c6cb13aea   Wim Van Sebroeck   [WATCHDOG] misc_r...
454
  	rc = register_reboot_notifier(&wdt977_notifier);
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
455
456
457
458
  	if (rc) {
  		printk(KERN_ERR PFX
  			"cannot register reboot notifier (err=%d)
  ", rc);
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
459
460
  		goto err_out_region;
  	}
c6cb13aea   Wim Van Sebroeck   [WATCHDOG] misc_r...
461
  	rc = misc_register(&wdt977_miscdev);
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
462
463
464
465
466
  	if (rc) {
  		printk(KERN_ERR PFX
  			"cannot register miscdev on minor=%d (err=%d)
  ",
  						wdt977_miscdev.minor, rc);
c6cb13aea   Wim Van Sebroeck   [WATCHDOG] misc_r...
467
  		goto err_out_reboot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  	}
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
469
470
471
472
  	printk(KERN_INFO PFX
  		"initialized. timeout=%d sec (nowayout=%d, testmode=%i)
  ",
  						timeout, nowayout, testmode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
  
  	return 0;
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
475

c6cb13aea   Wim Van Sebroeck   [WATCHDOG] misc_r...
476
477
  err_out_reboot:
  	unregister_reboot_notifier(&wdt977_notifier);
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
478
479
  err_out_region:
  	if (!machine_is_netwinder())
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
480
  		release_region(IO_INDEX_PORT, 2);
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
481
482
  err_out:
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
  }
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
484
  static void __exit wd977_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
  {
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
486
  	wdt977_stop();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
  	misc_deregister(&wdt977_miscdev);
  	unregister_reboot_notifier(&wdt977_notifier);
f2b79c6ed   Alan Cox   [WATCHDOG 56/57] ...
489
  	release_region(IO_INDEX_PORT, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
  }
4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
491
492
  module_init(wd977_init);
  module_exit(wd977_exit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493

4dab06fa7   Woody Suwalski   [PATCH] ARM Netwi...
494
  MODULE_AUTHOR("Woody Suwalski <woodys@xandros.com>");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
  MODULE_DESCRIPTION("W83977AF Watchdog driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);