xref: /freebsd/sys/dev/wbwd/wbwd.c (revision 3ef51c5fb9163f2aafb1c14729e06a8bf0c4d113)
1 /*-
2  * Copyright (c) 2011 Sandvine Incorporated ULC.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /*
27  * Support for Winbond watchdog.
28  *
29  * With minor abstractions it might be possible to add support for other
30  * different Winbond Super I/O chips as well.  Winbond seems to have four
31  * different types of chips, four different ways to get into extended config
32  * mode.
33  *
34  * Note: there is no serialization between the debugging sysctl handlers and
35  * the watchdog functions and possibly others poking the registers at the same
36  * time.  For that at least possibly interfering sysctls are hidden by default.
37  */
38 
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41 
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/systm.h>
45 #include <sys/bus.h>
46 #include <sys/eventhandler.h>
47 #include <sys/lock.h>
48 #include <sys/module.h>
49 #include <sys/rman.h>
50 #include <sys/sbuf.h>
51 #include <sys/sysctl.h>
52 #include <sys/watchdog.h>
53 
54 #include <isa/isavar.h>
55 
56 #include <machine/bus.h>
57 #include <machine/resource.h>
58 
59 /*
60  * Global registers.
61  */
62 #define	WB_DEVICE_ID_REG	0x20	/* Device ID */
63 #define	WB_DEVICE_REV_REG	0x21	/* Device revision */
64 #define	WB_CR26			0x26	/* Bit6: HEFRAS (base port selector) */
65 
66 /* LDN selection. */
67 #define	WB_LDN_REG		0x07
68 #define	WB_LDN_REG_LDN8		0x08	/* GPIO 2, Watchdog */
69 
70 /*
71  * LDN8 (GPIO 2, Watchdog) specific registers and options.
72  */
73 /* CR30: LDN8 activation control. */
74 #define	WB_LDN8_CR30		0x30
75 #define	WB_LDN8_CR30_ACTIVE	0x01	/* 1: LD active */
76 
77 /* CRF5: Watchdog scale, P20. Mapped to reg_1. */
78 #define	WB_LDN8_CRF5		0xF5
79 #define	WB_LDN8_CRF5_SCALE	0x08	/* 0: 1s, 1: 60s */
80 #define	WB_LDN8_CRF5_KEYB_P20	0x04	/* 1: keyb P20 forces timeout */
81 
82 /* CRF6: Watchdog Timeout (0 == off). Mapped to reg_timeout. */
83 #define	WB_LDN8_CRF6		0xF6
84 
85 /* CRF7: Watchdog mouse, keyb, force, .. Mapped to reg_2. */
86 #define	WB_LDN8_CRF7		0xF7
87 #define	WB_LDN8_CRF7_MOUSE	0x80	/* 1: mouse irq resets wd timer */
88 #define	WB_LDN8_CRF7_KEYB	0x40	/* 1: keyb irq resets wd timer */
89 #define	WB_LDN8_CRF7_FORCE	0x20	/* 1: force timeout (self-clear) */
90 #define	WB_LDN8_CRF7_TS		0x10	/* 0: counting, 1: fired */
91 #define	WB_LDN8_CRF7_IRQS	0x0f	/* irq source for watchdog, 2 == SMI */
92 #define	WB_LDN8_CRF7_CLEAR_MASK	\
93     (WB_LDN8_CRF7_MOUSE|WB_LDN8_CRF7_KEYB|WB_LDN8_CRF7_TS|WB_LDN8_CRF7_IRQS)
94 
95 #define	write_efir_1(sc, value)						\
96 	bus_space_write_1((sc)->bst, (sc)->bsh, 0, (value))
97 #define	read_efir_1(sc)							\
98 	bus_space_read_1((sc)->bst, (sc)->bsh, 0)
99 #define	write_efdr_1(sc, value)						\
100 	bus_space_write_1((sc)->bst, (sc)->bsh, 1, (value))
101 #define	read_efdr_1(sc)							\
102 	bus_space_read_1((sc)->bst, (sc)->bsh, 1)
103 
104 struct wb_softc {
105 	device_t		dev;
106 	struct resource		*portres;
107 	bus_space_tag_t		bst;
108 	bus_space_handle_t	bsh;
109 	int			rid;
110 	eventhandler_tag	ev_tag;
111 	int			(*ext_cfg_enter_f)(struct wb_softc *);
112 	void			(*ext_cfg_exit_f)(struct wb_softc *);
113 	int			debug_verbose;
114 
115 	/*
116 	 * Special feature to let the watchdog fire at a different
117 	 * timeout as set by watchdog(4) but still use that API to
118 	 * re-load it periodically.
119 	 */
120 	unsigned int		timeout_override;
121 
122 	/*
123 	 * Space to save current state temporary and for sysctls.
124 	 * We want to know the timeout value and usually need two
125 	 * additional registers for options. Do not name them by
126 	 * register as these might be different by chip.
127 	 */
128 	uint8_t			reg_timeout;
129 	uint8_t			reg_1;
130 	uint8_t			reg_2;
131 };
132 
133 static int	ext_cfg_enter_0x87_0x87(struct wb_softc *);
134 static void	ext_cfg_exit_0xaa(struct wb_softc *);
135 
136 struct winbond_superio_cfg {
137 	uint8_t			efer;	/* and efir */
138 	int			(*ext_cfg_enter_f)(struct wb_softc *);
139 	void			(*ext_cfg_exit_f)(struct wb_softc *);
140 } probe_addrs[] = {
141 	{
142 		.efer			= 0x2e,
143 		.ext_cfg_enter_f	= ext_cfg_enter_0x87_0x87,
144 		.ext_cfg_exit_f		= ext_cfg_exit_0xaa,
145 	},
146 	{
147 		.efer			= 0x4e,
148 		.ext_cfg_enter_f	= ext_cfg_enter_0x87_0x87,
149 		.ext_cfg_exit_f		= ext_cfg_exit_0xaa,
150 	},
151 };
152 
153 struct winbond_vendor_device_id {
154 	uint16_t		vendor_id;
155 	uint8_t			device_id;
156 	uint8_t			device_rev;
157 	const char *		descr;
158 } wb_devs[] = {
159 	{
160 		.vendor_id	= 0x5ca3,
161 		.device_id	= 0x52,
162 		.device_rev	= 0x17,
163 		.descr		= "Winbond 83627HF/F/HG/G Rev. G",
164 	},
165 	{
166 		.vendor_id	= 0x5ca3,
167 		.device_id	= 0x52,
168 		.device_rev	= 0x3a,
169 		.descr		= "Winbond 83627HF/F/HG/G Rev. J",
170 	},
171 	{
172 		.vendor_id	= 0x5ca3,
173 		.device_id	= 0x52,
174 		.device_rev	= 0x41,
175 		.descr		= "Winbond 83627HF/F/HG/G Rev. UD-A",
176 	},
177 	{
178 		.vendor_id	= 0x5ca3,
179 		.device_id	= 0xa0,
180 		.device_rev	= 0x25,
181 		.descr		= "Winbond 83627DHG IC ver. 5",
182 	},
183 };
184 
185 /*
186  * Return the watchdog related registers as we last read them.  This will
187  * usually not give the current timeout or state on whether the watchdog
188  * fired.
189  */
190 static int
191 sysctl_wb_debug(SYSCTL_HANDLER_ARGS)
192 {
193 	struct wb_softc *sc;
194 	struct sbuf sb;
195 	int error;
196 
197 	sc = arg1;
198 
199 	sbuf_new_for_sysctl(&sb, NULL, 64, req);
200 
201 	sbuf_printf(&sb, "LDN8 (GPIO2, Watchdog): ");
202 	sbuf_printf(&sb, "CRF5 0x%02x ", sc->reg_1);
203 	sbuf_printf(&sb, "CRF6 0x%02x ", sc->reg_timeout);
204 	sbuf_printf(&sb, "CRF7 0x%02x ", sc->reg_2);
205 
206 	sbuf_trim(&sb);
207 	error = sbuf_finish(&sb);
208 	sbuf_delete(&sb);
209 	return (error);
210 }
211 
212 /*
213  * Read the current values before returning them.  Given this might poke
214  * the registers the same time as the watchdog, this sysctl handler should
215  * be marked CTLFLAG_SKIP to not show up by default.
216  */
217 static int
218 sysctl_wb_debug_current(SYSCTL_HANDLER_ARGS)
219 {
220 	struct wb_softc *sc;
221 
222 	sc = arg1;
223 
224 	/*
225 	 * Enter extended function mode in case someone else has been
226 	 * poking on the registers.  We will not leave it though.
227 	 */
228 	if ((*sc->ext_cfg_enter_f)(sc) != 0)
229 		return (ENXIO);
230 
231 	/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */
232 	write_efir_1(sc, WB_LDN_REG);
233 	write_efdr_1(sc, WB_LDN_REG_LDN8);
234 
235 	write_efir_1(sc, WB_LDN8_CRF5);
236 	sc->reg_1 = read_efdr_1(sc);
237 	write_efir_1(sc, WB_LDN8_CRF6);
238 	sc->reg_timeout = read_efdr_1(sc);
239 	write_efir_1(sc, WB_LDN8_CRF7);
240 	sc->reg_2 = read_efdr_1(sc);
241 
242 	return (sysctl_wb_debug(oidp, arg1, arg2, req));
243 }
244 
245 /*
246  * Sysctl handlers to force a watchdog timeout or to test the NMI functionality
247  * works as expetced.
248  * For testing we could set a test_nmi flag in the softc that, in case of NMI, a
249  * callback function from trap.c could check whether we fired and not report the
250  * timeout but clear the flag for the sysctl again.  This is interesting given a
251  * lot of boards have jumpers to change the action on watchdog timeout or
252  * disable the watchdog completely.
253  * XXX-BZ notyet: currently no general infrastructure exists to do this.
254  */
255 static int
256 sysctl_wb_force_test_nmi(SYSCTL_HANDLER_ARGS)
257 {
258 	struct wb_softc *sc;
259 	int error, test, val;
260 
261 	sc = arg1;
262 	test = arg2;
263 
264 #ifdef notyet
265 	val = sc->test_nmi;
266 #else
267 	val = 0;
268 #endif
269 	error = sysctl_handle_int(oidp, &val, 0, req);
270         if (error || !req->newptr)
271                 return (error);
272 
273 #ifdef notyet
274 	/* Manually clear the test for a value of 0 and do nothing else. */
275 	if (test && val == 0) {
276 		sc->test_nmi = 0;
277 		return (0);
278 	}
279 #endif
280 
281 	/*
282 	 * Enter extended function mode in case someone else has been
283 	 * poking on the registers.  We will not leave it though.
284 	 */
285 	if ((*sc->ext_cfg_enter_f)(sc) != 0)
286 		return (ENXIO);
287 
288 #ifdef notyet
289 	/*
290 	 * If we are testing the NMI functionality, set the flag before
291 	 * forcing the timeout.
292 	 */
293 	if (test)
294 		sc->test_nmi = 1;
295 #endif
296 
297 	/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */
298 	write_efir_1(sc, WB_LDN_REG);
299 	write_efdr_1(sc, WB_LDN_REG_LDN8);
300 
301 	/* Force watchdog to fire. */
302 	write_efir_1(sc, WB_LDN8_CRF7);
303 	sc->reg_2 = read_efdr_1(sc);
304 	sc->reg_2 |= WB_LDN8_CRF7_FORCE;
305 
306 	write_efir_1(sc, WB_LDN8_CRF7);
307 	write_efdr_1(sc, sc->reg_2);
308 
309 	return (0);
310 }
311 
312 /*
313  * Print current watchdog state.
314  *
315  * Note: it is the responsibility of the caller to update the registers
316  * upfront.
317  */
318 static void
319 wb_print_state(struct wb_softc *sc, const char *msg)
320 {
321 
322 	device_printf(sc->dev, "%s%sWatchdog %sabled. %s"
323 	    "Scaling by %ds, timer at %d (%s=%ds%s). "
324 	    "CRF5 0x%02x CRF7 0x%02x\n",
325 	    (msg != NULL) ? msg : "", (msg != NULL) ? ": " : "",
326 	    (sc->reg_timeout > 0x00) ? "en" : "dis",
327 	    (sc->reg_2 & WB_LDN8_CRF7_TS) ? "Watchdog fired. " : "",
328 	    (sc->reg_1 & WB_LDN8_CRF5_SCALE) ? 60 : 1,
329 	    sc->reg_timeout,
330 	    (sc->reg_timeout > 0x00) ? "<" : "",
331 	    sc->reg_timeout * ((sc->reg_1 & WB_LDN8_CRF5_SCALE) ? 60 : 1),
332 	    (sc->reg_timeout > 0x00) ? " left" : "",
333 	    sc->reg_1, sc->reg_2);
334 }
335 
336 /*
337  * Functions to enter and exit extended function mode.  Possibly shared
338  * between different chips.
339  */
340 static int
341 ext_cfg_enter_0x87_0x87(struct wb_softc *sc)
342 {
343 
344 	/*
345 	 * Enable extended function mode.
346 	 * Winbond does not allow us to validate so always return success.
347 	 */
348 	write_efir_1(sc, 0x87);
349 	write_efir_1(sc, 0x87);
350 
351 	return (0);
352 }
353 
354 static void
355 ext_cfg_exit_0xaa(struct wb_softc *sc)
356 {
357 
358 	write_efir_1(sc, 0xaa);
359 }
360 
361 /*
362  * (Re)load the watchdog counter depending on timeout.  A timeout of 0 will
363  * disable the watchdog.
364  */
365 static int
366 wb_set_watchdog(struct wb_softc *sc, unsigned int timeout)
367 {
368 
369 	if (sc->debug_verbose)
370 		wb_print_state(sc, "Before watchdog counter (re)load");
371 
372 	/*
373 	 * Enter extended function mode in case someone else has been
374 	 * poking on the registers.  We will not leave it though.
375 	 */
376 	if ((*sc->ext_cfg_enter_f)(sc) != 0)
377 		return (ENXIO);
378 
379 	/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog) */
380 	write_efir_1(sc, WB_LDN_REG);
381 	write_efdr_1(sc, WB_LDN_REG_LDN8);
382 
383 	/* Disable and validate or arm/reset watchdog. */
384 	if (timeout == 0) {
385 		/* Disable watchdog. */
386 		write_efir_1(sc, WB_LDN8_CRF6);
387 		write_efdr_1(sc, 0x00);
388 
389 		/* Re-check. */
390 		write_efir_1(sc, WB_LDN8_CRF6);
391 		sc->reg_timeout = read_efdr_1(sc);
392 
393 		if (sc->reg_timeout != 0x00) {
394 			device_printf(sc->dev, "Failed to disable watchdog: "
395 			    "0x%02x.\n", sc->reg_timeout);
396 			return (EIO);
397 		}
398 
399 	} else {
400 		/*
401 		 * In case an override is set, let it override.  It may lead
402 		 * to strange results as we do not check the input of the sysctl.
403 		 */
404 		if (sc->timeout_override > 0)
405 			timeout = sc->timeout_override;
406 
407 		/* Make sure we support the requested timeout. */
408 		if (timeout > 255 * 60)
409 			return (EINVAL);
410 
411 		/* Read current scaling factor. */
412 		write_efir_1(sc, WB_LDN8_CRF5);
413 		sc->reg_1 = read_efdr_1(sc);
414 
415 		if (timeout > 255) {
416 			/* Set scaling factor to 60s. */
417 			sc->reg_1 |= WB_LDN8_CRF5_SCALE;
418 			sc->reg_timeout = (timeout / 60);
419 			if (timeout % 60)
420 				sc->reg_timeout++;
421 		} else {
422 			/* Set scaling factor to 1s. */
423 			sc->reg_1 &= ~WB_LDN8_CRF5_SCALE;
424 			sc->reg_timeout = timeout;
425 		}
426 
427 		/* In case we fired before we need to clear to fire again. */
428 		write_efir_1(sc, WB_LDN8_CRF7);
429 		sc->reg_2 = read_efdr_1(sc);
430 		if (sc->reg_2 & WB_LDN8_CRF7_TS) {
431 			sc->reg_2 &= ~WB_LDN8_CRF7_TS;
432 			write_efir_1(sc, WB_LDN8_CRF7);
433 			write_efdr_1(sc, sc->reg_2);
434 		}
435 
436 		/* Write back scaling factor. */
437 		write_efir_1(sc, WB_LDN8_CRF5);
438 		write_efdr_1(sc, sc->reg_1);
439 
440 		/* Set timer and arm/reset the watchdog. */
441 		write_efir_1(sc, WB_LDN8_CRF6);
442 		write_efdr_1(sc, sc->reg_timeout);
443 	}
444 
445 	if (sc->debug_verbose)
446 		wb_print_state(sc, "After watchdog counter (re)load");
447 
448 	return (0);
449 }
450 
451 /*
452  * watchdog(9) EVENTHANDLER function implementation to (re)load the counter
453  * with the given timeout or disable the watchdog.
454  */
455 static void
456 wb_watchdog_fn(void *private, u_int cmd, int *error)
457 {
458 	struct wb_softc *sc;
459 	unsigned int timeout;
460 	int e;
461 
462 	sc = private;
463 	KASSERT(sc != NULL, ("%s: watchdog handler function called without "
464 	    "softc.", __func__));
465 
466 	cmd &= WD_INTERVAL;
467 	if (cmd > 0 && cmd <= 63) {
468 		/* Reset (and arm) watchdog. */
469 		timeout = ((uint64_t)1 << cmd) / 1000000000;
470 		if (timeout == 0)
471 			timeout = 1;
472 		e = wb_set_watchdog(sc, timeout);
473 		if (e == 0) {
474 			if (error != NULL)
475 				*error = 0;
476 		} else {
477 			/* On error, try to make sure the WD is disabled. */
478 			wb_set_watchdog(sc, 0);
479 		}
480 
481 	} else {
482 		/* Disable watchdog. */
483 		e = wb_set_watchdog(sc, 0);
484 		if (e != 0 && cmd == 0 && error != NULL) {
485 			/* Failed to disable watchdog. */
486 			*error = EOPNOTSUPP;
487 		}
488 	}
489 }
490 
491 /*
492  * Probe/attach the Winbond Super I/O chip.
493  *
494  * Initial abstraction to possibly support more chips:
495  * - Iterate over the well known base ports, try to enable extended function
496  *   mode and read and match the device ID and device revision.  Unfortunately
497  *   the Vendor ID is in the hardware monitoring section accessible by different
498  *   base ports only.
499  * - Also HEFRAS, which would tell use the base port, is only accessible after
500  *   entering extended function mode, for which the base port is needed.
501  *   At least check HEFRAS to match the current base port we are probing.
502  * - On match set the description, remember functions to enter/exit extended
503  *   function mode as well as the base port.
504  */
505 static int
506 wb_probe_enable(device_t dev, int probe)
507 {
508 	struct wb_softc *sc;
509 	int error, found, i, j;
510 	uint8_t dev_id, dev_rev, cr26;
511 
512 	sc = device_get_softc(dev);
513 	bzero(sc, sizeof(*sc));
514 	sc->dev = dev;
515 
516 	error = ENXIO;
517 	for (i = 0; i < sizeof(probe_addrs) / sizeof(*probe_addrs); i++) {
518 
519 		/* Allocate bus resources for IO index/data register access. */
520 		sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid,
521 		    probe_addrs[i].efer, probe_addrs[i].efer + 1, 2, RF_ACTIVE);
522 		if (sc->portres == NULL)
523 			continue;
524 		sc->bst = rman_get_bustag(sc->portres);
525 		sc->bsh = rman_get_bushandle(sc->portres);
526 
527 		found = 0;
528 		error = (*probe_addrs[i].ext_cfg_enter_f)(sc);
529 		if (error != 0)
530 			goto cleanup;
531 
532 		/* Identify the SuperIO chip. */
533 		write_efir_1(sc, WB_DEVICE_ID_REG);
534 		dev_id = read_efdr_1(sc);
535 		write_efir_1(sc, WB_DEVICE_REV_REG);
536 		dev_rev = read_efdr_1(sc);
537 		write_efir_1(sc, WB_CR26);
538 		cr26 = read_efdr_1(sc);
539 
540 		/* HEFRAS of 0 means EFER at 0x2e, 1 means EFER at 0x4e. */
541 		if (((cr26 & 0x40) == 0x00 && probe_addrs[i].efer != 0x2e) ||
542 		    ((cr26 & 0x40) == 0x40 && probe_addrs[i].efer != 0x4e)) {
543 			device_printf(dev, "HEFRAS and EFER do not align: EFER "
544 			    "0x%02x DevID 0x%02x DevRev 0x%02x CR26 0x%02x\n",
545 			     probe_addrs[i].efer, dev_id, dev_rev, cr26);
546 			goto cleanup;
547 		}
548 
549 		for (j = 0; j < sizeof(wb_devs) / sizeof(*wb_devs); j++) {
550 			if (wb_devs[j].device_id == dev_id &&
551 			    wb_devs[j].device_rev == dev_rev) {
552 				if (probe)
553 					device_set_desc(dev, wb_devs[j].descr);
554 				found++;
555 				break;
556 			}
557 		}
558 		if (probe && found && bootverbose)
559 			device_printf(dev, "%s EFER 0x%02x ID 0x%02x Rev 0x%02x"
560 			     " CR26 0x%02x (probing)\n", device_get_desc(dev),
561 			     probe_addrs[i].efer, dev_id, dev_rev, cr26);
562 cleanup:
563 		if (probe || !found) {
564 			(*probe_addrs[i].ext_cfg_exit_f)(sc);
565 
566 			(void) bus_release_resource(dev, SYS_RES_IOPORT, sc->rid,
567 			    sc->portres);
568 		}
569 
570 		/*
571 		 * Stop probing if have successfully identified the SuperIO.
572 		 * Remember the extended function mode enter/exit functions
573 		 * for operations.
574 		 */
575 		if (found) {
576 			sc->ext_cfg_enter_f = probe_addrs[i].ext_cfg_enter_f;
577 			sc->ext_cfg_exit_f = probe_addrs[i].ext_cfg_exit_f;
578 			error = BUS_PROBE_DEFAULT;
579 			break;
580 		} else
581 			error = ENXIO;
582 	}
583 
584 	return (error);
585 }
586 
587 static int
588 wb_probe(device_t dev)
589 {
590 
591 	/* Make sure we do not claim some ISA PNP device. */
592 	if (isa_get_logicalid(dev) != 0)
593 		return (ENXIO);
594 
595 	return (wb_probe_enable(dev, 1));
596 }
597 
598 static int
599 wb_attach(device_t dev)
600 {
601 	struct wb_softc *sc;
602 	struct sysctl_ctx_list *sctx;
603 	struct sysctl_oid *soid;
604 	unsigned long timeout;
605 	int error;
606 
607 	error = wb_probe_enable(dev, 0);
608 	if (error > 0)
609 		return (ENXIO);
610 
611 	sc = device_get_softc(dev);
612 	KASSERT(sc->ext_cfg_enter_f != NULL && sc->ext_cfg_exit_f != NULL,
613 	    ("%s: successfull probe result but not setup correctly", __func__));
614 
615 	/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */
616 	write_efir_1(sc, WB_LDN_REG);
617 	write_efdr_1(sc, WB_LDN_REG_LDN8);
618 
619 	/* Make sure LDN8 is enabled (Do we need to? Also affects GPIO). */
620 	write_efir_1(sc, WB_LDN8_CR30);
621 	write_efdr_1(sc, WB_LDN8_CR30_ACTIVE);
622 
623 	/* Read the current watchdog configuration. */
624 	write_efir_1(sc, WB_LDN8_CRF5);
625 	sc->reg_1 = read_efdr_1(sc);
626 	write_efir_1(sc, WB_LDN8_CRF6);
627 	sc->reg_timeout = read_efdr_1(sc);
628 	write_efir_1(sc, WB_LDN8_CRF7);
629 	sc->reg_2 = read_efdr_1(sc);
630 
631 	/* Print current state if bootverbose or watchdog already enabled. */
632 	if (bootverbose || (sc->reg_timeout > 0x00))
633 		wb_print_state(sc, "Before watchdog attach");
634 
635 	/*
636 	 * Clear a previous watchdog timeout event (if (still) set).
637 	 * Disable all all interrupt reset sources (defaults).
638 	 */
639 	sc->reg_1 &= ~(WB_LDN8_CRF5_KEYB_P20);
640 	write_efir_1(sc, WB_LDN8_CRF5);
641 	write_efir_1(sc, sc->reg_1);
642 
643 	sc->reg_2 &= ~WB_LDN8_CRF7_CLEAR_MASK;
644 	write_efir_1(sc, WB_LDN8_CRF7);
645 	write_efdr_1(sc, sc->reg_2);
646 
647 	/* Read global timeout override tunable, Add per device sysctls. */
648 	if (TUNABLE_ULONG_FETCH("hw.wbwd.timeout_override", &timeout)) {
649 		if (timeout > 0)
650 			sc->timeout_override = timeout;
651 	}
652 	sctx = device_get_sysctl_ctx(dev);
653 	soid = device_get_sysctl_tree(dev);
654         SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO,
655 	    "timeout_override", CTLFLAG_RW, &sc->timeout_override, 0,
656             "Timeout in seconds overriding default watchdog timeout");
657         SYSCTL_ADD_INT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO,
658 	    "debug_verbose", CTLFLAG_RW, &sc->debug_verbose, 0,
659             "Enables extra debugging information");
660         SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "debug",
661 	    CTLTYPE_STRING|CTLFLAG_RD, sc, 0, sysctl_wb_debug, "A",
662             "Selected register information from last change by driver");
663         SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "debug_current",
664 	    CTLTYPE_STRING|CTLFLAG_RD|CTLFLAG_SKIP, sc, 0,
665 	     sysctl_wb_debug_current, "A",
666 	     "Selected register information (may interfere)");
667 	SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "force_timeout",
668 	    CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_SKIP, sc, 0,
669 	    sysctl_wb_force_test_nmi, "I", "Enable to force watchdog to fire.");
670 
671 	/* Register watchdog. */
672 	sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, wb_watchdog_fn, sc,
673 	    0);
674 
675 	if (bootverbose)
676 		wb_print_state(sc, "After watchdog attach");
677 
678 	return (0);
679 }
680 
681 static int
682 wb_detach(device_t dev)
683 {
684 	struct wb_softc *sc;
685 
686 	sc = device_get_softc(dev);
687 
688 	/* Unregister and stop the watchdog if running. */
689 	if (sc->ev_tag)
690 		EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag);
691 	wb_set_watchdog(sc, 0);
692 
693 	/* Disable extended function mode. */
694 	(*sc->ext_cfg_exit_f)(sc);
695 
696 	/* Cleanup resources. */
697 	(void) bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
698 
699 	/* Bus subroutines take care of sysctls already. */
700 
701 	return (0);
702 }
703 
704 static device_method_t wb_methods[] = {
705 	/* Device interface */
706 	DEVMETHOD(device_probe,		wb_probe),
707 	DEVMETHOD(device_attach,	wb_attach),
708 	DEVMETHOD(device_detach,	wb_detach),
709 
710 	{ 0, 0 }
711 };
712 
713 static driver_t wb_isa_driver = {
714 	"wbwd",
715 	wb_methods,
716 	sizeof(struct wb_softc)
717 };
718 
719 static devclass_t wb_devclass;
720 
721 DRIVER_MODULE(wb, isa, wb_isa_driver, wb_devclass, NULL, NULL);
722