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