📄 i8250sio.c
字号:
/* 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 + -