]> pd.if.org Git - mmurtl/commitdiff
autocommit for file dated 1994-12-29 22:10:04
authorRichard Burgess <>
Thu, 29 Dec 1994 22:10:04 +0000 (22:10 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Mon, 17 Oct 2016 14:03:47 +0000 (14:03 +0000)
ossource/rs232.c [new file with mode: 0644]

diff --git a/ossource/rs232.c b/ossource/rs232.c
new file mode 100644 (file)
index 0000000..b43f146
--- /dev/null
@@ -0,0 +1,1032 @@
+/*  RS232 Device Driver (2 channel v1.0).\r
+    Next version adds flow control XON/XOFF & CTS/RTS  */\r
+\r
+/*  Copyright 1991,1992,1993,1994 R.A. Burgess */\r
+\r
+\r
+#define U32 unsigned long\r
+#define S32 long\r
+#define U16 unsigned int\r
+#define S16 int\r
+#define U8 unsigned char\r
+#define S8 char\r
+#define TRUE   1\r
+#define FALSE  0\r
+\r
+#include "RS232.h"\r
+\r
+/* MMURTL OS Prototypes */\r
+\r
+extern far U32 AllocExch(U32 *pExchRet);\r
+\r
+extern far U32 InitDevDr(U32 dDevNum,\r
+                                         S8  *pDCBs,\r
+                                                 U32 nDevices,\r
+                                                 U32 dfReplace);\r
+\r
+extern far U32 AllocOSPage(U32 nPages, U8 **ppMemRet);\r
+extern far U32 DeAllocPage(U8 *pOrigMem, U32 nPages);\r
+\r
+extern far U32 UnMaskIRQ(U32 IRQNum);\r
+extern far U32 MaskIRQ(U32 IRQNum);\r
+extern far U32 SetIRQVector(U32 IRQNum, S8  *pIRQ);\r
+extern far U32 EndOfIRQ(U32 IRQNum);\r
+extern far U32 SendMsg(U32 Exch, U32 msg1, U32 msg2);\r
+extern far U32 ISendMsg(U32 Exch, U32 msg1, U32 msg2);\r
+extern far U32 WaitMsg(U32 Exch, S8  *pMsgRet);\r
+extern far U32 CheckMsg(U32 Exch, S8  *pMsgRet);\r
+extern far U32 GetTimerTick(U32 *pTickRet);\r
+extern far U32 Alarm(U32 Exch, U32 count);\r
+extern far U32 KillAlarm(U32 Exch);\r
+extern far U32 Sleep(U32 count);\r
+extern far void MicroDelay(U32 us15count);\r
+extern far void OutByte(U8 Byte, U16 wPort);\r
+extern far U8 InByte(U16 wPort);\r
+extern far void CopyData(U8 *pSource, U8 *pDestination, U32 dBytes);\r
+\r
+extern far long GetJobNum(long *pJobNumRet);\r
+\r
+/* local prototypes. These will be called form the device driver interface. */\r
+\r
+static U32 comdev_stat(U32  dDevice,\r
+                         S8  *pStatRet,\r
+                         U32 dStatusMax,\r
+                         U32 *pdStatusRet);\r
+\r
+static S32 comdev_init(U32  dDevice,\r
+                        S8  *pInitData,\r
+                        U32  sdInitData);\r
+\r
+static U32 comdev_op(U32 dDevice,\r
+                   U32 dOpNum,\r
+                   U32 dLBA,\r
+                   U32 dnBlocks,\r
+                   U8  *pData);\r
+\r
+\r
+#define CmdReadRec   1                         /* Read one or more bytes */\r
+#define CmdWriteRec  2                         /* Write one or more bytes */\r
+\r
+#define CmdOpenC    10                         /* Open Comm Channel */\r
+#define CmdCloseC   11                         /* Close Comm Channel */\r
+#define CmdDiscardRcv 12\r
+#define CmdSetRTO      13\r
+#define CmdSetXTO      14\r
+#define CmdSetDTR   15                         /* Set DTR (On) */\r
+#define CmdSetRTS      16                              /* Set CTS (On) */\r
+#define CmdReSetDTR 17                         /* Set DTR (On) */\r
+#define CmdReSetRTS 18                         /* Set CTS (On) */\r
+#define CmdBreak       19\r
+#define CmdGetDC       20\r
+#define CmdGetDSR      21\r
+#define CmdGetCTS      22\r
+#define CmdGetRI       23\r
+\r
+#define CmdReadB       31\r
+#define CmdWriteB      32\r
+\r
+/* The following definitions are used to identify, set\r
+   and reset signal line condition and functions.\r
+*/\r
+\r
+#define CTS         0x10               /* Clear To Send       */\r
+#define DSR         0x20               /* Data Set Ready      */\r
+#define RI          0x40               /* Ring Indicator      */\r
+#define CD          0x80               /* Carrier Detect      */\r
+\r
+#define DTR         0x01               /* Data Terminal Ready */\r
+#define RTS         0x02               /* Request To Send     */\r
+#define OUT2           0x08            /* Not used */\r
+\r
+/* Values from IIR register */\r
+\r
+#define MDMSTAT                0x00\r
+#define NOINT          0x01\r
+#define TXEMPTY        0x02\r
+#define RVCDATA        0x04\r
+#define RCVSTAT                0x06\r
+\r
+/* For errors returned from Comms calls see COMMDRV.H */\r
+\r
+#define SSENDBUF 4096          /* 1 Page Send Buf Default */\r
+#define SRECVBUF 4096          /* 1 Page Recv Buf Default */\r
+\r
+static U32  recv_timeout[2] = 1;       /* 10ms intervals */\r
+static U32  xmit_timeout[2] = 10;      /* 10ms intervals */\r
+\r
+/* variables for ISRs */\r
+\r
+static U8      f16550[2];\r
+static U8      stat_byte[2];\r
+static U8      mstat_byte[2];\r
+static U8      int_id[2];\r
+static U8      fExpectInt[2];\r
+\r
+static U32 recv_error[2];      /* NON-ZERO = an error has occurred */\r
+\r
+static U8   *pSendBuf[2];      /* pointers to Xmit bufs */\r
+static U32  head_send[2];      /* Next char to send */\r
+static U32  tail_send[2];      /* Where next char goes in buf */\r
+static U32  cSendBuf[2];       /* Count of bytes in buf */\r
+static U32  sSendBuf[2];       /* Size of buffer (allocated) */\r
+\r
+static U8   *pRecvBuf[2];      /* pointers to Recv bufs */\r
+static U32  head_recv[2];      /* Next char from chip */\r
+static U32  tail_recv[2];      /* Next char to read for caller */\r
+static U32  cRecvBuf[2];       /* Count of bytes in buf */\r
+static U32  sRecvBuf[2];       /* Size of buffer (allocated) */\r
+\r
+static U8   control_byte[2] = 0;\r
+\r
+ /* array of registers from port base for each channel */\r
+\r
+static U16      THR[2];                /* Transmitter Holding Register */\r
+static U16      IER[2];                /* Interrupt Enable Register */\r
+static U16      IIR[2];                /* Interrupt Id Register */\r
+static U16      FCR[2];                /* FIFO control for 16550 */\r
+static U16      LCR[2];                /* Line Control Register */\r
+static U16      MCR[2];                /* Modem Control Register */\r
+static U16      LSR[2];                /* Line Status Register */\r
+static U16      MSR[2];                /* Modem Status Register */\r
+static U16      DLAB_LO[2];    /* same address as THR  */\r
+static U16      DLAB_HI[2];   /* same address as IER  */\r
+\r
+/* Complete description of Register bits follows:\r
+\r
+       THR -- TX data, RX data, Divisor Latch LSB\r
+\r
+       IER -- Interrupt Enable, Divisor Latch MSB\r
+\r
+                           7 6 5 4 3 2 1 0\r
+                           | | | | | | |  \_ Data Available\r
+                           | | | | | |  \___ Xmit Holding Reg Empty\r
+                           | | | | |  \_____ Receiver Line Status\r
+                           | | | |  \_______ Modem Status\r
+                           \ _ _ _\_________ Always 0000\r
+\r
+       IIR -- Interrupt Identification Register\r
+\r
+                           7 6 5 4 3 2 1 0\r
+                           | | | | \_\_\_\__________ 0001 = no interrupt\r
+                           | | | |                     0110 = rcvr status\r
+                           | | | |                     0100 = rcvd data\r
+                           | | | |                     0010 = THR empty\r
+                           | | | |                     0000 = Modem status\r
+                           | | | |                     1101 = Rcv Fifo Timeout (16550)\r
+                           | | |  \_________ = 0.\r
+                           | |  \___________ = 0.\r
+                            \ \_____________ = (16550 only)\r
+                                               00 = FIFOs disabled\r
+                                               non-zero = 16550 enabled\r
+\r
+       FCR -- FIFO Control Register (16550 only)\r
+                       This is a write only port at the same\r
+                       address as the IIR on an 8250/16450\r
+\r
+                           7 6 5 4 3 2 1 0\r
+                           | | | | | | |  \__= 1 = FIFO Enable\r
+                           | | | | | |  \___ = 1 = Recv FIFO Reset\r
+                           | | | | |  \_____ = 1 = Xmit FIFO Reset\r
+                           | | | |  \_______ = (DMA) 0 = Single char, 1 = Multichar\r
+                           | | |  \_________ = 0.\r
+                           | |  \___________ = 0.\r
+                           \__\_____________ = FIFO Rcv Trigger Level\r
+                                                               00 - 1 char\r
+                                                               01 - 2 chars\r
+                                                               10 - 4 chars\r
+                                                               11 - 8 chars\r
+\r
+       LCR --  Line Control Register\r
+\r
+                           7 6 5 4 3 2 1 0\r
+                           | | | | | | |  \_ Word Length Select Bit 0.\r
+                           | | | | | |  \___ Word Length Select Bit 1.\r
+                           | | | | |  \_____ Number Stop Bits (0=1, 1=2)\r
+                           | | | |  \_______ Parity Enable\r
+                           | | |  \_________ Even Parity Select\r
+                           | |  \___________ Stick Parity\r
+                           |  \_____________ Set Break\r
+                            \_______________ Divisor Latch Access Bit\r
+\r
+       MCR -- Modem Control Register\r
+\r
+                           7 6 5 4 3 2 1 0\r
+                           | | | | | | |  \_ Data Terminal Ready\r
+                           | | | | | |  \___ Request to Send\r
+                           | | | | |  \_____ Out 1\r
+                           | | | |  \_______ Out 2  (= 1 to enable ints.)\r
+                           | | |  \_________ Loop\r
+                           \ _ _\___________ = Always 0\r
+\r
+       LSR -- Line Status Register\r
+\r
+                           7 6 5 4 3 2 1 0\r
+                           | | | | | | |  \_ Data Ready\r
+                           | | | | | |  \___ Overrun Error\r
+                           | | | | |  \_____ Parity Error\r
+                           | | | |  \_______ Framing Error\r
+                           | | |  \_________ Break interrupt\r
+                           | |  \___________ Transmitter Holding Reg Empty\r
+                           |  \_____________ Transmitter Shift Reg Empty\r
+                            \_______________ Recv FIFO Error (16550 Only)\r
+\r
+       MSR -- Modem Status Register\r
+\r
+                           7 6 5 4 3 2 1 0\r
+                           | | | | | | |  \_ Delta Clear to Send\r
+                           | | | | | |  \___ Delta Data Set Ready\r
+                           | | | | |  \_____ Trailing Edge Ring Indicator\r
+                           | | | |  \_______ Delta Rx Line Signal Detect\r
+                           | | |  \_________ Clear to Send\r
+                           | |  \___________ Data Set Ready\r
+                           |  \_____________ Ring Indicator\r
+                            \_______________ Receive Line Signal Detect\r
+\r
+*/\r
+\r
+\r
+/* Record for 64 byte status and init record */\r
+/* This structure is peculiar to the comms driver */\r
+\r
+#define sStatus 64\r
+\r
+static struct statRecC comstat[2];\r
+static struct statRecC *pCS;\r
+\r
+static struct dcbtype \r
+{\r
+       S8   Name[12];\r
+       S8   sbName;\r
+       S8   type;\r
+       S16  nBPB;\r
+       U32  last_erc;\r
+       U32  nBlocks;\r
+       S8  *pDevOp;\r
+       S8  *pDevInit;\r
+       S8  *pDevSt;\r
+       S8   fDevReent;\r
+       S8   fSingleUser;\r
+       S16  wJob;\r
+       U32  OS1;\r
+       U32  OS2;\r
+       U32  OS3;\r
+       U32  OS4;\r
+       U32  OS5;\r
+       U32  OS6;\r
+       };\r
+\r
+static struct dcbtype comdcb[2];               /* Two RS-232 ports */\r
+\r
+\r
+/* THE COMMS INTERRUPT FUNCTION PROTOTYPES */\r
+\r
+static void interrupt comISR0(void);\r
+static void interrupt comISR1(void);\r
+\r
+\r
+/*********************************************************\r
+    This is called ONCE to initialize the 2 default\r
+    comms channels with the OS device driver interface.\r
+    It sets up defaults for both channels to 9600, 8N1.\r
+*********************************************************/\r
+\r
+U32  coms_setup(void)\r
+{\r
+U32  erc;\r
+\r
+  /* first we set up the 2 DCBs in anticipation of calling InitDevDr */\r
+\r
+       comdcb[0].Name[0]  = 'C';\r
+       comdcb[0].Name[1]  = 'O';\r
+       comdcb[0].Name[2]  = 'M';\r
+       comdcb[0].Name[3]  = '1';\r
+       comdcb[0].sbName   = 4;\r
+       comdcb[0].type     = 2;                 /* Sequential */\r
+       comdcb[0].nBPB     = 1;                 /* 1 byte per block */\r
+       comdcb[0].nBlocks  = 0;                 /* 0 for Sequential devices */\r
+       comdcb[0].pDevOp   = &comdev_op;\r
+       comdcb[0].pDevInit = &comdev_init;\r
+       comdcb[0].pDevSt   = &comdev_stat;\r
+\r
+       comdcb[1].Name[0]  = 'C';\r
+       comdcb[1].Name[1]  = 'O';\r
+       comdcb[1].Name[2]  = 'M';\r
+       comdcb[1].Name[3]  = '2';\r
+       comdcb[1].sbName   = 4;\r
+       comdcb[1].type     = 2;                 /* Sequential */\r
+       comdcb[1].nBPB     = 1;                 /* 1 byte per block */\r
+       comdcb[1].nBlocks  = 0;                 /* 0 for Sequential devices */\r
+       comdcb[1].pDevOp   = &comdev_op;\r
+       comdcb[1].pDevInit = &comdev_init;\r
+       comdcb[1].pDevSt   = &comdev_stat;\r
+\r
+       /* Set default comms params in stat records */\r
+\r
+       comstat[0].Baudrate = 9600;\r
+       comstat[0].parity   = 0;        /* none */\r
+       comstat[0].databits = 8;\r
+       comstat[0].stopbits = 1;\r
+       comstat[0].XTimeOut = 100;\r
+       comstat[0].RTimeOut = 2;\r
+       comstat[0].IOBase = 0x3F8;\r
+       comstat[0].IRQNum = 4;\r
+       comstat[0].XBufSize = 4096;\r
+       comstat[0].RBufSize = 4096;\r
+       sSendBuf[0] = 4096;\r
+       sRecvBuf[0] = 4096;\r
+\r
+       comstat[1].Baudrate = 9600;\r
+       comstat[1].parity   = 0;        /* none */\r
+       comstat[1].databits = 8;\r
+       comstat[1].stopbits = 1;\r
+       comstat[1].XTimeOut = 100;\r
+       comstat[1].RTimeOut = 2;\r
+       comstat[1].IOBase = 0x2F8;\r
+       comstat[1].IRQNum = 3;\r
+       comstat[1].XBufSize = 4096;\r
+       comstat[1].RBufSize = 4096;\r
+       sSendBuf[1] = 4096;\r
+       sRecvBuf[1] = 4096;\r
+\r
+       MaskIRQ(4);\r
+       MaskIRQ(3);\r
+\r
+       SetIRQVector(4, &comISR0);      /* COM1 */\r
+       SetIRQVector(3, &comISR1);      /* COM2 */\r
+\r
+       return(erc = InitDevDr(5, &comdcb, 2, 1));\r
+\r
+}\r
+\r
+/*********************************************************\r
+  This does the grunt work for each of the two ISRs\r
+  This MUST remain reentrant for two ISRs.\r
+*********************************************************/\r
+\r
+static void handleISR(U32 i)           /* i is the device */\r
+{\r
+U8 *pRBuf, *pXBuf;\r
+\r
+pRBuf = pRecvBuf[i];\r
+pXBuf = pSendBuf[i];\r
+\r
+while (TRUE) \r
+{\r
+       int_id[i] = InByte (IIR[i]);            /* Get ID Byte from IIR */\r
+       switch (int_id[i]) \r
+       {\r
+               case RCVSTAT:\r
+                   stat_byte[i] = InByte(LSR[i]);  /* clear error conditions */\r
+                       break;\r
+\r
+               case RVCDATA:\r
+               if (cRecvBuf[i] == sRecvBuf[i]) \r
+               {               /* Overflow!! */\r
+                               recv_error[i] = ErcRcvBufOvr;           /* Do not put in buf */\r
+                   InByte (THR[i]);                                    /* trash the byte */\r
+                       }\r
+                       else \r
+                       {\r
+#asm\r
+       CLI\r
+#endasm\r
+                       pRBuf[head_recv[i]] =\r
+                               InByte (THR[i]);        /* Get the byte */\r
+                               ++cRecvBuf[i];\r
+               if (++head_recv[i] == SRECVBUF)\r
+                           head_recv[i] = 0;\r
+#asm\r
+       STI\r
+#endasm\r
+                               recv_error[i] = 0;\r
+                   }\r
+           break;\r
+\r
+               case TXEMPTY:\r
+#asm\r
+       CLI\r
+#endasm\r
+               if (cSendBuf[i]) \r
+               {\r
+                   OutByte(pXBuf[tail_send[i]], THR[i]);  /* Send the byte */\r
+                   if (++tail_send[i] == sSendBuf[i])\r
+                               tail_send[i] = 0;\r
+                       --cSendBuf[i];\r
+                               fExpectInt[i] = TRUE;\r
+                       }\r
+                       else\r
+                               fExpectInt[i] = FALSE;\r
+#asm\r
+       STI\r
+#endasm\r
+               break;\r
+\r
+               case MDMSTAT:\r
+           mstat_byte[i] = InByte (MSR[i]);   /* Get Modem Status */\r
+               break;\r
+\r
+               case NOINT:\r
+           stat_byte[i] = InByte(LSR[i]);  /* clear error conditions */\r
+               default:\r
+       return;\r
+       }\r
+}\r
+}\r
+\r
+\r
+static void interrupt comISR0(void)\r
+{\r
+;              /* ; needed if asm is first in function */\r
+#asm\r
+       STI\r
+#endasm\r
+       handleISR(0);\r
+       EndOfIRQ(4);\r
+       return;\r
+}\r
+\r
+\r
+static void interrupt comISR1(void)\r
+{\r
+;              /* ; needed if asm is first in function */\r
+#asm\r
+       STI\r
+#endasm\r
+       handleISR(1);\r
+       EndOfIRQ(3);\r
+       return;\r
+}\r
+\r
+/********************************************/\r
+\r
+\r
+static long ReadByteC(U32 device, unsigned char *pByteRet)\r
+{\r
+U32 counter;\r
+U8 *pRBuf;\r
+\r
+       pRBuf = pRecvBuf[device];\r
+       if (recv_error[device]) return (recv_error[device]);\r
+\r
+       if (cRecvBuf[device]) \r
+       {\r
+        *pByteRet = pRBuf[tail_recv[device]];\r
+        if (++tail_recv[device] == sRecvBuf[device])\r
+               tail_recv[device] = 0;\r
+               --cRecvBuf[device];\r
+               return (0);\r
+       }\r
+\r
+       counter = comstat[device].RTimeOut;             /* set up for timeout */\r
+       while (counter--) \r
+       {\r
+               Sleep(1);\r
+               if (cRecvBuf[device]) \r
+               {\r
+               *pByteRet = pRBuf[tail_recv[device]];\r
+               if (++tail_recv[device] == sRecvBuf[device])\r
+                       tail_recv[device] = 0;\r
+               --cRecvBuf[device];\r
+                       return (0);\r
+               }\r
+       }\r
+       return (ErcRecvTimeout);\r
+}\r
+\r
+/********************************************/\r
+\r
+\r
+static long ReadRecordC(U32 device,\r
+                               unsigned char *pDataRet,\r
+                unsigned int  sDataMax,\r
+                unsigned int *pcbRet)\r
+{\r
+int  erc, cb;\r
+\r
+       erc = 0;\r
+       cb = 0;\r
+       while ((cb < sDataMax) && (!erc)) \r
+       {\r
+               erc = ReadByteC(device, pDataRet++);\r
+               if (!erc) ++cb;\r
+       }\r
+       *pcbRet = cb;           /* tell em how many bytes */\r
+    return (erc);\r
+}\r
+\r
+\r
+\r
+/********************************************/\r
+static long WriteByteC(U32 device, unsigned char b)\r
+{\r
+\r
+U32 erc, counter;\r
+U8 *pXBuf;\r
+\r
+       erc = 0;\r
+       pXBuf = pSendBuf[device];\r
+       counter = comstat[device].XTimeOut;             /* set up for timeout */\r
+\r
+       while (cSendBuf[device] == sSendBuf[device]) \r
+       {\r
+               Sleep(1);\r
+               counter--;\r
+               if  (!counter)\r
+                       return (ErcXmitTimeout);                /* never got sent */\r
+       }\r
+\r
+#asm\r
+       CLI\r
+#endasm\r
+\r
+       if (!fExpectInt[device])\r
+       {                       /* Xmit buf empty, send ourself */\r
+        OutByte(b, THR[device]);\r
+               fExpectInt[device] = TRUE;\r
+               }\r
+       else \r
+       {\r
+        pXBuf[head_send[device]] = b;\r
+        if (++head_send[device] == sSendBuf[device])\r
+            head_send[device]  = 0;\r
+               ++cSendBuf[device];                             /* one more in buf */\r
+       }\r
+#asm\r
+       STI\r
+#endasm\r
+       return (erc);\r
+}\r
+\r
+\r
+/********************************************/\r
+static long WriteRecordC(U32 device,\r
+                                unsigned char *pSendData,\r
+                 unsigned int cbSendData)\r
+{\r
+int erc;\r
+\r
+       erc = 0;\r
+    while ((cbSendData) && (!erc)) \r
+    {\r
+               erc = WriteByteC(device, *pSendData++);\r
+               --cbSendData;\r
+       }\r
+       return (erc);\r
+}\r
+\r
+\r
+/********************************************/\r
+\r
+static long DiscardRecvC(U32 device)\r
+{\r
+U32    saveto, erc;\r
+U8  b;\r
+\r
+       saveto = comstat[device].RTimeOut;\r
+       comstat[device].RTimeOut = 1;\r
+       erc = 0;\r
+       while (!erc)\r
+               erc = ReadByteC(device, &b);\r
+       comstat[device].RTimeOut = saveto;\r
+       return (0);\r
+}\r
+\r
+\r
+\r
+/********************************************\r
+ This sets comms params prior to opening, or\r
+ while a channel is in use.\r
+********************************************/\r
+\r
+static U32 SetParams(U32 device)\r
+\r
+{\r
+U32  divisor, speed;\r
+U8   c, parity, bits, stop_bit, temp;\r
+\r
+       parity = comstat[device].parity;\r
+       bits = comstat[device].databits;\r
+       stop_bit = comstat[device].stopbits;\r
+       speed = comstat[device].Baudrate;\r
+\r
+       /* Set up baud rate */\r
+\r
+    divisor = 115200/speed;\r
+\r
+#asm\r
+       CLI\r
+#endasm\r
+    c=InByte (LCR[device]);\r
+    OutByte  ((c | 0x80), LCR[device]);\r
+    OutByte  ((divisor & 0x00ff), DLAB_LO[device]);\r
+    OutByte  (((divisor>>8) & 0x00ff), DLAB_HI[device]);\r
+    OutByte  (c, LCR[device]);\r
+#asm\r
+       STI\r
+#endasm\r
+\r
+       /* set coms params */\r
+\r
+    temp = bits - 5;\r
+    temp |= ((stop_bit == 1) ? 0x00 : 0x04);\r
+\r
+    switch (parity)\r
+    {\r
+       case NO_PAR : temp |= 0x00; break;\r
+       case OD_PAR : temp |= 0x08; break;\r
+       case EV_PAR : temp |= 0x18; break;\r
+    }\r
+\r
+#asm\r
+       CLI\r
+#endasm\r
+    OutByte (temp, LCR[device]);\r
+#asm\r
+       STI\r
+#endasm\r
+\r
+       return (0);\r
+}\r
+\r
+\r
+/********************************************\r
+ This allocates buffers, sets up the ISR\r
+ and IRQ values and open the channel for use.\r
+*********************************************/\r
+\r
+static U32  OpenCommC(U32 device)\r
+\r
+{\r
+U32  erc;\r
+U16  port_base;\r
+U8   c;\r
+\r
+       if (comstat[device].commJob)\r
+               return(ErcChannelOpen);\r
+\r
+       GetJobNum(&comstat[device].commJob);\r
+\r
+       erc = AllocOSPage(comstat[device].XBufSize/4096,\r
+                                         &pSendBuf[device]);\r
+\r
+       if (!erc) \r
+       {\r
+               erc = AllocOSPage(comstat[device].RBufSize/4096,\r
+                                                 &pRecvBuf[device]);\r
+\r
+               if (erc)  /* get rid of Xmit buf if we can't recv */\r
+            DeAllocPage(pSendBuf[device],\r
+                               comstat[device].XBufSize/4096);\r
+       }\r
+\r
+       if (erc)\r
+       {\r
+               comstat[device].commJob = 0;\r
+               return (erc);\r
+       }\r
+\r
+       port_base = comstat[device].IOBase;\r
+\r
+       /* Set up buffer variables for this port */\r
+\r
+       cSendBuf[device] = 0;\r
+       head_send[device] = 0;\r
+       tail_send[device] = 0;\r
+\r
+       cRecvBuf[device] = 0;\r
+       head_recv[device] = 0;\r
+       tail_recv[device] = 0;\r
+       recv_error[device] = 0;\r
+\r
+\r
+    THR[device]     = port_base;\r
+    IER[device]     = port_base + 1;\r
+    IIR[device]     = port_base + 2;\r
+    FCR[device]     = port_base + 2;\r
+    LCR[device]     = port_base + 3;\r
+    MCR[device]     = port_base + 4;\r
+    LSR[device]     = port_base + 5;\r
+    MSR[device]     = port_base + 6;\r
+    DLAB_HI[device] = port_base + 1;\r
+    DLAB_LO[device] = port_base;\r
+\r
+    InByte(THR[device]);       /* reset any pending ints on chip */\r
+    InByte(LSR[device]);\r
+\r
+#asm\r
+       CLI\r
+#endasm\r
+       control_byte[device] = RTS | DTR | OUT2;\r
+    OutByte(control_byte[device], MCR[device]);        /* Mod Ctrl Reg   */\r
+    OutByte(0x0F, IER[device]);                                        /* Int Enable Reg */\r
+\r
+       /* See if we have a 16550 and set it up if we do!! */\r
+\r
+    OutByte(0x03, FCR[device]);\r
+    c = InByte(IIR[device]);\r
+       if (c & 0xC0)           /* we have a 16550 and it's set to go! */\r
+               f16550[device] = 1;\r
+       else\r
+               f16550[device] = 0;             /* 8250 or 16450 */\r
+\r
+#asm\r
+       STI\r
+#endasm\r
+\r
+       SetParams(device);\r
+\r
+       UnMaskIRQ(comstat[device].IRQNum);\r
+       return (0);\r
+}\r
+\r
+/********************************************\r
+ This closes the port, sets the owner to 0\r
+ and deallocates the buffers.\r
+********************************************/\r
+\r
+static int  CloseCommC (U32 device)\r
+{\r
+U32 erc;\r
+\r
+       MaskIRQ(comstat[device].IRQNum);\r
+    OutByte(0, MCR[device]);\r
+    OutByte(0, IER[device]);\r
+    erc = DeAllocPage(pSendBuf[device],\r
+                               comstat[device].XBufSize/4096);\r
+    erc = DeAllocPage(pRecvBuf[device],\r
+                               comstat[device].RBufSize/4096);\r
+       comstat[device].commJob = 0;\r
+    return (erc);\r
+}\r
+\r
+/***************************************************************************\r
+Now begins the PUBLIC routines that are interfaced to for all DEVICE DRIVERS\r
+****************************************************************************/\r
+\r
+/******************************************\r
+Called for all device operations.  This\r
+assigns physical device from logical number\r
+that outside callers use. For RS-232, 5=0\r
+and 6=1.\r
+*******************************************/\r
+\r
+static U32 comdev_op(U32 dDevice,\r
+                   U32 dOpNum,\r
+                   U32 dLBA,\r
+                   U32 dnBlocks,\r
+                   U8  *pData)\r
+{\r
+U32 erc;\r
+U32 Job, device;\r
+U8 c;\r
+\r
+/* Set internal drive number */\r
+/* 5   RS-232 1        COM1    (OS built-in) */\r
+/* 6   RS-232 2        COM2    (OS built-in) */\r
+\r
+       if (dDevice == 5)\r
+               device = 0;\r
+       else\r
+               device = 1;\r
+\r
+       GetJobNum(&Job);\r
+\r
+       if ((!comstat[device].commJob) && (dOpNum != CmdOpenC))\r
+               return(ErcNotOpen);\r
+\r
+       if (comstat[device].commJob) \r
+       {\r
+               if ((comstat[device].commJob != Job) &&\r
+                       (Job != 1))\r
+                       return(ErcNotOwner);\r
+       }\r
+\r
+       erc = 0;                /* default error */\r
+\r
+       switch(dOpNum) \r
+       {\r
+\r
+               case(0):\r
+                       break;                          /* Null Command */\r
+               case CmdReadB:\r
+                       erc = ReadByteC(device, pData);\r
+                       break;\r
+               case CmdWriteB:\r
+                       erc = WriteByteC(device, *pData);\r
+                       break;\r
+               case CmdReadRec:\r
+                       erc = ReadRecordC(device, pData, dnBlocks,\r
+                                               &comstat[device].LastTotal);\r
+                       break;\r
+               case CmdWriteRec:\r
+                       erc = WriteRecordC(device, pData, dnBlocks);\r
+                       break;\r
+               case CmdSetRTO:\r
+                       comstat[device].RTimeOut = dLBA;                /* 10ms intervals */\r
+                       break;\r
+               case CmdSetXTO:\r
+                       comstat[device].XTimeOut = dLBA;                /* 10ms intervals */\r
+                       break;\r
+               case CmdOpenC:\r
+                       erc =  OpenCommC(device);\r
+                       break;\r
+               case CmdCloseC:\r
+                       erc =  CloseCommC(device);\r
+                       break;\r
+               case CmdDiscardRcv:\r
+                       erc = DiscardRecvC(device);\r
+                       break;\r
+               case CmdSetDTR:\r
+                       control_byte[device] |= DTR;\r
+                   OutByte(control_byte[device], LCR[device]);\r
+                       break;\r
+               case CmdSetRTS:\r
+                       control_byte[device] |= RTS;\r
+                       OutByte(control_byte[device], MCR[device]);\r
+                       break;\r
+               case CmdReSetDTR:\r
+                       control_byte[device] &= ~DTR;\r
+                       OutByte(control_byte[device], LCR[device]);\r
+               case CmdReSetRTS:\r
+                       control_byte[device] &= ~RTS;\r
+                   OutByte(control_byte[device], MCR[device]);\r
+                   break;\r
+               case CmdBreak:\r
+                       c = InByte(LCR[device]);\r
+                       OutByte((c | 0x40), LCR[device]);\r
+                       Sleep(dLBA);\r
+                       OutByte(c, LCR[device]);\r
+                       break;\r
+               case CmdGetDC:\r
+                   *pData = mstat_byte[device] & CD;\r
+                       break;\r
+               case CmdGetDSR:\r
+               *pData = mstat_byte[device] & DSR;\r
+                       break;\r
+               case CmdGetCTS:\r
+                       *pData = mstat_byte[device] & CTS;\r
+                       break;\r
+               case CmdGetRI:\r
+                       *pData = mstat_byte[device] & RI;\r
+                       break;\r
+               default:\r
+                       break;\r
+       }\r
+\r
+       comstat[device].LastErc = erc;\r
+       return(erc);\r
+}\r
+\r
+\r
+/******************************************\r
+Called for status report on coms channel.\r
+Returns 64 byte block for channel specified.\r
+This is called by the PUBLIC call DeviceStat\r
+*******************************************/\r
+\r
+static U32 comdev_stat(U32  dDevice,\r
+                         S8  *pStatRet,\r
+                         U32 dStatusMax,\r
+                         U32 *pdStatusRet)\r
+{\r
+U32 i, device;\r
+\r
+       /* Set internal device number */\r
+       if (dDevice == 5)\r
+               device = 0;\r
+       else device = 1;\r
+\r
+       if (dStatusMax > 64)\r
+               i = 64;\r
+       else\r
+           i = dStatusMax;\r
+\r
+       if (!device)\r
+       {\r
+               CopyData(&comstat[0], pStatRet, i);             /* copy the status data */\r
+       }\r
+       else\r
+       {\r
+               CopyData(&comstat[1], pStatRet, i);             /* copy the status data */\r
+       }\r
+\r
+       *pdStatusRet = dStatusMax;              /* give em the size returned */\r
+\r
+       return(0);\r
+}\r
+\r
+/******************************************\r
+Called to set parameters for the comms\r
+channels prior to opening or while in use.\r
+If an invalid value is passed in, all params\r
+remain the same as before.\r
+Some comms channel params may not be changed\r
+while the channel is in use.\r
+This is called by the PUBLIC call DeviceInit.\r
+*******************************************/\r
+\r
+static S32 comdev_init(U32  dDevice,\r
+                        S8  *pInitData,\r
+                        U32  sdInitData)\r
+\r
+{\r
+U32  erc, Xbufsize, Rbufsize, device;\r
+U32  speed, XTO, RTO;\r
+U16  port_base;\r
+U8   parity, bits, stop_bit, IRQNUM;\r
+\r
+       if (dDevice == 5)\r
+               device = 0;                     /* Set internal device number */\r
+       else\r
+               device = 1;\r
+\r
+       if (sdInitData < 40)\r
+               return(ErcBadInitSize);\r
+\r
+       pCS = pInitData;\r
+\r
+       /* Get the callers new params */\r
+\r
+       speed     = pCS->Baudrate;      /* Non Volatile */\r
+       parity    = pCS->parity;        /* Non Volatile */\r
+       bits      = pCS->databits;      /* Non Volatile */\r
+       stop_bit  = pCS->stopbits;      /* Non Volatile */\r
+       XTO       = pCS->XTimeOut;      /* Non Volatile */\r
+       RTO       = pCS->RTimeOut;      /* Non Volatile */\r
+\r
+       port_base = pCS->IOBase;\r
+       Xbufsize  = pCS->XBufSize;\r
+       Rbufsize  = pCS->RBufSize;\r
+       IRQNUM    = pCS->IRQNum;\r
+\r
+       /* Non Volatile params can be set whether or not the\r
+          channel is open. Do these first and return errors. */\r
+\r
+    if ((speed > MAX_BAUD) || (speed < MIN_BAUD))\r
+       return (ErcBadBaud);\r
+\r
+    if ((parity < NO_PAR) || (parity > OD_PAR))\r
+       return (ErcBadParity);\r
+\r
+    if ((bits < 5) || (bits > 8))\r
+       return (ErcBadDataBits);\r
+\r
+    if ((stop_bit < 1) || (stop_bit > 2))\r
+       return (ErcBadStopBits);\r
+\r
+    if (!XTO)  XTO = 1;\r
+    if (!RTO)  RTO = 1;\r
+\r
+       comstat[device].Baudrate = speed;\r
+       comstat[device].parity   = parity;\r
+       comstat[device].databits = bits;\r
+       comstat[device].stopbits = stop_bit;\r
+       comstat[device].XTimeOut = XTO;\r
+       comstat[device].RTimeOut = RTO;\r
+\r
+       /* If we got here, the params are OK.  Now we check\r
+          to see if the channel is open and call SetParams\r
+          if so.  The channel is open if the JobNumber\r
+          in the commstat record is NON-ZERO.\r
+       */\r
+\r
+       if (comstat[device].commJob)\r
+       {  /* Channel Open! */\r
+               SetParams(device);\r
+       }\r
+\r
+       /* Channel is not open so we check and set rest of params */\r
+\r
+       else\r
+       {\r
+\r
+           if (!port_base)\r
+               return (ErcBadIOBase);\r
+           if (IRQNUM < 3)\r
+               return (ErcBadCommIRQ);\r
+\r
+               /* We now round up buffer sizes to whole pages */\r
+\r
+               Xbufsize = Xbufsize/4096 * 4096;\r
+               if (Xbufsize % 4096) Xbufsize+=4096; /* another page */\r
+\r
+\r
+               Rbufsize = Rbufsize/4096 * 4096;\r
+               if (Rbufsize % 4096) Rbufsize+=4096; /* another page */\r
+\r
+\r
+               comstat[device].IOBase = port_base;\r
+               comstat[device].IRQNum = IRQNUM;\r
+               comstat[device].XBufSize = Xbufsize;\r
+               comstat[device].RBufSize = Rbufsize;\r
+\r
+               /* Local copies so we don't work from a structure in ISR */\r
+\r
+               sSendBuf[device] = Xbufsize;    /* Size of buffer (allocated) */\r
+               sRecvBuf[device] = Rbufsize;    /* Size of buffer (allocated) */\r
+\r
+               erc = 0;\r
+       }\r
+\r
+ return(erc);\r
+}\r