#include "sys/param.h" #include "sys/biaddr.h" #include "sys/conf.h" #include "sys/user.h" #include "sys/buf.h" #include "sys/pte.h" extern caddr_t bitest[]; extern struct biaddr bitstaddr[]; extern int bitstcnt; static bitstopen(); static bitstread(), bitstwrite(); struct cdevsw bitstcdev = cdinit(bitstopen, nulldev, bitstread, bitstwrite, nodev); char biscratch[4096]; /* * BVP data structures */ typedef struct quadque { struct quadque *head, *tail; } quadque; struct pqb { quadque p_cmdq[4]; /* command queues */ quadque p_rspq; /* response queue */ short p_vector; /* interrupt vector, BR */ short p_nodmsk; /* interrupt node mask */ long p_nfreeq; /* number of free queues */ struct fqb *p_fqb; /* fqp virtual address */ char pp_junk0[156]; long p_bvplvl; /* BVP protocol version */ struct pqb *p_pqb; /* pqb virtual self-pointer */ struct bdt *p_bdt; /* bdt virtual address */ long p_bdtlen; /* and size */ struct pte *p_spt; /* system page table phys addr */ long p_sptlen; /* and size */ struct pte *p_gpt; /* global page pable phys addr */ long p_gptlen; /* and size */ long p_funcmask; /* ?? */ char pp_junk1[24]; /* stuff filled in by port after init */ short p_maxdg; /* max datagram size */ short p_maxmsg; /* max message size */ long p_ucodetype; long p_ucodevers; long p_hwtype; long p_vers[3]; char p_qelogo[216]; /* `queue entry logout area' */ }; /* * free queue block */ struct fqb { long f_size; /* max size of things in this queue */ long f_junk; /* reserved, apparently */ quadque f_q; /* the free queue itself */ }; #define NFREEQ 1 /* * buffer descriptor */ struct bdt { short b_flags; short b_key; long b_len; /* length of buffer */ struct pte *b_pte; /* relevant page table */ long b_sw; /* reserved for software */ }; #define NBDT 1 /* * bundle of data for one port * the pqb must be page-aligned; * stick this in a buffer, * which means it must all fit in one */ struct bvpdata { struct pqb p; struct fqb f[NFREEQ]; struct bdt b[NBDT]; }; /* * port registers */ struct regs { long ctrl; long stat; long err; long data; }; /* * control bits */ #define PCOWN 0x80 /* port own -- here is a command */ #define PCINIT 1 #define PCENAB 2 #define PCCMDQ 6 /* command queue not empty */ #define PCFREQ 7 /* free queue not empty */ /* * status bits */ #define PSOWN 0x80000000 /* port own -- status valid */ #define PSSTD 0x20000000 /* self test done */ #define PSACC 0x10000000 /* adapter can communicate */ #define PSSTAT 0x70000 /* port state: */ #define SUNDEF 0x10000 /* undefined */ #define SINIT 0x20000 /* initialized */ #define SENAB 0x40000 /* enabled */ #define PSERR 0x40 /* error summary */ /* * to a header later */ struct bvp { struct bvpdata *d; struct regs *r; struct buf *dbuf; }; char *bitsnd, *bitrcv; /* places to put packets */ struct bvp bvp; static bitstopen(dev, flag) int dev, flag; { if (minor(dev)) { u.u_error = ENXIO; return; } if (bitest[0] == 0) { /* wrong */ if ((bitest[0] = biaddr(&bitstaddr[0])) == 0 || badaddr(bitest[0], sizeof(long))) { printf("bitest absent\n"); u.u_error = ENXIO; return; } bvp.r = (struct regs *)(bitest[0] + 0x204); /* cheat */ bitsnd = biscratch+7; bitrcv = bitsnd + 2048; bitsnd -= (long)bitsnd & 07; /* quad align */ bitrcv -= (long)bitrcv & 07; } if (bvpinit(&bvp) == 0) { u.u_error = ENXIO; return; } } /* * read routine: * nab a packet */ static bitstread(dev) { register struct bvpdata *b; b = bvp.d; b->f[0].f_size = 2048; if (insqti(bitrcv, &b->p.p_fqb[0].f_q)) bvpcomm(bvp.r, PCOWN|PCFREQ); /* let someone else wait for now */ } /* * write routine: * send a packet */ static bitstwrite(dev) { register struct bvpdata *b; b = bvp.d; if (insqti(bitsnd, &b->p.p_cmdq[0])) bvpcomm(bvp.r, PCOWN|PCCMDQ); } bvpinit(bv) register struct bvp *bv; { register struct bvpdata *b; register struct regs *r; if (bv->dbuf == NULL) { bv->dbuf = geteblk(); if (bv->dbuf->b_bcount < sizeof(struct bvpdata)) { printf("bcount too small\n"); brelse(bv->dbuf); return (0); } clrbuf(bv->dbuf); bv->d = (struct bvpdata *)bv->dbuf->b_un.b_addr; } r = bv->r; if ((r->stat & PSSTAT) == SUNDEF) { bvpdatinit(bv->d); bvpcomm(r, physadr(&bv->d->p)|PCOWN|PCINIT); bvpstat(r); } if ((r->stat & PSSTAT) == SINIT) { bvpcomm(r, PCOWN|PCENAB); bvpstat(r); } if ((r->stat & PSSTAT) != SENAB) { printf("ps %x pe %x pd %x\n", r->stat, r->err, r->data); return (0); } return (1); } bvpdatinit(b) register struct bvpdata *b; { /* * just enough to make hardware happy */ b->p.p_nfreeq = NFREEQ; b->p.p_fqb = b->f; b->p.p_bvplvl = 1; b->p.p_pqb = &b->p; b->p.p_bdt = b->b; b->p.p_bdtlen = NBDT; b->p.p_spt = (struct pte *)physadr(Sysmap); b->p.p_sptlen = 0x100000; /* huge */ b->p.p_gpt = b->p.p_spt; b->p.p_gptlen = b->p.p_sptlen; } /* * send a port command * need a timeout */ bvpcomm(r, c) register struct regs *r; long c; { while (r->ctrl & PCOWN) ; r->stat &=~ PSOWN; r->ctrl = c; } /* * wait for status in init * needs timeout */ long bvpstat(r) register struct regs *r; { while ((r->stat & PSOWN) == 0) ; return (r->stat); } /* * VAX queue primitives */ /* * make an empty queue */ initvq(q) register quadque *q; { q->head = q->tail = 0; } /* * remove entry from head; * return entry, or 0 if none */ caddr_t remqhi(q) quadque *q; { asm("clrl r0"); asm("0: remqhi *4(ap),r0"); asm("bcs 0b"); /* couldn't interlock; try again */ } /* * insert entry to tail * return 1 if this was the first entry */ insqti(e, q) caddr_t e; quadque *q; { asm("clrl r0"); asm("0: insqti *4(ap),*8(ap)"); asm("bcs 0b"); asm("bneq 1f"); asm("incl r0"); asm("1:"); }