1 #ifndef LINT
2 static char *rcsid="$Id: comio.c,v 1.3 1998/10/18 13:18:27 crosser Exp $";
3 #endif
4
5 /*
6 $Log: comio.c,v $
7 Revision 1.3 1998/10/18 13:18:27 crosser
8 Put RCS logs and I.D. into the source
9
10 Revision 1.2 1998/08/01 13:12:41 lightner
11 Four com ports support
12
13 Revision 1.1 1998/01/18 02:16:45 crosser
14 Initial revision
15
16 */
17
18 #include <stdio.h>
19 #include <dos.h>
20
21 #define MDMDAT1 0x03F8 /* Address of modem port 1 data */
22 #define MDMCOM1 0x03FB /* Address of modem port 1 command */
23 #define MDMSTS1 0x03FD /* Address of modem port 1 status */
24
25 #define MDMDAT2 0x02F8 /* Address of modem port 2 data */
26 #define MDMCOM2 0x02FB /* Address of modem port 2 command */
27 #define MDMSTS2 0x02FD /* Address of modem port 2 status */
28
29 #define MDMDAT3 0x03E8 /* Address of modem port 3 data */
30 #define MDMCOM3 0x03EB /* Address of modem port 3 command */
31 #define MDMSTS3 0x03ED /* Address of modem port 3 status */
32
33 #define MDMDAT4 0x02E8 /* Address of modem port 4 data */
34 #define MDMCOM4 0x02EB /* Address of modem port 4 command */
35 #define MDMSTS4 0x02ED /* Address of modem port 4 status */
36
37 #define MDMINTV 0x000C /* Com 1 interrupt vector */
38 #define MDINTV2 0x000B /* Com 2 interrupt vector */
39 #define MDMINTO 0x0EF /* Mask to enable IRQ3 for port 1 */
40 #define MDINTO2 0x0F7 /* Mask to enable IRQ4 for port 2 */
41 #define MDMINTC 0x010 /* Mask to Disable IRQ4 for port 1 */
42 #define MDINTC2 0x008 /* Mask to Disable IRQ3 for port 2 */
43 #define INTCONT 0x0021 /* 8259 interrupt controller ICW2-3 */
44 #define INTCON1 0x0020 /* Address of 8259 ICW1 */
45
46 #define COM_BUFF_SIZE 2048 /* Communications port buffer size */
47 #define XOFFPT COM_BUFF_SIZE*3/4 /* chars in buff before sending XOFF */
48 #define XONPT COM_BUFF_SIZE*1/4 /* chars in buff to send XON after XOFF */
49 #define XOFF 0x13 /* XOFF value */
50 #define XON 0x11 /* XON value */
51
52 /*****************************************************************************/
53 /* function prototypes */
54
55 void TTinit(int port, long speed);/* Initialize the communications system */
56 int ttopen(); /* Open a port for communications */
57 int ttclose( void ); /* Close the communications port */
58 int ttchk( void ); /* Return count of received characters */
59 void ttoc( unsigned char ); /* Output a character to the com port */
60 int ttinc( void ); /* Input a character from circular buffer */
61 void ttflui( void ); /* Flush circular buffer of characters */
62 int dobaud( long ); /* Set the baud rate for the port */
63 void coms( int ); /* Establish modem data */
64 void serini( void ); /* Initialize the com port for interrupts */
65 void serrst( void ); /* Reset the com port to original settings */
66 void interrupt serint( void ); /* Com port receiver ISR */
67
68
69 /*****************************************************************************/
70 /* Global Data */
71
72 unsigned int port; /* COM port */
73 long speed; /* BAUD rate */
74 char parity[5]; /* Parity setting */
75 unsigned int databits; /* Number of Data bits */
76 unsigned int stopbits; /* Number of Stop bits */
77
78 /*****************************************************************************/
79 /* External variables */
80
81
82
83 /*****************************************************************************/
84 /* Local Static Data */
85
86 static char buffer[COM_BUFF_SIZE];/* Circular buffer */
87 static char *inptr; /* Pointer to input point of circular buff*/
88 static char *outptr; /* Pointer to output point of circular buff*/
89 static int count = 0; /* Number of characters in buffer */
90
91 struct mdminfo { /* struct to hold current com port info */
92 unsigned int mddat; /* 8250 data register */
93 unsigned int mdstat; /* 8250 line-status register */
94 unsigned int mdcom; /* 8250 line-control register */
95 unsigned char mden; /* 8259 IRQ enable mask */
96 unsigned char mddis; /* 8259 IRQ disable mask */
97 unsigned char mdintv; /* Interrupt for selected com port */
98 } modem ;
99
100 void interrupt (*oldvec)(); /* Vector of previous com interrupt */
101 int portin = 0; /* Flag to indicate com port is open */
102 int xofsnt = 0; /* Flag to indicate an XOFF transmitted */
103 int xofrcv = 0; /* Flag to indicate an XOFF received */
104
105 /*****************************************************************************/
106
107 /* T T I N I T -- Initialize the communications system */
108
TTinit(int new_port,long new_speed)109 void TTinit(int new_port, long new_speed) {
110 port = new_port;
111 speed = new_speed;
112 strcpy(parity,"NONE");
113 databits = 8;
114 stopbits = 0;
115 }
116
117
118 /* T T O P E N -- Open the communications port */
119
ttopen()120 ttopen() {
121 if (portin == 0) { /* Ignore call if already open */
122 switch (port) {
123 case 1:
124 coms(1); /* COM 1 */
125 break;
126 case 2:
127 coms(2); /* COM 2 */
128 break;
129 case 3:
130 coms(3); /* COM 3 */
131 break;
132 case 4:
133 coms(4); /* COM 4 */
134 break;
135 default: /* others not supported, return error */
136 return(-1);
137 }
138 dobaud(speed); /* Set baud rate */
139 serini(); /* enable interrupt handler */
140 }
141 return(0); /* return success */
142 }
143
144
145 /* T T C L O S E -- Close the communications port */
146
ttclose()147 ttclose() {
148 if (portin != 0) /* Ignore if port is already closed */
149 serrst(); /* otherwise disable interrupts */
150 return(0); /* return success */
151 }
152
153
154
155
156 /* T T C H K -- Return a count of characters at the serial port */
157
ttchk()158 ttchk() {
159 return( count ); /* return maintained count */
160 }
161
162
163 /* T T O C -- Output a character to the current serial port */
164
ttoc(unsigned char c)165 void ttoc( unsigned char c ) {
166
167 while( (inportb(modem.mdstat) & 0x20) == 0 )
168 ; /* Wait til transmitter is ready */
169 outportb(modem.mddat,c); /* then output the character */
170 }
171
172
173 /* T T F L U I -- Clear the input buffer of characters */
174
175
ttflui()176 void ttflui() {
177
178 #ifdef XONXOFF
179 if (xofsnt){ /* Check if XON should be sent after XOFF */
180 xofsnt = 0; /* if so then reset XOFF sent status */
181 ttoc(XON); /* and send the XON */
182 }
183 #endif
184 disable(); /* NO interrupts allowed now */
185 inptr = outptr = buffer; /* Reset input out output pointers */
186 count = 0; /* Set received characters count to 0 */
187 enable(); /* Now interrupts are ok */
188 }
189
190
191 /* T T I N C -- Read a character from serial ports circular buffer */
192
ttinc()193 ttinc() {
194 int c;
195 register char * ptr;
196
197 #ifdef XONXOFF
198 if (count < XONPT && xofsnt){ /* Check if XON should be sent after XOFF */
199 xofsnt = 0; /* if so then reset XOFF sent status */
200 ttoc(XON); /* and send the XON */
201 }
202 #endif
203
204 while (count == 0) /* If no characters have arrived then */
205 ; /* wait til one arrives */
206
207 ptr = outptr; /* Save address of buffer output point */
208
209 c = *ptr++; /* Get this character and increment ptr */
210
211 /* See if circular buff should be wrapped */
212 if (ptr == &buffer[COM_BUFF_SIZE])
213 ptr = buffer; /* if so then save new output point */
214
215 disable(); /* NO interrupts allowed now */
216 outptr = ptr; /* Save the address of output point */
217 count--; /* Decrement count of received characters */
218 enable(); /* Interrupts can continue now */
219
220 return(c); /* Return the received character */
221 }
222
223
224 /* D O B A U D -- Set the baud rate for the current port */
225
dobaud(long baudrate)226 dobaud( long baudrate ) {
227 unsigned char portval;
228 unsigned char blo, bhi;
229 switch (baudrate) { /* Get 8250 baud rate divisor values */
230 case 50: bhi = 0x9; blo = 0x00; break;
231 case 75: bhi = 0x6; blo = 0x00; break;
232 case 110: bhi = 0x4; blo = 0x17; break;
233 case 150: bhi = 0x3; blo = 0x00; break;
234 case 300: bhi = 0x1; blo = 0x80; break;
235 case 600: bhi = 0x0; blo = 0xC0; break;
236 case 1200: bhi = 0x0; blo = 0x60; break;
237 case 1800: bhi = 0x0; blo = 0x40; break;
238 case 2000: bhi = 0x0; blo = 0x3A; break;
239 case 2400: bhi = 0x0; blo = 0x30; break;
240 case 4800: bhi = 0x0; blo = 0x18; break;
241 case 9600: bhi = 0x0; blo = 0x0C; break;
242 case 19200: bhi = 0x0; blo = 0x06; break;
243 case 38400: bhi = 0x0; blo = 0x03; break;
244 case 57600: bhi = 0x0; blo = 0x02; break;
245 case 115200: bhi = 0x0; blo = 0x01; break;
246
247 default: /* Return failure if baud unsupported */
248 return(-1);
249 }
250
251 portval = inportb(modem.mdcom);/* Save current value of command register */
252
253 /* In order to set the baud rate the */
254 /* high bit of command data register is */
255 outportb(modem.mdcom,portval | 0x80 ); /* set before sending baud data */
256
257 outportb(modem.mddat,blo); /* Set LSB Baud-Rate divisor for baud */
258 outportb(modem.mddat + 1,bhi); /* Set MSB Baud-Rate divisor for baud */
259
260 outportb(modem.mdcom,portval); /* Reset original command register value */
261
262 return(0); /* Return success */
263 }
264
265
266 /* C O M S -- Set up the modem structure for the specified com port */
267
coms(int portid)268 void coms( int portid ) {
269
270 if (portid == 1) { /* Port data for COM 1 */
271 modem.mddat = MDMDAT1; /* Port 1 Data register */
272 modem.mdstat = MDMSTS1; /* Port 1 Status register */
273 modem.mdcom = MDMCOM1; /* Port 1 Command register */
274 modem.mddis = MDMINTC; /* Port 1 8259 IRQ4 disable mask */
275 modem.mden = MDMINTO; /* Port 1 8259 IRQ4 enable mask */
276 modem.mdintv = MDMINTV; /* Port 1 interrupt number */
277 }
278 else if (portid == 2) { /* Port data for COM 2 */
279 modem.mddat = MDMDAT2; /* Port 2 Data register */
280 modem.mdstat = MDMSTS2; /* Port 2 Status register */
281 modem.mdcom = MDMCOM2; /* Port 2 Command register */
282 modem.mddis = MDINTC2; /* Port 2 8259 IRQ4 disable mask */
283 modem.mden = MDINTO2; /* Port 2 8259 IRQ4 enable mask */
284 modem.mdintv = MDINTV2; /* Port 2 interrupt number */
285 }
286 else if (portid == 3) { /* Port data for COM 3 */
287 modem.mddat = MDMDAT3; /* Port 3 Data register */
288 modem.mdstat = MDMSTS3; /* Port 3 Status register */
289 modem.mdcom = MDMCOM3; /* Port 3 Command register */
290 modem.mddis = MDMINTC; /* Port 3 8259 IRQ4 disable mask */
291 modem.mden = MDMINTO; /* Port 3 8259 IRQ4 enable mask */
292 modem.mdintv = MDMINTV; /* Port 3 interrupt number */
293 }
294 else if (portid == 4) { /* Port data for COM 4 */
295 modem.mddat = MDMDAT4; /* Port 4 Data register */
296 modem.mdstat = MDMSTS4; /* Port 4 Status register */
297 modem.mdcom = MDMCOM4; /* Port 4 Command register */
298 modem.mddis = MDINTC2; /* Port 4 8259 IRQ4 disable mask */
299 modem.mden = MDINTO2; /* Port 4 8259 IRQ4 enable mask */
300 modem.mdintv = MDINTV2; /* Port 4 interrupt number */
301 }
302 }
303
304 /* S E R I N I -- initialize the serial port for interrupts */
305
serini()306 void serini() {
307 unsigned char portval;
308
309 if (portin == 0) { /* Ignore if already open */
310 portin = 1; /* save port open status */
311 inptr = outptr = buffer; /* set circular buffer pointers */
312 count = 0; /* indicate no characters received */
313 oldvec=getvect(modem.mdintv);/* save old com interrupt */
314 setvect(modem.mdintv,serint);/* set SERINT as communications ISR */
315
316 portval = 0; /* Byte value to output to the Line */
317 /* Control Register (LCR) to set the */
318 /* Parity, Stopbits, Databits */
319 /* Start out with all bits zero */
320
321 if (strcmp(parity,"EVEN") == 0)
322 portval |= 0x8; /* Set bit 3 on for odd parity */
323 else if (strcmp(parity,"ODD") == 0)
324 portval |= 0x18; /* Set bits 3 and 4 on for even parity */
325 /* Leave bits 3 and 4 off for no parity */
326
327
328 if (stopbits == 2) /* Set bit 2 on if 2 Stopbits are used */
329 portval |= 0x4;
330 /* Leave bit 2 off for 1 Stopbit */
331
332 if (databits == 6) /* Set bit 0 on for 6 data bits */
333 portval |= 0x1;
334 else if (databits == 7) /* Set bit 1 on for 7 data bits */
335 portval |= 0x2;
336 else if (databits == 8) /* Set bits 0 and 1 on for 8 data bits */
337 portval |= 0x3;
338 /* Leave bits 0 and 1 off for 5 data bits */
339
340 outportb(modem.mdcom,portval); /* Output the settings to the LCR */
341
342
343 outportb(modem.mdcom + 1,0xb); /* Assert OUT2, RTS, DTR */
344
345 inportb(modem.mddat); /* Clear any left over characters */
346 outportb(modem.mddat+1,0x1); /* Enable receiver interrupts */
347
348 portval = inportb(INTCONT); /* Read 8259 interrupt enable mask */
349 outportb(INTCONT,modem.mden & portval); /*Set bit on for com IRQ */
350 }
351 }
352
353
354 /* S E R R S T -- Reset serial port interrupts */
355
serrst()356 void serrst() {
357 unsigned char portval;
358
359 if (portin != 0) { /* Ignore if interrupts already disabled */
360 portin = 0; /* save port closed status */
361 portval = inportb(INTCONT); /* Read 8259 interrupt enable mask */
362 outportb(INTCONT,modem.mddis | portval);/*Set bit off for com IRQ */
363 setvect(modem.mdintv,oldvec); /* return original interrupt vector */
364 }
365 }
366
367
368 /* S E R I N T -- Serial interrupt handler, recieves incoming characters */
369
serint()370 void interrupt serint() {
371
372 more:
373 *inptr++=inportb(modem.mddat);/* Quickly read arriving character */
374 count++; /* Increment received count */
375
376 #ifdef XONXOFF
377 if (count > XOFFPT && xofsnt != 1){ /* If buffer almost full then */
378 ttoc(XOFF); /* send an XOFF */
379 xofsnt = 1; /* and save XOFF sent status */
380 }
381 #endif
382 disable(); /* NO interrupts are allowed while */
383 /* new input pointer is stored */
384 if (inptr == &buffer[COM_BUFF_SIZE]) /* At end of circular buff? */
385 inptr = buffer; /* if so then save new output point */
386
387 enable(); /* Interrupts ok now */
388
389 #define LAST_LOOK
390 #ifdef LAST_LOOK
391 if (inportb(modem.mddat + 5) & 1) /* another character ready? */
392 goto more;
393 #endif
394
395 outportb(0x20,0x20); /* send End Of Interrupt to 8259 */
396 }
397
398