/* +----------------------------------------------------+ | Thunderbird Software | +----------------------------------------------------+ | Filespec : Serial.c | | Date : October 24, 1991 | | Time : 15:03 | | Revision : 1.1 | | Update: August 29, 1994 | +----------------------------------------------------+ | Programmer: Scott Andrews | | Address : 5358 Summit RD SW | | City/State: Pataskala, Ohio | | Zip : 43062 | +----------------------------------------------------+ | Released to the Public Domain | +----------------------------------------------------+ */ /* +----------------------------------------------------------+ | Call open_serial to install the interrupt handler | | You must call close_serial before exiting your program | | or a machine crash will occur! | +----------------------------------------------------------+ */ #include #include #include #include "serial.h" #include "queue.h" QUEUE *Serial_In_Queue; QUEUE *Serial_Out_Queue; OLD_COMM_PARAMS old_comm_params; COMM_STATUS comm_status; void ( INTERRUPT FAR * oldvector_serial) ( ); /* save addr for intr handler */ int ComBase; /* Comm port address */ int IrqNum; /* Comm interrupt request */ void CloseComPort( void) { int status; /* restore UART to previous state */ outp(ComBase + INT_EN, (unsigned char) 0); outp(ComBase + MODEM_CNTRL, (unsigned char) old_comm_params.modem); status = inp(ComBase + LINE_CNTRL); outp(ComBase + LINE_CNTRL, (unsigned char) status | 0x80); outp(ComBase + BAUD_LSB, (unsigned char) old_comm_params.baud_lsb); outp(ComBase + BAUD_MSB, (unsigned char) old_comm_params.baud_msb); outp(ComBase + LINE_CNTRL, (unsigned char) old_comm_params.line); outp(0x21, (unsigned char) old_comm_params.int_cntrl); /* restore old interrupt handler */ setvect(IrqNum + 8, oldvector_serial); /* free input and output queues */ free(Serial_In_Queue); free(Serial_Out_Queue); return; } int OpenComPort( char Port) { /* install int. handler */ unsigned status; int retval = -1; /* allocate input and output queues */ Serial_In_Queue = alloc_queue(SerInBufSize); if ((QUEUE *) 0 == Serial_In_Queue) return retval; Serial_Out_Queue = alloc_queue(SerOutBufSize); if ((QUEUE *) 0 == Serial_Out_Queue) { free(Serial_In_Queue); return retval; } retval = 0; /* Setup Comm base port address and IRQ number */ switch (Port) { case '1': ComBase = 0x3F8; IrqNum = 4; break; case '2': ComBase = 0x2F8; IrqNum = 3; break; case '3': ComBase = 0x3E8; IrqNum = 4; break; case '4': ComBase = 0x2E8; IrqNum = 3; break; default: ComBase = 0x3F8; IrqNum = 4; break; } old_comm_params.int_enable = inp(ComBase + INT_EN); outp(ComBase + INT_EN, 0); /* turn off comm interrupts */ /* save old comm parameters */ old_comm_params.line = inp(ComBase + LINE_CNTRL); old_comm_params.modem = inp(ComBase + MODEM_CNTRL); status = inp(ComBase + LINE_CNTRL); outp(ComBase + LINE_CNTRL, (unsigned char) status | 0x80); old_comm_params.baud_lsb = inp(ComBase + BAUD_LSB); old_comm_params.baud_msb = inp(ComBase + BAUD_MSB); status = inp(ComBase + LINE_CNTRL); outp(ComBase + LINE_CNTRL, (unsigned char) status | 0x7F); status = OUT2 | DTR; /* DTR/OUT2 must be set! */ outp(ComBase + MODEM_CNTRL, (unsigned char) status); /* get serial port address/vector */ oldvector_serial = (void (INTERRUPT FAR *) (void)) getvect(IrqNum + 8); /* set our interrupt handler */ setvect(IrqNum + 8, serial); /* save the PIC */ old_comm_params.int_cntrl = inp(0x21); status = (1 << IrqNum); /* calculate int enable bit */ status = ~status; /* ok enable comm ints */ outp(0x21, (unsigned char) old_comm_params.int_cntrl & (unsigned char) status); atexit(CloseComPort); return retval; } void InitComPort( char Baud[], char Databits, char Parity, char Stopbits) { int status; unsigned divisor; long baudrate; /* set baud rate */ status = inp(ComBase + LINE_CNTRL); outp(ComBase + LINE_CNTRL, (unsigned char) status | 0x80); baudrate = atol(Baud); if (baudrate == 0) baudrate = 2400L; divisor = (unsigned) (115200L / baudrate); outp(ComBase + BAUD_LSB, (unsigned char) (divisor & 0x00FF)); outp(ComBase + BAUD_MSB, (unsigned char) ((divisor >> 8) & 0x00FF)); status = 0x00; /* set parity */ switch (Parity) { /* set parity value */ case 'O': /* odd parity */ case 'o': status = 0x08; break; case 'E': /* even parity */ case 'e': status = 0x18; break; case 'S': /* stick parity */ case 's': status = 0x28; break; case 'N': /* no parity */ case 'n': default: status = 0x00; } /* set number data bits */ switch (Databits) { case '5': break; case '6': status = status | 0x01; break; case '7': status = status | 0x02; break; case '8': default: status = status | 0x03; } /* set number stop bits */ switch (Stopbits) { case '2': status = status | 0x04; break; case '1': default: ; } outp(ComBase + LINE_CNTRL, (unsigned char) status); status = OUT2 | DTR; /* DTR/OUT2 must be set! */ outp(ComBase + MODEM_CNTRL, (unsigned char) status); /* enable serial interrupts */ outp(ComBase + INT_EN, RX_INT | ERR_INT | RS_INT); return; } void DropDtr( void) { int status; status = inp(ComBase + MODEM_CNTRL); status &= 0xFE; /* turn off DTR bit */ outp(ComBase + MODEM_CNTRL, (unsigned char) status); return; } void RaiseDtr( void) { int status; status = inp(ComBase + MODEM_CNTRL); status |= 0x01; /* turn on DTR bit */ outp(ComBase + MODEM_CNTRL, (unsigned char) status); return; } int ComRecChar( void) { return de_queue(Serial_In_Queue); } int ComSendString( char *string) { int retval; char *pointer; pointer = string; while (*pointer) { retval = en_queue(Serial_Out_Queue, *pointer); pointer++; } if (0x0 == (comm_status.modem & 0x40)) RaiseDtr(); outp(ComBase + INT_EN, RX_INT | TBE_INT | ERR_INT | RS_INT); return retval; } int ComSendData( char *buffer, unsigned buffer_length) { int retval; char *pointer; pointer = buffer; unsigned i; for (i = 0; i < buffer_length; i++) { retval = en_queue(Serial_Out_Queue, *pointer); pointer++; } if (0x0 == (comm_status.modem & 0x40)) RaiseDtr(); outp(ComBase + INT_EN, RX_INT | TBE_INT | ERR_INT | RS_INT); return retval; } int ComSendChar( char character) { int retval; /* interrupt driven send */ if (0x0 == (comm_status.modem & 0x40)) RaiseDtr(); retval = en_queue(Serial_Out_Queue, character); if (-1 != retval) outp(ComBase + INT_EN, RX_INT | TBE_INT | ERR_INT | RS_INT); return retval; } int ComStatus( void) { unsigned status; unsigned retval; retval = inp(ComBase + LINE_STATUS); retval = retval << 8; status = inp(ComBase + MODEM_STATUS); retval = retval | status; if (queue_empty(Serial_In_Queue)) retval &= 0xFEFF; else retval |= 0x0100; return (int) retval; } void INTERRUPT FAR serial( void) { /* interrupt handler */ int temp; disable(); while (1) { comm_status.intrupt = inp(ComBase + INT_ID); comm_status.intrupt &= 0x0f; switch (comm_status.intrupt) { case 0x00: /* modem interrupt */ comm_status.modem = inp(ComBase + MODEM_STATUS); break; case 0x02: /* xmit interrupt */ if (queue_empty(Serial_Out_Queue)) outp(ComBase + INT_EN, RX_INT | ERR_INT | RS_INT); else { temp = de_queue(Serial_Out_Queue); if (-1 != temp) outp(ComBase + XMIT, temp); } break; case 0x04: /* receive interrupt */ en_queue(Serial_In_Queue, (char) inp(ComBase + REC)); break; case 0x06: /* line interrupt */ comm_status.line = inp(ComBase + LINE_STATUS); (void) inp(ComBase + REC); en_queue(Serial_In_Queue, '!'); break; default: /* No Mo` Left */ comm_status.modem = inp(ComBase + MODEM_STATUS); outp(0x20, 0x20); enable(); return; } /* switch */ } /* while */ } /* End of Serial.C */