#include <dos.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>

/* Stack and pointer checking off */
#pragma check_stack( off )
#pragma check_pointer( off )
#pragma intrinsic( _enable, _disable )

/* Prototypes for interrupt function */
void (_interrupt _far *oldint65)( void );
void (_interrupt _far *oldint8)( void );
void _interrupt _far rout( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
			       unsigned _flags );
void _interrupt _far int8( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
			       unsigned _flags );
int fb(void *p);
int SetRing();
int rcv();

struct nau {
     char name[8]    ;       /* nau name                   */
     unsigned char type ;    /* type                       *//* @0115 */
     struct hscb *link;      /* hscb pointer               */
     struct rqb *opnq;       /* opndst queue               */
     short sid;              /* session id                 */
     char rsrv[3];           /* 0123 */
     }naua[2];

void _far *nau_lst_ptr;
void _far *hscb_lst_ptr;


/* Huge pointers force compiler to do segment arithmetic for us. */

void _far  *InArea;
char _huge *tsrstack;
char _huge *svstack;
char _huge *tsvstack;
char _huge *tsrbottom;
int  code;
int  length;
int  total = 0;
unsigned lock = 1;

speed = 1;
width = 8;
parity = 2;
n_port = 2;
stop_num = 1;

void *fe;
void *le;

char _far *dosok;

unsigned ProgPrefix;

void main( int argc, char *argv[] )
        {
            unsigned tsrsize;
            unsigned env_seg;
            unsigned *t_seg;
	    char _near *p;
            unsigned char t;
	    unsigned dseg;
	    unsigned doff;


            /* Initialize stack and bottom of program. */
	    _asm {
		     mov  ax, seg tsrstack
		     mov  es, ax
		     mov  WORD PTR es:tsrstack[0], sp
		     mov  WORD PTR es:tsrstack[2], ss
                 }

	    if (argc < 2) {
		speed = 2;
		n_port = 2;
	    }
	    else
		{
		n_port = argv[1][0] & 0x0f;
		if (n_port > 2)
		    n_port = 2;
		if (argc < 3) {
		    speed = 2;
		}
		else
		    {
		      t = argv[2][0];
		      switch( t ) {
			case 'L' :
			case 'l' : speed = 8;
				   break;
			case 'M' :
			case 'm' : speed = 2;
				   break;
			case 'H' :
			case 'h' : speed = 1;
				   break;
			default  : speed = 2;
		      }
		    }
		}
            FP_SEG( tsrbottom ) = _psp;
            FP_OFF( tsrbottom ) = 0;

            ProgPrefix = _psp;   /* Save PSP value */

            /* Program size is:
             *     top of stack
             *   - bottom of program (converted to paragraphs)
             *   + one extra paragraph
             */
            tsrsize = ((tsrstack - tsrbottom) >> 4) + 1;

            _asm {
                mov  ah, 3                ; check function
                int  6eh
                mov  byte ptr t[0], al    ; was int6e routine set ?
            }
            if (t != 0x55) {
                printf("I can't find Async. driver.\n");
                printf("Async. driver must be installed!\n");
                return 0;
            }

            if (SetRing() == -1) {
                printf("No core to install INT65.\n");
                return 0;
            }


            /* Initialization NAU */
            memcpy(naua[0].name,"LU1     ", 8);
            memcpy(naua[1].name,"LU2     ", 8);
            naua[0].opnq = NULL;
            naua[1].opnq = NULL;
            naua[0].sid = 0;
            naua[1].sid = 0;
            hscb_lst_ptr = NULL;
            nau_lst_ptr = &naua[0];

            _asm {
                mov   ax, 3400h
		int   21h
                mov   word ptr doff[0], bx
                mov   ax, es
                mov   word ptr dseg[0], ax
            }

            FP_SEG( dosok ) = dseg;
            FP_OFF( dosok ) = doff;

            printf("Mini-Port now installed.\n");

            /* Replace existing int65 & int8 routine with our. */
            _asm cli
	     oldint8 = _dos_getvect( 0x8 );
            _dos_setvect( 0x8, int8 );
            oldint65 = _dos_getvect( 0x65 );
            _dos_setvect( 0x65, rout );

            /* Free the PSP segment and terminate with program resident. */
	     _dos_keep( 0, tsrsize );
        }

void _interrupt _far rout( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
                               unsigned _flags )
{

      FP_OFF( InArea ) = _dx;
      FP_SEG( InArea ) = _ds;
      code = _ax;
      length = _cx;
      _asm {
               mov  ax, seg svstack
               mov  es, ax
               mov  WORD PTR es:svstack[0], sp
               mov  WORD PTR es:svstack[2], ss
               mov  ax, seg tsrstack
               mov  es, ax
               mov  sp, WORD PTR es:tsrstack[0]
               mov  ss, WORD PTR es:tsrstack[2]
           }

      if (lock) {
            lock = 0;
            switch (code) {
	      case 0:  appl(InArea);
                       break;
              case 1:  if (!total) {
                          rcv();
                       }
                       break;
              case 2:  fb(InArea);
                       break;
            }
            _asm cli
            lock = 1;
      }
      _asm {
               cli
               mov  ax, seg svstack
               mov  es, ax
               mov  sp, WORD PTR es:svstack[0]
               mov  ss, WORD PTR es:svstack[2]
           }
 }

int fb(char *p)
{
        register int rest;
        char *t;
        struct ce {
                     struct ce *next;
                     unsigned desc;
		     int lt;
		     char b[120];
                   } *re;

        re = le; /* last element */
        t = p;
        rest = length;
        while (rest) {
            if (rest > 120) {
                memcpy(re -> b, p, 120);
                re -> desc = 1; /* middle segment */
                re -> lt = 120;
                p += 120;
                rest -= 120;
                re = re -> next;
            }
            else {
		   memcpy(re -> b, p, rest);
                   re -> desc = 0; /* end or single segment */
                   re -> lt = rest;
                   rest = 0;
                 }
        }
        le = re -> next; /* Reset pointer to last element */
        total = 1;
        return 0;
}

int rcv()
{
        struct ce {
                     struct ce *next;
                     unsigned desc;
		     int lt;
		     char b[120];
                   } *re;
        register int i;
        register unsigned dsc;
        char *p;
        char *t;


        re = fe; /* first element of the buffer ring */
  Repete:
        i = 0;
        do {
                i += re -> lt;
                dsc = re -> desc;
                re = re -> next;
        } while (dsc);

        if ((p = malloc(i)) == NULL) {
            printf("No memory for make receive function.\n");
            return 0;
        }

        re = fe; /* first element of the buffer ring */
        t = p;
        do {
                memcpy(t, re -> b, re -> lt);
                t += re -> lt;
                dsc = re -> desc;
                re = re -> next;
        } while (dsc);

        appl(p + 12);
        free( p );
        fe = re;

        if (le == fe) {
                total = 0;
        }
        else
                goto Repete;

        return 0;
}

/*
 * Set ring of the input buffers.
 * Input buffers will be fills by Async. exit
 * subruotine.
 */

int SetRing()
{
        /* Element of the buffer ring */

        struct ce {
                     struct ce *next;
                     unsigned desc;
                     int lt;
                     char b[120];
                   } *re;

        struct ce *first;
        struct ce *temp;
        register int i;

	if ((temp = malloc(sizeof(struct ce))) == NULL) {
            return -1;
        }
        first = temp;

        for (i = 0; i < 18; i++) {
	    if ((re = malloc(sizeof(struct ce))) == NULL) {
                break;
            }
            else  {
                     temp -> next = re;
                     temp = re;
                  }
        }
        re -> next = first;   /* Complete the ring */

        fe = first;  /* first element of the ring */
        le = first;  /* last element of the ring */
        return 0;
}

void _interrupt _far int8( unsigned _es, unsigned _ds, unsigned _di,
			       unsigned _si, unsigned _bp, unsigned _sp,
			       unsigned _bx, unsigned _dx, unsigned _cx,
			       unsigned _ax, unsigned _ip, unsigned _cs,
                               unsigned _flags )
{

       (*oldint8)();
       _disable();
        if ((total != 0) && (lock != 0)) {
                if (*dosok == 0) {
                        _asm {
                                 mov  ax, seg tsvstack
                                 mov  es, ax
                                 mov  WORD PTR es:tsvstack[0], sp
                                 mov  WORD PTR es:tsvstack[2], ss
                                 mov  ax, seg tsrstack
                                 mov  es, ax
                                 mov  sp, WORD PTR es:tsrstack[0]
                                 mov  ss, WORD PTR es:tsrstack[2]
                         }
                        lock = 0;
                        _asm sti
                        rcv();
                        _asm cli
                        lock = 1;
                        _disable();
                        _asm {
                                 mov  ax, seg tsvstack
                                 mov  es, ax
                                 mov  sp, WORD PTR es:tsvstack[0]
                                 mov  ss, WORD PTR es:tsvstack[2]
                                 mov  bp, sp
                             }
                }
	}
}
