/* Copyright (C) Magna Carta Software, Inc. 1991. All Rights Reserved INS8250I.C -- Serial interrupt handling routines for the INS8250 family. */ #define CCT_DEVELOPMENT #if (defined(CCTW) || defined(_WINDOWS)) #include #endif #include #include #if (defined(MSC) || defined(__WATCOMC__) || defined(_INTELC32_) || defined(__HIGHC__)) #include #endif /* U8250_DEINSTALL_IPR_ -- Generic 8250 family ISR deinstallation procedure. */ short u8250_deinstall_ipr_(COMM_PORT *p, WORD itype) { short i, val=0, ret=0; _disable(); /* serial interrupts could already be in use */ switch(itype) { case U8250_LINE_STATUS: case LINE_STATUS: if (p->a_ipr[3] == (void FAR_ *) com_dummy_) ret = EOF; else { p->a_ipr[3] = (void FAR_ *) com_dummy_; val |= U8250_LINE_STATUS; } break; case U8250_RX_DATA_AVAILABLE: case RECEIVE: if (p->a_ipr[2] == (void FAR_ *) com_dummy_) ret = EOF; else { p->a_ipr[2] = (void FAR_ *) com_dummy_; val |= U8250_RX_DATA_AVAILABLE; p->c_read = u8250_read_; p->rxstat = u8250_rxstat_; } break; case U8250_TX_BUFFER_EMPTY: case TRANSMIT: if (p->a_ipr[1] == (void FAR_ *) com_dummy_) ret = EOF; else { p->a_ipr[1] = (void FAR_ *) com_dummy_; val |= U8250_TX_BUFFER_EMPTY; p->c_write = p->c_write_; /* single byte port write function */ p->txstat = p->txstat_; } break; case U8250_MODEM_STATUS: case MODEM_STATUS: if (p->a_ipr[0] == (void FAR_ *) com_dummy_) ret = EOF; else { p->a_ipr[0] = (void FAR_ *) com_dummy_; val |= U8250_MODEM_STATUS; } break; default: ret = EOF; break; } if (!ret) { u8250_int_set_(p, val, FALSE); for (i=0; i < MAX_IPRS; i++) if (p->a_ipr[i] != (void FAR_ *) com_dummy_) break; if (i == MAX_IPRS) { u8250_set_(p, OUT2, LOW); /* set OUT2 line low */ /* ALL IPRs NUKED -- DEINSTALL THE ISR */ deinstall_isr(p); } } _enable(); return (ret); } /* U8250_DISABLE_COMM_INT_ -- Disable interrupts at the communications chip. */ short u8250_disable_comm_int_(COMM_PORT *p, WORD int_type) { return(u8250_int_set_(p, int_type, FALSE)); } /* U8250_ENABLE_COMM_INT_ -- Enable interrupts at the communications chip. */ short u8250_enable_comm_int_(COMM_PORT *p, WORD int_type) { return(u8250_int_set_(p, int_type, TRUE)); } /* U8250_INSTALL_IPR -- Generic interrupt processing routine (IPR) install and enable function for the INS8250 family. Installs one of: Receive line status (priority 1) Receive data ready (priority 2) TX holding reg. empty (priority 3) MODEM status (priority 4) Call successively to install more than one type of INT. Return value: 0 -- OK; EOF -- IRQ not assigned (p->rxintnum = 0); -2 -- Invalid interrupt type. -3 -- Interrupt buffer size not assigned non-zero value; -4 -- No available IRQs; */ short u8250_install_ipr_(COMM_PORT *p, WORD itype, void FAR_ *fn, BYTE FAR_ *buf, WORD len) { short ret = 0; _disable(); /* serial interrupts could already be in use */ switch(itype) { case U8250_LINE_STATUS: case LINE_STATUS: if (fn == NULL) p->a_ipr[3] = (void FAR_ *) com_rls_ipr_; else p->a_ipr[3] = fn; break; case U8250_RX_DATA_AVAILABLE: case RECEIVE: if (fn == NULL) p->a_ipr[2] = (void FAR_ *) com_rx_ipr_; else p->a_ipr[2] = fn; p->rxbufhead = p->rxbuftail = p->rxbuf = buf; p->rx_bufsiz = len; p->rxbufend = buf + p->rx_bufsiz - 1; if (!p->highwater) p->highwater = (p->rx_bufsiz/10) * 8; /* 80% full */ if (!p->lowwater) p->lowwater = (p->rx_bufsiz/10) * 2; /* 20% full */ p->c_read = i_read; p->rxstat = i_rxstat; break; case U8250_TX_BUFFER_EMPTY: case TRANSMIT: if (fn == NULL) p->a_ipr[1] = (void FAR_ *) com_tx_ipr_; else p->a_ipr[1] = fn; p->txbufhead = p->txbuftail = p->txbuf = buf; p->tx_bufsiz = len; p->txbufend = buf + p->tx_bufsiz - 1; p->c_write = (short (*)(COMM_PORT *, WORD)) i_write; /* single byte port write function */ p->txstat = i_txstat; p->txstart = i_txstart; break; case U8250_MODEM_STATUS: case MODEM_STATUS: if (fn == NULL) p->a_ipr[0] = (void FAR_ *) com_ms_ipr_; else p->a_ipr[0] = fn; break; default: ret = EOF; } if (!ret) u8250_int_set_(p, itype, TRUE); _enable(); return (ret); } /* U8250_INT_SET_ -- Enable or disable the desired type of 8250 communications interrupt by setting or clearing the appropriate bit in the 8250 Interrupt Enable register. */ short u8250_int_set_(COMM_PORT *p, WORD itype, WORD state) { short regval; if (itype > 1000 && itype < 1009) itype -= 1000; regval = inp(p->uart.u8250.ier_addr); if (state) { p->intr |= itype; /* SET THE BIT CORRESPONDING TO THE INTERRUPT TYPE IN THE 8250 */ outp(p->uart.u8250.ier_addr, regval | itype); u8250_set_(p, OUT2, HIGH); } /* CLEAR THE BIT CORRESPONDING TO THE INTERRUPT TYPE IN THE 8250 */ else { p->intr &= ~itype; outp(p->uart.u8250.ier_addr, regval & ~itype); } /* CLEAR PENDING UART INTERRUPTS */ do { inp(p->uart.u8250.lsr_addr); /* clear LS INT */ inp(p->ubase_addr); /* clear RX INT */ inp(p->uart.u8250.msr_addr); /* clear MS INT */ } while (!(inp(p->uart.u8250.iir_addr) & 1)); /* clear pending */ return (0); }