Metropoli BBS
VIEWER: isauart.c MODE: TEXT (ASCII)
/*
Copyright (C) Magna Carta Software, Inc. 1990.  All Rights Reserved
INS8250.C -- Routines specific to the National Semiconductor INS8250 family.
*/

#include <ccttype.h>
#if (defined(MSC) || defined(__WATCOMC__) || defined(__HIGHC__))
    #include <conio.h>
#endif


/*
MSC v6.0A bugs force sub-optimization of this file
To see the problem, try $(C_OPT) instead of $(C_OPTR) in large model
*/
#if defined(MSC)
    #pragma optimize("e", off)
#endif


/*
ISAUART -- Attempt to recognize the UART type when it is a member of the
INS8250 family.
Return value:
    EOF -- not recognized;
    0   -- INS8250/INS8250-B;
    1   -- INS8250A/NS16450;
    2   -- NS16550;
    3   -- NS16550A;
*/
short isauart(WORD addr)
{
    short old_reg, new_reg;
    short ret = 0;      /* assume an INS8250/B */

    /* CHECK FOR A MEMBER OF THE INS8250 FAMILY BY PUTTING IT INTO LOOPBACK */
    old_reg = inp(addr+4);                  /* save MCR */
    outp(addr+4, old_reg | 0X10);           /* set loopback on */
    inp(addr+6);                            /* reset delta status */
    outp(addr+4, inp(addr+4) | 1);          /* set DTR HIGH */
    if (!(inp(addr+6) & 0X20)) {
        ret = -1;                           /* DSR not HIGH so not recognized */
        outp(addr+4, old_reg);              /* restore MCR */
    }
    else {
        outp(addr+4, inp(addr+4) & ~1);     /* set DTR LOW */
        if ((inp(addr+6) & 0X20)) {
            ret = -1;                       /* DSR not LOW so not recognized */
            outp(addr+4, old_reg);          /* restore MCR */
        }
        else {
            outp(addr+4, old_reg);          /* restore MCR */
            /* READ THE SCRATCH REGISTER */
            old_reg = (short) inp(addr+7);
            outp(addr+7, ~old_reg);
            if (((~old_reg) & 0XFF) == inp(addr+7)) {
                ret = 1;
                outp(addr+7, old_reg);
            }
            if (ret) {
                /* THE UART IS 16450 COMPATIBLE -- CHECK FOR 16550x */
                old_reg = inp(addr+2);
                if (old_reg & 0X30) ret = -1;
                if (ret != -1) {
                    outp(addr+2, 0X1);  /* turn on FIFOs */
                    new_reg = inp(addr+2);
                    if (new_reg & 0XC0) ret = (new_reg >> 6) & 0XFF;
                }
            }
        }
    }

    return (ret);
}
[ RETURN TO DIRECTORY ]