#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <sys\stat.h>
#include <i86.h>
#include <malloc.h>
#include <dos.h>

#include "..\..\api.h"

void Microsecond_Delay_Init(void);


char OS_String[0x100];

int OS_Init(void)
{
union REGS in_regs, out_regs;
	
	in_regs.h.ah = 0x30; // Get DOS version
	intdos( &in_regs, &out_regs );
	
	sprintf(OS_String,"DOS %d.%d",out_regs.h.al,out_regs.h.ah);
	
	Microsecond_Delay_Init();
	return 1;
}

void OS_Deinit(void)
{
}


void OS_OutPortByte(unsigned short Adr,unsigned char Data)
{
	outp(Adr,Data);
}

void OS_OutPortWord(unsigned short Adr,unsigned short Data)
{
	outpw(Adr,Data);
}
void OS_OutPortDword(unsigned short Adr,unsigned long Data)
{
	outpd(Adr,Data);
}

unsigned char  OS_InPortByte(unsigned short Adr)
{
	return inp(Adr);
}
unsigned short OS_InPortWord(unsigned short Adr)
{
	return inpw(Adr);
}
unsigned long  OS_InPortDword(unsigned short Adr)
{
	return inpd(Adr);
}

void * OS_Alloc_Execute_Read_Write(unsigned int Size)
{
	return (void *) malloc(Size);
}

void   OS_Free_Execute_Read_Write(void * Adr,unsigned int Size)
{
	Size;
	free(Adr);
}

void * OS_Memory_Allocate(unsigned long Size)
{
	return (void *) malloc(Size);
}

void   OS_Memory_Free(void * Adr,unsigned long Size)
{
	Size;
	free(Adr);
}

void * OS_Physical_Memory_Map(void * Adr,unsigned long Size)
{
union REGS  regs;

unsigned int ReturnVal;


	if ((unsigned long)Adr>0x100000)
	{
		regs.w.ax=0x0800;
		regs.w.cx=((unsigned long )Adr) & 0xffff;
		regs.w.bx=(((unsigned long )Adr) >> 16) & 0xffff;

		regs.w.di=Size & 0xffff;
		regs.w.si=(Size >> 16) & 0xffff;

		int386( 0x31, &regs, &regs );

		ReturnVal=(unsigned int) (regs.w.bx<<16) | regs.w.cx;
	}
	else
	{
		ReturnVal=(unsigned int) Adr;
	}

	return (void *) ReturnVal;
}

void  OS_Physical_Memory_Unmap(void * Adr,unsigned long Size)
{
union REGS  regs;

	Size;
	if ((unsigned int)Adr>0x100000)
	{

		regs.w.ax=0x0801;
		regs.w.cx=((unsigned int)Adr) & 0xffff;
		regs.w.bx=(((unsigned int)Adr) >> 16) & 0xffff;
		int386( 0x31, &regs, &regs );
	}

}

unsigned int OS_Execute_IO_Block(_API_IO_Struct * IO_Block,unsigned int Size)
{


unsigned int Index1;
unsigned int Index2;
unsigned int Data[0x20];
unsigned int uiLoop;

	while((IO_Block->Command&0xff)!=_API_iob_END)
	{

		Index1=(IO_Block->Command>>8)&0x1f;
		Index2=(IO_Block->Command>>16)&0x1f;

		switch(IO_Block->Command & 0xff)
		{
		case  _API_iob_ADD:
			Data[Index1]+=IO_Block->Data;
			break;
		case  _API_iob_AND:
			Data[Index1]&=IO_Block->Data;
			break;
		case _API_iob_OR:
			Data[Index1]|=IO_Block->Data;
			break;
		case  _API_iob_XOR:
			Data[Index1]^=IO_Block->Data;
			break;
		case  _API_iob_SHL:
			Data[Index1]<<=IO_Block->Data;
			break;
		case  _API_iob_SHR:
			Data[Index1]>>=IO_Block->Data;
			break;
		case  _API_iob_Set_Data:
			Data[Index1]=IO_Block->Data;
			break;
		case  _API_iob_Copy:
			Data[Index1]=Data[Index2];
			break;
		case  _API_iob_IO_Read_Byte:
			*(unsigned char *)&Data[Index1]=OS_InPortByte(Data[Index2]);
			break;
		case  _API_iob_IO_Read_Word:
			*(unsigned short *)&Data[Index1]=OS_InPortWord(Data[Index2]);
			break;
		case  _API_iob_IO_Read_Dword:
			Data[Index1]=OS_InPortDword(Data[Index2]);
			break;
		case  _API_iob_IO_Write_Byte:
			OS_OutPortByte(Data[Index2],Data[Index1]);
			break;
		case  _API_iob_IO_Write_Word:
			OS_OutPortWord(Data[Index2],Data[Index1]);
			break;
		case  _API_iob_IO_Write_Dword:
			OS_OutPortDword(Data[Index2],Data[Index1]);
			break;     
		case _API_iob_IO_Delay:
			for(uiLoop=0;uiLoop<IO_Block->Data;uiLoop++)
				OS_InPortByte(Data[Index1]);
			break;			
			
		}
		IO_Block++;
	}

	return Data[Index1];

}

unsigned long CpuResult = 0;
unsigned long clks1;
unsigned long clks2;


int Time_Stamp_Counter = 0;

void Microsecond_Delay_Init(void)
{
/*
unsigned int clock2;
unsigned long Start;
unsigned long Stop;

unsigned long features = 0;             // cpuid Features
int cpuid_support = 1;

	__asm{.386
	        pushfd
	        pop     eax
	        mov     ebx,eax
	        xor     eax,00200000h
	        push    eax
	        popfd
	        pushfd
	        pop     eax
	        cmp     eax,ebx
		jnz     cpuid_found
	        mov     cpuid_support,0      // ; PIII serial nr.
    	    cpuid_found:
	     }

	if(cpuid_support == 1)
	{
		_asm
		{
	        mov     eax,1
	        db 0x0f,0xa2
			mov     [features],edx
		}
	}

	Time_Stamp_Counter = ((features >> 4) & 1);

	if(Time_Stamp_Counter == 1)
	{

		delay(10);
		_disable();

		_asm
	        {
	        db 0fh
	        db 31h
	        mov     dword ptr [clks1], eax
	        }

        delay(333);

        _asm
        	{
	        db 0fh
	        db 31h
	        mov     dword ptr [clks2], eax
	        }

		_enable();

		CpuResult = (clks2-clks1)/1000000;
		CpuResult*=3;


	}
*/
}

int OS_Microsecond_Delay(unsigned int DelayCount)
{
/*
	if(Time_Stamp_Counter == 1)
	{

	_asm
		{
		db 0fh
		db 31h
		mov     dword ptr [clks1], eax
		}

		do{
	        _asm
	        	{
		        db 0fh
		        db 31h
		        mov     dword ptr [clks2], eax
		        }

		}while( (clks2-clks1) <= (DelayCount*CpuResult) );
	}
	else
	{
		if(DelayCount>=1000)
			delay(DelayCount/1000);
		else
			delay(1);
	}


*/
	return _API_se_OK;
}


int OS_CPUID(_API_ASM_REGS_Struct * _API_ASM_REGS)
{
	_asm{
		.686
		
		pushad		
		mov		esi,_API_ASM_REGS
		mov		eax,0x00[esi] 
		mov		ebx,0x04[esi] 
		mov		ecx,0x08[esi] 
		mov		edx,0x0c[esi] 
		CPUID
		mov		0x00[esi],eax
		mov		0x04[esi],ebx
		mov		0x08[esi],ecx
		mov		0x0c[esi],edx
		popad
	}
	return _API_se_OK;	
}
int OS_Read_MSR(_API_ASM_REGS_Struct * _API_ASM_REGS)
{
	_asm{
		.686
		pushad		
		mov		esi,_API_ASM_REGS
		mov		eax,0x00[esi] 
		mov		ebx,0x04[esi] 
		mov		ecx,0x08[esi] 
		mov		edx,0x0c[esi] 
		RDMSR
		mov		0x00[esi],eax
		mov		0x04[esi],ebx
		mov		0x08[esi],ecx
		mov		0x0c[esi],edx
		popad
	}
	return _API_se_OK;
}

int OS_Write_MSR(_API_ASM_REGS_Struct * _API_ASM_REGS)
{
	_asm{
		.686
		pushad
		mov		esi,_API_ASM_REGS
		mov		eax,0x00[esi] 
		mov		ebx,0x04[esi] 
		mov		ecx,0x08[esi] 
		mov		edx,0x0c[esi] 
		WRMSR
		popad
	}
	return _API_se_OK;
}
