[BACK]Return to wdt.c CVS log [TXT][DIR] Up to [local] / sys / dev / pci

Annotation of sys/dev/pci/wdt.c, Revision 1.1.1.1

1.1       nbrk        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

CVSweb