#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <dos.h>
#include "vesa.h"

// Описание функций
int	main( int argc, char * argv[] );
int	GetBaseVESAInfo(FILE*);
int	AnalyseResult(union REGS);

// Главная функция
int main( int argc, char * argv[] )
{
	FILE	*fileVesaReport;
	int   iResult;

	// Проверка командной строки программы
	if( argc != 2 )
	{
		printf("\nФормат вызова: VESATEST <имя файла>"
			 "\n  <имя файла>: имя файла, в который будет записана информация");

		return -1;
	}

	// Открываем файл
	fileVesaReport = fopen(argv[1], "w+");

	// Записываем в файл fileVesaReport информацию о VBE и видеоадаптере
	iResult = GetBaseVESAInfo(fileVesaReport);

	// Закрываем файл
	fclose(fileVesaReport);

	return ((iResult==0) ? 0 : -1);
}

//=================================================
// Функция GetBaseVESAInfo
//=================================================
int
GetBaseVESAInfo(FILE *file)
{
	union REGS regs;
	struct SREGS segregs;
	int	iResult, i;

	// Структуры для получения информации о VBE
	VESAINFO			vesaInfo;
	VESAMODEINFO	modeInfo;

	// Подготавливаем буфер для VBE версии 2.0
	strcpy( vesaInfo.cSignature, "VBE2" );

	// Получаем данные о реализации VBE и видеоадаптере
	regs.h.ah = 0x4f;
	regs.h.al = 0x00;
	segregs.es = FP_SEG((void far *)&vesaInfo);
	regs.x.di = FP_OFF((void far *)&vesaInfo);
	int86x(0x10, &regs, &regs, &segregs);

	// Проверяем результат вызова функции VBE
	iResult = AnalyseResult(regs);
	if(iResult != 0) return -1;

	// Записываем в файл информацию из структуры vesaInfo
	fprintf(file, "Сигнатура: '%4.4s' \n", vesaInfo.cSignature );
	fprintf(file, "Информация фирмы производителя: '%s'\n", vesaInfo.fpInfoOEM );

	fprintf(file, "Версия VBE: %Xh \n", vesaInfo.usVersion);

	fprintf(file, "Возможности видеоадаптера: '%x%x%x%x' \n",
		vesaInfo.ucCapabilities[0], vesaInfo.ucCapabilities[1],
		vesaInfo.ucCapabilities[2], vesaInfo.ucCapabilities[3]);

	fprintf(file, "Поддерживаются следующие режимы VESA: \n");

	 for( i=0; i<50; i++ )	 {
		if(vesaInfo.fpModeTable[i] == 0xFFFF)	break;
		fprintf(file,  "   %Xh \n", vesaInfo.fpModeTable[i] );
	 }

	// Объем видеопамяти определяется VBE версии не младше 1.2
	if( vesaInfo.usVersion >= 0x102 )
		fprintf(file,  "Объем видеопамяти %d Кбайт\n", vesaInfo.usTotalMemory * 64);

	// Следующая информация доступна только для VBE версии 2.0 и старше
	if( vesaInfo.usVersion >= 0x200 )
	{
		fprintf(file,  "Дополнительный номер версии VBE: %04Xh\n",
			vesaInfo.usRevVersion);
		fprintf(file, "Дополнительный номер версии видеоадаптера: '%s'\n",
			vesaInfo.fpOEMRevVersion);
		fprintf(file, "Имя фирмы разработчика: '%s'\n", vesaInfo.fpOEMName);
		fprintf(file, "Название видеоадаптера: '%s'\n", vesaInfo.fpOEMProductName);
	}

	// Теперь получаем информацию для каждого доступного режима VESA
	for( i=0; i<50; i++ )	 {

		// Получаем очередной номер режима VESA
		if(vesaInfo.fpModeTable[i] == 0xFFFF)	break;
		fprintf(file,  "\n\nРежим %Xh \n", vesaInfo.fpModeTable[i] );

		// Получаем информацию о режиме vesaInfo.fpModeTable[i]
		regs.h.ah = 0x4f;
		regs.h.al = 0x01;
		regs.x.cx = vesaInfo.fpModeTable[i];
		segregs.es = FP_SEG((void far *)&modeInfo);
		regs.x.di = FP_OFF((void far *)&modeInfo);
		int86x(0x10, &regs, &regs, &segregs);

		// Проверяем результат вызова функции VBE
		iResult = AnalyseResult(regs);
		if(iResult != 0) return -1;

		// Записываем в файл информацию из структуры modeInfo
		fprintf(file, "Атрибуты режима: %04Xh \n", modeInfo.usModeAttr);
		fprintf(file, "Атрибуты окна: A %02Xh \n", modeInfo.ucWinAAttr);
		fprintf(file, "Атрибуты окна: B %02Xh \n", modeInfo.ucWinBAttr);
		fprintf(file, "Шаг позиционирования окна: %d Кбайт \n", modeInfo.usWinGranularity);
		fprintf(file, "Размер окна, Кбайт: %d  \n", modeInfo.usWinSize );
		fprintf(file, "Начало сегмента окна A: %04Xh \n", modeInfo.usBegSegA );
		fprintf(file, "Начало сегмента окна B: %04Xh \n", modeInfo.usBegSegB );
		fprintf(file, "Функция перемещения окна: %p \n", modeInfo.fpWinFunc );
		fprintf(file, "Количество байт на линию сканирования: %d \n",
			modeInfo.usBytesPerScanLine );

		// Объем видеопамяти определяется VBE версии не младше 1.2
//		if(vesaInfo.usVersion >= 0x102)
		if(1)
		{
			fprintf(file,  "Разрешение по горизонтали: %d \n", modeInfo.usSizeX);
			fprintf(file,  "Разрешение по вертикали: %d \n", modeInfo.usSizeY);
			fprintf(file,  "Ширина символа:  %02Xh \n", modeInfo.ucCharSizeX);
			fprintf(file,  "Высота символа: %02Xh \n", modeInfo.ucCharSizeY);
			fprintf(file,  "Количество слоев видеопамяти: %02Xh \n", modeInfo.ucNumPlanes);
			fprintf(file,  "Количество бит на пиксел: %02Xh \n", modeInfo.ucNumPixelBits);
			fprintf(file,  "Количество банков памяти: %02Xh \n", modeInfo.ucBanksNum);
			fprintf(file,  "Тип модели памяти: %02Xh \n", modeInfo.ucTypeMemModel);
			fprintf(file,  "Размер банка памяти: %02Xh \n", modeInfo.ucBankSize);

			fprintf(file,  "Количество доступных страниц видеопамяти: %02Xh \n",
				modeInfo.ucPageNum);

			fprintf(file,  "Размер поля красного компоненты цвета: %02Xh \n",
				modeInfo.ucRedSize);
			fprintf(file,  "Положение красного поля: %02Xh \n",
				modeInfo.ucRedField);
			fprintf(file,  "Размер поля зеленой компоненты цвета пикселов: %02Xh \n",
				modeInfo.ucGreenSize);
			fprintf(file,  "Положение зеленого поля: %02Xh \n",
				modeInfo.ucGreenField);
			fprintf(file,  "Размер поля синей компоненты цвета пикселов: %02Xh \n",
				modeInfo.ucBlueSize);
			fprintf(file,  "Положение синего поля: %02Xh \n",
				modeInfo.ucBlueField);
			fprintf(file,  "Размер резервной области: %02Xh \n",
				modeInfo.ucResSize);
			fprintf(file,  "Положение резервного поля: %02Xh \n",
				modeInfo.ucResField);
			fprintf(file,  "Режим ЦАП: %02X\n", modeInfo.ucDACInfo);
		}
	}
	return iResult;
}


//=================================================
// Функция AnalyseResult
//=================================================
int
AnalyseResult(union REGS regs)
{
	int	iResult;

	if((regs.h.al == 0x4f) && (regs.h.ah == 0))
		iResult = 0;
	else if(regs.h.al != 0x4f)
		iResult = -1;
	else
		iResult = 1;

	return iResult;
}
