mac@idacrd.UUCP (Robert McGwier) (06/11/90)
Microsoft C lets you define ISR's. Here's code to do what you want if you
decide that Microsoft might do the job. I understand that Turbo C had this
function type first. asc_enab enables the ISR, asc_disab disables that
port. I have included code that could be used to do both COM1 and COM2
simultaneously. You should call signal and replace the control break signal
with a dummy routine. If you don't, the first time a character comes
in the serial port and you have control C ended the routine, the
system will most likely hang. Writing serial interrupt handlers
is one of the most trivial exercises a beginning programmer can do with
the PC. It is disgusting beyond belief to me that IBM, etc. never did
this in the BIOS. I have run this code at 19200 by programming the
hardware directly as mentioned in an earlier article on a 4.77 Mhz
PC and I am sure that it will run faster. The following is Microsoft
5.1 I will modify it for 6.0 and repost in my next posting in three
months. It seems this needs sending about once every three months, ;-).
/* Copyright Bob McGwier, 1990. ALL RIGHTS RESERVED */
/* May be used freely for non-commercial purposes */
#include <stdio.h>
#include <dos.h>
#include <malloc.h>
#define PIC_MASK 0x21
#define PIC_EOI 0x20
#define ERR_MSK 0x9E
/* Definitions for interrupt handling */
/* COM1 */
#define COM_DATA_1 0x3F8 /* Data received on this I/O address */
#define COM_IER_1 0x3F9 /* This register enables interrupts */
#define COM_MCR_1 0x3FC /* Control Register (signals) */
#define COM_STAT_1 0x3FD /* Status Register */
#define COM_INT_1 0xC /* 0xC handles IRQ4 or COM1 by standard */
#define INT_MASK_1 0x10 /* Mask for PIC (programmable interrupt
controller) 8259A */
/* COM2 */
#define COM_DATA_2 0x2F8 /* Data received on this I/O address */
#define COM_IER_2 0x2F9 /* This register enables interrupts */
#define COM_MCR_2 0x2FC /* Control Register (signals) */
#define COM_STAT_2 0x2FD /* Status Register */
#define COM_INT_2 0xB /* 0xB handles IRQ3 or COM2 by standard */
#define INT_MASK_2 0x8 /* Mask for PIC (programmable interrupt
controller) 8259A */
static unsigned char *c1_buf;
static unsigned char *c2_buf;
static unsigned asc_in_1,asc_in_2,asc_old_1,asc_old_2;
static void interrupt cdecl far int_com1();
static void interrupt cdecl far int_com2();
static void far *old_c1,far *old_c2;
/* Instat is trivial.*/
/* If the ring buffer write pointer is not the same as the ring buffer
read pointer, then a character is in the buffer */
int instat(com_port)
int com_port;
{
switch(com_port) {
case 0:{
if (asc_old_1 == asc_in_1) return 0;
else return 1;
break;
}
case 1:{
if (asc_old_2 == asc_in_2) return 0;
else return 1;
break;
}
}
}
/* If the ring buffer write pointer is not the same as the ring buffer
read pointer, then a character is in the buffer */
int rcvbyte(com_port)
int com_port;
{
int ch;
switch(com_port) {
case 0: {
if (asc_old_1 == asc_in_1) return -1;
else {
ch = c1_buf[asc_old_1];
asc_old_1 = (asc_old_1+1)&4095;
return ch;
}
}
case 1: {
if (asc_old_2 == asc_in_2) return -1;
else {
ch = c2_buf[asc_old_2];
asc_old_2 = (asc_old_2+1)&4095;
return ch;
}
}
}
}
/* COM1 Interrupt handler. HARDWARE DEPENDENT */
static void interrupt cdecl far int_com1(es,ds,di,si,bp,sp,bx,dx,cx,ax)
unsigned es,ds,di, si, bp, sp, bx, dx, cx, ax;
{
char ch;
_disable(); /* Disable interrupts while we move data
and pointers */
if((ch = (inp(COM_STAT_1)&ERR_MSK)) == 0) { /*If no error message */
ch = inp(COM_DATA_1); /* Get the character */
c1_buf[asc_in_1] = ch; /* Store data in circular buffer */
asc_in_1 = (asc_in_1+1)&4095; /*iterate and wrap */
} else ch = inp(COM_DATA_1); /* Get the character */
_enable(); /* Enable interrupts */
outp(PIC_EOI,0x20); /* Tell 8259A we have handled the interrupt */
}
/* COM2 Interrupt handler. HARDWARE DEPENDENT */
static void interrupt cdecl far int_com2(es,ds,di,si,bp,sp,bx,dx,cx,ax)
unsigned es,ds,di, si, bp, sp, bx, dx, cx, ax;
{
char ch;
_disable(); /* Disable interrupts while we move data
and pointers */
if((ch = (inp(COM_STAT_2)&ERR_MSK)) == 0) {/* If no error message*/
ch = inp(COM_DATA_2); /* Get the character */
c2_buf[asc_in_2] = ch; /* Store data in circular buffer */
asc_in_2 = (asc_in_2+1)&4095; /*iterate and wrap */
} else ch=inp(COM_DATA_2);
_enable(); /* Enable interrupts */
outp(PIC_EOI,0x20); /* Tell 8259A we have handled the interrupt */
}
/* 4096 character buffers are utilized, that is usually more than a screenful
of data ;-) */
void asc_enab(com_port)
int com_port;
{
char ch;
switch(com_port) {
case 0:{
asc_in_1 = asc_old_1 = 0;
if((c1_buf = (unsigned char *)malloc(4096)) == NULL) {
perror("Out of memory");
exit(0);
}
old_c1 = _dos_getvect(COM_INT_1); /* Be a friendly
ISR and save the
old vector for
restoration */
_dos_setvect(COM_INT_1,int_com1); /* Tell DOS whose got
the vector now */
outp(COM_MCR_1,0xB); /* Raise DTR and OUT2 */
outp(COM_IER_1,1); /* Interrupt enable register*/
ch = inp(PIC_MASK); /* Read the current 8259A
interrupt mask */
ch &= (0xFF^INT_MASK_1);/* Reset mask for COM1 */
outp(PIC_MASK,ch); /* Send it to the 8259A */
break;
}
case 1:{
asc_in_2 = asc_old_2 = 0;
if((c2_buf = (unsigned char *)malloc(4096)) == NULL) {
perror("Out of memory");
exit(0);
}
old_c2 = _dos_getvect(COM_INT_2); /* Be a friendly
ISR and save the
old vector for
restoration */
_dos_setvect(COM_INT_2,int_com2); /* Tell DOS whose
got the vector
now */
outp(COM_MCR_2,0xB); /* Raise DTR and OUT2 */
outp(COM_IER_2,1); /* Interrupt enable register*/
ch = inp(PIC_MASK); /* Read the current 8259A
interrupt mask */
ch &= (0xFF^INT_MASK_2);/* Reset mask for COM2 */
outp(PIC_MASK,ch); /* Send it to the 8259A */
break;
}
}
}
void asc_disab(com_port)
int com_port;
{
char ch;
switch(com_port){
case 0: {
free(c1_buf); /* Free the ring buffer */
ch = inp(PIC_MASK); /* Get 8259A (PIC) Mask */
ch |= INT_MASK_1; /* Set Interrupt Mask COM1 */
outp(PIC_MASK,ch); /* Write int. mask to 8259A*/
outp(COM_MCR_1,inp(COM_MCR_1)^0xB);/* Lower DTR and OUT2 */
_dos_setvect(COM_INT_1,old_c1);/* Return the vector
to its old position*/
break;
}
case 1: {
free(c2_buf); /*Free the ring buffer */
ch = inp(PIC_MASK); /* Get 8259A (PIC) Mask */
ch |= INT_MASK_2; /* Set Interrupt Mask COM1 */
outp(PIC_MASK,ch); /* Write int. mask to 8259A*/
outp(COM_MCR_2,inp(COM_MCR_2)^0xB);/* Lower DTR and OUT2 */
_dos_setvect(COM_INT_2,old_c2);/* Restore the old
vector */
break;
}
}
}
putcom(p,ch)
int p;
unsigned char ch;
{
unsigned char status;
switch(p) {
case 0:{
do {
status = inp(COM_STAT_1);
} while (!(status&0x20));
outp(COM_DATA_1,ch);
break;
}
case 1:{
do {
status = inp(COM_STAT_2);
} while (!(status&0x20));
outp(COM_DATA_2,ch);
break;
}
}
}
--
____________________________________________________________________________
My opinions are my own no matter | Robert W. McGwier, N4HY
who I work for! ;-) | CCR, AMSAT, etc.
----------------------------------------------------------------------------