/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* |_o_o|\\ Copyright (c) 1986 The Software Distillery. All Rights Reserved */ /* |. o.| || This program may not be distributed without the permission of */ /* | . | || the authors. */ /* | o | || Dave Baker Ed Burnette Stan Chow Jay Denebeim */ /* | . |// Gordon Keener Jack Rouse John Toebes Doug Walker */ /* ====== BBS:(919)-471-6436 VOICE:(919)-469-4210 */ /* */ /* Contributed to Columbia University for inclusion in C-Kermit. */ /* Permission is granted to any individual or institution to use, copy, or */ /* redistribute this software so long as it is not sold for profit, provided */ /* this copyright notice is retained. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char *ckxv = "Amiga tty I/O, 4D(005), 31 Jul 87"; /* C K I T I O -- Serial and Console I/O support for the Amiga */ /* Author: Jack Rouse, The Software Distillery Based on the CKUTIO.C module for Unix */ #include /* standard I/O stuff */ #undef NULL #include "exec/types.h" #include "exec/exec.h" #include "devices/serial.h" #include "devices/timer.h" #include "libraries/dos.h" #include "libraries/dosextens.h" #define fh_Interact fh_Port #define fh_Process fh_Type #include "intuition/intuition.h" #include "intuition/intuitionbase.h" #define BREAKSIGS (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D) #ifdef LAT310 #include "fcntl.h" #include "signal.h" #include "ios1.h" /* defines ufbs structure */ #else #include "lattice/ios1.h" /* defines ufbs structure */ #endif char *ckxsys = " Commodore Amiga"; /* system name */ /* external declarations */ extern int speed, mdmtyp, parity, flow; /* external definitions */ char *dftty = SERIALNAME; /* serial device name */ int dfloc = 1; /* serial line is external */ int dfprty = 0; /* default parity is none */ int ttprty = 0; /* parity in use */ int dfflow = 1; /* default flow control is on */ int backgrd = 0; /* default to foreground */ int ckxech = 0; /* echo in case redirected stdin */ struct Process *CurProc; /* current process */ struct CommandLineInterface *CurCLI; /* current CLI info */ extern struct IntuitionBase *IntuitionBase; /* ptr to Intuition lib */ /* static definitions */ static struct MsgPort *serport; /* message port for serial comm */ static struct MsgPort *conport; /* console packet port */ static struct timerequest *TimerIOB; /* timer request */ static struct IOExtSer *ReadIOB; /* serial input request */ static struct IOExtSer *WriteIOB; /* serial output request */ static struct DosPacket *conpkt; /* console I/O packet */ static WORD serialopen; /* true iff serial device open */ static WORD timeropen; /* true iff timer device open */ static WORD pendwrite; /* true iff WriteIOB in use */ static WORD pendread; /* true iff ReadIOB in use */ static WORD pendconsole; /* true when console read pending */ static int queuedser; /* serial pushback char or -1 */ static UBYTE serbufc; /* char buffer for read ahead I/O */ #define NTTOQ 64 /* connect output queue size */ static char ttoq[NTTOQ]; /* connect output queue */ static int nttoq; /* number of chars in ttoq */ static int pttoq; /* next char to output in ttoq */ static int queuedcon; /* contti pushback char or -1 */ static LONG intsigs; /* signals for aborting serial I/O */ static int (*inthdlr)(); /* function to signal break to */ static BPTR rawcon; /* file handle for RAW: window */ static BPTR saverr; /* saved stderr file handle */ static APTR savewindow; /* saved process WindowPtr */ static APTR pushwindow; /* pushed process WindowPtr */ static struct DateStamp prevtime; /* saved time value */ /* Exec routines */ APTR AllocMem(); LONG AllocSignal(); struct IORequest *CheckIO(); VOID CloseDevice(), CloseLibrary(); LONG DoIO(); struct MsgPort *FindPort(); struct Task *FindTask(); VOID FreeMem(), FreeSignal(); struct Message *GetMsg(); LONG OpenDevice(); struct Library *OpenLibrary(); VOID PutMsg(), ReplyMsg(); VOID SendIO(); LONG SetSignal(); VOID Signal(); LONG Wait(); LONG WaitIO(); struct Message *WaitPort(); /* Exec support */ struct IORequest *CreateExtIO(); VOID DeleteExtIO(); struct MsgPort *CreatePort(); VOID DeletePort(); struct Task *CreateTask(); VOID DeleteTask(); /* AmigaDOS routines */ VOID Delay(); BPTR Open(); VOID Close(); BPTR Input(), Output(); LONG Read(); LONG WaitForChar(); struct DateStamp *DateStamp(); /* AmigaDOS support (from ckiutl.c) */ struct DosPacket *CreatePacket(); VOID DeletePacket(); #ifdef LAT310 /* translate Unix file handle (0, 1, or 2) to AmigaDOS file handle */ #define DOSFH(n) fileno(&_iob[n]) /* translate Unix file handle (0, 1, or 2) to Lattice file handle */ #define FILENO(n) fileno(&_iob[n]) #else /* Lattice runtime externals */ extern struct UFB _ufbs[]; extern int Enable_Abort; #define DOSFH(n) (_ufbs[n].ufbfh) #define FILENO(n) (n) #endif /* * make note of a serial error and quit */ static Fail(msg) char *msg; { syscleanup(); fprintf(stderr, msg); fprintf(stderr, "\n"); exit(2); } /* * default interrupt handler */ static int defhdlr() { printf("*** BREAK ***\n"); doexit(1); } /* * sysinit -- Amiga specific initialization */ sysinit() { register struct IOExtSer *iob; /* set current process info */ CurProc = (struct Process *)FindTask((char *)NULL); CurCLI = (struct CommandLineInterface *)BADDR(CurProc->pr_CLI); backgrd = (CurCLI == NULL || CurCLI->cli_Background); savewindow = CurProc->pr_WindowPtr; /* default interrupts to exit handler */ intsigs = BREAKSIGS; inthdlr = defhdlr; #ifdef LAT310 signal(SIGINT, SIG_IGN); #else Enable_Abort = 0; #endif /* allocate console ports and IO blocks */ if ((conport = CreatePort((char *)NULL, 0L)) == NULL) Fail("no console MsgPort"); if ((conpkt = CreatePacket()) == NULL) Fail("no console packet"); /* allocate serial ports and IO blocks */ if ((serport = CreatePort((char *)NULL, 0L)) == NULL) Fail("no serial MsgPort"); iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob)); if ((WriteIOB = iob) == NULL) Fail("no WriteIOB"); iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob)); if ((ReadIOB = iob) == NULL) Fail("no ReadIOB"); /* open the timer device */ TimerIOB = (struct timerequest *) CreateExtIO(serport,(LONG)sizeof(*TimerIOB)); if (TimerIOB == NULL) Fail("no TimerIOB"); if (OpenDevice(TIMERNAME, (LONG)UNIT_VBLANK, TimerIOB, 0L) != 0) Fail("no timer device"); timeropen = TRUE; /* open the Intuition library */ if (!IntuitionBase && (IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0L) ) == NULL ) Fail("can't open Intuition"); /* open the serial device to get configuration */ iob->io_SerFlags = SERF_SHARED; if (OpenDevice(SERIALNAME, 0L, iob, 0L) != 0) Fail("can't open serial.device"); /* set parameters from system defaults */ flow = !(iob->io_SerFlags & SERF_XDISABLED); parity = !(iob->io_SerFlags & SERF_PARTY_ON) ? 0 : (iob->io_SerFlags & SERF_PARTY_ODD) ? 'o' : 'e'; speed = iob->io_Baud; mdmtyp = (iob->io_SerFlags & SERF_7WIRE) != 0; CloseDevice(iob); serialopen = FALSE; return(0); } /* * syscleanup -- Amiga specific cleanup */ syscleanup() { /* close everything */ if (serialopen) CloseDevice(ReadIOB); if (timeropen) CloseDevice(TimerIOB); if (TimerIOB) DeleteExtIO(TimerIOB, (LONG)sizeof(*TimerIOB)); if (WriteIOB) DeleteExtIO(WriteIOB, (LONG)sizeof(*WriteIOB)); if (ReadIOB) DeleteExtIO(ReadIOB, (LONG)sizeof(*ReadIOB)); if (serport) DeletePort(serport); if (conpkt) DeletePacket(conpkt); if (conport) DeletePort(conport); reqres(); if (IntuitionBase) { CloseLibrary(IntuitionBase); IntuitionBase = NULL; } /* reset standard I/O */ if (rawcon > 0) { /* restore Lattice AmigaDOS file handles */ DOSFH(0) = Input(); DOSFH(1) = Output(); DOSFH(2) = saverr; #ifdef LAT310 close(rawcon); #else Close(rawcon); #endif } } /* * reqoff -- turn requestors off * When AmigaDOS encounters an error that user intervention can fix * (like inserting the correct disk), it normally puts up a requestor. * The following code disables requestors, causing an error to be * returned instead. */ reqoff() { pushwindow = CurProc->pr_WindowPtr; CurProc->pr_WindowPtr = (APTR)-1; } /* * reqpop -- restore requesters to action at last reqoff */ reqpop() { CurProc->pr_WindowPtr = pushwindow; } /* * reqres -- restore requestors to startup action */ reqres() { CurProc->pr_WindowPtr = savewindow; } /* * KillIO -- terminate an I/O request */ static int KillIO(iob) struct IORequest *iob; { AbortIO(iob); return(WaitIO(iob)); } /* * DoIOQuick -- DoIO with quick IO * This should not be used where waiting is expected since * it cannot be interrupted. */ static int DoIOQuick(iob) register struct IORequest *iob; { register int D7Save; /* V1.1 bug. IO sometimes trashes D7 */ /* do I/O with quick option, wait around if necessary */ iob->io_Flags = IOF_QUICK; if (BeginIO(iob) == 0 && !(iob->io_Flags & IOF_QUICK)) WaitIO(iob); /* return the error, if any */ return((int)iob->io_Error); } /* * ttopen -- open the serial device * If already open, returns 0 immediately. * Otherwise, the ttname is compare to SERIALNAME and used to * open the serial device, and, if the value of *lcl is < 0, it is * reset to 1 indicating local mode. Returns -1 on error. */ ttopen(ttname, lcl, modem) char *ttname; int *lcl; int modem; { register struct IOExtSer *iob = ReadIOB; if (serialopen) return(0); /* ignore if already open */ /* verify the serial name */ if (strcmp(ttname, SERIALNAME) != 0) return(-1); /* set open modes */ iob->io_SerFlags = (modem) ? (SERF_SHARED|SERF_7WIRE) : SERF_SHARED; /* open the serial device */ if (OpenDevice(ttname, 0L, iob, 0L) != 0) return(-1); serialopen = TRUE; pendread = pendwrite = pendconsole = FALSE; queuedser = -1; /* fill in the fields of the other IO blocks */ *WriteIOB = *iob; /* set local mode */ if (*lcl == -1) *lcl = 1; /* always local */ return(0); } /* * StartTimer -- start a timeout */ static VOID StartTimer(secs, micro) LONG secs, micro; { TimerIOB->tr_node.io_Command = TR_ADDREQUEST; TimerIOB->tr_time.tv_secs = secs; TimerIOB->tr_time.tv_micro = micro; SendIO(TimerIOB); } /* * SerialWait -- wait for serial I/O to terminate * return I/O error */ static int SerialWait(iob, timeout) register struct IOExtSer *iob; int timeout; { register int D7Save; /* save register D7 */ register LONG sigs; register struct timerequest *timer = TimerIOB; register LONG waitsigs; /* set up timeout if necessary */ if (timeout > 0) StartTimer((LONG)timeout, 0L); /* wait for completion, timeout, or interrupt */ sigs = 0; waitsigs = (1L << serport->mp_SigBit) | intsigs; for (;;) { if (sigs & intsigs) { /* interrupted */ if (timeout > 0) KillIO(timer); KillIO(iob); testint(sigs); return(-1); } if (CheckIO(iob)) { if (timeout > 0) KillIO(timer); return(WaitIO(iob)); } if (timeout > 0 && CheckIO(timer)) { KillIO(iob); WaitIO(timer); /* restart if XOFF'ed */ iob->IOSer.io_Command = CMD_START; DoIOQuick(iob); return(-1); } sigs = Wait(waitsigs); } } /* * TerminateRead -- wait for queued read to finish */ static int TerminateRead() { if (!pendread) return(0); if (WaitIO(ReadIOB) == 0) queuedser = serbufc; pendread = FALSE; return((int)ReadIOB->IOSer.io_Error); } /* * TerminateWrite -- ensure WriteIOB is ready for reuse */ static int TerminateWrite(timeout) int timeout; { testint(0L); if (!pendwrite) return(0); pendwrite = FALSE; return(SerialWait(WriteIOB, timeout)); } /* * SerialReset -- terminate pending serial and console I/O */ static VOID SerialReset() { if (pendread) { AbortIO(ReadIOB); /* should work even if read finished */ TerminateRead(); } if (pendconsole) { /* this does not happen normally */ WaitPort(conport); GetMsg(conport); pendconsole = FALSE; } if (pendwrite) TerminateWrite(1); } /* * ttres -- reset serial device */ ttres() { if (!serialopen) return(-1); /* reset everything */ SerialReset(); ReadIOB->IOSer.io_Command = CMD_RESET; return(DoIOQuick(ReadIOB) ? -1 : 0); } /* * ttclos -- close the serial device */ ttclos() { if (!serialopen) return(0); if (ttres() < 0) return(-1); CloseDevice(ReadIOB); serialopen = FALSE; return(0); } /* * tthang -- hang up phone line * Drops DTR by closing serial.device */ tthang() { return((serialopen) ? ttclos() : -1); } /* * ttpkt -- set serial device up for packet transmission * sets serial parameters */ ttpkt(baud, flow) int baud, flow; { extern UBYTE eol; register struct IOExtSer *iob = ReadIOB; int speed; if (!serialopen || pendread) return(-1); /* terminate any pending writes */ TerminateWrite(1); /* fill in parameters */ iob->io_CtlChar = 0x11130000; if (baud >= 0 && (speed = ttsspd(baud)) >= 0) iob->io_Baud = speed; setmem(&iob->io_TermArray, sizeof(struct IOTArray), eol); iob->io_ReadLen = iob->io_WriteLen = 8; iob->io_StopBits = 1; if (flow) iob->io_SerFlags &= ~SERF_XDISABLED; else iob->io_SerFlags |= SERF_XDISABLED; /* if no flow and high baud rate, RAD_BOOGIE is appropriate */ if (!flow && iob->io_Baud > 19200) iob->io_SerFlags |= SERF_RAD_BOOGIE; else iob->io_SerFlags &= ~SERF_RAD_BOOGIE; iob->io_SerFlags &= ~(SERF_EOFMODE|SERF_PARTY_ON|SERF_PARTY_ODD); /* set the parameters */ iob->IOSer.io_Command = SDCMD_SETPARAMS; if (DoIOQuick(iob) != 0) return(-1); return(ttflui()); } /* * ttvt -- set up serial device for connect mode */ ttvt(baud, flow) int baud, flow; { return(ttpkt(baud, flow)); } /* * ttsspd -- verify baud rate */ int ttsspd(speed) { if (speed < 110 || speed > 292000) return(-1); return(max(112, speed)); } /* * ttflui -- flush serial device input buffer */ ttflui() { if (!serialopen || pendread) return(-1); queuedser = -1; ReadIOB->IOSer.io_Command = CMD_CLEAR; return(DoIOQuick(ReadIOB) ? -1 : 0); } static struct IntuiText BodyText = { -1, -1, 0, 4, 4, NULL, "Interrupt Requested", NULL }; static struct IntuiText ContinueText = { -1, -1, 0, 4, 4, NULL, "Continue", NULL }; static struct IntuiText AbortText = { -1, -1, 0, 4, 4, NULL, "Exit C-Kermit", NULL }; /* * test for and catch interrupt */ testint(sigs) LONG sigs; { int (*catch)(); /* test for and reset caught interrupt signals */ if (((sigs | SetSignal(0L, (LONG)BREAKSIGS)) & intsigs) && inthdlr) { if (AutoRequest((struct Window *)NULL, &BodyText, &ContinueText, &AbortText, 0L, 0L, 260L, 55L) ) return; catch = inthdlr; inthdlr = NULL; intsigs = 0; (*catch)(); } } /* * conint -- set console interrupt handler */ conint(newhdlr) int (*newhdlr)(); { testint(0L); /* handle any pending interrupts */ inthdlr = newhdlr; /* set the new handler */ intsigs = BREAKSIGS; /* note signal caught */ } /* * connoi -- disable interrupt trapping */ connoi() { inthdlr = NULL; /* disable interrupts */ intsigs = 0; /* note signal ignored */ testint(0L); /* ignore pending interrupts */ } /* * ttchk -- return number of chars immediately available from serial device */ ttchk() { register struct IOExtSer *read = ReadIOB; if (!serialopen) return(-1); testint(0L); if (pendread && !CheckIO(read)) return(0); if (TerminateRead() != 0) return(-1); read->IOSer.io_Command = SDCMD_QUERY; return((DoIOQuick(read) == 0) ? ((queuedser >= 0) + (int)read->IOSer.io_Actual) : -1); } /* * ttxin -- get n characters from serial device */ ttxin(n, buf) int n; char *buf; { return(ttinl(buf, n, 0, -1)); } /* * ttinc -- read character from serial line */ ttinc(timeout) int timeout; { UBYTE ch; return((ttinl(&ch, 1, timeout, -1) > 0) ? (int)ch : -1); } /* * ttol -- write n chars to serial device, assumes <= 256 characters */ ttol(buf, n) char *buf; int n; { register int D7Save; register struct IOExtSer *write = WriteIOB; static char outbuf[256]; /* safe place for output characters */ if (!serialopen) return(-1); if (TerminateWrite(0) != 0) return(-1); pendwrite = TRUE; movmem(buf, outbuf, n); write->IOSer.io_Command = CMD_WRITE; write->IOSer.io_Data = (APTR)outbuf; write->IOSer.io_Length = n; SendIO(write); return(n); } /* * ttoc -- output single character to serial device */ ttoc(c) char c; { return(ttol(&c, 1)); } /* * ttinl -- read from serial device, possibly with timeout and eol character * reads up to n characters, returning the number of characters read * if eol >= 0, reading the eol character will terminate read * if timeout > 0, terminates read if timeout elapses * returns -1 on error, such as timeout or interrupt */ ttinl(buf, n, timeout, eol) register char *buf; int n; int timeout; /* timeout in seconds or <= 0 */ int eol; /* end of line character */ { int m; register int D7Save; register struct IOExtSer *read = ReadIOB; register int count; testint(0L); if (!serialopen || pendread || n <= 0) return(-1); m = (ttprty ? 0177 : 0377); /* parity stripping mask */ /* handle pushback */ if (queuedser >= 0) { *buf = queuedser; queuedser = -1; if ((*buf & 0177) == eol || n == 1) return(1); ++buf; --n; count = 1; } else count = 0; /* set up line terminator */ if (eol >= 0) { /* set up line terminator */ /*** Watch out -- need to recognize 7-bit eol, even if it comes in with ***/ /*** parity bit on. It's not obvious to me how to change this code to ***/ /*** do that! - Frank, C-Kermit 4E ***/ if (eol != *(UBYTE *)&read->io_TermArray) { setmem(&read->io_TermArray, sizeof(struct IOTArray), eol); read->IOSer.io_Command = SDCMD_SETPARAMS; DoIOQuick(read); } read->io_SerFlags |= SERF_EOFMODE; } else read->io_SerFlags &= ~SERF_EOFMODE; /* set up the read */ read->IOSer.io_Command = CMD_READ; read->IOSer.io_Data = (APTR)buf; read->IOSer.io_Length = n; /* perform read quickly if possible */ read->IOSer.io_Flags = IOF_QUICK; BeginIO(read); if (read->IOSer.io_Flags & IOF_QUICK) { read->IOSer.io_Flags = 0; return ((read->IOSer.io_Error == 0) ? (count + (int)read->IOSer.io_Actual) : -1); } /*** Need code somewhere here to strip parity if ttprty != 0 ***/ /* wait for read to complete */ return ((SerialWait(read, timeout) != 0) ? -1 : count + (int)read->IOSer.io_Actual ); } /* * Sleeper -- perform an interruptible timeout */ static Sleeper(secs, micro) LONG secs, micro; { register int D7Save; register LONG sigs; register LONG waitsigs; register struct timerequest *timer = TimerIOB; if (!timeropen) return(-1); StartTimer(secs, micro); sigs = 0; waitsigs = (1L << serport->mp_SigBit) | intsigs; for (;;) { if (CheckIO(timer)) { WaitIO(timer); return(0); } if (sigs & intsigs) { KillIO(timer); testint(sigs); return(-1); } sigs = Wait(waitsigs); } } /* * sleep -- wait n seconds */ sleep(n) int n; { return(Sleeper((LONG)n, 0L)); } /* * msleep -- wait n milliseconds */ msleep(m) int m; { return(Sleeper((LONG)(m / 1000), (m % 1000) * 1000L)); } /* * rtimer -- reset elapsed time */ rtimer() { DateStamp(&prevtime); } /* * gtimer -- get currently elapsed time in seconds */ gtimer() { int x; struct DateStamp curtime; DateStamp(&curtime); x = ((curtime.ds_Days - prevtime.ds_Days ) * 1440 + (curtime.ds_Minute - prevtime.ds_Minute) ) * 60 + (curtime.ds_Tick - prevtime.ds_Tick ) / 50; return((x < 0) ? 0 : x ); } /* * ztime -- format current date and time into string */ ztime(s) char **s; { /* * The following date code taken from a USENET article by * Tomas Rokicki(rokicki@Navajo.ARPA) */ static char *months[] = { NULL, "January","February","March","April","May","June", "July","August","September","October","November","December"}; static char buf[32]; long n ; int m, d, y ; struct DateStamp datetime; DateStamp(&datetime); n = datetime.ds_Days - 2251 ; y = (4 * n + 3) / 1461 ; n -= 1461 * y / 4 ; y += 1984 ; m = (5 * n + 2) / 153 ; d = n - (153 * m + 2) / 5 + 1 ; m += 3 ; if (m > 12) { y++ ; m -= 12 ; } sprintf(buf, "%02d:%02d:%02d %s %d, %d", datetime.ds_Minute / 60, datetime.ds_Minute % 60, datetime.ds_Tick / 50, months[m], d, y) ; *s = buf; } /* * congm -- save console modes */ congm() { if (!saverr) saverr = DOSFH(2); return(0); } /* * CreateWindow -- create window and jam it into standard I/O */ int CreateWindow(esc) { if (rawcon > 0) return(0); congm(); #ifdef LAT310 if ((rawcon = open("RAW:0/0/640/200/Kermit", O_RDWR)) <= 0) return(-1); #else if ((rawcon = Open("RAW:0/0/640/200/Kermit", (LONG)MODE_NEWFILE)) == 0) return(-1); #endif DOSFH(0) = DOSFH(1) = DOSFH(2) = rawcon; /* if we create a window, don't abort on errors or echo */ backgrd = FALSE; ckxech = 1; return(0); } /* * concb -- put console in single character wakeup mode */ concb(esc) { if (rawcon) return(0); if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput) return(0); return(CreateWindow(esc)); } /* * conbin -- put console in raw mode */ conbin(esc) { if (rawcon) return(0); if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput) return(isatty(0) ? 0 : -1); return(CreateWindow(esc)); } /* * conres -- restore console * we actually restore in syscleanup() */ conres() { return(0); } /* * conoc -- output character to console */ conoc(c) { putchar(c); fflush(stdout); testint(0L); } /* * conxo -- output x chars to console */ conxo(n, buf) char *buf; int n; { fflush(stdout); write(FILENO(1), buf, n); testint(0L); } /* * conol -- output line to console */ conol(l) char *l; { fputs(l, stdout); fflush(stdout); testint(0L); } /* * conola -- output line array to console */ conola(l) char **l; { for (; **l; ++l) conol(*l); } /* * conoll -- output line with CRLF */ conoll(l) char *l; { conol(l); conxo(2, "\r\n"); } /* * conchk -- returns nonzero if characters available from console */ conchk() { fflush(stdout); testint(0L); return(WaitForChar(DOSFH(0), 0L) != 0); } /* * coninc -- get input character from console */ coninc(timeout) int timeout; { UBYTE ch; fflush(stdout); testint(0L); if (timeout > 0 && !WaitForChar(DOSFH(0), timeout * 1000000L)) return(-1); if (read(FILENO(0), &ch, 1) < 1) return(-1); testint(0L); return((int)ch); } /* * ttsndb -- send a BREAK * flushes queued and active output */ ttsndb() { register int D7Save; if (!serialopen) return(-1); /* flush queued output */ TerminateWrite(1); nttoq = 0; pendwrite = TRUE; WriteIOB->IOSer.io_Command = SDCMD_BREAK; WriteIOB->io_SerFlags &= ~SERF_QUEUEDBRK; SendIO(WriteIOB); return(0); } /* * ttocq -- write char to serial device, queueing if necessary * returns -2 on overrun, -1 on serial error * use only in connect mode */ ttocq(c) char c; { register int i; if (!serialopen) return(-1); if (pendwrite && CheckIO(WriteIOB)) { pendwrite = FALSE; if (WaitIO(WriteIOB) != 0) return(-1); } if (pendwrite) { if (nttoq >= NTTOQ) return(-2); /* overrun */ ttoq[(pttoq + nttoq++) % NTTOQ] = c; } else if (nttoq == 0) return(ttoc(c)); else { i = ttoc(ttoq[pttoq]); ttoq[(pttoq + nttoq) % NTTOQ] = c; pttoq = (pttoq + 1) % NTTOQ; if (i < 0) return(-1); } return(1); } /* * ttonq -- returns number of characters in serial output queue */ int ttonq() { return(nttoq); } /* * conttb -- prepare for contti() usage */ conttb() { /* flush queued input and output */ queuedcon = -1; pttoq = nttoq = 0; } /* * contte -- end contti() usage * this can be called after a tthang, it which case ttres will already * have done this cleanup */ contte() { /* clear any pending ^C, ^D interrupts */ testint(0L); /* terminate any pending I/O */ if (serialopen) SerialReset(); } /* * contti -- wait for console or tty input * returns next console input or -1 when serial input available */ int contti() { register int D7Save; register int i; register LONG waitsigs; register struct DosPacket *pkt = conpkt; register struct IOExtSer *read = ReadIOB; static UBYTE conchar; BPTR dosfh = DOSFH(0); struct FileHandle *fh = (struct FileHandle *)BADDR(dosfh); if (queuedcon >= 0) { conchar = queuedcon; queuedcon = -1; return((int)conchar); } if (!pendconsole) { /* start a console read */ pkt->dp_Port = conport; pkt->dp_Type = ACTION_READ; pkt->dp_Arg1 = (LONG)dosfh; pkt->dp_Arg2 = (LONG)&conchar; pkt->dp_Arg3 = 1; PutMsg(fh->fh_Process, pkt->dp_Link); pendconsole = TRUE; } if (queuedser < 0 && !pendread) { /* start a serial read */ read->IOSer.io_Command = CMD_READ; read->IOSer.io_Data = (APTR)&serbufc; read->IOSer.io_Length = 1; SendIO(read); pendread = TRUE; } waitsigs = (1L << serport->mp_SigBit) | (1L << conport->mp_SigBit); for (;;) { if (pendwrite && CheckIO(WriteIOB)) { pendwrite = FALSE; if (nttoq > 0) { i = ttoc(ttoq[pttoq]); pttoq = (pttoq + 1) % NTTOQ; --nttoq; if (i < 0) return(-1); } } /* give the console first chance */ if (GetMsg(conport)) { pendconsole = FALSE; if (pkt->dp_Res1 != 1) return(-1); /* translate CSI to ESC [ */ if (conchar == 0x9B) { conchar = 0x1B; queuedcon = '['; } return((int)conchar); } if (queuedser >= 0) return(-2); if (CheckIO(read)) return((TerminateRead() == 0) ? -2 : -1); Wait(waitsigs); } }