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/isa/weasel_isa.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 /*      $NetBSD: weasel_isa.c,v 1.1 2001/12/16 22:35:31 thorpej Exp $   */
    2 
    3 /*-
    4  * Copyright (c) 2000 Zembu Labs, Inc.
    5  * All rights reserved.
    6  *
    7  * Author: Jason R. Thorpe <thorpej@zembu.com>
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed by Zembu Labs, Inc.
   20  * 4. Neither the name of Zembu Labs nor the names of its employees may
   21  *    be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
   25  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
   26  * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
   27  * CLAIMED.  IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
   28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 
   36 /*
   37  * Device driver for the Middle Digital, Inc. PC-Weasel serial
   38  * console board.
   39  *
   40  * We're glued into the MDA display driver (`pcdisplay'), and
   41  * handle things like the watchdog timer.
   42  */
   43 
   44 #include <sys/cdefs.h>
   45 __KERNEL_RCSID(0, "$NetBSD: weasel_isa.c,v 1.1 2001/12/16 22:35:31 thorpej Exp $");
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/device.h>
   50 #include <sys/wdog.h>
   51 
   52 #include <machine/bus.h>
   53 
   54 #include <dev/isa/weaselreg.h>
   55 #include <dev/isa/weaselvar.h>
   56 
   57 #include <dev/sysmon/sysmonvar.h>
   58 
   59 int     weasel_isa_wdog_setmode(struct sysmon_wdog *);
   60 int     weasel_isa_wdog_tickle(struct sysmon_wdog *);
   61 int     weasel_isa_wdog_arm_disarm(struct weasel_handle *, u_int8_t);
   62 int     weasel_isa_wdog_query_state(struct weasel_handle *);
   63 
   64 
   65 void    pcweaselattach(int);
   66 
   67 /* ARGSUSED */
   68 void
   69 pcweaselattach(int count)
   70 {
   71 
   72         /* Nothing to do; pseudo-device glue. */
   73 }
   74 
   75 void
   76 weasel_isa_init(struct weasel_handle *wh)
   77 {
   78         struct weasel_config_block cfg;
   79         int i, j; 
   80         u_int8_t *cp, sum; 
   81         const char *vers, *mode;
   82 
   83         /*
   84          * Write a NOP to the command register and see if it
   85          * reverts back to READY within 1.5 seconds.
   86          */
   87         bus_space_write_1(wh->wh_st, wh->wh_sh, WEASEL_MISC_COMMAND, OS_NOP);
   88         for (i = 0; i < 1500; i++) {
   89                 delay(1000);
   90                 sum = bus_space_read_1(wh->wh_st, wh->wh_sh,
   91                     WEASEL_MISC_COMMAND);
   92                 if (sum == OS_READY)
   93                         break;
   94         }
   95         if (sum != OS_READY) {
   96                 /* This is not a Weasel. */
   97                 return;
   98         }
   99 
  100         /*
  101          * It can take a while for the config block to be copied
  102          * into the offscreen area, as the Weasel may be busy
  103          * sending data to the terminal.  Wait up to 3 seconds,
  104          * reading the block each time, and breaking out of the
  105          * loop once the checksum passes.
  106          */
  107 
  108         bus_space_write_1(wh->wh_st, wh->wh_sh, WEASEL_MISC_COMMAND,
  109             OS_CONFIG_COPY);
  110 
  111         /* ...one second to get it started... */
  112         delay(1000 * 1000);
  113 
  114         /* ...two seconds to let it finish... */
  115         for (i = 0; i < 2000; i++) {
  116                 delay(1000);
  117                 bus_space_read_region_1(wh->wh_st, wh->wh_sh,
  118                     WEASEL_CONFIG_BLOCK, &cfg, sizeof(cfg));
  119                 /*
  120                  * Compute the checksum of the config block.
  121                  */
  122                 for (cp = (u_int8_t *)&cfg, j = 0, sum = 1;
  123                      j < (sizeof(cfg) - 1); j++)
  124                         sum += cp[j];
  125                 if (sum == cfg.cksum)
  126                         break;
  127         }
  128 
  129         if (sum != cfg.cksum) {
  130                 /*
  131                  * Checksum doesn't match; either it's not a Weasel,
  132                  * or something is wrong with it.
  133                  */
  134                 printf("%s: PC-Weasel config block checksum mismatch "
  135                     "0x%02x != 0x%02x\n", wh->wh_parent->dv_xname,
  136                     sum, cfg.cksum);
  137                 return;
  138         }
  139 
  140         switch (cfg.cfg_version) {
  141         case CFG_VERSION_1_0:
  142                 vers = "1.0";
  143                 switch (cfg.enable_duart_switching) {
  144                 case 0:
  145                         mode = "emulation";
  146                         break;
  147 
  148                 case 1:
  149                         mode = "autoswitch";
  150                         break;
  151 
  152                 default:
  153                         mode = "unknown";
  154                 }
  155                 break;
  156 
  157         case CFG_VERSION_1_1:
  158                 vers = "1.1";
  159                 switch (cfg.enable_duart_switching) {
  160                 case 0:
  161                         mode = "emulation";
  162                         break;
  163 
  164                 case 1:
  165                         mode = "serial";
  166                         break;
  167 
  168                 case 2:
  169                         mode = "autoswitch";
  170                         break;
  171 
  172                 default:
  173                         mode = "unknown";
  174                 }
  175                 break;
  176 
  177         default:
  178                 vers = mode = NULL;
  179         }
  180 
  181         printf("%s: PC-Weasel, ", wh->wh_parent->dv_xname);
  182         if (vers != NULL)
  183                 printf("version %s, %s mode", vers, mode);
  184         else
  185                 printf("unknown version 0x%x", cfg.cfg_version);
  186         printf("\n");
  187 
  188         printf("%s: break passthrough %s", wh->wh_parent->dv_xname,
  189             cfg.break_passthru ? "enabled" : "disabled");
  190         if (cfg.wdt_msec == 0) {
  191                 /*
  192                  * Old firmware -- these Weasels have
  193                  * a 3000ms watchdog period.
  194                  */
  195                 cfg.wdt_msec = 3000;
  196         }
  197 
  198         if ((wh->wh_wdog_armed = weasel_isa_wdog_query_state(wh)) == -1)
  199                 wh->wh_wdog_armed = 0;
  200         wh->wh_wdog_period = cfg.wdt_msec / 1000;
  201 
  202         printf(", watchdog interval %d sec.\n", wh->wh_wdog_period);
  203 
  204         /*
  205          * Always register the Weasel watchdog timer in case user decides
  206          * to set 'allow watchdog' to 'YES' after the machine has booted.
  207          */
  208         wh->wh_smw.smw_name = "weasel";
  209         wh->wh_smw.smw_cookie = wh;
  210         wh->wh_smw.smw_setmode = weasel_isa_wdog_setmode;
  211         wh->wh_smw.smw_tickle = weasel_isa_wdog_tickle;
  212         wh->wh_smw.smw_period = wh->wh_wdog_period;
  213 
  214         if (sysmon_wdog_register(&wh->wh_smw) != 0)
  215                 printf("%s: unable to register PC-Weasel watchdog "
  216                     "with sysmon\n", wh->wh_parent->dv_xname);
  217 }
  218 
  219 int
  220 weasel_isa_wdog_setmode(struct sysmon_wdog *smw)
  221 {
  222         struct weasel_handle *wh = smw->smw_cookie;
  223         int error = 0;
  224 
  225         if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
  226                 error = weasel_isa_wdog_arm_disarm(wh, WDT_DISABLE);
  227         } else {
  228                 if (smw->smw_period == WDOG_PERIOD_DEFAULT)
  229                         smw->smw_period = wh->wh_wdog_period;
  230                 else if (smw->smw_period != wh->wh_wdog_period) {
  231                         /* Can't change the period on the Weasel. */
  232                         return (EINVAL);
  233                 }
  234                 error = weasel_isa_wdog_arm_disarm(wh, WDT_ENABLE);
  235                 weasel_isa_wdog_tickle(smw);
  236         }
  237 
  238         return (error);
  239 }
  240 
  241 int
  242 weasel_isa_wdog_tickle(struct sysmon_wdog *smw)
  243 {
  244         struct weasel_handle *wh = smw->smw_cookie; 
  245         u_int8_t reg;
  246         int x;
  247         int s;
  248         int error = 0;
  249 
  250         s = splhigh();
  251         /*
  252          * first we tickle the watchdog
  253          */
  254         reg = bus_space_read_1(wh->wh_st, wh->wh_sh, WEASEL_WDT_TICKLE);
  255         bus_space_write_1(wh->wh_st, wh->wh_sh, WEASEL_WDT_TICKLE, ~reg);
  256 
  257         /*
  258          * then we check to make sure the weasel is still armed. If someone
  259          * has rebooted the weasel for whatever reason (firmware update),
  260          * then the watchdog timer would no longer be armed and we'd be 
  261          * servicing nothing. Let the user know that the machine is no
  262          * longer being monitored by the weasel.
  263          */
  264         if((x = weasel_isa_wdog_query_state(wh)) == -1)
  265                 error = EIO;
  266         if (x == 1) { 
  267                 error = 0;
  268         } else {
  269                 printf("%s: Watchdog timer disabled on PC/Weasel! Disarming wdog.\n", 
  270                         wh->wh_parent->dv_xname);
  271                 wh->wh_wdog_armed = 0;
  272                 error = 1;
  273         }
  274         splx(s);
  275 
  276         return (error);
  277 }
  278 
  279 int
  280 weasel_isa_wdog_arm_disarm(struct weasel_handle *wh, u_int8_t mode)
  281 {
  282         u_int8_t reg;
  283         int timeout;
  284         int s, x;
  285         int error = 0;
  286 
  287         s = splhigh();
  288 
  289         bus_space_write_1(wh->wh_st, wh->wh_sh, WEASEL_WDT_SEMAPHORE,
  290                 WDT_ATTENTION);
  291         for (timeout = 5000; timeout; timeout--) {
  292                 delay(1500);
  293                 reg = bus_space_read_1(wh->wh_st, wh->wh_sh,
  294                         WEASEL_WDT_SEMAPHORE);
  295                 if (reg == WDT_OK)
  296                         break;
  297         }
  298         if (timeout == 0) {
  299                 splx(s);
  300                 return(EIO);
  301         }
  302         bus_space_write_1(wh->wh_st, wh->wh_sh, WEASEL_WDT_SEMAPHORE, mode);
  303         for (timeout = 500 ; timeout; timeout--) {
  304                 delay(1500);
  305                 reg = bus_space_read_1(wh->wh_st, wh->wh_sh,
  306                         WEASEL_WDT_SEMAPHORE);
  307                 if (reg != mode)
  308                         break;
  309         }
  310         if (timeout == 0) {
  311                 splx(s);
  312                 return(EIO);
  313         }
  314         bus_space_write_1(wh->wh_st, wh->wh_sh, WEASEL_WDT_SEMAPHORE, ~reg);
  315         for (timeout = 500; timeout; timeout--) {
  316                 delay(1500);
  317                 reg = bus_space_read_1(wh->wh_st, wh->wh_sh,
  318                         WEASEL_WDT_SEMAPHORE);
  319                 if (reg == WDT_OK)
  320                         break;
  321         }
  322 
  323         /*
  324          * Ensure that the Weasel thinks it's in the same mode we want it to
  325          * be in.   EIO if not.
  326          */
  327         x = weasel_isa_wdog_query_state(wh);
  328         switch (x) {
  329                 case -1:
  330                         error = EIO;
  331                         break;
  332                 case 0: 
  333                         if (mode == WDT_DISABLE) {
  334                                 wh->wh_wdog_armed = 0;
  335                                 error = 0;
  336                         } else
  337                                 error = EIO;
  338                         break;
  339                 case 1:
  340                         if (mode == WDT_ENABLE) {
  341                                 wh->wh_wdog_armed = 1;
  342                                 error = 0;
  343                         } else
  344                                 error = EIO;
  345                         break;
  346         }
  347                                 
  348         splx(s);
  349         return(error);
  350 }
  351 
  352 int
  353 weasel_isa_wdog_query_state(struct weasel_handle *wh)
  354 {
  355         int timeout, reg;
  356 
  357         bus_space_write_1(wh->wh_st, wh->wh_sh,
  358                 WEASEL_MISC_COMMAND, OS_WDT_QUERY);
  359         for (timeout = 0; timeout < 1500; timeout++) {
  360                 delay(1000);
  361                 reg = bus_space_read_1(wh->wh_st, wh->wh_sh,
  362                         WEASEL_MISC_COMMAND);
  363                 if (reg == OS_READY)
  364                         break;
  365         }
  366         return(bus_space_read_1(wh->wh_st, wh->wh_sh, WEASEL_MISC_RESPONSE));
  367 }

Cache object: 07c0aac91dfd6e7da1035f8d626b61f0


[ 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.