⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 net_comx.c

📁 quake1 dos源代码最新版本
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// net_comx.c

#include <dos.h>
#include <dpmi.h>

#define NUM_COM_PORTS	2

#define ERR_TTY_LINE_STATUS		-1
#define ERR_TTY_MODEM_STATUS	-2
#define ERR_TTY_NODATA			-3

#define QUEUESIZE	8192
#define QUEUEMASK	(QUEUESIZE - 1)

typedef struct
{
	volatile int  head;
	volatile int  tail;
	volatile byte data[QUEUESIZE];
} queue;

#define FULL(q)			(q.head == ((q.tail-1) & QUEUEMASK))
#define EMPTY(q)		(q.tail == q.head)
#define ENQUEUE(q,b)	(q.data[q.head] = b, q.head = (q.head + 1) & QUEUEMASK)
#define DEQUEUE(q,b)	(b = q.data[q.tail], q.tail = (q.tail + 1) & QUEUEMASK)

extern cvar_t	*config_com_port;
extern cvar_t	*config_com_irq;
extern cvar_t	*config_com_baud;
extern cvar_t	*config_com_modem;
extern cvar_t	*config_modem_dialtype;
extern cvar_t	*config_modem_clear;
extern cvar_t	*config_modem_init;
extern cvar_t	*config_modem_hangup;

extern int m_return_state;
extern int m_state;
extern qboolean m_return_onerror;
extern char m_return_reason[32];

// 8250, 16550 definitions
#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   IIR_FIFO_TIMEOUT                   0x0c
#define   IIR_FIFO_ENABLED                   0xc0
#define FIFO_CONTROL_REGISTER                0x02
#define   FCR_FIFO_ENABLE                    0x01
#define   FCR_RCVR_FIFO_RESET                0x02
#define   FCR_XMIT_FIFO_RESET                0x04
#define   FCR_TRIGGER_01                     0x00
#define   FCR_TRIGGER_04                     0x40
#define   FCR_TRIGGER_08                     0x80
#define   FCR_TRIGGER_16                     0xc0
#define LINE_CONTROL_REGISTER                0x03
#define   LCR_DATA_BITS_5                    0x00
#define   LCR_DATA_BITS_6                    0x01
#define   LCR_DATA_BITS_7                    0x02
#define   LCR_DATA_BITS_8                    0x03
#define   LCR_STOP_BITS_1                    0x00
#define   LCR_STOP_BITS_2                    0x04
#define   LCR_PARITY_NONE                    0x00
#define   LCR_PARITY_ODD                     0x08
#define   LCR_PARITY_EVEN                    0x18
#define   LCR_PARITY_MARK                    0x28
#define   LCR_PARITY_SPACE                   0x38
#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_TRANSMITTER_BUFFER_EMPTY       0x20
#define   LSR_TRANSMITTER_EMPTY              0x40
#define   LSR_FIFO_DIRTY                     0x80
#define MODEM_STATUS_REGISTER                0x06
#define   MSR_DELTA_CTS                      0x01
#define   MSR_DELTA_DSR                      0x02
#define   MSR_DELTA_RI                       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 MODEM_STATUS_MASK	(MSR_CTS | MSR_DSR | MSR_CD)

#define UART_AUTO	0
#define UART_8250	1
#define UART_16550	2

static int ISA_uarts[]	= {0x3f8,0x2f8,0x3e8,0x2e8};
static int ISA_IRQs[]	= {4,3,4,3};

typedef struct ComPort_s
{
	struct ComPort_s		*next;
	_go32_dpmi_seginfo		protectedModeInfo;
	_go32_dpmi_seginfo		protectedModeSaveInfo;
	int						uart;
	volatile byte			modemStatus;
	byte					modemStatusIgnore;
	byte					lineStatus;
	byte					bufferUsed;
	qboolean				enabled;
	volatile qboolean		statusUpdated;
	qboolean				useModem;
	qboolean				modemInitialized;
	qboolean				modemRang;
	qboolean				modemConnected;
	queue					inputQueue;
	queue					outputQueue;
	char					clear[16];
	char					startup[32];
	char					shutdown[16];
	char					buffer[128];
	PollProcedure			poll;
	double					timestamp;
	byte					uartType;
	byte					irq;
	byte					baudBits;
	byte					lineControl;
	byte					portNumber;
	char					dialType;
	char					name[4];
} ComPort;

ComPort *portList = NULL;
ComPort *handleToPort [NUM_COM_PORTS];

static int Modem_Command(ComPort *p, char *commandString);
static char *Modem_Response(ComPort *p);
static void Modem_Hangup(ComPort *p);

int TTY_Init(void);
void TTY_Shutdown(void);
int TTY_Open(int serialPortNumber);
void TTY_Close(int handle);
int TTY_ReadByte(int handle);
int TTY_WriteByte(int handle, byte data);
void TTY_Flush(int handle);
int TTY_Connect(int handle, char *host);
void TTY_Disconnect(int handle);
qboolean TTY_CheckForConnection(int handle);
qboolean TTY_IsEnabled(int serialPortNumber);
qboolean TTY_IsModem(int serialPortNumber);
qboolean TTY_OutputQueueIsEmpty(int handle);

static void ISR_8250 (ComPort *p)
{
	byte	source = 0;
	byte	b;

	disable();

	while((source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07) != 1)
	{
		switch (source)
		{
			case IIR_RX_DATA_READY_INTERRUPT:
				b = inportb (p->uart + RECEIVE_BUFFER_REGISTER);
				if (! FULL(p->inputQueue))
				{
					ENQUEUE (p->inputQueue, b);
				}
				else
				{
					p->lineStatus |= LSR_OVERRUN_ERROR;
					p->statusUpdated = true;
				}
				break;

			case IIR_TX_HOLDING_REGISTER_INTERRUPT:
				if (! EMPTY(p->outputQueue))
				{
					DEQUEUE (p->outputQueue, b);
					outportb (p->uart + TRANSMIT_HOLDING_REGISTER, b);
				}
				break;

			case IIR_MODEM_STATUS_INTERRUPT:
				p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
				p->statusUpdated = true;
				break;

			case IIR_LINE_STATUS_INTERRUPT:
				p->lineStatus = inportb (p->uart + LINE_STATUS_REGISTER);
				p->statusUpdated = true;
				break;
		}
		source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07;
	}
	outportb (0x20, 0x20);
}

static void COM1_ISR_8250 (void)
{
	ISR_8250 (handleToPort[0]);
}

static void COM2_ISR_8250 (void)
{
	ISR_8250 (handleToPort[1]);
}



static void ISR_16550 (ComPort *p)
{
	int		count;
	byte	source;
	byte	b;

	disable();
	while((source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07) != 1)
	{
		switch (source)
		{
			case IIR_RX_DATA_READY_INTERRUPT:
				do
				{
					b = inportb (p->uart + RECEIVE_BUFFER_REGISTER);
					if (!FULL(p->inputQueue))
					{
						ENQUEUE (p->inputQueue, b);
					}
					else
					{
						p->lineStatus |= LSR_OVERRUN_ERROR;
						p->statusUpdated = true;
					}
				} while (inportb (p->uart + LINE_STATUS_REGISTER) & LSR_DATA_READY);
				break;

			case IIR_TX_HOLDING_REGISTER_INTERRUPT:
				count = 16;
				while ((! EMPTY(p->outputQueue)) && count--)
				{
					DEQUEUE (p->outputQueue, b);
					outportb (p->uart + TRANSMIT_HOLDING_REGISTER, b);
				}
				break;

			case IIR_MODEM_STATUS_INTERRUPT:
				p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
				p->statusUpdated = true;
				break;

			case IIR_LINE_STATUS_INTERRUPT:
				p->lineStatus = inportb (p->uart + LINE_STATUS_REGISTER);
				p->statusUpdated = true;
				break;
		}
		source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07;
	}

	// check for lost IIR_TX_HOLDING_REGISTER_INTERRUPT on 16550a!
	if (inportb (p->uart + LINE_STATUS_REGISTER ) & LSR_TRANSMITTER_EMPTY)
	{
		count = 16;
		while ((! EMPTY(p->outputQueue)) && count--)
		{
			DEQUEUE (p->outputQueue, b);
			outportb (p->uart + TRANSMIT_HOLDING_REGISTER, b);
		}
	}

	outportb (0x20, 0x20);
}

static void COM1_ISR_16550 (void)
{
	ISR_16550 (handleToPort[0]);
}

static void COM2_ISR_16550 (void)
{
	ISR_16550 (handleToPort[1]);
}


void TTY_GetComPortConfig (int portNumber, int *port, int *irq, int *baud, qboolean *useModem)
{
	ComPort	*p;

	p = handleToPort[portNumber];
	*port = p->uart;
	*irq = p->irq;
	*baud = 115200 / p->baudBits;
	*useModem = p->useModem;
}

void TTY_SetComPortConfig (int portNumber, int port, int irq, int baud, qboolean useModem)
{
	ComPort	*p;
	float	temp;

	if (useModem)
	{
		if (baud == 14400)
			baud = 19200;
		if (baud == 28800)
			baud = 38400;
	}

	p = handleToPort[portNumber];
	p->uart = port;
	p->irq = irq;
	p->baudBits = 115200 / baud;
	p->useModem = useModem;

	if (useModem)
		temp = 1.0;
	else
		temp = 0.0;

	Cvar_SetValue (config_com_port, (float)port);
	Cvar_SetValue (config_com_irq, (float)irq);
	Cvar_SetValue (config_com_baud, (float)baud);
	Cvar_SetValue (config_com_modem, temp);
}

void TTY_GetModemConfig (int portNumber, char *dialType, char *clear, char *init, char *hangup)
{
	ComPort	*p;

	p = handleToPort[portNumber];
	*dialType = p->dialType;
	strcpy(clear, p->clear);
	strcpy(init, p->startup);
	strcpy(hangup, p->shutdown);
}

void TTY_SetModemConfig (int portNumber, char *dialType, char *clear, char *init, char *hangup)
{
	ComPort	*p;

	p = handleToPort[portNumber];
	p->dialType = dialType[0];
	strcpy(p->clear, clear);
	strcpy(p->startup, init);
	strcpy(p->shutdown, hangup);

	p->modemInitialized = false;

	Cvar_Set (config_modem_dialtype, dialType);
	Cvar_Set (config_modem_clear, clear);
	Cvar_Set (config_modem_init, init);
	Cvar_Set (config_modem_hangup, hangup);
}


static void ResetComPortConfig (ComPort *p)
{
	p->useModem = false;
	p->uartType = UART_AUTO;
	p->uart = ISA_uarts[p->portNumber];
	p->irq = ISA_IRQs[p->portNumber];
	p->modemStatusIgnore = MSR_CD | MSR_CTS | MSR_DSR;
	p->baudBits = 115200 / 57600;
	p->lineControl = LCR_DATA_BITS_8 | LCR_STOP_BITS_1 | LCR_PARITY_NONE;
	strcpy(p->clear, "ATZ");
	strcpy(p->startup, "");
	strcpy(p->shutdown, "AT H");
	p->modemRang = false;
	p->modemConnected = false;
	p->statusUpdated = false;
	p->outputQueue.head = p->outputQueue.tail = 0;
	p->inputQueue.head = p->inputQueue.tail = 0;
}


static void ComPort_Enable(ComPort *p)
{
	void	(*isr)(void);
	int		n;
	byte	b;

	if (p->enabled)
	{
		Con_Printf("Already enabled\n");
		return;
	}

	// disable all UART interrupts
	outportb (p->uart + INTERRUPT_ENABLE_REGISTER, 0);

	// clear out any buffered uncoming data
	while((inportb (p->uart + LINE_STATUS_REGISTER)) & LSR_DATA_READY)
		inportb (p->uart + RECEIVE_BUFFER_REGISTER);

	// get the current line and modem status
	p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
	p->lineStatus = inportb (p->uart + LINE_STATUS_REGISTER);

	// clear any UART interrupts
	do
	{
		n = inportb (p->uart + INTERRUPT_ID_REGISTER) & 7;
		if (n == IIR_RX_DATA_READY_INTERRUPT)
			inportb (p->uart + RECEIVE_BUFFER_REGISTER);
	} while (!(n & 1));

	if (p->uartType == UART_AUTO)
	{
		outportb (p->uart + FIFO_CONTROL_REGISTER, FCR_FIFO_ENABLE);
		b = inportb (p->uart + INTERRUPT_ID_REGISTER);
		if ((b & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED)
			p->uartType = UART_16550;
		else
			p->uartType = UART_8250;
	}

	// save the old interrupt handler
	_go32_dpmi_get_protected_mode_interrupt_vector(p->irq + 8, &p->protectedModeSaveInfo);

	if (p->uartType == UART_8250)
	{
		outportb (p->uart + FIFO_CONTROL_REGISTER, 0);
		if (p == handleToPort[0])
			isr = COM1_ISR_8250;
		else
			isr = COM2_ISR_8250;
	}
	else
	{
		outportb (p->uart + FIFO_CONTROL_REGISTER, FCR_FIFO_ENABLE | FCR_RCVR_FIFO_RESET | FCR_XMIT_FIFO_RESET | FCR_TRIGGER_08);
		if (p == handleToPort[0])
			isr = COM1_ISR_16550;
		else
			isr = COM2_ISR_16550;
	}

	p->protectedModeInfo.pm_offset = (int)isr;

	n = _go32_dpmi_allocate_iret_wrapper(&p->protectedModeInfo);
	if (n)
	{
		Con_Printf("serial: protected mode callback allocation failed\n");
		return;
	}

	// disable interrupts at the processor
	disable();

	// install our interrupt handlers now
	_go32_dpmi_set_protected_mode_interrupt_vector(p->irq + 8, &p->protectedModeInfo);

	// enable our interrupt at the PIC
	outportb (0x21, inportb (0x21) & ~(1<<p->irq));

	// enable interrupts at the processor
	enable();

	// enable interrupts at the PIC
	outportb (0x20, 0xc2);

	// set baud rate & line control
	outportb (p->uart + LINE_CONTROL_REGISTER, LCR_DLAB | p->lineControl);
	outportb (p->uart, p->baudBits);
	outportb (p->uart + 1, 0);
	outportb (p->uart + LINE_CONTROL_REGISTER, p->lineControl);

	// set modem control register & enable uart interrupt generation
	outportb(p->uart + MODEM_CONTROL_REGISTER, MCR_OUT2 | MCR_RTS | MCR_DTR);

	// enable the individual interrupts at the uart
	outportb (p->uart + INTERRUPT_ENABLE_REGISTER, IER_RX_DATA_READY | IER_TX_HOLDING_REGISTER_EMPTY | IER_LINE_STATUS | IER_MODEM_STATUS);

	p->enabled = true;
}


static void ComPort_Disable(ComPort *p)
{
	if (!p->enabled)
	{
		Con_Printf("Already disabled\n");
		return;
	}

	// disable interrupts at the uart
	outportb (p->uart + INTERRUPT_ENABLE_REGISTER, 0);

	// disable our interrupt at the PIC
	outportb (0x21, inportb (0x21) | (1<<p->irq));

	// disable interrupts at the processor
	disable();

	// restore the old interrupt handler
	_go32_dpmi_set_protected_mode_interrupt_vector(p->irq + 8, &p->protectedModeSaveInfo);
	_go32_dpmi_free_iret_wrapper(&p->protectedModeInfo);

	// enable interrupts at the processor
	enable();

	p->enabled = false;
}


static int CheckStatus (ComPort *p)
{
	int		ret = 0;

	if (p->statusUpdated)
	{
		p->statusUpdated = false;

		if (p->lineStatus & (LSR_OVERRUN_ERROR | LSR_PARITY_ERROR | LSR_FRAMING_ERROR | LSR_BREAK_DETECT))
		{
			if (p->lineStatus & LSR_OVERRUN_ERROR)
				Con_DPrintf ("Serial overrun error\n");
			if (p->lineStatus & LSR_PARITY_ERROR)
				Con_DPrintf ("Serial parity error\n");
			if (p->lineStatus & LSR_FRAMING_ERROR)
				Con_DPrintf ("Serial framing error\n");
			if (p->lineStatus & LSR_BREAK_DETECT)
				Con_DPrintf ("Serial break detect\n");
			ret = ERR_TTY_LINE_STATUS;
		}

		if ((p->modemStatus & MODEM_STATUS_MASK) != MODEM_STATUS_MASK)
		{
			if (!(p->modemStatus & MSR_CTS))
				Con_Printf ("Serial lost CTS\n");
			if (!(p->modemStatus & MSR_DSR))
				Con_Printf ("Serial lost DSR\n");
			if (!(p->modemStatus & MSR_CD))
				Con_Printf ("Serial lost Carrier\n");
			ret = ERR_TTY_MODEM_STATUS;
		}
	}

	return ret;
}


static void Modem_Init(ComPort *p)
{
	double	start;
	char	*response;

	Con_Printf ("Initializing modem...\n");

	// write 0 to MCR, wait 1/2 sec, then write the real value back again
	// I got this from the guys at head-to-head who say it's necessary.
	outportb(p->uart + MODEM_CONTROL_REGISTER, 0);
	start = Sys_FloatTime();
	while ((Sys_FloatTime() - start) < 0.5)
		;
	outportb(p->uart + MODEM_CONTROL_REGISTER, MCR_OUT2 | MCR_RTS | MCR_DTR);
	start = Sys_FloatTime();
	while ((Sys_FloatTime() - start) < 0.25)
		;

	if (*p->clear)
	{
		Modem_Command (p, p->clear);
		start = Sys_FloatTime();
		while(1)
		{
			if ((Sys_FloatTime() - start) > 3.0)
			{
				Con_Printf("No response - clear failed\n");
				p->enabled = false;
				goto failed;
			}
			response = Modem_Response(p);
			if (!response)
				continue;
			if (strncmp(response, "OK", 2) == 0)
				break;
			if (strncmp(response, "ERROR", 5) == 0)
			{
				p->enabled = false;
				goto failed;
			}
		}
	}

	if (*p->startup)
	{
		Modem_Command (p, p->startup);
		start = Sys_FloatTime();
		while(1)
		{
			if ((Sys_FloatTime() - start) > 3.0)
			{
				Con_Printf("No response - init failed\n");
				p->enabled = false;
				goto failed;
			}
			response = Modem_Response(p);
			if (!response)
				continue;
			if (strncmp(response, "OK", 2) == 0)
				break;
			if (strncmp(response, "ERROR", 5) == 0)
			{
				p->enabled = false;
				goto failed;
			}
		}
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -