Metropoli BBS
VIEWER: z80sioi.c MODE: TEXT (ASCII)
/*
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

[ RETURN TO DIRECTORY ]