commit 77735c3ff0772609e9c8d29e3ce2ab42ff54d20b
parent 73424b6129f1c3ca9fc22aedcfe1f5330db137a9
Author: Travis Bradshaw <travis.bradshaw@idsoftware.com>
Date:   Tue, 31 Jan 2012 15:57:38 -0600
The source for the DOOM serial / model driver.
Diffstat:
8 files changed, 1443 insertions(+), 0 deletions(-)
diff --git a/sersrc/DOOMNET.C b/sersrc/DOOMNET.C
@@ -0,0 +1,126 @@
+#include <stdio.h>
+#include <io.h>
+#include <stdlib.h>
+#include <string.h>
+#include <process.h>
+#include <dos.h>
+#include "doomnet.h"
+
+//#include "serstr.h"
+#include "ser_frch.h"		// FRENCH VERSION
+
+#define DOOM2
+
+extern	int	myargc;
+extern	char **myargv;
+
+doomcom_t	doomcom;
+int			vectorishooked;
+void interrupt (*olddoomvect) (void);
+
+
+
+/*
+=================
+=
+= CheckParm
+=
+= Checks for the given parameter in the program's command line arguments
+=
+= Returns the argument number (1 to argc-1) or 0 if not present
+=
+=================
+*/
+
+int CheckParm (char *check)
+{
+	int             i;
+
+	for (i = 1;i<myargc;i++)
+		if ( !stricmp(check,myargv[i]) )
+			return i;
+
+	return 0;
+}
+
+
+/*
+=============
+=
+= LaunchDOOM
+=
+These fields in doomcom should be filled in before calling:
+
+	short	numnodes;		// console is allways node 0
+	short	ticdup;			// 1 = no duplication, 2-5 = dup for slow nets
+	short	extratics;		// 1 = send a backup tic in every packet
+
+	short	consoleplayer;	// 0-3 = player number
+	short	numplayers;		// 1-4
+	short	angleoffset;	// 1 = left, 0 = center, -1 = right
+	short	drone;			// 1 = drone
+=============
+*/
+
+void LaunchDOOM (void)
+{
+	char	*newargs[99];
+	char	adrstring[10];
+	long  	flatadr;
+	int		p;
+	unsigned char	far	*vector;
+
+// prepare for DOOM
+	doomcom.id = DOOMCOM_ID;
+
+// hook an interrupt vector
+	p= CheckParm ("-vector");
+
+	if (p)
+	{
+		doomcom.intnum = sscanf ("0x%x",_argv[p+1]);
+	}
+	else
+	{
+		for (doomcom.intnum = 0x60 ; doomcom.intnum <= 0x66 ; doomcom.intnum++)
+		{
+			vector = *(char far * far *)(doomcom.intnum*4);
+			if ( !vector || *vector == 0xcf )
+				break;
+		}
+		if (doomcom.intnum == 0x67)
+		{
+			printf (STR_WARNING);
+			doomcom.intnum = 0x66;
+		}
+	}
+	printf (STR_COMM"\n",doomcom.intnum);
+
+	olddoomvect = getvect (doomcom.intnum);
+	setvect (doomcom.intnum,NetISR);
+	vectorishooked = 1;
+
+// build the argument list for DOOM, adding a -net &doomcom
+	memcpy (newargs, myargv, (myargc+1)*2);
+	newargs[myargc] = "-net";
+	flatadr = (long)_DS*16 + (unsigned)&doomcom;
+	sprintf (adrstring,"%lu",flatadr);
+	newargs[myargc+1] = adrstring;
+	newargs[myargc+2] = NULL;
+
+//	spawnv  (P_WAIT, "m:\\newdoom\\doom", newargs);
+	if (!access("doom2.exe",0))
+		spawnv  (P_WAIT, "doom2", newargs);
+	else
+		spawnv  (P_WAIT, "doom", newargs);
+
+	#ifdef DOOM2
+	printf (STR_RETURNED"\n");
+	#else
+	printf ("Returned from DOOM\n");
+	#endif
+
+
+}
+
+
diff --git a/sersrc/DOOMNET.H b/sersrc/DOOMNET.H
@@ -0,0 +1,60 @@
+// doomnet.h
+
+
+#define PEL_WRITE_ADR   0x3c8
+#define PEL_DATA        0x3c9
+
+#define I_ColorBlack(r,g,b) {outp(PEL_WRITE_ADR,0);outp(PEL_DATA,r);outp(PEL_DATA,g);outp(PEL_DATA,b);};
+
+
+
+
+#define	MAXNETNODES		8			// max computers in a game
+#define	MAXPLAYERS		4			// 4 players max + drones
+
+
+#define	CMD_SEND	1
+#define	CMD_GET		2
+
+#define	DOOMCOM_ID		0x12345678l
+
+typedef struct
+{
+	long	id;
+	short	intnum;			// DOOM executes an int to send commands
+
+// communication between DOOM and the driver
+	short	command;		// CMD_SEND or CMD_GET
+	short	remotenode;		// dest for send, set by get (-1 = no packet)
+	short	datalength;		// bytes in doomdata to be sent / bytes read
+
+// info common to all nodes
+	short	numnodes;		// console is allways node 0
+	short	ticdup;			// 1 = no duplication, 2-5 = dup for slow nets
+	short	extratics;		// 1 = send a backup tic in every packet
+	short	deathmatch;		// 1 = deathmatch
+	short	savegame;		// -1 = new game, 0-5 = load savegame
+	short	episode;		// 1-3
+	short	map;			// 1-9
+	short	skill;			// 1-5
+
+// info specific to this node
+	short	consoleplayer;	// 0-3 = player number
+	short	numplayers;		// 1-4
+	short	angleoffset;	// 1 = left, 0 = center, -1 = right
+	short	drone;			// 1 = drone
+
+// packet data to be sent
+	char	data[512];
+} doomcom_t;
+
+
+
+extern	doomcom_t	doomcom;
+extern	void interrupt (*olddoomvect) (void);
+extern	int			vectorishooked;
+
+int CheckParm (char *check);
+void LaunchDOOM (void);
+void interrupt NetISR (void);
+
diff --git a/sersrc/PORT.C b/sersrc/PORT.C
@@ -0,0 +1,428 @@
+// port.c
+
+#include "doomnet.h"
+#include "sersetup.h"
+//#include "serstr.h"
+#include "ser_frch.h"		// FRENCH VERSION
+
+
+void jump_start( void );
+
+void interrupt isr_8250 (void);
+void interrupt isr_16550 (void);
+
+union	REGS	regs;
+struct	SREGS	sregs;
+
+que_t		inque, outque;
+
+
+int			uart;			// io address
+enum {UART_8250, UART_16550} uart_type;
+int			irq;
+
+int			modem_status = -1;
+int			line_status = -1;
+
+void interrupt (*oldirqvect) (void);
+int			irqintnum;
+
+int	   		comport;
+
+int			baudbits;
+
+
+/*
+==============
+=
+= GetUart
+=
+==============
+*/
+
+void GetUart (void)
+{
+	char   far *system_data;
+	static int ISA_uarts[] = {0x3f8,0x2f8,0x3e8,0x2e8};
+	static int ISA_IRQs[] = {4,3,4,3};
+	static int MCA_uarts[] = {0x03f8,0x02f8,0x3220,0x3228};
+	static int MCA_IRQs[] = {4,3,3,3};
+	int		p;
+
+	if (CheckParm ("-com2"))
+		comport = 2;
+	else if (CheckParm ("-com3"))
+		comport = 3;
+	else if (CheckParm ("-com4"))
+		comport = 4;
+	else
+		comport = 1;
+
+	regs.h.ah = 0xc0;
+	int86x( 0x15, ®s, ®s, &sregs );
+	if ( regs.x.cflag )
+	{
+		irq = ISA_IRQs[ comport-1 ];
+		uart = ISA_uarts[ comport-1 ];
+		return;
+	}
+	system_data = ( char far *) ( ( (long) sregs.es << 16 ) + regs.x.bx );
+	if ( system_data[ 5 ] & 0x02 )
+	{
+		irq = MCA_IRQs[ comport-1 ];
+		uart = MCA_uarts[ comport-1 ];
+	}
+	else
+	{
+		irq = ISA_IRQs[ comport-1 ];
+		uart = ISA_uarts[ comport-1 ];
+	}
+
+	p = CheckParm ("-port");
+	if (p)
+		sscanf (_argv[p+1],"0x%x",&uart);
+	p = CheckParm ("-irq");
+	if (p)
+		sscanf (_argv[p+1],"%i",&irq);
+
+
+	printf (STR_PORTLOOK" 0x%x, irq %i\n",uart,irq);
+}
+
+
+
+
+/*
+===============
+=
+= InitPort
+=
+===============
+*/
+
+void InitPort (void)
+{
+	int mcr;
+	int	temp;
+	int	u;
+
+//
+// find the irq and io address of the port
+//
+	GetUart ();
+
+//
+// disable all uart interrupts
+//
+	OUTPUT( uart + INTERRUPT_ENABLE_REGISTER, 0 );
+
+//
+// init com port settings
+//
+
+	printf (STR_PORTSET"\n",115200l/baudbits);
+
+// set baud rate
+	OUTPUT(uart + LINE_CONTROL_REGISTER, 0x83);
+	OUTPUT(uart, baudbits);
+	OUTPUT(uart + 1, 0);
+
+// set line control register (N81)
+	OUTPUT(uart + LINE_CONTROL_REGISTER, 0x03);
+
+// set modem control register (OUT2+RTS+DTR)
+	OUTPUT( uart + MODEM_CONTROL_REGISTER,8+2+1);
+
+//
+// check for a 16550
+//
+	if (CheckParm("-8250"))
+	// allow a forced 8250
+	{
+		uart_type = UART_8250;
+		printf (STR_UART8250"\n\n");
+	}
+	else
+	{	
+		OUTPUT ( uart + FIFO_CONTROL_REGISTER,
+			FCR_FIFO_ENABLE + FCR_TRIGGER_04 );
+		temp = INPUT( uart + INTERRUPT_ID_REGISTER );
+		if ( ( temp & 0xf8 ) == 0xc0 )
+		{
+			uart_type = UART_16550;
+		}
+		else
+		{
+			uart_type = UART_8250;
+			OUTPUT( uart + FIFO_CONTROL_REGISTER, 0 );
+		}
+	}
+
+//
+// clear out any pending uart events
+//
+	printf (STR_CLEARPEND);
+	for (u=0 ; u<16 ; u++)		// clear an entire 16550 silo
+		INPUT( uart + RECEIVE_BUFFER_REGISTER );
+
+	do
+	{
+		switch( u = INPUT( uart + INTERRUPT_ID_REGISTER ) & 7 )
+		{
+		case IIR_MODEM_STATUS_INTERRUPT :
+			modem_status = INPUT( uart + MODEM_STATUS_REGISTER );
+			break;
+
+		case IIR_LINE_STATUS_INTERRUPT :
+			line_status = INPUT( uart + LINE_STATUS_REGISTER );
+			break;
+
+		case IIR_TX_HOLDING_REGISTER_INTERRUPT :
+			break;
+
+		case IIR_RX_DATA_READY_INTERRUPT :
+			INPUT( uart + RECEIVE_BUFFER_REGISTER );
+			break;
+		}
+	} while (! (u&1) );
+
+
+//
+// hook the irq vector
+//
+	irqintnum = irq + 8;
+
+	oldirqvect = getvect (irqintnum);
+	if (uart_type == UART_16550)
+	{
+		setvect (irqintnum,isr_16550);
+		printf (STR_UART16550"\n\n");
+	}
+	else
+	{
+		setvect (irqintnum,isr_8250);
+		printf (STR_UART8250"\n\n");
+
+	}
+
+
+	OUTPUT( 0x20 + 1, INPUT( 0x20 + 1 ) & ~(1<<irq) );
+
+	CLI();
+
+// enable RX and TX interrupts at the uart
+
+	OUTPUT( uart + INTERRUPT_ENABLE_REGISTER,IER_RX_DATA_READY + IER_TX_HOLDING_REGISTER_EMPTY);
+
+// enable interrupts through the interrupt controller
+
+	OUTPUT( 0x20, 0xc2 );
+
+	STI();
+}
+
+
+/*
+=============
+=
+= ShutdownPort
+=
+=============
+*/
+
+void ShutdownPort ( void )
+{
+	int		u;
+	
+	OUTPUT( uart + INTERRUPT_ENABLE_REGISTER, 0 );
+	OUTPUT( uart + MODEM_CONTROL_REGISTER, 0 );
+
+	for (u=0 ; u<16 ; u++)		// clear an entire 16550 silo
+		INPUT( uart + RECEIVE_BUFFER_REGISTER );
+
+	OUTPUT( 0x20 + 1, INPUT( 0x20 + 1 ) | (1<<irq) );
+
+	setvect (irqintnum,oldirqvect);
+
+//
+// init com port settings to defaults
+//
+	regs.x.ax = 0xf3;		//f3= 9600 n 8 1
+	regs.x.dx = comport - 1;
+	int86 (0x14, ®s, ®s);
+}
+
+
+int read_byte( void )
+{
+	int	c;
+
+	if (inque.tail >= inque.head)
+		return -1;
+	c = inque.data[inque.tail&(QUESIZE-1)];
+	inque.tail++;
+	return c;
+}
+
+
+void write_byte( int c )
+{
+	outque.data[outque.head&(QUESIZE-1)] = c;
+	outque.head++;
+}
+
+
+
+//==========================================================================
+
+
+/*
+==============
+=
+= isr_8250
+=
+==============
+*/
+
+void interrupt isr_8250(void)
+{
+	int c;
+
+	while (1)
+	{
+		switch( INPUT( uart + INTERRUPT_ID_REGISTER ) & 7 )
+		{
+// not enabled
+		case IIR_MODEM_STATUS_INTERRUPT :
+			modem_status = INPUT( uart + MODEM_STATUS_REGISTER );
+			break;
+
+// not enabled
+		case IIR_LINE_STATUS_INTERRUPT :
+			line_status = INPUT( uart + LINE_STATUS_REGISTER );
+			break;
+
+//
+// transmit
+//
+		case IIR_TX_HOLDING_REGISTER_INTERRUPT :
+//I_ColorBlack (63,0,0);
+			if (outque.tail < outque.head)
+			{
+				c = outque.data[outque.tail&(QUESIZE-1)];
+				outque.tail++;
+				OUTPUT( uart + TRANSMIT_HOLDING_REGISTER, c );
+			}
+			break;
+
+//
+// receive
+//
+		case IIR_RX_DATA_READY_INTERRUPT :
+//I_ColorBlack (0,63,0);
+			c = INPUT( uart + RECEIVE_BUFFER_REGISTER );
+			inque.data[inque.head&(QUESIZE-1)] = c;
+			inque.head++;
+			break;
+
+//
+// done
+//
+		default :
+//I_ColorBlack (0,0,0);
+			OUTPUT( 0x20, 0x20 );
+			return;
+		}
+	}
+}
+
+
+/*
+==============
+=
+= isr_16550
+=
+==============
+*/
+
+void interrupt isr_16550(void)
+{
+	int c;
+	int	count;
+
+	while (1)
+	{
+		switch( INPUT( uart + INTERRUPT_ID_REGISTER ) & 7 )
+		{
+// not enabled
+		case IIR_MODEM_STATUS_INTERRUPT :
+			modem_status = INPUT( uart + MODEM_STATUS_REGISTER );
+			break;
+
+// not enabled
+		case IIR_LINE_STATUS_INTERRUPT :
+			line_status = INPUT( uart + LINE_STATUS_REGISTER );
+			break;
+
+//
+// transmit
+//
+		case IIR_TX_HOLDING_REGISTER_INTERRUPT :
+//I_ColorBlack (63,0,0);
+			count = 16;
+			while (outque.tail < outque.head && count--)
+			{
+				c = outque.data[outque.tail&(QUESIZE-1)];
+				outque.tail++;
+				OUTPUT( uart + TRANSMIT_HOLDING_REGISTER, c );
+			}
+			break;
+
+//
+// receive
+//
+		case IIR_RX_DATA_READY_INTERRUPT :
+//I_ColorBlack (0,63,0);
+			do
+			{
+				c = INPUT( uart + RECEIVE_BUFFER_REGISTER );
+				inque.data[inque.head&(QUESIZE-1)] = c;
+				inque.head++;
+			} while (INPUT( uart + LINE_STATUS_REGISTER ) & LSR_DATA_READY );
+
+			break;
+
+//
+// done
+//
+		default :
+//I_ColorBlack (0,0,0);
+			OUTPUT( 0x20, 0x20 );
+			return;
+		}
+	}
+}
+
+
+/*
+===============
+=
+= jump_start
+=
+= Start up the transmition interrupts by sending the first char
+===============
+*/
+
+void jump_start( void )
+{
+	int c;
+
+	if (outque.tail < outque.head)
+	{
+		c = outque.data [outque.tail&(QUESIZE-1)];
+		outque.tail++;
+		OUTPUT( uart, c );
+	}
+}
+
+
diff --git a/sersrc/README.TXT b/sersrc/README.TXT
@@ -0,0 +1 @@
+This is the source for the DOOM serial / modem driver.
diff --git a/sersrc/SERSETUP.C b/sersrc/SERSETUP.C
@@ -0,0 +1,680 @@
+// sersetup.c
+#define DOOM2
+#include "sersetup.h"
+//#include "serstr.h"
+#include "ser_frch.h"		// FRENCH VERSION
+#include "DoomNet.h"
+
+extern	que_t		inque, outque;
+
+void jump_start( void );
+extern int 	uart;
+
+int			usemodem;
+char		startup[256], shutdown[256], baudrate[256];
+
+extern		int baudbits;
+
+void ModemCommand (char *str);
+
+int		myargc;
+char	**myargv;
+
+//======================================
+//
+// I_Error
+//
+//======================================
+void I_Error(char *string)
+{
+	printf("%s\n",string);
+	exit(1);
+}
+
+/*
+================
+=
+= write_buffer
+=
+================
+*/
+
+void write_buffer( char *buffer, unsigned int count )
+{
+	int	i;
+
+// if this would overrun the buffer, throw everything else out
+	if (outque.head-outque.tail+count > QUESIZE)
+		outque.tail = outque.head;
+
+	while (count--)
+		write_byte (*buffer++);
+
+	if ( INPUT( uart + LINE_STATUS_REGISTER ) & 0x40)
+		jump_start();
+}
+
+
+/*
+=================
+=
+= Error
+=
+= For abnormal program terminations
+=
+=================
+*/
+
+void Error (char *error, ...)
+{
+	va_list argptr;
+
+	if (usemodem)
+	{
+		printf ("\n");
+		printf ("\n"STR_DROPDTR"\n");
+
+		OUTPUT(uart+MODEM_CONTROL_REGISTER, INPUT(uart+MODEM_CONTROL_REGISTER)&~MCR_DTR);
+		delay (1250);
+		OUTPUT( uart + MODEM_CONTROL_REGISTER, INPUT( uart + MODEM_CONTROL_REGISTER ) | MCR_DTR );
+		ModemCommand("+++");
+		delay (1250);
+		ModemCommand(shutdown);
+		delay (1250);
+
+	}
+
+	ShutdownPort ();
+
+	if (vectorishooked)
+		setvect (doomcom.intnum,olddoomvect);
+
+	if (error)
+	{
+		va_start (argptr,error);
+		vprintf (error,argptr);
+		va_end (argptr);
+		printf ("\n");
+		exit (1);
+	}
+
+	printf (STR_CLEANEXIT"\n");
+	exit (0);
+}
+
+
+/*
+================
+=
+= ReadPacket
+=
+================
+*/
+
+#define MAXPACKET	512
+#define	FRAMECHAR	0x70
+
+char	packet[MAXPACKET];
+int		packetlen;
+int		inescape;
+int		newpacket;
+
+boolean ReadPacket (void)
+{
+	int	c;
+
+// if the buffer has overflowed, throw everything out
+
+	if (inque.head-inque.tail > QUESIZE - 4)	// check for buffer overflow
+	{
+		inque.tail = inque.head;
+		newpacket = true;
+		return false;
+	}
+
+	if (newpacket)
+	{
+		packetlen = 0;
+		newpacket = 0;
+	}
+
+	do
+	{
+		c = read_byte ();
+		if (c < 0)
+			return false;		// haven't read a complete packet
+//printf ("%c",c);
+		if (inescape)
+		{
+			inescape = false;
+			if (c!=FRAMECHAR)
+			{
+				newpacket = 1;
+				return true;	// got a good packet
+			}
+		}
+		else if (c==FRAMECHAR)
+		{
+			inescape = true;
+			continue;			// don't know yet if it is a terminator
+		}						// or a literal FRAMECHAR
+
+		if (packetlen >= MAXPACKET)
+			continue;			// oversize packet
+		packet[packetlen] = c;
+		packetlen++;
+	} while (1);
+
+}
+
+
+/*
+=============
+=
+= WritePacket
+=
+=============
+*/
+
+
+
+void WritePacket (char *buffer, int len)
+{
+	int		b;
+	char	static localbuffer[MAXPACKET*2+2];
+
+	b = 0;
+	if (len > MAXPACKET)
+		return;
+
+	while (len--)
+	{
+		if (*buffer == FRAMECHAR)
+			localbuffer[b++] = FRAMECHAR;	// escape it for literal
+		localbuffer[b++] = *buffer++;
+	}
+
+	localbuffer[b++] = FRAMECHAR;
+	localbuffer[b++] = 0;
+
+	write_buffer (localbuffer, b);
+}
+
+
+/*
+=============
+=
+= NetISR
+=
+=============
+*/
+
+void interrupt NetISR (void)
+{
+	if (doomcom.command == CMD_SEND)
+	{
+//I_ColorBlack (0,0,63);
+		WritePacket ((char *)&doomcom.data, doomcom.datalength);
+	}
+	else if (doomcom.command == CMD_GET)
+	{
+//I_ColorBlack (63,63,0);
+
+		if (ReadPacket () && packetlen <= sizeof(doomcom.data) )
+		{
+			doomcom.remotenode = 1;
+			doomcom.datalength = packetlen;
+			memcpy (&doomcom.data, &packet, packetlen);
+		}
+		else
+			doomcom.remotenode = -1;
+
+	}
+//I_ColorBlack (0,0,0);
+}
+
+
+
+
+/*
+=================
+=
+= Connect
+=
+= Figures out who is player 0 and 1
+=================
+*/
+
+void Connect (void)
+{
+	struct time	time;
+	int			oldsec;
+	int			localstage, remotestage;
+	char		str[20];
+	char		idstr[7];
+	char		remoteidstr[7];
+	unsigned long		idnum;
+	int			i;
+	
+//
+// wait for a good packet
+//
+	printf (STR_ATTEMPT"\n");
+
+//
+// build a (hopefully) unique id string by hashing up the current milliseconds
+// and the interrupt table
+//
+	if (CheckParm ("-player1"))
+		idnum = 0;
+	else if (CheckParm ("-player2"))
+		idnum = 999999;
+	else
+	{
+		gettime (&time);
+		idnum = time.ti_sec*100+time.ti_hund;
+		for (i=0 ; i<512 ; i++)
+			idnum += ((unsigned far *)0)[i];
+		idnum %= 1000000;
+	}
+	
+	idstr[0] = '0' + idnum/ 100000l;
+	idnum -= (idstr[0]-'0')*100000l;
+	idstr[1] = '0' + idnum/ 10000l;
+	idnum -= (idstr[1]-'0')*10000l;
+	idstr[2] = '0' + idnum/ 1000l;
+	idnum -= (idstr[2]-'0')*1000l;
+	idstr[3] = '0' + idnum/ 100l;
+	idnum -= (idstr[3]-'0')*100l;
+	idstr[4] = '0' + idnum/ 10l;
+	idnum -= (idstr[4]-'0')*10l;
+	idstr[5] = '0' + idnum;
+	idstr[6] = 0;
+	
+//
+// sit in a loop until things are worked out
+//
+// the packet is:  ID000000_0
+// the first field is the idnum, the second is the acknowledge stage
+// ack stage starts out 0, is bumped to 1 after the other computer's id
+// is known, and is bumped to 2 after the other computer has raised to 1
+//
+	oldsec = -1;
+	localstage = remotestage = 0;
+
+	do
+	{
+		while ( bioskey(1) )
+		{
+			if ( (bioskey (0) & 0xff) == 27)
+				Error ("\n\n"STR_NETABORT);
+		}
+
+		if (ReadPacket ())
+		{
+			packet[packetlen] = 0;
+			printf ("read : %s\n",packet);
+			if (packetlen != 10)
+				continue;
+			if (strncmp(packet,"ID",2) )
+				continue;
+			if (!strncmp (packet+2,idstr,6))
+				Error ("\n\n"STR_DUPLICATE);
+			strncpy (remoteidstr,packet+2,6);
+				
+			remotestage = packet[9] - '0';
+			localstage = remotestage+1;
+			oldsec = -1;
+		}
+
+		gettime (&time);
+		if (time.ti_sec != oldsec)
+		{
+			oldsec = time.ti_sec;
+			sprintf (str,"ID%s_%i",idstr,localstage);
+			WritePacket (str,strlen(str));
+			printf ("wrote: %s\n",str);
+		}
+
+	} while (localstage < 2);
+
+//
+// decide who is who
+//
+	if (strcmp(remoteidstr,idstr) > 0)
+		doomcom.consoleplayer = 0;
+	else
+		doomcom.consoleplayer = 1;
+	
+
+//
+// flush out any extras
+//
+	while (ReadPacket ())
+	;
+}
+
+
+
+/*
+==============
+=
+= ModemCommand
+=
+==============
+*/
+
+void ModemCommand (char *str)
+{
+	int		i,l;
+	
+	printf (STR_MODEMCMD,str);
+	l = strlen(str);
+	for (i=0 ; i<l ; i++)
+	{
+		write_buffer (str+i,1);
+		printf ("%c",str[i]);
+		delay (100);
+	}
+
+	write_buffer ("\r",1);
+	printf ("\n");
+}
+
+
+/*
+==============
+=
+= ModemResponse
+=
+= Waits for OK, RING, CONNECT, etc
+==============
+*/
+
+char	response[80];
+
+void ModemResponse (char *resp)
+{
+	int		c;
+	int		respptr;
+
+	do
+	{
+		printf (STR_MODEMRESP);
+		respptr=0;
+		do
+		{
+			while ( bioskey(1) )
+			{
+				if ( (bioskey (0) & 0xff) == 27)
+					Error ("\n"STR_RESPABORT);
+			}
+			c = read_byte ();
+			if (c==-1)
+				continue;
+			if (c=='\n' || respptr == 79)
+			{
+				response[respptr] = 0;
+				printf ("%s\n",response);
+				break;
+			}
+			if (c>=' ')
+			{
+				response[respptr] = c;
+				respptr++;
+			}
+		} while (1);
+
+	} while (strncmp(response,resp,strlen(resp)));
+}
+
+
+/*
+=============
+=
+= ReadLine
+=
+=============
+*/
+
+void ReadLine (FILE *f, char *dest)
+{
+	int	c;
+
+	do
+	{
+		c = fgetc (f);
+		if (c == EOF || c == '\r' || c == '\n')
+			break;
+		*dest++ = c;
+	} while (1);
+	*dest = 0;
+}
+
+
+/*
+=============
+=
+= ReadModemCfg
+=
+=============
+*/
+
+void ReadModemCfg (void)
+{
+	int		mcr;
+	FILE	*f;
+	unsigned	baud;
+
+	f = fopen ("modem.cfg","r");
+	if (!f)
+		Error (STR_CANTREAD);
+	ReadLine (f, startup);
+	ReadLine (f, shutdown);
+	ReadLine (f, baudrate);
+	fclose (f);
+
+	baud = atol(baudrate);
+	if (baud)
+		baudbits = 115200l/baud;
+
+	usemodem = true;
+}
+
+
+/*
+=============
+=
+= Dial
+=
+=============
+*/
+
+void Dial (void)
+{
+	char	cmd[80];
+	int		p;
+
+	ModemCommand(startup);
+	ModemResponse ("OK");
+
+	printf ("\n"STR_DIALING"\n\n");
+	p = CheckParm ("-dial");
+	sprintf (cmd,"ATDT%s",myargv[p+1]);
+
+	ModemCommand(cmd);
+	ModemResponse (STR_CONNECT);
+	doomcom.consoleplayer = 1;
+}
+
+
+/*
+=============
+=
+= Answer
+=
+=============
+*/
+
+void Answer (void)
+{
+	ModemCommand(startup);
+	ModemResponse ("OK");
+	printf ("\n"STR_WAITRING"\n\n");
+
+	ModemResponse (STR_RING);
+	ModemCommand ("ATA");
+	ModemResponse (STR_CONNECT);
+
+	doomcom.consoleplayer = 0;
+}
+
+//========================================================
+//
+//	Find a Response File
+//
+//========================================================
+void FindResponseFile (void)
+{
+	int		i;
+	#define	MAXARGVS	100
+
+	for (i = 1;i < myargc;i++)
+		if (myargv[i][0] == '@')
+		{
+			FILE *		handle;
+			int		size;
+			int		k;
+			int		index;
+			int		indexinfile;
+			char	*infile;
+			char	*file;
+			char	*moreargs[20];
+			char	*firstargv;
+
+			// READ THE RESPONSE FILE INTO MEMORY
+			handle = fopen (&myargv[i][1],"rb");
+			if (!handle)
+				I_Error (STR_NORESP);
+			printf("Found response file \"%s\"!\n",strupr(&myargv[i][1]));
+			fseek (handle,0,SEEK_END);
+			size = ftell(handle);
+			fseek (handle,0,SEEK_SET);
+			file = malloc (size);
+			fread (file,size,1,handle);
+			fclose (handle);
+
+			// KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
+			for (index = 0,k = i+1; k < myargc; k++)
+				moreargs[index++] = myargv[k];
+
+			firstargv = myargv[0];
+			myargv = malloc(sizeof(char *)*MAXARGVS);
+			memset(myargv,0,sizeof(char *)*MAXARGVS);
+			myargv[0] = firstargv;
+
+			infile = file;
+			indexinfile = k = 0;
+			indexinfile++;	// SKIP PAST ARGV[0] (KEEP IT)
+			do
+			{
+				myargv[indexinfile++] = infile+k;
+				while(k < size &&
+					((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
+					k++;
+				*(infile+k) = 0;
+				while(k < size &&
+					((*(infile+k)<= ' ') || (*(infile+k)>'z')))
+					k++;
+			} while(k < size);
+
+			for (k = 0;k < index;k++)
+				myargv[indexinfile++] = moreargs[k];
+			myargc = indexinfile;
+
+			// DISPLAY ARGS
+//			printf("%d command-line args:\n",myargc);
+//			for (k=1;k<myargc;k++)
+//				printf("%s\n",myargv[k]);
+
+			break;
+		}
+}
+
+
+
+/*
+=================
+=
+= main
+=
+=================
+*/
+
+void main(void)
+{
+	int				p;
+
+//
+// set network characteristics
+//
+	doomcom.ticdup = 1;
+	doomcom.extratics = 0;
+	doomcom.numnodes = 2;
+	doomcom.numplayers = 2;
+	doomcom.drone = 0;
+
+	printf("\n"
+		   "---------------------------------\n"
+		   #ifdef DOOM2
+		   STR_DOOMSERIAL"\n"
+		   #else
+		   "DOOM SERIAL DEVICE DRIVER v1.4\n"
+		   #endif
+		   "---------------------------------\n");
+	myargc = _argc;
+	myargv = _argv;
+	FindResponseFile();
+
+//
+// allow override of automatic player ordering to allow a slower computer
+// to be set as player 1 allways
+//
+
+//
+// establish communications
+//
+
+	baudbits = 0x08;		// default to 9600 if not specified on cmd line
+							// or in modem.cfg
+
+	if (CheckParm ("-dial") || CheckParm ("-answer") )
+		ReadModemCfg ();		// may set baudbits
+
+//
+// allow command-line override of modem.cfg baud rate
+//
+	if (CheckParm ("-9600")) baudbits = 0x0c;
+	else if (CheckParm ("-14400")) baudbits = 0x08;
+	else if (CheckParm ("-19200")) baudbits = 0x06;
+	else if (CheckParm ("-38400")) baudbits = 0x03;
+	else if (CheckParm ("-57600")) baudbits = 0x02;
+	else if (CheckParm ("-115200")) baudbits = 0x01;
+
+	InitPort ();
+
+	if (CheckParm ("-dial"))
+		Dial ();
+	else if (CheckParm ("-answer"))
+		Answer ();
+
+	Connect ();
+
+//
+// launch DOOM
+//
+	LaunchDOOM ();
+
+	Error (NULL);
+}
+
diff --git a/sersrc/SERSETUP.H b/sersrc/SERSETUP.H
@@ -0,0 +1,102 @@
+#include <conio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <conio.h>
+#include <ctype.h>
+#include <dos.h>
+#include <process.h>
+#include <stdarg.h>
+#include <bios.h>
+#include <ctype.h>
+
+
+#define INPUT(port)       	inportb(port)
+#define OUTPUT(port,data)  	outportb(port,data)
+#define CLI()               disable()
+#define STI()               enable()
+
+
+typedef enum {false, true} boolean;
+typedef unsigned char byte;
+
+
+#define TRANSMIT_HOLDING_REGISTER            0x00
+#define RECEIVE_BUFFER_REGISTER              0x00
+#define INTERRUPT_ENABLE_REGISTER            0x01
+#define   IER_RX_DATA_READY                  0x01
+#define   IER_TX_HOLDING_REGISTER_EMPTY      0x02
+#define   IER_LINE_STATUS                    0x04
+#define   IER_MODEM_STATUS                   0x08
+#define INTERRUPT_ID_REGISTER                0x02
+#define   IIR_MODEM_STATUS_INTERRUPT         0x00
+#define   IIR_TX_HOLDING_REGISTER_INTERRUPT  0x02
+#define   IIR_RX_DATA_READY_INTERRUPT        0x04
+#define   IIR_LINE_STATUS_INTERRUPT          0x06
+#define FIFO_CONTROL_REGISTER                0x02
+#define   FCR_FIFO_ENABLE                    0x01
+#define   FCR_RCVR_FIFO_RESET                0x02
+#define   FCR_XMIT_FIFO_RESET                0x04
+#define   FCR_RCVR_TRIGGER_LSB               0x40
+#define   FCR_RCVR_TRIGGER_MSB               0x80
+#define   FCR_TRIGGER_01                     0x00
+#define   FCR_TRIGGER_04                     0x40
+#define   FCR_TRIGGER_08                     0x80
+#define   FCR_TRIGGER_14                     0xc0
+#define LINE_CONTROL_REGISTER                0x03
+#define   LCR_WORD_LENGTH_MASK               0x03
+#define   LCR_WORD_LENGTH_SELECT_0           0x01
+#define   LCR_WORD_LENGTH_SELECT_1           0x02
+#define   LCR_STOP_BITS                      0x04
+#define   LCR_PARITY_MASK                    0x38
+#define   LCR_PARITY_ENABLE                  0x08
+#define   LCR_EVEN_PARITY_SELECT             0x10
+#define   LCR_STICK_PARITY                   0x20
+#define   LCR_SET_BREAK                      0x40
+#define   LCR_DLAB                           0x80
+#define MODEM_CONTROL_REGISTER               0x04
+#define   MCR_DTR                            0x01
+#define   MCR_RTS                            0x02
+#define   MCR_OUT1                           0x04
+#define   MCR_OUT2                           0x08
+#define   MCR_LOOPBACK                       0x10
+#define LINE_STATUS_REGISTER                 0x05
+#define   LSR_DATA_READY                     0x01
+#define   LSR_OVERRUN_ERROR                  0x02
+#define   LSR_PARITY_ERROR                   0x04
+#define   LSR_FRAMING_ERROR                  0x08
+#define   LSR_BREAK_DETECT                   0x10
+#define   LSR_THRE                           0x20
+#define MODEM_STATUS_REGISTER                0x06
+#define   MSR_DELTA_CTS                      0x01
+#define   MSR_DELTA_DSR                      0x02
+#define   MSR_TERI                           0x04
+#define   MSR_DELTA_CD                       0x08
+#define   MSR_CTS                            0x10
+#define   MSR_DSR                            0x20
+#define   MSR_RI                             0x40
+#define   MSR_CD                             0x80
+#define DIVISOR_LATCH_LOW                    0x00
+#define DIVISOR_LATCH_HIGH                   0x01
+
+
+
+#define	QUESIZE	2048
+
+typedef struct
+{
+	long	head, tail;		// bytes are put on head and pulled from tail
+	unsigned char	data[QUESIZE];
+} que_t;
+
+void InitPort (void);
+void ShutdownPort (void);
+
+int read_byte( void );
+void write_byte( int c );
+
+
+void Error (char *error, ...);
+
+extern	int		argc;
+extern	char	**argv;
diff --git a/sersrc/SERSTR.H b/sersrc/SERSTR.H
@@ -0,0 +1,21 @@
+#define STR_DROPDTR		"Dropping DTR"
+#define STR_CLEANEXIT	"Clean exit from SERSETUP"
+#define STR_ATTEMPT		"Attempting to connect across serial link, press escape to abort."
+#define STR_NETABORT	"Network game synchronization aborted."
+#define STR_DUPLICATE	"Duplicate id string, try again or check modem init string."
+#define STR_MODEMCMD	"Modem command : "
+#define STR_MODEMRESP	"Modem response: "
+#define STR_RESPABORT	"Modem response aborted."
+#define STR_CANTREAD	"Couldn't read MODEM.CFG"
+#define STR_DIALING		"Dialing..."
+#define STR_CONNECT		"CONNECT"
+#define STR_WAITRING	"Waiting for ring..."
+#define STR_RING		"RING"
+#define STR_NORESP		"No such response file!"
+#define STR_DOOMSERIAL	"DOOM II SERIAL DEVICE DRIVER v1.4"
+#define STR_WARNING \
+"Warning: no NULL or iret interrupt vectors were found in the 0x60 to 0x66\n"\
+"range.  You can specify a vector with the -vector 0x<num> parameter.\n"
+#define STR_COMM		"Communicating with interrupt vector 0x%x"
+#define STR_RETURNED	"Returned from DOOM II"
+#define STR_PORTSET		"Setting port to %lu baud"
diff --git a/sersrc/SER_FRCH.H b/sersrc/SER_FRCH.H
@@ -0,0 +1,25 @@
+#define STR_DROPDTR		"Abandon de DTR"
+#define STR_CLEANEXIT	"Sortie normale de SERSETUP"
+#define STR_ATTEMPT		"Tentative de connexion en s‚rie, appuyez sur ESC pour annuler."
+#define STR_NETABORT	"Synchronisation de jeu sur r‚seau annul‚e."
+#define STR_DUPLICATE	"ChaŒne id en double. R‚essayez ou v‚rifiez la chaŒne d'initialistion du modem."
+#define STR_MODEMCMD	"Commande du modem: "
+#define STR_MODEMRESP	"R‚ponse du modem: "
+#define STR_RESPABORT	"R‚ponse du modem annul‚e."
+#define STR_CANTREAD	"Lecture de MODEM.CFG impossible"
+#define STR_DIALING		"Composition du num‚ro..."
+#define STR_CONNECT		"CONNECTION"
+#define STR_WAITRING	"Attente d'appel..."
+#define STR_RING		"APPEL"
+#define STR_NORESP		"Ce fichier de r‚ponse n'existe pas!"
+#define STR_DOOMSERIAL	"GESTIONNAIRE DE LIAISON SERIE DOOM II v1.4"
+#define STR_WARNING \
+"Attention: pas de vecteurs d'interruption NULL ou iret trouv‚s entre 0x60 et 0x66.\n"\
+"Vous pouvez sp‚cifier un vecteur avec le paramŠtre -vector 0x<num‚ro>."
+#define STR_COMM		"Communication avec le vecteur d'interruption 0x%x"
+#define STR_RETURNED	"Retour de DOOM II"
+#define STR_PORTLOOK	"Recherche de l'UART sur le port"
+#define STR_UART8250	"UART = 8250"
+#define STR_UART16550	"UART = 16550"
+#define STR_CLEARPEND	"Riinitilisation des interruptions en attente.\n"
+#define STR_PORTSET		"Réglage du port à %lu baud"