home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / NETWORK / SLFP.ZIP / SLFP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-18  |  37.5 KB  |  1,946 lines

  1. /****************************************************************
  2.  *                                                                *
  3.  *                SLFP packet driver                                *
  4.  *                                                                *
  5.  *    Glenn H McGregor, Merit Computer Network                    *
  6.  *    William A Simpson, Computer Systems Consulting Services        *
  7.  *                                                                *
  8.  ****************************************************************/
  9.  
  10. #define SLFP_VERSION    "1.30"
  11.  
  12. /*
  13.  *  trace
  14.  */
  15.  
  16. #undef    DEBUG
  17. #define SCREEN_EGA
  18. #define TRACE_HEX
  19. #define TRACE_ALL_HEX
  20.  
  21. #ifdef DEBUG
  22. #define trace(ch,color) Trace(ch,color)
  23. #else
  24. #define trace(ch,color)
  25. #endif
  26.  
  27. /*
  28.  *  Includes
  29.  */
  30.  
  31. #include    <stdio.h>
  32. #include    <stdlib.h>
  33. #include    <conio.h>
  34. #include    <dos.h>
  35. #include    <mem.h>
  36. #include    <graphics.h>
  37. #include    <string.h>
  38.  
  39. #include    "getopt.h"
  40. #include    "gen.h"
  41.  
  42. /*
  43.  *  Memory layout
  44.  */
  45.  
  46. word    _stklen        =    256;
  47. word    _heaplen    =    256;
  48.  
  49. /*
  50.  *  Configuration options & defaults
  51.  */
  52.  
  53. byte    ConfPackInt        =    0x60;
  54. byte    ConfSerialIrq    =    4;
  55. word    ConfSerialBase    =    0x3F8;
  56. word    ConfSerialSpeed    =    2400;
  57. char    ConfSerialDial[40] =    "";
  58. word    ConfInitTime    =    60;
  59. byte    ConfHandshake    =    1;
  60. byte    ConfFifoCheck    =    1;
  61. byte    ConfQuitSoft    =    0;
  62.  
  63. /*
  64.  *  Error level returns
  65.  */
  66.  
  67. enum
  68.     {
  69.     ERL_none,
  70.     ERL_parse,
  71.     ERL_packet,
  72.     ERL_break,
  73.     ERL_handshake
  74.     };
  75.  
  76. /*
  77.  *  SLFP characters
  78.  */
  79.  
  80. enum
  81.     {
  82.     SLFP_ESC    =    0xF2,    /* next character substitution */
  83.     SLFP_REQ    =    0xF3,    /* request transmit oportunity */
  84.     SLFP_ACK    =    0xF4,    /* transmit request acknowledged */
  85.     SLFP_END    =    0xF5,    /* end of transmission block */
  86.     };
  87.  
  88. /*
  89.  *  Interrupt events
  90.  */
  91.  
  92. enum
  93.     {
  94.     RECV_RDA,
  95.     RECV_GOT_REQ,
  96.     RECV_REINIT
  97.     };
  98.  
  99. enum
  100.     {
  101.     XMIT_MESSAGE,
  102.     XMIT_GOT_REQ,
  103.     XMIT_GOT_ACK,
  104.     XMIT_THRE,
  105.     XMIT_LOOP,
  106.     XMIT_TIMEOUT,
  107.     XMIT_REINIT
  108.     };
  109.  
  110. /*
  111.  *  I/O queues
  112.  */
  113.  
  114. #define    QLEN    0x1000
  115.  
  116. word        RecvQHead    =    0;
  117. word        RecvQTail    =    0;
  118. int            RecvQSize    =    0;
  119. byte        RecvQ[QLEN];
  120.  
  121. word        XmitQHead    =    0;
  122. word        XmitQTail    =    0;
  123. int            XmitQSize    =    0;
  124. byte        XmitQ[QLEN];
  125.  
  126. /*
  127.  *  8250 I/O base offsets
  128.  */
  129.  
  130. enum
  131.     {
  132.     IOO_THR        =    0,        /* transmitter holding register */
  133.     IOO_RBR        =    0,        /* receiver buffer register */
  134.     IOO_DLL        =    0,        /* divisor latch LSB */
  135.     IOO_DLM        =    1,        /* divisor latch MSB */
  136.     IOO_IER        =    1,        /* interrupt enable register */
  137.     IOO_IIR        =    2,        /* interrupt ident register */
  138.     IOO_FCR        =    2,        /* fifo control register */
  139.     IOO_LCR        =    3,        /* line control register */
  140.     IOO_MCR        =    4,        /* modem control register */
  141.     IOO_LSR        =    5,        /* line status register */
  142.     IOO_MSR        =    6        /* modem status register */
  143.     };
  144.  
  145. /*
  146.  *  8250 line control register
  147.  */
  148.  
  149. enum
  150.     {
  151.     LCR_5BITS    =    0x00,    /* five bit words */
  152.     LCR_6BITS    =    0x01,    /* six bit words */
  153.     LCR_7BITS    =    0x02,    /* seven bit words */
  154.     LCR_8BITS    =    0x03,    /* eight bit words */
  155.     LCR_NSB        =    0x04,    /* number of stop bits */
  156.     LCR_PEN        =    0x08,    /* parity enable */
  157.     LCR_EPS        =    0x10,    /* even parity select */
  158.     LCR_SP        =    0x20,    /* stick parity */
  159.     LCR_SB        =    0x40,    /* set break */
  160.     LCR_DLAB    =    0x80    /* divisor latch access bit */
  161.     };
  162.  
  163. /*
  164.  *  8250 line status register
  165.  */
  166.  
  167. enum
  168.     {
  169.     LSR_DR        =    0x01,    /* data ready */
  170.     LSR_OE        =    0x02,    /* overrun error */
  171.     LSR_PE        =    0x04,    /* parity error */
  172.     LSR_FE        =    0x08,    /* framing error */
  173.     LSR_BI        =    0x10,    /* break interrupt */
  174.     LSR_THRE    =    0x20,    /* transmitter line holding register empty */
  175.     LSR_TSRE    =    0x40,    /* transmitter shift register empty */
  176.     };
  177.  
  178. /*
  179.  *  8250 interrupt identification register
  180.  */
  181.  
  182. enum
  183.     {
  184.     IIR_IP        =    0x01,    /* not interrupt pending */
  185.     IIR_ID        =    0x06,    /* mask for interrupt id */
  186.     IIR_RLS        =    0x06,    /* receive line status interrupt */
  187.     IIR_RDA        =    0x04,    /* receive data available interrupt */
  188.     IIR_THRE    =    0x02,    /* transmit holding reg empty interrupt */
  189.     IIR_MSTAT    =    0x00,    /* modem status interrupt */
  190.  
  191.     IIR_FIFO_TO    =    0x08,    /* fifo timeout interrupt pending (16550A only */
  192.     IIR_FIFO_ENB=    0xC0    /* fifo enabled (16550A only) */
  193.     };
  194.  
  195. /*
  196.  *  8250 interrupt enable register bits
  197.  */
  198.  
  199. enum
  200.     {
  201.     IER_DAV        =    0x01,    /* data available interrupt */
  202.     IER_TXE        =    0x02,    /* transmit buffer empty interrupt */
  203.     IER_RLS        =    0x04,    /* receive line status interrupt */
  204.     IER_MS        =    0x08    /* modem status interrupt */
  205.     };
  206.  
  207. /*
  208.  *  8250 modem control register
  209.  */
  210.  
  211. enum
  212.     {
  213.     MCR_DTR        =    0x01,    /* data terminal ready */
  214.     MCR_RTS        =    0x02,    /* request to send */
  215.     MCR_OUT1    =    0x04,    /* out 1 (not used) */
  216.     MCR_OUT2    =    0x08,    /* out 2 (master interrupt enable) */
  217.     MCR_LOOP    =    0x10    /* loopback test mode */
  218.     };
  219.  
  220. /*
  221.  *  8250 modem status register
  222.  */
  223.  
  224. enum
  225.     {
  226.     MSR_DCTS    =    0x01,    /* delta clear-to-send */
  227.     MSR_DDSR    =    0x02,    /* delta data-set-ready */
  228.     MSR_TERI    =    0x04,    /* trailing edge ring indicator */
  229.     MSR_DRLSD    =    0x08,    /* delta rx line signal detect */
  230.     MSR_CTS        =    0x10,    /* clear-to-send */
  231.     MSR_DSR        =    0x20,    /* data-set-ready */
  232.     MSR_RI        =    0x40,    /* ring indicator */
  233.     MSR_RLSD    =    0x80    /* received line signal detect */
  234.     };
  235. /*
  236.  *  16550 fifo control register
  237.  */
  238.  
  239. enum
  240.     {
  241.     FCR_RESET    =    0x00,    /* disable TX & RX fifo */
  242.     FCR_ENABLE    =    0x01,    /* enable TX & RX fifo */
  243.     FCR_CLR_RX    =    0x02,    /* clear receive fifo */
  244.     FCR_CLR_TX    =    0x04,    /* clear transmit fifo */
  245.     FCR_ST_DMA    =    0x08,    /* enable TXRDY/RXRDY pin DMA handshake */
  246.  
  247.     FCR_RXT_1    =    0x00,    /* RX fifo trigger levels */
  248.     FCR_RXT_4    =    0x40,
  249.     FCR_RXT_8    =    0x80,
  250.     FCR_RXT_14    =    0xC0,
  251.  
  252.     FCR_SETUP    =    FCR_ENABLE|FCR_CLR_RX|FCR_CLR_TX|FCR_RXT_4
  253.     };
  254.  
  255. /*
  256.  *  Serial global data
  257.  */
  258.  
  259. word        Serial_IOBase;    /* I/O address of 8250 chip */
  260. byte        Serial_IRQ;        /* Interrupt number of 8250 chip */
  261. dword        Serial_Speed;    /* Line speed of interface */
  262. InterruptPtrType
  263.             SaveSerialInt;    /* Old serial ISR */
  264.  
  265. dword        RealIP_Address;
  266. BOOLEAN        Serial_16550A = FALSE;    /* UART is a 16550A */
  267. byte        XmitCount = 1;            /* number of bytes to transmit */
  268. BOOLEAN        Serial_Handshake = FALSE;    /* REQ/ACK handshake has occurred */
  269.  
  270. word        IOA_THR        =    IOO_THR;
  271. word        IOA_RBR        =    IOO_RBR;
  272. word        IOA_DLL        =    IOO_DLL;
  273. word        IOA_DLM        =    IOO_DLM;
  274. word        IOA_IER        =    IOO_IER;
  275. word        IOA_IIR        =    IOO_IIR;
  276. word        IOA_FCR        =    IOO_FCR;
  277. word        IOA_LCR        =    IOO_LCR;
  278. word        IOA_MCR        =    IOO_MCR;
  279. word        IOA_LSR        =    IOO_LSR;
  280. word        IOA_MSR        =    IOO_MSR;
  281.  
  282. #define    IOA_First    IOA_THR
  283. #define    IOA_Count    11
  284.  
  285. dword        IOE_LostTHRE=    0;
  286. dword        IOE_OverRun    =    0;
  287. dword        IOE_Parity    =    0;
  288. dword        IOE_Framing    =    0;
  289. dword        IOE_Break    =    0;
  290. dword        IOE_ReqTO    =    0;
  291. dword        IOE_IntrIn    =    0;
  292. dword        IOE_IntrOut    =    0;
  293. dword        IOE_FifoHi    =    0;
  294. dword        IOE_FifoTO    =    0;
  295. #define    IOE_Table    IOE_LostTHRE
  296.  
  297. dword        IOS_PktIn    =    0;
  298. dword        IOS_PktOut    =    0;
  299. dword        IOS_ByteIn    =    0;
  300. dword        IOS_ByteOut    =    0;
  301. dword        IOS_ErrIn    =    0;
  302. dword        IOS_ErrOut    =    0;
  303. dword        IOS_PktDrop    =    0;
  304. #define    IOS_Table    IOS_PktIn
  305.  
  306. /*
  307.  *  Timer support
  308.  */
  309.  
  310. #define    SECONDS        18
  311. InterruptPtrType
  312.             SaveTimerInt;
  313. word        InitTimer    =    0;
  314. word        XmitTimer    =    0;
  315. word        TermTimer    =    0;
  316.  
  317. /*
  318.  *  Packet Driver Hook
  319.  */
  320.  
  321. char                    PacketDriverHook[17];
  322. InterruptPtrType        SavePacketInt;
  323.  
  324. /*
  325.  *  Handle Table
  326.  */
  327.  
  328. typedef void (far *RecvType)(void);
  329.  
  330. typedef    struct
  331.     {
  332.     byte        Hand_InUse;
  333.     byte        Hand_TypeLen;
  334.     RecvType    Hand_Receiver;
  335.     word        Hand_TypeVal;
  336.     }    HandleType;
  337.  
  338. HandleType        HandleTable;
  339.  
  340. /*
  341.  *  Packet Driver values
  342.  */
  343.  
  344. #define        PD_version        0x0010
  345. #define        PDV_basic        1
  346. #define        PDV_extended    2
  347. #define        PDT_Merit        1
  348. #define        PDT_any            0xFFFF
  349. char        PDN_slfp[]    =    "SLFP8250";
  350.  
  351. /*
  352.  *  Packet Driver Classes
  353.  */
  354.  
  355. enum    PD_Classes
  356.     {
  357.     PDC_Ethernet    =    1,
  358.     PDC_Pronet_10,
  359.     PDC_IEEE_8025,
  360.     PDC_Omninet,
  361.     PDC_Appletalk,
  362.     PDC_SerialLine,
  363.     PDC_Starlan,
  364.     PDC_Arcnet,
  365.     PDC_AX25,
  366.     PDC_KISS,
  367.     PDC_IEEE_8023,
  368.     PDC_FDDI,
  369.     PDC_Internet_X25,
  370.     PDC_LANSTAR,
  371.     PDC_SLFP
  372.     };
  373.  
  374. /*
  375.  *  Function calls
  376.  */
  377.  
  378. enum    PD_Functions
  379.     {
  380.     PDF_DriverInfo            =    1,
  381.     PDF_AccessType,
  382.     PDF_ReleaseType,
  383.     PDF_SendPkt,
  384.     PDF_Terminate,
  385.     PDF_GetAddress,
  386.     PDF_ResetInterface,
  387.     PDF_SetRcvMode,
  388.     PDF_GetRcvMode,
  389.     PDF_SetMulticastList    =    22,
  390.     PDF_GetMulticastList,
  391.     PDF_GetStatistics,
  392.     PDF_GetErrors
  393.     };
  394.  
  395. /*
  396.  *  Error codes
  397.  */
  398.  
  399. enum    PD_Errors
  400.     {
  401.     PDE_BadHandle            =    1,
  402.     PDE_NoClass,
  403.     PDE_NoType,
  404.     PDE_NoNumber,
  405.     PDE_BadType,
  406.     PDE_NoMulticast,
  407.     PDE_CantTerminate,
  408.     PDE_BadMode,
  409.     PDE_NoSpace,
  410.     PDE_TypeInUse,
  411.     PDE_BadCommand,
  412.     PDE_CantSend,
  413.     PDE_CantSet,
  414.     PDE_BadAddress
  415.     };
  416.  
  417. /*
  418.  *  Forward declarations
  419.  */
  420.  
  421. void PassUp ( void *buf, word len );
  422. void proc_echo ( void );
  423. void RecvFSM ( byte RecvEvent, byte value );
  424. void XmitQput ( char *header, byte *buffer, word buffer_size );
  425.  
  426. /****************************************************************
  427.  *                                                                *
  428.  *                Trace                                            *
  429.  *                                                                *
  430.  ****************************************************************/
  431.  
  432. #ifdef DEBUG
  433.  
  434. #ifdef SCREEN_EGA
  435. #define SCREEN_BASE    0xB800
  436. #define SCREEN_WRAP 4000
  437. #else
  438. #define SCREEN_BASE    0xB000
  439. #define SCREEN_WRAP 2560    /* leave some room at bottom of screen */
  440. #endif
  441.  
  442. void Trace ( byte val, byte color )
  443. {
  444.     static int    BufOfs    =    0;
  445. #ifdef TRACE_HEX
  446.     static char    HexRep[] = "0123456789ABCDEF";
  447. #ifdef TRACE_ALL_HEX
  448.     static all_hex = TRUE;
  449. #else
  450.     static all_hex = FALSE;
  451. #endif
  452.  
  453.     if ( all_hex || val <= ' ' || val >= '\x7f' )
  454.     {
  455.         *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = HexRep[val>>4];
  456.         BufOfs %= SCREEN_WRAP;
  457.         *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = color;
  458.         BufOfs %= SCREEN_WRAP;
  459.         *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = HexRep[val&0xF];
  460.         BufOfs %= SCREEN_WRAP;
  461.         *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = color;
  462.         BufOfs %= SCREEN_WRAP;
  463.     }
  464. #endif
  465.  
  466.     *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = val;
  467.     BufOfs %= SCREEN_WRAP;
  468.     *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = color;
  469.     BufOfs %= SCREEN_WRAP;
  470.  
  471. #ifdef TRACE_HEX
  472.     *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = ' ';
  473.     BufOfs %= SCREEN_WRAP;
  474.     *(byte *)MK_FP ( SCREEN_BASE, BufOfs++ ) = color;
  475.     BufOfs %= SCREEN_WRAP;
  476. #endif
  477. }
  478. #endif
  479.  
  480.  
  481. /****************************************************************
  482.  *                                                                *
  483.  *                N u m e r i c   R o u t i n e s                    *
  484.  *                                                                *
  485.  ****************************************************************/
  486.  
  487. byte
  488. GetDig ( char ch )
  489. {
  490.     if ( ( ch >= '0' ) && ( ch <= '9' ) )
  491.         return ch - '0';
  492.     else if ( ( ch >= 'A' ) && ( ch <= 'F' ) )
  493.         return ch - 'A' + 10;
  494.     else if ( ( ch >= 'a' ) && ( ch <= 'f' ) )
  495.         return ch - 'a' + 10;
  496.     else if ( ( ch == 'x' ) || ( ch == 'X' ) )
  497.         return 'x';
  498.     else if ( ch == '#' )
  499.         return '#';
  500.     else if ( ch == 0 )
  501.         return '0';
  502.     else
  503.         return '?';
  504. }
  505.  
  506. dword
  507. GetNum(void)
  508. {
  509.     byte        state;
  510.     dword        base;
  511.     dword        num;
  512.     char        ch;
  513.     byte        digit;
  514.  
  515.     num = 0;
  516.     state = 0;
  517.  
  518.     for (;;)
  519.     {
  520.         ch = *optarg++;
  521.         digit = GetDig ( ch );
  522.         switch ( state )
  523.         {
  524.         case 0:
  525.             if ( digit == 0 )
  526.             {
  527.                 base = 8;
  528.                 state = 1;
  529.             }
  530.             else if ( digit == '#' )
  531.             {
  532.                 base = 16;
  533.                 state = 3;
  534.             }
  535.             else if ( digit <= 9 )
  536.             {
  537.                 base = 10;
  538.                 num = digit;
  539.                 state = 2;
  540.             }
  541.             else
  542.             {
  543.                 return ErrInt;
  544.             }
  545.             break;
  546.  
  547.         case 1:
  548.             if ( digit == 'x' )
  549.             {
  550.                 if ( num == 0 )
  551.                 {
  552.                     base = 16;
  553.                     state = 3;
  554.                 }
  555.             else
  556.                 {
  557.                 return ErrInt;
  558.                 }
  559.             }
  560.             else if ( digit <= 9 )
  561.             {
  562.                 num = num * base + digit;
  563.             }
  564.             else if ( digit == '0' )
  565.             {
  566.                 return num;
  567.             }
  568.             else
  569.             {
  570.                 return ErrInt;
  571.             }
  572.             break;
  573.  
  574.         case 2:
  575.             if ( digit == '#' )
  576.             {
  577.                 base = num;
  578.                 num = 0;
  579.                 if ( ( base < 2 ) || ( base > 16 ) )
  580.                     return ErrInt;
  581.                 state = 3;
  582.             }
  583.             else if ( digit <= 9 )
  584.             {
  585.                 num = num * base + digit;
  586.             }
  587.             else if ( digit == '0' )
  588.             {
  589.                 return num;
  590.             }
  591.             else
  592.             {
  593.                 return ErrInt;
  594.             }
  595.             break;
  596.  
  597.         case 3:
  598.             if ( digit < base )
  599.             {
  600.                 num = num * base + digit;
  601.             }
  602.             else if ( digit == '0' )
  603.             {
  604.                 return num;
  605.             }
  606.             else
  607.             {
  608.                 return ErrInt;
  609.             }
  610.             break;
  611.  
  612.         }
  613.     }
  614. }
  615.  
  616. /****************************************************************
  617.  *                                                                *
  618.  *                S e r i a l   U t i l i t i e s                    *
  619.  *                                                                *
  620.  ****************************************************************/
  621.  
  622. void setportb ( word Port, byte Mask )
  623. {
  624.     outportb ( Port, inportb ( Port ) | Mask );
  625. }
  626.  
  627. void clrportb ( word Port, byte Mask )
  628. {
  629.     outportb ( Port, inportb ( Port ) & ~Mask );
  630. }
  631.  
  632. /****************************************************************
  633.  *                                                                *
  634.  *                R e c v P r o c                                    *
  635.  *                                                                *
  636.  ****************************************************************/
  637.  
  638. void RecvProc ( byte *buf, word len )
  639. {
  640.     switch ( *(dword *) (buf) )
  641.     {
  642.     case 0x0102:    /* IP datagram */
  643.         PassUp ( buf+4, len-4 );
  644.         IOS_PktIn++;
  645.         IOS_ByteIn += len-4;
  646.         break;
  647.  
  648.     case 0x0302:    /* Address reply */
  649.         RealIP_Address = ((dword)buf[4] << 24) | ((dword)buf[5] << 16)
  650.                        | ((dword)buf[6] << 8)  | ((dword)buf[7]);
  651.         InitTimer = 0;
  652.         break;
  653.  
  654.     default:
  655.         break;
  656.     }
  657. }
  658.  
  659. /****************************************************************
  660.  *                                                                *
  661.  *                R e c v F S M                                    *
  662.  *                                                                *
  663.  ****************************************************************/
  664.  
  665. void RecvFSM ( byte RecvEvent, byte value )
  666. {
  667.     static byte        RecvState = 0;
  668.     static byte        *RecvPtr = (byte *)&RecvQ;
  669.  
  670.     if ( RecvEvent == RECV_REINIT )
  671.     {
  672.         RecvState = 0;
  673.         RecvPtr = (byte *)&RecvQ;
  674.         return;
  675.     }
  676.  
  677.     switch ( RecvState )
  678.     {
  679.  
  680.     /* state 0 -- dialing */
  681.  
  682.     case 0:
  683.         switch ( RecvEvent )
  684.         {
  685.         case RECV_GOT_REQ:
  686.             RecvState = 2;
  687.             break;
  688.  
  689.         case RECV_RDA:
  690.             if ( RecvQSize != QLEN )
  691.             {
  692.                 RecvQ[RecvQTail++] = value;
  693.                 RecvQTail &= (QLEN-1);
  694.                 RecvQSize++;
  695.             }
  696.             break;
  697.         }
  698.         break;
  699.  
  700.     /* state 1 -- receiver idle */
  701.  
  702.     case 1:
  703.         switch ( RecvEvent )
  704.         {
  705.         case RECV_GOT_REQ:
  706.             RecvPtr = (byte *)&RecvQ;
  707.             RecvState = 2;
  708.             break;
  709.  
  710.         case RECV_RDA:
  711.             break;
  712.         }
  713.         break;
  714.  
  715.     /* state 2 -- REQ has been received, receiving chars */
  716.  
  717.     case 2:
  718.         switch ( RecvEvent )
  719.         {
  720.         case RECV_RDA:
  721.             switch ( value )
  722.             {
  723.             case SLFP_ESC:
  724.                 RecvState = 3;
  725.                 break;
  726.  
  727.             case SLFP_END:
  728.                 RecvProc ( (byte *)&RecvQ, RecvPtr - (byte *)&RecvQ );
  729.                 RecvPtr = (byte *)&RecvQ;
  730.                 RecvState = 1;
  731.                 break;
  732.  
  733.             default:
  734.                 *RecvPtr++ = value;
  735.                 break;
  736.             }
  737.             break;
  738.  
  739.         case RECV_GOT_REQ:
  740.             RecvPtr = (byte *)&RecvQ;
  741.             break;
  742.         }
  743.         break;
  744.  
  745.     /* state 3 -- ESC received, waiting second char */
  746.  
  747.     case 3:
  748.         switch ( RecvEvent )
  749.         {
  750.         case RECV_RDA:
  751.             if ( value <= 3 )
  752.             {
  753.                 *RecvPtr++ = SLFP_ESC + value;
  754.                 RecvState = 2;
  755.             }
  756.             else
  757.             {
  758.                 RecvPtr = (byte *)&RecvQ;
  759.                 RecvState = 1;
  760.             }
  761.             break;
  762.  
  763.         case RECV_GOT_REQ:
  764.             RecvState = 2;
  765.             RecvPtr = (byte *)&RecvQ;
  766.             break;
  767.  
  768.         }
  769.         break;
  770.  
  771.     default:
  772.         break;
  773.     }
  774. }
  775.  
  776. /****************************************************************
  777.  *                                                                *
  778.  *                X m i t F S M                                    *
  779.  *                                                                *
  780.  ****************************************************************/
  781.  
  782. void
  783. XmitFSM ( byte event )
  784. {
  785.     typedef enum
  786.         {
  787.         s_Idle,                    /* wait for anything (DI) */
  788.         s_Idle_Ack,                /* after sending Ack in Idle */
  789.         s_Check,                /* pseudo state to combine code */
  790.         s_Sent_Req,                /* after sending Req */
  791.         s_Wait,                    /* wait for Ack (DI) */
  792.         s_Wait_Ack,                /* after sending Ack in Wait */
  793.         s_Message,                /* sending message */
  794.         s_Sent_End                /* after sending End */
  795.         } s_t;
  796.     static s_t state = s_Idle;
  797.  
  798.     static word Qcount;
  799.     static byte Qvalue;
  800.  
  801.     static BOOLEAN Framing = FALSE;
  802.     static BOOLEAN SendAck = FALSE;
  803.     static BOOLEAN SentEsc = FALSE;
  804.  
  805.     int counter = XmitCount;
  806.  
  807.     do
  808.     {
  809.         switch ( event )
  810.         {
  811.         case XMIT_MESSAGE:
  812.             if ( state == s_Idle )
  813.             {
  814.                 setportb ( IOA_IER, IER_TXE );
  815.                 state = s_Check;
  816.                 event = XMIT_THRE;                /* fake interrupt */
  817.             }
  818.             break;
  819.  
  820.         case XMIT_GOT_REQ:
  821.             switch ( state )
  822.             {
  823.             case s_Idle:
  824.             case s_Wait:
  825.                 setportb ( IOA_IER, IER_TXE );
  826.                 XmitTimer = 1 * SECONDS;
  827.                 SendAck = FALSE;                /* paranoia */
  828.                 trace ( SLFP_ACK, LIGHTBLUE );
  829.                 outportb ( IOA_THR, SLFP_ACK );
  830.                 state++;                        /* _Ack state */
  831.                 break;
  832.             default:
  833.                 SendAck = TRUE;
  834.                 break;
  835.             };
  836.             Serial_Handshake = TRUE;
  837.             break;
  838.  
  839.         case XMIT_GOT_ACK:
  840.             switch ( state )
  841.             {
  842.             case s_Wait:                    /* tx interrupt is off */
  843.                 setportb ( IOA_IER, IER_TXE );
  844.                 /* fallthru */
  845.  
  846.             case s_Sent_Req:                /* must have missed THRE */
  847.                 event = XMIT_THRE;            /* fake interrupt */
  848.                 /* fallthru */
  849.  
  850.             case s_Wait_Ack:                /* must wait for ACK THRE */
  851.                 XmitQHead += 2;                /* skip count */
  852.                 XmitQHead &= (QLEN-1);
  853.                 XmitQSize -= 2;
  854.                 state = s_Message;
  855.                 break;
  856.  
  857.             default:
  858.                 /* ignore spurious Ack */
  859.                 break;
  860.             };
  861.             break;
  862.  
  863.         case XMIT_THRE:
  864.         case XMIT_LOOP:
  865.             XmitTimer = 1 * SECONDS;
  866.  
  867.             if ( SentEsc )
  868.             {
  869.                 SentEsc = FALSE;
  870.                 trace ( Qvalue - SLFP_ESC, MAGENTA );
  871.                 outportb ( IOA_THR, Qvalue - SLFP_ESC );
  872.                 event = XMIT_LOOP;
  873.                 counter--;
  874.             }
  875.             else if ( SendAck )
  876.             {
  877.                 SendAck = FALSE;
  878.                 trace ( SLFP_ACK, LIGHTBLUE );
  879.                 outportb ( IOA_THR, SLFP_ACK );
  880.                 counter = 0;    /* wait for real THRE */
  881.             }
  882.             else
  883.             {
  884.                 switch ( state )
  885.                 {
  886.                 case s_Sent_End:
  887.                 case s_Idle_Ack:
  888.                 case s_Check:
  889.                     if ( XmitQSize < 2 )
  890.                     {
  891.                         if ( XmitQSize != 0 )
  892.                         {
  893.                             XmitQHead =
  894.                             XmitQTail =
  895.                             XmitQSize = 0;
  896.                         }
  897.                         if ( event == XMIT_THRE )
  898.                         {
  899.                             clrportb ( IOA_IER, IER_TXE );
  900.                             XmitTimer = 0;
  901.                             state = s_Idle;
  902.                         }
  903.                         counter = 0;    /* wait for event */
  904.                     }
  905.                     else
  906.                     {
  907.                         word Qindex;
  908.  
  909.                         Qindex = XmitQHead;
  910.                         Qcount = XmitQ[Qindex++];
  911.                         Qindex &= (QLEN-1);
  912.                         Qcount |= (word)(XmitQ[Qindex++]) << 8;
  913.                         Qindex &= (QLEN-1);
  914.  
  915.                         if ( Qcount > 0  &&  Framing )
  916.                         {
  917.                             trace ( SLFP_REQ, LIGHTRED );
  918.                             outportb ( IOA_THR, SLFP_REQ );
  919.                             counter = 0;    /* wait for real THRE */
  920.                             state = s_Sent_Req;
  921.                         }
  922.                         else
  923.                         {
  924.                             XmitQHead += 2;        /* skip count, just like Ack */
  925.                             XmitQHead &= (QLEN-1);
  926.                             XmitQSize -= 2;
  927.  
  928.                             if ( !Framing )
  929.                             {
  930.                                 state = s_Message;
  931.                             }
  932.                         }
  933.                     }
  934.                     break;
  935.  
  936.                 case s_Sent_Req:
  937.                 case s_Wait_Ack:
  938.                     clrportb ( IOA_IER, IER_TXE );
  939.                     XmitTimer = 3 * SECONDS;
  940.                     counter = 0;    /* wait for event or timer */
  941.                     state = s_Wait;
  942.                     break;
  943.  
  944.                 case s_Message:
  945.                     if ( Qcount-- > 0 )
  946.                     {
  947.                         Qvalue = XmitQ[XmitQHead++];
  948.                         XmitQHead &= (QLEN-1);
  949.                         XmitQSize--;
  950.  
  951.                         if ( Qvalue >= SLFP_ESC && Qvalue <= SLFP_END )
  952.                         {
  953.                             SentEsc = TRUE;
  954.                             trace ( SLFP_ESC, LIGHTMAGENTA );
  955.                             outportb ( IOA_THR, SLFP_ESC );
  956.                         }
  957.                         else
  958.                         {
  959.                             trace ( Qvalue, LIGHTGREEN );
  960.                             outportb ( IOA_THR, Qvalue );
  961.                         }
  962.                         event = XMIT_LOOP;
  963.                         counter--;
  964.                     }
  965.                     else
  966.                     {
  967.                         if ( Framing )
  968.                         {
  969.                             trace ( SLFP_END, LIGHTCYAN );
  970.                             outportb ( IOA_THR, SLFP_END );
  971.                             event = XMIT_LOOP;
  972.                             counter--;
  973.                         }
  974.                         else
  975.                         {
  976.                             Framing = TRUE;
  977.                         }
  978.                         state = s_Sent_End;
  979.                     }
  980.                     break;
  981.  
  982.                 default:
  983.                     /* spurious interrupt */
  984.                     clrportb ( IOA_IER, IER_TXE );
  985.                     counter = 0;    /* wait for external event */
  986.                     break;
  987.                 };
  988.             }
  989.             break;
  990.  
  991.         case XMIT_TIMEOUT:
  992.             switch ( state )
  993.             {
  994.             case s_Wait:
  995.                 IOE_ReqTO++;
  996.                 setportb ( IOA_IER, IER_TXE );
  997.                 state = s_Check;            /* try again */
  998.                 event = XMIT_THRE;            /* fake interrupt */
  999.                 break;
  1000.  
  1001.             case s_Idle_Ack:
  1002.             case s_Sent_Req:
  1003.             case s_Wait_Ack:
  1004.             case s_Message:
  1005.             case s_Sent_End:
  1006.                 IOE_LostTHRE++;
  1007.                 event = XMIT_THRE;            /* fake interrupt */
  1008.  
  1009.             default:
  1010.                 /* ignore spurious timeout */
  1011.                 break;
  1012.             };
  1013.             XmitTimer = 0;                    /* should already be zero */
  1014.             break;
  1015.  
  1016.         case XMIT_REINIT:
  1017.             state = s_Idle;
  1018.             Framing = FALSE;
  1019.             SendAck = FALSE;
  1020.             SentEsc = FALSE;
  1021.             break;
  1022.  
  1023.         default:
  1024.             /* unknown event */
  1025.             break;
  1026.         }
  1027.     } while ( (event == XMIT_THRE || event == XMIT_LOOP) && counter > 0 );
  1028. }
  1029.  
  1030.  
  1031. void
  1032. XmitQput ( char *header, byte *buffer, word buffer_size )
  1033. {
  1034.     register word count;
  1035.     register word Qindex;
  1036.  
  1037.     if ( header != NULL )
  1038.         buffer_size += 4;
  1039.  
  1040.     Qindex = XmitQTail;
  1041.     XmitQ[Qindex++] = (byte)(buffer_size);
  1042.     Qindex &= (QLEN-1);
  1043.     XmitQ[Qindex++] = (byte)(buffer_size >> 8);
  1044.     Qindex &= (QLEN-1);
  1045.  
  1046.     count = 0;
  1047.  
  1048.     if ( header != NULL )
  1049.     {
  1050.         for ( ; count < 4; count++ )
  1051.         {
  1052.             XmitQ[Qindex++] = *header++;
  1053.             Qindex &= (QLEN-1);
  1054.         }
  1055.     }
  1056.  
  1057.     while ( count++ < buffer_size )
  1058.     {
  1059.         XmitQ[Qindex++] = *buffer++;
  1060.         Qindex &= (QLEN-1);
  1061.     }
  1062.  
  1063.     disable();
  1064.     XmitQTail = Qindex;
  1065.     XmitQSize += buffer_size + 2;
  1066.     XmitFSM ( XMIT_MESSAGE );
  1067.     enable();
  1068. }
  1069.  
  1070.  
  1071. /****************************************************************
  1072.  *                                                                *
  1073.  *                S e r i a l I S R                                *
  1074.  *                                                                *
  1075.  ****************************************************************/
  1076.  
  1077. void interrupt SerialISR ( )
  1078. {
  1079.     byte        IntrIdent;
  1080.     byte        ch;
  1081.     byte        ErrMask;
  1082.     int            HighWater    =    0;
  1083.  
  1084.     outportb ( 0x20, 0x20 );
  1085.     while ( ( ( IntrIdent = inportb ( IOA_IIR ) ) & IIR_IP ) == 0 )
  1086.     {
  1087.         switch ( IntrIdent & IIR_ID )
  1088.         {
  1089.         case IIR_RDA:
  1090.             for (;;)
  1091.             {
  1092.                 ErrMask = inportb ( IOA_LSR );
  1093.                 if ( ErrMask & LSR_OE )
  1094.                     IOE_OverRun++;
  1095.                 if ( ErrMask & LSR_PE )
  1096.                     IOE_Parity++;
  1097.                 if ( ErrMask & LSR_FE )
  1098.                     IOE_Framing++;
  1099.                 if ( ErrMask & LSR_BI )
  1100.                     IOE_Break++;
  1101.  
  1102.                 if ( (ErrMask & LSR_DR) == 0 )
  1103.                     break;
  1104.  
  1105.                 HighWater++;
  1106.                 ch = inportb ( IOA_RBR );
  1107.                 trace ( ch, BROWN );
  1108.  
  1109.                 switch ( ch )
  1110.                 {
  1111.                 case SLFP_REQ:
  1112.                     RecvFSM ( RECV_GOT_REQ, 0 );
  1113.                     XmitFSM ( XMIT_GOT_REQ );
  1114.                     break;
  1115.                 case SLFP_ACK:
  1116.                     XmitFSM ( XMIT_GOT_ACK );
  1117.                     break;
  1118.                 default:
  1119.                     RecvFSM ( RECV_RDA, ch );
  1120.                     break;
  1121.                 }
  1122.             }
  1123.             IOE_IntrIn++;
  1124.             IOE_FifoHi = max ( IOE_FifoHi, HighWater );
  1125.             break;
  1126.  
  1127.         case IIR_THRE:
  1128.             XmitFSM ( XMIT_THRE );
  1129.             IOE_IntrOut++;
  1130.             break;
  1131.  
  1132.         case IIR_MSTAT:
  1133.             break;
  1134.  
  1135.         case IIR_RLS:
  1136.             ErrMask = inportb ( IOA_LSR );
  1137.             if ( ErrMask & LSR_OE )
  1138.                 IOE_OverRun++;
  1139.             if ( ErrMask & LSR_PE )
  1140.                 IOE_Parity++;
  1141.             if ( ErrMask & LSR_FE )
  1142.                 IOE_Framing++;
  1143.             if ( ErrMask & LSR_BI )
  1144.                 IOE_Break++;
  1145.             break;
  1146.         }
  1147.         if ( IntrIdent & IIR_FIFO_TO )
  1148.             IOE_FifoTO++;
  1149.     }
  1150. }
  1151.  
  1152. /****************************************************************
  1153.  *                                                                *
  1154.  *                S e r i a l I n i t                                *
  1155.  *                                                                *
  1156.  ****************************************************************/
  1157.  
  1158. BOOLEAN SerialInit ( word IOBase, byte IRQ, word Speed )
  1159. {
  1160.     word        *IOA_ptr;
  1161.     word        ClockRate;
  1162.     int            ind;
  1163.  
  1164.     /* check parameters for consistancy */
  1165.  
  1166.     if ( ( IOBase == 0x3F8 ) && ( IRQ != 4 ) )
  1167.     {
  1168.         printf ( "Warning: COM1 usually uses IRQ 4\n" );
  1169.     }
  1170.  
  1171.     if ( ( IOBase == 0x2F8 ) && ( IRQ != 3 ) )
  1172.     {
  1173.         printf ( "Warning: COM2 usually uses IRQ 3\n" );
  1174.     }
  1175.  
  1176.     if ( ( IRQ < 1 ) || ( IRQ > 7 ) )
  1177.     {
  1178.         printf ( "Error: Only first interrupt controller supported\n" );
  1179.         return FALSE;
  1180.     }
  1181.  
  1182.     if ( ( 115200L % Speed ) != 0 )
  1183.     {
  1184.         printf ( "Warning: Line speed can only be approximated\n" );
  1185.     }
  1186.  
  1187.     /* save parameters */
  1188.  
  1189.     IOA_ptr = &IOA_First;
  1190.     for ( ind=0; ind<IOA_Count; ind++ )
  1191.     {
  1192.         *IOA_ptr++ += IOBase;
  1193.     }
  1194.     Serial_IRQ = IRQ;
  1195.     Serial_Speed = Speed;
  1196.  
  1197.     /*
  1198.      *  Initialize 8250
  1199.      */
  1200.  
  1201.     /* disable interrupts */
  1202.  
  1203.     disable();
  1204.  
  1205.     /* empty receiver buffer */
  1206.  
  1207.     (void) inportb ( IOA_RBR );
  1208.  
  1209.     /* set 8 bits, no parity, one stop bit */
  1210.  
  1211.     outportb ( IOA_LCR, LCR_8BITS );
  1212.  
  1213.     /* check for 16550A and enable fifo */
  1214.  
  1215.     if ( ConfFifoCheck )
  1216.     {
  1217.         outportb ( IOA_FCR, FCR_ENABLE );
  1218.  
  1219.         if ( ( inportb ( IOA_IIR ) & IIR_FIFO_ENB ) == IIR_FIFO_ENB )
  1220.         {
  1221.             /* Chip is a 16550A. Setup the FIFOs
  1222.              */
  1223.             Serial_16550A = TRUE;
  1224.             XmitCount = 16;
  1225.             outportb ( IOA_FCR, FCR_SETUP);
  1226.             printf ( "16650A detected\n" );
  1227.         }
  1228.         else
  1229.         {
  1230.             /* Chip is not a 16550A. In case it's a 16550 (which has a
  1231.              * broken FIFO), turn off the FIFO bit.
  1232.              */
  1233.             outportb ( IOA_FCR, FCR_RESET );
  1234.         }
  1235.     }
  1236.  
  1237.     /* enable receiver interrupts */
  1238.  
  1239.     outportb ( IOA_IER, IER_DAV|IER_RLS );
  1240.  
  1241.     /* raise DTR, RTS & enable master interrupts */
  1242.  
  1243.     outportb ( IOA_MCR, MCR_DTR | MCR_RTS | MCR_OUT2 );
  1244.  
  1245.     /* set up clock rate */
  1246.  
  1247.     ClockRate = 115200L / Speed;
  1248.     setportb ( IOA_LCR, LCR_DLAB );
  1249.     outportb ( IOA_DLL, (byte)( ClockRate ) );
  1250.     outportb ( IOA_DLM, (byte)( ClockRate >> 8 ) );
  1251.     clrportb ( IOA_LCR, LCR_DLAB );
  1252.  
  1253.     /* set up serial ISR */
  1254.  
  1255.     SaveSerialInt = getvect ( IRQ+8 );
  1256.     setvect ( IRQ+8, SerialISR );
  1257.  
  1258.     /* enable interrupt on 8259 */
  1259.  
  1260.     outportb ( 0x21, inportb ( 0x21 ) & ~ ( 1 << IRQ ) );
  1261.  
  1262.     /* transmit state machine */
  1263.  
  1264.     enable();
  1265.     delay ( 1000 );
  1266.     disable();
  1267.  
  1268.     /* all done */
  1269.  
  1270.     enable();
  1271.     return TRUE;
  1272. }
  1273.  
  1274. /****************************************************************
  1275.  *                                                                *
  1276.  *                S e r i a l I n i t                                *
  1277.  *                                                                *
  1278.  ****************************************************************/
  1279.  
  1280. void SerialTerm ( void )
  1281. {
  1282.     /* disable 8250 interrupts */
  1283.  
  1284.     outportb ( IOA_IER, 0 );
  1285.     outportb ( IOA_MCR, 0 );
  1286.     outportb ( 0x21, inportb ( 0x21 ) | ( 1 << Serial_IRQ ) );
  1287.  
  1288.     /* restore interrupt vector */
  1289.  
  1290.     setvect ( Serial_IRQ+8, SaveSerialInt );
  1291. }
  1292.  
  1293. /****************************************************************
  1294.  *                                                                *
  1295.  *                Timer Tick                                        *
  1296.  *                                                                *
  1297.  ****************************************************************/
  1298.  
  1299. void interrupt TimerTick ( )
  1300. {
  1301.     /* handle tick */
  1302.  
  1303.     if ( XmitTimer != 0 && --XmitTimer == 0 )
  1304.     {
  1305.         XmitFSM ( XMIT_TIMEOUT );
  1306.     }
  1307.  
  1308.     if ( InitTimer != 0 && --InitTimer == 0 )
  1309.     {
  1310.     }
  1311.  
  1312.     if ( TermTimer != 0 && --TermTimer == 0 )
  1313.     {
  1314.     }
  1315.  
  1316.     /* chain on old interrupt handler */
  1317.  
  1318.     (*SaveTimerInt)();
  1319.  
  1320. }
  1321.  
  1322. /****************************************************************
  1323.  *                                                                *
  1324.  *                Pass Up                                            *
  1325.  *                                                                *
  1326.  ****************************************************************/
  1327.  
  1328. void PassUp ( void * buf, word len )
  1329. {
  1330.     RecvType    TempRecv;
  1331.     void        *TempPtr;
  1332.  
  1333.     /* ensure a handle to return message on */
  1334.  
  1335.     if ( !HandleTable.Hand_InUse )
  1336.     {
  1337.         IOS_PktDrop++;
  1338.         return;
  1339.     }
  1340.  
  1341.     /* ensure receiver hasn't asked for a specific type */
  1342.  
  1343.     if ( HandleTable.Hand_TypeLen != 0 )
  1344.     {
  1345.         IOS_PktDrop++;
  1346.         return;
  1347.     }
  1348.  
  1349.     /* get buffer */
  1350.  
  1351.     TempRecv = HandleTable.Hand_Receiver;
  1352.     if ( TempRecv == NULL )
  1353.     {
  1354.         IOS_PktDrop++;
  1355.         return;
  1356.     }
  1357.  
  1358.     _AX = 0;
  1359.     _CX = len;
  1360.     _BX = 1;
  1361.     TempRecv();
  1362.     TempPtr = (void *) MK_FP ( _ES, _DI );
  1363.  
  1364.     if ( TempPtr == NULL )
  1365.     {
  1366.         IOS_PktDrop++;
  1367.         return;
  1368.     }
  1369.  
  1370.     /* move data into buffer */
  1371.  
  1372.     memcpy ( TempPtr, buf, len );
  1373.  
  1374.     /* pass up to receiver */
  1375.  
  1376.     __emit__ ( 0x1E );            /* push ds */
  1377.     _DS = FP_SEG ( TempPtr );
  1378.     _SI = FP_OFF ( TempPtr );
  1379.     _AX = 1;
  1380.     _CX = len;
  1381.     _BX = 1;
  1382.     TempRecv();
  1383.     __emit__ ( 0x1F );            /* pop ds */
  1384.  
  1385. }
  1386.  
  1387. /****************************************************************
  1388.  *                                                                *
  1389.  *                PDF Driver Info                                    *
  1390.  *                                                                *
  1391.  ****************************************************************/
  1392.  
  1393. void DriverInfo ( IntrRegsType *IntrRegs )
  1394.  
  1395. {
  1396.     /* ensure real function */
  1397.  
  1398.     if ( IntrRegs->b.al != 0xFF )
  1399.     {
  1400.         IntrRegs->w.fl |= FL_CARRY;
  1401.         IntrRegs->b.dh = PDE_BadCommand;
  1402.         return;
  1403.     }
  1404.  
  1405.     /* return driver info */
  1406.  
  1407.     IntrRegs->w.fl &= ~FL_CARRY;
  1408.     IntrRegs->w.bx = PD_version;
  1409.     IntrRegs->b.ch = PDC_SLFP;
  1410.     IntrRegs->w.dx = PDT_Merit;
  1411.     IntrRegs->b.cl = 0;        /* number */
  1412.     IntrRegs->w.ds = FP_SEG(PDN_slfp);
  1413.     IntrRegs->w.si = FP_OFF(PDN_slfp);
  1414.     IntrRegs->b.al = PDV_extended;
  1415. }
  1416.  
  1417. /****************************************************************
  1418.  *                                                                *
  1419.  *                PDF Access Type                                    *
  1420.  *                                                                *
  1421.  ****************************************************************/
  1422.  
  1423. void AccessType ( IntrRegsType *IntrRegs )
  1424.  
  1425. {
  1426.     /* assume error */
  1427.  
  1428.     IntrRegs->w.fl |= FL_CARRY;
  1429.  
  1430.     /* ensure SLFP class request */
  1431.  
  1432.     if ( IntrRegs->b.al != PDC_SLFP )
  1433.     {
  1434.         IntrRegs->b.dh = PDE_NoClass;
  1435.         return;
  1436.     }
  1437.  
  1438.     /* ensure proper type request */
  1439.  
  1440.     if ( ( IntrRegs->w.bx != PDT_any ) && ( IntrRegs->w.bx != PDT_Merit ) )
  1441.     {
  1442.         IntrRegs->b.dh = PDE_NoType;
  1443.         return;
  1444.     }
  1445.  
  1446.     /* ensure proper number request */
  1447.  
  1448.     if ( ( IntrRegs->b.dl != 0 ) && ( IntrRegs->b.dl != 1 ) )
  1449.     {
  1450.         IntrRegs->b.dh = PDE_NoNumber;
  1451.         return;
  1452.     }
  1453.  
  1454.     /* ensure already not in use */
  1455.  
  1456.     if ( HandleTable.Hand_InUse )
  1457.     {
  1458.         IntrRegs->b.dh = PDE_TypeInUse;
  1459.         return;
  1460.     }
  1461.  
  1462.     /* type value length must be <= 8 */
  1463.  
  1464.     if ( IntrRegs->w.cx > 8 )
  1465.     {
  1466.         IntrRegs->b.dh = PDE_BadType;
  1467.         return;
  1468.     }
  1469.  
  1470.     /* enter info into handler table entry */
  1471.  
  1472.     HandleTable.Hand_InUse = TRUE;
  1473.     HandleTable.Hand_Receiver =
  1474.         (RecvType) MK_FP ( IntrRegs->w.es, IntrRegs->w.di );
  1475.     HandleTable.Hand_TypeLen = IntrRegs->w.cx;
  1476.  
  1477.     /* all done */
  1478.  
  1479.     IntrRegs->w.fl &= ~FL_CARRY;
  1480.     IntrRegs->w.ax = 1;
  1481.  
  1482. }
  1483.  
  1484. /****************************************************************
  1485.  *                                                                *
  1486.  *                PDF Release Type                                *
  1487.  *                                                                *
  1488.  ****************************************************************/
  1489.  
  1490. void ReleaseType ( IntrRegsType *IntrRegs )
  1491. {
  1492.     word        hand;
  1493.  
  1494.     hand = IntrRegs->w.bx;
  1495.  
  1496.     /* ensure good handle */
  1497.  
  1498.     if ( hand != 1 )
  1499.     {
  1500.         IntrRegs->w.fl |= FL_CARRY;
  1501.         IntrRegs->b.dh = PDE_BadHandle;
  1502.         return;
  1503.     }
  1504.  
  1505.     /* clear table entry */
  1506.  
  1507.     HandleTable.Hand_InUse = FALSE;
  1508.     HandleTable.Hand_Receiver = (RecvType) NULL;
  1509.  
  1510.     /* all done */
  1511.  
  1512.     IntrRegs->w.fl &= ~FL_CARRY;
  1513.  
  1514. }
  1515.  
  1516. /****************************************************************
  1517.  *                                                                *
  1518.  *                PDF SendPkt                                        *
  1519.  *                                                                *
  1520.  ****************************************************************/
  1521.  
  1522. void SendPkt ( IntrRegsType *IntrRegs )
  1523. {
  1524.     word        TotalLen;
  1525.     byte        *BufPtr;
  1526.  
  1527.     /* set up */
  1528.  
  1529.     IntrRegs->w.fl |= FL_CARRY;
  1530.     IntrRegs->b.dh = PDE_CantSend;
  1531.  
  1532.     TotalLen = IntrRegs->w.cx;
  1533.     if ( TotalLen + 2 + 4 > QLEN - XmitQSize )
  1534.     {
  1535.         IOS_ErrOut++;
  1536.         return;
  1537.     }
  1538.  
  1539.     /* put message on transmit queue */
  1540.  
  1541.     BufPtr = (byte *) MK_FP ( IntrRegs->w.ds, IntrRegs->w.si );
  1542.     XmitQput( "\x2\x1\x0\x0", BufPtr, TotalLen );
  1543.  
  1544.     /* record stats */
  1545.  
  1546.     IOS_PktOut++;
  1547.     IOS_ByteOut += IntrRegs->w.cx;
  1548.  
  1549.     /* all done */
  1550.  
  1551.     IntrRegs->w.fl &= ~FL_CARRY;
  1552. }
  1553.  
  1554. /****************************************************************
  1555.  *                                                                *
  1556.  *                PDF Terminate                                    *
  1557.  *                                                                *
  1558.  ****************************************************************/
  1559.  
  1560. void Terminate ( IntrRegsType *IntrRegs )
  1561. {
  1562.     union    REGS    regs;
  1563.     struct    SREGS    sregs;
  1564.     int             count;
  1565.  
  1566.     /* perform dumb hayes-style hangup if necessary */
  1567.  
  1568.     if ( ConfQuitSoft )
  1569.     {
  1570.         /* enter command mode */
  1571.  
  1572.         delay ( 1000 );
  1573.         for ( count=0; count<3; count++ )
  1574.         {
  1575.             XmitFSM ( XMIT_REINIT );
  1576.             XmitQput ( NULL, (byte *)"+", 1 );
  1577.             delay ( 100 );
  1578.         }
  1579.         RecvFSM ( RECV_REINIT, 0 );
  1580.         TermTimer = 1 * SECONDS;
  1581.         while ( TermTimer )
  1582.             proc_echo();
  1583.  
  1584.         /* hang up */
  1585.  
  1586.         XmitFSM ( XMIT_REINIT );
  1587.         XmitQput ( NULL, (byte *)"ATH0\r", 5 );
  1588.  
  1589.         TermTimer = 5 * SECONDS;
  1590.         while ( TermTimer )
  1591.             proc_echo();
  1592.     }
  1593.  
  1594.     /* restore hardware and interrupts */
  1595.  
  1596.     disable();
  1597.     SerialTerm();
  1598.     setvect ( 0x08, SaveTimerInt );
  1599.     setvect ( ConfPackInt, SavePacketInt );
  1600.     enable();
  1601.  
  1602.     /* assume failure */
  1603.  
  1604.     IntrRegs->w.fl |= FL_CARRY;
  1605.     IntrRegs->b.dh = PDE_CantTerminate;
  1606.  
  1607.     /* return program block */
  1608.  
  1609.     regs.h.ah = 0x49;
  1610.     sregs.es = _psp;
  1611.     intdosx ( ®s, ®s, &sregs );
  1612.     if ( regs.x.cflag != 0 )
  1613.         return;
  1614.  
  1615.     /* return environment block */
  1616.  
  1617.     regs.h.ah = 0x49;
  1618.     sregs.es = ( (PSP_Ptr) MK_FP ( _psp, 0 ) ) -> PSP_Environment;
  1619.     intdosx ( ®s, ®s, &sregs );
  1620.     if ( regs.x.cflag != 0 )
  1621.         return;
  1622.  
  1623.     /* all OK */
  1624.  
  1625.     IntrRegs->w.fl &= ~FL_CARRY;
  1626. }
  1627.  
  1628. /****************************************************************
  1629.  *                                                                *
  1630.  *                PDF Get Address                                    *
  1631.  *                                                                *
  1632.  ****************************************************************/
  1633.  
  1634. void GetAddress ( IntrRegsType *IntrRegs )
  1635. {
  1636.     word        hand;
  1637.  
  1638.     /* set up */
  1639.  
  1640.     hand = IntrRegs->w.bx;
  1641.     IntrRegs->w.fl |= FL_CARRY;
  1642.  
  1643.     /* ensure a good handle */
  1644.  
  1645.     if ( hand > 1 )
  1646.         {
  1647.         IntrRegs->b.dh = PDE_BadHandle;
  1648.         return;
  1649.         }
  1650.  
  1651.     /* make sure enough space to return address */
  1652.  
  1653.     if ( IntrRegs->w.cx < 4 )
  1654.         {
  1655.         IntrRegs->b.dh = PDE_NoSpace;
  1656.         return;
  1657.         }
  1658.  
  1659.     /* return address */
  1660.  
  1661.     IntrRegs->w.fl &= ~FL_CARRY;
  1662.     IntrRegs->w.cx = 4;
  1663.     memcpy ( MK_FP(IntrRegs->w.es,IntrRegs->w.di),
  1664.         (const void *) &RealIP_Address, 4 );
  1665. }
  1666.  
  1667. /****************************************************************
  1668.  *                                                                *
  1669.  *                Packet Driver Interrupt Handler                 *
  1670.  *                                                                *
  1671.  ****************************************************************/
  1672.  
  1673. void interrupt PacketDriver ( IntrRegsType IntrRegs )
  1674.  
  1675. {
  1676.     enable();
  1677.  
  1678.     switch ( IntrRegs.b.ah )
  1679.     {
  1680.  
  1681.     case PDF_DriverInfo:
  1682.         DriverInfo ( &IntrRegs );
  1683.         break;
  1684.  
  1685.     case PDF_AccessType:
  1686.         AccessType ( &IntrRegs );
  1687.         break;
  1688.  
  1689.     case PDF_ReleaseType:
  1690.         ReleaseType ( &IntrRegs );
  1691.         break;
  1692.  
  1693.     case PDF_SendPkt:
  1694.         SendPkt ( &IntrRegs );
  1695.         break;
  1696.  
  1697.     case PDF_Terminate:
  1698.         Terminate ( &IntrRegs );
  1699.         break;
  1700.  
  1701.     case PDF_GetAddress:
  1702.         while ( InitTimer )
  1703.             ;
  1704.         GetAddress ( &IntrRegs );
  1705.         break;
  1706.  
  1707.     case PDF_GetStatistics:
  1708.         IntrRegs.w.fl &= ~FL_CARRY;
  1709.         IntrRegs.w.ds = FP_SEG ( &IOS_Table );
  1710.         IntrRegs.w.si = FP_OFF ( &IOS_Table );
  1711.         break;
  1712.  
  1713.     case PDF_GetErrors:
  1714.         IntrRegs.w.fl &= ~FL_CARRY;
  1715.         IntrRegs.w.ds = FP_SEG ( &IOE_Table );
  1716.         IntrRegs.w.si = FP_OFF ( &IOE_Table );
  1717.         break;
  1718.  
  1719.     default:
  1720.         IntrRegs.w.fl |= FL_CARRY;
  1721.         IntrRegs.b.dh = PDE_BadCommand;
  1722.     }
  1723. }
  1724.  
  1725. /****************************************************************
  1726.  *                                                                *
  1727.  *                Ctl-C(break) handler                            *
  1728.  *                                                                *
  1729.  ****************************************************************/
  1730.  
  1731. int BreakHandler ( void )
  1732. {
  1733.     printf ( "SLFP aborted\n" );
  1734.  
  1735.     /* restore hardware and interrupts */
  1736.  
  1737.     disable();
  1738.     SerialTerm();
  1739.     setvect ( 0x08, SaveTimerInt );
  1740.     setvect ( ConfPackInt, SavePacketInt );
  1741.     enable();
  1742.     exit ( ERL_break );
  1743.     return 0;
  1744. }
  1745.  
  1746. /****************************************************************
  1747.  *                                                                *
  1748.  *                Process echo                                    *
  1749.  *                                                                *
  1750.  ****************************************************************/
  1751.  
  1752. void
  1753. proc_echo(void)
  1754. {
  1755.     char        ch;
  1756.  
  1757.     if ( RecvQSize )
  1758.     {
  1759.         disable();
  1760.         ch = RecvQ[RecvQHead++];
  1761.         RecvQHead &= (QLEN-1);
  1762.         RecvQSize--;
  1763.         enable();
  1764.         putchar ( ch );
  1765.     }
  1766. (void) kbhit();
  1767. }
  1768.  
  1769. /****************************************************************
  1770.  *                                                                *
  1771.  *                Main routine                                    *
  1772.  *                                                                *
  1773.  ****************************************************************/
  1774.  
  1775. void main ( int argc, char **argv )
  1776. {
  1777.     void        *HookPtr;
  1778.     dword        PSize;
  1779.     int            opt;
  1780.     BOOLEAN        err;
  1781.     InterruptPtrType
  1782.                 OldPackInt;
  1783.     char        PDSig[8];
  1784.  
  1785.  
  1786. /* give version message */
  1787.  
  1788. printf ( "SLFP: version " SLFP_VERSION "\n" );
  1789.  
  1790. /* parse command image */
  1791.  
  1792. err = FALSE;
  1793.  
  1794. do
  1795. {
  1796.     opt = getopt ( argc, argv, "p:i:b:s:d:t:h:f:q:" );
  1797.  
  1798.     switch ( opt )
  1799.     {
  1800.     case 'p':
  1801.         ConfPackInt = GetNum();
  1802.         break;
  1803.  
  1804.     case 'i':
  1805.         ConfSerialIrq = GetNum();
  1806.         break;
  1807.  
  1808.     case 'b':
  1809.         ConfSerialBase = GetNum();
  1810.         break;
  1811.  
  1812.     case 's':
  1813.         ConfSerialSpeed = GetNum();
  1814.         break;
  1815.  
  1816.     case 'd':
  1817.         strcpy ( ConfSerialDial, optarg );
  1818.         break;
  1819.  
  1820.     case 't':
  1821.         ConfInitTime = GetNum();
  1822.         break;
  1823.  
  1824.     case 'h':
  1825.         ConfHandshake = GetNum();
  1826.         break;
  1827.  
  1828.     case 'f':
  1829.         ConfFifoCheck = GetNum();
  1830.         break;
  1831.  
  1832.     case 'q':
  1833.         ConfQuitSoft = GetNum();
  1834.         break;
  1835.  
  1836.     case EOF:
  1837.         break;
  1838.  
  1839.     default:
  1840.         err = TRUE;
  1841.         break;
  1842.     }
  1843. }
  1844. while ( opt != EOF );
  1845.  
  1846. if ( err )
  1847. {
  1848.     printf ( "Usage: slfp [/p PacketIntNo] [/i SerialIntNo]"
  1849.         " [/b SerialBase] [/s SerialSpeed] [/d DialCmd] /t [InitTime]"
  1850.         " [/h Handshake] [/f FifoCheck] [/t QuitSoft]\n" );
  1851.     exit ( ERL_parse );
  1852. }
  1853.  
  1854. /* check for packet driver already loaded */
  1855.  
  1856. OldPackInt = getvect ( ConfPackInt );
  1857.  
  1858. movedata ( FP_SEG(OldPackInt), FP_OFF(OldPackInt)+3,
  1859.     FP_SEG(PDSig), FP_OFF(PDSig), 8 );
  1860.  
  1861. if ( strncmp ( PDSig, "PKT DRVR", 8 ) == 0 )
  1862. {
  1863.     printf ( "Packet driver already loaded at 0x%X\n", ConfPackInt );
  1864.     exit ( ERL_packet );
  1865. }
  1866.  
  1867. /* output parameters */
  1868.  
  1869. printf ( "slfp /p 0x%X /i %d /b 0x%X /s %d /t %d /h %d /f %d /q %d /d %s\n",
  1870.     ConfPackInt, ConfSerialIrq, ConfSerialBase, ConfSerialSpeed,
  1871.     ConfInitTime, ConfHandshake, ConfFifoCheck, ConfQuitSoft, ConfSerialDial );
  1872.  
  1873. strcat ( ConfSerialDial, "\r" );
  1874. InitTimer = ConfInitTime * SECONDS;
  1875.  
  1876. /* set up ctl-C handler */
  1877.  
  1878. ctrlbrk ( BreakHandler );
  1879.  
  1880. /* clear Handle table */
  1881.  
  1882. HandleTable.Hand_InUse = FALSE;
  1883. HandleTable.Hand_Receiver = (RecvType) NULL;
  1884.  
  1885. /* build driver hook */
  1886.  
  1887. memcpy ( PacketDriverHook, "\xEB\x0A\x90PKT DRVR\0\xEA", 13 );
  1888. HookPtr = (void *)PacketDriver;
  1889. memcpy ( &PacketDriverHook[13], &HookPtr, 4 );
  1890.  
  1891. /* set up packet driver vector */
  1892.  
  1893. SavePacketInt = getvect ( ConfPackInt );
  1894. setvect ( ConfPackInt, (InterruptPtrType) PacketDriverHook );
  1895.  
  1896. /* set up Timer routine */
  1897.  
  1898. SaveTimerInt = getvect ( 0x08 );
  1899. setvect ( 0x08, TimerTick );
  1900.  
  1901. /* initialize serial link */
  1902.  
  1903. SerialInit ( ConfSerialBase, ConfSerialIrq, ConfSerialSpeed );
  1904.  
  1905. /* wait for IP addr handshake, output dial handshake */
  1906.  
  1907. XmitQput( NULL, (byte *)ConfSerialDial, strlen( ConfSerialDial ) );
  1908.  
  1909. while ( InitTimer && ConfHandshake && !Serial_Handshake )
  1910.     proc_echo();
  1911.  
  1912. XmitQput( "\x2\x3\x0\x0", NULL, 0 );
  1913.  
  1914. while ( InitTimer  &&  RealIP_Address == 0L )
  1915.     proc_echo();
  1916.  
  1917. if ( RealIP_Address != 0L )
  1918. {
  1919.     printf ( "\nIP address set to %d.%d.%d.%d\n",
  1920.         (byte)( RealIP_Address >> 24 ),
  1921.         (byte)( RealIP_Address >> 16 ),
  1922.         (byte)( RealIP_Address >>  8 ),
  1923.         (byte)( RealIP_Address       ) );
  1924. }
  1925. else
  1926. {
  1927.     printf ( "\nUnable to establish IP address. SLFP aborted\n" );
  1928.  
  1929.     /* restore hardware and interrupts */
  1930.  
  1931.     disable();
  1932.     SerialTerm();
  1933.     setvect ( 0x08, SaveTimerInt );
  1934.     setvect ( ConfPackInt, SavePacketInt );
  1935.     enable();
  1936.  
  1937.     exit ( ERL_handshake );
  1938. }
  1939.  
  1940. /* terminate, stay resident */
  1941.  
  1942. PSize = ( (byte huge *)MK_FP(_SS,_SP+15) - (byte huge *)MK_FP(_CS,0) ) / 16;
  1943. keep ( ERL_none, PSize );
  1944.  
  1945. }
  1946.