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.26 1993/07/11 14:03:54 mycroft 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" 51 #include "systm.h" 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 "machine/segments.h" 59 #include "machine/cpufunc.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 #include "i386/isa/timerreg.h" 67 68 /* sorry, has to be here, no place else really suitable */ 69 #include "machine/pc/display.h" 70 u_short *Crtat = (u_short *)MONO_BUF; 71 72 /* 73 ** Register definitions for DMA controller 1 (channels 0..3): 74 */ 75 #define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */ 76 #define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */ 77 #define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */ 78 #define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */ 79 80 /* 81 ** Register definitions for DMA controller 2 (channels 4..7): 82 */ 83 #define DMA2_CHN(c) (IO_DMA1 + 2*(2*(c))) /* addr reg for channel c */ 84 #define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */ 85 #define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */ 86 #define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */ 87 88 int config_isadev(struct isa_device *, u_int *); 89 void config_attach(struct isa_driver *, struct isa_device *); 90 static void sysbeepstop(int); 91 92 /* 93 * Configure all ISA devices 94 */ 95 void 96 isa_configure() { 97 struct isa_device *dvp; 98 struct isa_driver *dp; 99 100 enable_intr(); 101 splhigh(); 102 INTREN(IRQ_SLAVE); 103 for (dvp = isa_devtab_tty; config_isadev(dvp,&ttymask); dvp++) 104 ; 105 for (dvp = isa_devtab_bio; config_isadev(dvp,&biomask); dvp++) 106 ; 107 for (dvp = isa_devtab_net; config_isadev(dvp,&netmask); dvp++) 108 ; 109 for (dvp = isa_devtab_null; config_isadev(dvp, (u_int *) NULL); dvp++) 110 ; 111 112 impmask = ttymask | netmask; 113 114 /* and the problem is... if netmask == 0, then the loopback 115 * code can do some really ugly things. 116 * workaround for this: if netmask == 0, set it to 0x8000, which 117 * is the value used by splsoftclock. this is nasty, but it 118 * should work until this interrupt system goes away. -- cgd 119 */ 120 if (netmask == 0) 121 netmask = 0x8000; /* same as for softclock. XXX */ 122 123 /* biomask |= ttymask ; can some tty devices use buffers? */ 124 printf("biomask %x ttymask %x netmask %x impmask %x\n", 125 biomask, ttymask, netmask, impmask); 126 splnone(); 127 } 128 129 /* 130 * Configure an ISA device. 131 */ 132 int 133 config_isadev(isdp, mp) 134 struct isa_device *isdp; 135 u_int *mp; 136 { 137 struct isa_driver *dp; 138 139 if (dp = isdp->id_driver) { 140 if (isdp->id_maddr) { 141 extern u_int atdevbase; 142 143 isdp->id_maddr -= 0xa0000; /* XXX should be a define */ 144 isdp->id_maddr += atdevbase; 145 } 146 isdp->id_alive = (*dp->probe)(isdp); 147 if (isdp->id_irq == (u_short)-1) 148 isdp->id_alive = 0; 149 /* 150 * Only print the I/O address range if id_alive != -1 151 * Right now this is a temporary fix just for the new 152 * NPX code so that if it finds a 486 that can use trap 153 * 16 it will not report I/O addresses. 154 * Rod Grimes 04/26/94 155 * 156 * XXX -- cgd 157 */ 158 if (isdp->id_alive) { 159 printf("%s%d", dp->name, isdp->id_unit); 160 printf(" at 0x%x", isdp->id_iobase); 161 if ((isdp->id_iobase + isdp->id_alive - 1) != 162 isdp->id_iobase) 163 printf("-0x%x", 164 isdp->id_iobase + isdp->id_alive - 1); 165 if (isdp->id_irq != 0) 166 printf(" irq %d", ffs(isdp->id_irq)-1); 167 if (isdp->id_drq != -1) 168 printf(" drq %d", isdp->id_drq); 169 if (isdp->id_maddr != 0) 170 printf(" maddr 0x%x", kvtop(isdp->id_maddr)); 171 if (isdp->id_msize != 0) 172 printf("-0x%x", kvtop(isdp->id_maddr) + 173 isdp->id_msize - 1); 174 if (isdp->id_flags != 0) 175 printf(" flags 0x%x", isdp->id_flags); 176 printf(" on isa\n"); 177 178 config_attach(dp, isdp); 179 180 if (isdp->id_irq) { 181 int intrno; 182 183 intrno = ffs(isdp->id_irq)-1; 184 setidt(ICU_OFFSET+intrno, isdp->id_intr, 185 SDT_SYS386IGT, SEL_KPL); 186 if(mp) 187 INTRMASK(*mp,isdp->id_irq); 188 INTREN(isdp->id_irq); 189 } 190 } 191 return (1); 192 } else return(0); 193 } 194 195 void 196 config_attach(struct isa_driver *dp, struct isa_device *isdp) 197 { 198 extern struct isa_device isa_subdev[]; 199 struct isa_device *dvp; 200 201 if(isdp->id_masunit==-1) { 202 (void)(*dp->attach)(isdp); 203 return; 204 } 205 206 if(isdp->id_masunit==0) { 207 for(dvp = isa_subdev; dvp->id_driver; dvp++) { 208 if (dvp->id_driver != dp) 209 continue; 210 if (dvp->id_masunit != isdp->id_unit) 211 continue; 212 if (dvp->id_physid == -1) 213 continue; 214 dvp->id_alive = (*dp->attach)(dvp); 215 } 216 for(dvp = isa_subdev; dvp->id_driver; dvp++) { 217 if (dvp->id_driver != dp) 218 continue; 219 if (dvp->id_masunit != isdp->id_unit) 220 continue; 221 if (dvp->id_physid != -1) 222 continue; 223 dvp->id_alive = (*dp->attach)(dvp); 224 } 225 return; 226 } 227 printf("id_masunit has weird value\n"); 228 } 229 230 231 #define IDTVEC(name) __CONCAT(X,name) 232 /* default interrupt vector table entries */ 233 extern IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3), 234 IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7), 235 IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11), 236 IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15); 237 238 static *defvec[16] = { 239 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3), 240 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7), 241 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11), 242 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) }; 243 244 /* out of range default interrupt vector gate entry */ 245 extern IDTVEC(intrdefault); 246 247 /* 248 * Fill in default interrupt table (in case of spuruious interrupt 249 * during configuration of kernel, setup interrupt control unit 250 */ 251 void 252 isa_defaultirq() { 253 int i; 254 255 /* icu vectors */ 256 for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++) 257 setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL); 258 259 /* out of range vectors */ 260 for (i = NRSVIDT; i < NIDT; i++) 261 setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL); 262 263 /* initialize 8259's */ 264 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ 265 outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */ 266 outb(IO_ICU1+1, 1<<2); /* slave on line 2 */ 267 #ifdef AUTO_EOI_1 268 outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */ 269 #else 270 outb(IO_ICU1+1, 1); /* 8086 mode */ 271 #endif 272 outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ 273 outb(IO_ICU1, 0x0a); /* default to IRR on read */ 274 #ifdef REORDER_IRQ 275 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ 276 #endif 277 278 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ 279 outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */ 280 outb(IO_ICU2+1,2); /* my slave id is 2 */ 281 #ifdef AUTO_EOI_2 282 outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */ 283 #else 284 outb(IO_ICU2+1,1); /* 8086 mode */ 285 #endif 286 outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ 287 outb(IO_ICU2, 0x0a); /* default to IRR on read */ 288 } 289 290 /* region of physical memory known to be contiguous */ 291 vm_offset_t isaphysmem; 292 static caddr_t dma_bounce[8]; /* XXX */ 293 static char bounced[8]; /* XXX */ 294 #define MAXDMASZ 512 /* XXX */ 295 296 /* high byte of address is stored in this port for i-th dma channel */ 297 static short dmapageport[8] = 298 { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; 299 300 /* 301 * isa_dmacascade(): program 8237 DMA controller channel to accept 302 * external dma control by a board. 303 */ 304 void 305 isa_dmacascade(unsigned chan) 306 { 307 if (chan > 7) 308 panic("isa_dmacascade: impossible request"); 309 310 /* set dma channel mode, and set dma channel mode */ 311 if ((chan & 4) == 0) { 312 outb(DMA1_MODE, DMA37MD_CASCADE | chan); 313 outb(DMA1_SMSK, chan); 314 } else { 315 outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); 316 outb(DMA2_SMSK, chan & 3); 317 } 318 } 319 320 /* 321 * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment 322 * problems by using a bounce buffer. 323 */ 324 void 325 isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan) 326 { vm_offset_t phys; 327 int waport; 328 caddr_t newaddr; 329 330 if ( chan > 7 331 || (chan < 4 && nbytes > (1<<16)) 332 || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1))) 333 panic("isa_dmastart: impossible request"); 334 335 if (isa_dmarangecheck(addr, nbytes, chan)) { 336 if (dma_bounce[chan] == 0) 337 dma_bounce[chan] = 338 /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/ 339 (caddr_t) isaphysmem + NBPG*chan; 340 bounced[chan] = 1; 341 newaddr = dma_bounce[chan]; 342 *(int *) newaddr = 0; /* XXX */ 343 344 /* copy bounce buffer on write */ 345 if (!(flags & B_READ)) 346 bcopy(addr, newaddr, nbytes); 347 addr = newaddr; 348 } 349 350 /* translate to physical */ 351 phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr); 352 353 if ((chan & 4) == 0) { 354 /* 355 * Program one of DMA channels 0..3. These are 356 * byte mode channels. 357 */ 358 /* set dma channel mode, and reset address ff */ 359 if (flags & B_READ) 360 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); 361 else 362 outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); 363 outb(DMA1_FFC, 0); 364 365 /* send start address */ 366 waport = DMA1_CHN(chan); 367 outb(waport, phys); 368 outb(waport, phys>>8); 369 outb(dmapageport[chan], phys>>16); 370 371 /* send count */ 372 outb(waport + 1, --nbytes); 373 outb(waport + 1, nbytes>>8); 374 375 /* unmask channel */ 376 outb(DMA1_SMSK, chan); 377 } else { 378 /* 379 * Program one of DMA channels 4..7. These are 380 * word mode channels. 381 */ 382 /* set dma channel mode, and reset address ff */ 383 if (flags & B_READ) 384 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); 385 else 386 outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); 387 outb(DMA2_FFC, 0); 388 389 /* send start address */ 390 waport = DMA2_CHN(chan - 4); 391 outb(waport, phys>>1); 392 outb(waport, phys>>9); 393 outb(dmapageport[chan], phys>>16); 394 395 /* send count */ 396 nbytes >>= 1; 397 outb(waport + 2, --nbytes); 398 outb(waport + 2, nbytes>>8); 399 400 /* unmask channel */ 401 outb(DMA2_SMSK, chan & 3); 402 } 403 } 404 405 void 406 isa_dmadone(int flags, caddr_t addr, int nbytes, int chan) 407 { 408 409 /* copy bounce buffer on read */ 410 /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/ 411 if (bounced[chan]) { 412 bcopy(dma_bounce[chan], addr, nbytes); 413 bounced[chan] = 0; 414 } 415 } 416 417 /* 418 * Check for problems with the address range of a DMA transfer 419 * (non-contiguous physical pages, outside of bus address space, 420 * crossing DMA page boundaries). 421 * Return true if special handling needed. 422 */ 423 424 int 425 isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) { 426 vm_offset_t phys, priorpage = 0, endva; 427 u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); 428 429 endva = (vm_offset_t)round_page(va + length); 430 for (; va < (caddr_t) endva ; va += NBPG) { 431 phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va)); 432 #define ISARAM_END RAM_END 433 if (phys == 0) 434 panic("isa_dmacheck: no physical page present"); 435 if (phys > ISARAM_END) 436 return (1); 437 if (priorpage) { 438 if (priorpage + NBPG != phys) 439 return (1); 440 /* check if crossing a DMA page boundary */ 441 if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk) 442 return (1); 443 } 444 priorpage = phys; 445 } 446 return (0); 447 } 448 449 /* head of queue waiting for physmem to become available */ 450 struct buf isa_physmemq; 451 452 /* blocked waiting for resource to become free for exclusive use */ 453 static isaphysmemflag; 454 /* if waited for and call requested when free (B_CALL) */ 455 static void (*isaphysmemunblock)(); /* needs to be a list */ 456 457 /* 458 * Allocate contiguous physical memory for transfer, returning 459 * a *virtual* address to region. May block waiting for resource. 460 * (assumed to be called at splbio()) 461 */ 462 caddr_t 463 isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) { 464 465 isaphysmemunblock = func; 466 while (isaphysmemflag & B_BUSY) { 467 isaphysmemflag |= B_WANTED; 468 sleep((caddr_t)&isaphysmemflag, PRIBIO); 469 } 470 isaphysmemflag |= B_BUSY; 471 472 return((caddr_t)isaphysmem); 473 } 474 475 /* 476 * Free contiguous physical memory used for transfer. 477 * (assumed to be called at splbio()) 478 */ 479 void 480 isa_freephysmem(caddr_t va, unsigned length) { 481 482 isaphysmemflag &= ~B_BUSY; 483 if (isaphysmemflag & B_WANTED) { 484 isaphysmemflag &= B_WANTED; 485 wakeup((caddr_t)&isaphysmemflag); 486 if (isaphysmemunblock) 487 (*isaphysmemunblock)(); 488 } 489 } 490 491 /* 492 * Handle a NMI, possibly a machine check. 493 * return true to panic system, false to ignore. 494 */ 495 int 496 isa_nmi(cd) { 497 498 log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70)); 499 return(0); 500 } 501 502 /* 503 * Caught a stray interrupt, notify 504 */ 505 void 506 isa_strayintr(d) { 507 508 /* DON'T BOTHER FOR NOW! */ 509 /* for some reason, we get bursts of intr #7, even if not enabled! */ 510 /* 511 * Well the reason you got bursts of intr #7 is because someone 512 * raised an interrupt line and dropped it before the 8259 could 513 * prioritize it. This is documented in the intel data book. This 514 * means you have BAD hardware! I have changed this so that only 515 * the first 5 get logged, then it quits logging them, and puts 516 * out a special message. rgrimes 3/25/1993 517 */ 518 extern u_long intrcnt_stray; 519 520 intrcnt_stray++; 521 if (intrcnt_stray <= 5) 522 log(LOG_ERR,"ISA strayintr %x\n", d); 523 if (intrcnt_stray == 5) 524 log(LOG_CRIT,"Too many ISA strayintr not logging any more\n"); 525 } 526 527 /* 528 * Wait "n" microseconds. 529 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at 530 * (1 * TIMER_FREQ) Hz. 531 * Note: timer had better have been programmed before this is first used! 532 * (Note that we use `rate generator' mode, which counts at 1:1; `square 533 * wave' mode counts at 2:1). 534 */ 535 #define CF (1 * TIMER_FREQ) 536 537 extern int hz; /* XXX - should be elsewhere */ 538 539 void 540 DELAY(n) 541 int n; 542 { 543 int counter_limit; 544 int prev_tick; 545 int tick; 546 int ticks_left; 547 int sec; 548 int usec; 549 550 #ifdef DELAYDEBUG 551 int gettick_calls = 1; 552 int n1; 553 static int state = 0; 554 555 if (state == 0) { 556 state = 1; 557 for (n1 = 1; n1 <= 10000000; n1 *= 10) 558 DELAY(n1); 559 state = 2; 560 } 561 if (state == 1) 562 printf("DELAY(%d)...", n); 563 #endif 564 565 /* 566 * Read the counter first, so that the rest of the setup overhead is 567 * counted. Guess the initial overhead is 20 usec (on most systems it 568 * takes about 1.5 usec for each of the i/o's in gettick(). The loop 569 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The 570 * multiplications and divisions to scale the count take a while). 571 */ 572 prev_tick = gettick(); 573 n -= 20; 574 575 /* 576 * Calculate (n * (CF / 1e6)) without using floating point and without 577 * any avoidable overflows. 578 */ 579 sec = n / 1000000; 580 usec = n - sec * 1000000; 581 ticks_left = sec * CF 582 + usec * (CF / 1000000) 583 + usec * ((CF % 1000000) / 1000) / 1000 584 + usec * (CF % 1000) / 1000000; 585 586 counter_limit = TIMER_FREQ / hz; 587 while (ticks_left > 0) { 588 tick = gettick(); 589 #ifdef DELAYDEBUG 590 ++gettick_calls; 591 #endif 592 if (tick > prev_tick) 593 ticks_left -= prev_tick - (tick - counter_limit); 594 else 595 ticks_left -= prev_tick - tick; 596 prev_tick = tick; 597 } 598 #ifdef DELAYDEBUG 599 if (state == 1) 600 printf(" %d calls to gettick() at %d usec each\n", 601 gettick_calls, (n + 5) / gettick_calls); 602 #endif 603 } 604 605 int 606 gettick() { 607 int high; 608 int low; 609 610 /* 611 * Protect ourself against interrupts. 612 */ 613 disable_intr(); 614 /* 615 * Latch the count for 'timer' (cc00xxxx, c = counter, x = any). 616 */ 617 outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 618 low = inb(TIMER_CNTR0); 619 high = inb(TIMER_CNTR0); 620 enable_intr(); 621 return ((high << 8) | low); 622 } 623 624 static beeping; 625 static void 626 sysbeepstop(int f) 627 { 628 int s = splhigh(); 629 630 /* disable counter 2 */ 631 disable_intr(); 632 outb(0x61, inb(0x61) & 0xFC); 633 enable_intr(); 634 if (f) 635 timeout((timeout_t)sysbeepstop, (caddr_t)0, f); 636 else 637 beeping = 0; 638 639 splx(s); 640 } 641 642 void 643 sysbeep(int pitch, int period) 644 { 645 int s = splhigh(); 646 static int last_pitch, last_period; 647 648 if (beeping) { 649 untimeout((timeout_t)sysbeepstop, (caddr_t)(last_period/2)); 650 untimeout((timeout_t)sysbeepstop, (caddr_t)0); 651 } 652 if (!beeping || last_pitch != pitch) { 653 /* 654 * XXX - move timer stuff to clock.c. 655 */ 656 disable_intr(); 657 outb(TIMER_MODE, TIMER_SEL2|TIMER_16BIT|TIMER_SQWAVE); 658 outb(TIMER_CNTR2, TIMER_DIV(pitch)%256); 659 outb(TIMER_CNTR2, TIMER_DIV(pitch)/256); 660 outb(0x61, inb(0x61) | 3); /* enable counter 2 */ 661 enable_intr(); 662 } 663 last_pitch = pitch; 664 beeping = last_period = period; 665 timeout((timeout_t)sysbeepstop, (caddr_t)(period/2), period); 666 667 splx(s); 668 } 669 670 /* 671 * Pass command to keyboard controller (8042) 672 */ 673 unsigned 674 kbc_8042cmd(int val) 675 { 676 while (inb(KBSTATP)&KBS_IBF); 677 if (val) outb(KBCMDP, val); 678 while (inb(KBSTATP)&KBS_IBF); 679 return (inb(KBDATAP)); 680 } 681 682 /* 683 * Return nonzero if a (masked) irq is pending for a given device. 684 */ 685 int 686 isa_irq_pending(dvp) 687 struct isa_device *dvp; 688 { 689 unsigned id_irq; 690 691 id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */ 692 if (id_irq & 0xff) 693 return (inb(IO_ICU1) & id_irq); 694 return (inb(IO_ICU2) & (id_irq >> 8)); 695 } 696