📄 s3c2410sio.c
字号:
/* primeCellSio.c - ARM AMBA UART tty driver */
/* Copyright 1997-2000 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
*/
/*
DESCRIPTION
*/
#include "vxWorks.h"
#include "intLib.h"
#include "errnoLib.h"
#include "errno.h"
#include "sioLib.h"
#include "s3c2410Sio.h"
/* local defines */
#ifndef AMBA_UART_REG
#define AMBA_UART_REG(pChan, reg) \
(*(volatile UINT32 *)((UINT32)(pChan)->regs + (reg)))
#endif
#ifndef AMBA_UART_REG_READ
#define AMBA_UART_REG_READ(pChan, reg, result) \
(result) = (AMBA_UART_REG(pChan, reg))
#endif
#ifndef AMBA_UART_REG_WRITE
#define AMBA_UART_REG_WRITE(pChan, reg, data) \
(AMBA_UART_REG(pChan, reg)) = (data)
#endif
#ifndef AMBA_UART_REG_BIT_SET
#define AMBA_UART_REG_BIT_SET(pChan, reg, data) \
(AMBA_UART_REG(pChan, reg)) |= (data)
#endif
#ifndef AMBA_UART_REG_BIT_CLR
#define AMBA_UART_REG_BIT_CLR(pChan, reg, data) \
(AMBA_UART_REG(pChan, reg)) &= ~(data)
#endif
/* locals */
/* function prototypes */
LOCAL STATUS ambaDummyCallback (void);
LOCAL void ambaInitChannel (AMBA_CHAN * pChan);
LOCAL STATUS ambaIoctl (SIO_CHAN * pSioChan, int request, int arg);
LOCAL int ambaTxStartup (SIO_CHAN * pSioChan);
LOCAL int ambaCallbackInstall (SIO_CHAN * pSioChan, int callbackType,
STATUS (*callback)(), void * callbackArg);
LOCAL int ambaPollInput (SIO_CHAN * pSioChan, char *);
LOCAL int ambaPollOutput (SIO_CHAN * pSioChan, char);
/* driver functions */
LOCAL SIO_DRV_FUNCS ambaSioDrvFuncs =
{
(int (*)())ambaIoctl,
ambaTxStartup,
ambaCallbackInstall,
ambaPollInput,
ambaPollOutput
};
/*******************************************************************************
*
* ambaDummyCallback - dummy callback routine.
*
* RETURNS: ERROR, always.
*/
LOCAL STATUS ambaDummyCallback (void)
{
return ERROR;
}
/*******************************************************************************
*
* primeCellSioDevInit - initialise an AMBA channel
*
* This routine initialises some SIO_CHAN function pointers and then resets
* the chip to a quiescent state. Before this routine is called, the BSP
* must already have initialised all the device addresses, etc. in the
* AMBA_CHAN structure.
*
* RETURNS: N/A
*/
void primeCellSioDevInit
(
AMBA_CHAN * pChan /* ptr to AMBA_CHAN describing this channel */
)
{
int oldlevel = intLock();
/* initialise the driver function pointers in the SIO_CHAN */
pChan->sio.pDrvFuncs = &ambaSioDrvFuncs;
/* set the non BSP-specific constants */
pChan->getTxChar = ambaDummyCallback;
pChan->putRcvChar = ambaDummyCallback;
pChan->channelMode = SIO_MODE_POLL;
/* initialise the chip */
ambaInitChannel (pChan);
intUnlock (oldlevel);
}
/*******************************************************************************
*
* ambaInitChannel - initialise UART
*
* This routine performs hardware initialisation of the UART channel.
*
* RETURNS: N/A
*/
LOCAL void ambaInitChannel
(
AMBA_CHAN * pChan /* ptr to AMBA_CHAN describing this channel */
)
{
int i;
UINT32 discard;
AMBA_UART_REG_WRITE(pChan, UART_FIFO_CON, 0x00);
AMBA_UART_REG_WRITE(pChan, UART_MODEM_CON, 0x00);
/*Line control register : Normal,No parity,1 stop,8 bits*/
AMBA_UART_REG_WRITE(pChan, UART_LINE_CON, 0x03);
/*
// [10] [9] [8] [7] [6] [5] [4] [3:2] [1:0]
// Clock Sel, Tx Int, Rx Int, Rx Time Out, Rx err, Loop-back, Send break, Transmit Mode, Receive Mode
// 0 1 0 , 0 1 0 0 , 01 01
// PCLK Level Pulse Disable Generate Normal Normal Interrupt or Polling
*/
AMBA_UART_REG_WRITE(pChan, UART_CON, 0x245); /* Control register */
/*ambaIoctl ((SIO_CHAN *)pChan, SIO_BAUD_SET, (void *)pChan->baudRate); */
AMBA_UART_REG_WRITE(pChan, UART_BAUD_DIV, (pChan->xtal / (16 * pChan->baudRate) - 1) );
/*( (int)(pclk/16./baud) -1 )); //Baud rate divisior register 0 */
AMBA_UART_REG_WRITE(pChan, UART_TX_DATA, '\r');
AMBA_UART_REG_WRITE(pChan, UART_TX_DATA, '\n');
AMBA_UART_REG_WRITE(pChan, UART_TX_DATA, 'H');
AMBA_UART_REG_WRITE(pChan, UART_TX_DATA, 'E');
AMBA_UART_REG_WRITE(pChan, UART_TX_DATA, 'L');
AMBA_UART_REG_WRITE(pChan, UART_TX_DATA, 'L');
AMBA_UART_REG_WRITE(pChan, UART_TX_DATA, 'O');
/* Clear Rx FIFO */
for(i=0;i<16;i++)
AMBA_UART_REG_READ(pChan, UART_RX_DATA, discard);
ambaIoctl ((SIO_CHAN *)pChan, SIO_MODE_SET, (int)pChan->channelMode);
}
/*******************************************************************************
*
* ambaIoctl - special device control
*
* This routine handles the IOCTL messages from the user.
*
* RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed
* request.
*/
LOCAL STATUS ambaIoctl
(
SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
int request, /* request code */
int arg /* some argument */
)
{
int oldlevel; /* current interrupt level mask */
STATUS status; /* status to return */
UINT32 brd; /* baud rate divisor */
AMBA_CHAN * pChan = (AMBA_CHAN *)pSioChan;
status = OK; /* preset to return OK */
switch (request)
{
case SIO_BAUD_SET:
/*
* Set the baud rate. Return EIO for an invalid baud rate, or
* OK on success.
*/
/*
* baudrate divisor must be non-zero and must fit in a 12-bit
* register.
*/
brd = (pChan->xtal/(16*arg)) - 1; /* calculate baudrate divisor */
/* disable interrupts during chip access */
oldlevel = intLock ();
/* Set baud rate divisor in UART */
AMBA_UART_REG_WRITE(pChan, UART_BAUD_DIV, brd );
pChan->baudRate = arg;
intUnlock (oldlevel);
break;
case SIO_BAUD_GET:
/* Get the baud rate and return OK */
*(int *)arg = pChan->baudRate;
break;
case SIO_MODE_SET:
/*
* Set the mode (e.g., to interrupt or polled). Return OK
* or EIO for an unknown or unsupported mode.
*/
if ((arg != SIO_MODE_POLL) && (arg != SIO_MODE_INT))
{
status = EIO;
break;
}
oldlevel = intLock ();
if (arg == SIO_MODE_INT)
{
/* Enable appropriate interrupts. */
AMBA_UART_REG_WRITE(pChan, UART_FIFO_CON, 0x00);
intEnable (pChan->levelRx);
*(volatile UINT32 *)((UINT32)(S3C2410_INTSUBMSK)) &= ~pChan->intRxSubMask;
}
else
{
/* Disable all interrupts for this UART. */
intDisable (pChan->levelRx);
*(volatile UINT32 *)((UINT32)(S3C2410_INTSUBMSK)) |=
(pChan->intTxSubMask|pChan->intRxSubMask);
}
pChan->channelMode = arg;
intUnlock (oldlevel);
break;
case SIO_MODE_GET:
/* Get the current mode and return OK */
*(int *)arg = pChan->channelMode;
break;
case SIO_AVAIL_MODES_GET:
/* Get the available modes and return OK */
*(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
break;
case SIO_HW_OPTS_SET:
/*
* Optional command to set the hardware options (as defined
* in sioLib.h).
* Return OK, or ENOSYS if this command is not implemented.
* Note: several hardware options are specified at once.
* This routine should set as many as it can and then return
* OK. The SIO_HW_OPTS_GET is used to find out which options
* were actually set.
*/
case SIO_HW_OPTS_GET:
/*
* Optional command to get the hardware options (as defined
* in sioLib.h). Return OK or ENOSYS if this command is not
* implemented. Note: if this command is unimplemented, it
* will be assumed that the driver options are CREAD | CS8
* (e.g., eight data bits, one stop bit, no parity, ints enabled).
*/
default:
status = ENOSYS;
}
return status;
}
/*******************************************************************************
*
* primeCellSioIntTx - handle a transmitter interrupt
*
* This routine handles write interrupts from the UART.
*
* RETURNS: N/A
*/
void primeCellSioIntTx
(
AMBA_CHAN * pChan /* ptr to AMBA_CHAN describing this channel */
)
{
char outChar;
UINT32 status;
/*
* If there's a character to transmit then write it out, else reset
* the transmitter. For chips with output FIFO's it is more efficient
* to fill the entire FIFO here.
*/
AMBA_UART_REG_READ(pChan, UART_TXRX_STATUS, status);
if((status & UART_TX_READY) != UART_TX_READY)
return;
if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
AMBA_UART_REG_WRITE(pChan, UART_TX_DATA, outChar);
else
{
*(volatile UINT32 *)((UINT32)(S3C2410_INTSUBMSK)) |= pChan->intTxSubMask;
}
}
/*****************************************************************************
*
* primeCellSioIntRx - handle a receiver interrupt
*
* This routine handles read interrupts from the UART.
*
* RETURNS: N/A
*/
void primeCellSioIntRx
(
AMBA_CHAN * pChan /* ptr to AMBA_CHAN describing this channel */
)
{
char inchar;
char flags;
/* While RX FIFO isn't empty, we have more data to read */
AMBA_UART_REG_READ(pChan, UART_TXRX_STATUS, flags);
if ((flags & UART_RX_READY) == UART_RX_READY)
{
/* Read from data register. */
AMBA_UART_REG_READ(pChan, UART_RX_DATA, inchar);
(*pChan->putRcvChar) (pChan->putRcvArg, inchar);
}
}
/******************************************************************************
*
* primeCellSioInt - handle any UART interrupt
*
* This routine handles interrupts from the UART and determines whether
* the source is a transmit interrupt or receive/receive-timeout interrupt.
*
* The Prime Cell UART generates a receive interrupt when the RX FIFO is
* half-full, and a receive-timeout interrupt after 32 bit-clocks have
* elapsed with no incoming data.
*
* RETURNS: N/A
*/
void primeCellSioInt
(
AMBA_CHAN * pChan /* ptr to AMBA_CHAN describing this channel */
)
{
char intId;
/*AMBA_UART_REG_READ(pChan, UART_TXRX_STATUS, intId);*/
intId = *(volatile UINT32 *)((UINT32)(S3C2410_INTSUBPND));
/*if (intId & UART_TX_READY)*/
if (intId & pChan->intTxSubMask)
{
primeCellSioIntTx (pChan);
*(volatile UINT32 *)((UINT32)(S3C2410_INTSUBPND))|=pChan->intTxSubMask;
}
/*if (intId & UART_RX_READY)*/
if(intId & pChan->intRxSubMask)
{
primeCellSioIntRx (pChan);
*(volatile UINT32 *)((UINT32)(S3C2410_INTSUBPND))|=pChan->intRxSubMask;
}
/*AMBA_UART_REG_WRITE(pChan, UARTICR, intId);*/ /* clear interrupts */
}
/*******************************************************************************
*
* ambaTxStartup - transmitter startup routine
*
* Enable interrupt so that interrupt-level char output routine will be called.
*
* RETURNS: OK on success, ENOSYS if the device is polled-only, or
* EIO on hardware error.
*/
LOCAL int ambaTxStartup
(
SIO_CHAN * pSioChan /* ptr to SIO_CHAN describing this channel */
)
{
AMBA_CHAN * pChan = (AMBA_CHAN *)pSioChan;
if (pChan->channelMode == SIO_MODE_INT)
{
/*primeCellSioIntTx(pChan);*/
*(volatile UINT32 *)((UINT32)(S3C2410_INTSUBMSK)) &= ~pChan->intTxSubMask;
return OK;
}
else
return ENOSYS;
}
/******************************************************************************
*
* ambaPollOutput - output a character in polled mode.
*
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN
* if the output buffer is full, ENOSYS if the device is interrupt-only.
*/
LOCAL int ambaPollOutput
(
SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
char outChar /* char to output */
)
{
AMBA_CHAN * pChan = (AMBA_CHAN *)pSioChan;
FAST UINT32 pollStatus;
AMBA_UART_REG_READ(pChan, UART_TXRX_STATUS, pollStatus);
/* is the transmitter ready to accept a character? */
if ((pollStatus & UART_TX_READY) != UART_TX_READY)
return EAGAIN;
/* write out the character */
AMBA_UART_REG_WRITE(pChan, UART_TX_DATA, outChar); /* transmit character */
return OK;
}
/******************************************************************************
*
* ambaPollInput - poll the device for input.
*
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN
* if the input buffer is empty, ENOSYS if the device is interrupt-only.
*/
LOCAL int ambaPollInput
(
SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
char * thisChar /* pointer to where to return character */
)
{
AMBA_CHAN * pChan = (AMBA_CHAN *)pSioChan;
FAST UINT32 pollStatus;
AMBA_UART_REG_READ(pChan, UART_TXRX_STATUS, pollStatus);
if ((pollStatus & UART_RX_READY) != UART_RX_READY)
return EAGAIN;
/* got a character */
AMBA_UART_REG_READ(pChan, UART_RX_DATA, *thisChar);
return OK;
}
/******************************************************************************
*
* ambaCallbackInstall - install ISR callbacks to get/put chars.
*
* This routine installs interrupt callbacks for transmitting characters
* and receiving characters.
*
* RETURNS: OK on success, or ENOSYS for an unsupported callback type.
*
*/
LOCAL int ambaCallbackInstall
(
SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
int callbackType, /* type of callback */
STATUS (*callback)(), /* callback */
void * callbackArg /* parameter to callback */
)
{
AMBA_CHAN * pChan = (AMBA_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;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -