net_comx.c 29 KB

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