diff --git a/serial.c b/serial.c index 2cfcd6f..d5bfe7f 100644 --- a/serial.c +++ b/serial.c @@ -1,1647 +1,1705 @@ -#include -#include -#include "serial.h" - -#if defined( __DJGPP__ ) -#include -#include -#include -#define Interrupt -#define Far -#define Farpeekw(s, o) _farpeekw((s),(o)) -#define _Outp(a,b) (outp(a,b),(b)) -#define _Outpw(a,w) (outpw(a,w),(w)) -#define CPU_DISABLE_INTERRUPTS() asm("CLI") -#define CPU_ENABLE_INTERRUPTS() asm("STI") -#elif defined( _MSC_VER ) || defined( __WATCOMC__ ) -#define Interrupt __interrupt -#define Far __far -#define Farpeekw(s, o) (*((unsigned short Far*)(MK_FP((s), (o))))) -#define _Outp(a,b) outp(a,b) -#define _Outpw(a,w) outpw(a,w) -#define CPU_DISABLE_INTERRUPTS() __asm CLI -#define CPU_ENABLE_INTERRUPTS() __asm STI -#else /* __BORLANDC__ */ -#define Interrupt interrupt -#define Far far -#define Farpeekw(s, o) (*((unsigned short Far*)(MK_FP((s), (o))))) -#define _Outp(a,b) outp(a,b) -#define _Outpw(a,w) outpw(a,w) -#define CPU_DISABLE_INTERRUPTS() asm CLI -#define CPU_ENABLE_INTERRUPTS() asm STI -#endif /* _MSC_VER */ -#if defined( __386__ ) || defined( __DJGPP__ ) -#define PROTECTED_MODE -#endif - -/* ======================================================================== */ -/* =========================== DEFINES & MACROS =========================== */ -/* ======================================================================== */ - - -/* Tweak Values */ -#define SER_RX_BUFFER_SIZE_BITS 11 /* 2048 */ -#define SER_RX_BUFFER_HIGH_PERCENT 80 -#define SER_RX_BUFFER_LOW_PERCENT 20 - -#define SER_TX_BUFFER_SIZE_BITS 11 /* 2048 */ -#define SER_TX_BUFFER_HIGH_PERCENT 80 -#define SER_TX_BUFFER_LOW_PERCENT 20 - -#define UART_FIFO_DEFAULT_THRESHOLD 14 /* 14, 8, 4, 1, or 0 (off) */ - -#define COM1_DEFAULT_IRQ 4 -#define COM2_DEFAULT_IRQ 3 -#define COM3_DEFAULT_IRQ 4 -#define COM4_DEFAULT_IRQ 3 - -#define COM_MIN COM_1 -#define COM_MAX COM_4 - -#define IRQ_MIN 3 -#define IRQ_MAX 15 -#define IRQ_NONE 0xff - - -/* Receive and transmit buffers - * - * Both head and tail work in pre-increment mode: - * - * H->W->W->W - * * * * - * 0 1 2 3 4 5 ... - * * * * - * T->R->R->R - * - * Buffer empty: - * - * H - * ... 4 5 6 7 ... - * T - * - * Buffer full: - * - * H - * ... 4 5 6 7 ... - * T - */ - -#define SER_RX_BUFFER_SIZE (1L<rx_buff[(C)->rx_tail = ((C)->rx_tail+1) & SER_RX_BUFFER_SIZE_MASK] -#define SER_RX_BUFFER_WRITE(C, D) (C)->rx_buff[(C)->rx_head = ((C)->rx_head+1) & SER_RX_BUFFER_SIZE_MASK] = D -#define SER_RX_BUFFER_INIT(C) (C)->rx_head = (C)->rx_tail = 0 -#define SER_RX_BUFFER_EMPTY(C) ((C)->rx_head == (C)->rx_tail) -#define SER_RX_BUFFER_FULL(C) ((((C)->rx_head+1) & SER_RX_BUFFER_SIZE_MASK) == (C)->rx_tail) -#define SER_RX_BUFFER_CURRENT(C) (((C)->rx_head - (C)->rx_tail) & SER_RX_BUFFER_SIZE_MASK) -#define SER_RX_BUFFER_LOWATER(C) (SER_RX_BUFFER_CURRENT(C) < SER_RX_BUFFER_LOW) -#define SER_RX_BUFFER_HIWATER(C) (SER_RX_BUFFER_CURRENT(C) > SER_RX_BUFFER_HIGH) - -#define SER_TX_BUFFER_SIZE (1L<tx_buff[(C)->tx_tail = ((C)->tx_tail+1) & SER_TX_BUFFER_SIZE_MASK] -#define SER_TX_BUFFER_WRITE(C, D) (C)->tx_buff[(C)->tx_head = ((C)->tx_head+1) & SER_TX_BUFFER_SIZE_MASK] = D -#define SER_TX_BUFFER_INIT(C) (C)->tx_head = (C)->tx_tail = 0 -#define SER_TX_BUFFER_EMPTY(C) ((C)->tx_head == (C)->tx_tail) -#define SER_TX_BUFFER_FULL(C) ((((C)->tx_head+1) & SER_TX_BUFFER_SIZE_MASK) == (C)->tx_tail) -#define SER_TX_BUFFER_CURRENT(C) (((C)->tx_head - (C)->tx_tail) & SER_TX_BUFFER_SIZE_MASK) -#define SER_TX_BUFFER_LOWATER(C) (SER_TX_BUFFER_CURRENT(C) < SER_TX_BUFFER_LOW) -#define SER_TX_BUFFER_HIWATER(C) (SER_TX_BUFFER_CURRENT(C) > SER_TX_BUFFER_HIGH) - - -/* XON/XOFF Flow Control Commands */ -#define SER_XON 0x11 -#define SER_XOFF 0x13 - - -/* PIC Registers & interrupts */ -#define INTERRUPT_VECTOR_OFFSET 8 - -#define PIC_MASTER 0x20 -#define PIC_SLAVE 0xa0 -#define PIC_EOI 0x20 -#define PIC_RR 0x02 - -#define PIC_WRITE_IMR(P, D) outp((P)|1, D) /* interrupt masks */ -#define PIC_WRITE_OCW2(P, D) outp(P, D) /* R, SL, EOI, 0, 0, L2, L1, L0 */ -#define PIC_WRITE_OCW3(P, D) outp(P, (D)|8) /* 0, ESMM, SMM, 0, 1, P, RR, RIS */ -#define PIC_READ_IMR(P) inp((P)|1) /* interrupt masks */ -#define PIC_END_INTERRUPT(P) PIC_WRITE_OCW2(P, PIC_EOI) -static unsigned char PIC_READ_IRR(unsigned int port){PIC_WRITE_OCW3(port, PIC_RR); return inp(port);} -#define PIC_ENABLE_IRQ(I) {if(I <= 7) PIC_WRITE_IMR(PIC_MASTER, PIC_READ_IMR(PIC_MASTER) & ~(1 << I)); \ - else PIC_WRITE_IMR(PIC_SLAVE, PIC_READ_IMR(PIC_SLAVE) & ~(1 << ((I)-7)));} -#define PIC_DISABLE_IRQ(I) {if(I <= 7) PIC_WRITE_IMR(PIC_MASTER, PIC_READ_IMR(PIC_MASTER) | (1 << I)); \ - else PIC_WRITE_IMR(PIC_SLAVE, PIC_READ_IMR(PIC_SLAVE) | (1 << ((I)-7)));} - - -/* UART Registers */ -#define UART_RX_BUFFER 0 -#define UART_TX_BUFFER 0 -#define UART_INTERRUPT_ENABLE 1 - -#define UART_DIVISOR_LATCH_WORD 0 -#define UART_DIVISOR_LATCH_LSB 0 -#define UART_DIVISOR_LATCH_MSB 1 - -#define UART_INTERRUPT_IDENTIFY 2 -#define UART_FIFO_CONTROL 2 -#define UART_LINE_CONTROL 3 -#define UART_MODEM_CONTROL 4 -#define UART_LINE_STATUS 5 -#define UART_MODEM_STATUS 6 - - -/* UART Read commands (B = UART Base Address ) */ -#define UART_READ_DATA(C) inp((C)->base+UART_RX_BUFFER) -#define UART_READ_INTERRUPT_ENABLE(C) inp((C)->base+UART_INTERRUPT_ENABLE) -#define UART_READ_INTERRUPT_IDENTIFY(C) inp((C)->base+UART_INTERRUPT_IDENTIFY) -#define UART_READ_LINE_CONTROL(C) inp((C)->base+UART_LINE_CONTROL) -#define UART_READ_MODEM_CONTROL(C) inp((C)->base+UART_MODEM_CONTROL) -#define UART_READ_LINE_STATUS(C) ((C)->lsr = inp((C)->base+UART_LINE_STATUS)) -#define UART_READ_MODEM_STATUS(C) ((C)->msr = inp((C)->base+UART_MODEM_STATUS)) -#define UART_READ_BPS(C) ((_Outp((C)->base+UART_LINE_CONTROL, inp((C)->base+UART_LINE_CONTROL) | UART_LCR_DIVISOR_LATCH) & 0) | \ - inpw((C)->base+UART_DIVISOR_LATCH_WORD) | \ - (_Outp((C)->base+UART_LINE_CONTROL, inp((C)->base+UART_LINE_CONTROL) & ~UART_LCR_DIVISOR_LATCH) & 0)) - - -/* UART Write Commands (B = UART Base Address , D = Data ) */ -#define UART_WRITE_DATA(C, D) outp((C)->base+UART_TX_BUFFER, D) -#define UART_WRITE_INTERRUPT_ENABLE(C, D) ((C)->ier = _Outp((C)->base+UART_INTERRUPT_ENABLE, D)) -#define UART_WRITE_FIFO_CONTROL(C, D) ((C)->fcr = _Outp((C)->base+UART_FIFO_CONTROL, D)) -#define UART_WRITE_LINE_CONTROL(C, D) ((C)->lcr = _Outp((C)->base+UART_LINE_CONTROL, D)) -#define UART_WRITE_MODEM_CONTROL(C, D) ((C)->mcr = _Outp((C)->base+UART_MODEM_CONTROL, D)) -#define UART_WRITE_BPS(C, D) {outp((C)->base+UART_LINE_CONTROL, inp((C)->base+UART_LINE_CONTROL) | UART_LCR_DIVISOR_LATCH); \ - (C)->dlatch = _Outpw((C)->base+UART_DIVISOR_LATCH_WORD, D); \ - outp((C)->base+UART_LINE_CONTROL, inp((C)->base+UART_LINE_CONTROL) & ~UART_LCR_DIVISOR_LATCH);} - - -/* Interrupt Enable Register Components */ -#define UART_IER_MODEM_STATUS 0x08 -#define UART_IER_ERRORS 0x04 -#define UART_IER_TX_HOLD_EMPTY 0x02 -#define UART_IER_DATA_READY 0x01 - - -/* Interrupt Identify Register Components */ -#define UART_IIR_FIFO_ENABLE_1 0x80 -#define UART_IIR_FIFO_ENABLE_0 0x40 -#define UART_IIR_IDENTIFY_2 0x08 -#define UART_IIR_IDENTIFY_1 0x04 -#define UART_IIR_IDENTIFY_0 0x02 -#define UART_IIR_NO_INTERRUPT_PENDING 0x01 - -#define UART_IIR_MASK (UART_IIR_NO_INTERRUPT_PENDING | UART_IIR_IDENTIFY_0 | UART_IIR_IDENTIFY_1) -#define UART_IIR_LINE_STATUS (UART_IIR_IDENTIFY_0 | UART_IIR_IDENTIFY_1) -#define UART_IIR_DATA_READY UART_IIR_IDENTIFY_1 -#define UART_IIR_TX_HOLD_EMPTY UART_IIR_IDENTIFY_0 -#define UART_IIR_MODEM_STATUS 0x00 -#define UART_IIR_NO_INTERRUPT UART_IIR_NO_INTERRUPT_PENDING - - -/* Fifo Control Register Components */ -#define UART_FCR_TRIGGER_1 0x80 -#define UART_FCR_TRIGGER_0 0x40 -#define UART_FCR_DMA_SELECT 0x08 -#define UART_FCR_TX_FIFO_RESET 0x04 -#define UART_FCR_RX_FIFO_RESET 0x02 -#define UART_FCR_FIFO_ENABLE 0x01 - -#define UART_FCR_TRIGGER_AT_1 0x00 -#define UART_FCR_TRIGGER_AT_4 UART_FCR_TRIGGER_0 -#define UART_FCR_TRIGGER_AT_8 UART_FCR_TRIGGER_1 -#define UART_FCR_TRIGGER_AT_14 (UART_FCR_TRIGGER_0 | UART_FCR_TRIGGER_1) - - -/* Line Control Register Components */ - -#define UART_LCR_DIVISOR_LATCH 0x80 -#define UART_LCR_SET_BREAK 0x40 -#define UART_LCR_STICK_PARITY 0x20 -#define UART_LCR_EVEN_PARITY 0x10 -#define UART_LCR_PARITY_ENABLE 0x08 -#define UART_LCR_STOPBITS 0x04 -#define UART_LCR_WORD_LENGTH_1 0x02 -#define UART_LCR_WORD_LENGTH_0 0x01 - -#define UART_DATA_5 0x00 -#define UART_DATA_6 UART_LCR_WORD_LENGTH_0 -#define UART_DATA_7 UART_LCR_WORD_LENGTH_1 -#define UART_DATA_8 (UART_LCR_WORD_LENGTH_0 | UART_LCR_WORD_LENGTH_1) -#define UART_DATA_MASK (UART_LCR_WORD_LENGTH_0 | UART_LCR_WORD_LENGTH_1) - -#define UART_PARITY_NONE 0x00 -#define UART_PARITY_ODD UART_LCR_PARITY_ENABLE -#define UART_PARITY_EVEN (UART_LCR_PARITY_ENABLE | UART_LCR_EVEN_PARITY) -#define UART_PARITY_MARK (UART_LCR_PARITY_ENABLE | UART_LCR_STICK_PARITY) -#define UART_PARITY_SPACE (UART_LCR_PARITY_ENABLE | UART_LCR_EVEN_PARITY | UART_LCR_STICK_PARITY) -#define UART_PARITY_MASK (UART_LCR_PARITY_ENABLE | UART_LCR_EVEN_PARITY | UART_LCR_STICK_PARITY) - -#define UART_STOP_1 0x00 -#define UART_STOP_2 UART_LCR_STOPBITS -#define UART_STOP_MASK UART_LCR_STOPBITS - - -/* Modem Control Register Components */ -#define UART_MCR_LOOPBACK 0x10 -#define UART_MCR_OUT2 0x08 -#define UART_MCR_OUT1 0x04 -#define UART_MCR_RTS 0x02 -#define UART_MCR_DTR 0x01 -#define UART_MCR_MASK ( UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT1 | UART_MCR_OUT2 | UART_MCR_LOOPBACK ) - - -/* Line Status Register Components */ -#define UART_LSR_FIFO_ERROR 0x80 -#define UART_LSR_TX_EMPTY 0x40 -#define UART_LSR_TX_HOLD_EMPTY 0x20 -#define UART_LSR_BREAK_INDICATOR 0x10 -#define UART_LSR_FRAME_ERROR 0x08 -#define UART_LSR_PARITY_ERROR 0x04 -#define UART_LSR_OVERRUN_ERROR 0x02 -#define UART_LSR_DATA_READY 0x01 - - -/* Modem Status Register Components */ -#define UART_MSR_DCD 0x80 -#define UART_MSR_RI 0x40 -#define UART_MSR_DSR 0x20 -#define UART_MSR_CTS 0x10 -#define UART_MSR_DLT_DCD 0x08 -#define UART_MSR_NEW_RING 0x04 -#define UART_MSR_DLT_DSR 0x02 -#define UART_MSR_DLT_CTS 0x01 - - -/* BPS Rates (based on 1.8432 MHz crystal) */ -#define UART_BPS_DIVISOR_50 2304 -#define UART_BPS_DIVISOR_75 1536 -#define UART_BPS_DIVISOR_110 1047 /* 0.026% error */ -#define UART_BPS_DIVISOR_134_5 857 /* 0.058% error */ -#define UART_BPS_DIVISOR_150 768 -#define UART_BPS_DIVISOR_300 384 -#define UART_BPS_DIVISOR_600 192 -#define UART_BPS_DIVISOR_1200 96 -#define UART_BPS_DIVISOR_1800 64 -#define UART_BPS_DIVISOR_2400 48 -#define UART_BPS_DIVISOR_3800 32 -#define UART_BPS_DIVISOR_4800 24 -#define UART_BPS_DIVISOR_7200 16 -#define UART_BPS_DIVISOR_9600 12 -#define UART_BPS_DIVISOR_19200 6 -#define UART_BPS_DIVISOR_38400 3 -#define UART_BPS_DIVISOR_57600 2 -#define UART_BPS_DIVISOR_115200 1 - -/* FIFO size */ -#define UART_FIFO_SIZE_IN_BYTES 16 - -/* ======================================================================== */ -/* ==================== PROTOTYPES, TYPEDEFS & GLOBALS ==================== */ -/* ======================================================================== */ - - -typedef struct -{ - unsigned char port; - unsigned char default_irq; - unsigned char irq; - unsigned char open; - unsigned char ier; - unsigned char fcr; - unsigned char lcr; - unsigned char mcr; - unsigned char lsr; - unsigned char msr; - unsigned char flow_mode; - unsigned char rx_flow_on; - unsigned char tx_flow_on; - unsigned char rx_buff[(unsigned short)SER_RX_BUFFER_SIZE]; - unsigned char tx_buff[(unsigned short)SER_TX_BUFFER_SIZE]; - unsigned int base; - unsigned int dlatch; - unsigned int rx_head; - unsigned int tx_head; - unsigned int rx_tail; - unsigned int tx_tail; -} serial_struct; - - -#if defined( __DJGPP__ ) -typedef _go32_dpmi_seginfo int_handler_ptr; -static _go32_dpmi_seginfo g_old_isrs[16]; -#else -typedef void Interrupt Far (*int_handler_ptr)(void); -static int_handler_ptr g_old_isrs[16]; -#endif -static unsigned char g_isrs_taken[16] = {0}; -#ifdef PROTECTED_MODE -static int_handler_ptr g_isr_addr; -static unsigned int g_isrs_count = 0; -#endif - - -/* serial port data */ -static serial_struct g_comports[COM_MAX+1] = -{ -#if defined( __GNUC__ ) - {port: 0, default_irq: COM1_DEFAULT_IRQ, irq: IRQ_NONE}, - {port: 1, default_irq: COM2_DEFAULT_IRQ, irq: IRQ_NONE}, - {port: 2, default_irq: COM3_DEFAULT_IRQ, irq: IRQ_NONE}, - {port: 3, default_irq: COM4_DEFAULT_IRQ, irq: IRQ_NONE} -#else - {0, COM1_DEFAULT_IRQ, IRQ_NONE}, - {1, COM2_DEFAULT_IRQ, IRQ_NONE}, - {2, COM3_DEFAULT_IRQ, IRQ_NONE}, - {3, COM4_DEFAULT_IRQ, IRQ_NONE} -#endif -}; - - - -/* ======================================================================== */ -/* ====================== INTERRUPT SERVICE ROUTINE ======================= */ -/* ======================================================================== */ - -static void Interrupt com_general_isr(void) -{ - serial_struct* com_min = (serial_struct*)(g_comports); - serial_struct* com_max = com_min + COM_MAX; - unsigned char int_id; - unsigned char data; - unsigned char slave_interrupted = 0; - serial_struct* com; - - /* Disable IRQs for all COM ports, then re-enable interrupts. - * This allows other faster devices to be serviced. - */ - for(com=com_min;com<=com_max;com++) - { - if(com->open) - { - if(com->irq > 7) - slave_interrupted = 1; - PIC_DISABLE_IRQ(com->irq); - } - } - CPU_ENABLE_INTERRUPTS(); - - /* Process all pending interrupts */ - for(com=com_min;com<=com_max;com++) - { - if(com->open) - { - while((int_id=UART_READ_INTERRUPT_IDENTIFY(com) & UART_IIR_MASK) != UART_IIR_NO_INTERRUPT) - { - switch(int_id) - { - case UART_IIR_DATA_READY: - /* Read all data from the UART */ - while(UART_READ_LINE_STATUS(com) & UART_LSR_DATA_READY) - { - data = UART_READ_DATA(com); - - /* Handle XON/XOFF flow control (TX) */ - if(com->flow_mode == SER_HANDSHAKING_XONXOFF && (data == SER_XOFF || data == SER_XON)) - { - com->tx_flow_on = data == SER_XON; - if(!SER_TX_BUFFER_EMPTY(com) && com->tx_flow_on) - UART_WRITE_INTERRUPT_ENABLE(com, UART_READ_INTERRUPT_ENABLE(com) | UART_IER_TX_HOLD_EMPTY); - } - - /* Store it if there's room, or throw it out */ - else if(!SER_RX_BUFFER_FULL(com)) - { - SER_RX_BUFFER_WRITE(com, data); - - /* Flow control (RX) - Turn off if buffer almost full */ - if(com->rx_flow_on && SER_RX_BUFFER_HIWATER(com)) - { - com->rx_flow_on = 0; - - switch(com->flow_mode) - { - case SER_HANDSHAKING_RTSCTS: - UART_WRITE_MODEM_CONTROL(com, UART_READ_MODEM_CONTROL(com) & ~UART_MCR_RTS); - break; - case SER_HANDSHAKING_NONE: - break; - case SER_HANDSHAKING_XONXOFF: - UART_WRITE_DATA(com, SER_XOFF); - break; - case SER_HANDSHAKING_DTRDSR: - UART_WRITE_MODEM_CONTROL(com, UART_READ_MODEM_CONTROL(com) & ~UART_MCR_DTR); - break; - } - } - } - } - break; - /* Change in line status */ - case UART_IIR_LINE_STATUS: - UART_READ_LINE_STATUS(com); - break; - /* Change in modem status */ - case UART_IIR_MODEM_STATUS: - UART_READ_MODEM_STATUS(com); - - /* Handle RTS/CTS or DSR/DTR flow control (TX) */ - if(com->flow_mode == SER_HANDSHAKING_RTSCTS) - com->tx_flow_on = (com->msr & UART_MSR_CTS) != 0; - else if(com->flow_mode == SER_HANDSHAKING_DTRDSR) - com->tx_flow_on = (com->msr & UART_MSR_DSR) != 0; - if(!SER_TX_BUFFER_EMPTY(com) && com->tx_flow_on) - UART_WRITE_INTERRUPT_ENABLE(com, UART_READ_INTERRUPT_ENABLE(com) | UART_IER_TX_HOLD_EMPTY); - break; - /* UART is empty */ - case UART_IIR_TX_HOLD_EMPTY: - { - int cnt; - for (cnt=0; cnttx_flow_on && !SER_TX_BUFFER_EMPTY(com); cnt++) - UART_WRITE_DATA(com, SER_TX_BUFFER_READ(com)); - if(SER_TX_BUFFER_EMPTY(com) || !com->tx_flow_on) - UART_WRITE_INTERRUPT_ENABLE(com, UART_READ_INTERRUPT_ENABLE(com) & ~UART_IER_TX_HOLD_EMPTY); - break; - } - } - } - } - } - - CPU_DISABLE_INTERRUPTS(); - - /* End the interrupt on the PIC */ - if(slave_interrupted) - PIC_END_INTERRUPT(PIC_SLAVE); - PIC_END_INTERRUPT(PIC_MASTER); - - /* Re-enable all interrupts */ - for(com=com_min;com<=com_max;com++) - if(com->open) - PIC_ENABLE_IRQ(com->irq); - - /* We must explicitely call 'sti' before 'iret' because 'iret' - won't always restore interrupts in a virtual environment */ - CPU_ENABLE_INTERRUPTS(); -} - - - -/* ======================================================================== */ -/* =========================== UTILITY ROUTINES =========================== */ -/* ======================================================================== */ - - -#ifdef PROTECTED_MODE - -/* we do not know the exact size of com_general_isr() function - but for sure it's not longer then 2048 bytes */ -#define ISR_SIZE 2048 - -#if defined( __DJGPP__ ) - -static void serial_dpmi_get_pvect(int vector, _go32_dpmi_seginfo *info) -{ - _go32_dpmi_get_protected_mode_interrupt_vector(vector, info); -} - -static void serial_dpmi_set_pvect(int vector, _go32_dpmi_seginfo *info) -{ - _go32_dpmi_set_protected_mode_interrupt_vector(vector, info); -} - -static int serial_dpmi_lock_memory(void) -{ - unsigned long dataaddr, codeaddr; - __dpmi_meminfo dataregion, coderegion; - - if(__dpmi_get_segment_base_address(_my_cs(), &codeaddr) == 0 && - __dpmi_get_segment_base_address(_my_ds(), &dataaddr) == 0) - { - coderegion.handle = 0; - coderegion.size = ISR_SIZE; - coderegion.address = codeaddr + (unsigned long)com_general_isr; - dataregion.handle = 0; - dataregion.size = sizeof(g_comports); - dataregion.address = codeaddr + (unsigned long)g_comports; - if(__dpmi_lock_linear_region(&coderegion) == 0) - { - if(__dpmi_lock_linear_region(&dataregion) == 0) - { - g_isr_addr.pm_offset = (unsigned long)com_general_isr; - g_isr_addr.pm_selector = _go32_my_cs(); - if(_go32_dpmi_allocate_iret_wrapper(&g_isr_addr) == 0) - return 1; - __dpmi_unlock_linear_region(&dataregion); - } - __dpmi_unlock_linear_region(&coderegion); - } - } - return 0; -} - -static void serial_dpmi_unlock_memory(void) -{ - unsigned long baseaddr; - __dpmi_meminfo region; - - if(__dpmi_get_segment_base_address(_my_ds(), &baseaddr) == 0) - { - region.handle = 0; - region.size = sizeof(g_comports); - region.address = baseaddr + (unsigned long)g_comports; - __dpmi_unlock_linear_region(®ion); - } - if(__dpmi_get_segment_base_address(_my_cs(), &baseaddr) == 0) - { - region.handle = 0; - region.size = ISR_SIZE; - region.address = baseaddr + (unsigned long)com_general_isr; - __dpmi_unlock_linear_region(®ion); - } - _go32_dpmi_free_iret_wrapper(&g_isr_addr); -} - -#else /* ! __DJGPP__ */ - -static void serial_dpmi_get_pvect(int vect, int_handler_ptr *handler) -{ - union REGS r; - unsigned short sel; - unsigned long off; - - /* DPMI get protected mode interrupt vector: Int 31H, Fn 0204H */ - r.x.eax = 0x0204; - r.x.ebx = vect; - int386(0x31, &r, &r); - sel = (unsigned short) r.x.ecx; - off = r.x.edx; - - *handler=(int_handler_ptr) MK_FP(sel, off); -} - -static void serial_dpmi_set_pvect(int vect, int_handler_ptr *handler) -{ - union REGS r; - void Far *ptr; - - /* DPMI set protected mode interrupt vector: Int 31H, Fn 0205H */ - ptr = (void Far *)*handler; - r.x.eax = 0x0205; - r.x.ebx = vect; - r.x.ecx = FP_SEG(ptr); - r.x.edx = FP_OFF(ptr); - int386(0x31, &r, &r); -} - -static int serial_dpmi_lock_linear_memory(void Far *ptr, unsigned long size) -{ - union REGS r; - - /* DPMI get segment base address: Int 31H, Fn 0006H */ - r.x.eax = 0x0006; - r.x.ebx = FP_SEG(ptr); - int386(0x31, &r, &r); - if(r.w.cflag == 0) - { - unsigned long addr = FP_OFF( ptr ) + ((r.w.cx << 16) | r.w.dx); - - /* DPMI lock linear region: Int 31H, Fn 0600H */ - r.x.eax = 0x0600; - r.x.ebx = addr >> 16; - r.x.ecx = addr & 0xFFFF; - r.x.esi = size >> 16; - r.x.edi = size & 0xFFFF; - int386(0x31, &r, &r); - if(r.w.cflag == 0) - { - g_isr_addr = com_general_isr; - return 1; - } - } - return 0; -} - -static void serial_dpmi_unlock_linear_memory(void Far *ptr, unsigned long size) -{ - union REGS r; - - /* DPMI get segment base address: Int 31H, Fn 0006H */ - r.x.eax = 0x0006; - r.x.ebx = FP_SEG(ptr); - int386(0x31, &r, &r); - if(r.w.cflag == 0) - { - unsigned long addr = FP_OFF( ptr ) + ((r.w.cx << 16) | r.w.dx); - - /* DPMI unlock linear region: Int 31H, Fn 0601H */ - r.x.eax = 0x0601; - r.x.ebx = addr >> 16; - r.x.ecx = addr & 0xFFFF; - r.x.esi = size >> 16; - r.x.edi = size & 0xFFFF; - int386(0x31, &r, &r); - } - int386 (0x31, &r, &r); -} - -static int serial_dpmi_lock_memory(void) -{ - if(serial_dpmi_lock_linear_memory(com_general_isr, ISR_SIZE)) - { - if(serial_dpmi_lock_linear_memory(g_comports, sizeof(g_comports))) - return 1; - serial_dpmi_unlock_linear_memory(com_general_isr, ISR_SIZE); - } - return 0; -} - -static void serial_dpmi_unlock_memory(void) -{ - serial_dpmi_unlock_linear_memory(com_general_isr, ISR_SIZE); - serial_dpmi_unlock_linear_memory(g_comports, sizeof(g_comports)); -} - -#endif /* ! __DJGPP__ */ - -static int serial_install_irqhandler(int irq) -{ - /* If we haven't taken this IRQ's ISR already, take it */ - if(!g_isrs_taken[irq]) - { - if( g_isrs_count++ == 0 ) - { - /* lock memory used by interrupt handler in DPMI mode */ - if(!serial_dpmi_lock_memory()) - { - --g_isrs_count; - return SER_ERR_LOCK_MEM; - } - } - serial_dpmi_get_pvect(irq+INTERRUPT_VECTOR_OFFSET, &g_old_isrs[irq]); - serial_dpmi_set_pvect(irq+INTERRUPT_VECTOR_OFFSET, &g_isr_addr); - g_isrs_taken[irq] = 1; - } - return SER_SUCCESS; -} - -static void serial_remove_irqhandler(int irq) -{ - if(g_isrs_taken[irq]) - { - serial_dpmi_set_pvect(irq+INTERRUPT_VECTOR_OFFSET, &g_old_isrs[irq]); - g_isrs_taken[irq] = 0; - - if( --g_isrs_count == 0 ) - /* unlock memory used by interrupt handler in DPMI mode */ - serial_dpmi_unlock_memory(); - } -} - -#else /* ! PROTECTED_MODE */ - -static int serial_install_irqhandler(int irq) -{ - /* If we haven't taken this IRQ's ISR already, take it */ - if(!g_isrs_taken[irq]) - { - g_old_isrs[irq] = _dos_getvect(irq+INTERRUPT_VECTOR_OFFSET); - _dos_setvect(irq+INTERRUPT_VECTOR_OFFSET, com_general_isr); - g_isrs_taken[irq] = 1; - } - return SER_SUCCESS; -} - -static void serial_remove_irqhandler(int irq) -{ - _dos_setvect(irq+INTERRUPT_VECTOR_OFFSET, g_old_isrs[irq]); - g_isrs_taken[irq] = 0; -} - -#endif /* ! PROTECTED_MODE */ - - -static int serial_find_irq(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - unsigned char imr_m = PIC_READ_IMR(PIC_MASTER); /* Interrupt Mask Registers */ - unsigned char imr_s = PIC_READ_IMR(PIC_SLAVE); - unsigned char irr_m; /* Interrupt Request Registers */ - unsigned char irr_s; - - /* Set up the UART */ - UART_WRITE_MODEM_CONTROL(com, UART_MCR_OUT2); - UART_WRITE_FIFO_CONTROL(com, 0); - - /* Wait until tx hold register is empty */ - while((UART_READ_LINE_STATUS(com) & UART_LSR_TX_HOLD_EMPTY) == 0); - - CPU_DISABLE_INTERRUPTS(); - - /* Allow any interrupt on PIC */ - PIC_WRITE_IMR(PIC_MASTER, 0); - PIC_WRITE_IMR(PIC_SLAVE, 0); - - /* Do some initial polls to let things settle (win95 needs this) */ - UART_WRITE_INTERRUPT_ENABLE(com, UART_IER_TX_HOLD_EMPTY); - PIC_READ_IRR(PIC_MASTER); - PIC_READ_IRR(PIC_SLAVE); - UART_WRITE_INTERRUPT_ENABLE(com, 0); - PIC_READ_IRR(PIC_MASTER); - PIC_READ_IRR(PIC_SLAVE); - - /* Generate an interrupt and record all active IRQs */ - UART_WRITE_INTERRUPT_ENABLE(com, UART_IER_TX_HOLD_EMPTY); - irr_m = PIC_READ_IRR(PIC_MASTER); - irr_s = PIC_READ_IRR(PIC_SLAVE); - - /* Remove the interrupt and mask out all IRQs still active */ - UART_WRITE_INTERRUPT_ENABLE(com, 0); - irr_m &= ~PIC_READ_IRR(PIC_MASTER); - irr_s &= ~PIC_READ_IRR(PIC_SLAVE); - - /* Interrupt again to make sure */ - UART_WRITE_INTERRUPT_ENABLE(com, UART_IER_TX_HOLD_EMPTY); - irr_m &= PIC_READ_IRR(PIC_MASTER); - irr_s &= PIC_READ_IRR(PIC_SLAVE); - - /* Return everything to normal */ - PIC_WRITE_IMR(PIC_MASTER, imr_m); - PIC_WRITE_IMR(PIC_SLAVE, imr_s); - UART_WRITE_INTERRUPT_ENABLE(com, 0); - - CPU_ENABLE_INTERRUPTS(); - - switch(irr_m) - { - case 0x01: return 0; - case 0x02: return 1; - case 0x04: - switch(irr_s) - { - case 0x01: return 8; - case 0x02: return 9; - case 0x04: return 10; - case 0x08: return 11; - case 0x10: return 12; - case 0x20: return 13; - case 0x40: return 14; - case 0x80: return 15; - default: return 2; - } - case 0x08: return 3; - case 0x10: return 4; - case 0x20: return 5; - case 0x40: return 6; - case 0x80: return 7; - } - return SER_ERR_IRQ_NOT_FOUND; -} - -static void serial_free_irq(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - serial_struct* com_min = (serial_struct*)(g_comports); - serial_struct* com_max = com_min + COM_MAX; - unsigned int irq = com->irq; - serial_struct* ptr; - - if(irq == IRQ_NONE) - return; - - CPU_DISABLE_INTERRUPTS(); - - /* Disable interrupts from the UART */ - UART_WRITE_INTERRUPT_ENABLE(com, 0); - UART_WRITE_MODEM_CONTROL(com, UART_MCR_OUT2); - /* Clear the FIFO and rx registers */ - UART_WRITE_FIFO_CONTROL(com, 0); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_DATA(com); - UART_READ_INTERRUPT_IDENTIFY(com); - UART_READ_LINE_STATUS(com); - UART_READ_DATA(com); - /* Clear any other possible interrupt causes */ - UART_READ_INTERRUPT_IDENTIFY(com); - UART_READ_MODEM_STATUS(com); - UART_READ_INTERRUPT_IDENTIFY(com); - UART_READ_LINE_STATUS(com); - UART_READ_INTERRUPT_IDENTIFY(com); - - com->irq = IRQ_NONE; - - CPU_ENABLE_INTERRUPTS(); - - for(ptr=com_min;ptr<=com_max;ptr++) - if(ptr != com && ptr->irq == irq) - return; - - /* Disable interrupts from the PIC and restore the old vector */ - PIC_DISABLE_IRQ(irq); - serial_remove_irqhandler(irq); -} - - -/* ======================================================================== */ -/* ======================== BASIC SERIAL ROUTINES ========================= */ -/* ======================================================================== */ - -int serial_open(int comport, long bps, int data_bits, char parity, int stop_bits, int handshaking) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - int rc = SER_SUCCESS; - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(com->open) - return SER_ERR_ALREADY_OPEN; - - com->open = 1; - - /* Initialize buffers */ - com->rx_flow_on = 1; - com->tx_flow_on = 1; - SER_RX_BUFFER_INIT(com); - SER_TX_BUFFER_INIT(com); - - /* look in bios tables (0040:0000 - 0040:0006) for com base addresses */ - if(serial_set_base(comport, Farpeekw(0x0040, comport<<1)) != SER_SUCCESS) - return SER_ERR_NO_UART; - - /* Turn off interrupts from UART */ - UART_WRITE_INTERRUPT_ENABLE(com, 0); - - /* Auto-detect IRQ if we can */ - if((rc=serial_find_irq(comport)) < 0) - rc = com->default_irq; - - if((rc=serial_set_irq(comport, rc)) != SER_SUCCESS) - return rc; - - /* Turn off interrupts from PIC */ - PIC_DISABLE_IRQ(com->irq); - - /* Set the comport */ - if((rc=serial_set(comport, bps, data_bits, parity, stop_bits, handshaking)) == SER_SUCCESS) - { - UART_WRITE_MODEM_CONTROL(com, UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT1 | UART_MCR_OUT2); - rc = serial_set_fifo_threshold(comport, UART_FIFO_DEFAULT_THRESHOLD); - - /* Get some info */ - UART_READ_LINE_STATUS(com); - UART_READ_MODEM_STATUS(com); - } - - /* Re-enable interrupts */ - UART_WRITE_INTERRUPT_ENABLE(com, UART_IER_DATA_READY | UART_IER_MODEM_STATUS | UART_IER_ERRORS); - PIC_ENABLE_IRQ(com->irq); - - if(rc != SER_SUCCESS) /* We failed to set the comport */ - serial_close(comport); - - return rc; -} - -int serial_close(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - /* Restore old interrupts */ - serial_free_irq(comport); - - /* Turn everything off */ - UART_WRITE_INTERRUPT_ENABLE(com, 0); - UART_WRITE_MODEM_CONTROL(com, 0); - serial_set_fifo_threshold(comport, 0); - - com->open = 0; - - return SER_SUCCESS; -} - -int serial_read(int comport, char* data, int len) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - int i; - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - if(data == 0) - return SER_ERR_NULL_PTR; - - CPU_DISABLE_INTERRUPTS(); - /* Fill in the array given to us */ - for(i=0;!SER_RX_BUFFER_EMPTY(com) && i < len;i++) - data[i] = SER_RX_BUFFER_READ(com); - - /* Flow control (RX) - Turn on if buffer almost empty */ - if(!com->rx_flow_on && SER_RX_BUFFER_LOWATER(com)) - { - com->rx_flow_on = 1; - if(com->flow_mode == SER_HANDSHAKING_XONXOFF) - UART_WRITE_DATA(com, SER_XON); - else if(com->flow_mode == SER_HANDSHAKING_RTSCTS) - UART_WRITE_MODEM_CONTROL(com, UART_READ_MODEM_CONTROL(com) | UART_MCR_RTS); - else if(com->flow_mode == SER_HANDSHAKING_DTRDSR) - UART_WRITE_MODEM_CONTROL(com, UART_READ_MODEM_CONTROL(com) | UART_MCR_DTR); - } - CPU_ENABLE_INTERRUPTS(); - - return i; -} - - -int serial_write(int comport, const char* data, int len) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - int i; - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - if(data == 0) - return SER_ERR_NULL_PTR; - - for(i=0;i < len;i++) - { - /* Wait until we can write */ - while(!(UART_READ_LINE_STATUS(com) & UART_LSR_TX_HOLD_EMPTY)) - {} - - /* Write 1 char */ - if(com->tx_flow_on) - UART_WRITE_DATA(com, data[i]); - else - break; - } - return i; -} - -int serial_write_buffered(int comport, const char* data, int len) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - int i; - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - if(data == 0) - return SER_ERR_NULL_PTR; - - CPU_DISABLE_INTERRUPTS(); - for(i=0;i < len ;i++) - { - /* stop when sent buffer is full */ - if(SER_TX_BUFFER_FULL(com)) - break; - /* Write 1 char */ - SER_TX_BUFFER_WRITE(com, data[i]); - } - - /* If there's data to send, enable TX_HOLD_EMPTY interrupt */ - if(!SER_TX_BUFFER_EMPTY(com)) - UART_WRITE_INTERRUPT_ENABLE(com, UART_READ_INTERRUPT_ENABLE(com) | UART_IER_TX_HOLD_EMPTY); - CPU_ENABLE_INTERRUPTS(); - - return i; -} - - -int serial_set(int comport, long bps, int data_bits, char parity, int stop_bits, int handshaking) -{ - int rc; - - if((rc=serial_set_bps(comport, bps)) == SER_SUCCESS) - if((rc=serial_set_data(comport, data_bits)) == SER_SUCCESS) - if((rc=serial_set_parity(comport, parity)) == SER_SUCCESS) - if((rc=serial_set_stop(comport, stop_bits)) == SER_SUCCESS) - return serial_set_handshaking(comport, handshaking); - return rc; -} - - -/* ======================================================================== */ -/* ========================== SETTINGS ROUTINES =========================== */ -/* ======================================================================== */ - - -int serial_set_base(int comport, int base) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(base < 1 || base > 0xfff) - return SER_ERR_INVALID_BASE; - - com->base = base; - return SER_SUCCESS; -} - -int serial_set_irq(int comport, int irq) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - int rc; - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(irq < IRQ_MIN || irq > IRQ_MAX) - return SER_ERR_INVALID_IRQ; - if(!com->open) - return SER_ERR_NOT_OPEN; - - /* Remove any ISRs on this com port's current IRQ */ - serial_free_irq(comport); - - if((rc=serial_install_irqhandler(irq)) == SER_SUCCESS) - { - com->irq = irq; - PIC_ENABLE_IRQ(com->irq); - } - return rc; -} - -int serial_set_fifo_threshold(int comport, int threshold) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - int i; - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - switch(threshold) - { - case 14: - UART_WRITE_FIFO_CONTROL(com, UART_FCR_FIFO_ENABLE | UART_FCR_RX_FIFO_RESET | UART_FCR_TX_FIFO_RESET | UART_FCR_TRIGGER_AT_14); - break; - case 8: - UART_WRITE_FIFO_CONTROL(com, UART_FCR_FIFO_ENABLE | UART_FCR_RX_FIFO_RESET | UART_FCR_TX_FIFO_RESET | UART_FCR_TRIGGER_AT_8); - break; - case 4: - UART_WRITE_FIFO_CONTROL(com, UART_FCR_FIFO_ENABLE | UART_FCR_RX_FIFO_RESET | UART_FCR_TX_FIFO_RESET | UART_FCR_TRIGGER_AT_4); - break; - case 1: - UART_WRITE_FIFO_CONTROL(com, UART_FCR_FIFO_ENABLE | UART_FCR_RX_FIFO_RESET | UART_FCR_TX_FIFO_RESET | UART_FCR_TRIGGER_AT_1); - break; - case 0: - UART_WRITE_FIFO_CONTROL(com, 0); - break; - default: - return SER_ERR_INVALID_FIFO_THRESHOLD; - } - - /* Clear out any garbage in the UART interrupts and FIFO */ - for(i=0;i<16;i++) - UART_READ_DATA(com); - UART_READ_LINE_STATUS(com); - - return SER_SUCCESS; -} - - -int serial_set_bps(int comport, long bps) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - switch(bps) - { - case 115200L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_115200); - return SER_SUCCESS; - case 57600L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_57600); - return SER_SUCCESS; - case 38400L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_38400); - return SER_SUCCESS; - case 19200L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_19200); - return SER_SUCCESS; - case 9600L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_9600); - return SER_SUCCESS; - case 7200L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_7200); - return SER_SUCCESS; - case 4800L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_4800); - return SER_SUCCESS; - case 3800L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_3800); - return SER_SUCCESS; - case 1800L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_1800); - return SER_SUCCESS; - case 2400L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_2400); - return SER_SUCCESS; - case 1200L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_1200); - return SER_SUCCESS; - case 600L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_600); - return SER_SUCCESS; - case 300L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_300); - return SER_SUCCESS; - case 150L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_150); - return SER_SUCCESS; - case 110L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_110); - return SER_SUCCESS; - case 75L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_75); - return SER_SUCCESS; - case 50L: - UART_WRITE_BPS(com, UART_BPS_DIVISOR_50); - return SER_SUCCESS; - } - return SER_ERR_INVALID_BPS; -} - - -int serial_set_data(int comport, int data_bits) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - switch(data_bits) - { - case 5: - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_DATA_MASK) | UART_DATA_5); - return SER_SUCCESS; - case 6: - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_DATA_MASK) | UART_DATA_6); - return SER_SUCCESS; - case 7: - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_DATA_MASK) | UART_DATA_7); - return SER_SUCCESS; - case 8: - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_DATA_MASK) | UART_DATA_8); - return SER_SUCCESS; - } - return SER_ERR_INVALID_DATA_BITS; -} - - -int serial_set_parity(int comport, char parity) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - switch(parity) - { - case 'n': - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_PARITY_MASK) | UART_PARITY_NONE); - return SER_SUCCESS; - case 'e': - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_PARITY_MASK) | UART_PARITY_EVEN); - return SER_SUCCESS; - case 'o': - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_PARITY_MASK) | UART_PARITY_ODD); - return SER_SUCCESS; - case 'm': - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_PARITY_MASK) | UART_PARITY_MARK); - return SER_SUCCESS; - case 's': - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_PARITY_MASK) | UART_PARITY_SPACE); - return SER_SUCCESS; - } - return SER_ERR_INVALID_PARITY; -} - - -int serial_set_stop(int comport, int stop_bits) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - switch(stop_bits) - { - case 1: - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_STOP_MASK) | UART_STOP_1); - return SER_SUCCESS; - case 2: - UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_STOP_MASK) | UART_STOP_2); - return SER_SUCCESS; - } - return SER_ERR_INVALID_STOP_BITS; -} - - -int serial_set_handshaking(int comport, int handshaking) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - com->tx_flow_on = 1; - com->rx_flow_on = 1; - - if(handshaking < SER_HANDSHAKING_NONE || handshaking > SER_HANDSHAKING_DTRDSR) - return SER_ERR_INVALID_HANDSHAKING; - - com->flow_mode = handshaking; - return SER_SUCCESS; -} - - -int serial_set_rts(int comport, int rts) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - if(rts) - UART_WRITE_MODEM_CONTROL(com, com->mcr | UART_MCR_RTS); - else - UART_WRITE_MODEM_CONTROL(com, com->mcr & ~UART_MCR_RTS); - - return SER_SUCCESS; -} - - -int serial_set_dtr(int comport, int dtr) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - if(dtr) - UART_WRITE_MODEM_CONTROL(com, com->mcr | UART_MCR_DTR); - else - UART_WRITE_MODEM_CONTROL(com, com->mcr & ~UART_MCR_DTR); - - return SER_SUCCESS; -} - - -int serial_set_mcr(int comport, int mcr) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - UART_WRITE_MODEM_CONTROL(com, mcr & UART_MCR_MASK ); - - return SER_SUCCESS; -} - - - -int serial_get_base(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(com->base < 1 || com->base > 0xfff) - return SER_ERR_INVALID_BASE; - - return com->base; -} - -int serial_get_irq(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(com->irq < IRQ_MIN || com->irq > IRQ_MAX) - return SER_ERR_INVALID_IRQ; - - return com->irq; -} - -long serial_get_bps(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - switch(UART_READ_BPS(com)) - { - case UART_BPS_DIVISOR_115200: - return 115200L; - case UART_BPS_DIVISOR_57600: - return 57600L; - case UART_BPS_DIVISOR_38400: - return 38400L; - case UART_BPS_DIVISOR_19200: - return 19200L; - case UART_BPS_DIVISOR_9600: - return 9600L; - case UART_BPS_DIVISOR_7200: - return 7200L; - case UART_BPS_DIVISOR_4800: - return 4800L; - case UART_BPS_DIVISOR_3800: - return 3800L; - case UART_BPS_DIVISOR_2400: - return 2400L; - case UART_BPS_DIVISOR_1800: - return 1800L; - case UART_BPS_DIVISOR_1200: - return 1200L; - case UART_BPS_DIVISOR_600: - return 600L; - case UART_BPS_DIVISOR_300: - return 300L; - case UART_BPS_DIVISOR_150: - return 150L; - case UART_BPS_DIVISOR_110: - return 110L; - case UART_BPS_DIVISOR_75: - return 75L; - case UART_BPS_DIVISOR_50: - return 50L; - } - return SER_ERR_INVALID_BPS; -} - - -int serial_get_data(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - switch(UART_READ_LINE_CONTROL(com) & UART_DATA_MASK) - { - case UART_DATA_5: - return 5; - case UART_DATA_6: - return 6; - case UART_DATA_7: - return 7; - case UART_DATA_8: - return 8; - } - return SER_ERR_INVALID_DATA_BITS; -} - - -char serial_get_parity(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - switch(UART_READ_LINE_CONTROL(com) & UART_PARITY_MASK) - { - case UART_PARITY_NONE: - return 'n'; - case UART_PARITY_EVEN: - return 'e'; - case UART_PARITY_ODD: - return 'o'; - case UART_PARITY_MARK: - return 'm'; - case UART_PARITY_SPACE: - return 's'; - } - return SER_ERR_INVALID_PARITY; -} - - -int serial_get_stop(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - switch(UART_READ_LINE_CONTROL(com) & UART_STOP_MASK) - { - case UART_STOP_1: - return 1; - case UART_STOP_2: - return 2; - } - return SER_ERR_INVALID_STOP_BITS; -} - - -int serial_get_handshaking(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - - return com->flow_mode; -} - - -int serial_get_rts(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - - return (com->mcr & UART_MCR_RTS) != 0; -} - - -int serial_get_dtr(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - - return (com->mcr & UART_MCR_DTR) != 0; -} - - -int serial_get_mcr(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - - return com->mcr; -} - - -int serial_get_dsr(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - - return (com->msr & UART_MSR_DSR) != 0; -} - - -int serial_get_cts(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - - return (com->msr & UART_MSR_CTS) != 0; -} - - -int serial_get_msr(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - - return com->msr; -} - - -int serial_get_lsr(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - - return com->lsr; -} - - - -int serial_get_tx_buffered(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - int count; - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - CPU_DISABLE_INTERRUPTS(); - count = SER_TX_BUFFER_CURRENT(com); - CPU_ENABLE_INTERRUPTS(); - - return count; -} - - -int serial_get_rx_buffered(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - int count; - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - CPU_DISABLE_INTERRUPTS(); - count = SER_RX_BUFFER_CURRENT(com); - CPU_ENABLE_INTERRUPTS(); - - return count; -} - - -int serial_clear_tx_buffer(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - CPU_DISABLE_INTERRUPTS(); - SER_TX_BUFFER_INIT(com); - CPU_ENABLE_INTERRUPTS(); - - return SER_SUCCESS; -} - - -int serial_clear_rx_buffer(int comport) -{ - serial_struct* com = (serial_struct*)(g_comports + comport); - - if(comport < COM_MIN || comport > COM_MAX) - return SER_ERR_INVALID_COMPORT; - if(!com->open) - return SER_ERR_NOT_OPEN; - - CPU_DISABLE_INTERRUPTS(); - SER_RX_BUFFER_INIT(com); - CPU_ENABLE_INTERRUPTS(); - - return SER_SUCCESS; -} +#include +#include +#include "serial.h" + +#if defined( __DJGPP__ ) +#include +#include +#include +#define Interrupt +#define Far +#define Farpeekw(s, o) _farpeekw((s),(o)) +#define _Outp(a,b) (outp(a,b),(b)) +#define _Outpw(a,w) (outpw(a,w),(w)) +#define CPU_DISABLE_INTERRUPTS() asm("CLI") +#define CPU_ENABLE_INTERRUPTS() asm("STI") +#elif defined( _MSC_VER ) || defined( __WATCOMC__ ) +#define Interrupt __interrupt +#define Far __far +#define Farpeekw(s, o) (*((unsigned short Far*)(MK_FP((s), (o))))) +#define _Outp(a,b) outp(a,b) +#define _Outpw(a,w) outpw(a,w) +#define CPU_DISABLE_INTERRUPTS() __asm CLI +#define CPU_ENABLE_INTERRUPTS() __asm STI +#else /* __BORLANDC__ */ +#define Interrupt interrupt +#define Far far +#define Farpeekw(s, o) (*((unsigned short Far*)(MK_FP((s), (o))))) +#define _Outp(a,b) outp(a,b) +#define _Outpw(a,w) outpw(a,w) +#define CPU_DISABLE_INTERRUPTS() asm CLI +#define CPU_ENABLE_INTERRUPTS() asm STI +#endif /* _MSC_VER */ +#if defined( __386__ ) || defined( __DJGPP__ ) +#define PROTECTED_MODE +#endif + +/* ======================================================================== */ +/* =========================== DEFINES & MACROS =========================== */ +/* ======================================================================== */ + + +/* Tweak Values */ +#define SER_RX_BUFFER_SIZE_BITS 11 /* 2048 */ +#define SER_RX_BUFFER_HIGH_PERCENT 80 +#define SER_RX_BUFFER_LOW_PERCENT 20 + +#define SER_TX_BUFFER_SIZE_BITS 11 /* 2048 */ +#define SER_TX_BUFFER_HIGH_PERCENT 80 +#define SER_TX_BUFFER_LOW_PERCENT 20 + +#define UART_FIFO_DEFAULT_THRESHOLD 14 /* 14, 8, 4, 1, or 0 (off) */ + +#define COM1_DEFAULT_IRQ 4 +#define COM2_DEFAULT_IRQ 3 +#define COM3_DEFAULT_IRQ 4 +#define COM4_DEFAULT_IRQ 3 + +#define COM_MIN COM_1 +#define COM_MAX COM_4 + +#define IRQ_MIN 3 +#define IRQ_MAX 15 +#define IRQ_NONE 0xff + + +/* Receive and transmit buffers + * + * Both head and tail work in pre-increment mode: + * + * H->W->W->W + * * * * + * 0 1 2 3 4 5 ... + * * * * + * T->R->R->R + * + * Buffer empty: + * + * H + * ... 4 5 6 7 ... + * T + * + * Buffer full: + * + * H + * ... 4 5 6 7 ... + * T + */ + +#define SER_RX_BUFFER_SIZE (1L<rx_buff[(C)->rx_tail = ((C)->rx_tail+1) & SER_RX_BUFFER_SIZE_MASK] +#define SER_RX_BUFFER_WRITE(C, D) (C)->rx_buff[(C)->rx_head = ((C)->rx_head+1) & SER_RX_BUFFER_SIZE_MASK] = D +#define SER_RX_BUFFER_INIT(C) (C)->rx_head = (C)->rx_tail = 0 +#define SER_RX_BUFFER_EMPTY(C) ((C)->rx_head == (C)->rx_tail) +#define SER_RX_BUFFER_FULL(C) ((((C)->rx_head+1) & SER_RX_BUFFER_SIZE_MASK) == (C)->rx_tail) +#define SER_RX_BUFFER_CURRENT(C) (((C)->rx_head - (C)->rx_tail) & SER_RX_BUFFER_SIZE_MASK) +#define SER_RX_BUFFER_LOWATER(C) (SER_RX_BUFFER_CURRENT(C) < SER_RX_BUFFER_LOW) +#define SER_RX_BUFFER_HIWATER(C) (SER_RX_BUFFER_CURRENT(C) > SER_RX_BUFFER_HIGH) + +#define SER_TX_BUFFER_SIZE (1L<tx_buff[(C)->tx_tail = ((C)->tx_tail+1) & SER_TX_BUFFER_SIZE_MASK] +#define SER_TX_BUFFER_WRITE(C, D) (C)->tx_buff[(C)->tx_head = ((C)->tx_head+1) & SER_TX_BUFFER_SIZE_MASK] = D +#define SER_TX_BUFFER_INIT(C) (C)->tx_head = (C)->tx_tail = 0 +#define SER_TX_BUFFER_EMPTY(C) ((C)->tx_head == (C)->tx_tail) +#define SER_TX_BUFFER_FULL(C) ((((C)->tx_head+1) & SER_TX_BUFFER_SIZE_MASK) == (C)->tx_tail) +#define SER_TX_BUFFER_CURRENT(C) (((C)->tx_head - (C)->tx_tail) & SER_TX_BUFFER_SIZE_MASK) +#define SER_TX_BUFFER_LOWATER(C) (SER_TX_BUFFER_CURRENT(C) < SER_TX_BUFFER_LOW) +#define SER_TX_BUFFER_HIWATER(C) (SER_TX_BUFFER_CURRENT(C) > SER_TX_BUFFER_HIGH) + + +/* XON/XOFF Flow Control Commands */ +#define SER_XON 0x11 +#define SER_XOFF 0x13 + + +/* PIC Registers & interrupts */ +#define INTERRUPT_VECTOR_OFFSET 8 + +#define PIC_MASTER 0x20 +#define PIC_SLAVE 0xa0 +#define PIC_EOI 0x20 +#define PIC_RR 0x02 + +#define PIC_WRITE_IMR(P, D) outp((P)|1, D) /* interrupt masks */ +#define PIC_WRITE_OCW2(P, D) outp(P, D) /* R, SL, EOI, 0, 0, L2, L1, L0 */ +#define PIC_WRITE_OCW3(P, D) outp(P, (D)|8) /* 0, ESMM, SMM, 0, 1, P, RR, RIS */ +#define PIC_READ_IMR(P) inp((P)|1) /* interrupt masks */ +#define PIC_END_INTERRUPT(P) PIC_WRITE_OCW2(P, PIC_EOI) +static unsigned char PIC_READ_IRR(unsigned int port){PIC_WRITE_OCW3(port, PIC_RR); return inp(port);} +#define PIC_ENABLE_IRQ(I) {if(I <= 7) PIC_WRITE_IMR(PIC_MASTER, PIC_READ_IMR(PIC_MASTER) & ~(1 << I)); \ + else PIC_WRITE_IMR(PIC_SLAVE, PIC_READ_IMR(PIC_SLAVE) & ~(1 << ((I)-7)));} +#define PIC_DISABLE_IRQ(I) {if(I <= 7) PIC_WRITE_IMR(PIC_MASTER, PIC_READ_IMR(PIC_MASTER) | (1 << I)); \ + else PIC_WRITE_IMR(PIC_SLAVE, PIC_READ_IMR(PIC_SLAVE) | (1 << ((I)-7)));} + + +/* UART Registers */ +#define UART_RX_BUFFER 0 +#define UART_TX_BUFFER 0 +#define UART_INTERRUPT_ENABLE 1 + +#define UART_DIVISOR_LATCH_WORD 0 +#define UART_DIVISOR_LATCH_LSB 0 +#define UART_DIVISOR_LATCH_MSB 1 + +#define UART_INTERRUPT_IDENTIFY 2 +#define UART_FIFO_CONTROL 2 +#define UART_LINE_CONTROL 3 +#define UART_MODEM_CONTROL 4 +#define UART_LINE_STATUS 5 +#define UART_MODEM_STATUS 6 + + +/* UART Read commands (B = UART Base Address ) */ +#define UART_READ_DATA(C) inp((C)->base+UART_RX_BUFFER) +#define UART_READ_INTERRUPT_ENABLE(C) inp((C)->base+UART_INTERRUPT_ENABLE) +#define UART_READ_INTERRUPT_IDENTIFY(C) inp((C)->base+UART_INTERRUPT_IDENTIFY) +#define UART_READ_LINE_CONTROL(C) inp((C)->base+UART_LINE_CONTROL) +#define UART_READ_MODEM_CONTROL(C) inp((C)->base+UART_MODEM_CONTROL) +#define UART_READ_LINE_STATUS(C) ((C)->lsr = inp((C)->base+UART_LINE_STATUS)) +#define UART_READ_MODEM_STATUS(C) ((C)->msr = inp((C)->base+UART_MODEM_STATUS)) +#define UART_READ_BPS(C) ((_Outp((C)->base+UART_LINE_CONTROL, inp((C)->base+UART_LINE_CONTROL) | UART_LCR_DIVISOR_LATCH) & 0) | \ + inpw((C)->base+UART_DIVISOR_LATCH_WORD) | \ + (_Outp((C)->base+UART_LINE_CONTROL, inp((C)->base+UART_LINE_CONTROL) & ~UART_LCR_DIVISOR_LATCH) & 0)) + + +/* UART Write Commands (B = UART Base Address , D = Data ) */ +#define UART_WRITE_DATA(C, D) outp((C)->base+UART_TX_BUFFER, D) +#define UART_WRITE_INTERRUPT_ENABLE(C, D) ((C)->ier = _Outp((C)->base+UART_INTERRUPT_ENABLE, D)) +#define UART_WRITE_FIFO_CONTROL(C, D) ((C)->fcr = _Outp((C)->base+UART_FIFO_CONTROL, D)) +#define UART_WRITE_LINE_CONTROL(C, D) ((C)->lcr = _Outp((C)->base+UART_LINE_CONTROL, D)) +#define UART_WRITE_MODEM_CONTROL(C, D) ((C)->mcr = _Outp((C)->base+UART_MODEM_CONTROL, D)) +#define UART_WRITE_BPS(C, D) {outp((C)->base+UART_LINE_CONTROL, inp((C)->base+UART_LINE_CONTROL) | UART_LCR_DIVISOR_LATCH); \ + (C)->dlatch = _Outpw((C)->base+UART_DIVISOR_LATCH_WORD, D); \ + outp((C)->base+UART_LINE_CONTROL, inp((C)->base+UART_LINE_CONTROL) & ~UART_LCR_DIVISOR_LATCH);} + + +/* Interrupt Enable Register Components */ +#define UART_IER_MODEM_STATUS 0x08 +#define UART_IER_ERRORS 0x04 +#define UART_IER_TX_HOLD_EMPTY 0x02 +#define UART_IER_DATA_READY 0x01 + + +/* Interrupt Identify Register Components */ +#define UART_IIR_FIFO_ENABLE_1 0x80 +#define UART_IIR_FIFO_ENABLE_0 0x40 +#define UART_IIR_IDENTIFY_2 0x08 +#define UART_IIR_IDENTIFY_1 0x04 +#define UART_IIR_IDENTIFY_0 0x02 +#define UART_IIR_NO_INTERRUPT_PENDING 0x01 + +#define UART_IIR_MASK (UART_IIR_NO_INTERRUPT_PENDING | UART_IIR_IDENTIFY_0 | UART_IIR_IDENTIFY_1) +#define UART_IIR_LINE_STATUS (UART_IIR_IDENTIFY_0 | UART_IIR_IDENTIFY_1) +#define UART_IIR_DATA_READY UART_IIR_IDENTIFY_1 +#define UART_IIR_TX_HOLD_EMPTY UART_IIR_IDENTIFY_0 +#define UART_IIR_MODEM_STATUS 0x00 +#define UART_IIR_NO_INTERRUPT UART_IIR_NO_INTERRUPT_PENDING + + +/* Fifo Control Register Components */ +#define UART_FCR_TRIGGER_1 0x80 +#define UART_FCR_TRIGGER_0 0x40 +#define UART_FCR_DMA_SELECT 0x08 +#define UART_FCR_TX_FIFO_RESET 0x04 +#define UART_FCR_RX_FIFO_RESET 0x02 +#define UART_FCR_FIFO_ENABLE 0x01 + +#define UART_FCR_TRIGGER_AT_1 0x00 +#define UART_FCR_TRIGGER_AT_4 UART_FCR_TRIGGER_0 +#define UART_FCR_TRIGGER_AT_8 UART_FCR_TRIGGER_1 +#define UART_FCR_TRIGGER_AT_14 (UART_FCR_TRIGGER_0 | UART_FCR_TRIGGER_1) + + +/* Line Control Register Components */ + +#define UART_LCR_DIVISOR_LATCH 0x80 +#define UART_LCR_SET_BREAK 0x40 +#define UART_LCR_STICK_PARITY 0x20 +#define UART_LCR_EVEN_PARITY 0x10 +#define UART_LCR_PARITY_ENABLE 0x08 +#define UART_LCR_STOPBITS 0x04 +#define UART_LCR_WORD_LENGTH_1 0x02 +#define UART_LCR_WORD_LENGTH_0 0x01 + +#define UART_DATA_5 0x00 +#define UART_DATA_6 UART_LCR_WORD_LENGTH_0 +#define UART_DATA_7 UART_LCR_WORD_LENGTH_1 +#define UART_DATA_8 (UART_LCR_WORD_LENGTH_0 | UART_LCR_WORD_LENGTH_1) +#define UART_DATA_MASK (UART_LCR_WORD_LENGTH_0 | UART_LCR_WORD_LENGTH_1) + +#define UART_PARITY_NONE 0x00 +#define UART_PARITY_ODD UART_LCR_PARITY_ENABLE +#define UART_PARITY_EVEN (UART_LCR_PARITY_ENABLE | UART_LCR_EVEN_PARITY) +#define UART_PARITY_MARK (UART_LCR_PARITY_ENABLE | UART_LCR_STICK_PARITY) +#define UART_PARITY_SPACE (UART_LCR_PARITY_ENABLE | UART_LCR_EVEN_PARITY | UART_LCR_STICK_PARITY) +#define UART_PARITY_MASK (UART_LCR_PARITY_ENABLE | UART_LCR_EVEN_PARITY | UART_LCR_STICK_PARITY) + +#define UART_STOP_1 0x00 +#define UART_STOP_2 UART_LCR_STOPBITS +#define UART_STOP_MASK UART_LCR_STOPBITS + + +/* Modem Control Register Components */ +#define UART_MCR_LOOPBACK 0x10 +#define UART_MCR_OUT2 0x08 +#define UART_MCR_OUT1 0x04 +#define UART_MCR_RTS 0x02 +#define UART_MCR_DTR 0x01 +#define UART_MCR_MASK ( UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT1 | UART_MCR_OUT2 | UART_MCR_LOOPBACK ) + + +/* Line Status Register Components */ +#define UART_LSR_FIFO_ERROR 0x80 +#define UART_LSR_TX_EMPTY 0x40 +#define UART_LSR_TX_HOLD_EMPTY 0x20 +#define UART_LSR_BREAK_INDICATOR 0x10 +#define UART_LSR_FRAME_ERROR 0x08 +#define UART_LSR_PARITY_ERROR 0x04 +#define UART_LSR_OVERRUN_ERROR 0x02 +#define UART_LSR_DATA_READY 0x01 + + +/* Modem Status Register Components */ +#define UART_MSR_DCD 0x80 +#define UART_MSR_RI 0x40 +#define UART_MSR_DSR 0x20 +#define UART_MSR_CTS 0x10 +#define UART_MSR_DLT_DCD 0x08 +#define UART_MSR_NEW_RING 0x04 +#define UART_MSR_DLT_DSR 0x02 +#define UART_MSR_DLT_CTS 0x01 + + +/* BPS Rates (based on 1.8432 MHz crystal) */ +#define UART_BPS_DIVISOR_50 2304 +#define UART_BPS_DIVISOR_75 1536 +#define UART_BPS_DIVISOR_110 1047 /* 0.026% error */ +#define UART_BPS_DIVISOR_134_5 857 /* 0.058% error */ +#define UART_BPS_DIVISOR_150 768 +#define UART_BPS_DIVISOR_300 384 +#define UART_BPS_DIVISOR_600 192 +#define UART_BPS_DIVISOR_1200 96 +#define UART_BPS_DIVISOR_1800 64 +#define UART_BPS_DIVISOR_2400 48 +#define UART_BPS_DIVISOR_3800 32 +#define UART_BPS_DIVISOR_4800 24 +#define UART_BPS_DIVISOR_7200 16 +#define UART_BPS_DIVISOR_9600 12 +#define UART_BPS_DIVISOR_19200 6 +#define UART_BPS_DIVISOR_38400 3 +#define UART_BPS_DIVISOR_57600 2 +#define UART_BPS_DIVISOR_115200 1 + +/* FIFO size */ +#define UART_FIFO_SIZE_IN_BYTES 16 + +/* ======================================================================== */ +/* ==================== PROTOTYPES, TYPEDEFS & GLOBALS ==================== */ +/* ======================================================================== */ + + +typedef struct +{ + unsigned char port; + unsigned char default_irq; + unsigned char irq; + unsigned char open; + unsigned char ier; + unsigned char fcr; + unsigned char lcr; + unsigned char mcr; + unsigned char lsr; + unsigned char msr; + unsigned char flow_mode; + unsigned char rx_flow_on; + unsigned char tx_flow_on; + unsigned char rx_buff[(unsigned short)SER_RX_BUFFER_SIZE]; + unsigned char tx_buff[(unsigned short)SER_TX_BUFFER_SIZE]; + unsigned int base; + unsigned int dlatch; + unsigned int rx_head; + unsigned int tx_head; + unsigned int rx_tail; + unsigned int tx_tail; +} serial_struct; + + +#if defined( __DJGPP__ ) +typedef _go32_dpmi_seginfo int_handler_ptr; +static _go32_dpmi_seginfo g_old_isrs[16]; +#else +typedef void Interrupt Far (*int_handler_ptr)(void); +static int_handler_ptr g_old_isrs[16]; +#endif +static unsigned char g_isrs_taken[16] = {0}; +#ifdef PROTECTED_MODE +static int_handler_ptr g_isr_addr; +static unsigned int g_isrs_count = 0; +#endif + + +/* serial port data */ +static serial_struct g_comports[COM_MAX+1] = +{ +#if defined( __GNUC__ ) + {port: 0, default_irq: COM1_DEFAULT_IRQ, irq: IRQ_NONE}, + {port: 1, default_irq: COM2_DEFAULT_IRQ, irq: IRQ_NONE}, + {port: 2, default_irq: COM3_DEFAULT_IRQ, irq: IRQ_NONE}, + {port: 3, default_irq: COM4_DEFAULT_IRQ, irq: IRQ_NONE} +#else + {0, COM1_DEFAULT_IRQ, IRQ_NONE}, + {1, COM2_DEFAULT_IRQ, IRQ_NONE}, + {2, COM3_DEFAULT_IRQ, IRQ_NONE}, + {3, COM4_DEFAULT_IRQ, IRQ_NONE} +#endif +}; + + + +/* ======================================================================== */ +/* ====================== INTERRUPT SERVICE ROUTINE ======================= */ +/* ======================================================================== */ + +static void Interrupt com_general_isr(void) +{ + serial_struct* com_min = (serial_struct*)(g_comports); + serial_struct* com_max = com_min + COM_MAX; + unsigned char int_id; + unsigned char data; + unsigned char slave_interrupted = 0; + serial_struct* com; + + /* Disable IRQs for all COM ports, then re-enable interrupts. + * This allows other faster devices to be serviced. + */ + for(com=com_min;com<=com_max;com++) + { + if(com->open) + { + if(com->irq > 7) + slave_interrupted = 1; + PIC_DISABLE_IRQ(com->irq); + } + } + CPU_ENABLE_INTERRUPTS(); + + /* Process all pending interrupts */ + for(com=com_min;com<=com_max;com++) + { + if(com->open) + { + while((int_id=UART_READ_INTERRUPT_IDENTIFY(com) & UART_IIR_MASK) != UART_IIR_NO_INTERRUPT) + { + switch(int_id) + { + case UART_IIR_DATA_READY: + /* Read all data from the UART */ + while(UART_READ_LINE_STATUS(com) & UART_LSR_DATA_READY) + { + data = UART_READ_DATA(com); + + /* Handle XON/XOFF flow control (TX) */ + if(com->flow_mode == SER_HANDSHAKING_XONXOFF && (data == SER_XOFF || data == SER_XON)) + { + com->tx_flow_on = data == SER_XON; + if(!SER_TX_BUFFER_EMPTY(com) && com->tx_flow_on) + UART_WRITE_INTERRUPT_ENABLE(com, UART_READ_INTERRUPT_ENABLE(com) | UART_IER_TX_HOLD_EMPTY); + } + + /* Store it if there's room, or throw it out */ + else if(!SER_RX_BUFFER_FULL(com)) + { + SER_RX_BUFFER_WRITE(com, data); + + /* Flow control (RX) - Turn off if buffer almost full */ + if(com->rx_flow_on && SER_RX_BUFFER_HIWATER(com)) + { + com->rx_flow_on = 0; + + switch(com->flow_mode) + { + case SER_HANDSHAKING_RTSCTS: + UART_WRITE_MODEM_CONTROL(com, UART_READ_MODEM_CONTROL(com) & ~UART_MCR_RTS); + break; + case SER_HANDSHAKING_NONE: + break; + case SER_HANDSHAKING_XONXOFF: + UART_WRITE_DATA(com, SER_XOFF); + break; + case SER_HANDSHAKING_DTRDSR: + UART_WRITE_MODEM_CONTROL(com, UART_READ_MODEM_CONTROL(com) & ~UART_MCR_DTR); + break; + } + } + } + } + break; + /* Change in line status */ + case UART_IIR_LINE_STATUS: + UART_READ_LINE_STATUS(com); + break; + /* Change in modem status */ + case UART_IIR_MODEM_STATUS: + UART_READ_MODEM_STATUS(com); + + /* Handle RTS/CTS or DSR/DTR flow control (TX) */ + if(com->flow_mode == SER_HANDSHAKING_RTSCTS) + com->tx_flow_on = (com->msr & UART_MSR_CTS) != 0; + else if(com->flow_mode == SER_HANDSHAKING_DTRDSR) + com->tx_flow_on = (com->msr & UART_MSR_DSR) != 0; + if(!SER_TX_BUFFER_EMPTY(com) && com->tx_flow_on) + UART_WRITE_INTERRUPT_ENABLE(com, UART_READ_INTERRUPT_ENABLE(com) | UART_IER_TX_HOLD_EMPTY); + break; + /* UART is empty */ + case UART_IIR_TX_HOLD_EMPTY: + { + int cnt; + for (cnt=0; cnttx_flow_on && !SER_TX_BUFFER_EMPTY(com); cnt++) + UART_WRITE_DATA(com, SER_TX_BUFFER_READ(com)); + if(SER_TX_BUFFER_EMPTY(com) || !com->tx_flow_on) + UART_WRITE_INTERRUPT_ENABLE(com, UART_READ_INTERRUPT_ENABLE(com) & ~UART_IER_TX_HOLD_EMPTY); + break; + } + } + } + } + } + + CPU_DISABLE_INTERRUPTS(); + + /* End the interrupt on the PIC */ + if(slave_interrupted) + PIC_END_INTERRUPT(PIC_SLAVE); + PIC_END_INTERRUPT(PIC_MASTER); + + /* Re-enable all interrupts */ + for(com=com_min;com<=com_max;com++) + if(com->open) + PIC_ENABLE_IRQ(com->irq); + + /* We must explicitely call 'sti' before 'iret' because 'iret' + won't always restore interrupts in a virtual environment */ + CPU_ENABLE_INTERRUPTS(); +} + + + +/* ======================================================================== */ +/* =========================== UTILITY ROUTINES =========================== */ +/* ======================================================================== */ + + +#ifdef PROTECTED_MODE + +/* we do not know the exact size of com_general_isr() function + but for sure it's not longer then 2048 bytes */ +#define ISR_SIZE 2048 + +#if defined( __DJGPP__ ) + +static void serial_dpmi_get_pvect(int vector, _go32_dpmi_seginfo *info) +{ + _go32_dpmi_get_protected_mode_interrupt_vector(vector, info); +} + +static void serial_dpmi_set_pvect(int vector, _go32_dpmi_seginfo *info) +{ + _go32_dpmi_set_protected_mode_interrupt_vector(vector, info); +} + +static int serial_dpmi_lock_memory(void) +{ + unsigned long dataaddr, codeaddr; + __dpmi_meminfo dataregion, coderegion; + + if(__dpmi_get_segment_base_address(_my_cs(), &codeaddr) == 0 && + __dpmi_get_segment_base_address(_my_ds(), &dataaddr) == 0) + { + coderegion.handle = 0; + coderegion.size = ISR_SIZE; + coderegion.address = codeaddr + (unsigned long)com_general_isr; + dataregion.handle = 0; + dataregion.size = sizeof(g_comports); + dataregion.address = codeaddr + (unsigned long)g_comports; + if(__dpmi_lock_linear_region(&coderegion) == 0) + { + if(__dpmi_lock_linear_region(&dataregion) == 0) + { + g_isr_addr.pm_offset = (unsigned long)com_general_isr; + g_isr_addr.pm_selector = _go32_my_cs(); + if(_go32_dpmi_allocate_iret_wrapper(&g_isr_addr) == 0) + return 1; + __dpmi_unlock_linear_region(&dataregion); + } + __dpmi_unlock_linear_region(&coderegion); + } + } + return 0; +} + +static void serial_dpmi_unlock_memory(void) +{ + unsigned long baseaddr; + __dpmi_meminfo region; + + if(__dpmi_get_segment_base_address(_my_ds(), &baseaddr) == 0) + { + region.handle = 0; + region.size = sizeof(g_comports); + region.address = baseaddr + (unsigned long)g_comports; + __dpmi_unlock_linear_region(®ion); + } + if(__dpmi_get_segment_base_address(_my_cs(), &baseaddr) == 0) + { + region.handle = 0; + region.size = ISR_SIZE; + region.address = baseaddr + (unsigned long)com_general_isr; + __dpmi_unlock_linear_region(®ion); + } + _go32_dpmi_free_iret_wrapper(&g_isr_addr); +} + +#else /* ! __DJGPP__ */ + +static void serial_dpmi_get_pvect(int vect, int_handler_ptr *handler) +{ + union REGS r; + unsigned short sel; + unsigned long off; + + /* DPMI get protected mode interrupt vector: Int 31H, Fn 0204H */ + r.x.eax = 0x0204; + r.x.ebx = vect; + int386(0x31, &r, &r); + sel = (unsigned short) r.x.ecx; + off = r.x.edx; + + *handler=(int_handler_ptr) MK_FP(sel, off); +} + +static void serial_dpmi_set_pvect(int vect, int_handler_ptr *handler) +{ + union REGS r; + void Far *ptr; + + /* DPMI set protected mode interrupt vector: Int 31H, Fn 0205H */ + ptr = (void Far *)*handler; + r.x.eax = 0x0205; + r.x.ebx = vect; + r.x.ecx = FP_SEG(ptr); + r.x.edx = FP_OFF(ptr); + int386(0x31, &r, &r); +} + +static int serial_dpmi_lock_linear_memory(void Far *ptr, unsigned long size) +{ + union REGS r; + + /* DPMI get segment base address: Int 31H, Fn 0006H */ + r.x.eax = 0x0006; + r.x.ebx = FP_SEG(ptr); + int386(0x31, &r, &r); + if(r.w.cflag == 0) + { + unsigned long addr = FP_OFF( ptr ) + ((r.w.cx << 16) | r.w.dx); + + /* DPMI lock linear region: Int 31H, Fn 0600H */ + r.x.eax = 0x0600; + r.x.ebx = addr >> 16; + r.x.ecx = addr & 0xFFFF; + r.x.esi = size >> 16; + r.x.edi = size & 0xFFFF; + int386(0x31, &r, &r); + if(r.w.cflag == 0) + { + g_isr_addr = com_general_isr; + return 1; + } + } + return 0; +} + +static void serial_dpmi_unlock_linear_memory(void Far *ptr, unsigned long size) +{ + union REGS r; + + /* DPMI get segment base address: Int 31H, Fn 0006H */ + r.x.eax = 0x0006; + r.x.ebx = FP_SEG(ptr); + int386(0x31, &r, &r); + if(r.w.cflag == 0) + { + unsigned long addr = FP_OFF( ptr ) + ((r.w.cx << 16) | r.w.dx); + + /* DPMI unlock linear region: Int 31H, Fn 0601H */ + r.x.eax = 0x0601; + r.x.ebx = addr >> 16; + r.x.ecx = addr & 0xFFFF; + r.x.esi = size >> 16; + r.x.edi = size & 0xFFFF; + int386(0x31, &r, &r); + } + int386 (0x31, &r, &r); +} + +static int serial_dpmi_lock_memory(void) +{ + if(serial_dpmi_lock_linear_memory(com_general_isr, ISR_SIZE)) + { + if(serial_dpmi_lock_linear_memory(g_comports, sizeof(g_comports))) + return 1; + serial_dpmi_unlock_linear_memory(com_general_isr, ISR_SIZE); + } + return 0; +} + +static void serial_dpmi_unlock_memory(void) +{ + serial_dpmi_unlock_linear_memory(com_general_isr, ISR_SIZE); + serial_dpmi_unlock_linear_memory(g_comports, sizeof(g_comports)); +} + +#endif /* ! __DJGPP__ */ + +static int serial_install_irqhandler(int irq) +{ + /* If we haven't taken this IRQ's ISR already, take it */ + if(!g_isrs_taken[irq]) + { + if( g_isrs_count++ == 0 ) + { + /* lock memory used by interrupt handler in DPMI mode */ + if(!serial_dpmi_lock_memory()) + { + --g_isrs_count; + return SER_ERR_LOCK_MEM; + } + } + serial_dpmi_get_pvect(irq+INTERRUPT_VECTOR_OFFSET, &g_old_isrs[irq]); + serial_dpmi_set_pvect(irq+INTERRUPT_VECTOR_OFFSET, &g_isr_addr); + g_isrs_taken[irq] = 1; + } + return SER_SUCCESS; +} + +static void serial_remove_irqhandler(int irq) +{ + if(g_isrs_taken[irq]) + { + serial_dpmi_set_pvect(irq+INTERRUPT_VECTOR_OFFSET, &g_old_isrs[irq]); + g_isrs_taken[irq] = 0; + + if( --g_isrs_count == 0 ) + /* unlock memory used by interrupt handler in DPMI mode */ + serial_dpmi_unlock_memory(); + } +} + +#else /* ! PROTECTED_MODE */ + +static int serial_install_irqhandler(int irq) +{ + /* If we haven't taken this IRQ's ISR already, take it */ + if(!g_isrs_taken[irq]) + { + g_old_isrs[irq] = _dos_getvect(irq+INTERRUPT_VECTOR_OFFSET); + _dos_setvect(irq+INTERRUPT_VECTOR_OFFSET, com_general_isr); + g_isrs_taken[irq] = 1; + } + return SER_SUCCESS; +} + +static void serial_remove_irqhandler(int irq) +{ + _dos_setvect(irq+INTERRUPT_VECTOR_OFFSET, g_old_isrs[irq]); + g_isrs_taken[irq] = 0; +} + +#endif /* ! PROTECTED_MODE */ + + +static int serial_find_irq(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + unsigned char imr_m = PIC_READ_IMR(PIC_MASTER); /* Interrupt Mask Registers */ + unsigned char imr_s = PIC_READ_IMR(PIC_SLAVE); + unsigned char irr_m; /* Interrupt Request Registers */ + unsigned char irr_s; + + /* Set up the UART */ + UART_WRITE_MODEM_CONTROL(com, UART_MCR_OUT2); + UART_WRITE_FIFO_CONTROL(com, 0); + + /* Wait until tx hold register is empty */ + while((UART_READ_LINE_STATUS(com) & UART_LSR_TX_HOLD_EMPTY) == 0); + + CPU_DISABLE_INTERRUPTS(); + + /* Allow any interrupt on PIC */ + PIC_WRITE_IMR(PIC_MASTER, 0); + PIC_WRITE_IMR(PIC_SLAVE, 0); + + /* Do some initial polls to let things settle (win95 needs this) */ + UART_WRITE_INTERRUPT_ENABLE(com, UART_IER_TX_HOLD_EMPTY); + PIC_READ_IRR(PIC_MASTER); + PIC_READ_IRR(PIC_SLAVE); + UART_WRITE_INTERRUPT_ENABLE(com, 0); + PIC_READ_IRR(PIC_MASTER); + PIC_READ_IRR(PIC_SLAVE); + + /* Generate an interrupt and record all active IRQs */ + UART_WRITE_INTERRUPT_ENABLE(com, UART_IER_TX_HOLD_EMPTY); + irr_m = PIC_READ_IRR(PIC_MASTER); + irr_s = PIC_READ_IRR(PIC_SLAVE); + + /* Remove the interrupt and mask out all IRQs still active */ + UART_WRITE_INTERRUPT_ENABLE(com, 0); + irr_m &= ~PIC_READ_IRR(PIC_MASTER); + irr_s &= ~PIC_READ_IRR(PIC_SLAVE); + + /* Interrupt again to make sure */ + UART_WRITE_INTERRUPT_ENABLE(com, UART_IER_TX_HOLD_EMPTY); + irr_m &= PIC_READ_IRR(PIC_MASTER); + irr_s &= PIC_READ_IRR(PIC_SLAVE); + + /* Return everything to normal */ + PIC_WRITE_IMR(PIC_MASTER, imr_m); + PIC_WRITE_IMR(PIC_SLAVE, imr_s); + UART_WRITE_INTERRUPT_ENABLE(com, 0); + + CPU_ENABLE_INTERRUPTS(); + + switch(irr_m) + { + case 0x01: return 0; + case 0x02: return 1; + case 0x04: + switch(irr_s) + { + case 0x01: return 8; + case 0x02: return 9; + case 0x04: return 10; + case 0x08: return 11; + case 0x10: return 12; + case 0x20: return 13; + case 0x40: return 14; + case 0x80: return 15; + default: return 2; + } + case 0x08: return 3; + case 0x10: return 4; + case 0x20: return 5; + case 0x40: return 6; + case 0x80: return 7; + } + return SER_ERR_IRQ_NOT_FOUND; +} + +static void serial_free_irq(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + serial_struct* com_min = (serial_struct*)(g_comports); + serial_struct* com_max = com_min + COM_MAX; + unsigned int irq = com->irq; + serial_struct* ptr; + + if(irq == IRQ_NONE) + return; + + CPU_DISABLE_INTERRUPTS(); + + /* Disable interrupts from the UART */ + UART_WRITE_INTERRUPT_ENABLE(com, 0); + UART_WRITE_MODEM_CONTROL(com, UART_MCR_OUT2); + /* Clear the FIFO and rx registers */ + UART_WRITE_FIFO_CONTROL(com, 0); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_DATA(com); + UART_READ_INTERRUPT_IDENTIFY(com); + UART_READ_LINE_STATUS(com); + UART_READ_DATA(com); + /* Clear any other possible interrupt causes */ + UART_READ_INTERRUPT_IDENTIFY(com); + UART_READ_MODEM_STATUS(com); + UART_READ_INTERRUPT_IDENTIFY(com); + UART_READ_LINE_STATUS(com); + UART_READ_INTERRUPT_IDENTIFY(com); + + com->irq = IRQ_NONE; + + CPU_ENABLE_INTERRUPTS(); + + for(ptr=com_min;ptr<=com_max;ptr++) + if(ptr != com && ptr->irq == irq) + return; + + /* Disable interrupts from the PIC and restore the old vector */ + PIC_DISABLE_IRQ(irq); + serial_remove_irqhandler(irq); +} + + +/* ======================================================================== */ +/* ======================== BASIC SERIAL ROUTINES ========================= */ +/* ======================================================================== */ + +int serial_is_port_open(int portnum) +{ + // added 2/29/24 EES + // 4/25/24 EES simplified based on kstenerud's recommendation + if (portnum < COM_MIN || portnum > COM_MAX) + return 0; // Invalid port number; can't be opened + + serial_struct* com = (serial_struct*)(g_comports + portnum); + + // Note: If 'open' can ever have anything other than 1 or 0, this will need updating. + return com->open; +} + +int serial_open(int comport, long bps, int data_bits, char parity, int stop_bits, int handshaking) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + int rc = SER_SUCCESS; + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(com->open) + return SER_ERR_ALREADY_OPEN; + + com->open = 1; + + /* Initialize buffers */ + com->rx_flow_on = 1; + com->tx_flow_on = 1; + SER_RX_BUFFER_INIT(com); + SER_TX_BUFFER_INIT(com); + + /* look in bios tables (0040:0000 - 0040:0006) for com base addresses */ + if(serial_set_base(comport, Farpeekw(0x0040, comport<<1)) != SER_SUCCESS) + return SER_ERR_NO_UART; + + /* Turn off interrupts from UART */ + UART_WRITE_INTERRUPT_ENABLE(com, 0); + + /* Auto-detect IRQ if we can */ + if((rc=serial_find_irq(comport)) < 0) + rc = com->default_irq; + + if((rc=serial_set_irq(comport, rc)) != SER_SUCCESS) + return rc; + + /* Turn off interrupts from PIC */ + PIC_DISABLE_IRQ(com->irq); + + /* Set the comport */ + if((rc=serial_set(comport, bps, data_bits, parity, stop_bits, handshaking)) == SER_SUCCESS) + { + UART_WRITE_MODEM_CONTROL(com, UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT1 | UART_MCR_OUT2); + rc = serial_set_fifo_threshold(comport, UART_FIFO_DEFAULT_THRESHOLD); + + /* Get some info */ + UART_READ_LINE_STATUS(com); + UART_READ_MODEM_STATUS(com); + } + + /* Re-enable interrupts */ + UART_WRITE_INTERRUPT_ENABLE(com, UART_IER_DATA_READY | UART_IER_MODEM_STATUS | UART_IER_ERRORS); + PIC_ENABLE_IRQ(com->irq); + + if(rc != SER_SUCCESS) /* We failed to set the comport */ + serial_close(comport); + + return rc; +} + +int serial_close(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + /* Restore old interrupts */ + serial_free_irq(comport); + + /* Turn everything off */ + UART_WRITE_INTERRUPT_ENABLE(com, 0); + UART_WRITE_MODEM_CONTROL(com, 0); + serial_set_fifo_threshold(comport, 0); + + com->open = 0; + + return SER_SUCCESS; +} + +int serial_read(int comport, char* data, int len) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + int i; + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + if(data == 0) + return SER_ERR_NULL_PTR; + + CPU_DISABLE_INTERRUPTS(); + /* Fill in the array given to us */ + for(i=0;!SER_RX_BUFFER_EMPTY(com) && i < len;i++) + data[i] = SER_RX_BUFFER_READ(com); + + /* Flow control (RX) - Turn on if buffer almost empty */ + if(!com->rx_flow_on && SER_RX_BUFFER_LOWATER(com)) + { + com->rx_flow_on = 1; + if(com->flow_mode == SER_HANDSHAKING_XONXOFF) + UART_WRITE_DATA(com, SER_XON); + else if(com->flow_mode == SER_HANDSHAKING_RTSCTS) + UART_WRITE_MODEM_CONTROL(com, UART_READ_MODEM_CONTROL(com) | UART_MCR_RTS); + else if(com->flow_mode == SER_HANDSHAKING_DTRDSR) + UART_WRITE_MODEM_CONTROL(com, UART_READ_MODEM_CONTROL(com) | UART_MCR_DTR); + } + CPU_ENABLE_INTERRUPTS(); + + return i; +} + + +int serial_write(int comport, const char* data, int len) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + int i; + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + if(data == 0) + return SER_ERR_NULL_PTR; + + for(i=0;i < len;i++) + { + /* Wait until we can write */ + while(!(UART_READ_LINE_STATUS(com) & UART_LSR_TX_HOLD_EMPTY)) + {} + + /* Write 1 char */ + if(com->tx_flow_on) + UART_WRITE_DATA(com, data[i]); + else + break; + } + return i; +} + +int serial_write_buffered(int comport, const char* data, int len) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + int i; + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + if(data == 0) + return SER_ERR_NULL_PTR; + + CPU_DISABLE_INTERRUPTS(); + for(i=0;i < len ;i++) + { + /* stop when sent buffer is full */ + if(SER_TX_BUFFER_FULL(com)) + break; + /* Write 1 char */ + SER_TX_BUFFER_WRITE(com, data[i]); + } + + /* If there's data to send, enable TX_HOLD_EMPTY interrupt */ + if(!SER_TX_BUFFER_EMPTY(com)) + UART_WRITE_INTERRUPT_ENABLE(com, UART_READ_INTERRUPT_ENABLE(com) | UART_IER_TX_HOLD_EMPTY); + CPU_ENABLE_INTERRUPTS(); + + return i; +} + + +int serial_set(int comport, long bps, int data_bits, char parity, int stop_bits, int handshaking) +{ + int rc; + + if((rc=serial_set_bps(comport, bps)) == SER_SUCCESS) + if((rc=serial_set_data(comport, data_bits)) == SER_SUCCESS) + if((rc=serial_set_parity(comport, parity)) == SER_SUCCESS) + if((rc=serial_set_stop(comport, stop_bits)) == SER_SUCCESS) + return serial_set_handshaking(comport, handshaking); + return rc; +} + + +/* ======================================================================== */ +/* ========================== SETTINGS ROUTINES =========================== */ +/* ======================================================================== */ + + +int serial_set_base(int comport, int base) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(base < 1 || base > 0xfff) + return SER_ERR_INVALID_BASE; + + com->base = base; + return SER_SUCCESS; +} + +int serial_set_irq(int comport, int irq) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + int rc; + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(irq < IRQ_MIN || irq > IRQ_MAX) + return SER_ERR_INVALID_IRQ; + if(!com->open) + return SER_ERR_NOT_OPEN; + + /* Remove any ISRs on this com port's current IRQ */ + serial_free_irq(comport); + + if((rc=serial_install_irqhandler(irq)) == SER_SUCCESS) + { + com->irq = irq; + PIC_ENABLE_IRQ(com->irq); + } + return rc; +} + +int serial_set_fifo_threshold(int comport, int threshold) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + int i; + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + switch(threshold) + { + case 14: + UART_WRITE_FIFO_CONTROL(com, UART_FCR_FIFO_ENABLE | UART_FCR_RX_FIFO_RESET | UART_FCR_TX_FIFO_RESET | UART_FCR_TRIGGER_AT_14); + break; + case 8: + UART_WRITE_FIFO_CONTROL(com, UART_FCR_FIFO_ENABLE | UART_FCR_RX_FIFO_RESET | UART_FCR_TX_FIFO_RESET | UART_FCR_TRIGGER_AT_8); + break; + case 4: + UART_WRITE_FIFO_CONTROL(com, UART_FCR_FIFO_ENABLE | UART_FCR_RX_FIFO_RESET | UART_FCR_TX_FIFO_RESET | UART_FCR_TRIGGER_AT_4); + break; + case 1: + UART_WRITE_FIFO_CONTROL(com, UART_FCR_FIFO_ENABLE | UART_FCR_RX_FIFO_RESET | UART_FCR_TX_FIFO_RESET | UART_FCR_TRIGGER_AT_1); + break; + case 0: + UART_WRITE_FIFO_CONTROL(com, 0); + break; + default: + return SER_ERR_INVALID_FIFO_THRESHOLD; + } + + /* Clear out any garbage in the UART interrupts and FIFO */ + for(i=0;i<16;i++) + UART_READ_DATA(com); + UART_READ_LINE_STATUS(com); + + return SER_SUCCESS; +} + + +int serial_set_bps(int comport, long bps) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + switch(bps) + { + case 115200L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_115200); + return SER_SUCCESS; + case 57600L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_57600); + return SER_SUCCESS; + case 38400L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_38400); + return SER_SUCCESS; + case 19200L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_19200); + return SER_SUCCESS; + case 9600L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_9600); + return SER_SUCCESS; + case 7200L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_7200); + return SER_SUCCESS; + case 4800L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_4800); + return SER_SUCCESS; + case 3800L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_3800); + return SER_SUCCESS; + case 1800L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_1800); + return SER_SUCCESS; + case 2400L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_2400); + return SER_SUCCESS; + case 1200L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_1200); + return SER_SUCCESS; + case 600L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_600); + return SER_SUCCESS; + case 300L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_300); + return SER_SUCCESS; + case 150L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_150); + return SER_SUCCESS; + case 110L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_110); + return SER_SUCCESS; + case 75L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_75); + return SER_SUCCESS; + case 50L: + UART_WRITE_BPS(com, UART_BPS_DIVISOR_50); + return SER_SUCCESS; + } + return SER_ERR_INVALID_BPS; +} + + +int serial_set_data(int comport, int data_bits) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + switch(data_bits) + { + case 5: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_DATA_MASK) | UART_DATA_5); + return SER_SUCCESS; + case 6: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_DATA_MASK) | UART_DATA_6); + return SER_SUCCESS; + case 7: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_DATA_MASK) | UART_DATA_7); + return SER_SUCCESS; + case 8: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_DATA_MASK) | UART_DATA_8); + return SER_SUCCESS; + } + return SER_ERR_INVALID_DATA_BITS; +} + + +int serial_set_parity(int comport, char parity) +{ + /* valid values for parity: + PARITY_NONE 'n' none + PARITY_EVEN 'e' even + PARITY_ODD 'o' odd + PARITY_MARK 'm' mark + PARITY_SPACE 's' space + */ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + switch(parity) + { + case PARITY_NONE: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_PARITY_MASK) | UART_PARITY_NONE); + return SER_SUCCESS; + case PARITY_EVEN: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_PARITY_MASK) | UART_PARITY_EVEN); + return SER_SUCCESS; + case PARITY_ODD: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_PARITY_MASK) | UART_PARITY_ODD); + return SER_SUCCESS; + case PARITY_MARK: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_PARITY_MASK) | UART_PARITY_MARK); + return SER_SUCCESS; + case PARITY_SPACE: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_PARITY_MASK) | UART_PARITY_SPACE); + return SER_SUCCESS; + } + return SER_ERR_INVALID_PARITY; +} + + +int serial_set_stop(int comport, int stop_bits) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + switch(stop_bits) + { + case 1: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_STOP_MASK) | UART_STOP_1); + return SER_SUCCESS; + case 2: + UART_WRITE_LINE_CONTROL(com, (UART_READ_LINE_CONTROL(com) & ~UART_STOP_MASK) | UART_STOP_2); + return SER_SUCCESS; + } + return SER_ERR_INVALID_STOP_BITS; +} + + +int serial_set_handshaking(int comport, int handshaking) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + com->tx_flow_on = 1; + com->rx_flow_on = 1; + + if(handshaking < SER_HANDSHAKING_NONE || handshaking > SER_HANDSHAKING_DTRDSR) + return SER_ERR_INVALID_HANDSHAKING; + + com->flow_mode = handshaking; + return SER_SUCCESS; +} + + +int serial_set_rts(int comport, int rts) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + if(rts) + UART_WRITE_MODEM_CONTROL(com, com->mcr | UART_MCR_RTS); + else + UART_WRITE_MODEM_CONTROL(com, com->mcr & ~UART_MCR_RTS); + + return SER_SUCCESS; +} + + +int serial_set_dtr(int comport, int dtr) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + if(dtr) + UART_WRITE_MODEM_CONTROL(com, com->mcr | UART_MCR_DTR); + else + UART_WRITE_MODEM_CONTROL(com, com->mcr & ~UART_MCR_DTR); + + return SER_SUCCESS; +} + + +int serial_set_mcr(int comport, int mcr) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + UART_WRITE_MODEM_CONTROL(com, mcr & UART_MCR_MASK ); + + return SER_SUCCESS; +} + + + +int serial_get_base(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(com->base < 1 || com->base > 0xfff) + return SER_ERR_INVALID_BASE; + + return com->base; +} + +int serial_get_irq(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(com->irq < IRQ_MIN || com->irq > IRQ_MAX) + return SER_ERR_INVALID_IRQ; + + return com->irq; +} + +long serial_get_bps(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + switch(UART_READ_BPS(com)) + { + case UART_BPS_DIVISOR_115200: + return 115200L; + case UART_BPS_DIVISOR_57600: + return 57600L; + case UART_BPS_DIVISOR_38400: + return 38400L; + case UART_BPS_DIVISOR_19200: + return 19200L; + case UART_BPS_DIVISOR_9600: + return 9600L; + case UART_BPS_DIVISOR_7200: + return 7200L; + case UART_BPS_DIVISOR_4800: + return 4800L; + case UART_BPS_DIVISOR_3800: + return 3800L; + case UART_BPS_DIVISOR_2400: + return 2400L; + case UART_BPS_DIVISOR_1800: + return 1800L; + case UART_BPS_DIVISOR_1200: + return 1200L; + case UART_BPS_DIVISOR_600: + return 600L; + case UART_BPS_DIVISOR_300: + return 300L; + case UART_BPS_DIVISOR_150: + return 150L; + case UART_BPS_DIVISOR_110: + return 110L; + case UART_BPS_DIVISOR_75: + return 75L; + case UART_BPS_DIVISOR_50: + return 50L; + } + return SER_ERR_INVALID_BPS; +} + + +int serial_get_data(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + switch(UART_READ_LINE_CONTROL(com) & UART_DATA_MASK) + { + case UART_DATA_5: + return 5; + case UART_DATA_6: + return 6; + case UART_DATA_7: + return 7; + case UART_DATA_8: + return 8; + } + return SER_ERR_INVALID_DATA_BITS; +} + + +char serial_get_parity(int comport) +{ + /* valid return values: + PARITY_NONE 'n' none + PARITY_EVEN 'e' even + PARITY_ODD 'o' odd + PARITY_MARK 'm' mark + PARITY_SPACE 's' space + */ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + switch(UART_READ_LINE_CONTROL(com) & UART_PARITY_MASK) + { + case UART_PARITY_NONE: + return PARITY_NONE; + case UART_PARITY_EVEN: + return PARITY_EVEN; + case UART_PARITY_ODD: + return PARITY_ODD; + case UART_PARITY_MARK: + return PARITY_MARK; + case UART_PARITY_SPACE: + return PARITY_SPACE; + } + return SER_ERR_INVALID_PARITY; +} + + +int serial_get_stop(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + switch(UART_READ_LINE_CONTROL(com) & UART_STOP_MASK) + { + case UART_STOP_1: + return 1; + case UART_STOP_2: + return 2; + } + return SER_ERR_INVALID_STOP_BITS; +} + + +int serial_get_handshaking(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + + return com->flow_mode; +} + + +int serial_get_rts(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + + return (com->mcr & UART_MCR_RTS) != 0; +} + + +int serial_get_dtr(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + + return (com->mcr & UART_MCR_DTR) != 0; +} + + +int serial_get_mcr(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + + return com->mcr; +} + + +int serial_get_dsr(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + + return (com->msr & UART_MSR_DSR) != 0; +} + + +int serial_get_cts(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + + return (com->msr & UART_MSR_CTS) != 0; +} + + +int serial_get_msr(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + + return com->msr; +} + + +int serial_get_lsr(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + + return com->lsr; +} + + + +int serial_get_tx_buffered(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + int count; + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + CPU_DISABLE_INTERRUPTS(); + count = SER_TX_BUFFER_CURRENT(com); + CPU_ENABLE_INTERRUPTS(); + + return count; +} + + +int serial_get_rx_buffered(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + int count; + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + CPU_DISABLE_INTERRUPTS(); + count = SER_RX_BUFFER_CURRENT(com); + CPU_ENABLE_INTERRUPTS(); + + return count; +} + + +int serial_clear_tx_buffer(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + CPU_DISABLE_INTERRUPTS(); + SER_TX_BUFFER_INIT(com); + CPU_ENABLE_INTERRUPTS(); + + return SER_SUCCESS; +} + + +int serial_clear_rx_buffer(int comport) +{ + serial_struct* com = (serial_struct*)(g_comports + comport); + + if(comport < COM_MIN || comport > COM_MAX) + return SER_ERR_INVALID_COMPORT; + if(!com->open) + return SER_ERR_NOT_OPEN; + + CPU_DISABLE_INTERRUPTS(); + SER_RX_BUFFER_INIT(com); + CPU_ENABLE_INTERRUPTS(); + + return SER_SUCCESS; +} + + +/* ======================================================================== */ +/* ============================ OTHER ROUTINES ============================ */ +/* ======================================================================== */ + + +char* GetErrorText (int err_num) +{ + /* added 2/29/24 EES */ + switch (err_num) + { + case SER_SUCCESS: return "Function completed successfully"; break; + case SER_ERR_NOT_OPEN: return "The specified COM port is not opened"; break; + case SER_ERR_ALREADY_OPEN: return "The specified COM port is already opened"; break; + case SER_ERR_NO_UART: return "Could not find a UART for this COM port"; break; + case SER_ERR_INVALID_COMPORT: return "User specified an invalid COM port"; break; + case SER_ERR_INVALID_BASE: return "User specified an invalid base address"; break; + case SER_ERR_INVALID_IRQ: return "User specified an invalid IRQ number"; break; + case SER_ERR_INVALID_BPS: return "User specified an invalid BPS rate"; break; + case SER_ERR_INVALID_DATA_BITS: return "User specified an invalid number of data bits"; break; + case SER_ERR_INVALID_PARITY: return "User specified an invalid parity type"; break; + case SER_ERR_INVALID_STOP_BITS: return "User specified an invalid number of stop bits"; break; + case SER_ERR_INVALID_HANDSHAKING: return "User specified an invalid handshaking type"; break; + case SER_ERR_INVALID_FIFO_THRESHOLD: return "User specified an invalid fifo threshold value"; break; + case SER_ERR_NULL_PTR: return "User specified a buffer address that was NULL"; break; + case SER_ERR_IRQ_NOT_FOUND: return "Could not find an IRQ for the specified COM port"; break; + case SER_ERR_LOCK_MEM: return "Could not lock memory in DPMI mode"; break; + case SER_ERR_UNKNOWN: default: return "An unknown error occured"; + } +} diff --git a/serial.h b/serial.h index 4764b9f..3dc545b 100644 --- a/serial.h +++ b/serial.h @@ -1,195 +1,225 @@ -/* Serial Library 1.4 (22-Jun-2000) (c) 1998 Karl Stenerud - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef SERIAL__HEADER -#define SERIAL__HEADER - -/* COM Ports */ -#define COM_1 0 -#define COM_2 1 -#define COM_3 2 -#define COM_4 3 - -/* Handshaking Modes */ -#define SER_HANDSHAKING_NONE 0 -#define SER_HANDSHAKING_XONXOFF 1 -#define SER_HANDSHAKING_RTSCTS 2 -#define SER_HANDSHAKING_DTRDSR 3 - -/* Error Codes */ -#define SER_SUCCESS 0 /* Function completed successfully */ -#define SER_ERR_UNKNOWN -1 /* An unknown error occured */ -#define SER_ERR_NOT_OPEN -2 /* The specified COM port is not opened */ -#define SER_ERR_ALREADY_OPEN -3 /* The specified COM port is already opened */ -#define SER_ERR_NO_UART -4 /* Could not find a UART for this COM port */ -#define SER_ERR_INVALID_COMPORT -5 /* User specified an invalid COM port */ -#define SER_ERR_INVALID_BASE -6 /* User specified an invalid base address */ -#define SER_ERR_INVALID_IRQ -7 /* User specified an invalid IRQ number */ -#define SER_ERR_INVALID_BPS -8 /* User specified an invalid BPS rate */ -#define SER_ERR_INVALID_DATA_BITS -9 /* User specified an invalid number of data bits */ -#define SER_ERR_INVALID_PARITY -10 /* User specified an invalid parity type */ -#define SER_ERR_INVALID_STOP_BITS -11 /* User specified an invalid number of stop bits */ -#define SER_ERR_INVALID_HANDSHAKING -12 /* User specified an invalid handshaking type */ -#define SER_ERR_INVALID_FIFO_THRESHOLD -13 /* User specified an invalid fifo threshold value */ -#define SER_ERR_NULL_PTR -14 /* User specified a buffer address that was NULL */ -#define SER_ERR_IRQ_NOT_FOUND -15 /* Could not find an IRQ for the specified COM port */ -#define SER_ERR_LOCK_MEM -16 /* Could not lock memory in DPMI mode */ - - -/* Name: serial_open() - * - * Desc: Finds and initializes the specified COM port. - * - * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) - * long bps: Bits per second. - * (50, 75, 110, 150, 300, 600, 1200, 2400, 4800, - * 9600, 19200, 38400, 57600, 115200) - * int data_bits: Number of data word bits (5-8) - * char parity: Parity mode ('e', 'o', 'n', 'm', 's') - * int stop_bits: Stop bits (1-2). If data_bits=5 and stop_bits=2, - * actual stop bits is 1.5. - * int handshaking: Handshaking mode - * (SER_HANDSHAKING_NONE, SER_HANDSHAKING_XONXOFF, - * SER_HANDSHAKING_RTSCTS, SER_HANDSHAKING_DTRDSR) - * - * Return: SER_SUCCESS or an error code - */ -int serial_open(int com, long bps, int data_bits, char parity, int stop_bits, int handshaking); - - -/* Name: serial_close() - * - * Desc: Clean up and close the specified serial port. - * - * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) - * - * Return: SER_SUCCESS or an error code - */ -int serial_close(int com); - - -/* Name: serial_read() - * - * Desc: Read data from the specified serial port buffer. - * - * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) - * char* data: Pointer to data buffer - * int len: Number of bytes to read - * - * Return: number of bytes read or an error code - */ -int serial_read(int com, char* data, int len); - - -/* Name: serial_write() and serial_write_buffered() - * - * Desc: Write data to the serial port. - * serial_write() will write the data directly to serial port and will - * block until it has completely sent the data or handshaking has - * stopped output transmission while serial_write_buffered() will copy - * as much as possible data bytes to the transmit buffer and will return - * immediately enabling asynchronous output. - * - * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) - * char* data: Pointer to data buffer - * int len: Number of bytes to write - * - * Return: number of bytes written or an error code - */ -int serial_write (int com, const char* data, int len); -int serial_write_buffered(int com, const char* data, int len); - - -/* Name: serial_set() - * - * Desc: Change the specified serial port's settings. - * - * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) - * long bps: Bits per second. - * (50, 75, 110, 150, 300, 600, 1200, 2400, 4800, - * 9600, 19200, 38400, 57600, 115200) - * int data_bits: Data bits (5, 6, 7, or 8) - * char parity: Parity ('n' = none, 'e' = even, 'o' = odd, 'm' = mark, 's' = space) - * int stop_bits: Stop bits (1-2). If data_bits=5 and stop_bits=2, - * actual stop bits is 1.5. - * int handshaking: Handshaking type (see handshaking modes at top of file) - * - * Return: SER_SUCCESS or an error code - */ -int serial_set(int com, long bps, int data_bits, char parity, int stop_bits, int handshaking); - - -/* serial_set_xxx() functions. These take the same arguments - * as the corresponding ones in serial_set() and return either - * SER_SUCCESS or an error code. - */ -int serial_set_bps (int com, long bps); -int serial_set_parity (int com, char parity); -int serial_set_data (int com, int data); -int serial_set_stop (int com, int stop); -int serial_set_handshaking (int com, int handshaking); - -/* Advanced settings. Use these only if you know what you are doing. */ - -/* UART's FIFO threshold -- 14, 8, 4, 1, or 0 (off) */ -int serial_set_fifo_threshold(int com, int threshold); -/* UART's base address */ -int serial_set_base (int com, int base); -/* UART's IRQ */ -int serial_set_irq (int com, int base); - -int serial_set_rts(int comport, int rts); -int serial_set_dtr(int comport, int dtr); - -int serial_set_mcr(int comport, int mcr); - - -/* serial_get_xxx() functions. These return the same types as are supplied - * to serial_set(). The returned type may be negative, in which case it - * is an error code. - */ -int serial_get_base (int com); -int serial_get_irq (int com); -long serial_get_bps (int com); -char serial_get_parity (int com); -int serial_get_data (int com); -int serial_get_stop (int com); -int serial_get_handshaking (int com); - - -int serial_get_rts(int comport); -int serial_get_dtr(int comport); -int serial_get_cts(int comport); -int serial_get_dsr(int comport); - -int serial_get_mcr(int comport); -int serial_get_msr(int comport); -int serial_get_lsr(int comport); - - -/* get number of bytes or discard data in TX/RX buffers - */ -int serial_get_tx_buffered(int comport); -int serial_get_rx_buffered(int comport); -int serial_clear_tx_buffer(int comport); -int serial_clear_rx_buffer(int comport); - -#endif +/* Serial Library 1.4 (22-Jun-2000) (c) 1998 Karl Stenerud + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SERIAL__HEADER +#define SERIAL__HEADER + +/* COM Ports */ +#define COM_1 0 +#define COM_2 1 +#define COM_3 2 +#define COM_4 3 + +/* Handshaking Modes */ +#define SER_HANDSHAKING_NONE 0 +#define SER_HANDSHAKING_XONXOFF 1 +#define SER_HANDSHAKING_RTSCTS 2 +#define SER_HANDSHAKING_DTRDSR 3 + +/* Parity defines (added to avoid magic numbers 2/29/24 EES) */ +#define PARITY_NONE 'n' +#define PARITY_EVEN 'e' +#define PARITY_ODD 'o' +#define PARITY_MARK 'm' +#define PARITY_SPACE 's' + +/* Error Codes */ +#define SER_SUCCESS 0 /* Function completed successfully */ +#define SER_ERR_UNKNOWN -1 /* An unknown error occured */ +#define SER_ERR_NOT_OPEN -2 /* The specified COM port is not opened */ +#define SER_ERR_ALREADY_OPEN -3 /* The specified COM port is already opened */ +#define SER_ERR_NO_UART -4 /* Could not find a UART for this COM port */ +#define SER_ERR_INVALID_COMPORT -5 /* User specified an invalid COM port */ +#define SER_ERR_INVALID_BASE -6 /* User specified an invalid base address */ +#define SER_ERR_INVALID_IRQ -7 /* User specified an invalid IRQ number */ +#define SER_ERR_INVALID_BPS -8 /* User specified an invalid BPS rate */ +#define SER_ERR_INVALID_DATA_BITS -9 /* User specified an invalid number of data bits */ +#define SER_ERR_INVALID_PARITY -10 /* User specified an invalid parity type */ +#define SER_ERR_INVALID_STOP_BITS -11 /* User specified an invalid number of stop bits */ +#define SER_ERR_INVALID_HANDSHAKING -12 /* User specified an invalid handshaking type */ +#define SER_ERR_INVALID_FIFO_THRESHOLD -13 /* User specified an invalid fifo threshold value */ +#define SER_ERR_NULL_PTR -14 /* User specified a buffer address that was NULL */ +#define SER_ERR_IRQ_NOT_FOUND -15 /* Could not find an IRQ for the specified COM port */ +#define SER_ERR_LOCK_MEM -16 /* Could not lock memory in DPMI mode */ + + +/* Name: GetErrorText() added 2/29/24 EES + * + * Desc: Return the text description of a numeric error code. + * + * Params: int err_num: The error code. + * + * Return: The text description of the error code passed in. + */ +char* GetErrorText (int err_num); + + +/* Name: serial_is_port_open() + * + * Desc: Determines whether or not a particular COM port is open. + * + * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) + * + * Return: 1 port is open + * 0 port is not open + */ +int serial_is_port_open(int com); + + +/* Name: serial_open() + * + * Desc: Finds and initializes the specified COM port. + * + * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) + * long bps: Bits per second. + * (50, 75, 110, 150, 300, 600, 1200, 2400, 4800, + * 9600, 19200, 38400, 57600, 115200) + * int data_bits: Number of data word bits (5-8) + * char parity: Parity mode ('e', 'o', 'n', 'm', 's') + * int stop_bits: Stop bits (1-2). If data_bits=5 and stop_bits=2, + * actual stop bits is 1.5. + * int handshaking: Handshaking mode + * (SER_HANDSHAKING_NONE, SER_HANDSHAKING_XONXOFF, + * SER_HANDSHAKING_RTSCTS, SER_HANDSHAKING_DTRDSR) + * + * Return: SER_SUCCESS or an error code + */ +int serial_open(int com, long bps, int data_bits, char parity, int stop_bits, int handshaking); + + +/* Name: serial_close() + * + * Desc: Clean up and close the specified serial port. + * + * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) + * + * Return: SER_SUCCESS or an error code + */ +int serial_close(int com); + + +/* Name: serial_read() + * + * Desc: Read data from the specified serial port buffer. + * + * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) + * char* data: Pointer to data buffer + * int len: Number of bytes to read + * + * Return: number of bytes read or an error code + */ +int serial_read(int com, char* data, int len); + + +/* Name: serial_write() and serial_write_buffered() + * + * Desc: Write data to the serial port. + * serial_write() will write the data directly to serial port and will + * block until it has completely sent the data or handshaking has + * stopped output transmission while serial_write_buffered() will copy + * as much as possible data bytes to the transmit buffer and will return + * immediately enabling asynchronous output. + * + * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) + * char* data: Pointer to data buffer + * int len: Number of bytes to write + * + * Return: number of bytes written or an error code + */ +int serial_write (int com, const char* data, int len); +int serial_write_buffered(int com, const char* data, int len); + + +/* Name: serial_set() + * + * Desc: Change the specified serial port's settings. + * + * Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4) + * long bps: Bits per second. + * (50, 75, 110, 150, 300, 600, 1200, 2400, 4800, + * 9600, 19200, 38400, 57600, 115200) + * int data_bits: Data bits (5, 6, 7, or 8) + * char parity: Parity ('n' = none, 'e' = even, 'o' = odd, 'm' = mark, 's' = space) + * int stop_bits: Stop bits (1-2). If data_bits=5 and stop_bits=2, + * actual stop bits is 1.5. + * int handshaking: Handshaking type (see handshaking modes at top of file) + * + * Return: SER_SUCCESS or an error code + */ +int serial_set(int com, long bps, int data_bits, char parity, int stop_bits, int handshaking); + + +/* serial_set_xxx() functions. These take the same arguments + * as the corresponding ones in serial_set() and return either + * SER_SUCCESS or an error code. + */ +int serial_set_bps (int com, long bps); +int serial_set_parity (int com, char parity); +int serial_set_data (int com, int data); +int serial_set_stop (int com, int stop); +int serial_set_handshaking (int com, int handshaking); + +/* Advanced settings. Use these only if you know what you are doing. */ + +/* UART's FIFO threshold -- 14, 8, 4, 1, or 0 (off) */ +int serial_set_fifo_threshold(int com, int threshold); +/* UART's base address */ +int serial_set_base (int com, int base); +/* UART's IRQ */ +int serial_set_irq (int com, int base); + +int serial_set_rts(int comport, int rts); +int serial_set_dtr(int comport, int dtr); + +int serial_set_mcr(int comport, int mcr); + + +/* serial_get_xxx() functions. These return the same types as are supplied + * to serial_set(). The returned type may be negative, in which case it + * is an error code. + */ +int serial_get_base (int com); +int serial_get_irq (int com); +long serial_get_bps (int com); +char serial_get_parity (int com); +int serial_get_data (int com); +int serial_get_stop (int com); +int serial_get_handshaking (int com); + + +int serial_get_rts(int comport); +int serial_get_dtr(int comport); +int serial_get_cts(int comport); +int serial_get_dsr(int comport); + +int serial_get_mcr(int comport); +int serial_get_msr(int comport); +int serial_get_lsr(int comport); + + +/* get number of bytes or discard data in TX/RX buffers + */ +int serial_get_tx_buffered(int comport); +int serial_get_rx_buffered(int comport); +int serial_clear_tx_buffer(int comport); +int serial_clear_rx_buffer(int comport); + +#endif