--- /dev/null
+/* 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