#include <stdio.h>
#include <bios.h>

typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;

#define F92STATE 	0
#define F92BKGD	1
#define I10TIMER	2
#define I08STATE 	3

struct f92buf
{
	int snum;
	uint xmsh;
	long xmso;
	long xmss;
	long rate;
	uint chan;
	uint comp;
	uint dsiz;
	char name[16];
};

struct f92state
{
	uint pasdmaoff;
	uint pasdmaseg;
	uint pasdmasize;
	uint pasdmadivs;
	uint pasdivsize;
	uint sbdmaoff;
	uint sbdmaseg;
	uint sbdmasize;
	uint sbdmadivs;
	uint sbdivsize;
	uint ourdmaoff;
	uint ourdmaseg;
	uint ourdmasize;
	uint ourdmadivs;
	uint ourdivsize;
	struct f92buf recbuf;
	struct f92buf playbuf[256];
};

struct xmsmove
{
	long msiz;
	uint srch;
	long srco;
	uint trgh;
	long trgo;
};

struct f92bkgd
{
	struct xmsmove xmsm;

	uint f92buf;
	long byteleft;
	uint xmsh;
	long xmso;
	uint blocks;
	uint statflag;

	uint pasf92buf;
	long pasbyteleft;
	uint pasxmsh;
	long pasxmso;
	uint pasblocks;
	uint passtatflag;

	uint sbf92buf;
	long sbbyteleft;
	uint sbxmsh;
	long sbxmso;
	uint sbblocks;
	uint sbstatflag;

	uint sem;
	uint savess;
	uint savesp;

	uint functable;
	uint cardmask;
	uint pasfunctable[8];
	uint sbfunctable[8];

	char stackdata[];
};

struct i10timer
{
	uint control;
	uint noacttime;
	uint noactnokey;
	uint noactkeys;
	uint randomtime;
	uint randomval;
	uint randomsnd;
	uint randommin;
	uint randommax;

	char timercontrol[64/ 8];
	long timertime[64];
	long timerval[64];
	void (far *timerfunc[64])();
	long timerreset[64];
};

struct i08state
{
	uint keys;
	uint nokey;
	uint keytime;
	uint saving;
};

char *syntax= "Syntax: wpcmcom [-bXXX]\n";
char *pcmcom= "Requires that \"pcm.com\" or \"pcmfun.com\" be loaded.\n";
char *pcmnot= "error: no pcm driver is loaded.\n";
char *copyright= "wpcmcom - v(1.0) - Copyright Media Vision, Inc. 1992\n";
char *programmer= "Bart Crane";

main(int argc, char **argv)
{
	unsigned int boardaddress= 0;
	unsigned int pcmstatus;

	struct f92bkgd far *f92bkgd;
	struct f92state far *f92state;
	struct i10timer far *i10timer;
	struct i08state far *i08state;

	if (argv[1][0] == '-' && argv[1][1] == 'b')
		{
		char *b= &argv[1][2];

		while (isxdigit(*b))
			{
			boardaddress*= 16;
			if (*b >= '0' && *b <= '9') boardaddress+= *b- '0';
			else
			if (*b >= 'A' && *b <= 'F') boardaddress+= *b- 'A'+ 10;
			else
			if (*b >= 'a' && *b <= 'f') boardaddress+= *b- 'a'+ 10;
			b++;
			}

			{
			int i= 1;

			while (i < argc- 1)
				{
				argv[i]= argv[i+ 1];
				i++;
				}
			argv[i]= NULL;
			}

		boardaddress<<= 4;
		}

	if (!checkforsig(boardaddress))
		{
		fprintf(stderr, pcmnot);
		return(2);
		}


		{
		_asm
			{
			push si

			mov al, 0
			mov si, 8018h
			int 94h
			mov word ptr f92state[0], ax
			mov word ptr f92state[2], dx

			mov al, 1
			mov si, 8018h
			int 94h
			mov word ptr f92bkgd[0], ax
			mov word ptr f92bkgd[2], dx

			mov al, 2
			mov si, 8018h
			int 94h
			mov word ptr i10timer[0], ax
			mov word ptr i10timer[2], dx

			mov al, 3
			mov si, 8018h
			int 94h
			mov word ptr i08state[0], ax
			mov word ptr i08state[2], dx

			pop si
			}
		}

	printf("%c[2J", 0x1B);
	again:
	printf("%c[H", 0x1B);

	if (f92state->recbuf.snum)
		{
		printf("%c[K", 0x1B);
		printf("%4d REC %4X - %7ld - %7ld - %6ld/%1d/%1d/%1d - %16s\n", f92state->recbuf.snum,
			f92state->recbuf.xmsh, f92state->recbuf.xmso, f92state->recbuf.xmss,
			f92state->recbuf.rate, f92state->recbuf.chan, f92state->recbuf.comp, f92state->recbuf.dsiz,
			f92state->recbuf.name);
		}

		{
		int i;

		for (i= 0; i < 64; i++)
			{
			if (f92state->playbuf[i].snum)
				{
				printf("%c[K", 0x1B);
				printf("%4d %3s %4X - %7ld - %7ld - %6ld/%1d/%1d/%1d - %16s\n", i, f92state->playbuf[i].snum& 0x4000 ? "SB" : "PAS",
					f92state->playbuf[i].xmsh, f92state->playbuf[i].xmso, f92state->playbuf[i].xmss,
					f92state->playbuf[i].rate, f92state->playbuf[i].chan, f92state->playbuf[i].comp, f92state->playbuf[i].dsiz,
					f92state->playbuf[i].name);
				}
			}
		}

	printf("%c[K", 0x1B);
	printf("Background Operations: %4X\n", i10timer->control);
	printf("%c[K", 0x1B);
	printf("Control-G intercept:     ");
		printf("%3s\n", i10timer->control& 0x01 ? "On" : "Off");
	printf("%c[K", 0x1B);
	printf("Double-Shift Key Detect: ");
		printf("%3s\n", i10timer->control& 0x02 ? "On" : "Off");
	printf("%c[K", 0x1B);
	printf("Random Sounds:           ");
		printf("%3s %5u/%5u/%5u/%5u/%5u\n", i10timer->control& 0x04 ? "On" : "Off", 
			i10timer->randomtime, i10timer->randomval, i10timer->randomsnd, i10timer->randommin, i10timer->randommax);
	printf("%c[K", 0x1B);
	printf("No-Activity Detections:  ");
		printf("%3s %5u/%5u/%5u\n", i10timer->control& 0x08 ? "On" : "Off", 
			i10timer->noacttime, i10timer->noactnokey, i10timer->noactkeys);

	printf("%c[K", 0x1B);
	printf("Timer Controls:\n");
		{
		int i;
		int timer;
		for (i= 0, timer= 0; i < 8 && timer < 64; i++)
			{
			int mask;
			for (mask= 0x01; mask& 0xFF; mask<<= 1, timer++)
				if (i10timer->timercontrol[i]& mask || i10timer->timerval[timer] || i10timer->timertime[timer])
					{
					printf("%c[K", 0x1B);
					printf("%4d %3s %7ld - %7ld - %7d - %Fp\n", timer, i10timer->timercontrol[i]& mask ? "On" : "Off", i10timer->timertime[timer], i10timer->timerval[timer], i10timer->timerreset[timer], i10timer->timerfunc[timer]);
					}
			}
		}

	printf("%c[K", 0x1B);
	printf("Background Status:\n");
	printf("%c[K", 0x1B);
	printf("PAS DMA: %4X:%04X - %4u*16B / %2u : %u\n",
		f92state->pasdmaseg, f92state->pasdmaoff, f92state->pasdmasize, f92state->pasdmadivs, f92state->pasdivsize);

	printf("%c[K", 0x1B);
	printf("SB  DMA: %4X:%04X - %4u*16B / %2u : %u\n",
		f92state->sbdmaseg, f92state->sbdmaoff, f92state->sbdmasize, f92state->sbdmadivs, f92state->sbdivsize);

	printf("%c[K", 0x1B);
	printf("CUR DMA: %4X:%04X - %4u*16B / %2u : %u\n",
		f92state->ourdmaseg, f92state->ourdmaoff, f92state->ourdmasize, f92state->ourdmadivs, f92state->ourdivsize);

	printf("%c[K", 0x1B);
	printf("Current     F92Buf: %4X - %7ld - %4X - %7ld - %4u - %3u\n", f92bkgd->f92buf,
		f92bkgd->byteleft, f92bkgd->xmsh, f92bkgd->xmso, f92bkgd->blocks, f92bkgd->statflag);

	printf("%c[K", 0x1B);
	printf("Current PAS F92Buf: %4X - %7ld - %4X - %7ld - %4u - %3u\n", f92bkgd->pasf92buf,
		f92bkgd->pasbyteleft, f92bkgd->pasxmsh, f92bkgd->pasxmso, f92bkgd->pasblocks, f92bkgd->passtatflag);

	printf("%c[K", 0x1B);
	printf("Current SB  F92Buf: %4X - %7ld - %4X - %7ld - %4u - %3u\n", f92bkgd->sbf92buf,
		f92bkgd->sbbyteleft, f92bkgd->sbxmsh, f92bkgd->sbxmso, f92bkgd->sbblocks, f92bkgd->sbstatflag);

	printf("%c[K", 0x1B);
	printf("Status Flags - PAS: %4u    SB: %4u   CUR: %4u\n", f92bkgd->passtatflag, f92bkgd->sbstatflag, f92bkgd->statflag);
	printf("%c[K", 0x1B);
	printf("Semaphore: %4X   Saved Stack Pointer: %4X:%04X   Function Table: %4X\n", f92bkgd->sem, f92bkgd->savess, f92bkgd->savesp, f92bkgd->functable);

	printf("%c[K", 0x1B);
	printf("XMSMove:   %7ld - %4X - %Fp / %4X - %Fp\n", f92bkgd->xmsm.msiz,
		f92bkgd->xmsm.srch, f92bkgd->xmsm.srco, f92bkgd->xmsm.trgh, f92bkgd->xmsm.trgo);

	if (!_bios_keybrd(_KEYBRD_READY))
		goto again;

	return(0);
}

checkforsig(int boardaddress)
{
	int status;
	int int94isthere= 0;

	_asm
		{
		mov al, 94h
		mov ah, 35h					; GETDOSVECTOR
		int 21h

		mov ax, es
		or ax, bx
		mov int94isthere, ax

		mov bx, 107h				; offset f_sig in segment holding int 94h

		mov ax, es:[bx][0]
		xor ax, 4350h				; 'CP'
		jnz nodriver

		mov ax, es:[bx][2]
		xor ax, 2D4dh				; '-M'
		jnz nodriver

		mov ax, es:[bx][4]
		xor ax, 4853h				; 'HS'
		jnz nodriver

		mov ax, es:[bx][6]
		xor ax, 5241h				; 'RA'
		jnz nodriver

		mov ax, es:[bx][8]
		xor al, 4Bh					; 'K'
		jnz nodriver

		cbw							; ax= 0

		cmp boardaddress, 0		; board specified?
		jz nodriver				

		cmp int94isthere, 0		; 
		jz nodriver
		
		push si
		mov si, 8002h
		or si, boardaddress
		int 94h
		pop si
		or ax, ax					; ax= 0 if not at address, !0 if is
		mov ax, 0					; ax= 0
		jnz nodriver				; ax= 0 if driver
		dec ax						; ax= !0 if nodriver

		nodriver:					

		mov status, ax				; ax= !0 if nodriver, 0 if driver
		}

	return(!status);				// status= 0 if nodriver, !0 if driver
}


