#include "../chunix/chsys.h" #include "../chunix/chconf.h" #include "../chaos/chaos.h" /* * Chaos device driver for the ch11 (CHAOS-11) broadcast network * interface. */ struct chxcvr ch11xcvr[NCHCH]; #define xc_chrtries xc_info.xc_ch11.ch_rtries int chchstart(), chchreset(); #ifdef VMUNIX #include "../h/buf.h" #include "../h/ubavar.h" int chchndev; /* * Autoconfiguration support for VMUNIX */ int chchprobe(), chchattach(), chchintr(); struct uba_device *chchdinfo[NCHCH]; unsigned short chchstd[] = { 0164140, 0165140, 0166140 }; struct uba_driver chchdriver = { chchprobe, 0, chchattach, 0, chchstd, "chch", chchdinfo }; chchprobe(reg) caddr_t reg; { register int br, cvec; #ifdef lint br = 0; cvec = br; br = cvec; #endif ((struct ch11 *)reg)->ch_csr = CHTCLR; ((struct ch11 *)reg)->ch_csr = CHTIEN; DELAY(10000); ((struct ch11 *)reg)->ch_csr = 0; return (1); } /*ARGSUSED*/ chchattach(ui) register struct uba_device *ui; { if (++chchndev > NCHCH) panic("too many ch11's"); chchsetup(&ch11xcvr[chchndev - 1], (struct ch11 *)ui->ui_addr); } #else VMUNIX int chchndev = NCHCH; int chchaddr[NCHCH] = { CHCH_ADDR }; #endif VMUNIX /* * Do the run-time initialization of the given transceiver. */ chchsetup(xp, cp) register struct chxcvr *xp; register struct ch11 *cp; { xp->xc_devaddr = (unsigned *)cp; xp->xc_addr = cp->ch_myaddr; xp->xc_start = chchstart; xp->xc_reset = chchreset; printf("CHAOS cable: subnet: %o, host: %o, (%o)\n", xp->xc_subnet, xp->xc_host, xp->xc_addr); if (xp->xc_subnet >= CHNSUBNET) panic("bad ch11 address"); } /* * chaos11 initialization. Also does initialization to the static xcvr * structure since initialized unions don't work anyway. */ chchinit() { register struct chxcvr *xp; register int i; for (i = 0, xp = &ch11xcvr[0]; xp < &ch11xcvr[chchndev]; xp++, i++) { #ifndef VMUNIX chchsetup(xp, (struct ch11 *)chchaddr[i]); #endif not VMUNIX chchreset(xp); } } /* * Reset things from an unknown state */ chchreset(xp) register struct chxcvr *xp; { register struct ch11 *cp = (struct ch11 *)xp->xc_devaddr; register struct chroute *r; if (cp == 0) return; r = &Chroutetab[xp->xc_subnet]; r->rt_type = CHDIRECT; r->rt_cost = CHHCOST/2; r->rt_xcvr = xp; cp->ch_csr = CHRST | CHRIEN | CHREN | CHTIEN; } /* * Start output on an idle line */ chchstart(xp) register struct chxcvr *xp; { if (xp->xc_tpkt != NOPKT) panic("chchstart: already busy"); chchtint(xp); } /* * Receiver interrupt */ chchrint(xcvr) struct chxcvr *xcvr; { register nshorts; register struct ch11 *cp; register short *p; register struct chxcvr *xp = xcvr; /* needed so xp is last reg */ cp = (struct ch11 *)xp->xc_devaddr; nshorts = (((cp->ch_rbc & 07777) + 1) >> 4) - 3; if ((cp->ch_rbc & 017) != 017 || nshorts < 8) xp->xc_leng++; /* bit count not multiple of 16 */ else if (cp->ch_csr & CHCRC) xp->xc_crcr++; /* crc error during reception */ else if ((xp->xc_rpkt = hpkalloc(nshorts)) == NOPKT) xp->xc_rej++; /* can't allocate a packet */ else { p = (short *)&xp->xc_rpkt->pk_phead; do { *p++ = cp->ch_rbf; } while (--nshorts); nshorts = cp->ch_rbf; nshorts = cp->ch_rbf; nshorts = cp->ch_rbf; if (cp->ch_csr & CHCRC) { xp->xc_crci++; /* crc error during readout */ ch_free((char *)xp->xc_rpkt); } else { register struct chroute *r; LOCK; r = &Chroutetab[xp->xc_subnet]; r->rt_type = CHDIRECT; r->rt_cost = CHCCOST; r->rt_xcvr = xp; xp->xc_rcvd++; rcvpkt((struct packet *)xp->xc_rpkt); } } xp->xc_lost += (cp->ch_csr >> CHLCPOS) & CHLCMASK; cp->ch_csr |= CHREN | CHRIEN; /* CHRIEN is "not really needed" */ } /* * Transmit interrupt */ chchtint(xcvr) struct chxcvr *xcvr; { register struct ch11 *cp; register struct packet *pkt; /* shouldn't be reg on pdp11 */ { register struct chxcvr *xp = xcvr; LOCK; cp = (struct ch11 *)xp->xc_devaddr; cp->ch_csr &= ~CHTIEN; if ((pkt = xp->xc_tpkt) != NOPKT) { /* if a real interrupt */ if (cp->ch_csr & CHABRT) { /* should retry here first */ xp->xc_abrt++; if (++xp->xc_chrtries < 5) goto retry; } else xp->xc_xmtd++; xmitdone(pkt); xp->xc_chrtries = 0; } if ((pkt = xmitnext(xp)) == NOPKT) return; retry: ; }{ register int nshorts; register short *p; nshorts = (sizeof(struct pkt_header) + pkt->pk_len + sizeof(short)-1) /* / sizeof(short) */ >> 1; debug(DTRANS,printf("Trans size=%d, %x\n", nshorts, pkt)); cp->ch_csr |= CHTCLR; p = (short *)&pkt->pk_phead; do { cp->ch_wbf = *p++; } while (--nshorts); }{ register struct chroute *r; r = &Chroutetab[pkt->pk_dsubnet]; if (r->rt_type != CHDIRECT) cp->ch_wbf = r->rt_addr; else cp->ch_wbf = pkt->pk_daddr; /* where to send it */ r = (struct chroute *)cp->ch_xmt; /* start transmission */ cp->ch_csr |= CHTIEN; } } /* * CHAOS-11 interrupt * call chchrint and/or chchtint */ chchintr(dev) { register struct chxcvr *xp = &ch11xcvr[dev]; register struct ch11 *cp = (struct ch11 *)xp->xc_devaddr; if (cp->ch_csr & (CHTDN | CHRDN)) { if (cp->ch_csr & CHRDN) if (cp->ch_csr & CHRIEN) chchrint(xp); if (cp->ch_csr & CHTDN) if (cp->ch_csr & CHTIEN) chchtint(xp); } else debug(DTRANS, printf("spurious CHAOS11 interrupt\n")); }