#include <scl1xms.h>
#include <memory.h>
#include <dos.h>

    /************************************
        eXtended (XMS) Memory functions */

void Pause(void);
void PrintA20Status(void);
void PrintError(unsigned int Error);
void PrintHandleInfo(int handle);

typedef struct{
    unsigned int ErrorCode;
    char *ErrorMess;
    }XMSERRORS;

XMSERRORS xmse[]=
    {
    XMS_NOT_IMPLEMENTED         ,"XMS function not available",
    XMS_VDISK_PRESENT           ,"Virtual Disk present",
    XMS_A20_ERROR               ,"A20 line error",
    XMS_GENERAL_DRIVER_ERROR    ,"General XMS driver error",
    XMS_UNRECOVERABLE_ERROR     ,"Unrecoverable error",
    XMS_HMA_NOT_EXIST           ,"HMA does not exist",
    XMS_HMA_IN_USE              ,"HMA already in use",
    XMS_HMA_NOT_ALLOCATED       ,"HMA is not allocated",
    XMS_A20_ALREADY_ENABLED     ,"A20 is already enabled",
    XMS_ALL_EXTENDED_ALLOCATED  ,"All XMS memory allocated",
    XMS_NO_MORE_HANDLES         ,"No more handles available",
    XMS_INVALID_HANDLE          ,"Invalid handle number",
    XMS_INVALID_SOURCE_HANDLE   ,"Invalid source handle",
    XMS_INVALID_SOURCE_OFFSET   ,"Invalid source offset",
    XMS_INVALID_DEST_HANDLE     ,"Invalid destination handle",
    XMS_INVALID_DEST_OFFSET     ,"Invalid destination offset",
    XMS_INVALID_LENGTH          ,"Invalid length",
    XMS_INVALID_OVERLAP         ,"Invalid overlap",
    XMS_PARITY_ERROR            ,"Parity error",
    XMS_BLOCK_NOT_LOCKED        ,"Block not locked",
    XMS_BLOCK_LOCKED            ,"Block locked",
    XMS_LOCK_COUNT_OVERFLOW     ,"Lock count overflow",
    XMS_LOCK_FAIL               ,"Lock fail",
    XMS_UMB_SMALL_AVAILABLE     ,"Smaller UMB available",
    XMS_UMB_NOT_AVAILABLE       ,"UMB not available",
    XMS_UMB_INVALID_SEGMENT     ,"Invalid segment",
    };

char CompOkStr[]="\tCompare OK\n";
char CompErrStr[]="\tCompare ERROR\n";

/* struct used to move or copy data from extended memory */

XMSMove xmove;

char TestData[80]="This string will be used to test XMS functions";

main()
{
unsigned int available,total,i,handle;
char buffer[sizeof(TestData)];
void far *p;

/***********************************************
    initialize, check if XMS driver is present */

if(XMS_Init() != XMS_OK)
    {
    printf("No XMS available\n");
    exit(-1);
    }
else
    printf("\n\nSCL1 Version 3.0 eXtended (XMS) Memory Test\n");

XMS_GetVersion(&i);           /* get version number */

    /* add 0x30 to returned value to get ASCII code */

memset(buffer,0,sizeof(buffer));
buffer[0]=XMS_MAJOR_VER(i) + 0x30;
buffer[1]='.';
buffer[2]=XMS_MINOR_VER(i) + 0x30;
printf("XMS Version %s\n\n",buffer);

    /***********************
     High Memory Area Test */

printf("High Memory Area (HMA) Test\n");

if((i=XMS_RequestHMA())==XMS_OK)
    {

    /* allocated OK */

    printf("\tHMA allocated...\n");

    /* enable the A20 line so that we can access HMA */

    if((i=XMS_GlobalEnableA20())==XMS_OK)
        {

        _fmemcpy(XMS_HMA,(void far *)TestData,sizeof(TestData));
        printf("\tData copied to HMA...\n");

        /* copy HMA to local buffer */

        memset(buffer,0,sizeof(buffer));
        _fmemcpy((void far *)buffer,XMS_HMA,sizeof(buffer));

        if(memcmp(buffer,TestData,sizeof(TestData))==0)
            printf(CompOkStr);
        else
            printf(CompErrStr);
        }
    else

        printf("\tError enabling A20 line, cannot access HMA\n");

     /* free HMA */

    XMS_ReleaseHMA();

    printf("\tReleasing HMA...\n");
    }
else

    PrintError(i);

Pause();

    /*************************
        Extended Memory Test */

printf("Extended Memory Test\n");

if((i=XMS_QueryFreeExtended(&available,&total))==XMS_OK && available > 0)
    {
    printf("\tLargest available block: %u KB\n",available);
    printf("\tTotal available memory: %u KB\n",total);

     /* allocate all memory */

    if((i=XMS_AllocExtended(&handle,available))==XMS_OK)
        {
        printf("\tSuccesful allocation of %u KB...\n",available);
        printf("\tCopying data to allocated memory...\n");

        /* copy TestData buffer to extended memory */

        xmove.bytes=(unsigned long)sizeof(TestData);
        xmove.shandle=0;
        xmove.source=(void far *)TestData;
        xmove.dhandle=handle;
        xmove.destination=0;
        if((i=XMS_MoveExtended(&xmove))==XMS_OK)
            {

            /* copy extended memory to local buffer */

            memset(buffer,0,sizeof(buffer));
            xmove.bytes=sizeof(TestData);
            xmove.shandle=handle;
            xmove.source=0;
            xmove.dhandle=0;
            xmove.destination=(void far *)buffer;
            if((i=XMS_MoveExtended(&xmove))==XMS_OK)
                {
                if(memcmp(TestData,buffer,sizeof(TestData))==0)
                    printf(CompOkStr);
                else
                    printf(CompErrStr);
                }
            else
                PrintError(i);
            }
        else
            PrintError(i);

        /* get handle information */

        PrintHandleInfo(handle);
        Pause();

        /*******************
          Lock/Unlock Test */

        printf("Lock/Unlock Test\n\tLocking allocated memory...\n");
        if((i=XMS_LockExtended(handle,&p))==XMS_OK)
            {
            printf("\tLocked block 32-bit linear address: %lX\n",p);
            PrintHandleInfo(handle);
            printf("\tUnlocking allocated memory...\n");
            XMS_UnlockExtended(handle);
            PrintHandleInfo(handle);
            }
        else
            PrintError(i);

        /*********************
          Reallocating Test  */

        Pause();
        printf("Reallocating Test\n");

        /* realllocate buffer to 1kb */

        if((i=XMS_ReallocExtended(handle,1))==XMS_OK)
            {
            printf("\tBlock reallocated to 1 KB\n");

            /* get handle info */

            PrintHandleInfo(handle);
            }
        else
            printf("\tError reallocating\n");

          /* free memory */

          XMS_FreeExtended(handle);
          printf("\tReleasing Extended memory...\n");
          }
     else
          printf("\tError Allocating\n");
     }

Pause();

    /****************
      A20 Line Test */

printf("A20 Line Test\n");
PrintA20Status();

if((i=XMS_LocalEnableA20())==XMS_OK)
    {
    printf("\tLocally enabling A20 line...\n");
    XMS_LocalEnableA20();
    PrintA20Status();

    printf("\tLocally disabling A20 line...\n");
    XMS_LocalDisableA20();
    PrintA20Status();
    }
else
    PrintError(i);

Pause();

    /****************************
      Upper Memory Blocks Test  */

printf("Upper Memory Block (UMB) Test\n");

  /* By requesting 0xffff paragraphs, the largest available block size will be 
     reported if UMB blocks are available */

if((i=XMS_RequestUMB(0xffff,&p,&available))==XMS_OK || i==XMS_UMB_SMALL_AVAILABLE)
     {
     printf("\tUMB available, allocating largest block available...\n");
     if(i==XMS_UMB_SMALL_AVAILABLE)
        {
        if((i=XMS_RequestUMB(available,&p,&available))!=XMS_OK)
            PrintError(i);
        else
            {
            printf("\tUMB Size: %li bytes\n\tUMB Address: %X\n",(long) available * 16L,FP_SEG(p));
            printf("\tCopying data to allocated memory...\n");
            _fmemcpy(p,(void far *)TestData,sizeof(TestData));
            memset(buffer,0,sizeof(buffer));
            _fmemcpy((void far *)buffer,p,sizeof(TestData));
            if(memcmp(buffer,TestData,sizeof(TestData))==0)
                printf(CompOkStr);
            else
                printf(CompErrStr);
            printf("\tReleasing UMB...\n");
            XMS_ReleaseUMB(p);
            }
        }
     }
else
    PrintError(i);
}


void PrintError(unsigned int Error)
{
int i;

for(i=0;i < sizeof(xmse) /sizeof(XMSERRORS);++i)
    {
    if(xmse[i].ErrorCode==Error)
        {
        printf("\t%s\n",xmse[i].ErrorMess);
        return;
        }
    }
printf("\tUnknown error #%X\n",Error);
}

void Pause(void)
{
printf("-- more --");
GetKey();
printf("\r          \n");
}

void PrintHandleInfo(int handle)
{
int lcount,fhandle,bsize;

XMS_GetEMBHandleInfo(handle,&lcount,&fhandle,&bsize);
printf("\tHandle Report:\n");
printf("\t\tFree Handles: %i\n",fhandle);
printf("\t\tAllocated Block Lock Count: %i\n",lcount);
printf("\t\tAllocated Block Size: %i KB\n",bsize);
}

void PrintA20Status(void)
{
unsigned int i;
int j;

if((j=XMS_QueryA20(&i))==XMS_OK)
    {
    if(i==XMS_A20_ENABLED)
        printf("\tA20 enabled\n");
    else
        printf("\tA20 NOT enabled\n");
    }
else
    PrintError(j);
}
