home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / bbs_mail / bsrc_250.arj / ASYNC.C next >
C/C++ Source or Header  |  1991-09-15  |  21KB  |  714 lines

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