home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / net_comx.c < prev    next >
C/C++ Source or Header  |  2000-06-17  |  31KB  |  1,286 lines

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