/* 'whoisit.c' K.Saito Sep.2.1989
		Editor K.Kono Mar.7.1996
   reports system configuration and BIOS data */

#include <stdio.h>
#include <dos.h>

#define SYSTEM_SERVICE 0x15
#define SYSTEM_CONFIG 0xc0

union REGS inregs, outregs;
struct SREGS segregs;

int inspection(unsigned char far *ptr);
int understandable(unsigned char far *ptr);
int disp_date();

int main(void)
{
	unsigned char far *ptr; /* HEXﾊﾞｲﾄ表示のため符号なし */
	unsigned char far *model_byte = (char far *) 0xf000ffel; /* farﾎﾟｲﾝﾀによって特定ｱﾄﾞﾚｽを指定 */

	inregs.h.ah = SYSTEM_CONFIG;
	int86x(SYSTEM_SERVICE, &inregs, &outregs, &segregs); /* BIOSｺｰﾙ */
	if(outregs.x.cflag)
		switch(outregs.h.ah){
			case 0x80:
				switch(*model_byte){
					case 0xff:
						printf("\nIBM PC");
						disp_date();
						break;
					case 0xfd:
						printf("\nIBM PCjr");
						disp_date();
						break;
					default:
						printf("\nUNKNOWN");
				}
				break;
			case 0x86:
				switch(*model_byte){
					case 0xfe:
						printf("\nIBM PC XT");
						disp_date();
						break;
					case 0xfc:
						printf("\nIBM PC AT");
						disp_date();
						break;
					default:
						printf("\nUNKNOWN");
				}
				break;
			default:
				printf("\nUNKNOWN !");
		}
	else
		if(outregs.h.ah)
			printf("\nUNKNOWN !");
		else{
			ptr = (char far *)((unsigned long)segregs.es << 16 | (unsigned)outregs.x.bx); /* es, bxを連結して32ﾋﾞｯﾄのfarｱﾄﾞﾚｽを生成 */
			inspection(ptr);
			printf("\nSystem descriptors [%p]", ptr);
			printf("\n  Model: %02Xh", *(ptr+2));
			printf("\n  Submodel: %02Xh", *(ptr+3));
			printf("\n  BIOS revision: %02Xh", *(ptr+4));
			printf("\n  Feature information: %02Xh", *(ptr+5));
			understandable(ptr+5);
			disp_date();
		}
	printf("\n\n");
	return 0;
}

int inspection(ptr)
unsigned char far *ptr;
{
	printf("\nProduct: "); /* 機種を判定する関数 */
	switch(*(ptr+2)){
		case 0xfc:
			switch(*(ptr+3)){
				case 0:
				case 1:
					printf("PC AT");
					break;
				case 2:
					printf("PC XT 286");
					break;
				case 4:
					printf("PS/2 Model 50");
					break;
				case 5:
					printf("PS/2 Model 60");
					break;
				case 9:
					printf("PS/2 Model 30 286");
					break;
				default:
					printf("May be PC AT compatible");
			}
			break;
		case 0xfb:
			printf("PC XT");
			break;
		case 0xfa:
			printf("PS/2 Model 30");
			break;
		case 0xf9:
			printf("PC Convertible");
			break;
		case 0xf8:
			printf("PS/2 Model 80");
			break;
		default:
			printf("May be PC or PS/2 Compatible");
	}
	return 0;
}

int understandable(ptr)
unsigned char far *ptr; /* 各機種ごとに違う特徴を判定して表示する関数(85年以降) */
{
	if(*ptr & 0x80) printf("\n\tFixed disk BIOS uses DMA ch3");
	else printf("\n\tDMA channel 3 used by fixed disk");

	printf("\n\t2nd interrupt chip ");
	if(*ptr & 0x40) printf("present");
	else printf("not present");

	printf("\n\tReal time clock ");
	if(*ptr & 0x20) printf("present");
	else printf("not present");

	printf("\n\tKeyboard intercept sequence ");
	if(*ptr & 0x10) printf("called in keyboard interrupt");
	else printf("not called");

	printf("\n\tWait for external event ");
	if(*ptr & 0x8) printf("supported");
	else printf("not supported");

	printf("\n\tExtened BIOS data area is ");
	if(*ptr & 0x4) printf("allocated");
	else printf("not allocated");

	if(*ptr & 0x2) printf("\n\tMicro channel");
	else printf("\n\tPC type I/O channel");

	return 0;
}

int disp_date() /* BIOS日付を表示する関数 */
{
	int n;
	unsigned char far *bios_date = (char far *) 0xf000fff5l;

	printf("\nBIOS dated: ");
	for(n=0;n<8;n++){
		printf("%c", *bios_date);
		*bios_date++;
	}
	return 0;
}
