Blame view

drivers/watchdog/w83977f_wdt.c 12 KB
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   *	W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip
   *
   *	(c) Copyright 2005  Jose Goncalves <jose.goncalves@inov.pt>
   *
   *      Based on w83877f_wdt.c by Scott Jennings,
   *           and wdt977.c by Woody Suwalski
   *
   *			-----------------------
   *
   *	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.
   *
   */
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
20
21
22
23
24
25
26
27
28
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/fs.h>
  #include <linux/miscdevice.h>
  #include <linux/init.h>
  #include <linux/ioport.h>
  #include <linux/watchdog.h>
  #include <linux/notifier.h>
  #include <linux/reboot.h>
84af401af   Alan Cox   [WATCHDOG 52/57] ...
29
30
  #include <linux/uaccess.h>
  #include <linux/io.h>
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
31

b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
32
  #include <asm/system.h>
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  
  #define WATCHDOG_VERSION  "1.00"
  #define WATCHDOG_NAME     "W83977F WDT"
  #define PFX WATCHDOG_NAME ": "
  #define DRIVER_VERSION    WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "
  "
  
  #define IO_INDEX_PORT     0x3F0
  #define IO_DATA_PORT      (IO_INDEX_PORT+1)
  
  #define UNLOCK_DATA       0x87
  #define LOCK_DATA         0xAA
  #define DEVICE_REGISTER   0x07
  
  #define	DEFAULT_TIMEOUT   45		/* default timeout in seconds */
  
  static	int timeout = DEFAULT_TIMEOUT;
  static	int timeoutW;			/* timeout in watchdog counter units */
  static	unsigned long timer_alive;
  static	int testmode;
  static	char expect_close;
c7dfd0cca   Alexey Dobriyan   [WATCHDOG] spin_l...
54
  static	DEFINE_SPINLOCK(spinlock);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
55
56
  
  module_param(timeout, int, 0);
84af401af   Alan Cox   [WATCHDOG 52/57] ...
57
58
59
  MODULE_PARM_DESC(timeout,
  		"Watchdog timeout in seconds (15..7635), default="
  				__MODULE_STRING(DEFAULT_TIMEOUT) ")");
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
60
  module_param(testmode, int, 0);
84af401af   Alan Cox   [WATCHDOG 52/57] ...
61
  MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
62

3908bb186   Wim Van Sebroeck   [WATCHDOG] sbc836...
63
  static int nowayout = WATCHDOG_NOWAYOUT;
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
64
  module_param(nowayout, int, 0);
84af401af   Alan Cox   [WATCHDOG 52/57] ...
65
66
67
  MODULE_PARM_DESC(nowayout,
  		"Watchdog cannot be stopped once started (default="
  				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
68
69
70
71
72
73
74
75
76
77
78
79
  
  /*
   * Start the watchdog
   */
  
  static int wdt_start(void)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&spinlock, flags);
  
  	/* Unlock the SuperIO chip */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
80
81
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
82
83
84
85
86
87
88
  
  	/*
  	 * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
  	 * F2 has the timeout in watchdog counter units.
  	 * F3 is set to enable watchdog LED blink at timeout.
  	 * F4 is used to just clear the TIMEOUT'ed state (bit 0).
  	 */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
89
90
91
92
93
94
95
96
  	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  	outb_p(0x08, IO_DATA_PORT);
  	outb_p(0xF2, IO_INDEX_PORT);
  	outb_p(timeoutW, IO_DATA_PORT);
  	outb_p(0xF3, IO_INDEX_PORT);
  	outb_p(0x08, IO_DATA_PORT);
  	outb_p(0xF4, IO_INDEX_PORT);
  	outb_p(0x00, IO_DATA_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
97
98
  
  	/* Set device Aux2 active */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
99
100
  	outb_p(0x30, IO_INDEX_PORT);
  	outb_p(0x01, IO_DATA_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
101

84af401af   Alan Cox   [WATCHDOG 52/57] ...
102
  	/*
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
103
104
105
106
107
108
  	 * Select device Aux1 (dev=7) to set GP16 as the watchdog output
  	 * (in reg E6) and GP13 as the watchdog LED output (in reg E3).
  	 * Map GP16 at pin 119.
  	 * In test mode watch the bit 0 on F4 to indicate "triggered" or
  	 * check watchdog LED on SBC.
  	 */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
109
110
111
  	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  	outb_p(0x07, IO_DATA_PORT);
  	if (!testmode) {
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
112
  		unsigned pin_map;
84af401af   Alan Cox   [WATCHDOG 52/57] ...
113
114
115
  		outb_p(0xE6, IO_INDEX_PORT);
  		outb_p(0x0A, IO_DATA_PORT);
  		outb_p(0x2C, IO_INDEX_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
116
117
118
  		pin_map = inb_p(IO_DATA_PORT);
  		pin_map |= 0x10;
  		pin_map &= ~(0x20);
84af401af   Alan Cox   [WATCHDOG 52/57] ...
119
120
  		outb_p(0x2C, IO_INDEX_PORT);
  		outb_p(pin_map, IO_DATA_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
121
  	}
84af401af   Alan Cox   [WATCHDOG 52/57] ...
122
123
  	outb_p(0xE3, IO_INDEX_PORT);
  	outb_p(0x08, IO_DATA_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
124
125
  
  	/* Set device Aux1 active */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
126
127
  	outb_p(0x30, IO_INDEX_PORT);
  	outb_p(0x01, IO_DATA_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
128
129
  
  	/* Lock the SuperIO chip */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
130
  	outb_p(LOCK_DATA, IO_INDEX_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  
  	spin_unlock_irqrestore(&spinlock, flags);
  
  	printk(KERN_INFO PFX "activated.
  ");
  
  	return 0;
  }
  
  /*
   * Stop the watchdog
   */
  
  static int wdt_stop(void)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&spinlock, flags);
  
  	/* Unlock the SuperIO chip */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
151
152
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
153

84af401af   Alan Cox   [WATCHDOG 52/57] ...
154
  	/*
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
155
156
157
158
159
  	 * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
  	 * F2 is reset to its default value (watchdog timer disabled).
  	 * F3 is reset to its default state.
  	 * F4 clears the TIMEOUT'ed state (bit 0) - back to default.
  	 */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
160
161
162
163
164
165
166
167
168
169
  	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);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
170
171
  
  	/*
84af401af   Alan Cox   [WATCHDOG 52/57] ...
172
  	 * Select device Aux1 (dev=7) to set GP16 (in reg E6) and
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
173
174
  	 * Gp13 (in reg E3) as inputs.
  	 */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
175
176
177
178
179
  	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  	outb_p(0x07, IO_DATA_PORT);
  	if (!testmode) {
  		outb_p(0xE6, IO_INDEX_PORT);
  		outb_p(0x01, IO_DATA_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
180
  	}
84af401af   Alan Cox   [WATCHDOG 52/57] ...
181
182
  	outb_p(0xE3, IO_INDEX_PORT);
  	outb_p(0x01, IO_DATA_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
183
184
  
  	/* Lock the SuperIO chip */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
185
  	outb_p(LOCK_DATA, IO_INDEX_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  
  	spin_unlock_irqrestore(&spinlock, flags);
  
  	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 wdt_keepalive(void)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&spinlock, flags);
  
  	/* Unlock the SuperIO chip */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
207
208
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
209
210
  
  	/* Select device Aux2 (device=8) to kick watchdog reg F2 */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
211
212
213
214
  	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  	outb_p(0x08, IO_DATA_PORT);
  	outb_p(0xF2, IO_INDEX_PORT);
  	outb_p(timeoutW, IO_DATA_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
215
216
  
  	/* Lock the SuperIO chip */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
217
  	outb_p(LOCK_DATA, IO_INDEX_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  
  	spin_unlock_irqrestore(&spinlock, flags);
  
  	return 0;
  }
  
  /*
   * Set the watchdog timeout value
   */
  
  static int wdt_set_timeout(int t)
  {
  	int tmrval;
  
  	/*
  	 * Convert seconds to watchdog counter time units, rounding up.
84af401af   Alan Cox   [WATCHDOG 52/57] ...
234
  	 * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
235
236
237
238
239
240
241
242
243
244
245
246
247
  	 * value. This information is supplied in the PCM-5335 manual and was
  	 * checked by me on a real board. This is a bit strange because W83977f
  	 * datasheet says counter unit is in minutes!
  	 */
  	if (t < 15)
  		return -EINVAL;
  
  	tmrval = ((t + 15) + 29) / 30;
  
  	if (tmrval > 255)
  		return -EINVAL;
  
  	/*
84af401af   Alan Cox   [WATCHDOG 52/57] ...
248
  	 * timeout is the timeout in seconds,
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  	 * timeoutW is the timeout in watchdog counter units.
  	 */
  	timeoutW = tmrval;
  	timeout = (timeoutW * 30) - 15;
  	return 0;
  }
  
  /*
   * Get the watchdog status
   */
  
  static int wdt_get_status(int *status)
  {
  	int new_status;
  	unsigned long flags;
  
  	spin_lock_irqsave(&spinlock, flags);
  
  	/* Unlock the SuperIO chip */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
268
269
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
  	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
270
271
  
  	/* Select device Aux2 (device=8) to read watchdog reg F4 */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
272
273
274
  	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
  	outb_p(0x08, IO_DATA_PORT);
  	outb_p(0xF4, IO_INDEX_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
275
276
277
  	new_status = inb_p(IO_DATA_PORT);
  
  	/* Lock the SuperIO chip */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
278
  	outb_p(LOCK_DATA, IO_INDEX_PORT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
  
  	spin_unlock_irqrestore(&spinlock, flags);
  
  	*status = 0;
  	if (new_status & 1)
  		*status |= WDIOF_CARDRESET;
  
  	return 0;
  }
  
  
  /*
   *	/dev/watchdog handling
   */
  
  static int wdt_open(struct inode *inode, struct file *file)
  {
  	/* If the watchdog is alive we don't need to start it again */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
297
  	if (test_and_set_bit(0, &timer_alive))
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  		return -EBUSY;
  
  	if (nowayout)
  		__module_get(THIS_MODULE);
  
  	wdt_start();
  	return nonseekable_open(inode, file);
  }
  
  static int wdt_release(struct inode *inode, struct file *file)
  {
  	/*
  	 * Shut off the timer.
  	 * Lock it in if it's a module and we set nowayout
  	 */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
313
  	if (expect_close == 42) {
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
314
315
316
317
  		wdt_stop();
  		clear_bit(0, &timer_alive);
  	} else {
  		wdt_keepalive();
84af401af   Alan Cox   [WATCHDOG 52/57] ...
318
319
320
  		printk(KERN_CRIT PFX
  			"unexpected close, not stopping watchdog!
  ");
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
  	}
  	expect_close = 0;
  	return 0;
  }
  
  /*
   *      wdt_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 wdt_write(struct file *file, const char __user *buf,
  			    size_t count, loff_t *ppos)
  {
  	/* See if we got the magic character 'V' and reload the timer */
84af401af   Alan Cox   [WATCHDOG 52/57] ...
341
342
  	if (count) {
  		if (!nowayout) {
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
343
  			size_t ofs;
84af401af   Alan Cox   [WATCHDOG 52/57] ...
344
345
  			/* note: just in case someone wrote the
  			   magic character long ago */
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
346
  			expect_close = 0;
84af401af   Alan Cox   [WATCHDOG 52/57] ...
347
348
349
  			/* scan to see whether or not we got the
  			   magic character */
  			for (ofs = 0; ofs != count; ofs++) {
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
350
351
352
  				char c;
  				if (get_user(c, buf + ofs))
  					return -EFAULT;
84af401af   Alan Cox   [WATCHDOG 52/57] ...
353
  				if (c == 'V')
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
354
  					expect_close = 42;
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
  			}
  		}
  
  		/* someone wrote to us, we should restart timer */
  		wdt_keepalive();
  	}
  	return count;
  }
  
  /*
   *      wdt_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.
   */
42747d712   Wim Van Sebroeck   [WATCHDOG] watchd...
374
  static const struct watchdog_info ident = {
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
375
376
377
378
  	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
  	.firmware_version =	1,
  	.identity = WATCHDOG_NAME,
  };
84af401af   Alan Cox   [WATCHDOG 52/57] ...
379
  static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
380
381
382
383
384
385
386
387
388
389
  {
  	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;
84af401af   Alan Cox   [WATCHDOG 52/57] ...
390
  	switch (cmd) {
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
391
  	case WDIOC_GETSUPPORT:
84af401af   Alan Cox   [WATCHDOG 52/57] ...
392
393
  		return copy_to_user(uarg.ident, &ident,
  						sizeof(ident)) ? -EFAULT : 0;
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
394
395
396
397
398
399
400
  
  	case WDIOC_GETSTATUS:
  		wdt_get_status(&status);
  		return put_user(status, uarg.i);
  
  	case WDIOC_GETBOOTSTATUS:
  		return put_user(0, uarg.i);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
401
  	case WDIOC_SETOPTIONS:
84af401af   Alan Cox   [WATCHDOG 52/57] ...
402
  		if (get_user(new_options, uarg.i))
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
403
404
405
406
407
408
409
410
411
412
413
414
415
  			return -EFAULT;
  
  		if (new_options & WDIOS_DISABLECARD) {
  			wdt_stop();
  			retval = 0;
  		}
  
  		if (new_options & WDIOS_ENABLECARD) {
  			wdt_start();
  			retval = 0;
  		}
  
  		return retval;
0c06090c9   Wim Van Sebroeck   [WATCHDOG] Coding...
416
417
418
  	case WDIOC_KEEPALIVE:
  		wdt_keepalive();
  		return 0;
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
419
420
421
422
423
  	case WDIOC_SETTIMEOUT:
  		if (get_user(new_timeout, uarg.i))
  			return -EFAULT;
  
  		if (wdt_set_timeout(new_timeout))
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
424
  			return -EINVAL;
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
425
426
427
428
429
430
  
  		wdt_keepalive();
  		/* Fall */
  
  	case WDIOC_GETTIMEOUT:
  		return put_user(timeout, uarg.i);
0c06090c9   Wim Van Sebroeck   [WATCHDOG] Coding...
431
432
  	default:
  		return -ENOTTY;
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
433
434
435
436
437
438
  	}
  }
  
  static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
  	void *unused)
  {
84af401af   Alan Cox   [WATCHDOG 52/57] ...
439
  	if (code == SYS_DOWN || code == SYS_HALT)
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
440
441
442
  		wdt_stop();
  	return NOTIFY_DONE;
  }
84af401af   Alan Cox   [WATCHDOG 52/57] ...
443
  static const struct file_operations wdt_fops = {
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
444
445
446
  	.owner		= THIS_MODULE,
  	.llseek		= no_llseek,
  	.write		= wdt_write,
84af401af   Alan Cox   [WATCHDOG 52/57] ...
447
  	.unlocked_ioctl	= wdt_ioctl,
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
448
449
450
  	.open		= wdt_open,
  	.release	= wdt_release,
  };
84af401af   Alan Cox   [WATCHDOG 52/57] ...
451
  static struct miscdevice wdt_miscdev = {
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
452
453
454
455
456
457
458
459
460
461
462
463
  	.minor		= WATCHDOG_MINOR,
  	.name		= "watchdog",
  	.fops		= &wdt_fops,
  };
  
  static struct notifier_block wdt_notifier = {
  	.notifier_call = wdt_notify_sys,
  };
  
  static int __init w83977f_wdt_init(void)
  {
  	int rc;
84af401af   Alan Cox   [WATCHDOG 52/57] ...
464
  	printk(KERN_INFO PFX DRIVER_VERSION);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
465

b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
466
  	/*
84af401af   Alan Cox   [WATCHDOG 52/57] ...
467
  	 * Check that the timeout value is within it's range;
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
468
469
470
471
  	 * if not reset to the default
  	 */
  	if (wdt_set_timeout(timeout)) {
  		wdt_set_timeout(DEFAULT_TIMEOUT);
84af401af   Alan Cox   [WATCHDOG 52/57] ...
472
473
474
475
  		printk(KERN_INFO PFX
  		    "timeout value must be 15 <= timeout <= 7635, using %d
  ",
  							DEFAULT_TIMEOUT);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
476
  	}
84af401af   Alan Cox   [WATCHDOG 52/57] ...
477
  	if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
478
479
480
481
482
483
  		printk(KERN_ERR PFX "I/O address 0x%04x already in use
  ",
  			IO_INDEX_PORT);
  		rc = -EIO;
  		goto err_out;
  	}
c6cb13aea   Wim Van Sebroeck   [WATCHDOG] misc_r...
484
  	rc = register_reboot_notifier(&wdt_notifier);
84af401af   Alan Cox   [WATCHDOG 52/57] ...
485
486
487
488
  	if (rc) {
  		printk(KERN_ERR PFX
  			"cannot register reboot notifier (err=%d)
  ", rc);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
489
490
  		goto err_out_region;
  	}
c6cb13aea   Wim Van Sebroeck   [WATCHDOG] misc_r...
491
  	rc = misc_register(&wdt_miscdev);
84af401af   Alan Cox   [WATCHDOG 52/57] ...
492
493
494
495
496
  	if (rc) {
  		printk(KERN_ERR PFX
  			"cannot register miscdev on minor=%d (err=%d)
  ",
  						wdt_miscdev.minor, rc);
c6cb13aea   Wim Van Sebroeck   [WATCHDOG] misc_r...
497
  		goto err_out_reboot;
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
498
  	}
84af401af   Alan Cox   [WATCHDOG 52/57] ...
499
500
501
502
  	printk(KERN_INFO PFX
  		"initialized. timeout=%d sec (nowayout=%d testmode=%d)
  ",
  					timeout, nowayout, testmode);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
503
504
  
  	return 0;
c6cb13aea   Wim Van Sebroeck   [WATCHDOG] misc_r...
505
506
  err_out_reboot:
  	unregister_reboot_notifier(&wdt_notifier);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
507
  err_out_region:
84af401af   Alan Cox   [WATCHDOG 52/57] ...
508
  	release_region(IO_INDEX_PORT, 2);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
509
510
511
512
513
514
515
516
517
  err_out:
  	return rc;
  }
  
  static void __exit w83977f_wdt_exit(void)
  {
  	wdt_stop();
  	misc_deregister(&wdt_miscdev);
  	unregister_reboot_notifier(&wdt_notifier);
84af401af   Alan Cox   [WATCHDOG 52/57] ...
518
  	release_region(IO_INDEX_PORT, 2);
b4cc4aa24   Jose Miguel Goncalves   [WATCHDOG] w83977...
519
520
521
522
523
524
525
526
527
  }
  
  module_init(w83977f_wdt_init);
  module_exit(w83977f_wdt_exit);
  
  MODULE_AUTHOR("Jose Goncalves <jose.goncalves@inov.pt>");
  MODULE_DESCRIPTION("Driver for watchdog timer in W83977F I/O chip");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);