isa.c revision 24
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: /home/cvs/386BSD/src/sys.386bsd/i386/isa/isa.c,v 1.1.1.1 1993/06/12 14:58:01 rgrimes Exp $"; 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 * Only print the I/O address range if id_alive != -1 240 * Right now this is a temporary fix just for the new 241 * NPX code so that if it finds a 486 that can use trap 242 * 16 it will not report I/O addresses. 243 * Rod Grimes 04/26/94 244 */ 245 if (isdp->id_alive != -1) { 246 printf(" at 0x%x", isdp->id_iobase); 247 if ((isdp->id_iobase + isdp->id_alive - 1) != 248 isdp->id_iobase) 249 printf("-0x%x", 250 isdp->id_iobase + 251 isdp->id_alive - 1); 252 } 253 if(isdp->id_irq) 254 printf(" irq %d", ffs(isdp->id_irq)-1); 255 if (isdp->id_drq != -1) 256 printf(" drq %d", isdp->id_drq); 257 if (isdp->id_maddr != 0) 258 printf(" maddr 0x%x", kvtop(isdp->id_maddr)); 259 if (isdp->id_msize != 0) 260 printf(" msize %d", isdp->id_msize); 261 if (isdp->id_flags != 0) 262 printf(" flags 0x%x", isdp->id_flags); 263 printf(" on isa\n"); 264 265 (*dp->attach)(isdp); 266 267 if(isdp->id_irq) { 268 int intrno; 269 270 intrno = ffs(isdp->id_irq)-1; 271 setidt(ICU_OFFSET+intrno, isdp->id_intr, 272 SDT_SYS386IGT, SEL_KPL); 273 if(mp) 274 INTRMASK(*mp,isdp->id_irq); 275 INTREN(isdp->id_irq); 276 } 277 } 278 return (1); 279 } else return(0); 280} 281#endif /* (!) notyet */ 282 283#define IDTVEC(name) __CONCAT(X,name) 284/* default interrupt vector table entries */ 285extern IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3), 286 IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7), 287 IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11), 288 IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15); 289 290static *defvec[16] = { 291 &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 296/* out of range default interrupt vector gate entry */ 297extern IDTVEC(intrdefault); 298 299/* 300 * Fill in default interrupt table (in case of spuruious interrupt 301 * during configuration of kernel, setup interrupt control unit 302 */ 303isa_defaultirq() { 304 int i; 305 306 /* icu vectors */ 307 for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++) 308 setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL); 309 310 /* out of range vectors */ 311 for (i = NRSVIDT; i < NIDT; i++) 312 setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL); 313 314 /* initialize 8259's */ 315 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ 316 outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */ 317 outb(IO_ICU1+1, 1<<2); /* slave on line 2 */ 318#ifdef AUTO_EOI_1 319 outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */ 320#else 321 outb(IO_ICU1+1, 1); /* 8086 mode */ 322#endif 323 outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ 324 outb(IO_ICU1, 0x0a); /* default to IRR on read */ 325 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ 326 327 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ 328 outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */ 329 outb(IO_ICU2+1,2); /* my slave id is 2 */ 330#ifdef AUTO_EOI_2 331 outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */ 332#else 333 outb(IO_ICU2+1,1); /* 8086 mode */ 334#endif 335 outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ 336 outb(IO_ICU2, 0x0a); /* default to IRR on read */ 337} 338 339/* region of physical memory known to be contiguous */ 340vm_offset_t isaphysmem; 341static caddr_t dma_bounce[8]; /* XXX */ 342static char bounced[8]; /* XXX */ 343#define MAXDMASZ 512 /* XXX */ 344 345/* high byte of address is stored in this port for i-th dma channel */ 346static short dmapageport[8] = 347 { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; 348 349/* 350 * isa_dmacascade(): program 8237 DMA controller channel to accept 351 * external dma control by a board. 352 */ 353void isa_dmacascade(unsigned chan) 354{ 355 if (chan > 7) 356 panic("isa_dmacascade: impossible request"); 357 358 /* set dma channel mode, and set dma channel mode */ 359 if ((chan & 4) == 0) { 360 outb(DMA1_MODE, DMA37MD_CASCADE | chan); 361 outb(DMA1_SMSK, chan); 362 } else { 363 outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); 364 outb(DMA2_SMSK, chan & 3); 365 } 366} 367 368/* 369 * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment 370 * problems by using a bounce buffer. 371 */ 372void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan) 373{ vm_offset_t phys; 374 int waport; 375 caddr_t newaddr; 376 377 if ( chan > 7 378 || (chan < 4 && nbytes > (1<<16)) 379 || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1))) 380 panic("isa_dmastart: impossible request"); 381 382 if (isa_dmarangecheck(addr, nbytes, chan)) { 383 if (dma_bounce[chan] == 0) 384 dma_bounce[chan] = 385 /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/ 386 (caddr_t) isaphysmem + NBPG*chan; 387 bounced[chan] = 1; 388 newaddr = dma_bounce[chan]; 389 *(int *) newaddr = 0; /* XXX */ 390 391 /* copy bounce buffer on write */ 392 if (!(flags & B_READ)) 393 bcopy(addr, newaddr, nbytes); 394 addr = newaddr; 395 } 396 397 /* translate to physical */ 398 phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr); 399 400 if ((chan & 4) == 0) { 401 /* 402 * Program one of DMA channels 0..3. These are 403 * byte mode channels. 404 */ 405 /* set dma channel mode, and reset address ff */ 406 if (flags & B_READ) 407 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); 408 else 409 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); 410 outb(DMA1_FFC, 0); 411 412 /* send start address */ 413 waport = DMA1_CHN(chan); 414 outb(waport, phys); 415 outb(waport, phys>>8); 416 outb(dmapageport[chan], phys>>16); 417 418 /* send count */ 419 outb(waport + 1, --nbytes); 420 outb(waport + 1, nbytes>>8); 421 422 /* unmask channel */ 423 outb(DMA1_SMSK, chan); 424 } else { 425 /* 426 * Program one of DMA channels 4..7. These are 427 * word mode channels. 428 */ 429 /* set dma channel mode, and reset address ff */ 430 if (flags & B_READ) 431 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); 432 else 433 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); 434 outb(DMA2_FFC, 0); 435 436 /* send start address */ 437 waport = DMA2_CHN(chan - 4); 438 outb(waport, phys>>1); 439 outb(waport, phys>>9); 440 outb(dmapageport[chan], phys>>16); 441 442 /* send count */ 443 nbytes >>= 1; 444 outb(waport + 2, --nbytes); 445 outb(waport + 2, nbytes>>8); 446 447 /* unmask channel */ 448 outb(DMA2_SMSK, chan & 3); 449 } 450} 451 452void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan) 453{ 454 455 /* copy bounce buffer on read */ 456 /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/ 457 if (bounced[chan]) { 458 bcopy(dma_bounce[chan], addr, nbytes); 459 bounced[chan] = 0; 460 } 461} 462 463/* 464 * Check for problems with the address range of a DMA transfer 465 * (non-contiguous physical pages, outside of bus address space, 466 * crossing DMA page boundaries). 467 * Return true if special handling needed. 468 */ 469 470isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) { 471 vm_offset_t phys, priorpage = 0, endva; 472 u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); 473 474 endva = (vm_offset_t)round_page(va + length); 475 for (; va < (caddr_t) endva ; va += NBPG) { 476 phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va)); 477#define ISARAM_END RAM_END 478 if (phys == 0) 479 panic("isa_dmacheck: no physical page present"); 480 if (phys > ISARAM_END) 481 return (1); 482 if (priorpage) { 483 if (priorpage + NBPG != phys) 484 return (1); 485 /* check if crossing a DMA page boundary */ 486 if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk) 487 return (1); 488 } 489 priorpage = phys; 490 } 491 return (0); 492} 493 494/* head of queue waiting for physmem to become available */ 495struct buf isa_physmemq; 496 497/* blocked waiting for resource to become free for exclusive use */ 498static isaphysmemflag; 499/* if waited for and call requested when free (B_CALL) */ 500static void (*isaphysmemunblock)(); /* needs to be a list */ 501 502/* 503 * Allocate contiguous physical memory for transfer, returning 504 * a *virtual* address to region. May block waiting for resource. 505 * (assumed to be called at splbio()) 506 */ 507caddr_t 508isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) { 509 510 isaphysmemunblock = func; 511 while (isaphysmemflag & B_BUSY) { 512 isaphysmemflag |= B_WANTED; 513 sleep(&isaphysmemflag, PRIBIO); 514 } 515 isaphysmemflag |= B_BUSY; 516 517 return((caddr_t)isaphysmem); 518} 519 520/* 521 * Free contiguous physical memory used for transfer. 522 * (assumed to be called at splbio()) 523 */ 524void 525isa_freephysmem(caddr_t va, unsigned length) { 526 527 isaphysmemflag &= ~B_BUSY; 528 if (isaphysmemflag & B_WANTED) { 529 isaphysmemflag &= B_WANTED; 530 wakeup(&isaphysmemflag); 531 if (isaphysmemunblock) 532 (*isaphysmemunblock)(); 533 } 534} 535 536/* 537 * Handle a NMI, possibly a machine check. 538 * return true to panic system, false to ignore. 539 */ 540isa_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 */ 549isa_strayintr(d) { 550 551 /* DON'T BOTHER FOR NOW! */ 552 /* for some reason, we get bursts of intr #7, even if not enabled! */ 553 /* 554 * Well the reason you got bursts of intr #7 is because someone 555 * raised an interrupt line and dropped it before the 8259 could 556 * prioritize it. This is documented in the intel data book. This 557 * means you have BAD hardware! I have changed this so that only 558 * the first 5 get logged, then it quits logging them, and puts 559 * out a special message. rgrimes 3/25/1993 560 */ 561 extern u_long intrcnt_stray; 562 563 intrcnt_stray++; 564 if (intrcnt_stray <= 5) 565 log(LOG_ERR,"ISA strayintr %x\n", d); 566 if (intrcnt_stray == 5) 567 log(LOG_CRIT,"Too many ISA strayintr not logging any more\n"); 568} 569 570/* 571 * Wait "n" microseconds. 572 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at 573 * (2 * TIMER_FREQ) Hz. 574 * Note: timer had better have been programmed before this is first used! 575 * (The standard programming causes the timer to generate a square wave and 576 * the counter is decremented twice every cycle.) 577 */ 578#define CF (2 * TIMER_FREQ) 579#define TIMER_FREQ 1193182 /* XXX - should be elsewhere */ 580 581extern int hz; /* XXX - should be elsewhere */ 582 583int DELAY(n) 584 int n; 585{ 586 int counter_limit; 587 int prev_tick; 588 int tick; 589 int ticks_left; 590 int sec; 591 int usec; 592 593#ifdef DELAYDEBUG 594 int getit_calls = 1; 595 int n1; 596 static int state = 0; 597 598 if (state == 0) { 599 state = 1; 600 for (n1 = 1; n1 <= 10000000; n1 *= 10) 601 DELAY(n1); 602 state = 2; 603 } 604 if (state == 1) 605 printf("DELAY(%d)...", n); 606#endif 607 608 /* 609 * Read the counter first, so that the rest of the setup overhead is 610 * counted. Guess the initial overhead is 20 usec (on most systems it 611 * takes about 1.5 usec for each of the i/o's in getit(). The loop 612 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The 613 * multiplications and divisions to scale the count take a while). 614 */ 615 prev_tick = getit(0, 0); 616 n -= 20; 617 618 /* 619 * Calculate (n * (CF / 1e6)) without using floating point and without 620 * any avoidable overflows. 621 */ 622 sec = n / 1000000; 623 usec = n - sec * 1000000; 624 ticks_left = sec * CF 625 + usec * (CF / 1000000) 626 + usec * ((CF % 1000000) / 1000) / 1000 627 + usec * (CF % 1000) / 1000000; 628 629 counter_limit = TIMER_FREQ / hz; 630 while (ticks_left > 0) { 631 tick = getit(0, 0); 632#ifdef DELAYDEBUG 633 ++getit_calls; 634#endif 635 if (tick > prev_tick) 636 ticks_left -= prev_tick - (tick - counter_limit); 637 else 638 ticks_left -= prev_tick - tick; 639 prev_tick = tick; 640 } 641#ifdef DELAYDEBUG 642 if (state == 1) 643 printf(" %d calls to getit() at %d usec each\n", 644 getit_calls, (n + 5) / getit_calls); 645#endif 646} 647 648getit(unit, timer) { 649 int high; 650 int low; 651 652 /* 653 * XXX - isa.h defines bogus timers. There's no such timer as 654 * IO_TIMER_2 = 0x48. There's a timer in the CMOS RAM chip but 655 * its interface is quite different. Neither timer is an 8252. 656 * We actually only call this with unit = 0 and timer = 0. It 657 * could be static... 658 */ 659 /* 660 * Protect ourself against interrupts. 661 * XXX - sysbeep() and sysbeepstop() need protection. 662 */ 663 disable_intr(); 664 /* 665 * Latch the count for 'timer' (cc00xxxx, c = counter, x = any). 666 */ 667 outb(IO_TIMER1 + 3, timer << 6); 668 669 low = inb(IO_TIMER1 + timer); 670 high = inb(IO_TIMER1 + timer); 671 enable_intr(); 672 return ((high << 8) | low); 673} 674 675static beeping; 676static 677sysbeepstop(f) 678{ 679 /* disable counter 2 */ 680 outb(0x61, inb(0x61) & 0xFC); 681 if (f) 682 timeout(sysbeepstop, 0, f); 683 else 684 beeping = 0; 685} 686 687void sysbeep(int pitch, int period) 688{ 689 690 outb(0x61, inb(0x61) | 3); /* enable counter 2 */ 691 /* 692 * XXX - move timer stuff to clock.c. 693 * Program counter 2: 694 * ccaammmb, c counter, a = access, m = mode, b = BCD 695 * 1011x110, 11 for aa = LSB then MSB, x11 for mmm = square wave. 696 */ 697 outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */ 698 699 outb(0x42, pitch); 700 outb(0x42, (pitch>>8)); 701 702 if (!beeping) { 703 beeping = period; 704 timeout(sysbeepstop, period/2, period); 705 } 706} 707 708/* 709 * Pass command to keyboard controller (8042) 710 */ 711unsigned kbc_8042cmd(val) { 712 713 while (inb(KBSTATP)&KBS_IBF); 714 if (val) outb(KBCMDP, val); 715 while (inb(KBSTATP)&KBS_IBF); 716 return (inb(KBDATAP)); 717} 718 719/* 720 * find an ISA device in a given isa_devtab_* table, given 721 * the table to search, the expected id_driver entry, and the unit number. 722 * 723 * this function is defined in isa_device.h, and this location is debatable; 724 * i put it there because it's useless w/o, and directly operates on 725 * the other stuff in that file. 726 * 727 */ 728 729struct isa_device *find_isadev(table, driverp, unit) 730 struct isa_device *table; 731 struct isa_driver *driverp; 732 int unit; 733{ 734 if (driverp == NULL) /* sanity check */ 735 return NULL; 736 737 while ((table->id_driver != driverp) || (table->id_unit != unit)) { 738 if (table->id_driver == 0) 739 return NULL; 740 741 table++; 742 } 743 744 return table; 745} 746 747/* 748 * Return nonzero if a (masked) irq is pending for a given device. 749 */ 750int 751isa_irq_pending(dvp) 752 struct isa_device *dvp; 753{ 754 unsigned id_irq; 755 756 id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */ 757 if (id_irq & 0xff) 758 return (inb(IO_ICU1) & id_irq); 759 return (inb(IO_ICU2) & (id_irq >> 8)); 760} 761