Deleted Added
full compact
isa.c (775) isa.c (798)
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
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 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
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 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
37 * $Id: isa.c,v 1.8 1993/11/14 23:53:32 ache Exp $
37 * $Id: isa.c,v 1.9 1993/11/17 00:21:03 ache Exp $
38 */
39
40/*
41 * code to manage AT bus
42 *
43 * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com):
44 * Fixed uninitialized variable problem and added code to deal
45 * with DMA page boundaries in isa_dmarangecheck(). Fixed word
46 * mode DMA count compution and reorganized DMA setup code in
47 * isa_dmastart()
48 */
49
50#include "param.h"
38 */
39
40/*
41 * code to manage AT bus
42 *
43 * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com):
44 * Fixed uninitialized variable problem and added code to deal
45 * with DMA page boundaries in isa_dmarangecheck(). Fixed word
46 * mode DMA count compution and reorganized DMA setup code in
47 * isa_dmastart()
48 */
49
50#include "param.h"
51#include "systm.h"
51#include "systm.h" /* isn't it a joy */
52#include "kernel.h" /* to have three of these */
52#include "conf.h"
53#include "file.h"
54#include "buf.h"
55#include "uio.h"
56#include "syslog.h"
57#include "malloc.h"
58#include "rlist.h"
59#include "machine/segments.h"
60#include "vm/vm.h"
61#include "i386/isa/isa_device.h"
62#include "i386/isa/isa.h"
63#include "i386/isa/icu.h"
64#include "i386/isa/ic/i8237.h"
65#include "i386/isa/ic/i8042.h"
66
67/*
68** Register definitions for DMA controller 1 (channels 0..3):
69*/
70#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */
71#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */
72#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */
73#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */
74
75/*
76** Register definitions for DMA controller 2 (channels 4..7):
77*/
78#define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */
79#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */
80#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
81#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
82
53#include "conf.h"
54#include "file.h"
55#include "buf.h"
56#include "uio.h"
57#include "syslog.h"
58#include "malloc.h"
59#include "rlist.h"
60#include "machine/segments.h"
61#include "vm/vm.h"
62#include "i386/isa/isa_device.h"
63#include "i386/isa/isa.h"
64#include "i386/isa/icu.h"
65#include "i386/isa/ic/i8237.h"
66#include "i386/isa/ic/i8042.h"
67
68/*
69** Register definitions for DMA controller 1 (channels 0..3):
70*/
71#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */
72#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */
73#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */
74#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */
75
76/*
77** Register definitions for DMA controller 2 (channels 4..7):
78*/
79#define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */
80#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */
81#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
82#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
83
83int config_isadev __P((struct isa_device *, u_int *));
84void config_isadev __P((struct isa_device *, u_int *));
84
85/*
86 * print a conflict message
87 */
88void
89conflict(dvp, tmpdvp, item, reason, format)
90 struct isa_device *dvp, *tmpdvp;
91 int item;
92 char *reason;
93 char *format;
94{
95 printf("%s%d not probed due to %s conflict with %s%d at ",
96 dvp->id_driver->name, dvp->id_unit, reason,
97 tmpdvp->id_driver->name, tmpdvp->id_unit);
98 printf(format, item);
99 printf("\n");
100}
101
102/*
103 * Check to see if things are alread in use, like IRQ's, I/O addresses
104 * and Memory addresses.
105 */
106int
107haveseen(dvp, tmpdvp)
108 struct isa_device *dvp, *tmpdvp;
109{
110 int status = 0;
111
112 /*
113 * Only check against devices that have already been found
114 */
115 if (tmpdvp->id_alive) {
116 /*
117 * Check for I/O address conflict. We can only check the
118 * starting address of the device against the range of the
119 * device that has already been probed since we do not
120 * know how many I/O addresses this device uses.
121 */
122 if (tmpdvp->id_alive != -1) {
123 if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
124 (dvp->id_iobase <=
125 (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
126 conflict(dvp, tmpdvp, dvp->id_iobase,
127 "I/O address", "0x%x");
128 status = 1;
129 }
130 }
131 /*
132 * Check for Memory address conflict. We can check for
133 * range overlap, but it will not catch all cases since the
134 * driver may adjust the msize paramater during probe, for
135 * now we just check that the starting address does not
136 * fall within any allocated region.
137 * XXX could add a second check after the probe for overlap,
138 * since at that time we would know the full range.
139 * XXX KERNBASE is a hack, we should have vaddr in the table!
140 */
141 if(tmpdvp->id_maddr) {
142 if((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
143 (KERNBASE + dvp->id_maddr <=
144 (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
145 conflict(dvp, tmpdvp, dvp->id_maddr, "maddr",
146 "0x%x");
147 status = 1;
148 }
149 }
150#ifndef COM_MULTIPORT
151 /*
152 * Check for IRQ conflicts.
153 */
154 if(tmpdvp->id_irq) {
155 if (tmpdvp->id_irq == dvp->id_irq) {
156 conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1,
157 "irq", "%d");
158 status = 1;
159 }
160 }
161#endif
162 /*
163 * Check for DRQ conflicts.
164 */
165 if(tmpdvp->id_drq != -1) {
166 if (tmpdvp->id_drq == dvp->id_drq) {
167 conflict(dvp, tmpdvp, dvp->id_drq,
168 "drq", "%d");
169 status = 1;
170 }
171 }
172 }
173 return (status);
174}
175
176/*
177 * Search through all the isa_devtab_* tables looking for anything that
178 * conflicts with the current device.
179 */
180int
181haveseen_isadev(dvp)
182 struct isa_device *dvp;
183{
184 struct isa_device *tmpdvp;
185 int status = 0;
186
187 for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) {
188 status |= haveseen(dvp, tmpdvp);
189 }
190 for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) {
191 status |= haveseen(dvp, tmpdvp);
192 }
193 for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) {
194 status |= haveseen(dvp, tmpdvp);
195 }
196 for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) {
197 status |= haveseen(dvp, tmpdvp);
198 }
199 return(status);
200}
201
202/*
203 * Configure all ISA devices
204 */
205void
206isa_configure() {
207 struct isa_device *dvp;
208
209 enable_intr();
210 splhigh();
211 INTREN(IRQ_SLAVE);
212 printf("Probing for devices on the ISA bus:\n");
213 for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) {
214 if (!haveseen_isadev(dvp))
215 config_isadev(dvp,&ttymask);
216 }
217 for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) {
218 if (!haveseen_isadev(dvp))
219 config_isadev(dvp,&biomask);
220 }
221 for (dvp = isa_devtab_net; dvp->id_driver; dvp++) {
222 if (!haveseen_isadev(dvp))
223 config_isadev(dvp,&netmask);
224 }
225 for (dvp = isa_devtab_null; dvp->id_driver; dvp++) {
226 if (!haveseen_isadev(dvp))
227 config_isadev(dvp,(u_int *) NULL);
228 }
229/*
230 * XXX We should really add the tty device to netmask when the line is
231 * switched to SLIPDISC, and then remove it when it is switched away from
232 * SLIPDISC. No need to block out ALL ttys during a splnet when only one
233 * of them is running slip.
234 */
235#include "sl.h"
236#if NSL > 0
237 netmask |= ttymask;
238 ttymask |= netmask;
239#endif
240 /* if netmask == 0, then the loopback code can do some really
241 * bad things.
242 */
243 if (netmask == 0)
244 netmask = 0x10000;
245 /* biomask |= ttymask ; can some tty devices use buffers? */
246 printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask);
247 splnone();
248}
249
250/*
251 * Configure an ISA device.
252 */
85
86/*
87 * print a conflict message
88 */
89void
90conflict(dvp, tmpdvp, item, reason, format)
91 struct isa_device *dvp, *tmpdvp;
92 int item;
93 char *reason;
94 char *format;
95{
96 printf("%s%d not probed due to %s conflict with %s%d at ",
97 dvp->id_driver->name, dvp->id_unit, reason,
98 tmpdvp->id_driver->name, tmpdvp->id_unit);
99 printf(format, item);
100 printf("\n");
101}
102
103/*
104 * Check to see if things are alread in use, like IRQ's, I/O addresses
105 * and Memory addresses.
106 */
107int
108haveseen(dvp, tmpdvp)
109 struct isa_device *dvp, *tmpdvp;
110{
111 int status = 0;
112
113 /*
114 * Only check against devices that have already been found
115 */
116 if (tmpdvp->id_alive) {
117 /*
118 * Check for I/O address conflict. We can only check the
119 * starting address of the device against the range of the
120 * device that has already been probed since we do not
121 * know how many I/O addresses this device uses.
122 */
123 if (tmpdvp->id_alive != -1) {
124 if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
125 (dvp->id_iobase <=
126 (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
127 conflict(dvp, tmpdvp, dvp->id_iobase,
128 "I/O address", "0x%x");
129 status = 1;
130 }
131 }
132 /*
133 * Check for Memory address conflict. We can check for
134 * range overlap, but it will not catch all cases since the
135 * driver may adjust the msize paramater during probe, for
136 * now we just check that the starting address does not
137 * fall within any allocated region.
138 * XXX could add a second check after the probe for overlap,
139 * since at that time we would know the full range.
140 * XXX KERNBASE is a hack, we should have vaddr in the table!
141 */
142 if(tmpdvp->id_maddr) {
143 if((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
144 (KERNBASE + dvp->id_maddr <=
145 (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
146 conflict(dvp, tmpdvp, dvp->id_maddr, "maddr",
147 "0x%x");
148 status = 1;
149 }
150 }
151#ifndef COM_MULTIPORT
152 /*
153 * Check for IRQ conflicts.
154 */
155 if(tmpdvp->id_irq) {
156 if (tmpdvp->id_irq == dvp->id_irq) {
157 conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1,
158 "irq", "%d");
159 status = 1;
160 }
161 }
162#endif
163 /*
164 * Check for DRQ conflicts.
165 */
166 if(tmpdvp->id_drq != -1) {
167 if (tmpdvp->id_drq == dvp->id_drq) {
168 conflict(dvp, tmpdvp, dvp->id_drq,
169 "drq", "%d");
170 status = 1;
171 }
172 }
173 }
174 return (status);
175}
176
177/*
178 * Search through all the isa_devtab_* tables looking for anything that
179 * conflicts with the current device.
180 */
181int
182haveseen_isadev(dvp)
183 struct isa_device *dvp;
184{
185 struct isa_device *tmpdvp;
186 int status = 0;
187
188 for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) {
189 status |= haveseen(dvp, tmpdvp);
190 }
191 for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) {
192 status |= haveseen(dvp, tmpdvp);
193 }
194 for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) {
195 status |= haveseen(dvp, tmpdvp);
196 }
197 for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) {
198 status |= haveseen(dvp, tmpdvp);
199 }
200 return(status);
201}
202
203/*
204 * Configure all ISA devices
205 */
206void
207isa_configure() {
208 struct isa_device *dvp;
209
210 enable_intr();
211 splhigh();
212 INTREN(IRQ_SLAVE);
213 printf("Probing for devices on the ISA bus:\n");
214 for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) {
215 if (!haveseen_isadev(dvp))
216 config_isadev(dvp,&ttymask);
217 }
218 for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) {
219 if (!haveseen_isadev(dvp))
220 config_isadev(dvp,&biomask);
221 }
222 for (dvp = isa_devtab_net; dvp->id_driver; dvp++) {
223 if (!haveseen_isadev(dvp))
224 config_isadev(dvp,&netmask);
225 }
226 for (dvp = isa_devtab_null; dvp->id_driver; dvp++) {
227 if (!haveseen_isadev(dvp))
228 config_isadev(dvp,(u_int *) NULL);
229 }
230/*
231 * XXX We should really add the tty device to netmask when the line is
232 * switched to SLIPDISC, and then remove it when it is switched away from
233 * SLIPDISC. No need to block out ALL ttys during a splnet when only one
234 * of them is running slip.
235 */
236#include "sl.h"
237#if NSL > 0
238 netmask |= ttymask;
239 ttymask |= netmask;
240#endif
241 /* if netmask == 0, then the loopback code can do some really
242 * bad things.
243 */
244 if (netmask == 0)
245 netmask = 0x10000;
246 /* biomask |= ttymask ; can some tty devices use buffers? */
247 printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask);
248 splnone();
249}
250
251/*
252 * Configure an ISA device.
253 */
254void
253config_isadev(isdp, mp)
254 struct isa_device *isdp;
255 u_int *mp;
256{
257 struct isa_driver *dp = isdp->id_driver;
258
259 if (isdp->id_maddr) {
260 extern u_int atdevbase;
261
262 isdp->id_maddr -= 0xa0000; /* XXX should be a define */
263 isdp->id_maddr += atdevbase;
264 }
265 isdp->id_alive = (*dp->probe)(isdp);
266 if (isdp->id_alive) {
267 /*
268 * Only print the I/O address range if id_alive != -1
269 * Right now this is a temporary fix just for the new
270 * NPX code so that if it finds a 486 that can use trap
271 * 16 it will not report I/O addresses.
272 * Rod Grimes 04/26/94
273 */
274 printf("%s%d", dp->name, isdp->id_unit);
275 if (isdp->id_alive != -1) {
276 printf(" at 0x%x", isdp->id_iobase);
277 if ((isdp->id_iobase + isdp->id_alive - 1) !=
278 isdp->id_iobase) {
279 printf("-0x%x",
280 isdp->id_iobase +
281 isdp->id_alive - 1);
282 }
283 }
284 if(isdp->id_irq)
285 printf(" irq %d", ffs(isdp->id_irq) - 1);
286 if (isdp->id_drq != -1)
287 printf(" drq %d", isdp->id_drq);
288 if (isdp->id_maddr)
289 printf(" maddr 0x%x", kvtop(isdp->id_maddr));
290 if (isdp->id_msize)
291 printf(" msize %d", isdp->id_msize);
292 if (isdp->id_flags)
293 printf(" flags 0x%x", isdp->id_flags);
294 if (isdp->id_iobase < 0x100)
295 printf(" on motherboard\n");
296 else
297 printf(" on isa\n");
298
299 (*dp->attach)(isdp);
300
301 if(isdp->id_irq) {
302 int intrno;
303
304 intrno = ffs(isdp->id_irq)-1;
305 setidt(ICU_OFFSET+intrno, isdp->id_intr,
306 SDT_SYS386IGT, SEL_KPL);
307 if(mp) {
308 INTRMASK(*mp,isdp->id_irq);
309 }
310 INTREN(isdp->id_irq);
311 }
312 } else {
313 printf("%s%d not found", dp->name, isdp->id_unit);
314 if (isdp->id_iobase) {
315 printf(" at 0x%x", isdp->id_iobase);
316 }
317 printf("\n");
318 }
319}
320
321#define IDTVEC(name) __CONCAT(X,name)
322/* default interrupt vector table entries */
323extern IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
324 IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
325 IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
326 IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
327
328static *defvec[16] = {
329 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
330 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
331 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
332 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
333
334/* out of range default interrupt vector gate entry */
335extern IDTVEC(intrdefault);
336
337/*
338 * Fill in default interrupt table (in case of spuruious interrupt
339 * during configuration of kernel, setup interrupt control unit
340 */
255config_isadev(isdp, mp)
256 struct isa_device *isdp;
257 u_int *mp;
258{
259 struct isa_driver *dp = isdp->id_driver;
260
261 if (isdp->id_maddr) {
262 extern u_int atdevbase;
263
264 isdp->id_maddr -= 0xa0000; /* XXX should be a define */
265 isdp->id_maddr += atdevbase;
266 }
267 isdp->id_alive = (*dp->probe)(isdp);
268 if (isdp->id_alive) {
269 /*
270 * Only print the I/O address range if id_alive != -1
271 * Right now this is a temporary fix just for the new
272 * NPX code so that if it finds a 486 that can use trap
273 * 16 it will not report I/O addresses.
274 * Rod Grimes 04/26/94
275 */
276 printf("%s%d", dp->name, isdp->id_unit);
277 if (isdp->id_alive != -1) {
278 printf(" at 0x%x", isdp->id_iobase);
279 if ((isdp->id_iobase + isdp->id_alive - 1) !=
280 isdp->id_iobase) {
281 printf("-0x%x",
282 isdp->id_iobase +
283 isdp->id_alive - 1);
284 }
285 }
286 if(isdp->id_irq)
287 printf(" irq %d", ffs(isdp->id_irq) - 1);
288 if (isdp->id_drq != -1)
289 printf(" drq %d", isdp->id_drq);
290 if (isdp->id_maddr)
291 printf(" maddr 0x%x", kvtop(isdp->id_maddr));
292 if (isdp->id_msize)
293 printf(" msize %d", isdp->id_msize);
294 if (isdp->id_flags)
295 printf(" flags 0x%x", isdp->id_flags);
296 if (isdp->id_iobase < 0x100)
297 printf(" on motherboard\n");
298 else
299 printf(" on isa\n");
300
301 (*dp->attach)(isdp);
302
303 if(isdp->id_irq) {
304 int intrno;
305
306 intrno = ffs(isdp->id_irq)-1;
307 setidt(ICU_OFFSET+intrno, isdp->id_intr,
308 SDT_SYS386IGT, SEL_KPL);
309 if(mp) {
310 INTRMASK(*mp,isdp->id_irq);
311 }
312 INTREN(isdp->id_irq);
313 }
314 } else {
315 printf("%s%d not found", dp->name, isdp->id_unit);
316 if (isdp->id_iobase) {
317 printf(" at 0x%x", isdp->id_iobase);
318 }
319 printf("\n");
320 }
321}
322
323#define IDTVEC(name) __CONCAT(X,name)
324/* default interrupt vector table entries */
325extern IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
326 IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
327 IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
328 IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
329
330static *defvec[16] = {
331 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
332 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
333 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
334 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
335
336/* out of range default interrupt vector gate entry */
337extern IDTVEC(intrdefault);
338
339/*
340 * Fill in default interrupt table (in case of spuruious interrupt
341 * during configuration of kernel, setup interrupt control unit
342 */
341isa_defaultirq() {
343void
344isa_defaultirq()
345{
342 int i;
343
344 /* icu vectors */
345 for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++)
346 setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL);
347
348 /* out of range vectors */
349 for (i = NRSVIDT; i < NIDT; i++)
350 setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL);
351
352 /* initialize 8259's */
353 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
354 outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
355 outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
356#ifdef AUTO_EOI_1
357 outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
358#else
359 outb(IO_ICU1+1, 1); /* 8086 mode */
360#endif
361 outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
362 outb(IO_ICU1, 0x0a); /* default to IRR on read */
363 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
364
365 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
366 outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
367 outb(IO_ICU2+1,2); /* my slave id is 2 */
368#ifdef AUTO_EOI_2
369 outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
370#else
371 outb(IO_ICU2+1,1); /* 8086 mode */
372#endif
373 outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
374 outb(IO_ICU2, 0x0a); /* default to IRR on read */
375}
376
377/* region of physical memory known to be contiguous */
378vm_offset_t isaphysmem;
379static caddr_t dma_bounce[8]; /* XXX */
380static char bounced[8]; /* XXX */
381#define MAXDMASZ 512 /* XXX */
382
383/* high byte of address is stored in this port for i-th dma channel */
384static short dmapageport[8] =
385 { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
386
387/*
388 * isa_dmacascade(): program 8237 DMA controller channel to accept
389 * external dma control by a board.
390 */
391void isa_dmacascade(unsigned chan)
392{
393 if (chan > 7)
394 panic("isa_dmacascade: impossible request");
395
396 /* set dma channel mode, and set dma channel mode */
397 if ((chan & 4) == 0) {
398 outb(DMA1_MODE, DMA37MD_CASCADE | chan);
399 outb(DMA1_SMSK, chan);
400 } else {
401 outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
402 outb(DMA2_SMSK, chan & 3);
403 }
404}
405
406/*
407 * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
408 * problems by using a bounce buffer.
409 */
410void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
411{ vm_offset_t phys;
412 int waport;
413 caddr_t newaddr;
414
415 if ( chan > 7
416 || (chan < 4 && nbytes > (1<<16))
417 || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
418 panic("isa_dmastart: impossible request");
419
420 if (isa_dmarangecheck(addr, nbytes, chan)) {
421 if (dma_bounce[chan] == 0)
422 dma_bounce[chan] =
423 /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
424 (caddr_t) isaphysmem + NBPG*chan;
425 bounced[chan] = 1;
426 newaddr = dma_bounce[chan];
427 *(int *) newaddr = 0; /* XXX */
428
429 /* copy bounce buffer on write */
430 if (!(flags & B_READ))
431 bcopy(addr, newaddr, nbytes);
432 addr = newaddr;
433 }
434
435 /* translate to physical */
436 phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
437
438 if ((chan & 4) == 0) {
439 /*
440 * Program one of DMA channels 0..3. These are
441 * byte mode channels.
442 */
443 /* set dma channel mode, and reset address ff */
444 if (flags & B_READ)
445 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
446 else
447 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
448 outb(DMA1_FFC, 0);
449
450 /* send start address */
451 waport = DMA1_CHN(chan);
452 outb(waport, phys);
453 outb(waport, phys>>8);
454 outb(dmapageport[chan], phys>>16);
455
456 /* send count */
457 outb(waport + 1, --nbytes);
458 outb(waport + 1, nbytes>>8);
459
460 /* unmask channel */
461 outb(DMA1_SMSK, chan);
462 } else {
463 /*
464 * Program one of DMA channels 4..7. These are
465 * word mode channels.
466 */
467 /* set dma channel mode, and reset address ff */
468 if (flags & B_READ)
469 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
470 else
471 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
472 outb(DMA2_FFC, 0);
473
474 /* send start address */
475 waport = DMA2_CHN(chan - 4);
476 outb(waport, phys>>1);
477 outb(waport, phys>>9);
478 outb(dmapageport[chan], phys>>16);
479
480 /* send count */
481 nbytes >>= 1;
482 outb(waport + 2, --nbytes);
483 outb(waport + 2, nbytes>>8);
484
485 /* unmask channel */
486 outb(DMA2_SMSK, chan & 3);
487 }
488}
489
490void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
491{
492
493 /* copy bounce buffer on read */
494 /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/
495 if (bounced[chan]) {
496 bcopy(dma_bounce[chan], addr, nbytes);
497 bounced[chan] = 0;
498 }
499}
500
501/*
502 * Check for problems with the address range of a DMA transfer
503 * (non-contiguous physical pages, outside of bus address space,
504 * crossing DMA page boundaries).
505 * Return true if special handling needed.
506 */
507
346 int i;
347
348 /* icu vectors */
349 for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++)
350 setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL);
351
352 /* out of range vectors */
353 for (i = NRSVIDT; i < NIDT; i++)
354 setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL);
355
356 /* initialize 8259's */
357 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
358 outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
359 outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
360#ifdef AUTO_EOI_1
361 outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
362#else
363 outb(IO_ICU1+1, 1); /* 8086 mode */
364#endif
365 outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
366 outb(IO_ICU1, 0x0a); /* default to IRR on read */
367 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
368
369 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
370 outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
371 outb(IO_ICU2+1,2); /* my slave id is 2 */
372#ifdef AUTO_EOI_2
373 outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
374#else
375 outb(IO_ICU2+1,1); /* 8086 mode */
376#endif
377 outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
378 outb(IO_ICU2, 0x0a); /* default to IRR on read */
379}
380
381/* region of physical memory known to be contiguous */
382vm_offset_t isaphysmem;
383static caddr_t dma_bounce[8]; /* XXX */
384static char bounced[8]; /* XXX */
385#define MAXDMASZ 512 /* XXX */
386
387/* high byte of address is stored in this port for i-th dma channel */
388static short dmapageport[8] =
389 { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
390
391/*
392 * isa_dmacascade(): program 8237 DMA controller channel to accept
393 * external dma control by a board.
394 */
395void isa_dmacascade(unsigned chan)
396{
397 if (chan > 7)
398 panic("isa_dmacascade: impossible request");
399
400 /* set dma channel mode, and set dma channel mode */
401 if ((chan & 4) == 0) {
402 outb(DMA1_MODE, DMA37MD_CASCADE | chan);
403 outb(DMA1_SMSK, chan);
404 } else {
405 outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
406 outb(DMA2_SMSK, chan & 3);
407 }
408}
409
410/*
411 * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
412 * problems by using a bounce buffer.
413 */
414void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
415{ vm_offset_t phys;
416 int waport;
417 caddr_t newaddr;
418
419 if ( chan > 7
420 || (chan < 4 && nbytes > (1<<16))
421 || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
422 panic("isa_dmastart: impossible request");
423
424 if (isa_dmarangecheck(addr, nbytes, chan)) {
425 if (dma_bounce[chan] == 0)
426 dma_bounce[chan] =
427 /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
428 (caddr_t) isaphysmem + NBPG*chan;
429 bounced[chan] = 1;
430 newaddr = dma_bounce[chan];
431 *(int *) newaddr = 0; /* XXX */
432
433 /* copy bounce buffer on write */
434 if (!(flags & B_READ))
435 bcopy(addr, newaddr, nbytes);
436 addr = newaddr;
437 }
438
439 /* translate to physical */
440 phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
441
442 if ((chan & 4) == 0) {
443 /*
444 * Program one of DMA channels 0..3. These are
445 * byte mode channels.
446 */
447 /* set dma channel mode, and reset address ff */
448 if (flags & B_READ)
449 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
450 else
451 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
452 outb(DMA1_FFC, 0);
453
454 /* send start address */
455 waport = DMA1_CHN(chan);
456 outb(waport, phys);
457 outb(waport, phys>>8);
458 outb(dmapageport[chan], phys>>16);
459
460 /* send count */
461 outb(waport + 1, --nbytes);
462 outb(waport + 1, nbytes>>8);
463
464 /* unmask channel */
465 outb(DMA1_SMSK, chan);
466 } else {
467 /*
468 * Program one of DMA channels 4..7. These are
469 * word mode channels.
470 */
471 /* set dma channel mode, and reset address ff */
472 if (flags & B_READ)
473 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
474 else
475 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
476 outb(DMA2_FFC, 0);
477
478 /* send start address */
479 waport = DMA2_CHN(chan - 4);
480 outb(waport, phys>>1);
481 outb(waport, phys>>9);
482 outb(dmapageport[chan], phys>>16);
483
484 /* send count */
485 nbytes >>= 1;
486 outb(waport + 2, --nbytes);
487 outb(waport + 2, nbytes>>8);
488
489 /* unmask channel */
490 outb(DMA2_SMSK, chan & 3);
491 }
492}
493
494void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
495{
496
497 /* copy bounce buffer on read */
498 /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/
499 if (bounced[chan]) {
500 bcopy(dma_bounce[chan], addr, nbytes);
501 bounced[chan] = 0;
502 }
503}
504
505/*
506 * Check for problems with the address range of a DMA transfer
507 * (non-contiguous physical pages, outside of bus address space,
508 * crossing DMA page boundaries).
509 * Return true if special handling needed.
510 */
511
512int
508isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
509 vm_offset_t phys, priorpage = 0, endva;
510 u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
511
512 endva = (vm_offset_t)round_page(va + length);
513 for (; va < (caddr_t) endva ; va += NBPG) {
514 phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
515#define ISARAM_END RAM_END
516 if (phys == 0)
517 panic("isa_dmacheck: no physical page present");
518 if (phys > ISARAM_END)
519 return (1);
520 if (priorpage) {
521 if (priorpage + NBPG != phys)
522 return (1);
523 /* check if crossing a DMA page boundary */
524 if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
525 return (1);
526 }
527 priorpage = phys;
528 }
529 return (0);
530}
531
532/* head of queue waiting for physmem to become available */
533struct buf isa_physmemq;
534
535/* blocked waiting for resource to become free for exclusive use */
536static isaphysmemflag;
537/* if waited for and call requested when free (B_CALL) */
538static void (*isaphysmemunblock)(); /* needs to be a list */
539
540/*
541 * Allocate contiguous physical memory for transfer, returning
542 * a *virtual* address to region. May block waiting for resource.
543 * (assumed to be called at splbio())
544 */
545caddr_t
546isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
547
548 isaphysmemunblock = func;
549 while (isaphysmemflag & B_BUSY) {
550 isaphysmemflag |= B_WANTED;
513isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
514 vm_offset_t phys, priorpage = 0, endva;
515 u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
516
517 endva = (vm_offset_t)round_page(va + length);
518 for (; va < (caddr_t) endva ; va += NBPG) {
519 phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
520#define ISARAM_END RAM_END
521 if (phys == 0)
522 panic("isa_dmacheck: no physical page present");
523 if (phys > ISARAM_END)
524 return (1);
525 if (priorpage) {
526 if (priorpage + NBPG != phys)
527 return (1);
528 /* check if crossing a DMA page boundary */
529 if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
530 return (1);
531 }
532 priorpage = phys;
533 }
534 return (0);
535}
536
537/* head of queue waiting for physmem to become available */
538struct buf isa_physmemq;
539
540/* blocked waiting for resource to become free for exclusive use */
541static isaphysmemflag;
542/* if waited for and call requested when free (B_CALL) */
543static void (*isaphysmemunblock)(); /* needs to be a list */
544
545/*
546 * Allocate contiguous physical memory for transfer, returning
547 * a *virtual* address to region. May block waiting for resource.
548 * (assumed to be called at splbio())
549 */
550caddr_t
551isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
552
553 isaphysmemunblock = func;
554 while (isaphysmemflag & B_BUSY) {
555 isaphysmemflag |= B_WANTED;
551 tsleep(&isaphysmemflag, PRIBIO, "isaphys", 0);
556 tsleep((caddr_t)&isaphysmemflag, PRIBIO, "isaphys", 0);
552 }
553 isaphysmemflag |= B_BUSY;
554
555 return((caddr_t)isaphysmem);
556}
557
558/*
559 * Free contiguous physical memory used for transfer.
560 * (assumed to be called at splbio())
561 */
562void
563isa_freephysmem(caddr_t va, unsigned length) {
564
565 isaphysmemflag &= ~B_BUSY;
566 if (isaphysmemflag & B_WANTED) {
567 isaphysmemflag &= B_WANTED;
557 }
558 isaphysmemflag |= B_BUSY;
559
560 return((caddr_t)isaphysmem);
561}
562
563/*
564 * Free contiguous physical memory used for transfer.
565 * (assumed to be called at splbio())
566 */
567void
568isa_freephysmem(caddr_t va, unsigned length) {
569
570 isaphysmemflag &= ~B_BUSY;
571 if (isaphysmemflag & B_WANTED) {
572 isaphysmemflag &= B_WANTED;
568 wakeup(&isaphysmemflag);
573 wakeup((caddr_t)&isaphysmemflag);
569 if (isaphysmemunblock)
570 (*isaphysmemunblock)();
571 }
572}
573
574/*
575 * Handle a NMI, possibly a machine check.
576 * return true to panic system, false to ignore.
577 */
574 if (isaphysmemunblock)
575 (*isaphysmemunblock)();
576 }
577}
578
579/*
580 * Handle a NMI, possibly a machine check.
581 * return true to panic system, false to ignore.
582 */
578isa_nmi(cd) {
583int
584isa_nmi(cd)
585 int cd;
586{
579
580 log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
581 return(0);
582}
583
584/*
585 * Caught a stray interrupt, notify
586 */
587
588 log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
589 return(0);
590}
591
592/*
593 * Caught a stray interrupt, notify
594 */
587isa_strayintr(d) {
595void
596isa_strayintr(d)
597 int d;
598{
588
589 /* DON'T BOTHER FOR NOW! */
590 /* for some reason, we get bursts of intr #7, even if not enabled! */
591 /*
592 * Well the reason you got bursts of intr #7 is because someone
593 * raised an interrupt line and dropped it before the 8259 could
594 * prioritize it. This is documented in the intel data book. This
595 * means you have BAD hardware! I have changed this so that only
596 * the first 5 get logged, then it quits logging them, and puts
597 * out a special message. rgrimes 3/25/1993
598 */
599 extern u_long intrcnt_stray;
600
601 intrcnt_stray++;
602 if (intrcnt_stray <= 5)
603 log(LOG_ERR,"ISA strayintr %x\n", d);
604 if (intrcnt_stray == 5)
605 log(LOG_CRIT,"Too many ISA strayintr not logging any more\n");
606}
607
608/*
609 * Wait "n" microseconds.
610 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at
611 * (1 * TIMER_FREQ) Hz.
612 * Note: timer had better have been programmed before this is first used!
613 * (The standard programming causes the timer to generate a square wave and
614 * the counter is decremented twice every cycle.)
615 */
616#define CF (1 * TIMER_FREQ)
617#define TIMER_FREQ 1193182 /* XXX - should be elsewhere */
618
599
600 /* DON'T BOTHER FOR NOW! */
601 /* for some reason, we get bursts of intr #7, even if not enabled! */
602 /*
603 * Well the reason you got bursts of intr #7 is because someone
604 * raised an interrupt line and dropped it before the 8259 could
605 * prioritize it. This is documented in the intel data book. This
606 * means you have BAD hardware! I have changed this so that only
607 * the first 5 get logged, then it quits logging them, and puts
608 * out a special message. rgrimes 3/25/1993
609 */
610 extern u_long intrcnt_stray;
611
612 intrcnt_stray++;
613 if (intrcnt_stray <= 5)
614 log(LOG_ERR,"ISA strayintr %x\n", d);
615 if (intrcnt_stray == 5)
616 log(LOG_CRIT,"Too many ISA strayintr not logging any more\n");
617}
618
619/*
620 * Wait "n" microseconds.
621 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at
622 * (1 * TIMER_FREQ) Hz.
623 * Note: timer had better have been programmed before this is first used!
624 * (The standard programming causes the timer to generate a square wave and
625 * the counter is decremented twice every cycle.)
626 */
627#define CF (1 * TIMER_FREQ)
628#define TIMER_FREQ 1193182 /* XXX - should be elsewhere */
629
619extern int hz; /* XXX - should be elsewhere */
620
621int DELAY(n)
630void
631DELAY(n)
622 int n;
623{
624 int counter_limit;
625 int prev_tick;
626 int tick;
627 int ticks_left;
628 int sec;
629 int usec;
630
631#ifdef DELAYDEBUG
632 int getit_calls = 1;
633 int n1;
634 static int state = 0;
635
636 if (state == 0) {
637 state = 1;
638 for (n1 = 1; n1 <= 10000000; n1 *= 10)
639 DELAY(n1);
640 state = 2;
641 }
642 if (state == 1)
643 printf("DELAY(%d)...", n);
644#endif
645
646 /*
647 * Read the counter first, so that the rest of the setup overhead is
648 * counted. Guess the initial overhead is 20 usec (on most systems it
649 * takes about 1.5 usec for each of the i/o's in getit(). The loop
650 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
651 * multiplications and divisions to scale the count take a while).
652 */
653 prev_tick = getit(0, 0);
654 n -= 20;
655
656 /*
657 * Calculate (n * (CF / 1e6)) without using floating point and without
658 * any avoidable overflows.
659 */
660 sec = n / 1000000;
661 usec = n - sec * 1000000;
662 ticks_left = sec * CF
663 + usec * (CF / 1000000)
664 + usec * ((CF % 1000000) / 1000) / 1000
665 + usec * (CF % 1000) / 1000000;
666
667 counter_limit = TIMER_FREQ / hz;
668 while (ticks_left > 0) {
669 tick = getit(0, 0);
670#ifdef DELAYDEBUG
671 ++getit_calls;
672#endif
673 if (tick > prev_tick)
674 ticks_left -= prev_tick - (tick - counter_limit);
675 else
676 ticks_left -= prev_tick - tick;
677 prev_tick = tick;
678 }
679#ifdef DELAYDEBUG
680 if (state == 1)
681 printf(" %d calls to getit() at %d usec each\n",
682 getit_calls, (n + 5) / getit_calls);
683#endif
684}
685
632 int n;
633{
634 int counter_limit;
635 int prev_tick;
636 int tick;
637 int ticks_left;
638 int sec;
639 int usec;
640
641#ifdef DELAYDEBUG
642 int getit_calls = 1;
643 int n1;
644 static int state = 0;
645
646 if (state == 0) {
647 state = 1;
648 for (n1 = 1; n1 <= 10000000; n1 *= 10)
649 DELAY(n1);
650 state = 2;
651 }
652 if (state == 1)
653 printf("DELAY(%d)...", n);
654#endif
655
656 /*
657 * Read the counter first, so that the rest of the setup overhead is
658 * counted. Guess the initial overhead is 20 usec (on most systems it
659 * takes about 1.5 usec for each of the i/o's in getit(). The loop
660 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
661 * multiplications and divisions to scale the count take a while).
662 */
663 prev_tick = getit(0, 0);
664 n -= 20;
665
666 /*
667 * Calculate (n * (CF / 1e6)) without using floating point and without
668 * any avoidable overflows.
669 */
670 sec = n / 1000000;
671 usec = n - sec * 1000000;
672 ticks_left = sec * CF
673 + usec * (CF / 1000000)
674 + usec * ((CF % 1000000) / 1000) / 1000
675 + usec * (CF % 1000) / 1000000;
676
677 counter_limit = TIMER_FREQ / hz;
678 while (ticks_left > 0) {
679 tick = getit(0, 0);
680#ifdef DELAYDEBUG
681 ++getit_calls;
682#endif
683 if (tick > prev_tick)
684 ticks_left -= prev_tick - (tick - counter_limit);
685 else
686 ticks_left -= prev_tick - tick;
687 prev_tick = tick;
688 }
689#ifdef DELAYDEBUG
690 if (state == 1)
691 printf(" %d calls to getit() at %d usec each\n",
692 getit_calls, (n + 5) / getit_calls);
693#endif
694}
695
686getit(unit, timer) {
696int
697getit(unit, timer)
698 int unit;
699 int timer;
700{
687 int high;
688 int low;
689
690 /*
691 * XXX - isa.h defines bogus timers. There's no such timer as
692 * IO_TIMER_2 = 0x48. There's a timer in the CMOS RAM chip but
693 * its interface is quite different. Neither timer is an 8252.
694 * We actually only call this with unit = 0 and timer = 0. It
695 * could be static...
696 */
697 /*
698 * Protect ourself against interrupts.
699 * XXX - sysbeep() and sysbeepstop() need protection.
700 */
701 disable_intr();
702 /*
703 * Latch the count for 'timer' (cc00xxxx, c = counter, x = any).
704 */
705 outb(IO_TIMER1 + 3, timer << 6);
706
707 low = inb(IO_TIMER1 + timer);
708 high = inb(IO_TIMER1 + timer);
709 enable_intr();
710 return ((high << 8) | low);
711}
712
701 int high;
702 int low;
703
704 /*
705 * XXX - isa.h defines bogus timers. There's no such timer as
706 * IO_TIMER_2 = 0x48. There's a timer in the CMOS RAM chip but
707 * its interface is quite different. Neither timer is an 8252.
708 * We actually only call this with unit = 0 and timer = 0. It
709 * could be static...
710 */
711 /*
712 * Protect ourself against interrupts.
713 * XXX - sysbeep() and sysbeepstop() need protection.
714 */
715 disable_intr();
716 /*
717 * Latch the count for 'timer' (cc00xxxx, c = counter, x = any).
718 */
719 outb(IO_TIMER1 + 3, timer << 6);
720
721 low = inb(IO_TIMER1 + timer);
722 high = inb(IO_TIMER1 + timer);
723 enable_intr();
724 return ((high << 8) | low);
725}
726
713static beeping;
714static
715sysbeepstop(f)
727static int beeping;
728
729static void
730sysbeepstop(f, dummy)
731 caddr_t f;
732 int dummy;
716{
717 /* disable counter 2 */
718 outb(0x61, inb(0x61) & 0xFC);
719 if (f)
733{
734 /* disable counter 2 */
735 outb(0x61, inb(0x61) & 0xFC);
736 if (f)
720 timeout(sysbeepstop, 0, f);
737 timeout(sysbeepstop, (caddr_t)0, (int)f);
721 else
722 beeping = 0;
723}
724
738 else
739 beeping = 0;
740}
741
725void sysbeep(int pitch, int period)
742void
743sysbeep(int pitch, int period)
726{
727
728 outb(0x61, inb(0x61) | 3); /* enable counter 2 */
729 /*
730 * XXX - move timer stuff to clock.c.
731 * Program counter 2:
732 * ccaammmb, c counter, a = access, m = mode, b = BCD
733 * 1011x110, 11 for aa = LSB then MSB, x11 for mmm = square wave.
734 */
735 outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */
736
737 outb(0x42, pitch);
738 outb(0x42, (pitch>>8));
739
740 if (!beeping) {
741 beeping = period;
744{
745
746 outb(0x61, inb(0x61) | 3); /* enable counter 2 */
747 /*
748 * XXX - move timer stuff to clock.c.
749 * Program counter 2:
750 * ccaammmb, c counter, a = access, m = mode, b = BCD
751 * 1011x110, 11 for aa = LSB then MSB, x11 for mmm = square wave.
752 */
753 outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */
754
755 outb(0x42, pitch);
756 outb(0x42, (pitch>>8));
757
758 if (!beeping) {
759 beeping = period;
742 timeout(sysbeepstop, period/2, period);
760 timeout(sysbeepstop, (caddr_t)(period/2), period);
743 }
744}
745
746/*
747 * Pass command to keyboard controller (8042)
748 */
761 }
762}
763
764/*
765 * Pass command to keyboard controller (8042)
766 */
749unsigned kbc_8042cmd(val) {
767unsigned
768kbc_8042cmd(val)
769 int val;
770{
750
751 while (inb(KBSTATP)&KBS_IBF);
752 if (val) outb(KBCMDP, val);
753 while (inb(KBSTATP)&KBS_IBF);
754 return (inb(KBDATAP));
755}
756
757/*
758 * find an ISA device in a given isa_devtab_* table, given
759 * the table to search, the expected id_driver entry, and the unit number.
760 *
761 * this function is defined in isa_device.h, and this location is debatable;
762 * i put it there because it's useless w/o, and directly operates on
763 * the other stuff in that file.
764 *
765 */
766
767struct isa_device *find_isadev(table, driverp, unit)
768 struct isa_device *table;
769 struct isa_driver *driverp;
770 int unit;
771{
772 if (driverp == NULL) /* sanity check */
773 return NULL;
774
775 while ((table->id_driver != driverp) || (table->id_unit != unit)) {
776 if (table->id_driver == 0)
777 return NULL;
778
779 table++;
780 }
781
782 return table;
783}
784
785/*
786 * Return nonzero if a (masked) irq is pending for a given device.
787 */
788int
789isa_irq_pending(dvp)
790 struct isa_device *dvp;
791{
792 unsigned id_irq;
793
794 id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */
795 if (id_irq & 0xff)
796 return (inb(IO_ICU1) & id_irq);
797 return (inb(IO_ICU2) & (id_irq >> 8));
798}
771
772 while (inb(KBSTATP)&KBS_IBF);
773 if (val) outb(KBCMDP, val);
774 while (inb(KBSTATP)&KBS_IBF);
775 return (inb(KBDATAP));
776}
777
778/*
779 * find an ISA device in a given isa_devtab_* table, given
780 * the table to search, the expected id_driver entry, and the unit number.
781 *
782 * this function is defined in isa_device.h, and this location is debatable;
783 * i put it there because it's useless w/o, and directly operates on
784 * the other stuff in that file.
785 *
786 */
787
788struct isa_device *find_isadev(table, driverp, unit)
789 struct isa_device *table;
790 struct isa_driver *driverp;
791 int unit;
792{
793 if (driverp == NULL) /* sanity check */
794 return NULL;
795
796 while ((table->id_driver != driverp) || (table->id_unit != unit)) {
797 if (table->id_driver == 0)
798 return NULL;
799
800 table++;
801 }
802
803 return table;
804}
805
806/*
807 * Return nonzero if a (masked) irq is pending for a given device.
808 */
809int
810isa_irq_pending(dvp)
811 struct isa_device *dvp;
812{
813 unsigned id_irq;
814
815 id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */
816 if (id_irq & 0xff)
817 return (inb(IO_ICU1) & id_irq);
818 return (inb(IO_ICU2) & (id_irq >> 8));
819}