aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/watchdog
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/watchdog')
-rw-r--r--drivers/char/watchdog/Kconfig549
-rw-r--r--drivers/char/watchdog/Makefile42
-rw-r--r--drivers/char/watchdog/acquirewdt.c332
-rw-r--r--drivers/char/watchdog/advantechwdt.c333
-rw-r--r--drivers/char/watchdog/alim1535_wdt.c463
-rw-r--r--drivers/char/watchdog/alim7101_wdt.c421
-rw-r--r--drivers/char/watchdog/cpu5wdt.c303
-rw-r--r--drivers/char/watchdog/eurotechwdt.c474
-rw-r--r--drivers/char/watchdog/i8xx_tco.c535
-rw-r--r--drivers/char/watchdog/i8xx_tco.h42
-rw-r--r--drivers/char/watchdog/ib700wdt.c352
-rw-r--r--drivers/char/watchdog/indydog.c221
-rw-r--r--drivers/char/watchdog/ixp2000_wdt.c219
-rw-r--r--drivers/char/watchdog/ixp4xx_wdt.c230
-rw-r--r--drivers/char/watchdog/machzwd.c501
-rw-r--r--drivers/char/watchdog/mixcomwd.c306
-rw-r--r--drivers/char/watchdog/mpc8xx_wdt.c164
-rw-r--r--drivers/char/watchdog/pcwd.c926
-rw-r--r--drivers/char/watchdog/pcwd_pci.c677
-rw-r--r--drivers/char/watchdog/pcwd_usb.c796
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c516
-rw-r--r--drivers/char/watchdog/sa1100_wdt.c223
-rw-r--r--drivers/char/watchdog/sbc60xxwdt.c413
-rw-r--r--drivers/char/watchdog/sc1200wdt.c467
-rw-r--r--drivers/char/watchdog/sc520_wdt.c447
-rw-r--r--drivers/char/watchdog/scx200_wdt.c274
-rw-r--r--drivers/char/watchdog/shwdt.c452
-rw-r--r--drivers/char/watchdog/softdog.c309
-rw-r--r--drivers/char/watchdog/w83627hf_wdt.c362
-rw-r--r--drivers/char/watchdog/w83877f_wdt.c426
-rw-r--r--drivers/char/watchdog/wafer5823wdt.c330
-rw-r--r--drivers/char/watchdog/wd501p.h52
-rw-r--r--drivers/char/watchdog/wdt.c647
-rw-r--r--drivers/char/watchdog/wdt285.c229
-rw-r--r--drivers/char/watchdog/wdt977.c459
-rw-r--r--drivers/char/watchdog/wdt_pci.c763
36 files changed, 14255 insertions, 0 deletions
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
new file mode 100644
index 000000000000..06a31da2381c
--- /dev/null
+++ b/drivers/char/watchdog/Kconfig
@@ -0,0 +1,549 @@
1#
2# Watchdog device configuration
3#
4
5menu "Watchdog Cards"
6
7config WATCHDOG
8 bool "Watchdog Timer Support"
9 ---help---
10 If you say Y here (and to one of the following options) and create a
11 character special file /dev/watchdog with major number 10 and minor
12 number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
13 subsequently opening the file and then failing to write to it for
14 longer than 1 minute will result in rebooting the machine. This
15 could be useful for a networked machine that needs to come back
16 online as fast as possible after a lock-up. There's both a watchdog
17 implementation entirely in software (which can sometimes fail to
18 reboot the machine) and a driver for hardware watchdog boards, which
19 are more robust and can also keep track of the temperature inside
20 your computer. For details, read <file:Documentation/watchdog/watchdog.txt>
21 in the kernel source.
22
23 The watchdog is usually used together with the watchdog daemon
24 which is available from
25 <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. This daemon can
26 also monitor NFS connections and can reboot the machine when the process
27 table is full.
28
29 If unsure, say N.
30
31config WATCHDOG_NOWAYOUT
32 bool "Disable watchdog shutdown on close"
33 depends on WATCHDOG
34 help
35 The default watchdog behaviour (which you get if you say N here) is
36 to stop the timer if the process managing it closes the file
37 /dev/watchdog. It's always remotely possible that this process might
38 get killed. If you say Y here, the watchdog cannot be stopped once
39 it has been started.
40
41#
42# General Watchdog drivers
43#
44
45comment "Watchdog Device Drivers"
46 depends on WATCHDOG
47
48# Architecture Independant
49
50config SOFT_WATCHDOG
51 tristate "Software watchdog"
52 depends on WATCHDOG
53 help
54 A software monitoring watchdog. This will fail to reboot your system
55 from some situations that the hardware watchdog will recover
56 from. Equally it's a lot cheaper to install.
57
58 To compile this driver as a module, choose M here: the
59 module will be called softdog.
60
61# ARM Architecture
62
63config 21285_WATCHDOG
64 tristate "DC21285 watchdog"
65 depends on WATCHDOG && FOOTBRIDGE
66 help
67 The Intel Footbridge chip contains a builtin watchdog circuit. Say Y
68 here if you wish to use this. Alternatively say M to compile the
69 driver as a module, which will be called wdt285.
70
71 This driver does not work on all machines. In particular, early CATS
72 boards have hardware problems that will cause the machine to simply
73 lock up if the watchdog fires.
74
75 "If in doubt, leave it out" - say N.
76
77config 977_WATCHDOG
78 tristate "NetWinder WB83C977 watchdog"
79 depends on WATCHDOG && FOOTBRIDGE && ARCH_NETWINDER
80 help
81 Say Y here to include support for the WB977 watchdog included in
82 NetWinder machines. Alternatively say M to compile the driver as
83 a module, which will be called wdt977.
84
85 Not sure? It's safe to say N.
86
87config IXP4XX_WATCHDOG
88 tristate "IXP4xx Watchdog"
89 depends on WATCHDOG && ARCH_IXP4XX
90 help
91 Say Y here if to include support for the watchdog timer
92 in the Intel IXP4xx network processors. This driver can
93 be built as a module by choosing M. The module will
94 be called ixp4xx_wdt.
95
96 Note: The internal IXP4xx watchdog does a soft CPU reset
97 which doesn't reset any peripherals. There are circumstances
98 where the watchdog will fail to reset the board correctly
99 (e.g., if the boot ROM is in an unreadable state).
100
101 Say N if you are unsure.
102
103config IXP2000_WATCHDOG
104 tristate "IXP2000 Watchdog"
105 depends on WATCHDOG && ARCH_IXP2000
106 help
107 Say Y here if to include support for the watchdog timer
108 in the Intel IXP2000(2400, 2800, 2850) network processors.
109 This driver can be built as a module by choosing M. The module
110 will be called ixp2000_wdt.
111
112 Say N if you are unsure.
113
114config S3C2410_WATCHDOG
115 tristate "S3C2410 Watchdog"
116 depends on WATCHDOG && ARCH_S3C2410
117 help
118 Watchdog timer block in the Samsung S3C2410 chips. This will
119 reboot the system when the timer expires with the watchdog
120 enabled.
121
122 The driver is limited by the speed of the system's PCLK
123 signal, so with reasonbaly fast systems (PCLK around 50-66MHz)
124 then watchdog intervals of over approximately 20seconds are
125 unavailable.
126
127 The driver can be built as a module by choosing M, and will
128 be called s3c2410_wdt
129
130config SA1100_WATCHDOG
131 tristate "SA1100/PXA2xx watchdog"
132 depends on WATCHDOG && ( ARCH_SA1100 || ARCH_PXA )
133 help
134 Watchdog timer embedded into SA11x0 and PXA2xx chips. This will
135 reboot your system when timeout is reached.
136
137 NOTE: once enabled, this timer cannot be disabled.
138
139 To compile this driver as a module, choose M here: the
140 module will be called sa1100_wdt.
141
142# X86 (i386 + ia64 + x86_64) Architecture
143
144config ACQUIRE_WDT
145 tristate "Acquire SBC Watchdog Timer"
146 depends on WATCHDOG && X86
147 ---help---
148 This is the driver for the hardware watchdog on Single Board
149 Computers produced by Acquire Inc (and others). This watchdog
150 simply watches your kernel to make sure it doesn't freeze, and if
151 it does, it reboots your computer after a certain amount of time.
152
153 To compile this driver as a module, choose M here: the
154 module will be called acquirewdt.
155
156 Most people will say N.
157
158config ADVANTECH_WDT
159 tristate "Advantech SBC Watchdog Timer"
160 depends on WATCHDOG && X86
161 help
162 If you are configuring a Linux kernel for the Advantech single-board
163 computer, say `Y' here to support its built-in watchdog timer
164 feature. More information can be found at
165 <http://www.advantech.com.tw/products/>
166
167config ALIM1535_WDT
168 tristate "ALi M1535 PMU Watchdog Timer"
169 depends on WATCHDOG && X86 && PCI
170 ---help---
171 This is the driver for the hardware watchdog on the ALi M1535 PMU.
172
173 To compile this driver as a module, choose M here: the
174 module will be called alim1535_wdt.
175
176 Most people will say N.
177
178config ALIM7101_WDT
179 tristate "ALi M7101 PMU Computer Watchdog"
180 depends on WATCHDOG && X86 && PCI
181 help
182 This is the driver for the hardware watchdog on the ALi M7101 PMU
183 as used in the x86 Cobalt servers.
184
185 To compile this driver as a module, choose M here: the
186 module will be called alim7101_wdt.
187
188 Most people will say N.
189
190config SC520_WDT
191 tristate "AMD Elan SC520 processor Watchdog"
192 depends on WATCHDOG && X86
193 help
194 This is the driver for the hardware watchdog built in to the
195 AMD "Elan" SC520 microcomputer commonly used in embedded systems.
196 This watchdog simply watches your kernel to make sure it doesn't
197 freeze, and if it does, it reboots your computer after a certain
198 amount of time.
199
200 You can compile this driver directly into the kernel, or use
201 it as a module. The module will be called sc520_wdt.
202
203config EUROTECH_WDT
204 tristate "Eurotech CPU-1220/1410 Watchdog Timer"
205 depends on WATCHDOG && X86
206 help
207 Enable support for the watchdog timer on the Eurotech CPU-1220 and
208 CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product
209 information are at <http://www.eurotech.it/>.
210
211config IB700_WDT
212 tristate "IB700 SBC Watchdog Timer"
213 depends on WATCHDOG && X86
214 ---help---
215 This is the driver for the hardware watchdog on the IB700 Single
216 Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog
217 simply watches your kernel to make sure it doesn't freeze, and if
218 it does, it reboots your computer after a certain amount of time.
219
220 This driver is like the WDT501 driver but for slightly different hardware.
221
222 To compile this driver as a module, choose M here: the
223 module will be called ib700wdt.
224
225 Most people will say N.
226
227config WAFER_WDT
228 tristate "ICP Wafer 5823 Single Board Computer Watchdog"
229 depends on WATCHDOG && X86
230 help
231 This is a driver for the hardware watchdog on the ICP Wafer 5823
232 Single Board Computer (and probably other similar models).
233
234 To compile this driver as a module, choose M here: the
235 module will be called wafer5823wdt.
236
237config I8XX_TCO
238 tristate "Intel i8xx TCO Timer/Watchdog"
239 depends on WATCHDOG && (X86 || IA64) && PCI
240 ---help---
241 Hardware driver for the TCO timer built into the Intel 82801
242 I/O Controller Hub family. The TCO (Total Cost of Ownership)
243 timer is a watchdog timer that will reboot the machine after
244 its second expiration. The expiration time can be configured
245 with the "heartbeat" parameter.
246
247 On some motherboards the driver may fail to reset the chipset's
248 NO_REBOOT flag which prevents the watchdog from rebooting the
249 machine. If this is the case you will get a kernel message like
250 "failed to reset NO_REBOOT flag, reboot disabled by hardware".
251
252 To compile this driver as a module, choose M here: the
253 module will be called i8xx_tco.
254
255config SC1200_WDT
256 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
257 depends on WATCHDOG && X86
258 help
259 This is a driver for National Semiconductor PC87307/PC97307 hardware
260 watchdog cards as found on the SC1200. This watchdog is mainly used
261 for power management purposes and can be used to power down the device
262 during inactivity periods (includes interrupt activity monitoring).
263
264 To compile this driver as a module, choose M here: the
265 module will be called sc1200wdt.
266
267 Most people will say N.
268
269config SCx200_WDT
270 tristate "National Semiconductor SCx200 Watchdog"
271 depends on WATCHDOG && SCx200 && PCI
272 help
273 Enable the built-in watchdog timer support on the National
274 Semiconductor SCx200 processors.
275
276 If compiled as a module, it will be called scx200_wdt.
277
278config 60XX_WDT
279 tristate "SBC-60XX Watchdog Timer"
280 depends on WATCHDOG && X86
281 help
282 This driver can be used with the watchdog timer found on some
283 single board computers, namely the 6010 PII based computer.
284 It may well work with other cards. It reads port 0x443 to enable
285 and re-set the watchdog timer, and reads port 0x45 to disable
286 the watchdog. If you have a card that behave in similar ways,
287 you can probably make this driver work with your card as well.
288
289 You can compile this driver directly into the kernel, or use
290 it as a module. The module will be called sbc60xxwdt.
291
292config CPU5_WDT
293 tristate "SMA CPU5 Watchdog"
294 depends on WATCHDOG && X86
295 ---help---
296 TBD.
297 To compile this driver as a module, choose M here: the
298 module will be called cpu5wdt.
299
300config W83627HF_WDT
301 tristate "W83627HF Watchdog Timer"
302 depends on WATCHDOG && X86
303 ---help---
304 This is the driver for the hardware watchdog on the W83627HF chipset
305 as used in Advantech PC-9578 and Tyan S2721-533 motherboards
306 (and likely others). This watchdog simply watches your kernel to
307 make sure it doesn't freeze, and if it does, it reboots your computer
308 after a certain amount of time.
309
310 To compile this driver as a module, choose M here: the
311 module will be called w83627hf_wdt.
312
313 Most people will say N.
314
315config W83877F_WDT
316 tristate "W83877F (EMACS) Watchdog Timer"
317 depends on WATCHDOG && X86
318 ---help---
319 This is the driver for the hardware watchdog on the W83877F chipset
320 as used in EMACS PC-104 motherboards (and likely others). This
321 watchdog simply watches your kernel to make sure it doesn't freeze,
322 and if it does, it reboots your computer after a certain amount of
323 time.
324
325 To compile this driver as a module, choose M here: the
326 module will be called w83877f_wdt.
327
328 Most people will say N.
329
330config MACHZ_WDT
331 tristate "ZF MachZ Watchdog"
332 depends on WATCHDOG && X86
333 ---help---
334 If you are using a ZF Micro MachZ processor, say Y here, otherwise
335 N. This is the driver for the watchdog timer builtin on that
336 processor using ZF-Logic interface. This watchdog simply watches
337 your kernel to make sure it doesn't freeze, and if it does, it
338 reboots your computer after a certain amount of time.
339
340 To compile this driver as a module, choose M here: the
341 module will be called machzwd.
342
343# PowerPC Architecture
344
345config 8xx_WDT
346 tristate "MPC8xx Watchdog Timer"
347 depends on WATCHDOG && 8xx
348
349# MIPS Architecture
350
351config INDYDOG
352 tristate "Indy/I2 Hardware Watchdog"
353 depends on WATCHDOG && SGI_IP22
354 help
355 Hardwaredriver for the Indy's/I2's watchdog. This is a
356 watchdog timer that will reboot the machine after a 60 second
357 timer expired and no process has written to /dev/watchdog during
358 that time.
359
360# S390 Architecture
361
362config ZVM_WATCHDOG
363 tristate "z/VM Watchdog Timer"
364 depends on WATCHDOG && ARCH_S390
365 help
366 IBM s/390 and zSeries machines running under z/VM 5.1 or later
367 provide a virtual watchdog timer to their guest that cause a
368 user define Control Program command to be executed after a
369 timeout.
370
371 To compile this driver as a module, choose M here. The module
372 will be called vmwatchdog.
373
374# SUPERH Architecture
375
376config SH_WDT
377 tristate "SuperH Watchdog"
378 depends on WATCHDOG && SUPERH
379 help
380 This driver adds watchdog support for the integrated watchdog in the
381 SuperH processors. If you have one of these processors and wish
382 to have watchdog support enabled, say Y, otherwise say N.
383
384 As a side note, saying Y here will automatically boost HZ to 1000
385 so that the timer has a chance to clear the overflow counter. On
386 slower systems (such as the SH-2 and SH-3) this will likely yield
387 some performance issues. As such, the WDT should be avoided here
388 unless it is absolutely necessary.
389
390 To compile this driver as a module, choose M here: the
391 module will be called shwdt.
392
393# SPARC64 Architecture
394
395config WATCHDOG_CP1XXX
396 tristate "CP1XXX Hardware Watchdog support"
397 depends on WATCHDOG && SPARC64 && PCI
398 ---help---
399 This is the driver for the hardware watchdog timers present on
400 Sun Microsystems CompactPCI models CP1400 and CP1500.
401
402 To compile this driver as a module, choose M here: the
403 module will be called cpwatchdog.
404
405 If you do not have a CompactPCI model CP1400 or CP1500, or
406 another UltraSPARC-IIi-cEngine boardset with hardware watchdog,
407 you should say N to this option.
408
409config WATCHDOG_RIO
410 tristate "RIO Hardware Watchdog support"
411 depends on WATCHDOG && SPARC64 && PCI
412 help
413 Say Y here to support the hardware watchdog capability on Sun RIO
414 machines. The watchdog timeout period is normally one minute but
415 can be changed with a boot-time parameter.
416
417#
418# ISA-based Watchdog Cards
419#
420
421comment "ISA-based Watchdog Cards"
422 depends on WATCHDOG && ISA
423
424config PCWATCHDOG
425 tristate "Berkshire Products ISA-PC Watchdog"
426 depends on WATCHDOG && ISA
427 ---help---
428 This is the driver for the Berkshire Products ISA-PC Watchdog card.
429 This card simply watches your kernel to make sure it doesn't freeze,
430 and if it does, it reboots your computer after a certain amount of
431 time. This driver is like the WDT501 driver but for different
432 hardware. Please read <file:Documentation/watchdog/pcwd-watchdog.txt>. The PC
433 watchdog cards can be ordered from <http://www.berkprod.com/>.
434
435 To compile this driver as a module, choose M here: the
436 module will be called pcwd.
437
438 Most people will say N.
439
440config MIXCOMWD
441 tristate "Mixcom Watchdog"
442 depends on WATCHDOG && ISA
443 ---help---
444 This is a driver for the Mixcom hardware watchdog cards. This
445 watchdog simply watches your kernel to make sure it doesn't freeze,
446 and if it does, it reboots your computer after a certain amount of
447 time.
448
449 To compile this driver as a module, choose M here: the
450 module will be called mixcomwd.
451
452 Most people will say N.
453
454config WDT
455 tristate "WDT Watchdog timer"
456 depends on WATCHDOG && ISA
457 ---help---
458 If you have a WDT500P or WDT501P watchdog board, say Y here,
459 otherwise N. It is not possible to probe for this board, which means
460 that you have to inform the kernel about the IO port and IRQ that
461 is needed (you can do this via the io and irq parameters)
462
463 To compile this driver as a module, choose M here: the
464 module will be called wdt.
465
466config WDT_501
467 bool "WDT501 features"
468 depends on WDT
469 help
470 Saying Y here and creating a character special file /dev/temperature
471 with major number 10 and minor number 131 ("man mknod") will give
472 you a thermometer inside your computer: reading from
473 /dev/temperature yields one byte, the temperature in degrees
474 Fahrenheit. This works only if you have a WDT501P watchdog board
475 installed.
476
477 If you want to enable the Fan Tachometer on the WDT501P, then you
478 can do this via the tachometer parameter. Only do this if you have a
479 fan tachometer actually set up.
480
481#
482# PCI-based Watchdog Cards
483#
484
485comment "PCI-based Watchdog Cards"
486 depends on WATCHDOG && PCI
487
488config PCIPCWATCHDOG
489 tristate "Berkshire Products PCI-PC Watchdog"
490 depends on WATCHDOG && PCI
491 ---help---
492 This is the driver for the Berkshire Products PCI-PC Watchdog card.
493 This card simply watches your kernel to make sure it doesn't freeze,
494 and if it does, it reboots your computer after a certain amount of
495 time. The card can also monitor the internal temperature of the PC.
496 More info is available at <http://www.berkprod.com/pci_pc_watchdog.htm>.
497
498 To compile this driver as a module, choose M here: the
499 module will be called pcwd_pci.
500
501 Most people will say N.
502
503config WDTPCI
504 tristate "PCI-WDT500/501 Watchdog timer"
505 depends on WATCHDOG && PCI
506 ---help---
507 If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N.
508
509 To compile this driver as a module, choose M here: the
510 module will be called wdt_pci.
511
512config WDT_501_PCI
513 bool "PCI-WDT501 features"
514 depends on WDTPCI
515 help
516 Saying Y here and creating a character special file /dev/temperature
517 with major number 10 and minor number 131 ("man mknod") will give
518 you a thermometer inside your computer: reading from
519 /dev/temperature yields one byte, the temperature in degrees
520 Fahrenheit. This works only if you have a PCI-WDT501 watchdog board
521 installed.
522
523 If you want to enable the Fan Tachometer on the PCI-WDT501, then you
524 can do this via the tachometer parameter. Only do this if you have a
525 fan tachometer actually set up.
526
527#
528# USB-based Watchdog Cards
529#
530
531comment "USB-based Watchdog Cards"
532 depends on WATCHDOG && USB
533
534config USBPCWATCHDOG
535 tristate "Berkshire Products USB-PC Watchdog"
536 depends on WATCHDOG && USB
537 ---help---
538 This is the driver for the Berkshire Products USB-PC Watchdog card.
539 This card simply watches your kernel to make sure it doesn't freeze,
540 and if it does, it reboots your computer after a certain amount of
541 time. The card can also monitor the internal temperature of the PC.
542 More info is available at <http://www.berkprod.com/usb_pc_watchdog.htm>.
543
544 To compile this driver as a module, choose M here: the
545 module will be called pcwd_usb.
546
547 Most people will say N.
548
549endmenu
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
new file mode 100644
index 000000000000..1cd27efa35c1
--- /dev/null
+++ b/drivers/char/watchdog/Makefile
@@ -0,0 +1,42 @@
1#
2# Makefile for the WatchDog device drivers.
3#
4
5obj-$(CONFIG_PCWATCHDOG) += pcwd.o
6obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
7obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
8obj-$(CONFIG_IB700_WDT) += ib700wdt.o
9obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
10obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
11obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
12obj-$(CONFIG_WDT) += wdt.o
13obj-$(CONFIG_WDTPCI) += wdt_pci.o
14obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
15obj-$(CONFIG_977_WATCHDOG) += wdt977.o
16obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
17obj-$(CONFIG_MACHZ_WDT) += machzwd.o
18obj-$(CONFIG_SH_WDT) += shwdt.o
19obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
20obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
21obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
22obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
23obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
24obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
25obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
26obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
27obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
28obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
29obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
30obj-$(CONFIG_INDYDOG) += indydog.o
31obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
32obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
33obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
34obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
35obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
36
37# Only one watchdog can succeed. We probe the hardware watchdog
38# drivers first, then the softdog driver. This means if your hardware
39# watchdog dies or is 'borrowed' for some reason the software watchdog
40# still gives you some cover.
41
42obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c
new file mode 100644
index 000000000000..8f302121741b
--- /dev/null
+++ b/drivers/char/watchdog/acquirewdt.c
@@ -0,0 +1,332 @@
1/*
2 * Acquire Single Board Computer Watchdog Timer driver
3 *
4 * Based on wdt.c. Original copyright messages:
5 *
6 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
7 * http://www.redhat.com
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 *
14 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
15 * warranty for any of this software. This material is provided
16 * "AS-IS" and at no charge.
17 *
18 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
19 *
20 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
21 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
22 * Can't add timeout - driver doesn't allow changing value
23 */
24
25/*
26 * Theory of Operation:
27 * The Watch-Dog Timer is provided to ensure that standalone
28 * Systems can always recover from catastrophic conditions that
29 * caused the CPU to crash. This condition may have occured by
30 * external EMI or a software bug. When the CPU stops working
31 * correctly, hardware on the board will either perform a hardware
32 * reset (cold boot) or a non-maskable interrupt (NMI) to bring the
33 * system back to a known state.
34 *
35 * The Watch-Dog Timer is controlled by two I/O Ports.
36 * 443 hex - Read - Enable or refresh the Watch-Dog Timer
37 * 043 hex - Read - Disable the Watch-Dog Timer
38 *
39 * To enable the Watch-Dog Timer, a read from I/O port 443h must
40 * be performed. This will enable and activate the countdown timer
41 * which will eventually time out and either reset the CPU or cause
42 * an NMI depending on the setting of a jumper. To ensure that this
43 * reset condition does not occur, the Watch-Dog Timer must be
44 * periodically refreshed by reading the same I/O port 443h.
45 * The Watch-Dog Timer is disabled by reading I/O port 043h.
46 *
47 * The Watch-Dog Timer Time-Out Period is set via jumpers.
48 * It can be 1, 2, 10, 20, 110 or 220 seconds.
49 */
50
51#include <linux/module.h>
52#include <linux/moduleparam.h>
53#include <linux/types.h>
54#include <linux/miscdevice.h>
55#include <linux/watchdog.h>
56#include <linux/fs.h>
57#include <linux/ioport.h>
58#include <linux/notifier.h>
59#include <linux/reboot.h>
60#include <linux/init.h>
61
62#include <asm/io.h>
63#include <asm/uaccess.h>
64#include <asm/system.h>
65
66#define WATCHDOG_NAME "Acquire WDT"
67#define PFX WATCHDOG_NAME ": "
68#define WATCHDOG_HEARTBEAT 0 /* There is no way to see what the correct time-out period is */
69
70static unsigned long acq_is_open;
71static char expect_close;
72
73/*
74 * You must set these - there is no sane way to probe for this board.
75 */
76
77static int wdt_stop = 0x43;
78module_param(wdt_stop, int, 0);
79MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)");
80
81static int wdt_start = 0x443;
82module_param(wdt_start, int, 0);
83MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
84
85#ifdef CONFIG_WATCHDOG_NOWAYOUT
86static int nowayout = 1;
87#else
88static int nowayout = 0;
89#endif
90
91module_param(nowayout, int, 0);
92MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
93
94/*
95 * Kernel methods.
96 */
97
98static void acq_keepalive(void)
99{
100 /* Write a watchdog value */
101 inb_p(wdt_start);
102}
103
104static void acq_stop(void)
105{
106 /* Turn the card off */
107 inb_p(wdt_stop);
108}
109
110/*
111 * /dev/watchdog handling.
112 */
113
114static ssize_t acq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
115{
116 /* See if we got the magic character 'V' and reload the timer */
117 if(count) {
118 if (!nowayout) {
119 size_t i;
120
121 /* note: just in case someone wrote the magic character
122 * five months ago... */
123 expect_close = 0;
124
125 /* scan to see whether or not we got the magic character */
126 for (i = 0; i != count; i++) {
127 char c;
128 if (get_user(c, buf + i))
129 return -EFAULT;
130 if (c == 'V')
131 expect_close = 42;
132 }
133 }
134
135 /* Well, anyhow someone wrote to us, we should return that favour */
136 acq_keepalive();
137 }
138 return count;
139}
140
141static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
142 unsigned long arg)
143{
144 int options, retval = -EINVAL;
145 void __user *argp = (void __user *)arg;
146 int __user *p = argp;
147 static struct watchdog_info ident =
148 {
149 .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
150 .firmware_version = 1,
151 .identity = "Acquire WDT",
152 };
153
154 switch(cmd)
155 {
156 case WDIOC_GETSUPPORT:
157 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
158
159 case WDIOC_GETSTATUS:
160 case WDIOC_GETBOOTSTATUS:
161 return put_user(0, p);
162
163 case WDIOC_KEEPALIVE:
164 acq_keepalive();
165 return 0;
166
167 case WDIOC_GETTIMEOUT:
168 return put_user(WATCHDOG_HEARTBEAT, p);
169
170 case WDIOC_SETOPTIONS:
171 {
172 if (get_user(options, p))
173 return -EFAULT;
174
175 if (options & WDIOS_DISABLECARD)
176 {
177 acq_stop();
178 retval = 0;
179 }
180
181 if (options & WDIOS_ENABLECARD)
182 {
183 acq_keepalive();
184 retval = 0;
185 }
186
187 return retval;
188 }
189
190 default:
191 return -ENOIOCTLCMD;
192 }
193}
194
195static int acq_open(struct inode *inode, struct file *file)
196{
197 if (test_and_set_bit(0, &acq_is_open))
198 return -EBUSY;
199
200 if (nowayout)
201 __module_get(THIS_MODULE);
202
203 /* Activate */
204 acq_keepalive();
205 return nonseekable_open(inode, file);
206}
207
208static int acq_close(struct inode *inode, struct file *file)
209{
210 if (expect_close == 42) {
211 acq_stop();
212 } else {
213 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
214 acq_keepalive();
215 }
216 clear_bit(0, &acq_is_open);
217 expect_close = 0;
218 return 0;
219}
220
221/*
222 * Notifier for system down
223 */
224
225static int acq_notify_sys(struct notifier_block *this, unsigned long code,
226 void *unused)
227{
228 if(code==SYS_DOWN || code==SYS_HALT) {
229 /* Turn the WDT off */
230 acq_stop();
231 }
232 return NOTIFY_DONE;
233}
234
235/*
236 * Kernel Interfaces
237 */
238
239static struct file_operations acq_fops = {
240 .owner = THIS_MODULE,
241 .llseek = no_llseek,
242 .write = acq_write,
243 .ioctl = acq_ioctl,
244 .open = acq_open,
245 .release = acq_close,
246};
247
248static struct miscdevice acq_miscdev=
249{
250 .minor = WATCHDOG_MINOR,
251 .name = "watchdog",
252 .fops = &acq_fops,
253};
254
255/*
256 * The WDT card needs to learn about soft shutdowns in order to
257 * turn the timebomb registers off.
258 */
259
260static struct notifier_block acq_notifier =
261{
262 .notifier_call = acq_notify_sys,
263};
264
265static int __init acq_init(void)
266{
267 int ret;
268
269 printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n");
270
271 if (wdt_stop != wdt_start) {
272 if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
273 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
274 wdt_stop);
275 ret = -EIO;
276 goto out;
277 }
278 }
279
280 if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
281 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
282 wdt_start);
283 ret = -EIO;
284 goto unreg_stop;
285 }
286
287 ret = register_reboot_notifier(&acq_notifier);
288 if (ret != 0) {
289 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
290 ret);
291 goto unreg_regions;
292 }
293
294 ret = misc_register(&acq_miscdev);
295 if (ret != 0) {
296 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
297 WATCHDOG_MINOR, ret);
298 goto unreg_reboot;
299 }
300
301 printk (KERN_INFO PFX "initialized. (nowayout=%d)\n",
302 nowayout);
303
304 return 0;
305
306unreg_reboot:
307 unregister_reboot_notifier(&acq_notifier);
308unreg_regions:
309 release_region(wdt_start, 1);
310unreg_stop:
311 if (wdt_stop != wdt_start)
312 release_region(wdt_stop, 1);
313out:
314 return ret;
315}
316
317static void __exit acq_exit(void)
318{
319 misc_deregister(&acq_miscdev);
320 unregister_reboot_notifier(&acq_notifier);
321 if(wdt_stop != wdt_start)
322 release_region(wdt_stop,1);
323 release_region(wdt_start,1);
324}
325
326module_init(acq_init);
327module_exit(acq_exit);
328
329MODULE_AUTHOR("David Woodhouse");
330MODULE_DESCRIPTION("Acquire Inc. Single Board Computer Watchdog Timer driver");
331MODULE_LICENSE("GPL");
332MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c
new file mode 100644
index 000000000000..ea73c8379bdd
--- /dev/null
+++ b/drivers/char/watchdog/advantechwdt.c
@@ -0,0 +1,333 @@
1/*
2 * Advantech Single Board Computer WDT driver
3 *
4 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
5 *
6 * Based on acquirewdt.c which is based on wdt.c.
7 * Original copyright messages:
8 *
9 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
10 * http://www.redhat.com
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 *
17 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
18 * warranty for any of this software. This material is provided
19 * "AS-IS" and at no charge.
20 *
21 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
22 *
23 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
24 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
25 *
26 * 16-Oct-2002 Rob Radez <rob@osinvestor.com>
27 * Clean up ioctls, clean up init + exit, add expect close support,
28 * add wdt_start and wdt_stop as parameters.
29 */
30
31#include <linux/module.h>
32#include <linux/moduleparam.h>
33#include <linux/types.h>
34#include <linux/miscdevice.h>
35#include <linux/watchdog.h>
36#include <linux/fs.h>
37#include <linux/ioport.h>
38#include <linux/notifier.h>
39#include <linux/reboot.h>
40#include <linux/init.h>
41
42#include <asm/io.h>
43#include <asm/uaccess.h>
44#include <asm/system.h>
45
46#define WATCHDOG_NAME "Advantech WDT"
47#define PFX WATCHDOG_NAME ": "
48#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
49
50static unsigned long advwdt_is_open;
51static char adv_expect_close;
52
53/*
54 * You must set these - there is no sane way to probe for this board.
55 *
56 * To enable or restart, write the timeout value in seconds (1 to 63)
57 * to I/O port wdt_start. To disable, read I/O port wdt_stop.
58 * Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but
59 * check your manual (at least the PCA-6159 seems to be different -
60 * the manual says wdt_stop is 0x43, not 0x443).
61 * (0x43 is also a write-only control register for the 8254 timer!)
62 */
63
64static int wdt_stop = 0x443;
65module_param(wdt_stop, int, 0);
66MODULE_PARM_DESC(wdt_stop, "Advantech WDT 'stop' io port (default 0x443)");
67
68static int wdt_start = 0x443;
69module_param(wdt_start, int, 0);
70MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)");
71
72static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
73module_param(timeout, int, 0);
74MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
75
76#ifdef CONFIG_WATCHDOG_NOWAYOUT
77static int nowayout = 1;
78#else
79static int nowayout = 0;
80#endif
81
82module_param(nowayout, int, 0);
83MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
84
85/*
86 * Kernel methods.
87 */
88
89static void
90advwdt_ping(void)
91{
92 /* Write a watchdog value */
93 outb_p(timeout, wdt_start);
94}
95
96static void
97advwdt_disable(void)
98{
99 inb_p(wdt_stop);
100}
101
102static ssize_t
103advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
104{
105 if (count) {
106 if (!nowayout) {
107 size_t i;
108
109 adv_expect_close = 0;
110
111 for (i = 0; i != count; i++) {
112 char c;
113 if (get_user(c, buf+i))
114 return -EFAULT;
115 if (c == 'V')
116 adv_expect_close = 42;
117 }
118 }
119 advwdt_ping();
120 }
121 return count;
122}
123
124static int
125advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
126 unsigned long arg)
127{
128 int new_timeout;
129 void __user *argp = (void __user *)arg;
130 int __user *p = argp;
131 static struct watchdog_info ident = {
132 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
133 .firmware_version = 1,
134 .identity = "Advantech WDT",
135 };
136
137 switch (cmd) {
138 case WDIOC_GETSUPPORT:
139 if (copy_to_user(argp, &ident, sizeof(ident)))
140 return -EFAULT;
141 break;
142
143 case WDIOC_GETSTATUS:
144 case WDIOC_GETBOOTSTATUS:
145 return put_user(0, p);
146
147 case WDIOC_KEEPALIVE:
148 advwdt_ping();
149 break;
150
151 case WDIOC_SETTIMEOUT:
152 if (get_user(new_timeout, p))
153 return -EFAULT;
154 if ((new_timeout < 1) || (new_timeout > 63))
155 return -EINVAL;
156 timeout = new_timeout;
157 advwdt_ping();
158 /* Fall */
159
160 case WDIOC_GETTIMEOUT:
161 return put_user(timeout, p);
162
163 case WDIOC_SETOPTIONS:
164 {
165 int options, retval = -EINVAL;
166
167 if (get_user(options, p))
168 return -EFAULT;
169
170 if (options & WDIOS_DISABLECARD) {
171 advwdt_disable();
172 retval = 0;
173 }
174
175 if (options & WDIOS_ENABLECARD) {
176 advwdt_ping();
177 retval = 0;
178 }
179
180 return retval;
181 }
182
183 default:
184 return -ENOIOCTLCMD;
185 }
186 return 0;
187}
188
189static int
190advwdt_open(struct inode *inode, struct file *file)
191{
192 if (test_and_set_bit(0, &advwdt_is_open))
193 return -EBUSY;
194 /*
195 * Activate
196 */
197
198 advwdt_ping();
199 return nonseekable_open(inode, file);
200}
201
202static int
203advwdt_close(struct inode *inode, struct file *file)
204{
205 if (adv_expect_close == 42) {
206 advwdt_disable();
207 } else {
208 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
209 advwdt_ping();
210 }
211 clear_bit(0, &advwdt_is_open);
212 adv_expect_close = 0;
213 return 0;
214}
215
216/*
217 * Notifier for system down
218 */
219
220static int
221advwdt_notify_sys(struct notifier_block *this, unsigned long code,
222 void *unused)
223{
224 if (code == SYS_DOWN || code == SYS_HALT) {
225 /* Turn the WDT off */
226 advwdt_disable();
227 }
228 return NOTIFY_DONE;
229}
230
231/*
232 * Kernel Interfaces
233 */
234
235static struct file_operations advwdt_fops = {
236 .owner = THIS_MODULE,
237 .llseek = no_llseek,
238 .write = advwdt_write,
239 .ioctl = advwdt_ioctl,
240 .open = advwdt_open,
241 .release = advwdt_close,
242};
243
244static struct miscdevice advwdt_miscdev = {
245 .minor = WATCHDOG_MINOR,
246 .name = "watchdog",
247 .fops = &advwdt_fops,
248};
249
250/*
251 * The WDT needs to learn about soft shutdowns in order to
252 * turn the timebomb registers off.
253 */
254
255static struct notifier_block advwdt_notifier = {
256 .notifier_call = advwdt_notify_sys,
257};
258
259static int __init
260advwdt_init(void)
261{
262 int ret;
263
264 printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
265
266 if (timeout < 1 || timeout > 63) {
267 timeout = WATCHDOG_TIMEOUT;
268 printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n",
269 timeout);
270 }
271
272 if (wdt_stop != wdt_start) {
273 if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
274 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
275 wdt_stop);
276 ret = -EIO;
277 goto out;
278 }
279 }
280
281 if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
282 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
283 wdt_start);
284 ret = -EIO;
285 goto unreg_stop;
286 }
287
288 ret = register_reboot_notifier(&advwdt_notifier);
289 if (ret != 0) {
290 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
291 ret);
292 goto unreg_regions;
293 }
294
295 ret = misc_register(&advwdt_miscdev);
296 if (ret != 0) {
297 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
298 WATCHDOG_MINOR, ret);
299 goto unreg_reboot;
300 }
301
302 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
303 timeout, nowayout);
304
305out:
306 return ret;
307unreg_reboot:
308 unregister_reboot_notifier(&advwdt_notifier);
309unreg_regions:
310 release_region(wdt_start, 1);
311unreg_stop:
312 if (wdt_stop != wdt_start)
313 release_region(wdt_stop, 1);
314 goto out;
315}
316
317static void __exit
318advwdt_exit(void)
319{
320 misc_deregister(&advwdt_miscdev);
321 unregister_reboot_notifier(&advwdt_notifier);
322 if(wdt_stop != wdt_start)
323 release_region(wdt_stop,1);
324 release_region(wdt_start,1);
325}
326
327module_init(advwdt_init);
328module_exit(advwdt_exit);
329
330MODULE_LICENSE("GPL");
331MODULE_AUTHOR("Marek Michalkiewicz <marekm@linux.org.pl>");
332MODULE_DESCRIPTION("Advantech Single Board Computer WDT driver");
333MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
new file mode 100644
index 000000000000..35dcbf8be7d1
--- /dev/null
+++ b/drivers/char/watchdog/alim1535_wdt.c
@@ -0,0 +1,463 @@
1/*
2 * Watchdog for the 7101 PMU version found in the ALi M1535 chipsets
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include <linux/module.h>
11#include <linux/moduleparam.h>
12#include <linux/types.h>
13#include <linux/miscdevice.h>
14#include <linux/watchdog.h>
15#include <linux/ioport.h>
16#include <linux/notifier.h>
17#include <linux/reboot.h>
18#include <linux/init.h>
19#include <linux/fs.h>
20#include <linux/pci.h>
21
22#include <asm/uaccess.h>
23#include <asm/io.h>
24
25#define WATCHDOG_NAME "ALi_M1535"
26#define PFX WATCHDOG_NAME ": "
27#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
28
29/* internal variables */
30static unsigned long ali_is_open;
31static char ali_expect_release;
32static struct pci_dev *ali_pci;
33static u32 ali_timeout_bits; /* stores the computed timeout */
34static spinlock_t ali_lock; /* Guards the hardware */
35
36/* module parameters */
37static int timeout = WATCHDOG_TIMEOUT;
38module_param(timeout, int, 0);
39MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (0<timeout<18000, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
40
41#ifdef CONFIG_WATCHDOG_NOWAYOUT
42static int nowayout = 1;
43#else
44static int nowayout = 0;
45#endif
46
47module_param(nowayout, int, 0);
48MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
49
50/*
51 * ali_start - start watchdog countdown
52 *
53 * Starts the timer running providing the timer has a counter
54 * configuration set.
55 */
56
57static void ali_start(void)
58{
59 u32 val;
60
61 spin_lock(&ali_lock);
62
63 pci_read_config_dword(ali_pci, 0xCC, &val);
64 val &= ~0x3F; /* Mask count */
65 val |= (1<<25) | ali_timeout_bits;
66 pci_write_config_dword(ali_pci, 0xCC, val);
67
68 spin_unlock(&ali_lock);
69}
70
71/*
72 * ali_stop - stop the timer countdown
73 *
74 * Stop the ALi watchdog countdown
75 */
76
77static void ali_stop(void)
78{
79 u32 val;
80
81 spin_lock(&ali_lock);
82
83 pci_read_config_dword(ali_pci, 0xCC, &val);
84 val &= ~0x3F; /* Mask count to zero (disabled) */
85 val &= ~(1<<25);/* and for safety mask the reset enable */
86 pci_write_config_dword(ali_pci, 0xCC, val);
87
88 spin_unlock(&ali_lock);
89}
90
91/*
92 * ali_keepalive - send a keepalive to the watchdog
93 *
94 * Send a keepalive to the timer (actually we restart the timer).
95 */
96
97static void ali_keepalive(void)
98{
99 ali_start();
100}
101
102/*
103 * ali_settimer - compute the timer reload value
104 * @t: time in seconds
105 *
106 * Computes the timeout values needed
107 */
108
109static int ali_settimer(int t)
110{
111 if(t < 0)
112 return -EINVAL;
113 else if(t < 60)
114 ali_timeout_bits = t|(1<<6);
115 else if(t < 3600)
116 ali_timeout_bits = (t/60)|(1<<7);
117 else if(t < 18000)
118 ali_timeout_bits = (t/300)|(1<<6)|(1<<7);
119 else return -EINVAL;
120
121 timeout = t;
122 return 0;
123}
124
125/*
126 * /dev/watchdog handling
127 */
128
129/*
130 * ali_write - writes to ALi watchdog
131 * @file: file from VFS
132 * @data: user address of data
133 * @len: length of data
134 * @ppos: pointer to the file offset
135 *
136 * Handle a write to the ALi watchdog. Writing to the file pings
137 * the watchdog and resets it. Writing the magic 'V' sequence allows
138 * the next close to turn off the watchdog.
139 */
140
141static ssize_t ali_write(struct file *file, const char __user *data,
142 size_t len, loff_t * ppos)
143{
144 /* See if we got the magic character 'V' and reload the timer */
145 if (len) {
146 if (!nowayout) {
147 size_t i;
148
149 /* note: just in case someone wrote the magic character
150 * five months ago... */
151 ali_expect_release = 0;
152
153 /* scan to see whether or not we got the magic character */
154 for (i = 0; i != len; i++) {
155 char c;
156 if(get_user(c, data+i))
157 return -EFAULT;
158 if (c == 'V')
159 ali_expect_release = 42;
160 }
161 }
162
163 /* someone wrote to us, we should reload the timer */
164 ali_start();
165 }
166 return len;
167}
168
169/*
170 * ali_ioctl - handle watchdog ioctls
171 * @inode: VFS inode
172 * @file: VFS file pointer
173 * @cmd: ioctl number
174 * @arg: arguments to the ioctl
175 *
176 * Handle the watchdog ioctls supported by the ALi driver. Really
177 * we want an extension to enable irq ack monitoring and the like
178 */
179
180static int ali_ioctl(struct inode *inode, struct file *file,
181 unsigned int cmd, unsigned long arg)
182{
183 void __user *argp = (void __user *)arg;
184 int __user *p = argp;
185 static struct watchdog_info ident = {
186 .options = WDIOF_KEEPALIVEPING |
187 WDIOF_SETTIMEOUT |
188 WDIOF_MAGICCLOSE,
189 .firmware_version = 0,
190 .identity = "ALi M1535 WatchDog Timer",
191 };
192
193 switch (cmd) {
194 case WDIOC_GETSUPPORT:
195 return copy_to_user(argp, &ident,
196 sizeof (ident)) ? -EFAULT : 0;
197
198 case WDIOC_GETSTATUS:
199 case WDIOC_GETBOOTSTATUS:
200 return put_user(0, p);
201
202 case WDIOC_KEEPALIVE:
203 ali_keepalive();
204 return 0;
205
206 case WDIOC_SETOPTIONS:
207 {
208 int new_options, retval = -EINVAL;
209
210 if (get_user (new_options, p))
211 return -EFAULT;
212
213 if (new_options & WDIOS_DISABLECARD) {
214 ali_stop();
215 retval = 0;
216 }
217
218 if (new_options & WDIOS_ENABLECARD) {
219 ali_start();
220 retval = 0;
221 }
222
223 return retval;
224 }
225
226 case WDIOC_SETTIMEOUT:
227 {
228 int new_timeout;
229
230 if (get_user(new_timeout, p))
231 return -EFAULT;
232
233 if (ali_settimer(new_timeout))
234 return -EINVAL;
235
236 ali_keepalive();
237 /* Fall */
238 }
239
240 case WDIOC_GETTIMEOUT:
241 return put_user(timeout, p);
242
243 default:
244 return -ENOIOCTLCMD;
245 }
246}
247
248/*
249 * ali_open - handle open of ali watchdog
250 * @inode: inode from VFS
251 * @file: file from VFS
252 *
253 * Open the ALi watchdog device. Ensure only one person opens it
254 * at a time. Also start the watchdog running.
255 */
256
257static int ali_open(struct inode *inode, struct file *file)
258{
259 /* /dev/watchdog can only be opened once */
260 if (test_and_set_bit(0, &ali_is_open))
261 return -EBUSY;
262
263 /* Activate */
264 ali_start();
265 return nonseekable_open(inode, file);
266}
267
268/*
269 * ali_release - close an ALi watchdog
270 * @inode: inode from VFS
271 * @file: file from VFS
272 *
273 * Close the ALi watchdog device. Actual shutdown of the timer
274 * only occurs if the magic sequence has been set.
275 */
276
277static int ali_release(struct inode *inode, struct file *file)
278{
279 /*
280 * Shut off the timer.
281 */
282 if (ali_expect_release == 42) {
283 ali_stop();
284 } else {
285 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
286 ali_keepalive();
287 }
288 clear_bit(0, &ali_is_open);
289 ali_expect_release = 0;
290 return 0;
291}
292
293/*
294 * ali_notify_sys - System down notifier
295 *
296 * Notifier for system down
297 */
298
299
300static int ali_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
301{
302 if (code==SYS_DOWN || code==SYS_HALT) {
303 /* Turn the WDT off */
304 ali_stop();
305 }
306
307 return NOTIFY_DONE;
308}
309
310/*
311 * Data for PCI driver interface
312 *
313 * This data only exists for exporting the supported
314 * PCI ids via MODULE_DEVICE_TABLE. We do not actually
315 * register a pci_driver, because someone else might one day
316 * want to register another driver on the same PCI id.
317 */
318
319static struct pci_device_id ali_pci_tbl[] = {
320 { PCI_VENDOR_ID_AL, 1535, PCI_ANY_ID, PCI_ANY_ID,},
321 { 0, },
322};
323MODULE_DEVICE_TABLE(pci, ali_pci_tbl);
324
325/*
326 * ali_find_watchdog - find a 1535 and 7101
327 *
328 * Scans the PCI hardware for a 1535 series bridge and matching 7101
329 * watchdog device. This may be overtight but it is better to be safe
330 */
331
332static int __init ali_find_watchdog(void)
333{
334 struct pci_dev *pdev;
335 u32 wdog;
336
337 /* Check for a 1535 series bridge */
338 pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
339 if(pdev == NULL)
340 return -ENODEV;
341
342 /* Check for the a 7101 PMU */
343 pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
344 if(pdev == NULL)
345 return -ENODEV;
346
347 if(pci_enable_device(pdev))
348 return -EIO;
349
350 ali_pci = pdev;
351
352 /*
353 * Initialize the timer bits
354 */
355 pci_read_config_dword(pdev, 0xCC, &wdog);
356
357 wdog &= ~0x3F; /* Timer bits */
358 wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24)); /* Issued events */
359 wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)); /* No monitor bits */
360
361 pci_write_config_dword(pdev, 0xCC, wdog);
362
363 return 0;
364}
365
366/*
367 * Kernel Interfaces
368 */
369
370static struct file_operations ali_fops = {
371 .owner = THIS_MODULE,
372 .llseek = no_llseek,
373 .write = ali_write,
374 .ioctl = ali_ioctl,
375 .open = ali_open,
376 .release = ali_release,
377};
378
379static struct miscdevice ali_miscdev = {
380 .minor = WATCHDOG_MINOR,
381 .name = "watchdog",
382 .fops = &ali_fops,
383};
384
385static struct notifier_block ali_notifier = {
386 .notifier_call = ali_notify_sys,
387};
388
389/*
390 * watchdog_init - module initialiser
391 *
392 * Scan for a suitable watchdog and if so initialize it. Return an error
393 * if we cannot, the error causes the module to unload
394 */
395
396static int __init watchdog_init(void)
397{
398 int ret;
399
400 spin_lock_init(&ali_lock);
401
402 /* Check whether or not the hardware watchdog is there */
403 if (ali_find_watchdog() != 0) {
404 return -ENODEV;
405 }
406
407 /* Check that the timeout value is within it's range ; if not reset to the default */
408 if (timeout < 1 || timeout >= 18000) {
409 timeout = WATCHDOG_TIMEOUT;
410 printk(KERN_INFO PFX "timeout value must be 0<timeout<18000, using %d\n",
411 timeout);
412 }
413
414 /* Calculate the watchdog's timeout */
415 ali_settimer(timeout);
416
417 ret = misc_register(&ali_miscdev);
418 if (ret != 0) {
419 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
420 WATCHDOG_MINOR, ret);
421 goto out;
422 }
423
424 ret = register_reboot_notifier(&ali_notifier);
425 if (ret != 0) {
426 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
427 ret);
428 goto unreg_miscdev;
429 }
430
431 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
432 timeout, nowayout);
433
434out:
435 return ret;
436unreg_miscdev:
437 misc_deregister(&ali_miscdev);
438 goto out;
439}
440
441/*
442 * watchdog_exit - module de-initialiser
443 *
444 * Called while unloading a successfully installed watchdog module.
445 */
446
447static void __exit watchdog_exit(void)
448{
449 /* Stop the timer before we leave */
450 ali_stop();
451
452 /* Deregister */
453 unregister_reboot_notifier(&ali_notifier);
454 misc_deregister(&ali_miscdev);
455}
456
457module_init(watchdog_init);
458module_exit(watchdog_exit);
459
460MODULE_AUTHOR("Alan Cox");
461MODULE_DESCRIPTION("ALi M1535 PMU Watchdog Timer driver");
462MODULE_LICENSE("GPL");
463MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c
new file mode 100644
index 000000000000..90c091d9e0f5
--- /dev/null
+++ b/drivers/char/watchdog/alim7101_wdt.c
@@ -0,0 +1,421 @@
1/*
2 * ALi M7101 PMU Computer Watchdog Timer driver
3 *
4 * Based on w83877f_wdt.c by Scott Jennings <linuxdrivers@oro.net>
5 * and the Cobalt kernel WDT timer driver by Tim Hockin
6 * <thockin@cobaltnet.com>
7 *
8 * (c)2002 Steve Hill <steve@navaho.co.uk>
9 *
10 * This WDT driver is different from most other Linux WDT
11 * drivers in that the driver will ping the watchdog by itself,
12 * because this particular WDT has a very short timeout (1.6
13 * seconds) and it would be insane to count on any userspace
14 * daemon always getting scheduled within that time frame.
15 *
16 * Additions:
17 * Aug 23, 2004 - Added use_gpio module parameter for use on revision a1d PMUs
18 * found on very old cobalt hardware.
19 * -- Mike Waychison <michael.waychison@sun.com>
20 */
21
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/types.h>
25#include <linux/timer.h>
26#include <linux/miscdevice.h>
27#include <linux/watchdog.h>
28#include <linux/ioport.h>
29#include <linux/notifier.h>
30#include <linux/reboot.h>
31#include <linux/init.h>
32#include <linux/fs.h>
33#include <linux/pci.h>
34
35#include <asm/io.h>
36#include <asm/uaccess.h>
37#include <asm/system.h>
38
39#define OUR_NAME "alim7101_wdt"
40#define PFX OUR_NAME ": "
41
42#define WDT_ENABLE 0x9C
43#define WDT_DISABLE 0x8C
44
45#define ALI_7101_WDT 0x92
46#define ALI_7101_GPIO 0x7D
47#define ALI_7101_GPIO_O 0x7E
48#define ALI_WDT_ARM 0x01
49
50/*
51 * We're going to use a 1 second timeout.
52 * If we reset the watchdog every ~250ms we should be safe. */
53
54#define WDT_INTERVAL (HZ/4+1)
55
56/*
57 * We must not require too good response from the userspace daemon.
58 * Here we require the userspace daemon to send us a heartbeat
59 * char to /dev/watchdog every 30 seconds.
60 */
61
62#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
63static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
64module_param(timeout, int, 0);
65MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
66
67static int use_gpio = 0; /* Use the pic (for a1d revision alim7101) */
68module_param(use_gpio, int, 0);
69MODULE_PARM_DESC(use_gpio, "Use the gpio watchdog. (required by old cobalt boards)");
70
71static void wdt_timer_ping(unsigned long);
72static struct timer_list timer;
73static unsigned long next_heartbeat;
74static unsigned long wdt_is_open;
75static char wdt_expect_close;
76static struct pci_dev *alim7101_pmu;
77
78#ifdef CONFIG_WATCHDOG_NOWAYOUT
79static int nowayout = 1;
80#else
81static int nowayout = 0;
82#endif
83
84module_param(nowayout, int, 0);
85MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
86
87/*
88 * Whack the dog
89 */
90
91static void wdt_timer_ping(unsigned long data)
92{
93 /* If we got a heartbeat pulse within the WDT_US_INTERVAL
94 * we agree to ping the WDT
95 */
96 char tmp;
97
98 if(time_before(jiffies, next_heartbeat))
99 {
100 /* Ping the WDT (this is actually a disarm/arm sequence) */
101 pci_read_config_byte(alim7101_pmu, 0x92, &tmp);
102 pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM));
103 pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM));
104 if (use_gpio) {
105 pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
106 pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp
107 | 0x20);
108 pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp
109 & ~0x20);
110 }
111 } else {
112 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
113 }
114 /* Re-set the timer interval */
115 timer.expires = jiffies + WDT_INTERVAL;
116 add_timer(&timer);
117}
118
119/*
120 * Utility routines
121 */
122
123static void wdt_change(int writeval)
124{
125 char tmp;
126
127 pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp);
128 if (writeval == WDT_ENABLE) {
129 pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM));
130 if (use_gpio) {
131 pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
132 pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp & ~0x20);
133 }
134
135 } else {
136 pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM));
137 if (use_gpio) {
138 pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
139 pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 0x20);
140 }
141 }
142}
143
144static void wdt_startup(void)
145{
146 next_heartbeat = jiffies + (timeout * HZ);
147
148 /* We must enable before we kick off the timer in case the timer
149 occurs as we ping it */
150
151 wdt_change(WDT_ENABLE);
152
153 /* Start the timer */
154 timer.expires = jiffies + WDT_INTERVAL;
155 add_timer(&timer);
156
157
158 printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
159}
160
161static void wdt_turnoff(void)
162{
163 /* Stop the timer */
164 del_timer_sync(&timer);
165 wdt_change(WDT_DISABLE);
166 printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
167}
168
169static void wdt_keepalive(void)
170{
171 /* user land ping */
172 next_heartbeat = jiffies + (timeout * HZ);
173}
174
175/*
176 * /dev/watchdog handling
177 */
178
179static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
180{
181 /* See if we got the magic character 'V' and reload the timer */
182 if(count) {
183 if (!nowayout) {
184 size_t ofs;
185
186 /* note: just in case someone wrote the magic character
187 * five months ago... */
188 wdt_expect_close = 0;
189
190 /* now scan */
191 for (ofs = 0; ofs != count; ofs++) {
192 char c;
193 if (get_user(c, buf+ofs))
194 return -EFAULT;
195 if (c == 'V')
196 wdt_expect_close = 42;
197 }
198 }
199 /* someone wrote to us, we should restart timer */
200 wdt_keepalive();
201 }
202 return count;
203}
204
205static int fop_open(struct inode * inode, struct file * file)
206{
207 /* Just in case we're already talking to someone... */
208 if(test_and_set_bit(0, &wdt_is_open))
209 return -EBUSY;
210 /* Good, fire up the show */
211 wdt_startup();
212 return nonseekable_open(inode, file);
213}
214
215static int fop_close(struct inode * inode, struct file * file)
216{
217 if(wdt_expect_close == 42)
218 wdt_turnoff();
219 else {
220 /* wim: shouldn't there be a: del_timer(&timer); */
221 printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n");
222 }
223 clear_bit(0, &wdt_is_open);
224 wdt_expect_close = 0;
225 return 0;
226}
227
228static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
229{
230 void __user *argp = (void __user *)arg;
231 int __user *p = argp;
232 static struct watchdog_info ident =
233 {
234 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
235 .firmware_version = 1,
236 .identity = "ALiM7101",
237 };
238
239 switch(cmd)
240 {
241 case WDIOC_GETSUPPORT:
242 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
243 case WDIOC_GETSTATUS:
244 case WDIOC_GETBOOTSTATUS:
245 return put_user(0, p);
246 case WDIOC_KEEPALIVE:
247 wdt_keepalive();
248 return 0;
249 case WDIOC_SETOPTIONS:
250 {
251 int new_options, retval = -EINVAL;
252
253 if(get_user(new_options, p))
254 return -EFAULT;
255
256 if(new_options & WDIOS_DISABLECARD) {
257 wdt_turnoff();
258 retval = 0;
259 }
260
261 if(new_options & WDIOS_ENABLECARD) {
262 wdt_startup();
263 retval = 0;
264 }
265
266 return retval;
267 }
268 case WDIOC_SETTIMEOUT:
269 {
270 int new_timeout;
271
272 if(get_user(new_timeout, p))
273 return -EFAULT;
274
275 if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
276 return -EINVAL;
277
278 timeout = new_timeout;
279 wdt_keepalive();
280 /* Fall through */
281 }
282 case WDIOC_GETTIMEOUT:
283 return put_user(timeout, p);
284 default:
285 return -ENOIOCTLCMD;
286 }
287}
288
289static struct file_operations wdt_fops = {
290 .owner= THIS_MODULE,
291 .llseek= no_llseek,
292 .write= fop_write,
293 .open= fop_open,
294 .release= fop_close,
295 .ioctl= fop_ioctl,
296};
297
298static struct miscdevice wdt_miscdev = {
299 .minor=WATCHDOG_MINOR,
300 .name="watchdog",
301 .fops=&wdt_fops,
302};
303
304/*
305 * Notifier for system down
306 */
307
308static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
309{
310 if (code==SYS_DOWN || code==SYS_HALT)
311 wdt_turnoff();
312
313 if (code==SYS_RESTART) {
314 /*
315 * Cobalt devices have no way of rebooting themselves other than
316 * getting the watchdog to pull reset, so we restart the watchdog on
317 * reboot with no heartbeat
318 */
319 wdt_change(WDT_ENABLE);
320 printk(KERN_INFO PFX "Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n");
321 }
322 return NOTIFY_DONE;
323}
324
325/*
326 * The WDT needs to learn about soft shutdowns in order to
327 * turn the timebomb registers off.
328 */
329
330static struct notifier_block wdt_notifier=
331{
332 .notifier_call = wdt_notify_sys,
333};
334
335static void __exit alim7101_wdt_unload(void)
336{
337 wdt_turnoff();
338 /* Deregister */
339 misc_deregister(&wdt_miscdev);
340 unregister_reboot_notifier(&wdt_notifier);
341}
342
343static int __init alim7101_wdt_init(void)
344{
345 int rc = -EBUSY;
346 struct pci_dev *ali1543_south;
347 char tmp;
348
349 printk(KERN_INFO PFX "Steve Hill <steve@navaho.co.uk>.\n");
350 alim7101_pmu = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,NULL);
351 if (!alim7101_pmu) {
352 printk(KERN_INFO PFX "ALi M7101 PMU not present - WDT not set\n");
353 return -EBUSY;
354 }
355
356 /* Set the WDT in the PMU to 1 second */
357 pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02);
358
359 ali1543_south = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
360 if (!ali1543_south) {
361 printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n");
362 return -EBUSY;
363 }
364 pci_read_config_byte(ali1543_south, 0x5e, &tmp);
365 if ((tmp & 0x1e) == 0x00) {
366 if (!use_gpio) {
367 printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n");
368 return -EBUSY;
369 }
370 nowayout = 1;
371 } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
372 printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
373 return -EBUSY;
374 }
375
376 if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
377 {
378 timeout = WATCHDOG_TIMEOUT;
379 printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
380 timeout);
381 }
382
383 init_timer(&timer);
384 timer.function = wdt_timer_ping;
385 timer.data = 1;
386
387 rc = misc_register(&wdt_miscdev);
388 if (rc) {
389 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
390 wdt_miscdev.minor, rc);
391 goto err_out;
392 }
393
394 rc = register_reboot_notifier(&wdt_notifier);
395 if (rc) {
396 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
397 rc);
398 goto err_out_miscdev;
399 }
400
401 if (nowayout) {
402 __module_get(THIS_MODULE);
403 }
404
405 printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n",
406 timeout, nowayout);
407 return 0;
408
409err_out_miscdev:
410 misc_deregister(&wdt_miscdev);
411err_out:
412 return rc;
413}
414
415module_init(alim7101_wdt_init);
416module_exit(alim7101_wdt_unload);
417
418MODULE_AUTHOR("Steve Hill");
419MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver");
420MODULE_LICENSE("GPL");
421MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
new file mode 100644
index 000000000000..2865dac0a813
--- /dev/null
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -0,0 +1,303 @@
1/*
2 * sma cpu5 watchdog driver
3 *
4 * Copyright (C) 2003 Heiko Ronsdorf <hero@ihg.uni-duisburg.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 */
21
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/types.h>
25#include <linux/errno.h>
26#include <linux/miscdevice.h>
27#include <linux/fs.h>
28#include <linux/init.h>
29#include <linux/ioport.h>
30#include <linux/timer.h>
31#include <asm/io.h>
32#include <asm/uaccess.h>
33
34#include <linux/watchdog.h>
35
36/* adjustable parameters */
37
38static int verbose = 0;
39static int port = 0x91;
40static int ticks = 10000;
41
42#define PFX "cpu5wdt: "
43
44#define CPU5WDT_EXTENT 0x0A
45
46#define CPU5WDT_STATUS_REG 0x00
47#define CPU5WDT_TIME_A_REG 0x02
48#define CPU5WDT_TIME_B_REG 0x03
49#define CPU5WDT_MODE_REG 0x04
50#define CPU5WDT_TRIGGER_REG 0x07
51#define CPU5WDT_ENABLE_REG 0x08
52#define CPU5WDT_RESET_REG 0x09
53
54#define CPU5WDT_INTERVAL (HZ/10+1)
55
56/* some device data */
57
58static struct {
59 struct semaphore stop;
60 volatile int running;
61 struct timer_list timer;
62 volatile int queue;
63 int default_ticks;
64 unsigned long inuse;
65} cpu5wdt_device;
66
67/* generic helper functions */
68
69static void cpu5wdt_trigger(unsigned long unused)
70{
71 if ( verbose > 2 )
72 printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks);
73
74 if( cpu5wdt_device.running )
75 ticks--;
76
77 /* keep watchdog alive */
78 outb(1, port + CPU5WDT_TRIGGER_REG);
79
80 /* requeue?? */
81 if( cpu5wdt_device.queue && ticks ) {
82 cpu5wdt_device.timer.expires = jiffies + CPU5WDT_INTERVAL;
83 add_timer(&cpu5wdt_device.timer);
84 }
85 else {
86 /* ticks doesn't matter anyway */
87 up(&cpu5wdt_device.stop);
88 }
89
90}
91
92static void cpu5wdt_reset(void)
93{
94 ticks = cpu5wdt_device.default_ticks;
95
96 if ( verbose )
97 printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks);
98
99}
100
101static void cpu5wdt_start(void)
102{
103 if ( !cpu5wdt_device.queue ) {
104 cpu5wdt_device.queue = 1;
105 outb(0, port + CPU5WDT_TIME_A_REG);
106 outb(0, port + CPU5WDT_TIME_B_REG);
107 outb(1, port + CPU5WDT_MODE_REG);
108 outb(0, port + CPU5WDT_RESET_REG);
109 outb(0, port + CPU5WDT_ENABLE_REG);
110 cpu5wdt_device.timer.expires = jiffies + CPU5WDT_INTERVAL;
111 add_timer(&cpu5wdt_device.timer);
112 }
113 /* if process dies, counter is not decremented */
114 cpu5wdt_device.running++;
115}
116
117static int cpu5wdt_stop(void)
118{
119 if ( cpu5wdt_device.running )
120 cpu5wdt_device.running = 0;
121
122 ticks = cpu5wdt_device.default_ticks;
123
124 if ( verbose )
125 printk(KERN_CRIT PFX "stop not possible\n");
126
127 return -EIO;
128}
129
130/* filesystem operations */
131
132static int cpu5wdt_open(struct inode *inode, struct file *file)
133{
134 if ( test_and_set_bit(0, &cpu5wdt_device.inuse) )
135 return -EBUSY;
136
137 return nonseekable_open(inode, file);
138}
139
140static int cpu5wdt_release(struct inode *inode, struct file *file)
141{
142 clear_bit(0, &cpu5wdt_device.inuse);
143 return 0;
144}
145
146static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
147{
148 void __user *argp = (void __user *)arg;
149 unsigned int value;
150 static struct watchdog_info ident =
151 {
152 .options = WDIOF_CARDRESET,
153 .identity = "CPU5 WDT",
154 };
155
156 switch(cmd) {
157 case WDIOC_KEEPALIVE:
158 cpu5wdt_reset();
159 break;
160 case WDIOC_GETSTATUS:
161 value = inb(port + CPU5WDT_STATUS_REG);
162 value = (value >> 2) & 1;
163 if ( copy_to_user(argp, &value, sizeof(int)) )
164 return -EFAULT;
165 break;
166 case WDIOC_GETSUPPORT:
167 if ( copy_to_user(argp, &ident, sizeof(ident)) )
168 return -EFAULT;
169 break;
170 case WDIOC_SETOPTIONS:
171 if ( copy_from_user(&value, argp, sizeof(int)) )
172 return -EFAULT;
173 switch(value) {
174 case WDIOS_ENABLECARD:
175 cpu5wdt_start();
176 break;
177 case WDIOS_DISABLECARD:
178 return cpu5wdt_stop();
179 default:
180 return -EINVAL;
181 }
182 break;
183 default:
184 return -ENOIOCTLCMD;
185 }
186 return 0;
187}
188
189static ssize_t cpu5wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
190{
191 if ( !count )
192 return -EIO;
193
194 cpu5wdt_reset();
195
196 return count;
197}
198
199static struct file_operations cpu5wdt_fops = {
200 .owner = THIS_MODULE,
201 .llseek = no_llseek,
202 .ioctl = cpu5wdt_ioctl,
203 .open = cpu5wdt_open,
204 .write = cpu5wdt_write,
205 .release = cpu5wdt_release,
206};
207
208static struct miscdevice cpu5wdt_misc = {
209 .minor = WATCHDOG_MINOR,
210 .name = "watchdog",
211 .fops = &cpu5wdt_fops,
212};
213
214/* init/exit function */
215
216static int __devinit cpu5wdt_init(void)
217{
218 unsigned int val;
219 int err;
220
221 if ( verbose )
222 printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose);
223
224 if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
225 printk(KERN_ERR PFX "misc_register failed\n");
226 goto no_misc;
227 }
228
229 if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) {
230 printk(KERN_ERR PFX "request_region failed\n");
231 err = -EBUSY;
232 goto no_port;
233 }
234
235 /* watchdog reboot? */
236 val = inb(port + CPU5WDT_STATUS_REG);
237 val = (val >> 2) & 1;
238 if ( !val )
239 printk(KERN_INFO PFX "sorry, was my fault\n");
240
241 init_MUTEX_LOCKED(&cpu5wdt_device.stop);
242 cpu5wdt_device.queue = 0;
243
244 clear_bit(0, &cpu5wdt_device.inuse);
245
246 init_timer(&cpu5wdt_device.timer);
247 cpu5wdt_device.timer.function = cpu5wdt_trigger;
248 cpu5wdt_device.timer.data = 0;
249
250 cpu5wdt_device.default_ticks = ticks;
251
252 printk(KERN_INFO PFX "init success\n");
253
254 return 0;
255
256no_port:
257 misc_deregister(&cpu5wdt_misc);
258no_misc:
259 return err;
260}
261
262static int __devinit cpu5wdt_init_module(void)
263{
264 return cpu5wdt_init();
265}
266
267static void __devexit cpu5wdt_exit(void)
268{
269 if ( cpu5wdt_device.queue ) {
270 cpu5wdt_device.queue = 0;
271 down(&cpu5wdt_device.stop);
272 }
273
274 misc_deregister(&cpu5wdt_misc);
275
276 release_region(port, CPU5WDT_EXTENT);
277
278}
279
280static void __devexit cpu5wdt_exit_module(void)
281{
282 cpu5wdt_exit();
283}
284
285/* module entry points */
286
287module_init(cpu5wdt_init_module);
288module_exit(cpu5wdt_exit_module);
289
290MODULE_AUTHOR("Heiko Ronsdorf <hero@ihg.uni-duisburg.de>");
291MODULE_DESCRIPTION("sma cpu5 watchdog driver");
292MODULE_SUPPORTED_DEVICE("sma cpu5 watchdog");
293MODULE_LICENSE("GPL");
294MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
295
296module_param(port, int, 0);
297MODULE_PARM_DESC(port, "base address of watchdog card, default is 0x91");
298
299module_param(verbose, int, 0);
300MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
301
302module_param(ticks, int, 0);
303MODULE_PARM_DESC(ticks, "count down ticks, default is 10000");
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
new file mode 100644
index 000000000000..d10e554a14d6
--- /dev/null
+++ b/drivers/char/watchdog/eurotechwdt.c
@@ -0,0 +1,474 @@
1/*
2 * Eurotech CPU-1220/1410 on board WDT driver
3 *
4 * (c) Copyright 2001 Ascensit <support@ascensit.com>
5 * (c) Copyright 2001 Rodolfo Giometti <giometti@ascensit.com>
6 * (c) Copyright 2002 Rob Radez <rob@osinvestor.com>
7 *
8 * Based on wdt.c.
9 * Original copyright messages:
10 *
11 * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
12 * http://www.redhat.com
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version
17 * 2 of the License, or (at your option) any later version.
18 *
19 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
20 * warranty for any of this software. This material is provided
21 * "AS-IS" and at no charge.
22 *
23 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>*
24 */
25
26/* Changelog:
27 *
28 * 2002/04/25 - Rob Radez
29 * clean up #includes
30 * clean up locking
31 * make __setup param unique
32 * proper options in watchdog_info
33 * add WDIOC_GETSTATUS and WDIOC_SETOPTIONS ioctls
34 * add expect_close support
35 *
36 * 2001 - Rodolfo Giometti
37 * Initial release
38 *
39 * 2002.05.30 - Joel Becker <joel.becker@oracle.com>
40 * Added Matt Domsch's nowayout module option.
41 */
42
43#include <linux/config.h>
44#include <linux/interrupt.h>
45#include <linux/module.h>
46#include <linux/moduleparam.h>
47#include <linux/types.h>
48#include <linux/miscdevice.h>
49#include <linux/watchdog.h>
50#include <linux/fs.h>
51#include <linux/ioport.h>
52#include <linux/notifier.h>
53#include <linux/reboot.h>
54#include <linux/init.h>
55
56#include <asm/io.h>
57#include <asm/uaccess.h>
58#include <asm/system.h>
59
60static unsigned long eurwdt_is_open;
61static int eurwdt_timeout;
62static char eur_expect_close;
63
64/*
65 * You must set these - there is no sane way to probe for this board.
66 * You can use eurwdt=x,y to set these now.
67 */
68
69static int io = 0x3f0;
70static int irq = 10;
71static char *ev = "int";
72
73#define WDT_TIMEOUT 60 /* 1 minute */
74
75#ifdef CONFIG_WATCHDOG_NOWAYOUT
76static int nowayout = 1;
77#else
78static int nowayout = 0;
79#endif
80
81module_param(nowayout, int, 0);
82MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
83
84/*
85 * Some symbolic names
86 */
87
88#define WDT_CTRL_REG 0x30
89#define WDT_OUTPIN_CFG 0xe2
90#define WDT_EVENT_INT 0x00
91#define WDT_EVENT_REBOOT 0x08
92#define WDT_UNIT_SEL 0xf1
93#define WDT_UNIT_SECS 0x80
94#define WDT_TIMEOUT_VAL 0xf2
95#define WDT_TIMER_CFG 0xf3
96
97
98module_param(io, int, 0);
99MODULE_PARM_DESC(io, "Eurotech WDT io port (default=0x3f0)");
100module_param(irq, int, 0);
101MODULE_PARM_DESC(irq, "Eurotech WDT irq (default=10)");
102module_param(ev, charp, 0);
103MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `int')");
104
105
106/*
107 * Programming support
108 */
109
110static inline void eurwdt_write_reg(u8 index, u8 data)
111{
112 outb(index, io);
113 outb(data, io+1);
114}
115
116static inline void eurwdt_lock_chip(void)
117{
118 outb(0xaa, io);
119}
120
121static inline void eurwdt_unlock_chip(void)
122{
123 outb(0x55, io);
124 eurwdt_write_reg(0x07, 0x08); /* set the logical device */
125}
126
127static inline void eurwdt_set_timeout(int timeout)
128{
129 eurwdt_write_reg(WDT_TIMEOUT_VAL, (u8) timeout);
130}
131
132static inline void eurwdt_disable_timer(void)
133{
134 eurwdt_set_timeout(0);
135}
136
137static void eurwdt_activate_timer(void)
138{
139 eurwdt_disable_timer();
140 eurwdt_write_reg(WDT_CTRL_REG, 0x01); /* activate the WDT */
141 eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ? WDT_EVENT_INT : WDT_EVENT_REBOOT);
142
143 /* Setting interrupt line */
144 if (irq == 2 || irq > 15 || irq < 0) {
145 printk(KERN_ERR ": invalid irq number\n");
146 irq = 0; /* if invalid we disable interrupt */
147 }
148 if (irq == 0)
149 printk(KERN_INFO ": interrupt disabled\n");
150
151 eurwdt_write_reg(WDT_TIMER_CFG, irq<<4);
152
153 eurwdt_write_reg(WDT_UNIT_SEL, WDT_UNIT_SECS); /* we use seconds */
154 eurwdt_set_timeout(0); /* the default timeout */
155}
156
157
158/*
159 * Kernel methods.
160 */
161
162static irqreturn_t eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
163{
164 printk(KERN_CRIT "timeout WDT timeout\n");
165
166#ifdef ONLY_TESTING
167 printk(KERN_CRIT "Would Reboot.\n");
168#else
169 printk(KERN_CRIT "Initiating system reboot.\n");
170 machine_restart(NULL);
171#endif
172 return IRQ_HANDLED;
173}
174
175
176/**
177 * eurwdt_ping:
178 *
179 * Reload counter one with the watchdog timeout.
180 */
181
182static void eurwdt_ping(void)
183{
184 /* Write the watchdog default value */
185 eurwdt_set_timeout(eurwdt_timeout);
186}
187
188/**
189 * eurwdt_write:
190 * @file: file handle to the watchdog
191 * @buf: buffer to write (unused as data does not matter here
192 * @count: count of bytes
193 * @ppos: pointer to the position to write. No seeks allowed
194 *
195 * A write to a watchdog device is defined as a keepalive signal. Any
196 * write of data will do, as we we don't define content meaning.
197 */
198
199static ssize_t eurwdt_write(struct file *file, const char __user *buf,
200size_t count, loff_t *ppos)
201{
202 if (count) {
203 if (!nowayout) {
204 size_t i;
205
206 eur_expect_close = 0;
207
208 for (i = 0; i != count; i++) {
209 char c;
210 if(get_user(c, buf+i))
211 return -EFAULT;
212 if (c == 'V')
213 eur_expect_close = 42;
214 }
215 }
216 eurwdt_ping(); /* the default timeout */
217 }
218
219 return count;
220}
221
222/**
223 * eurwdt_ioctl:
224 * @inode: inode of the device
225 * @file: file handle to the device
226 * @cmd: watchdog command
227 * @arg: argument pointer
228 *
229 * The watchdog API defines a common set of functions for all watchdogs
230 * according to their available features.
231 */
232
233static int eurwdt_ioctl(struct inode *inode, struct file *file,
234 unsigned int cmd, unsigned long arg)
235{
236 void __user *argp = (void __user *)arg;
237 int __user *p = argp;
238 static struct watchdog_info ident = {
239 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
240 .firmware_version = 1,
241 .identity = "WDT Eurotech CPU-1220/1410",
242 };
243
244 int time;
245 int options, retval = -EINVAL;
246
247 switch(cmd) {
248 default:
249 return -ENOIOCTLCMD;
250
251 case WDIOC_GETSUPPORT:
252 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
253
254 case WDIOC_GETSTATUS:
255 case WDIOC_GETBOOTSTATUS:
256 return put_user(0, p);
257
258 case WDIOC_KEEPALIVE:
259 eurwdt_ping();
260 return 0;
261
262 case WDIOC_SETTIMEOUT:
263 if (copy_from_user(&time, p, sizeof(int)))
264 return -EFAULT;
265
266 /* Sanity check */
267 if (time < 0 || time > 255)
268 return -EINVAL;
269
270 eurwdt_timeout = time;
271 eurwdt_set_timeout(time);
272 /* Fall */
273
274 case WDIOC_GETTIMEOUT:
275 return put_user(eurwdt_timeout, p);
276
277 case WDIOC_SETOPTIONS:
278 if (get_user(options, p))
279 return -EFAULT;
280 if (options & WDIOS_DISABLECARD) {
281 eurwdt_disable_timer();
282 retval = 0;
283 }
284 if (options & WDIOS_ENABLECARD) {
285 eurwdt_activate_timer();
286 eurwdt_ping();
287 retval = 0;
288 }
289 return retval;
290 }
291}
292
293/**
294 * eurwdt_open:
295 * @inode: inode of device
296 * @file: file handle to device
297 *
298 * The misc device has been opened. The watchdog device is single
299 * open and on opening we load the counter.
300 */
301
302static int eurwdt_open(struct inode *inode, struct file *file)
303{
304 if (test_and_set_bit(0, &eurwdt_is_open))
305 return -EBUSY;
306 eurwdt_timeout = WDT_TIMEOUT; /* initial timeout */
307 /* Activate the WDT */
308 eurwdt_activate_timer();
309 return nonseekable_open(inode, file);
310}
311
312/**
313 * eurwdt_release:
314 * @inode: inode to board
315 * @file: file handle to board
316 *
317 * The watchdog has a configurable API. There is a religious dispute
318 * between people who want their watchdog to be able to shut down and
319 * those who want to be sure if the watchdog manager dies the machine
320 * reboots. In the former case we disable the counters, in the latter
321 * case you have to open it again very soon.
322 */
323
324static int eurwdt_release(struct inode *inode, struct file *file)
325{
326 if (eur_expect_close == 42) {
327 eurwdt_disable_timer();
328 } else {
329 printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n");
330 eurwdt_ping();
331 }
332 clear_bit(0, &eurwdt_is_open);
333 eur_expect_close = 0;
334 return 0;
335}
336
337/**
338 * eurwdt_notify_sys:
339 * @this: our notifier block
340 * @code: the event being reported
341 * @unused: unused
342 *
343 * Our notifier is called on system shutdowns. We want to turn the card
344 * off at reboot otherwise the machine will reboot again during memory
345 * test or worse yet during the following fsck. This would suck, in fact
346 * trust me - if it happens it does suck.
347 */
348
349static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code,
350 void *unused)
351{
352 if (code == SYS_DOWN || code == SYS_HALT) {
353 /* Turn the card off */
354 eurwdt_disable_timer();
355 }
356
357 return NOTIFY_DONE;
358}
359
360/*
361 * Kernel Interfaces
362 */
363
364
365static struct file_operations eurwdt_fops = {
366 .owner = THIS_MODULE,
367 .llseek = no_llseek,
368 .write = eurwdt_write,
369 .ioctl = eurwdt_ioctl,
370 .open = eurwdt_open,
371 .release = eurwdt_release,
372};
373
374static struct miscdevice eurwdt_miscdev = {
375 .minor = WATCHDOG_MINOR,
376 .name = "watchdog",
377 .fops = &eurwdt_fops,
378};
379
380/*
381 * The WDT card needs to learn about soft shutdowns in order to
382 * turn the timebomb registers off.
383 */
384
385static struct notifier_block eurwdt_notifier = {
386 .notifier_call = eurwdt_notify_sys,
387};
388
389/**
390 * cleanup_module:
391 *
392 * Unload the watchdog. You cannot do this with any file handles open.
393 * If your watchdog is set to continue ticking on close and you unload
394 * it, well it keeps ticking. We won't get the interrupt but the board
395 * will not touch PC memory so all is fine. You just have to load a new
396 * module in 60 seconds or reboot.
397 */
398
399static void __exit eurwdt_exit(void)
400{
401 eurwdt_lock_chip();
402
403 misc_deregister(&eurwdt_miscdev);
404
405 unregister_reboot_notifier(&eurwdt_notifier);
406 release_region(io, 2);
407 free_irq(irq, NULL);
408}
409
410/**
411 * eurwdt_init:
412 *
413 * Set up the WDT watchdog board. After grabbing the resources
414 * we require we need also to unlock the device.
415 * The open() function will actually kick the board off.
416 */
417
418static int __init eurwdt_init(void)
419{
420 int ret;
421
422 ret = misc_register(&eurwdt_miscdev);
423 if (ret) {
424 printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
425 WATCHDOG_MINOR);
426 goto out;
427 }
428
429 ret = request_irq(irq, eurwdt_interrupt, SA_INTERRUPT, "eurwdt", NULL);
430 if(ret) {
431 printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
432 goto outmisc;
433 }
434
435 if (!request_region(io, 2, "eurwdt")) {
436 printk(KERN_ERR "eurwdt: IO %X is not free.\n", io);
437 ret = -EBUSY;
438 goto outirq;
439 }
440
441 ret = register_reboot_notifier(&eurwdt_notifier);
442 if (ret) {
443 printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret);
444 goto outreg;
445 }
446
447 eurwdt_unlock_chip();
448
449 ret = 0;
450 printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)"
451 " - timeout event: %s\n",
452 io, irq, (!strcmp("int", ev) ? "int" : "reboot"));
453
454out:
455 return ret;
456
457outreg:
458 release_region(io, 2);
459
460outirq:
461 free_irq(irq, NULL);
462
463outmisc:
464 misc_deregister(&eurwdt_miscdev);
465 goto out;
466}
467
468module_init(eurwdt_init);
469module_exit(eurwdt_exit);
470
471MODULE_AUTHOR("Rodolfo Giometti");
472MODULE_DESCRIPTION("Driver for Eurotech CPU-1220/1410 on board watchdog");
473MODULE_LICENSE("GPL");
474MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
new file mode 100644
index 000000000000..c337978dc966
--- /dev/null
+++ b/drivers/char/watchdog/i8xx_tco.c
@@ -0,0 +1,535 @@
1/*
2 * i8xx_tco 0.07: TCO timer driver for i8xx chipsets
3 *
4 * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
5 * http://www.kernelconcepts.de
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * Neither kernel concepts nor Nils Faerber admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
15 *
16 * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>
17 * developed for
18 * Jentro AG, Haar/Munich (Germany)
19 *
20 * TCO timer driver for i8xx chipsets
21 * based on softdog.c by Alan Cox <alan@redhat.com>
22 *
23 * The TCO timer is implemented in the following I/O controller hubs:
24 * (See the intel documentation on http://developer.intel.com.)
25 * 82801AA (ICH) : document number 290655-003, 290677-014,
26 * 82801AB (ICHO) : document number 290655-003, 290677-014,
27 * 82801BA (ICH2) : document number 290687-002, 298242-027,
28 * 82801BAM (ICH2-M) : document number 290687-002, 298242-027,
29 * 82801CA (ICH3-S) : document number 290733-003, 290739-013,
30 * 82801CAM (ICH3-M) : document number 290716-001, 290718-007,
31 * 82801DB (ICH4) : document number 290744-001, 290745-020,
32 * 82801DBM (ICH4-M) : document number 252337-001, 252663-005,
33 * 82801E (C-ICH) : document number 273599-001, 273645-002,
34 * 82801EB (ICH5) : document number 252516-001, 252517-003,
35 * 82801ER (ICH5R) : document number 252516-001, 252517-003,
36 * 82801FB (ICH6) : document number 301473-002, 301474-007,
37 * 82801FR (ICH6R) : document number 301473-002, 301474-007,
38 * 82801FBM (ICH6-M) : document number 301473-002, 301474-007,
39 * 82801FW (ICH6W) : document number 301473-001, 301474-007,
40 * 82801FRW (ICH6RW) : document number 301473-001, 301474-007
41 *
42 * 20000710 Nils Faerber
43 * Initial Version 0.01
44 * 20000728 Nils Faerber
45 * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
46 * 20011214 Matt Domsch <Matt_Domsch@dell.com>
47 * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
48 * Didn't add timeout option as i810_margin already exists.
49 * 20020224 Joel Becker, Wim Van Sebroeck
50 * 0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3,
51 * add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT.
52 * 20020412 Rob Radez <rob@osinvestor.com>, Wim Van Sebroeck
53 * 0.05 Fix possible timer_alive race, add expect close support,
54 * clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and
55 * WDIOC_SETOPTIONS), made i810tco_getdevice __init,
56 * removed boot_status, removed tco_timer_read,
57 * added support for 82801DB and 82801E chipset,
58 * added support for 82801EB and 8280ER chipset,
59 * general cleanup.
60 * 20030921 Wim Van Sebroeck <wim@iguana.be>
61 * 0.06 change i810_margin to heartbeat, use module_param,
62 * added notify system support, renamed module to i8xx_tco.
63 * 20050128 Wim Van Sebroeck <wim@iguana.be>
64 * 0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW
65 * chipsets. Also added support for the "undocumented" ICH7 chipset.
66 */
67
68/*
69 * Includes, defines, variables, module parameters, ...
70 */
71
72#include <linux/module.h>
73#include <linux/moduleparam.h>
74#include <linux/types.h>
75#include <linux/miscdevice.h>
76#include <linux/watchdog.h>
77#include <linux/notifier.h>
78#include <linux/reboot.h>
79#include <linux/init.h>
80#include <linux/fs.h>
81#include <linux/pci.h>
82#include <linux/ioport.h>
83
84#include <asm/uaccess.h>
85#include <asm/io.h>
86
87#include "i8xx_tco.h"
88
89/* Module and version information */
90#define TCO_VERSION "0.07"
91#define TCO_MODULE_NAME "i8xx TCO timer"
92#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
93#define PFX TCO_MODULE_NAME ": "
94
95/* internal variables */
96static unsigned int ACPIBASE;
97static spinlock_t tco_lock; /* Guards the hardware */
98static unsigned long timer_alive;
99static char tco_expect_close;
100static struct pci_dev *i8xx_tco_pci;
101
102/* module parameters */
103#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (2<heartbeat<39) */
104static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
105module_param(heartbeat, int, 0);
106MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
107
108#ifdef CONFIG_WATCHDOG_NOWAYOUT
109static int nowayout = 1;
110#else
111static int nowayout = 0;
112#endif
113
114module_param(nowayout, int, 0);
115MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
116
117/*
118 * Some TCO specific functions
119 */
120
121static inline unsigned char seconds_to_ticks(int seconds)
122{
123 /* the internal timer is stored as ticks which decrement
124 * every 0.6 seconds */
125 return (seconds * 10) / 6;
126}
127
128static int tco_timer_start (void)
129{
130 unsigned char val;
131
132 spin_lock(&tco_lock);
133 val = inb (TCO1_CNT + 1);
134 val &= 0xf7;
135 outb (val, TCO1_CNT + 1);
136 val = inb (TCO1_CNT + 1);
137 spin_unlock(&tco_lock);
138
139 if (val & 0x08)
140 return -1;
141 return 0;
142}
143
144static int tco_timer_stop (void)
145{
146 unsigned char val;
147
148 spin_lock(&tco_lock);
149 val = inb (TCO1_CNT + 1);
150 val |= 0x08;
151 outb (val, TCO1_CNT + 1);
152 val = inb (TCO1_CNT + 1);
153 spin_unlock(&tco_lock);
154
155 if ((val & 0x08) == 0)
156 return -1;
157 return 0;
158}
159
160static int tco_timer_keepalive (void)
161{
162 spin_lock(&tco_lock);
163 outb (0x01, TCO1_RLD);
164 spin_unlock(&tco_lock);
165 return 0;
166}
167
168static int tco_timer_set_heartbeat (int t)
169{
170 unsigned char val;
171 unsigned char tmrval;
172
173 tmrval = seconds_to_ticks(t);
174 /* from the specs: */
175 /* "Values of 0h-3h are ignored and should not be attempted" */
176 if (tmrval > 0x3f || tmrval < 0x04)
177 return -EINVAL;
178
179 /* Write new heartbeat to watchdog */
180 spin_lock(&tco_lock);
181 val = inb (TCO1_TMR);
182 val &= 0xc0;
183 val |= tmrval;
184 outb (val, TCO1_TMR);
185 val = inb (TCO1_TMR);
186 spin_unlock(&tco_lock);
187
188 if ((val & 0x3f) != tmrval)
189 return -EINVAL;
190
191 heartbeat = t;
192 return 0;
193}
194
195/*
196 * /dev/watchdog handling
197 */
198
199static int i8xx_tco_open (struct inode *inode, struct file *file)
200{
201 /* /dev/watchdog can only be opened once */
202 if (test_and_set_bit(0, &timer_alive))
203 return -EBUSY;
204
205 /*
206 * Reload and activate timer
207 */
208 tco_timer_keepalive ();
209 tco_timer_start ();
210 return nonseekable_open(inode, file);
211}
212
213static int i8xx_tco_release (struct inode *inode, struct file *file)
214{
215 /*
216 * Shut off the timer.
217 */
218 if (tco_expect_close == 42) {
219 tco_timer_stop ();
220 } else {
221 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
222 tco_timer_keepalive ();
223 }
224 clear_bit(0, &timer_alive);
225 tco_expect_close = 0;
226 return 0;
227}
228
229static ssize_t i8xx_tco_write (struct file *file, const char __user *data,
230 size_t len, loff_t * ppos)
231{
232 /* See if we got the magic character 'V' and reload the timer */
233 if (len) {
234 if (!nowayout) {
235 size_t i;
236
237 /* note: just in case someone wrote the magic character
238 * five months ago... */
239 tco_expect_close = 0;
240
241 /* scan to see whether or not we got the magic character */
242 for (i = 0; i != len; i++) {
243 char c;
244 if(get_user(c, data+i))
245 return -EFAULT;
246 if (c == 'V')
247 tco_expect_close = 42;
248 }
249 }
250
251 /* someone wrote to us, we should reload the timer */
252 tco_timer_keepalive ();
253 }
254 return len;
255}
256
257static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
258 unsigned int cmd, unsigned long arg)
259{
260 int new_options, retval = -EINVAL;
261 int new_heartbeat;
262 void __user *argp = (void __user *)arg;
263 int __user *p = argp;
264 static struct watchdog_info ident = {
265 .options = WDIOF_SETTIMEOUT |
266 WDIOF_KEEPALIVEPING |
267 WDIOF_MAGICCLOSE,
268 .firmware_version = 0,
269 .identity = TCO_MODULE_NAME,
270 };
271
272 switch (cmd) {
273 case WDIOC_GETSUPPORT:
274 return copy_to_user(argp, &ident,
275 sizeof (ident)) ? -EFAULT : 0;
276
277 case WDIOC_GETSTATUS:
278 case WDIOC_GETBOOTSTATUS:
279 return put_user (0, p);
280
281 case WDIOC_KEEPALIVE:
282 tco_timer_keepalive ();
283 return 0;
284
285 case WDIOC_SETOPTIONS:
286 {
287 if (get_user (new_options, p))
288 return -EFAULT;
289
290 if (new_options & WDIOS_DISABLECARD) {
291 tco_timer_stop ();
292 retval = 0;
293 }
294
295 if (new_options & WDIOS_ENABLECARD) {
296 tco_timer_keepalive ();
297 tco_timer_start ();
298 retval = 0;
299 }
300
301 return retval;
302 }
303
304 case WDIOC_SETTIMEOUT:
305 {
306 if (get_user(new_heartbeat, p))
307 return -EFAULT;
308
309 if (tco_timer_set_heartbeat(new_heartbeat))
310 return -EINVAL;
311
312 tco_timer_keepalive ();
313 /* Fall */
314 }
315
316 case WDIOC_GETTIMEOUT:
317 return put_user(heartbeat, p);
318
319 default:
320 return -ENOIOCTLCMD;
321 }
322}
323
324/*
325 * Notify system
326 */
327
328static int i8xx_tco_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
329{
330 if (code==SYS_DOWN || code==SYS_HALT) {
331 /* Turn the WDT off */
332 tco_timer_stop ();
333 }
334
335 return NOTIFY_DONE;
336}
337
338/*
339 * Kernel Interfaces
340 */
341
342static struct file_operations i8xx_tco_fops = {
343 .owner = THIS_MODULE,
344 .llseek = no_llseek,
345 .write = i8xx_tco_write,
346 .ioctl = i8xx_tco_ioctl,
347 .open = i8xx_tco_open,
348 .release = i8xx_tco_release,
349};
350
351static struct miscdevice i8xx_tco_miscdev = {
352 .minor = WATCHDOG_MINOR,
353 .name = "watchdog",
354 .fops = &i8xx_tco_fops,
355};
356
357static struct notifier_block i8xx_tco_notifier = {
358 .notifier_call = i8xx_tco_notify_sys,
359};
360
361/*
362 * Data for PCI driver interface
363 *
364 * This data only exists for exporting the supported
365 * PCI ids via MODULE_DEVICE_TABLE. We do not actually
366 * register a pci_driver, because someone else might one day
367 * want to register another driver on the same PCI id.
368 */
369static struct pci_device_id i8xx_tco_pci_tbl[] = {
370 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, },
371 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, },
372 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, },
373 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, },
374 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, },
375 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, },
376 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, },
377 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, },
378 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, },
379 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, },
380 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, },
381 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, },
382 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, },
383 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, },
384 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, },
385 { 0, }, /* End of list */
386};
387MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl);
388
389/*
390 * Init & exit routines
391 */
392
393static unsigned char __init i8xx_tco_getdevice (void)
394{
395 struct pci_dev *dev = NULL;
396 u8 val1, val2;
397 u16 badr;
398 /*
399 * Find the PCI device
400 */
401
402 while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
403 if (pci_match_device(i8xx_tco_pci_tbl, dev)) {
404 i8xx_tco_pci = dev;
405 break;
406 }
407 }
408
409 if (i8xx_tco_pci) {
410 /*
411 * Find the ACPI base I/O address which is the base
412 * for the TCO registers (TCOBASE=ACPIBASE + 0x60)
413 * ACPIBASE is bits [15:7] from 0x40-0x43
414 */
415 pci_read_config_byte (i8xx_tco_pci, 0x40, &val1);
416 pci_read_config_byte (i8xx_tco_pci, 0x41, &val2);
417 badr = ((val2 << 1) | (val1 >> 7)) << 7;
418 ACPIBASE = badr;
419 /* Something's wrong here, ACPIBASE has to be set */
420 if (badr == 0x0001 || badr == 0x0000) {
421 printk (KERN_ERR PFX "failed to get TCOBASE address\n");
422 return 0;
423 }
424 /*
425 * Check chipset's NO_REBOOT bit
426 */
427 pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
428 if (val1 & 0x02) {
429 val1 &= 0xfd;
430 pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
431 pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
432 if (val1 & 0x02) {
433 printk (KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
434 return 0; /* Cannot reset NO_REBOOT bit */
435 }
436 }
437 /* Set the TCO_EN bit in SMI_EN register */
438 if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) {
439 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
440 SMI_EN + 1);
441 return 0;
442 }
443 val1 = inb (SMI_EN + 1);
444 val1 &= 0xdf;
445 outb (val1, SMI_EN + 1);
446 release_region (SMI_EN + 1, 1);
447 return 1;
448 }
449 return 0;
450}
451
452static int __init watchdog_init (void)
453{
454 int ret;
455
456 spin_lock_init(&tco_lock);
457
458 /* Check whether or not the hardware watchdog is there */
459 if (!i8xx_tco_getdevice () || i8xx_tco_pci == NULL)
460 return -ENODEV;
461
462 if (!request_region (TCOBASE, 0x10, "i8xx TCO")) {
463 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
464 TCOBASE);
465 ret = -EIO;
466 goto out;
467 }
468
469 /* Clear out the (probably old) status */
470 outb (0, TCO1_STS);
471 outb (3, TCO2_STS);
472
473 /* Check that the heartbeat value is within it's range ; if not reset to the default */
474 if (tco_timer_set_heartbeat (heartbeat)) {
475 heartbeat = WATCHDOG_HEARTBEAT;
476 tco_timer_set_heartbeat (heartbeat);
477 printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, using %d\n",
478 heartbeat);
479 }
480
481 ret = register_reboot_notifier(&i8xx_tco_notifier);
482 if (ret != 0) {
483 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
484 ret);
485 goto unreg_region;
486 }
487
488 ret = misc_register(&i8xx_tco_miscdev);
489 if (ret != 0) {
490 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
491 WATCHDOG_MINOR, ret);
492 goto unreg_notifier;
493 }
494
495 tco_timer_stop ();
496
497 printk (KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n",
498 TCOBASE, heartbeat, nowayout);
499
500 return 0;
501
502unreg_notifier:
503 unregister_reboot_notifier(&i8xx_tco_notifier);
504unreg_region:
505 release_region (TCOBASE, 0x10);
506out:
507 return ret;
508}
509
510static void __exit watchdog_cleanup (void)
511{
512 u8 val;
513
514 /* Stop the timer before we leave */
515 if (!nowayout)
516 tco_timer_stop ();
517
518 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
519 pci_read_config_byte (i8xx_tco_pci, 0xd4, &val);
520 val |= 0x02;
521 pci_write_config_byte (i8xx_tco_pci, 0xd4, val);
522
523 /* Deregister */
524 misc_deregister (&i8xx_tco_miscdev);
525 unregister_reboot_notifier(&i8xx_tco_notifier);
526 release_region (TCOBASE, 0x10);
527}
528
529module_init(watchdog_init);
530module_exit(watchdog_cleanup);
531
532MODULE_AUTHOR("Nils Faerber");
533MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets");
534MODULE_LICENSE("GPL");
535MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/i8xx_tco.h b/drivers/char/watchdog/i8xx_tco.h
new file mode 100644
index 000000000000..cc14eb8ac3d6
--- /dev/null
+++ b/drivers/char/watchdog/i8xx_tco.h
@@ -0,0 +1,42 @@
1/*
2 * i8xx_tco: TCO timer driver for i8xx chipsets
3 *
4 * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
5 * http://www.kernelconcepts.de
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * Neither kernel concepts nor Nils Faerber admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
15 *
16 * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>
17 * developed for
18 * Jentro AG, Haar/Munich (Germany)
19 *
20 * TCO timer driver for i8xx chipsets
21 * based on softdog.c by Alan Cox <alan@redhat.com>
22 *
23 * For history and the complete list of supported I/O Controller Hub's
24 * see i8xx_tco.c
25 */
26
27
28/*
29 * Some address definitions for the TCO
30 */
31
32#define TCOBASE ACPIBASE + 0x60 /* TCO base address */
33#define TCO1_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */
34#define TCO1_TMR TCOBASE + 0x01 /* TCO Timer Initial Value */
35#define TCO1_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */
36#define TCO1_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */
37#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
38#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */
39#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */
40#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */
41
42#define SMI_EN ACPIBASE + 0x30 /* SMI Control and Enable Register */
diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c
new file mode 100644
index 000000000000..d974f16e84d2
--- /dev/null
+++ b/drivers/char/watchdog/ib700wdt.c
@@ -0,0 +1,352 @@
1/*
2 * IB700 Single Board Computer WDT driver
3 *
4 * (c) Copyright 2001 Charles Howes <chowes@vsol.net>
5 *
6 * Based on advantechwdt.c which is based on acquirewdt.c which
7 * is based on wdt.c.
8 *
9 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
10 *
11 * Based on acquirewdt.c which is based on wdt.c.
12 * Original copyright messages:
13 *
14 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
15 * http://www.redhat.com
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version
20 * 2 of the License, or (at your option) any later version.
21 *
22 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
23 * warranty for any of this software. This material is provided
24 * "AS-IS" and at no charge.
25 *
26 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
27 *
28 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
29 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
30 * Added timeout module option to override default
31 *
32 */
33
34#include <linux/config.h>
35#include <linux/module.h>
36#include <linux/types.h>
37#include <linux/miscdevice.h>
38#include <linux/watchdog.h>
39#include <linux/ioport.h>
40#include <linux/notifier.h>
41#include <linux/fs.h>
42#include <linux/reboot.h>
43#include <linux/init.h>
44#include <linux/spinlock.h>
45#include <linux/moduleparam.h>
46
47#include <asm/io.h>
48#include <asm/uaccess.h>
49#include <asm/system.h>
50
51static unsigned long ibwdt_is_open;
52static spinlock_t ibwdt_lock;
53static char expect_close;
54
55#define PFX "ib700wdt: "
56
57/*
58 *
59 * Watchdog Timer Configuration
60 *
61 * The function of the watchdog timer is to reset the system
62 * automatically and is defined at I/O port 0443H. To enable the
63 * watchdog timer and allow the system to reset, write I/O port 0443H.
64 * To disable the timer, write I/O port 0441H for the system to stop the
65 * watchdog function. The timer has a tolerance of 20% for its
66 * intervals.
67 *
68 * The following describes how the timer should be programmed.
69 *
70 * Enabling Watchdog:
71 * MOV AX,000FH (Choose the values from 0 to F)
72 * MOV DX,0443H
73 * OUT DX,AX
74 *
75 * Disabling Watchdog:
76 * MOV AX,000FH (Any value is fine.)
77 * MOV DX,0441H
78 * OUT DX,AX
79 *
80 * Watchdog timer control table:
81 * Level Value Time/sec | Level Value Time/sec
82 * 1 F 0 | 9 7 16
83 * 2 E 2 | 10 6 18
84 * 3 D 4 | 11 5 20
85 * 4 C 6 | 12 4 22
86 * 5 B 8 | 13 3 24
87 * 6 A 10 | 14 2 26
88 * 7 9 12 | 15 1 28
89 * 8 8 14 | 16 0 30
90 *
91 */
92
93static int wd_times[] = {
94 30, /* 0x0 */
95 28, /* 0x1 */
96 26, /* 0x2 */
97 24, /* 0x3 */
98 22, /* 0x4 */
99 20, /* 0x5 */
100 18, /* 0x6 */
101 16, /* 0x7 */
102 14, /* 0x8 */
103 12, /* 0x9 */
104 10, /* 0xA */
105 8, /* 0xB */
106 6, /* 0xC */
107 4, /* 0xD */
108 2, /* 0xE */
109 0, /* 0xF */
110};
111
112#define WDT_STOP 0x441
113#define WDT_START 0x443
114
115/* Default timeout */
116#define WD_TIMO 0 /* 30 seconds +/- 20%, from table */
117
118static int wd_margin = WD_TIMO;
119
120#ifdef CONFIG_WATCHDOG_NOWAYOUT
121static int nowayout = 1;
122#else
123static int nowayout = 0;
124#endif
125
126module_param(nowayout, int, 0);
127MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
128
129
130/*
131 * Kernel methods.
132 */
133
134static void
135ibwdt_ping(void)
136{
137 /* Write a watchdog value */
138 outb_p(wd_margin, WDT_START);
139}
140
141static ssize_t
142ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
143{
144 if (count) {
145 if (!nowayout) {
146 size_t i;
147
148 /* In case it was set long ago */
149 expect_close = 0;
150
151 for (i = 0; i != count; i++) {
152 char c;
153 if (get_user(c, buf + i))
154 return -EFAULT;
155 if (c == 'V')
156 expect_close = 42;
157 }
158 }
159 ibwdt_ping();
160 }
161 return count;
162}
163
164static int
165ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
166 unsigned long arg)
167{
168 int i, new_margin;
169 void __user *argp = (void __user *)arg;
170 int __user *p = argp;
171
172 static struct watchdog_info ident = {
173 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
174 .firmware_version = 1,
175 .identity = "IB700 WDT",
176 };
177
178 switch (cmd) {
179 case WDIOC_GETSUPPORT:
180 if (copy_to_user(argp, &ident, sizeof(ident)))
181 return -EFAULT;
182 break;
183
184 case WDIOC_GETSTATUS:
185 return put_user(0, p);
186
187 case WDIOC_KEEPALIVE:
188 ibwdt_ping();
189 break;
190
191 case WDIOC_SETTIMEOUT:
192 if (get_user(new_margin, p))
193 return -EFAULT;
194 if ((new_margin < 0) || (new_margin > 30))
195 return -EINVAL;
196 for (i = 0x0F; i > -1; i--)
197 if (wd_times[i] > new_margin)
198 break;
199 wd_margin = i;
200 ibwdt_ping();
201 /* Fall */
202
203 case WDIOC_GETTIMEOUT:
204 return put_user(wd_times[wd_margin], p);
205 break;
206
207 default:
208 return -ENOIOCTLCMD;
209 }
210 return 0;
211}
212
213static int
214ibwdt_open(struct inode *inode, struct file *file)
215{
216 spin_lock(&ibwdt_lock);
217 if (test_and_set_bit(0, &ibwdt_is_open)) {
218 spin_unlock(&ibwdt_lock);
219 return -EBUSY;
220 }
221 if (nowayout)
222 __module_get(THIS_MODULE);
223
224 /* Activate */
225 ibwdt_ping();
226 spin_unlock(&ibwdt_lock);
227 return nonseekable_open(inode, file);
228}
229
230static int
231ibwdt_close(struct inode *inode, struct file *file)
232{
233 spin_lock(&ibwdt_lock);
234 if (expect_close == 42)
235 outb_p(0, WDT_STOP);
236 else
237 printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
238
239 clear_bit(0, &ibwdt_is_open);
240 expect_close = 0;
241 spin_unlock(&ibwdt_lock);
242 return 0;
243}
244
245/*
246 * Notifier for system down
247 */
248
249static int
250ibwdt_notify_sys(struct notifier_block *this, unsigned long code,
251 void *unused)
252{
253 if (code == SYS_DOWN || code == SYS_HALT) {
254 /* Turn the WDT off */
255 outb_p(0, WDT_STOP);
256 }
257 return NOTIFY_DONE;
258}
259
260/*
261 * Kernel Interfaces
262 */
263
264static struct file_operations ibwdt_fops = {
265 .owner = THIS_MODULE,
266 .llseek = no_llseek,
267 .write = ibwdt_write,
268 .ioctl = ibwdt_ioctl,
269 .open = ibwdt_open,
270 .release = ibwdt_close,
271};
272
273static struct miscdevice ibwdt_miscdev = {
274 .minor = WATCHDOG_MINOR,
275 .name = "watchdog",
276 .fops = &ibwdt_fops,
277};
278
279/*
280 * The WDT needs to learn about soft shutdowns in order to
281 * turn the timebomb registers off.
282 */
283
284static struct notifier_block ibwdt_notifier = {
285 .notifier_call = ibwdt_notify_sys,
286};
287
288static int __init ibwdt_init(void)
289{
290 int res;
291
292 printk(KERN_INFO PFX "WDT driver for IB700 single board computer initialising.\n");
293
294 spin_lock_init(&ibwdt_lock);
295 res = misc_register(&ibwdt_miscdev);
296 if (res) {
297 printk (KERN_ERR PFX "failed to register misc device\n");
298 goto out_nomisc;
299 }
300
301#if WDT_START != WDT_STOP
302 if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
303 printk (KERN_ERR PFX "STOP method I/O %X is not available.\n", WDT_STOP);
304 res = -EIO;
305 goto out_nostopreg;
306 }
307#endif
308
309 if (!request_region(WDT_START, 1, "IB700 WDT")) {
310 printk (KERN_ERR PFX "START method I/O %X is not available.\n", WDT_START);
311 res = -EIO;
312 goto out_nostartreg;
313 }
314 res = register_reboot_notifier(&ibwdt_notifier);
315 if (res) {
316 printk (KERN_ERR PFX "Failed to register reboot notifier.\n");
317 goto out_noreboot;
318 }
319 return 0;
320
321out_noreboot:
322 release_region(WDT_START, 1);
323out_nostartreg:
324#if WDT_START != WDT_STOP
325 release_region(WDT_STOP, 1);
326#endif
327out_nostopreg:
328 misc_deregister(&ibwdt_miscdev);
329out_nomisc:
330 return res;
331}
332
333static void __exit
334ibwdt_exit(void)
335{
336 misc_deregister(&ibwdt_miscdev);
337 unregister_reboot_notifier(&ibwdt_notifier);
338#if WDT_START != WDT_STOP
339 release_region(WDT_STOP,1);
340#endif
341 release_region(WDT_START,1);
342}
343
344module_init(ibwdt_init);
345module_exit(ibwdt_exit);
346
347MODULE_AUTHOR("Charles Howes <chowes@vsol.net>");
348MODULE_DESCRIPTION("IB700 SBC watchdog driver");
349MODULE_LICENSE("GPL");
350MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
351
352/* end of ib700wdt.c */
diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c
new file mode 100644
index 000000000000..6af2c799b57e
--- /dev/null
+++ b/drivers/char/watchdog/indydog.c
@@ -0,0 +1,221 @@
1/*
2 * IndyDog 0.3 A Hardware Watchdog Device for SGI IP22
3 *
4 * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * based on softdog.c by Alan Cox <alan@redhat.com>
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/config.h>
17#include <linux/types.h>
18#include <linux/kernel.h>
19#include <linux/fs.h>
20#include <linux/mm.h>
21#include <linux/miscdevice.h>
22#include <linux/watchdog.h>
23#include <linux/notifier.h>
24#include <linux/reboot.h>
25#include <linux/init.h>
26#include <asm/uaccess.h>
27#include <asm/sgi/mc.h>
28
29#define PFX "indydog: "
30static int indydog_alive;
31
32#ifdef CONFIG_WATCHDOG_NOWAYOUT
33static int nowayout = 1;
34#else
35static int nowayout = 0;
36#endif
37
38#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
39
40module_param(nowayout, int, 0);
41MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
42
43static void indydog_start(void)
44{
45 u32 mc_ctrl0 = sgimc->cpuctrl0;
46
47 mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
48 sgimc->cpuctrl0 = mc_ctrl0;
49}
50
51static void indydog_stop(void)
52{
53 u32 mc_ctrl0 = sgimc->cpuctrl0;
54
55 mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
56 sgimc->cpuctrl0 = mc_ctrl0;
57
58 printk(KERN_INFO PFX "Stopped watchdog timer.\n");
59}
60
61static void indydog_ping(void)
62{
63 sgimc->watchdogt = 0;
64}
65
66/*
67 * Allow only one person to hold it open
68 */
69static int indydog_open(struct inode *inode, struct file *file)
70{
71 if (indydog_alive)
72 return -EBUSY;
73
74 if (nowayout)
75 __module_get(THIS_MODULE);
76
77 /* Activate timer */
78 indydog_start();
79 indydog_ping();
80
81 indydog_alive = 1;
82 printk(KERN_INFO "Started watchdog timer.\n");
83
84 return nonseekable_open(inode, file);
85}
86
87static int indydog_release(struct inode *inode, struct file *file)
88{
89 /* Shut off the timer.
90 * Lock it in if it's a module and we defined ...NOWAYOUT */
91 if (!nowayout)
92 indydog_stop(); /* Turn the WDT off */
93
94 indydog_alive = 0;
95
96 return 0;
97}
98
99static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
100{
101 /* Refresh the timer. */
102 if (len) {
103 indydog_ping();
104 }
105 return len;
106}
107
108static int indydog_ioctl(struct inode *inode, struct file *file,
109 unsigned int cmd, unsigned long arg)
110{
111 int options, retval = -EINVAL;
112 static struct watchdog_info ident = {
113 .options = WDIOF_KEEPALIVEPING |
114 WDIOF_MAGICCLOSE,
115 .firmware_version = 0,
116 .identity = "Hardware Watchdog for SGI IP22",
117 };
118
119 switch (cmd) {
120 default:
121 return -ENOIOCTLCMD;
122 case WDIOC_GETSUPPORT:
123 if (copy_to_user((struct watchdog_info *)arg,
124 &ident, sizeof(ident)))
125 return -EFAULT;
126 return 0;
127 case WDIOC_GETSTATUS:
128 case WDIOC_GETBOOTSTATUS:
129 return put_user(0,(int *)arg);
130 case WDIOC_KEEPALIVE:
131 indydog_ping();
132 return 0;
133 case WDIOC_GETTIMEOUT:
134 return put_user(WATCHDOG_TIMEOUT,(int *)arg);
135 case WDIOC_SETOPTIONS:
136 {
137 if (get_user(options, (int *)arg))
138 return -EFAULT;
139
140 if (options & WDIOS_DISABLECARD) {
141 indydog_stop();
142 retval = 0;
143 }
144
145 if (options & WDIOS_ENABLECARD) {
146 indydog_start();
147 retval = 0;
148 }
149
150 return retval;
151 }
152 }
153}
154
155static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
156{
157 if (code == SYS_DOWN || code == SYS_HALT)
158 indydog_stop(); /* Turn the WDT off */
159
160 return NOTIFY_DONE;
161}
162
163static struct file_operations indydog_fops = {
164 .owner = THIS_MODULE,
165 .llseek = no_llseek,
166 .write = indydog_write,
167 .ioctl = indydog_ioctl,
168 .open = indydog_open,
169 .release = indydog_release,
170};
171
172static struct miscdevice indydog_miscdev = {
173 .minor = WATCHDOG_MINOR,
174 .name = "watchdog",
175 .fops = &indydog_fops,
176};
177
178static struct notifier_block indydog_notifier = {
179 .notifier_call = indydog_notify_sys,
180};
181
182static char banner[] __initdata =
183 KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
184
185static int __init watchdog_init(void)
186{
187 int ret;
188
189 ret = register_reboot_notifier(&indydog_notifier);
190 if (ret) {
191 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
192 ret);
193 return ret;
194 }
195
196 ret = misc_register(&indydog_miscdev);
197 if (ret) {
198 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
199 WATCHDOG_MINOR, ret);
200 unregister_reboot_notifier(&indydog_notifier);
201 return ret;
202 }
203
204 printk(banner);
205
206 return 0;
207}
208
209static void __exit watchdog_exit(void)
210{
211 misc_deregister(&indydog_miscdev);
212 unregister_reboot_notifier(&indydog_notifier);
213}
214
215module_init(watchdog_init);
216module_exit(watchdog_exit);
217
218MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
219MODULE_DESCRIPTION("Hardware Watchdog Device for SGI IP22");
220MODULE_LICENSE("GPL");
221MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
new file mode 100644
index 000000000000..ab659d37b4d2
--- /dev/null
+++ b/drivers/char/watchdog/ixp2000_wdt.c
@@ -0,0 +1,219 @@
1/*
2 * drivers/watchdog/ixp2000_wdt.c
3 *
4 * Watchdog driver for Intel IXP2000 network processors
5 *
6 * Adapted from the IXP4xx watchdog driver by Lennert Buytenhek.
7 * The original version carries these notices:
8 *
9 * Author: Deepak Saxena <dsaxena@plexity.net>
10 *
11 * Copyright 2004 (c) MontaVista, Software, Inc.
12 * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
13 *
14 * This file is licensed under the terms of the GNU General Public
15 * License version 2. This program is licensed "as is" without any
16 * warranty of any kind, whether express or implied.
17 */
18
19#include <linux/config.h>
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/types.h>
23#include <linux/kernel.h>
24#include <linux/fs.h>
25#include <linux/miscdevice.h>
26#include <linux/watchdog.h>
27#include <linux/init.h>
28#include <linux/bitops.h>
29
30#include <asm/hardware.h>
31#include <asm/uaccess.h>
32
33#ifdef CONFIG_WATCHDOG_NOWAYOUT
34static int nowayout = 1;
35#else
36static int nowayout = 0;
37#endif
38static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */
39static unsigned long wdt_status;
40
41#define WDT_IN_USE 0
42#define WDT_OK_TO_CLOSE 1
43
44static unsigned long wdt_tick_rate;
45
46static void
47wdt_enable(void)
48{
49 ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
50 ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
51 ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
52 ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
53}
54
55static void
56wdt_disable(void)
57{
58 ixp2000_reg_write(IXP2000_T4_CTL, 0);
59}
60
61static void
62wdt_keepalive(void)
63{
64 ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
65}
66
67static int
68ixp2000_wdt_open(struct inode *inode, struct file *file)
69{
70 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
71 return -EBUSY;
72
73 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
74
75 wdt_enable();
76
77 return nonseekable_open(inode, file);
78}
79
80static ssize_t
81ixp2000_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
82{
83 if (len) {
84 if (!nowayout) {
85 size_t i;
86
87 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
88
89 for (i = 0; i != len; i++) {
90 char c;
91
92 if (get_user(c, data + i))
93 return -EFAULT;
94 if (c == 'V')
95 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
96 }
97 }
98 wdt_keepalive();
99 }
100
101 return len;
102}
103
104
105static struct watchdog_info ident = {
106 .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
107 WDIOF_KEEPALIVEPING,
108 .identity = "IXP2000 Watchdog",
109};
110
111static int
112ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
113 unsigned long arg)
114{
115 int ret = -ENOIOCTLCMD;
116 int time;
117
118 switch (cmd) {
119 case WDIOC_GETSUPPORT:
120 ret = copy_to_user((struct watchdog_info *)arg, &ident,
121 sizeof(ident)) ? -EFAULT : 0;
122 break;
123
124 case WDIOC_GETSTATUS:
125 ret = put_user(0, (int *)arg);
126 break;
127
128 case WDIOC_GETBOOTSTATUS:
129 ret = put_user(0, (int *)arg);
130 break;
131
132 case WDIOC_SETTIMEOUT:
133 ret = get_user(time, (int *)arg);
134 if (ret)
135 break;
136
137 if (time <= 0 || time > 60) {
138 ret = -EINVAL;
139 break;
140 }
141
142 heartbeat = time;
143 wdt_keepalive();
144 /* Fall through */
145
146 case WDIOC_GETTIMEOUT:
147 ret = put_user(heartbeat, (int *)arg);
148 break;
149
150 case WDIOC_KEEPALIVE:
151 wdt_enable();
152 ret = 0;
153 break;
154 }
155
156 return ret;
157}
158
159static int
160ixp2000_wdt_release(struct inode *inode, struct file *file)
161{
162 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
163 wdt_disable();
164 } else {
165 printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
166 "timer will not stop\n");
167 }
168
169 clear_bit(WDT_IN_USE, &wdt_status);
170 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
171
172 return 0;
173}
174
175
176static struct file_operations ixp2000_wdt_fops =
177{
178 .owner = THIS_MODULE,
179 .llseek = no_llseek,
180 .write = ixp2000_wdt_write,
181 .ioctl = ixp2000_wdt_ioctl,
182 .open = ixp2000_wdt_open,
183 .release = ixp2000_wdt_release,
184};
185
186static struct miscdevice ixp2000_wdt_miscdev =
187{
188 .minor = WATCHDOG_MINOR,
189 .name = "IXP2000 Watchdog",
190 .fops = &ixp2000_wdt_fops,
191};
192
193static int __init ixp2000_wdt_init(void)
194{
195 wdt_tick_rate = (*IXP2000_T1_CLD * HZ)/ 256;;
196
197 return misc_register(&ixp2000_wdt_miscdev);
198}
199
200static void __exit ixp2000_wdt_exit(void)
201{
202 misc_deregister(&ixp2000_wdt_miscdev);
203}
204
205module_init(ixp2000_wdt_init);
206module_exit(ixp2000_wdt_exit);
207
208MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net">);
209MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
210
211module_param(heartbeat, int, 0);
212MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
213
214module_param(nowayout, int, 0);
215MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
216
217MODULE_LICENSE("GPL");
218MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
219
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c
new file mode 100644
index 000000000000..82396e06c8a8
--- /dev/null
+++ b/drivers/char/watchdog/ixp4xx_wdt.c
@@ -0,0 +1,230 @@
1/*
2 * drivers/watchdog/ixp4xx_wdt.c
3 *
4 * Watchdog driver for Intel IXP4xx network processors
5 *
6 * Author: Deepak Saxena <dsaxena@plexity.net>
7 *
8 * Copyright 2004 (c) MontaVista, Software, Inc.
9 * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
10 *
11 * This file is licensed under the terms of the GNU General Public
12 * License version 2. This program is licensed "as is" without any
13 * warranty of any kind, whether express or implied.
14 */
15
16#include <linux/config.h>
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/types.h>
20#include <linux/kernel.h>
21#include <linux/fs.h>
22#include <linux/miscdevice.h>
23#include <linux/watchdog.h>
24#include <linux/init.h>
25#include <linux/bitops.h>
26
27#include <asm/hardware.h>
28#include <asm/uaccess.h>
29
30#ifdef CONFIG_WATCHDOG_NOWAYOUT
31static int nowayout = 1;
32#else
33static int nowayout = 0;
34#endif
35static int heartbeat = 60; /* (secs) Default is 1 minute */
36static unsigned long wdt_status;
37static unsigned long boot_status;
38
39#define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL)
40
41#define WDT_IN_USE 0
42#define WDT_OK_TO_CLOSE 1
43
44static void
45wdt_enable(void)
46{
47 *IXP4XX_OSWK = IXP4XX_WDT_KEY;
48 *IXP4XX_OSWE = 0;
49 *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat;
50 *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
51 *IXP4XX_OSWK = 0;
52}
53
54static void
55wdt_disable(void)
56{
57 *IXP4XX_OSWK = IXP4XX_WDT_KEY;
58 *IXP4XX_OSWE = 0;
59 *IXP4XX_OSWK = 0;
60}
61
62static int
63ixp4xx_wdt_open(struct inode *inode, struct file *file)
64{
65 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
66 return -EBUSY;
67
68 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
69
70 wdt_enable();
71
72 return nonseekable_open(inode, file);
73}
74
75static ssize_t
76ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
77{
78 if (len) {
79 if (!nowayout) {
80 size_t i;
81
82 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
83
84 for (i = 0; i != len; i++) {
85 char c;
86
87 if (get_user(c, data + i))
88 return -EFAULT;
89 if (c == 'V')
90 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
91 }
92 }
93 wdt_enable();
94 }
95
96 return len;
97}
98
99static struct watchdog_info ident = {
100 .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
101 WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
102 .identity = "IXP4xx Watchdog",
103};
104
105
106static int
107ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
108 unsigned long arg)
109{
110 int ret = -ENOIOCTLCMD;
111 int time;
112
113 switch (cmd) {
114 case WDIOC_GETSUPPORT:
115 ret = copy_to_user((struct watchdog_info *)arg, &ident,
116 sizeof(ident)) ? -EFAULT : 0;
117 break;
118
119 case WDIOC_GETSTATUS:
120 ret = put_user(0, (int *)arg);
121 break;
122
123 case WDIOC_GETBOOTSTATUS:
124 ret = put_user(boot_status, (int *)arg);
125 break;
126
127 case WDIOC_SETTIMEOUT:
128 ret = get_user(time, (int *)arg);
129 if (ret)
130 break;
131
132 if (time <= 0 || time > 60) {
133 ret = -EINVAL;
134 break;
135 }
136
137 heartbeat = time;
138 wdt_enable();
139 /* Fall through */
140
141 case WDIOC_GETTIMEOUT:
142 ret = put_user(heartbeat, (int *)arg);
143 break;
144
145 case WDIOC_KEEPALIVE:
146 wdt_enable();
147 ret = 0;
148 break;
149 }
150 return ret;
151}
152
153static int
154ixp4xx_wdt_release(struct inode *inode, struct file *file)
155{
156 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
157 wdt_disable();
158 } else {
159 printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
160 "timer will not stop\n");
161 }
162
163 clear_bit(WDT_IN_USE, &wdt_status);
164 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
165
166 return 0;
167}
168
169
170static struct file_operations ixp4xx_wdt_fops =
171{
172 .owner = THIS_MODULE,
173 .llseek = no_llseek,
174 .write = ixp4xx_wdt_write,
175 .ioctl = ixp4xx_wdt_ioctl,
176 .open = ixp4xx_wdt_open,
177 .release = ixp4xx_wdt_release,
178};
179
180static struct miscdevice ixp4xx_wdt_miscdev =
181{
182 .minor = WATCHDOG_MINOR,
183 .name = "IXP4xx Watchdog",
184 .fops = &ixp4xx_wdt_fops,
185};
186
187static int __init ixp4xx_wdt_init(void)
188{
189 int ret;
190 unsigned long processor_id;
191
192 asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
193 if (!(processor_id & 0xf)) {
194 printk("IXP4XXX Watchdog: Rev. A0 CPU detected - "
195 "watchdog disabled\n");
196
197 return -ENODEV;
198 }
199
200 ret = misc_register(&ixp4xx_wdt_miscdev);
201 if (ret == 0)
202 printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat);
203
204 boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ?
205 WDIOF_CARDRESET : 0;
206
207 return ret;
208}
209
210static void __exit ixp4xx_wdt_exit(void)
211{
212 misc_deregister(&ixp4xx_wdt_miscdev);
213}
214
215
216module_init(ixp4xx_wdt_init);
217module_exit(ixp4xx_wdt_exit);
218
219MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
220MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog");
221
222module_param(heartbeat, int, 0);
223MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
224
225module_param(nowayout, int, 0);
226MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
227
228MODULE_LICENSE("GPL");
229MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
230
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
new file mode 100644
index 000000000000..9da395fa7794
--- /dev/null
+++ b/drivers/char/watchdog/machzwd.c
@@ -0,0 +1,501 @@
1/*
2 * MachZ ZF-Logic Watchdog Timer driver for Linux
3 *
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * The author does NOT admit liability nor provide warranty for
11 * any of this software. This material is provided "AS-IS" in
12 * the hope that it may be useful for others.
13 *
14 * Author: Fernando Fuganti <fuganti@conectiva.com.br>
15 *
16 * Based on sbc60xxwdt.c by Jakob Oestergaard
17 *
18 *
19 * We have two timers (wd#1, wd#2) driven by a 32 KHz clock with the
20 * following periods:
21 * wd#1 - 2 seconds;
22 * wd#2 - 7.2 ms;
23 * After the expiration of wd#1, it can generate a NMI, SCI, SMI, or
24 * a system RESET and it starts wd#2 that unconditionaly will RESET
25 * the system when the counter reaches zero.
26 *
27 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
28 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
29 */
30
31#include <linux/config.h>
32#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/types.h>
35#include <linux/timer.h>
36#include <linux/jiffies.h>
37#include <linux/miscdevice.h>
38#include <linux/watchdog.h>
39#include <linux/fs.h>
40#include <linux/ioport.h>
41#include <linux/notifier.h>
42#include <linux/reboot.h>
43#include <linux/init.h>
44
45#include <asm/io.h>
46#include <asm/uaccess.h>
47#include <asm/system.h>
48
49/* ports */
50#define ZF_IOBASE 0x218
51#define INDEX 0x218
52#define DATA_B 0x219
53#define DATA_W 0x21A
54#define DATA_D 0x21A
55
56/* indexes */ /* size */
57#define ZFL_VERSION 0x02 /* 16 */
58#define CONTROL 0x10 /* 16 */
59#define STATUS 0x12 /* 8 */
60#define COUNTER_1 0x0C /* 16 */
61#define COUNTER_2 0x0E /* 8 */
62#define PULSE_LEN 0x0F /* 8 */
63
64/* controls */
65#define ENABLE_WD1 0x0001
66#define ENABLE_WD2 0x0002
67#define RESET_WD1 0x0010
68#define RESET_WD2 0x0020
69#define GEN_SCI 0x0100
70#define GEN_NMI 0x0200
71#define GEN_SMI 0x0400
72#define GEN_RESET 0x0800
73
74
75/* utilities */
76
77#define WD1 0
78#define WD2 1
79
80#define zf_writew(port, data) { outb(port, INDEX); outw(data, DATA_W); }
81#define zf_writeb(port, data) { outb(port, INDEX); outb(data, DATA_B); }
82#define zf_get_ZFL_version() zf_readw(ZFL_VERSION)
83
84
85static unsigned short zf_readw(unsigned char port)
86{
87 outb(port, INDEX);
88 return inw(DATA_W);
89}
90
91
92MODULE_AUTHOR("Fernando Fuganti <fuganti@conectiva.com.br>");
93MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver");
94MODULE_LICENSE("GPL");
95MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
96
97#ifdef CONFIG_WATCHDOG_NOWAYOUT
98static int nowayout = 1;
99#else
100static int nowayout = 0;
101#endif
102
103module_param(nowayout, int, 0);
104MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
105
106#define PFX "machzwd"
107
108static struct watchdog_info zf_info = {
109 .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
110 .firmware_version = 1,
111 .identity = "ZF-Logic watchdog",
112};
113
114
115/*
116 * action refers to action taken when watchdog resets
117 * 0 = GEN_RESET
118 * 1 = GEN_SMI
119 * 2 = GEN_NMI
120 * 3 = GEN_SCI
121 * defaults to GEN_RESET (0)
122 */
123static int action = 0;
124module_param(action, int, 0);
125MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI");
126
127static int zf_action = GEN_RESET;
128static unsigned long zf_is_open;
129static char zf_expect_close;
130static spinlock_t zf_lock;
131static spinlock_t zf_port_lock;
132static struct timer_list zf_timer;
133static unsigned long next_heartbeat = 0;
134
135
136/* timeout for user land heart beat (10 seconds) */
137#define ZF_USER_TIMEO (HZ*10)
138
139/* timeout for hardware watchdog (~500ms) */
140#define ZF_HW_TIMEO (HZ/2)
141
142/* number of ticks on WD#1 (driven by a 32KHz clock, 2s) */
143#define ZF_CTIMEOUT 0xffff
144
145#ifndef ZF_DEBUG
146# define dprintk(format, args...)
147#else
148# define dprintk(format, args...) printk(KERN_DEBUG PFX ":%s:%d: " format, __FUNCTION__, __LINE__ , ## args)
149#endif
150
151
152static inline void zf_set_status(unsigned char new)
153{
154 zf_writeb(STATUS, new);
155}
156
157
158/* CONTROL register functions */
159
160static inline unsigned short zf_get_control(void)
161{
162 return zf_readw(CONTROL);
163}
164
165static inline void zf_set_control(unsigned short new)
166{
167 zf_writew(CONTROL, new);
168}
169
170
171/* WD#? counter functions */
172/*
173 * Just set counter value
174 */
175
176static inline void zf_set_timer(unsigned short new, unsigned char n)
177{
178 switch(n){
179 case WD1:
180 zf_writew(COUNTER_1, new);
181 case WD2:
182 zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
183 default:
184 return;
185 }
186}
187
188/*
189 * stop hardware timer
190 */
191static void zf_timer_off(void)
192{
193 unsigned int ctrl_reg = 0;
194 unsigned long flags;
195
196 /* stop internal ping */
197 del_timer_sync(&zf_timer);
198
199 spin_lock_irqsave(&zf_port_lock, flags);
200 /* stop watchdog timer */
201 ctrl_reg = zf_get_control();
202 ctrl_reg |= (ENABLE_WD1|ENABLE_WD2); /* disable wd1 and wd2 */
203 ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2);
204 zf_set_control(ctrl_reg);
205 spin_unlock_irqrestore(&zf_port_lock, flags);
206
207 printk(KERN_INFO PFX ": Watchdog timer is now disabled\n");
208}
209
210
211/*
212 * start hardware timer
213 */
214static void zf_timer_on(void)
215{
216 unsigned int ctrl_reg = 0;
217 unsigned long flags;
218
219 spin_lock_irqsave(&zf_port_lock, flags);
220
221 zf_writeb(PULSE_LEN, 0xff);
222
223 zf_set_timer(ZF_CTIMEOUT, WD1);
224
225 /* user land ping */
226 next_heartbeat = jiffies + ZF_USER_TIMEO;
227
228 /* start the timer for internal ping */
229 zf_timer.expires = jiffies + ZF_HW_TIMEO;
230
231 add_timer(&zf_timer);
232
233 /* start watchdog timer */
234 ctrl_reg = zf_get_control();
235 ctrl_reg |= (ENABLE_WD1|zf_action);
236 zf_set_control(ctrl_reg);
237 spin_unlock_irqrestore(&zf_port_lock, flags);
238
239 printk(KERN_INFO PFX ": Watchdog timer is now enabled\n");
240}
241
242
243static void zf_ping(unsigned long data)
244{
245 unsigned int ctrl_reg = 0;
246 unsigned long flags;
247
248 zf_writeb(COUNTER_2, 0xff);
249
250 if(time_before(jiffies, next_heartbeat)){
251
252 dprintk("time_before: %ld\n", next_heartbeat - jiffies);
253
254 /*
255 * reset event is activated by transition from 0 to 1 on
256 * RESET_WD1 bit and we assume that it is already zero...
257 */
258
259 spin_lock_irqsave(&zf_port_lock, flags);
260 ctrl_reg = zf_get_control();
261 ctrl_reg |= RESET_WD1;
262 zf_set_control(ctrl_reg);
263
264 /* ...and nothing changes until here */
265 ctrl_reg &= ~(RESET_WD1);
266 zf_set_control(ctrl_reg);
267 spin_unlock_irqrestore(&zf_port_lock, flags);
268
269 zf_timer.expires = jiffies + ZF_HW_TIMEO;
270 add_timer(&zf_timer);
271 }else{
272 printk(KERN_CRIT PFX ": I will reset your machine\n");
273 }
274}
275
276static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
277 loff_t *ppos)
278{
279 /* See if we got the magic character */
280 if(count){
281
282 /*
283 * no need to check for close confirmation
284 * no way to disable watchdog ;)
285 */
286 if (!nowayout) {
287 size_t ofs;
288
289 /*
290 * note: just in case someone wrote the magic character
291 * five months ago...
292 */
293 zf_expect_close = 0;
294
295 /* now scan */
296 for (ofs = 0; ofs != count; ofs++){
297 char c;
298 if (get_user(c, buf + ofs))
299 return -EFAULT;
300 if (c == 'V'){
301 zf_expect_close = 42;
302 dprintk("zf_expect_close = 42\n");
303 }
304 }
305 }
306
307 /*
308 * Well, anyhow someone wrote to us,
309 * we should return that favour
310 */
311 next_heartbeat = jiffies + ZF_USER_TIMEO;
312 dprintk("user ping at %ld\n", jiffies);
313
314 }
315
316 return count;
317}
318
319static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
320 unsigned long arg)
321{
322 void __user *argp = (void __user *)arg;
323 int __user *p = argp;
324 switch(cmd){
325 case WDIOC_GETSUPPORT:
326 if (copy_to_user(argp, &zf_info, sizeof(zf_info)))
327 return -EFAULT;
328 break;
329
330 case WDIOC_GETSTATUS:
331 return put_user(0, p);
332
333 case WDIOC_KEEPALIVE:
334 zf_ping(0);
335 break;
336
337 default:
338 return -ENOIOCTLCMD;
339 }
340
341 return 0;
342}
343
344static int zf_open(struct inode *inode, struct file *file)
345{
346 spin_lock(&zf_lock);
347 if(test_and_set_bit(0, &zf_is_open)) {
348 spin_unlock(&zf_lock);
349 return -EBUSY;
350 }
351
352 if (nowayout)
353 __module_get(THIS_MODULE);
354
355 spin_unlock(&zf_lock);
356
357 zf_timer_on();
358
359 return nonseekable_open(inode, file);
360}
361
362static int zf_close(struct inode *inode, struct file *file)
363{
364 if(zf_expect_close == 42){
365 zf_timer_off();
366 } else {
367 del_timer(&zf_timer);
368 printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n");
369 }
370
371 spin_lock(&zf_lock);
372 clear_bit(0, &zf_is_open);
373 spin_unlock(&zf_lock);
374
375 zf_expect_close = 0;
376
377 return 0;
378}
379
380/*
381 * Notifier for system down
382 */
383
384static int zf_notify_sys(struct notifier_block *this, unsigned long code,
385 void *unused)
386{
387 if(code == SYS_DOWN || code == SYS_HALT){
388 zf_timer_off();
389 }
390
391 return NOTIFY_DONE;
392}
393
394
395
396
397static struct file_operations zf_fops = {
398 .owner = THIS_MODULE,
399 .llseek = no_llseek,
400 .write = zf_write,
401 .ioctl = zf_ioctl,
402 .open = zf_open,
403 .release = zf_close,
404};
405
406static struct miscdevice zf_miscdev = {
407 .minor = WATCHDOG_MINOR,
408 .name = "watchdog",
409 .fops = &zf_fops,
410};
411
412
413/*
414 * The device needs to learn about soft shutdowns in order to
415 * turn the timebomb registers off.
416 */
417static struct notifier_block zf_notifier = {
418 .notifier_call = zf_notify_sys,
419};
420
421static void __init zf_show_action(int act)
422{
423 char *str[] = { "RESET", "SMI", "NMI", "SCI" };
424
425 printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]);
426}
427
428static int __init zf_init(void)
429{
430 int ret;
431
432 printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n");
433
434 ret = zf_get_ZFL_version();
435 printk("%#x\n", ret);
436 if((!ret) || (ret != 0xffff)){
437 printk(KERN_WARNING PFX ": no ZF-Logic found\n");
438 return -ENODEV;
439 }
440
441 if((action <= 3) && (action >= 0)){
442 zf_action = zf_action>>action;
443 } else
444 action = 0;
445
446 zf_show_action(action);
447
448 spin_lock_init(&zf_lock);
449 spin_lock_init(&zf_port_lock);
450
451 ret = misc_register(&zf_miscdev);
452 if (ret){
453 printk(KERN_ERR "can't misc_register on minor=%d\n",
454 WATCHDOG_MINOR);
455 goto out;
456 }
457
458 if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){
459 printk(KERN_ERR "cannot reserve I/O ports at %d\n",
460 ZF_IOBASE);
461 ret = -EBUSY;
462 goto no_region;
463 }
464
465 ret = register_reboot_notifier(&zf_notifier);
466 if(ret){
467 printk(KERN_ERR "can't register reboot notifier (err=%d)\n",
468 ret);
469 goto no_reboot;
470 }
471
472 zf_set_status(0);
473 zf_set_control(0);
474
475 /* this is the timer that will do the hard work */
476 init_timer(&zf_timer);
477 zf_timer.function = zf_ping;
478 zf_timer.data = 0;
479
480 return 0;
481
482no_reboot:
483 release_region(ZF_IOBASE, 3);
484no_region:
485 misc_deregister(&zf_miscdev);
486out:
487 return ret;
488}
489
490
491static void __exit zf_exit(void)
492{
493 zf_timer_off();
494
495 misc_deregister(&zf_miscdev);
496 unregister_reboot_notifier(&zf_notifier);
497 release_region(ZF_IOBASE, 3);
498}
499
500module_init(zf_init);
501module_exit(zf_exit);
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
new file mode 100644
index 000000000000..3143e4a07535
--- /dev/null
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -0,0 +1,306 @@
1/*
2 * MixCom Watchdog: A Simple Hardware Watchdog Device
3 * Based on Softdog driver by Alan Cox and PC Watchdog driver by Ken Hollis
4 *
5 * Author: Gergely Madarasz <gorgo@itc.hu>
6 *
7 * Copyright (c) 1999 ITConsult-Pro Co. <info@itc.hu>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 *
14 * Version 0.1 (99/04/15):
15 * - first version
16 *
17 * Version 0.2 (99/06/16):
18 * - added kernel timer watchdog ping after close
19 * since the hardware does not support watchdog shutdown
20 *
21 * Version 0.3 (99/06/21):
22 * - added WDIOC_GETSTATUS and WDIOC_GETSUPPORT ioctl calls
23 *
24 * Version 0.3.1 (99/06/22):
25 * - allow module removal while internal timer is active,
26 * print warning about probable reset
27 *
28 * Version 0.4 (99/11/15):
29 * - support for one more type board
30 *
31 * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
32 * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
33 *
34 */
35
36#define VERSION "0.5"
37
38#include <linux/module.h>
39#include <linux/moduleparam.h>
40#include <linux/config.h>
41#include <linux/types.h>
42#include <linux/miscdevice.h>
43#include <linux/ioport.h>
44#include <linux/watchdog.h>
45#include <linux/fs.h>
46#include <linux/reboot.h>
47#include <linux/init.h>
48#include <asm/uaccess.h>
49#include <asm/io.h>
50
51static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 };
52
53#define MIXCOM_WATCHDOG_OFFSET 0xc10
54#define MIXCOM_ID 0x11
55#define FLASHCOM_WATCHDOG_OFFSET 0x4
56#define FLASHCOM_ID 0x18
57
58static unsigned long mixcomwd_opened; /* long req'd for setbit --RR */
59
60static int watchdog_port;
61static int mixcomwd_timer_alive;
62static struct timer_list mixcomwd_timer = TIMER_INITIALIZER(NULL, 0, 0);
63static char expect_close;
64
65#ifdef CONFIG_WATCHDOG_NOWAYOUT
66static int nowayout = 1;
67#else
68static int nowayout = 0;
69#endif
70
71module_param(nowayout, int, 0);
72MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
73
74static void mixcomwd_ping(void)
75{
76 outb_p(55,watchdog_port);
77 return;
78}
79
80static void mixcomwd_timerfun(unsigned long d)
81{
82 mixcomwd_ping();
83
84 mod_timer(&mixcomwd_timer,jiffies+ 5*HZ);
85}
86
87/*
88 * Allow only one person to hold it open
89 */
90
91static int mixcomwd_open(struct inode *inode, struct file *file)
92{
93 if(test_and_set_bit(0,&mixcomwd_opened)) {
94 return -EBUSY;
95 }
96 mixcomwd_ping();
97
98 if (nowayout) {
99 /*
100 * fops_get() code via open() has already done
101 * a try_module_get() so it is safe to do the
102 * __module_get().
103 */
104 __module_get(THIS_MODULE);
105 } else {
106 if(mixcomwd_timer_alive) {
107 del_timer(&mixcomwd_timer);
108 mixcomwd_timer_alive=0;
109 }
110 }
111 return nonseekable_open(inode, file);
112}
113
114static int mixcomwd_release(struct inode *inode, struct file *file)
115{
116 if (expect_close == 42) {
117 if(mixcomwd_timer_alive) {
118 printk(KERN_ERR "mixcomwd: release called while internal timer alive");
119 return -EBUSY;
120 }
121 init_timer(&mixcomwd_timer);
122 mixcomwd_timer.expires=jiffies + 5 * HZ;
123 mixcomwd_timer.function=mixcomwd_timerfun;
124 mixcomwd_timer.data=0;
125 mixcomwd_timer_alive=1;
126 add_timer(&mixcomwd_timer);
127 } else {
128 printk(KERN_CRIT "mixcomwd: WDT device closed unexpectedly. WDT will not stop!\n");
129 }
130
131 clear_bit(0,&mixcomwd_opened);
132 expect_close=0;
133 return 0;
134}
135
136
137static ssize_t mixcomwd_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
138{
139 if(len)
140 {
141 if (!nowayout) {
142 size_t i;
143
144 /* In case it was set long ago */
145 expect_close = 0;
146
147 for (i = 0; i != len; i++) {
148 char c;
149 if (get_user(c, data + i))
150 return -EFAULT;
151 if (c == 'V')
152 expect_close = 42;
153 }
154 }
155 mixcomwd_ping();
156 }
157 return len;
158}
159
160static int mixcomwd_ioctl(struct inode *inode, struct file *file,
161 unsigned int cmd, unsigned long arg)
162{
163 void __user *argp = (void __user *)arg;
164 int __user *p = argp;
165 int status;
166 static struct watchdog_info ident = {
167 .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
168 .firmware_version = 1,
169 .identity = "MixCOM watchdog",
170 };
171
172 switch(cmd)
173 {
174 case WDIOC_GETSTATUS:
175 status=mixcomwd_opened;
176 if (!nowayout) {
177 status|=mixcomwd_timer_alive;
178 }
179 if (copy_to_user(p, &status, sizeof(int))) {
180 return -EFAULT;
181 }
182 break;
183 case WDIOC_GETSUPPORT:
184 if (copy_to_user(argp, &ident, sizeof(ident))) {
185 return -EFAULT;
186 }
187 break;
188 case WDIOC_KEEPALIVE:
189 mixcomwd_ping();
190 break;
191 default:
192 return -ENOIOCTLCMD;
193 }
194 return 0;
195}
196
197static struct file_operations mixcomwd_fops=
198{
199 .owner = THIS_MODULE,
200 .llseek = no_llseek,
201 .write = mixcomwd_write,
202 .ioctl = mixcomwd_ioctl,
203 .open = mixcomwd_open,
204 .release = mixcomwd_release,
205};
206
207static struct miscdevice mixcomwd_miscdev=
208{
209 .minor = WATCHDOG_MINOR,
210 .name = "watchdog",
211 .fops = &mixcomwd_fops,
212};
213
214static int __init mixcomwd_checkcard(int port)
215{
216 int id;
217
218 port += MIXCOM_WATCHDOG_OFFSET;
219 if (!request_region(port, 1, "MixCOM watchdog")) {
220 return 0;
221 }
222
223 id=inb_p(port) & 0x3f;
224 if(id!=MIXCOM_ID) {
225 release_region(port, 1);
226 return 0;
227 }
228 return port;
229}
230
231static int __init flashcom_checkcard(int port)
232{
233 int id;
234
235 port += FLASHCOM_WATCHDOG_OFFSET;
236 if (!request_region(port, 1, "MixCOM watchdog")) {
237 return 0;
238 }
239
240 id=inb_p(port);
241 if(id!=FLASHCOM_ID) {
242 release_region(port, 1);
243 return 0;
244 }
245 return port;
246 }
247
248static int __init mixcomwd_init(void)
249{
250 int i;
251 int ret;
252 int found=0;
253
254 for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) {
255 watchdog_port = mixcomwd_checkcard(mixcomwd_ioports[i]);
256 if (watchdog_port) {
257 found = 1;
258 }
259 }
260
261 /* The FlashCOM card can be set up at 0x300 -> 0x378, in 0x8 jumps */
262 for (i = 0x300; !found && i < 0x380; i+=0x8) {
263 watchdog_port = flashcom_checkcard(i);
264 if (watchdog_port) {
265 found = 1;
266 }
267 }
268
269 if (!found) {
270 printk("mixcomwd: No card detected, or port not available.\n");
271 return -ENODEV;
272 }
273
274 ret = misc_register(&mixcomwd_miscdev);
275 if (ret)
276 {
277 release_region(watchdog_port, 1);
278 return ret;
279 }
280
281 printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port);
282
283 return 0;
284}
285
286static void __exit mixcomwd_exit(void)
287{
288 if (!nowayout) {
289 if(mixcomwd_timer_alive) {
290 printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
291 " probably reboot!\n");
292 del_timer(&mixcomwd_timer);
293 mixcomwd_timer_alive=0;
294 }
295 }
296 release_region(watchdog_port,1);
297 misc_deregister(&mixcomwd_miscdev);
298}
299
300module_init(mixcomwd_init);
301module_exit(mixcomwd_exit);
302
303MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
304MODULE_DESCRIPTION("MixCom Watchdog driver");
305MODULE_LICENSE("GPL");
306MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
new file mode 100644
index 000000000000..56d62ba7c6ce
--- /dev/null
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -0,0 +1,164 @@
1/*
2 * mpc8xx_wdt.c - MPC8xx watchdog userspace interface
3 *
4 * Author: Florian Schirmer <jolt@tuxbox.org>
5 *
6 * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
9 * or implied.
10 */
11
12#include <linux/config.h>
13#include <linux/fs.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/miscdevice.h>
17#include <linux/module.h>
18#include <linux/watchdog.h>
19#include <asm/8xx_immap.h>
20#include <asm/uaccess.h>
21#include <syslib/m8xx_wdt.h>
22
23static unsigned long wdt_opened;
24static int wdt_status;
25
26static void mpc8xx_wdt_handler_disable(void)
27{
28 volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
29
30 imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE);
31
32 printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
33}
34
35static void mpc8xx_wdt_handler_enable(void)
36{
37 volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
38
39 imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE;
40
41 printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
42}
43
44static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
45{
46 if (test_and_set_bit(0, &wdt_opened))
47 return -EBUSY;
48
49 m8xx_wdt_reset();
50 mpc8xx_wdt_handler_disable();
51
52 return 0;
53}
54
55static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
56{
57 m8xx_wdt_reset();
58
59#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
60 mpc8xx_wdt_handler_enable();
61#endif
62
63 clear_bit(0, &wdt_opened);
64
65 return 0;
66}
67
68static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
69 loff_t * ppos)
70{
71 if (ppos != &file->f_pos)
72 return -ESPIPE;
73
74 if (len)
75 m8xx_wdt_reset();
76
77 return len;
78}
79
80static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
81 unsigned int cmd, unsigned long arg)
82{
83 int timeout;
84 static struct watchdog_info info = {
85 .options = WDIOF_KEEPALIVEPING,
86 .firmware_version = 0,
87 .identity = "MPC8xx watchdog",
88 };
89
90 switch (cmd) {
91 case WDIOC_GETSUPPORT:
92 if (copy_to_user((void *)arg, &info, sizeof(info)))
93 return -EFAULT;
94 break;
95
96 case WDIOC_GETSTATUS:
97 case WDIOC_GETBOOTSTATUS:
98 if (put_user(wdt_status, (int *)arg))
99 return -EFAULT;
100 wdt_status &= ~WDIOF_KEEPALIVEPING;
101 break;
102
103 case WDIOC_GETTEMP:
104 return -EOPNOTSUPP;
105
106 case WDIOC_SETOPTIONS:
107 return -EOPNOTSUPP;
108
109 case WDIOC_KEEPALIVE:
110 m8xx_wdt_reset();
111 wdt_status |= WDIOF_KEEPALIVEPING;
112 break;
113
114 case WDIOC_SETTIMEOUT:
115 return -EOPNOTSUPP;
116
117 case WDIOC_GETTIMEOUT:
118 timeout = m8xx_wdt_get_timeout();
119 if (put_user(timeout, (int *)arg))
120 return -EFAULT;
121 break;
122
123 default:
124 return -ENOIOCTLCMD;
125 }
126
127 return 0;
128}
129
130static struct file_operations mpc8xx_wdt_fops = {
131 .owner = THIS_MODULE,
132 .llseek = no_llseek,
133 .write = mpc8xx_wdt_write,
134 .ioctl = mpc8xx_wdt_ioctl,
135 .open = mpc8xx_wdt_open,
136 .release = mpc8xx_wdt_release,
137};
138
139static struct miscdevice mpc8xx_wdt_miscdev = {
140 .minor = WATCHDOG_MINOR,
141 .name = "watchdog",
142 .fops = &mpc8xx_wdt_fops,
143};
144
145static int __init mpc8xx_wdt_init(void)
146{
147 return misc_register(&mpc8xx_wdt_miscdev);
148}
149
150static void __exit mpc8xx_wdt_exit(void)
151{
152 misc_deregister(&mpc8xx_wdt_miscdev);
153
154 m8xx_wdt_reset();
155 mpc8xx_wdt_handler_enable();
156}
157
158module_init(mpc8xx_wdt_init);
159module_exit(mpc8xx_wdt_exit);
160
161MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
162MODULE_DESCRIPTION("MPC8xx watchdog driver");
163MODULE_LICENSE("GPL");
164MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
new file mode 100644
index 000000000000..592dca108866
--- /dev/null
+++ b/drivers/char/watchdog/pcwd.c
@@ -0,0 +1,926 @@
1/*
2 * PC Watchdog Driver
3 * by Ken Hollis (khollis@bitgate.com)
4 *
5 * Permission granted from Simon Machell (73244.1270@compuserve.com)
6 * Written for the Linux Kernel, and GPLed by Ken Hollis
7 *
8 * 960107 Added request_region routines, modulized the whole thing.
9 * 960108 Fixed end-of-file pointer (Thanks to Dan Hollis), added
10 * WD_TIMEOUT define.
11 * 960216 Added eof marker on the file, and changed verbose messages.
12 * 960716 Made functional and cosmetic changes to the source for
13 * inclusion in Linux 2.0.x kernels, thanks to Alan Cox.
14 * 960717 Removed read/seek routines, replaced with ioctl. Also, added
15 * check_region command due to Alan's suggestion.
16 * 960821 Made changes to compile in newer 2.0.x kernels. Added
17 * "cold reboot sense" entry.
18 * 960825 Made a few changes to code, deleted some defines and made
19 * typedefs to replace them. Made heartbeat reset only available
20 * via ioctl, and removed the write routine.
21 * 960828 Added new items for PC Watchdog Rev.C card.
22 * 960829 Changed around all of the IOCTLs, added new features,
23 * added watchdog disable/re-enable routines. Added firmware
24 * version reporting. Added read routine for temperature.
25 * Removed some extra defines, added an autodetect Revision
26 * routine.
27 * 961006 Revised some documentation, fixed some cosmetic bugs. Made
28 * drivers to panic the system if it's overheating at bootup.
29 * 961118 Changed some verbiage on some of the output, tidied up
30 * code bits, and added compatibility to 2.1.x.
31 * 970912 Enabled board on open and disable on close.
32 * 971107 Took account of recent VFS changes (broke read).
33 * 971210 Disable board on initialisation in case board already ticking.
34 * 971222 Changed open/close for temperature handling
35 * Michael Meskes <meskes@debian.org>.
36 * 980112 Used minor numbers from include/linux/miscdevice.h
37 * 990403 Clear reset status after reading control status register in
38 * pcwd_showprevstate(). [Marc Boucher <marc@mbsi.ca>]
39 * 990605 Made changes to code to support Firmware 1.22a, added
40 * fairly useless proc entry.
41 * 990610 removed said useless proc code for the merge <alan>
42 * 000403 Removed last traces of proc code. <davej>
43 * 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com>
44 * Added timeout module option to override default
45 */
46
47/*
48 * A bells and whistles driver is available from http://www.pcwd.de/
49 * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
50 */
51
52#include <linux/module.h>
53#include <linux/moduleparam.h>
54#include <linux/types.h>
55#include <linux/timer.h>
56#include <linux/jiffies.h>
57#include <linux/config.h>
58#include <linux/wait.h>
59#include <linux/slab.h>
60#include <linux/ioport.h>
61#include <linux/delay.h>
62#include <linux/fs.h>
63#include <linux/miscdevice.h>
64#include <linux/watchdog.h>
65#include <linux/notifier.h>
66#include <linux/init.h>
67#include <linux/spinlock.h>
68#include <linux/reboot.h>
69
70#include <asm/uaccess.h>
71#include <asm/io.h>
72
73#define WD_VER "1.16 (06/12/2004)"
74#define PFX "pcwd: "
75
76/*
77 * It should be noted that PCWD_REVISION_B was removed because A and B
78 * are essentially the same types of card, with the exception that B
79 * has temperature reporting. Since I didn't receive a Rev.B card,
80 * the Rev.B card is not supported. (It's a good thing too, as they
81 * are no longer in production.)
82 */
83#define PCWD_REVISION_A 1
84#define PCWD_REVISION_C 2
85
86/*
87 * These are the defines that describe the control status bits for the
88 * PC Watchdog card, revision A.
89 */
90#define WD_WDRST 0x01 /* Previously reset state */
91#define WD_T110 0x02 /* Temperature overheat sense */
92#define WD_HRTBT 0x04 /* Heartbeat sense */
93#define WD_RLY2 0x08 /* External relay triggered */
94#define WD_SRLY2 0x80 /* Software external relay triggered */
95
96/*
97 * These are the defines that describe the control status bits for the
98 * PC Watchdog card, revision C.
99 */
100#define WD_REVC_WTRP 0x01 /* Watchdog Trip status */
101#define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */
102#define WD_REVC_TTRP 0x04 /* Temperature Trip status */
103
104/* max. time we give an ISA watchdog card to process a command */
105/* 500ms for each 4 bit response (according to spec.) */
106#define ISA_COMMAND_TIMEOUT 1000
107
108/* Watchdog's internal commands */
109#define CMD_ISA_IDLE 0x00
110#define CMD_ISA_VERSION_INTEGER 0x01
111#define CMD_ISA_VERSION_TENTH 0x02
112#define CMD_ISA_VERSION_HUNDRETH 0x03
113#define CMD_ISA_VERSION_MINOR 0x04
114#define CMD_ISA_SWITCH_SETTINGS 0x05
115#define CMD_ISA_DELAY_TIME_2SECS 0x0A
116#define CMD_ISA_DELAY_TIME_4SECS 0x0B
117#define CMD_ISA_DELAY_TIME_8SECS 0x0C
118
119/*
120 * We are using an kernel timer to do the pinging of the watchdog
121 * every ~500ms. We try to set the internal heartbeat of the
122 * watchdog to 2 ms.
123 */
124
125#define WDT_INTERVAL (HZ/2+1)
126
127/* We can only use 1 card due to the /dev/watchdog restriction */
128static int cards_found;
129
130/* internal variables */
131static atomic_t open_allowed = ATOMIC_INIT(1);
132static char expect_close;
133static struct timer_list timer;
134static unsigned long next_heartbeat;
135static int temp_panic;
136static int revision; /* The card's revision */
137static int supports_temp; /* Wether or not the card has a temperature device */
138static int command_mode; /* Wether or not the card is in command mode */
139static int initial_status; /* The card's boot status */
140static int current_readport; /* The cards I/O address */
141static spinlock_t io_lock;
142
143/* module parameters */
144#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */
145static int heartbeat = WATCHDOG_HEARTBEAT;
146module_param(heartbeat, int, 0);
147MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
148
149#ifdef CONFIG_WATCHDOG_NOWAYOUT
150static int nowayout = 1;
151#else
152static int nowayout = 0;
153#endif
154
155module_param(nowayout, int, 0);
156MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
157
158/*
159 * Internal functions
160 */
161
162static int send_isa_command(int cmd)
163{
164 int i;
165 int control_status;
166 int port0, last_port0; /* Double read for stabilising */
167
168 /* The WCMD bit must be 1 and the command is only 4 bits in size */
169 control_status = (cmd & 0x0F) | 0x80;
170 outb_p(control_status, current_readport + 2);
171 udelay(ISA_COMMAND_TIMEOUT);
172
173 port0 = inb_p(current_readport);
174 for (i = 0; i < 25; ++i) {
175 last_port0 = port0;
176 port0 = inb_p(current_readport);
177
178 if (port0 == last_port0)
179 break; /* Data is stable */
180
181 udelay (250);
182 }
183
184 return port0;
185}
186
187static int set_command_mode(void)
188{
189 int i, found=0, count=0;
190
191 /* Set the card into command mode */
192 spin_lock(&io_lock);
193 while ((!found) && (count < 3)) {
194 i = send_isa_command(CMD_ISA_IDLE);
195
196 if (i == 0x00)
197 found = 1;
198 else if (i == 0xF3) {
199 /* Card does not like what we've done to it */
200 outb_p(0x00, current_readport + 2);
201 udelay(1200); /* Spec says wait 1ms */
202 outb_p(0x00, current_readport + 2);
203 udelay(ISA_COMMAND_TIMEOUT);
204 }
205 count++;
206 }
207 spin_unlock(&io_lock);
208 command_mode = found;
209
210 return(found);
211}
212
213static void unset_command_mode(void)
214{
215 /* Set the card into normal mode */
216 spin_lock(&io_lock);
217 outb_p(0x00, current_readport + 2);
218 udelay(ISA_COMMAND_TIMEOUT);
219 spin_unlock(&io_lock);
220
221 command_mode = 0;
222}
223
224static void pcwd_timer_ping(unsigned long data)
225{
226 int wdrst_stat;
227
228 /* If we got a heartbeat pulse within the WDT_INTERVAL
229 * we agree to ping the WDT */
230 if(time_before(jiffies, next_heartbeat)) {
231 /* Ping the watchdog */
232 spin_lock(&io_lock);
233 if (revision == PCWD_REVISION_A) {
234 /* Rev A cards are reset by setting the WD_WDRST bit in register 1 */
235 wdrst_stat = inb_p(current_readport);
236 wdrst_stat &= 0x0F;
237 wdrst_stat |= WD_WDRST;
238
239 outb_p(wdrst_stat, current_readport + 1);
240 } else {
241 /* Re-trigger watchdog by writing to port 0 */
242 outb_p(0x00, current_readport);
243 }
244
245 /* Re-set the timer interval */
246 mod_timer(&timer, jiffies + WDT_INTERVAL);
247
248 spin_unlock(&io_lock);
249 } else {
250 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
251 }
252}
253
254static int pcwd_start(void)
255{
256 int stat_reg;
257
258 next_heartbeat = jiffies + (heartbeat * HZ);
259
260 /* Start the timer */
261 mod_timer(&timer, jiffies + WDT_INTERVAL);
262
263 /* Enable the port */
264 if (revision == PCWD_REVISION_C) {
265 spin_lock(&io_lock);
266 outb_p(0x00, current_readport + 3);
267 udelay(ISA_COMMAND_TIMEOUT);
268 stat_reg = inb_p(current_readport + 2);
269 spin_unlock(&io_lock);
270 if (stat_reg & 0x10) {
271 printk(KERN_INFO PFX "Could not start watchdog\n");
272 return -EIO;
273 }
274 }
275 return 0;
276}
277
278static int pcwd_stop(void)
279{
280 int stat_reg;
281
282 /* Stop the timer */
283 del_timer(&timer);
284
285 /* Disable the board */
286 if (revision == PCWD_REVISION_C) {
287 spin_lock(&io_lock);
288 outb_p(0xA5, current_readport + 3);
289 udelay(ISA_COMMAND_TIMEOUT);
290 outb_p(0xA5, current_readport + 3);
291 udelay(ISA_COMMAND_TIMEOUT);
292 stat_reg = inb_p(current_readport + 2);
293 spin_unlock(&io_lock);
294 if ((stat_reg & 0x10) == 0) {
295 printk(KERN_INFO PFX "Could not stop watchdog\n");
296 return -EIO;
297 }
298 }
299 return 0;
300}
301
302static int pcwd_keepalive(void)
303{
304 /* user land ping */
305 next_heartbeat = jiffies + (heartbeat * HZ);
306 return 0;
307}
308
309static int pcwd_set_heartbeat(int t)
310{
311 if ((t < 2) || (t > 7200)) /* arbitrary upper limit */
312 return -EINVAL;
313
314 heartbeat = t;
315 return 0;
316}
317
318static int pcwd_get_status(int *status)
319{
320 int card_status;
321
322 *status=0;
323 spin_lock(&io_lock);
324 if (revision == PCWD_REVISION_A)
325 /* Rev A cards return status information from
326 * the base register, which is used for the
327 * temperature in other cards. */
328 card_status = inb(current_readport);
329 else {
330 /* Rev C cards return card status in the base
331 * address + 1 register. And use different bits
332 * to indicate a card initiated reset, and an
333 * over-temperature condition. And the reboot
334 * status can be reset. */
335 card_status = inb(current_readport + 1);
336 }
337 spin_unlock(&io_lock);
338
339 if (revision == PCWD_REVISION_A) {
340 if (card_status & WD_WDRST)
341 *status |= WDIOF_CARDRESET;
342
343 if (card_status & WD_T110) {
344 *status |= WDIOF_OVERHEAT;
345 if (temp_panic) {
346 printk (KERN_INFO PFX "Temperature overheat trip!\n");
347 machine_power_off();
348 }
349 }
350 } else {
351 if (card_status & WD_REVC_WTRP)
352 *status |= WDIOF_CARDRESET;
353
354 if (card_status & WD_REVC_TTRP) {
355 *status |= WDIOF_OVERHEAT;
356 if (temp_panic) {
357 printk (KERN_INFO PFX "Temperature overheat trip!\n");
358 machine_power_off();
359 }
360 }
361 }
362
363 return 0;
364}
365
366static int pcwd_clear_status(void)
367{
368 if (revision == PCWD_REVISION_C) {
369 spin_lock(&io_lock);
370 outb_p(0x00, current_readport + 1); /* clear reset status */
371 spin_unlock(&io_lock);
372 }
373 return 0;
374}
375
376static int pcwd_get_temperature(int *temperature)
377{
378 /* check that port 0 gives temperature info and no command results */
379 if (command_mode)
380 return -1;
381
382 *temperature = 0;
383 if (!supports_temp)
384 return -ENODEV;
385
386 /*
387 * Convert celsius to fahrenheit, since this was
388 * the decided 'standard' for this return value.
389 */
390 spin_lock(&io_lock);
391 *temperature = ((inb(current_readport)) * 9 / 5) + 32;
392 spin_unlock(&io_lock);
393
394 return 0;
395}
396
397/*
398 * /dev/watchdog handling
399 */
400
401static int pcwd_ioctl(struct inode *inode, struct file *file,
402 unsigned int cmd, unsigned long arg)
403{
404 int rv;
405 int status;
406 int temperature;
407 int new_heartbeat;
408 int __user *argp = (int __user *)arg;
409 static struct watchdog_info ident = {
410 .options = WDIOF_OVERHEAT |
411 WDIOF_CARDRESET |
412 WDIOF_KEEPALIVEPING |
413 WDIOF_SETTIMEOUT |
414 WDIOF_MAGICCLOSE,
415 .firmware_version = 1,
416 .identity = "PCWD",
417 };
418
419 switch(cmd) {
420 default:
421 return -ENOIOCTLCMD;
422
423 case WDIOC_GETSUPPORT:
424 if(copy_to_user(argp, &ident, sizeof(ident)))
425 return -EFAULT;
426 return 0;
427
428 case WDIOC_GETSTATUS:
429 pcwd_get_status(&status);
430 return put_user(status, argp);
431
432 case WDIOC_GETBOOTSTATUS:
433 return put_user(initial_status, argp);
434
435 case WDIOC_GETTEMP:
436 if (pcwd_get_temperature(&temperature))
437 return -EFAULT;
438
439 return put_user(temperature, argp);
440
441 case WDIOC_SETOPTIONS:
442 if (revision == PCWD_REVISION_C)
443 {
444 if(copy_from_user(&rv, argp, sizeof(int)))
445 return -EFAULT;
446
447 if (rv & WDIOS_DISABLECARD)
448 {
449 return pcwd_stop();
450 }
451
452 if (rv & WDIOS_ENABLECARD)
453 {
454 return pcwd_start();
455 }
456
457 if (rv & WDIOS_TEMPPANIC)
458 {
459 temp_panic = 1;
460 }
461 }
462 return -EINVAL;
463
464 case WDIOC_KEEPALIVE:
465 pcwd_keepalive();
466 return 0;
467
468 case WDIOC_SETTIMEOUT:
469 if (get_user(new_heartbeat, argp))
470 return -EFAULT;
471
472 if (pcwd_set_heartbeat(new_heartbeat))
473 return -EINVAL;
474
475 pcwd_keepalive();
476 /* Fall */
477
478 case WDIOC_GETTIMEOUT:
479 return put_user(heartbeat, argp);
480 }
481
482 return 0;
483}
484
485static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len,
486 loff_t *ppos)
487{
488 if (len) {
489 if (!nowayout) {
490 size_t i;
491
492 /* In case it was set long ago */
493 expect_close = 0;
494
495 for (i = 0; i != len; i++) {
496 char c;
497
498 if (get_user(c, buf + i))
499 return -EFAULT;
500 if (c == 'V')
501 expect_close = 42;
502 }
503 }
504 pcwd_keepalive();
505 }
506 return len;
507}
508
509static int pcwd_open(struct inode *inode, struct file *file)
510{
511 if (!atomic_dec_and_test(&open_allowed) ) {
512 atomic_inc( &open_allowed );
513 return -EBUSY;
514 }
515
516 if (nowayout)
517 __module_get(THIS_MODULE);
518
519 /* Activate */
520 pcwd_start();
521 pcwd_keepalive();
522 return nonseekable_open(inode, file);
523}
524
525static int pcwd_close(struct inode *inode, struct file *file)
526{
527 if (expect_close == 42) {
528 pcwd_stop();
529 } else {
530 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
531 pcwd_keepalive();
532 }
533 expect_close = 0;
534 atomic_inc( &open_allowed );
535 return 0;
536}
537
538/*
539 * /dev/temperature handling
540 */
541
542static ssize_t pcwd_temp_read(struct file *file, char __user *buf, size_t count,
543 loff_t *ppos)
544{
545 int temperature;
546
547 if (pcwd_get_temperature(&temperature))
548 return -EFAULT;
549
550 if (copy_to_user(buf, &temperature, 1))
551 return -EFAULT;
552
553 return 1;
554}
555
556static int pcwd_temp_open(struct inode *inode, struct file *file)
557{
558 if (!supports_temp)
559 return -ENODEV;
560
561 return nonseekable_open(inode, file);
562}
563
564static int pcwd_temp_close(struct inode *inode, struct file *file)
565{
566 return 0;
567}
568
569/*
570 * Notify system
571 */
572
573static int pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
574{
575 if (code==SYS_DOWN || code==SYS_HALT) {
576 /* Turn the WDT off */
577 pcwd_stop();
578 }
579
580 return NOTIFY_DONE;
581}
582
583/*
584 * Kernel Interfaces
585 */
586
587static struct file_operations pcwd_fops = {
588 .owner = THIS_MODULE,
589 .llseek = no_llseek,
590 .write = pcwd_write,
591 .ioctl = pcwd_ioctl,
592 .open = pcwd_open,
593 .release = pcwd_close,
594};
595
596static struct miscdevice pcwd_miscdev = {
597 .minor = WATCHDOG_MINOR,
598 .name = "watchdog",
599 .fops = &pcwd_fops,
600};
601
602static struct file_operations pcwd_temp_fops = {
603 .owner = THIS_MODULE,
604 .llseek = no_llseek,
605 .read = pcwd_temp_read,
606 .open = pcwd_temp_open,
607 .release = pcwd_temp_close,
608};
609
610static struct miscdevice temp_miscdev = {
611 .minor = TEMP_MINOR,
612 .name = "temperature",
613 .fops = &pcwd_temp_fops,
614};
615
616static struct notifier_block pcwd_notifier = {
617 .notifier_call = pcwd_notify_sys,
618};
619
620/*
621 * Init & exit routines
622 */
623
624static inline void get_support(void)
625{
626 if (inb(current_readport) != 0xF0)
627 supports_temp = 1;
628}
629
630static inline int get_revision(void)
631{
632 int r = PCWD_REVISION_C;
633
634 spin_lock(&io_lock);
635 /* REV A cards use only 2 io ports; test
636 * presumes a floating bus reads as 0xff. */
637 if ((inb(current_readport + 2) == 0xFF) ||
638 (inb(current_readport + 3) == 0xFF))
639 r=PCWD_REVISION_A;
640 spin_unlock(&io_lock);
641
642 return r;
643}
644
645static inline char *get_firmware(void)
646{
647 int one, ten, hund, minor;
648 char *ret;
649
650 ret = kmalloc(6, GFP_KERNEL);
651 if(ret == NULL)
652 return NULL;
653
654 if (set_command_mode()) {
655 one = send_isa_command(CMD_ISA_VERSION_INTEGER);
656 ten = send_isa_command(CMD_ISA_VERSION_TENTH);
657 hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
658 minor = send_isa_command(CMD_ISA_VERSION_MINOR);
659 sprintf(ret, "%c.%c%c%c", one, ten, hund, minor);
660 }
661 else
662 sprintf(ret, "ERROR");
663
664 unset_command_mode();
665 return(ret);
666}
667
668static inline int get_option_switches(void)
669{
670 int rv=0;
671
672 if (set_command_mode()) {
673 /* Get switch settings */
674 rv = send_isa_command(CMD_ISA_SWITCH_SETTINGS);
675 }
676
677 unset_command_mode();
678 return(rv);
679}
680
681static int __devinit pcwatchdog_init(int base_addr)
682{
683 int ret;
684 char *firmware;
685 int option_switches;
686
687 cards_found++;
688 if (cards_found == 1)
689 printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
690
691 if (cards_found > 1) {
692 printk(KERN_ERR PFX "This driver only supports 1 device\n");
693 return -ENODEV;
694 }
695
696 if (base_addr == 0x0000) {
697 printk(KERN_ERR PFX "No I/O-Address for card detected\n");
698 return -ENODEV;
699 }
700 current_readport = base_addr;
701
702 /* Check card's revision */
703 revision = get_revision();
704
705 if (!request_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
706 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
707 current_readport);
708 current_readport = 0x0000;
709 return -EIO;
710 }
711
712 /* Initial variables */
713 supports_temp = 0;
714 temp_panic = 0;
715 initial_status = 0x0000;
716
717 /* get the boot_status */
718 pcwd_get_status(&initial_status);
719
720 /* clear the "card caused reboot" flag */
721 pcwd_clear_status();
722
723 init_timer(&timer);
724 timer.function = pcwd_timer_ping;
725 timer.data = 0;
726
727 /* Disable the board */
728 pcwd_stop();
729
730 /* Check whether or not the card supports the temperature device */
731 get_support();
732
733 /* Get some extra info from the hardware (in command/debug/diag mode) */
734 if (revision == PCWD_REVISION_A)
735 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", current_readport);
736 else if (revision == PCWD_REVISION_C) {
737 firmware = get_firmware();
738 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
739 current_readport, firmware);
740 kfree(firmware);
741 option_switches = get_option_switches();
742 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
743 option_switches,
744 ((option_switches & 0x10) ? "ON" : "OFF"),
745 ((option_switches & 0x08) ? "ON" : "OFF"));
746
747 /* Reprogram internal heartbeat to 2 seconds */
748 if (set_command_mode()) {
749 send_isa_command(CMD_ISA_DELAY_TIME_2SECS);
750 unset_command_mode();
751 }
752 } else {
753 /* Should NEVER happen, unless get_revision() fails. */
754 printk(KERN_INFO PFX "Unable to get revision\n");
755 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
756 current_readport = 0x0000;
757 return -1;
758 }
759
760 if (supports_temp)
761 printk(KERN_INFO PFX "Temperature Option Detected\n");
762
763 if (initial_status & WDIOF_CARDRESET)
764 printk(KERN_INFO PFX "Previous reboot was caused by the card\n");
765
766 if (initial_status & WDIOF_OVERHEAT) {
767 printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n");
768 printk(KERN_EMERG PFX "CPU Overheat\n");
769 }
770
771 if (initial_status == 0)
772 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
773
774 /* Check that the heartbeat value is within it's range ; if not reset to the default */
775 if (pcwd_set_heartbeat(heartbeat)) {
776 pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
777 printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n",
778 WATCHDOG_HEARTBEAT);
779 }
780
781 ret = register_reboot_notifier(&pcwd_notifier);
782 if (ret) {
783 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
784 ret);
785 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
786 current_readport = 0x0000;
787 return ret;
788 }
789
790 if (supports_temp) {
791 ret = misc_register(&temp_miscdev);
792 if (ret) {
793 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
794 TEMP_MINOR, ret);
795 unregister_reboot_notifier(&pcwd_notifier);
796 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
797 current_readport = 0x0000;
798 return ret;
799 }
800 }
801
802 ret = misc_register(&pcwd_miscdev);
803 if (ret) {
804 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
805 WATCHDOG_MINOR, ret);
806 if (supports_temp)
807 misc_deregister(&temp_miscdev);
808 unregister_reboot_notifier(&pcwd_notifier);
809 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
810 current_readport = 0x0000;
811 return ret;
812 }
813
814 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
815 heartbeat, nowayout);
816
817 return 0;
818}
819
820static void __devexit pcwatchdog_exit(void)
821{
822 /* Disable the board */
823 if (!nowayout)
824 pcwd_stop();
825
826 /* Deregister */
827 misc_deregister(&pcwd_miscdev);
828 if (supports_temp)
829 misc_deregister(&temp_miscdev);
830 unregister_reboot_notifier(&pcwd_notifier);
831 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
832 current_readport = 0x0000;
833}
834
835/*
836 * The ISA cards have a heartbeat bit in one of the registers, which
837 * register is card dependent. The heartbeat bit is monitored, and if
838 * found, is considered proof that a Berkshire card has been found.
839 * The initial rate is once per second at board start up, then twice
840 * per second for normal operation.
841 */
842static int __init pcwd_checkcard(int base_addr)
843{
844 int port0, last_port0; /* Reg 0, in case it's REV A */
845 int port1, last_port1; /* Register 1 for REV C cards */
846 int i;
847 int retval;
848
849 if (!request_region (base_addr, 4, "PCWD")) {
850 printk (KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
851 return 0;
852 }
853
854 retval = 0;
855
856 port0 = inb_p(base_addr); /* For REV A boards */
857 port1 = inb_p(base_addr + 1); /* For REV C boards */
858 if (port0 != 0xff || port1 != 0xff) {
859 /* Not an 'ff' from a floating bus, so must be a card! */
860 for (i = 0; i < 4; ++i) {
861
862 msleep(500);
863
864 last_port0 = port0;
865 last_port1 = port1;
866
867 port0 = inb_p(base_addr);
868 port1 = inb_p(base_addr + 1);
869
870 /* Has either hearbeat bit changed? */
871 if ((port0 ^ last_port0) & WD_HRTBT ||
872 (port1 ^ last_port1) & WD_REVC_HRBT) {
873 retval = 1;
874 break;
875 }
876 }
877 }
878 release_region (base_addr, 4);
879
880 return retval;
881}
882
883/*
884 * These are the auto-probe addresses available.
885 *
886 * Revision A only uses ports 0x270 and 0x370. Revision C introduced 0x350.
887 * Revision A has an address range of 2 addresses, while Revision C has 4.
888 */
889static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
890
891static int __init pcwd_init_module(void)
892{
893 int i, found = 0;
894
895 spin_lock_init(&io_lock);
896
897 for (i = 0; pcwd_ioports[i] != 0; i++) {
898 if (pcwd_checkcard(pcwd_ioports[i])) {
899 if (!(pcwatchdog_init(pcwd_ioports[i])))
900 found++;
901 }
902 }
903
904 if (!found) {
905 printk (KERN_INFO PFX "No card detected, or port not available\n");
906 return -ENODEV;
907 }
908
909 return 0;
910}
911
912static void __exit pcwd_cleanup_module(void)
913{
914 if (current_readport)
915 pcwatchdog_exit();
916 return;
917}
918
919module_init(pcwd_init_module);
920module_exit(pcwd_cleanup_module);
921
922MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>");
923MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver");
924MODULE_LICENSE("GPL");
925MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
926MODULE_ALIAS_MISCDEV(TEMP_MINOR);
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
new file mode 100644
index 000000000000..8ce066627326
--- /dev/null
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -0,0 +1,677 @@
1/*
2 * Berkshire PCI-PC Watchdog Card Driver
3 *
4 * (c) Copyright 2003 Wim Van Sebroeck <wim@iguana.be>.
5 *
6 * Based on source code of the following authors:
7 * Ken Hollis <kenji@bitgate.com>,
8 * Lindsay Harris <lindsay@bluegum.com>,
9 * Alan Cox <alan@redhat.com>,
10 * Matt Domsch <Matt_Domsch@dell.com>,
11 * Rob Radez <rob@osinvestor.com>
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
17 *
18 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
19 * provide warranty for any of this software. This material is
20 * provided "AS-IS" and at no charge.
21 */
22
23/*
24 * A bells and whistles driver is available from http://www.pcwd.de/
25 * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
26 */
27
28/*
29 * Includes, defines, variables, module parameters, ...
30 */
31
32#include <linux/config.h>
33#include <linux/module.h>
34#include <linux/moduleparam.h>
35#include <linux/types.h>
36#include <linux/delay.h>
37#include <linux/miscdevice.h>
38#include <linux/watchdog.h>
39#include <linux/notifier.h>
40#include <linux/reboot.h>
41#include <linux/init.h>
42#include <linux/fs.h>
43#include <linux/pci.h>
44#include <linux/ioport.h>
45#include <linux/spinlock.h>
46
47#include <asm/uaccess.h>
48#include <asm/io.h>
49
50/* Module and version information */
51#define WATCHDOG_VERSION "1.01"
52#define WATCHDOG_DATE "15 Mar 2005"
53#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
54#define WATCHDOG_NAME "pcwd_pci"
55#define PFX WATCHDOG_NAME ": "
56#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION " (" WATCHDOG_DATE ")\n"
57
58/* Stuff for the PCI ID's */
59#ifndef PCI_VENDOR_ID_QUICKLOGIC
60#define PCI_VENDOR_ID_QUICKLOGIC 0x11e3
61#endif
62
63#ifndef PCI_DEVICE_ID_WATCHDOG_PCIPCWD
64#define PCI_DEVICE_ID_WATCHDOG_PCIPCWD 0x5030
65#endif
66
67/*
68 * These are the defines that describe the control status bits for the
69 * PCI-PC Watchdog card.
70 */
71#define WD_PCI_WTRP 0x01 /* Watchdog Trip status */
72#define WD_PCI_HRBT 0x02 /* Watchdog Heartbeat */
73#define WD_PCI_TTRP 0x04 /* Temperature Trip status */
74
75/* according to documentation max. time to process a command for the pci
76 * watchdog card is 100 ms, so we give it 150 ms to do it's job */
77#define PCI_COMMAND_TIMEOUT 150
78
79/* Watchdog's internal commands */
80#define CMD_GET_STATUS 0x04
81#define CMD_GET_FIRMWARE_VERSION 0x08
82#define CMD_READ_WATCHDOG_TIMEOUT 0x18
83#define CMD_WRITE_WATCHDOG_TIMEOUT 0x19
84
85/* We can only use 1 card due to the /dev/watchdog restriction */
86static int cards_found;
87
88/* internal variables */
89static int temp_panic;
90static unsigned long is_active;
91static char expect_release;
92static struct {
93 int supports_temp; /* Wether or not the card has a temperature device */
94 int boot_status; /* The card's boot status */
95 unsigned long io_addr; /* The cards I/O address */
96 spinlock_t io_lock;
97 struct pci_dev *pdev;
98} pcipcwd_private;
99
100/* module parameters */
101#define WATCHDOG_HEARTBEAT 2 /* 2 sec default heartbeat */
102static int heartbeat = WATCHDOG_HEARTBEAT;
103module_param(heartbeat, int, 0);
104MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
105
106#ifdef CONFIG_WATCHDOG_NOWAYOUT
107static int nowayout = 1;
108#else
109static int nowayout = 0;
110#endif
111
112module_param(nowayout, int, 0);
113MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
114
115/*
116 * Internal functions
117 */
118
119static int send_command(int cmd, int *msb, int *lsb)
120{
121 int got_response, count;
122
123 spin_lock(&pcipcwd_private.io_lock);
124 /* If a command requires data it should be written first.
125 * Data for commands with 8 bits of data should be written to port 4.
126 * Commands with 16 bits of data, should be written as LSB to port 4
127 * and MSB to port 5.
128 * After the required data has been written then write the command to
129 * port 6. */
130 outb_p(*lsb, pcipcwd_private.io_addr + 4);
131 outb_p(*msb, pcipcwd_private.io_addr + 5);
132 outb_p(cmd, pcipcwd_private.io_addr + 6);
133
134 /* wait till the pci card processed the command, signaled by
135 * the WRSP bit in port 2 and give it a max. timeout of
136 * PCI_COMMAND_TIMEOUT to process */
137 got_response = inb_p(pcipcwd_private.io_addr + 2) & 0x40;
138 for (count = 0; (count < PCI_COMMAND_TIMEOUT) && (!got_response); count++) {
139 mdelay(1);
140 got_response = inb_p(pcipcwd_private.io_addr + 2) & 0x40;
141 }
142
143 if (got_response) {
144 /* read back response */
145 *lsb = inb_p(pcipcwd_private.io_addr + 4);
146 *msb = inb_p(pcipcwd_private.io_addr + 5);
147
148 /* clear WRSP bit */
149 inb_p(pcipcwd_private.io_addr + 6);
150 }
151 spin_unlock(&pcipcwd_private.io_lock);
152
153 return got_response;
154}
155
156static int pcipcwd_start(void)
157{
158 int stat_reg;
159
160 spin_lock(&pcipcwd_private.io_lock);
161 outb_p(0x00, pcipcwd_private.io_addr + 3);
162 udelay(1000);
163
164 stat_reg = inb_p(pcipcwd_private.io_addr + 2);
165 spin_unlock(&pcipcwd_private.io_lock);
166
167 if (stat_reg & 0x10) {
168 printk(KERN_ERR PFX "Card timer not enabled\n");
169 return -1;
170 }
171
172 return 0;
173}
174
175static int pcipcwd_stop(void)
176{
177 int stat_reg;
178
179 spin_lock(&pcipcwd_private.io_lock);
180 outb_p(0xA5, pcipcwd_private.io_addr + 3);
181 udelay(1000);
182
183 outb_p(0xA5, pcipcwd_private.io_addr + 3);
184 udelay(1000);
185
186 stat_reg = inb_p(pcipcwd_private.io_addr + 2);
187 spin_unlock(&pcipcwd_private.io_lock);
188
189 if (!(stat_reg & 0x10)) {
190 printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n");
191 return -1;
192 }
193
194 return 0;
195}
196
197static int pcipcwd_keepalive(void)
198{
199 /* Re-trigger watchdog by writing to port 0 */
200 outb_p(0x42, pcipcwd_private.io_addr);
201 return 0;
202}
203
204static int pcipcwd_set_heartbeat(int t)
205{
206 int t_msb = t / 256;
207 int t_lsb = t % 256;
208
209 if ((t < 0x0001) || (t > 0xFFFF))
210 return -EINVAL;
211
212 /* Write new heartbeat to watchdog */
213 send_command(CMD_WRITE_WATCHDOG_TIMEOUT, &t_msb, &t_lsb);
214
215 heartbeat = t;
216 return 0;
217}
218
219static int pcipcwd_get_status(int *status)
220{
221 int new_status;
222
223 *status=0;
224 new_status = inb_p(pcipcwd_private.io_addr + 1);
225 if (new_status & WD_PCI_WTRP)
226 *status |= WDIOF_CARDRESET;
227 if (new_status & WD_PCI_TTRP) {
228 *status |= WDIOF_OVERHEAT;
229 if (temp_panic)
230 panic(PFX "Temperature overheat trip!\n");
231 }
232
233 return 0;
234}
235
236static int pcipcwd_clear_status(void)
237{
238 outb_p(0x01, pcipcwd_private.io_addr + 1);
239 return 0;
240}
241
242static int pcipcwd_get_temperature(int *temperature)
243{
244 *temperature = 0;
245 if (!pcipcwd_private.supports_temp)
246 return -ENODEV;
247
248 /*
249 * Convert celsius to fahrenheit, since this was
250 * the decided 'standard' for this return value.
251 */
252 *temperature = ((inb_p(pcipcwd_private.io_addr)) * 9 / 5) + 32;
253
254 return 0;
255}
256
257/*
258 * /dev/watchdog handling
259 */
260
261static ssize_t pcipcwd_write(struct file *file, const char __user *data,
262 size_t len, loff_t *ppos)
263{
264 /* See if we got the magic character 'V' and reload the timer */
265 if (len) {
266 if (!nowayout) {
267 size_t i;
268
269 /* note: just in case someone wrote the magic character
270 * five months ago... */
271 expect_release = 0;
272
273 /* scan to see whether or not we got the magic character */
274 for (i = 0; i != len; i++) {
275 char c;
276 if(get_user(c, data+i))
277 return -EFAULT;
278 if (c == 'V')
279 expect_release = 42;
280 }
281 }
282
283 /* someone wrote to us, we should reload the timer */
284 pcipcwd_keepalive();
285 }
286 return len;
287}
288
289static int pcipcwd_ioctl(struct inode *inode, struct file *file,
290 unsigned int cmd, unsigned long arg)
291{
292 void __user *argp = (void __user *)arg;
293 int __user *p = argp;
294 static struct watchdog_info ident = {
295 .options = WDIOF_OVERHEAT |
296 WDIOF_CARDRESET |
297 WDIOF_KEEPALIVEPING |
298 WDIOF_SETTIMEOUT |
299 WDIOF_MAGICCLOSE,
300 .firmware_version = 1,
301 .identity = WATCHDOG_DRIVER_NAME,
302 };
303
304 switch (cmd) {
305 case WDIOC_GETSUPPORT:
306 return copy_to_user(argp, &ident,
307 sizeof (ident)) ? -EFAULT : 0;
308
309 case WDIOC_GETSTATUS:
310 {
311 int status;
312
313 pcipcwd_get_status(&status);
314
315 return put_user(status, p);
316 }
317
318 case WDIOC_GETBOOTSTATUS:
319 return put_user(pcipcwd_private.boot_status, p);
320
321 case WDIOC_GETTEMP:
322 {
323 int temperature;
324
325 if (pcipcwd_get_temperature(&temperature))
326 return -EFAULT;
327
328 return put_user(temperature, p);
329 }
330
331 case WDIOC_KEEPALIVE:
332 pcipcwd_keepalive();
333 return 0;
334
335 case WDIOC_SETOPTIONS:
336 {
337 int new_options, retval = -EINVAL;
338
339 if (get_user (new_options, p))
340 return -EFAULT;
341
342 if (new_options & WDIOS_DISABLECARD) {
343 pcipcwd_stop();
344 retval = 0;
345 }
346
347 if (new_options & WDIOS_ENABLECARD) {
348 pcipcwd_start();
349 retval = 0;
350 }
351
352 if (new_options & WDIOS_TEMPPANIC) {
353 temp_panic = 1;
354 retval = 0;
355 }
356
357 return retval;
358 }
359
360 case WDIOC_SETTIMEOUT:
361 {
362 int new_heartbeat;
363
364 if (get_user(new_heartbeat, p))
365 return -EFAULT;
366
367 if (pcipcwd_set_heartbeat(new_heartbeat))
368 return -EINVAL;
369
370 pcipcwd_keepalive();
371 /* Fall */
372 }
373
374 case WDIOC_GETTIMEOUT:
375 return put_user(heartbeat, p);
376
377 default:
378 return -ENOIOCTLCMD;
379 }
380}
381
382static int pcipcwd_open(struct inode *inode, struct file *file)
383{
384 /* /dev/watchdog can only be opened once */
385 if (test_and_set_bit(0, &is_active))
386 return -EBUSY;
387
388 /* Activate */
389 pcipcwd_start();
390 pcipcwd_keepalive();
391 return nonseekable_open(inode, file);
392}
393
394static int pcipcwd_release(struct inode *inode, struct file *file)
395{
396 /*
397 * Shut off the timer.
398 */
399 if (expect_release == 42) {
400 pcipcwd_stop();
401 } else {
402 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
403 pcipcwd_keepalive();
404 }
405 expect_release = 0;
406 clear_bit(0, &is_active);
407 return 0;
408}
409
410/*
411 * /dev/temperature handling
412 */
413
414static ssize_t pcipcwd_temp_read(struct file *file, char __user *data,
415 size_t len, loff_t *ppos)
416{
417 int temperature;
418
419 if (pcipcwd_get_temperature(&temperature))
420 return -EFAULT;
421
422 if (copy_to_user (data, &temperature, 1))
423 return -EFAULT;
424
425 return 1;
426}
427
428static int pcipcwd_temp_open(struct inode *inode, struct file *file)
429{
430 if (!pcipcwd_private.supports_temp)
431 return -ENODEV;
432
433 return nonseekable_open(inode, file);
434}
435
436static int pcipcwd_temp_release(struct inode *inode, struct file *file)
437{
438 return 0;
439}
440
441/*
442 * Notify system
443 */
444
445static int pcipcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
446{
447 if (code==SYS_DOWN || code==SYS_HALT) {
448 /* Turn the WDT off */
449 pcipcwd_stop();
450 }
451
452 return NOTIFY_DONE;
453}
454
455/*
456 * Kernel Interfaces
457 */
458
459static struct file_operations pcipcwd_fops = {
460 .owner = THIS_MODULE,
461 .llseek = no_llseek,
462 .write = pcipcwd_write,
463 .ioctl = pcipcwd_ioctl,
464 .open = pcipcwd_open,
465 .release = pcipcwd_release,
466};
467
468static struct miscdevice pcipcwd_miscdev = {
469 .minor = WATCHDOG_MINOR,
470 .name = "watchdog",
471 .fops = &pcipcwd_fops,
472};
473
474static struct file_operations pcipcwd_temp_fops = {
475 .owner = THIS_MODULE,
476 .llseek = no_llseek,
477 .read = pcipcwd_temp_read,
478 .open = pcipcwd_temp_open,
479 .release = pcipcwd_temp_release,
480};
481
482static struct miscdevice pcipcwd_temp_miscdev = {
483 .minor = TEMP_MINOR,
484 .name = "temperature",
485 .fops = &pcipcwd_temp_fops,
486};
487
488static struct notifier_block pcipcwd_notifier = {
489 .notifier_call = pcipcwd_notify_sys,
490};
491
492/*
493 * Init & exit routines
494 */
495
496static inline void check_temperature_support(void)
497{
498 if (inb_p(pcipcwd_private.io_addr) != 0xF0)
499 pcipcwd_private.supports_temp = 1;
500}
501
502static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
503 const struct pci_device_id *ent)
504{
505 int ret = -EIO;
506 int got_fw_rev, fw_rev_major, fw_rev_minor;
507 char fw_ver_str[20];
508 char option_switches;
509
510 cards_found++;
511 if (cards_found == 1)
512 printk(KERN_INFO PFX DRIVER_VERSION);
513
514 if (cards_found > 1) {
515 printk(KERN_ERR PFX "This driver only supports 1 device\n");
516 return -ENODEV;
517 }
518
519 if (pci_enable_device(pdev)) {
520 printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
521 return -ENODEV;
522 }
523
524 if (pci_resource_start(pdev, 0) == 0x0000) {
525 printk(KERN_ERR PFX "No I/O-Address for card detected\n");
526 ret = -ENODEV;
527 goto err_out_disable_device;
528 }
529
530 pcipcwd_private.pdev = pdev;
531 pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
532
533 if (pci_request_regions(pdev, WATCHDOG_NAME)) {
534 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
535 (int) pcipcwd_private.io_addr);
536 ret = -EIO;
537 goto err_out_disable_device;
538 }
539
540 /* get the boot_status */
541 pcipcwd_get_status(&pcipcwd_private.boot_status);
542
543 /* clear the "card caused reboot" flag */
544 pcipcwd_clear_status();
545
546 /* disable card */
547 pcipcwd_stop();
548
549 /* Check whether or not the card supports the temperature device */
550 check_temperature_support();
551
552 /* Get the Firmware Version */
553 got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
554 if (got_fw_rev) {
555 sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
556 } else {
557 sprintf(fw_ver_str, "<card no answer>");
558 }
559
560 /* Get switch settings */
561 option_switches = inb_p(pcipcwd_private.io_addr + 3);
562
563 printk(KERN_INFO PFX "Found card at port 0x%04x (Firmware: %s) %s temp option\n",
564 (int) pcipcwd_private.io_addr, fw_ver_str,
565 (pcipcwd_private.supports_temp ? "with" : "without"));
566
567 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
568 option_switches,
569 ((option_switches & 0x10) ? "ON" : "OFF"),
570 ((option_switches & 0x08) ? "ON" : "OFF"));
571
572 if (pcipcwd_private.boot_status & WDIOF_CARDRESET)
573 printk(KERN_INFO PFX "Previous reset was caused by the Watchdog card\n");
574
575 if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)
576 printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");
577
578 if (pcipcwd_private.boot_status == 0)
579 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
580
581 /* Check that the heartbeat value is within it's range ; if not reset to the default */
582 if (pcipcwd_set_heartbeat(heartbeat)) {
583 pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
584 printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
585 WATCHDOG_HEARTBEAT);
586 }
587
588 ret = register_reboot_notifier(&pcipcwd_notifier);
589 if (ret != 0) {
590 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
591 ret);
592 goto err_out_release_region;
593 }
594
595 if (pcipcwd_private.supports_temp) {
596 ret = misc_register(&pcipcwd_temp_miscdev);
597 if (ret != 0) {
598 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
599 TEMP_MINOR, ret);
600 goto err_out_unregister_reboot;
601 }
602 }
603
604 ret = misc_register(&pcipcwd_miscdev);
605 if (ret != 0) {
606 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
607 WATCHDOG_MINOR, ret);
608 goto err_out_misc_deregister;
609 }
610
611 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
612 heartbeat, nowayout);
613
614 return 0;
615
616err_out_misc_deregister:
617 if (pcipcwd_private.supports_temp)
618 misc_deregister(&pcipcwd_temp_miscdev);
619err_out_unregister_reboot:
620 unregister_reboot_notifier(&pcipcwd_notifier);
621err_out_release_region:
622 pci_release_regions(pdev);
623err_out_disable_device:
624 pci_disable_device(pdev);
625 return ret;
626}
627
628static void __devexit pcipcwd_card_exit(struct pci_dev *pdev)
629{
630 /* Stop the timer before we leave */
631 if (!nowayout)
632 pcipcwd_stop();
633
634 /* Deregister */
635 misc_deregister(&pcipcwd_miscdev);
636 if (pcipcwd_private.supports_temp)
637 misc_deregister(&pcipcwd_temp_miscdev);
638 unregister_reboot_notifier(&pcipcwd_notifier);
639 pci_release_regions(pdev);
640 pci_disable_device(pdev);
641 cards_found--;
642}
643
644static struct pci_device_id pcipcwd_pci_tbl[] = {
645 { PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD,
646 PCI_ANY_ID, PCI_ANY_ID, },
647 { 0 }, /* End of list */
648};
649MODULE_DEVICE_TABLE(pci, pcipcwd_pci_tbl);
650
651static struct pci_driver pcipcwd_driver = {
652 .name = WATCHDOG_NAME,
653 .id_table = pcipcwd_pci_tbl,
654 .probe = pcipcwd_card_init,
655 .remove = __devexit_p(pcipcwd_card_exit),
656};
657
658static int __init pcipcwd_init_module(void)
659{
660 spin_lock_init (&pcipcwd_private.io_lock);
661
662 return pci_register_driver(&pcipcwd_driver);
663}
664
665static void __exit pcipcwd_cleanup_module(void)
666{
667 pci_unregister_driver(&pcipcwd_driver);
668}
669
670module_init(pcipcwd_init_module);
671module_exit(pcipcwd_cleanup_module);
672
673MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
674MODULE_DESCRIPTION("Berkshire PCI-PC Watchdog driver");
675MODULE_LICENSE("GPL");
676MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
677MODULE_ALIAS_MISCDEV(TEMP_MINOR);
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
new file mode 100644
index 000000000000..1127201d73b8
--- /dev/null
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -0,0 +1,796 @@
1/*
2 * Berkshire USB-PC Watchdog Card Driver
3 *
4 * (c) Copyright 2004 Wim Van Sebroeck <wim@iguana.be>.
5 *
6 * Based on source code of the following authors:
7 * Ken Hollis <kenji@bitgate.com>,
8 * Alan Cox <alan@redhat.com>,
9 * Matt Domsch <Matt_Domsch@dell.com>,
10 * Rob Radez <rob@osinvestor.com>,
11 * Greg Kroah-Hartman <greg@kroah.com>
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
17 *
18 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
19 * provide warranty for any of this software. This material is
20 * provided "AS-IS" and at no charge.
21 *
22 * Thanks also to Simon Machell at Berkshire Products Inc. for
23 * providing the test hardware. More info is available at
24 * http://www.berkprod.com/ or http://www.pcwatchdog.com/
25 */
26
27#include <linux/config.h>
28#include <linux/kernel.h>
29#include <linux/errno.h>
30#include <linux/init.h>
31#include <linux/slab.h>
32#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/types.h>
35#include <linux/delay.h>
36#include <linux/miscdevice.h>
37#include <linux/watchdog.h>
38#include <linux/notifier.h>
39#include <linux/reboot.h>
40#include <linux/fs.h>
41#include <linux/smp_lock.h>
42#include <linux/completion.h>
43#include <asm/uaccess.h>
44#include <linux/usb.h>
45
46
47#ifdef CONFIG_USB_DEBUG
48 static int debug = 1;
49#else
50 static int debug;
51#endif
52
53/* Use our own dbg macro */
54#undef dbg
55#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG PFX format "\n" , ## arg); } while (0)
56
57
58/* Module and Version Information */
59#define DRIVER_VERSION "1.01"
60#define DRIVER_DATE "15 Mar 2005"
61#define DRIVER_AUTHOR "Wim Van Sebroeck <wim@iguana.be>"
62#define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
63#define DRIVER_LICENSE "GPL"
64#define DRIVER_NAME "pcwd_usb"
65#define PFX DRIVER_NAME ": "
66
67MODULE_AUTHOR(DRIVER_AUTHOR);
68MODULE_DESCRIPTION(DRIVER_DESC);
69MODULE_LICENSE(DRIVER_LICENSE);
70MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
71MODULE_ALIAS_MISCDEV(TEMP_MINOR);
72
73/* Module Parameters */
74module_param(debug, int, 0);
75MODULE_PARM_DESC(debug, "Debug enabled or not");
76
77#define WATCHDOG_HEARTBEAT 2 /* 2 sec default heartbeat */
78static int heartbeat = WATCHDOG_HEARTBEAT;
79module_param(heartbeat, int, 0);
80MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
81
82#ifdef CONFIG_WATCHDOG_NOWAYOUT
83static int nowayout = 1;
84#else
85static int nowayout = 0;
86#endif
87
88module_param(nowayout, int, 0);
89MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
90
91/* The vendor and product id's for the USB-PC Watchdog card */
92#define USB_PCWD_VENDOR_ID 0x0c98
93#define USB_PCWD_PRODUCT_ID 0x1140
94
95/* table of devices that work with this driver */
96static struct usb_device_id usb_pcwd_table [] = {
97 { USB_DEVICE(USB_PCWD_VENDOR_ID, USB_PCWD_PRODUCT_ID) },
98 { } /* Terminating entry */
99};
100MODULE_DEVICE_TABLE (usb, usb_pcwd_table);
101
102/* according to documentation max. time to process a command for the USB
103 * watchdog card is 100 or 200 ms, so we give it 250 ms to do it's job */
104#define USB_COMMAND_TIMEOUT 250
105
106/* Watchdog's internal commands */
107#define CMD_READ_TEMP 0x02 /* Read Temperature; Re-trigger Watchdog */
108#define CMD_TRIGGER CMD_READ_TEMP
109#define CMD_GET_STATUS 0x04 /* Get Status Information */
110#define CMD_GET_FIRMWARE_VERSION 0x08 /* Get Firmware Version */
111#define CMD_GET_DIP_SWITCH_SETTINGS 0x0c /* Get Dip Switch Settings */
112#define CMD_READ_WATCHDOG_TIMEOUT 0x18 /* Read Current Watchdog Time */
113#define CMD_WRITE_WATCHDOG_TIMEOUT 0x19 /* Write Current Watchdog Time */
114#define CMD_ENABLE_WATCHDOG 0x30 /* Enable / Disable Watchdog */
115#define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG
116
117/* Some defines that I like to be somewhere else like include/linux/usb_hid.h */
118#define HID_REQ_SET_REPORT 0x09
119#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02)
120
121/* We can only use 1 card due to the /dev/watchdog restriction */
122static int cards_found;
123
124/* some internal variables */
125static unsigned long is_active;
126static char expect_release;
127
128/* Structure to hold all of our device specific stuff */
129struct usb_pcwd_private {
130 struct usb_device * udev; /* save off the usb device pointer */
131 struct usb_interface * interface; /* the interface for this device */
132
133 unsigned int interface_number; /* the interface number used for cmd's */
134
135 unsigned char * intr_buffer; /* the buffer to intr data */
136 dma_addr_t intr_dma; /* the dma address for the intr buffer */
137 size_t intr_size; /* the size of the intr buffer */
138 struct urb * intr_urb; /* the urb used for the intr pipe */
139
140 unsigned char cmd_command; /* The command that is reported back */
141 unsigned char cmd_data_msb; /* The data MSB that is reported back */
142 unsigned char cmd_data_lsb; /* The data LSB that is reported back */
143 atomic_t cmd_received; /* true if we received a report after a command */
144
145 int exists; /* Wether or not the device exists */
146 struct semaphore sem; /* locks this structure */
147};
148static struct usb_pcwd_private *usb_pcwd_device;
149
150/* prevent races between open() and disconnect() */
151static DECLARE_MUTEX (disconnect_sem);
152
153/* local function prototypes */
154static int usb_pcwd_probe (struct usb_interface *interface, const struct usb_device_id *id);
155static void usb_pcwd_disconnect (struct usb_interface *interface);
156
157/* usb specific object needed to register this driver with the usb subsystem */
158static struct usb_driver usb_pcwd_driver = {
159 .owner = THIS_MODULE,
160 .name = DRIVER_NAME,
161 .probe = usb_pcwd_probe,
162 .disconnect = usb_pcwd_disconnect,
163 .id_table = usb_pcwd_table,
164};
165
166
167static void usb_pcwd_intr_done(struct urb *urb, struct pt_regs *regs)
168{
169 struct usb_pcwd_private *usb_pcwd = (struct usb_pcwd_private *)urb->context;
170 unsigned char *data = usb_pcwd->intr_buffer;
171 int retval;
172
173 switch (urb->status) {
174 case 0: /* success */
175 break;
176 case -ECONNRESET: /* unlink */
177 case -ENOENT:
178 case -ESHUTDOWN:
179 /* this urb is terminated, clean up */
180 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
181 return;
182 /* -EPIPE: should clear the halt */
183 default: /* error */
184 dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
185 goto resubmit;
186 }
187
188 dbg("received following data cmd=0x%02x msb=0x%02x lsb=0x%02x",
189 data[0], data[1], data[2]);
190
191 usb_pcwd->cmd_command = data[0];
192 usb_pcwd->cmd_data_msb = data[1];
193 usb_pcwd->cmd_data_lsb = data[2];
194
195 /* notify anyone waiting that the cmd has finished */
196 atomic_set (&usb_pcwd->cmd_received, 1);
197
198resubmit:
199 retval = usb_submit_urb (urb, GFP_ATOMIC);
200 if (retval)
201 printk(KERN_ERR PFX "can't resubmit intr, usb_submit_urb failed with result %d\n",
202 retval);
203}
204
205static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned char cmd,
206 unsigned char *msb, unsigned char *lsb)
207{
208 int got_response, count;
209 unsigned char buf[6];
210
211 /* We will not send any commands if the USB PCWD device does not exist */
212 if ((!usb_pcwd) || (!usb_pcwd->exists))
213 return -1;
214
215 /* The USB PC Watchdog uses a 6 byte report format. The board currently uses
216 * only 3 of the six bytes of the report. */
217 buf[0] = cmd; /* Byte 0 = CMD */
218 buf[1] = *msb; /* Byte 1 = Data MSB */
219 buf[2] = *lsb; /* Byte 2 = Data LSB */
220 buf[3] = buf[4] = buf[5] = 0; /* All other bytes not used */
221
222 dbg("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x",
223 buf[0], buf[1], buf[2]);
224
225 atomic_set (&usb_pcwd->cmd_received, 0);
226
227 if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0),
228 HID_REQ_SET_REPORT, HID_DT_REPORT,
229 0x0200, usb_pcwd->interface_number, buf, sizeof(buf),
230 USB_COMMAND_TIMEOUT) != sizeof(buf)) {
231 dbg("usb_pcwd_send_command: error in usb_control_msg for cmd 0x%x 0x%x 0x%x\n", cmd, *msb, *lsb);
232 }
233 /* wait till the usb card processed the command,
234 * with a max. timeout of USB_COMMAND_TIMEOUT */
235 got_response = 0;
236 for (count = 0; (count < USB_COMMAND_TIMEOUT) && (!got_response); count++) {
237 mdelay(1);
238 if (atomic_read (&usb_pcwd->cmd_received))
239 got_response = 1;
240 }
241
242 if ((got_response) && (cmd == usb_pcwd->cmd_command)) {
243 /* read back response */
244 *msb = usb_pcwd->cmd_data_msb;
245 *lsb = usb_pcwd->cmd_data_lsb;
246 }
247
248 return got_response;
249}
250
251static int usb_pcwd_start(struct usb_pcwd_private *usb_pcwd)
252{
253 unsigned char msb = 0x00;
254 unsigned char lsb = 0x00;
255 int retval;
256
257 /* Enable Watchdog */
258 retval = usb_pcwd_send_command(usb_pcwd, CMD_ENABLE_WATCHDOG, &msb, &lsb);
259
260 if ((retval == 0) || (lsb == 0)) {
261 printk(KERN_ERR PFX "Card did not acknowledge enable attempt\n");
262 return -1;
263 }
264
265 return 0;
266}
267
268static int usb_pcwd_stop(struct usb_pcwd_private *usb_pcwd)
269{
270 unsigned char msb = 0xA5;
271 unsigned char lsb = 0xC3;
272 int retval;
273
274 /* Disable Watchdog */
275 retval = usb_pcwd_send_command(usb_pcwd, CMD_DISABLE_WATCHDOG, &msb, &lsb);
276
277 if ((retval == 0) || (lsb != 0)) {
278 printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n");
279 return -1;
280 }
281
282 return 0;
283}
284
285static int usb_pcwd_keepalive(struct usb_pcwd_private *usb_pcwd)
286{
287 unsigned char dummy;
288
289 /* Re-trigger Watchdog */
290 usb_pcwd_send_command(usb_pcwd, CMD_TRIGGER, &dummy, &dummy);
291
292 return 0;
293}
294
295static int usb_pcwd_set_heartbeat(struct usb_pcwd_private *usb_pcwd, int t)
296{
297 unsigned char msb = t / 256;
298 unsigned char lsb = t % 256;
299
300 if ((t < 0x0001) || (t > 0xFFFF))
301 return -EINVAL;
302
303 /* Write new heartbeat to watchdog */
304 usb_pcwd_send_command(usb_pcwd, CMD_WRITE_WATCHDOG_TIMEOUT, &msb, &lsb);
305
306 heartbeat = t;
307 return 0;
308}
309
310static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd, int *temperature)
311{
312 unsigned char msb, lsb;
313
314 usb_pcwd_send_command(usb_pcwd, CMD_READ_TEMP, &msb, &lsb);
315
316 /*
317 * Convert celsius to fahrenheit, since this was
318 * the decided 'standard' for this return value.
319 */
320 *temperature = (lsb * 9 / 5) + 32;
321
322 return 0;
323}
324
325/*
326 * /dev/watchdog handling
327 */
328
329static ssize_t usb_pcwd_write(struct file *file, const char __user *data,
330 size_t len, loff_t *ppos)
331{
332 /* See if we got the magic character 'V' and reload the timer */
333 if (len) {
334 if (!nowayout) {
335 size_t i;
336
337 /* note: just in case someone wrote the magic character
338 * five months ago... */
339 expect_release = 0;
340
341 /* scan to see whether or not we got the magic character */
342 for (i = 0; i != len; i++) {
343 char c;
344 if(get_user(c, data+i))
345 return -EFAULT;
346 if (c == 'V')
347 expect_release = 42;
348 }
349 }
350
351 /* someone wrote to us, we should reload the timer */
352 usb_pcwd_keepalive(usb_pcwd_device);
353 }
354 return len;
355}
356
357static int usb_pcwd_ioctl(struct inode *inode, struct file *file,
358 unsigned int cmd, unsigned long arg)
359{
360 void __user *argp = (void __user *)arg;
361 int __user *p = argp;
362 static struct watchdog_info ident = {
363 .options = WDIOF_KEEPALIVEPING |
364 WDIOF_SETTIMEOUT |
365 WDIOF_MAGICCLOSE,
366 .firmware_version = 1,
367 .identity = DRIVER_NAME,
368 };
369
370 switch (cmd) {
371 case WDIOC_GETSUPPORT:
372 return copy_to_user(argp, &ident,
373 sizeof (ident)) ? -EFAULT : 0;
374
375 case WDIOC_GETSTATUS:
376 case WDIOC_GETBOOTSTATUS:
377 return put_user(0, p);
378
379 case WDIOC_GETTEMP:
380 {
381 int temperature;
382
383 if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))
384 return -EFAULT;
385
386 return put_user(temperature, p);
387 }
388
389 case WDIOC_KEEPALIVE:
390 usb_pcwd_keepalive(usb_pcwd_device);
391 return 0;
392
393 case WDIOC_SETOPTIONS:
394 {
395 int new_options, retval = -EINVAL;
396
397 if (get_user (new_options, p))
398 return -EFAULT;
399
400 if (new_options & WDIOS_DISABLECARD) {
401 usb_pcwd_stop(usb_pcwd_device);
402 retval = 0;
403 }
404
405 if (new_options & WDIOS_ENABLECARD) {
406 usb_pcwd_start(usb_pcwd_device);
407 retval = 0;
408 }
409
410 return retval;
411 }
412
413 case WDIOC_SETTIMEOUT:
414 {
415 int new_heartbeat;
416
417 if (get_user(new_heartbeat, p))
418 return -EFAULT;
419
420 if (usb_pcwd_set_heartbeat(usb_pcwd_device, new_heartbeat))
421 return -EINVAL;
422
423 usb_pcwd_keepalive(usb_pcwd_device);
424 /* Fall */
425 }
426
427 case WDIOC_GETTIMEOUT:
428 return put_user(heartbeat, p);
429
430 default:
431 return -ENOIOCTLCMD;
432 }
433}
434
435static int usb_pcwd_open(struct inode *inode, struct file *file)
436{
437 /* /dev/watchdog can only be opened once */
438 if (test_and_set_bit(0, &is_active))
439 return -EBUSY;
440
441 /* Activate */
442 usb_pcwd_start(usb_pcwd_device);
443 usb_pcwd_keepalive(usb_pcwd_device);
444 return nonseekable_open(inode, file);
445}
446
447static int usb_pcwd_release(struct inode *inode, struct file *file)
448{
449 /*
450 * Shut off the timer.
451 */
452 if (expect_release == 42) {
453 usb_pcwd_stop(usb_pcwd_device);
454 } else {
455 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
456 usb_pcwd_keepalive(usb_pcwd_device);
457 }
458 expect_release = 0;
459 clear_bit(0, &is_active);
460 return 0;
461}
462
463/*
464 * /dev/temperature handling
465 */
466
467static ssize_t usb_pcwd_temperature_read(struct file *file, char __user *data,
468 size_t len, loff_t *ppos)
469{
470 int temperature;
471
472 if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))
473 return -EFAULT;
474
475 if (copy_to_user(data, &temperature, 1))
476 return -EFAULT;
477
478 return 1;
479}
480
481static int usb_pcwd_temperature_open(struct inode *inode, struct file *file)
482{
483 return nonseekable_open(inode, file);
484}
485
486static int usb_pcwd_temperature_release(struct inode *inode, struct file *file)
487{
488 return 0;
489}
490
491/*
492 * Notify system
493 */
494
495static int usb_pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
496{
497 if (code==SYS_DOWN || code==SYS_HALT) {
498 /* Turn the WDT off */
499 usb_pcwd_stop(usb_pcwd_device);
500 }
501
502 return NOTIFY_DONE;
503}
504
505/*
506 * Kernel Interfaces
507 */
508
509static struct file_operations usb_pcwd_fops = {
510 .owner = THIS_MODULE,
511 .llseek = no_llseek,
512 .write = usb_pcwd_write,
513 .ioctl = usb_pcwd_ioctl,
514 .open = usb_pcwd_open,
515 .release = usb_pcwd_release,
516};
517
518static struct miscdevice usb_pcwd_miscdev = {
519 .minor = WATCHDOG_MINOR,
520 .name = "watchdog",
521 .fops = &usb_pcwd_fops,
522};
523
524static struct file_operations usb_pcwd_temperature_fops = {
525 .owner = THIS_MODULE,
526 .llseek = no_llseek,
527 .read = usb_pcwd_temperature_read,
528 .open = usb_pcwd_temperature_open,
529 .release = usb_pcwd_temperature_release,
530};
531
532static struct miscdevice usb_pcwd_temperature_miscdev = {
533 .minor = TEMP_MINOR,
534 .name = "temperature",
535 .fops = &usb_pcwd_temperature_fops,
536};
537
538static struct notifier_block usb_pcwd_notifier = {
539 .notifier_call = usb_pcwd_notify_sys,
540};
541
542/**
543 * usb_pcwd_delete
544 */
545static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd)
546{
547 if (usb_pcwd->intr_urb != NULL)
548 usb_free_urb (usb_pcwd->intr_urb);
549 if (usb_pcwd->intr_buffer != NULL)
550 usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size,
551 usb_pcwd->intr_buffer, usb_pcwd->intr_dma);
552 kfree (usb_pcwd);
553}
554
555/**
556 * usb_pcwd_probe
557 *
558 * Called by the usb core when a new device is connected that it thinks
559 * this driver might be interested in.
560 */
561static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_device_id *id)
562{
563 struct usb_device *udev = interface_to_usbdev(interface);
564 struct usb_host_interface *iface_desc;
565 struct usb_endpoint_descriptor *endpoint;
566 struct usb_pcwd_private *usb_pcwd = NULL;
567 int pipe, maxp;
568 int retval = -ENOMEM;
569 int got_fw_rev;
570 unsigned char fw_rev_major, fw_rev_minor;
571 char fw_ver_str[20];
572 unsigned char option_switches, dummy;
573
574 cards_found++;
575 if (cards_found > 1) {
576 printk(KERN_ERR PFX "This driver only supports 1 device\n");
577 return -ENODEV;
578 }
579
580 /* get the active interface descriptor */
581 iface_desc = interface->cur_altsetting;
582
583 /* check out that we have a HID device */
584 if (!(iface_desc->desc.bInterfaceClass == USB_CLASS_HID)) {
585 printk(KERN_ERR PFX "The device isn't a Human Interface Device\n");
586 return -ENODEV;
587 }
588
589 /* check out the endpoint: it has to be Interrupt & IN */
590 endpoint = &iface_desc->endpoint[0].desc;
591
592 if (!((endpoint->bEndpointAddress & USB_DIR_IN) &&
593 ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
594 == USB_ENDPOINT_XFER_INT))) {
595 /* we didn't find a Interrupt endpoint with direction IN */
596 printk(KERN_ERR PFX "Couldn't find an INTR & IN endpoint\n");
597 return -ENODEV;
598 }
599
600 /* get a handle to the interrupt data pipe */
601 pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
602 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
603
604 /* allocate memory for our device and initialize it */
605 usb_pcwd = kmalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
606 if (usb_pcwd == NULL) {
607 printk(KERN_ERR PFX "Out of memory\n");
608 goto error;
609 }
610 memset (usb_pcwd, 0x00, sizeof (*usb_pcwd));
611
612 usb_pcwd_device = usb_pcwd;
613
614 init_MUTEX (&usb_pcwd->sem);
615 usb_pcwd->udev = udev;
616 usb_pcwd->interface = interface;
617 usb_pcwd->interface_number = iface_desc->desc.bInterfaceNumber;
618 usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8);
619
620 /* set up the memory buffer's */
621 if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, SLAB_ATOMIC, &usb_pcwd->intr_dma))) {
622 printk(KERN_ERR PFX "Out of memory\n");
623 goto error;
624 }
625
626 /* allocate the urb's */
627 usb_pcwd->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
628 if (!usb_pcwd->intr_urb) {
629 printk(KERN_ERR PFX "Out of memory\n");
630 goto error;
631 }
632
633 /* initialise the intr urb's */
634 usb_fill_int_urb(usb_pcwd->intr_urb, udev, pipe,
635 usb_pcwd->intr_buffer, usb_pcwd->intr_size,
636 usb_pcwd_intr_done, usb_pcwd, endpoint->bInterval);
637 usb_pcwd->intr_urb->transfer_dma = usb_pcwd->intr_dma;
638 usb_pcwd->intr_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
639
640 /* register our interrupt URB with the USB system */
641 if (usb_submit_urb(usb_pcwd->intr_urb, GFP_KERNEL)) {
642 printk(KERN_ERR PFX "Problem registering interrupt URB\n");
643 retval = -EIO; /* failure */
644 goto error;
645 }
646
647 /* The device exists and can be communicated with */
648 usb_pcwd->exists = 1;
649
650 /* disable card */
651 usb_pcwd_stop(usb_pcwd);
652
653 /* Get the Firmware Version */
654 got_fw_rev = usb_pcwd_send_command(usb_pcwd, CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
655 if (got_fw_rev) {
656 sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
657 } else {
658 sprintf(fw_ver_str, "<card no answer>");
659 }
660
661 printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n",
662 fw_ver_str);
663
664 /* Get switch settings */
665 usb_pcwd_send_command(usb_pcwd, CMD_GET_DIP_SWITCH_SETTINGS, &dummy, &option_switches);
666
667 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
668 option_switches,
669 ((option_switches & 0x10) ? "ON" : "OFF"),
670 ((option_switches & 0x08) ? "ON" : "OFF"));
671
672 /* Check that the heartbeat value is within it's range ; if not reset to the default */
673 if (usb_pcwd_set_heartbeat(usb_pcwd, heartbeat)) {
674 usb_pcwd_set_heartbeat(usb_pcwd, WATCHDOG_HEARTBEAT);
675 printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
676 WATCHDOG_HEARTBEAT);
677 }
678
679 retval = register_reboot_notifier(&usb_pcwd_notifier);
680 if (retval != 0) {
681 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
682 retval);
683 goto error;
684 }
685
686 retval = misc_register(&usb_pcwd_temperature_miscdev);
687 if (retval != 0) {
688 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
689 TEMP_MINOR, retval);
690 goto err_out_unregister_reboot;
691 }
692
693 retval = misc_register(&usb_pcwd_miscdev);
694 if (retval != 0) {
695 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
696 WATCHDOG_MINOR, retval);
697 goto err_out_misc_deregister;
698 }
699
700 /* we can register the device now, as it is ready */
701 usb_set_intfdata (interface, usb_pcwd);
702
703 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
704 heartbeat, nowayout);
705
706 return 0;
707
708err_out_misc_deregister:
709 misc_deregister(&usb_pcwd_temperature_miscdev);
710err_out_unregister_reboot:
711 unregister_reboot_notifier(&usb_pcwd_notifier);
712error:
713 usb_pcwd_delete (usb_pcwd);
714 usb_pcwd_device = NULL;
715 return retval;
716}
717
718
719/**
720 * usb_pcwd_disconnect
721 *
722 * Called by the usb core when the device is removed from the system.
723 *
724 * This routine guarantees that the driver will not submit any more urbs
725 * by clearing dev->udev.
726 */
727static void usb_pcwd_disconnect(struct usb_interface *interface)
728{
729 struct usb_pcwd_private *usb_pcwd;
730
731 /* prevent races with open() */
732 down (&disconnect_sem);
733
734 usb_pcwd = usb_get_intfdata (interface);
735 usb_set_intfdata (interface, NULL);
736
737 down (&usb_pcwd->sem);
738
739 /* Stop the timer before we leave */
740 if (!nowayout)
741 usb_pcwd_stop(usb_pcwd);
742
743 /* We should now stop communicating with the USB PCWD device */
744 usb_pcwd->exists = 0;
745
746 /* Deregister */
747 misc_deregister(&usb_pcwd_miscdev);
748 misc_deregister(&usb_pcwd_temperature_miscdev);
749 unregister_reboot_notifier(&usb_pcwd_notifier);
750
751 up (&usb_pcwd->sem);
752
753 /* Delete the USB PCWD device */
754 usb_pcwd_delete(usb_pcwd);
755
756 cards_found--;
757
758 up (&disconnect_sem);
759
760 printk(KERN_INFO PFX "USB PC Watchdog disconnected\n");
761}
762
763
764
765/**
766 * usb_pcwd_init
767 */
768static int __init usb_pcwd_init(void)
769{
770 int result;
771
772 /* register this driver with the USB subsystem */
773 result = usb_register(&usb_pcwd_driver);
774 if (result) {
775 printk(KERN_ERR PFX "usb_register failed. Error number %d\n",
776 result);
777 return result;
778 }
779
780 printk(KERN_INFO PFX DRIVER_DESC " v" DRIVER_VERSION " (" DRIVER_DATE ")\n");
781 return 0;
782}
783
784
785/**
786 * usb_pcwd_exit
787 */
788static void __exit usb_pcwd_exit(void)
789{
790 /* deregister this driver with the USB subsystem */
791 usb_deregister(&usb_pcwd_driver);
792}
793
794
795module_init (usb_pcwd_init);
796module_exit (usb_pcwd_exit);
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
new file mode 100644
index 000000000000..1699d2c28ce5
--- /dev/null
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -0,0 +1,516 @@
1/* linux/drivers/char/watchdog/s3c2410_wdt.c
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 Watchdog Timer Support
7 *
8 * Based on, softdog.c by Alan Cox,
9 * (c) Copyright 1996 Alan Cox <alan@redhat.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 * Changelog:
26 * 05-Oct-2004 BJD Added semaphore init to stop crashes on open
27 * Fixed tmr_count / wdt_count confusion
28 * Added configurable debug
29 *
30 * 11-Jan-2004 BJD Fixed divide-by-2 in timeout code
31 *
32 * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
33*/
34
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/config.h>
38#include <linux/types.h>
39#include <linux/timer.h>
40#include <linux/miscdevice.h>
41#include <linux/watchdog.h>
42#include <linux/fs.h>
43#include <linux/notifier.h>
44#include <linux/reboot.h>
45#include <linux/init.h>
46#include <linux/device.h>
47#include <linux/interrupt.h>
48
49#include <asm/uaccess.h>
50#include <asm/io.h>
51
52#include <asm/arch/map.h>
53#include <asm/hardware/clock.h>
54
55#undef S3C24XX_VA_WATCHDOG
56#define S3C24XX_VA_WATCHDOG (0)
57
58#include <asm/arch/regs-watchdog.h>
59
60#define PFX "s3c2410-wdt: "
61
62#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
63#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
64
65#ifdef CONFIG_WATCHDOG_NOWAYOUT
66static int nowayout = 1;
67#else
68static int nowayout = 0;
69#endif
70
71static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
72static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;
73static int soft_noboot = 0;
74static int debug = 0;
75
76module_param(tmr_margin, int, 0);
77module_param(tmr_atboot, int, 0);
78module_param(nowayout, int, 0);
79module_param(soft_noboot, int, 0);
80module_param(debug, int, 0);
81
82MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");
83
84MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
85
86MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
87
88MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)");
89
90MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)");
91
92
93typedef enum close_state {
94 CLOSE_STATE_NOT,
95 CLOSE_STATE_ALLOW=0x4021
96} close_state_t;
97
98static DECLARE_MUTEX(open_lock);
99
100static struct resource *wdt_mem;
101static struct resource *wdt_irq;
102static struct clk *wdt_clock;
103static void __iomem *wdt_base;
104static unsigned int wdt_count;
105static close_state_t allow_close;
106
107/* watchdog control routines */
108
109#define DBG(msg...) do { \
110 if (debug) \
111 printk(KERN_INFO msg); \
112 } while(0)
113
114/* functions */
115
116static int s3c2410wdt_keepalive(void)
117{
118 writel(wdt_count, wdt_base + S3C2410_WTCNT);
119 return 0;
120}
121
122static int s3c2410wdt_stop(void)
123{
124 unsigned long wtcon;
125
126 wtcon = readl(wdt_base + S3C2410_WTCON);
127 wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
128 writel(wtcon, wdt_base + S3C2410_WTCON);
129
130 return 0;
131}
132
133static int s3c2410wdt_start(void)
134{
135 unsigned long wtcon;
136
137 s3c2410wdt_stop();
138
139 wtcon = readl(wdt_base + S3C2410_WTCON);
140 wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
141
142 if (soft_noboot) {
143 wtcon |= S3C2410_WTCON_INTEN;
144 wtcon &= ~S3C2410_WTCON_RSTEN;
145 } else {
146 wtcon &= ~S3C2410_WTCON_INTEN;
147 wtcon |= S3C2410_WTCON_RSTEN;
148 }
149
150 DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n",
151 __FUNCTION__, wdt_count, wtcon);
152
153 writel(wdt_count, wdt_base + S3C2410_WTDAT);
154 writel(wdt_count, wdt_base + S3C2410_WTCNT);
155 writel(wtcon, wdt_base + S3C2410_WTCON);
156
157 return 0;
158}
159
160static int s3c2410wdt_set_heartbeat(int timeout)
161{
162 unsigned int freq = clk_get_rate(wdt_clock);
163 unsigned int count;
164 unsigned int divisor = 1;
165 unsigned long wtcon;
166
167 if (timeout < 1)
168 return -EINVAL;
169
170 freq /= 128;
171 count = timeout * freq;
172
173 DBG("%s: count=%d, timeout=%d, freq=%d\n",
174 __FUNCTION__, count, timeout, freq);
175
176 /* if the count is bigger than the watchdog register,
177 then work out what we need to do (and if) we can
178 actually make this value
179 */
180
181 if (count >= 0x10000) {
182 for (divisor = 1; divisor <= 0x100; divisor++) {
183 if ((count / divisor) < 0x10000)
184 break;
185 }
186
187 if ((count / divisor) >= 0x10000) {
188 printk(KERN_ERR PFX "timeout %d too big\n", timeout);
189 return -EINVAL;
190 }
191 }
192
193 tmr_margin = timeout;
194
195 DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n",
196 __FUNCTION__, timeout, divisor, count, count/divisor);
197
198 count /= divisor;
199 wdt_count = count;
200
201 /* update the pre-scaler */
202 wtcon = readl(wdt_base + S3C2410_WTCON);
203 wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;
204 wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);
205
206 writel(count, wdt_base + S3C2410_WTDAT);
207 writel(wtcon, wdt_base + S3C2410_WTCON);
208
209 return 0;
210}
211
212/*
213 * /dev/watchdog handling
214 */
215
216static int s3c2410wdt_open(struct inode *inode, struct file *file)
217{
218 if(down_trylock(&open_lock))
219 return -EBUSY;
220
221 if (nowayout) {
222 __module_get(THIS_MODULE);
223 } else {
224 allow_close = CLOSE_STATE_ALLOW;
225 }
226
227 /* start the timer */
228 s3c2410wdt_start();
229 return nonseekable_open(inode, file);
230}
231
232static int s3c2410wdt_release(struct inode *inode, struct file *file)
233{
234 /*
235 * Shut off the timer.
236 * Lock it in if it's a module and we set nowayout
237 */
238 if (allow_close == CLOSE_STATE_ALLOW) {
239 s3c2410wdt_stop();
240 } else {
241 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
242 s3c2410wdt_keepalive();
243 }
244
245 allow_close = CLOSE_STATE_NOT;
246 up(&open_lock);
247 return 0;
248}
249
250static ssize_t s3c2410wdt_write(struct file *file, const char __user *data,
251 size_t len, loff_t *ppos)
252{
253 /*
254 * Refresh the timer.
255 */
256 if(len) {
257 if (!nowayout) {
258 size_t i;
259
260 /* In case it was set long ago */
261 allow_close = CLOSE_STATE_NOT;
262
263 for (i = 0; i != len; i++) {
264 char c;
265
266 if (get_user(c, data + i))
267 return -EFAULT;
268 if (c == 'V')
269 allow_close = CLOSE_STATE_ALLOW;
270 }
271 }
272
273 s3c2410wdt_keepalive();
274 }
275 return len;
276}
277
278#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
279
280static struct watchdog_info s3c2410_wdt_ident = {
281 .options = OPTIONS,
282 .firmware_version = 0,
283 .identity = "S3C2410 Watchdog",
284};
285
286
287static int s3c2410wdt_ioctl(struct inode *inode, struct file *file,
288 unsigned int cmd, unsigned long arg)
289{
290 void __user *argp = (void __user *)arg;
291 int __user *p = argp;
292 int new_margin;
293
294 switch (cmd) {
295 default:
296 return -ENOIOCTLCMD;
297
298 case WDIOC_GETSUPPORT:
299 return copy_to_user(argp, &s3c2410_wdt_ident,
300 sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0;
301
302 case WDIOC_GETSTATUS:
303 case WDIOC_GETBOOTSTATUS:
304 return put_user(0, p);
305
306 case WDIOC_KEEPALIVE:
307 s3c2410wdt_keepalive();
308 return 0;
309
310 case WDIOC_SETTIMEOUT:
311 if (get_user(new_margin, p))
312 return -EFAULT;
313
314 if (s3c2410wdt_set_heartbeat(new_margin))
315 return -EINVAL;
316
317 s3c2410wdt_keepalive();
318 return put_user(tmr_margin, p);
319
320 case WDIOC_GETTIMEOUT:
321 return put_user(tmr_margin, p);
322 }
323}
324
325/*
326 * Notifier for system down
327 */
328
329static int s3c2410wdt_notify_sys(struct notifier_block *this, unsigned long code,
330 void *unused)
331{
332 if(code==SYS_DOWN || code==SYS_HALT) {
333 /* Turn the WDT off */
334 s3c2410wdt_stop();
335 }
336 return NOTIFY_DONE;
337}
338
339/* kernel interface */
340
341static struct file_operations s3c2410wdt_fops = {
342 .owner = THIS_MODULE,
343 .llseek = no_llseek,
344 .write = s3c2410wdt_write,
345 .ioctl = s3c2410wdt_ioctl,
346 .open = s3c2410wdt_open,
347 .release = s3c2410wdt_release,
348};
349
350static struct miscdevice s3c2410wdt_miscdev = {
351 .minor = WATCHDOG_MINOR,
352 .name = "watchdog",
353 .fops = &s3c2410wdt_fops,
354};
355
356static struct notifier_block s3c2410wdt_notifier = {
357 .notifier_call = s3c2410wdt_notify_sys,
358};
359
360/* interrupt handler code */
361
362static irqreturn_t s3c2410wdt_irq(int irqno, void *param,
363 struct pt_regs *regs)
364{
365 printk(KERN_INFO PFX "Watchdog timer expired!\n");
366
367 s3c2410wdt_keepalive();
368 return IRQ_HANDLED;
369}
370/* device interface */
371
372static int s3c2410wdt_probe(struct device *dev)
373{
374 struct platform_device *pdev = to_platform_device(dev);
375 struct resource *res;
376 int started = 0;
377 int ret;
378 int size;
379
380 DBG("%s: probe=%p, device=%p\n", __FUNCTION__, pdev, dev);
381
382 /* get the memory region for the watchdog timer */
383
384 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
385 if (res == NULL) {
386 printk(KERN_INFO PFX "failed to get memory region resouce\n");
387 return -ENOENT;
388 }
389
390 size = (res->end-res->start)+1;
391 wdt_mem = request_mem_region(res->start, size, pdev->name);
392 if (wdt_mem == NULL) {
393 printk(KERN_INFO PFX "failed to get memory region\n");
394 return -ENOENT;
395 }
396
397 wdt_base = ioremap(res->start, size);
398 if (wdt_base == 0) {
399 printk(KERN_INFO PFX "failed to ioremap() region\n");
400 return -EINVAL;
401 }
402
403 DBG("probe: mapped wdt_base=%p\n", wdt_base);
404
405 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
406 if (res == NULL) {
407 printk(KERN_INFO PFX "failed to get irq resource\n");
408 return -ENOENT;
409 }
410
411 ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, dev);
412 if (ret != 0) {
413 printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
414 return ret;
415 }
416
417 wdt_clock = clk_get(dev, "watchdog");
418 if (wdt_clock == NULL) {
419 printk(KERN_INFO PFX "failed to find watchdog clock source\n");
420 return -ENOENT;
421 }
422
423 clk_use(wdt_clock);
424 clk_enable(wdt_clock);
425
426 /* see if we can actually set the requested timer margin, and if
427 * not, try the default value */
428
429 if (s3c2410wdt_set_heartbeat(tmr_margin)) {
430 started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
431
432 if (started == 0) {
433 printk(KERN_INFO PFX "tmr_margin value out of range, default %d used\n",
434 CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
435 } else {
436 printk(KERN_INFO PFX "default timer value is out of range, cannot start\n");
437 }
438 }
439
440 ret = register_reboot_notifier(&s3c2410wdt_notifier);
441 if (ret) {
442 printk (KERN_ERR PFX "cannot register reboot notifier (%d)\n",
443 ret);
444 return ret;
445 }
446
447 ret = misc_register(&s3c2410wdt_miscdev);
448 if (ret) {
449 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
450 WATCHDOG_MINOR, ret);
451 unregister_reboot_notifier(&s3c2410wdt_notifier);
452 return ret;
453 }
454
455 if (tmr_atboot && started == 0) {
456 printk(KERN_INFO PFX "Starting Watchdog Timer\n");
457 s3c2410wdt_start();
458 }
459
460 return 0;
461}
462
463static int s3c2410wdt_remove(struct device *dev)
464{
465 if (wdt_mem != NULL) {
466 release_resource(wdt_mem);
467 kfree(wdt_mem);
468 wdt_mem = NULL;
469 }
470
471 if (wdt_irq != NULL) {
472 free_irq(wdt_irq->start, dev);
473 wdt_irq = NULL;
474 }
475
476 if (wdt_clock != NULL) {
477 clk_disable(wdt_clock);
478 clk_unuse(wdt_clock);
479 clk_put(wdt_clock);
480 wdt_clock = NULL;
481 }
482
483 misc_deregister(&s3c2410wdt_miscdev);
484 return 0;
485}
486
487static struct device_driver s3c2410wdt_driver = {
488 .name = "s3c2410-wdt",
489 .bus = &platform_bus_type,
490 .probe = s3c2410wdt_probe,
491 .remove = s3c2410wdt_remove,
492};
493
494
495
496static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
497
498static int __init watchdog_init(void)
499{
500 printk(banner);
501 return driver_register(&s3c2410wdt_driver);
502}
503
504static void __exit watchdog_exit(void)
505{
506 driver_unregister(&s3c2410wdt_driver);
507 unregister_reboot_notifier(&s3c2410wdt_notifier);
508}
509
510module_init(watchdog_init);
511module_exit(watchdog_exit);
512
513MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
514MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");
515MODULE_LICENSE("GPL");
516MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c
new file mode 100644
index 000000000000..34e8f7b15e30
--- /dev/null
+++ b/drivers/char/watchdog/sa1100_wdt.c
@@ -0,0 +1,223 @@
1/*
2 * Watchdog driver for the SA11x0/PXA2xx
3 *
4 * (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
5 * Based on SoftDog driver by Alan Cox <alan@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * Neither Oleg Drokin nor iXcelerator.com admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
15 *
16 * (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
17 *
18 * 27/11/2000 Initial release
19 */
20#include <linux/config.h>
21#include <linux/module.h>
22#include <linux/moduleparam.h>
23#include <linux/types.h>
24#include <linux/kernel.h>
25#include <linux/fs.h>
26#include <linux/miscdevice.h>
27#include <linux/watchdog.h>
28#include <linux/init.h>
29
30#ifdef CONFIG_ARCH_PXA
31#include <asm/arch/pxa-regs.h>
32#endif
33
34#include <asm/hardware.h>
35#include <asm/bitops.h>
36#include <asm/uaccess.h>
37
38#define OSCR_FREQ CLOCK_TICK_RATE
39#define SA1100_CLOSE_MAGIC (0x5afc4453)
40
41static unsigned long sa1100wdt_users;
42static int expect_close;
43static int pre_margin;
44static int boot_status;
45#ifdef CONFIG_WATCHDOG_NOWAYOUT
46static int nowayout = 1;
47#else
48static int nowayout = 0;
49#endif
50
51/*
52 * Allow only one person to hold it open
53 */
54static int sa1100dog_open(struct inode *inode, struct file *file)
55{
56 nonseekable_open(inode, file);
57 if (test_and_set_bit(1,&sa1100wdt_users))
58 return -EBUSY;
59
60 /* Activate SA1100 Watchdog timer */
61 OSMR3 = OSCR + pre_margin;
62 OSSR = OSSR_M3;
63 OWER = OWER_WME;
64 OIER |= OIER_E3;
65 return 0;
66}
67
68/*
69 * Shut off the timer.
70 * Lock it in if it's a module and we defined ...NOWAYOUT
71 * Oddly, the watchdog can only be enabled, but we can turn off
72 * the interrupt, which appears to prevent the watchdog timing out.
73 */
74static int sa1100dog_release(struct inode *inode, struct file *file)
75{
76 OSMR3 = OSCR + pre_margin;
77
78 if (expect_close == SA1100_CLOSE_MAGIC) {
79 OIER &= ~OIER_E3;
80 } else {
81 printk(KERN_CRIT "WATCHDOG: WDT device closed unexpectedly. WDT will not stop!\n");
82 }
83
84 clear_bit(1, &sa1100wdt_users);
85 expect_close = 0;
86
87 return 0;
88}
89
90static ssize_t sa1100dog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
91{
92 if (len) {
93 if (!nowayout) {
94 size_t i;
95
96 expect_close = 0;
97
98 for (i = 0; i != len; i++) {
99 char c;
100
101 if (get_user(c, data + i))
102 return -EFAULT;
103 if (c == 'V')
104 expect_close = SA1100_CLOSE_MAGIC;
105 }
106 }
107 /* Refresh OSMR3 timer. */
108 OSMR3 = OSCR + pre_margin;
109 }
110
111 return len;
112}
113
114static struct watchdog_info ident = {
115 .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
116 WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
117 .identity = "SA1100 Watchdog",
118};
119
120static int sa1100dog_ioctl(struct inode *inode, struct file *file,
121 unsigned int cmd, unsigned long arg)
122{
123 int ret = -ENOIOCTLCMD;
124 int time;
125
126 switch (cmd) {
127 case WDIOC_GETSUPPORT:
128 ret = copy_to_user((struct watchdog_info *)arg, &ident,
129 sizeof(ident)) ? -EFAULT : 0;
130 break;
131
132 case WDIOC_GETSTATUS:
133 ret = put_user(0, (int *)arg);
134 break;
135
136 case WDIOC_GETBOOTSTATUS:
137 ret = put_user(boot_status, (int *)arg);
138 break;
139
140 case WDIOC_SETTIMEOUT:
141 ret = get_user(time, (int *)arg);
142 if (ret)
143 break;
144
145 if (time <= 0 || time > 255) {
146 ret = -EINVAL;
147 break;
148 }
149
150 pre_margin = OSCR_FREQ * time;
151 OSMR3 = OSCR + pre_margin;
152 /*fall through*/
153
154 case WDIOC_GETTIMEOUT:
155 ret = put_user(pre_margin / OSCR_FREQ, (int *)arg);
156 break;
157
158 case WDIOC_KEEPALIVE:
159 OSMR3 = OSCR + pre_margin;
160 ret = 0;
161 break;
162 }
163 return ret;
164}
165
166static struct file_operations sa1100dog_fops =
167{
168 .owner = THIS_MODULE,
169 .llseek = no_llseek,
170 .write = sa1100dog_write,
171 .ioctl = sa1100dog_ioctl,
172 .open = sa1100dog_open,
173 .release = sa1100dog_release,
174};
175
176static struct miscdevice sa1100dog_miscdev =
177{
178 .minor = WATCHDOG_MINOR,
179 .name = "SA1100/PXA2xx watchdog",
180 .fops = &sa1100dog_fops,
181};
182
183static int margin __initdata = 60; /* (secs) Default is 1 minute */
184
185static int __init sa1100dog_init(void)
186{
187 int ret;
188
189 /*
190 * Read the reset status, and save it for later. If
191 * we suspend, RCSR will be cleared, and the watchdog
192 * reset reason will be lost.
193 */
194 boot_status = (RCSR & RCSR_WDR) ? WDIOF_CARDRESET : 0;
195 pre_margin = OSCR_FREQ * margin;
196
197 ret = misc_register(&sa1100dog_miscdev);
198 if (ret == 0)
199 printk("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
200 margin);
201
202 return ret;
203}
204
205static void __exit sa1100dog_exit(void)
206{
207 misc_deregister(&sa1100dog_miscdev);
208}
209
210module_init(sa1100dog_init);
211module_exit(sa1100dog_exit);
212
213MODULE_AUTHOR("Oleg Drokin <green@crimea.edu>");
214MODULE_DESCRIPTION("SA1100/PXA2xx Watchdog");
215
216module_param(margin, int, 0);
217MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
218
219module_param(nowayout, int, 0);
220MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
221
222MODULE_LICENSE("GPL");
223MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
new file mode 100644
index 000000000000..d7de9880605a
--- /dev/null
+++ b/drivers/char/watchdog/sbc60xxwdt.c
@@ -0,0 +1,413 @@
1/*
2 * 60xx Single Board Computer Watchdog Timer driver for Linux 2.2.x
3 *
4 * Based on acquirewdt.c by Alan Cox.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * The author does NOT admit liability nor provide warranty for
12 * any of this software. This material is provided "AS-IS" in
13 * the hope that it may be useful for others.
14 *
15 * (c) Copyright 2000 Jakob Oestergaard <jakob@unthought.net>
16 *
17 * 12/4 - 2000 [Initial revision]
18 * 25/4 - 2000 Added /dev/watchdog support
19 * 09/5 - 2001 [smj@oro.net] fixed fop_write to "return 1" on success
20 * 12/4 - 2002 [rob@osinvestor.com] eliminate fop_read
21 * fix possible wdt_is_open race
22 * add CONFIG_WATCHDOG_NOWAYOUT support
23 * remove lock_kernel/unlock_kernel pairs
24 * added KERN_* to printk's
25 * got rid of extraneous comments
26 * changed watchdog_info to correctly reflect what the driver offers
27 * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT,
28 * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls
29 * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces
30 * use module_param
31 * made timeout (the emulated heartbeat) a module_param
32 * made the keepalive ping an internal subroutine
33 * made wdt_stop and wdt_start module params
34 * added extra printk's for startup problems
35 * added MODULE_AUTHOR and MODULE_DESCRIPTION info
36 *
37 *
38 * This WDT driver is different from the other Linux WDT
39 * drivers in the following ways:
40 * *) The driver will ping the watchdog by itself, because this
41 * particular WDT has a very short timeout (one second) and it
42 * would be insane to count on any userspace daemon always
43 * getting scheduled within that time frame.
44 *
45 */
46
47#include <linux/module.h>
48#include <linux/moduleparam.h>
49#include <linux/types.h>
50#include <linux/timer.h>
51#include <linux/jiffies.h>
52#include <linux/miscdevice.h>
53#include <linux/watchdog.h>
54#include <linux/fs.h>
55#include <linux/ioport.h>
56#include <linux/notifier.h>
57#include <linux/reboot.h>
58#include <linux/init.h>
59
60#include <asm/io.h>
61#include <asm/uaccess.h>
62#include <asm/system.h>
63
64#define OUR_NAME "sbc60xxwdt"
65#define PFX OUR_NAME ": "
66
67/*
68 * You must set these - The driver cannot probe for the settings
69 */
70
71static int wdt_stop = 0x45;
72module_param(wdt_stop, int, 0);
73MODULE_PARM_DESC(wdt_stop, "SBC60xx WDT 'stop' io port (default 0x45)");
74
75static int wdt_start = 0x443;
76module_param(wdt_start, int, 0);
77MODULE_PARM_DESC(wdt_start, "SBC60xx WDT 'start' io port (default 0x443)");
78
79/*
80 * The 60xx board can use watchdog timeout values from one second
81 * to several minutes. The default is one second, so if we reset
82 * the watchdog every ~250ms we should be safe.
83 */
84
85#define WDT_INTERVAL (HZ/4+1)
86
87/*
88 * We must not require too good response from the userspace daemon.
89 * Here we require the userspace daemon to send us a heartbeat
90 * char to /dev/watchdog every 30 seconds.
91 * If the daemon pulses us every 25 seconds, we can still afford
92 * a 5 second scheduling delay on the (high priority) daemon. That
93 * should be sufficient for a box under any load.
94 */
95
96#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
97static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
98module_param(timeout, int, 0);
99MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
100
101#ifdef CONFIG_WATCHDOG_NOWAYOUT
102static int nowayout = 1;
103#else
104static int nowayout = 0;
105#endif
106
107module_param(nowayout, int, 0);
108MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
109
110static void wdt_timer_ping(unsigned long);
111static struct timer_list timer;
112static unsigned long next_heartbeat;
113static unsigned long wdt_is_open;
114static char wdt_expect_close;
115
116/*
117 * Whack the dog
118 */
119
120static void wdt_timer_ping(unsigned long data)
121{
122 /* If we got a heartbeat pulse within the WDT_US_INTERVAL
123 * we agree to ping the WDT
124 */
125 if(time_before(jiffies, next_heartbeat))
126 {
127 /* Ping the WDT by reading from wdt_start */
128 inb_p(wdt_start);
129 /* Re-set the timer interval */
130 timer.expires = jiffies + WDT_INTERVAL;
131 add_timer(&timer);
132 } else {
133 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
134 }
135}
136
137/*
138 * Utility routines
139 */
140
141static void wdt_startup(void)
142{
143 next_heartbeat = jiffies + (timeout * HZ);
144
145 /* Start the timer */
146 timer.expires = jiffies + WDT_INTERVAL;
147 add_timer(&timer);
148 printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
149}
150
151static void wdt_turnoff(void)
152{
153 /* Stop the timer */
154 del_timer(&timer);
155 inb_p(wdt_stop);
156 printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
157}
158
159static void wdt_keepalive(void)
160{
161 /* user land ping */
162 next_heartbeat = jiffies + (timeout * HZ);
163}
164
165/*
166 * /dev/watchdog handling
167 */
168
169static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
170{
171 /* See if we got the magic character 'V' and reload the timer */
172 if(count)
173 {
174 if (!nowayout)
175 {
176 size_t ofs;
177
178 /* note: just in case someone wrote the magic character
179 * five months ago... */
180 wdt_expect_close = 0;
181
182 /* scan to see whether or not we got the magic character */
183 for(ofs = 0; ofs != count; ofs++)
184 {
185 char c;
186 if(get_user(c, buf+ofs))
187 return -EFAULT;
188 if(c == 'V')
189 wdt_expect_close = 42;
190 }
191 }
192
193 /* Well, anyhow someone wrote to us, we should return that favour */
194 wdt_keepalive();
195 }
196 return count;
197}
198
199static int fop_open(struct inode * inode, struct file * file)
200{
201 nonseekable_open(inode, file);
202
203 /* Just in case we're already talking to someone... */
204 if(test_and_set_bit(0, &wdt_is_open))
205 return -EBUSY;
206
207 if (nowayout)
208 __module_get(THIS_MODULE);
209
210 /* Good, fire up the show */
211 wdt_startup();
212 return 0;
213}
214
215static int fop_close(struct inode * inode, struct file * file)
216{
217 if(wdt_expect_close == 42)
218 wdt_turnoff();
219 else {
220 del_timer(&timer);
221 printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n");
222 }
223 clear_bit(0, &wdt_is_open);
224 wdt_expect_close = 0;
225 return 0;
226}
227
228static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
229 unsigned long arg)
230{
231 void __user *argp = (void __user *)arg;
232 int __user *p = argp;
233 static struct watchdog_info ident=
234 {
235 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
236 .firmware_version = 1,
237 .identity = "SBC60xx",
238 };
239
240 switch(cmd)
241 {
242 default:
243 return -ENOIOCTLCMD;
244 case WDIOC_GETSUPPORT:
245 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
246 case WDIOC_GETSTATUS:
247 case WDIOC_GETBOOTSTATUS:
248 return put_user(0, p);
249 case WDIOC_KEEPALIVE:
250 wdt_keepalive();
251 return 0;
252 case WDIOC_SETOPTIONS:
253 {
254 int new_options, retval = -EINVAL;
255
256 if(get_user(new_options, p))
257 return -EFAULT;
258
259 if(new_options & WDIOS_DISABLECARD) {
260 wdt_turnoff();
261 retval = 0;
262 }
263
264 if(new_options & WDIOS_ENABLECARD) {
265 wdt_startup();
266 retval = 0;
267 }
268
269 return retval;
270 }
271 case WDIOC_SETTIMEOUT:
272 {
273 int new_timeout;
274
275 if(get_user(new_timeout, p))
276 return -EFAULT;
277
278 if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
279 return -EINVAL;
280
281 timeout = new_timeout;
282 wdt_keepalive();
283 /* Fall through */
284 }
285 case WDIOC_GETTIMEOUT:
286 return put_user(timeout, p);
287 }
288}
289
290static struct file_operations wdt_fops = {
291 .owner = THIS_MODULE,
292 .llseek = no_llseek,
293 .write = fop_write,
294 .open = fop_open,
295 .release = fop_close,
296 .ioctl = fop_ioctl,
297};
298
299static struct miscdevice wdt_miscdev = {
300 .minor = WATCHDOG_MINOR,
301 .name = "watchdog",
302 .fops = &wdt_fops,
303};
304
305/*
306 * Notifier for system down
307 */
308
309static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
310 void *unused)
311{
312 if(code==SYS_DOWN || code==SYS_HALT)
313 wdt_turnoff();
314 return NOTIFY_DONE;
315}
316
317/*
318 * The WDT needs to learn about soft shutdowns in order to
319 * turn the timebomb registers off.
320 */
321
322static struct notifier_block wdt_notifier=
323{
324 .notifier_call = wdt_notify_sys,
325};
326
327static void __exit sbc60xxwdt_unload(void)
328{
329 wdt_turnoff();
330
331 /* Deregister */
332 misc_deregister(&wdt_miscdev);
333
334 unregister_reboot_notifier(&wdt_notifier);
335 if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
336 release_region(wdt_stop,1);
337 release_region(wdt_start,1);
338}
339
340static int __init sbc60xxwdt_init(void)
341{
342 int rc = -EBUSY;
343
344 if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
345 {
346 timeout = WATCHDOG_TIMEOUT;
347 printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
348 timeout);
349 }
350
351 if (!request_region(wdt_start, 1, "SBC 60XX WDT"))
352 {
353 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
354 wdt_start);
355 rc = -EIO;
356 goto err_out;
357 }
358
359 /* We cannot reserve 0x45 - the kernel already has! */
360 if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
361 {
362 if (!request_region(wdt_stop, 1, "SBC 60XX WDT"))
363 {
364 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
365 wdt_stop);
366 rc = -EIO;
367 goto err_out_region1;
368 }
369 }
370
371 init_timer(&timer);
372 timer.function = wdt_timer_ping;
373 timer.data = 0;
374
375 rc = misc_register(&wdt_miscdev);
376 if (rc)
377 {
378 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
379 wdt_miscdev.minor, rc);
380 goto err_out_region2;
381 }
382
383 rc = register_reboot_notifier(&wdt_notifier);
384 if (rc)
385 {
386 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
387 rc);
388 goto err_out_miscdev;
389 }
390
391 printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
392 timeout, nowayout);
393
394 return 0;
395
396err_out_miscdev:
397 misc_deregister(&wdt_miscdev);
398err_out_region2:
399 if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
400 release_region(wdt_stop,1);
401err_out_region1:
402 release_region(wdt_start,1);
403err_out:
404 return rc;
405}
406
407module_init(sbc60xxwdt_init);
408module_exit(sbc60xxwdt_unload);
409
410MODULE_AUTHOR("Jakob Oestergaard <jakob@unthought.net>");
411MODULE_DESCRIPTION("60xx Single Board Computer Watchdog Timer driver");
412MODULE_LICENSE("GPL");
413MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
new file mode 100644
index 000000000000..24401e84729e
--- /dev/null
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -0,0 +1,467 @@
1/*
2 * National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
3 * (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>,
4 * All Rights Reserved.
5 * Based on wdt.c and wdt977.c by Alan Cox and Woody Suwalski respectively.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * The author(s) of this software shall not be held liable for damages
13 * of any nature resulting due to the use of this software. This
14 * software is provided AS-IS with no warranties.
15 *
16 * Changelog:
17 * 20020220 Zwane Mwaikambo Code based on datasheet, no hardware.
18 * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik and Alan Cox.
19 * 20020222 Zwane Mwaikambo Added probing.
20 * 20020225 Zwane Mwaikambo Added ISAPNP support.
21 * 20020412 Rob Radez Broke out start/stop functions
22 * <rob@osinvestor.com> Return proper status instead of temperature warning
23 * Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls
24 * Fix CONFIG_WATCHDOG_NOWAYOUT
25 * 20020530 Joel Becker Add Matt Domsch's nowayout module option
26 * 20030116 Adam Belay Updated to the latest pnp code
27 *
28 */
29
30#include <linux/config.h>
31#include <linux/module.h>
32#include <linux/moduleparam.h>
33#include <linux/miscdevice.h>
34#include <linux/watchdog.h>
35#include <linux/ioport.h>
36#include <linux/spinlock.h>
37#include <linux/notifier.h>
38#include <linux/reboot.h>
39#include <linux/init.h>
40#include <linux/pnp.h>
41#include <linux/fs.h>
42#include <linux/pci.h>
43
44#include <asm/semaphore.h>
45#include <asm/io.h>
46#include <asm/uaccess.h>
47
48#define SC1200_MODULE_VER "build 20020303"
49#define SC1200_MODULE_NAME "sc1200wdt"
50#define PFX SC1200_MODULE_NAME ": "
51
52#define MAX_TIMEOUT 255 /* 255 minutes */
53#define PMIR (io) /* Power Management Index Register */
54#define PMDR (io+1) /* Power Management Data Register */
55
56/* Data Register indexes */
57#define FER1 0x00 /* Function enable register 1 */
58#define FER2 0x01 /* Function enable register 2 */
59#define PMC1 0x02 /* Power Management Ctrl 1 */
60#define PMC2 0x03 /* Power Management Ctrl 2 */
61#define PMC3 0x04 /* Power Management Ctrl 3 */
62#define WDTO 0x05 /* Watchdog timeout register */
63#define WDCF 0x06 /* Watchdog config register */
64#define WDST 0x07 /* Watchdog status register */
65
66/* WDCF bitfields - which devices assert WDO */
67#define KBC_IRQ 0x01 /* Keyboard Controller */
68#define MSE_IRQ 0x02 /* Mouse */
69#define UART1_IRQ 0x03 /* Serial0 */
70#define UART2_IRQ 0x04 /* Serial1 */
71/* 5 -7 are reserved */
72
73static char banner[] __initdata = KERN_INFO PFX SC1200_MODULE_VER;
74static int timeout = 1;
75static int io = -1;
76static int io_len = 2; /* for non plug and play */
77static struct semaphore open_sem;
78static char expect_close;
79static spinlock_t sc1200wdt_lock; /* io port access serialisation */
80
81#if defined CONFIG_PNP
82static int isapnp = 1;
83static struct pnp_dev *wdt_dev;
84
85module_param(isapnp, int, 0);
86MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled");
87#endif
88
89module_param(io, int, 0);
90MODULE_PARM_DESC(io, "io port");
91module_param(timeout, int, 0);
92MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
93
94#ifdef CONFIG_WATCHDOG_NOWAYOUT
95static int nowayout = 1;
96#else
97static int nowayout = 0;
98#endif
99
100module_param(nowayout, int, 0);
101MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
102
103
104
105/* Read from Data Register */
106static inline void sc1200wdt_read_data(unsigned char index, unsigned char *data)
107{
108 spin_lock(&sc1200wdt_lock);
109 outb_p(index, PMIR);
110 *data = inb(PMDR);
111 spin_unlock(&sc1200wdt_lock);
112}
113
114
115/* Write to Data Register */
116static inline void sc1200wdt_write_data(unsigned char index, unsigned char data)
117{
118 spin_lock(&sc1200wdt_lock);
119 outb_p(index, PMIR);
120 outb(data, PMDR);
121 spin_unlock(&sc1200wdt_lock);
122}
123
124
125static void sc1200wdt_start(void)
126{
127 unsigned char reg;
128
129 sc1200wdt_read_data(WDCF, &reg);
130 /* assert WDO when any of the following interrupts are triggered too */
131 reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ);
132 sc1200wdt_write_data(WDCF, reg);
133 /* set the timeout and get the ball rolling */
134 sc1200wdt_write_data(WDTO, timeout);
135}
136
137
138static void sc1200wdt_stop(void)
139{
140 sc1200wdt_write_data(WDTO, 0);
141}
142
143
144/* This returns the status of the WDO signal, inactive high. */
145static inline int sc1200wdt_status(void)
146{
147 unsigned char ret;
148
149 sc1200wdt_read_data(WDST, &ret);
150 /* If the bit is inactive, the watchdog is enabled, so return
151 * KEEPALIVEPING which is a bit of a kludge because there's nothing
152 * else for enabled/disabled status
153 */
154 return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING; /* bits 1 - 7 are undefined */
155}
156
157
158static int sc1200wdt_open(struct inode *inode, struct file *file)
159{
160 nonseekable_open(inode, file);
161
162 /* allow one at a time */
163 if (down_trylock(&open_sem))
164 return -EBUSY;
165
166 if (timeout > MAX_TIMEOUT)
167 timeout = MAX_TIMEOUT;
168
169 sc1200wdt_start();
170 printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
171
172 return 0;
173}
174
175
176static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
177{
178 int new_timeout;
179 void __user *argp = (void __user *)arg;
180 int __user *p = argp;
181 static struct watchdog_info ident = {
182 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
183 .firmware_version = 0,
184 .identity = "PC87307/PC97307",
185 };
186
187 switch (cmd) {
188 default:
189 return -ENOIOCTLCMD; /* Keep Pavel Machek amused ;) */
190
191 case WDIOC_GETSUPPORT:
192 if (copy_to_user(argp, &ident, sizeof ident))
193 return -EFAULT;
194 return 0;
195
196 case WDIOC_GETSTATUS:
197 return put_user(sc1200wdt_status(), p);
198
199 case WDIOC_GETBOOTSTATUS:
200 return put_user(0, p);
201
202 case WDIOC_KEEPALIVE:
203 sc1200wdt_write_data(WDTO, timeout);
204 return 0;
205
206 case WDIOC_SETTIMEOUT:
207 if (get_user(new_timeout, p))
208 return -EFAULT;
209
210 /* the API states this is given in secs */
211 new_timeout /= 60;
212 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
213 return -EINVAL;
214
215 timeout = new_timeout;
216 sc1200wdt_write_data(WDTO, timeout);
217 /* fall through and return the new timeout */
218
219 case WDIOC_GETTIMEOUT:
220 return put_user(timeout * 60, p);
221
222 case WDIOC_SETOPTIONS:
223 {
224 int options, retval = -EINVAL;
225
226 if (get_user(options, p))
227 return -EFAULT;
228
229 if (options & WDIOS_DISABLECARD) {
230 sc1200wdt_stop();
231 retval = 0;
232 }
233
234 if (options & WDIOS_ENABLECARD) {
235 sc1200wdt_start();
236 retval = 0;
237 }
238
239 return retval;
240 }
241 }
242}
243
244
245static int sc1200wdt_release(struct inode *inode, struct file *file)
246{
247 if (expect_close == 42) {
248 sc1200wdt_stop();
249 printk(KERN_INFO PFX "Watchdog disabled\n");
250 } else {
251 sc1200wdt_write_data(WDTO, timeout);
252 printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout);
253 }
254 up(&open_sem);
255 expect_close = 0;
256
257 return 0;
258}
259
260
261static ssize_t sc1200wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
262{
263 if (len) {
264 if (!nowayout) {
265 size_t i;
266
267 expect_close = 0;
268
269 for (i = 0; i != len; i++) {
270 char c;
271
272 if (get_user(c, data+i))
273 return -EFAULT;
274 if (c == 'V')
275 expect_close = 42;
276 }
277 }
278
279 sc1200wdt_write_data(WDTO, timeout);
280 return len;
281 }
282
283 return 0;
284}
285
286
287static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
288{
289 if (code == SYS_DOWN || code == SYS_HALT)
290 sc1200wdt_stop();
291
292 return NOTIFY_DONE;
293}
294
295
296static struct notifier_block sc1200wdt_notifier =
297{
298 .notifier_call = sc1200wdt_notify_sys,
299};
300
301static struct file_operations sc1200wdt_fops =
302{
303 .owner = THIS_MODULE,
304 .llseek = no_llseek,
305 .write = sc1200wdt_write,
306 .ioctl = sc1200wdt_ioctl,
307 .open = sc1200wdt_open,
308 .release = sc1200wdt_release,
309};
310
311static struct miscdevice sc1200wdt_miscdev =
312{
313 .minor = WATCHDOG_MINOR,
314 .name = "watchdog",
315 .fops = &sc1200wdt_fops,
316};
317
318
319static int __init sc1200wdt_probe(void)
320{
321 /* The probe works by reading the PMC3 register's default value of 0x0e
322 * there is one caveat, if the device disables the parallel port or any
323 * of the UARTs we won't be able to detect it.
324 * Nb. This could be done with accuracy by reading the SID registers, but
325 * we don't have access to those io regions.
326 */
327
328 unsigned char reg;
329
330 sc1200wdt_read_data(PMC3, &reg);
331 reg &= 0x0f; /* we don't want the UART busy bits */
332 return (reg == 0x0e) ? 0 : -ENODEV;
333}
334
335
336#if defined CONFIG_PNP
337
338static struct pnp_device_id scl200wdt_pnp_devices[] = {
339 /* National Semiconductor PC87307/PC97307 watchdog component */
340 {.id = "NSC0800", .driver_data = 0},
341 {.id = ""},
342};
343
344static int scl200wdt_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
345{
346 /* this driver only supports one card at a time */
347 if (wdt_dev || !isapnp)
348 return -EBUSY;
349
350 wdt_dev = dev;
351 io = pnp_port_start(wdt_dev, 0);
352 io_len = pnp_port_len(wdt_dev, 0);
353
354 if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
355 printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
356 return -EBUSY;
357 }
358
359 printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n", io, io_len);
360 return 0;
361}
362
363static void scl200wdt_pnp_remove(struct pnp_dev * dev)
364{
365 if (wdt_dev){
366 release_region(io, io_len);
367 wdt_dev = NULL;
368 }
369}
370
371static struct pnp_driver scl200wdt_pnp_driver = {
372 .name = "scl200wdt",
373 .id_table = scl200wdt_pnp_devices,
374 .probe = scl200wdt_pnp_probe,
375 .remove = scl200wdt_pnp_remove,
376};
377
378#endif /* CONFIG_PNP */
379
380
381static int __init sc1200wdt_init(void)
382{
383 int ret;
384
385 printk(banner);
386
387 spin_lock_init(&sc1200wdt_lock);
388 sema_init(&open_sem, 1);
389
390#if defined CONFIG_PNP
391 if (isapnp) {
392 ret = pnp_register_driver(&scl200wdt_pnp_driver);
393 if (ret)
394 goto out_clean;
395 }
396#endif
397
398 if (io == -1) {
399 printk(KERN_ERR PFX "io parameter must be specified\n");
400 ret = -EINVAL;
401 goto out_clean;
402 }
403
404#if defined CONFIG_PNP
405 /* now that the user has specified an IO port and we haven't detected
406 * any devices, disable pnp support */
407 isapnp = 0;
408 pnp_unregister_driver(&scl200wdt_pnp_driver);
409#endif
410
411 if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
412 printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
413 ret = -EBUSY;
414 goto out_clean;
415 }
416
417 ret = sc1200wdt_probe();
418 if (ret)
419 goto out_io;
420
421 ret = register_reboot_notifier(&sc1200wdt_notifier);
422 if (ret) {
423 printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret);
424 goto out_io;
425 }
426
427 ret = misc_register(&sc1200wdt_miscdev);
428 if (ret) {
429 printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
430 goto out_rbt;
431 }
432
433 /* ret = 0 */
434
435out_clean:
436 return ret;
437
438out_rbt:
439 unregister_reboot_notifier(&sc1200wdt_notifier);
440
441out_io:
442 release_region(io, io_len);
443
444 goto out_clean;
445}
446
447
448static void __exit sc1200wdt_exit(void)
449{
450 misc_deregister(&sc1200wdt_miscdev);
451 unregister_reboot_notifier(&sc1200wdt_notifier);
452
453#if defined CONFIG_PNP
454 if(isapnp)
455 pnp_unregister_driver(&scl200wdt_pnp_driver);
456 else
457#endif
458 release_region(io, io_len);
459}
460
461module_init(sc1200wdt_init);
462module_exit(sc1200wdt_exit);
463
464MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
465MODULE_DESCRIPTION("Driver for National Semiconductor PC87307/PC97307 watchdog component");
466MODULE_LICENSE("GPL");
467MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
new file mode 100644
index 000000000000..f6d143e1900d
--- /dev/null
+++ b/drivers/char/watchdog/sc520_wdt.c
@@ -0,0 +1,447 @@
1/*
2 * AMD Elan SC520 processor Watchdog Timer driver
3 *
4 * Based on acquirewdt.c by Alan Cox,
5 * and sbc60xxwdt.c by Jakob Oestergaard <jakob@unthought.net>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * The authors do NOT admit liability nor provide warranty for
13 * any of this software. This material is provided "AS-IS" in
14 * the hope that it may be useful for others.
15 *
16 * (c) Copyright 2001 Scott Jennings <linuxdrivers@oro.net>
17 * 9/27 - 2001 [Initial release]
18 *
19 * Additional fixes Alan Cox
20 * - Fixed formatting
21 * - Removed debug printks
22 * - Fixed SMP built kernel deadlock
23 * - Switched to private locks not lock_kernel
24 * - Used ioremap/writew/readw
25 * - Added NOWAYOUT support
26 * 4/12 - 2002 Changes by Rob Radez <rob@osinvestor.com>
27 * - Change comments
28 * - Eliminate fop_llseek
29 * - Change CONFIG_WATCHDOG_NOWAYOUT semantics
30 * - Add KERN_* tags to printks
31 * - fix possible wdt_is_open race
32 * - Report proper capabilities in watchdog_info
33 * - Add WDIOC_{GETSTATUS, GETBOOTSTATUS, SETTIMEOUT,
34 * GETTIMEOUT, SETOPTIONS} ioctls
35 * 09/8 - 2003 Changes by Wim Van Sebroeck <wim@iguana.be>
36 * - cleanup of trailing spaces
37 * - added extra printk's for startup problems
38 * - use module_param
39 * - made timeout (the emulated heartbeat) a module_param
40 * - made the keepalive ping an internal subroutine
41 * 3/27 - 2004 Changes by Sean Young <sean@mess.org>
42 * - set MMCR_BASE to 0xfffef000
43 * - CBAR does not need to be read
44 * - removed debugging printks
45 *
46 * This WDT driver is different from most other Linux WDT
47 * drivers in that the driver will ping the watchdog by itself,
48 * because this particular WDT has a very short timeout (1.6
49 * seconds) and it would be insane to count on any userspace
50 * daemon always getting scheduled within that time frame.
51 *
52 * This driver uses memory mapped IO, and spinlock.
53 */
54
55#include <linux/module.h>
56#include <linux/moduleparam.h>
57#include <linux/types.h>
58#include <linux/timer.h>
59#include <linux/miscdevice.h>
60#include <linux/watchdog.h>
61#include <linux/fs.h>
62#include <linux/ioport.h>
63#include <linux/notifier.h>
64#include <linux/reboot.h>
65#include <linux/init.h>
66
67#include <asm/io.h>
68#include <asm/uaccess.h>
69#include <asm/system.h>
70
71#define OUR_NAME "sc520_wdt"
72#define PFX OUR_NAME ": "
73
74/*
75 * The AMD Elan SC520 timeout value is 492us times a power of 2 (0-7)
76 *
77 * 0: 492us 2: 1.01s 4: 4.03s 6: 16.22s
78 * 1: 503ms 3: 2.01s 5: 8.05s 7: 32.21s
79 *
80 * We will program the SC520 watchdog for a timeout of 2.01s.
81 * If we reset the watchdog every ~250ms we should be safe.
82 */
83
84#define WDT_INTERVAL (HZ/4+1)
85
86/*
87 * We must not require too good response from the userspace daemon.
88 * Here we require the userspace daemon to send us a heartbeat
89 * char to /dev/watchdog every 30 seconds.
90 */
91
92#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
93static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
94module_param(timeout, int, 0);
95MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
96
97#ifdef CONFIG_WATCHDOG_NOWAYOUT
98static int nowayout = 1;
99#else
100static int nowayout = 0;
101#endif
102
103module_param(nowayout, int, 0);
104MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
105
106/*
107 * AMD Elan SC520 - Watchdog Timer Registers
108 */
109#define MMCR_BASE 0xfffef000 /* The default base address */
110#define OFFS_WDTMRCTL 0xCB0 /* Watchdog Timer Control Register */
111
112/* WDT Control Register bit definitions */
113#define WDT_EXP_SEL_01 0x0001 /* [01] Time-out = 496 us (with 33 Mhz clk). */
114#define WDT_EXP_SEL_02 0x0002 /* [02] Time-out = 508 ms (with 33 Mhz clk). */
115#define WDT_EXP_SEL_03 0x0004 /* [03] Time-out = 1.02 s (with 33 Mhz clk). */
116#define WDT_EXP_SEL_04 0x0008 /* [04] Time-out = 2.03 s (with 33 Mhz clk). */
117#define WDT_EXP_SEL_05 0x0010 /* [05] Time-out = 4.07 s (with 33 Mhz clk). */
118#define WDT_EXP_SEL_06 0x0020 /* [06] Time-out = 8.13 s (with 33 Mhz clk). */
119#define WDT_EXP_SEL_07 0x0040 /* [07] Time-out = 16.27s (with 33 Mhz clk). */
120#define WDT_EXP_SEL_08 0x0080 /* [08] Time-out = 32.54s (with 33 Mhz clk). */
121#define WDT_IRQ_FLG 0x1000 /* [12] Interrupt Request Flag */
122#define WDT_WRST_ENB 0x4000 /* [14] Watchdog Timer Reset Enable */
123#define WDT_ENB 0x8000 /* [15] Watchdog Timer Enable */
124
125static __u16 __iomem *wdtmrctl;
126
127static void wdt_timer_ping(unsigned long);
128static struct timer_list timer;
129static unsigned long next_heartbeat;
130static unsigned long wdt_is_open;
131static char wdt_expect_close;
132static spinlock_t wdt_spinlock;
133
134/*
135 * Whack the dog
136 */
137
138static void wdt_timer_ping(unsigned long data)
139{
140 /* If we got a heartbeat pulse within the WDT_US_INTERVAL
141 * we agree to ping the WDT
142 */
143 if(time_before(jiffies, next_heartbeat))
144 {
145 /* Ping the WDT */
146 spin_lock(&wdt_spinlock);
147 writew(0xAAAA, wdtmrctl);
148 writew(0x5555, wdtmrctl);
149 spin_unlock(&wdt_spinlock);
150
151 /* Re-set the timer interval */
152 timer.expires = jiffies + WDT_INTERVAL;
153 add_timer(&timer);
154 } else {
155 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
156 }
157}
158
159/*
160 * Utility routines
161 */
162
163static void wdt_config(int writeval)
164{
165 __u16 dummy;
166 unsigned long flags;
167
168 /* buy some time (ping) */
169 spin_lock_irqsave(&wdt_spinlock, flags);
170 dummy=readw(wdtmrctl); /* ensure write synchronization */
171 writew(0xAAAA, wdtmrctl);
172 writew(0x5555, wdtmrctl);
173 /* unlock WDT = make WDT configuration register writable one time */
174 writew(0x3333, wdtmrctl);
175 writew(0xCCCC, wdtmrctl);
176 /* write WDT configuration register */
177 writew(writeval, wdtmrctl);
178 spin_unlock_irqrestore(&wdt_spinlock, flags);
179}
180
181static int wdt_startup(void)
182{
183 next_heartbeat = jiffies + (timeout * HZ);
184
185 /* Start the timer */
186 timer.expires = jiffies + WDT_INTERVAL;
187 add_timer(&timer);
188
189 /* Start the watchdog */
190 wdt_config(WDT_ENB | WDT_WRST_ENB | WDT_EXP_SEL_04);
191
192 printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
193 return 0;
194}
195
196static int wdt_turnoff(void)
197{
198 /* Stop the timer */
199 del_timer(&timer);
200
201 /* Stop the watchdog */
202 wdt_config(0);
203
204 printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
205 return 0;
206}
207
208static int wdt_keepalive(void)
209{
210 /* user land ping */
211 next_heartbeat = jiffies + (timeout * HZ);
212 return 0;
213}
214
215static int wdt_set_heartbeat(int t)
216{
217 if ((t < 1) || (t > 3600)) /* arbitrary upper limit */
218 return -EINVAL;
219
220 timeout = t;
221 return 0;
222}
223
224/*
225 * /dev/watchdog handling
226 */
227
228static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
229{
230 /* See if we got the magic character 'V' and reload the timer */
231 if(count) {
232 if (!nowayout) {
233 size_t ofs;
234
235 /* note: just in case someone wrote the magic character
236 * five months ago... */
237 wdt_expect_close = 0;
238
239 /* now scan */
240 for(ofs = 0; ofs != count; ofs++) {
241 char c;
242 if (get_user(c, buf + ofs))
243 return -EFAULT;
244 if(c == 'V')
245 wdt_expect_close = 42;
246 }
247 }
248
249 /* Well, anyhow someone wrote to us, we should return that favour */
250 wdt_keepalive();
251 }
252 return count;
253}
254
255static int fop_open(struct inode * inode, struct file * file)
256{
257 nonseekable_open(inode, file);
258
259 /* Just in case we're already talking to someone... */
260 if(test_and_set_bit(0, &wdt_is_open))
261 return -EBUSY;
262 if (nowayout)
263 __module_get(THIS_MODULE);
264
265 /* Good, fire up the show */
266 wdt_startup();
267 return 0;
268}
269
270static int fop_close(struct inode * inode, struct file * file)
271{
272 if(wdt_expect_close == 42) {
273 wdt_turnoff();
274 } else {
275 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
276 wdt_keepalive();
277 }
278 clear_bit(0, &wdt_is_open);
279 wdt_expect_close = 0;
280 return 0;
281}
282
283static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
284 unsigned long arg)
285{
286 void __user *argp = (void __user *)arg;
287 int __user *p = argp;
288 static struct watchdog_info ident = {
289 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
290 .firmware_version = 1,
291 .identity = "SC520",
292 };
293
294 switch(cmd)
295 {
296 default:
297 return -ENOIOCTLCMD;
298 case WDIOC_GETSUPPORT:
299 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
300 case WDIOC_GETSTATUS:
301 case WDIOC_GETBOOTSTATUS:
302 return put_user(0, p);
303 case WDIOC_KEEPALIVE:
304 wdt_keepalive();
305 return 0;
306 case WDIOC_SETOPTIONS:
307 {
308 int new_options, retval = -EINVAL;
309
310 if(get_user(new_options, p))
311 return -EFAULT;
312
313 if(new_options & WDIOS_DISABLECARD) {
314 wdt_turnoff();
315 retval = 0;
316 }
317
318 if(new_options & WDIOS_ENABLECARD) {
319 wdt_startup();
320 retval = 0;
321 }
322
323 return retval;
324 }
325 case WDIOC_SETTIMEOUT:
326 {
327 int new_timeout;
328
329 if(get_user(new_timeout, p))
330 return -EFAULT;
331
332 if(wdt_set_heartbeat(new_timeout))
333 return -EINVAL;
334
335 wdt_keepalive();
336 /* Fall through */
337 }
338 case WDIOC_GETTIMEOUT:
339 return put_user(timeout, p);
340 }
341}
342
343static struct file_operations wdt_fops = {
344 .owner = THIS_MODULE,
345 .llseek = no_llseek,
346 .write = fop_write,
347 .open = fop_open,
348 .release = fop_close,
349 .ioctl = fop_ioctl,
350};
351
352static struct miscdevice wdt_miscdev = {
353 .minor = WATCHDOG_MINOR,
354 .name = "watchdog",
355 .fops = &wdt_fops,
356};
357
358/*
359 * Notifier for system down
360 */
361
362static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
363 void *unused)
364{
365 if(code==SYS_DOWN || code==SYS_HALT)
366 wdt_turnoff();
367 return NOTIFY_DONE;
368}
369
370/*
371 * The WDT needs to learn about soft shutdowns in order to
372 * turn the timebomb registers off.
373 */
374
375static struct notifier_block wdt_notifier = {
376 .notifier_call = wdt_notify_sys,
377};
378
379static void __exit sc520_wdt_unload(void)
380{
381 if (!nowayout)
382 wdt_turnoff();
383
384 /* Deregister */
385 misc_deregister(&wdt_miscdev);
386 unregister_reboot_notifier(&wdt_notifier);
387 iounmap(wdtmrctl);
388}
389
390static int __init sc520_wdt_init(void)
391{
392 int rc = -EBUSY;
393
394 spin_lock_init(&wdt_spinlock);
395
396 init_timer(&timer);
397 timer.function = wdt_timer_ping;
398 timer.data = 0;
399
400 /* Check that the timeout value is within it's range ; if not reset to the default */
401 if (wdt_set_heartbeat(timeout)) {
402 wdt_set_heartbeat(WATCHDOG_TIMEOUT);
403 printk(KERN_INFO PFX "timeout value must be 1<=timeout<=3600, using %d\n",
404 WATCHDOG_TIMEOUT);
405 }
406
407 wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2);
408 if (!wdtmrctl) {
409 printk(KERN_ERR PFX "Unable to remap memory\n");
410 rc = -ENOMEM;
411 goto err_out_region2;
412 }
413
414 rc = register_reboot_notifier(&wdt_notifier);
415 if (rc) {
416 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
417 rc);
418 goto err_out_ioremap;
419 }
420
421 rc = misc_register(&wdt_miscdev);
422 if (rc) {
423 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
424 WATCHDOG_MINOR, rc);
425 goto err_out_notifier;
426 }
427
428 printk(KERN_INFO PFX "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
429 timeout,nowayout);
430
431 return 0;
432
433err_out_notifier:
434 unregister_reboot_notifier(&wdt_notifier);
435err_out_ioremap:
436 iounmap(wdtmrctl);
437err_out_region2:
438 return rc;
439}
440
441module_init(sc520_wdt_init);
442module_exit(sc520_wdt_unload);
443
444MODULE_AUTHOR("Scott and Bill Jennings");
445MODULE_DESCRIPTION("Driver for watchdog timer in AMD \"Elan\" SC520 uProcessor");
446MODULE_LICENSE("GPL");
447MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
new file mode 100644
index 000000000000..b569670e4ed5
--- /dev/null
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -0,0 +1,274 @@
1/* drivers/char/watchdog/scx200_wdt.c
2
3 National Semiconductor SCx200 Watchdog support
4
5 Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
6
7 Some code taken from:
8 National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
9 (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version.
15
16 The author(s) of this software shall not be held liable for damages
17 of any nature resulting due to the use of this software. This
18 software is provided AS-IS with no warranties. */
19
20#include <linux/config.h>
21#include <linux/module.h>
22#include <linux/moduleparam.h>
23#include <linux/init.h>
24#include <linux/miscdevice.h>
25#include <linux/watchdog.h>
26#include <linux/notifier.h>
27#include <linux/reboot.h>
28#include <linux/fs.h>
29#include <linux/pci.h>
30#include <linux/scx200.h>
31
32#include <asm/uaccess.h>
33#include <asm/io.h>
34
35#define NAME "scx200_wdt"
36
37MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
38MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
39MODULE_LICENSE("GPL");
40MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
41
42#ifndef CONFIG_WATCHDOG_NOWAYOUT
43#define CONFIG_WATCHDOG_NOWAYOUT 0
44#endif
45
46static int margin = 60; /* in seconds */
47module_param(margin, int, 0);
48MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
49
50static int nowayout = CONFIG_WATCHDOG_NOWAYOUT;
51module_param(nowayout, int, 0);
52MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
53
54static u16 wdto_restart;
55static struct semaphore open_semaphore;
56static char expect_close;
57
58/* Bits of the WDCNFG register */
59#define W_ENABLE 0x00fa /* Enable watchdog */
60#define W_DISABLE 0x0000 /* Disable watchdog */
61
62/* The scaling factor for the timer, this depends on the value of W_ENABLE */
63#define W_SCALE (32768/1024)
64
65static void scx200_wdt_ping(void)
66{
67 outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO);
68}
69
70static void scx200_wdt_update_margin(void)
71{
72 printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
73 wdto_restart = margin * W_SCALE;
74}
75
76static void scx200_wdt_enable(void)
77{
78 printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n",
79 wdto_restart);
80
81 outw(0, scx200_cb_base + SCx200_WDT_WDTO);
82 outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS);
83 outw(W_ENABLE, scx200_cb_base + SCx200_WDT_WDCNFG);
84
85 scx200_wdt_ping();
86}
87
88static void scx200_wdt_disable(void)
89{
90 printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
91
92 outw(0, scx200_cb_base + SCx200_WDT_WDTO);
93 outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS);
94 outw(W_DISABLE, scx200_cb_base + SCx200_WDT_WDCNFG);
95}
96
97static int scx200_wdt_open(struct inode *inode, struct file *file)
98{
99 /* only allow one at a time */
100 if (down_trylock(&open_semaphore))
101 return -EBUSY;
102 scx200_wdt_enable();
103
104 return nonseekable_open(inode, file);
105}
106
107static int scx200_wdt_release(struct inode *inode, struct file *file)
108{
109 if (expect_close != 42) {
110 printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
111 } else if (!nowayout) {
112 scx200_wdt_disable();
113 }
114 expect_close = 0;
115 up(&open_semaphore);
116
117 return 0;
118}
119
120static int scx200_wdt_notify_sys(struct notifier_block *this,
121 unsigned long code, void *unused)
122{
123 if (code == SYS_HALT || code == SYS_POWER_OFF)
124 if (!nowayout)
125 scx200_wdt_disable();
126
127 return NOTIFY_DONE;
128}
129
130static struct notifier_block scx200_wdt_notifier =
131{
132 .notifier_call = scx200_wdt_notify_sys,
133};
134
135static ssize_t scx200_wdt_write(struct file *file, const char __user *data,
136 size_t len, loff_t *ppos)
137{
138 /* check for a magic close character */
139 if (len)
140 {
141 size_t i;
142
143 scx200_wdt_ping();
144
145 expect_close = 0;
146 for (i = 0; i < len; ++i) {
147 char c;
148 if (get_user(c, data+i))
149 return -EFAULT;
150 if (c == 'V')
151 expect_close = 42;
152 }
153
154 return len;
155 }
156
157 return 0;
158}
159
160static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
161 unsigned int cmd, unsigned long arg)
162{
163 void __user *argp = (void __user *)arg;
164 int __user *p = argp;
165 static struct watchdog_info ident = {
166 .identity = "NatSemi SCx200 Watchdog",
167 .firmware_version = 1,
168 .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
169 };
170 int new_margin;
171
172 switch (cmd) {
173 default:
174 return -ENOIOCTLCMD;
175 case WDIOC_GETSUPPORT:
176 if(copy_to_user(argp, &ident, sizeof(ident)))
177 return -EFAULT;
178 return 0;
179 case WDIOC_GETSTATUS:
180 case WDIOC_GETBOOTSTATUS:
181 if (put_user(0, p))
182 return -EFAULT;
183 return 0;
184 case WDIOC_KEEPALIVE:
185 scx200_wdt_ping();
186 return 0;
187 case WDIOC_SETTIMEOUT:
188 if (get_user(new_margin, p))
189 return -EFAULT;
190 if (new_margin < 1)
191 return -EINVAL;
192 margin = new_margin;
193 scx200_wdt_update_margin();
194 scx200_wdt_ping();
195 case WDIOC_GETTIMEOUT:
196 if (put_user(margin, p))
197 return -EFAULT;
198 return 0;
199 }
200}
201
202static struct file_operations scx200_wdt_fops = {
203 .owner = THIS_MODULE,
204 .llseek = no_llseek,
205 .write = scx200_wdt_write,
206 .ioctl = scx200_wdt_ioctl,
207 .open = scx200_wdt_open,
208 .release = scx200_wdt_release,
209};
210
211static struct miscdevice scx200_wdt_miscdev = {
212 .minor = WATCHDOG_MINOR,
213 .name = NAME,
214 .fops = &scx200_wdt_fops,
215};
216
217static int __init scx200_wdt_init(void)
218{
219 int r;
220
221 printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
222
223 /* check that we have found the configuration block */
224 if (!scx200_cb_present())
225 return -ENODEV;
226
227 if (!request_region(scx200_cb_base + SCx200_WDT_OFFSET,
228 SCx200_WDT_SIZE,
229 "NatSemi SCx200 Watchdog")) {
230 printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
231 return -EBUSY;
232 }
233
234 scx200_wdt_update_margin();
235 scx200_wdt_disable();
236
237 sema_init(&open_semaphore, 1);
238
239 r = misc_register(&scx200_wdt_miscdev);
240 if (r) {
241 release_region(scx200_cb_base + SCx200_WDT_OFFSET,
242 SCx200_WDT_SIZE);
243 return r;
244 }
245
246 r = register_reboot_notifier(&scx200_wdt_notifier);
247 if (r) {
248 printk(KERN_ERR NAME ": unable to register reboot notifier");
249 misc_deregister(&scx200_wdt_miscdev);
250 release_region(scx200_cb_base + SCx200_WDT_OFFSET,
251 SCx200_WDT_SIZE);
252 return r;
253 }
254
255 return 0;
256}
257
258static void __exit scx200_wdt_cleanup(void)
259{
260 unregister_reboot_notifier(&scx200_wdt_notifier);
261 misc_deregister(&scx200_wdt_miscdev);
262 release_region(scx200_cb_base + SCx200_WDT_OFFSET,
263 SCx200_WDT_SIZE);
264}
265
266module_init(scx200_wdt_init);
267module_exit(scx200_wdt_cleanup);
268
269/*
270 Local variables:
271 compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
272 c-basic-offset: 8
273 End:
274*/
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c
new file mode 100644
index 000000000000..3bc9272a474c
--- /dev/null
+++ b/drivers/char/watchdog/shwdt.c
@@ -0,0 +1,452 @@
1/*
2 * drivers/char/watchdog/shwdt.c
3 *
4 * Watchdog driver for integrated watchdog in the SuperH processors.
5 *
6 * Copyright (C) 2001, 2002, 2003 Paul Mundt <lethal@linux-sh.org>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
14 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
15 *
16 * 19-Apr-2002 Rob Radez <rob@osinvestor.com>
17 * Added expect close support, made emulated timeout runtime changeable
18 * general cleanups, add some ioctls
19 */
20#include <linux/config.h>
21#include <linux/module.h>
22#include <linux/moduleparam.h>
23#include <linux/init.h>
24#include <linux/types.h>
25#include <linux/miscdevice.h>
26#include <linux/watchdog.h>
27#include <linux/reboot.h>
28#include <linux/notifier.h>
29#include <linux/ioport.h>
30#include <linux/fs.h>
31
32#include <asm/io.h>
33#include <asm/uaccess.h>
34#include <asm/watchdog.h>
35
36#define PFX "shwdt: "
37
38/*
39 * Default clock division ratio is 5.25 msecs. For an additional table of
40 * values, consult the asm-sh/watchdog.h. Overload this at module load
41 * time.
42 *
43 * In order for this to work reliably we need to have HZ set to 1000 or
44 * something quite higher than 100 (or we need a proper high-res timer
45 * implementation that will deal with this properly), otherwise the 10ms
46 * resolution of a jiffy is enough to trigger the overflow. For things like
47 * the SH-4 and SH-5, this isn't necessarily that big of a problem, though
48 * for the SH-2 and SH-3, this isn't recommended unless the WDT is absolutely
49 * necssary.
50 *
51 * As a result of this timing problem, the only modes that are particularly
52 * feasible are the 4096 and the 2048 divisors, which yeild 5.25 and 2.62ms
53 * overflow periods respectively.
54 *
55 * Also, since we can't really expect userspace to be responsive enough
56 * before the overflow happens, we maintain two seperate timers .. One in
57 * the kernel for clearing out WOVF every 2ms or so (again, this depends on
58 * HZ == 1000), and another for monitoring userspace writes to the WDT device.
59 *
60 * As such, we currently use a configurable heartbeat interval which defaults
61 * to 30s. In this case, the userspace daemon is only responsible for periodic
62 * writes to the device before the next heartbeat is scheduled. If the daemon
63 * misses its deadline, the kernel timer will allow the WDT to overflow.
64 */
65static int clock_division_ratio = WTCSR_CKS_4096;
66
67#define next_ping_period(cks) msecs_to_jiffies(cks - 4)
68
69static unsigned long shwdt_is_open;
70static struct watchdog_info sh_wdt_info;
71static char shwdt_expect_close;
72static struct timer_list timer;
73static unsigned long next_heartbeat;
74
75#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
76static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
77
78#ifdef CONFIG_WATCHDOG_NOWAYOUT
79static int nowayout = 1;
80#else
81static int nowayout = 0;
82#endif
83
84/**
85 * sh_wdt_start - Start the Watchdog
86 *
87 * Starts the watchdog.
88 */
89static void sh_wdt_start(void)
90{
91 __u8 csr;
92
93 next_heartbeat = jiffies + (heartbeat * HZ);
94 mod_timer(&timer, next_ping_period(clock_division_ratio));
95
96 csr = sh_wdt_read_csr();
97 csr |= WTCSR_WT | clock_division_ratio;
98 sh_wdt_write_csr(csr);
99
100 sh_wdt_write_cnt(0);
101
102 /*
103 * These processors have a bit of an inconsistent initialization
104 * process.. starting with SH-3, RSTS was moved to WTCSR, and the
105 * RSTCSR register was removed.
106 *
107 * On the SH-2 however, in addition with bits being in different
108 * locations, we must deal with RSTCSR outright..
109 */
110 csr = sh_wdt_read_csr();
111 csr |= WTCSR_TME;
112 csr &= ~WTCSR_RSTS;
113 sh_wdt_write_csr(csr);
114
115#ifdef CONFIG_CPU_SH2
116 /*
117 * Whoever came up with the RSTCSR semantics must've been smoking
118 * some of the good stuff, since in addition to the WTCSR/WTCNT write
119 * brain-damage, it's managed to fuck things up one step further..
120 *
121 * If we need to clear the WOVF bit, the upper byte has to be 0xa5..
122 * but if we want to touch RSTE or RSTS, the upper byte has to be
123 * 0x5a..
124 */
125 csr = sh_wdt_read_rstcsr();
126 csr &= ~RSTCSR_RSTS;
127 sh_wdt_write_rstcsr(csr);
128#endif
129}
130
131/**
132 * sh_wdt_stop - Stop the Watchdog
133 *
134 * Stops the watchdog.
135 */
136static void sh_wdt_stop(void)
137{
138 __u8 csr;
139
140 del_timer(&timer);
141
142 csr = sh_wdt_read_csr();
143 csr &= ~WTCSR_TME;
144 sh_wdt_write_csr(csr);
145}
146
147/**
148 * sh_wdt_keepalive - Keep the Userspace Watchdog Alive
149 *
150 * The Userspace watchdog got a KeepAlive: schedule the next heartbeat.
151 */
152static void sh_wdt_keepalive(void)
153{
154 next_heartbeat = jiffies + (heartbeat * HZ);
155}
156
157/**
158 * sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat
159 *
160 * Set the Userspace Watchdog heartbeat
161 */
162static int sh_wdt_set_heartbeat(int t)
163{
164 if ((t < 1) || (t > 3600)) /* arbitrary upper limit */
165 return -EINVAL;
166
167 heartbeat = t;
168 return 0;
169}
170
171/**
172 * sh_wdt_ping - Ping the Watchdog
173 *
174 * @data: Unused
175 *
176 * Clears overflow bit, resets timer counter.
177 */
178static void sh_wdt_ping(unsigned long data)
179{
180 if (time_before(jiffies, next_heartbeat)) {
181 __u8 csr;
182
183 csr = sh_wdt_read_csr();
184 csr &= ~WTCSR_IOVF;
185 sh_wdt_write_csr(csr);
186
187 sh_wdt_write_cnt(0);
188
189 mod_timer(&timer, next_ping_period(clock_division_ratio));
190 } else {
191 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
192 }
193}
194
195/**
196 * sh_wdt_open - Open the Device
197 *
198 * @inode: inode of device
199 * @file: file handle of device
200 *
201 * Watchdog device is opened and started.
202 */
203static int sh_wdt_open(struct inode *inode, struct file *file)
204{
205 if (test_and_set_bit(0, &shwdt_is_open))
206 return -EBUSY;
207 if (nowayout)
208 __module_get(THIS_MODULE);
209
210 sh_wdt_start();
211
212 return nonseekable_open(inode, file);
213}
214
215/**
216 * sh_wdt_close - Close the Device
217 *
218 * @inode: inode of device
219 * @file: file handle of device
220 *
221 * Watchdog device is closed and stopped.
222 */
223static int sh_wdt_close(struct inode *inode, struct file *file)
224{
225 if (shwdt_expect_close == 42) {
226 sh_wdt_stop();
227 } else {
228 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
229 sh_wdt_keepalive();
230 }
231
232 clear_bit(0, &shwdt_is_open);
233 shwdt_expect_close = 0;
234
235 return 0;
236}
237
238/**
239 * sh_wdt_write - Write to Device
240 *
241 * @file: file handle of device
242 * @buf: buffer to write
243 * @count: length of buffer
244 * @ppos: offset
245 *
246 * Pings the watchdog on write.
247 */
248static ssize_t sh_wdt_write(struct file *file, const char *buf,
249 size_t count, loff_t *ppos)
250{
251 if (count) {
252 if (!nowayout) {
253 size_t i;
254
255 shwdt_expect_close = 0;
256
257 for (i = 0; i != count; i++) {
258 char c;
259 if (get_user(c, buf + i))
260 return -EFAULT;
261 if (c == 'V')
262 shwdt_expect_close = 42;
263 }
264 }
265 sh_wdt_keepalive();
266 }
267
268 return count;
269}
270
271/**
272 * sh_wdt_ioctl - Query Device
273 *
274 * @inode: inode of device
275 * @file: file handle of device
276 * @cmd: watchdog command
277 * @arg: argument
278 *
279 * Query basic information from the device or ping it, as outlined by the
280 * watchdog API.
281 */
282static int sh_wdt_ioctl(struct inode *inode, struct file *file,
283 unsigned int cmd, unsigned long arg)
284{
285 int new_heartbeat;
286 int options, retval = -EINVAL;
287
288 switch (cmd) {
289 case WDIOC_GETSUPPORT:
290 return copy_to_user((struct watchdog_info *)arg,
291 &sh_wdt_info,
292 sizeof(sh_wdt_info)) ? -EFAULT : 0;
293 case WDIOC_GETSTATUS:
294 case WDIOC_GETBOOTSTATUS:
295 return put_user(0, (int *)arg);
296 case WDIOC_KEEPALIVE:
297 sh_wdt_keepalive();
298 return 0;
299 case WDIOC_SETTIMEOUT:
300 if (get_user(new_heartbeat, (int *)arg))
301 return -EFAULT;
302
303 if (sh_wdt_set_heartbeat(new_heartbeat))
304 return -EINVAL;
305
306 sh_wdt_keepalive();
307 /* Fall */
308 case WDIOC_GETTIMEOUT:
309 return put_user(heartbeat, (int *)arg);
310 case WDIOC_SETOPTIONS:
311 if (get_user(options, (int *)arg))
312 return -EFAULT;
313
314 if (options & WDIOS_DISABLECARD) {
315 sh_wdt_stop();
316 retval = 0;
317 }
318
319 if (options & WDIOS_ENABLECARD) {
320 sh_wdt_start();
321 retval = 0;
322 }
323
324 return retval;
325 default:
326 return -ENOIOCTLCMD;
327 }
328
329 return 0;
330}
331
332/**
333 * sh_wdt_notify_sys - Notifier Handler
334 *
335 * @this: notifier block
336 * @code: notifier event
337 * @unused: unused
338 *
339 * Handles specific events, such as turning off the watchdog during a
340 * shutdown event.
341 */
342static int sh_wdt_notify_sys(struct notifier_block *this,
343 unsigned long code, void *unused)
344{
345 if (code == SYS_DOWN || code == SYS_HALT) {
346 sh_wdt_stop();
347 }
348
349 return NOTIFY_DONE;
350}
351
352static struct file_operations sh_wdt_fops = {
353 .owner = THIS_MODULE,
354 .llseek = no_llseek,
355 .write = sh_wdt_write,
356 .ioctl = sh_wdt_ioctl,
357 .open = sh_wdt_open,
358 .release = sh_wdt_close,
359};
360
361static struct watchdog_info sh_wdt_info = {
362 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
363 .firmware_version = 1,
364 .identity = "SH WDT",
365};
366
367static struct notifier_block sh_wdt_notifier = {
368 .notifier_call = sh_wdt_notify_sys,
369};
370
371static struct miscdevice sh_wdt_miscdev = {
372 .minor = WATCHDOG_MINOR,
373 .name = "watchdog",
374 .fops = &sh_wdt_fops,
375};
376
377/**
378 * sh_wdt_init - Initialize module
379 *
380 * Registers the device and notifier handler. Actual device
381 * initialization is handled by sh_wdt_open().
382 */
383static int __init sh_wdt_init(void)
384{
385 int rc;
386
387 if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) {
388 clock_division_ratio = WTCSR_CKS_4096;
389 printk(KERN_INFO PFX "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n",
390 clock_division_ratio);
391 }
392
393 if (sh_wdt_set_heartbeat(heartbeat))
394 {
395 heartbeat = WATCHDOG_HEARTBEAT;
396 printk(KERN_INFO PFX "heartbeat value must be 1<=x<=3600, using %d\n",
397 heartbeat);
398 }
399
400 init_timer(&timer);
401 timer.function = sh_wdt_ping;
402 timer.data = 0;
403
404 rc = register_reboot_notifier(&sh_wdt_notifier);
405 if (rc) {
406 printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", rc);
407 return rc;
408 }
409
410 rc = misc_register(&sh_wdt_miscdev);
411 if (rc) {
412 printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n",
413 sh_wdt_miscdev.minor, rc);
414 unregister_reboot_notifier(&sh_wdt_notifier);
415 return rc;
416 }
417
418 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
419 heartbeat, nowayout);
420
421 return 0;
422}
423
424/**
425 * sh_wdt_exit - Deinitialize module
426 *
427 * Unregisters the device and notifier handler. Actual device
428 * deinitialization is handled by sh_wdt_close().
429 */
430static void __exit sh_wdt_exit(void)
431{
432 misc_deregister(&sh_wdt_miscdev);
433 unregister_reboot_notifier(&sh_wdt_notifier);
434}
435
436MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
437MODULE_DESCRIPTION("SuperH watchdog driver");
438MODULE_LICENSE("GPL");
439MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
440
441module_param(clock_division_ratio, int, 0);
442MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7.");
443
444module_param(heartbeat, int, 0);
445MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
446
447module_param(nowayout, int, 0);
448MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
449
450module_init(sh_wdt_init);
451module_exit(sh_wdt_exit);
452
diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
new file mode 100644
index 000000000000..117903498a01
--- /dev/null
+++ b/drivers/char/watchdog/softdog.c
@@ -0,0 +1,309 @@
1/*
2 * SoftDog 0.07: A Software Watchdog Device
3 *
4 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
5 * http://www.redhat.com
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
15 *
16 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
17 *
18 * Software only watchdog driver. Unlike its big brother the WDT501P
19 * driver this won't always recover a failed machine.
20 *
21 * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
22 * Modularised.
23 * Added soft_margin; use upon insmod to change the timer delay.
24 * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
25 * minors.
26 *
27 * 19980911 Alan Cox
28 * Made SMP safe for 2.3.x
29 *
30 * 20011127 Joel Becker (jlbec@evilplan.org>
31 * Added soft_noboot; Allows testing the softdog trigger without
32 * requiring a recompile.
33 * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
34 *
35 * 20020530 Joel Becker <joel.becker@oracle.com>
36 * Added Matt Domsch's nowayout module option.
37 */
38
39#include <linux/module.h>
40#include <linux/moduleparam.h>
41#include <linux/config.h>
42#include <linux/types.h>
43#include <linux/timer.h>
44#include <linux/miscdevice.h>
45#include <linux/watchdog.h>
46#include <linux/fs.h>
47#include <linux/notifier.h>
48#include <linux/reboot.h>
49#include <linux/init.h>
50#include <asm/uaccess.h>
51
52#define PFX "SoftDog: "
53
54#define TIMER_MARGIN 60 /* Default is 60 seconds */
55static int soft_margin = TIMER_MARGIN; /* in seconds */
56module_param(soft_margin, int, 0);
57MODULE_PARM_DESC(soft_margin, "Watchdog soft_margin in seconds. (0<soft_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")");
58
59#ifdef CONFIG_WATCHDOG_NOWAYOUT
60static int nowayout = 1;
61#else
62static int nowayout = 0;
63#endif
64
65module_param(nowayout, int, 0);
66MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
67
68#ifdef ONLY_TESTING
69static int soft_noboot = 1;
70#else
71static int soft_noboot = 0;
72#endif /* ONLY_TESTING */
73
74module_param(soft_noboot, int, 0);
75MODULE_PARM_DESC(soft_noboot, "Softdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)");
76
77/*
78 * Our timer
79 */
80
81static void watchdog_fire(unsigned long);
82
83static struct timer_list watchdog_ticktock =
84 TIMER_INITIALIZER(watchdog_fire, 0, 0);
85static unsigned long timer_alive;
86static char expect_close;
87
88
89/*
90 * If the timer expires..
91 */
92
93static void watchdog_fire(unsigned long data)
94{
95 if (soft_noboot)
96 printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
97 else
98 {
99 printk(KERN_CRIT PFX "Initiating system reboot.\n");
100 machine_restart(NULL);
101 printk(KERN_CRIT PFX "Reboot didn't ?????\n");
102 }
103}
104
105/*
106 * Softdog operations
107 */
108
109static int softdog_keepalive(void)
110{
111 mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
112 return 0;
113}
114
115static int softdog_stop(void)
116{
117 del_timer(&watchdog_ticktock);
118 return 0;
119}
120
121static int softdog_set_heartbeat(int t)
122{
123 if ((t < 0x0001) || (t > 0xFFFF))
124 return -EINVAL;
125
126 soft_margin = t;
127 return 0;
128}
129
130/*
131 * /dev/watchdog handling
132 */
133
134static int softdog_open(struct inode *inode, struct file *file)
135{
136 if(test_and_set_bit(0, &timer_alive))
137 return -EBUSY;
138 if (nowayout)
139 __module_get(THIS_MODULE);
140 /*
141 * Activate timer
142 */
143 softdog_keepalive();
144 return nonseekable_open(inode, file);
145}
146
147static int softdog_release(struct inode *inode, struct file *file)
148{
149 /*
150 * Shut off the timer.
151 * Lock it in if it's a module and we set nowayout
152 */
153 if (expect_close == 42) {
154 softdog_stop();
155 } else {
156 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
157 softdog_keepalive();
158 }
159 clear_bit(0, &timer_alive);
160 expect_close = 0;
161 return 0;
162}
163
164static ssize_t softdog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
165{
166 /*
167 * Refresh the timer.
168 */
169 if(len) {
170 if (!nowayout) {
171 size_t i;
172
173 /* In case it was set long ago */
174 expect_close = 0;
175
176 for (i = 0; i != len; i++) {
177 char c;
178
179 if (get_user(c, data + i))
180 return -EFAULT;
181 if (c == 'V')
182 expect_close = 42;
183 }
184 }
185 softdog_keepalive();
186 }
187 return len;
188}
189
190static int softdog_ioctl(struct inode *inode, struct file *file,
191 unsigned int cmd, unsigned long arg)
192{
193 void __user *argp = (void __user *)arg;
194 int __user *p = argp;
195 int new_margin;
196 static struct watchdog_info ident = {
197 .options = WDIOF_SETTIMEOUT |
198 WDIOF_KEEPALIVEPING |
199 WDIOF_MAGICCLOSE,
200 .firmware_version = 0,
201 .identity = "Software Watchdog",
202 };
203 switch (cmd) {
204 default:
205 return -ENOIOCTLCMD;
206 case WDIOC_GETSUPPORT:
207 return copy_to_user(argp, &ident,
208 sizeof(ident)) ? -EFAULT : 0;
209 case WDIOC_GETSTATUS:
210 case WDIOC_GETBOOTSTATUS:
211 return put_user(0, p);
212 case WDIOC_KEEPALIVE:
213 softdog_keepalive();
214 return 0;
215 case WDIOC_SETTIMEOUT:
216 if (get_user(new_margin, p))
217 return -EFAULT;
218 if (softdog_set_heartbeat(new_margin))
219 return -EINVAL;
220 softdog_keepalive();
221 /* Fall */
222 case WDIOC_GETTIMEOUT:
223 return put_user(soft_margin, p);
224 }
225}
226
227/*
228 * Notifier for system down
229 */
230
231static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
232 void *unused)
233{
234 if(code==SYS_DOWN || code==SYS_HALT) {
235 /* Turn the WDT off */
236 softdog_stop();
237 }
238 return NOTIFY_DONE;
239}
240
241/*
242 * Kernel Interfaces
243 */
244
245static struct file_operations softdog_fops = {
246 .owner = THIS_MODULE,
247 .llseek = no_llseek,
248 .write = softdog_write,
249 .ioctl = softdog_ioctl,
250 .open = softdog_open,
251 .release = softdog_release,
252};
253
254static struct miscdevice softdog_miscdev = {
255 .minor = WATCHDOG_MINOR,
256 .name = "watchdog",
257 .fops = &softdog_fops,
258};
259
260static struct notifier_block softdog_notifier = {
261 .notifier_call = softdog_notify_sys,
262};
263
264static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 initialized. soft_noboot=%d soft_margin=%d sec (nowayout= %d)\n";
265
266static int __init watchdog_init(void)
267{
268 int ret;
269
270 /* Check that the soft_margin value is within it's range ; if not reset to the default */
271 if (softdog_set_heartbeat(soft_margin)) {
272 softdog_set_heartbeat(TIMER_MARGIN);
273 printk(KERN_INFO PFX "soft_margin value must be 0<soft_margin<65536, using %d\n",
274 TIMER_MARGIN);
275 }
276
277 ret = register_reboot_notifier(&softdog_notifier);
278 if (ret) {
279 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
280 ret);
281 return ret;
282 }
283
284 ret = misc_register(&softdog_miscdev);
285 if (ret) {
286 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
287 WATCHDOG_MINOR, ret);
288 unregister_reboot_notifier(&softdog_notifier);
289 return ret;
290 }
291
292 printk(banner, soft_noboot, soft_margin, nowayout);
293
294 return 0;
295}
296
297static void __exit watchdog_exit(void)
298{
299 misc_deregister(&softdog_miscdev);
300 unregister_reboot_notifier(&softdog_notifier);
301}
302
303module_init(watchdog_init);
304module_exit(watchdog_exit);
305
306MODULE_AUTHOR("Alan Cox");
307MODULE_DESCRIPTION("Software Watchdog Device Driver");
308MODULE_LICENSE("GPL");
309MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
new file mode 100644
index 000000000000..813c97038f84
--- /dev/null
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -0,0 +1,362 @@
1/*
2 * w83627hf WDT driver
3 *
4 * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
5 *
6 * Based on advantechwdt.c which is based on wdt.c.
7 * Original copyright messages:
8 *
9 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
10 *
11 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
12 * http://www.redhat.com
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version
17 * 2 of the License, or (at your option) any later version.
18 *
19 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
20 * warranty for any of this software. This material is provided
21 * "AS-IS" and at no charge.
22 *
23 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
24 */
25
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/types.h>
29#include <linux/miscdevice.h>
30#include <linux/watchdog.h>
31#include <linux/fs.h>
32#include <linux/ioport.h>
33#include <linux/notifier.h>
34#include <linux/reboot.h>
35#include <linux/init.h>
36
37#include <asm/io.h>
38#include <asm/uaccess.h>
39#include <asm/system.h>
40
41#define WATCHDOG_NAME "w83627hf WDT"
42#define PFX WATCHDOG_NAME ": "
43#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
44
45static unsigned long wdt_is_open;
46static char expect_close;
47
48/* You must set this - there is no sane way to probe for this board. */
49static int wdt_io = 0x2E;
50module_param(wdt_io, int, 0);
51MODULE_PARM_DESC(wdt_io, "w83627hf WDT io port (default 0x2E)");
52
53static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
54module_param(timeout, int, 0);
55MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
56
57#ifdef CONFIG_WATCHDOG_NOWAYOUT
58static int nowayout = 1;
59#else
60static int nowayout = 0;
61#endif
62
63module_param(nowayout, int, 0);
64MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
65
66/*
67 * Kernel methods.
68 */
69
70#define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */
71#define WDT_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */
72#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
73
74static void
75w83627hf_select_wd_register(void)
76{
77 outb_p(0x87, WDT_EFER); /* Enter extended function mode */
78 outb_p(0x87, WDT_EFER); /* Again according to manual */
79
80 outb_p(0x07, WDT_EFER); /* point to logical device number reg */
81 outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
82 outb_p(0x30, WDT_EFER); /* select CR30 */
83 outb_p(0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
84}
85
86static void
87w83627hf_unselect_wd_register(void)
88{
89 outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
90}
91
92/* tyan motherboards seem to set F5 to 0x4C ?
93 * So explicitly init to appropriate value. */
94static void
95w83627hf_init(void)
96{
97 unsigned char t;
98
99 w83627hf_select_wd_register();
100
101 outb_p(0xF5, WDT_EFER); /* Select CRF5 */
102 t=inb_p(WDT_EFDR); /* read CRF5 */
103 t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */
104 outb_p(t, WDT_EFDR); /* Write back to CRF5 */
105
106 w83627hf_unselect_wd_register();
107}
108
109static void
110wdt_ctrl(int timeout)
111{
112 w83627hf_select_wd_register();
113
114 outb_p(0xF6, WDT_EFER); /* Select CRF6 */
115 outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */
116
117 w83627hf_unselect_wd_register();
118}
119
120static int
121wdt_ping(void)
122{
123 wdt_ctrl(timeout);
124 return 0;
125}
126
127static int
128wdt_disable(void)
129{
130 wdt_ctrl(0);
131 return 0;
132}
133
134static int
135wdt_set_heartbeat(int t)
136{
137 if ((t < 1) || (t > 63))
138 return -EINVAL;
139
140 timeout = t;
141 return 0;
142}
143
144static ssize_t
145wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
146{
147 if (count) {
148 if (!nowayout) {
149 size_t i;
150
151 expect_close = 0;
152
153 for (i = 0; i != count; i++) {
154 char c;
155 if (get_user(c, buf+i))
156 return -EFAULT;
157 if (c == 'V')
158 expect_close = 42;
159 }
160 }
161 wdt_ping();
162 }
163 return count;
164}
165
166static int
167wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
168 unsigned long arg)
169{
170 void __user *argp = (void __user *)arg;
171 int __user *p = argp;
172 int new_timeout;
173 static struct watchdog_info ident = {
174 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
175 .firmware_version = 1,
176 .identity = "W83627HF WDT",
177 };
178
179 switch (cmd) {
180 case WDIOC_GETSUPPORT:
181 if (copy_to_user(argp, &ident, sizeof(ident)))
182 return -EFAULT;
183 break;
184
185 case WDIOC_GETSTATUS:
186 case WDIOC_GETBOOTSTATUS:
187 return put_user(0, p);
188
189 case WDIOC_KEEPALIVE:
190 wdt_ping();
191 break;
192
193 case WDIOC_SETTIMEOUT:
194 if (get_user(new_timeout, p))
195 return -EFAULT;
196 if (wdt_set_heartbeat(new_timeout))
197 return -EINVAL;
198 wdt_ping();
199 /* Fall */
200
201 case WDIOC_GETTIMEOUT:
202 return put_user(timeout, p);
203
204 case WDIOC_SETOPTIONS:
205 {
206 int options, retval = -EINVAL;
207
208 if (get_user(options, p))
209 return -EFAULT;
210
211 if (options & WDIOS_DISABLECARD) {
212 wdt_disable();
213 retval = 0;
214 }
215
216 if (options & WDIOS_ENABLECARD) {
217 wdt_ping();
218 retval = 0;
219 }
220
221 return retval;
222 }
223
224 default:
225 return -ENOIOCTLCMD;
226 }
227 return 0;
228}
229
230static int
231wdt_open(struct inode *inode, struct file *file)
232{
233 if (test_and_set_bit(0, &wdt_is_open))
234 return -EBUSY;
235 /*
236 * Activate
237 */
238
239 wdt_ping();
240 return nonseekable_open(inode, file);
241}
242
243static int
244wdt_close(struct inode *inode, struct file *file)
245{
246 if (expect_close == 42) {
247 wdt_disable();
248 } else {
249 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
250 wdt_ping();
251 }
252 expect_close = 0;
253 clear_bit(0, &wdt_is_open);
254 return 0;
255}
256
257/*
258 * Notifier for system down
259 */
260
261static int
262wdt_notify_sys(struct notifier_block *this, unsigned long code,
263 void *unused)
264{
265 if (code == SYS_DOWN || code == SYS_HALT) {
266 /* Turn the WDT off */
267 wdt_disable();
268 }
269 return NOTIFY_DONE;
270}
271
272/*
273 * Kernel Interfaces
274 */
275
276static struct file_operations wdt_fops = {
277 .owner = THIS_MODULE,
278 .llseek = no_llseek,
279 .write = wdt_write,
280 .ioctl = wdt_ioctl,
281 .open = wdt_open,
282 .release = wdt_close,
283};
284
285static struct miscdevice wdt_miscdev = {
286 .minor = WATCHDOG_MINOR,
287 .name = "watchdog",
288 .fops = &wdt_fops,
289};
290
291/*
292 * The WDT needs to learn about soft shutdowns in order to
293 * turn the timebomb registers off.
294 */
295
296static struct notifier_block wdt_notifier = {
297 .notifier_call = wdt_notify_sys,
298};
299
300static int __init
301wdt_init(void)
302{
303 int ret;
304
305 printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n");
306
307 if (wdt_set_heartbeat(timeout)) {
308 wdt_set_heartbeat(WATCHDOG_TIMEOUT);
309 printk (KERN_INFO PFX "timeout value must be 1<=timeout<=63, using %d\n",
310 WATCHDOG_TIMEOUT);
311 }
312
313 if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
314 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
315 wdt_io);
316 ret = -EIO;
317 goto out;
318 }
319
320 w83627hf_init();
321
322 ret = register_reboot_notifier(&wdt_notifier);
323 if (ret != 0) {
324 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
325 ret);
326 goto unreg_regions;
327 }
328
329 ret = misc_register(&wdt_miscdev);
330 if (ret != 0) {
331 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
332 WATCHDOG_MINOR, ret);
333 goto unreg_reboot;
334 }
335
336 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
337 timeout, nowayout);
338
339out:
340 return ret;
341unreg_reboot:
342 unregister_reboot_notifier(&wdt_notifier);
343unreg_regions:
344 release_region(wdt_io, 1);
345 goto out;
346}
347
348static void __exit
349wdt_exit(void)
350{
351 misc_deregister(&wdt_miscdev);
352 unregister_reboot_notifier(&wdt_notifier);
353 release_region(wdt_io,1);
354}
355
356module_init(wdt_init);
357module_exit(wdt_exit);
358
359MODULE_LICENSE("GPL");
360MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>");
361MODULE_DESCRIPTION("w38627hf WDT driver");
362MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c
new file mode 100644
index 000000000000..bccbd4d6ac2d
--- /dev/null
+++ b/drivers/char/watchdog/w83877f_wdt.c
@@ -0,0 +1,426 @@
1/*
2 * W83877F Computer Watchdog Timer driver
3 *
4 * Based on acquirewdt.c by Alan Cox,
5 * and sbc60xxwdt.c by Jakob Oestergaard <jakob@unthought.net>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * The authors do NOT admit liability nor provide warranty for
13 * any of this software. This material is provided "AS-IS" in
14 * the hope that it may be useful for others.
15 *
16 * (c) Copyright 2001 Scott Jennings <linuxdrivers@oro.net>
17 *
18 * 4/19 - 2001 [Initial revision]
19 * 9/27 - 2001 Added spinlocking
20 * 4/12 - 2002 [rob@osinvestor.com] Eliminate extra comments
21 * Eliminate fop_read
22 * Eliminate extra spin_unlock
23 * Added KERN_* tags to printks
24 * add CONFIG_WATCHDOG_NOWAYOUT support
25 * fix possible wdt_is_open race
26 * changed watchdog_info to correctly reflect what the driver offers
27 * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT,
28 * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls
29 * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces
30 * added extra printk's for startup problems
31 * use module_param
32 * made timeout (the emulated heartbeat) a module_param
33 * made the keepalive ping an internal subroutine
34 *
35 * This WDT driver is different from most other Linux WDT
36 * drivers in that the driver will ping the watchdog by itself,
37 * because this particular WDT has a very short timeout (1.6
38 * seconds) and it would be insane to count on any userspace
39 * daemon always getting scheduled within that time frame.
40 */
41
42#include <linux/module.h>
43#include <linux/moduleparam.h>
44#include <linux/types.h>
45#include <linux/timer.h>
46#include <linux/jiffies.h>
47#include <linux/miscdevice.h>
48#include <linux/watchdog.h>
49#include <linux/fs.h>
50#include <linux/ioport.h>
51#include <linux/notifier.h>
52#include <linux/reboot.h>
53#include <linux/init.h>
54#include <asm/io.h>
55#include <asm/uaccess.h>
56#include <asm/system.h>
57
58#define OUR_NAME "w83877f_wdt"
59#define PFX OUR_NAME ": "
60
61#define ENABLE_W83877F_PORT 0x3F0
62#define ENABLE_W83877F 0x87
63#define DISABLE_W83877F 0xAA
64#define WDT_PING 0x443
65#define WDT_REGISTER 0x14
66#define WDT_ENABLE 0x9C
67#define WDT_DISABLE 0x8C
68
69/*
70 * The W83877F seems to be fixed at 1.6s timeout (at least on the
71 * EMACS PC-104 board I'm using). If we reset the watchdog every
72 * ~250ms we should be safe. */
73
74#define WDT_INTERVAL (HZ/4+1)
75
76/*
77 * We must not require too good response from the userspace daemon.
78 * Here we require the userspace daemon to send us a heartbeat
79 * char to /dev/watchdog every 30 seconds.
80 */
81
82#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
83static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
84module_param(timeout, int, 0);
85MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
86
87
88#ifdef CONFIG_WATCHDOG_NOWAYOUT
89static int nowayout = 1;
90#else
91static int nowayout = 0;
92#endif
93
94module_param(nowayout, int, 0);
95MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
96
97static void wdt_timer_ping(unsigned long);
98static struct timer_list timer;
99static unsigned long next_heartbeat;
100static unsigned long wdt_is_open;
101static char wdt_expect_close;
102static spinlock_t wdt_spinlock;
103
104/*
105 * Whack the dog
106 */
107
108static void wdt_timer_ping(unsigned long data)
109{
110 /* If we got a heartbeat pulse within the WDT_US_INTERVAL
111 * we agree to ping the WDT
112 */
113 if(time_before(jiffies, next_heartbeat))
114 {
115 /* Ping the WDT */
116 spin_lock(&wdt_spinlock);
117
118 /* Ping the WDT by reading from WDT_PING */
119 inb_p(WDT_PING);
120
121 /* Re-set the timer interval */
122 timer.expires = jiffies + WDT_INTERVAL;
123 add_timer(&timer);
124
125 spin_unlock(&wdt_spinlock);
126
127 } else {
128 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
129 }
130}
131
132/*
133 * Utility routines
134 */
135
136static void wdt_change(int writeval)
137{
138 unsigned long flags;
139 spin_lock_irqsave(&wdt_spinlock, flags);
140
141 /* buy some time */
142 inb_p(WDT_PING);
143
144 /* make W83877F available */
145 outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT);
146 outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT);
147
148 /* enable watchdog */
149 outb_p(WDT_REGISTER, ENABLE_W83877F_PORT);
150 outb_p(writeval, ENABLE_W83877F_PORT+1);
151
152 /* lock the W8387FF away */
153 outb_p(DISABLE_W83877F, ENABLE_W83877F_PORT);
154
155 spin_unlock_irqrestore(&wdt_spinlock, flags);
156}
157
158static void wdt_startup(void)
159{
160 next_heartbeat = jiffies + (timeout * HZ);
161
162 /* Start the timer */
163 timer.expires = jiffies + WDT_INTERVAL;
164 add_timer(&timer);
165
166 wdt_change(WDT_ENABLE);
167
168 printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
169}
170
171static void wdt_turnoff(void)
172{
173 /* Stop the timer */
174 del_timer(&timer);
175
176 wdt_change(WDT_DISABLE);
177
178 printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
179}
180
181static void wdt_keepalive(void)
182{
183 /* user land ping */
184 next_heartbeat = jiffies + (timeout * HZ);
185}
186
187/*
188 * /dev/watchdog handling
189 */
190
191static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
192{
193 /* See if we got the magic character 'V' and reload the timer */
194 if(count)
195 {
196 if (!nowayout)
197 {
198 size_t ofs;
199
200 /* note: just in case someone wrote the magic character
201 * five months ago... */
202 wdt_expect_close = 0;
203
204 /* scan to see whether or not we got the magic character */
205 for(ofs = 0; ofs != count; ofs++)
206 {
207 char c;
208 if (get_user(c, buf + ofs))
209 return -EFAULT;
210 if (c == 'V')
211 wdt_expect_close = 42;
212 }
213 }
214
215 /* someone wrote to us, we should restart timer */
216 wdt_keepalive();
217 }
218 return count;
219}
220
221static int fop_open(struct inode * inode, struct file * file)
222{
223 /* Just in case we're already talking to someone... */
224 if(test_and_set_bit(0, &wdt_is_open))
225 return -EBUSY;
226
227 /* Good, fire up the show */
228 wdt_startup();
229 return nonseekable_open(inode, file);
230}
231
232static int fop_close(struct inode * inode, struct file * file)
233{
234 if(wdt_expect_close == 42)
235 wdt_turnoff();
236 else {
237 del_timer(&timer);
238 printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n");
239 }
240 clear_bit(0, &wdt_is_open);
241 wdt_expect_close = 0;
242 return 0;
243}
244
245static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
246 unsigned long arg)
247{
248 void __user *argp = (void __user *)arg;
249 int __user *p = argp;
250 static struct watchdog_info ident=
251 {
252 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
253 .firmware_version = 1,
254 .identity = "W83877F",
255 };
256
257 switch(cmd)
258 {
259 default:
260 return -ENOIOCTLCMD;
261 case WDIOC_GETSUPPORT:
262 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
263 case WDIOC_GETSTATUS:
264 case WDIOC_GETBOOTSTATUS:
265 return put_user(0, p);
266 case WDIOC_KEEPALIVE:
267 wdt_keepalive();
268 return 0;
269 case WDIOC_SETOPTIONS:
270 {
271 int new_options, retval = -EINVAL;
272
273 if(get_user(new_options, p))
274 return -EFAULT;
275
276 if(new_options & WDIOS_DISABLECARD) {
277 wdt_turnoff();
278 retval = 0;
279 }
280
281 if(new_options & WDIOS_ENABLECARD) {
282 wdt_startup();
283 retval = 0;
284 }
285
286 return retval;
287 }
288 case WDIOC_SETTIMEOUT:
289 {
290 int new_timeout;
291
292 if(get_user(new_timeout, p))
293 return -EFAULT;
294
295 if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
296 return -EINVAL;
297
298 timeout = new_timeout;
299 wdt_keepalive();
300 /* Fall through */
301 }
302 case WDIOC_GETTIMEOUT:
303 return put_user(timeout, p);
304 }
305}
306
307static struct file_operations wdt_fops = {
308 .owner = THIS_MODULE,
309 .llseek = no_llseek,
310 .write = fop_write,
311 .open = fop_open,
312 .release = fop_close,
313 .ioctl = fop_ioctl,
314};
315
316static struct miscdevice wdt_miscdev = {
317 .minor = WATCHDOG_MINOR,
318 .name = "watchdog",
319 .fops = &wdt_fops,
320};
321
322/*
323 * Notifier for system down
324 */
325
326static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
327 void *unused)
328{
329 if(code==SYS_DOWN || code==SYS_HALT)
330 wdt_turnoff();
331 return NOTIFY_DONE;
332}
333
334/*
335 * The WDT needs to learn about soft shutdowns in order to
336 * turn the timebomb registers off.
337 */
338
339static struct notifier_block wdt_notifier=
340{
341 .notifier_call = wdt_notify_sys,
342};
343
344static void __exit w83877f_wdt_unload(void)
345{
346 wdt_turnoff();
347
348 /* Deregister */
349 misc_deregister(&wdt_miscdev);
350
351 unregister_reboot_notifier(&wdt_notifier);
352 release_region(WDT_PING,1);
353 release_region(ENABLE_W83877F_PORT,2);
354}
355
356static int __init w83877f_wdt_init(void)
357{
358 int rc = -EBUSY;
359
360 spin_lock_init(&wdt_spinlock);
361
362 if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
363 {
364 timeout = WATCHDOG_TIMEOUT;
365 printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
366 timeout);
367 }
368
369 if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT"))
370 {
371 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
372 ENABLE_W83877F_PORT);
373 rc = -EIO;
374 goto err_out;
375 }
376
377 if (!request_region(WDT_PING, 1, "W8387FF WDT"))
378 {
379 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
380 WDT_PING);
381 rc = -EIO;
382 goto err_out_region1;
383 }
384
385 init_timer(&timer);
386 timer.function = wdt_timer_ping;
387 timer.data = 0;
388
389 rc = misc_register(&wdt_miscdev);
390 if (rc)
391 {
392 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
393 wdt_miscdev.minor, rc);
394 goto err_out_region2;
395 }
396
397 rc = register_reboot_notifier(&wdt_notifier);
398 if (rc)
399 {
400 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
401 rc);
402 goto err_out_miscdev;
403 }
404
405 printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
406 timeout, nowayout);
407
408 return 0;
409
410err_out_miscdev:
411 misc_deregister(&wdt_miscdev);
412err_out_region2:
413 release_region(WDT_PING,1);
414err_out_region1:
415 release_region(ENABLE_W83877F_PORT,2);
416err_out:
417 return rc;
418}
419
420module_init(w83877f_wdt_init);
421module_exit(w83877f_wdt_unload);
422
423MODULE_AUTHOR("Scott and Bill Jennings");
424MODULE_DESCRIPTION("Driver for watchdog timer in w83877f chip");
425MODULE_LICENSE("GPL");
426MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c
new file mode 100644
index 000000000000..abb0bea45c02
--- /dev/null
+++ b/drivers/char/watchdog/wafer5823wdt.c
@@ -0,0 +1,330 @@
1/*
2 * ICP Wafer 5823 Single Board Computer WDT driver
3 * http://www.icpamerica.com/wafer_5823.php
4 * May also work on other similar models
5 *
6 * (c) Copyright 2002 Justin Cormack <justin@street-vision.com>
7 *
8 * Release 0.02
9 *
10 * Based on advantechwdt.c which is based on wdt.c.
11 * Original copyright messages:
12 *
13 * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
14 * http://www.redhat.com
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version
19 * 2 of the License, or (at your option) any later version.
20 *
21 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
22 * warranty for any of this software. This material is provided
23 * "AS-IS" and at no charge.
24 *
25 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
26 *
27 */
28
29#include <linux/module.h>
30#include <linux/moduleparam.h>
31#include <linux/miscdevice.h>
32#include <linux/watchdog.h>
33#include <linux/fs.h>
34#include <linux/ioport.h>
35#include <linux/notifier.h>
36#include <linux/reboot.h>
37#include <linux/init.h>
38#include <linux/spinlock.h>
39#include <asm/io.h>
40#include <asm/uaccess.h>
41
42#define WATCHDOG_NAME "Wafer 5823 WDT"
43#define PFX WATCHDOG_NAME ": "
44#define WD_TIMO 60 /* 60 sec default timeout */
45
46static unsigned long wafwdt_is_open;
47static char expect_close;
48static spinlock_t wafwdt_lock;
49
50/*
51 * You must set these - there is no sane way to probe for this board.
52 *
53 * To enable, write the timeout value in seconds (1 to 255) to I/O
54 * port WDT_START, then read the port to start the watchdog. To pat
55 * the dog, read port WDT_STOP to stop the timer, then read WDT_START
56 * to restart it again.
57 */
58
59static int wdt_stop = 0x843;
60static int wdt_start = 0x443;
61
62static int timeout = WD_TIMO; /* in seconds */
63module_param(timeout, int, 0);
64MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WD_TIMO) ".");
65
66#ifdef CONFIG_WATCHDOG_NOWAYOUT
67static int nowayout = 1;
68#else
69static int nowayout = 0;
70#endif
71
72module_param(nowayout, int, 0);
73MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
74
75static void wafwdt_ping(void)
76{
77 /* pat watchdog */
78 spin_lock(&wafwdt_lock);
79 inb_p(wdt_stop);
80 inb_p(wdt_start);
81 spin_unlock(&wafwdt_lock);
82}
83
84static void wafwdt_start(void)
85{
86 /* start up watchdog */
87 outb_p(timeout, wdt_start);
88 inb_p(wdt_start);
89}
90
91static void
92wafwdt_stop(void)
93{
94 /* stop watchdog */
95 inb_p(wdt_stop);
96}
97
98static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
99{
100 /* See if we got the magic character 'V' and reload the timer */
101 if (count) {
102 if (!nowayout) {
103 size_t i;
104
105 /* In case it was set long ago */
106 expect_close = 0;
107
108 /* scan to see whether or not we got the magic character */
109 for (i = 0; i != count; i++) {
110 char c;
111 if (get_user(c, buf + i))
112 return -EFAULT;
113 if (c == 'V')
114 expect_close = 42;
115 }
116 }
117 /* Well, anyhow someone wrote to us, we should return that favour */
118 wafwdt_ping();
119 }
120 return count;
121}
122
123static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
124 unsigned long arg)
125{
126 int new_timeout;
127 void __user *argp = (void __user *)arg;
128 int __user *p = argp;
129 static struct watchdog_info ident = {
130 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
131 .firmware_version = 1,
132 .identity = "Wafer 5823 WDT",
133 };
134
135 switch (cmd) {
136 case WDIOC_GETSUPPORT:
137 if (copy_to_user(argp, &ident, sizeof (ident)))
138 return -EFAULT;
139 break;
140
141 case WDIOC_GETSTATUS:
142 case WDIOC_GETBOOTSTATUS:
143 return put_user(0, p);
144
145 case WDIOC_KEEPALIVE:
146 wafwdt_ping();
147 break;
148
149 case WDIOC_SETTIMEOUT:
150 if (get_user(new_timeout, p))
151 return -EFAULT;
152 if ((new_timeout < 1) || (new_timeout > 255))
153 return -EINVAL;
154 timeout = new_timeout;
155 wafwdt_stop();
156 wafwdt_start();
157 /* Fall */
158 case WDIOC_GETTIMEOUT:
159 return put_user(timeout, p);
160
161 case WDIOC_SETOPTIONS:
162 {
163 int options, retval = -EINVAL;
164
165 if (get_user(options, p))
166 return -EFAULT;
167
168 if (options & WDIOS_DISABLECARD) {
169 wafwdt_start();
170 retval = 0;
171 }
172
173 if (options & WDIOS_ENABLECARD) {
174 wafwdt_stop();
175 retval = 0;
176 }
177
178 return retval;
179 }
180
181 default:
182 return -ENOIOCTLCMD;
183 }
184 return 0;
185}
186
187static int wafwdt_open(struct inode *inode, struct file *file)
188{
189 if (test_and_set_bit(0, &wafwdt_is_open))
190 return -EBUSY;
191
192 /*
193 * Activate
194 */
195 wafwdt_start();
196 return nonseekable_open(inode, file);
197}
198
199static int
200wafwdt_close(struct inode *inode, struct file *file)
201{
202 if (expect_close == 42) {
203 wafwdt_stop();
204 } else {
205 printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
206 wafwdt_ping();
207 }
208 clear_bit(0, &wafwdt_is_open);
209 expect_close = 0;
210 return 0;
211}
212
213/*
214 * Notifier for system down
215 */
216
217static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
218{
219 if (code == SYS_DOWN || code == SYS_HALT) {
220 /* Turn the WDT off */
221 wafwdt_stop();
222 }
223 return NOTIFY_DONE;
224}
225
226/*
227 * Kernel Interfaces
228 */
229
230static struct file_operations wafwdt_fops = {
231 .owner = THIS_MODULE,
232 .llseek = no_llseek,
233 .write = wafwdt_write,
234 .ioctl = wafwdt_ioctl,
235 .open = wafwdt_open,
236 .release = wafwdt_close,
237};
238
239static struct miscdevice wafwdt_miscdev = {
240 .minor = WATCHDOG_MINOR,
241 .name = "watchdog",
242 .fops = &wafwdt_fops,
243};
244
245/*
246 * The WDT needs to learn about soft shutdowns in order to
247 * turn the timebomb registers off.
248 */
249
250static struct notifier_block wafwdt_notifier = {
251 .notifier_call = wafwdt_notify_sys,
252};
253
254static int __init wafwdt_init(void)
255{
256 int ret;
257
258 printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n");
259
260 spin_lock_init(&wafwdt_lock);
261
262 if (timeout < 1 || timeout > 255) {
263 timeout = WD_TIMO;
264 printk (KERN_INFO PFX "timeout value must be 1<=x<=255, using %d\n",
265 timeout);
266 }
267
268 if (wdt_stop != wdt_start) {
269 if(!request_region(wdt_stop, 1, "Wafer 5823 WDT")) {
270 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
271 wdt_stop);
272 ret = -EIO;
273 goto error;
274 }
275 }
276
277 if(!request_region(wdt_start, 1, "Wafer 5823 WDT")) {
278 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
279 wdt_start);
280 ret = -EIO;
281 goto error2;
282 }
283
284 ret = register_reboot_notifier(&wafwdt_notifier);
285 if (ret != 0) {
286 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
287 ret);
288 goto error3;
289 }
290
291 ret = misc_register(&wafwdt_miscdev);
292 if (ret != 0) {
293 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
294 WATCHDOG_MINOR, ret);
295 goto error4;
296 }
297
298 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
299 timeout, nowayout);
300
301 return ret;
302error4:
303 unregister_reboot_notifier(&wafwdt_notifier);
304error3:
305 release_region(wdt_start, 1);
306error2:
307 if (wdt_stop != wdt_start)
308 release_region(wdt_stop, 1);
309error:
310 return ret;
311}
312
313static void __exit wafwdt_exit(void)
314{
315 misc_deregister(&wafwdt_miscdev);
316 unregister_reboot_notifier(&wafwdt_notifier);
317 if(wdt_stop != wdt_start)
318 release_region(wdt_stop, 1);
319 release_region(wdt_start, 1);
320}
321
322module_init(wafwdt_init);
323module_exit(wafwdt_exit);
324
325MODULE_AUTHOR("Justin Cormack");
326MODULE_DESCRIPTION("ICP Wafer 5823 Single Board Computer WDT driver");
327MODULE_LICENSE("GPL");
328MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
329
330/* end of wafer5823wdt.c */
diff --git a/drivers/char/watchdog/wd501p.h b/drivers/char/watchdog/wd501p.h
new file mode 100644
index 000000000000..84e60eb74337
--- /dev/null
+++ b/drivers/char/watchdog/wd501p.h
@@ -0,0 +1,52 @@
1/*
2 * Industrial Computer Source WDT500/501 driver
3 *
4 * (c) Copyright 1995 CymruNET Ltd
5 * Innovation Centre
6 * Singleton Park
7 * Swansea
8 * Wales
9 * UK
10 * SA2 8PP
11 *
12 * http://www.cymru.net
13 *
14 * This driver is provided under the GNU General Public License, incorporated
15 * herein by reference. The driver is provided without warranty or
16 * support.
17 *
18 * Release 0.04.
19 *
20 */
21
22#include <linux/config.h>
23
24#define WDT_COUNT0 (io+0)
25#define WDT_COUNT1 (io+1)
26#define WDT_COUNT2 (io+2)
27#define WDT_CR (io+3)
28#define WDT_SR (io+4) /* Start buzzer on PCI write */
29#define WDT_RT (io+5) /* Stop buzzer on PCI write */
30#define WDT_BUZZER (io+6) /* PCI only: rd=disable, wr=enable */
31#define WDT_DC (io+7)
32
33/* The following are only on the PCI card, they're outside of I/O space on
34 * the ISA card: */
35#define WDT_CLOCK (io+12) /* COUNT2: rd=16.67MHz, wr=2.0833MHz */
36/* inverted opto isolated reset output: */
37#define WDT_OPTONOTRST (io+13) /* wr=enable, rd=disable */
38/* opto isolated reset output: */
39#define WDT_OPTORST (io+14) /* wr=enable, rd=disable */
40/* programmable outputs: */
41#define WDT_PROGOUT (io+15) /* wr=enable, rd=disable */
42
43 /* FAN 501 500 */
44#define WDC_SR_WCCR 1 /* Active low */ /* X X X */
45#define WDC_SR_TGOOD 2 /* X X - */
46#define WDC_SR_ISOI0 4 /* X X X */
47#define WDC_SR_ISII1 8 /* X X X */
48#define WDC_SR_FANGOOD 16 /* X - - */
49#define WDC_SR_PSUOVER 32 /* Active low */ /* X X - */
50#define WDC_SR_PSUUNDR 64 /* Active low */ /* X X - */
51#define WDC_SR_IRQ 128 /* Active low */ /* X X X */
52
diff --git a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c
new file mode 100644
index 000000000000..5684aa379886
--- /dev/null
+++ b/drivers/char/watchdog/wdt.c
@@ -0,0 +1,647 @@
1/*
2 * Industrial Computer Source WDT500/501 driver
3 *
4 * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
5 * http://www.redhat.com
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
15 *
16 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
17 *
18 * Release 0.10.
19 *
20 * Fixes
21 * Dave Gregorich : Modularisation and minor bugs
22 * Alan Cox : Added the watchdog ioctl() stuff
23 * Alan Cox : Fixed the reboot problem (as noted by
24 * Matt Crocker).
25 * Alan Cox : Added wdt= boot option
26 * Alan Cox : Cleaned up copy/user stuff
27 * Tim Hockin : Added insmod parameters, comment cleanup
28 * Parameterized timeout
29 * Tigran Aivazian : Restructured wdt_init() to handle failures
30 * Joel Becker : Added WDIOC_GET/SETTIMEOUT
31 * Matt Domsch : Added nowayout module option
32 */
33
34#include <linux/config.h>
35#include <linux/interrupt.h>
36#include <linux/module.h>
37#include <linux/moduleparam.h>
38#include <linux/types.h>
39#include <linux/miscdevice.h>
40#include <linux/watchdog.h>
41#include <linux/fs.h>
42#include <linux/ioport.h>
43#include <linux/notifier.h>
44#include <linux/reboot.h>
45#include <linux/init.h>
46
47#include <asm/io.h>
48#include <asm/uaccess.h>
49#include <asm/system.h>
50#include "wd501p.h"
51
52static unsigned long wdt_is_open;
53static char expect_close;
54
55/*
56 * Module parameters
57 */
58
59#define WD_TIMO 60 /* Default heartbeat = 60 seconds */
60
61static int heartbeat = WD_TIMO;
62static int wd_heartbeat;
63module_param(heartbeat, int, 0);
64MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")");
65
66#ifdef CONFIG_WATCHDOG_NOWAYOUT
67static int nowayout = 1;
68#else
69static int nowayout = 0;
70#endif
71
72module_param(nowayout, int, 0);
73MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
74
75/* You must set these - there is no sane way to probe for this board. */
76static int io=0x240;
77static int irq=11;
78
79module_param(io, int, 0);
80MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
81module_param(irq, int, 0);
82MODULE_PARM_DESC(irq, "WDT irq (default=11)");
83
84#ifdef CONFIG_WDT_501
85/* Support for the Fan Tachometer on the WDT501-P */
86static int tachometer;
87
88module_param(tachometer, int, 0);
89MODULE_PARM_DESC(tachometer, "WDT501-P Fan Tachometer support (0=disable, default=0)");
90#endif /* CONFIG_WDT_501 */
91
92/*
93 * Programming support
94 */
95
96static void wdt_ctr_mode(int ctr, int mode)
97{
98 ctr<<=6;
99 ctr|=0x30;
100 ctr|=(mode<<1);
101 outb_p(ctr, WDT_CR);
102}
103
104static void wdt_ctr_load(int ctr, int val)
105{
106 outb_p(val&0xFF, WDT_COUNT0+ctr);
107 outb_p(val>>8, WDT_COUNT0+ctr);
108}
109
110/**
111 * wdt_start:
112 *
113 * Start the watchdog driver.
114 */
115
116static int wdt_start(void)
117{
118 inb_p(WDT_DC); /* Disable watchdog */
119 wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */
120 wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */
121 wdt_ctr_mode(2,0); /* Program CTR2 for Mode 0: Pulse on Terminal Count */
122 wdt_ctr_load(0, 8948); /* Count at 100Hz */
123 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */
124 wdt_ctr_load(2,65535); /* Length of reset pulse */
125 outb_p(0, WDT_DC); /* Enable watchdog */
126 return 0;
127}
128
129/**
130 * wdt_stop:
131 *
132 * Stop the watchdog driver.
133 */
134
135static int wdt_stop (void)
136{
137 /* Turn the card off */
138 inb_p(WDT_DC); /* Disable watchdog */
139 wdt_ctr_load(2,0); /* 0 length reset pulses now */
140 return 0;
141}
142
143/**
144 * wdt_ping:
145 *
146 * Reload counter one with the watchdog heartbeat. We don't bother reloading
147 * the cascade counter.
148 */
149
150static int wdt_ping(void)
151{
152 /* Write a watchdog value */
153 inb_p(WDT_DC); /* Disable watchdog */
154 wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */
155 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */
156 outb_p(0, WDT_DC); /* Enable watchdog */
157 return 0;
158}
159
160/**
161 * wdt_set_heartbeat:
162 * @t: the new heartbeat value that needs to be set.
163 *
164 * Set a new heartbeat value for the watchdog device. If the heartbeat value is
165 * incorrect we keep the old value and return -EINVAL. If successfull we
166 * return 0.
167 */
168static int wdt_set_heartbeat(int t)
169{
170 if ((t < 1) || (t > 65535))
171 return -EINVAL;
172
173 heartbeat = t;
174 wd_heartbeat = t * 100;
175 return 0;
176}
177
178/**
179 * wdt_get_status:
180 * @status: the new status.
181 *
182 * Extract the status information from a WDT watchdog device. There are
183 * several board variants so we have to know which bits are valid. Some
184 * bits default to one and some to zero in order to be maximally painful.
185 *
186 * we then map the bits onto the status ioctl flags.
187 */
188
189static int wdt_get_status(int *status)
190{
191 unsigned char new_status=inb_p(WDT_SR);
192
193 *status=0;
194 if (new_status & WDC_SR_ISOI0)
195 *status |= WDIOF_EXTERN1;
196 if (new_status & WDC_SR_ISII1)
197 *status |= WDIOF_EXTERN2;
198#ifdef CONFIG_WDT_501
199 if (!(new_status & WDC_SR_TGOOD))
200 *status |= WDIOF_OVERHEAT;
201 if (!(new_status & WDC_SR_PSUOVER))
202 *status |= WDIOF_POWEROVER;
203 if (!(new_status & WDC_SR_PSUUNDR))
204 *status |= WDIOF_POWERUNDER;
205 if (tachometer) {
206 if (!(new_status & WDC_SR_FANGOOD))
207 *status |= WDIOF_FANFAULT;
208 }
209#endif /* CONFIG_WDT_501 */
210 return 0;
211}
212
213#ifdef CONFIG_WDT_501
214/**
215 * wdt_get_temperature:
216 *
217 * Reports the temperature in degrees Fahrenheit. The API is in
218 * farenheit. It was designed by an imperial measurement luddite.
219 */
220
221static int wdt_get_temperature(int *temperature)
222{
223 unsigned short c=inb_p(WDT_RT);
224
225 *temperature = (c * 11 / 15) + 7;
226 return 0;
227}
228#endif /* CONFIG_WDT_501 */
229
230/**
231 * wdt_interrupt:
232 * @irq: Interrupt number
233 * @dev_id: Unused as we don't allow multiple devices.
234 * @regs: Unused.
235 *
236 * Handle an interrupt from the board. These are raised when the status
237 * map changes in what the board considers an interesting way. That means
238 * a failure condition occurring.
239 */
240
241static irqreturn_t wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
242{
243 /*
244 * Read the status register see what is up and
245 * then printk it.
246 */
247 unsigned char status=inb_p(WDT_SR);
248
249 printk(KERN_CRIT "WDT status %d\n", status);
250
251#ifdef CONFIG_WDT_501
252 if (!(status & WDC_SR_TGOOD))
253 printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT));
254 if (!(status & WDC_SR_PSUOVER))
255 printk(KERN_CRIT "PSU over voltage.\n");
256 if (!(status & WDC_SR_PSUUNDR))
257 printk(KERN_CRIT "PSU under voltage.\n");
258 if (tachometer) {
259 if (!(status & WDC_SR_FANGOOD))
260 printk(KERN_CRIT "Possible fan fault.\n");
261 }
262#endif /* CONFIG_WDT_501 */
263 if (!(status & WDC_SR_WCCR))
264#ifdef SOFTWARE_REBOOT
265#ifdef ONLY_TESTING
266 printk(KERN_CRIT "Would Reboot.\n");
267#else
268 printk(KERN_CRIT "Initiating system reboot.\n");
269 machine_restart(NULL);
270#endif
271#else
272 printk(KERN_CRIT "Reset in 5ms.\n");
273#endif
274 return IRQ_HANDLED;
275}
276
277
278/**
279 * wdt_write:
280 * @file: file handle to the watchdog
281 * @buf: buffer to write (unused as data does not matter here
282 * @count: count of bytes
283 * @ppos: pointer to the position to write. No seeks allowed
284 *
285 * A write to a watchdog device is defined as a keepalive signal. Any
286 * write of data will do, as we we don't define content meaning.
287 */
288
289static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
290{
291 if(count) {
292 if (!nowayout) {
293 size_t i;
294
295 /* In case it was set long ago */
296 expect_close = 0;
297
298 for (i = 0; i != count; i++) {
299 char c;
300 if (get_user(c, buf + i))
301 return -EFAULT;
302 if (c == 'V')
303 expect_close = 42;
304 }
305 }
306 wdt_ping();
307 }
308 return count;
309}
310
311/**
312 * wdt_ioctl:
313 * @inode: inode of the device
314 * @file: file handle to the device
315 * @cmd: watchdog command
316 * @arg: argument pointer
317 *
318 * The watchdog API defines a common set of functions for all watchdogs
319 * according to their available features. We only actually usefully support
320 * querying capabilities and current status.
321 */
322
323static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
324 unsigned long arg)
325{
326 void __user *argp = (void __user *)arg;
327 int __user *p = argp;
328 int new_heartbeat;
329 int status;
330
331 static struct watchdog_info ident = {
332 .options = WDIOF_SETTIMEOUT|
333 WDIOF_MAGICCLOSE|
334 WDIOF_KEEPALIVEPING,
335 .firmware_version = 1,
336 .identity = "WDT500/501",
337 };
338
339 /* Add options according to the card we have */
340 ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
341#ifdef CONFIG_WDT_501
342 ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER);
343 if (tachometer)
344 ident.options |= WDIOF_FANFAULT;
345#endif /* CONFIG_WDT_501 */
346
347 switch(cmd)
348 {
349 default:
350 return -ENOIOCTLCMD;
351 case WDIOC_GETSUPPORT:
352 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
353
354 case WDIOC_GETSTATUS:
355 wdt_get_status(&status);
356 return put_user(status, p);
357 case WDIOC_GETBOOTSTATUS:
358 return put_user(0, p);
359 case WDIOC_KEEPALIVE:
360 wdt_ping();
361 return 0;
362 case WDIOC_SETTIMEOUT:
363 if (get_user(new_heartbeat, p))
364 return -EFAULT;
365
366 if (wdt_set_heartbeat(new_heartbeat))
367 return -EINVAL;
368
369 wdt_ping();
370 /* Fall */
371 case WDIOC_GETTIMEOUT:
372 return put_user(heartbeat, p);
373 }
374}
375
376/**
377 * wdt_open:
378 * @inode: inode of device
379 * @file: file handle to device
380 *
381 * The watchdog device has been opened. The watchdog device is single
382 * open and on opening we load the counters. Counter zero is a 100Hz
383 * cascade, into counter 1 which downcounts to reboot. When the counter
384 * triggers counter 2 downcounts the length of the reset pulse which
385 * set set to be as long as possible.
386 */
387
388static int wdt_open(struct inode *inode, struct file *file)
389{
390 if(test_and_set_bit(0, &wdt_is_open))
391 return -EBUSY;
392 /*
393 * Activate
394 */
395 wdt_start();
396 return nonseekable_open(inode, file);
397}
398
399/**
400 * wdt_release:
401 * @inode: inode to board
402 * @file: file handle to board
403 *
404 * The watchdog has a configurable API. There is a religious dispute
405 * between people who want their watchdog to be able to shut down and
406 * those who want to be sure if the watchdog manager dies the machine
407 * reboots. In the former case we disable the counters, in the latter
408 * case you have to open it again very soon.
409 */
410
411static int wdt_release(struct inode *inode, struct file *file)
412{
413 if (expect_close == 42) {
414 wdt_stop();
415 clear_bit(0, &wdt_is_open);
416 } else {
417 printk(KERN_CRIT "wdt: WDT device closed unexpectedly. WDT will not stop!\n");
418 wdt_ping();
419 }
420 expect_close = 0;
421 return 0;
422}
423
424#ifdef CONFIG_WDT_501
425/**
426 * wdt_temp_read:
427 * @file: file handle to the watchdog board
428 * @buf: buffer to write 1 byte into
429 * @count: length of buffer
430 * @ptr: offset (no seek allowed)
431 *
432 * Temp_read reports the temperature in degrees Fahrenheit. The API is in
433 * farenheit. It was designed by an imperial measurement luddite.
434 */
435
436static ssize_t wdt_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)
437{
438 int temperature;
439
440 if (wdt_get_temperature(&temperature))
441 return -EFAULT;
442
443 if (copy_to_user (buf, &temperature, 1))
444 return -EFAULT;
445
446 return 1;
447}
448
449/**
450 * wdt_temp_open:
451 * @inode: inode of device
452 * @file: file handle to device
453 *
454 * The temperature device has been opened.
455 */
456
457static int wdt_temp_open(struct inode *inode, struct file *file)
458{
459 return nonseekable_open(inode, file);
460}
461
462/**
463 * wdt_temp_release:
464 * @inode: inode to board
465 * @file: file handle to board
466 *
467 * The temperature device has been closed.
468 */
469
470static int wdt_temp_release(struct inode *inode, struct file *file)
471{
472 return 0;
473}
474#endif /* CONFIG_WDT_501 */
475
476/**
477 * notify_sys:
478 * @this: our notifier block
479 * @code: the event being reported
480 * @unused: unused
481 *
482 * Our notifier is called on system shutdowns. We want to turn the card
483 * off at reboot otherwise the machine will reboot again during memory
484 * test or worse yet during the following fsck. This would suck, in fact
485 * trust me - if it happens it does suck.
486 */
487
488static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
489 void *unused)
490{
491 if(code==SYS_DOWN || code==SYS_HALT) {
492 /* Turn the card off */
493 wdt_stop();
494 }
495 return NOTIFY_DONE;
496}
497
498/*
499 * Kernel Interfaces
500 */
501
502
503static struct file_operations wdt_fops = {
504 .owner = THIS_MODULE,
505 .llseek = no_llseek,
506 .write = wdt_write,
507 .ioctl = wdt_ioctl,
508 .open = wdt_open,
509 .release = wdt_release,
510};
511
512static struct miscdevice wdt_miscdev = {
513 .minor = WATCHDOG_MINOR,
514 .name = "watchdog",
515 .fops = &wdt_fops,
516};
517
518#ifdef CONFIG_WDT_501
519static struct file_operations wdt_temp_fops = {
520 .owner = THIS_MODULE,
521 .llseek = no_llseek,
522 .read = wdt_temp_read,
523 .open = wdt_temp_open,
524 .release = wdt_temp_release,
525};
526
527static struct miscdevice temp_miscdev = {
528 .minor = TEMP_MINOR,
529 .name = "temperature",
530 .fops = &wdt_temp_fops,
531};
532#endif /* CONFIG_WDT_501 */
533
534/*
535 * The WDT card needs to learn about soft shutdowns in order to
536 * turn the timebomb registers off.
537 */
538
539static struct notifier_block wdt_notifier = {
540 .notifier_call = wdt_notify_sys,
541};
542
543/**
544 * cleanup_module:
545 *
546 * Unload the watchdog. You cannot do this with any file handles open.
547 * If your watchdog is set to continue ticking on close and you unload
548 * it, well it keeps ticking. We won't get the interrupt but the board
549 * will not touch PC memory so all is fine. You just have to load a new
550 * module in 60 seconds or reboot.
551 */
552
553static void __exit wdt_exit(void)
554{
555 misc_deregister(&wdt_miscdev);
556#ifdef CONFIG_WDT_501
557 misc_deregister(&temp_miscdev);
558#endif /* CONFIG_WDT_501 */
559 unregister_reboot_notifier(&wdt_notifier);
560 free_irq(irq, NULL);
561 release_region(io,8);
562}
563
564/**
565 * wdt_init:
566 *
567 * Set up the WDT watchdog board. All we have to do is grab the
568 * resources we require and bitch if anyone beat us to them.
569 * The open() function will actually kick the board off.
570 */
571
572static int __init wdt_init(void)
573{
574 int ret;
575
576 /* Check that the heartbeat value is within it's range ; if not reset to the default */
577 if (wdt_set_heartbeat(heartbeat)) {
578 wdt_set_heartbeat(WD_TIMO);
579 printk(KERN_INFO "wdt: heartbeat value must be 0<heartbeat<65536, using %d\n",
580 WD_TIMO);
581 }
582
583 if (!request_region(io, 8, "wdt501p")) {
584 printk(KERN_ERR "wdt: I/O address 0x%04x already in use\n", io);
585 ret = -EBUSY;
586 goto out;
587 }
588
589 ret = request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL);
590 if(ret) {
591 printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq);
592 goto outreg;
593 }
594
595 ret = register_reboot_notifier(&wdt_notifier);
596 if(ret) {
597 printk(KERN_ERR "wdt: cannot register reboot notifier (err=%d)\n", ret);
598 goto outirq;
599 }
600
601#ifdef CONFIG_WDT_501
602 ret = misc_register(&temp_miscdev);
603 if (ret) {
604 printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n",
605 TEMP_MINOR, ret);
606 goto outrbt;
607 }
608#endif /* CONFIG_WDT_501 */
609
610 ret = misc_register(&wdt_miscdev);
611 if (ret) {
612 printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n",
613 WATCHDOG_MINOR, ret);
614 goto outmisc;
615 }
616
617 ret = 0;
618 printk(KERN_INFO "WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
619 io, irq, heartbeat, nowayout);
620#ifdef CONFIG_WDT_501
621 printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled"));
622#endif /* CONFIG_WDT_501 */
623
624out:
625 return ret;
626
627outmisc:
628#ifdef CONFIG_WDT_501
629 misc_deregister(&temp_miscdev);
630outrbt:
631#endif /* CONFIG_WDT_501 */
632 unregister_reboot_notifier(&wdt_notifier);
633outirq:
634 free_irq(irq, NULL);
635outreg:
636 release_region(io,8);
637 goto out;
638}
639
640module_init(wdt_init);
641module_exit(wdt_exit);
642
643MODULE_AUTHOR("Alan Cox");
644MODULE_DESCRIPTION("Driver for ISA ICS watchdog cards (WDT500/501)");
645MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
646MODULE_ALIAS_MISCDEV(TEMP_MINOR);
647MODULE_LICENSE("GPL");
diff --git a/drivers/char/watchdog/wdt285.c b/drivers/char/watchdog/wdt285.c
new file mode 100644
index 000000000000..52825a1f1779
--- /dev/null
+++ b/drivers/char/watchdog/wdt285.c
@@ -0,0 +1,229 @@
1/*
2 * Intel 21285 watchdog driver
3 * Copyright (c) Phil Blundell <pb@nexus.co.uk>, 1998
4 *
5 * based on
6 *
7 * SoftDog 0.05: A Software Watchdog Device
8 *
9 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/types.h>
21#include <linux/kernel.h>
22#include <linux/fs.h>
23#include <linux/mm.h>
24#include <linux/miscdevice.h>
25#include <linux/watchdog.h>
26#include <linux/reboot.h>
27#include <linux/init.h>
28#include <linux/interrupt.h>
29
30#include <asm/irq.h>
31#include <asm/uaccess.h>
32#include <asm/hardware.h>
33#include <asm/mach-types.h>
34#include <asm/hardware/dec21285.h>
35
36/*
37 * Define this to stop the watchdog actually rebooting the machine.
38 */
39#undef ONLY_TESTING
40
41static unsigned int soft_margin = 60; /* in seconds */
42static unsigned int reload;
43static unsigned long timer_alive;
44
45#ifdef ONLY_TESTING
46/*
47 * If the timer expires..
48 */
49static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs)
50{
51 printk(KERN_CRIT "Watchdog: Would Reboot.\n");
52 *CSR_TIMER4_CNTL = 0;
53 *CSR_TIMER4_CLR = 0;
54}
55#endif
56
57/*
58 * Refresh the timer.
59 */
60static void watchdog_ping(void)
61{
62 *CSR_TIMER4_LOAD = reload;
63}
64
65/*
66 * Allow only one person to hold it open
67 */
68static int watchdog_open(struct inode *inode, struct file *file)
69{
70 int ret;
71
72 if (*CSR_SA110_CNTL & (1 << 13))
73 return -EBUSY;
74
75 if (test_and_set_bit(1, &timer_alive))
76 return -EBUSY;
77
78 reload = soft_margin * (mem_fclk_21285 / 256);
79
80 *CSR_TIMER4_CLR = 0;
81 watchdog_ping();
82 *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD
83 | TIMER_CNTL_DIV256;
84
85#ifdef ONLY_TESTING
86 ret = request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL);
87 if (ret) {
88 *CSR_TIMER4_CNTL = 0;
89 clear_bit(1, &timer_alive);
90 }
91#else
92 /*
93 * Setting this bit is irreversible; once enabled, there is
94 * no way to disable the watchdog.
95 */
96 *CSR_SA110_CNTL |= 1 << 13;
97
98 ret = 0;
99#endif
100 nonseekable_open(inode, file);
101 return ret;
102}
103
104/*
105 * Shut off the timer.
106 * Note: if we really have enabled the watchdog, there
107 * is no way to turn off.
108 */
109static int watchdog_release(struct inode *inode, struct file *file)
110{
111#ifdef ONLY_TESTING
112 free_irq(IRQ_TIMER4, NULL);
113 clear_bit(1, &timer_alive);
114#endif
115 return 0;
116}
117
118static ssize_t
119watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
120{
121 /*
122 * Refresh the timer.
123 */
124 if (len)
125 watchdog_ping();
126
127 return len;
128}
129
130static struct watchdog_info ident = {
131 .options = WDIOF_SETTIMEOUT,
132 .identity = "Footbridge Watchdog",
133};
134
135static int
136watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
137 unsigned long arg)
138{
139 unsigned int new_margin;
140 int ret = -ENOIOCTLCMD;
141
142 switch(cmd) {
143 case WDIOC_GETSUPPORT:
144 ret = 0;
145 if (copy_to_user((void *)arg, &ident, sizeof(ident)))
146 ret = -EFAULT;
147 break;
148
149 case WDIOC_GETSTATUS:
150 case WDIOC_GETBOOTSTATUS:
151 ret = put_user(0,(int *)arg);
152 break;
153
154 case WDIOC_KEEPALIVE:
155 watchdog_ping();
156 ret = 0;
157 break;
158
159 case WDIOC_SETTIMEOUT:
160 ret = get_user(new_margin, (int *)arg);
161 if (ret)
162 break;
163
164 /* Arbitrary, can't find the card's limits */
165 if (new_margin < 0 || new_margin > 60) {
166 ret = -EINVAL;
167 break;
168 }
169
170 soft_margin = new_margin;
171 reload = soft_margin * (mem_fclk_21285 / 256);
172 watchdog_ping();
173 /* Fall */
174 case WDIOC_GETTIMEOUT:
175 ret = put_user(soft_margin, (int *)arg);
176 break;
177 }
178 return ret;
179}
180
181static struct file_operations watchdog_fops = {
182 .owner = THIS_MODULE,
183 .llseek = no_llseek,
184 .write = watchdog_write,
185 .ioctl = watchdog_ioctl,
186 .open = watchdog_open,
187 .release = watchdog_release,
188};
189
190static struct miscdevice watchdog_miscdev = {
191 .minor = WATCHDOG_MINOR,
192 .name = "watchdog",
193 .fops = &watchdog_fops,
194};
195
196static int __init footbridge_watchdog_init(void)
197{
198 int retval;
199
200 if (machine_is_netwinder())
201 return -ENODEV;
202
203 retval = misc_register(&watchdog_miscdev);
204 if (retval < 0)
205 return retval;
206
207 printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
208 soft_margin);
209
210 if (machine_is_cats())
211 printk("Warning: Watchdog reset may not work on this machine.\n");
212 return 0;
213}
214
215static void __exit footbridge_watchdog_exit(void)
216{
217 misc_deregister(&watchdog_miscdev);
218}
219
220MODULE_AUTHOR("Phil Blundell <pb@nexus.co.uk>");
221MODULE_DESCRIPTION("Footbridge watchdog driver");
222MODULE_LICENSE("GPL");
223MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
224
225module_param(soft_margin, int, 0);
226MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds");
227
228module_init(footbridge_watchdog_init);
229module_exit(footbridge_watchdog_exit);
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
new file mode 100644
index 000000000000..072e9b214759
--- /dev/null
+++ b/drivers/char/watchdog/wdt977.c
@@ -0,0 +1,459 @@
1/*
2 * Wdt977 0.03: A Watchdog Device for Netwinder W83977AF chip
3 *
4 * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
5 *
6 * -----------------------
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 * -----------------------
14 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
15 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
16 * 19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface
17 * 06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts
18 * from minutes to seconds.
19 * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in
20 * nwwatchdog_init.
21 */
22
23#include <linux/module.h>
24#include <linux/moduleparam.h>
25#include <linux/config.h>
26#include <linux/types.h>
27#include <linux/kernel.h>
28#include <linux/fs.h>
29#include <linux/miscdevice.h>
30#include <linux/init.h>
31#include <linux/watchdog.h>
32#include <linux/notifier.h>
33#include <linux/reboot.h>
34
35#include <asm/io.h>
36#include <asm/system.h>
37#include <asm/mach-types.h>
38#include <asm/uaccess.h>
39
40#define PFX "Wdt977: "
41#define WATCHDOG_MINOR 130
42
43#define DEFAULT_TIMEOUT 60 /* default timeout in seconds */
44
45static int timeout = DEFAULT_TIMEOUT;
46static int timeoutM; /* timeout in minutes */
47static unsigned long timer_alive;
48static int testmode;
49static char expect_close;
50
51module_param(timeout, int, 0);
52MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
53module_param(testmode, int, 0);
54MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
55
56#ifdef CONFIG_WATCHDOG_NOWAYOUT
57static int nowayout = 1;
58#else
59static int nowayout = 0;
60#endif
61
62module_param(nowayout, int, 0);
63MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
64
65/*
66 * Start the watchdog
67 */
68
69static int wdt977_start(void)
70{
71 /* unlock the SuperIO chip */
72 outb(0x87,0x370);
73 outb(0x87,0x370);
74
75 /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
76 * F2 has the timeout in minutes
77 * F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
78 * at timeout, and to reset timer on kbd/mouse activity (not impl.)
79 * F4 is used to just clear the TIMEOUT'ed state (bit 0)
80 */
81 outb(0x07,0x370);
82 outb(0x08,0x371);
83 outb(0xF2,0x370);
84 outb(timeoutM,0x371);
85 outb(0xF3,0x370);
86 outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */
87 outb(0xF4,0x370);
88 outb(0x00,0x371);
89
90 /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
91 /* in test mode watch the bit 1 on F4 to indicate "triggered" */
92 if (!testmode)
93 {
94 outb(0x07,0x370);
95 outb(0x07,0x371);
96 outb(0xE6,0x370);
97 outb(0x08,0x371);
98 }
99
100 /* lock the SuperIO chip */
101 outb(0xAA,0x370);
102
103 printk(KERN_INFO PFX "activated.\n");
104
105 return 0;
106}
107
108/*
109 * Stop the watchdog
110 */
111
112static int wdt977_stop(void)
113{
114 /* unlock the SuperIO chip */
115 outb(0x87,0x370);
116 outb(0x87,0x370);
117
118 /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
119 * F3 is reset to its default state
120 * F4 can clear the TIMEOUT'ed state (bit 0) - back to default
121 * We can not use GP17 as a PowerLed, as we use its usage as a RedLed
122 */
123 outb(0x07,0x370);
124 outb(0x08,0x371);
125 outb(0xF2,0x370);
126 outb(0xFF,0x371);
127 outb(0xF3,0x370);
128 outb(0x00,0x371);
129 outb(0xF4,0x370);
130 outb(0x00,0x371);
131 outb(0xF2,0x370);
132 outb(0x00,0x371);
133
134 /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
135 outb(0x07,0x370);
136 outb(0x07,0x371);
137 outb(0xE6,0x370);
138 outb(0x08,0x371);
139
140 /* lock the SuperIO chip */
141 outb(0xAA,0x370);
142
143 printk(KERN_INFO PFX "shutdown.\n");
144
145 return 0;
146}
147
148/*
149 * Send a keepalive ping to the watchdog
150 * This is done by simply re-writing the timeout to reg. 0xF2
151 */
152
153static int wdt977_keepalive(void)
154{
155 /* unlock the SuperIO chip */
156 outb(0x87,0x370);
157 outb(0x87,0x370);
158
159 /* select device Aux2 (device=8) and kicks watchdog reg F2 */
160 /* F2 has the timeout in minutes */
161 outb(0x07,0x370);
162 outb(0x08,0x371);
163 outb(0xF2,0x370);
164 outb(timeoutM,0x371);
165
166 /* lock the SuperIO chip */
167 outb(0xAA,0x370);
168
169 return 0;
170}
171
172/*
173 * Set the watchdog timeout value
174 */
175
176static int wdt977_set_timeout(int t)
177{
178 int tmrval;
179
180 /* convert seconds to minutes, rounding up */
181 tmrval = (t + 59) / 60;
182
183 if (machine_is_netwinder()) {
184 /* we have a hw bug somewhere, so each 977 minute is actually only 30sec
185 * this limits the max timeout to half of device max of 255 minutes...
186 */
187 tmrval += tmrval;
188 }
189
190 if ((tmrval < 1) || (tmrval > 255))
191 return -EINVAL;
192
193 /* timeout is the timeout in seconds, timeoutM is the timeout in minutes) */
194 timeout = t;
195 timeoutM = tmrval;
196 return 0;
197}
198
199/*
200 * Get the watchdog status
201 */
202
203static int wdt977_get_status(int *status)
204{
205 int new_status;
206
207 *status=0;
208
209 /* unlock the SuperIO chip */
210 outb(0x87,0x370);
211 outb(0x87,0x370);
212
213 /* select device Aux2 (device=8) and read watchdog reg F4 */
214 outb(0x07,0x370);
215 outb(0x08,0x371);
216 outb(0xF4,0x370);
217 new_status = inb(0x371);
218
219 /* lock the SuperIO chip */
220 outb(0xAA,0x370);
221
222 if (new_status & 1)
223 *status |= WDIOF_CARDRESET;
224
225 return 0;
226}
227
228
229/*
230 * /dev/watchdog handling
231 */
232
233static int wdt977_open(struct inode *inode, struct file *file)
234{
235 /* If the watchdog is alive we don't need to start it again */
236 if( test_and_set_bit(0,&timer_alive) )
237 return -EBUSY;
238
239 if (nowayout)
240 __module_get(THIS_MODULE);
241
242 wdt977_start();
243 return nonseekable_open(inode, file);
244}
245
246static int wdt977_release(struct inode *inode, struct file *file)
247{
248 /*
249 * Shut off the timer.
250 * Lock it in if it's a module and we set nowayout
251 */
252 if (expect_close == 42)
253 {
254 wdt977_stop();
255 clear_bit(0,&timer_alive);
256 } else {
257 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
258 wdt977_keepalive();
259 }
260 expect_close = 0;
261 return 0;
262}
263
264
265/*
266 * wdt977_write:
267 * @file: file handle to the watchdog
268 * @buf: buffer to write (unused as data does not matter here
269 * @count: count of bytes
270 * @ppos: pointer to the position to write. No seeks allowed
271 *
272 * A write to a watchdog device is defined as a keepalive signal. Any
273 * write of data will do, as we we don't define content meaning.
274 */
275
276static ssize_t wdt977_write(struct file *file, const char __user *buf,
277 size_t count, loff_t *ppos)
278{
279 if (count) {
280 if (!nowayout) {
281 size_t i;
282
283 /* In case it was set long ago */
284 expect_close = 0;
285
286 for (i = 0; i != count; i++) {
287 char c;
288 if (get_user(c, buf + i))
289 return -EFAULT;
290 if (c == 'V')
291 expect_close = 42;
292 }
293 }
294
295 wdt977_keepalive();
296 }
297 return count;
298}
299
300/*
301 * wdt977_ioctl:
302 * @inode: inode of the device
303 * @file: file handle to the device
304 * @cmd: watchdog command
305 * @arg: argument pointer
306 *
307 * The watchdog API defines a common set of functions for all watchdogs
308 * according to their available features.
309 */
310
311static struct watchdog_info ident = {
312 .options = WDIOF_SETTIMEOUT |
313 WDIOF_MAGICCLOSE |
314 WDIOF_KEEPALIVEPING,
315 .firmware_version = 1,
316 .identity = "Winbond 83977",
317};
318
319static int wdt977_ioctl(struct inode *inode, struct file *file,
320 unsigned int cmd, unsigned long arg)
321{
322 int status;
323 int new_options, retval = -EINVAL;
324 int new_timeout;
325 union {
326 struct watchdog_info __user *ident;
327 int __user *i;
328 } uarg;
329
330 uarg.i = (int __user *)arg;
331
332 switch(cmd)
333 {
334 default:
335 return -ENOIOCTLCMD;
336
337 case WDIOC_GETSUPPORT:
338 return copy_to_user(uarg.ident, &ident,
339 sizeof(ident)) ? -EFAULT : 0;
340
341 case WDIOC_GETSTATUS:
342 wdt977_get_status(&status);
343 return put_user(status, uarg.i);
344
345 case WDIOC_GETBOOTSTATUS:
346 return put_user(0, uarg.i);
347
348 case WDIOC_KEEPALIVE:
349 wdt977_keepalive();
350 return 0;
351
352 case WDIOC_SETOPTIONS:
353 if (get_user (new_options, uarg.i))
354 return -EFAULT;
355
356 if (new_options & WDIOS_DISABLECARD) {
357 wdt977_stop();
358 retval = 0;
359 }
360
361 if (new_options & WDIOS_ENABLECARD) {
362 wdt977_start();
363 retval = 0;
364 }
365
366 return retval;
367
368 case WDIOC_SETTIMEOUT:
369 if (get_user(new_timeout, uarg.i))
370 return -EFAULT;
371
372 if (wdt977_set_timeout(new_timeout))
373 return -EINVAL;
374
375 wdt977_keepalive();
376 /* Fall */
377
378 case WDIOC_GETTIMEOUT:
379 return put_user(timeout, uarg.i);
380
381 }
382}
383
384static int wdt977_notify_sys(struct notifier_block *this, unsigned long code,
385 void *unused)
386{
387 if(code==SYS_DOWN || code==SYS_HALT)
388 wdt977_stop();
389 return NOTIFY_DONE;
390}
391
392static struct file_operations wdt977_fops=
393{
394 .owner = THIS_MODULE,
395 .llseek = no_llseek,
396 .write = wdt977_write,
397 .ioctl = wdt977_ioctl,
398 .open = wdt977_open,
399 .release = wdt977_release,
400};
401
402static struct miscdevice wdt977_miscdev=
403{
404 .minor = WATCHDOG_MINOR,
405 .name = "watchdog",
406 .fops = &wdt977_fops,
407};
408
409static struct notifier_block wdt977_notifier = {
410 .notifier_call = wdt977_notify_sys,
411};
412
413static int __init nwwatchdog_init(void)
414{
415 int retval;
416 if (!machine_is_netwinder())
417 return -ENODEV;
418
419 /* Check that the timeout value is within it's range ; if not reset to the default */
420 if (wdt977_set_timeout(timeout)) {
421 wdt977_set_timeout(DEFAULT_TIMEOUT);
422 printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n",
423 DEFAULT_TIMEOUT);
424 }
425
426 retval = register_reboot_notifier(&wdt977_notifier);
427 if (retval) {
428 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
429 retval);
430 return retval;
431 }
432
433 retval = misc_register(&wdt977_miscdev);
434 if (retval) {
435 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
436 WATCHDOG_MINOR, retval);
437 unregister_reboot_notifier(&wdt977_notifier);
438 return retval;
439 }
440
441 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode = %i)\n",
442 timeout, nowayout, testmode);
443
444 return 0;
445}
446
447static void __exit nwwatchdog_exit(void)
448{
449 misc_deregister(&wdt977_miscdev);
450 unregister_reboot_notifier(&wdt977_notifier);
451}
452
453module_init(nwwatchdog_init);
454module_exit(nwwatchdog_exit);
455
456MODULE_AUTHOR("Woody Suwalski <woody@netwinder.org>");
457MODULE_DESCRIPTION("W83977AF Watchdog driver");
458MODULE_LICENSE("GPL");
459MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
new file mode 100644
index 000000000000..7651deda928c
--- /dev/null
+++ b/drivers/char/watchdog/wdt_pci.c
@@ -0,0 +1,763 @@
1/*
2 * Industrial Computer Source PCI-WDT500/501 driver
3 *
4 * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
5 * http://www.redhat.com
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
15 *
16 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
17 *
18 * Release 0.10.
19 *
20 * Fixes
21 * Dave Gregorich : Modularisation and minor bugs
22 * Alan Cox : Added the watchdog ioctl() stuff
23 * Alan Cox : Fixed the reboot problem (as noted by
24 * Matt Crocker).
25 * Alan Cox : Added wdt= boot option
26 * Alan Cox : Cleaned up copy/user stuff
27 * Tim Hockin : Added insmod parameters, comment cleanup
28 * Parameterized timeout
29 * JP Nollmann : Added support for PCI wdt501p
30 * Alan Cox : Split ISA and PCI cards into two drivers
31 * Jeff Garzik : PCI cleanups
32 * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures
33 * Joel Becker : Added WDIOC_GET/SETTIMEOUT
34 * Zwane Mwaikambo : Magic char closing, locking changes, cleanups
35 * Matt Domsch : nowayout module option
36 */
37
38#include <linux/config.h>
39#include <linux/interrupt.h>
40#include <linux/module.h>
41#include <linux/moduleparam.h>
42#include <linux/types.h>
43#include <linux/miscdevice.h>
44#include <linux/watchdog.h>
45#include <linux/ioport.h>
46#include <linux/notifier.h>
47#include <linux/reboot.h>
48#include <linux/init.h>
49#include <linux/fs.h>
50#include <linux/pci.h>
51
52#include <asm/io.h>
53#include <asm/uaccess.h>
54#include <asm/system.h>
55
56#define WDT_IS_PCI
57#include "wd501p.h"
58
59#define PFX "wdt_pci: "
60
61/*
62 * Until Access I/O gets their application for a PCI vendor ID approved,
63 * I don't think that it's appropriate to move these constants into the
64 * regular pci_ids.h file. -- JPN 2000/01/18
65 */
66
67#ifndef PCI_VENDOR_ID_ACCESSIO
68#define PCI_VENDOR_ID_ACCESSIO 0x494f
69#endif
70#ifndef PCI_DEVICE_ID_WDG_CSM
71#define PCI_DEVICE_ID_WDG_CSM 0x22c0
72#endif
73
74/* We can only use 1 card due to the /dev/watchdog restriction */
75static int dev_count;
76
77static struct semaphore open_sem;
78static spinlock_t wdtpci_lock;
79static char expect_close;
80
81static int io;
82static int irq;
83
84/* Default timeout */
85#define WD_TIMO 60 /* Default heartbeat = 60 seconds */
86
87static int heartbeat = WD_TIMO;
88static int wd_heartbeat;
89module_param(heartbeat, int, 0);
90MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")");
91
92#ifdef CONFIG_WATCHDOG_NOWAYOUT
93static int nowayout = 1;
94#else
95static int nowayout = 0;
96#endif
97
98module_param(nowayout, int, 0);
99MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
100
101#ifdef CONFIG_WDT_501_PCI
102/* Support for the Fan Tachometer on the PCI-WDT501 */
103static int tachometer;
104
105module_param(tachometer, int, 0);
106MODULE_PARM_DESC(tachometer, "PCI-WDT501 Fan Tachometer support (0=disable, default=0)");
107#endif /* CONFIG_WDT_501_PCI */
108
109/*
110 * Programming support
111 */
112
113static void wdtpci_ctr_mode(int ctr, int mode)
114{
115 ctr<<=6;
116 ctr|=0x30;
117 ctr|=(mode<<1);
118 outb_p(ctr, WDT_CR);
119}
120
121static void wdtpci_ctr_load(int ctr, int val)
122{
123 outb_p(val&0xFF, WDT_COUNT0+ctr);
124 outb_p(val>>8, WDT_COUNT0+ctr);
125}
126
127/**
128 * wdtpci_start:
129 *
130 * Start the watchdog driver.
131 */
132
133static int wdtpci_start(void)
134{
135 unsigned long flags;
136
137 spin_lock_irqsave(&wdtpci_lock, flags);
138
139 /*
140 * "pet" the watchdog, as Access says.
141 * This resets the clock outputs.
142 */
143 inb_p(WDT_DC); /* Disable watchdog */
144 wdtpci_ctr_mode(2,0); /* Program CTR2 for Mode 0: Pulse on Terminal Count */
145 outb_p(0, WDT_DC); /* Enable watchdog */
146
147 inb_p(WDT_DC); /* Disable watchdog */
148 outb_p(0, WDT_CLOCK); /* 2.0833MHz clock */
149 inb_p(WDT_BUZZER); /* disable */
150 inb_p(WDT_OPTONOTRST); /* disable */
151 inb_p(WDT_OPTORST); /* disable */
152 inb_p(WDT_PROGOUT); /* disable */
153 wdtpci_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */
154 wdtpci_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */
155 wdtpci_ctr_mode(2,1); /* Program CTR2 for Mode 1: Retriggerable One-Shot */
156 wdtpci_ctr_load(0,20833); /* count at 100Hz */
157 wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */
158 /* DO NOT LOAD CTR2 on PCI card! -- JPN */
159 outb_p(0, WDT_DC); /* Enable watchdog */
160
161 spin_unlock_irqrestore(&wdtpci_lock, flags);
162 return 0;
163}
164
165/**
166 * wdtpci_stop:
167 *
168 * Stop the watchdog driver.
169 */
170
171static int wdtpci_stop (void)
172{
173 unsigned long flags;
174
175 /* Turn the card off */
176 spin_lock_irqsave(&wdtpci_lock, flags);
177 inb_p(WDT_DC); /* Disable watchdog */
178 wdtpci_ctr_load(2,0); /* 0 length reset pulses now */
179 spin_unlock_irqrestore(&wdtpci_lock, flags);
180 return 0;
181}
182
183/**
184 * wdtpci_ping:
185 *
186 * Reload counter one with the watchdog heartbeat. We don't bother reloading
187 * the cascade counter.
188 */
189
190static int wdtpci_ping(void)
191{
192 unsigned long flags;
193
194 /* Write a watchdog value */
195 spin_lock_irqsave(&wdtpci_lock, flags);
196 inb_p(WDT_DC); /* Disable watchdog */
197 wdtpci_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */
198 wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */
199 outb_p(0, WDT_DC); /* Enable watchdog */
200 spin_unlock_irqrestore(&wdtpci_lock, flags);
201 return 0;
202}
203
204/**
205 * wdtpci_set_heartbeat:
206 * @t: the new heartbeat value that needs to be set.
207 *
208 * Set a new heartbeat value for the watchdog device. If the heartbeat value is
209 * incorrect we keep the old value and return -EINVAL. If successfull we
210 * return 0.
211 */
212static int wdtpci_set_heartbeat(int t)
213{
214 /* Arbitrary, can't find the card's limits */
215 if ((t < 1) || (t > 65535))
216 return -EINVAL;
217
218 heartbeat = t;
219 wd_heartbeat = t * 100;
220 return 0;
221}
222
223/**
224 * wdtpci_get_status:
225 * @status: the new status.
226 *
227 * Extract the status information from a WDT watchdog device. There are
228 * several board variants so we have to know which bits are valid. Some
229 * bits default to one and some to zero in order to be maximally painful.
230 *
231 * we then map the bits onto the status ioctl flags.
232 */
233
234static int wdtpci_get_status(int *status)
235{
236 unsigned char new_status=inb_p(WDT_SR);
237
238 *status=0;
239 if (new_status & WDC_SR_ISOI0)
240 *status |= WDIOF_EXTERN1;
241 if (new_status & WDC_SR_ISII1)
242 *status |= WDIOF_EXTERN2;
243#ifdef CONFIG_WDT_501_PCI
244 if (!(new_status & WDC_SR_TGOOD))
245 *status |= WDIOF_OVERHEAT;
246 if (!(new_status & WDC_SR_PSUOVER))
247 *status |= WDIOF_POWEROVER;
248 if (!(new_status & WDC_SR_PSUUNDR))
249 *status |= WDIOF_POWERUNDER;
250 if (tachometer) {
251 if (!(new_status & WDC_SR_FANGOOD))
252 *status |= WDIOF_FANFAULT;
253 }
254#endif /* CONFIG_WDT_501_PCI */
255 return 0;
256}
257
258#ifdef CONFIG_WDT_501_PCI
259/**
260 * wdtpci_get_temperature:
261 *
262 * Reports the temperature in degrees Fahrenheit. The API is in
263 * farenheit. It was designed by an imperial measurement luddite.
264 */
265
266static int wdtpci_get_temperature(int *temperature)
267{
268 unsigned short c=inb_p(WDT_RT);
269
270 *temperature = (c * 11 / 15) + 7;
271 return 0;
272}
273#endif /* CONFIG_WDT_501_PCI */
274
275/**
276 * wdtpci_interrupt:
277 * @irq: Interrupt number
278 * @dev_id: Unused as we don't allow multiple devices.
279 * @regs: Unused.
280 *
281 * Handle an interrupt from the board. These are raised when the status
282 * map changes in what the board considers an interesting way. That means
283 * a failure condition occurring.
284 */
285
286static irqreturn_t wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
287{
288 /*
289 * Read the status register see what is up and
290 * then printk it.
291 */
292 unsigned char status=inb_p(WDT_SR);
293
294 printk(KERN_CRIT PFX "status %d\n", status);
295
296#ifdef CONFIG_WDT_501_PCI
297 if (!(status & WDC_SR_TGOOD))
298 printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",inb_p(WDT_RT));
299 if (!(status & WDC_SR_PSUOVER))
300 printk(KERN_CRIT PFX "PSU over voltage.\n");
301 if (!(status & WDC_SR_PSUUNDR))
302 printk(KERN_CRIT PFX "PSU under voltage.\n");
303 if (tachometer) {
304 if (!(status & WDC_SR_FANGOOD))
305 printk(KERN_CRIT PFX "Possible fan fault.\n");
306 }
307#endif /* CONFIG_WDT_501_PCI */
308 if (!(status&WDC_SR_WCCR))
309#ifdef SOFTWARE_REBOOT
310#ifdef ONLY_TESTING
311 printk(KERN_CRIT PFX "Would Reboot.\n");
312#else
313 printk(KERN_CRIT PFX "Initiating system reboot.\n");
314 machine_restart(NULL);
315#endif
316#else
317 printk(KERN_CRIT PFX "Reset in 5ms.\n");
318#endif
319 return IRQ_HANDLED;
320}
321
322
323/**
324 * wdtpci_write:
325 * @file: file handle to the watchdog
326 * @buf: buffer to write (unused as data does not matter here
327 * @count: count of bytes
328 * @ppos: pointer to the position to write. No seeks allowed
329 *
330 * A write to a watchdog device is defined as a keepalive signal. Any
331 * write of data will do, as we we don't define content meaning.
332 */
333
334static ssize_t wdtpci_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
335{
336 if (count) {
337 if (!nowayout) {
338 size_t i;
339
340 expect_close = 0;
341
342 for (i = 0; i != count; i++) {
343 char c;
344 if(get_user(c, buf+i))
345 return -EFAULT;
346 if (c == 'V')
347 expect_close = 42;
348 }
349 }
350 wdtpci_ping();
351 }
352
353 return count;
354}
355
356/**
357 * wdtpci_ioctl:
358 * @inode: inode of the device
359 * @file: file handle to the device
360 * @cmd: watchdog command
361 * @arg: argument pointer
362 *
363 * The watchdog API defines a common set of functions for all watchdogs
364 * according to their available features. We only actually usefully support
365 * querying capabilities and current status.
366 */
367
368static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
369 unsigned long arg)
370{
371 int new_heartbeat;
372 int status;
373 void __user *argp = (void __user *)arg;
374 int __user *p = argp;
375
376 static struct watchdog_info ident = {
377 .options = WDIOF_SETTIMEOUT|
378 WDIOF_MAGICCLOSE|
379 WDIOF_KEEPALIVEPING,
380 .firmware_version = 1,
381 .identity = "PCI-WDT500/501",
382 };
383
384 /* Add options according to the card we have */
385 ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
386#ifdef CONFIG_WDT_501_PCI
387 ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER);
388 if (tachometer)
389 ident.options |= WDIOF_FANFAULT;
390#endif /* CONFIG_WDT_501_PCI */
391
392 switch(cmd)
393 {
394 default:
395 return -ENOIOCTLCMD;
396 case WDIOC_GETSUPPORT:
397 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
398
399 case WDIOC_GETSTATUS:
400 wdtpci_get_status(&status);
401 return put_user(status, p);
402 case WDIOC_GETBOOTSTATUS:
403 return put_user(0, p);
404 case WDIOC_KEEPALIVE:
405 wdtpci_ping();
406 return 0;
407 case WDIOC_SETTIMEOUT:
408 if (get_user(new_heartbeat, p))
409 return -EFAULT;
410
411 if (wdtpci_set_heartbeat(new_heartbeat))
412 return -EINVAL;
413
414 wdtpci_ping();
415 /* Fall */
416 case WDIOC_GETTIMEOUT:
417 return put_user(heartbeat, p);
418 }
419}
420
421/**
422 * wdtpci_open:
423 * @inode: inode of device
424 * @file: file handle to device
425 *
426 * The watchdog device has been opened. The watchdog device is single
427 * open and on opening we load the counters. Counter zero is a 100Hz
428 * cascade, into counter 1 which downcounts to reboot. When the counter
429 * triggers counter 2 downcounts the length of the reset pulse which
430 * set set to be as long as possible.
431 */
432
433static int wdtpci_open(struct inode *inode, struct file *file)
434{
435 if (down_trylock(&open_sem))
436 return -EBUSY;
437
438 if (nowayout) {
439 __module_get(THIS_MODULE);
440 }
441 /*
442 * Activate
443 */
444 wdtpci_start();
445 return nonseekable_open(inode, file);
446}
447
448/**
449 * wdtpci_release:
450 * @inode: inode to board
451 * @file: file handle to board
452 *
453 * The watchdog has a configurable API. There is a religious dispute
454 * between people who want their watchdog to be able to shut down and
455 * those who want to be sure if the watchdog manager dies the machine
456 * reboots. In the former case we disable the counters, in the latter
457 * case you have to open it again very soon.
458 */
459
460static int wdtpci_release(struct inode *inode, struct file *file)
461{
462 if (expect_close == 42) {
463 wdtpci_stop();
464 } else {
465 printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
466 wdtpci_ping();
467 }
468 expect_close = 0;
469 up(&open_sem);
470 return 0;
471}
472
473#ifdef CONFIG_WDT_501_PCI
474/**
475 * wdtpci_temp_read:
476 * @file: file handle to the watchdog board
477 * @buf: buffer to write 1 byte into
478 * @count: length of buffer
479 * @ptr: offset (no seek allowed)
480 *
481 * Read reports the temperature in degrees Fahrenheit. The API is in
482 * fahrenheit. It was designed by an imperial measurement luddite.
483 */
484
485static ssize_t wdtpci_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)
486{
487 int temperature;
488
489 if (wdtpci_get_temperature(&temperature))
490 return -EFAULT;
491
492 if (copy_to_user (buf, &temperature, 1))
493 return -EFAULT;
494
495 return 1;
496}
497
498/**
499 * wdtpci_temp_open:
500 * @inode: inode of device
501 * @file: file handle to device
502 *
503 * The temperature device has been opened.
504 */
505
506static int wdtpci_temp_open(struct inode *inode, struct file *file)
507{
508 return nonseekable_open(inode, file);
509}
510
511/**
512 * wdtpci_temp_release:
513 * @inode: inode to board
514 * @file: file handle to board
515 *
516 * The temperature device has been closed.
517 */
518
519static int wdtpci_temp_release(struct inode *inode, struct file *file)
520{
521 return 0;
522}
523#endif /* CONFIG_WDT_501_PCI */
524
525/**
526 * notify_sys:
527 * @this: our notifier block
528 * @code: the event being reported
529 * @unused: unused
530 *
531 * Our notifier is called on system shutdowns. We want to turn the card
532 * off at reboot otherwise the machine will reboot again during memory
533 * test or worse yet during the following fsck. This would suck, in fact
534 * trust me - if it happens it does suck.
535 */
536
537static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
538 void *unused)
539{
540 if (code==SYS_DOWN || code==SYS_HALT) {
541 /* Turn the card off */
542 wdtpci_stop();
543 }
544 return NOTIFY_DONE;
545}
546
547/*
548 * Kernel Interfaces
549 */
550
551
552static struct file_operations wdtpci_fops = {
553 .owner = THIS_MODULE,
554 .llseek = no_llseek,
555 .write = wdtpci_write,
556 .ioctl = wdtpci_ioctl,
557 .open = wdtpci_open,
558 .release = wdtpci_release,
559};
560
561static struct miscdevice wdtpci_miscdev = {
562 .minor = WATCHDOG_MINOR,
563 .name = "watchdog",
564 .fops = &wdtpci_fops,
565};
566
567#ifdef CONFIG_WDT_501_PCI
568static struct file_operations wdtpci_temp_fops = {
569 .owner = THIS_MODULE,
570 .llseek = no_llseek,
571 .read = wdtpci_temp_read,
572 .open = wdtpci_temp_open,
573 .release = wdtpci_temp_release,
574};
575
576static struct miscdevice temp_miscdev = {
577 .minor = TEMP_MINOR,
578 .name = "temperature",
579 .fops = &wdtpci_temp_fops,
580};
581#endif /* CONFIG_WDT_501_PCI */
582
583/*
584 * The WDT card needs to learn about soft shutdowns in order to
585 * turn the timebomb registers off.
586 */
587
588static struct notifier_block wdtpci_notifier = {
589 .notifier_call = wdtpci_notify_sys,
590};
591
592
593static int __devinit wdtpci_init_one (struct pci_dev *dev,
594 const struct pci_device_id *ent)
595{
596 int ret = -EIO;
597
598 dev_count++;
599 if (dev_count > 1) {
600 printk (KERN_ERR PFX "this driver only supports 1 device\n");
601 return -ENODEV;
602 }
603
604 if (pci_enable_device (dev)) {
605 printk (KERN_ERR PFX "Not possible to enable PCI Device\n");
606 return -ENODEV;
607 }
608
609 if (pci_resource_start (dev, 2) == 0x0000) {
610 printk (KERN_ERR PFX "No I/O-Address for card detected\n");
611 ret = -ENODEV;
612 goto out_pci;
613 }
614
615 sema_init(&open_sem, 1);
616 spin_lock_init(&wdtpci_lock);
617
618 irq = dev->irq;
619 io = pci_resource_start (dev, 2);
620
621 if (request_region (io, 16, "wdt_pci") == NULL) {
622 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", io);
623 goto out_pci;
624 }
625
626 if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ,
627 "wdt_pci", &wdtpci_miscdev)) {
628 printk (KERN_ERR PFX "IRQ %d is not free\n", irq);
629 goto out_reg;
630 }
631
632 printk ("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%04x (Interrupt %d)\n",
633 io, irq);
634
635 /* Check that the heartbeat value is within it's range ; if not reset to the default */
636 if (wdtpci_set_heartbeat(heartbeat)) {
637 wdtpci_set_heartbeat(WD_TIMO);
638 printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
639 WD_TIMO);
640 }
641
642 ret = register_reboot_notifier (&wdtpci_notifier);
643 if (ret) {
644 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
645 goto out_irq;
646 }
647
648#ifdef CONFIG_WDT_501_PCI
649 ret = misc_register (&temp_miscdev);
650 if (ret) {
651 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
652 TEMP_MINOR, ret);
653 goto out_rbt;
654 }
655#endif /* CONFIG_WDT_501_PCI */
656
657 ret = misc_register (&wdtpci_miscdev);
658 if (ret) {
659 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
660 WATCHDOG_MINOR, ret);
661 goto out_misc;
662 }
663
664 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
665 heartbeat, nowayout);
666#ifdef CONFIG_WDT_501_PCI
667 printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled"));
668#endif /* CONFIG_WDT_501_PCI */
669
670 ret = 0;
671out:
672 return ret;
673
674out_misc:
675#ifdef CONFIG_WDT_501_PCI
676 misc_deregister(&temp_miscdev);
677out_rbt:
678#endif /* CONFIG_WDT_501_PCI */
679 unregister_reboot_notifier(&wdtpci_notifier);
680out_irq:
681 free_irq(irq, &wdtpci_miscdev);
682out_reg:
683 release_region (io, 16);
684out_pci:
685 pci_disable_device(dev);
686 goto out;
687}
688
689
690static void __devexit wdtpci_remove_one (struct pci_dev *pdev)
691{
692 /* here we assume only one device will ever have
693 * been picked up and registered by probe function */
694 misc_deregister(&wdtpci_miscdev);
695#ifdef CONFIG_WDT_501_PCI
696 misc_deregister(&temp_miscdev);
697#endif /* CONFIG_WDT_501_PCI */
698 unregister_reboot_notifier(&wdtpci_notifier);
699 free_irq(irq, &wdtpci_miscdev);
700 release_region(io, 16);
701 pci_disable_device(pdev);
702 dev_count--;
703}
704
705
706static struct pci_device_id wdtpci_pci_tbl[] = {
707 {
708 .vendor = PCI_VENDOR_ID_ACCESSIO,
709 .device = PCI_DEVICE_ID_WDG_CSM,
710 .subvendor = PCI_ANY_ID,
711 .subdevice = PCI_ANY_ID,
712 },
713 { 0, }, /* terminate list */
714};
715MODULE_DEVICE_TABLE(pci, wdtpci_pci_tbl);
716
717
718static struct pci_driver wdtpci_driver = {
719 .name = "wdt_pci",
720 .id_table = wdtpci_pci_tbl,
721 .probe = wdtpci_init_one,
722 .remove = __devexit_p(wdtpci_remove_one),
723};
724
725
726/**
727 * wdtpci_cleanup:
728 *
729 * Unload the watchdog. You cannot do this with any file handles open.
730 * If your watchdog is set to continue ticking on close and you unload
731 * it, well it keeps ticking. We won't get the interrupt but the board
732 * will not touch PC memory so all is fine. You just have to load a new
733 * module in xx seconds or reboot.
734 */
735
736static void __exit wdtpci_cleanup(void)
737{
738 pci_unregister_driver (&wdtpci_driver);
739}
740
741
742/**
743 * wdtpci_init:
744 *
745 * Set up the WDT watchdog board. All we have to do is grab the
746 * resources we require and bitch if anyone beat us to them.
747 * The open() function will actually kick the board off.
748 */
749
750static int __init wdtpci_init(void)
751{
752 return pci_register_driver (&wdtpci_driver);
753}
754
755
756module_init(wdtpci_init);
757module_exit(wdtpci_cleanup);
758
759MODULE_AUTHOR("JP Nollmann, Alan Cox");
760MODULE_DESCRIPTION("Driver for the ICS PCI-WDT500/501 watchdog cards");
761MODULE_LICENSE("GPL");
762MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
763MODULE_ALIAS_MISCDEV(TEMP_MINOR);