// SIO2.CPP Copyright White Falcon Software House and Sapikli TM.

/*#################### Importlsok ######################################*/

#include <conio.h>
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include "sio2.h"

static char VERSION_STRING[]="SIO2 v3.2  07/1995";

/*############## Exportlt (globlis) vltozk ###########################*/

char inpuf[puflen]; 			//soros input puffer
char csat=1;				//COM x
char level=4;				//IRQ x
int inwrpoi=0;				//input puffer mutat
int inrdpoi=0;				//olvassnl/rsnl
int count;                              //a timer IT-hez
unsigned rs_bas=0x03f8;			//COMx bziscm

/*#################### Modul (loklis) vltozk ##########################*/

static char hiba=0;			//RS-232 hiba vltoz
static char lastit;			//az elz IT maszk
static char savedbits=0;		//az elmentett adatbitszm, stopbitszm, parits
static unsigned savedrate=1200;		//az elmentett BaudRate (ld. SaveLineDatas)
static unsigned it_seg;			//a megszakts cmnek mentshez
static unsigned it_ofs;
static unsigned rs_seg;			//az RS_Intr cme
static unsigned rs_ofs;
static unsigned test_seg;		//tesztvektor
static unsigned test_ofs;
static unsigned w;
static unsigned it_vekt=0x30;		//IT bziscm a vektortblban
static char megszak=0x0c;		//megszaktsszm

/*#################### Modul (loklis) fggvnydeklarcik ###############*/

static void interrupt (*oldhandler)(...);   //a rgi megszakts meghvshoz
static void interrupt (*oldtimer)(...);     //a rgi timer-interrupt

static char IT_Test();		//ellenrzi, hogy a vektor RS_Intr-re mutat-e
static void interrupt RS_Intr();	//a megszaktsrutin
static void interrupt handler(...);        //timer IT

/*########################################################################*/

static void interrupt handler(...)	//a timer IT-re hurkoldunk a timeout vizsglathoz
{
   count++;				//a szmll nvelse
   oldtimer();				//a rgi rutin meghvsa
}

char RSError()				//visszaadja a port llapott vagy a hibakdot
{
  char seged;

  seged=hiba;			//lekrdezzk az llapotot
  hiba=0;			//trljk a globlis vltozt
  return seged;
}				// 1: tele az input puffer
				// 2: tele az output puffer
				// 3: overrun
				// 4: par_test
				// 5: chr_ok
				// 6: DSR
				// 7: CTS
				// 8: res az input puffer
				// 9: nincs grafikus driver
				//10: hardverhiba
				//11: felhasznl ltal megszaktva
				//13: rvnytelen portcm. (Nincs COM...)
				//14: rvnytelen paramter
				//15: nincs tablet

/*########################################################################*/

int GetComNum()				// megkeresi a program els 
//paramtereknt megadott port szmt, ennek hinyban az els fizikailag
//ltez portot illetve kikeresi a port cmt is
{
  char len=0;
  int seged;

  asm {
    push ax
    push bx
    push cx
    push ds
    mov ax,_psp
    mov ds,ax
    mov bx,0x0080
    mov cl,[bx]				// a PSP-ben megkeressk az els paramtert
    xor al,al
    or cl,cl
    jz GCN4
    xor ch,ch
  }
GCN1:
  asm {
    inc bx
    mov al,[bx]
    cmp al,0x30
    jnc GCN2
    loop GCN1
    xor al,al
    jmp GCN4
  }
GCN2:
  asm {
    cmp al,0x3a				// ha szmmal kezddik, akkor vizsglunk csak
    jc GCN3
    loop GCN2
    xor al,al
    jmp GCN4
  }
GCN3:
  asm {
    sub al,0x30;
  }
GCN4:
  asm {
    mov len,al
    pop ds
    pop cx
    pop bx
    pop ax
  }
  if (!len) {				// automatikus portcmkeress (ha nem volt paramter)
    len=1;
    while (len<5) {
      asm {
        push ax
        push bx
        push es
        xor ax,ax
        mov es,ax
        mov bx,0x03fe			// a BIOS tblzatbl kikeressk a port cmt
        mov al,len
        xor ah,ah
        shl ax,1
        add bx,ax
        mov ax,es:[bx]
        mov bl,len
        add bl,5
        mov len,bl
        or ax,ax			//ha ez res, akkor ugyanez a kvetkez portra
        jnz GCN5
        sub bl,5
        mov len,bl
      }
GCN5:
      asm {
        pop es
        pop bx
        pop ax
      }
    }
    if (len!=5) len-=5;		 	//a "len"-ben folyatott manipulcik a tallat jelzsre szolglnak
  }
  seged=len;
  if ((seged<1) || (seged>4)) hiba=invalidparam;	//rvnytelen paramterrel indtottk a programot
  return seged;
}

/*########################################################################*/

void ChrOut(char b)
{
  long idozito;

  if (hiba) return;
//  idozito=10000;
//  while (idozito && (!hiba)) --idozito;		//egy kis vrakozs a torldsok megelzsre
  if (hiba) return;
  asm {
    push ax
    push dx
    mov dx,rs_bas			//vrakozs az adspuffer rlsre
    add dx,rs_lsr
  }
SendCikl:
  asm {
    in al,dx
    test al,chr_out
    jz SendCikl
    pop dx
    pop ax
  }
  outportb(rs_bas+rs_mcr,10);			//request-to-send
  outportb(rs_bas,b);				//az adat kikldse
  outportb(int_bas,0x20);			//esetleges ads IT esetn IT-vg jelzs
}

/*########################################################################*/

char ChrIn()					//karakter olvassa a portrl
{
  char data;

  if (hiba) return 0;
  if (((inrdpoi+1)==inwrpoi) || ((inrdpoi-puflen+1)>=inwrpoi)) {
    hiba=1;				//tele az input puffer
    return 0;
  }
  if (inwrpoi==inrdpoi) {
    hiba=8;				//res az input puffer
    return 0;
  }
  data=inpuf[inwrpoi];			//az adat beolvassa
  (++inwrpoi)%=puflen;			//mutat-lptets
  return data;
}

/*########################################################################*/

char ReadPort()				//karakter olvassa a portrl vrakozssal
{
  while ((inrdpoi==inwrpoi) && (!hiba)) {	//vrakozunk adat rkezsre
    if (kbhit()) hiba=userbrk;
  };
  return ChrIn();			//beolvassuk
}

/*########################################################################*/

static void interrupt RS_Intr()		//Ez a rutin vgzi a portrl jv adatok beolvasst
{
  asm {
    mov dx,rs_bas
    add dx,rs_lsr
    in al,dx
    test al,errors			//sttusz olvassa
    jz RS3
    test al,chr_ok			//srlt karakter?
    jz RS1
    mov al,5
    mov hiba,al
    jmp RS_Vege
  }
RS1:
  asm {
    test al,par_test			//paritshiba?
    jz RS2
    mov al,4
    mov hiba,al
    jmp RS_Vege
  }
RS2:
  asm {
    test al,overrun			//overrun?
    jz RS_Vege
    mov al,3
    mov hiba,al
    jmp RS_Vege
  }
RS3:
  asm {
    test al,chr_in			//rkezett rvnyes karakter?
    jz RS_Vege
    mov dx,rs_bas			//adatbeolvass
    in al,dx
    lea bx,inpuf
    mov di,inrdpoi			//az adat eltrolsa
    mov [bx+di],al
    inc word ptr inrdpoi
    cmp word ptr inrdpoi,puflen
    jc RS_Vege
    xor dx,dx
    mov inrdpoi,dx
  }
RS_Vege:
  asm {
    mov dx,int_bas			//jelezzk, hogy jhet a kvetkez megszakts
    mov al,0x20
    out dx,al
  }
  oldhandler();				//meghvjuk az elz rutint
  return;
}

/*########################################################################*/

static char IT_Test()			//Megvizsgljuk, hogy t van-e lltva az IT (0: nem, 1: igen)
{
  char a=0;				//segdvltoz

  asm {					//megszakts ellenrzse
    push ax
    push bx
    push cx
    push dx
    push es
    mov ax,cs
    lea dx,RS_Intr
    mov rs_seg,ax
    mov rs_ofs,dx			//az "RS_Intr" rutin cmnek lekrdezse s eltrolsa
    xor ax,ax
    mov es,ax
    mov bx,it_vekt
    mov ax,es:[bx+2]			//a soros porthoz tartoz megszakts vektorok kiolvassa
    mov cx,es:[bx]
    mov test_seg,ax			//az "RS_Intr" rutin cmnek visszaolvassa
    mov test_ofs,cx
    mov bx,rs_seg
    push cx				// Ha ax:cx == bx:dx, akkor a:=1
    push dx				// (IT vektor == &RS_Intr)
    shr cx,4
    shr dx,4
    add ax,cx				//a cmekbl 20 bites cmet ksztnk
    add bx,dx				//(gy oldhat meg az ugyanahhoz a cmet kpvisel,
    pop dx				//de klnbz ofszet-szegmens cmek detektlsa)
    pop cx
    and cl,0x0f
    and dl,0x0f
    cmp cl,dl				//gy mr kzvetlenl ssze lehet ket hasonltani
    jnz Vege1
    cmp ax,bx
    jnz Vege1
    mov al,1
    mov a,al
  }
Vege1:
  asm {
    pop es
    pop dx
    pop bx
    pop cx
    pop ax
  }
  return a;
}

/*########################################################################*/

void IntrInit(char vonal, char irq, char uzem)	//IT zemmd bellts
					//vonal: 1-4 [COM x]
					//irq: 0-7   [IRQ x]
					//uzem: 1 -- vtel IT
					//      2 -- ads IT
					//      4 -- vteli sttusz IT
					//      8 -- modem IT engedlyezs
//*** Mivel jelen file-ban az ads nem IT-vel megoldott, nem clszer ennek a bitnek a belltsa
{
  char kontrolszo;

  csat=vonal;
  level=irq;
  asm {
    push ax
    push bx
    push es
    xor ax,ax
    mov es,ax
    mov bx,0x03fe			//a BIOS tblzatbl kiolvassuk a port cmt
    mov al,csat
    xor ah,ah
    shl ax,1
    add bx,ax
    mov ax,es:[bx]
    mov rs_bas,ax			//el is troljuk egy vltozba
    pop es
    pop bx
    pop ax
  }
  if (!rs_bas) {			//ha nincs ilyen port
    hiba=invalidport;
    return;
  }
  megszak=level+8;
  it_vekt=megszak*4;
  if (IT_Test()) return;		//mr t van lltva?
  kontrolszo=lastit=inportb((int_bas+1));     //az elz IT maszk elmentse
  kontrolszo&=(0xff-(1<<level));	//IRQ x engedlyezse
  outportb((int_bas+1),kontrolszo);
  oldhandler=getvect(megszak);
  asm {					//megszakts trsa
    push ax
    push bx
    push dx
    push es
    mov dx,rs_bas			//az IT-k ideiglenes lekapcsolsa
    push dx
    add dx,rs_ier
    xor al,al
    out dx,al
    pop dx				//a modemvez. OUT2 bitjnek bekapcs.
    add dx,rs_mcr
    out dx,al
    mov al,8
    out dx,al
    cli					//az tllts idejre lekapcsoljuk az IT-ket
    mov ax,test_seg
    mov it_seg,ax
    mov ax,test_ofs
    mov it_ofs,ax
    xor ax,ax
    mov es,ax
    mov bx,it_vekt
    mov dx,rs_ofs
    mov es:[bx],dx
    mov ax,cs
    mov es:[bx+2],ax
    sti					//IT-k jraengedlyezse
    pop es
    pop dx
    pop bx
    pop ax
  }
  outportb((rs_bas+rs_lcr),(inportb(rs_bas+rs_lcr) & 0x7f));   //IER elrhet
  outportb((rs_bas+rs_ier),uzem);	//megszakts maszkolsa
  inportb(rs_bas);
}

/*########################################################################*/

void ClearIntr()			//IT kikapcsols
{
  char a;				//segdvltoz

  if (!IT_Test()) return;	        //t van lltva egyltaln?
  a=inportb(int_bas+1);
  a=lastit;				//az elzl IT maszk visszamentse
  outportb(int_bas+1,a);
  asm {					//megszakts visszalltsa
    push ax
    push bx
    push dx
    push es
    cli
    xor ax,ax
    mov es,ax
    mov bx,it_vekt
    mov dx,it_ofs
    mov es:[bx],dx
    mov dx,it_seg
    mov es:[bx+2],dx
    sti
    pop es
    pop dx
    pop bx
    pop ax
  }
}

/*########################################################################*/

void SaveLineDatas()		        //az aktulis port belltsainak mentse
{
  unsigned division;

  outportb((rs_bas+rs_lcr),0x80);	//a division regiszterek elrhetk
  division=inportw(rs_bas);         //az oszts (BaudRate) elmentse
  savedbits=inportb(rs_bas+rs_lcr);	//az adatbitek, a stopbitek s a parits elmentse
  if (division) savedrate=115200/division;
  else savedrate=1200;
}

/*########################################################################*/

void RestoreLineDatas()		         //az aktulis port belltsainak visszalltsa
{
  unsigned division;

  division=115200/savedrate;
  outportb((rs_bas+rs_lcr),0x80);	//a division regiszterek elrhetk
  outportw(rs_bas,division);	      //BaudRate
  outportb((rs_bas+rs_lcr),savedbits);	//protokolmd
  outportb((int_bas+1),lastit);		//megszakts engedlyezse
}

/*########################################################################*/

void InitLine(unsigned baud, char bit, char stopbit, Partip paritas)
						//COMx felprogramozs
				//baud:	1..115200
				//bit: 5..8
				//stopbit: 1,2
				//paritas: none,odd,even,stickodd,stickeven
{
  char kontrolszo;
  unsigned division;

  if (baud) division=115200/baud;
  else division=96;			//a BaudRate-nek megfelel osztsarny kiszmtsa
  switch (paritas)
  {
    case none: kontrolszo=0; break;				//nincs
    case odd: kontrolszo=paren; break;				//pratlan
    case even: kontrolszo=(paren|evpar); break;			//pros
    case stickodd: kontrolszo=(paren|stpar); break;		//fix 0
    case stickeven: kontrolszo=(paren|stpar|evpar); break;	//fix 1
  }
  kontrolszo+=bit;			//a bitszm belltsa
  kontrolszo-=5;
  if (stopbit==2) kontrolszo|=stops;	//a stopbitek szmnak belltsa
  outportb((rs_bas+rs_lcr),0x80);	//a division regiszterek elrhetk
  outportw(rs_bas,division);
  outportb((rs_bas+rs_lcr),kontrolszo);	//protokolmd
  kontrolszo=inportb((int_bas+1));	//megszakts engedlyezse
  lastit=kontrolszo;			//az elz IT maszk elmentse
  if (csat&1) kontrolszo&=0xef;		//IRQ 4 engedlyezse
  else kontrolszo&=0xf7;		//IRQ 3 engedlyezse
  outportb((int_bas+1),kontrolszo);
  inportb(rs_bas);
  inportb(rs_bas+rs_lsr);		//status registerek trlse
  inportb(rs_bas+rs_msr);
  inportb(rs_bas+rs_iir);
  inpuf[inrdpoi]=inportb(rs_bas);
  oldtimer=getvect(0x1c);		//a timer IT tlltsa
  setvect(0x1c,handler);
  count=0;

// while () {
//  ...  (Idztett perifria-ellenrzs)
// }

  setvect(0x1c,oldtimer);		//visszalltjuk a timer IT-t
  if (count>=porttimeout) hiba=notablet;	//ha nem jtt idben vlasz
}

/*#################### Modul vge ########################################*/

