Blame view

drivers/watchdog/pcwd_pci.c 20.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *	Berkshire PCI-PC Watchdog Card Driver
   *
39e3a0556   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
4
   *	(c) Copyright 2003-2007 Wim Van Sebroeck <wim@iguana.be>.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
   *
   *	Based on source code of the following authors:
   *	  Ken Hollis <kenji@bitgate.com>,
   *	  Lindsay Harris <lindsay@bluegum.com>,
29fa0586d   Alan Cox   [PATCH] Switch al...
9
   *	  Alan Cox <alan@lxorguk.ukuu.org.uk>,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   *	  Matt Domsch <Matt_Domsch@dell.com>,
   *	  Rob Radez <rob@osinvestor.com>
   *
   *	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.
   *
   *	Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
   *	provide warranty for any of this software. This material is
   *	provided "AS-IS" and at no charge.
   */
  
  /*
58b519f3e   Wim Van Sebroeck   [WATCHDOG] add WD...
24
   *	A bells and whistles driver is available from:
b3faed637   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
25
26
   *	http://www.kernel.org/pub/linux/kernel/people/wim/pcwd/pcwd_pci/
   *
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
27
28
   *	More info available at
   *	http://www.berkprod.com/ or http://www.pcwatchdog.com/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
   */
  
  /*
   *	Includes, defines, variables, module parameters, ...
   */
c315b7e84   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  #include <linux/module.h>	/* For module specific items */
  #include <linux/moduleparam.h>	/* For new moduleparam's */
  #include <linux/types.h>	/* For standard types (like size_t) */
  #include <linux/errno.h>	/* For the -ENODEV/... values */
  #include <linux/kernel.h>	/* For printk/panic/... */
  #include <linux/delay.h>	/* For mdelay function */
  #include <linux/miscdevice.h>	/* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
  #include <linux/watchdog.h>	/* For the watchdog specific items */
  #include <linux/notifier.h>	/* For notifier support */
  #include <linux/reboot.h>	/* For reboot_notifier stuff */
  #include <linux/init.h>		/* For __init/__exit/... */
  #include <linux/fs.h>		/* For file operations */
  #include <linux/pci.h>		/* For pci functions */
  #include <linux/ioport.h>	/* For io-port access */
  #include <linux/spinlock.h>	/* For spin_lock/spin_unlock/... */
089ab0791   Wim Van Sebroeck   [WATCHDOG] Clean-...
49
50
  #include <linux/uaccess.h>	/* For copy_to_user/put_user/... */
  #include <linux/io.h>		/* For inb/outb/... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
  
  /* Module and version information */
39e3a0556   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
53
  #define WATCHDOG_VERSION "1.03"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
  #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
  #define WATCHDOG_NAME "pcwd_pci"
  #define PFX WATCHDOG_NAME ": "
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
57
58
  #define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION "
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  
  /* Stuff for the PCI ID's  */
  #ifndef PCI_VENDOR_ID_QUICKLOGIC
  #define PCI_VENDOR_ID_QUICKLOGIC    0x11e3
  #endif
  
  #ifndef PCI_DEVICE_ID_WATCHDOG_PCIPCWD
  #define PCI_DEVICE_ID_WATCHDOG_PCIPCWD 0x5030
  #endif
  
  /*
   * These are the defines that describe the control status bits for the
   * PCI-PC Watchdog card.
   */
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
73
74
75
76
77
78
  /* Port 1 : Control Status #1 */
  #define WD_PCI_WTRP		0x01	/* Watchdog Trip status */
  #define WD_PCI_HRBT		0x02	/* Watchdog Heartbeat */
  #define WD_PCI_TTRP		0x04	/* Temperature Trip status */
  #define WD_PCI_RL2A		0x08	/* Relay 2 Active */
  #define WD_PCI_RL1A		0x10	/* Relay 1 Active */
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
79
80
  #define WD_PCI_R2DS		0x40	/* Relay 2 Disable Temperature-trip /
  									reset */
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
81
82
83
84
85
86
  #define WD_PCI_RLY2		0x80	/* Activate Relay 2 on the board */
  /* Port 2 : Control Status #2 */
  #define WD_PCI_WDIS		0x10	/* Watchdog Disable */
  #define WD_PCI_ENTP		0x20	/* Enable Temperature Trip Reset */
  #define WD_PCI_WRSP		0x40	/* Watchdog wrote response */
  #define WD_PCI_PCMD		0x80	/* PC has sent command */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
92
  
  /* according to documentation max. time to process a command for the pci
   * watchdog card is 100 ms, so we give it 150 ms to do it's job */
  #define PCI_COMMAND_TIMEOUT	150
  
  /* Watchdog's internal commands */
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
93
94
95
96
97
  #define CMD_GET_STATUS				0x04
  #define CMD_GET_FIRMWARE_VERSION		0x08
  #define CMD_READ_WATCHDOG_TIMEOUT		0x18
  #define CMD_WRITE_WATCHDOG_TIMEOUT		0x19
  #define CMD_GET_CLEAR_RESET_COUNT		0x84
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98

39e3a0556   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
99
  /* Watchdog's Dip Switch heartbeat values */
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
100
  static const int heartbeat_tbl[] = {
39e3a0556   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
101
102
103
104
105
106
107
108
109
  	5,	/* OFF-OFF-OFF	=  5 Sec  */
  	10,	/* OFF-OFF-ON	= 10 Sec  */
  	30,	/* OFF-ON-OFF	= 30 Sec  */
  	60,	/* OFF-ON-ON	=  1 Min  */
  	300,	/* ON-OFF-OFF	=  5 Min  */
  	600,	/* ON-OFF-ON	= 10 Min  */
  	1800,	/* ON-ON-OFF	= 30 Min  */
  	3600,	/* ON-ON-ON	=  1 hour */
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
115
116
  /* We can only use 1 card due to the /dev/watchdog restriction */
  static int cards_found;
  
  /* internal variables */
  static int temp_panic;
  static unsigned long is_active;
  static char expect_release;
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
117
118
119
120
121
122
123
124
125
126
127
128
  /* this is private data for each PCI-PC watchdog card */
  static struct {
  	/* Wether or not the card has a temperature device */
  	int supports_temp;
  	/* The card's boot status */
  	int boot_status;
  	/* The cards I/O address */
  	unsigned long io_addr;
  	/* the lock for io operations */
  	spinlock_t io_lock;
  	/* the PCI-device */
  	struct pci_dev *pdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
  } pcipcwd_private;
  
  /* module parameters */
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
132
133
134
135
136
137
  #define QUIET	0	/* Default */
  #define VERBOSE	1	/* Verbose */
  #define DEBUG	2	/* print fancy stuff too */
  static int debug = QUIET;
  module_param(debug, int, 0);
  MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)");
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
138
139
  #define WATCHDOG_HEARTBEAT 0	/* default heartbeat =
  						delay-time from dip-switches */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
  static int heartbeat = WATCHDOG_HEARTBEAT;
  module_param(heartbeat, int, 0);
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
142
143
144
  MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. "
  	"(0<heartbeat<65536 or 0=delay-time from dip-switches, default="
  				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145

4bfdf3783   Andrey Panin   [PATCH] consolida...
146
  static int nowayout = WATCHDOG_NOWAYOUT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  module_param(nowayout, int, 0);
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
148
149
  MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
  					__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
154
155
156
157
  
  /*
   *	Internal functions
   */
  
  static int send_command(int cmd, int *msb, int *lsb)
  {
  	int got_response, count;
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
158
  	if (debug >= DEBUG)
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
159
160
161
  		printk(KERN_DEBUG PFX "sending following data "
  		"cmd=0x%02x msb=0x%02x lsb=0x%02x
  ", cmd, *msb, *lsb);
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
162

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  	spin_lock(&pcipcwd_private.io_lock);
  	/* If a command requires data it should be written first.
  	 * Data for commands with 8 bits of data should be written to port 4.
  	 * Commands with 16 bits of data, should be written as LSB to port 4
  	 * and MSB to port 5.
  	 * After the required data has been written then write the command to
  	 * port 6. */
  	outb_p(*lsb, pcipcwd_private.io_addr + 4);
  	outb_p(*msb, pcipcwd_private.io_addr + 5);
  	outb_p(cmd, pcipcwd_private.io_addr + 6);
  
  	/* wait till the pci card processed the command, signaled by
  	 * the WRSP bit in port 2 and give it a max. timeout of
  	 * PCI_COMMAND_TIMEOUT to process */
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
177
  	got_response = inb_p(pcipcwd_private.io_addr + 2) & WD_PCI_WRSP;
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
178
179
  	for (count = 0; (count < PCI_COMMAND_TIMEOUT) && (!got_response);
  								count++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  		mdelay(1);
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
181
  		got_response = inb_p(pcipcwd_private.io_addr + 2) & WD_PCI_WRSP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  	}
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
183
184
  	if (debug >= DEBUG) {
  		if (got_response) {
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
185
186
187
  			printk(KERN_DEBUG PFX
  				"time to process command was: %d ms
  ",
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
188
189
  				count);
  		} else {
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
190
191
192
  			printk(KERN_DEBUG PFX
  				"card did not respond on command!
  ");
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
193
194
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
198
199
200
201
  	if (got_response) {
  		/* read back response */
  		*lsb = inb_p(pcipcwd_private.io_addr + 4);
  		*msb = inb_p(pcipcwd_private.io_addr + 5);
  
  		/* clear WRSP bit */
  		inb_p(pcipcwd_private.io_addr + 6);
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
202
203
  
  		if (debug >= DEBUG)
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
204
205
206
  			printk(KERN_DEBUG PFX "received following data for "
  				"cmd=0x%02x: msb=0x%02x lsb=0x%02x
  ",
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
207
  				cmd, *msb, *lsb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  	}
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
209

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
  	spin_unlock(&pcipcwd_private.io_lock);
  
  	return got_response;
  }
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  static inline void pcipcwd_check_temperature_support(void)
  {
  	if (inb_p(pcipcwd_private.io_addr) != 0xF0)
  		pcipcwd_private.supports_temp = 1;
  }
  
  static int pcipcwd_get_option_switches(void)
  {
  	int option_switches;
  
  	option_switches = inb_p(pcipcwd_private.io_addr + 3);
  	return option_switches;
  }
  
  static void pcipcwd_show_card_info(void)
  {
  	int got_fw_rev, fw_rev_major, fw_rev_minor;
  	char fw_ver_str[20];		/* The cards firmware version */
  	int option_switches;
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
233
234
  	got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major,
  								&fw_rev_minor);
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
235
  	if (got_fw_rev)
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
236
  		sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
237
  	else
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
238
  		sprintf(fw_ver_str, "<card no answer>");
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
239
240
241
  
  	/* Get switch settings */
  	option_switches = pcipcwd_get_option_switches();
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
242
243
244
  	printk(KERN_INFO PFX "Found card at port "
  		"0x%04x (Firmware: %s) %s temp option
  ",
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
245
246
  		(int) pcipcwd_private.io_addr, fw_ver_str,
  		(pcipcwd_private.supports_temp ? "with" : "without"));
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
247
248
249
  	printk(KERN_INFO PFX "Option switches (0x%02x): "
  		"Temperature Reset Enable=%s, Power On Delay=%s
  ",
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
250
251
252
253
254
  		option_switches,
  		((option_switches & 0x10) ? "ON" : "OFF"),
  		((option_switches & 0x08) ? "ON" : "OFF"));
  
  	if (pcipcwd_private.boot_status & WDIOF_CARDRESET)
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
255
256
257
  		printk(KERN_INFO PFX
  			"Previous reset was caused by the Watchdog card
  ");
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
258
259
260
261
262
263
  
  	if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)
  		printk(KERN_INFO PFX "Card sensed a CPU Overheat
  ");
  
  	if (pcipcwd_private.boot_status == 0)
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
264
265
266
  		printk(KERN_INFO PFX
  			"No previous trip detected - Cold boot or reset
  ");
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
267
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
271
272
273
274
275
276
277
  static int pcipcwd_start(void)
  {
  	int stat_reg;
  
  	spin_lock(&pcipcwd_private.io_lock);
  	outb_p(0x00, pcipcwd_private.io_addr + 3);
  	udelay(1000);
  
  	stat_reg = inb_p(pcipcwd_private.io_addr + 2);
  	spin_unlock(&pcipcwd_private.io_lock);
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
278
  	if (stat_reg & WD_PCI_WDIS) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
  		printk(KERN_ERR PFX "Card timer not enabled
  ");
  		return -1;
  	}
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
283
284
285
  	if (debug >= VERBOSE)
  		printk(KERN_DEBUG PFX "Watchdog started
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
  	return 0;
  }
  
  static int pcipcwd_stop(void)
  {
  	int stat_reg;
  
  	spin_lock(&pcipcwd_private.io_lock);
  	outb_p(0xA5, pcipcwd_private.io_addr + 3);
  	udelay(1000);
  
  	outb_p(0xA5, pcipcwd_private.io_addr + 3);
  	udelay(1000);
  
  	stat_reg = inb_p(pcipcwd_private.io_addr + 2);
  	spin_unlock(&pcipcwd_private.io_lock);
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
302
  	if (!(stat_reg & WD_PCI_WDIS)) {
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
303
304
305
  		printk(KERN_ERR PFX
  			"Card did not acknowledge disable attempt
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
  		return -1;
  	}
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
308
309
310
  	if (debug >= VERBOSE)
  		printk(KERN_DEBUG PFX "Watchdog stopped
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
316
  	return 0;
  }
  
  static int pcipcwd_keepalive(void)
  {
  	/* Re-trigger watchdog by writing to port 0 */
045798b56   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
317
  	spin_lock(&pcipcwd_private.io_lock);
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
318
  	outb_p(0x42, pcipcwd_private.io_addr);	/* send out any data */
045798b56   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
319
  	spin_unlock(&pcipcwd_private.io_lock);
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
320
321
322
323
  
  	if (debug >= DEBUG)
  		printk(KERN_DEBUG PFX "Watchdog keepalive signal send
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  	return 0;
  }
  
  static int pcipcwd_set_heartbeat(int t)
  {
  	int t_msb = t / 256;
  	int t_lsb = t % 256;
  
  	if ((t < 0x0001) || (t > 0xFFFF))
  		return -EINVAL;
  
  	/* Write new heartbeat to watchdog */
  	send_command(CMD_WRITE_WATCHDOG_TIMEOUT, &t_msb, &t_lsb);
  
  	heartbeat = t;
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
339
340
341
342
  	if (debug >= VERBOSE)
  		printk(KERN_DEBUG PFX "New heartbeat: %d
  ",
  		       heartbeat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
346
347
  	return 0;
  }
  
  static int pcipcwd_get_status(int *status)
  {
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
348
  	int control_status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349

7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
350
  	*status = 0;
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
351
352
  	control_status = inb_p(pcipcwd_private.io_addr + 1);
  	if (control_status & WD_PCI_WTRP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  		*status |= WDIOF_CARDRESET;
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
354
  	if (control_status & WD_PCI_TTRP) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
359
  		*status |= WDIOF_OVERHEAT;
  		if (temp_panic)
  			panic(PFX "Temperature overheat trip!
  ");
  	}
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
360
361
362
363
  	if (debug >= DEBUG)
  		printk(KERN_DEBUG PFX "Control Status #1: 0x%02x
  ",
  		       control_status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
367
368
  	return 0;
  }
  
  static int pcipcwd_clear_status(void)
  {
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
369
370
371
  	int control_status;
  	int msb;
  	int reset_counter;
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
372
373
374
  	if (debug >= VERBOSE)
  		printk(KERN_INFO PFX "clearing watchdog trip status & LED
  ");
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
375
  	control_status = inb_p(pcipcwd_private.io_addr + 1);
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
376
377
378
379
380
381
382
  	if (debug >= DEBUG) {
  		printk(KERN_DEBUG PFX "status was: 0x%02x
  ", control_status);
  		printk(KERN_DEBUG PFX "sending: 0x%02x
  ",
  		       (control_status & WD_PCI_R2DS) | WD_PCI_WTRP);
  	}
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
383
  	/* clear trip status & LED and keep mode of relay 2 */
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
384
385
  	outb_p((control_status & WD_PCI_R2DS) | WD_PCI_WTRP,
  						pcipcwd_private.io_addr + 1);
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
386
387
  
  	/* clear reset counter */
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
388
389
  	msb = 0;
  	reset_counter = 0xff;
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
390
  	send_command(CMD_GET_CLEAR_RESET_COUNT, &msb, &reset_counter);
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
391
392
393
394
395
  	if (debug >= DEBUG) {
  		printk(KERN_DEBUG PFX "reset count was: 0x%02x
  ",
  		       reset_counter);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
399
400
401
402
403
  	return 0;
  }
  
  static int pcipcwd_get_temperature(int *temperature)
  {
  	*temperature = 0;
  	if (!pcipcwd_private.supports_temp)
  		return -ENODEV;
045798b56   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
404
  	spin_lock(&pcipcwd_private.io_lock);
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
405
  	*temperature = inb_p(pcipcwd_private.io_addr);
045798b56   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
406
  	spin_unlock(&pcipcwd_private.io_lock);
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
407

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
411
  	/*
  	 * Convert celsius to fahrenheit, since this was
  	 * the decided 'standard' for this return value.
  	 */
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
412
  	*temperature = (*temperature * 9 / 5) + 32;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413

195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
414
415
416
417
418
  	if (debug >= DEBUG) {
  		printk(KERN_DEBUG PFX "temperature is: %d F
  ",
  		       *temperature);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
  	return 0;
  }
58b519f3e   Wim Van Sebroeck   [WATCHDOG] add WD...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  static int pcipcwd_get_timeleft(int *time_left)
  {
  	int msb;
  	int lsb;
  
  	/* Read the time that's left before rebooting */
  	/* Note: if the board is not yet armed then we will read 0xFFFF */
  	send_command(CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
  
  	*time_left = (msb << 8) + lsb;
  
  	if (debug >= VERBOSE)
  		printk(KERN_DEBUG PFX "Time left before next reboot: %d
  ",
  		       *time_left);
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
443
  /*
   *	/dev/watchdog handling
   */
  
  static ssize_t pcipcwd_write(struct file *file, const char __user *data,
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
444
  			     size_t len, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
450
451
452
453
  {
  	/* See if we got the magic character 'V' and reload the timer */
  	if (len) {
  		if (!nowayout) {
  			size_t i;
  
  			/* note: just in case someone wrote the magic character
  			 * five months ago... */
  			expect_release = 0;
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
454
455
  			/* scan to see whether or not we got the
  			 * magic character */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
  			for (i = 0; i != len; i++) {
  				char c;
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
458
  				if (get_user(c, data + i))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
462
463
464
465
466
467
468
469
  					return -EFAULT;
  				if (c == 'V')
  					expect_release = 42;
  			}
  		}
  
  		/* someone wrote to us, we should reload the timer */
  		pcipcwd_keepalive();
  	}
  	return len;
  }
c94885205   Alan Cox   [WATCHDOG] pcwd: ...
470
471
  static long pcipcwd_ioctl(struct file *file, unsigned int cmd,
  						unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
  {
  	void __user *argp = (void __user *)arg;
  	int __user *p = argp;
42747d712   Wim Van Sebroeck   [WATCHDOG] watchd...
475
  	static const struct watchdog_info ident = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
479
480
481
482
483
484
485
  		.options =		WDIOF_OVERHEAT |
  					WDIOF_CARDRESET |
  					WDIOF_KEEPALIVEPING |
  					WDIOF_SETTIMEOUT |
  					WDIOF_MAGICCLOSE,
  		.firmware_version =	1,
  		.identity =		WATCHDOG_DRIVER_NAME,
  	};
  
  	switch (cmd) {
5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
486
  	case WDIOC_GETSUPPORT:
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
487
  		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
488
489
490
491
492
493
494
  
  	case WDIOC_GETSTATUS:
  	{
  		int status;
  		pcipcwd_get_status(&status);
  		return put_user(status, p);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
496
497
  	case WDIOC_GETBOOTSTATUS:
  		return put_user(pcipcwd_private.boot_status, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
499
500
501
  	case WDIOC_GETTEMP:
  	{
  		int temperature;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
503
504
  		if (pcipcwd_get_temperature(&temperature))
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
506
507
  		return put_user(temperature, p);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
509
510
511
  	case WDIOC_SETOPTIONS:
  	{
  		int new_options, retval = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512

7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
513
  		if (get_user(new_options, p))
5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
514
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
516
517
518
519
520
  		if (new_options & WDIOS_DISABLECARD) {
  			if (pcipcwd_stop())
  				return -EIO;
  			retval = 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
522
523
524
525
526
  		if (new_options & WDIOS_ENABLECARD) {
  			if (pcipcwd_start())
  				return -EIO;
  			retval = 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
528
529
530
  		if (new_options & WDIOS_TEMPPANIC) {
  			temp_panic = 1;
  			retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  		}
5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
532
533
  		return retval;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534

0c06090c9   Wim Van Sebroeck   [WATCHDOG] Coding...
535
536
537
  	case WDIOC_KEEPALIVE:
  		pcipcwd_keepalive();
  		return 0;
5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
538
539
540
  	case WDIOC_SETTIMEOUT:
  	{
  		int new_heartbeat;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
542
543
  		if (get_user(new_heartbeat, p))
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
545
  		if (pcipcwd_set_heartbeat(new_heartbeat))
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
546
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
548
549
550
  		pcipcwd_keepalive();
  		/* Fall */
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
552
553
  	case WDIOC_GETTIMEOUT:
  		return put_user(heartbeat, p);
58b519f3e   Wim Van Sebroeck   [WATCHDOG] add WD...
554

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
555
556
557
  	case WDIOC_GETTIMELEFT:
  	{
  		int time_left;
58b519f3e   Wim Van Sebroeck   [WATCHDOG] add WD...
558

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
559
560
561
562
563
  		if (pcipcwd_get_timeleft(&time_left))
  			return -EFAULT;
  
  		return put_user(time_left, p);
  	}
58b519f3e   Wim Van Sebroeck   [WATCHDOG] add WD...
564

5eb82498e   Wim Van Sebroeck   [WATCHDOG] Coding...
565
566
  	default:
  		return -ENOTTY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
569
570
571
572
  	}
  }
  
  static int pcipcwd_open(struct inode *inode, struct file *file)
  {
  	/* /dev/watchdog can only be opened once */
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
573
  	if (test_and_set_bit(0, &is_active)) {
195331d7c   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
574
  		if (debug >= VERBOSE)
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
575
576
577
  			printk(KERN_ERR PFX
  				"Attempt to open already opened device.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  		return -EBUSY;
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
579
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
  
  	/* Activate */
  	pcipcwd_start();
  	pcipcwd_keepalive();
  	return nonseekable_open(inode, file);
  }
  
  static int pcipcwd_release(struct inode *inode, struct file *file)
  {
  	/*
  	 *      Shut off the timer.
  	 */
  	if (expect_release == 42) {
  		pcipcwd_stop();
  	} else {
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
595
596
597
  		printk(KERN_CRIT PFX
  			"Unexpected close, not stopping watchdog!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
  		pcipcwd_keepalive();
  	}
  	expect_release = 0;
  	clear_bit(0, &is_active);
  	return 0;
  }
  
  /*
   *	/dev/temperature handling
   */
  
  static ssize_t pcipcwd_temp_read(struct file *file, char __user *data,
  				size_t len, loff_t *ppos)
  {
  	int temperature;
  
  	if (pcipcwd_get_temperature(&temperature))
  		return -EFAULT;
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
616
  	if (copy_to_user(data, &temperature, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
  		return -EFAULT;
  
  	return 1;
  }
  
  static int pcipcwd_temp_open(struct inode *inode, struct file *file)
  {
  	if (!pcipcwd_private.supports_temp)
  		return -ENODEV;
  
  	return nonseekable_open(inode, file);
  }
  
  static int pcipcwd_temp_release(struct inode *inode, struct file *file)
  {
  	return 0;
  }
  
  /*
   *	Notify system
   */
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
638
639
  static int pcipcwd_notify_sys(struct notifier_block *this, unsigned long code,
  								void *unused)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
  {
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
641
642
  	if (code == SYS_DOWN || code == SYS_HALT)
  		pcipcwd_stop();	/* Turn the WDT off */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
646
647
648
649
  
  	return NOTIFY_DONE;
  }
  
  /*
   *	Kernel Interfaces
   */
62322d255   Arjan van de Ven   [PATCH] make more...
650
  static const struct file_operations pcipcwd_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
  	.owner =	THIS_MODULE,
  	.llseek =	no_llseek,
  	.write =	pcipcwd_write,
c94885205   Alan Cox   [WATCHDOG] pcwd: ...
654
  	.unlocked_ioctl = pcipcwd_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
656
657
658
659
660
661
662
663
  	.open =		pcipcwd_open,
  	.release =	pcipcwd_release,
  };
  
  static struct miscdevice pcipcwd_miscdev = {
  	.minor =	WATCHDOG_MINOR,
  	.name =		"watchdog",
  	.fops =		&pcipcwd_fops,
  };
62322d255   Arjan van de Ven   [PATCH] make more...
664
  static const struct file_operations pcipcwd_temp_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
  	.owner =	THIS_MODULE,
  	.llseek =	no_llseek,
  	.read =		pcipcwd_temp_read,
  	.open =		pcipcwd_temp_open,
  	.release =	pcipcwd_temp_release,
  };
  
  static struct miscdevice pcipcwd_temp_miscdev = {
  	.minor =	TEMP_MINOR,
  	.name =		"temperature",
  	.fops =		&pcipcwd_temp_fops,
  };
  
  static struct notifier_block pcipcwd_notifier = {
  	.notifier_call =	pcipcwd_notify_sys,
  };
  
  /*
   *	Init & exit routines
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
  static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
  		const struct pci_device_id *ent)
  {
  	int ret = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
  
  	cards_found++;
  	if (cards_found == 1)
  		printk(KERN_INFO PFX DRIVER_VERSION);
  
  	if (cards_found > 1) {
  		printk(KERN_ERR PFX "This driver only supports 1 device
  ");
  		return -ENODEV;
  	}
  
  	if (pci_enable_device(pdev)) {
  		printk(KERN_ERR PFX "Not possible to enable PCI Device
  ");
  		return -ENODEV;
  	}
  
  	if (pci_resource_start(pdev, 0) == 0x0000) {
  		printk(KERN_ERR PFX "No I/O-Address for card detected
  ");
  		ret = -ENODEV;
  		goto err_out_disable_device;
  	}
  
  	pcipcwd_private.pdev = pdev;
  	pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
  
  	if (pci_request_regions(pdev, WATCHDOG_NAME)) {
  		printk(KERN_ERR PFX "I/O address 0x%04x already in use
  ",
  			(int) pcipcwd_private.io_addr);
  		ret = -EIO;
  		goto err_out_disable_device;
  	}
  
  	/* get the boot_status */
  	pcipcwd_get_status(&pcipcwd_private.boot_status);
  
  	/* clear the "card caused reboot" flag */
  	pcipcwd_clear_status();
  
  	/* disable card */
  	pcipcwd_stop();
  
  	/* Check whether or not the card supports the temperature device */
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
734
  	pcipcwd_check_temperature_support();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735

a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
736
737
  	/* Show info about the card itself */
  	pcipcwd_show_card_info();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738

39e3a0556   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
739
740
  	/* If heartbeat = 0 then we use the heartbeat from the dip-switches */
  	if (heartbeat == 0)
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
741
742
  		heartbeat =
  			heartbeat_tbl[(pcipcwd_get_option_switches() & 0x07)];
39e3a0556   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
743

143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
744
745
  	/* Check that the heartbeat value is within it's range ;
  	 * if not reset to the default */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
  	if (pcipcwd_set_heartbeat(heartbeat)) {
  		pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
748
749
750
  		printk(KERN_INFO PFX
  			"heartbeat value must be 0<heartbeat<65536, using %d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
754
755
  			WATCHDOG_HEARTBEAT);
  	}
  
  	ret = register_reboot_notifier(&pcipcwd_notifier);
  	if (ret != 0) {
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
756
757
758
  		printk(KERN_ERR PFX
  			"cannot register reboot notifier (err=%d)
  ", ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
761
762
763
764
  		goto err_out_release_region;
  	}
  
  	if (pcipcwd_private.supports_temp) {
  		ret = misc_register(&pcipcwd_temp_miscdev);
  		if (ret != 0) {
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
765
766
767
  			printk(KERN_ERR PFX "cannot register miscdev on "
  				"minor=%d (err=%d)
  ", TEMP_MINOR, ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
770
771
772
773
  			goto err_out_unregister_reboot;
  		}
  	}
  
  	ret = misc_register(&pcipcwd_miscdev);
  	if (ret != 0) {
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
774
775
776
  		printk(KERN_ERR PFX
  			"cannot register miscdev on minor=%d (err=%d)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
  			WATCHDOG_MINOR, ret);
  		goto err_out_misc_deregister;
  	}
  
  	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)
  ",
  		heartbeat, nowayout);
  
  	return 0;
  
  err_out_misc_deregister:
  	if (pcipcwd_private.supports_temp)
  		misc_deregister(&pcipcwd_temp_miscdev);
  err_out_unregister_reboot:
  	unregister_reboot_notifier(&pcipcwd_notifier);
  err_out_release_region:
  	pci_release_regions(pdev);
  err_out_disable_device:
  	pci_disable_device(pdev);
  	return ret;
  }
  
  static void __devexit pcipcwd_card_exit(struct pci_dev *pdev)
  {
  	/* Stop the timer before we leave */
  	if (!nowayout)
  		pcipcwd_stop();
  
  	/* Deregister */
  	misc_deregister(&pcipcwd_miscdev);
  	if (pcipcwd_private.supports_temp)
  		misc_deregister(&pcipcwd_temp_miscdev);
  	unregister_reboot_notifier(&pcipcwd_notifier);
  	pci_release_regions(pdev);
  	pci_disable_device(pdev);
  	cards_found--;
  }
4562f5394   Wim Van Sebroeck   watchdog: convert...
814
  static DEFINE_PCI_DEVICE_TABLE(pcipcwd_pci_tbl) = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
  	{ PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD,
  		PCI_ANY_ID, PCI_ANY_ID, },
  	{ 0 },			/* End of list */
  };
  MODULE_DEVICE_TABLE(pci, pcipcwd_pci_tbl);
  
  static struct pci_driver pcipcwd_driver = {
  	.name		= WATCHDOG_NAME,
  	.id_table	= pcipcwd_pci_tbl,
  	.probe		= pcipcwd_card_init,
  	.remove		= __devexit_p(pcipcwd_card_exit),
  };
  
  static int __init pcipcwd_init_module(void)
  {
a0800f6da   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
830
  	spin_lock_init(&pcipcwd_private.io_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
834
835
836
837
  
  	return pci_register_driver(&pcipcwd_driver);
  }
  
  static void __exit pcipcwd_cleanup_module(void)
  {
  	pci_unregister_driver(&pcipcwd_driver);
045798b56   Wim Van Sebroeck   [WATCHDOG] pcwd_p...
838
839
840
  
  	printk(KERN_INFO PFX "Watchdog Module Unloaded.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
843
844
845
846
847
848
849
850
  }
  
  module_init(pcipcwd_init_module);
  module_exit(pcipcwd_cleanup_module);
  
  MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
  MODULE_DESCRIPTION("Berkshire PCI-PC Watchdog driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
  MODULE_ALIAS_MISCDEV(TEMP_MINOR);