Note: Dump PNPBIOS interface source code

Compiler: Open Watcom 1.9, 16bit real mode
Test on FreeDOS/XP command box

/*
	Device Identifier Reference Table & Device Type Code Table
	(http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/devids.txt)
*/
#include <stdio.h>
#include <i86.h>

typedef unsigned char	byte;
typedef unsigned int	word;
typedef unsigned long	dword;
typedef unsigned char	u8;
typedef unsigned int	u16;
typedef unsigned long	u32;

#define F_SEGMENT	(0xF000)

#pragma pack (push, 1)
typedef struct _PNPHEADER_ {
	u8	sign[4];
	u8	ver;
	u8	len;
	u16	ctrl;
	u8	chksum;
	u32	eaddr;
	u16	rfp_off;
	u16	rfp_seg;
	u16	pfp_off;
	u32	pfp_seg;
	u32	oem;
	u16	rdp_seg;
	u32	pdp_seg;
} PNPHEADER;

typedef struct _DevNode_ {
	u16	size;
	u8	num;
	u8	id[4];
	u8	type[3];
	u16	attr;
} DEVNODE;
#pragma pack (pop)

int FindPnPBIOS(u16* offset)
{
	dword far* ptr = (dword far*) MK_FP(F_SEGMENT, 0x0);
	const dword sign= 0x506e5024; // 'P'. 'n', 'P', '$'

	do
	{
		//if (('$' == ptr[0]) && ( 'P' == ptr[1]) &&
		//	('n' == ptr[2]) && ( 'P' == ptr[3]))
		if (sign == *ptr)
		{
			u8 far* tp = (u8 far*)ptr;
			u8 chksum = 0;
			u8 len = *(ptr+5);

			while(len--)
			{
				chksum += *tp;
			};

			if (0 == chksum)
			{
				*offset = FP_OFF(ptr);
				return 1;
			}
		}
		ptr += 4;
	} while (FP_OFF(ptr) != 0);

	*offset = 0;
	return 0;
}

void ShowPNPBIOS(u16 offset)
{
	PNPHEADER far* pnpheader;

	printf("Found PnPBIOS interface at F000:%04X\n", offset);
	pnpheader = (PNPHEADER far*) MK_FP(F_SEGMENT, offset);
	printf("Interface structure\n");
	printf("  Version: 0x%02X\n", pnpheader->ver);
	printf("  Length: 0x%02X\n", pnpheader->len);
	printf("  Checksum: 0x%02X\n", pnpheader->chksum);
	printf("  Entry point for Real mode at %04X:%04X\n", pnpheader->rfp_seg, pnpheader->rfp_off);
	printf("  OEM Device Identifier: %04X%04X\n", (pnpheader->oem>>16), (pnpheader->oem & 0xFFFF));
	printf("  BiosSelector(real mode date segment): %04X\n", pnpheader->rdp_seg);
}

typedef int far (*PNPEntry)(u16 fn, ...);

static PNPEntry gpFn;
static int gBiosSelector;

void initPnPFunc(u16 offset)
{
	PNPHEADER far* ph;
	ph = (PNPHEADER far*)MK_FP(F_SEGMENT, offset);
	gpFn = MK_FP(ph->rfp_seg, ph->rfp_off);
	gBiosSelector = ph->rdp_seg;
}

int PnPgetNodeNum(u8 far* numNodes, u16 far* Nodesize)
{
	static const u16 NFunc = 0;
	return gpFn(NFunc, numNodes, Nodesize, gBiosSelector);
}

int PnPgetSystemNode(u8 far *NodeNum, u8 far* nodeBuff)
{
	static const u16 NFunc = 1;
	static const u16 ctrl = 0x01;
	return gpFn(NFunc, NodeNum, nodeBuff, ctrl, gBiosSelector);
}

inline u8 ToHex(u8 n)
{
	if (n >= 10)
		return n - 10 + 'A';

	return n + '0';
}

inline u8 UpperChar(u8 c)
{
	if ((c >= 'a') && (c <= 'z'))
	{
		c -= 'a';
		c += 'A';
	}

	return c;
}

void de_eisaid (u8 far* id)
{
	u8 Manu[8];

	Manu[0] = id[0] >> 2;
	Manu[1] = id[1] >> 5;
	Manu[1] += id[0] << 3;
	Manu[2] = id[1] & 0x1F;
	Manu[3] = id[2] >> 4;
	Manu[4] = id[2] & 0xF;
	Manu[5] = id[3] >> 4;
	Manu[6] = id[3] & 0xF;

	Manu[0] += 0x40;
	Manu[1] += 0x40;
	Manu[2] += 0x40;
	Manu[0] = UpperChar(Manu[0]);
	Manu[1] = UpperChar(Manu[1]);
	Manu[2] = UpperChar(Manu[2]);
	Manu[3] = ToHex(Manu[3]);
	Manu[4] = ToHex(Manu[4]);
	Manu[5] = ToHex(Manu[5]);
	Manu[6] = ToHex(Manu[6]);
	Manu[7] = 0;

	printf("%s\n", Manu);
}

void dumpDevNode(void)
{
	u8 far Buff[1024];
	u8 far NodeNum;
	DEVNODE far * pdn;
	NodeNum = 0;

	do {
		u8 t = NodeNum;

		if (0 == PnPgetSystemNode(&NodeNum, Buff))
		{
			pdn = (DEVNODE far*)Buff;
			printf(" Node# 0x%02X, EISA ID:", t);
			de_eisaid(pdn->id);
		}
	} while(0xFF != NodeNum);
}

int main(void)
{
	u16 offset;
	u8 far numNodes;
	u16 far Nodesize;

	printf("PnP Interface Information by Kun-Yi\n");
	printf("Reference PnPBIOS 1.0a Specification\n\n");

	if (!FindPnPBIOS(&offset))
	{
		printf("Not Found PNPBIOS interface\n");
		return 0;
	}
	ShowPNPBIOS(offset);
	initPnPFunc(offset);

	if (0 != PnPgetNodeNum(&numNodes, &Nodesize))
	{
		printf("PnP to get Node number failed!\n");
		return -1;
	}
	printf("PnP node count = %d, size = %d\n", numNodes, Nodesize);

	dumpDevNode();
	return 0;
}

廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

%d 位部落客按了讚: