#define KERNEL 1 #include "../h/pk.p" /* * input framing and block checking. * frame layout for most devices is: * * S|K|X|Y|C|Z| ... data ... | * * where S == initial synch byte * K == encoded frame size (indexes pksizes[]) * X, Y == block check bytes * C == control byte * Z == XOR of header (K^X^Y^C) * data == 0 or more data bytes * * device driver interfaces on input are: * pkrint - byte level * pkrend - dma or pseudo-dma transfer level * pkdata - packet level */ int pksizes[] ={ 1, 32, 64, 128, 256, 512, 1024, 2048, 4096, 1 }; /* * Pseudo-dma byte collection. * This code can be put in the device driver * interrupt routine to eliminate the per byte * subroutine call. */ pkrint(c, tp) register c; register struct tty *tp; { if (q1.c_cc<0) { if (q1.c_cf != NULL) { tp->t_erase = 0; *q1.c_cf++ = c; } if (++q1.c_cc) return; pkrend(tp); return; } } /* * End of input transfer. */ pkrend(tp) register struct tty *tp; { register char *p; struct pack *pk; struct header *h; register x; char cntl, hdcheck; unsigned short sum; int i,j,k; char **bp; p = q1.c_cl; x = (int)q1.c_cf - (int)p; pk = (struct pack *)tp->t_linep; h = (struct header * )&pk->p_ihbuf; if (x == HDRSIZ) { if (*p++ == SYN ) { hdcheck = k = *p++; sum = (unsigned)*p; hdcheck ^= *p++; sum |= (unsigned)*p << 8; hdcheck ^= *p++; hdcheck ^= cntl = *p++; if (hdcheck != *p) { goto bad; } if (k == 9) { pkcntl(cntl, pk); q1.c_cf = q1.c_cl; q1.c_cc = -HDRSIZ; goto istart1; } if (k && pksizes[k]==pk->p_rsize) { pk->p_rpr = cntl&MOD8; pksack(pk); bp = pk->p_ipool; if (bp) { pk->p_ipool = (char **)*bp; pk->p_io = bp; } else { } q1.c_cf = (char *)bp; q1.c_cc = -pk->p_rsize; h->sum = sum; h->cntl = cntl; goto istart1; } bad: pkbadframe(pk); } scan: x = HDRSIZ; j = 0; p = (caddr_t)h; for (i = 1; i < HDRSIZ; i++) if (p[i] == SYN) for(x=i; ip_rsize) { pkdata(h->cntl, h->sum, pk, q1.c_cl); pk->p_io = NULL; q1.c_cf = (char *)h; q1.c_cc = -HDRSIZ; goto istart1; } if (x == 0) { q1.c_cf = (char *)h; q1.c_cc = -HDRSIZ; pkbadframe(pk); } else { pkbadframe(pk); goto scan; } istart1: q1.c_cl = q1.c_cf; istart2: if (tp->t_iproc != NULL) (*tp->t_iproc)(tp); } /* * Put packet located at address bp * in an input slot for further processing. */ pkdata(c, sum, pk, cp) char c; unsigned short sum; register struct pack *pk; char *cp; { register struct tty *tp; register x; char **bp; int t; pk->p_state &= ~BADFRAME; bp = (char **)cp; tp = pk->p_ttyp; if (pk->p_state&DRAINO || !(pk->p_state&LIVE)) { pk->p_msg |= pk->p_rmsg; pkoutput(pk); goto drop; } t = next[pk->p_pr]; for(x=pk->p_pr; x!=t; x = (x-1)&7) { if (pk->p_is[x] == 0) goto slot; } /* * this can't happen */ printf("no slot\n"); drop: *bp = (char *)pk->p_ipool; pk->p_ipool = bp; return; slot: pk->p_imap |= mask[x]; pk->p_is[x] = c; pk->p_isum[x] = sum; pk->p_ib[x] = cp; if (tp->t_chan) sdata(tp->t_chan); else wakeup(&pk->p_pr); } /* * Start transmission on output device associated with pk. * For asynch devices (t_line==1) framing is * imposed. For devices with framing and crc * in the driver (t_line==2) the transfer is * passed on to the driver. */ pkxstart(pk, cntl, x) struct pack *pk; char cntl; register x; { struct tty *tp; register char *p; short checkword; char hdcheck; p = (caddr_t)&pk->p_ohbuf; tp = pk->p_ttyp; if (tp->t_line==1) { *p++ = SYN; if (x < 0) { *p = 9; checkword = cntl; q3.c_cl = NULL; } else { *p = pk->p_lpsize; checkword = pk->p_osum[x] ^ (unsigned)cntl; q3.c_cl = pk->p_ob[x]; } checkword = CHECK - checkword; hdcheck = *p++; hdcheck ^= *p++ = checkword; hdcheck ^= *p++ = checkword>>8; q3.c_cc = -HDRSIZ; } else { q3.c_cc = -1; } hdcheck ^= *p++ = cntl; *p = hdcheck; q3.c_cf = (caddr_t)&pk->p_ohbuf; /* pk->p_srxmit++; */ (*tp->t_oproc)(tp); } /* * transmitter interrupt. */ int pkdelay = 2; pkxint(tp) register struct tty *tp; { register struct pack *pk; register s; extern int pkoutput(); pk = (struct pack *)tp->t_linep; s = spl6(); tp->t_state &= ~BUSY; if (q3.c_cl == NULL) { pkoutput(pk); } else { q3.c_cf = q3.c_cl; q3.c_cl = NULL; q3.c_cc = -pk->p_xsize; (*tp->t_oproc)(tp); } splx(s); }