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