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