isa.c revision 1.41 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.41 1994/03/08 13:24:57 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/cpu.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 (void) splhigh();
111 INTREN(IRQ_SLAVE);
112 enable_intr();
113
114 for (dvp = isa_devtab_tty; config_isadev(dvp, &imask[PIL_TTY]); dvp++)
115 ;
116 for (dvp = isa_devtab_bio; config_isadev(dvp, &imask[PIL_BIO]); dvp++)
117 ;
118 for (dvp = isa_devtab_net; config_isadev(dvp, &imask[PIL_IMP]); dvp++)
119 ;
120 for (dvp = isa_devtab_null; config_isadev(dvp, (u_int *) NULL); dvp++)
121 ;
122
123 printf("biomask %x ttymask %x impmask %x\n",
124 imask[PIL_BIO], imask[PIL_TTY], imask[PIL_IMP]);
125
126 imask[PIL_AST] |= 0x80000000; /* must be non-zero */
127 imask[PIL_IMP] |= imask[PIL_AST];
128 imask[PIL_TTY] |= imask[PIL_AST];
129 imask[PIL_BIO] |= imask[PIL_AST];
130 imask[PIL_CLOCK] |= imask[PIL_AST];
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_dmadone(flags, addr, nbytes, chan)
425 int flags;
426 caddr_t addr;
427 vm_size_t nbytes;
428 int chan;
429 {
430 u_char tc;
431
432 #ifdef DIAGNOSTIC
433 if (chan < 0 || chan > 7)
434 panic("isa_dmadone: impossible request");
435 #endif
436
437 /* check that the terminal count was reached */
438 if ((chan & 4) == 0)
439 tc = inb(DMA1_SR) & (1 << chan);
440 else
441 tc = inb(DMA2_SR) & (1 << (chan & 3));
442 if (tc == 0)
443 /* XXX probably should panic or something */
444 log(LOG_ERR, "dma channel %d not finished\n", chan);
445
446 /* copy bounce buffer on read */
447 if (bounced[chan]) {
448 bcopy(dma_bounce[chan], addr, nbytes);
449 bounced[chan] = 0;
450 }
451
452 /* mask channel */
453 if ((chan & 4) == 0)
454 outb(DMA1_SMSK, DMA37SM_SET | chan);
455 else
456 outb(DMA2_SMSK, DMA37SM_SET | (chan & 3));
457 }
458
459 /*
460 * Check for problems with the address range of a DMA transfer
461 * (non-contiguous physical pages, outside of bus address space,
462 * crossing DMA page boundaries).
463 * Return true if special handling needed.
464 */
465 int
466 isa_dmarangecheck(va, length, chan)
467 vm_offset_t va;
468 u_long length;
469 int chan;
470 {
471 vm_offset_t phys, priorpage = 0, endva;
472 u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
473
474 endva = round_page(va + length);
475 for (; va < endva ; va += NBPG) {
476 phys = trunc_page(pmap_extract(pmap_kernel(), va));
477 if (phys == 0)
478 panic("isa_dmacheck: no physical page present");
479 if (phys >= (1<<24))
480 return 1;
481 if (priorpage) {
482 if (priorpage + NBPG != phys)
483 return 1;
484 /* check if crossing a DMA page boundary */
485 if ((priorpage ^ phys) & dma_pgmsk)
486 return 1;
487 }
488 priorpage = phys;
489 }
490 return 0;
491 }
492
493 /* head of queue waiting for physmem to become available */
494 struct buf isa_physmemq;
495
496 /* blocked waiting for resource to become free for exclusive use */
497 static isaphysmemflag;
498 /* if waited for and call requested when free (B_CALL) */
499 static void (*isaphysmemunblock)(); /* needs to be a list */
500
501 /*
502 * Allocate contiguous physical memory for transfer, returning
503 * a *virtual* address to region. May block waiting for resource.
504 * (assumed to be called at splbio())
505 */
506 caddr_t
507 isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
508
509 isaphysmemunblock = func;
510 while (isaphysmemflag & B_BUSY) {
511 isaphysmemflag |= B_WANTED;
512 sleep((caddr_t)&isaphysmemflag, PRIBIO);
513 }
514 isaphysmemflag |= B_BUSY;
515
516 return((caddr_t)isaphysmem);
517 }
518
519 /*
520 * Free contiguous physical memory used for transfer.
521 * (assumed to be called at splbio())
522 */
523 void
524 isa_freephysmem(caddr_t va, unsigned length) {
525
526 isaphysmemflag &= ~B_BUSY;
527 if (isaphysmemflag & B_WANTED) {
528 isaphysmemflag &= B_WANTED;
529 wakeup((caddr_t)&isaphysmemflag);
530 if (isaphysmemunblock)
531 (*isaphysmemunblock)();
532 }
533 }
534
535 /*
536 * Handle a NMI, possibly a machine check.
537 * return true to panic system, false to ignore.
538 */
539 int
540 isa_nmi(cd) {
541
542 log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
543 return(0);
544 }
545
546 /*
547 * Caught a stray interrupt, notify
548 */
549 void
550 isa_strayintr(d) {
551
552 /* DON'T BOTHER FOR NOW! */
553 /* for some reason, we get bursts of intr #7, even if not enabled! */
554 /*
555 * Well the reason you got bursts of intr #7 is because someone
556 * raised an interrupt line and dropped it before the 8259 could
557 * prioritize it. This is documented in the intel data book. This
558 * means you have BAD hardware! I have changed this so that only
559 * the first 5 get logged, then it quits logging them, and puts
560 * out a special message. rgrimes 3/25/1993
561 */
562 extern u_long intrcnt_stray;
563
564 intrcnt_stray++;
565 if (intrcnt_stray <= 5)
566 log(LOG_ERR,"ISA strayintr %x\n", d);
567 if (intrcnt_stray == 5)
568 log(LOG_CRIT,"Too many ISA strayintr not logging any more\n");
569 }
570
571 /*
572 * Wait "n" microseconds.
573 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
574 * Note: timer had better have been programmed before this is first used!
575 * (Note that we use `rate generator' mode, which counts at 1:1; `square
576 * wave' mode counts at 2:1).
577 */
578 void
579 delay(n)
580 int n;
581 {
582 int limit, tick, otick;
583
584 /*
585 * Read the counter first, so that the rest of the setup overhead is
586 * counted.
587 */
588 otick = gettick();
589
590 #ifdef __GNUC__
591 /*
592 * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler code so
593 * we can take advantage of the intermediate 64-bit quantity to prevent
594 * loss of significance.
595 */
596 n -= 5;
597 if (n < 0)
598 return;
599 {register int m;
600 __asm __volatile("mul %3"
601 : "=a" (n), "=d" (m)
602 : "0" (n), "r" (TIMER_FREQ));
603 __asm __volatile("div %3"
604 : "=a" (n)
605 : "0" (n), "d" (m), "r" (1000000)
606 : "%edx");}
607 #else
608 /*
609 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and
610 * without any avoidable overflows.
611 */
612 n -= 20;
613 {
614 int sec = n / 1000000,
615 usec = n % 1000000;
616 n = sec * TIMER_FREQ +
617 usec * (TIMER_FREQ / 1000000) +
618 usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 +
619 usec * (TIMER_FREQ % 1000) / 1000000;
620 }
621 #endif
622
623 limit = TIMER_FREQ / hz;
624
625 while (n > 0) {
626 tick = gettick();
627 if (tick > otick)
628 n -= limit - (tick - otick);
629 else
630 n -= otick - tick;
631 otick = tick;
632 }
633 }
634
635 int
636 gettick()
637 {
638 u_char lo, hi;
639
640 /* Don't want someone screwing with the counter while we're here. */
641 disable_intr();
642 /* Select counter 0 and latch it. */
643 outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
644 lo = inb(TIMER_CNTR0);
645 hi = inb(TIMER_CNTR0);
646 enable_intr();
647 return ((hi << 8) | lo);
648 }
649
650 static beeping;
651 static void
652 sysbeepstop(int f)
653 {
654 int s = splhigh();
655
656 /* disable counter 2 */
657 disable_intr();
658 outb(PITAUX_PORT, inb(PITAUX_PORT) & ~PIT_SPKR);
659 enable_intr();
660 if (f)
661 timeout((timeout_t)sysbeepstop, (caddr_t)0, f);
662 else
663 beeping = 0;
664
665 splx(s);
666 }
667
668 void
669 sysbeep(int pitch, int period)
670 {
671 int s = splhigh();
672 static int last_pitch, last_period;
673
674 if (beeping) {
675 untimeout((timeout_t)sysbeepstop, (caddr_t)(last_period/2));
676 untimeout((timeout_t)sysbeepstop, (caddr_t)0);
677 }
678 if (!beeping || last_pitch != pitch) {
679 /*
680 * XXX - move timer stuff to clock.c.
681 */
682 disable_intr();
683 outb(TIMER_MODE, TIMER_SEL2|TIMER_16BIT|TIMER_SQWAVE);
684 outb(TIMER_CNTR2, TIMER_DIV(pitch)%256);
685 outb(TIMER_CNTR2, TIMER_DIV(pitch)/256);
686 outb(PITAUX_PORT, inb(PITAUX_PORT) | PIT_SPKR); /* enable counter 2 */
687 enable_intr();
688 }
689 last_pitch = pitch;
690 beeping = last_period = period;
691 timeout((timeout_t)sysbeepstop, (caddr_t)(period/2), period);
692
693 splx(s);
694 }
695
696 /*
697 * find an ISA device in a given isa_devtab_* table, given
698 * the table to search, the expected id_driver entry, and the unit number.
699 *
700 * this function is defined in isa_device.h, and this location is debatable;
701 * i put it there because it's useless w/o, and directly operates on
702 * the other stuff in that file.
703 *
704 */
705
706 struct isa_device *find_isadev(table, driverp, unit)
707 struct isa_device *table;
708 struct isa_driver *driverp;
709 int unit;
710 {
711 if (driverp == NULL) /* sanity check */
712 return NULL;
713
714 while ((table->id_driver != driverp) || (table->id_unit != unit)) {
715 if (table->id_driver == 0)
716 return NULL;
717
718 table++;
719 }
720
721 return table;
722 }
723
724 /*
725 * Return nonzero if a (masked) irq is pending for a given device.
726 */
727 int
728 isa_irq_pending(dvp)
729 struct isa_device *dvp;
730 {
731 unsigned id_irq;
732
733 id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */
734 if (id_irq & 0xff)
735 return (inb(IO_ICU1) & id_irq);
736 return (inb(IO_ICU2) & (id_irq >> 8));
737 }
738