|
|
1.1 ! root 1: #include "u.h" ! 2: #include "../port/lib.h" ! 3: #include "mem.h" ! 4: #include "dat.h" ! 5: #include "fns.h" ! 6: ! 7: /* ! 8: * headland chip set for the safari. ! 9: */ ! 10: typedef struct DMAport DMAport; ! 11: typedef struct DMA DMA; ! 12: typedef struct DMAxfer DMAxfer; ! 13: ! 14: enum ! 15: { ! 16: /* ! 17: * the byte registers for DMA0 are all one byte apart ! 18: */ ! 19: Dma0= 0x00, ! 20: Dma0status= Dma0+0x8, /* status port */ ! 21: Dma0reset= Dma0+0xD, /* reset port */ ! 22: ! 23: /* ! 24: * the byte registers for DMA1 are all two bytes apart (why?) ! 25: */ ! 26: Dma1= 0xC0, ! 27: Dma1status= Dma1+2*0x8, /* status port */ ! 28: Dma1reset= Dma1+2*0xD, /* reset port */ ! 29: }; ! 30: ! 31: /* ! 32: * state of a dma transfer ! 33: */ ! 34: struct DMAxfer ! 35: { ! 36: Page pg; /* page used by dma */ ! 37: void *va; /* virtual address destination/src */ ! 38: long len; /* bytes to be transferred */ ! 39: int isread; ! 40: }; ! 41: ! 42: /* ! 43: * the dma controllers. the first half of this structure specifies ! 44: * the I/O ports used by the DMA controllers. ! 45: */ ! 46: struct DMAport ! 47: { ! 48: uchar addr[4]; /* current address (4 channels) */ ! 49: uchar count[4]; /* current count (4 channels) */ ! 50: uchar page[4]; /* page registers (4 channels) */ ! 51: uchar cmd; /* command status register */ ! 52: uchar req; /* request registers */ ! 53: uchar sbm; /* single bit mask register */ ! 54: uchar mode; /* mode register */ ! 55: uchar cbp; /* clear byte pointer */ ! 56: uchar mc; /* master clear */ ! 57: uchar cmask; /* clear mask register */ ! 58: uchar wam; /* write all mask register bit */ ! 59: }; ! 60: ! 61: struct DMA ! 62: { ! 63: DMAport; ! 64: int shift; ! 65: Lock; ! 66: DMAxfer x[4]; ! 67: }; ! 68: ! 69: DMA dma[2] = { ! 70: { 0x00, 0x02, 0x04, 0x06, ! 71: 0x01, 0x03, 0x05, 0x07, ! 72: 0x87, 0x83, 0x81, 0x82, ! 73: 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ! 74: 0 }, ! 75: ! 76: { 0xc0, 0xc4, 0xc8, 0xcc, ! 77: 0xc2, 0xc6, 0xca, 0xce, ! 78: 0x8f, 0x8b, 0x89, 0x8a, ! 79: 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, ! 80: 1 }, ! 81: }; ! 82: ! 83: /* ! 84: * DMA must be in the first 16 meg. This gets called early by main() to ! 85: * ensure that. ! 86: */ ! 87: void ! 88: dmainit(void) ! 89: { ! 90: int i, chan; ! 91: DMA *dp; ! 92: DMAxfer *xp; ! 93: ! 94: for(i = 0; i < 2; i++){ ! 95: dp = &dma[i]; ! 96: for(chan = 0; chan < 4; chan++){ ! 97: xp = &dp->x[chan]; ! 98: xp->pg.pa = (ulong)xspanalloc(BY2PG, BY2PG, 0); ! 99: xp->pg.va = KZERO|xp->pg.pa; ! 100: xp->len = 0; ! 101: xp->isread = 0; ! 102: } ! 103: } ! 104: } ! 105: ! 106: /* ! 107: * setup a dma transfer. if the destination is not in kernel ! 108: * memory, allocate a page for the transfer. ! 109: * ! 110: * we assume BIOS has set up the command register before we ! 111: * are booted. ! 112: * ! 113: * return the updated transfer length (we can't transfer across 64k ! 114: * boundaries) ! 115: */ ! 116: long ! 117: dmasetup(int chan, void *va, long len, int isread) ! 118: { ! 119: DMA *dp; ! 120: DMAxfer *xp; ! 121: ulong pa; ! 122: uchar mode; ! 123: ! 124: dp = &dma[(chan>>2)&1]; ! 125: chan = chan & 3; ! 126: xp = &dp->x[chan]; ! 127: ! 128: /* ! 129: * if this isn't kernel memory or crossing 64k boundary or above 16 meg ! 130: * use the allocated low memory page. ! 131: */ ! 132: pa = PADDR(va); ! 133: if((((ulong)va)&0xF0000000) != KZERO ! 134: || (pa&0xFFFF0000) != ((pa+len)&0xFFFF0000) ! 135: || pa > 16*MB){ ! 136: if(len > BY2PG) ! 137: len = BY2PG; ! 138: if(!isread) ! 139: memmove((void*)(xp->pg.va), va, len); ! 140: xp->va = va; ! 141: xp->len = len; ! 142: xp->isread = isread; ! 143: pa = xp->pg.pa; ! 144: } else ! 145: xp->len = 0; ! 146: ! 147: /* ! 148: * this setup must be atomic ! 149: */ ! 150: ilock(dp); ! 151: mode = (isread ? 0x44 : 0x48) | chan; ! 152: outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */ ! 153: outb(dp->page[chan], pa>>16); ! 154: outb(dp->cbp, 0); /* set count & address to their first byte */ ! 155: outb(dp->addr[chan], pa>>dp->shift); /* set address */ ! 156: outb(dp->addr[chan], pa>>(8+dp->shift)); ! 157: outb(dp->count[chan], (len>>dp->shift)-1); /* set count */ ! 158: outb(dp->count[chan], ((len>>dp->shift)-1)>>8); ! 159: outb(dp->sbm, chan); /* enable the channel */ ! 160: iunlock(dp); ! 161: ! 162: return len; ! 163: } ! 164: ! 165: /* ! 166: * this must be called after a dma has been completed. ! 167: * ! 168: * if a page has been allocated for the dma, ! 169: * copy the data into the actual destination ! 170: * and free the page. ! 171: */ ! 172: void ! 173: dmaend(int chan) ! 174: { ! 175: DMA *dp; ! 176: DMAxfer *xp; ! 177: ! 178: dp = &dma[(chan>>2)&1]; ! 179: chan = chan & 3; ! 180: ! 181: /* ! 182: * disable the channel ! 183: */ ! 184: ilock(dp); ! 185: outb(dp->sbm, 4|chan); ! 186: iunlock(dp); ! 187: ! 188: xp = &dp->x[chan]; ! 189: if(xp->len == 0 || !xp->isread) ! 190: return; ! 191: ! 192: /* ! 193: * copy out of temporary page ! 194: */ ! 195: memmove(xp->va, (void*)(xp->pg.va), xp->len); ! 196: xp->len = 0; ! 197: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.