home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / OS2 / BSRCP240.ZIP / ASYNC.C next >
Encoding:
C/C++ Source or Header  |  1990-09-01  |  15.0 KB  |  664 lines

  1. #ifndef OS_2
  2. #pragma message("This Module For OS/2")
  3. #else
  4. #include <stdio.h>
  5. #ifdef IBM_C
  6. #include <stdarg.h>
  7. #else
  8. #include <varargs.h>
  9. #endif
  10. #include <ctype.h>
  11. #include <conio.h>
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #define INCL_DOS
  15. #define INCL_DOSDEVICES
  16. #define INCL_DOSDEVIOCTL
  17. #define INCL_DOSSEMAPHORES
  18. #define INCL_NOPM
  19. #include <os2.h>
  20. #include "bink.h"
  21. #include "com.h"
  22. #include "async.h"
  23.  
  24. /*--------------------------------------------------------*
  25.  * This file contains the operating system specific       *
  26.  * serial communications routines for OS/2.               *
  27.  *                                                          *
  28.  * (C) Copyright Peter Fitzsimmons Sun    04-16-1989          *
  29.  *                                                          *
  30.  * Add-ins for BinkleyTerm on Sat  05-06-1989              *
  31.  *--------------------------------------------------------*/
  32.  
  33. /* This one has excellent send or receive, even with 8088 */
  34. /* but the xmit rate is a bit low in Janus w/o SetPrty.   */
  35.  
  36.  
  37. /* #define DEBUG */
  38. /* #define MultiWrt */
  39.  
  40.  
  41. void status_line (char *,...);
  42. static void zap_zbuf(void);
  43.  
  44. /* Private data */
  45. /* static HFILE hfComHandle = -1; */     /* handle from DosOpen() */
  46. HFILE hfComHandle = -1;      /* handle from DosOpen() */
  47.  
  48. /* transmitter stuff */
  49. #define TSIZE 8192
  50. static unsigned char tBuf[TSIZE];
  51. static int tpos = 0;
  52. static unsigned char zTxBuf[TSIZE];
  53. static int zpos = 0;
  54. static int tBufsize = 0;
  55. static unsigned int TQSize = 0;
  56. /* static HSEM WriteSem = 0; */
  57. ULONG WriteSem = 0;
  58.  
  59. /* receiver stuff */
  60. #define RSIZE 8192
  61. static unsigned char rbuf[RSIZE];
  62. static int rpos = 0;
  63. static int rbufsize = 0;
  64. static USHORT Rbytes = 0;
  65. static word RQBbytes = 0;
  66. static word RQBbyte2 = 0;
  67.  
  68. #ifdef DEBUG
  69.  
  70. #define debug_msg(m,c)    status_line("!" m, c)
  71. #define IOCtl(func, data, parm)  _ioctl(#func, func, (void far *) data, (void far *) parm)
  72.  
  73. static int _ioctl(char *funcname, int func, void far * data, void far * parm)
  74. {
  75.     int i;
  76.  
  77.     if (i = DosDevIOCtl((PVOID) data, (PVOID) parm, func, IOCTL_ASYNC, (HFILE) hfComHandle)) {
  78.         printf("ioctl(%s) err(0x%04x)\n", funcname, i);
  79.         status_line("!ioctl(%s) err(0x%04x)", funcname, i);
  80.     }
  81.     return (i);
  82. }
  83.  
  84. #else
  85. #define debug_msg(m,c)
  86. #define IOCtl(func, data, parm) DosDevIOCtl((PVOID) data, (PVOID) parm, func, IOCTL_ASYNC, (HFILE) hfComHandle)
  87. #endif
  88.  
  89. static int com_getDCB(struct _DCBINFO far * dcb);
  90. static int com_setDCB(struct _DCBINFO far * dcb);
  91. static void com_kick(void);
  92.  
  93.  
  94. /* com_init() : Intialize communications port. Baud rate is preserved.
  95.  *              int port    : Hardware port (0 based) to init
  96.  *      -OR-    char *unc    : Full UNC \\networkId\modemId to init.
  97.  *
  98.  * if unc==NULL, port is used. if unc != NULL, unc is used
  99.  */
  100. int com_init(int port, char far *unc)
  101. {
  102.     char str[30];
  103.     char *s;
  104.     USHORT ActionTaken;         /* action: returned by OS/2 */
  105.     USHORT stat;
  106.     DCBINFO sDCB;
  107.     RXQUEUE q;
  108.  
  109.     cputs("\033[1;33mOS/2 FOSSIL emulator for BinkleyTerm, Peter Fitzsimmons (1:250/628)\033[0m\r\n");
  110.     sprintf(str, "COM%d", port + 1);
  111.     if (!unc)
  112.        unc = str;
  113. #ifdef DEBUG
  114.     stat = DosOpen((PSZ) unc,(PHFILE) &hfComHandle,(PUSHORT) &ActionTaken, 0L, 0, 0x0001, 0x4012, 0L);
  115. #else
  116.     stat = DosOpen((PSZ) unc,(PHFILE) &hfComHandle,(PUSHORT) &ActionTaken, 0L, 0, 0x0001, 0x6012, 0L);
  117. #endif
  118.     if (stat) {
  119.        hfComHandle = -1;
  120.        printf("com_init() : DosOpen() error 0x%04x on '%s'\n", stat, unc);
  121.        return (FALSE);
  122.     }
  123.     (void) DosSemClear((HSEM) &WriteSem);
  124.     if (!IOCtl(ASYNC_GETINQUECOUNT, (PVOID) &q, (PVOID) 0L)) {
  125.        s = getenv("RBUF");
  126.        if (s)
  127.            rbufsize = min( RSIZE, atoi(s));
  128.        else
  129.            rbufsize = RSIZE;
  130.        RQBbytes = min( RSIZE, rbufsize);
  131.        RQBbyte2 = RQBbytes/2;
  132. #ifdef DEBUG
  133.        printf("com_init() : ASYNC Input Buffer size is %d'\n", q.cbQueue);
  134. #endif
  135.     }
  136.     if (!IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L)) {
  137.        s = getenv("TBUF");
  138.        if (s)
  139.            tBufsize = min( TSIZE, atoi(s));
  140.        else
  141.            tBufsize = TSIZE;
  142.        TQSize = min(TSIZE, q.cbQueue);
  143. #ifdef DEBUG
  144.        printf("com_init() : ASYNC Output Buffer size is %d'\n", q.cbQueue);
  145. #endif
  146.     }
  147.     com_XON_disable();
  148.  
  149.     com_getDCB((struct _DCBINFO far *) &sDCB);
  150.  
  151.     /* turn off IDSR, ODSR */
  152. /*    sDCB.bFlags1 &= ~(MODE_DSR_HANDSHAKE | MODE_DSR_SENSITIVITY); */
  153.  
  154.     /* raise DTR, CTS output flow control */
  155. /*    sDCB.bFlags1 |= (MODE_DTR_CONTROL | MODE_CTS_HANDSHAKE); */
  156.  
  157.     /* turn off XON/XOFF flow control, error replacement off, null
  158.      * stripping off, break replacement off */
  159.     sDCB.bFlags2 &= ~(MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE |
  160.                       MODE_ERROR_CHAR | MODE_NULL_STRIPPING |
  161.                       MODE_BREAK_CHAR);
  162.  
  163.     /* RTS enable */
  164. /*    sDCB.bFlags2 |= MODE_RTS_CONTROL; */
  165.  
  166.     sDCB.bFlags3 |= (MODE_NO_WRITE_TIMEOUT | MODE_NOWAIT_READ_TIMEOUT);
  167.  
  168.     sDCB.usReadTimeout = 1000;
  169.     sDCB.usWriteTimeout = 1000;
  170.     com_setDCB((struct _DCBINFO far *) &sDCB);
  171.  
  172.     return (!stat);
  173. }
  174.  
  175. void com_DTR_on(void)
  176. {
  177.     DCBINFO sDCB;
  178.  
  179.     com_getDCB((struct _DCBINFO far *) &sDCB);
  180.     sDCB.bFlags1 |= MODE_DTR_CONTROL;    /* raise DTR */
  181.     com_setDCB((struct _DCBINFO far *) &sDCB);
  182. }
  183.  
  184. void com_DTR_off(void)
  185. {
  186.     DCBINFO sDCB;
  187.  
  188.     com_getDCB((struct _DCBINFO far *) &sDCB);
  189.     sDCB.bFlags1 &= ~MODE_DTR_CONTROL; /* lower DTR */
  190.     com_setDCB((struct _DCBINFO far *) &sDCB);
  191. }
  192.  
  193. /* close communications channel. Baud rate is preserved. */
  194. int com_fini(void)
  195. {
  196.     int stat;
  197.  
  198.     if (!(hfComHandle == -1)) {
  199.        com_wait();
  200.        while ((DosSemWait((HSEM) &WriteSem, 1L)) && (com_online()))
  201.           ;
  202.        com_clear_in();
  203.        com_clear_out();
  204.        if (stat = DosClose(hfComHandle)) {
  205.           hfComHandle = -1;
  206.           debug_msg("DosClose() error 0x%04x", stat);
  207.           return (FALSE);
  208.        }
  209.        hfComHandle = -1;
  210.     }
  211.     return(TRUE);
  212. }
  213.  
  214. long com_cur_baud(void)
  215. {
  216.     USHORT rate = 0;
  217.  
  218.     IOCtl(ASYNC_GETBAUDRATE, (PVOID) &rate, (PVOID) 0L);
  219.     return ((long) rate);
  220. }
  221.  
  222. /* com_set_baud() :
  223.  *
  224.  *    rate = 110..19200
  225.  *    parity = N, E, O, M, S (none,even, odd, mark, space)
  226.  *    databits = 5..8
  227.  *    stopbits = 1..2
  228.  *
  229.  */
  230. int com_set_baud(unsigned rate, char parity, int databits, int stopbits)
  231. {
  232.     int stat;
  233.     struct _LINECONTROL {
  234.     BYTE bDataBits;
  235.     BYTE bParity;
  236.     BYTE bStopBits;
  237.     BYTE fbTransBreak;
  238.     } lc;
  239.  
  240.     stat = IOCtl(ASYNC_SETBAUDRATE, (PVOID) 0L, (PVOID) &rate);
  241.     if (stat) {
  242.        return (FALSE);
  243.     }
  244.     lc.bDataBits = (BYTE) databits;
  245.     switch (stopbits) {
  246.     case 1:
  247.         lc.bStopBits = 0;
  248.         break;
  249.     case 2:
  250.         lc.bStopBits = 2;
  251.         break;
  252.     default:
  253.         if (databits == 5)
  254.         lc.bStopBits = 1;
  255.     }
  256.     lc.fbTransBreak = 0;
  257.     switch (toupper(parity)) {
  258.     case 'N':
  259.         lc.bParity = 0;
  260.         break;
  261.     case 'O':
  262.         lc.bParity = 1;
  263.         break;
  264.     case 'E':
  265.         lc.bParity = 2;
  266.         break;
  267.     case 'M':
  268.         lc.bParity = 3;
  269.         break;
  270.     case 'S':
  271.         lc.bParity = 4;
  272.         break;
  273.     default:
  274.         debug_msg("Bad parity '%c'", parity);
  275.         return (FALSE);
  276.     }
  277.     stat = IOCtl(ASYNC_SETLINECTRL, (PVOID) 0L, (PVOID) &lc);
  278.     if (stat) {
  279.        return (FALSE);
  280.     }
  281.     return (TRUE);
  282. }
  283.  
  284. static int com_getDCB(struct _DCBINFO far * dcb)
  285. {
  286.     int stat;
  287.  
  288.     stat = IOCtl(ASYNC_GETDCBINFO, (PVOID) dcb, (PVOID) 0L);
  289.     return (!stat);
  290. }
  291.  
  292. static int com_setDCB(struct _DCBINFO far * dcb)
  293. {
  294.     int stat;
  295.  
  296.     stat = IOCtl(ASYNC_SETDCBINFO, (PVOID) 0L, (PVOID) dcb);
  297.     return (!stat);
  298. }
  299.  
  300. void com_XON_disable(void)
  301. {
  302.     DCBINFO sDCB;
  303.  
  304.     if (com_getDCB((struct _DCBINFO far *) &sDCB)) {
  305.        /* disable auto Xmit and recv flow control */
  306.        sDCB.bFlags2 &= ~(MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE);
  307.        com_setDCB((struct _DCBINFO far *) &sDCB);
  308.     }
  309. }
  310.  
  311. void com_XON_enable(void)
  312. {
  313.     DCBINFO sDCB;
  314.  
  315.     if (com_getDCB((struct _DCBINFO far *) &sDCB)) {
  316.        /* enable auto Xmit and recv flow control */
  317.        sDCB.bFlags2 |= (MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE);
  318.        com_setDCB((struct _DCBINFO far *) &sDCB);
  319.     }
  320. }
  321.  
  322. /* nuke receive buffer */
  323. void com_clear_in(void)
  324. {
  325.     int stat;
  326.     char FlushParm = 0;         /* param to flush IOCTL function */
  327.  
  328.     Rbytes = rpos = 0;
  329.     stat = DosDevIOCtl((PVOID) 0L, (PVOID) &FlushParm, DEV_FLUSHINPUT, IOCTL_GENERAL, hfComHandle);
  330.     if (stat) {
  331.        debug_msg("DEV_FLUSHINPUT err 0x%04x", stat);
  332.     }
  333. }
  334.  
  335. /* com_getbuf() : return negative value if error */
  336. int com_getbuf(void)
  337. {
  338.    int stat = 0;
  339.    RXQUEUE q;
  340.    USHORT Rbytet;
  341.  
  342.    if (rpos == Rbytes)                      /* If buffer empty, */
  343.       rpos = Rbytes = 0;                  /* reset pointers   */
  344.  
  345.    Rbytet = Rbytes;                       /* Save old count   */
  346.    Rbytes = 0;                              /* Clear new count  */
  347.  
  348.    if (!(IOCtl(ASYNC_GETINQUECOUNT, (PVOID) &q, (PVOID) 0L))) {
  349.       if (q.cbChars > 0)
  350.          stat = DosRead(hfComHandle, rbuf+Rbytet, (USHORT) min(RQBbytes-Rbytet,q.cbChars), &Rbytes);
  351.       else
  352.          return (-1);
  353.    }  else
  354.          return (-1);
  355.  
  356.    if (stat && !Rbytes && (!(stat==ERROR_MORE_DATA))) {
  357.       debug_msg("DosRead() error 0x%04x", stat);
  358.       return (-1);
  359.    }
  360.  
  361.    Rbytes += Rbytet;
  362.    return (TRUE);
  363. }
  364.  
  365. /* com_getchar() : return negative value if error */
  366. int com_getchar(void)
  367. {
  368.    if (rpos != Rbytes)
  369.       return ((int) rbuf[rpos++]);
  370.  
  371.    if (com_getbuf() == TRUE)
  372.       return ((int) rbuf[rpos++]);
  373.    return (-1);
  374. }
  375.  
  376. /*non destructive read ahead; no wait */
  377. int com_peek(void)
  378. {
  379.    int c;
  380.  
  381.    if (!com_char_avail())
  382.       c = -1;
  383.    else {
  384.       c = com_getchar();
  385.       if (c != -1)
  386.          rpos--;
  387.    }
  388.    return (c);
  389. }
  390.  
  391. /* if RXQueue over half full, return TRUE */
  392. bool com_in_check(void)
  393. {
  394.    RXQUEUE q;
  395.  
  396.    if (IOCtl(ASYNC_GETINQUECOUNT, (PVOID) &q, (PVOID) 0L))
  397.       return (FALSE);
  398.    return ((bool)((q.cbChars > RQBbyte2) ? TRUE : FALSE));
  399. }
  400.  
  401. /* return number of chars in input buffer */
  402. int com_char_avail(void)
  403. {
  404.    RXQUEUE q;
  405.  
  406.    if (rpos < Rbytes)
  407.       return (Rbytes-rpos);
  408.  
  409.    return ((!(IOCtl(ASYNC_GETINQUECOUNT, (PVOID) (PVOID) &q, 0L))) ? q.cbChars : FALSE );
  410. }
  411.  
  412. /* return non 0 value if carrier detected */
  413. bool com_online(void)
  414. {
  415.    BYTE msr;
  416.  
  417.    if (hfComHandle == -1)
  418.       return(FALSE);
  419.    if (IOCtl(ASYNC_GETMODEMINPUT, (PVOID) &msr, (PVOID) 0L))
  420.       return (FALSE);
  421.    return (msr & DCD_ON);
  422. }
  423.  
  424. /* com_break() : start break if on==TRUE, stop break if on==FALSE */
  425. void com_break(int on)
  426. {
  427.    int cmd;
  428.    USHORT comerr;
  429.  
  430.    cmd = (on) ? ASYNC_SETBREAKON : ASYNC_SETBREAKOFF;
  431.    IOCtl(cmd, (PVOID) &comerr, (PVOID) 0L);
  432. }
  433.  
  434. /* com_out_empty() : return TRUE if output buffer is empty */
  435. bool com_out_empty(void)
  436. {
  437.    RXQUEUE q;
  438.  
  439.    if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L))
  440.       return (TRUE);
  441.  
  442.    if (!com_online())
  443.       return (TRUE);
  444.  
  445.    if (com_in_check())
  446.       (void) com_getbuf();
  447.  
  448. /* if (DosSemWait((HSEM) &WriteSem, 1L))
  449.       return (FALSE); */
  450.  
  451.    if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L))
  452.       return (TRUE);
  453.  
  454.    return ((bool) (q.cbChars < q.cbQueue));
  455. }
  456.  
  457. /* com_out_full() : return TRUE if output buffer is full */
  458. bool com_out_full(void)
  459. {
  460.    RXQUEUE q;
  461.  
  462.    if (com_in_check())
  463.       (void) com_getbuf();
  464.    if (!com_online())
  465.       return (FALSE);
  466.  
  467. /* if (DosSemWait((HSEM) &WriteSem, 1L))
  468.       return (TRUE); */
  469.  
  470.    if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L))
  471.       return (TRUE);
  472.  
  473.    return ((bool) !(q.cbChars < q.cbQueue));
  474. }
  475.  
  476. /* nuke transmit buffer */
  477. void com_clear_out(void)
  478. {
  479.    char FlushParm = 0;           /* param to flush IOCTL function */
  480.    int stat;
  481.  
  482. /* do {
  483.       if (!com_online())
  484.          break;
  485.        if (com_in_check())
  486.           (void) com_getbuf();
  487.    }  while(DosSemWait((HSEM) &WriteSem, 1L)); */
  488.  
  489.    stat = IOCtl(ASYNC_STARTTRANSMIT, (PVOID) 0L, (PVOID) 0L);
  490.    if (stat) {
  491.       debug_msg("ASYNC_STARTTRANSMIT err 0x%04x", stat);
  492.    }
  493.  
  494.    zap_zbuf();
  495.  
  496.    stat = DosDevIOCtl((PVOID) 0L, (PVOID) &FlushParm, DEV_FLUSHOUTPUT, IOCTL_GENERAL, hfComHandle);
  497.    if (stat) {
  498.       debug_msg("DEV_FLUSHOUTPUT err 0x%04x", stat);
  499.    }
  500.    DosSemClear((HSEM) &WriteSem);
  501. }
  502.  
  503. /* com_putc_now() : disregard any buffering and send a byte now damnit! */
  504. /* this function should be called only during emergencies...like when
  505.  * trying to cancel a file transfer
  506.  */
  507. /* Since the equivalent is a Com_ call, which in DOS is unsigned... */
  508. unsigned com_putc_now(byte c)
  509. {
  510.    return (!IOCtl(ASYNC_TRANSMITIMM, (PVOID) 0L, (PVOID) &c));
  511. }
  512.  
  513. /* com_putc() : output to com port */
  514. /* This function is very slow..where possile, write to com port in blocks
  515.  * using com_write() instead...especially above 2400 bps
  516.  */
  517. void com_putc(byte c)
  518. {
  519.    static USHORT bytes;
  520.    int stat;
  521.    RXQUEUE q;
  522.  
  523.    if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L))
  524.       return;
  525.  
  526.    do {
  527.       if (com_in_check())
  528.          (void) com_getbuf();
  529.     } while(DosSemWait((HSEM) &WriteSem, 1L));
  530.  
  531.    do {
  532.       if (IOCtl(ASYNC_GETOUTQUECOUNT, (PVOID) &q, (PVOID) 0L))
  533.          return;
  534.       if (com_in_check())
  535.           (void) com_getbuf();
  536.       if (q.cbChars >= q.cbQueue)
  537.          DosSleep (1L);
  538.    } while (q.cbChars >= q.cbQueue);
  539.  
  540.    /*
  541.     * DosWriteAsync() didn't work here.
  542.     */
  543.    if (stat = DosWrite(hfComHandle, &c, 1, &bytes))
  544.       debug_msg("DosWrite() err 0x%04x", stat);
  545. }
  546.  
  547. /* com_write() : buffered block write */
  548. void com_write(char *buf, unsigned int num, int carcheck)
  549. {
  550.    static USHORT err, bytes;
  551. #ifdef MultiWrt
  552.    unsigned int tnum = 0;
  553. #endif
  554.  
  555.    do {
  556.       if ((carcheck) && !com_online())
  557.          return;
  558.       if (com_in_check())
  559.          (void) com_getbuf();
  560.    } while(DosSemWait((HSEM) &WriteSem, 1L));
  561.  
  562.    (void) DosSemRequest((HSEM) &WriteSem, 0L);
  563.  
  564. #ifdef MultiWrt
  565.    while (tnum+TQSize > num+TQSize) {
  566.       memcpy (tBuf, &buf[tnum], TQSize);
  567.       DosWriteAsync(hfComHandle, (PULONG) &WriteSem, &err, tBuf, TQSize, &bytes);
  568.       tnum += TQSize;
  569.       do {
  570.          if ((carcheck) && !com_online())
  571.             return;
  572.          if (com_in_check())
  573.             (void) com_getbuf();
  574.       } while(DosSemWait((HSEM) &WriteSem, 1L));
  575.  
  576.       (void) DosSemRequest((HSEM) &WriteSem, 0L);
  577.    }
  578.  
  579.    memcpy (tBuf, &buf[tnum], num-tnum);
  580.    DosWriteAsync(hfComHandle, (PULONG) &WriteSem, &err, tBuf, num-tnum, &bytes);
  581. #else
  582.  
  583.    memcpy (tBuf, buf, num);
  584.    DosWriteAsync(hfComHandle, (PULONG) &WriteSem, &err, tBuf, num, &bytes);
  585. #endif
  586. }
  587.  
  588. /* wait for output buffer to empty */
  589. void com_wait(void)
  590. {
  591.     while ((!com_out_empty()) && com_online())
  592.        DosSleep (1L);
  593. }
  594.  
  595. extern unsigned int baud;
  596. extern unsigned int comm_bits;
  597. extern unsigned int parity;
  598. extern unsigned int stop_bits;
  599. extern struct baud_str btypes[];
  600.  
  601. void MDM_ENABLE(unsigned rate)
  602. {
  603.     char _parity;
  604.     int databits;
  605.     int stopbits;
  606.  
  607.     com_clear_out();
  608.     com_clear_in();
  609.     databits = 7 + (comm_bits == BITS_8);
  610.     stopbits = 1 + (stop_bits == STOP_2);
  611.     switch (parity) {
  612.     case NO_PARITY:
  613.         _parity = 'N';
  614.         break;
  615.     case ODD_PARITY:
  616.         _parity = 'O';
  617.         break;
  618.     case EVEN_PARITY:
  619.         _parity = 'E';
  620.         break;
  621.     }
  622.     com_set_baud(rate, _parity, databits, stopbits);
  623. }
  624.  
  625. void MDM_DISABLE(void)
  626. {
  627.     if (hfComHandle == -1)
  628.        return;
  629.     com_clear_out();
  630.     com_clear_in();
  631.     com_fini();
  632. }
  633.  
  634. /* zsend.c uses BUFFER_BYTE and UNBUFFER_BYTES...good idea. */
  635. void BUFFER_BYTE(unsigned char ch)
  636. {
  637.       if (zpos == tBufsize)
  638.          UNBUFFER_BYTES();
  639.       zTxBuf[zpos++]  = ch;
  640. }
  641.  
  642. void UNBUFFER_BYTES(void)
  643. {
  644.    if (com_online() && zpos)
  645.       (zpos == 1)?(com_putc(zTxBuf[0])):(com_write(zTxBuf,zpos,1));
  646.    zpos = 0;
  647. }
  648.  
  649. static void zap_zbuf(void)
  650. {
  651.     zpos = 0;
  652. }
  653.  
  654. unsigned Cominit(int port)
  655. {
  656.     if (hfComHandle != -1)
  657.        com_fini();
  658.     if (port == 0xff || com_init(port, NULL))
  659.        return (0x1954);
  660.     else
  661.        return (0);
  662. }
  663. #endif /* OS_2 */
  664.