/*
Copyright (C) Magna Carta Software, Inc. 1990, 1991. All Rights Reserved
Z80SIOI.C -- Z-80 SIO interrupt handling routines.
*/
#define CCT_DEVELOPMENT
#if (defined(CCTW) || defined(_WINDOWS))
#include <windows.h>
#endif
#include <dos.h>
#include <comm.h>
#include <z80sio.h>
#if !defined(__NDPC__)
#include <conio.h>
#endif
/*
UZ80_DEINSTALL_IPR -- Generic Z80 family IPR deinstallation procedure.
*/
short uz80_deinstall_ipr_(COMM_PORT *p, WORD itype)
{
short i, val=0, ret=0;
_disable(); /* serial interrupts could already be in use */
switch(itype) {
case UZ80_ES:
case MODEM_STATUS:
break;
case UZ80_RX_ALL:
case RECEIVE:
if (p->a_ipr[2] == (void FAR_ *) com_dummy_) ret = EOF;
else {
p->a_ipr[2] = (void FAR_ *) com_dummy_;
val |= UZ80_RX_ALL;
p->c_read = uz80_read_;
p->rxstat = uz80_rxstat_;
}
break;
case UZ80_TX_ALL:
case TRANSMIT:
if (p->a_ipr[1] == (void FAR_ *) com_dummy_) ret = EOF;
else {
p->a_ipr[1] = (void FAR_ *) com_dummy_;
val |= UZ80_TX_ALL;
p->c_write = p->c_write_; /* single byte port write function */
p->txstat = p->txstat_;
}
break;
default:
ret = EOF;
break;
}
if (!ret) {
uz80_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) {
/* ALL IPRs NUKED -- DEINSTALL THE ISR */
deinstall_isr(p);
}
}
_enable();
return (ret);
}
/*
UZ80_DISABLE_COMM_INT -- Disable interrupts at the communications chip.
*/
short uz80_disable_comm_int_(COMM_PORT *p, WORD int_type)
{
return(uz80_int_set_(p, int_type, FALSE));
}
/*
UZ80_ENABLE_COMM_INT -- Enable interrupts at the communications chip.
*/
short uz80_enable_comm_int_(COMM_PORT *p, WORD int_type)
{
return(uz80_int_set_(p, int_type, TRUE));
}
/*
UZ80_INSTALL_IPR -- Install an interrupt processing routine.
*/
short uz80_install_ipr_(COMM_PORT *p, WORD itype, void FAR_ *fn, BYTE FAR_ *buf, WORD buflen)
{
short ret = 0;
_disable(); /* serial interrupts could already be in use */
switch(itype) {
case UZ80_ES:
case MODEM_STATUS:
#if 0
if (fn == NULL) p->a_ipr[3] = com_ls_int;
else p->a_ipr[3] = fn;
#endif
break;
case UZ80_RX_ALL:
case RECEIVE:
itype = UZ80_RX_ALL;
if (fn == NULL) p->a_ipr[2] = (void FAR_ *) uz80_rx_int_;
else p->a_ipr[2] = fn;
p->rxbufhead = p->rxbuftail = p->rxbuf = buf;
p->rx_bufsiz = buflen;
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 UZ80_TX_ALL:
case TRANSMIT:
itype = UZ80_TX_ALL;
if (fn == NULL) p->a_ipr[1] = (void FAR_ *) uz80_tx_int_;
else p->a_ipr[1] = fn;
p->txbufhead = p->txbuftail = p->txbuf = buf;
p->tx_bufsiz = buflen;
p->txbufend = buf + p->tx_bufsiz - 1;
p->c_write = (short (*)(COMM_PORT *, WORD)) i_write;
p->txstat = i_txstat;
p->txstart = i_txstart;
break;
default:
ret = EOF;
}
/* ENABLE INTERRUPTS AT THE Z80SIO */
if (!ret) uz80_int_set_(p, itype, TRUE);
_enable();
return (ret);
}
/*
UZ80_INT_SET -- Enable or disable the desired type of Z80SIO/DART
communications interrupt by setting or clearing the correct bit in the
Z80 Interrupt Enable register.
Arguments: COMM_PORT *p -- pointer to the comm. port structure
unsigned type -- the condition that generates an interrupt
0X2 = Tx character
0X8 = Rx first character
0X10 = Rx all characters (parity error is a special receive condition)
0X18 = Rx all characters (parity error is NOT a special receive condition)
*/
short uz80_int_set_(COMM_PORT *p, WORD itype, WORD state)
{
int regval;
regval = uz80_get_wr_(p, WR1);
/* SET THE BIT CORRESPONDING TO THE INTERRUPT TYPE IN THE 8250 */
if (state) {
if (itype == UZ80_RX_ALL || itype == UZ80_RX_ALL_SPECIAL_RECEIVE ||
itype == UZ80_RX_FIRST_CHARACTER) p->intr |= 1;
if (itype & UZ80_TX_ALL) p->intr |= 2;
/* CLEAR OUT GARBAGE */
while (c_inchar(p) != EOF);
regval |= itype;
}
/* CLEAR THE BIT CORRESPONDING TO THE INTERRUPT TYPE IN THE 8250 */
else {
regval &= ~itype;
if (itype == UZ80_RX_ALL || itype == UZ80_RX_ALL_SPECIAL_RECEIVE ||
itype == UZ80_RX_FIRST_CHARACTER) p->intr &= ~1;
if (itype & UZ80_TX_ALL) p->intr &= ~2;
}
uz80_set_reg_(p, WR1, regval);
return (0);
}
/* SAMPLE Z80 SIO ISRs. USE IF YOU WISH */
#if 0
#define AST 0X300 /* base address of AST port */
#define RXBUFSIZE 1024*2 /* Receive interrupt buffer size */
#define TXBUFSIZE 1024 /* Transmit interrupt buffer size */
/*
UZ80_RX_INT -- interrupt handler for receive data.
Note: A circular buffer of char "buff1" must be declared prior to use.
EOI must be defined as 0X20.
BYTE is typedef unsigned char BYTE.
*/
void INTERRUPT_ uz80_rx_int_(void)
{
#if XDEBUG
static BYTE c, rr1;
#endif
static volatile BYTE FAR_ *b_ptr;
_enable();
#if defined(CCT_TEST)
outp(AST+3,1); /* read register 1 for int type */
rr1 = inp(AST+3);
if (rr1 & 0X20) {
c = 'o'; /* receiver overrun error */
outp(AST+3, 0X30); /* issue error reset command */
if (inp(AST+3) & 1) inp(AST+3); /* IF a char is ready get it */
}
else if (rr1 & 0X40) {
c = 'f'; /* receiver framing error */
outp(AST+3, 0X30); /* issue error reset command */
if (inp(AST+3) & 1) inp(AST+1); /* IF a char is ready get it */
}
#endif
if (inp(AST+3) & 1) { /* IF a char is ready get it */
b_ptr = sio0->rxbufhead + 1;
if (b_ptr > sio0->rxbufend) b_ptr = sio0->rxbuf;
if (!(b_ptr == sio0->rxbuftail)) { /* buffer is full */
*sio0->rxbufhead = (BYTE) inp(AST+1);
sio0->rxbufhead = b_ptr;
}
}
outp(EOINT, 0X20); /* Send EOI to 8259 */
}
#if XDEBUG
WORD FAR_ *s = (WORD FAR_ *) 0XB8000000L;
#endif
/*
UZ80_TX_INT -- Interrupt handler for the Z80SIO/DART transmit data interrupt.
For use under the IBM architecture.
Note: A circular buffer of char "txbuff1" must be declared prior to use.
EOI must be defined as 0X20.
The comm port number must be specified.
BYTE is typedef unsigned char BYTE.
*/
void INTERRUPT_ uz80_tx_int_(void)
{
/* _enable(); */
if (sio0->txbuftail == sio0->txbufhead) {
sio0->f_txbusy |= FALSE;
uz80_set_reg_(sio0, WR0, UZ80_TX_RESET);
}
else {
outp(sio0->udata_reg_addr, *sio0->txbuftail++); /* send byte */
if (sio0->txbuftail > sio0->txbufend) sio0->txbuftail = sio0->txbuf;
#if XDEBUG
**s++ = (0XF << 8) | 'o';
#endif
}
/* _disable(); */
outp(EOINT, 0X20); /* Send EOI to 8259 */
}
#endif