www.pudn.com > S3c2410bsp.zip > s3c2410xSio.c
/* s3c2410xSio.c - Samsung S3C2410X serial driver */
#include "copyright_wrs.h"
#include "vxWorks.h"
#include "sioLib.h"
#include "intLib.h"
#include "errno.h"
#include "s3c2410xSio.h"
#include "ioLib.h"
#define S3C2410X_BAUD_MIN 1200
#define S3C2410X_BAUD_MAX 460860
#define S3C2410X_SIO_DEFAULT_BAUD 9600
#ifndef s3c2410x_UART_REG
#define s3c2410x_UART_REG(pChan, reg) \
(*(volatile UINT32 *)((UINT32)(pChan)->regs + (reg)))
#endif
#ifndef S3C2410X_SIO_REG_READ
#define S3C2410X_SIO_REG_READ(pChan, reg, result) \
((result) = (*(volatile UINT32 *)((UINT32)(pChan)->regs + (reg))))
#endif
#ifndef S3C2410X_SIO_REG_WRITE
#define S3C2410X_SIO_REG_WRITE(pChan, reg, data) \
((*(volatile UINT32 *)((UINT32)(pChan)->regs + (reg))) = (data))
#endif
#ifndef s3c2410x_UART_REG_READ
#define s3c2410x_UART_REG_READ(pChan, reg, result) \
(result) = (s3c2410x_UART_REG(pChan, reg))
#endif
#ifndef s3c2410x_UART_REG_WRITE
#define s3c2410x_UART_REG_WRITE(pChan, reg, data) \
(s3c2410x_UART_REG(pChan, reg)) = (data)
#endif
#ifndef s3c2410x_UART_REG_BIT_SET
#define s3c2410x_UART_REG_BIT_SET(pChan, reg, data) \
(s3c2410x_UART_REG(pChan, reg)) |= (data)
#endif
#ifndef s3c2410x_UART_REG_BIT_CLR
#define s3c2410x_UART_REG_BIT_CLR(pChan, reg, data) \
(s3c2410x_UART_REG(pChan, reg)) &= ~(data)
#endif
#ifndef s3c2410x_INT_REG_READ
#define s3c2410x_INT_REG_READ(reg,result) \
((result) = *(volatile UINT32 *)(reg))
#endif
#ifndef s3c2410x_INT_REG_WRITE
#define s3c2410x_INT_REG_WRITE(reg,data) \
(*((volatile UINT32 *)(reg)) = (data))
#endif
#define _IS_USER_FIFO_
/* for backward compatibility */
#ifndef SIO_HUP
# define SIO_OPEN 0x100A
# define SIO_HUP 0x100B
#endif
LOCAL int s3c2410xTxStartup (SIO_CHAN * pSioChan);
LOCAL int s3c2410xCallbackInstall (SIO_CHAN *pSioChan, int callbackType,
STATUS (*callback)(), void *callbackArg);
LOCAL int s3c2410xPollOutput (SIO_CHAN *pSioChan, char outChar);
LOCAL int s3c2410xPollInput (SIO_CHAN *pSioChan, char *thisChar);
LOCAL int s3c2410xIoctl (SIO_CHAN *pSioChan, int request, void *arg);
LOCAL STATUS dummyCallback (void);
/* local variables */
LOCAL SIO_DRV_FUNCS s3c2410xSioDrvFuncs =
{
s3c2410xIoctl,
s3c2410xTxStartup,
s3c2410xCallbackInstall,
s3c2410xPollInput,
s3c2410xPollOutput
};
LOCAL BOOL s3c2410xIntrMode = FALSE;
/******************************************************************************
*
* s3c2410xDevInit - initialize a S3C2410X_DUSART
*
*
* RETURNS: N/A
*/
void s3c2410xDevInit(S3C2410X_CHAN * pChan)
{
pChan->sio.pDrvFuncs = &s3c2410xSioDrvFuncs;
pChan->getTxChar = dummyCallback;
pChan->putRcvChar = dummyCallback;
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_ULCON,(INFRA_RED_NONE | PARITY_NONE | ONE_STOP | WORD_LEN));
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UCON,0x005);
#ifdef _IS_USER_FIFO_
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UFCON,0xd7);
#else
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UFCON,0x00);
#endif
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UMCON,0);
s3c2410xIoctl ((SIO_CHAN *)pChan, SIO_MODE_SET, (void *)SIO_MODE_POLL);
s3c2410xIoctl ((SIO_CHAN *)pChan, SIO_BAUD_SET, (void *)S3C2410X_SIO_DEFAULT_BAUD);
}
/******************************************************************************
*
* s3c2410xDevInit2 - initialize a S3C2410X_DUSART, part 2
*
*
* RETURNS: N/A
* ARGSUSED
*/
void s3c2410xDevInit2
(
S3C2410X_CHAN * pChan /* device to initialize */
)
{
char outchar = '\0';
UINT32 tempUINT32;
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_ULCON,(INFRA_RED_NONE | PARITY_NONE | ONE_STOP | WORD_LEN));
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UTXBUF,outchar);
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UCON,UCON_RX|UCON_TX|0x80);
s3c2410x_INT_REG_READ(S3C2410X_INTSUBMSK,tempUINT32);
switch((int)(pChan->regs))
{
case SERIAL_B_BASE_ADR:
tempUINT32 &= ~((1<regs))
{
case SERIAL_B_BASE_ADR:
s3c2410x_INT_REG_WRITE(S3C2410X_SUBSRCPND, (1<putRcvChar) (pChan->putRcvArg, inChar);
}
#else
S3C2410X_SIO_REG_READ(pChan,S3C2410X_USTAT, status);
if((status & USTAT_RX_READY) == USTAT_RX_READY)
{
S3C2410X_SIO_REG_READ(pChan,S3C2410X_URXBUF, inChar);
(*pChan->putRcvChar) (pChan->putRcvArg, inChar);
}
#endif
}
static int sending = 0;
/******************************************************************************
*
* s3c2410xIntTx - handle a channels transmitter-ready interrupt
*
* RETURNS: N/A
*/
void s3c2410xIntTx
(
S3C2410X_CHAN * pChan /* channel generating the interrupt */
)
{
char outChar;
UINT32 status;
FAST int oldlevel;
switch((int)(pChan->regs))
{
case SERIAL_B_BASE_ADR:
s3c2410x_INT_REG_WRITE(S3C2410X_SUBSRCPND, (1<getTxChar) (pChan->getTxArg, &outChar) != ERROR)
{
#ifdef _IS_USER_FIFO_
S3C2410X_SIO_REG_WRITE(pChan, S3C2410X_UTXBUF, outChar);
while(1)
{
S3C2410X_SIO_REG_READ(pChan,S3C2410X_UFSTAT, status);
if((status & UFSTAT_TX_FULL) == UFSTAT_TX_FULL)
break;
if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) == ERROR)
break;
S3C2410X_SIO_REG_WRITE(pChan, S3C2410X_UTXBUF, outChar);
}
#else
S3C2410X_SIO_REG_WRITE(pChan, S3C2410X_UTXBUF, outChar);
#endif
}
intUnlock (oldlevel);
}
/********************
************************/
void s3c2410xInt (S3C2410X_CHAN *pChan)
{
UINT32 intId;
s3c2410x_INT_REG_READ(S3C2410X_SUBSRCPND , intId);
if(intId & ((1<mode == SIO_MODE_INT)
{
intEnable(pChan->intLevelTx);
s3c2410xIntTx(pChan);
return OK;
}
else
{
return ERROR;
}
}
/******************************************************************************
*
* s3c2410xCallbackInstall - install ISR callbacks to get/put chars
*
*
* RETURNS: OK on success, or ENOSYS for an unsupported callback type.
*/
LOCAL int s3c2410xCallbackInstall
(
SIO_CHAN * pSioChan,
int callbackType,
STATUS (*callback)(),
void * callbackArg
)
{
S3C2410X_CHAN * pChan = (S3C2410X_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);
}
}
/*******************************************************************************
*
* s3c2410xPollOutput - 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 s3c2410xPollOutput
(
SIO_CHAN *pSioChan,
char outChar
)
{
S3C2410X_CHAN * pChan = (S3C2410X_CHAN *)pSioChan;
UINT32 status;
S3C2410X_SIO_REG_READ (pChan, S3C2410X_USTAT, status);
if ((status & USTAT_TX_READY) == 0x00)
return (EAGAIN);
S3C2410X_SIO_REG_WRITE(pChan, S3C2410X_UTXBUF, outChar);
return (OK);
}
/******************************************************************************
*
* s3c2410xPollInput - 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 s3c2410xPollInput
(
SIO_CHAN * pSioChan,
char * thisChar
)
{
S3C2410X_CHAN * pChan = (S3C2410X_CHAN *)pSioChan;
UINT32 status;
S3C2410X_SIO_REG_READ (pChan,S3C2410X_USTAT, status);
if ((status & USTAT_RX_AVAIL) == 0x00)
return (EAGAIN);
S3C2410X_SIO_REG_READ(pChan, S3C2410X_URXBUF, *thisChar);
return (OK);
}
/******************************************************************************
*
* s3c2410xModeSet - toggle between interrupt and polled mode
*
* RETURNS: OK on success, EIO on unsupported mode.
*/
LOCAL int s3c2410xModeSet
(
S3C2410X_CHAN * pChan, /* channel */
uint_t newMode /* new mode */
)
{
UINT32 temp;
UINT32 tempUINT32;
if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT))
return (EIO);
if ((newMode == SIO_MODE_INT) && (!s3c2410xIntrMode))
return (EIO);
pChan->mode = newMode;
if (pChan->mode == SIO_MODE_INT)
{
switch((int)(pChan->regs))
{
case SERIAL_B_BASE_ADR:
s3c2410x_INT_REG_WRITE(S3C2410X_SUBSRCPND, ((1<intLevelRx);
S3C2410X_SIO_REG_READ(pChan, S3C2410X_UCON, temp);
temp &=UCON_RX_TX_RESET;
temp |= (UCON_RX|UCON_TX);
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UCON, temp);
s3c2410x_INT_REG_READ(S3C2410X_INTSUBMSK,tempUINT32);
switch((int)(pChan->regs))
{
case SERIAL_B_BASE_ADR:
tempUINT32 &= ~((1<intLevelRx);
s3c2410x_INT_REG_READ(S3C2410X_INTSUBMSK,tempUINT32);
switch((int)(pChan->regs))
{
case SERIAL_B_BASE_ADR:
tempUINT32 |= ((1<options == newOpts)
return OK;
switch (newOpts & CSIZE)
{
case CS5:
dataBits = 0x00; break;
case CS6:
dataBits = 0x01; break;
case CS7:
dataBits = 0x02; break;
case CS8:
default:
dataBits = 0x03; break;
}
if (newOpts & STOPB)
stopBits = 0x04;
else
stopBits = 0x00;
switch (newOpts & (PARENB|PARODD))
{
case PARENB|PARODD:
temp=PARITY_ODD;
break;
case PARENB:
temp=PARITY_EVEN;
break;
case PARODD:
break;
default:
case 0:
temp=PARITY_NONE ;/* no parity */
break;
}
if (newOpts & CLOCAL)
{
hdweFlowCtrl = FALSE;
}
if ((newOpts & CREAD) == 0)
rcvrEnable = FALSE;
lvl = intLock ();
S3C2410X_SIO_REG_READ(pChan, S3C2410X_ULCON, result);
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_ULCON,(result|dataBits|temp|stopBits));
intUnlock (lvl);
pChan->options = newOpts;
return (OK);
}
/*******************************************************************************
*
* s3c2410xIoctl - special device control
*
*
* RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed
* request.
*/
LOCAL int s3c2410xIoctl
(
SIO_CHAN * pSioChan, /* device to control */
int request, /* request code */
void * someArg /* some argument */
)
{
S3C2410X_CHAN *pChan = (S3C2410X_CHAN *) pSioChan;
int oldlevel; /* current interrupt level mask */
int arg = (int)someArg;
switch (request)
{
case SIO_BAUD_SET:
if (arg == 0)
return s3c2410xHup (pChan);
if (arg < S3C2410X_BAUD_MIN || arg > S3C2410X_BAUD_MAX)
{
return (EIO);
}
switch(arg)
{
case 1200:
oldlevel = intLock ();
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_1200|S3C2410X_CNT1_VAL);
intUnlock (oldlevel);
pChan->baudRate=arg;
return (OK);
case 2400:
oldlevel = intLock ();
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_2400|S3C2410X_CNT1_VAL);
intUnlock (oldlevel);
pChan->baudRate=arg;
return (OK);
case 4800:
oldlevel = intLock ();
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_4800|S3C2410X_CNT1_VAL);
intUnlock (oldlevel);
pChan->baudRate=arg;
return (OK);
case 9600:
oldlevel = intLock ();
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_9600|S3C2410X_CNT1_VAL);
intUnlock (oldlevel);
pChan->baudRate=arg;
return (OK);
case 19200:
oldlevel = intLock ();
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_19200|S3C2410X_CNT1_VAL);
intUnlock (oldlevel);
pChan->baudRate=arg;
return (OK);
case 38400:
oldlevel = intLock ();
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_38400|S3C2410X_CNT1_VAL);
intUnlock (oldlevel);
pChan->baudRate=arg;
return (OK);
case 57600:
oldlevel = intLock ();
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_57600|S3C2410X_CNT1_VAL);
intUnlock (oldlevel);
pChan->baudRate=arg;
return (OK);
case 115200:
oldlevel = intLock ();
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_115200|S3C2410X_CNT1_VAL);
intUnlock (oldlevel);
pChan->baudRate=arg;
return (OK);
case 230400:
oldlevel = intLock ();
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_230400|S3C2410X_CNT1_VAL);
intUnlock (oldlevel);
pChan->baudRate=arg;
return (OK);
case 460800:
oldlevel = intLock ();
S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_460800|S3C2410X_CNT1_VAL);
intUnlock (oldlevel);
pChan->baudRate=arg;
return (OK);
default:
return(EIO);
}
break;
case SIO_BAUD_GET:
*(int *)arg = pChan->baudRate;
break;
case SIO_MODE_SET:
return (s3c2410xModeSet (pChan, arg));
case SIO_MODE_GET:
*(int *)arg = pChan->mode;
return (OK);
case SIO_AVAIL_MODES_GET:
*(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
return (OK);
case SIO_HW_OPTS_SET:
return (s3c2410xOptSet (pChan, arg));
case SIO_HW_OPTS_GET:
*(int *)arg = pChan->options;
return (OK);
case SIO_HUP:
if (pChan->options & HUPCL)
return (s3c2410xHup (pChan));
return (OK);
case SIO_OPEN:
return (s3c2410xOpen (pChan));
default:
return (ENOSYS);
}
return (ENOSYS);
}
/*******************************************************************************
*
* dummyCallback - dummy callback routine
*
* RETURNS: ERROR.
*/
LOCAL STATUS dummyCallback (void)
{
return (ERROR);
}