#include"bhole.h"
#include"ems.h"

/**** HERE ARE THINGS RELATED TO EMS (you know, like EMM386) *****/

/* NOTICE: some of the EMS/EMM stuff are in bhole.c in _redirected_addr
 *         and in some file handling routines (the emmxxxx0 device)
 *         (possibly in other places as well?)
 */

/* is there a handle pointing to the EMS device?
 * if so, it is here, if not, then it contains a -1
 */
 
int emm_dev_handle = -1;
#define EMM_SIZE   0x1050000
int emm_availble = 0x1000000; /* availble EMM memory */
emm_handle ehandles[MAX_EMM_HANDLES] = {0x50000,"",NULL};


/* EMM to conventional memory mappings - EMM can only mapped to one of the
 * MAX_EMM_MAPPINGS mappable physical pages
 * therefore, there are only MAX_EMM_MAPPINGS entries:
 * entry 0 - mapped to page 0
 * entry 1 - mapped to page 1
 * etc.
 *
 *
 * the way it is currently set up
 *
 * NOTICE: when handle == -1 it means - non allocated
 */
emm_mapping emappings[MAX_EMM_MAPPINGS];




/********************************************/





void int67_allochandle()
	/* TODO: handle "out of memory" case */
{
	int i;
	for(i = 0;i < MAX_EMM_HANDLES;i++)
	{
		if (ehandles[i].size == 0)
		{
			break;
		}
	}
	if (i == MAX_EMM_HANDLES)
	{
		ah = 0x85; /* 0x85 - no handles availble */
		return;
	}

	ehandles[i].data = malloc(bx * EMM_LPAGE_SIZE);
	ehandles[i].size = bx * EMM_LPAGE_SIZE;
	emm_availble -= bx * EMM_LPAGE_SIZE;
	if (emm_availble < 0)
	{
		fputs("BHole: ALERT!!!: unhandled case of not enough EMM\n",report_file);
	}
	ah = 0x00;
	dx = i;
	fprintf(report_file,"BHole: EMM handle of size %lx was allocated\n",
	       bx * EMM_LPAGE_SIZE);

	return;
}


void int67_maphandle()
{
	/* NOTICE : mappings does NOT affect contents of conventional memory
	 *          after mapping is done, conventional memory is UNAFFECTED
         */

	/* level 1: check if all values are correct */
	if (al >= MAX_EMM_MAPPINGS)
	{
		fprintf(report_file,"BHole: EMM mapping to a physical page greater than %d\n",al);
		fputs("BHole: IGNORED!!!\n",report_file);
		ah = 0x8B; /* 8B - illegal physical page */
		return;
	}
	if (ehandles[dx].size == 0)
	{
		ah = 0x83; /* 83 - invalid handle */
		return;
	}
	if (bx >= (ehandles[dx].size / EMM_LPAGE_SIZE))
	{
		ah = 0x8A; /* 8A - illegal logical page */
		return;
	}

	/* level 2: write the mapping to the mappings array */
	emappings[al].lpage = bx;
	emappings[al].handle = dx;


}


void kill_emmhandle_mappings(int handle)
	/* routine: kill_emmhandle_mappings
	 * purpose: kills all mappings done for an EMM handle
	 * params : int handle - the handle which is being unmapped
	 * NOTICE : mappings does NOT affect contents of conventional memory
	 *          after mapping is done, conventional memory is UNAFFECTED
	 */
{
	int i;

	/* level 1: now, kill all mappings for this handle */
	for(i = 0;i < MAX_EMM_MAPPINGS;i++)
	{
		if (emappings[i].handle == dx)
		{
			emappings[i].handle = emappings[i].lpage = -1;
		}
	}

}

void int67_freehandle()
	/* TODO: fully implement errors */
{

	/* set size to 0 and free memory */
	if (ehandles[dx].size)
	{
		emm_availble+=ehandles[dx].size;
		ehandles[dx].size = 0;
		free(ehandles[dx].data);
		kill_emmhandle_mappings(dx);
	}
	else
	{
		ah = 0x83; /* 0x83 - invalid handle */
	}

	fputs("BHole: EMM handle dealloacted\n",report_file);

}

void int67_countpages()
{
	long sum = 0;
	int i;
	ah = 0x00;
	bx = 0x800; /* memory size is 32 Megs */

	for(i = 0;i < MAX_EMM_HANDLES;i++)
	{
		sum+=ehandles[i].size;
	}
	sum/=EMM_LPAGE_SIZE;

	if (sum < 0x500) dx = sum; /* EMM seems to pre-allocate some memory */
	else             dx = sum;

}

void int67_namehandle()
{
	if (ehandles[dx].size == 0)
	{
		ah = 0x83; /* invalid handle */
		return;
	}

	switch(al)
	{
	case 0x0: /* get name */
		mem2emumem(ds,di,ehandles[dx].name,8);
		break;
	case 0x1: /* set name */
		emumem2mem(ehandles[dx].name,ds,si,8);

	}

	fprintf(report_file,"BHole: EMM: handle %x has a new name: %s\n",dx,ehandles[dx].name);

	ah = 0x0;
}

void int67_freemem()
{
	bx = emm_availble / EMM_LPAGE_SIZE;
	dx = EMM_SIZE     / EMM_LPAGE_SIZE;
	ah = 0x00;
}


void int67_maphandles()
{
	int i;
	int si2 = si;
	unsigned short physpage;
	unsigned short logipage;
	switch(al)
	{
	case 0:
/*		fputs("BHole: EMM: multipage mapping AL=0\n",report_file); */
		for(i = 0;i < cx;i++)
		{
			if ((logipage = GET_MEM_WORD(ds,si2)) == 0xFFFF)
			{
				si2+=2;
				physpage = GET_MEM_WORD(ds,si2);
				emappings[physpage].handle = emappings[physpage].lpage = -1;
			}
			else
			{
				si2+=2;
				physpage = GET_MEM_WORD(ds,si2);
				emappings[physpage].handle = dx;
				emappings[physpage].lpage  = logipage;
			}
			si2+=2;
		}
		ah = 0;
		return;
	case 1:
/*		fputs("BHole: EMM: multipage mapping AL=1\n",report_file); */
		for(i = 0;i < cx;i++)
		{
			if ((logipage = GET_MEM_WORD(ds,si2)) == 0xFFFF)
			{
				si2+=2;
				physpage = (GET_MEM_WORD(ds,si2) - EMM_PAGEFRAME_BASESEG) / (EMM_LPAGE_SIZE / 16);
				emappings[physpage].handle = emappings[physpage].lpage = -1;
			}
			else
			{
				si2+=2;
				physpage = (GET_MEM_WORD(ds,si2) - EMM_PAGEFRAME_BASESEG) / (EMM_LPAGE_SIZE / 16);
				emappings[physpage].handle = dx;
				emappings[physpage].lpage  = logipage;
			}
			si2+=2;
		}
		ah = 0;
		return;
	default:
		fputs("BHole: ALERT!!!: int67 with bad al\n",report_file);
		ah = 0x8F;
		return;
	}
}

/* do_int67 */
int do_int67()
{
/* TODO: LUT */
	switch(ah)
	{
	case 0x40:
		ah = 0x00;
		return 1;
	case 0x46: /* get EMM version and status */
		ah = 0x0; /* all is okay */
		al = 0x40; /* EMM version, go figure... */
		return 1;
	case 0x41: /* the page frame segment is returned (whatever...) */
		ah = 0x00;
		bx = EMM_PAGEFRAME_BASESEG;
		return 1;
	case 0x43:
		int67_allochandle();
		return 1;
	case 0x47:
		ah = 0x84; /* this means - unimplemented */
		return 1;
	case 0x4B: /* counts the number of already allocated EMM pages */
	           /* NOTICE: to be more similar to the way it is emulated */
	           /* NOTICE 2: we always start with extra handle allocated
	            *           straight from the beginning
	            */
		ah = 0x00;
		bx = ((EMM_SIZE) - (emm_availble)) / EMM_LPAGE_SIZE;
		return 1;
	case 0x53:
		int67_namehandle();
		return 1;
	case 0x59:
		int67_freemem();
		return 1;
	case 0x42:
		int67_countpages();
		return 1;
	case 0x45:
		int67_freehandle();
		return 1;
	case 0x44:
		int67_maphandle();
		return 1;
	case 0x50:
		int67_maphandles();
		return 1;
	default:
		fprintf(report_file,"BHole: unknown AH %x for int 67\n",ah);
		return 0;
	}
}
