1 /*
2 * net_comx.c -- TTY backend for the dosquake serial network driver.
3 * from quake1 source with minor adaptations for uhexen2.
4 * $Id: net_comx.c 5004 2012-11-05 16:38:26Z sezero $
5 *
6 * Copyright (C) 1996-1997 Id Software, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * See the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include <dos.h>
25 #include <dpmi.h>
26
27 #define NUM_COM_PORTS 2
28
29 #define ERR_TTY_LINE_STATUS (-1)
30 #define ERR_TTY_MODEM_STATUS (-2)
31 #define ERR_TTY_NODATA (-3)
32
33 #define QUEUESIZE 8192
34 #define QUEUEMASK (QUEUESIZE - 1)
35
36 typedef struct
37 {
38 volatile int head;
39 volatile int tail;
40 volatile byte data[QUEUESIZE];
41 } queue;
42
43 #define FULL(q) (q.head == ((q.tail-1) & QUEUEMASK))
44 #define EMPTY(q) (q.tail == q.head)
45 #define ENQUEUE(q,b) (q.data[q.head] = b, q.head = (q.head + 1) & QUEUEMASK)
46 #define DEQUEUE(q,b) (b = q.data[q.tail], q.tail = (q.tail + 1) & QUEUEMASK)
47
48 extern cvar_t config_com_port;
49 extern cvar_t config_com_irq;
50 extern cvar_t config_com_baud;
51 extern cvar_t config_com_modem;
52 extern cvar_t config_modem_dialtype;
53 extern cvar_t config_modem_clear;
54 extern cvar_t config_modem_init;
55 extern cvar_t config_modem_hangup;
56
57 #ifdef SERVERONLY
58 #define SCR_UpdateScreen() do {} while (0)
59 #endif
60 #ifndef SERVERONLY
61 extern qboolean m_return_onerror;
62 extern char m_return_reason[32];
63 #endif
64
65 /* 8250, 16550 definitions */
66 #define TRANSMIT_HOLDING_REGISTER 0x00
67 #define RECEIVE_BUFFER_REGISTER 0x00
68 #define INTERRUPT_ENABLE_REGISTER 0x01
69 #define IER_RX_DATA_READY 0x01
70 #define IER_TX_HOLDING_REGISTER_EMPTY 0x02
71 #define IER_LINE_STATUS 0x04
72 #define IER_MODEM_STATUS 0x08
73 #define INTERRUPT_ID_REGISTER 0x02
74 #define IIR_MODEM_STATUS_INTERRUPT 0x00
75 #define IIR_TX_HOLDING_REGISTER_INTERRUPT 0x02
76 #define IIR_RX_DATA_READY_INTERRUPT 0x04
77 #define IIR_LINE_STATUS_INTERRUPT 0x06
78 #define IIR_FIFO_TIMEOUT 0x0c
79 #define IIR_FIFO_ENABLED 0xc0
80 #define FIFO_CONTROL_REGISTER 0x02
81 #define FCR_FIFO_ENABLE 0x01
82 #define FCR_RCVR_FIFO_RESET 0x02
83 #define FCR_XMIT_FIFO_RESET 0x04
84 #define FCR_TRIGGER_01 0x00
85 #define FCR_TRIGGER_04 0x40
86 #define FCR_TRIGGER_08 0x80
87 #define FCR_TRIGGER_16 0xc0
88 #define LINE_CONTROL_REGISTER 0x03
89 #define LCR_DATA_BITS_5 0x00
90 #define LCR_DATA_BITS_6 0x01
91 #define LCR_DATA_BITS_7 0x02
92 #define LCR_DATA_BITS_8 0x03
93 #define LCR_STOP_BITS_1 0x00
94 #define LCR_STOP_BITS_2 0x04
95 #define LCR_PARITY_NONE 0x00
96 #define LCR_PARITY_ODD 0x08
97 #define LCR_PARITY_EVEN 0x18
98 #define LCR_PARITY_MARK 0x28
99 #define LCR_PARITY_SPACE 0x38
100 #define LCR_SET_BREAK 0x40
101 #define LCR_DLAB 0x80
102 #define MODEM_CONTROL_REGISTER 0x04
103 #define MCR_DTR 0x01
104 #define MCR_RTS 0x02
105 #define MCR_OUT1 0x04
106 #define MCR_OUT2 0x08
107 #define MCR_LOOPBACK 0x10
108 #define LINE_STATUS_REGISTER 0x05
109 #define LSR_DATA_READY 0x01
110 #define LSR_OVERRUN_ERROR 0x02
111 #define LSR_PARITY_ERROR 0x04
112 #define LSR_FRAMING_ERROR 0x08
113 #define LSR_BREAK_DETECT 0x10
114 #define LSR_TRANSMITTER_BUFFER_EMPTY 0x20
115 #define LSR_TRANSMITTER_EMPTY 0x40
116 #define LSR_FIFO_DIRTY 0x80
117 #define MODEM_STATUS_REGISTER 0x06
118 #define MSR_DELTA_CTS 0x01
119 #define MSR_DELTA_DSR 0x02
120 #define MSR_DELTA_RI 0x04
121 #define MSR_DELTA_CD 0x08
122 #define MSR_CTS 0x10
123 #define MSR_DSR 0x20
124 #define MSR_RI 0x40
125 #define MSR_CD 0x80
126 #define DIVISOR_LATCH_LOW 0x00
127 #define DIVISOR_LATCH_HIGH 0x01
128
129 #define MODEM_STATUS_MASK (MSR_CTS | MSR_DSR | MSR_CD)
130
131 #define UART_AUTO 0
132 #define UART_8250 1
133 #define UART_16550 2
134
135 static const int ISA_uarts[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
136 static const int ISA_IRQs[] = {4, 3, 4, 3};
137
138 typedef struct ComPort_s
139 {
140 struct ComPort_s *next;
141 _go32_dpmi_seginfo protectedModeInfo;
142 _go32_dpmi_seginfo protectedModeSaveInfo;
143 int uart;
144 volatile byte modemStatus;
145 byte modemStatusIgnore;
146 byte lineStatus;
147 byte bufferUsed;
148 qboolean enabled;
149 volatile qboolean statusUpdated;
150 qboolean useModem;
151 qboolean modemInitialized;
152 qboolean modemRang;
153 qboolean modemConnected;
154 queue inputQueue;
155 queue outputQueue;
156 char clear[16];
157 char startup[32];
158 char shutdown[16];
159 char buffer[128];
160 PollProcedure poll;
161 double timestamp;
162 byte uartType;
163 byte irq;
164 byte baudBits;
165 byte lineControl;
166 byte portNumber;
167 char dialType;
168 char name[4];
169 } ComPort;
170
171 static ComPort *portList = NULL;
172 static ComPort *handleToPort [NUM_COM_PORTS];
173
174 static int Modem_Command (ComPort *p, const char *commandString);
175 static const char *Modem_Response (ComPort *p);
176 static void Modem_Hangup (void *p);
177
178 int TTY_Init (void);
179 void TTY_Shutdown (void);
180 int TTY_Open (int serialPortNumber);
181 void TTY_Close (int handle);
182 int TTY_ReadByte (int handle);
183 int TTY_WriteByte (int handle, byte data);
184 void TTY_Flush (int handle);
185 #ifndef SERVERONLY
186 int TTY_Connect (int handle, const char *host);
187 #endif
188 void TTY_Disconnect (int handle);
189 qboolean TTY_CheckForConnection (int handle);
190 qboolean TTY_IsEnabled (int serialPortNumber);
191 qboolean TTY_IsModem (int serialPortNumber);
192 qboolean TTY_OutputQueueIsEmpty (int handle);
193
ISR_8250(ComPort * p)194 static void ISR_8250 (ComPort *p)
195 {
196 byte source = 0;
197 byte b;
198
199 disable();
200
201 while ((source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07) != 1)
202 {
203 switch (source)
204 {
205 case IIR_RX_DATA_READY_INTERRUPT:
206 b = inportb (p->uart + RECEIVE_BUFFER_REGISTER);
207 if (! FULL(p->inputQueue))
208 {
209 ENQUEUE (p->inputQueue, b);
210 }
211 else
212 {
213 p->lineStatus |= LSR_OVERRUN_ERROR;
214 p->statusUpdated = true;
215 }
216 break;
217
218 case IIR_TX_HOLDING_REGISTER_INTERRUPT:
219 if (! EMPTY(p->outputQueue))
220 {
221 DEQUEUE (p->outputQueue, b);
222 outportb (p->uart + TRANSMIT_HOLDING_REGISTER, b);
223 }
224 break;
225
226 case IIR_MODEM_STATUS_INTERRUPT:
227 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
228 p->statusUpdated = true;
229 break;
230
231 case IIR_LINE_STATUS_INTERRUPT:
232 p->lineStatus = inportb (p->uart + LINE_STATUS_REGISTER);
233 p->statusUpdated = true;
234 break;
235 }
236 source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07;
237 }
238 outportb (0x20, 0x20);
239 }
240
COM1_ISR_8250(void)241 static void COM1_ISR_8250 (void)
242 {
243 ISR_8250 (handleToPort[0]);
244 }
245
COM2_ISR_8250(void)246 static void COM2_ISR_8250 (void)
247 {
248 ISR_8250 (handleToPort[1]);
249 }
250
ISR_16550(ComPort * p)251 static void ISR_16550 (ComPort *p)
252 {
253 int count;
254 byte source;
255 byte b;
256
257 disable();
258 while ((source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07) != 1)
259 {
260 switch (source)
261 {
262 case IIR_RX_DATA_READY_INTERRUPT:
263 do
264 {
265 b = inportb (p->uart + RECEIVE_BUFFER_REGISTER);
266 if (!FULL(p->inputQueue))
267 {
268 ENQUEUE (p->inputQueue, b);
269 }
270 else
271 {
272 p->lineStatus |= LSR_OVERRUN_ERROR;
273 p->statusUpdated = true;
274 }
275 } while (inportb (p->uart + LINE_STATUS_REGISTER) & LSR_DATA_READY);
276 break;
277
278 case IIR_TX_HOLDING_REGISTER_INTERRUPT:
279 count = 16;
280 while ((! EMPTY(p->outputQueue)) && count--)
281 {
282 DEQUEUE (p->outputQueue, b);
283 outportb (p->uart + TRANSMIT_HOLDING_REGISTER, b);
284 }
285 break;
286
287 case IIR_MODEM_STATUS_INTERRUPT:
288 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
289 p->statusUpdated = true;
290 break;
291
292 case IIR_LINE_STATUS_INTERRUPT:
293 p->lineStatus = inportb (p->uart + LINE_STATUS_REGISTER);
294 p->statusUpdated = true;
295 break;
296 }
297 source = inportb (p->uart + INTERRUPT_ID_REGISTER) & 0x07;
298 }
299
300 /* check for lost IIR_TX_HOLDING_REGISTER_INTERRUPT on 16550a ! */
301 if (inportb (p->uart + LINE_STATUS_REGISTER ) & LSR_TRANSMITTER_EMPTY)
302 {
303 count = 16;
304 while ((! EMPTY(p->outputQueue)) && count--)
305 {
306 DEQUEUE (p->outputQueue, b);
307 outportb (p->uart + TRANSMIT_HOLDING_REGISTER, b);
308 }
309 }
310
311 outportb (0x20, 0x20);
312 }
313
COM1_ISR_16550(void)314 static void COM1_ISR_16550 (void)
315 {
316 ISR_16550 (handleToPort[0]);
317 }
318
COM2_ISR_16550(void)319 static void COM2_ISR_16550 (void)
320 {
321 ISR_16550 (handleToPort[1]);
322 }
323
324
TTY_GetComPortConfig(int portNumber,int * port,int * irq,int * baud,qboolean * useModem)325 static void TTY_GetComPortConfig (int portNumber, int *port, int *irq, int *baud, qboolean *useModem)
326 {
327 ComPort *p;
328
329 p = handleToPort[portNumber];
330 *port = p->uart;
331 *irq = p->irq;
332 *baud = 115200 / p->baudBits;
333 *useModem = p->useModem;
334 }
335
TTY_SetComPortConfig(int portNumber,int port,int irq,int baud,qboolean useModem)336 static void TTY_SetComPortConfig (int portNumber, int port, int irq, int baud, qboolean useModem)
337 {
338 ComPort *p;
339 float temp;
340
341 if (useModem)
342 {
343 if (baud == 14400)
344 baud = 19200;
345 if (baud == 28800)
346 baud = 38400;
347 }
348
349 p = handleToPort[portNumber];
350 p->uart = port;
351 p->irq = irq;
352 p->baudBits = 115200 / baud;
353 p->useModem = useModem;
354
355 if (useModem)
356 temp = 1.0;
357 else
358 temp = 0.0;
359
360 Cvar_SetValueQuick (&config_com_port, (float)port);
361 Cvar_SetValueQuick (&config_com_irq, (float)irq);
362 Cvar_SetValueQuick (&config_com_baud, (float)baud);
363 Cvar_SetValueQuick (&config_com_modem, temp);
364 }
365
TTY_GetModemConfig(int portNumber,char * dialType,char * clear,char * init,char * hangup)366 static void TTY_GetModemConfig (int portNumber, char *dialType, char *clear, char *init, char *hangup)
367 {
368 ComPort *p;
369
370 p = handleToPort[portNumber];
371 *dialType = p->dialType;
372 strcpy(clear, p->clear);
373 strcpy(init, p->startup);
374 strcpy(hangup, p->shutdown);
375 }
376
TTY_SetModemConfig(int portNumber,const char * dialType,const char * clear,const char * init,const char * hangup)377 static void TTY_SetModemConfig (int portNumber, const char *dialType, const char *clear, const char *init, const char *hangup)
378 {
379 ComPort *p;
380
381 p = handleToPort[portNumber];
382 p->dialType = dialType[0];
383 strcpy(p->clear, clear);
384 strcpy(p->startup, init);
385 strcpy(p->shutdown, hangup);
386
387 p->modemInitialized = false;
388
389 Cvar_SetQuick (&config_modem_dialtype, dialType);
390 Cvar_SetQuick (&config_modem_clear, clear);
391 Cvar_SetQuick (&config_modem_init, init);
392 Cvar_SetQuick (&config_modem_hangup, hangup);
393 }
394
395
ResetComPortConfig(ComPort * p)396 static void ResetComPortConfig (ComPort *p)
397 {
398 p->useModem = false;
399 p->uartType = UART_AUTO;
400 p->uart = ISA_uarts[p->portNumber];
401 p->irq = ISA_IRQs[p->portNumber];
402 p->modemStatusIgnore = MSR_CD | MSR_CTS | MSR_DSR;
403 p->baudBits = 115200 / 57600;
404 p->lineControl = LCR_DATA_BITS_8 | LCR_STOP_BITS_1 | LCR_PARITY_NONE;
405 strcpy(p->clear, "ATZ");
406 strcpy(p->startup, "");
407 strcpy(p->shutdown, "AT H");
408 p->modemRang = false;
409 p->modemConnected = false;
410 p->statusUpdated = false;
411 p->outputQueue.head = p->outputQueue.tail = 0;
412 p->inputQueue.head = p->inputQueue.tail = 0;
413 }
414
415
ComPort_Enable(ComPort * p)416 static void ComPort_Enable (ComPort *p)
417 {
418 void (*isr)(void);
419 int n;
420 byte b;
421
422 if (p->enabled)
423 {
424 Con_Printf("Already enabled\n");
425 return;
426 }
427
428 /* disable all UART interrupts */
429 outportb (p->uart + INTERRUPT_ENABLE_REGISTER, 0);
430
431 /* clear out any buffered uncoming data */
432 while ((inportb (p->uart + LINE_STATUS_REGISTER)) & LSR_DATA_READY)
433 inportb (p->uart + RECEIVE_BUFFER_REGISTER);
434
435 /* get the current line and modem status */
436 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
437 p->lineStatus = inportb (p->uart + LINE_STATUS_REGISTER);
438
439 /* clear any UART interrupts */
440 do
441 {
442 n = inportb (p->uart + INTERRUPT_ID_REGISTER) & 7;
443 if (n == IIR_RX_DATA_READY_INTERRUPT)
444 inportb (p->uart + RECEIVE_BUFFER_REGISTER);
445 } while (!(n & 1));
446
447 if (p->uartType == UART_AUTO)
448 {
449 outportb (p->uart + FIFO_CONTROL_REGISTER, FCR_FIFO_ENABLE);
450 b = inportb (p->uart + INTERRUPT_ID_REGISTER);
451 if ((b & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED)
452 p->uartType = UART_16550;
453 else
454 p->uartType = UART_8250;
455 }
456
457 /* save the old interrupt handler */
458 _go32_dpmi_get_protected_mode_interrupt_vector(p->irq + 8, &p->protectedModeSaveInfo);
459
460 if (p->uartType == UART_8250)
461 {
462 outportb (p->uart + FIFO_CONTROL_REGISTER, 0);
463 if (p == handleToPort[0])
464 isr = COM1_ISR_8250;
465 else
466 isr = COM2_ISR_8250;
467 }
468 else
469 {
470 outportb (p->uart + FIFO_CONTROL_REGISTER, FCR_FIFO_ENABLE | FCR_RCVR_FIFO_RESET | FCR_XMIT_FIFO_RESET | FCR_TRIGGER_08);
471 if (p == handleToPort[0])
472 isr = COM1_ISR_16550;
473 else
474 isr = COM2_ISR_16550;
475 }
476
477 p->protectedModeInfo.pm_offset = (int)isr;
478
479 n = _go32_dpmi_allocate_iret_wrapper(&p->protectedModeInfo);
480 if (n)
481 {
482 Con_Printf("serial: protected mode callback allocation failed\n");
483 return;
484 }
485
486 /* disable interrupts at the processor */
487 disable();
488
489 /* install our interrupt handlers now */
490 _go32_dpmi_set_protected_mode_interrupt_vector(p->irq + 8, &p->protectedModeInfo);
491
492 /* enable our interrupt at the PIC */
493 outportb (0x21, inportb (0x21) & ~(1<<p->irq));
494
495 /* enable interrupts at the processor */
496 enable();
497
498 /* enable interrupts at the PIC */
499 outportb (0x20, 0xc2);
500
501 /* set baud rate & line control */
502 outportb (p->uart + LINE_CONTROL_REGISTER, LCR_DLAB | p->lineControl);
503 outportb (p->uart, p->baudBits);
504 outportb (p->uart + 1, 0);
505 outportb (p->uart + LINE_CONTROL_REGISTER, p->lineControl);
506
507 /* set modem control register & enable uart interrupt generation */
508 outportb(p->uart + MODEM_CONTROL_REGISTER, MCR_OUT2 | MCR_RTS | MCR_DTR);
509
510 /* enable the individual interrupts at the uart */
511 outportb (p->uart + INTERRUPT_ENABLE_REGISTER, IER_RX_DATA_READY | IER_TX_HOLDING_REGISTER_EMPTY | IER_LINE_STATUS | IER_MODEM_STATUS);
512
513 p->enabled = true;
514 }
515
516
ComPort_Disable(ComPort * p)517 static void ComPort_Disable (ComPort *p)
518 {
519 if (!p->enabled)
520 {
521 Con_Printf("Already disabled\n");
522 return;
523 }
524
525 /* disable interrupts at the uart */
526 outportb (p->uart + INTERRUPT_ENABLE_REGISTER, 0);
527
528 /* disable our interrupt at the PIC */
529 outportb (0x21, inportb (0x21) | (1<<p->irq));
530
531 /* disable interrupts at the processor */
532 disable();
533
534 /* restore the old interrupt handler */
535 _go32_dpmi_set_protected_mode_interrupt_vector(p->irq + 8, &p->protectedModeSaveInfo);
536 _go32_dpmi_free_iret_wrapper(&p->protectedModeInfo);
537
538 /* enable interrupts at the processor */
539 enable();
540
541 p->enabled = false;
542 }
543
544
CheckStatus(ComPort * p)545 static int CheckStatus (ComPort *p)
546 {
547 int ret = 0;
548
549 if (p->statusUpdated)
550 {
551 p->statusUpdated = false;
552
553 if (p->lineStatus & (LSR_OVERRUN_ERROR | LSR_PARITY_ERROR | LSR_FRAMING_ERROR | LSR_BREAK_DETECT))
554 {
555 if (p->lineStatus & LSR_OVERRUN_ERROR)
556 Con_DPrintf ("Serial overrun error\n");
557 if (p->lineStatus & LSR_PARITY_ERROR)
558 Con_DPrintf ("Serial parity error\n");
559 if (p->lineStatus & LSR_FRAMING_ERROR)
560 Con_DPrintf ("Serial framing error\n");
561 if (p->lineStatus & LSR_BREAK_DETECT)
562 Con_DPrintf ("Serial break detect\n");
563 ret = ERR_TTY_LINE_STATUS;
564 }
565
566 if ((p->modemStatus & MODEM_STATUS_MASK) != MODEM_STATUS_MASK)
567 {
568 if (!(p->modemStatus & MSR_CTS))
569 Con_Printf ("Serial lost CTS\n");
570 if (!(p->modemStatus & MSR_DSR))
571 Con_Printf ("Serial lost DSR\n");
572 if (!(p->modemStatus & MSR_CD))
573 Con_Printf ("Serial lost Carrier\n");
574 ret = ERR_TTY_MODEM_STATUS;
575 }
576 }
577
578 return ret;
579 }
580
581
Modem_Init(ComPort * p)582 static void Modem_Init (ComPort *p)
583 {
584 double start;
585 const char *response;
586
587 Con_Printf ("Initializing modem...\n");
588
589 /* write 0 to MCR, wait 1/2 sec, then write the real value back again
590 * I got this from the guys at head-to-head who say it's necessary. */
591 outportb(p->uart + MODEM_CONTROL_REGISTER, 0);
592 start = Sys_DoubleTime();
593 while ((Sys_DoubleTime() - start) < 0.5)
594 ;
595 outportb(p->uart + MODEM_CONTROL_REGISTER, MCR_OUT2 | MCR_RTS | MCR_DTR);
596 start = Sys_DoubleTime();
597 while ((Sys_DoubleTime() - start) < 0.25)
598 ;
599
600 if (*p->clear)
601 {
602 Modem_Command (p, p->clear);
603 start = Sys_DoubleTime();
604 while (1)
605 {
606 if ((Sys_DoubleTime() - start) > 3.0)
607 {
608 Con_Printf("No response - clear failed\n");
609 p->enabled = false;
610 goto failed;
611 }
612 response = Modem_Response (p);
613 if (!response)
614 continue;
615 if (strncmp(response, "OK", 2) == 0)
616 break;
617 if (strncmp(response, "ERROR", 5) == 0)
618 {
619 p->enabled = false;
620 goto failed;
621 }
622 }
623 }
624
625 if (*p->startup)
626 {
627 Modem_Command (p, p->startup);
628 start = Sys_DoubleTime();
629 while (1)
630 {
631 if ((Sys_DoubleTime() - start) > 3.0)
632 {
633 Con_Printf("No response - init failed\n");
634 p->enabled = false;
635 goto failed;
636 }
637 response = Modem_Response (p);
638 if (!response)
639 continue;
640 if (strncmp(response, "OK", 2) == 0)
641 break;
642 if (strncmp(response, "ERROR", 5) == 0)
643 {
644 p->enabled = false;
645 goto failed;
646 }
647 }
648 }
649
650 p->modemInitialized = true;
651 return;
652
653 failed:
654 #if !defined(SERVERONLY)
655 if (m_return_onerror)
656 {
657 Key_SetDest (key_menu);
658 m_state = m_return_state;
659 m_return_onerror = false;
660 strcpy(m_return_reason, "Initialization Failed");
661 }
662 #endif /* SERVERONLY */
663 return;
664 }
665
666
TTY_Enable(int handle)667 void TTY_Enable (int handle)
668 {
669 ComPort *p;
670
671 p = handleToPort [handle];
672 if (p->enabled)
673 return;
674
675 ComPort_Enable(p);
676
677 if (p->useModem && !p->modemInitialized)
678 Modem_Init (p);
679 }
680
681
TTY_Open(int serialPortNumber)682 int TTY_Open (int serialPortNumber)
683 {
684 return serialPortNumber;
685 }
686
687
TTY_Close(int handle)688 void TTY_Close (int handle)
689 {
690 ComPort *p;
691 double startTime;
692
693 p = handleToPort [handle];
694
695 startTime = Sys_DoubleTime();
696 while ((Sys_DoubleTime() - startTime) < 1.0)
697 {
698 if (EMPTY(p->outputQueue))
699 break;
700 }
701
702 if (p->useModem)
703 {
704 if (p->modemConnected)
705 Modem_Hangup(p);
706 }
707 }
708
709
TTY_ReadByte(int handle)710 int TTY_ReadByte (int handle)
711 {
712 int ret;
713 ComPort *p;
714
715 p = handleToPort [handle];
716
717 if ((ret = CheckStatus (p)) != 0)
718 return ret;
719
720 if (EMPTY (p->inputQueue))
721 return ERR_TTY_NODATA;
722
723 DEQUEUE (p->inputQueue, ret);
724 return (ret & 0xff);
725 }
726
727
TTY_WriteByte(int handle,byte data)728 int TTY_WriteByte (int handle, byte data)
729 {
730 ComPort *p;
731
732 p = handleToPort [handle];
733 if (FULL(p->outputQueue))
734 return -1;
735
736 ENQUEUE (p->outputQueue, data);
737 return 0;
738 }
739
740
TTY_Flush(int handle)741 void TTY_Flush (int handle)
742 {
743 byte b;
744 ComPort *p;
745
746 p = handleToPort [handle];
747
748 if (inportb (p->uart + LINE_STATUS_REGISTER ) & LSR_TRANSMITTER_EMPTY)
749 {
750 DEQUEUE (p->outputQueue, b);
751 outportb(p->uart, b);
752 }
753 }
754
755
756 #if !defined(SERVERONLY)
TTY_Connect(int handle,const char * host)757 int TTY_Connect (int handle, const char *host)
758 {
759 double start;
760 ComPort *p;
761 const char *response = NULL;
762 keydest_t save_key_dest;
763 char dialstring[64];
764 byte b;
765
766 p = handleToPort[handle];
767
768 if ((p->modemStatus & MODEM_STATUS_MASK) != MODEM_STATUS_MASK)
769 {
770 Con_Printf ("Serial: line not ready (");
771 if ((p->modemStatus & MSR_CTS) == 0)
772 Con_Printf(" CTS");
773 if ((p->modemStatus & MSR_DSR) == 0)
774 Con_Printf(" DSR");
775 if ((p->modemStatus & MSR_CD) == 0)
776 Con_Printf(" CD");
777 Con_Printf(" )");
778 return -1;
779 }
780
781 /* discard any scraps in the input buffer */
782 while (! EMPTY (p->inputQueue))
783 DEQUEUE (p->inputQueue, b);
784
785 CheckStatus (p);
786
787 if (p->useModem)
788 {
789 save_key_dest = Key_GetDest ();
790 Key_SetDest (key_console);
791 key_count = -2;
792
793 Con_Printf ("Dialing...\n");
794 sprintf(dialstring, "AT D%c %s\r", p->dialType, host);
795 Modem_Command (p, dialstring);
796 start = Sys_DoubleTime();
797 while (1)
798 {
799 if ((Sys_DoubleTime() - start) > 60.0)
800 {
801 Con_Printf("Dialing failure!\n");
802 break;
803 }
804
805 Sys_SendKeyEvents ();
806 if (key_count == 0)
807 {
808 if (key_lastpress != K_ESCAPE)
809 {
810 key_count = -2;
811 continue;
812 }
813 Con_Printf("Aborting...\n");
814 while ((Sys_DoubleTime() - start) < 5.0)
815 ;
816 disable();
817 p->outputQueue.head = p->outputQueue.tail = 0;
818 p->inputQueue.head = p->inputQueue.tail = 0;
819 outportb(p->uart + MODEM_CONTROL_REGISTER, inportb(p->uart + MODEM_CONTROL_REGISTER) & ~MCR_DTR);
820 enable();
821 start = Sys_DoubleTime();
822 while ((Sys_DoubleTime() - start) < 0.75)
823 ;
824 outportb(p->uart + MODEM_CONTROL_REGISTER, inportb(p->uart + MODEM_CONTROL_REGISTER) | MCR_DTR);
825 response = "Aborted";
826 break;
827 }
828
829 response = Modem_Response (p);
830 if (!response)
831 continue;
832 if (strncmp(response, "CONNECT", 7) == 0)
833 {
834 disable();
835 p->modemRang = true;
836 p->modemConnected = true;
837 p->outputQueue.head = p->outputQueue.tail = 0;
838 p->inputQueue.head = p->inputQueue.tail = 0;
839 enable();
840 Key_SetDest (save_key_dest);
841 key_count = 0;
842 m_return_onerror = false;
843 return 0;
844 }
845 if (strncmp(response, "NO CARRIER", 10) == 0)
846 break;
847 if (strncmp(response, "NO DIALTONE", 11) == 0)
848 break;
849 if (strncmp(response, "NO DIAL TONE", 12) == 0)
850 break;
851 if (strncmp(response, "NO ANSWER", 9) == 0)
852 break;
853 if (strncmp(response, "BUSY", 4) == 0)
854 break;
855 if (strncmp(response, "ERROR", 5) == 0)
856 break;
857 }
858 Key_SetDest (save_key_dest);
859 key_count = 0;
860 if (m_return_onerror)
861 {
862 Key_SetDest (key_menu);
863 m_state = m_return_state;
864 m_return_onerror = false;
865 q_strlcpy(m_return_reason, response, sizeof(m_return_reason));
866 }
867 return -1;
868 }
869 m_return_onerror = false;
870 return 0;
871 }
872 #endif /* SERVERONLY */
873
874
TTY_Disconnect(int handle)875 void TTY_Disconnect (int handle)
876 {
877 ComPort *p;
878
879 p = handleToPort[handle];
880
881 if (p->useModem && p->modemConnected)
882 Modem_Hangup(p);
883 }
884
885
TTY_CheckForConnection(int handle)886 qboolean TTY_CheckForConnection (int handle)
887 {
888 ComPort *p;
889
890 p = handleToPort[handle];
891
892 CheckStatus (p);
893
894 if (p->useModem)
895 {
896 if (!p->modemRang)
897 {
898 if (!Modem_Response(p))
899 return false;
900
901 if (strncmp(p->buffer, "RING", 4) == 0)
902 {
903 Modem_Command (p, "ATA");
904 p->modemRang = true;
905 p->timestamp = net_time;
906 }
907 return false;
908 }
909 if (!p->modemConnected)
910 {
911 if ((net_time - p->timestamp) > 35.0)
912 {
913 Con_Printf("Unable to establish modem connection\n");
914 p->modemRang = false;
915 return false;
916 }
917
918 if (!Modem_Response(p))
919 return false;
920
921 if (strncmp (p->buffer, "CONNECT", 7) != 0)
922 return false;
923
924 disable();
925 p->modemConnected = true;
926 p->outputQueue.head = p->outputQueue.tail = 0;
927 p->inputQueue.head = p->inputQueue.tail = 0;
928 enable();
929 Con_Printf("Modem Connect\n");
930 return true;
931 }
932 return true;
933 }
934
935 /* direct connect case */
936 if (EMPTY (p->inputQueue))
937 return false;
938 return true;
939 }
940
941
TTY_IsEnabled(int serialPortNumber)942 qboolean TTY_IsEnabled (int serialPortNumber)
943 {
944 return handleToPort[serialPortNumber]->enabled;
945 }
946
947
TTY_IsModem(int serialPortNumber)948 qboolean TTY_IsModem (int serialPortNumber)
949 {
950 return handleToPort[serialPortNumber]->useModem;
951 }
952
953
TTY_OutputQueueIsEmpty(int handle)954 qboolean TTY_OutputQueueIsEmpty (int handle)
955 {
956 return EMPTY(handleToPort[handle]->outputQueue);
957 }
958
959
Com_f(void)960 void Com_f (void)
961 {
962 ComPort *p;
963 int portNumber;
964 int i;
965 int n;
966
967 /* first, determine which port they're messing with */
968 portNumber = atoi(Cmd_Argv (0) + 3) - 1;
969 if (portNumber > 1)
970 return;
971 p = handleToPort[portNumber];
972
973 if (Cmd_Argc() == 1)
974 {
975 Con_Printf("Settings for COM%i\n", portNumber + 1);
976 Con_Printf("enabled: %s\n", p->enabled ? "true" : "false");
977 Con_Printf("uart: ");
978 if (p->uartType == UART_AUTO)
979 Con_Printf("auto\n");
980 else if (p->uartType == UART_8250)
981 Con_Printf("8250\n");
982 else
983 Con_Printf("16550\n");
984 Con_Printf("port: %x\n", p->uart);
985 Con_Printf("irq: %i\n", p->irq);
986 Con_Printf("baud: %i\n", 115200 / p->baudBits);
987 Con_Printf("CTS: %s\n", (p->modemStatusIgnore & MSR_CTS) ? "ignored" : "honored");
988 Con_Printf("DSR: %s\n", (p->modemStatusIgnore & MSR_DSR) ? "ignored" : "honored");
989 Con_Printf("CD: %s\n", (p->modemStatusIgnore & MSR_CD) ? "ignored" : "honored");
990 if (p->useModem)
991 {
992 Con_Printf("type: Modem\n");
993 Con_Printf("clear: %s\n", p->clear);
994 Con_Printf("startup: %s\n", p->startup);
995 Con_Printf("shutdown: %s\n", p->shutdown);
996 }
997 else
998 Con_Printf("type: Direct connect\n");
999
1000 return;
1001 }
1002
1003 if (Cmd_CheckParm ("disable"))
1004 {
1005 if (p->enabled)
1006 ComPort_Disable(p);
1007 p->modemInitialized = false;
1008 return;
1009 }
1010
1011 if (Cmd_CheckParm ("reset"))
1012 {
1013 ComPort_Disable(p);
1014 ResetComPortConfig (p);
1015 return;
1016 }
1017
1018 if ((i = Cmd_CheckParm ("port")) != 0)
1019 {
1020 if (p->enabled)
1021 {
1022 Con_Printf("COM port must be disabled to change port\n");
1023 return;
1024 }
1025 p->uart = atoi (Cmd_Argv (i+1));
1026 }
1027
1028 if ((i = Cmd_CheckParm ("irq")) != 0)
1029 {
1030 if (p->enabled)
1031 {
1032 Con_Printf("COM port must be disabled to change irq\n");
1033 return;
1034 }
1035 p->irq = atoi (Cmd_Argv (i+1));
1036 }
1037
1038 if ((i = Cmd_CheckParm ("baud")) != 0)
1039 {
1040 if (p->enabled)
1041 {
1042 Con_Printf("COM port must be disabled to change baud\n");
1043 return;
1044 }
1045 n = atoi (Cmd_Argv (i+1));
1046 if (n == 0)
1047 Con_Printf("Invalid baud rate specified\n");
1048 else
1049 p->baudBits = 115200 / n;
1050 }
1051
1052 if (Cmd_CheckParm ("8250"))
1053 {
1054 if (p->enabled)
1055 {
1056 Con_Printf("COM port must be disabled to change uart\n");
1057 return;
1058 }
1059 p->uartType = UART_8250;
1060 }
1061 if (Cmd_CheckParm ("16550"))
1062 {
1063 if (p->enabled)
1064 {
1065 Con_Printf("COM port must be disabled to change uart\n");
1066 return;
1067 }
1068 p->uartType = UART_16550;
1069 }
1070 if (Cmd_CheckParm ("auto"))
1071 {
1072 if (p->enabled)
1073 {
1074 Con_Printf("COM port must be disabled to change uart\n");
1075 return;
1076 }
1077 p->uartType = UART_AUTO;
1078 }
1079
1080 if (Cmd_CheckParm ("pulse"))
1081 p->dialType = 'P';
1082 if (Cmd_CheckParm ("tone"))
1083 p->dialType = 'T';
1084
1085 if (Cmd_CheckParm ("direct"))
1086 p->useModem = false;
1087 if (Cmd_CheckParm ("modem"))
1088 p->useModem = true;
1089
1090 if ((i = Cmd_CheckParm ("clear")) != 0)
1091 {
1092 q_strlcpy (p->clear, Cmd_Argv (i+1), 16);
1093 }
1094
1095 if ((i = Cmd_CheckParm ("startup")) != 0)
1096 {
1097 q_strlcpy (p->startup, Cmd_Argv (i+1), 32);
1098 p->modemInitialized = false;
1099 }
1100
1101 if ((i = Cmd_CheckParm ("shutdown")) != 0)
1102 {
1103 q_strlcpy (p->shutdown, Cmd_Argv (i+1), 16);
1104 }
1105
1106 if (Cmd_CheckParm ("-cts"))
1107 {
1108 p->modemStatusIgnore |= MSR_CTS;
1109 p->modemStatus |= MSR_CTS;
1110 }
1111
1112 if (Cmd_CheckParm ("+cts"))
1113 {
1114 p->modemStatusIgnore &= (~MSR_CTS);
1115 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
1116 }
1117
1118 if (Cmd_CheckParm ("-dsr"))
1119 {
1120 p->modemStatusIgnore |= MSR_DSR;
1121 p->modemStatus |= MSR_DSR;
1122 }
1123
1124 if (Cmd_CheckParm ("+dsr"))
1125 {
1126 p->modemStatusIgnore &= (~MSR_DSR);
1127 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
1128 }
1129
1130 if (Cmd_CheckParm ("-cd"))
1131 {
1132 p->modemStatusIgnore |= MSR_CD;
1133 p->modemStatus |= MSR_CD;
1134 }
1135
1136 if (Cmd_CheckParm ("+cd"))
1137 {
1138 p->modemStatusIgnore &= (~MSR_CD);
1139 p->modemStatus = (inportb (p->uart + MODEM_STATUS_REGISTER) & MODEM_STATUS_MASK) | p->modemStatusIgnore;
1140 }
1141
1142 if (Cmd_CheckParm ("enable"))
1143 {
1144 if (!p->enabled)
1145 ComPort_Enable(p);
1146 if (p->useModem && !p->modemInitialized)
1147 Modem_Init (p);
1148 }
1149 }
1150
1151
TTY_Init(void)1152 int TTY_Init (void)
1153 {
1154 int n;
1155 ComPort *p;
1156
1157 for (n = 0; n < NUM_COM_PORTS; n++)
1158 {
1159 p = (ComPort *)Hunk_AllocName(sizeof(ComPort), "comport");
1160 if (p == NULL)
1161 Sys_Error("Hunk alloc failed for com port\n");
1162 p->next = portList;
1163 portList = p;
1164 handleToPort[n] = p;
1165 p->portNumber = n;
1166 p->dialType = 'T';
1167 sprintf(p->name, "com%d", n+1);
1168 Cmd_AddCommand (p->name, Com_f);
1169 ResetComPortConfig (p);
1170 }
1171
1172 GetComPortConfig = TTY_GetComPortConfig;
1173 SetComPortConfig = TTY_SetComPortConfig;
1174 GetModemConfig = TTY_GetModemConfig;
1175 SetModemConfig = TTY_SetModemConfig;
1176
1177 return 0;
1178 }
1179
1180
TTY_Shutdown(void)1181 void TTY_Shutdown (void)
1182 {
1183 int n;
1184 ComPort *p;
1185
1186 for (n = 0; n < NUM_COM_PORTS; n++)
1187 {
1188 p = handleToPort[n];
1189 if (p->enabled)
1190 {
1191 while (p->modemConnected)
1192 NET_Poll();
1193 ComPort_Disable (p);
1194 }
1195 }
1196 }
1197
1198
Modem_Command(ComPort * p,const char * commandString)1199 static int Modem_Command (ComPort *p, const char *commandString)
1200 {
1201 byte b;
1202
1203 if (CheckStatus (p))
1204 return -1;
1205
1206 disable();
1207 p->outputQueue.head = p->outputQueue.tail = 0;
1208 p->inputQueue.head = p->inputQueue.tail = 0;
1209 enable();
1210 p->bufferUsed = 0;
1211
1212 while (*commandString)
1213 ENQUEUE (p->outputQueue, *commandString++);
1214 ENQUEUE (p->outputQueue, '\r');
1215
1216 /* get the transmit rolling */
1217 DEQUEUE (p->outputQueue, b);
1218 outportb(p->uart, b);
1219
1220 return 0;
1221 }
1222
1223
Modem_Response(ComPort * p)1224 static const char *Modem_Response (ComPort *p)
1225 {
1226 byte b;
1227
1228 if (CheckStatus (p))
1229 return NULL;
1230
1231 while (! EMPTY(p->inputQueue))
1232 {
1233 DEQUEUE (p->inputQueue, b);
1234
1235 if (p->bufferUsed == (sizeof(p->buffer) - 1))
1236 b = '\r';
1237
1238 if (b == '\r' && p->bufferUsed)
1239 {
1240 p->buffer[p->bufferUsed] = 0;
1241 Con_Printf("%s\n", p->buffer);
1242 SCR_UpdateScreen ();
1243 p->bufferUsed = 0;
1244 return p->buffer;
1245 }
1246
1247 if (b < ' ' || b > 'z')
1248 continue;
1249 p->buffer[p->bufferUsed] = b;
1250 p->bufferUsed++;
1251 }
1252
1253 return NULL;
1254 }
1255
1256
1257 static void Modem_Hangup2 (void *p);
1258 static void Modem_Hangup3 (void *p);
1259 static void Modem_Hangup4 (void *p);
1260
Modem_Hangup(void * p)1261 static void Modem_Hangup (void *p)
1262 {
1263 ComPort *_p = (ComPort *) p;
1264 Con_Printf("Hanging up modem...\n");
1265 disable();
1266 _p->modemRang = false;
1267 _p->outputQueue.head = _p->outputQueue.tail = 0;
1268 _p->inputQueue.head = _p->inputQueue.tail = 0;
1269 outportb(_p->uart + MODEM_CONTROL_REGISTER, inportb(_p->uart + MODEM_CONTROL_REGISTER) & ~MCR_DTR);
1270 enable();
1271 _p->poll.procedure = Modem_Hangup2;
1272 _p->poll.arg = (void *) _p;
1273 SchedulePollProcedure(&_p->poll, 1.5);
1274 }
1275
Modem_Hangup2(void * p)1276 static void Modem_Hangup2 (void *p)
1277 {
1278 ComPort *_p = (ComPort *) p;
1279 outportb(_p->uart + MODEM_CONTROL_REGISTER, inportb(_p->uart + MODEM_CONTROL_REGISTER) | MCR_DTR);
1280 Modem_Command(_p, "+++");
1281 _p->poll.procedure = Modem_Hangup3;
1282 SchedulePollProcedure(&_p->poll, 1.5);
1283 }
1284
Modem_Hangup3(void * p)1285 static void Modem_Hangup3 (void *p)
1286 {
1287 ComPort *_p = (ComPort *) p;
1288 Modem_Command(_p, _p->shutdown);
1289 _p->poll.procedure = Modem_Hangup4;
1290 SchedulePollProcedure(&_p->poll, 1.5);
1291 }
1292
Modem_Hangup4(void * p)1293 static void Modem_Hangup4 (void *p)
1294 {
1295 ComPort *_p = (ComPort *) p;
1296 Modem_Response(_p);
1297 Con_Printf("Hangup complete\n");
1298 _p->modemConnected = false;
1299 }
1300
1301