📄 at91sio.c
字号:
/* at91Sio.c - Atmel AT91 USART tty driver */
/* Copyright 1999 ARM Limited */
/*
modification history
--------------------
01a,25jun99,jpd wriiten.
*/
#include "vxWorks.h"
#include "intLib.h"
#include "errnoLib.h"
#include "errno.h"
#include "sioLib.h"
#include "at91Sio.h"
/* Make all of code in file dependent upon this symbol */
#ifdef INCLUDE_SERIAL
/* defines */
/* globals */
int at91SioIntErrs = 0;
/* function prototypes */
LOCAL STATUS at91SioDummyCallback (void);
LOCAL void at91SioInitChannel (AT91_SIO_CHAN * pChan);
LOCAL STATUS at91SioIoctl (SIO_CHAN * pSioChan, int request, int arg);
LOCAL int at91SioTxStartup (SIO_CHAN * pSioChan);
LOCAL int at91SioCallbackInstall (SIO_CHAN * pSioChan, int callbackType,
STATUS (*callback)(), void * callbackArg);
LOCAL int at91SioPollInput (SIO_CHAN * pSioChan, char *);
LOCAL int at91SioPollOutput (SIO_CHAN * pSioChan, char);
/* driver functions */
LOCAL SIO_DRV_FUNCS at91SioDrvFuncs =
{
(int (*)())at91SioIoctl,
at91SioTxStartup,
at91SioCallbackInstall,
at91SioPollInput,
at91SioPollOutput
};
/*******************************************************************************
*
* at91SioDummyCallback - dummy callback routine.
*
* RETURNS: ERROR, always.
*/
LOCAL STATUS at91SioDummyCallback (void)
{
return ERROR;
}
/*******************************************************************************
*
* at91SioDevInit - initialise an AT91 SIO 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
* AT91_SIO_CHAN structure.
*
* RETURNS: N/A
*/
void at91SioDevInit
(
AT91_SIO_CHAN * pChan /* ptr to AT91_SIO_CHAN describing this chan */
)
{
int oldlevel = intLock();
/* initialise the driver function pointers in the SIO_CHAN */
pChan->sio.pDrvFuncs = &at91SioDrvFuncs;
/* set the non BSP-specific constants */
pChan->getTxChar = at91SioDummyCallback;
pChan->putRcvChar = at91SioDummyCallback;
pChan->channelMode = 0; /* am undefined mode */
/* initialise the chip */
at91SioInitChannel (pChan);
intUnlock (oldlevel);
return;
}
/*******************************************************************************
*
* at91SioInitChannel - initialise USART
*
* This routine performs hardware initialisation of the USART channel.
*
* RETURNS: N/A
*/
LOCAL void at91SioInitChannel
(
AT91_SIO_CHAN * pChan /* ptr to AT91_SIO_CHAN describing this chan */
)
{
UINT32 temp;
/* reset USART: Tx, Rx and clear error status */
AT91_USART_REG_WRITE (pChan, AT91_US_CR, \
(AT91_US_RSTRX | AT91_US_RSTTX | AT91_US_RSTSTA));
#ifndef AT91_USE_PDC
/* disable Peripheral data Controller */
AT91_USART_REG_WRITE (pChan, AT91_US_RCR, 0);
AT91_USART_REG_WRITE (pChan, AT91_US_RPR, 0);
AT91_USART_REG_WRITE (pChan, AT91_US_TCR, 0);
AT91_USART_REG_WRITE (pChan, AT91_US_TPR, 0);
#else /* AT91_USE_PDC */
AT91_USART_REG_WRITE (pChan, AT91_US_RTOR, 8); /* timeout ~= 4 chars */
/* start with swing-buffer A */
AT91_USART_REG_WRITE (pChan, AT91_US_RPR, (UINT32)(&pChan->rxBuffA[0]));
AT91_USART_REG_WRITE (pChan, AT91_US_RCR, AT91_RXBUFF_SIZE);
pChan->buffInUse = 0;
AT91_USART_REG_WRITE (pChan, AT91_US_TPR, (UINT32)(&pChan->txBuff[0]));
AT91_USART_REG_WRITE (pChan, AT91_US_TCR, 0);
#endif /* AT91_USE_PDC */
/* Enable Rx and Tx */
AT91_USART_REG_WRITE (pChan, AT91_US_CR, (AT91_US_RXEN | AT91_US_TXEN));
/*
* Set word format: set 8 bits, 1 stop bit, no parity, in
* normal (non-loopback), asynchronous mode.
*
* USART clocking mode has been configured in sysSerial.c.
*/
AT91_USART_REG_READ (pChan, AT91_US_MR, temp);
temp &= ~0x30; /* clear all except USCLKS field */
AT91_USART_REG_WRITE (pChan, AT91_US_MR,(temp | AT91_US_CHRL_8 | AT91_US_NOPAR));
/* Set baud rate divisor */
AT91_USART_REG_WRITE (pChan, AT91_US_BRGR,(pChan->xtal / (16 * pChan->baudRate)));
/* Disable Transmitter Time Guard function */
AT91_USART_REG_WRITE (pChan, AT91_US_TTGR, 0);
/*
* Enable USART Rx and Tx interrupts: errors and data. First disable
* unwanted interrupts, then enable the desired ones.
*/
#ifndef AT91_USE_PDC
AT91_USART_REG_WRITE (pChan, AT91_US_IDR, AT91_US_TXRDY | AT91_US_ENDRX | \
AT91_US_ENDTX | AT91_US_TIMEOUT);
/* Enable TxEmpty (THR and TSR empty) and RxRDY (RHR full) plus errors */
AT91_USART_REG_WRITE (pChan, AT91_US_IER, AT91_US_RXRDY | AT91_US_RXBRK | \
AT91_US_OVRE | AT91_US_FRAME | \
AT91_US_PARE | AT91_US_TXEMPTY);
#else /* AT91_USE_PDC */
AT91_USART_REG_WRITE (pChan, AT91_US_IDR, AT91_US_RXRDY | AT91_US_TXRDY | \
AT91_US_TXEMPTY);
/*
* Enable ENDTX, and ENDRX (Tx, Rx xfer complete), and Rx timeout.
* Also, start the timeout.
*/
AT91_USART_REG_WRITE (pChan, AT91_US_IER, AT91_US_RXBRK | AT91_US_ENDRX | \
AT91_US_ENDTX | AT91_US_OVRE | \
AT91_US_FRAME | AT91_US_PARE | \
AT91_US_TIMEOUT);
AT91_USART_REG_WRITE (pChan, AT91_US_CR, AT91_US_STTTO);
#endif /* AT91_USE_PDC */
}
/*******************************************************************************
*
* at91SioIoctl - 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 at91SioIoctl
(
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 */
AT91_SIO_CHAN * pChan = (AT91_SIO_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.
*
* Calculate the baud rate divisor: it must be non-zero and must
* fit in a 16-bit register.
*/
brd = pChan->xtal / (16 * arg);
if (brd & ~0xFFFF)
{
status = EIO; /* baud rate out of range */
break;
}
AT91_USART_REG_WRITE (pChan, AT91_US_BRGR, brd);
pChan->baudRate = arg;
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 interrupt */
intEnable (pChan->level);
}
else
{
/* Disable the interrupt */
intDisable (pChan->level);
}
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -