#include "sys/param.h" #include "sys/buf.h" #include "sys/dir.h" #include "sys/user.h" #include "sys/tty.h" #include "sys/uba.h" struct device *dmc_addr[]; struct device { union { char b[8]; short w[4]; } un; }; #define bsel0 un.b[0] #define bsel1 un.b[1] #define bsel2 un.b[2] #define bsel3 un.b[3] #define bsel4 un.b[4] #define bsel5 un.b[5] #define bsel6 un.b[6] #define bsel7 un.b[7] #define sel0 un.w[0] #define sel2 un.w[1] #define sel4 un.w[2] #define sel6 un.w[3] int dmc_cnt; #define RWMAX 7 #define MAXBUF 8192 /* Defines for bsel0 and bsel2. */ #define BACCI 0 #define CNTLI 1 #define BASEI 3 #define INX 0 /* transmit block */ #define INR 4 /* read block */ #define RQI 040 /* port request bit */ #define IEI 0100 /* enable input interrupts */ #define RDYI 0200 /* port ready */ #define BACCO 0 #define CNTLO 1 #define OUX 0 /* transmit block */ #define OUR 4 /* read block */ #define IEO 0100 /* enable output interrupts */ #define RDYO 0200 /* port available */ #define MCLR 0100 /* DMC11 Master Clear */ /* Defines for CNTLI mode (set into sel6). */ #define HDPLX 02000 /* half duplex DDCMP operation */ #define SEC 04000 /* half duplex secondary station */ #define MAINT 0400 /* enter maintenance mode */ /* Defines for BACCI/O and BASEI mode (set into sel6). */ #define DMXMEM 0140000 /* xmem bit position */ #define CCOUNT 037777 /* character count mask */ #define RESUME 02000 /* resume (BASEI only) */ /* Defines for CNTLO (set in sel6). */ #define FATAL 01620 struct dmc { int b_flags; struct buf *b_forw; struct buf *b_back; struct buf *av_forw; struct clist dm_que; char dm_rwq[2]; short dm_ioc[16]; struct buf dm_rbuf[2]; int dm_map[2]; short dm_base[128]; }; #define DMCOPEN 2 #define NDMC 2 struct dmc dmc11[NDMC]; dmcopen(dev) { register struct dmc *dmp; if (dev >= dmc_cnt || dev >= NDMC) { u.u_error = ENXIO; return; } dmp = &dmc11[dev]; if((dmp->b_flags&DMCOPEN) == 0) { dmp->b_flags = DMCOPEN; dmcinit(dev); dmp->dm_map[0] = ubmalloc(MAXBUF, 0); dmp->dm_map[1] = ubmalloc(MAXBUF, 0); } } dmcclose(dev) { register struct dmc *dmp; dmp = &dmc11[dev]; dmcclr(dev); ubmfree(dmp->dm_map[0]); ubmfree(dmp->dm_map[1]); dmp->b_flags &= ~DMCOPEN; } dmcinit(dev) { register struct dmc *dmp; paddr_t base; dmp = &dmc11[dev]; dmcclr(dev); dmc_addr[dev]->bsel2 |= IEO; base = ubmdata(dmp->dm_base); dmcload(dmp, BASEI, loword(base), hiword(base)<<14); dmcload(dmp, CNTLI, 0, 0); } dmcclr(dev) { int sps; register struct dmc *dmp; register struct buf *bp; sps = spl5(); dmc_addr[dev]->bsel1 = MCLR; splx(sps); dmp = &dmc11[dev]; dmp->dm_rwq[0] = dmp->dm_rwq[1] = 0; /* Mark all buffers bad. */ while(bp = dmp->av_forw) { bp->b_flags |= B_ERROR; dmp->av_forw = bp->av_forw; iodone(bp); } } dmcstrategy(bp) register struct buf *bp; { register struct dmc *dmp; register struct buf *abp; int sps; if (bp->b_bcount > MAXBUF) { bp->b_flags |= B_ERROR; iodone(bp); return; } dmp = &dmc11[minor(bp->b_dev)]; abp = (struct buf *)dmp; bp->av_forw = NULL; sps = spl5(); while (abp->av_forw) abp = abp->av_forw; abp->av_forw = bp; dmcstart(dmp, bp->b_flags&B_READ); splx(sps); } dmcstart(dmp, flag) register struct dmc *dmp; { register struct buf *bp; paddr_t addr; bp = (struct buf *)dmp; while (bp = bp->av_forw) { if ((bp->b_flags&(B_STALE|B_READ))!=flag) continue; if (dmp->dm_rwq[flag] >= RWMAX) { return; } dmp->dm_rwq[flag]++; bp->b_flags |= B_STALE; addr = ubmaddr(bp, dmp->dm_map[flag]); dmcload(dmp, flag<<2, loword(addr), (bp->b_bcount&CCOUNT)|((hiword(addr)&03)<<14)); return; } } dmcload(dmp, type, w0, w1) register struct dmc *dmp; { register struct device *kp; register dev; int sps; dev = dmp-dmc11; kp = dmc_addr[dev]; sps = spl5(); kp->bsel0 |= RQI; putc(lobyte(w0), &dmp->dm_que); putc(hibyte(w0), &dmp->dm_que); putc(lobyte(w1), &dmp->dm_que); putc(hibyte(w1), &dmp->dm_que); putc(type, &dmp->dm_que); dmcrint(dev); splx(sps); } dmcrint(dev) { register struct dmc *dmp; register struct device *kp; kp = dmc_addr[dev]; kp->bsel0 &= ~IEI; dmp = &dmc11[dev]; while (kp->bsel0&RDYI) { kp->bsel4 = getc(&dmp->dm_que); kp->bsel5 = getc(&dmp->dm_que); kp->bsel6 = getc(&dmp->dm_que); kp->bsel7 = getc(&dmp->dm_que); kp->bsel0 = getc(&dmp->dm_que)|RDYI; while (kp->bsel0&RDYI); if (dmp->dm_que.c_cc==0) return; kp->bsel0 = RQI; } if (dmp->dm_que.c_cc) kp->bsel0 |= IEI; } dmcxint(dev) { register struct device *dp; register struct dmc *dmp; register struct buf *bp, *abp; short *ip; int count, flag; dp = dmc_addr[dev]; count = dp->sel6; flag = dp->bsel2&7; dp->bsel2 &= ~RDYO; dmp = &dmc11[dev]; switch(flag) { case OUX: case OUR: bp = (struct buf *)dmp; flag >>= 2; /* * Look through the active Q for the buffer * the DMC11 says is finished. Assume the DMC11 * returns the buffers in FIFO order. */ while(abp = bp,bp = bp->av_forw) { if ((bp->b_flags&B_READ)!=flag) continue; dmp->dm_rwq[flag]--; dmp->dm_ioc[flag]++; bp->b_resid = bp->b_bcount - count&CCOUNT; abp->av_forw = bp->av_forw; iodone(bp); dmcstart(dmp, flag); return; } printf("DMC%d lost block\n", dev); return; case CNTLO: if (count&FATAL) dmcinit(dev); ip = &dmp->dm_ioc[2]; while(count) { if (count&01) (*ip)++; ip++; count >>= 1; } } } dmcread(dev) { physio(dmcstrategy,&dmc11[dev].dm_rbuf[B_READ],dev,B_READ); } dmcwrite(dev) { physio(dmcstrategy,&dmc11[dev].dm_rbuf[B_WRITE],dev,B_WRITE); }