/*
version 1.00
07/14/2022: initial version
*/
#include <dos.h>
#include <alloc.h>
#include <mem.h>
#include "xeh.h"
#include "xms.h"
#include "ems.h"
xeh_type xeh;
xehtable_type xehtable[XEH_MAX_HANDLES];
void XEHInit(unsigned int ATypes)
{
//clear
memset(&xeh, 0, sizeof(xeh_type));
memset(&xehtable, 0, sizeof(xehtable_type)*XEH_MAX_HANDLES);
//xms
if ((ATypes & XEH_XMS) && (XMSInit()==XMSERR_NONE))
xeh.xmsenabled=1;
//ems
if ((ATypes & XEH_EMS) && (EMSInit()==EMSERR_NONE))
xeh.emsenabled=1;
//heap
if (ATypes & XEH_HEAP)
xeh.heapenabled=1;
}
void XEHAvailable(unsigned int *APages)
{
unsigned int ui1, ui2;
unsigned long ul1;
//clear
ui1=0;
*APages=0;
//xms
if (xeh.xmsenabled && XMSAvailable(&ui2)==XMSERR_NONE)
{
ui2/=16;
ui1+=ui2;
}
//ems
if (xeh.emsenabled && EMSAvailable(&ui2)==EMSERR_NONE)
ui1+=ui2;
//heap
if (xeh.heapenabled)
{
//heap available
ul1=coreleft();
if (ul1>=1024)
ul1-=1024;
else ul1=0;
ui2=(unsigned int)(ul1/16384);
ui1+=ui2;
}
//set pages
*APages=ui1;
}
int XEHAlloc(unsigned int APages, unsigned int *AHandle)
{
unsigned int ui1, ui2, ui3, ui4;
unsigned long ul1;
//do we have a handle free
for (ui1=0; ui1<XEH_MAX_HANDLES; ui1++)
if (!xehtable[ui1].used)
break;
if (ui1==XEH_MAX_HANDLES)
return XEHERR_NOHANDLES;
//clear table and mark handle used
memset(&xehtable[ui1], 0, sizeof(xehtable_type));
xehtable[ui1].used=1;
//we need ui1 pages to be allocated
ui3=APages;
//xms
if (xeh.xmsenabled && ui3)
{
//xms available
ui4=XMSAvailable(&ui2);
if (ui4!=XMSERR_NONE)
return XMSERROFFSET+ui4;
ui2/=16;
//allocate
if (ui2>ui3)
ui2=ui3;
if (ui2)
{
ui4=XMSAlloc(ui2*16, &xehtable[ui1].xmshandle);
if (ui4!=XMSERR_NONE)
{
XEHFree(ui1);
return XMSERROFFSET+ui4;
}
xehtable[ui1].xmspages=ui2;
ui3-=ui2;
}
}
//ems
if (xeh.emsenabled && ui3)
{
//ems available
ui4=EMSAvailable(&ui2);
if (ui4!=EMSERR_NONE)
return EMSERROFFSET+ui4;
//allocate
if (ui2>ui3)
ui2=ui3;
if (ui2)
{
ui4=EMSAlloc(ui2, &xehtable[ui1].emshandle);
if (ui4!=EMSERR_NONE)
{
XEHFree(ui1);
return EMSERROFFSET+ui4;
}
xehtable[ui1].emspages=ui2;
ui3-=ui2;
}
}
//heap
if (xeh.heapenabled && ui3)
{
//heap available
ul1=coreleft();
if (ul1>=1024)
ul1-=1024;
else ul1=0;
ui2=(unsigned int)(ul1/16384);
//allocate
if (ui2>ui3)
ui2=ui3;
if (ui2)
{
if ((xehtable[ui1].heaphandle=(char *)farmalloc(ui2*16384L))==NULL)
{
heapfail:
XEHFree(ui1);
return XEHERR_NOPAGES;
}
xehtable[ui1].heappages=ui2;
ui3-=ui2;
}
}
//any pages not allocated
if (ui3)
goto heapfail;
//set handle
*AHandle=ui1;
//debug
//printf("xp%u, ep%u, hp%u\n", xehtable[ui1].xmspages, xehtable[ui1].emspages, xehtable[ui1].heappages);
//return success
return XEHERR_NONE;
}
//Frees memory and handle
int XEHFree(unsigned int AHandle)
{
//is this handle valid
if (AHandle>=XEH_MAX_HANDLES || !xehtable[AHandle].used)
return XEHERR_BADHANDLE;
//xms
if (xehtable[AHandle].xmspages)
XMSFree(xehtable[AHandle].xmshandle);
//ems
if (xehtable[AHandle].emspages)
EMSFree(xehtable[AHandle].emshandle);
//heap
if (xehtable[AHandle].heappages)
farfree(xehtable[AHandle].heaphandle);
//clear table
memset(&xehtable[AHandle], 0, sizeof(xehtable_type));
//return success
return XEHERR_NONE;
}
int XEHTransfer(unsigned int AHandle, unsigned long AOffset, unsigned int ASize, char *AMemory, char ARead)
{
unsigned int ui1, memoffset, page, pageoffset, copysize;
unsigned long ul1;
//is this handle valid
if (AHandle>=XEH_MAX_HANDLES || !xehtable[AHandle].used)
return XEHERR_BADHANDLE;
memoffset=0;
page=(unsigned int)(AOffset/16384);
pageoffset=(unsigned int)(AOffset%16384);
while (ASize)
{
//how much to copy
copysize=16384-pageoffset;
if (copysize>ASize)
copysize=ASize;
//type of memory
if (page>=xehtable[AHandle].xmspages+xehtable[AHandle].emspages+xehtable[AHandle].heappages)
return XEHERR_BADOFFSET;
else
if (page>=xehtable[AHandle].xmspages+xehtable[AHandle].emspages)
{
//heap
ul1=(page-xehtable[AHandle].xmspages-xehtable[AHandle].emspages)*16384L+pageoffset;
if (ARead)
memcpy(AMemory+memoffset, xehtable[AHandle].heaphandle+ul1, copysize);
else memcpy(xehtable[AHandle].heaphandle+ul1, AMemory+memoffset, copysize);
}
else
if (page>=xehtable[AHandle].xmspages)
{
//map page
ui1=EMSMap(xehtable[AHandle].emshandle, 0, page-xehtable[AHandle].xmspages);
if (ui1)
return EMSERROFFSET+ui1;
//read or write
if (ARead)
memcpy(AMemory+memoffset, EMSFrame+pageoffset, copysize);
else memcpy(EMSFrame+pageoffset, AMemory+memoffset, copysize);
}
else
{
//xms
ul1=page*16384L+pageoffset;
if (ARead)
ui1=XMSRead(xehtable[AHandle].xmshandle, ul1, copysize, AMemory+memoffset);
else ui1=XMSWrite(xehtable[AHandle].xmshandle, ul1, copysize, AMemory+memoffset);
if (ui1)
return XMSERROFFSET+ui1;
}
memoffset+=copysize;
ASize-=copysize;
pageoffset=0;
page++;
}
//return success
return XEHERR_NONE;
}