+#define KERNEL 1
+#include "../h/pk.p"
+
+
+/*
+ * kernel support routines.
+ */
+
+struct pack *pklines[NPLINES];
+int maxwindow =2;
+
+/*
+ * start initial synchronization.
+ * allocate space.
+ */
+pkopen(dev, tp, addr)
+register struct tty *tp;
+caddr_t addr;
+{
+register struct pack *pk;
+register i;
+int pktimeout();
+char **bp;
+static timer_on;
+int s;
+struct piocb piocb;
+
+
+ if (tp->t_line)
+ return;
+ /*
+ * copy user parameters
+ */
+ if (copyin(addr, (caddr_t)&piocb, sizeof (piocb))) {
+ u.u_error = EFAULT;
+ return;
+ }
+ npbits = dtom(sizeof(struct pack));
+ pk = (struct pack *)getepack(npbits);
+ if (pk==NULL)
+ goto notsobad;
+ pkzero((caddr_t)pk,sizeof (struct pack));
+ pk->p_rwindow = piocb.window;
+ if (pk->p_rwindow > maxwindow)
+ pk->p_rwindow = maxwindow;
+ pk->p_rsize = piocb.psize;
+ if (pk->p_rsize > 512 || pk->p_rsize & 037)
+ goto notsobad;
+ pk->p_mode = piocb.mode;
+ if (pk->p_mode & 01)
+ pkdebug++;
+ /*
+ * try to allocate input window
+ */
+ pk->p_bits = dtom(pk->p_rsize);
+ for(i=0; i<pk->p_rwindow; i++) {
+ bp = (char **)getepack(pk->p_bits);
+ if (bp==NULL)
+ break;
+ *bp = (char *)pk->p_ipool;
+ pk->p_ipool = bp;
+ }
+
+ if (i==0 && bp==NULL)
+ goto notsobad;
+ pk->p_rwindow = i;
+
+
+ /*
+ * start timer process,
+ * wait for synchronization.
+ */
+ flushtty(tp);
+ s = spl6();
+ pkdisc = tp->t_line = piocb.t;
+ pk->p_ttyp = tp;
+ tp->t_linep = (caddr_t)pk;
+ q2.c_cf = q2.c_cl = NULL;
+ q1.c_cf = q1.c_cl = (caddr_t)&pk->p_ihbuf;
+ q1.c_cc = -HDRSIZ;
+ if (tp->t_iproc != NULL)
+ (*tp->t_iproc)(tp);
+
+ pk->p_rmsg = M_INITA;
+ for(i=0; i<NPLINES; i++) {
+ if (pklines[i]==NULL) {
+ pklines[i] = pk;
+ goto found;
+ }
+ }
+ goto notsobad;
+found:
+ pk->p_timer++;
+ if (timer_on==0) {
+ timer_on++;
+ pktimeout();
+ }
+ splx(s);
+ SLEEP(&pk->p_state, PKOPRI);
+ pkreset(pk);
+
+ if ((pk->p_state&LIVE)==0) {
+ pk->p_state = DOWN;
+ pk->p_rmsg = 0;
+notsobad:
+ u.u_error = ENXIO;
+ return;
+ }
+
+ pksetgrp(tp);
+ pkioctl(DIOCGETP, tp, addr);
+
+}
+
+
+
+
+/*
+ * unix ioctl interface
+ */
+pkioctl(com,tp,addr)
+register struct tty *tp;
+caddr_t addr;
+{
+struct piocb piocb;
+register struct pack *pk;
+
+ pk = (struct pack *)tp->t_linep;
+ if (com == DIOCGETP) {
+ piocb.window = pk->p_swindow;
+ piocb.psize = pk->p_xsize;
+ piocb.state = pk->p_state;
+ if (copyout((caddr_t)&piocb, addr, sizeof(piocb))) {
+ u.u_error = EFAULT;
+ }
+ if (u.u_error==0)
+ u.u_r.r_val1 = piocb.psize;
+ }
+}
+
+
+/*
+ * Arrange for the device (i.e. tp)
+ * to be able to generate signals if need be.
+ */
+pksetgrp(tp)
+register struct tty *tp;
+{
+register struct proc *pp;
+
+ pp = u.u_procp;
+ if (pp->p_pgrp == 0)
+ pp->p_pgrp = pp->p_pid;
+ if (tp->t_pgrp == 0)
+ tp->t_pgrp = pp->p_pgrp;
+}
+
+
+
+/*
+ * Shut down io.
+ * The problem is mainly input since the
+ * device driver may have a buffer.
+ */
+pkturnoff(tp)
+register struct tty *tp;
+{
+register char **bp;
+register struct pack *pk;
+register s;
+
+ pk = PADDR;
+ LOCK;
+ bp = pk->p_io;
+ tp->t_line = 0;
+ q1.c_cf = NULL;
+ flushtty(tp);
+ if (bp!=NULL) {
+ *bp = (char *)pk->p_ipool;
+ pk->p_ipool = bp;
+ }
+ UNLOCK;
+}
+
+
+
+/*
+ * link dead?
+ */
+pklive(pk)
+register struct pack *pk;
+{
+register struct tty *tp;
+
+ tp = pk->p_ttyp;
+ if (tp->t_line!=pkdisc || tp->t_linep!=(caddr_t)pk) {
+ return(0);
+ }
+ return(tp->t_state&CARR_ON);
+}
+
+
+
+/*
+ * timeout process:
+ * wakes up periodically to check status
+ * of active lines.
+ */
+pktimeout()
+{
+register struct pack *pk;
+extern time_t time;
+register i;
+
+ for(i=0;i<NPLINES;i++) {
+ if ((pk=pklines[i])==NULL)
+ continue;
+ if (pk->p_nout == pk->p_tout) {
+ if (pk->p_xcount && pk->p_timer==0) {
+ pk->p_timer = 3;
+ pk->p_state |= WAITO;
+ }
+ } else
+ pk->p_tout = pk->p_nout;
+ if (pk->p_timer==0) {
+ if (pk->p_state & BADFRAME) {
+ pk->p_msg |= M_RJ;
+ pk->p_state &= ~BADFRAME;
+ goto startup;
+ }
+ if (pk->p_rmsg)
+ goto startup;
+ WAKEUP(&pk->p_ps);
+ continue;
+ }
+ if (--pk->p_timer == 0) {
+ if ((pk->p_state&LIVE)==0) {
+ startup:
+ pk->p_timer = 1;
+ } else
+ if (pk->p_state & WAITO) {
+ if (pk->p_state&DRAINO) {
+ pk->p_state |= DOWN;
+ } else {
+ pk->p_state |= RXMIT;
+ }
+ pkoutput(pk);
+ pk->p_timer = 5+2*pkzot;
+ }
+ WAKEUP(&pk->p_ps);
+ pk->p_msg |= pk->p_rmsg;
+ if (pk->p_msg)
+ pkoutput(pk);
+ }
+ }
+ timeout(pktimeout, (caddr_t)pk, 60);
+
+
+ /*
+ * randomize timeouts.
+ */
+ pkzot = 2 + time&07;
+}
+
+