⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i8250sio.c

📁 cpc-1631的BSP包for VxWorks操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* i8250Sio.c - I8250 serial driver */


/* Copyright 1984-2000 Wind River Systems, Inc. */
#include "copyright_wrs.h"


/*
modification history
--------------------
01k,05dec00,dat  merge from sustaining branch to tor2_0_x
01j,20nov00,pai  enabled receiver buffer full interrupt from UART in
                 i8250Startup() (SPR 32443).
01i,06oct99,pai  account for PC87307 hardware anomaly in i8250Int() (SPR 26117).
01h,26oct98,dbt  call i8250InitChannel() in i8250HrdInit() rather than in
                 i8250ModeSet(). (SPR #22349).
01g,23may97,db   added hardware options and modem control(SPR #7542).
                 fixed bugs reported in SPRs 9404, 9223.
01f,12oct95,dgf  added bauds > 38k
01e,03aug95,myz  fixed the warning messages
01d,12jul95,myz  fixed the baud rate problem.
01c,20jun95,ms   fixed comments for mangen.
01b,15jun95,ms   updated for new driver structure
01a,15mar95,myz  written (using i8250Serial.c + the VxMon polled driver).
*/


/*
DESCRIPTION
This is the driver for the Intel 8250 UART Chip used on the PC 386.
It uses the SCCs in asynchronous mode only.


USAGE
An I8250_CHAN structure is used to describe the chip.
The BSP's sysHwInit() routine typically calls sysSerialHwInit()
which initializes all the register values in the I8250_CHAN structure
(except the SIO_DRV_FUNCS) before calling i8250HrdInit().
The BSP's sysHwInit2() routine typically calls sysSerialHwInit2() which
connects the chips interrupt handler (i8250Int) via intConnect().


IOCTL FUNCTIONS
This driver responds to all the same ioctl() codes as a normal serial driver;
for more information, see the comments in sioLib.h.  As initialized, the
available baud rates are 110, 300, 600, 1200, 2400, 4800, 9600, 19200, and
38400.


This driver handles setting of hardware options such as parity(odd, even) and
number of data bits(5, 6, 7, 8). Hardware flow control is provided with the
handshakes RTS/CTS. The function HUPCL(hang up on last close) is available.


INCLUDE FILES: drv/sio/i8250Sio.h
*/


#include "vxWorks.h"
#include "iv.h"
#include "intLib.h"
#include "errnoLib.h"
#include "i8250Sio.h"



/* defines */

/* This value is used to specify the maximum number of times i8250Int()
 * routine will read the 8250 Interrupt Identification Register before
 * returning.  This value should optimally be derived from the BRDR.
 */
#define I8250_IIR_READ_MAX          40


#ifndef I8250_DEFAULT_BAUD
#   define  I8250_DEFAULT_BAUD      9600
#endif


#ifndef SIO_HUP
#   define SIO_OPEN     0x100A
#   define SIO_HUP      0x100B
#endif


/* locals */


/* baudTable is a table of the available baud rates, and the values to write
 * to the UART's baud rate divisor {high, low} register. the formula is
 * 1843200(source) / (16 * baudrate)
 */

static BAUD baudTable [] =
    {
    {50, 2304}, {75, 1536}, {110, 1047}, {134, 857}, {150, 768},
    {300, 384}, {600, 192}, {1200, 96}, {2000, 58}, {2400, 48},
    {3600,32}, {4800, 24}, {7200,16}, {9600, 12}, {19200, 6}, {38400, 3},
    {57600, 2}, {115200, 1}
    };


static SIO_DRV_FUNCS i8250SioDrvFuncs;


/* forward declarations */


LOCAL   void    i8250InitChannel (I8250_CHAN *);
LOCAL   int     i8250Ioctl(I8250_CHAN *, int, int);
LOCAL   int     i8250Startup(I8250_CHAN *pChan);
LOCAL   int     i8250PRxChar (I8250_CHAN *pChan, char *ch);
LOCAL   int     i8250PTxChar(I8250_CHAN *pChan, char ch);
LOCAL   STATUS  i8250OptsSet (I8250_CHAN *, UINT);
LOCAL   STATUS  i8250ModeSet (I8250_CHAN *, UINT);
LOCAL   STATUS  i8250BaudSet (I8250_CHAN *, UINT);


/******************************************************************************
*
* i8250CallbackInstall - install ISR callbacks to get put chars.
*
* This routine installs the callback functions for the driver
*
* RETURNS: OK on success or ENOSYS on unsupported callback type.
*/ 
static int i8250CallbackInstall
    (
    SIO_CHAN *  pSioChan,
    int         callbackType,
    STATUS      (*callback)(),
    void *      callbackArg
    )
    {
    I8250_CHAN * pChan = (I8250_CHAN *)pSioChan;


    switch (callbackType)
        {
        case SIO_CALLBACK_GET_TX_CHAR:
            pChan->getTxChar    = callback;
            pChan->getTxArg     = callbackArg;
            return (OK);
        case SIO_CALLBACK_PUT_RCV_CHAR:
            pChan->putRcvChar   = callback;
            pChan->putRcvArg    = callbackArg;
            return (OK);
        default:
            return (ENOSYS);
        }
    }

/******************************************************************************
*
* i8250HrdInit - initialize the chip
*
* This routine is called to reset the chip in a quiescent state.
* RETURNS: N/A
*/
void i8250HrdInit
    (
    I8250_CHAN *  pChan         /* pointer to device */
    )
    {
    if (i8250SioDrvFuncs.ioctl == NULL)
        {
        i8250SioDrvFuncs.ioctl          = (int (*)())i8250Ioctl;
        i8250SioDrvFuncs.txStartup      = (int (*)())i8250Startup;
        i8250SioDrvFuncs.callbackInstall = i8250CallbackInstall;
        i8250SioDrvFuncs.pollInput      = (int (*)())i8250PRxChar;
        i8250SioDrvFuncs.pollOutput     = (int (*)(SIO_CHAN *,char))i8250PTxChar;
        }


    pChan->pDrvFuncs = &i8250SioDrvFuncs;
	
    i8250InitChannel(pChan);    /* reset the channel */
    }

/*******************************************************************************
*
* i8250InitChannel  - initialize a single channel
*/
static void i8250InitChannel
    (
    I8250_CHAN *  pChan         /* pointer to device */
    )
    {
    int oldLevel;


    oldLevel = intLock ();


    /* set channel baud rate */


    (void) i8250BaudSet(pChan, I8250_DEFAULT_BAUD);


    /* 8 data bits, 1 stop bit, no parity */


    (*pChan->outByte) (pChan->lcr, (I8250_LCR_CS8 | I8250_LCR_1_STB));


    (*pChan->outByte) (pChan->mdc, (I8250_MCR_RTS | I8250_MCR_DTR | \
                                        I8250_MCR_OUT2));



    (*pChan->inByte) (pChan->data);     /* clear the port */


    /* disable interrupts  */


    (*pChan->outByte) (pChan->ier, 0x0);


    pChan->options = (CLOCAL | CREAD | CS8);


    intUnlock (oldLevel);
    }

/*******************************************************************************
*
* i8250Hup - hang up the modem control lines 
*
* Resets the RTS and DTR signals.
*
* RETURNS: OK
*/
LOCAL STATUS i8250Hup
    (
    I8250_CHAN * pChan          /* pointer to channel */
    )
    {
    FAST int     oldlevel;      /* current interrupt level mask */


    oldlevel = intLock ();


    (*pChan->outByte) (pChan->mdc, I8250_MCR_OUT2);


    intUnlock (oldlevel);


    return (OK);


    }    

/*******************************************************************************
*
* i8250Open - Set the modem control lines 
*
* Set the modem control lines(RTS, DTR) TRUE if not already set.  
* It also clears the receiver. 
*
* RETURNS: OK
*/
LOCAL STATUS i8250Open
    (
    I8250_CHAN * pChan          /* pointer to channel */
    )
    {
    FAST int     oldlevel;      /* current interrupt level mask */
    char mask;


    /* read modem control register */


    mask = ((*pChan->inByte) (pChan->mdc)) & (I8250_MCR_RTS | I8250_MCR_DTR);


    if (mask != (I8250_MCR_RTS | I8250_MCR_DTR)) 
        {
        /* RTS and DTR not set yet */


        oldlevel = intLock ();


        /* set RTS and DTR TRUE */


        (*pChan->outByte) (pChan->mdc, (I8250_MCR_RTS | I8250_MCR_DTR | \
                                        I8250_MCR_OUT2));


        intUnlock (oldlevel);
        }


    return (OK);
    }

/******************************************************************************
*
* i8250BaudSet - change baud rate for channel
*
* This routine sets the baud rate for the UART. The interrupts are disabled
* during chip access.
*
* RETURNS: OK to indicate success, otherwise ERROR is returned
*/
LOCAL STATUS  i8250BaudSet
    (
    I8250_CHAN *   pChan,       /* pointer to channel */
    UINT           baud         /* requested baud rate */
    )
    {
    int         oldlevel;
    STATUS      status;
    FAST        int     ix;
    UINT8       lcr;

    /* disable interrupts during chip access */


    oldlevel = intLock ();


    status = ERROR;


    for (ix = 0; ix < NELEMENTS (baudTable); ix++)
        {
        if (baudTable [ix].rate == baud)        /* lookup baud rate value */
            {
            
            lcr = (*pChan->inByte) (pChan->lcr);   
            (*pChan->outByte) (pChan->lcr, (char)(I8250_LCR_DLAB | lcr));
            (*pChan->outByte) (pChan->brdh, MSB (baudTable[ix].preset));
            (*pChan->outByte) (pChan->brdl, LSB (baudTable[ix].preset));
            (*pChan->outByte) (pChan->lcr, lcr);
            status = OK;						
            break;
            }
        }


    intUnlock(oldlevel);


    return (status);
    }

/*******************************************************************************
*
* i8250ModeSet - change channel mode setting
*
* This driver supports both polled and interrupt modes and is capable of
* switching between modes dynamically. 
*
* If interrupt mode is desired this routine enables the channels receiver and 
* transmitter interrupts. If the modem control option is TRUE, the Tx interrupt
* is disabled if the CTS signal is FALSE. It is enabled otherwise. 
*
* If polled mode is desired the device interrupts are disabled. 
*
* RETURNS:
* Returns a status of OK if the mode was set else ERROR.
*/
LOCAL STATUS i8250ModeSet
    (
    I8250_CHAN * pChan,         /* pointer to channel */
    UINT        newMode         /* mode requested */
    )
    {
    FAST int     oldlevel;      /* current interrupt level mask */
    char ier, mask;


    if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT))
        return (ERROR);


    oldlevel = intLock();
           
    if (newMode == SIO_MODE_POLL)
        ier = 0x00;
    else  
        {
        if (pChan->options & CLOCAL) 
            ier = I8250_IER_RXRDY;
        else  
            {
            mask = ((*pChan->inByte) (pChan->msr)) & I8250_MSR_CTS;


            /* if the CTS is asserted enable Tx interrupt */


            if (mask & I8250_MSR_CTS)
                ier = (I8250_IER_TBE | I8250_IER_MSI);
            else
                ier = (I8250_IER_MSI);
            }   
        }


    (*pChan->outByte) (pChan->ier, ier);
            
    pChan->channelMode = newMode;  
          
    intUnlock(oldlevel);


    return (OK);
    }

/*******************************************************************************
*
* i8250OptsSet - set the serial options
*
* Set the channel operating mode to that specified.  All sioLib options
* are supported: CLOCAL, HUPCL, CREAD, CSIZE, PARENB, and PARODD.
*
* RETURNS:
* Returns OK to indicate success, otherwise ERROR is returned
*/
LOCAL STATUS i8250OptsSet
    (
    I8250_CHAN * pChan,         /* pointer to channel */
    UINT options                /* new hardware options */
    )
    {
    FAST int     oldlevel;              /* current interrupt level mask */
    char lcr = 0; 
    char mcr = I8250_MCR_OUT2;
    char ier;
    char mask;


    ier = (*pChan->inByte) (pChan->ier);


    if (pChan == NULL || options & 0xffffff00)
        return ERROR;


    switch (options & CSIZE)
        {
        case CS5:
            lcr = I8250_LCR_CS5; break;
        case CS6:
            lcr = I8250_LCR_CS6; break;
        case CS7:
            lcr = I8250_LCR_CS7; break;
        default:
        case CS8:
            lcr = I8250_LCR_CS8; break;
        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -