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

📄 ns16550sio.c

📁 cpc-1631的BSP包for VxWorks操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ns16550Sio.c - NS 16550 UART tty driver */

/* Copyright 1984-2002 Wind River Systems, Inc. */

#include "copyright_wrs.h"

/*
modification history
--------------------
01m,24apr02,pmr  SPR 75161: returning int from ns16550TxStartup() as required.
01l,03apr02,jnz  fixed bug at ns16550SioDrvFuncs declraation.
01k,31oct01,mdg  Corrected transmit interrtupt race condition found on 
                  on MIPS Malta board with RM5261 processor. (SPR# 71830)
01j,14mar01,rcs  corrected baud rate divisor calculation formula. (SPR# 63899)
01i,17sep97,dat  fixed merge problems that caused baud rate setting to fail.
01h,06mar97,dat  SPR 7899, max baud rate set to 115200.
01g,08may97,db   added hardware options and modem control(SPRs #7570, #7082).
01f,18dec95,myz  added case IIR_TIMEOUT in ns16550Int routine.
01e,28nov95,myz  fixed bugs to work at 19200 baud or above with heavy traffic.
01d,09nov95,jdi  doc: style cleanup.
01c,02nov95,myz  undo 01b fix
01b,02nov95,p_m  added test for 960CA and 960JX around access to lcr field
		 in order to compile on all architectures.
01a,24oct95,myz  written from ns16550Serial.c.
*/

/*
DESCRIPTION
This is the driver for the NS16552 DUART. This device includes two universal
asynchronous receiver/transmitters, a baud rate generator, and a complete 
modem control capability. 

A NS16550_CHAN structure is used to describe the serial channel. This data 
structure is defined in ns16550Sio.h.

Only asynchronous serial operation is supported by this driver.
The default serial settings are 8 data bits, 1 stop bit, no parity, 9600
baud, and software flow control.  

USAGE
The BSP's sysHwInit() routine typically calls sysSerialHwInit(),
which creates the NS16550_CHAN structure and initializes all the values in the 
structure (except the SIO_DRV_FUNCS) before calling ns16550DevInit().
The BSP's sysHwInit2() routine typically calls sysSerialHwInit2(), which
connects the chips interrupts via intConnect() (either the single
interrupt `ns16550Int' or the three interrupts `ns16550IntWr', `ns16550IntRd',
and `ns16550IntEx').

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.
When hardware flow control is enabled, the signals RTS and DTR are set TRUE 
and remain set until a HUPCL is performed. 

INCLUDE FILES: drv/sio/ns16552Sio.h

*/

/* includes */

#include "vxWorks.h"
#include "intLib.h"
#include "errnoLib.h"
#include "errno.h"
#include "sioLib.h"
#include "ns16552Sio.h"

/* local defines       */

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

/* min/max baud rate */
 
#define NS16550_MIN_RATE 50
#define NS16550_MAX_RATE 115200

#define REG(reg, pchan) \
 (*(volatile UINT8 *)((UINT32)pchan->regs + (reg * pchan->regDelta)))
#define REGPTR(reg, pchan) \
 ((volatile UINT8 *)((UINT32)pchan->regs + (reg * pchan->regDelta)))

/* static forward declarations */

LOCAL 	int 	ns16550CallbackInstall (SIO_CHAN *, int, STATUS (*)(), void *);
LOCAL 	STATUS 	ns16550DummyCallback ();
LOCAL 	void 	ns16550InitChannel (NS16550_CHAN *);
LOCAL   STATUS  ns16550BaudSet (NS16550_CHAN *, UINT);
LOCAL 	STATUS  ns16550ModeSet (NS16550_CHAN *, UINT);
LOCAL 	STATUS 	ns16550Ioctl (NS16550_CHAN *, int, int);
LOCAL 	int  	ns16550TxStartup (NS16550_CHAN *);
LOCAL 	int 	ns16550PollOutput (NS16550_CHAN *, char);
LOCAL 	int 	ns16550PollInput (NS16550_CHAN *, char *);
LOCAL 	STATUS 	ns16550OptsSet (NS16550_CHAN *, UINT);
LOCAL 	STATUS 	ns16550Open (NS16550_CHAN * pChan );
LOCAL 	STATUS 	ns16550Hup (NS16550_CHAN * pChan );

/* driver functions */

static SIO_DRV_FUNCS ns16550SioDrvFuncs =
    {
    (int (*)())ns16550Ioctl,
    (int (*)())ns16550TxStartup,
    (int (*)())ns16550CallbackInstall,
    (int (*)())ns16550PollInput,
    (int (*)(SIO_CHAN *,char))ns16550PollOutput
    };

/******************************************************************************
*
* ns16550DummyCallback - dummy callback routine.
*/

LOCAL STATUS ns16550DummyCallback (void)
    {
    return (ERROR);
    }

/******************************************************************************
*
* ns16550DevInit - intialize an NS16550 channel
*
* This routine initializes some SIO_CHAN function pointers and then resets
* the chip in a quiescent state.  Before this routine is called, the BSP
* must already have initialized all the device addresses, etc. in the
* NS16550_CHAN structure.
*
* RETURNS: N/A
*/

void ns16550DevInit
    (
    NS16550_CHAN * pChan	/* pointer to channel */
    )
    {
    int oldlevel = intLock ();

    /* initialize the driver function pointers in the SIO_CHAN's */

    pChan->pDrvFuncs    = &ns16550SioDrvFuncs;

    /* set the non BSP-specific constants */

    pChan->getTxChar    = ns16550DummyCallback;
    pChan->putRcvChar   = ns16550DummyCallback;
    pChan->channelMode  = 0;    /* undefined */

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

    /* reset the chip */

    ns16550InitChannel (pChan);

    intUnlock (oldlevel);
    }

/*******************************************************************************
*
* ns16550InitChannel - initialize UART
*
* Initialize the number of data bits, parity and set the selected
* baud rate.
* Set the modem control signals if the option is selected.
*
* RETURNS: N/A
*/

LOCAL void ns16550InitChannel
    (
    NS16550_CHAN * pChan	/* pointer to channel */	
    )
    {

    /* set the requested baud rate */

    ns16550BaudSet(pChan, pChan->baudRate);

    /* set the options */

    ns16550OptsSet(pChan, pChan->options);
    }

/*******************************************************************************
*
* ns16550OptsSet - set the serial options
*
* Set the channel operating mode to that specified.  All sioLib options
* are supported: CLOCAL, HUPCL, CREAD, CSIZE, PARENB, and PARODD.
* When the HUPCL option is enabled, a connection is closed on the last
* close() call and opened on each open() call.
*
* Note, this routine disables the transmitter.  The calling routine
* may have to re-enable it.
*
* RETURNS:
* Returns OK to indicate success, otherwise ERROR is returned
*/

LOCAL STATUS ns16550OptsSet
    (
    NS16550_CHAN * pChan,	/* pointer to channel */
    UINT options		/* new hardware options */
    )
    {
    FAST int     oldlevel;		/* current interrupt level mask */

    pChan->lcr = 0; 
    pChan->mcr &= (~(MCR_RTS | MCR_DTR)); /* clear RTS and DTR bits */
    
    if (pChan == NULL || options & 0xffffff00)
	return ERROR;

    switch (options & CSIZE)
	{
	case CS5:
	    pChan->lcr = CHAR_LEN_5; break;
	case CS6:
	    pChan->lcr = CHAR_LEN_6; break;
	case CS7:
	    pChan->lcr = CHAR_LEN_7; break;
	default:
	case CS8:
	    pChan->lcr = CHAR_LEN_8; break;
	}

    if (options & STOPB)
	pChan->lcr |= LCR_STB;
    else
	pChan->lcr |= ONE_STOP;
    
    switch (options & (PARENB | PARODD))
	{
	case PARENB|PARODD:
	    pChan->lcr |= LCR_PEN; break;
	case PARENB:
	    pChan->lcr |= (LCR_PEN | LCR_EPS); break;
	default:
	case 0:
	    pChan->lcr |= PARITY_NONE; break;
	}

    REG(IER, pChan) = 0;

    if (!(options & CLOCAL))
	{
	/* !clocal enables hardware flow control(DTR/DSR) */

	pChan->mcr |= (MCR_DTR | MCR_RTS);
    	pChan->ier &= (~TxFIFO_BIT); 
	pChan->ier |= IER_EMSI;    /* enable modem status interrupt */
	}
    else
        pChan->ier &= ~IER_EMSI; /* disable modem status interrupt */ 

    oldlevel = intLock ();

    REG(LCR, pChan) = pChan->lcr;
    REG(MCR, pChan) = pChan->mcr;

    /* now reset the channel mode registers */

    REG(FCR, pChan) = (RxCLEAR | TxCLEAR | FIFO_ENABLE);

    if (options & CREAD)  
	pChan->ier |= RxFIFO_BIT;

    if (pChan->channelMode == SIO_MODE_INT)
	{
        REG(IER, pChan) = pChan->ier;
        }

    intUnlock (oldlevel);

    pChan->options = options;

    return OK;
    }

/*******************************************************************************
*
* ns16550Hup - hang up the modem control lines 
*
* Resets the RTS and DTR signals and clears both the receiver and
* transmitter sections.
*
* RETURNS: OK
*/

LOCAL STATUS ns16550Hup
    (
    NS16550_CHAN * pChan 	/* pointer to channel */
    )
    {
    FAST int     oldlevel;	/* current interrupt level mask */

    oldlevel = intLock ();

    pChan->mcr &= (~(MCR_RTS | MCR_DTR));
    REG(MCR, pChan) = pChan->mcr;
    REG(FCR, pChan) = (RxCLEAR | TxCLEAR); 

    intUnlock (oldlevel);

    return (OK);

    }    

/*******************************************************************************
*
* ns16550Open - Set the modem control lines 
*
* Set the modem control lines(RTS, DTR) TRUE if not already set.  
* It also clears the receiver, transmitter and enables the fifo. 
*
* RETURNS: OK
*/

LOCAL STATUS ns16550Open
    (
    NS16550_CHAN * pChan 	/* pointer to channel */
    )
    {
    FAST int     oldlevel;	/* current interrupt level mask */
    char mask;

    mask = REG(MCR, pChan) & (MCR_RTS | MCR_DTR);

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

    	oldlevel = intLock ();

	/* set RTS and DTR TRUE */

    	pChan->mcr |= (MCR_DTR | MCR_RTS); 
    	REG(MCR, pChan) = pChan->mcr; 

    	/* clear Tx and receive and enable FIFO */

        REG(FCR, pChan) = (RxCLEAR | TxCLEAR | FIFO_ENABLE);

    	intUnlock (oldlevel);
	}

    return (OK);
    }

/******************************************************************************
*
* ns16550BaudSet - change baud rate for channel
*
* This routine sets the baud rate for the UART. The interrupts are disabled
* during chip access.
*
* RETURNS: OK
*/

LOCAL STATUS  ns16550BaudSet
    (
    NS16550_CHAN * pChan,	/* pointer to channel */
    UINT	   baud		/* requested baud rate */
    )
    {
    int   oldlevel;
    int   divisor = ((pChan->xtal + (8 * baud)) / (16 * baud));

    /* disable interrupts during chip access */

    oldlevel = intLock ();

    /* Enable access to the divisor latches by setting DLAB in LCR. */

    REG(LCR, pChan) = LCR_DLAB | pChan->lcr;

    /* Set divisor latches. */

    REG(DLL,pChan) = divisor;
    REG(DLM,pChan) = (divisor >> 8);

    /* Restore line control register */

    REG(LCR, pChan) = pChan->lcr;

    pChan->baudRate = baud;
 
    intUnlock (oldlevel);

    return (OK);
    }

/*******************************************************************************
*
* ns16550ModeSet - 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 ns16550ModeSet
    (
    NS16550_CHAN * pChan,	/* pointer to channel */
    UINT	newMode		/* mode requested */
    )
    {
    FAST int     oldlevel;	/* current interrupt level mask */
    char mask;

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

    if (newMode == SIO_MODE_INT)
	{
        /* Enable appropriate interrupts */

⌨️ 快捷键说明

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