+# include "../h/param.h"
+# include "../h/dir.h"
+# include "../h/user.h"
+# include "../h/proc.h"
+# include "../h/uba.h"
+# include "../h/buf.h"
+/* */
+# define LNKADR (UBA0_DEV+0172410) /* DR11-B devive reg's */
+/*
+* UBA0_DEV = 0x80018000
+* LNKADR = 0x80027508
+*/
+/* DA11-B DR-11B Status & Command reg */
+# define ERR 0x8000 /* error bit */
+# define NEX 0x4000 /* non-existent memory */
+# define IIR 0x800 /* Input Interrupt Request */
+# define ID 0x400 /* Input direction */
+# define IM 0x200 /* Input mode */
+# define CYCLE 0x100 /* Cycle */
+# define RDY 0x80 /* Ready */
+# define IE 0x40 /* Interrupt Enable */
+# define OIR 8 /* Output interrupt request */
+# define OD 4 /* Output direction */
+# define OM 2 /* output mode */
+# define GO 1 /* Go bit */
+/* states */
+# define CLOSED 0 /* closed */
+# define OPEN 1 /* open */
+# define S1 2 /* write state 1 */
+# define S2 4 /* write state 2 */
+# define R1 8 /* read state 1 */
+# define R2 16 /* read state 2 */
+# define L_NOT 128 /* send OIR to other end link */
+# define IPEND 256
+# define PREread 512 /* 'lnkmon' wait */
+# define L_MON 1024 /* 'lnkmon' decr V11opn */
+# define L_WAKE 2048
+# define BUSY (S1|S2|R1|R2) /* i-o in progress for driver */
+# define S_ERR 0x8000
+/* */
+# define V11PRI 0
+# define BUFSIZ 512
+# define VSPEC 0100000
+/* */
+struct lnkreg {
+ short drwc , drba , drst , drdb ;
+ } ;
+struct {
+ short state ;
+ struct buf *bp ;
+ } V11tab ;
+char V11opn ;
+
+/* */
+
+V11open(dev,flag)
+{
+struct buf *geteblk() ;
+
+if (V11opn) {
+ u.u_error = EBUSY;
+ return;
+ }
+V11opn++;
+if (V11tab.bp == 0) /* grab system buffer */
+ V11tab.bp = geteblk() ; /* VAX call */
+((struct lnkreg *)LNKADR)->drst |= IE ;
+V11tab.state |= OPEN ;
+}
+
+/* */
+
+V11close(dev,flag) /* called on last close only ! ! */
+{
+V11opn = 0;
+V11tab.state = CLOSED ;
+((struct lnkreg *)LNKADR)->drst = 0 ; /* IE off */
+if (V11tab.bp) brelse(V11tab.bp) ; /* release system buffer */
+V11tab.bp = 0 ;
+}
+
+/* */
+
+V11write(dev)
+{
+register int i , j , k ;
+
+/* INIT clears OUTPUT DIR bit = transmitter */
+spl5() ;
+V11tab.state |= S1 ;
+/* setup for transmit */
+((struct lnkreg *)LNKADR)->drst &= ~(OD) ; /* 0 -> transmitter */
+spl0() ;
+
+i = uballoc(V11tab.bp->b_un.b_addr,BUFSIZ,1) ; /* get UBA map entry for
+ system buffer and set valid bit & BDP no. & BO bit & load map */
+j = i & 0x3ffff ; /* start map no. & byte offset */
+
+/* write loop, until done or error */
+while ((u.u_count > 0) && (u.u_error == 0)) {
+ iomove(V11tab.bp->b_un.b_addr,min(BUFSIZ,u.u_count),B_WRITE) ; /* move
+ data from user space to system buffer */
+ ((struct lnkreg *)LNKADR)->drwc = (-(BUFSIZ>>1)) ; /* word count */
+ ((struct lnkreg *)LNKADR)->drba = j ; /* map no. (SBI page) & byte offset */
+ spl5() ;
+ ((struct lnkreg *)LNKADR)->drst |= GO ; /* setup for transfer */
+ sleep(LNKADR,V11PRI) ; /* wait for transfer to finish(interrupt) */
+ spl0() ;
+ if (V11tab.state & S_ERR) {
+ u.u_error = ENXIO ;
+ V11tab.state &= (~S_ERR);
+ }
+ }
+ubafree(i) ;
+((struct lnkreg *)LNKADR)->drst &= (~OM);
+V11tab.state &= (~BUSY) ;
+}
+
+/* */
+
+V11read(dev)
+{
+register i , j ;
+
+spl5() ;
+V11tab.state |= R1 ;
+((struct lnkreg *)LNKADR)->drst |= OD ; /* receiver */
+spl0() ;
+i = uballoc(V11tab.bp->b_un.b_addr,BUFSIZ,1) ;
+j = i & 0x3ffff ; /* start map no. & byte offset */
+
+while ((u.u_count>0) && (u.u_error == 0)) {
+ ((struct lnkreg *)LNKADR)->drwc = (-(BUFSIZ>>1)) ;
+ ((struct lnkreg *)LNKADR)->drba = j ;
+ spl5() ;
+ ((struct lnkreg *)LNKADR)->drst |= GO ;
+ /* wait for i-o to finish */
+ sleep(LNKADR,V11PRI) ;
+ spl0() ;
+ if (V11tab.state & S_ERR) {
+ u.u_error = ENXIO ;
+ V11tab.state &= (~S_ERR);
+ continue ;
+ }
+ iomove(V11tab.bp->b_un.b_addr,min(BUFSIZ,u.u_count),B_READ) ;
+ }
+
+ubafree(i) ;
+V11tab.state &= (~BUSY) ;
+}
+
+/* */
+
+V11int(dev)
+{
+register unsigned short state ;
+register int i ;
+extern int V11ioctl() ;
+
+state = V11tab.state ;
+if ((i = ((struct lnkreg *)LNKADR)->drst) & ERR)
+ if (state&BUSY) V11tab.state |= S_ERR ;
+if (state&BUSY) {
+ wakeup(LNKADR) ;
+ return ;
+ }
+if (i&IM) {
+ if (state&PREread) {
+ wakeup(V11ioctl);
+ return;
+ }
+ if (((state&BUSY) == 0) && (state&OPEN))
+ V11tab.state |= IPEND ;
+ return;
+ }
+}
+
+/* */
+
+V11ioctl(dev,cmd,addr,flag)
+dev_t dev;
+caddr_t addr;
+{
+if (cmd & VSPEC) {
+ switch (cmd & 077777) {
+ case L_WAKE : { /* debug wakeup */
+ wakeup(LNKADR);
+ break;
+ }
+ case L_NOT : { /* send OIR to other end of link */
+ spl5();
+ ((struct lnkreg *)LNKADR)->drst |= (OIR|OM) ;
+ ((struct lnkreg *)LNKADR)->drst &= (~OIR);
+ spl0();
+ break;
+ }
+ case L_MON : { /* 'lnkmon' decr 'V11opn' */
+ V11opn--;
+ break;
+ }
+ case PREread : { /* 'lnkmon' wait */
+ spl5();
+ if (V11tab.state&IPEND) {
+ V11tab.state &= (~IPEND);
+ }
+ else {
+ V11tab.state |= PREread;
+ sleep(V11ioctl,PZERO+1);
+ V11tab.state &= (~PREread);
+ }
+ spl0();
+ break;
+ }
+ }
+ }
+else {
+ *((short *)addr) = V11tab.state;
+ }
+}