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. ----------------------------------------------------------------------------