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