#include	<stdio.h>
#include	<dos.h>
#include	<malloc.h>
#define	_EMM_
#include	"emm.h"
#undef	_EMM_


int	isemm()
{
	union REGS	reg;
	struct SREGS	sreg;
	char	far *fptr;
	int	fh,ret;

	ret = 0;

		/* open device "EMMXXXX0" */
	fptr = "EMMXXXX0";		/* emm device name */
	sreg.ds = FP_SEG(fptr);
	reg.x.dx = FP_OFF(fptr);
	reg.x.ax = 0x3d00;		/* open handle */
	intdosx(&reg,&reg,&sreg);
	if(reg.x.cflag)
	{
		emm.status = EMMNORDY;
		emm.errorno = EMMDEVER;
		return(0);
	}
	fh = reg.x.ax;	/* file handle */

		/* check device */
	reg.x.bx = fh;
	reg.x.ax = 0x4400;		/* get IOCTL */
	intdos(&reg,&reg);
	if(!reg.x.cflag && (reg.x.dx & 0x0080))	/* is handle device */
	{
			/* check device ready */
		reg.x.bx = fh;
		reg.x.ax = 0x4407;	/* get output IOCTL status */
		intdosx(&reg,&reg,&sreg);
		if(!reg.x.cflag && (reg.h.al == 0xff))	/* is device ready */
			ret = 1;
	}

		/* close device */
	reg.x.bx = fh;
	reg.x.ax = 0x3e00;
	intdos(&reg,&reg);

	if(ret == 0)
	{
		emm.status = EMMNORDY;
		emm.errorno = EMMDEVER;
		return(0);
	}

		/* check ems status */
	reg.h.ah = 0x40;
	emscall();
	emm.errorno = (unsigned int)(reg.h.ah);

	if(emm.errorno != 0)
	{
		emm.status = EMMNORDY;
		return(0);
	}
	emm.status |= EMMREADY;

	return(1);
}


unsigned int	emsver()
{
	union REGS	reg;

	if(!(emm.status & EMMREADY))
	{
		if(!isemm())
			return(0);
	}

	reg.h.ah = 0x46;
	emscall();
	if(reg.h.ah != 0)
	{
		emm.errorno = reg.h.ah;
		return(0);
	}

	return((unsigned int)(reg.h.al));
}


unsigned int	emsphys()
{
	union REGS	reg;
	struct SREGS	sreg;
	unsigned int	p,f;
	EMMPHYS	far *physical;

	if(emm.status & EMMGETPH)
		return(1);

		/* check version 4.0 */
	if(0x40 != emsver())
	{
		emm.errorno = EMMVERER;
		return(0);
	}

		/* get physical page number */
	reg.x.ax = 0x5801;
	emscall();
	if(reg.h.ah)
	{
		emm.errorno = reg.h.ah;
		return(0);
	}
	emm.ppages = (unsigned int)reg.x.cx;

		/* get physical page table */
	if(NULL == (emm.ppflame = (EMMPAGES *)calloc(emm.ppages,sizeof(EMMPAGES))))
	{
		emm.errorno = EMMMEMER;
		return(0);
	}

		/* get physical address table */
	if(NULL == (physical = (EMMPHYS far *)_fmalloc(sizeof(EMMPHYS) * emm.ppages)))
	{
		emm.errorno = EMMMEMER;
		free((char *)emm.ppflame);
		return(0);
	}

		/* get physical page address */
	reg.x.ax = 0x5800;
	reg.x.di = FP_OFF(physical);
	sreg.es = FP_SEG(physical);
	emscallx();
	if(0 != reg.h.ah)
	{
		emm.errorno = reg.h.ah;
		_ffree((char far *)physical);
		free((char *)emm.ppflame);
		return(0);
	}

		/* set physical page table */
	f = 0;
	for(p = 0;p < emm.ppages;p++)
	{
		if(physical[p].segment >= 0xa000)
		{
			emm.ppflame[f].ppage   = physical[p].ppage;
			emm.ppflame[f].segment = physical[p].segment;
			emm.ppflame[f].lpage   = 0xffff;
			f++;
		}
	}
	emm.epages = f;
	for(p = 0;p < emm.ppages;p++)
	{
		if(physical[p].segment < 0xa000)
		{
			emm.ppflame[f].ppage   = physical[p].ppage;
			emm.ppflame[f].segment = physical[p].segment;
			emm.ppflame[f].lpage   = 0xffff;
			f++;
		}
	}

		/* free working memory */
	_ffree((char far *)physical);

	emm.status |= EMMGETPH;

	return(1);
}


unsigned int	emsalloc(unsigned int logipage)
{
	union REGS	reg;

	if(emm.status & EMMALLOC)
		return(0);

		/* check version 4.0 */
	if(0x40 != emsver())
	{
		emm.errorno = EMMVERER;
		return(0);
	}

		/* allacation ems logical page */
	reg.x.ax = 0x5a00;
	reg.x.bx = logipage;
	emscall();
	if(0 != reg.h.ah)
	{
		emm.errorno = reg.h.ah;
		return(0);
	}
	emm.handle = reg.x.dx;
	emm.lpages = logipage;

	emm.status |= EMMALLOC;

	return(1);
}


unsigned int	emsrealc(unsigned int logipage)
{
	union REGS	reg;

	if(!(emm.status & EMMALLOC))
		return(emsalloc(logipage));

		/* reallacation ems logical page */
	reg.h.ah = 0x51;
	reg.x.dx = emm.handle;
	reg.x.bx = logipage;
	emscall();
	emm.lpages = reg.x.bx;
	if(0 != reg.h.ah)
	{
		emm.errorno = reg.h.ah;
		return(0);
	}

	return(1);
}


unsigned int	emsmap(unsigned int logipage,unsigned int physpage)
{
	union REGS	reg;
	unsigned int	p;

	if(!(emm.status & EMMALLOC))
	{
		emm.errorno = EMMALCER;
		return(0);
	}

	for(p = 0;p < emm.ppages;p++)
	{
		if(emm.ppflame[p].ppage == physpage)
			break;
	}
	if(p == emm.ppages)
	{
		emm.errorno = EMMARGER;
		return(0);
	}

	if(emm.ppflame[p].lpage == logipage)
		return(1);

		/* mapping ems logical page */
	reg.h.ah = 0x44;
	reg.h.al = (unsigned char)physpage;
	reg.x.bx = logipage;
	reg.x.dx = emm.handle;
	emscall();
	if(0 != reg.h.ah)
	{
		emm.errorno = reg.h.ah;
		return(0);
	}

	emm.ppflame[p].lpage = logipage;

	return(1);
}


unsigned int	emsmapf(unsigned int logipage,unsigned int flame)
{
	union REGS	reg;

	if(!(emm.status & EMMALLOC))
	{
		emm.errorno = EMMALCER;
		return(0);
	}

	if(flame >= emm.ppages)
	{
		emm.errorno = EMMARGER;
		return(0);
	}

	if(emm.ppflame[flame].lpage == logipage)
		return(1);

		/* mapping ems logical page */
	reg.h.ah = 0x44;
	reg.h.al = (unsigned char)emm.ppflame[flame].ppage;
	reg.x.bx = logipage;
	reg.x.dx = emm.handle;
	emscall();
	if(0 != reg.h.ah)
	{
		emm.errorno = reg.h.ah;
		return(0);
	}

	emm.ppflame[flame].lpage = logipage;

	return(1);
}


unsigned int	emsfree()
{
	union REGS	reg;

	if(emm.status & EMMALLOC)
	{
			/* free ems logical page */
		reg.h.ah = 0x45;
		reg.x.dx = emm.handle;
		emscall();
		if(0 != reg.h.ah)
		{
			emm.errorno = reg.h.ah;
			return(0);
		}
		emm.handle = 0;
		emm.lpages = 0;

		emm.status &= ~EMMALLOC;
	}

	if(emm.status & EMMGETPH)
	{
		free((char *)emm.ppflame);
		emm.ppages = 0;
		emm.epages = 0;
		emm.lpages = 0;
		emm.ppflame = NULL;

		emm.status &= ~EMMGETPH;
	}

	return(1);
}

