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