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