diff options
Diffstat (limited to 'WinQuake/net_comx.c')
| -rw-r--r-- | WinQuake/net_comx.c | 1285 |
1 files changed, 1285 insertions, 0 deletions
diff --git a/WinQuake/net_comx.c b/WinQuake/net_comx.c new file mode 100644 index 0000000..2115a14 --- /dev/null +++ b/WinQuake/net_comx.c @@ -0,0 +1,1285 @@ +/* +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; + Q_strcpy(clear, p->clear); + Q_strcpy(init, p->startup); + Q_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]; + Q_strcpy(p->clear, clear); + Q_strcpy(p->startup, init); + Q_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; + Q_strcpy(p->clear, "ATZ"); + Q_strcpy(p->startup, ""); + Q_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 (Q_strncmp(response, "OK", 2) == 0) + break; + if (Q_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 (Q_strncmp(response, "OK", 2) == 0) + break; + if (Q_strncmp(response, "ERROR", 5) == 0) + { + p->enabled = false; + goto failed; + } + } + } + + p->modemInitialized = true; + return; + +failed: + if (m_return_onerror) + { + key_dest = key_menu; + m_state = m_return_state; + m_return_onerror = false; + Q_strcpy(m_return_reason, "Initialization Failed"); + } + return; +} + + +void TTY_Enable(int handle) +{ + ComPort *p; + + p = handleToPort [handle]; + if (p->enabled) + return; + + ComPort_Enable(p); + + if (p->useModem && !p->modemInitialized) + Modem_Init (p); +} + + +int TTY_Open(int serialPortNumber) +{ + return serialPortNumber; +} + + +void TTY_Close(int handle) +{ + ComPort *p; + double startTime; + + p = handleToPort [handle]; + + startTime = Sys_FloatTime(); + while ((Sys_FloatTime() - startTime) < 1.0) + if (EMPTY(p->outputQueue)) + break; + + if (p->useModem) + { + if (p->modemConnected) + Modem_Hangup(p); + } +} + + +int TTY_ReadByte(int handle) +{ + int ret; + ComPort *p; + + p = handleToPort [handle]; + + if ((ret = CheckStatus (p)) != 0) + return ret; + + if (EMPTY (p->inputQueue)) + return ERR_TTY_NODATA; + + DEQUEUE (p->inputQueue, ret); + return (ret & 0xff); +} + + +int TTY_WriteByte(int handle, byte data) +{ + ComPort *p; + + p = handleToPort [handle]; + if (FULL(p->outputQueue)) + return -1; + + ENQUEUE (p->outputQueue, data); + return 0; +} + + +void TTY_Flush(int handle) +{ + byte b; + ComPort *p; + + p = handleToPort [handle]; + + if (inportb (p->uart + LINE_STATUS_REGISTER ) & LSR_TRANSMITTER_EMPTY) + { + DEQUEUE (p->outputQueue, b); + outportb(p->uart, b); + } +} + + +int TTY_Connect(int handle, char *host) +{ + double start; + ComPort *p; + char *response = NULL; + keydest_t save_key_dest; + byte dialstring[64]; + byte b; + + p = handleToPort[handle]; + + if ((p->modemStatus & MODEM_STATUS_MASK) != MODEM_STATUS_MASK) + { + Con_Printf ("Serial: line not ready ("); + if ((p->modemStatus & MSR_CTS) == 0) + Con_Printf(" CTS"); + if ((p->modemStatus & MSR_DSR) == 0) + Con_Printf(" DSR"); + if ((p->modemStatus & MSR_CD) == 0) + Con_Printf(" CD"); + Con_Printf(" )"); + return -1; + } + + // discard any scraps in the input buffer + while (! EMPTY (p->inputQueue)) + DEQUEUE (p->inputQueue, b); + + CheckStatus (p); + + if (p->useModem) + { + save_key_dest = key_dest; + key_dest = key_console; + key_count = -2; + + Con_Printf ("Dialing...\n"); + sprintf(dialstring, "AT D%c %s\r", p->dialType, host); + Modem_Command (p, dialstring); + start = Sys_FloatTime(); + while(1) + { + if ((Sys_FloatTime() - start) > 60.0) + { + Con_Printf("Dialing failure!\n"); + break; + } + + Sys_SendKeyEvents (); + if (key_count == 0) + { + if (key_lastpress != K_ESCAPE) + { + key_count = -2; + continue; + } + Con_Printf("Aborting...\n"); + while ((Sys_FloatTime() - start) < 5.0) + ; + disable(); + p->outputQueue.head = p->outputQueue.tail = 0; + p->inputQueue.head = p->inputQueue.tail = 0; + outportb(p->uart + MODEM_CONTROL_REGISTER, inportb(p->uart + MODEM_CONTROL_REGISTER) & ~MCR_DTR); + enable(); + start = Sys_FloatTime(); + while ((Sys_FloatTime() - start) < 0.75) + ; + outportb(p->uart + MODEM_CONTROL_REGISTER, inportb(p->uart + MODEM_CONTROL_REGISTER) | MCR_DTR); + response = "Aborted"; + break; + } + + response = Modem_Response(p); + if (!response) + continue; + if (Q_strncmp(response, "CONNECT", 7) == 0) + { + disable(); + p->modemRang = true; + p->modemConnected = true; + p->outputQueue.head = p->outputQueue.tail = 0; + p->inputQueue.head = p->inputQueue.tail = 0; + enable(); + key_dest = save_key_dest; + key_count = 0; + m_return_onerror = false; + return 0; + } + if (Q_strncmp(response, "NO CARRIER", 10) == 0) + break; + if (Q_strncmp(response, "NO DIALTONE", 11) == 0) + break; + if (Q_strncmp(response, "NO DIAL TONE", 12) == 0) + break; + if (Q_strncmp(response, "NO ANSWER", 9) == 0) + break; + if (Q_strncmp(response, "BUSY", 4) == 0) + break; + if (Q_strncmp(response, "ERROR", 5) == 0) + break; + } + key_dest = save_key_dest; + key_count = 0; + if (m_return_onerror) + { + key_dest = key_menu; + m_state = m_return_state; + m_return_onerror = false; + Q_strncpy(m_return_reason, response, 31); + } + return -1; + } + m_return_onerror = false; + return 0; +} + + +void TTY_Disconnect(int handle) +{ + ComPort *p; + + p = handleToPort[handle]; + + if (p->useModem && p->modemConnected) + Modem_Hangup(p); +} + + +qboolean TTY_CheckForConnection(int handle) +{ + ComPort *p; + + p = handleToPort[handle]; + + CheckStatus (p); + + if (p->useModem) + { + if (!p->modemRang) + { + if (!Modem_Response(p)) + return false; + + if (Q_strncmp(p->buffer, "RING", 4) == 0) + { + Modem_Command (p, "ATA"); + p->modemRang = true; + p->timestamp = net_time; + } + return false; + } + if (!p->modemConnected) + { + if ((net_time - p->timestamp) > 35.0) + { + Con_Printf("Unable to establish modem connection\n"); + p->modemRang = false; + return false; + } + + if (!Modem_Response(p)) + return false; + + if (Q_strncmp (p->buffer, "CONNECT", 7) != 0) + return false; + + disable(); + p->modemConnected = true; + p->outputQueue.head = p->outputQueue.tail = 0; + p->inputQueue.head = p->inputQueue.tail = 0; + enable(); + Con_Printf("Modem Connect\n"); + return true; + } + return true; + } + + // direct connect case + if (EMPTY (p->inputQueue)) + return false; + return true; +} + + +qboolean TTY_IsEnabled(int serialPortNumber) +{ + return handleToPort[serialPortNumber]->enabled; +} + + +qboolean TTY_IsModem(int serialPortNumber) +{ + return handleToPort[serialPortNumber]->useModem; +} + + +qboolean TTY_OutputQueueIsEmpty(int handle) +{ + return EMPTY(handleToPort[handle]->outputQueue); +} + + +void Com_f (void) +{ + ComPort *p; + int portNumber; + int i; + int n; + + // first, determine which port they're messing with + portNumber = Q_atoi(Cmd_Argv (0) + 3) - 1; + if (portNumber > 1) + return; + p = handleToPort[portNumber]; + + if (Cmd_Argc() == 1) + { + Con_Printf("Settings for COM%i\n", portNumber + 1); + Con_Printf("enabled: %s\n", p->enabled ? "true" : "false"); + Con_Printf("uart: "); + if (p->uartType == UART_AUTO) + Con_Printf("auto\n"); + else if (p->uartType == UART_8250) + Con_Printf("8250\n"); + else + Con_Printf("16550\n"); + Con_Printf("port: %x\n", p->uart); + Con_Printf("irq: %i\n", p->irq); + Con_Printf("baud: %i\n", 115200 / p->baudBits); + Con_Printf("CTS: %s\n", (p->modemStatusIgnore & MSR_CTS) ? "ignored" : "honored"); + Con_Printf("DSR: %s\n", (p->modemStatusIgnore & MSR_DSR) ? "ignored" : "honored"); + Con_Printf("CD: %s\n", (p->modemStatusIgnore & MSR_CD) ? "ignored" : "honored"); + if (p->useModem) + { + Con_Printf("type: Modem\n"); + Con_Printf("clear: %s\n", p->clear); + Con_Printf("startup: %s\n", p->startup); + Con_Printf("shutdown: %s\n", p->shutdown); + } + else + Con_Printf("type: Direct connect\n"); + + return; + } + + + if (Cmd_CheckParm ("disable")) + { + if (p->enabled) + ComPort_Disable(p); + p->modemInitialized = false; + return; + } + + if (Cmd_CheckParm ("reset")) + { + ComPort_Disable(p); + ResetComPortConfig (p); + return; + } + + if ((i = Cmd_CheckParm ("port")) != 0) + { + if (p->enabled) + { + Con_Printf("COM port must be disabled to change port\n"); + return; + } + p->uart = Q_atoi (Cmd_Argv (i+1)); + } + + if ((i = Cmd_CheckParm ("irq")) != 0) + { + if (p->enabled) + { + Con_Printf("COM port must be disabled to change irq\n"); + return; + } + p->irq = Q_atoi (Cmd_Argv (i+1)); + } + + if ((i = Cmd_CheckParm ("baud")) != 0) + { + if (p->enabled) + { + Con_Printf("COM port must be disabled to change baud\n"); + return; + } + n = Q_atoi (Cmd_Argv (i+1)); + if (n == 0) + Con_Printf("Invalid baud rate specified\n"); + else + p->baudBits = 115200 / n; + } + + if (Cmd_CheckParm ("8250")) + { + if (p->enabled) + { + Con_Printf("COM port must be disabled to change uart\n"); + return; + } + p->uartType = UART_8250; + } + if (Cmd_CheckParm ("16550")) + { + if (p->enabled) + { + Con_Printf("COM port must be disabled to change uart\n"); + return; + } + p->uartType = UART_16550; + } + if (Cmd_CheckParm ("auto")) + { + if (p->enabled) + { + Con_Printf("COM port must be disabled to change uart\n"); + return; + } + p->uartType = UART_AUTO; + } + + if (Cmd_CheckParm ("pulse")) + p->dialType = 'P'; + if (Cmd_CheckParm ("tone")) + p->dialType = 'T'; + + if (Cmd_CheckParm ("direct")) + p->useModem = false; + if (Cmd_CheckParm ("modem")) + p->useModem = true; + + if ((i = Cmd_CheckParm ("clear")) != 0) + { + Q_strncpy (p->clear, Cmd_Argv (i+1), 16); + } + + if ((i = Cmd_CheckParm ("startup")) != 0) + { + Q_strncpy (p->startup, Cmd_Argv (i+1), 32); + p->modemInitialized = false; + } + + if ((i = Cmd_CheckParm ("shutdown")) != 0) + { + Q_strncpy (p->shutdown, Cmd_Argv (i+1), 16); + } + + if (Cmd_CheckParm ("-cts")) + { + p->modemStatusIgnore |= MSR_CTS; + p->modemStatus |= MSR_CTS; + } + + if (Cmd_CheckParm ("+cts")) + { + p->modemStatusIgnore &= (~MSR_CTS); + p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore; + } + + if (Cmd_CheckParm ("-dsr")) + { + p->modemStatusIgnore |= MSR_DSR; + p->modemStatus |= MSR_DSR; + } + + if (Cmd_CheckParm ("+dsr")) + { + p->modemStatusIgnore &= (~MSR_DSR); + p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore; + } + + if (Cmd_CheckParm ("-cd")) + { + p->modemStatusIgnore |= MSR_CD; + p->modemStatus |= MSR_CD; + } + + if (Cmd_CheckParm ("+cd")) + { + p->modemStatusIgnore &= (~MSR_CD); + p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore; + } + + if (Cmd_CheckParm ("enable")) + { + if (!p->enabled) + ComPort_Enable(p); + if (p->useModem && !p->modemInitialized) + Modem_Init (p); + } +} + + +int TTY_Init(void) +{ + int n; + ComPort *p; + + for (n = 0; n < NUM_COM_PORTS; n++) + { + p = (ComPort *)Hunk_AllocName(sizeof(ComPort), "comport"); + if (p == NULL) + Sys_Error("Hunk alloc failed for com port\n"); + p->next = portList; + portList = p; + handleToPort[n] = p; + p->portNumber = n; + p->dialType = 'T'; + sprintf(p->name, "com%u", n+1); + Cmd_AddCommand (p->name, Com_f); + ResetComPortConfig (p); + } + + GetComPortConfig = TTY_GetComPortConfig; + SetComPortConfig = TTY_SetComPortConfig; + GetModemConfig = TTY_GetModemConfig; + SetModemConfig = TTY_SetModemConfig; + + return 0; +} + + +void TTY_Shutdown(void) +{ + int n; + ComPort *p; + + for (n = 0; n < NUM_COM_PORTS; n++) + { + p = handleToPort[n]; + if (p->enabled) + { + while (p->modemConnected) + NET_Poll(); + ComPort_Disable (p); + } + } +} + + +static int Modem_Command(ComPort *p, char *commandString) +{ + byte b; + + if (CheckStatus (p)) + return -1; + + disable(); + p->outputQueue.head = p->outputQueue.tail = 0; + p->inputQueue.head = p->inputQueue.tail = 0; + enable(); + p->bufferUsed = 0; + + while (*commandString) + ENQUEUE (p->outputQueue, *commandString++); + ENQUEUE (p->outputQueue, '\r'); + + // get the transmit rolling + DEQUEUE (p->outputQueue, b); + outportb(p->uart, b); + + return 0; +} + + +static char *Modem_Response(ComPort *p) +{ + byte b; + + if (CheckStatus (p)) + return NULL; + + while (! EMPTY(p->inputQueue)) + { + DEQUEUE (p->inputQueue, b); + + if (p->bufferUsed == (sizeof(p->buffer) - 1)) + b = '\r'; + + if (b == '\r' && p->bufferUsed) + { + p->buffer[p->bufferUsed] = 0; + Con_Printf("%s\n", p->buffer); + SCR_UpdateScreen (); + p->bufferUsed = 0; + return p->buffer; + } + + if (b < ' ' || b > 'z') + continue; + p->buffer[p->bufferUsed] = b; + p->bufferUsed++; + } + + return NULL; +} + + +static void Modem_Hangup2(ComPort *p); +static void Modem_Hangup3(ComPort *p); +static void Modem_Hangup4(ComPort *p); + +static void Modem_Hangup(ComPort *p) +{ + Con_Printf("Hanging up modem...\n"); + disable(); + p->modemRang = false; + p->outputQueue.head = p->outputQueue.tail = 0; + p->inputQueue.head = p->inputQueue.tail = 0; + outportb(p->uart + MODEM_CONTROL_REGISTER, inportb(p->uart + MODEM_CONTROL_REGISTER) & ~MCR_DTR); + enable(); + p->poll.procedure = Modem_Hangup2; + p->poll.arg = p; + SchedulePollProcedure(&p->poll, 1.5); +} + +static void Modem_Hangup2(ComPort *p) +{ + outportb(p->uart + MODEM_CONTROL_REGISTER, inportb(p->uart + MODEM_CONTROL_REGISTER) | MCR_DTR); + Modem_Command(p, "+++"); + p->poll.procedure = Modem_Hangup3; + SchedulePollProcedure(&p->poll, 1.5); +} + +static void Modem_Hangup3(ComPort *p) +{ + Modem_Command(p, p->shutdown); + p->poll.procedure = Modem_Hangup4; + SchedulePollProcedure(&p->poll, 1.5); +} + +static void Modem_Hangup4(ComPort *p) +{ + Modem_Response(p); + Con_Printf("Hangup complete\n"); + p->modemConnected = false; +} |
