📄 au1500sio.c
字号:
/* au1500Sio.c - Au1x00 UART tty driver */
/*
* This file has been developed or significantly modified by the
* MIPS Center of Excellence Dedicated Engineering Staff.
* This notice is as per the MIPS Center of Excellence Master Partner
* Agreement, do not remove this notice without checking first with
* WR/Platforms MIPS Center of Excellence engineering management.
*/
/* Copyright 1984-2001 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01b,12mar05,fhchen adopted from pb1500/au1000Sio.c
01a,16may02,ejd rewritten from ns16550Sio.c.
*/
/*
DESCRIPTION
This is the driver for the AU1x00 UART. This device includes a universal
asynchronous receiver/transmitter, a baud rate generator, and a complete
modem control capability.
A AUSIO_CHAN structure is used to describe the serial channel. This data
structure is defined in au1500Sio.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 AUSIO_CHAN structure and initializes all the values in the
structure (except the SIO_DRV_FUNCS) before calling auSioDevInit().
The BSP's sysHwInit2() routine typically calls sysSerialHwInit2(), which
connects the chips interrupts via intConnect() (either the single
interrupt `auSioInt' or the three interrupts `auSioIntWr',
auSioIntRd', and `auSioIntEx').
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.
*/
/* includes */
#include "vxWorks.h"
#include "intLib.h"
#include "errnoLib.h"
#include "errno.h"
#include "sioLib.h"
#include "au1500Sio.h"
/* local defines */
#ifndef SIO_HUP
# define SIO_OPEN 0x100A
# define SIO_HUP 0x100B
#endif
/* min/max baud rate - Arbitrary limits, depends on transceivers */
#define AU_UART_MIN_RATE 50
#define AU_UART_MAX_RATE 115200
/* static forward declarations */
LOCAL int auSioCallbackInstall (SIO_CHAN *, int, STATUS (*)(), void *);
LOCAL STATUS auSioBaudSet (AUSIO_CHAN *, UINT);
LOCAL STATUS auSioModeSet (AUSIO_CHAN *, UINT);
LOCAL STATUS auSioIoctl (AUSIO_CHAN *, int, int);
LOCAL void auSioTxStartup (AUSIO_CHAN *);
LOCAL int auSioPollOutput (AUSIO_CHAN *, char);
LOCAL int auSioPollInput (AUSIO_CHAN *, char *);
LOCAL STATUS auSioOptsSet (AUSIO_CHAN *, UINT);
LOCAL STATUS auSioOpen (AUSIO_CHAN * pChan );
LOCAL STATUS auSioHup (AUSIO_CHAN * pChan );
/* driver functions */
static SIO_DRV_FUNCS auSioDrvFuncs =
{
(int (*)())auSioIoctl,
(int (*)())auSioTxStartup,
(int (*)())auSioCallbackInstall,
(int (*)())auSioPollInput,
(int (*)(SIO_CHAN *,char))auSioPollOutput
};
/******************************************************************************
*
* auSioDummyCallback - dummy callback routine.
*/
LOCAL STATUS auSioDummyCallback (void)
{
return (ERROR);
}
/******************************************************************************
*
* auSioDevInit - intialize a UART 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(typically in sysSerialHwInit) all the device
* addresses, etc. in the AUSIO_CHAN structure.
*
* RETURNS: N/A
*/
void auSioDevInit
(
AUSIO_CHAN * pChan /* pointer to channel */
)
{
int oldlevel = intLock ();
AU1000_UART *regs = (AU1000_UART *)pChan->regs;
/* Enable UART module */
regs->uart_enable = UART_ENABLE_CE; /* enable clocks */
regs->uart_enable = UART_ENABLE_CE | UART_ENABLE_E; /* take away reset */
/* initialize the driver function pointers in the SIO_CHAN's */
pChan->pDrvFuncs = &auSioDrvFuncs;
/* set the non BSP-specific constants */
pChan->getTxChar = auSioDummyCallback;
pChan->putRcvChar = auSioDummyCallback;
pChan->channelMode = 0; /* initialized to undefined mode */
pChan->options = (CLOCAL | CREAD | CS8);
pChan->mcr = UART_MDMCTRL_I1;
pChan->ier = UART_INTEN_LIE; /* necessary for servicing Break */
/* set the requested baud rate */
auSioBaudSet(pChan, pChan->baudRate);
/* set the options */
auSioOptsSet(pChan, pChan->options);
intUnlock (oldlevel);
}
/*******************************************************************************
*
* auSioOptsSet - 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, other wise ERROR is returned
*/
LOCAL STATUS auSioOptsSet
(
AUSIO_CHAN * pChan, /* pointer to channel */
UINT options /* new hardware options */
)
{
FAST int oldlevel; /* current interrupt level mask */
AU1000_UART *regs = (AU1000_UART *)pChan->regs;
if (options & 0xffffff00)
return ERROR;
pChan->lcr = 0;
pChan->mcr &= ~(UART_MDMCTRL_RT | UART_MDMCTRL_DT); /* clear RTS and DTR bits */
/* word length */
switch (options & CSIZE)
{
case CS5:
pChan->lcr = UART_LINECTRL_WLS_5; break;
case CS6:
pChan->lcr = UART_LINECTRL_WLS_6; break;
case CS7:
pChan->lcr = UART_LINECTRL_WLS_7; break;
default:
case CS8:
pChan->lcr = UART_LINECTRL_WLS_8; break;
}
/* stop bit */
if (options & STOPB)
pChan->lcr |= UART_LINECTRL_ST;
else
pChan->lcr &= ~UART_LINECTRL_ST;
/* parity */
pChan->lcr &= ~(UART_LINECTRL_PAR | UART_LINECTRL_PE); /* no parity */
switch (options & (PARENB | PARODD))
{
case PARENB|PARODD:
pChan->lcr |= (UART_LINECTRL_PE | UART_LINECTRL_PAR_O);
break;
case PARENB:
pChan->lcr |= (UART_LINECTRL_PE | UART_LINECTRL_PAR_E);
break;
default:
break;
}
/* ensure interrupt disabled */
regs->uart_inten = 0;
/* modem status lines */
if (!(options & CLOCAL))
{
/* !clocal enables hardware flow control(DTR/DSR) */
pChan->mcr |= (UART_MDMCTRL_RT | UART_MDMCTRL_DT);
pChan->ier &= ~UART_INTEN_TIE; /* disable transmit interrupt */
pChan->ier |= UART_INTEN_MIE; /* enable modem status interrupt */
}
else
pChan->ier &= ~UART_INTEN_MIE; /* disable modem status interrupt */
oldlevel = intLock ();
regs->uart_linectrl = pChan->lcr;
regs->uart_mdmctrl = pChan->mcr;
/* reset tx/rx, enable 16 bytes tx/rx FIFO */
regs->uart_fifoctrl = UART_FIFOCTRL_RR | UART_FIFOCTRL_TR | UART_FIFOCTRL_FE;
/* receiver enabled? */
if (options & CREAD)
pChan->ier |= UART_INTEN_RIE;
/* SIO in interrupt mode? */
if (pChan->channelMode == SIO_MODE_INT)
{
regs->uart_inten = pChan->ier;
}
intUnlock (oldlevel);
pChan->options = options;
return OK;
}
/*******************************************************************************
*
* auSioHup - hang up the modem control lines
*
* Resets the RTS and DTR signals and clears both the receiver and
* transmitter sections.
*
* RETURNS: OK
*/
LOCAL STATUS auSioHup
(
AUSIO_CHAN * pChan /* pointer to channel */
)
{
FAST int oldlevel; /* current interrupt level mask */
AU1000_UART *regs = (AU1000_UART *)pChan->regs;
oldlevel = intLock ();
pChan->mcr &= ~(UART_MDMCTRL_RT | UART_MDMCTRL_DT);
regs->uart_mdmctrl = pChan->mcr;
regs->uart_fifoctrl = UART_FIFOCTRL_TR | UART_FIFOCTRL_RR;
intUnlock (oldlevel);
return (OK);
}
/*******************************************************************************
*
* auSioOpen - 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 auSioOpen
(
AUSIO_CHAN * pChan /* pointer to channel */
)
{
FAST int oldlevel; /* current interrupt level mask */
char mask;
AU1000_UART *regs = (AU1000_UART *)pChan->regs;
mask = regs->uart_mdmctrl & (UART_MDMCTRL_RT | UART_MDMCTRL_DT);
if (mask != (UART_MDMCTRL_RT | UART_MDMCTRL_DT))
{
/* RTS and DTR not set yet */
oldlevel = intLock ();
/* set RTS and DTR TRUE */
pChan->mcr |= (UART_MDMCTRL_RT | UART_MDMCTRL_DT);
regs->uart_mdmctrl = pChan->mcr;
/* clear Tx and receive and enable FIFO */
regs->uart_fifoctrl = UART_FIFOCTRL_RR | UART_FIFOCTRL_TR | UART_FIFOCTRL_FE;
intUnlock (oldlevel);
}
return (OK);
}
/******************************************************************************
*
* auSioBaudSet - change baud rate for channel
*
* This routine sets the baud rate for the UART. The interrupts are disabled
* during chip access.
*
* NOTE:
* - Baudrate = CPU / (SD * 2 * CLKDIV * 16)
*
* RETURNS: OK
*/
LOCAL STATUS auSioBaudSet
(
AUSIO_CHAN * pChan, /* pointer to channel */
UINT baud /* requested baud rate */
)
{
int oldlevel;
int divisor = ((pChan->xtal + (8 * baud)) / (16 * baud));
AU1000_UART *regs = (AU1000_UART *)pChan->regs;
/* disable interrupts during chip access */
oldlevel = intLock ();
/* set clkdiv to use new baud rate */
regs->uart_clkdiv = divisor;
pChan->baudRate = baud;
intUnlock (oldlevel);
return (OK);
}
/*******************************************************************************
*
* auSioModeSet - 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 auSioModeSet
(
AUSIO_CHAN * pChan, /* pointer to channel */
UINT newMode /* mode requested */
)
{
FAST int oldlevel; /* current interrupt level mask */
char mask;
AU1000_UART *regs = pChan->regs;
if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT))
return (ERROR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -