📄 s3c2510sio.c
字号:
/* s3c2510Sio.c - SAMSUNG S3C2510 UART controller driver */
/* Copyright 2002 SAMSUNG ELECTRONICS */
/*
modification history
--------------------
01a,08feb02,jmLee created.
*/
#include "vxWorks.h"
#include "intLib.h"
#include "errno.h"
#include "drv/multi/s3c2510.h"
#include "config.h"
#include "drv/intrCtl/s3c2510Intr.h"
#include "drv/sio/s3c2510Sio.h"
#define DEFAULT_BAUD 9600
/* Local Forward Declarations */
LOCAL STATUS s3c2510SioDummyCallback(void);
LOCAL int s3c2510SioBaudSet(S3C2510_SIO_CHAN *pChan, int baudRate);
LOCAL int s3c2510SioOptsSet(S3C2510_SIO_CHAN *pChan, int options);
LOCAL int s3c2510SioModeSet(S3C2510_SIO_CHAN *pChan, int sioMode);
LOCAL int s3c2510SioOpen(S3C2510_SIO_CHAN *pChan);
LOCAL int s3c2510SioHup(S3C2510_SIO_CHAN *pChan);
LOCAL int s3c2510SioIoctl(SIO_CHAN *pSioChan, int cmd, void* arg);
LOCAL int s3c2510SioTxStartup(SIO_CHAN *pSioChan);
LOCAL int s3c2510SioCallbackInstall(SIO_CHAN *pSioChan, int callbackType, STATUS(*callback)(), void *callbackArg);
LOCAL int s3c2510SioPollInput(SIO_CHAN *pSioChan, char *inChar);
LOCAL int s3c2510SioPollOutput(SIO_CHAN *pSioChan, char outChar);
/* Driver Function Table */
LOCAL SIO_DRV_FUNCS s3c2510SioDrvFuncs = {
s3c2510SioIoctl,
s3c2510SioTxStartup,
s3c2510SioCallbackInstall,
s3c2510SioPollInput,
s3c2510SioPollOutput
};
/******************************************************************************
*
* s3c2510SioDevInit - initialize a UART
*
* This routine is called to initialize the chip to a quiescent state. Note that
* the `ch' field of S3C2510_CHAN must be less than or equal to the maximum
* number of UART channels to configure as SIOs, as defined in s3c2510.h
*
* RETURNS: N/A
*/
void s3c2510SioDevInit(
S3C2510_SIO_CHAN *pChan /* device to initialize */
)
{
/* Enable peripheral clock. */
*S3C2510_PCLKDIS &= ~(S3C2510_PCLKDIS_CUART << pChan->ch);
/* Reset UART Status Register. */
*S3C2510_USTAT(pChan->ch) = 0xffffffff;
/* Initialize each channel's structure. */
pChan->pDrvFuncs = &s3c2510SioDrvFuncs;
pChan->getTxChar = s3c2510SioDummyCallback;
pChan->putRcvChar = s3c2510SioDummyCallback;
s3c2510SioBaudSet(pChan, DEFAULT_BAUD);
s3c2510SioOptsSet(pChan, CREAD | CS8);
s3c2510SioModeSet(pChan, SIO_MODE_POLL);
}
/******************************************************************************
*
* s3c2510SioDevInit2 - initialize a UART, part 2
*
* This routine is called by the BSP after interrupts have been connected. The
* driver can now operate in interrupt mode. Before this routine is called only
* polled mode operations should be allowed.
*
* RETURNS: N/A
*/
void s3c2510SioDevInit2(
S3C2510_SIO_CHAN *pChan /* device to initialize */
)
{
}
/*******************************************************************************
*
* s3c2510SioIoctl - special device control
*
* This routine handles the IOCTL messages from the user. It supports commands
* to get/set baud rate, mode(INT,POLL), hardware options(parity, number of data
* bits) and modem control(RTS/CTS and DTR/DSR handshakes). The ioctl commands
* SIO_HUP and SIO_OPEN are used to implement the HUPCL(hang up on last close)
* function.
*
* As on a UNIX system, requesting a baud rate of zero is translated into a
* hangup request. The DTR and RTS lines are dropped. This should cause a
* connected modem to drop the connection. The SIO_HUP command will only hangup
* if the HUPCL option is active. The SIO_OPEN function will raise DTR and RTS
* lines whenever it is called. Use the BAUD_RATE=0 function to hangup when HUPCL
* is not active.
*
* The CLOCAL option will disable hardware flow control. When selected, hardware
* flow control is not used. When not selected hardware flow control is based on
* the RTS/CTS signals. CTS is the clear to send input from the other end. It
* must be true for this end to begin sending new characters. In most drivers,
* the RTS signal will be assumed to be connected to the opposite end's CTS
* signal and can be used to control output from the other end. Raising RTS
* asserts CTS at the other end and the other end can send data. Lowering RTS
* de-asserts CTS and the other end will stop sending data. (This is non-EIA
* defined use of RTS).
*
* RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed request.
*/
LOCAL int s3c2510SioIoctl(
SIO_CHAN *pSioChan, /* device to control */
int cmd, /* request code */
void *arg /* some argument */
)
{
S3C2510_SIO_CHAN *pChan = (S3C2510_SIO_CHAN *)pSioChan;
int status = OK;
int lockKey;
switch (cmd)
{
/* Set the baud rate. */
case SIO_BAUD_SET:
/* Disable interrupts during chip access. */
lockKey = intLock();
status = s3c2510SioBaudSet(pChan, (int)arg);
/* Enable interrupts after chip access. */
intUnlock(lockKey);
break;
/* Get the baud rate. */
case SIO_BAUD_GET:
*(int *)arg = pChan->baudRate;
break;
/* Set the hardware options (as defined in sioLib.h). */
case SIO_HW_OPTS_SET:
/* Disable interrupts during chip access. */
lockKey = intLock();
status = s3c2510SioOptsSet(pChan, (int)arg);
/* Enable interrupts after chip access. */
intUnlock(lockKey);
break;
/* Get the hardware options (as defined in sioLib.h). */
case SIO_HW_OPTS_GET:
*(int *)arg = pChan->options;
break;
/* Set the mode (e.g., to interrupt or polled). */
case SIO_MODE_SET:
/* Disable interrupts during chip access. */
lockKey = intLock();
status = s3c2510SioModeSet(pChan, (int)arg);
/* Enable interrupts after chip access. */
intUnlock(lockKey);
break;
/* Get the current mode. */
case SIO_MODE_GET:
*(int *)arg = pChan->sioMode;
break;
/* Get the available modes. */
case SIO_AVAIL_MODES_GET:
*(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
break;
case SIO_OPEN:
status = s3c2510SioOpen(pChan);
break;
case SIO_HUP:
status = s3c2510SioHup(pChan);
break;
default:
status = ENOSYS;
}
return (status);
}
/******************************************************************************
*
* s3c2510SioTxStartup - start the interrupt transmitter
*
* RETURNS: OK on success, ENOSYS if the device is polled-only, or EIO on
* hardware error.
*/
LOCAL int s3c2510SioTxStartup(
SIO_CHAN *pSioChan /* device to start */
)
{
S3C2510_SIO_CHAN *pChan = (S3C2510_SIO_CHAN *)pSioChan;
if (pChan->sioMode != SIO_MODE_INT) /* polling mode */
{
return ENOSYS;
}
/* Enable Transmit Holding Register Empty Interrupt. */
*S3C2510_UINT(pChan->ch) |= S3C2510_UINT_THEIE;
return OK;
}
/******************************************************************************
*
* s3c2510SioCallbackInstall - install ISR callbacks to get/put chars
*
* This driver allows interrupt callbacks for transmitting characters and
* receiving characters. In general, drivers may support other types of callbacks
* too.
*
* RETURNS: OK on success, or ENOSYS for an unsupported callback type.
*/
LOCAL int s3c2510SioCallbackInstall(
SIO_CHAN *pSioChan, /* device */
int callbackType, /* type of callback */
STATUS (*callback)(), /* callback */
void* callbackArg /* parameter to callback */
)
{
S3C2510_SIO_CHAN *pChan = (S3C2510_SIO_CHAN *)pSioChan;
switch (callbackType)
{
case SIO_CALLBACK_GET_TX_CHAR:
pChan->getTxChar = callback;
pChan->getTxArg = callbackArg;
break;
case SIO_CALLBACK_PUT_RCV_CHAR:
pChan->putRcvChar = callback;
pChan->putRcvArg = callbackArg;
break;
default:
return ENOSYS;
}
return OK;
}
/******************************************************************************
*
* s3c2510SioPollInput - poll the device for input
*
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN if the input
* buffer if empty, ENOSYS if the device is interrupt-only.
*/
LOCAL int s3c2510SioPollInput(
SIO_CHAN *pSioChan, /* device to poll */
char *inChar /* buffer to receive char */
)
{
S3C2510_SIO_CHAN *pChan = (S3C2510_SIO_CHAN *)pSioChan;
UINT32 stat;
stat = *S3C2510_USTAT(pChan->ch);
/* If no valid data present, retry later. */
if (!(stat & S3C2510_USTAT_RDV)) /* Receive Data Valid */
{
return EAGAIN;
}
/* Read character from Receive Data Register. */
*inChar = (char)*S3C2510_URXBUF(pChan->ch);
return OK;
}
/*******************************************************************************
*
* s3c2510SioPollOutput - output a character in polled mode
*
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN if the output
* buffer if full. ENOSYS if the device is interrupt-only.
*/
LOCAL int s3c2510SioPollOutput(
SIO_CHAN *pSioChan, /* device to poll */
char outChar /* char to transmit */
)
{
S3C2510_SIO_CHAN *pChan = (S3C2510_SIO_CHAN *)pSioChan;
UINT32 stat;
stat = *S3C2510_USTAT(pChan->ch);
if (!(stat & S3C2510_USTAT_THE)) /* Transmit Holding Register Empty */
{
return EAGAIN;
}
/* Write char to Transmit Data Register. */
*S3C2510_UTXBUF(pChan->ch) = (VUINT8)outChar;
return OK;
}
/*******************************************************************************
*
* s3c2510SioIntRx - handle a receive interrupt
*
* This routine handles read interrupts from the UART.
*
* RETURNS: NA
*/
void s3c2510SioIntRx(
S3C2510_SIO_CHAN *pChan /* device caused Rx interrupt */
)
{
int ch = pChan->ch;
UINT32 stat;
char inChar;
stat = *S3C2510_USTAT(ch);
if (stat & (S3C2510_USTAT_OER | /* Overrun Error */
S3C2510_USTAT_PER | /* Parity Error */
S3C2510_USTAT_FER)) /* Frame Error */
{
/* Clear bits. */
*S3C2510_USTAT(ch) |= (S3C2510_USTAT_OER |
S3C2510_USTAT_PER |
S3C2510_USTAT_FER);
#ifdef INCLUDE_LED
LED_ON(LED8_MASK);
#endif /* INCLUDE_LED */
return;
}
if (ch == 0) /* console UART */
{
if (stat & S3C2510_USTAT_RDV) /* Receive Data Valid */
{
/* Read character from Receive Data Register. */
inChar = (char)*S3C2510_URXBUF(ch);
/* Call callback routine. */
(*pChan->putRcvChar)(pChan->putRcvArg, inChar);
}
#ifdef INCLUDE_LED
else
{
LED_ON(LED6_MASK);
}
#endif /* INCLUDE_LED */
}
else /* high-speed UART */
{
if (stat & S3C2510_HUSTAT_RFREA) /* Receive FIFO Trigger Level Reached */
{
UINT32 cnt, i;
switch (*S3C2510_UCON(ch) & S3C2510_HUCON_RFTL_MASK)
{
case S3C2510_HUCON_RFTL_8:
cnt = 8;
break;
case S3C2510_HUCON_RFTL_18:
cnt = 18;
break;
case S3C2510_HUCON_RFTL_28:
cnt = 28;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -