|
|
1.1 root 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: */
1.1.1.2 root 38: static 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 $";
1.1 root 39:
40: /*
41: * code to manage AT bus
42: */
43:
44: #include "param.h"
45: #include "systm.h"
46: #include "conf.h"
47: #include "file.h"
48: #include "buf.h"
49: #include "uio.h"
50: #include "syslog.h"
1.1.1.3 ! root 51: #include "malloc.h"
! 52: #include "rlist.h"
1.1 root 53: #include "machine/segments.h"
1.1.1.3 ! root 54: #include "vm/vm.h"
1.1 root 55: #include "i386/isa/isa_device.h"
1.1.1.3 ! root 56: #include "i386/isa/isa.h"
1.1 root 57: #include "i386/isa/icu.h"
1.1.1.3 ! root 58: #include "i386/isa/ic/i8237.h"
! 59: #include "i386/isa/ic/i8042.h"
1.1 root 60:
1.1.1.3 ! root 61: int config_isadev(struct isa_device *, u_short *);
! 62: #ifdef notyet
! 63: struct rlist *isa_iomem;
! 64:
! 65: /*
! 66: * Configure all ISA devices
! 67: */
! 68: isa_configure() {
! 69: struct isa_device *dvp;
! 70: struct isa_driver *dp;
! 71:
! 72: splhigh();
! 73: INTREN(IRQ_SLAVE);
! 74: /*rlist_free(&isa_iomem, 0xa0000, 0xfffff);*/
! 75: for (dvp = isa_devtab_tty; dvp; dvp++)
! 76: (void) config_isadev(dvp, &ttymask);
! 77: for (dvp = isa_devtab_bio; dvp; dvp++)
! 78: (void) config_isadev(dvp, &biomask);
! 79: for (dvp = isa_devtab_net; dvp; dvp++)
! 80: (void) config_isadev(dvp, &netmask);
! 81: for (dvp = isa_devtab_null; dvp; dvp++)
! 82: (void) config_isadev(dvp, 0);
! 83: #include "sl.h"
! 84: #if NSL > 0
! 85: netmask |= ttymask;
! 86: ttymask |= netmask;
! 87: #endif
! 88: /* printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); */
! 89: splnone();
! 90: }
! 91:
! 92: /*
! 93: * Configure an ISA device.
! 94: */
! 95: config_isadev(isdp, mp)
! 96: struct isa_device *isdp;
! 97: u_short *mp;
! 98: {
! 99: struct isa_driver *dp;
! 100: static short drqseen, irqseen;
! 101:
! 102: if (dp = isdp->id_driver) {
! 103: /* if a device with i/o memory, convert to virtual address */
! 104: if (isdp->id_maddr) {
! 105: extern unsigned int atdevbase;
! 106:
! 107: isdp->id_maddr -= IOM_BEGIN;
! 108: isdp->id_maddr += atdevbase;
! 109: }
! 110: isdp->id_alive = (*dp->probe)(isdp);
! 111: if (isdp->id_alive) {
! 112:
! 113: printf("%s%d at port 0x%x ", dp->name,
! 114: isdp->id_unit, isdp->id_iobase);
! 115:
! 116: /* check for conflicts */
! 117: if (irqseen & isdp->id_irq) {
! 118: printf("INTERRUPT CONFLICT - irq%d\n",
! 119: ffs(isdp->id_irq) - 1);
! 120: return (0);
! 121: }
! 122: if (isdp->id_drq != -1
! 123: && (drqseen & (1<<isdp->id_drq))) {
! 124: printf("DMA CONFLICT - drq%d\n", isdp->id_drq);
! 125: return (0);
! 126: }
! 127: /* NEED TO CHECK IOMEM CONFLICT HERE */
! 128:
! 129: /* allocate and wire in device */
! 130: if(isdp->id_irq) {
! 131: int intrno;
! 132:
! 133: intrno = ffs(isdp->id_irq)-1;
! 134: printf("irq %d ", intrno);
! 135: INTREN(isdp->id_irq);
! 136: if(mp)INTRMASK(*mp,isdp->id_irq);
! 137: setidt(NRSVIDT + intrno, isdp->id_intr,
! 138: SDT_SYS386IGT, SEL_KPL);
! 139: irqseen |= isdp->id_irq;
! 140: }
! 141: if (isdp->id_drq != -1) {
! 142: printf("drq %d ", isdp->id_drq);
! 143: drqseen |= 1 << isdp->id_drq;
! 144: }
! 145:
! 146: (*dp->attach)(isdp);
! 147:
! 148: printf("on isa\n");
! 149: }
! 150: return (1);
! 151: } else return(0);
! 152: }
! 153: #else
1.1 root 154: /*
155: * Configure all ISA devices
156: */
157: isa_configure() {
158: struct isa_device *dvp;
159: struct isa_driver *dp;
160:
161: splhigh();
162: INTREN(IRQ_SLAVE);
163: for (dvp = isa_devtab_tty; config_isadev(dvp,&ttymask); dvp++);
1.1.1.2 root 164: for (dvp = isa_devtab_bio; config_isadev(dvp,&biomask); dvp++);
1.1 root 165: for (dvp = isa_devtab_net; config_isadev(dvp,&netmask); dvp++);
166: for (dvp = isa_devtab_null; config_isadev(dvp,0); dvp++);
167: #include "sl.h"
168: #if NSL > 0
169: netmask |= ttymask;
170: ttymask |= netmask;
171: #endif
172: /* biomask |= ttymask ; can some tty devices use buffers? */
1.1.1.3 ! root 173: /* printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); */
1.1 root 174: splnone();
175: }
176:
177: /*
178: * Configure an ISA device.
179: */
180: config_isadev(isdp, mp)
181: struct isa_device *isdp;
1.1.1.3 ! root 182: u_short *mp;
1.1 root 183: {
184: struct isa_driver *dp;
185:
186: if (dp = isdp->id_driver) {
187: if (isdp->id_maddr) {
1.1.1.3 ! root 188: extern u_int atdevbase;
1.1 root 189:
190: isdp->id_maddr -= 0xa0000;
191: isdp->id_maddr += atdevbase;
192: }
193: isdp->id_alive = (*dp->probe)(isdp);
194: if (isdp->id_alive) {
195: printf("%s%d", dp->name, isdp->id_unit);
196: (*dp->attach)(isdp);
197: printf(" at 0x%x ", isdp->id_iobase);
198: if(isdp->id_irq) {
199: int intrno;
200:
201: intrno = ffs(isdp->id_irq)-1;
202: printf("irq %d ", intrno);
203: INTREN(isdp->id_irq);
204: if(mp)INTRMASK(*mp,isdp->id_irq);
205: setidt(ICU_OFFSET+intrno, isdp->id_intr,
206: SDT_SYS386IGT, SEL_KPL);
207: }
208: if (isdp->id_drq != -1) printf("drq %d ", isdp->id_drq);
209: printf("on isa\n");
210: }
211: return (1);
212: } else return(0);
213: }
1.1.1.3 ! root 214: #endif
1.1 root 215:
216: #define IDTVEC(name) __CONCAT(X,name)
1.1.1.3 ! root 217: /* default interrupt vector table entries */
1.1 root 218: extern IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
219: IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
220: IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
221: IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
1.1.1.3 ! root 222:
! 223: static *defvec[16] = {
! 224: &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
! 225: &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
! 226: &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
! 227: &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
! 228:
! 229: /* out of range default interrupt vector gate entry */
! 230: extern IDTVEC(intrdefault);
1.1 root 231:
232: /*
233: * Fill in default interrupt table (in case of spuruious interrupt
234: * during configuration of kernel, setup interrupt control unit
235: */
236: isa_defaultirq() {
1.1.1.3 ! root 237: int i;
1.1 root 238:
1.1.1.3 ! root 239: /* icu vectors */
! 240: for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++)
! 241: setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL);
1.1 root 242:
1.1.1.3 ! root 243: /* out of range vectors */
! 244: for (i = NRSVIDT; i < NIDT; i++)
! 245: setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL);
! 246:
! 247: /* clear npx intr latch */
1.1 root 248: outb(0xf1,0);
1.1.1.3 ! root 249:
! 250: /* initialize 8259's */
! 251: outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
! 252: outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
! 253: outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
! 254: outb(IO_ICU1+1, 1); /* 8086 mode */
! 255: outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
! 256: outb(IO_ICU1, 2); /* default to ISR on read */
! 257:
! 258: outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
! 259: outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
! 260: outb(IO_ICU2+1,2); /* my slave id is 2 */
! 261: outb(IO_ICU2+1,1); /* 8086 mode */
! 262: outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
! 263: outb(IO_ICU2, 2); /* default to ISR on read */
1.1 root 264: }
265:
1.1.1.3 ! root 266: /* region of physical memory known to be contiguous */
! 267: vm_offset_t isaphysmem;
! 268: static caddr_t dma_bounce[8]; /* XXX */
! 269: static char bounced[8]; /* XXX */
! 270: #define MAXDMASZ 512 /* XXX */
! 271:
! 272: /* high byte of address is stored in this port for i-th dma channel */
! 273: static short dmapageport[8] =
! 274: { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
1.1 root 275:
1.1.1.3 ! root 276: /*
! 277: * isa_dmacascade(): program 8237 DMA controller channel to accept
! 278: * external dma control by a board.
! 279: */
! 280: void isa_dmacascade(unsigned chan)
! 281: { int modeport;
! 282:
! 283: if (chan > 7)
! 284: panic("isa_dmacascade: impossible request");
1.1 root 285:
1.1.1.3 ! root 286: /* set dma channel mode, and set dma channel mode */
! 287: if ((chan & 4) == 0)
! 288: modeport = IO_DMA1 + 0xb;
! 289: else
! 290: modeport = IO_DMA2 + 0x16;
! 291: outb(modeport, DMA37MD_CASCADE | (chan & 3));
! 292: if ((chan & 4) == 0)
! 293: outb(modeport - 1, chan & 3);
! 294: else
! 295: outb(modeport - 2, chan & 3);
! 296: }
1.1 root 297:
1.1.1.3 ! root 298: /*
! 299: * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
! 300: * problems by using a bounce buffer.
! 301: */
! 302: void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
! 303: { vm_offset_t phys;
! 304: int modeport, waport, mskport;
! 305: caddr_t newaddr;
! 306:
! 307: if (chan > 7 || nbytes > (1<<16))
! 308: panic("isa_dmastart: impossible request");
! 309:
! 310: if (isa_dmarangecheck(addr, nbytes)) {
1.1 root 311: if (dma_bounce[chan] == 0)
1.1.1.3 ! root 312: dma_bounce[chan] =
! 313: /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
! 314: (caddr_t) isaphysmem + NBPG*chan;
! 315: bounced[chan] = 1;
! 316: newaddr = dma_bounce[chan];
! 317: *(int *) newaddr = 0; /* XXX */
! 318:
! 319: /* copy bounce buffer on write */
! 320: if (!(flags & B_READ))
! 321: bcopy(addr, newaddr, nbytes);
! 322: addr = newaddr;
1.1 root 323: }
324:
1.1.1.3 ! root 325: /* translate to physical */
! 326: phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
1.1 root 327:
1.1.1.3 ! root 328: /* set dma channel mode, and reset address ff */
! 329: if ((chan & 4) == 0)
! 330: modeport = IO_DMA1 + 0xb;
! 331: else
! 332: modeport = IO_DMA2 + 0x16;
! 333: if (flags & B_READ)
! 334: outb(modeport, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
! 335: else
! 336: outb(modeport, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
! 337: if ((chan & 4) == 0)
! 338: outb(modeport + 1, 0);
! 339: else
! 340: outb(modeport + 2, 0);
! 341:
! 342: /* send start address */
! 343: if ((chan & 4) == 0) {
! 344: waport = IO_DMA1 + (chan<<1);
! 345: outb(waport, phys);
! 346: outb(waport, phys>>8);
1.1 root 347: } else {
1.1.1.3 ! root 348: waport = IO_DMA2 + ((chan - 4)<<2);
! 349: outb(waport, phys>>1);
! 350: outb(waport, phys>>9);
1.1 root 351: }
1.1.1.3 ! root 352: outb(dmapageport[chan], phys>>16);
! 353:
! 354: /* send count */
! 355: if ((chan & 4) == 0) {
! 356: outb(waport + 1, --nbytes);
! 357: outb(waport + 1, nbytes>>8);
! 358: } else {
! 359: nbytes <<= 1;
! 360: outb(waport + 2, --nbytes);
! 361: outb(waport + 2, nbytes>>8);
! 362: }
! 363:
! 364: /* unmask channel */
! 365: if ((chan & 4) == 0)
! 366: mskport = IO_DMA1 + 0x0a;
! 367: else
! 368: mskport = IO_DMA2 + 0x14;
! 369: outb(mskport, chan & 3);
! 370: }
! 371:
! 372: void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
! 373: {
! 374:
! 375: /* copy bounce buffer on read */
! 376: /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/
! 377: if (bounced[chan]) {
! 378: bcopy(dma_bounce[chan], addr, nbytes);
! 379: bounced[chan] = 0;
! 380: }
! 381: }
! 382:
! 383: /*
! 384: * Check for problems with the address range of a DMA transfer
! 385: * (non-contiguous physical pages, outside of bus address space).
! 386: * Return true if special handling needed.
! 387: */
! 388:
! 389: isa_dmarangecheck(caddr_t va, unsigned length) {
! 390: vm_offset_t phys, priorpage, endva;
! 391:
! 392: endva = (vm_offset_t)round_page(va + length);
! 393: for (; va < (caddr_t) endva ; va += NBPG) {
! 394: phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
! 395: #define ISARAM_END RAM_END
! 396: if (phys == 0)
! 397: panic("isa_dmacheck: no physical page present");
! 398: if (phys > ISARAM_END)
! 399: return (1);
! 400: if (priorpage && priorpage + NBPG != phys)
! 401: return (1);
! 402: priorpage = phys;
! 403: }
! 404: return (0);
! 405: }
! 406:
! 407: /* head of queue waiting for physmem to become available */
! 408: struct buf isa_physmemq;
! 409:
! 410: /* blocked waiting for resource to become free for exclusive use */
! 411: static isaphysmemflag;
! 412: /* if waited for and call requested when free (B_CALL) */
! 413: static void (*isaphysmemunblock)(); /* needs to be a list */
! 414:
! 415: /*
! 416: * Allocate contiguous physical memory for transfer, returning
! 417: * a *virtual* address to region. May block waiting for resource.
! 418: * (assumed to be called at splbio())
! 419: */
! 420: caddr_t
! 421: isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
! 422:
! 423: isaphysmemunblock = func;
! 424: while (isaphysmemflag & B_BUSY) {
! 425: isaphysmemflag |= B_WANTED;
! 426: sleep(&isaphysmemflag, PRIBIO);
! 427: }
! 428: isaphysmemflag |= B_BUSY;
! 429:
! 430: return((caddr_t)isaphysmem);
1.1 root 431: }
432:
433: /*
1.1.1.3 ! root 434: * Free contiguous physical memory used for transfer.
! 435: * (assumed to be called at splbio())
! 436: */
! 437: void
! 438: isa_freephysmem(caddr_t va, unsigned length) {
! 439:
! 440: isaphysmemflag &= ~B_BUSY;
! 441: if (isaphysmemflag & B_WANTED) {
! 442: isaphysmemflag &= B_WANTED;
! 443: wakeup(&isaphysmemflag);
! 444: if (isaphysmemunblock)
! 445: (*isaphysmemunblock)();
! 446: }
! 447: }
! 448:
! 449: /*
1.1 root 450: * Handle a NMI, possibly a machine check.
451: * return true to panic system, false to ignore.
452: */
453: isa_nmi(cd) {
454:
455: log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
456: return(0);
457: }
458:
459: /*
460: * Caught a stray interrupt, notify
461: */
462: isa_strayintr(d) {
463:
1.1.1.3 ! root 464: #ifdef notdef
! 465: /* DON'T BOTHER FOR NOW! */
1.1 root 466: /* for some reason, we get bursts of intr #7, even if not enabled! */
1.1.1.3 ! root 467: log(LOG_ERR,"ISA strayintr %x", d);
! 468: #endif
! 469: }
! 470:
! 471: /*
! 472: * Wait "n" microseconds. Relies on timer 0 to have 1Mhz clock, regardless
! 473: * of processor board speed. Note: timer had better have been programmed
! 474: * before this is first used!
! 475: */
! 476: DELAY(n) {
! 477: int tick = getit(0,0) & 1;
! 478:
! 479: while (n--) {
! 480: /* wait approximately 1 micro second */
! 481: while (tick == getit(0,0) & 1) ;
! 482:
! 483: tick = getit(0,0) & 1;
! 484: }
! 485: }
! 486:
! 487: getit(unit, timer) {
! 488: int port = (unit ? IO_TIMER2 : IO_TIMER1) + timer, val;
! 489:
! 490: val = inb(port);
! 491: val = (inb(port) << 8) + val;
! 492: return (val);
! 493: }
! 494:
! 495: extern int hz;
! 496:
! 497: static beeping;
! 498: static
! 499: sysbeepstop(f)
! 500: {
! 501: /* disable counter 2 */
! 502: outb(0x61, inb(0x61) & 0xFC);
! 503: if (f)
! 504: timeout(sysbeepstop, 0, f);
! 505: else
! 506: beeping = 0;
! 507: }
! 508:
! 509: void sysbeep(int pitch, int period)
! 510: {
! 511:
! 512: outb(0x61, inb(0x61) | 3); /* enable counter 2 */
! 513: outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */
! 514:
! 515: outb(0x42, pitch);
! 516: outb(0x42, (pitch>>8));
! 517:
! 518: if (!beeping) {
! 519: beeping = period;
! 520: timeout(sysbeepstop, period/2, period);
! 521: }
! 522: }
! 523:
! 524: /*
! 525: * Pass command to keyboard controller (8042)
! 526: */
! 527: unsigned kbc_8042cmd(val) {
! 528:
! 529: while (inb(KBSTATP)&KBS_IBF);
! 530: if (val) outb(KBCMDP, val);
! 531: while (inb(KBSTATP)&KBS_IBF);
! 532: return (inb(KBDATAP));
1.1 root 533: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.