The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/wbwd/wbwd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2011 Sandvine Incorporated ULC.
    5  * Copyright (c) 2012 iXsystems, Inc.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 /*
   30  * Support for Winbond watchdog.
   31  *
   32  * With minor abstractions it might be possible to add support for other
   33  * different Winbond Super I/O chips as well.  Winbond seems to have four
   34  * different types of chips, four different ways to get into extended config
   35  * mode.
   36  *
   37  * Note: there is no serialization between the debugging sysctl handlers and
   38  * the watchdog functions and possibly others poking the registers at the same
   39  * time.  For that at least possibly interfering sysctls are hidden by default.
   40  */
   41 
   42 #include <sys/cdefs.h>
   43 __FBSDID("$FreeBSD$");
   44 
   45 #include <sys/param.h>
   46 #include <sys/kernel.h>
   47 #include <sys/systm.h>
   48 #include <sys/bus.h>
   49 #include <sys/eventhandler.h>
   50 #include <sys/module.h>
   51 #include <sys/sbuf.h>
   52 #include <sys/sysctl.h>
   53 #include <sys/watchdog.h>
   54 
   55 #include <dev/superio/superio.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 
   95 enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
   96              w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg,
   97              w83627dhg_p, w83667hg_b, nct6775, nct6776, nct6779, nct6791,
   98              nct6792, nct6793, nct6795, nct6102 };
   99 
  100 struct wb_softc {
  101         device_t                dev;
  102         eventhandler_tag        ev_tag;
  103         enum chips              chip;
  104         uint8_t                 ctl_reg;
  105         uint8_t                 time_reg;
  106         uint8_t                 csr_reg;
  107         int                     debug_verbose;
  108 
  109         /*
  110          * Special feature to let the watchdog fire at a different
  111          * timeout as set by watchdog(4) but still use that API to
  112          * re-load it periodically.
  113          */
  114         unsigned int            timeout_override;
  115 
  116         /*
  117          * Space to save current state temporary and for sysctls.
  118          * We want to know the timeout value and usually need two
  119          * additional registers for options. Do not name them by
  120          * register as these might be different by chip.
  121          */
  122         uint8_t                 reg_timeout;
  123         uint8_t                 reg_1;
  124         uint8_t                 reg_2;
  125 };
  126 
  127 struct winbond_vendor_device_id {
  128         uint8_t                 device_id;
  129         enum chips              chip;
  130         const char *            descr;
  131 } wb_devs[] = {
  132         {
  133                 .device_id      = 0x52,
  134                 .chip           = w83627hf,
  135                 .descr          = "Winbond 83627HF/F/HG/G",
  136         },
  137         {
  138                 .device_id      = 0x59,
  139                 .chip           = w83627s,
  140                 .descr          = "Winbond 83627S",
  141         },
  142         {
  143                 .device_id      = 0x60,
  144                 .chip           = w83697hf,
  145                 .descr          = "Winbond 83697HF",
  146         },
  147         {
  148                 .device_id      = 0x68,
  149                 .chip           = w83697ug,
  150                 .descr          = "Winbond 83697UG",
  151         },
  152         {
  153                 .device_id      = 0x70,
  154                 .chip           = w83637hf,
  155                 .descr          = "Winbond 83637HF",
  156         },
  157         {
  158                 .device_id      = 0x82,
  159                 .chip           = w83627thf,
  160                 .descr          = "Winbond 83627THF",
  161         },
  162         {
  163                 .device_id      = 0x85,
  164                 .chip           = w83687thf,
  165                 .descr          = "Winbond 83687THF",
  166         },
  167         {
  168                 .device_id      = 0x88,
  169                 .chip           = w83627ehf,
  170                 .descr          = "Winbond 83627EHF",
  171         },
  172         {
  173                 .device_id      = 0xa0,
  174                 .chip           = w83627dhg,
  175                 .descr          = "Winbond 83627DHG",
  176         },
  177         {
  178                 .device_id      = 0xa2,
  179                 .chip           = w83627uhg,
  180                 .descr          = "Winbond 83627UHG",
  181         },
  182         {
  183                 .device_id      = 0xa5,
  184                 .chip           = w83667hg,
  185                 .descr          = "Winbond 83667HG",
  186         },
  187         {
  188                 .device_id      = 0xb0,
  189                 .chip           = w83627dhg_p,
  190                 .descr          = "Winbond 83627DHG-P",
  191         },
  192         {
  193                 .device_id      = 0xb3,
  194                 .chip           = w83667hg_b,
  195                 .descr          = "Winbond 83667HG-B",
  196         },
  197         {
  198                 .device_id      = 0xb4,
  199                 .chip           = nct6775,
  200                 .descr          = "Nuvoton NCT6775",
  201         },
  202         {
  203                 .device_id      = 0xc3,
  204                 .chip           = nct6776,
  205                 .descr          = "Nuvoton NCT6776",
  206         },
  207         {
  208                 .device_id      = 0xc4,
  209                 .chip           = nct6102,
  210                 .descr          = "Nuvoton NCT6102",
  211         },
  212         {
  213                 .device_id      = 0xc5,
  214                 .chip           = nct6779,
  215                 .descr          = "Nuvoton NCT6779",
  216         },
  217         {
  218                 .device_id      = 0xc8,
  219                 .chip           = nct6791,
  220                 .descr          = "Nuvoton NCT6791",
  221         },
  222         {
  223                 .device_id      = 0xc9,
  224                 .chip           = nct6792,
  225                 .descr          = "Nuvoton NCT6792",
  226         },
  227         {
  228                 .device_id      = 0xd1,
  229                 .chip           = nct6793,
  230                 .descr          = "Nuvoton NCT6793",
  231         },
  232         {
  233                 .device_id      = 0xd3,
  234                 .chip           = nct6795,
  235                 .descr          = "Nuvoton NCT6795",
  236         },
  237 };
  238 
  239 /*
  240  * Return the watchdog related registers as we last read them.  This will
  241  * usually not give the current timeout or state on whether the watchdog
  242  * fired.
  243  */
  244 static int
  245 sysctl_wb_debug(SYSCTL_HANDLER_ARGS)
  246 {
  247         struct wb_softc *sc;
  248         struct sbuf sb;
  249         int error;
  250 
  251         sc = arg1;
  252 
  253         sbuf_new_for_sysctl(&sb, NULL, 64, req);
  254 
  255         sbuf_printf(&sb, "LDN8 (GPIO2, Watchdog): ");
  256         sbuf_printf(&sb, "CR%02X 0x%02x ", sc->ctl_reg, sc->reg_1);
  257         sbuf_printf(&sb, "CR%02X 0x%02x ", sc->time_reg, sc->reg_timeout);
  258         sbuf_printf(&sb, "CR%02X 0x%02x", sc->csr_reg, sc->reg_2);
  259 
  260         error = sbuf_finish(&sb);
  261         sbuf_delete(&sb);
  262         return (error);
  263 }
  264 
  265 /*
  266  * Read the current values before returning them.  Given this might poke
  267  * the registers the same time as the watchdog, this sysctl handler should
  268  * be marked CTLFLAG_SKIP to not show up by default.
  269  */
  270 static int
  271 sysctl_wb_debug_current(SYSCTL_HANDLER_ARGS)
  272 {
  273         struct wb_softc *sc;
  274 
  275         sc = arg1;
  276 
  277         sc->reg_1 = superio_read(sc->dev, sc->ctl_reg);
  278         sc->reg_timeout = superio_read(sc->dev, sc->time_reg);
  279         sc->reg_2 = superio_read(sc->dev, sc->csr_reg);
  280 
  281         return (sysctl_wb_debug(oidp, arg1, arg2, req));
  282 }
  283 
  284 /*
  285  * Sysctl handlers to force a watchdog timeout or to test the NMI functionality
  286  * works as expetced.
  287  * For testing we could set a test_nmi flag in the softc that, in case of NMI, a
  288  * callback function from trap.c could check whether we fired and not report the
  289  * timeout but clear the flag for the sysctl again.  This is interesting given a
  290  * lot of boards have jumpers to change the action on watchdog timeout or
  291  * disable the watchdog completely.
  292  * XXX-BZ notyet: currently no general infrastructure exists to do this.
  293  */
  294 static int
  295 sysctl_wb_force_test_nmi(SYSCTL_HANDLER_ARGS)
  296 {
  297         struct wb_softc *sc;
  298         int error, val;
  299 
  300         sc = arg1;
  301 
  302 #ifdef notyet
  303         val = sc->test_nmi;
  304 #else
  305         val = 0;
  306 #endif
  307         error = sysctl_handle_int(oidp, &val, 0, req);
  308         if (error || !req->newptr)
  309                 return (error);
  310 
  311 #ifdef notyet
  312         int test = arg2;
  313 
  314         /* Manually clear the test for a value of 0 and do nothing else. */
  315         if (test && val == 0) {
  316                 sc->test_nmi = 0;
  317                 return (0);
  318         }
  319 
  320         /*
  321          * If we are testing the NMI functionality, set the flag before
  322          * forcing the timeout.
  323          */
  324         if (test)
  325                 sc->test_nmi = 1;
  326 #endif
  327 
  328         /* Force watchdog to fire. */
  329         sc->reg_2 = superio_read(sc->dev, sc->csr_reg);
  330         sc->reg_2 |= WB_LDN8_CRF7_FORCE;
  331         superio_write(sc->dev, sc->csr_reg, sc->reg_2);
  332 
  333         return (0);
  334 }
  335 
  336 /*
  337  * Print current watchdog state.
  338  *
  339  * Note: it is the responsibility of the caller to update the registers
  340  * upfront.
  341  */
  342 static void
  343 wb_print_state(struct wb_softc *sc, const char *msg)
  344 {
  345 
  346         device_printf(sc->dev, "%s%sWatchdog %sabled. %s"
  347             "Scaling by %ds, timer at %d (%s=%ds%s). "
  348             "CR%02X 0x%02x CR%02X 0x%02x\n",
  349             (msg != NULL) ? msg : "", (msg != NULL) ? ": " : "",
  350             (sc->reg_timeout > 0x00) ? "en" : "dis",
  351             (sc->reg_2 & WB_LDN8_CRF7_TS) ? "Watchdog fired. " : "",
  352             (sc->reg_1 & WB_LDN8_CRF5_SCALE) ? 60 : 1,
  353             sc->reg_timeout,
  354             (sc->reg_timeout > 0x00) ? "<" : "",
  355             sc->reg_timeout * ((sc->reg_1 & WB_LDN8_CRF5_SCALE) ? 60 : 1),
  356             (sc->reg_timeout > 0x00) ? " left" : "",
  357             sc->ctl_reg, sc->reg_1, sc->csr_reg, sc->reg_2);
  358 }
  359 
  360 /*
  361  * (Re)load the watchdog counter depending on timeout.  A timeout of 0 will
  362  * disable the watchdog.
  363  */
  364 static int
  365 wb_set_watchdog(struct wb_softc *sc, unsigned int timeout)
  366 {
  367 
  368         if (timeout != 0) {
  369                 /*
  370                  * In case an override is set, let it override.  It may lead
  371                  * to strange results as we do not check the input of the sysctl.
  372                  */
  373                 if (sc->timeout_override > 0)
  374                         timeout = sc->timeout_override;
  375 
  376                 /* Make sure we support the requested timeout. */
  377                 if (timeout > 255 * 60)
  378                         return (EINVAL);
  379         }
  380 
  381         if (sc->debug_verbose)
  382                 wb_print_state(sc, "Before watchdog counter (re)load");
  383 
  384         if (timeout == 0) {
  385                 /* Disable watchdog. */
  386                 sc->reg_timeout = 0;
  387                 superio_write(sc->dev, sc->time_reg, sc->reg_timeout);
  388 
  389         } else {
  390                 /* Read current scaling factor. */
  391                 sc->reg_1 = superio_read(sc->dev, sc->ctl_reg);
  392 
  393                 if (timeout > 255) {
  394                         /* Set scaling factor to 60s. */
  395                         sc->reg_1 |= WB_LDN8_CRF5_SCALE;
  396                         sc->reg_timeout = (timeout / 60);
  397                         if (timeout % 60)
  398                                 sc->reg_timeout++;
  399                 } else {
  400                         /* Set scaling factor to 1s. */
  401                         sc->reg_1 &= ~WB_LDN8_CRF5_SCALE;
  402                         sc->reg_timeout = timeout;
  403                 }
  404 
  405                 /* In case we fired before we need to clear to fire again. */
  406                 sc->reg_2 = superio_read(sc->dev, sc->csr_reg);
  407                 if (sc->reg_2 & WB_LDN8_CRF7_TS) {
  408                         sc->reg_2 &= ~WB_LDN8_CRF7_TS;
  409                         superio_write(sc->dev, sc->csr_reg, sc->reg_2);
  410                 }
  411 
  412                 /* Write back scaling factor. */
  413                 superio_write(sc->dev, sc->ctl_reg, sc->reg_1);
  414 
  415                 /* Set timer and arm/reset the watchdog. */
  416                 superio_write(sc->dev, sc->time_reg, sc->reg_timeout);
  417         }
  418 
  419         if (sc->debug_verbose)
  420                 wb_print_state(sc, "After watchdog counter (re)load");
  421         return (0);
  422 }
  423 
  424 /*
  425  * watchdog(9) EVENTHANDLER function implementation to (re)load the counter
  426  * with the given timeout or disable the watchdog.
  427  */
  428 static void
  429 wb_watchdog_fn(void *private, u_int cmd, int *error)
  430 {
  431         struct wb_softc *sc;
  432         unsigned int timeout;
  433         int e;
  434 
  435         sc = private;
  436         KASSERT(sc != NULL, ("%s: watchdog handler function called without "
  437             "softc.", __func__));
  438 
  439         cmd &= WD_INTERVAL;
  440         if (cmd > 0 && cmd <= 63) {
  441                 /* Reset (and arm) watchdog. */
  442                 timeout = ((uint64_t)1 << cmd) / 1000000000;
  443                 if (timeout == 0)
  444                         timeout = 1;
  445                 e = wb_set_watchdog(sc, timeout);
  446                 if (e == 0) {
  447                         if (error != NULL)
  448                                 *error = 0;
  449                 } else {
  450                         /* On error, try to make sure the WD is disabled. */
  451                         wb_set_watchdog(sc, 0);
  452                 }
  453 
  454         } else {
  455                 /* Disable watchdog. */
  456                 e = wb_set_watchdog(sc, 0);
  457                 if (e != 0 && cmd == 0 && error != NULL) {
  458                         /* Failed to disable watchdog. */
  459                         *error = EOPNOTSUPP;
  460                 }
  461         }
  462 }
  463 
  464 static int
  465 wb_probe(device_t dev)
  466 {
  467         char buf[128];
  468         struct wb_softc *sc;
  469         int j;
  470         uint8_t devid;
  471         uint8_t revid;
  472 
  473         if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON)
  474                 return (ENXIO);
  475         if (superio_get_type(dev) != SUPERIO_DEV_WDT)
  476                 return (ENXIO);
  477 
  478         sc = device_get_softc(dev);
  479         devid = superio_devid(dev) >> 8;
  480         revid = superio_revid(dev);
  481         for (j = 0; j < nitems(wb_devs); j++) {
  482                 if (wb_devs[j].device_id == devid) {
  483                         sc->chip = wb_devs[j].chip;
  484                         snprintf(buf, sizeof(buf),
  485                             "%s (0x%02x/0x%02x) Watchdog Timer",
  486                             wb_devs[j].descr, devid, revid);
  487                         device_set_desc_copy(dev, buf);
  488                         return (BUS_PROBE_SPECIFIC);
  489                 }
  490         }
  491         if (bootverbose) {
  492                 device_printf(dev,
  493                     "unrecognized chip: devid 0x%02x, revid 0x%02x\n",
  494                     devid, revid);
  495         }
  496         return (ENXIO);
  497 }
  498 
  499 static int
  500 wb_attach(device_t dev)
  501 {
  502         struct wb_softc *sc;
  503         struct sysctl_ctx_list *sctx;
  504         struct sysctl_oid *soid;
  505         unsigned long timeout;
  506         uint8_t t;
  507 
  508         sc = device_get_softc(dev);
  509         sc->dev = dev;
  510 
  511         /* Make sure WDT is enabled. */
  512         superio_dev_enable(dev, WB_LDN8_CR30_ACTIVE);
  513 
  514         switch (sc->chip) {
  515         case w83697hf:
  516         case w83697ug:
  517                 sc->ctl_reg = 0xf3;
  518                 sc->time_reg = 0xf4;
  519                 sc->csr_reg = 0xf7;
  520                 break;
  521         case nct6102:
  522                 sc->ctl_reg = 0xf0;
  523                 sc->time_reg = 0xf1;
  524                 sc->csr_reg = 0xf2;
  525                 break;
  526         default:
  527                 sc->ctl_reg = 0xf5;
  528                 sc->time_reg = 0xf6;
  529                 sc->csr_reg = 0xf7;
  530                 break;
  531         }
  532 
  533         switch (sc->chip) {
  534         case w83627hf:
  535         case w83627s:
  536                 t = superio_read(dev, 0x2B) & ~0x10;
  537                 superio_write(dev, 0x2B, t); /* set GPIO24 to WDT0 */
  538                 break;
  539         case w83697hf:
  540                 /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
  541                 t = superio_read(dev, 0x29) & ~0x60;
  542                 t |= 0x20;
  543                 superio_write(dev, 0x29, t);
  544                 break;
  545         case w83697ug:
  546                 /* Set pin 118 to WDTO# mode */
  547                 t = superio_read(dev, 0x2b) & ~0x04;
  548                 superio_write(dev, 0x2b, t);
  549                 break;
  550         case w83627thf:
  551                 t = (superio_read(dev, 0x2B) & ~0x08) | 0x04;
  552                 superio_write(dev, 0x2B, t); /* set GPIO3 to WDT0 */
  553                 break;
  554         case w83627dhg:
  555         case w83627dhg_p:
  556                 t = superio_read(dev, 0x2D) & ~0x01; /* PIN77 -> WDT0# */
  557                 superio_write(dev, 0x2D, t); /* set GPIO5 to WDT0 */
  558                 t = superio_read(dev, sc->ctl_reg);
  559                 t |= 0x02;      /* enable the WDTO# output low pulse
  560                                  * to the KBRST# pin */
  561                 superio_write(dev, sc->ctl_reg, t);
  562                 break;
  563         case w83637hf:
  564                 break;
  565         case w83687thf:
  566                 t = superio_read(dev, 0x2C) & ~0x80; /* PIN47 -> WDT0# */
  567                 superio_write(dev, 0x2C, t);
  568                 break;
  569         case w83627ehf:
  570         case w83627uhg:
  571         case w83667hg:
  572         case w83667hg_b:
  573         case nct6775:
  574         case nct6776:
  575         case nct6779:
  576         case nct6791:
  577         case nct6792:
  578         case nct6793:
  579         case nct6795:
  580         case nct6102:
  581                 /*
  582                  * These chips have a fixed WDTO# output pin (W83627UHG),
  583                  * or support more than one WDTO# output pin.
  584                  * Don't touch its configuration, and hope the BIOS
  585                  * does the right thing.
  586                  */
  587                 t = superio_read(dev, sc->ctl_reg);
  588                 t |= 0x02;      /* enable the WDTO# output low pulse
  589                                  * to the KBRST# pin */
  590                 superio_write(dev, sc->ctl_reg, t);
  591                 break;
  592         default:
  593                 break;
  594         }
  595 
  596         /* Read the current watchdog configuration. */
  597         sc->reg_1 = superio_read(dev, sc->ctl_reg);
  598         sc->reg_timeout = superio_read(dev, sc->time_reg);
  599         sc->reg_2 = superio_read(dev, sc->csr_reg);
  600 
  601         /* Print current state if bootverbose or watchdog already enabled. */
  602         if (bootverbose || (sc->reg_timeout > 0x00))
  603                 wb_print_state(sc, "Before watchdog attach");
  604 
  605         sc->reg_1 &= ~WB_LDN8_CRF5_KEYB_P20;
  606         sc->reg_1 |= WB_LDN8_CRF5_KBRST;
  607         superio_write(dev, sc->ctl_reg, sc->reg_1);
  608 
  609         /*
  610          * Clear a previous watchdog timeout event (if still set).
  611          * Disable timer reset on mouse interrupts.  Leave reset on keyboard,
  612          * since one of my boards is getting stuck in reboot without it.
  613          */
  614         sc->reg_2 &= ~(WB_LDN8_CRF7_MOUSE|WB_LDN8_CRF7_TS);
  615         superio_write(dev, sc->csr_reg, sc->reg_2);
  616 
  617         /* Read global timeout override tunable, Add per device sysctls. */
  618         if (TUNABLE_ULONG_FETCH("hw.wbwd.timeout_override", &timeout)) {
  619                 if (timeout > 0)
  620                         sc->timeout_override = timeout;
  621         }
  622         sctx = device_get_sysctl_ctx(dev);
  623         soid = device_get_sysctl_tree(dev);
  624         SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO,
  625             "timeout_override", CTLFLAG_RW, &sc->timeout_override, 0,
  626             "Timeout in seconds overriding default watchdog timeout");
  627         SYSCTL_ADD_INT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO,
  628             "debug_verbose", CTLFLAG_RW, &sc->debug_verbose, 0,
  629             "Enables extra debugging information");
  630         SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "debug",
  631             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
  632             sysctl_wb_debug, "A",
  633             "Selected register information from last change by driver");
  634         SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "debug_current",
  635             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE,
  636             sc, 0, sysctl_wb_debug_current, "A",
  637              "Selected register information (may interfere)");
  638         SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "force_timeout",
  639             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SKIP | CTLFLAG_MPSAFE, sc, 0,
  640             sysctl_wb_force_test_nmi, "I", "Enable to force watchdog to fire.");
  641 
  642         /* Register watchdog. */
  643         sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, wb_watchdog_fn, sc,
  644             0);
  645 
  646         if (bootverbose)
  647                 wb_print_state(sc, "After watchdog attach");
  648 
  649         return (0);
  650 }
  651 
  652 static int
  653 wb_detach(device_t dev)
  654 {
  655         struct wb_softc *sc;
  656 
  657         sc = device_get_softc(dev);
  658 
  659         /* Unregister and stop the watchdog if running. */
  660         if (sc->ev_tag)
  661                 EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag);
  662         wb_set_watchdog(sc, 0);
  663 
  664         /* Bus subroutines take care of sysctls already. */
  665 
  666         return (0);
  667 }
  668 
  669 static device_method_t wb_methods[] = {
  670         /* Device interface */
  671         DEVMETHOD(device_probe,         wb_probe),
  672         DEVMETHOD(device_attach,        wb_attach),
  673         DEVMETHOD(device_detach,        wb_detach),
  674 
  675         DEVMETHOD_END
  676 };
  677 
  678 static driver_t wb_driver = {
  679         "wbwd",
  680         wb_methods,
  681         sizeof(struct wb_softc)
  682 };
  683 
  684 DRIVER_MODULE(wb, superio, wb_driver, NULL, NULL);
  685 MODULE_DEPEND(wb, superio, 1, 1, 1);
  686 MODULE_VERSION(wb, 1);

Cache object: 9472cf2e04d2ee0522f776684adba385


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.