home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- * *
- * SLFP packet driver *
- * *
- * Glenn H McGregor, Merit Computer Network *
- * William A Simpson, Computer Systems Consulting Services *
- * *
- ****************************************************************/
-
- #define SLFP_VERSION "1.23"
-
- /*
- * trace
- */
-
- #undef DEBUG
- #define SCREEN_EGA
- #define TRACE_HEX
- #define TRACE_ALL_HEX
-
- #ifdef DEBUG
- #define trace(ch,color) Trace(ch,color)
- #else
- #define trace(ch,color)
- #endif
-
- /*
- * Includes
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <conio.h>
- #include <dos.h>
- #include <mem.h>
- #include <graphics.h>
- #include <string.h>
-
- #include "getopt.h"
- #include "gen.h"
-
- /*
- * Memory layout
- */
-
- word _stklen = 256;
- word _heaplen = 256;
-
- /*
- * Configuration options & defaults
- */
-
- byte ConfPackInt = 0x60;
- byte ConfSerialIrq = 4;
- word ConfSerialBase = 0x3F8;
- word ConfSerialSpeed = 2400;
- char ConfSerialDial[40] = "";
- word ConfInitTime = 60;
- byte ConfHandshake = 1;
- byte ConfFifoCheck = 1;
-
- /*
- * Error level returns
- */
-
- enum
- {
- ERL_none,
- ERL_parse,
- ERL_packet,
- ERL_break,
- ERL_handshake
- };
-
- /*
- * SLFP characters
- */
-
- enum
- {
- SLFP_ESC = 0xF2, /* next character substitution */
- SLFP_REQ = 0xF3, /* request transmit oportunity */
- SLFP_ACK = 0xF4, /* transmit request acknowledged */
- SLFP_END = 0xF5, /* end of transmission block */
- };
-
- /*
- * Interrupt events
- */
-
- enum
- {
- RECV_RDA,
- RECV_GOT_REQ
- };
-
- enum
- {
- XMIT_MESSAGE,
- XMIT_GOT_REQ,
- XMIT_GOT_ACK,
- XMIT_THRE,
- XMIT_LOOP,
- XMIT_TIMEOUT
- };
-
- /*
- * I/O queues
- */
-
- #define QLEN 0x1000
-
- word RecvQHead = 0;
- word RecvQTail = 0;
- int RecvQSize = 0;
- byte RecvQ[QLEN];
-
- word XmitQHead = 0;
- word XmitQTail = 0;
- int XmitQSize = 0;
- byte XmitQ[QLEN];
-
- /*
- * 8250 I/O base offsets
- */
-
- enum
- {
- IOO_THR = 0, /* transmitter holding register */
- IOO_RBR = 0, /* receiver buffer register */
- IOO_DLL = 0, /* divisor latch LSB */
- IOO_DLM = 1, /* divisor latch MSB */
- IOO_IER = 1, /* interrupt enable register */
- IOO_IIR = 2, /* interrupt ident register */
- IOO_FCR = 2, /* fifo control register */
- IOO_LCR = 3, /* line control register */
- IOO_MCR = 4, /* modem control register */
- IOO_LSR = 5, /* line status register */
- IOO_MSR = 6 /* modem status register */
- };
-
- /*
- * 8250 line control register
- */
-
- enum
- {
- LCR_5BITS = 0x00, /* five bit words */
- LCR_6BITS = 0x01, /* six bit words */
- LCR_7BITS = 0x02, /* seven bit words */
- LCR_8BITS = 0x03, /* eight bit words */
- LCR_NSB = 0x04, /* number of stop bits */
- LCR_PEN = 0x08, /* parity enable */
- LCR_EPS = 0x10, /* even parity select */
- LCR_SP = 0x20, /* stick parity */
- LCR_SB = 0x40, /* set break */
- LCR_DLAB = 0x80 /* divisor latch access bit */
- };
-
- /*
- * 8250 line status register
- */
-
- enum
- {
- LSR_DR = 0x01, /* data ready */
- LSR_OE = 0x02, /* overrun error */
- LSR_PE = 0x04, /* parity error */
- LSR_FE = 0x08, /* framing error */
- LSR_BI = 0x10, /* break interrupt */
- LSR_THRE = 0x20, /* transmitter line holding register empty */
- LSR_TSRE = 0x40, /* transmitter shift register empty */
- };
-
- /*
- * 8250 interrupt identification register
- */
-
- enum
- {
- IIR_IP = 0x01, /* not interrupt pending */
- IIR_ID = 0x06, /* mask for interrupt id */
- IIR_RLS = 0x06, /* receive line status interrupt */
- IIR_RDA = 0x04, /* receive data available interrupt */
- IIR_THRE = 0x02, /* transmit holding reg empty interrupt */
- IIR_MSTAT = 0x00, /* modem status interrupt */
-
- IIR_FIFO_TO = 0x08, /* fifo timeout interrupt pending (16550A only */
- IIR_FIFO_ENB= 0xC0 /* fifo enabled (16550A only) */
- };
-
- /*
- * 8250 interrupt enable register bits
- */
-
- enum
- {
- IER_DAV = 0x01, /* data available interrupt */
- IER_TXE = 0x02, /* transmit buffer empty interrupt */
- IER_RLS = 0x04, /* receive line status interrupt */
- IER_MS = 0x08 /* modem status interrupt */
- };
-
- /*
- * 8250 modem control register
- */
-
- enum
- {
- MCR_DTR = 0x01, /* data terminal ready */
- MCR_RTS = 0x02, /* request to send */
- MCR_OUT1 = 0x04, /* out 1 (not used) */
- MCR_OUT2 = 0x08, /* out 2 (master interrupt enable) */
- MCR_LOOP = 0x10 /* loopback test mode */
- };
-
- /*
- * 8250 modem status register
- */
-
- enum
- {
- MSR_DCTS = 0x01, /* delta clear-to-send */
- MSR_DDSR = 0x02, /* delta data-set-ready */
- MSR_TERI = 0x04, /* trailing edge ring indicator */
- MSR_DRLSD = 0x08, /* delta rx line signal detect */
- MSR_CTS = 0x10, /* clear-to-send */
- MSR_DSR = 0x20, /* data-set-ready */
- MSR_RI = 0x40, /* ring indicator */
- MSR_RLSD = 0x80 /* received line signal detect */
- };
- /*
- * 16550 fifo control register
- */
-
- enum
- {
- FCR_RESET = 0x00, /* disable TX & RX fifo */
- FCR_ENABLE = 0x01, /* enable TX & RX fifo */
- FCR_CLR_RX = 0x02, /* clear receive fifo */
- FCR_CLR_TX = 0x04, /* clear transmit fifo */
- FCR_ST_DMA = 0x08, /* enable TXRDY/RXRDY pin DMA handshake */
-
- FCR_RXT_1 = 0x00, /* RX fifo trigger levels */
- FCR_RXT_4 = 0x40,
- FCR_RXT_8 = 0x80,
- FCR_RXT_14 = 0xC0,
-
- FCR_SETUP = FCR_ENABLE|FCR_CLR_RX|FCR_CLR_TX|FCR_RXT_4
- };
-
- /*
- * Serial global data
- */
-
- word Serial_IOBase; /* I/O address of 8250 chip */
- byte Serial_IRQ; /* Interrupt number of 8250 chip */
- dword Serial_Speed; /* Line speed of interface */
- InterruptPtrType
- SaveSerialInt; /* Old serial ISR */
-
- dword RealIP_Address;
- BOOLEAN Serial_16550A = FALSE; /* UART is a 16550A */
- byte XmitCount = 1; /* number of bytes to transmit */
- BOOLEAN Serial_Handshake = FALSE; /* REQ/ACK handshake has occurred */
-
- word IOA_THR = IOO_THR;
- word IOA_RBR = IOO_RBR;
- word IOA_DLL = IOO_DLL;
- word IOA_DLM = IOO_DLM;
- word IOA_IER = IOO_IER;
- word IOA_IIR = IOO_IIR;
- word IOA_FCR = IOO_FCR;
- word IOA_LCR = IOO_LCR;
- word IOA_MCR = IOO_MCR;
- word IOA_LSR = IOO_LSR;
- word IOA_MSR = IOO_MSR;
-
- #define IOA_First IOA_THR
- #define IOA_Count 11
-
- dword IOE_LostTHRE= 0;
- dword IOE_OverRun = 0;
- dword IOE_Parity = 0;
- dword IOE_Framing = 0;
- dword IOE_Break = 0;
- dword IOE_ReqTO = 0;
- dword IOE_IntrIn = 0;
- dword IOE_IntrOut = 0;
- dword IOE_FifoHi = 0;
- dword IOE_FifoTO = 0;
- #define IOE_Table IOE_LostTHRE
-
- dword IOS_PktIn = 0;
- dword IOS_PktOut = 0;
- dword IOS_ByteIn = 0;
- dword IOS_ByteOut = 0;
- dword IOS_ErrIn = 0;
- dword IOS_ErrOut = 0;
- dword IOS_PktDrop = 0;
- #define IOS_Table IOS_PktIn
-
- /*
- * Timer support
- */
-
- #define SECONDS 18
- InterruptPtrType
- SaveTimerInt;
- word InitTimer = 0;
- word XmitTimer = 0;
-
- /*
- * Packet Driver Hook
- */
-
- char PacketDriverHook[17];
- InterruptPtrType SavePacketInt;
-
- /*
- * Handle Table
- */
-
- typedef void (far *RecvType)(void);
-
- typedef struct
- {
- byte Hand_InUse;
- byte Hand_TypeLen;
- RecvType Hand_Receiver;
- word Hand_TypeVal;
- } HandleType;
-
- HandleType HandleTable;
-
- /*
- * Packet Driver values
- */
-
- #define PD_version 0x0010
- #define PDV_basic 1
- #define PDV_extended 2
- #define PDT_Merit 1
- #define PDT_any 0xFFFF
- char PDN_slfp[] = "SLFP8250";
-
- /*
- * Packet Driver Classes
- */
-
- enum PD_Classes
- {
- PDC_Ethernet = 1,
- PDC_Pronet_10,
- PDC_IEEE_8025,
- PDC_Omninet,
- PDC_Appletalk,
- PDC_SerialLine,
- PDC_Starlan,
- PDC_Arcnet,
- PDC_AX25,
- PDC_KISS,
- PDC_IEEE_8023,
- PDC_FDDI,
- PDC_Internet_X25,
- PDC_LANSTAR,
- PDC_SLFP
- };
-
- /*
- * Function calls
- */
-
- enum PD_Functions
- {
- PDF_DriverInfo = 1,
- PDF_AccessType,
- PDF_ReleaseType,
- PDF_SendPkt,
- PDF_Terminate,
- PDF_GetAddress,
- PDF_ResetInterface,
- PDF_SetRcvMode,
- PDF_GetRcvMode,
- PDF_SetMulticastList = 22,
- PDF_GetMulticastList,
- PDF_GetStatistics,
- PDF_GetErrors
- };
-
- /*
- * Error codes
- */
-
- enum PD_Errors
- {
- PDE_BadHandle = 1,
- PDE_NoClass,
- PDE_NoType,
- PDE_NoNumber,
- PDE_BadType,
- PDE_NoMulticast,
- PDE_CantTerminate,
- PDE_BadMode,
- PDE_NoSpace,
- PDE_TypeInUse,
- PDE_BadCommand,
- PDE_CantSend,
- PDE_CantSet,
- PDE_BadAddress
- };
-
- /*
- * Forward declarations
- */
-
- void PassUp ( void *buf, word len );
-
- /****************************************************************
- * *
- * Trace *
- * *
- ****************************************************************/
-
- #ifdef DEBUG
-
- #ifdef SCREEN_EGA
- #define SCREEN_BASE 0xB800
- #define SCREEN_WRAP 4000
- #else
- #define SCREEN_BASE 0xB000
- #define SCREEN_WRAP 2560 /* leave some room at bottom of screen */
- #endif
-
- void Trace ( byte val, byte color )
- {
- static int BufOfs = 0;
- #ifdef TRACE_HEX
- static char HexRep[] = "0123456789ABCDEF";
- #ifdef TRACE_ALL_HEX
- static all_hex = TRUE;
- #else
- static all_hex = FALSE;
- #endif
-
- if ( all_hex || val <= ' ' || val >= '\x7f' )
- {
- *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = HexRep[val>>4];
- BufOfs %= SCREEN_WRAP;
- *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = color;
- BufOfs %= SCREEN_WRAP;
- *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = HexRep[val&0xF];
- BufOfs %= SCREEN_WRAP;
- *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = color;
- BufOfs %= SCREEN_WRAP;
- }
- #endif
-
- *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = val;
- BufOfs %= SCREEN_WRAP;
- *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = color;
- BufOfs %= SCREEN_WRAP;
-
- #ifdef TRACE_HEX
- *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = ' ';
- BufOfs %= SCREEN_WRAP;
- *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = color;
- BufOfs %= SCREEN_WRAP;
- #endif
- }
- #endif
-
-
- /****************************************************************
- * *
- * N u m e r i c R o u t i n e s *
- * *
- ****************************************************************/
-
- byte
- GetDig ( char ch )
- {
- if ( ( ch >= '0' ) && ( ch <= '9' ) )
- return ch - '0';
- else if ( ( ch >= 'A' ) && ( ch <= 'F' ) )
- return ch - 'A' + 10;
- else if ( ( ch >= 'a' ) && ( ch <= 'f' ) )
- return ch - 'a' + 10;
- else if ( ( ch == 'x' ) || ( ch == 'X' ) )
- return 'x';
- else if ( ch == '#' )
- return '#';
- else if ( ch == 0 )
- return '0';
- else
- return '?';
- }
-
- dword
- GetNum(void)
- {
- byte state;
- dword base;
- dword num;
- char ch;
- byte digit;
-
- num = 0;
- state = 0;
-
- for (;;)
- {
- ch = *optarg++;
- digit = GetDig ( ch );
- switch ( state )
- {
- case 0:
- if ( digit == 0 )
- {
- base = 8;
- state = 1;
- }
- else if ( digit == '#' )
- {
- base = 16;
- state = 3;
- }
- else if ( digit <= 9 )
- {
- base = 10;
- num = digit;
- state = 2;
- }
- else
- {
- return ErrInt;
- }
- break;
-
- case 1:
- if ( digit == 'x' )
- {
- if ( num == 0 )
- {
- base = 16;
- state = 3;
- }
- else
- {
- return ErrInt;
- }
- }
- else if ( digit <= 9 )
- {
- num = num * base + digit;
- }
- else if ( digit == '0' )
- {
- return num;
- }
- else
- {
- return ErrInt;
- }
- break;
-
- case 2:
- if ( digit == '#' )
- {
- base = num;
- num = 0;
- if ( ( base < 2 ) || ( base > 16 ) )
- return ErrInt;
- state = 3;
- }
- else if ( digit <= 9 )
- {
- num = num * base + digit;
- }
- else if ( digit == '0' )
- {
- return num;
- }
- else
- {
- return ErrInt;
- }
- break;
-
- case 3:
- if ( digit < base )
- {
- num = num * base + digit;
- }
- else if ( digit == '0' )
- {
- return num;
- }
- else
- {
- return ErrInt;
- }
- break;
-
- }
- }
- }
-
- /****************************************************************
- * *
- * S e r i a l U t i l i t i e s *
- * *
- ****************************************************************/
-
- void setportb ( word Port, byte Mask )
- {
- outportb ( Port, inportb ( Port ) | Mask );
- }
-
- void clrportb ( word Port, byte Mask )
- {
- outportb ( Port, inportb ( Port ) & ~Mask );
- }
-
- /****************************************************************
- * *
- * R e c v P r o c *
- * *
- ****************************************************************/
-
- void RecvProc ( byte *buf, word len )
- {
- switch ( *(dword *) (buf) )
- {
- case 0x0102: /* IP datagram */
- PassUp ( buf+4, len-4 );
- IOS_PktIn++;
- IOS_ByteIn += len-4;
- break;
-
- case 0x0302: /* Address reply */
- RealIP_Address = ((dword)buf[4] << 24) | ((dword)buf[5] << 16)
- | ((dword)buf[6] << 8) | ((dword)buf[7]);
- InitTimer = 0;
- break;
-
- default:
- break;
- }
- }
-
- /****************************************************************
- * *
- * R e c v F S M *
- * *
- ****************************************************************/
-
- void RecvFSM ( byte RecvEvent, byte value )
- {
- static byte RecvState = 0;
- static byte *RecvPtr = (byte *)&RecvQ;
-
- switch ( RecvState )
- {
-
- /* state 0 -- dialing */
-
- case 0:
- switch ( RecvEvent )
- {
- case RECV_GOT_REQ:
- RecvState = 2;
- break;
-
- case RECV_RDA:
- if ( RecvQSize != QLEN )
- {
- RecvQ[RecvQTail++] = value;
- RecvQTail &= (QLEN-1);
- RecvQSize++;
- }
- break;
- }
- break;
-
- /* state 1 -- receiver idle */
-
- case 1:
- switch ( RecvEvent )
- {
- case RECV_GOT_REQ:
- RecvPtr = (byte *)&RecvQ;
- RecvState = 2;
- break;
-
- case RECV_RDA:
- break;
- }
- break;
-
- /* state 2 -- REQ has been received, receiving chars */
-
- case 2:
- switch ( RecvEvent )
- {
- case RECV_RDA:
- switch ( value )
- {
- case SLFP_ESC:
- RecvState = 3;
- break;
-
- case SLFP_END:
- RecvProc ( (byte *)&RecvQ, RecvPtr - (byte *)&RecvQ );
- RecvPtr = (byte *)&RecvQ;
- RecvState = 1;
- break;
-
- default:
- *RecvPtr++ = value;
- break;
- }
- break;
-
- case RECV_GOT_REQ:
- RecvPtr = (byte *)&RecvQ;
- break;
- }
- break;
-
- /* state 3 -- ESC received, waiting second char */
-
- case 3:
- switch ( RecvEvent )
- {
- case RECV_RDA:
- if ( value <= 3 )
- {
- *RecvPtr++ = SLFP_ESC + value;
- RecvState = 2;
- }
- else
- {
- RecvPtr = (byte *)&RecvQ;
- RecvState = 1;
- }
- break;
-
- case RECV_GOT_REQ:
- RecvState = 2;
- RecvPtr = (byte *)&RecvQ;
- break;
-
- }
- break;
-
- default:
- break;
- }
- }
-
- /****************************************************************
- * *
- * X m i t F S M *
- * *
- ****************************************************************/
-
- void
- XmitFSM ( byte event )
- {
- typedef enum
- {
- s_Idle, /* wait for anything (DI) */
- s_Idle_Ack, /* after sending Ack in Idle */
- s_Check, /* pseudo state to combine code */
- s_Sent_Req, /* after sending Req */
- s_Wait, /* wait for Ack (DI) */
- s_Wait_Ack, /* after sending Ack in Wait */
- s_Message, /* sending message */
- s_Sent_End /* after sending End */
- } s_t;
- static s_t state = s_Idle;
-
- static word Qcount;
- static byte Qvalue;
-
- static BOOLEAN Framing = FALSE;
- static BOOLEAN SendAck = FALSE;
- static BOOLEAN SentEsc = FALSE;
-
- int counter = XmitCount;
-
- do
- {
- switch ( event )
- {
- case XMIT_MESSAGE:
- if ( state == s_Idle )
- {
- setportb ( IOA_IER, IER_TXE );
- state = s_Check;
- event = XMIT_THRE; /* fake interrupt */
- }
- break;
-
- case XMIT_GOT_REQ:
- switch ( state )
- {
- case s_Idle:
- case s_Wait:
- setportb ( IOA_IER, IER_TXE );
- XmitTimer = 1 * SECONDS;
- SendAck = FALSE; /* paranoia */
- trace ( SLFP_ACK, LIGHTBLUE );
- outportb ( IOA_THR, SLFP_ACK );
- state++; /* _Ack state */
- break;
- default:
- SendAck = TRUE;
- break;
- };
- Serial_Handshake = TRUE;
- break;
-
- case XMIT_GOT_ACK:
- switch ( state )
- {
- case s_Wait: /* tx interrupt is off */
- setportb ( IOA_IER, IER_TXE );
- /* fallthru */
-
- case s_Sent_Req: /* must have missed THRE */
- event = XMIT_THRE; /* fake interrupt */
- /* fallthru */
-
- case s_Wait_Ack: /* must wait for ACK THRE */
- XmitQHead += 2; /* skip count */
- XmitQHead &= (QLEN-1);
- XmitQSize -= 2;
- state = s_Message;
- break;
-
- default:
- /* ignore spurious Ack */
- break;
- };
- break;
-
- case XMIT_THRE:
- case XMIT_LOOP:
- XmitTimer = 1 * SECONDS;
-
- if ( SentEsc )
- {
- SentEsc = FALSE;
- trace ( Qvalue - SLFP_ESC, MAGENTA );
- outportb ( IOA_THR, Qvalue - SLFP_ESC );
- event = XMIT_LOOP;
- counter--;
- }
- else if ( SendAck )
- {
- SendAck = FALSE;
- trace ( SLFP_ACK, LIGHTBLUE );
- outportb ( IOA_THR, SLFP_ACK );
- counter = 0; /* wait for real THRE */
- }
- else
- {
- switch ( state )
- {
- case s_Sent_End:
- case s_Idle_Ack:
- case s_Check:
- if ( XmitQSize < 2 )
- {
- if ( XmitQSize != 0 )
- {
- XmitQHead =
- XmitQTail =
- XmitQSize = 0;
- }
- if ( event == XMIT_THRE )
- {
- clrportb ( IOA_IER, IER_TXE );
- XmitTimer = 0;
- state = s_Idle;
- }
- counter = 0; /* wait for event */
- }
- else
- {
- word Qindex;
-
- Qindex = XmitQHead;
- Qcount = XmitQ[Qindex++];
- Qindex &= (QLEN-1);
- Qcount |= (word)(XmitQ[Qindex++]) << 8;
- Qindex &= (QLEN-1);
-
- if ( Qcount > 0 && Framing )
- {
- trace ( SLFP_REQ, LIGHTRED );
- outportb ( IOA_THR, SLFP_REQ );
- counter = 0; /* wait for real THRE */
- state = s_Sent_Req;
- }
- else
- {
- XmitQHead += 2; /* skip count, just like Ack */
- XmitQHead &= (QLEN-1);
- XmitQSize -= 2;
-
- if ( !Framing )
- {
- state = s_Message;
- }
- }
- }
- break;
-
- case s_Sent_Req:
- case s_Wait_Ack:
- clrportb ( IOA_IER, IER_TXE );
- XmitTimer = 3 * SECONDS;
- counter = 0; /* wait for event or timer */
- state = s_Wait;
- break;
-
- case s_Message:
- if ( Qcount-- > 0 )
- {
- Qvalue = XmitQ[XmitQHead++];
- XmitQHead &= (QLEN-1);
- XmitQSize--;
-
- if ( Qvalue >= SLFP_ESC && Qvalue <= SLFP_END )
- {
- SentEsc = TRUE;
- trace ( SLFP_ESC, LIGHTMAGENTA );
- outportb ( IOA_THR, SLFP_ESC );
- }
- else
- {
- trace ( Qvalue, LIGHTGREEN );
- outportb ( IOA_THR, Qvalue );
- }
- event = XMIT_LOOP;
- counter--;
- }
- else
- {
- if ( Framing )
- {
- trace ( SLFP_END, LIGHTCYAN );
- outportb ( IOA_THR, SLFP_END );
- event = XMIT_LOOP;
- counter--;
- }
- else
- {
- Framing = TRUE;
- }
- state = s_Sent_End;
- }
- break;
-
- default:
- /* spurious interrupt */
- clrportb ( IOA_IER, IER_TXE );
- counter = 0; /* wait for external event */
- break;
- };
- }
- break;
-
- case XMIT_TIMEOUT:
- switch ( state )
- {
- case s_Wait:
- IOE_ReqTO++;
- setportb ( IOA_IER, IER_TXE );
- state = s_Check; /* try again */
- event = XMIT_THRE; /* fake interrupt */
- break;
-
- case s_Idle_Ack:
- case s_Sent_Req:
- case s_Wait_Ack:
- case s_Message:
- case s_Sent_End:
- IOE_LostTHRE++;
- event = XMIT_THRE; /* fake interrupt */
-
- default:
- /* ignore spurious timeout */
- break;
- };
- XmitTimer = 0; /* should already be zero */
- break;
-
- default:
- /* unknown event */
- break;
- }
- } while ( (event == XMIT_THRE || event == XMIT_LOOP) && counter > 0 );
- }
-
-
- void
- XmitQput ( char *header, byte *buffer, word buffer_size )
- {
- register word count;
- register word Qindex;
-
- if ( header != NULL )
- buffer_size += 4;
-
- Qindex = XmitQTail;
- XmitQ[Qindex++] = (byte)(buffer_size);
- Qindex &= (QLEN-1);
- XmitQ[Qindex++] = (byte)(buffer_size >> 8);
- Qindex &= (QLEN-1);
-
- count = 0;
-
- if ( header != NULL )
- {
- for ( ; count < 4; count++ )
- {
- XmitQ[Qindex++] = *header++;
- Qindex &= (QLEN-1);
- }
- }
-
- while ( count++ < buffer_size )
- {
- XmitQ[Qindex++] = *buffer++;
- Qindex &= (QLEN-1);
- }
-
- disable();
- XmitQTail = Qindex;
- XmitQSize += buffer_size + 2;
- XmitFSM ( XMIT_MESSAGE );
- enable();
- }
-
-
- /****************************************************************
- * *
- * S e r i a l I S R *
- * *
- ****************************************************************/
-
- void interrupt SerialISR ( )
- {
- byte IntrIdent;
- byte ch;
- byte ErrMask;
- int HighWater = 0;
-
- outportb ( 0x20, 0x20 );
- while ( ( ( IntrIdent = inportb ( IOA_IIR ) ) & IIR_IP ) == 0 )
- {
- switch ( IntrIdent & IIR_ID )
- {
- case IIR_RDA:
- for (;;)
- {
- ErrMask = inportb ( IOA_LSR );
- if ( ErrMask & LSR_OE )
- IOE_OverRun++;
- if ( ErrMask & LSR_PE )
- IOE_Parity++;
- if ( ErrMask & LSR_FE )
- IOE_Framing++;
- if ( ErrMask & LSR_BI )
- IOE_Break++;
-
- if ( (ErrMask & LSR_DR) == 0 )
- break;
-
- HighWater++;
- ch = inportb ( IOA_RBR );
- trace ( ch, BROWN );
-
- switch ( ch )
- {
- case SLFP_REQ:
- RecvFSM ( RECV_GOT_REQ, 0 );
- XmitFSM ( XMIT_GOT_REQ );
- break;
- case SLFP_ACK:
- XmitFSM ( XMIT_GOT_ACK );
- break;
- default:
- RecvFSM ( RECV_RDA, ch );
- break;
- }
- }
- IOE_IntrIn++;
- IOE_FifoHi = max ( IOE_FifoHi, HighWater );
- break;
-
- case IIR_THRE:
- XmitFSM ( XMIT_THRE );
- IOE_IntrOut++;
- break;
-
- case IIR_MSTAT:
- break;
-
- case IIR_RLS:
- ErrMask = inportb ( IOA_LSR );
- if ( ErrMask & LSR_OE )
- IOE_OverRun++;
- if ( ErrMask & LSR_PE )
- IOE_Parity++;
- if ( ErrMask & LSR_FE )
- IOE_Framing++;
- if ( ErrMask & LSR_BI )
- IOE_Break++;
- break;
- }
- if ( IntrIdent & IIR_FIFO_TO )
- IOE_FifoTO++;
- }
- }
-
- /****************************************************************
- * *
- * S e r i a l I n i t *
- * *
- ****************************************************************/
-
- BOOLEAN SerialInit ( word IOBase, byte IRQ, word Speed )
- {
- word *IOA_ptr;
- word ClockRate;
- int ind;
-
- /* check parameters for consistancy */
-
- if ( ( IOBase == 0x3F8 ) && ( IRQ != 4 ) )
- {
- printf ( "Warning: COM1 usually uses IRQ 4\n" );
- }
-
- if ( ( IOBase == 0x2F8 ) && ( IRQ != 3 ) )
- {
- printf ( "Warning: COM2 usually uses IRQ 3\n" );
- }
-
- if ( ( IRQ < 1 ) || ( IRQ > 7 ) )
- {
- printf ( "Error: Only first interrupt controller supported\n" );
- return FALSE;
- }
-
- if ( ( 115200L % Speed ) != 0 )
- {
- printf ( "Warning: Line speed can only be approximated\n" );
- }
-
- /* save parameters */
-
- IOA_ptr = &IOA_First;
- for ( ind=0; ind<IOA_Count; ind++ )
- {
- *IOA_ptr++ += IOBase;
- }
- Serial_IRQ = IRQ;
- Serial_Speed = Speed;
-
- /*
- * Initialize 8250
- */
-
- /* disable interrupts */
-
- disable();
-
- /* empty receiver buffer */
-
- (void) inportb ( IOA_RBR );
-
- /* set 8 bits, no parity, one stop bit */
-
- outportb ( IOA_LCR, LCR_8BITS );
-
- /* check for 16550A and enable fifo */
-
- if ( ConfFifoCheck )
- {
- outportb ( IOA_FCR, FCR_ENABLE );
-
- if ( ( inportb ( IOA_IIR ) & IIR_FIFO_ENB ) == IIR_FIFO_ENB )
- {
- /* Chip is a 16550A. Setup the FIFOs
- */
- Serial_16550A = TRUE;
- XmitCount = 16;
- outportb ( IOA_FCR, FCR_SETUP);
- printf ( "16650A detected\n" );
- }
- else
- {
- /* Chip is not a 16550A. In case it's a 16550 (which has a
- * broken FIFO), turn off the FIFO bit.
- */
- outportb ( IOA_FCR, FCR_RESET );
- }
- }
-
- /* enable receiver interrupts */
-
- outportb ( IOA_IER, IER_DAV|IER_RLS );
-
- /* raise DTR, RTS & enable master interrupts */
-
- outportb ( IOA_MCR, MCR_DTR | MCR_RTS | MCR_OUT2 );
-
- /* set up clock rate */
-
- ClockRate = 115200L / Speed;
- setportb ( IOA_LCR, LCR_DLAB );
- outportb ( IOA_DLL, (byte)( ClockRate ) );
- outportb ( IOA_DLM, (byte)( ClockRate >> 8 ) );
- clrportb ( IOA_LCR, LCR_DLAB );
-
- /* set up serial ISR */
-
- SaveSerialInt = getvect ( IRQ+8 );
- setvect ( IRQ+8, SerialISR );
-
- /* enable interrupt on 8259 */
-
- outportb ( 0x21, inportb ( 0x21 ) & ~ ( 1 << IRQ ) );
-
- /* transmit state machine */
-
- enable();
- delay ( 1000 );
- disable();
-
- /* all done */
-
- enable();
- return TRUE;
- }
-
- /****************************************************************
- * *
- * S e r i a l I n i t *
- * *
- ****************************************************************/
-
- void SerialTerm ( void )
- {
- /* disable 8250 interrupts */
-
- outportb ( IOA_IER, 0 );
- outportb ( IOA_MCR, 0 );
- outportb ( 0x21, inportb ( 0x21 ) | ( 1 << Serial_IRQ ) );
-
- /* restore interrupt vector */
-
- setvect ( Serial_IRQ+8, SaveSerialInt );
- }
-
- /****************************************************************
- * *
- * Timer Tick *
- * *
- ****************************************************************/
-
- void interrupt TimerTick ( )
- {
- /* handle tick */
-
- if ( XmitTimer != 0 && --XmitTimer == 0 )
- {
- XmitFSM ( XMIT_TIMEOUT );
- }
-
- if ( InitTimer != 0 && --InitTimer == 0 )
- {
- }
-
- /* chain on old interrupt handler */
-
- (*SaveTimerInt)();
-
- }
-
- /****************************************************************
- * *
- * Pass Up *
- * *
- ****************************************************************/
-
- void PassUp ( void * buf, word len )
- {
- RecvType TempRecv;
- void *TempPtr;
-
- /* ensure a handle to return message on */
-
- if ( !HandleTable.Hand_InUse )
- {
- IOS_PktDrop++;
- return;
- }
-
- /* ensure receiver hasn't asked for a specific type */
-
- if ( HandleTable.Hand_TypeLen != 0 )
- {
- IOS_PktDrop++;
- return;
- }
-
- /* get buffer */
-
- TempRecv = HandleTable.Hand_Receiver;
- if ( TempRecv == NULL )
- {
- IOS_PktDrop++;
- return;
- }
-
- _AX = 0;
- _CX = len;
- _BX = 1;
- TempRecv();
- TempPtr = (void *) MK_FP ( _ES, _DI );
-
- if ( TempPtr == NULL )
- {
- IOS_PktDrop++;
- return;
- }
-
- /* move data into buffer */
-
- memcpy ( TempPtr, buf, len );
-
- /* pass up to receiver */
-
- __emit__ ( 0x1E ); /* push ds */
- _DS = FP_SEG ( TempPtr );
- _SI = FP_OFF ( TempPtr );
- _AX = 1;
- _CX = len;
- _BX = 1;
- TempRecv();
- __emit__ ( 0x1F ); /* pop ds */
-
- }
-
- /****************************************************************
- * *
- * PDF Driver Info *
- * *
- ****************************************************************/
-
- void DriverInfo ( IntrRegsType *IntrRegs )
-
- {
- /* ensure real function */
-
- if ( IntrRegs->b.al != 0xFF )
- {
- IntrRegs->w.fl |= FL_CARRY;
- IntrRegs->b.dh = PDE_BadCommand;
- return;
- }
-
- /* return driver info */
-
- IntrRegs->w.fl &= ~FL_CARRY;
- IntrRegs->w.bx = PD_version;
- IntrRegs->b.ch = PDC_SLFP;
- IntrRegs->w.dx = PDT_Merit;
- IntrRegs->b.cl = 0; /* number */
- IntrRegs->w.ds = FP_SEG(PDN_slfp);
- IntrRegs->w.si = FP_OFF(PDN_slfp);
- IntrRegs->b.al = PDV_extended;
- }
-
- /****************************************************************
- * *
- * PDF Access Type *
- * *
- ****************************************************************/
-
- void AccessType ( IntrRegsType *IntrRegs )
-
- {
- /* assume error */
-
- IntrRegs->w.fl |= FL_CARRY;
-
- /* ensure SLFP class request */
-
- if ( IntrRegs->b.al != PDC_SLFP )
- {
- IntrRegs->b.dh = PDE_NoClass;
- return;
- }
-
- /* ensure proper type request */
-
- if ( ( IntrRegs->w.bx != PDT_any ) && ( IntrRegs->w.bx != PDT_Merit ) )
- {
- IntrRegs->b.dh = PDE_NoType;
- return;
- }
-
- /* ensure proper number request */
-
- if ( ( IntrRegs->b.dl != 0 ) && ( IntrRegs->b.dl != 1 ) )
- {
- IntrRegs->b.dh = PDE_NoNumber;
- return;
- }
-
- /* ensure already not in use */
-
- if ( HandleTable.Hand_InUse )
- {
- IntrRegs->b.dh = PDE_TypeInUse;
- return;
- }
-
- /* type value length must be <= 8 */
-
- if ( IntrRegs->w.cx > 8 )
- {
- IntrRegs->b.dh = PDE_BadType;
- return;
- }
-
- /* enter info into handler table entry */
-
- HandleTable.Hand_InUse = TRUE;
- HandleTable.Hand_Receiver =
- (RecvType) MK_FP ( IntrRegs->w.es, IntrRegs->w.di );
- HandleTable.Hand_TypeLen = IntrRegs->w.cx;
-
- /* all done */
-
- IntrRegs->w.fl &= ~FL_CARRY;
- IntrRegs->w.ax = 1;
-
- }
-
- /****************************************************************
- * *
- * PDF Release Type *
- * *
- ****************************************************************/
-
- void ReleaseType ( IntrRegsType *IntrRegs )
- {
- word hand;
-
- hand = IntrRegs->w.bx;
-
- /* ensure good handle */
-
- if ( hand != 1 )
- {
- IntrRegs->w.fl |= FL_CARRY;
- IntrRegs->b.dh = PDE_BadHandle;
- return;
- }
-
- /* clear table entry */
-
- HandleTable.Hand_InUse = FALSE;
- HandleTable.Hand_Receiver = (RecvType) NULL;
-
- /* all done */
-
- IntrRegs->w.fl &= ~FL_CARRY;
-
- }
-
- /****************************************************************
- * *
- * PDF SendPkt *
- * *
- ****************************************************************/
-
- void SendPkt ( IntrRegsType *IntrRegs )
- {
- word TotalLen;
- byte *BufPtr;
-
- /* set up */
-
- IntrRegs->w.fl |= FL_CARRY;
- IntrRegs->b.dh = PDE_CantSend;
-
- TotalLen = IntrRegs->w.cx;
- if ( TotalLen + 2 + 4 > QLEN - XmitQSize )
- {
- IOS_ErrOut++;
- return;
- }
-
- /* put message on transmit queue */
-
- BufPtr = (byte *) MK_FP ( IntrRegs->w.ds, IntrRegs->w.si );
- XmitQput( "\x2\x1\x0\x0", BufPtr, TotalLen );
-
- /* record stats */
-
- IOS_PktOut++;
- IOS_ByteOut += IntrRegs->w.cx;
-
- /* all done */
-
- IntrRegs->w.fl &= ~FL_CARRY;
- }
-
- /****************************************************************
- * *
- * PDF Terminate *
- * *
- ****************************************************************/
-
- void Terminate ( IntrRegsType *IntrRegs )
- {
- union REGS regs;
- struct SREGS sregs;
-
- /* restore hardware and interrupts */
-
- disable();
- SerialTerm();
- setvect ( 0x08, SaveTimerInt );
- setvect ( ConfPackInt, SavePacketInt );
- enable();
-
- /* assume failure */
-
- IntrRegs->w.fl |= FL_CARRY;
- IntrRegs->b.dh = PDE_CantTerminate;
-
- /* return program block */
-
- regs.h.ah = 0x49;
- sregs.es = _psp;
- intdosx ( ®s, ®s, &sregs );
- if ( regs.x.cflag != 0 )
- return;
-
- /* return environment block */
-
- regs.h.ah = 0x49;
- sregs.es = ( (PSP_Ptr) MK_FP ( _psp, 0 ) ) -> PSP_Environment;
- intdosx ( ®s, ®s, &sregs );
- if ( regs.x.cflag != 0 )
- return;
-
- /* all OK */
-
- IntrRegs->w.fl &= ~FL_CARRY;
- }
-
- /****************************************************************
- * *
- * PDF Get Address *
- * *
- ****************************************************************/
-
- void GetAddress ( IntrRegsType *IntrRegs )
- {
- word hand;
-
- /* set up */
-
- hand = IntrRegs->w.bx;
- IntrRegs->w.fl |= FL_CARRY;
-
- /* ensure a good handle */
-
- if ( hand > 1 )
- {
- IntrRegs->b.dh = PDE_BadHandle;
- return;
- }
-
- /* make sure enough space to return address */
-
- if ( IntrRegs->w.cx < 4 )
- {
- IntrRegs->b.dh = PDE_NoSpace;
- return;
- }
-
- /* return address */
-
- IntrRegs->w.fl &= ~FL_CARRY;
- IntrRegs->w.cx = 4;
- memcpy ( MK_FP(IntrRegs->w.es,IntrRegs->w.di),
- (const void *) &RealIP_Address, 4 );
- }
-
- /****************************************************************
- * *
- * Packet Driver Interrupt Handler *
- * *
- ****************************************************************/
-
- void interrupt PacketDriver ( IntrRegsType IntrRegs )
-
- {
- enable();
-
- switch ( IntrRegs.b.ah )
- {
-
- case PDF_DriverInfo:
- DriverInfo ( &IntrRegs );
- break;
-
- case PDF_AccessType:
- AccessType ( &IntrRegs );
- break;
-
- case PDF_ReleaseType:
- ReleaseType ( &IntrRegs );
- break;
-
- case PDF_SendPkt:
- SendPkt ( &IntrRegs );
- break;
-
- case PDF_Terminate:
- Terminate ( &IntrRegs );
- break;
-
- case PDF_GetAddress:
- while ( InitTimer )
- ;
- GetAddress ( &IntrRegs );
- break;
-
- case PDF_GetStatistics:
- IntrRegs.w.fl &= ~FL_CARRY;
- IntrRegs.w.ds = FP_SEG ( &IOS_Table );
- IntrRegs.w.si = FP_OFF ( &IOS_Table );
- break;
-
- case PDF_GetErrors:
- IntrRegs.w.fl &= ~FL_CARRY;
- IntrRegs.w.ds = FP_SEG ( &IOE_Table );
- IntrRegs.w.si = FP_OFF ( &IOE_Table );
- break;
-
- default:
- IntrRegs.w.fl |= FL_CARRY;
- IntrRegs.b.dh = PDE_BadCommand;
- }
- }
-
- /****************************************************************
- * *
- * Ctl-C(break) handler *
- * *
- ****************************************************************/
-
- int BreakHandler ( void )
- {
- printf ( "SLFP aborted\n" );
-
- /* restore hardware and interrupts */
-
- disable();
- SerialTerm();
- setvect ( 0x08, SaveTimerInt );
- setvect ( ConfPackInt, SavePacketInt );
- enable();
- exit ( ERL_break );
- return 0;
- }
-
- /****************************************************************
- * *
- * Process echo *
- * *
- ****************************************************************/
-
- void
- proc_echo ( void )
- {
- char ch;
-
- if ( RecvQSize )
- {
- disable();
- ch = RecvQ[RecvQHead++];
- RecvQHead &= (QLEN-1);
- RecvQSize--;
- enable();
- putchar ( ch );
- }
- }
-
- /****************************************************************
- * *
- * Main routine *
- * *
- ****************************************************************/
-
- void main ( int argc, char **argv )
- {
- void *HookPtr;
- dword PSize;
- int opt;
- BOOLEAN err;
- InterruptPtrType
- OldPackInt;
- char PDSig[8];
-
-
- /* give version message */
-
- printf ( "SLFP: version " SLFP_VERSION "\n" );
-
- /* parse command image */
-
- err = FALSE;
-
- do
- {
- opt = getopt ( argc, argv, "p:i:b:s:d:t:h:f:" );
-
- switch ( opt )
- {
- case 'p':
- ConfPackInt = GetNum();
- break;
-
- case 'i':
- ConfSerialIrq = GetNum();
- break;
-
- case 'b':
- ConfSerialBase = GetNum();
- break;
-
- case 's':
- ConfSerialSpeed = GetNum();
- break;
-
- case 'd':
- strcpy ( ConfSerialDial, optarg );
- break;
-
- case 't':
- ConfInitTime = GetNum();
- break;
-
- case 'h':
- ConfHandshake = GetNum();
- break;
-
- case 'f':
- ConfFifoCheck = GetNum();
- break;
-
- case EOF:
- break;
-
- default:
- err = TRUE;
- break;
- }
- }
- while ( opt != EOF );
-
- if ( err )
- {
- printf ( "Usage: slfp [/p PacketIntNo] [/i SerialIntNo]"
- " [/b SerialBase] [/s SerialSpeed] [/d DialCmd] /t [InitTime]"
- " [/h Handshake] [/f FifoCheck]\n" );
- exit ( ERL_parse );
- }
-
- /* check for packet driver already loaded */
-
- OldPackInt = getvect ( ConfPackInt );
-
- movedata ( FP_SEG(OldPackInt), FP_OFF(OldPackInt)+3,
- FP_SEG(PDSig), FP_OFF(PDSig), 8 );
-
- if ( strncmp ( PDSig, "PKT DRVR", 8 ) == 0 )
- {
- printf ( "Packet driver already loaded at 0x%X\n", ConfPackInt );
- exit ( ERL_packet );
- }
-
- /* output parameters */
-
- printf ( "slfp /p 0x%X /i %d /b 0x%X /s %d /t %d /h %d /f %d /d %s\n",
- ConfPackInt, ConfSerialIrq, ConfSerialBase, ConfSerialSpeed,
- ConfInitTime, ConfHandshake, ConfFifoCheck, ConfSerialDial );
-
- strcat ( ConfSerialDial, "\r" );
- InitTimer = ConfInitTime * SECONDS;
-
- /* set up ctl-C handler */
-
- ctrlbrk ( BreakHandler );
-
- /* clear Handle table */
-
- HandleTable.Hand_InUse = FALSE;
- HandleTable.Hand_Receiver = (RecvType) NULL;
-
- /* build driver hook */
-
- memcpy ( PacketDriverHook, "\xEB\x0A\x90PKT DRVR\0\xEA", 13 );
- HookPtr = (void *)PacketDriver;
- memcpy ( &PacketDriverHook[13], &HookPtr, 4 );
-
- /* set up packet driver vector */
-
- SavePacketInt = getvect ( ConfPackInt );
- setvect ( ConfPackInt, (InterruptPtrType) PacketDriverHook );
-
- /* set up Timer routine */
-
- SaveTimerInt = getvect ( 0x08 );
- setvect ( 0x08, TimerTick );
-
- /* initialize serial link */
-
- SerialInit ( ConfSerialBase, ConfSerialIrq, ConfSerialSpeed );
-
- /* dial modem, wait for initial handshake */
-
- XmitQput( NULL, (byte *)ConfSerialDial, strlen( ConfSerialDial ) );
-
- while ( InitTimer && ConfHandshake && !Serial_Handshake )
- {
- proc_echo();
- (void) kbhit();
- }
-
- /* send IP address request, wait for IP address */
-
- XmitQput( "\x2\x3\x0\x0", NULL, 0 );
-
- while ( InitTimer && RealIP_Address == 0L )
- {
- proc_echo();
- (void) kbhit();
- }
-
- if ( RealIP_Address != 0L )
- {
- printf ( "\nIP address set to %d.%d.%d.%d\n",
- (byte)( RealIP_Address >> 24 ),
- (byte)( RealIP_Address >> 16 ),
- (byte)( RealIP_Address >> 8 ),
- (byte)( RealIP_Address ) );
- }
- else
- {
- printf ( "\nUnable to establish IP address. SLFP aborted\n" );
-
- /* restore hardware and interrupts */
-
- disable();
- SerialTerm();
- setvect ( 0x08, SaveTimerInt );
- setvect ( ConfPackInt, SavePacketInt );
- enable();
-
- exit ( ERL_handshake );
- }
-
- /* terminate, stay resident */
-
- PSize = ( (byte huge *)MK_FP(_SS,_SP+15) - (byte huge *)MK_FP(_CS,0) ) / 16;
- keep ( ERL_none, PSize );
-
- }
-