root/dev/pci/wdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wdtprobe
  2. wdtattach
  3. wdt_is501
  4. wdt_8254_count
  5. wdt_8254_mode
  6. wdt_set_timeout
  7. wdt_timer_disable
  8. wdt_init_timer
  9. wdt_buzzer_off
  10. wdt_buzzer_enable
  11. wdt_buzzer_disable

    1 /*      $OpenBSD: wdt.c,v 1.16 2007/08/14 07:16:26 mk Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 1998,1999 Alex Nash
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  */
   29 
   30 #include <sys/types.h>
   31 #include <sys/param.h>
   32 #include <sys/device.h>
   33 #include <sys/kernel.h>
   34 #include <sys/proc.h>
   35 #include <sys/systm.h>
   36 
   37 #include <machine/bus.h>
   38 
   39 #include <dev/pci/pcivar.h>
   40 #include <dev/pci/pcireg.h>
   41 #include <dev/pci/pcidevs.h>
   42 
   43 #include <dev/pci/wdt50x.h>
   44 
   45 struct wdt_softc {
   46         /* wdt_dev must be the first item in the struct */
   47         struct device           wdt_dev;
   48 
   49         /* feature set: 0 = none   1 = temp, buzzer, etc. */
   50         int                     features;
   51 
   52         /* device access through bus space */
   53         bus_space_tag_t         iot;
   54         bus_space_handle_t      ioh;
   55 };
   56 
   57 int     wdtprobe(struct device *, void *, void *);
   58 void    wdtattach(struct device *, struct device *, void *);
   59 
   60 int     wdt_is501(struct wdt_softc *);
   61 void    wdt_8254_count(struct wdt_softc *, int, u_int16_t);
   62 void    wdt_8254_mode(struct wdt_softc *, int, int);
   63 int     wdt_set_timeout(void *, int);
   64 void    wdt_init_timer(struct wdt_softc *);
   65 void    wdt_buzzer_off(struct wdt_softc *);
   66 void    wdt_timer_disable(struct wdt_softc *);
   67 void    wdt_buzzer_enable(struct wdt_softc *);
   68 
   69 struct cfattach wdt_ca = {
   70         sizeof(struct wdt_softc), wdtprobe, wdtattach
   71 };
   72 
   73 struct cfdriver wdt_cd = {
   74         NULL, "wdt", DV_DULL
   75 };
   76 
   77 const struct pci_matchid wdt_devices[] = {
   78         { PCI_VENDOR_INDCOMPSRC, PCI_PRODUCT_INDCOMPSRC_WDT50x }
   79 };
   80 
   81 /*
   82  *      8254 counter mappings
   83  */
   84 #define WDT_8254_TC_LO          0       /* low 16 bits of timeout counter  */
   85 #define WDT_8254_TC_HI          1       /* high 16 bits of timeout counter */
   86 #define WDT_8254_BUZZER         2
   87 
   88 /*
   89  *      WDT500/501 ports
   90  */
   91 #define WDT_8254_BASE           0
   92 #define WDT_8254_CTL            (WDT_8254_BASE + 3)
   93 #define WDT_DISABLE_TIMER       7
   94 #define WDT_ENABLE_TIMER        7
   95 
   96 /*
   97  *      WDT501 specific ports
   98  */
   99 #define WDT_STATUS_REG          4
  100 #define WDT_START_BUZZER        4
  101 #define WDT_TEMPERATURE         5
  102 #define WDT_STOP_BUZZER         5
  103 
  104 int
  105 wdtprobe(struct device *parent, void *match, void *aux)
  106 {
  107         return (pci_matchbyid((struct pci_attach_args *)aux, wdt_devices,
  108             sizeof(wdt_devices)/sizeof(wdt_devices[0])));
  109 }
  110 
  111 void
  112 wdtattach(struct device *parent, struct device *self, void *aux)
  113 {
  114         struct wdt_softc *wdt = (struct wdt_softc *)self;
  115         struct pci_attach_args *const pa = (struct pci_attach_args *)aux;
  116         bus_size_t iosize;
  117 
  118         /* retrieve the I/O region (BAR2) */
  119         if (pci_mapreg_map(pa, 0x18, PCI_MAPREG_TYPE_IO, 0,
  120             &wdt->iot, &wdt->ioh, NULL, &iosize, 0) != 0) {
  121                 printf("%s: couldn't find PCI I/O region\n",
  122                     wdt->wdt_dev.dv_xname);
  123                 return;
  124         }
  125 
  126         /* sanity check I/O size */
  127         if (iosize != (bus_size_t)16) {
  128                 printf("%s: invalid I/O region size\n",
  129                     wdt->wdt_dev.dv_xname);
  130                 return;
  131         }
  132 
  133         /* initialize the watchdog timer structure */
  134 
  135         /* check the feature set available */
  136         if (wdt_is501(wdt))
  137                 wdt->features = 1;
  138         else
  139                 wdt->features = 0;
  140 
  141         if (wdt->features) {
  142                 /*
  143                  * turn off the buzzer, it may have been activated
  144                  * by a previous timeout
  145                  */
  146                 wdt_buzzer_off(wdt);
  147 
  148                 wdt_buzzer_enable(wdt);
  149         }
  150 
  151         /* initialize the timer modes and the lower 16-bit counter */
  152         wdt_init_timer(wdt);
  153 
  154         /*
  155          * ensure that the watchdog is disabled
  156          */
  157         wdt_timer_disable(wdt);
  158 
  159         /*
  160          * register with the watchdog framework
  161          */
  162         wdog_register(wdt, wdt_set_timeout);
  163 }
  164 
  165 /*
  166  *      wdt_is501
  167  *
  168  *      Returns non-zero if the card is a 501 model.
  169  */
  170 int
  171 wdt_is501(struct wdt_softc *wdt)
  172 {
  173         /*
  174          *      It makes too much sense to detect the card type
  175          *      by the device ID, so we have to resort to testing
  176          *      the presence of a register to determine the type.
  177          */
  178         int v = bus_space_read_1(wdt->iot, wdt->ioh, WDT_TEMPERATURE);
  179 
  180         /* XXX may not be reliable */
  181         if (v == 0 || v == 0xFF)
  182                 return(0);
  183 
  184         return(1);
  185 }
  186 
  187 /*
  188  *      wdt_8254_count
  189  *
  190  *      Loads the specified counter with the 16-bit value 'v'.
  191  */
  192 void
  193 wdt_8254_count(struct wdt_softc *wdt, int counter, u_int16_t v)
  194 {
  195         bus_space_write_1(wdt->iot, wdt->ioh,
  196                         WDT_8254_BASE + counter, v & 0xFF);
  197         bus_space_write_1(wdt->iot, wdt->ioh, WDT_8254_BASE + counter, v >> 8);
  198 }
  199 
  200 /*
  201  *      wdt_8254_mode
  202  *
  203  *      Sets the mode of the specified counter.
  204  */
  205 void
  206 wdt_8254_mode(struct wdt_softc *wdt, int counter, int mode)
  207 {
  208         bus_space_write_1(wdt->iot, wdt->ioh, WDT_8254_CTL,
  209                 (counter << 6) | 0x30 | (mode << 1));
  210 }
  211 
  212 /*
  213  *      wdt_set_timeout
  214  *
  215  *      Load the watchdog timer with the specified number of seconds.
  216  *      Clamp seconds to be in the interval [2; 1800].
  217  */
  218 int
  219 wdt_set_timeout(void *self, int seconds)
  220 {
  221         struct wdt_softc *wdt = (struct wdt_softc *)self;
  222 
  223         u_int16_t v;
  224         int s;
  225 
  226         s = splclock();
  227 
  228         wdt_timer_disable(wdt);
  229 
  230         if (seconds == 0) {
  231                 splx(s);
  232                 return (0);
  233         } else if (seconds < 2)
  234                 seconds = 2;
  235         else if (seconds > 1800)
  236                 seconds = 1800;
  237 
  238         /* 8254 has been programmed with a 2ms period */
  239         v = (u_int16_t)seconds * 50;
  240 
  241         /* load the new timeout count */
  242         wdt_8254_count(wdt, WDT_8254_TC_HI, v);
  243 
  244         /* enable the timer */
  245         bus_space_write_1(wdt->iot, wdt->ioh, WDT_ENABLE_TIMER, 0);
  246 
  247         splx(s);
  248 
  249         return (seconds);
  250 }
  251 
  252 /*
  253  *      wdt_timer_disable
  254  *
  255  *      Disables the watchdog timer and cancels the scheduled (if any)
  256  *      kernel timeout.
  257  */
  258 void
  259 wdt_timer_disable(struct wdt_softc *wdt)
  260 {
  261         (void)bus_space_read_1(wdt->iot, wdt->ioh, WDT_DISABLE_TIMER);
  262 }
  263 
  264 /*
  265  *      wdt_init_timer
  266  *
  267  *      Configure the modes for the watchdog counters and initialize
  268  *      the low 16-bits of the watchdog counter to have a period of
  269  *      approximately 1/50th of a second.
  270  */
  271 void
  272 wdt_init_timer(struct wdt_softc *wdt)
  273 {
  274         wdt_8254_mode(wdt, WDT_8254_TC_LO, 3);
  275         wdt_8254_mode(wdt, WDT_8254_TC_HI, 2);
  276         wdt_8254_count(wdt, WDT_8254_TC_LO, 41666);
  277 }
  278 
  279 /*******************************************************************
  280  *      WDT501 specific functions
  281  *******************************************************************/
  282 
  283 /*
  284  *      wdt_buzzer_off
  285  *
  286  *      Turns the buzzer off.
  287  */
  288 void
  289 wdt_buzzer_off(struct wdt_softc *wdt)
  290 {
  291         bus_space_write_1(wdt->iot, wdt->ioh, WDT_STOP_BUZZER, 0);
  292 }
  293 
  294 #ifndef WDT_DISABLE_BUZZER
  295 /*
  296  *      wdt_buzzer_enable
  297  *
  298  *      Enables the buzzer when the watchdog counter expires.
  299  */
  300 void
  301 wdt_buzzer_enable(struct wdt_softc *wdt)
  302 {
  303         bus_space_write_1(wdt->iot, wdt->ioh, WDT_8254_BUZZER, 1);
  304         wdt_8254_mode(wdt, WDT_8254_BUZZER, 1);
  305 }
  306 #else
  307 /*
  308  *      wdt_buzzer_disable
  309  *
  310  *      Disables the buzzer from sounding when the watchdog counter
  311  *      expires.
  312  */
  313 void
  314 wdt_buzzer_disable(struct wdt_softc *wdt)
  315 {
  316         wdt_8254_mode(wdt, WDT_8254_BUZZER, 0);
  317 }
  318 #endif

/* [<][>][^][v][top][bottom][index][help] */