/* * Datakit driver * Common subroutines for all drivers * SCCSID[] = "@(#)dksub.c 1.2 Garage 84/03/27" */ #include "datakit.h" #if NDATAKIT>0 #include "param.h" #include "../machine/pte.h" #include "signal.h" #include "errno.h" #include "seg.h" #include "dir.h" #include "user.h" #include "ioctl.h" #include "tty.h" #include "syslog.h" #include "conf.h" #include "file.h" #include "inode.h" #include "systm.h" #include "proc.h" #include "mbuf.h" #include "buf.h" #include "uio.h" #include "dkit.h" #include "dk.h" #include "dkdev.h" #define DKBUFUSE 5 /* max buffers /channel */ extern struct dkdev dkdev[] ; int dksubdebug = 512; dkuread(chan, uio) register struct uio *uio; { register int len, blen ; register struct dkdev *tp ; short chanstat ; struct mbuf *mm ; int err = 0, s; extern wakeup() ; extern dkrdone() ; tp = &dkdev[chan]; MGET(mm, M_WAIT, DKMT_DATA); if (mm == NULL) return ENOBUFS; if (uio->uio_resid >= MLEN) { register struct mbuf *p; MCLALLOC(p, 1); if (p == 0) goto nopages; mm->m_off = (int)p - (int)mm; blen = CLBYTES; } else { nopages: blen = MIN(MLEN, uio->uio_resid); } if (setjmp(&u.u_qsave)) { s = spl5(); if (dk_status(chan) & DK_RCV) (void) dk_rabort(chan, dkrdone, (caddr_t) tp) ; splx(s); m_freem(mm); u.u_error = EINTR; return EINTR ; } while (uio->uio_resid && !err) { len = MIN(uio->uio_resid, blen) ; chanstat = dk_recv(chan, mtod(mm, caddr_t), len, tp->d_rmode, dkrdone, (caddr_t) tp) ; if (chanstat == 0) { if ((dk_status(chan) & DK_RESET) == 0) err = EIO ; break; } if ((tp->dc_state & DK_NDELAY) && (dk_status(chan) & DK_RCV)) { err = EWOULDBLOCK; break; } s = spl5() ; while (dk_status(chan) & DK_RCV) sleep((caddr_t)(tp), TTOPRI) ; splx(s) ; len -= tp->d_rresid ; if (len) err = uiomove(mtod(mm, caddr_t), len, UIO_READ, uio); if (tp->d_rdone != DKR_FULL) break ; } m_freem(mm) ; return err; } /*ARGSUSED*/ dkrdone(tp, chan, resid, rdone, rctl) register struct dkdev *tp ; { tp->d_rresid = resid ; tp->d_rdone = rdone ; tp->d_rctl = rctl ; wakeup((caddr_t) tp) ; } dkuwrite(chan, uio) register struct uio *uio; { extern wakeup() ; extern dkwdone() ; register struct dkdev *tp ; register len ; register struct mbuf *m; register struct iovec *iov; int s, error, eob; short xc; tp = &dkdev[chan] ; do { s = spl5() ; while (tp->d_bufct > DKBUFUSE) { if (tp->dc_state & DK_NDELAY) { splx(s); return EWOULDBLOCK; } tp->d_state |= DKWAIT ; sleep((caddr_t)(&tp->d_state), TTOPRI) ; } splx(s) ; iov = uio->uio_iov; if (iov->iov_len) { MGET(m, M_WAIT, DKMT_DATA); if (m == NULL) return ENOBUFS; if (iov->iov_len >= MLEN) { register struct mbuf *p; MCLALLOC(p, 1); if (p == 0) goto nopages; m->m_off = (int)p - (int)m; len = MIN(CLBYTES, iov->iov_len); } else { nopages: len = MIN(MLEN, iov->iov_len); } error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); if (error) { (void) m_free(m); return error; } m->m_len = len; } else m = NULL; s = spl5(); tp->d_bufct++; eob = (uio->uio_resid == 0); if (eob) { xc = tp->d_xctl; tp->d_xctl = 0; } else xc = 0; if (dk_xmit(chan, m, eob, xc, dkwdone, (caddr_t) 0) == 0) { tp->d_bufct-- ; return EIO ; } splx(s); } while (uio->uio_resid); return 0; } /*ARGSUSED*/ dkwdone(x, chan) { register struct dkdev *tp ; tp = &dkdev[chan] ; if (chan > dksubdebug) log(LOG_ERR, "dkwdone %d: state=0%o bufct=%d\n", chan, tp->d_state, tp->d_bufct); if (tp->d_bufct) tp->d_bufct-- ; if (tp->d_state & DKWAIT) { tp->d_state &= ~DKWAIT ; wakeup((caddr_t) &tp->d_state) ; } } /* wakeup and reinitialize channel upon receipt of reconnection message */ dkrsplice(chan) { register struct dkdev *tp ; tp = &dkdev[chan] ; tp->d_state |= DKSPLICED ; wakeup((caddr_t) tp) ; dk_cmd(chan, DKC_XINIT) ; } /* wait for reconnection message indicating that splice completed */ dksplwait(chan) { register struct dkdev *tp ; tp = &dkdev[chan] ; while ((tp->d_state & DKSPLICED) == 0) sleep((caddr_t) tp, TTOPRI) ; } /* convert file desciptor to Datakit channel */ dkgetdev(fildes) { extern struct file *getinode(); register struct file *fp; register struct inode *ip ; fp = getinode(fildes) ; ip = (struct inode *)fp->f_data; if ((ip->i_mode & IFMT) != IFCHR ) { u.u_error = ENOTTY ; return(-1) ; } if (dkdevtype((dev_t) ip->i_rdev)) return(minor(ip->i_rdev)) ; u.u_error = EINVAL ; return(-1) ; } /* validate device number as belonging to Datakit */ dkdevtype(dev) dev_t dev; { extern dkopen(); #if NDKTTY > 0 extern dktopen(); #endif #if NDKXQT > 0 extern dkxopen(); #endif #if NDKI > 0 extern dkiopen(); #endif register md = major(dev) ; if ((cdevsw[md].d_open == dkopen) #if NDKTTY > 0 || (cdevsw[md].d_open == dktopen) #endif #if NDKI > 0 || (cdevsw[md].d_open == dkiopen && md > 0) #endif #if NDKXQT > 0 || (cdevsw[md].d_open == dkxopen) #endif ) return(1); else return(0); } #endif