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