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.
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)
38 volatile byte data
[QUEUESIZE
];
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
;
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
97 #define MODEM_CONTROL_REGISTER 0x04
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
121 #define DIVISOR_LATCH_LOW 0x00
122 #define DIVISOR_LATCH_HIGH 0x01
124 #define MODEM_STATUS_MASK (MSR_CTS | MSR_DSR | MSR_CD)
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
;
139 volatile byte modemStatus
;
140 byte modemStatusIgnore
;
144 volatile qboolean statusUpdated
;
146 qboolean modemInitialized
;
148 qboolean modemConnected
;
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
);
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
)
194 while((source
= inportb (p
->uart
+ INTERRUPT_ID_REGISTER
) & 0x07) != 1)
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
);
206 p
->lineStatus
|= LSR_OVERRUN_ERROR
;
207 p
->statusUpdated
= true;
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
);
219 case IIR_MODEM_STATUS_INTERRUPT
:
220 p
->modemStatus
= (inportb (p
->uart
+ MODEM_STATUS_REGISTER
) & MODEM_STATUS_MASK
) | p
->modemStatusIgnore
;
221 p
->statusUpdated
= true;
224 case IIR_LINE_STATUS_INTERRUPT
:
225 p
->lineStatus
= inportb (p
->uart
+ LINE_STATUS_REGISTER
);
226 p
->statusUpdated
= true;
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
)
253 while((source
= inportb (p
->uart
+ INTERRUPT_ID_REGISTER
) & 0x07) != 1)
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
);
267 p
->lineStatus
|= LSR_OVERRUN_ERROR
;
268 p
->statusUpdated
= true;
270 } while (inportb (p
->uart
+ LINE_STATUS_REGISTER
) & LSR_DATA_READY
);
273 case IIR_TX_HOLDING_REGISTER_INTERRUPT
:
275 while ((! EMPTY(p
->outputQueue
)) && count
--)
277 DEQUEUE (p
->outputQueue
, b
);
278 outportb (p
->uart
+ TRANSMIT_HOLDING_REGISTER
, b
);
282 case IIR_MODEM_STATUS_INTERRUPT
:
283 p
->modemStatus
= (inportb (p
->uart
+ MODEM_STATUS_REGISTER
) & MODEM_STATUS_MASK
) | p
->modemStatusIgnore
;
284 p
->statusUpdated
= true;
287 case IIR_LINE_STATUS_INTERRUPT
:
288 p
->lineStatus
= inportb (p
->uart
+ LINE_STATUS_REGISTER
);
289 p
->statusUpdated
= true;
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
)
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
)
324 p
= handleToPort
[portNumber
];
327 *baud
= 115200 / p
->baudBits
;
328 *useModem
= p
->useModem
;
331 void TTY_SetComPortConfig (int portNumber
, int port
, int irq
, int baud
, qboolean useModem
)
344 p
= handleToPort
[portNumber
];
347 p
->baudBits
= 115200 / baud
;
348 p
->useModem
= useModem
;
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
)
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
)
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
)
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
)
419 Con_Printf("Already enabled\n");
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
);
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
;
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])
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
;
469 isr
= COM2_ISR_16550
;
472 p
->protectedModeInfo
.pm_offset
= (int)isr
;
474 n
= _go32_dpmi_allocate_iret_wrapper(&p
->protectedModeInfo
);
477 Con_Printf("serial: protected mode callback allocation failed\n");
481 // disable interrupts at the processor
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
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
);
512 static void ComPort_Disable(ComPort
*p
)
516 Con_Printf("Already disabled\n");
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
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
540 static int CheckStatus (ComPort
*p
)
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
;
577 static void Modem_Init(ComPort
*p
)
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)
597 Modem_Command (p
, p
->clear
);
598 start
= Sys_FloatTime();
601 if ((Sys_FloatTime() - start
) > 3.0)
603 Con_Printf("No response - clear failed\n");
607 response
= Modem_Response(p
);
610 if (Q_strncmp(response
, "OK", 2) == 0)
612 if (Q_strncmp(response
, "ERROR", 5) == 0)
622 Modem_Command (p
, p
->startup
);
623 start
= Sys_FloatTime();
626 if ((Sys_FloatTime() - start
) > 3.0)
628 Con_Printf("No response - init failed\n");
632 response
= Modem_Response(p
);
635 if (Q_strncmp(response
, "OK", 2) == 0)
637 if (Q_strncmp(response
, "ERROR", 5) == 0)
645 p
->modemInitialized
= true;
649 if (m_return_onerror
)
652 m_state
= m_return_state
;
653 m_return_onerror
= false;
654 Q_strcpy(m_return_reason
, "Initialization Failed");
660 void TTY_Enable(int handle
)
664 p
= handleToPort
[handle
];
670 if (p
->useModem
&& !p
->modemInitialized
)
675 int TTY_Open(int serialPortNumber
)
677 return serialPortNumber
;
681 void TTY_Close(int handle
)
686 p
= handleToPort
[handle
];
688 startTime
= Sys_FloatTime();
689 while ((Sys_FloatTime() - startTime
) < 1.0)
690 if (EMPTY(p
->outputQueue
))
695 if (p
->modemConnected
)
701 int TTY_ReadByte(int handle
)
706 p
= handleToPort
[handle
];
708 if ((ret
= CheckStatus (p
)) != 0)
711 if (EMPTY (p
->inputQueue
))
712 return ERR_TTY_NODATA
;
714 DEQUEUE (p
->inputQueue
, ret
);
719 int TTY_WriteByte(int handle
, byte data
)
723 p
= handleToPort
[handle
];
724 if (FULL(p
->outputQueue
))
727 ENQUEUE (p
->outputQueue
, data
);
732 void TTY_Flush(int handle
)
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
)
751 char *response
= NULL
;
752 keydest_t save_key_dest
;
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)
763 if ((p
->modemStatus
& MSR_DSR
) == 0)
765 if ((p
->modemStatus
& MSR_CD
) == 0)
771 // discard any scraps in the input buffer
772 while (! EMPTY (p
->inputQueue
))
773 DEQUEUE (p
->inputQueue
, b
);
779 save_key_dest
= key_dest
;
780 key_dest
= key_console
;
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();
789 if ((Sys_FloatTime() - start
) > 60.0)
791 Con_Printf("Dialing failure!\n");
795 Sys_SendKeyEvents ();
798 if (key_lastpress
!= K_ESCAPE
)
803 Con_Printf("Aborting...\n");
804 while ((Sys_FloatTime() - start
) < 5.0)
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
);
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";
819 response
= Modem_Response(p
);
822 if (Q_strncmp(response
, "CONNECT", 7) == 0)
826 p
->modemConnected
= true;
827 p
->outputQueue
.head
= p
->outputQueue
.tail
= 0;
828 p
->inputQueue
.head
= p
->inputQueue
.tail
= 0;
830 key_dest
= save_key_dest
;
832 m_return_onerror
= false;
835 if (Q_strncmp(response
, "NO CARRIER", 10) == 0)
837 if (Q_strncmp(response
, "NO DIALTONE", 11) == 0)
839 if (Q_strncmp(response
, "NO DIAL TONE", 12) == 0)
841 if (Q_strncmp(response
, "NO ANSWER", 9) == 0)
843 if (Q_strncmp(response
, "BUSY", 4) == 0)
845 if (Q_strncmp(response
, "ERROR", 5) == 0)
848 key_dest
= save_key_dest
;
850 if (m_return_onerror
)
853 m_state
= m_return_state
;
854 m_return_onerror
= false;
855 Q_strncpy(m_return_reason
, response
, 31);
859 m_return_onerror
= false;
864 void TTY_Disconnect(int handle
)
868 p
= handleToPort
[handle
];
870 if (p
->useModem
&& p
->modemConnected
)
875 qboolean
TTY_CheckForConnection(int handle
)
879 p
= handleToPort
[handle
];
887 if (!Modem_Response(p
))
890 if (Q_strncmp(p
->buffer
, "RING", 4) == 0)
892 Modem_Command (p
, "ATA");
894 p
->timestamp
= net_time
;
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;
907 if (!Modem_Response(p
))
910 if (Q_strncmp (p
->buffer
, "CONNECT", 7) != 0)
914 p
->modemConnected
= true;
915 p
->outputQueue
.head
= p
->outputQueue
.tail
= 0;
916 p
->inputQueue
.head
= p
->inputQueue
.tail
= 0;
918 Con_Printf("Modem Connect\n");
924 // direct connect case
925 if (EMPTY (p
->inputQueue
))
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
);
956 // first, determine which port they're messing with
957 portNumber
= Q_atoi(Cmd_Argv (0) + 3) - 1;
960 p
= handleToPort
[portNumber
];
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");
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");
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
);
987 Con_Printf("type: Direct connect\n");
993 if (Cmd_CheckParm ("disable"))
997 p
->modemInitialized
= false;
1001 if (Cmd_CheckParm ("reset"))
1004 ResetComPortConfig (p
);
1008 if ((i
= Cmd_CheckParm ("port")) != 0)
1012 Con_Printf("COM port must be disabled to change port\n");
1015 p
->uart
= Q_atoi (Cmd_Argv (i
+1));
1018 if ((i
= Cmd_CheckParm ("irq")) != 0)
1022 Con_Printf("COM port must be disabled to change irq\n");
1025 p
->irq
= Q_atoi (Cmd_Argv (i
+1));
1028 if ((i
= Cmd_CheckParm ("baud")) != 0)
1032 Con_Printf("COM port must be disabled to change baud\n");
1035 n
= Q_atoi (Cmd_Argv (i
+1));
1037 Con_Printf("Invalid baud rate specified\n");
1039 p
->baudBits
= 115200 / n
;
1042 if (Cmd_CheckParm ("8250"))
1046 Con_Printf("COM port must be disabled to change uart\n");
1049 p
->uartType
= UART_8250
;
1051 if (Cmd_CheckParm ("16550"))
1055 Con_Printf("COM port must be disabled to change uart\n");
1058 p
->uartType
= UART_16550
;
1060 if (Cmd_CheckParm ("auto"))
1064 Con_Printf("COM port must be disabled to change uart\n");
1067 p
->uartType
= UART_AUTO
;
1070 if (Cmd_CheckParm ("pulse"))
1072 if (Cmd_CheckParm ("tone"))
1075 if (Cmd_CheckParm ("direct"))
1076 p
->useModem
= false;
1077 if (Cmd_CheckParm ("modem"))
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"))
1136 if (p
->useModem
&& !p
->modemInitialized
)
1147 for (n
= 0; n
< NUM_COM_PORTS
; n
++)
1149 p
= (ComPort
*)Hunk_AllocName(sizeof(ComPort
), "comport");
1151 Sys_Error("Hunk alloc failed for com port\n");
1154 handleToPort
[n
] = p
;
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
;
1171 void TTY_Shutdown(void)
1176 for (n
= 0; n
< NUM_COM_PORTS
; n
++)
1178 p
= handleToPort
[n
];
1181 while (p
->modemConnected
)
1183 ComPort_Disable (p
);
1189 static int Modem_Command(ComPort
*p
, char *commandString
)
1193 if (CheckStatus (p
))
1197 p
->outputQueue
.head
= p
->outputQueue
.tail
= 0;
1198 p
->inputQueue
.head
= p
->inputQueue
.tail
= 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
);
1214 static char *Modem_Response(ComPort
*p
)
1218 if (CheckStatus (p
))
1221 while (! EMPTY(p
->inputQueue
))
1223 DEQUEUE (p
->inputQueue
, b
);
1225 if (p
->bufferUsed
== (sizeof(p
->buffer
) - 1))
1228 if (b
== '\r' && p
->bufferUsed
)
1230 p
->buffer
[p
->bufferUsed
] = 0;
1231 Con_Printf("%s\n", p
->buffer
);
1232 SCR_UpdateScreen ();
1237 if (b
< ' ' || b
> 'z')
1239 p
->buffer
[p
->bufferUsed
] = b
;
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");
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
);
1260 p
->poll
.procedure
= Modem_Hangup2
;
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
)
1283 Con_Printf("Hangup complete\n");
1284 p
->modemConnected
= false;