/************************************************ * Terminal "Emulator" for RSX-11M * * Environment: DECUS C, RSX-11M Ver. 4.0 * * Written: 03/14/83, D. Soldahl PMG * * * * Purpose: Pass all characters through a port * * to another computer (& back) * * * * Notes: Uses Qio's with AST's to asynchonously * * Input from both ports and output to * * both ports. * * Terminals should be set to typeahead, * * full duplex before running. * ************************************************/ #include #include #include /*** #define debug 1 ***/ #define BSIZ 4096 #define IS_TMO 002 #define IO_ATT 01400 #define IO_RAL 01010 #define IO_WVB 011000 #define IO_WAL 0410 #define IO_KIL 012 #define IO_DET 02000 #define TF_ESQ 020 #define TF_NOT 002 #define TF_RNE 020 #define TF_TMO 0200 #define TC_TBF 57 extern int qio(); extern wtse(); extern wtlo0(); extern int $dsw; extern rdast(); /* forward reference */ extern wrast(); int fnc; /* parm definitions for qio */ int eflag; int iosb[2]; int devpar[6]; struct bufsta { /* Tied to IOSB so AST gets address */ int iosb0; int iosb1; int lun; boolean iordy; /* Flag to indicate ready for I/O */ int iocnt; /* I/O in progress char count */ int *count; /* Ptr to char count for buffer */ char *bufptr; /* Ptr to next place for I/O */ char *bufstart; /* Ptr to start of ring buffer */ char *bufend; /* Ptr to end of ring buffer */ } bstat[4]; /* 0 & 1 = Input status blocks */ /* 2 & 3 = Output status blocks */ char buff[2][BSIZ]; /* Ring Buffers for I/O */ int count[2]; /* Count of characters in buffer */ static char *term[2]= {"TI0: ","TI0: "}; /* Port Device Names */ boolean abort; main(argc,argv) char *argv[]; { int mask; register int c; register int i; #ifdef debug iff argc == 1 then { cpystr(term[0],argv[0]); error("Arg = %s, Num = %o\n",term[0],otoi(term[0])); } #endif for (i = 1; i 2) or ((c = strlen(argv[i])) > 5) or (c < 2) then error("Format is: TERM TTi: [TTj:]"); cpystr(term[i-1],argv[i]); } /* Initialize I/O Buffers */ count[0] = 0; /* Character Count to 0 */ count[1] = 0; for (i = 0; i < 4; i++) { bstat[i].iordy = true; /* Buffer ready for input or output flag */ /* Init buffer pointers etc. */ bstat[i].bufptr = bstat[i].bufstart = &buff[i & 1]; bstat[i].count = &count[i & 1]; bstat[i].bufend = &(buff[i & 1][BSIZ - 1]); #ifdef debug printf("%d: IOSB = %o, Ptr = %o, &count = %o, end = %o\n",i, &bstat[i].iosb0,bstat[i].bufptr,bstat[i].count, bstat[i].bufend); #endif } mask = 074; /* Event flags 3 - 6 */ attach(term[0],4); /* Attach Terminals (lun was 2,3 not 4,5 */ bstat[0].lun = 4; /* input 0 eflag = 3 */ bstat[3].lun = 4; /* output 1 eflag = 5 */ attach(term[1],5); bstat[1].lun = 5; /* input 1 eflag = 4 */ bstat[2].lun = 5; /* output 0 eflag = 6 */ iosb[0] = 0; /* Clear ast error flag */ repeat /* Cycle for each way, In & Out */ { for (i = 0; i < 2; i++) { iff (bstat[i].iordy == true) then readbuf(&bstat[i]); iff (bstat[i+2].iordy == true) and (count[i] > 0) then writebuf(&bstat[i+2]); else clef(bstat[i+2].lun + 1); /* Clear output pending flag */ } wtlo0(mask); /* Wait for I/O Done before Retesting */ #ifdef debug printf("Counts = %d, %d. Rdy flags = %d,%d,%d,%d\n", count[0],count[1],bstat[0].iordy,bstat[1].iordy,bstat[2].iordy, bstat[3].iordy); #endif } untill(abort)); iff iosb[0] != 0 then error("I/O exception, iosb = %o, %o, dsw = %d.\n",iosb[0],iosb[1],$dsw); detach(bstat[0].lun); detach(bstat[1].lun); } /* end main */ /*** Attach Named Terminal ***/ proc attach(devnam,lun) char *devnam; int lun; { union { int dev; char name[2]; } dnam; int unit; register int i,c; /* assign device to given lun */ for (i = 0; i < 2; i++) dnam.name[i] = ifx islower(c = *devnam++) thenx c - ('a' - 'A') elsex c; unit = otoi(devnam); #ifdef debug printf("Dev = '%c%c', Unit = %d\n",dnam.name[0],dnam.name[1],unit); #endif alun(lun,dnam.dev,unit); /* Attach terminal to capture all characters & allow typeahead */ fnc = IO_ATT; eflag = 2; iosb[0] = 0; devpar[0] = 0; devpar[1] = 0; devpar[2] = 0; iff qio(fnc,lun,eflag,iosb,0,devpar) < 0 then error("Attach error dsw = %d\n",$dsw); /* Wait for Attach */ wtse(eflag); } /* end attach */ /*** Detach terminal & kill outstanding I/O ***/ proc detach(lun) int lun; { iff qio(IO_KIL,lun,0,iosb,0,0) < 0 then error("I/O Kill error, lun %d",lun); iff qio(IO_DET,lun,0,iosb,0,0) < 0 then error("Detach error, lun %d",lun); } /* end detach */ /*** Convert Octal Ascii number to Integer ***/ int proc otoi(octnum) char *octnum; { register int i, c; for (i = 0; ((c = *octnum++) >= '0') and ((c -= '0') < 8); i += c) i <<=3; return(i); } /* end otoi */ /*** Readbuf: Use Qio to Read all characters to buffer ***/ /*** Clear Iordy and set for RDAST routine ***/ proc readbuf(buf) struct bufsta *buf; { /*** Do qio IO.RAL with timeout, 1 character at a time. Possible inhancements: use G.MCS to determine number of chars in typeahead buffer (TC.TBF = unprocessed char count); If buffer > 7/8 full send XOFF, at 1/2 full send XON. ***/ eflag = buf->lun - 1; /* flags 3 & 4 for input */ devpar[0] = buf->bufptr; /* Set start of I/O */ devpar[1] = buf->iocnt = 1; /* Number of characters */ devpar[2] = 10; /* Timeout, 10 sec intervals */ fnc = IO_RAL | TF_TMO; buf->iordy = false; iff qio(fnc,buf->lun,eflag,&buf->iosb0,rdast,devpar) < 0 then error("Read error, lun %d, dsw = %d",buf->lun,$dsw); } /* end readbuf */ /* Writebuf: Use qio IO.WAL to write as many characters as possible from buffer, Clear iordy, set for WRAST routine */ proc writebuf(buf) struct bufsta *buf; { eflag = buf->lun + 1; /* flags 5 & 6 for output */ buf->iocnt = *buf->count; /* I/O count = count unless ring buffer wraps */ iff (buf->bufptr + buf->iocnt) > buf->bufend then buf->iocnt = buf->bufend - buf->bufptr; devpar[0] = buf->bufptr; /* Set start of I/O */ devpar[1] = buf->iocnt; /* Number of characters */ devpar[2] = 0; /* No VFC added to output */ fnc = IO_WAL; buf->iordy = false; iff qio(fnc,buf->lun,eflag,&buf->iosb0,wrast,devpar) < 0 then error("Write error, lun %d, dsw = %d",buf->lun,$dsw); } /* end writebuf */ /*** rdast: entered when read is done, Sets count, buffer pointer, input ready flag, and abort ***/ proc rdast() { register struct bufsta *buf; register int stat; astset(); /* Save registers */ buf = gtdp(0); /* Get IOSB addr from stack */ iff (stat = buf->iosb0 & 0377) == IS_SUC then { buf->iocnt = buf->iosb1; iff *buf->bufptr == '\03' then abort = true; *buf->count += buf->iocnt; buf->bufptr += buf->iocnt; iff buf->bufptr > buf->bufend then buf->bufptr = buf->bufstart; /* Wrap ring buffer */ } else iff stat != IS_TMO then { buf->iocnt = 0; iosb[0] = buf->iosb0; iosb[1] = buf->iosb1; abort = true; } buf->iordy = true; /* Ready for more input */ astx(1); /* remove iosb from stack on exit */ } /* end rdast */ /*** wrast: Entered when write is done, Sets count, buffer pointer, and output ready flag. ***/ proc wrast() { register struct bufsta *buf; astset(); /* Save registers */ buf = gtdp(0); /* Get IOSB addr from stack */ iff (buf->iosb0 & 0377) == IS_SUC then { *buf->count -= buf->iocnt; buf->bufptr += buf->iocnt; iff buf->bufptr > buf->bufend then buf->bufptr = buf->bufstart; /* Wrap ring buffer */ } else { iosb[0] = buf->iosb0; iosb[1] = buf->iosb1; abort = true; } buf->iordy = true; /* Ready for more output */ astx(1); /* remove iosb from stack on exit */ } /* end wrast */