#ifndef OS_2 #pragma message("This Module For OS/2") #else #include #ifdef IBM_C #include #else #include #endif #include #include #include #include #define INCL_DOS #define INCL_DOSDEVICES #define INCL_DOSDEVIOCTL #define INCL_DOSSEMAPHORES #define INCL_NOPM #include #include "bink.h" #include "com.h" #include "async.h" /*--------------------------------------------------------* * This file contains the operating system specific * * serial communications routines for OS/2. * * * * (C) Copyright Peter Fitzsimmons Sun 04-16-1989 * * * * Add-ins for BinkleyTerm on Sat 05-06-1989 * *--------------------------------------------------------*/ /* This one has excellent send or receive, even with 8088 */ /* but the xmit rate is a bit low in Janus w/o SetPrty. */ /* #define DEBUG */ /* #define MultiWrt */ void status_line (char *,...); static void zap_zbuf(void); /* Private data */ /* static HFILE hfComHandle = -1; */ /* handle from DosOpen() */ HFILE hfComHandle = -1; /* handle from DosOpen() */ /* transmitter stuff */ #define TSIZE 8192 static unsigned char tBuf[TSIZE]; static int tpos = 0; static unsigned char zTxBuf[TSIZE]; static int zpos = 0; static int tBufsize = 0; static unsigned int TQSize = 0; /* static HSEM WriteSem = 0; */ ULONG WriteSem = 0; /* receiver stuff */ #define RSIZE 8192 static unsigned char rbuf[RSIZE]; static int rpos = 0; static int rbufsize = 0; static USHORT Rbytes = 0; static word RQBbytes = 0; static word RQBbyte2 = 0; #ifdef DEBUG #define debug_msg(m,c) status_line("!" m, c) #define IOCtl(func, data, parm) _ioctl(#func, func, (void far *) data, (void far *) parm) static int _ioctl(char *funcname, int func, void far * data, void far * parm) { int i; if (i = DosDevIOCtl((PVOID) data, (PVOID) parm, func, IOCTL_ASYNC, (HFILE) hfComHandle)) { printf("ioctl(%s) err(0x%04x)\n", funcname, i); status_line("!ioctl(%s) err(0x%04x)", funcname, i); } return (i); } #else #define debug_msg(m,c) #define IOCtl(func, data, parm) DosDevIOCtl((PVOID) data, (PVOID) parm, func, IOCTL_ASYNC, (HFILE) hfComHandle) #endif static int com_getDCB(struct _DCBINFO far * dcb); static int com_setDCB(struct _DCBINFO far * dcb); static void com_kick(void); /* com_init() : Intialize communications port. Baud rate is preserved. * int port : Hardware port (0 based) to init * -OR- char *unc : Full UNC \\networkId\modemId to init. * * if unc==NULL, port is used. if unc != NULL, unc is used */ int com_init(int port, char far *unc) { char str[30]; char *s; USHORT ActionTaken; /* action: returned by OS/2 */ USHORT stat; DCBINFO sDCB; RXQUEUE q; cputs("\033[1;33mOS/2 FOSSIL emulator for BinkleyTerm, Peter Fitzsimmons (1:250/628)\033[0m\r\n"); sprintf(str, "COM%d", port + 1); if (!unc) unc = str; #ifdef DEBUG stat = DosOpen((PSZ) unc,(PHFILE) &hfComHandle,(PUSHORT) &ActionTaken, 0L, 0, 0x0001, 0x4012, 0L); #else stat = DosOpen((PSZ) unc,(PHFILE) &hfComHandle,(PUSHORT) &ActionTaken, 0L, 0, 0x0001, 0x6012, 0L); #endif if (stat) { hfComHandle = -1; printf("com_init() : DosOpen() error 0x%04x on '%s'\n", stat, unc); return (FALSE); } (void) DosSemClear((HSEM) &WriteSem); if (!IOCtl(ASYNC_GETINQUECOUNT, (PVOID) &q, (PVOID) 0L)) { s = getenv("RBUF"); if (s) rbufsize = min( RSIZE, atoi(s)); else rbufsize = RSIZE; RQBbytes = min( RSIZE, rbufsize); RQBbyte2 = RQBbytes/2; #ifdef DEBUG printf("com_init() : ASYNC Input Buffer size is %d'\n", q.cbQueue); #endif } if (!IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L)) { s = getenv("TBUF"); if (s) tBufsize = min( TSIZE, atoi(s)); else tBufsize = TSIZE; TQSize = min(TSIZE, q.cbQueue); #ifdef DEBUG printf("com_init() : ASYNC Output Buffer size is %d'\n", q.cbQueue); #endif } com_XON_disable(); com_getDCB((struct _DCBINFO far *) &sDCB); /* turn off IDSR, ODSR */ /* sDCB.bFlags1 &= ~(MODE_DSR_HANDSHAKE | MODE_DSR_SENSITIVITY); */ /* raise DTR, CTS output flow control */ /* sDCB.bFlags1 |= (MODE_DTR_CONTROL | MODE_CTS_HANDSHAKE); */ /* turn off XON/XOFF flow control, error replacement off, null * stripping off, break replacement off */ sDCB.bFlags2 &= ~(MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE | MODE_ERROR_CHAR | MODE_NULL_STRIPPING | MODE_BREAK_CHAR); /* RTS enable */ /* sDCB.bFlags2 |= MODE_RTS_CONTROL; */ sDCB.bFlags3 |= (MODE_NO_WRITE_TIMEOUT | MODE_NOWAIT_READ_TIMEOUT); sDCB.usReadTimeout = 1000; sDCB.usWriteTimeout = 1000; com_setDCB((struct _DCBINFO far *) &sDCB); return (!stat); } void com_DTR_on(void) { DCBINFO sDCB; com_getDCB((struct _DCBINFO far *) &sDCB); sDCB.bFlags1 |= MODE_DTR_CONTROL; /* raise DTR */ com_setDCB((struct _DCBINFO far *) &sDCB); } void com_DTR_off(void) { DCBINFO sDCB; com_getDCB((struct _DCBINFO far *) &sDCB); sDCB.bFlags1 &= ~MODE_DTR_CONTROL; /* lower DTR */ com_setDCB((struct _DCBINFO far *) &sDCB); } /* close communications channel. Baud rate is preserved. */ int com_fini(void) { int stat; if (!(hfComHandle == -1)) { com_wait(); while ((DosSemWait((HSEM) &WriteSem, 1L)) && (com_online())) ; com_clear_in(); com_clear_out(); if (stat = DosClose(hfComHandle)) { hfComHandle = -1; debug_msg("DosClose() error 0x%04x", stat); return (FALSE); } hfComHandle = -1; } return(TRUE); } long com_cur_baud(void) { USHORT rate = 0; IOCtl(ASYNC_GETBAUDRATE, (PVOID) &rate, (PVOID) 0L); return ((long) rate); } /* com_set_baud() : * * rate = 110..19200 * parity = N, E, O, M, S (none,even, odd, mark, space) * databits = 5..8 * stopbits = 1..2 * */ int com_set_baud(unsigned rate, char parity, int databits, int stopbits) { int stat; struct _LINECONTROL { BYTE bDataBits; BYTE bParity; BYTE bStopBits; BYTE fbTransBreak; } lc; stat = IOCtl(ASYNC_SETBAUDRATE, (PVOID) 0L, (PVOID) &rate); if (stat) { return (FALSE); } lc.bDataBits = (BYTE) databits; switch (stopbits) { case 1: lc.bStopBits = 0; break; case 2: lc.bStopBits = 2; break; default: if (databits == 5) lc.bStopBits = 1; } lc.fbTransBreak = 0; switch (toupper(parity)) { case 'N': lc.bParity = 0; break; case 'O': lc.bParity = 1; break; case 'E': lc.bParity = 2; break; case 'M': lc.bParity = 3; break; case 'S': lc.bParity = 4; break; default: debug_msg("Bad parity '%c'", parity); return (FALSE); } stat = IOCtl(ASYNC_SETLINECTRL, (PVOID) 0L, (PVOID) &lc); if (stat) { return (FALSE); } return (TRUE); } static int com_getDCB(struct _DCBINFO far * dcb) { int stat; stat = IOCtl(ASYNC_GETDCBINFO, (PVOID) dcb, (PVOID) 0L); return (!stat); } static int com_setDCB(struct _DCBINFO far * dcb) { int stat; stat = IOCtl(ASYNC_SETDCBINFO, (PVOID) 0L, (PVOID) dcb); return (!stat); } void com_XON_disable(void) { DCBINFO sDCB; if (com_getDCB((struct _DCBINFO far *) &sDCB)) { /* disable auto Xmit and recv flow control */ sDCB.bFlags2 &= ~(MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE); com_setDCB((struct _DCBINFO far *) &sDCB); } } void com_XON_enable(void) { DCBINFO sDCB; if (com_getDCB((struct _DCBINFO far *) &sDCB)) { /* enable auto Xmit and recv flow control */ sDCB.bFlags2 |= (MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE); com_setDCB((struct _DCBINFO far *) &sDCB); } } /* nuke receive buffer */ void com_clear_in(void) { int stat; char FlushParm = 0; /* param to flush IOCTL function */ Rbytes = rpos = 0; stat = DosDevIOCtl((PVOID) 0L, (PVOID) &FlushParm, DEV_FLUSHINPUT, IOCTL_GENERAL, hfComHandle); if (stat) { debug_msg("DEV_FLUSHINPUT err 0x%04x", stat); } } /* com_getbuf() : return negative value if error */ int com_getbuf(void) { int stat = 0; RXQUEUE q; USHORT Rbytet; if (rpos == Rbytes) /* If buffer empty, */ rpos = Rbytes = 0; /* reset pointers */ Rbytet = Rbytes; /* Save old count */ Rbytes = 0; /* Clear new count */ if (!(IOCtl(ASYNC_GETINQUECOUNT, (PVOID) &q, (PVOID) 0L))) { if (q.cbChars > 0) stat = DosRead(hfComHandle, rbuf+Rbytet, (USHORT) min(RQBbytes-Rbytet,q.cbChars), &Rbytes); else return (-1); } else return (-1); if (stat && !Rbytes && (!(stat==ERROR_MORE_DATA))) { debug_msg("DosRead() error 0x%04x", stat); return (-1); } Rbytes += Rbytet; return (TRUE); } /* com_getchar() : return negative value if error */ int com_getchar(void) { if (rpos != Rbytes) return ((int) rbuf[rpos++]); if (com_getbuf() == TRUE) return ((int) rbuf[rpos++]); return (-1); } /*non destructive read ahead; no wait */ int com_peek(void) { int c; if (!com_char_avail()) c = -1; else { c = com_getchar(); if (c != -1) rpos--; } return (c); } /* if RXQueue over half full, return TRUE */ bool com_in_check(void) { RXQUEUE q; if (IOCtl(ASYNC_GETINQUECOUNT, (PVOID) &q, (PVOID) 0L)) return (FALSE); return ((bool)((q.cbChars > RQBbyte2) ? TRUE : FALSE)); } /* return number of chars in input buffer */ int com_char_avail(void) { RXQUEUE q; if (rpos < Rbytes) return (Rbytes-rpos); return ((!(IOCtl(ASYNC_GETINQUECOUNT, (PVOID) (PVOID) &q, 0L))) ? q.cbChars : FALSE ); } /* return non 0 value if carrier detected */ bool com_online(void) { BYTE msr; if (hfComHandle == -1) return(FALSE); if (IOCtl(ASYNC_GETMODEMINPUT, (PVOID) &msr, (PVOID) 0L)) return (FALSE); return (msr & DCD_ON); } /* com_break() : start break if on==TRUE, stop break if on==FALSE */ void com_break(int on) { int cmd; USHORT comerr; cmd = (on) ? ASYNC_SETBREAKON : ASYNC_SETBREAKOFF; IOCtl(cmd, (PVOID) &comerr, (PVOID) 0L); } /* com_out_empty() : return TRUE if output buffer is empty */ bool com_out_empty(void) { RXQUEUE q; if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L)) return (TRUE); if (!com_online()) return (TRUE); if (com_in_check()) (void) com_getbuf(); /* if (DosSemWait((HSEM) &WriteSem, 1L)) return (FALSE); */ if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L)) return (TRUE); return ((bool) (q.cbChars < q.cbQueue)); } /* com_out_full() : return TRUE if output buffer is full */ bool com_out_full(void) { RXQUEUE q; if (com_in_check()) (void) com_getbuf(); if (!com_online()) return (FALSE); /* if (DosSemWait((HSEM) &WriteSem, 1L)) return (TRUE); */ if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L)) return (TRUE); return ((bool) !(q.cbChars < q.cbQueue)); } /* nuke transmit buffer */ void com_clear_out(void) { char FlushParm = 0; /* param to flush IOCTL function */ int stat; /* do { if (!com_online()) break; if (com_in_check()) (void) com_getbuf(); } while(DosSemWait((HSEM) &WriteSem, 1L)); */ stat = IOCtl(ASYNC_STARTTRANSMIT, (PVOID) 0L, (PVOID) 0L); if (stat) { debug_msg("ASYNC_STARTTRANSMIT err 0x%04x", stat); } zap_zbuf(); stat = DosDevIOCtl((PVOID) 0L, (PVOID) &FlushParm, DEV_FLUSHOUTPUT, IOCTL_GENERAL, hfComHandle); if (stat) { debug_msg("DEV_FLUSHOUTPUT err 0x%04x", stat); } DosSemClear((HSEM) &WriteSem); } /* com_putc_now() : disregard any buffering and send a byte now damnit! */ /* this function should be called only during emergencies...like when * trying to cancel a file transfer */ /* Since the equivalent is a Com_ call, which in DOS is unsigned... */ unsigned com_putc_now(byte c) { return (!IOCtl(ASYNC_TRANSMITIMM, (PVOID) 0L, (PVOID) &c)); } /* com_putc() : output to com port */ /* This function is very slow..where possile, write to com port in blocks * using com_write() instead...especially above 2400 bps */ void com_putc(byte c) { static USHORT bytes; int stat; RXQUEUE q; if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L)) return; do { if (com_in_check()) (void) com_getbuf(); } while(DosSemWait((HSEM) &WriteSem, 1L)); do { if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L)) return; if (com_in_check()) (void) com_getbuf(); if (q.cbChars >= q.cbQueue) DosSleep (1L); } while (q.cbChars >= q.cbQueue); /* * DosWriteAsync() didn't work here. */ if (stat = DosWrite(hfComHandle, &c, 1, &bytes)) debug_msg("DosWrite() err 0x%04x", stat); } /* com_write() : buffered block write */ void com_write(char *buf, unsigned int num, int carcheck) { static USHORT err, bytes; #ifdef MultiWrt unsigned int tnum = 0; #endif do { if ((carcheck) && !com_online()) return; if (com_in_check()) (void) com_getbuf(); } while(DosSemWait((HSEM) &WriteSem, 1L)); (void) DosSemRequest((HSEM) &WriteSem, 0L); #ifdef MultiWrt while (tnum+TQSize > num+TQSize) { memcpy (tBuf, &buf[tnum], TQSize); DosWriteAsync(hfComHandle, (PULONG) &WriteSem, &err, tBuf, TQSize, &bytes); tnum += TQSize; do { if ((carcheck) && !com_online()) return; if (com_in_check()) (void) com_getbuf(); } while(DosSemWait((HSEM) &WriteSem, 1L)); (void) DosSemRequest((HSEM) &WriteSem, 0L); } memcpy (tBuf, &buf[tnum], num-tnum); DosWriteAsync(hfComHandle, (PULONG) &WriteSem, &err, tBuf, num-tnum, &bytes); #else memcpy (tBuf, buf, num); DosWriteAsync(hfComHandle, (PULONG) &WriteSem, &err, tBuf, num, &bytes); #endif } /* wait for output buffer to empty */ void com_wait(void) { while ((!com_out_empty()) && com_online()) DosSleep (1L); } extern unsigned int baud; extern unsigned int comm_bits; extern unsigned int parity; extern unsigned int stop_bits; extern struct baud_str btypes[]; void MDM_ENABLE(unsigned rate) { char _parity; int databits; int stopbits; com_clear_out(); com_clear_in(); databits = 7 + (comm_bits == BITS_8); stopbits = 1 + (stop_bits == STOP_2); switch (parity) { case NO_PARITY: _parity = 'N'; break; case ODD_PARITY: _parity = 'O'; break; case EVEN_PARITY: _parity = 'E'; break; } com_set_baud(rate, _parity, databits, stopbits); } void MDM_DISABLE(void) { if (hfComHandle == -1) return; com_clear_out(); com_clear_in(); com_fini(); } /* zsend.c uses BUFFER_BYTE and UNBUFFER_BYTES...good idea. */ void BUFFER_BYTE(unsigned char ch) { if (zpos == tBufsize) UNBUFFER_BYTES(); zTxBuf[zpos++] = ch; } void UNBUFFER_BYTES(void) { if (com_online() && zpos) (zpos == 1)?(com_putc(zTxBuf[0])):(com_write(zTxBuf,zpos,1)); zpos = 0; } static void zap_zbuf(void) { zpos = 0; } unsigned Cominit(int port) { if (hfComHandle != -1) com_fini(); if (port == 0xff || com_init(port, NULL)) return (0x1954); else return (0); } #endif /* OS_2 */