Replaced Exit() by exit() because Exit() is like abort().
[AROS-Contrib.git] / Games / Quake / net_comx.c
blob2115a14e23d0ccc1a81dbaf9e776729b2cd17d25
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // net_comx.c
22 #include <dos.h>
23 #include <dpmi.h>
25 #define NUM_COM_PORTS 2
27 #define ERR_TTY_LINE_STATUS -1
28 #define ERR_TTY_MODEM_STATUS -2
29 #define ERR_TTY_NODATA -3
31 #define QUEUESIZE 8192
32 #define QUEUEMASK (QUEUESIZE - 1)
34 typedef struct
36 volatile int head;
37 volatile int tail;
38 volatile byte data[QUEUESIZE];
39 } queue;
41 #define FULL(q) (q.head == ((q.tail-1) & QUEUEMASK))
42 #define EMPTY(q) (q.tail == q.head)
43 #define ENQUEUE(q,b) (q.data[q.head] = b, q.head = (q.head + 1) & QUEUEMASK)
44 #define DEQUEUE(q,b) (b = q.data[q.tail], q.tail = (q.tail + 1) & QUEUEMASK)
46 extern cvar_t config_com_port;
47 extern cvar_t config_com_irq;
48 extern cvar_t config_com_baud;
49 extern cvar_t config_com_modem;
50 extern cvar_t config_modem_dialtype;
51 extern cvar_t config_modem_clear;
52 extern cvar_t config_modem_init;
53 extern cvar_t config_modem_hangup;
55 extern int m_return_state;
56 extern int m_state;
57 extern qboolean m_return_onerror;
58 extern char m_return_reason[32];
60 // 8250, 16550 definitions
61 #define TRANSMIT_HOLDING_REGISTER 0x00
62 #define RECEIVE_BUFFER_REGISTER 0x00
63 #define INTERRUPT_ENABLE_REGISTER 0x01
64 #define IER_RX_DATA_READY 0x01
65 #define IER_TX_HOLDING_REGISTER_EMPTY 0x02
66 #define IER_LINE_STATUS 0x04
67 #define IER_MODEM_STATUS 0x08
68 #define INTERRUPT_ID_REGISTER 0x02
69 #define IIR_MODEM_STATUS_INTERRUPT 0x00
70 #define IIR_TX_HOLDING_REGISTER_INTERRUPT 0x02
71 #define IIR_RX_DATA_READY_INTERRUPT 0x04
72 #define IIR_LINE_STATUS_INTERRUPT 0x06
73 #define IIR_FIFO_TIMEOUT 0x0c
74 #define IIR_FIFO_ENABLED 0xc0
75 #define FIFO_CONTROL_REGISTER 0x02
76 #define FCR_FIFO_ENABLE 0x01
77 #define FCR_RCVR_FIFO_RESET 0x02
78 #define FCR_XMIT_FIFO_RESET 0x04
79 #define FCR_TRIGGER_01 0x00
80 #define FCR_TRIGGER_04 0x40
81 #define FCR_TRIGGER_08 0x80
82 #define FCR_TRIGGER_16 0xc0
83 #define LINE_CONTROL_REGISTER 0x03
84 #define LCR_DATA_BITS_5 0x00
85 #define LCR_DATA_BITS_6 0x01
86 #define LCR_DATA_BITS_7 0x02
87 #define LCR_DATA_BITS_8 0x03
88 #define LCR_STOP_BITS_1 0x00
89 #define LCR_STOP_BITS_2 0x04
90 #define LCR_PARITY_NONE 0x00
91 #define LCR_PARITY_ODD 0x08
92 #define LCR_PARITY_EVEN 0x18
93 #define LCR_PARITY_MARK 0x28
94 #define LCR_PARITY_SPACE 0x38
95 #define LCR_SET_BREAK 0x40
96 #define LCR_DLAB 0x80
97 #define MODEM_CONTROL_REGISTER 0x04
98 #define MCR_DTR 0x01
99 #define MCR_RTS 0x02
100 #define MCR_OUT1 0x04
101 #define MCR_OUT2 0x08
102 #define MCR_LOOPBACK 0x10
103 #define LINE_STATUS_REGISTER 0x05
104 #define LSR_DATA_READY 0x01
105 #define LSR_OVERRUN_ERROR 0x02
106 #define LSR_PARITY_ERROR 0x04
107 #define LSR_FRAMING_ERROR 0x08
108 #define LSR_BREAK_DETECT 0x10
109 #define LSR_TRANSMITTER_BUFFER_EMPTY 0x20
110 #define LSR_TRANSMITTER_EMPTY 0x40
111 #define LSR_FIFO_DIRTY 0x80
112 #define MODEM_STATUS_REGISTER 0x06
113 #define MSR_DELTA_CTS 0x01
114 #define MSR_DELTA_DSR 0x02
115 #define MSR_DELTA_RI 0x04
116 #define MSR_DELTA_CD 0x08
117 #define MSR_CTS 0x10
118 #define MSR_DSR 0x20
119 #define MSR_RI 0x40
120 #define MSR_CD 0x80
121 #define DIVISOR_LATCH_LOW 0x00
122 #define DIVISOR_LATCH_HIGH 0x01
124 #define MODEM_STATUS_MASK (MSR_CTS | MSR_DSR | MSR_CD)
126 #define UART_AUTO 0
127 #define UART_8250 1
128 #define UART_16550 2
130 static int ISA_uarts[] = {0x3f8,0x2f8,0x3e8,0x2e8};
131 static int ISA_IRQs[] = {4,3,4,3};
133 typedef struct ComPort_s
135 struct ComPort_s *next;
136 _go32_dpmi_seginfo protectedModeInfo;
137 _go32_dpmi_seginfo protectedModeSaveInfo;
138 int uart;
139 volatile byte modemStatus;
140 byte modemStatusIgnore;
141 byte lineStatus;
142 byte bufferUsed;
143 qboolean enabled;
144 volatile qboolean statusUpdated;
145 qboolean useModem;
146 qboolean modemInitialized;
147 qboolean modemRang;
148 qboolean modemConnected;
149 queue inputQueue;
150 queue outputQueue;
151 char clear[16];
152 char startup[32];
153 char shutdown[16];
154 char buffer[128];
155 PollProcedure poll;
156 double timestamp;
157 byte uartType;
158 byte irq;
159 byte baudBits;
160 byte lineControl;
161 byte portNumber;
162 char dialType;
163 char name[4];
164 } ComPort;
166 ComPort *portList = NULL;
167 ComPort *handleToPort [NUM_COM_PORTS];
169 static int Modem_Command(ComPort *p, char *commandString);
170 static char *Modem_Response(ComPort *p);
171 static void Modem_Hangup(ComPort *p);
173 int TTY_Init(void);
174 void TTY_Shutdown(void);
175 int TTY_Open(int serialPortNumber);
176 void TTY_Close(int handle);
177 int TTY_ReadByte(int handle);
178 int TTY_WriteByte(int handle, byte data);
179 void TTY_Flush(int handle);
180 int TTY_Connect(int handle, char *host);
181 void TTY_Disconnect(int handle);
182 qboolean TTY_CheckForConnection(int handle);
183 qboolean TTY_IsEnabled(int serialPortNumber);
184 qboolean TTY_IsModem(int serialPortNumber);
185 qboolean TTY_OutputQueueIsEmpty(int handle);
187 static void ISR_8250 (ComPort *p)
189 byte source = 0;
190 byte b;
192 disable();
194 while((source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07) != 1)
196 switch (source)
198 case IIR_RX_DATA_READY_INTERRUPT:
199 b = inportb (p->uart + RECEIVE_BUFFER_REGISTER);
200 if (! FULL(p->inputQueue))
202 ENQUEUE (p->inputQueue, b);
204 else
206 p->lineStatus |= LSR_OVERRUN_ERROR;
207 p->statusUpdated = true;
209 break;
211 case IIR_TX_HOLDING_REGISTER_INTERRUPT:
212 if (! EMPTY(p->outputQueue))
214 DEQUEUE (p->outputQueue, b);
215 outportb (p->uart + TRANSMIT_HOLDING_REGISTER, b);
217 break;
219 case IIR_MODEM_STATUS_INTERRUPT:
220 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
221 p->statusUpdated = true;
222 break;
224 case IIR_LINE_STATUS_INTERRUPT:
225 p->lineStatus = inportb (p->uart + LINE_STATUS_REGISTER);
226 p->statusUpdated = true;
227 break;
229 source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07;
231 outportb (0x20, 0x20);
234 static void COM1_ISR_8250 (void)
236 ISR_8250 (handleToPort[0]);
239 static void COM2_ISR_8250 (void)
241 ISR_8250 (handleToPort[1]);
246 static void ISR_16550 (ComPort *p)
248 int count;
249 byte source;
250 byte b;
252 disable();
253 while((source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07) != 1)
255 switch (source)
257 case IIR_RX_DATA_READY_INTERRUPT:
260 b = inportb (p->uart + RECEIVE_BUFFER_REGISTER);
261 if (!FULL(p->inputQueue))
263 ENQUEUE (p->inputQueue, b);
265 else
267 p->lineStatus |= LSR_OVERRUN_ERROR;
268 p->statusUpdated = true;
270 } while (inportb (p->uart + LINE_STATUS_REGISTER) & LSR_DATA_READY);
271 break;
273 case IIR_TX_HOLDING_REGISTER_INTERRUPT:
274 count = 16;
275 while ((! EMPTY(p->outputQueue)) && count--)
277 DEQUEUE (p->outputQueue, b);
278 outportb (p->uart + TRANSMIT_HOLDING_REGISTER, b);
280 break;
282 case IIR_MODEM_STATUS_INTERRUPT:
283 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
284 p->statusUpdated = true;
285 break;
287 case IIR_LINE_STATUS_INTERRUPT:
288 p->lineStatus = inportb (p->uart + LINE_STATUS_REGISTER);
289 p->statusUpdated = true;
290 break;
292 source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07;
295 // check for lost IIR_TX_HOLDING_REGISTER_INTERRUPT on 16550a!
296 if (inportb (p->uart + LINE_STATUS_REGISTER ) & LSR_TRANSMITTER_EMPTY)
298 count = 16;
299 while ((! EMPTY(p->outputQueue)) && count--)
301 DEQUEUE (p->outputQueue, b);
302 outportb (p->uart + TRANSMIT_HOLDING_REGISTER, b);
306 outportb (0x20, 0x20);
309 static void COM1_ISR_16550 (void)
311 ISR_16550 (handleToPort[0]);
314 static void COM2_ISR_16550 (void)
316 ISR_16550 (handleToPort[1]);
320 void TTY_GetComPortConfig (int portNumber, int *port, int *irq, int *baud, qboolean *useModem)
322 ComPort *p;
324 p = handleToPort[portNumber];
325 *port = p->uart;
326 *irq = p->irq;
327 *baud = 115200 / p->baudBits;
328 *useModem = p->useModem;
331 void TTY_SetComPortConfig (int portNumber, int port, int irq, int baud, qboolean useModem)
333 ComPort *p;
334 float temp;
336 if (useModem)
338 if (baud == 14400)
339 baud = 19200;
340 if (baud == 28800)
341 baud = 38400;
344 p = handleToPort[portNumber];
345 p->uart = port;
346 p->irq = irq;
347 p->baudBits = 115200 / baud;
348 p->useModem = useModem;
350 if (useModem)
351 temp = 1.0;
352 else
353 temp = 0.0;
355 Cvar_SetValue ("_config_com_port", (float)port);
356 Cvar_SetValue ("_config_com_irq", (float)irq);
357 Cvar_SetValue ("_config_com_baud", (float)baud);
358 Cvar_SetValue ("_config_com_modem", temp);
361 void TTY_GetModemConfig (int portNumber, char *dialType, char *clear, char *init, char *hangup)
363 ComPort *p;
365 p = handleToPort[portNumber];
366 *dialType = p->dialType;
367 Q_strcpy(clear, p->clear);
368 Q_strcpy(init, p->startup);
369 Q_strcpy(hangup, p->shutdown);
372 void TTY_SetModemConfig (int portNumber, char *dialType, char *clear, char *init, char *hangup)
374 ComPort *p;
376 p = handleToPort[portNumber];
377 p->dialType = dialType[0];
378 Q_strcpy(p->clear, clear);
379 Q_strcpy(p->startup, init);
380 Q_strcpy(p->shutdown, hangup);
382 p->modemInitialized = false;
384 Cvar_Set ("_config_modem_dialtype", dialType);
385 Cvar_Set ("_config_modem_clear", clear);
386 Cvar_Set ("_config_modem_init", init);
387 Cvar_Set ("_config_modem_hangup", hangup);
391 static void ResetComPortConfig (ComPort *p)
393 p->useModem = false;
394 p->uartType = UART_AUTO;
395 p->uart = ISA_uarts[p->portNumber];
396 p->irq = ISA_IRQs[p->portNumber];
397 p->modemStatusIgnore = MSR_CD | MSR_CTS | MSR_DSR;
398 p->baudBits = 115200 / 57600;
399 p->lineControl = LCR_DATA_BITS_8 | LCR_STOP_BITS_1 | LCR_PARITY_NONE;
400 Q_strcpy(p->clear, "ATZ");
401 Q_strcpy(p->startup, "");
402 Q_strcpy(p->shutdown, "AT H");
403 p->modemRang = false;
404 p->modemConnected = false;
405 p->statusUpdated = false;
406 p->outputQueue.head = p->outputQueue.tail = 0;
407 p->inputQueue.head = p->inputQueue.tail = 0;
411 static void ComPort_Enable(ComPort *p)
413 void (*isr)(void);
414 int n;
415 byte b;
417 if (p->enabled)
419 Con_Printf("Already enabled\n");
420 return;
423 // disable all UART interrupts
424 outportb (p->uart + INTERRUPT_ENABLE_REGISTER, 0);
426 // clear out any buffered uncoming data
427 while((inportb (p->uart + LINE_STATUS_REGISTER)) & LSR_DATA_READY)
428 inportb (p->uart + RECEIVE_BUFFER_REGISTER);
430 // get the current line and modem status
431 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
432 p->lineStatus = inportb (p->uart + LINE_STATUS_REGISTER);
434 // clear any UART interrupts
437 n = inportb (p->uart + INTERRUPT_ID_REGISTER) & 7;
438 if (n == IIR_RX_DATA_READY_INTERRUPT)
439 inportb (p->uart + RECEIVE_BUFFER_REGISTER);
440 } while (!(n & 1));
442 if (p->uartType == UART_AUTO)
444 outportb (p->uart + FIFO_CONTROL_REGISTER, FCR_FIFO_ENABLE);
445 b = inportb (p->uart + INTERRUPT_ID_REGISTER);
446 if ((b & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED)
447 p->uartType = UART_16550;
448 else
449 p->uartType = UART_8250;
452 // save the old interrupt handler
453 _go32_dpmi_get_protected_mode_interrupt_vector(p->irq + 8, &p->protectedModeSaveInfo);
455 if (p->uartType == UART_8250)
457 outportb (p->uart + FIFO_CONTROL_REGISTER, 0);
458 if (p == handleToPort[0])
459 isr = COM1_ISR_8250;
460 else
461 isr = COM2_ISR_8250;
463 else
465 outportb (p->uart + FIFO_CONTROL_REGISTER, FCR_FIFO_ENABLE | FCR_RCVR_FIFO_RESET | FCR_XMIT_FIFO_RESET | FCR_TRIGGER_08);
466 if (p == handleToPort[0])
467 isr = COM1_ISR_16550;
468 else
469 isr = COM2_ISR_16550;
472 p->protectedModeInfo.pm_offset = (int)isr;
474 n = _go32_dpmi_allocate_iret_wrapper(&p->protectedModeInfo);
475 if (n)
477 Con_Printf("serial: protected mode callback allocation failed\n");
478 return;
481 // disable interrupts at the processor
482 disable();
484 // install our interrupt handlers now
485 _go32_dpmi_set_protected_mode_interrupt_vector(p->irq + 8, &p->protectedModeInfo);
487 // enable our interrupt at the PIC
488 outportb (0x21, inportb (0x21) & ~(1<<p->irq));
490 // enable interrupts at the processor
491 enable();
493 // enable interrupts at the PIC
494 outportb (0x20, 0xc2);
496 // set baud rate & line control
497 outportb (p->uart + LINE_CONTROL_REGISTER, LCR_DLAB | p->lineControl);
498 outportb (p->uart, p->baudBits);
499 outportb (p->uart + 1, 0);
500 outportb (p->uart + LINE_CONTROL_REGISTER, p->lineControl);
502 // set modem control register & enable uart interrupt generation
503 outportb(p->uart + MODEM_CONTROL_REGISTER, MCR_OUT2 | MCR_RTS | MCR_DTR);
505 // enable the individual interrupts at the uart
506 outportb (p->uart + INTERRUPT_ENABLE_REGISTER, IER_RX_DATA_READY | IER_TX_HOLDING_REGISTER_EMPTY | IER_LINE_STATUS | IER_MODEM_STATUS);
508 p->enabled = true;
512 static void ComPort_Disable(ComPort *p)
514 if (!p->enabled)
516 Con_Printf("Already disabled\n");
517 return;
520 // disable interrupts at the uart
521 outportb (p->uart + INTERRUPT_ENABLE_REGISTER, 0);
523 // disable our interrupt at the PIC
524 outportb (0x21, inportb (0x21) | (1<<p->irq));
526 // disable interrupts at the processor
527 disable();
529 // restore the old interrupt handler
530 _go32_dpmi_set_protected_mode_interrupt_vector(p->irq + 8, &p->protectedModeSaveInfo);
531 _go32_dpmi_free_iret_wrapper(&p->protectedModeInfo);
533 // enable interrupts at the processor
534 enable();
536 p->enabled = false;
540 static int CheckStatus (ComPort *p)
542 int ret = 0;
544 if (p->statusUpdated)
546 p->statusUpdated = false;
548 if (p->lineStatus & (LSR_OVERRUN_ERROR | LSR_PARITY_ERROR | LSR_FRAMING_ERROR | LSR_BREAK_DETECT))
550 if (p->lineStatus & LSR_OVERRUN_ERROR)
551 Con_DPrintf ("Serial overrun error\n");
552 if (p->lineStatus & LSR_PARITY_ERROR)
553 Con_DPrintf ("Serial parity error\n");
554 if (p->lineStatus & LSR_FRAMING_ERROR)
555 Con_DPrintf ("Serial framing error\n");
556 if (p->lineStatus & LSR_BREAK_DETECT)
557 Con_DPrintf ("Serial break detect\n");
558 ret = ERR_TTY_LINE_STATUS;
561 if ((p->modemStatus & MODEM_STATUS_MASK) != MODEM_STATUS_MASK)
563 if (!(p->modemStatus & MSR_CTS))
564 Con_Printf ("Serial lost CTS\n");
565 if (!(p->modemStatus & MSR_DSR))
566 Con_Printf ("Serial lost DSR\n");
567 if (!(p->modemStatus & MSR_CD))
568 Con_Printf ("Serial lost Carrier\n");
569 ret = ERR_TTY_MODEM_STATUS;
573 return ret;
577 static void Modem_Init(ComPort *p)
579 double start;
580 char *response;
582 Con_Printf ("Initializing modem...\n");
584 // write 0 to MCR, wait 1/2 sec, then write the real value back again
585 // I got this from the guys at head-to-head who say it's necessary.
586 outportb(p->uart + MODEM_CONTROL_REGISTER, 0);
587 start = Sys_FloatTime();
588 while ((Sys_FloatTime() - start) < 0.5)
590 outportb(p->uart + MODEM_CONTROL_REGISTER, MCR_OUT2 | MCR_RTS | MCR_DTR);
591 start = Sys_FloatTime();
592 while ((Sys_FloatTime() - start) < 0.25)
595 if (*p->clear)
597 Modem_Command (p, p->clear);
598 start = Sys_FloatTime();
599 while(1)
601 if ((Sys_FloatTime() - start) > 3.0)
603 Con_Printf("No response - clear failed\n");
604 p->enabled = false;
605 goto failed;
607 response = Modem_Response(p);
608 if (!response)
609 continue;
610 if (Q_strncmp(response, "OK", 2) == 0)
611 break;
612 if (Q_strncmp(response, "ERROR", 5) == 0)
614 p->enabled = false;
615 goto failed;
620 if (*p->startup)
622 Modem_Command (p, p->startup);
623 start = Sys_FloatTime();
624 while(1)
626 if ((Sys_FloatTime() - start) > 3.0)
628 Con_Printf("No response - init failed\n");
629 p->enabled = false;
630 goto failed;
632 response = Modem_Response(p);
633 if (!response)
634 continue;
635 if (Q_strncmp(response, "OK", 2) == 0)
636 break;
637 if (Q_strncmp(response, "ERROR", 5) == 0)
639 p->enabled = false;
640 goto failed;
645 p->modemInitialized = true;
646 return;
648 failed:
649 if (m_return_onerror)
651 key_dest = key_menu;
652 m_state = m_return_state;
653 m_return_onerror = false;
654 Q_strcpy(m_return_reason, "Initialization Failed");
656 return;
660 void TTY_Enable(int handle)
662 ComPort *p;
664 p = handleToPort [handle];
665 if (p->enabled)
666 return;
668 ComPort_Enable(p);
670 if (p->useModem && !p->modemInitialized)
671 Modem_Init (p);
675 int TTY_Open(int serialPortNumber)
677 return serialPortNumber;
681 void TTY_Close(int handle)
683 ComPort *p;
684 double startTime;
686 p = handleToPort [handle];
688 startTime = Sys_FloatTime();
689 while ((Sys_FloatTime() - startTime) < 1.0)
690 if (EMPTY(p->outputQueue))
691 break;
693 if (p->useModem)
695 if (p->modemConnected)
696 Modem_Hangup(p);
701 int TTY_ReadByte(int handle)
703 int ret;
704 ComPort *p;
706 p = handleToPort [handle];
708 if ((ret = CheckStatus (p)) != 0)
709 return ret;
711 if (EMPTY (p->inputQueue))
712 return ERR_TTY_NODATA;
714 DEQUEUE (p->inputQueue, ret);
715 return (ret & 0xff);
719 int TTY_WriteByte(int handle, byte data)
721 ComPort *p;
723 p = handleToPort [handle];
724 if (FULL(p->outputQueue))
725 return -1;
727 ENQUEUE (p->outputQueue, data);
728 return 0;
732 void TTY_Flush(int handle)
734 byte b;
735 ComPort *p;
737 p = handleToPort [handle];
739 if (inportb (p->uart + LINE_STATUS_REGISTER ) & LSR_TRANSMITTER_EMPTY)
741 DEQUEUE (p->outputQueue, b);
742 outportb(p->uart, b);
747 int TTY_Connect(int handle, char *host)
749 double start;
750 ComPort *p;
751 char *response = NULL;
752 keydest_t save_key_dest;
753 byte dialstring[64];
754 byte b;
756 p = handleToPort[handle];
758 if ((p->modemStatus & MODEM_STATUS_MASK) != MODEM_STATUS_MASK)
760 Con_Printf ("Serial: line not ready (");
761 if ((p->modemStatus & MSR_CTS) == 0)
762 Con_Printf(" CTS");
763 if ((p->modemStatus & MSR_DSR) == 0)
764 Con_Printf(" DSR");
765 if ((p->modemStatus & MSR_CD) == 0)
766 Con_Printf(" CD");
767 Con_Printf(" )");
768 return -1;
771 // discard any scraps in the input buffer
772 while (! EMPTY (p->inputQueue))
773 DEQUEUE (p->inputQueue, b);
775 CheckStatus (p);
777 if (p->useModem)
779 save_key_dest = key_dest;
780 key_dest = key_console;
781 key_count = -2;
783 Con_Printf ("Dialing...\n");
784 sprintf(dialstring, "AT D%c %s\r", p->dialType, host);
785 Modem_Command (p, dialstring);
786 start = Sys_FloatTime();
787 while(1)
789 if ((Sys_FloatTime() - start) > 60.0)
791 Con_Printf("Dialing failure!\n");
792 break;
795 Sys_SendKeyEvents ();
796 if (key_count == 0)
798 if (key_lastpress != K_ESCAPE)
800 key_count = -2;
801 continue;
803 Con_Printf("Aborting...\n");
804 while ((Sys_FloatTime() - start) < 5.0)
806 disable();
807 p->outputQueue.head = p->outputQueue.tail = 0;
808 p->inputQueue.head = p->inputQueue.tail = 0;
809 outportb(p->uart + MODEM_CONTROL_REGISTER, inportb(p->uart + MODEM_CONTROL_REGISTER) & ~MCR_DTR);
810 enable();
811 start = Sys_FloatTime();
812 while ((Sys_FloatTime() - start) < 0.75)
814 outportb(p->uart + MODEM_CONTROL_REGISTER, inportb(p->uart + MODEM_CONTROL_REGISTER) | MCR_DTR);
815 response = "Aborted";
816 break;
819 response = Modem_Response(p);
820 if (!response)
821 continue;
822 if (Q_strncmp(response, "CONNECT", 7) == 0)
824 disable();
825 p->modemRang = true;
826 p->modemConnected = true;
827 p->outputQueue.head = p->outputQueue.tail = 0;
828 p->inputQueue.head = p->inputQueue.tail = 0;
829 enable();
830 key_dest = save_key_dest;
831 key_count = 0;
832 m_return_onerror = false;
833 return 0;
835 if (Q_strncmp(response, "NO CARRIER", 10) == 0)
836 break;
837 if (Q_strncmp(response, "NO DIALTONE", 11) == 0)
838 break;
839 if (Q_strncmp(response, "NO DIAL TONE", 12) == 0)
840 break;
841 if (Q_strncmp(response, "NO ANSWER", 9) == 0)
842 break;
843 if (Q_strncmp(response, "BUSY", 4) == 0)
844 break;
845 if (Q_strncmp(response, "ERROR", 5) == 0)
846 break;
848 key_dest = save_key_dest;
849 key_count = 0;
850 if (m_return_onerror)
852 key_dest = key_menu;
853 m_state = m_return_state;
854 m_return_onerror = false;
855 Q_strncpy(m_return_reason, response, 31);
857 return -1;
859 m_return_onerror = false;
860 return 0;
864 void TTY_Disconnect(int handle)
866 ComPort *p;
868 p = handleToPort[handle];
870 if (p->useModem && p->modemConnected)
871 Modem_Hangup(p);
875 qboolean TTY_CheckForConnection(int handle)
877 ComPort *p;
879 p = handleToPort[handle];
881 CheckStatus (p);
883 if (p->useModem)
885 if (!p->modemRang)
887 if (!Modem_Response(p))
888 return false;
890 if (Q_strncmp(p->buffer, "RING", 4) == 0)
892 Modem_Command (p, "ATA");
893 p->modemRang = true;
894 p->timestamp = net_time;
896 return false;
898 if (!p->modemConnected)
900 if ((net_time - p->timestamp) > 35.0)
902 Con_Printf("Unable to establish modem connection\n");
903 p->modemRang = false;
904 return false;
907 if (!Modem_Response(p))
908 return false;
910 if (Q_strncmp (p->buffer, "CONNECT", 7) != 0)
911 return false;
913 disable();
914 p->modemConnected = true;
915 p->outputQueue.head = p->outputQueue.tail = 0;
916 p->inputQueue.head = p->inputQueue.tail = 0;
917 enable();
918 Con_Printf("Modem Connect\n");
919 return true;
921 return true;
924 // direct connect case
925 if (EMPTY (p->inputQueue))
926 return false;
927 return true;
931 qboolean TTY_IsEnabled(int serialPortNumber)
933 return handleToPort[serialPortNumber]->enabled;
937 qboolean TTY_IsModem(int serialPortNumber)
939 return handleToPort[serialPortNumber]->useModem;
943 qboolean TTY_OutputQueueIsEmpty(int handle)
945 return EMPTY(handleToPort[handle]->outputQueue);
949 void Com_f (void)
951 ComPort *p;
952 int portNumber;
953 int i;
954 int n;
956 // first, determine which port they're messing with
957 portNumber = Q_atoi(Cmd_Argv (0) + 3) - 1;
958 if (portNumber > 1)
959 return;
960 p = handleToPort[portNumber];
962 if (Cmd_Argc() == 1)
964 Con_Printf("Settings for COM%i\n", portNumber + 1);
965 Con_Printf("enabled: %s\n", p->enabled ? "true" : "false");
966 Con_Printf("uart: ");
967 if (p->uartType == UART_AUTO)
968 Con_Printf("auto\n");
969 else if (p->uartType == UART_8250)
970 Con_Printf("8250\n");
971 else
972 Con_Printf("16550\n");
973 Con_Printf("port: %x\n", p->uart);
974 Con_Printf("irq: %i\n", p->irq);
975 Con_Printf("baud: %i\n", 115200 / p->baudBits);
976 Con_Printf("CTS: %s\n", (p->modemStatusIgnore & MSR_CTS) ? "ignored" : "honored");
977 Con_Printf("DSR: %s\n", (p->modemStatusIgnore & MSR_DSR) ? "ignored" : "honored");
978 Con_Printf("CD: %s\n", (p->modemStatusIgnore & MSR_CD) ? "ignored" : "honored");
979 if (p->useModem)
981 Con_Printf("type: Modem\n");
982 Con_Printf("clear: %s\n", p->clear);
983 Con_Printf("startup: %s\n", p->startup);
984 Con_Printf("shutdown: %s\n", p->shutdown);
986 else
987 Con_Printf("type: Direct connect\n");
989 return;
993 if (Cmd_CheckParm ("disable"))
995 if (p->enabled)
996 ComPort_Disable(p);
997 p->modemInitialized = false;
998 return;
1001 if (Cmd_CheckParm ("reset"))
1003 ComPort_Disable(p);
1004 ResetComPortConfig (p);
1005 return;
1008 if ((i = Cmd_CheckParm ("port")) != 0)
1010 if (p->enabled)
1012 Con_Printf("COM port must be disabled to change port\n");
1013 return;
1015 p->uart = Q_atoi (Cmd_Argv (i+1));
1018 if ((i = Cmd_CheckParm ("irq")) != 0)
1020 if (p->enabled)
1022 Con_Printf("COM port must be disabled to change irq\n");
1023 return;
1025 p->irq = Q_atoi (Cmd_Argv (i+1));
1028 if ((i = Cmd_CheckParm ("baud")) != 0)
1030 if (p->enabled)
1032 Con_Printf("COM port must be disabled to change baud\n");
1033 return;
1035 n = Q_atoi (Cmd_Argv (i+1));
1036 if (n == 0)
1037 Con_Printf("Invalid baud rate specified\n");
1038 else
1039 p->baudBits = 115200 / n;
1042 if (Cmd_CheckParm ("8250"))
1044 if (p->enabled)
1046 Con_Printf("COM port must be disabled to change uart\n");
1047 return;
1049 p->uartType = UART_8250;
1051 if (Cmd_CheckParm ("16550"))
1053 if (p->enabled)
1055 Con_Printf("COM port must be disabled to change uart\n");
1056 return;
1058 p->uartType = UART_16550;
1060 if (Cmd_CheckParm ("auto"))
1062 if (p->enabled)
1064 Con_Printf("COM port must be disabled to change uart\n");
1065 return;
1067 p->uartType = UART_AUTO;
1070 if (Cmd_CheckParm ("pulse"))
1071 p->dialType = 'P';
1072 if (Cmd_CheckParm ("tone"))
1073 p->dialType = 'T';
1075 if (Cmd_CheckParm ("direct"))
1076 p->useModem = false;
1077 if (Cmd_CheckParm ("modem"))
1078 p->useModem = true;
1080 if ((i = Cmd_CheckParm ("clear")) != 0)
1082 Q_strncpy (p->clear, Cmd_Argv (i+1), 16);
1085 if ((i = Cmd_CheckParm ("startup")) != 0)
1087 Q_strncpy (p->startup, Cmd_Argv (i+1), 32);
1088 p->modemInitialized = false;
1091 if ((i = Cmd_CheckParm ("shutdown")) != 0)
1093 Q_strncpy (p->shutdown, Cmd_Argv (i+1), 16);
1096 if (Cmd_CheckParm ("-cts"))
1098 p->modemStatusIgnore |= MSR_CTS;
1099 p->modemStatus |= MSR_CTS;
1102 if (Cmd_CheckParm ("+cts"))
1104 p->modemStatusIgnore &= (~MSR_CTS);
1105 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
1108 if (Cmd_CheckParm ("-dsr"))
1110 p->modemStatusIgnore |= MSR_DSR;
1111 p->modemStatus |= MSR_DSR;
1114 if (Cmd_CheckParm ("+dsr"))
1116 p->modemStatusIgnore &= (~MSR_DSR);
1117 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
1120 if (Cmd_CheckParm ("-cd"))
1122 p->modemStatusIgnore |= MSR_CD;
1123 p->modemStatus |= MSR_CD;
1126 if (Cmd_CheckParm ("+cd"))
1128 p->modemStatusIgnore &= (~MSR_CD);
1129 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
1132 if (Cmd_CheckParm ("enable"))
1134 if (!p->enabled)
1135 ComPort_Enable(p);
1136 if (p->useModem && !p->modemInitialized)
1137 Modem_Init (p);
1142 int TTY_Init(void)
1144 int n;
1145 ComPort *p;
1147 for (n = 0; n < NUM_COM_PORTS; n++)
1149 p = (ComPort *)Hunk_AllocName(sizeof(ComPort), "comport");
1150 if (p == NULL)
1151 Sys_Error("Hunk alloc failed for com port\n");
1152 p->next = portList;
1153 portList = p;
1154 handleToPort[n] = p;
1155 p->portNumber = n;
1156 p->dialType = 'T';
1157 sprintf(p->name, "com%u", n+1);
1158 Cmd_AddCommand (p->name, Com_f);
1159 ResetComPortConfig (p);
1162 GetComPortConfig = TTY_GetComPortConfig;
1163 SetComPortConfig = TTY_SetComPortConfig;
1164 GetModemConfig = TTY_GetModemConfig;
1165 SetModemConfig = TTY_SetModemConfig;
1167 return 0;
1171 void TTY_Shutdown(void)
1173 int n;
1174 ComPort *p;
1176 for (n = 0; n < NUM_COM_PORTS; n++)
1178 p = handleToPort[n];
1179 if (p->enabled)
1181 while (p->modemConnected)
1182 NET_Poll();
1183 ComPort_Disable (p);
1189 static int Modem_Command(ComPort *p, char *commandString)
1191 byte b;
1193 if (CheckStatus (p))
1194 return -1;
1196 disable();
1197 p->outputQueue.head = p->outputQueue.tail = 0;
1198 p->inputQueue.head = p->inputQueue.tail = 0;
1199 enable();
1200 p->bufferUsed = 0;
1202 while (*commandString)
1203 ENQUEUE (p->outputQueue, *commandString++);
1204 ENQUEUE (p->outputQueue, '\r');
1206 // get the transmit rolling
1207 DEQUEUE (p->outputQueue, b);
1208 outportb(p->uart, b);
1210 return 0;
1214 static char *Modem_Response(ComPort *p)
1216 byte b;
1218 if (CheckStatus (p))
1219 return NULL;
1221 while (! EMPTY(p->inputQueue))
1223 DEQUEUE (p->inputQueue, b);
1225 if (p->bufferUsed == (sizeof(p->buffer) - 1))
1226 b = '\r';
1228 if (b == '\r' && p->bufferUsed)
1230 p->buffer[p->bufferUsed] = 0;
1231 Con_Printf("%s\n", p->buffer);
1232 SCR_UpdateScreen ();
1233 p->bufferUsed = 0;
1234 return p->buffer;
1237 if (b < ' ' || b > 'z')
1238 continue;
1239 p->buffer[p->bufferUsed] = b;
1240 p->bufferUsed++;
1243 return NULL;
1247 static void Modem_Hangup2(ComPort *p);
1248 static void Modem_Hangup3(ComPort *p);
1249 static void Modem_Hangup4(ComPort *p);
1251 static void Modem_Hangup(ComPort *p)
1253 Con_Printf("Hanging up modem...\n");
1254 disable();
1255 p->modemRang = false;
1256 p->outputQueue.head = p->outputQueue.tail = 0;
1257 p->inputQueue.head = p->inputQueue.tail = 0;
1258 outportb(p->uart + MODEM_CONTROL_REGISTER, inportb(p->uart + MODEM_CONTROL_REGISTER) & ~MCR_DTR);
1259 enable();
1260 p->poll.procedure = Modem_Hangup2;
1261 p->poll.arg = p;
1262 SchedulePollProcedure(&p->poll, 1.5);
1265 static void Modem_Hangup2(ComPort *p)
1267 outportb(p->uart + MODEM_CONTROL_REGISTER, inportb(p->uart + MODEM_CONTROL_REGISTER) | MCR_DTR);
1268 Modem_Command(p, "+++");
1269 p->poll.procedure = Modem_Hangup3;
1270 SchedulePollProcedure(&p->poll, 1.5);
1273 static void Modem_Hangup3(ComPort *p)
1275 Modem_Command(p, p->shutdown);
1276 p->poll.procedure = Modem_Hangup4;
1277 SchedulePollProcedure(&p->poll, 1.5);
1280 static void Modem_Hangup4(ComPort *p)
1282 Modem_Response(p);
1283 Con_Printf("Hangup complete\n");
1284 p->modemConnected = false;