📄 at91sio.c
字号:
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 */
if (pChan->isUsart)
{
intEnable (pChan->level);
}
else
{
sysPeripheralIntEnable(pChan->level);
}
}
else
{
/* Disable the interrupt */
if (pChan->isUsart)
{
intDisable (pChan->level);
}
else
{
sysPeripheralIntDisable(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
* 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;
}
/*******************************************************************************
*
* at91SioInt - handle an interrupt
*
* This routine handles interrupts from the USART.
*
* RETURNS: N/A
*/
void at91SioInt
(
AT91_SIO_CHAN * pChan /* ptr to AT91_SIO_CHAN describing this chan */
)
{
#ifndef AT91_USE_PDC
UINT32 ch; /* Possible char to be in/output */
#endif
UINT32 status; /* Status from USART */
UINT32 imr; /* interrupt mask register */
#ifdef AT91_USE_PDC
UINT8 * ptr;
int count;
#endif
/* read status register and mask register */
AT91_USART_REG_READ (pChan, AT91_US_CSR, status);
AT91_USART_REG_READ (pChan, AT91_US_IMR, imr);
#ifndef AT91_USE_PDC
if (status & AT91_US_RXRDY) /* data? */
{
AT91_USART_REG_READ (pChan, AT91_US_RHR, ch); /* read character */
(*pChan->putRcvChar) (pChan->putRcvArg, (char)ch); /* pass it on */
}
#else /* AT91_USE_PDC */
if (status & AT91_US_TIMEOUT)
{
/* restart timeout */
if (pChan->isUsart)
{
AT91_USART_REG_WRITE (pChan, AT91_US_CR, AT91_US_STTTO);
}
}
/*
* Read the Receiver Peripheral Data Controller count. It was originally
* set to the size of the receive buffer.
*/
AT91_USART_REG_READ (pChan, AT91_US_RCR, count);
while (count < AT91_RXBUFF_SIZE)
{
/*
* then characters have been received into the buffer - setup
* PDC to use the other swing-buffer whilst we deal with this
* one.
*/
AT91_USART_REG_WRITE (pChan, AT91_US_RCR, 0); /* stop Rx PDC */
/* reset ptr to beginning of new buffer */
if (pChan->buffInUse == 0)
{
ptr = &pChan->rxBuffA[0]; /* ptr to beginning of Rx buffer */
AT91_USART_REG_WRITE (pChan, AT91_US_RPR, (UINT32)(pChan->rxBuffB));
pChan->buffInUse = 1;
}
else
{
ptr = &pChan->rxBuffB[0]; /* ptr to beginning of Rx buffer */
AT91_USART_REG_WRITE (pChan, AT91_US_RPR, (UINT32)(pChan->rxBuffA));
pChan->buffInUse = 0;
}
/* reset count to size of buffer and restart timeout */
AT91_USART_REG_WRITE (pChan, AT91_US_RCR, AT91_RXBUFF_SIZE);
if (pChan->isUsart)
{
AT91_USART_REG_WRITE (pChan, AT91_US_CR, AT91_US_STTTO);
}
/* read chars from buffer and pass on to installed callback rtn */
while (count < AT91_RXBUFF_SIZE)
{
/* while there are chars in buffer we have not yet passed on */
(*pChan->putRcvChar) (pChan->putRcvArg, *ptr++); /* pass it on */
count++;
}
/* reread PDC Rx count */
AT91_USART_REG_READ (pChan, AT91_US_RCR, count);
} /* endwhile */
#endif /* AT91_USE_PDC */
#ifndef AT91_USE_PDC
/*
* There is a THR and the Tx Shift Register, so we may be able to push
* two characters into the USART.
*/
status &= imr;
if (status & AT91_US_TXRDY) /* if THR is empty */
{
if (((*pChan->getTxChar) (pChan->getTxArg, &ch)) != ERROR)
{
AT91_USART_REG_WRITE(pChan, AT91_US_THR, ch); /* tx char */
}
else /* no more chars to send - disable transmitter interrupts */
{
AT91_USART_REG_WRITE (pChan, AT91_US_IDR, AT91_US_TXRDY);
}
}
#else /* AT91_USE_PDC */
/* ENDTX interrupt => Tx is required */
if (status & AT91_US_ENDTX)
{
count = 0;
ptr = pChan->txBuff; /* ptr to beginning of Tx buffer */
do
{
if ((*pChan->getTxChar) (pChan->getTxArg, ptr++) == ERROR)
{
break;
}
count++;
}
while (count < AT91_TXBUFF_SIZE);
/* If nothing more to transmit, so disable ENDTX interrupt */
if (count == 0)
{
AT91_USART_REG_WRITE (pChan, AT91_US_IDR, AT91_US_ENDTX);
}
else
{
/* reset ptr to beginning of buffer and count to size of buffer */
AT91_USART_REG_WRITE (pChan, AT91_US_TPR, (UINT32)(pChan->txBuff));
AT91_USART_REG_WRITE (pChan, AT91_US_TCR, count);
}
} /* endif ENDTX was enabled */
#endif /* AT91_USE_PDC */
}
/*******************************************************************************
*
* at91SioTxStartup - transmitter startup routine
*
* Call interrupt level char output routine and enable interrupt
*
* RETURNS: OK on success, ENOSYS if the device is polled-only, or
* EIO on hardware error.
*/
LOCAL int at91SioTxStartup
(
SIO_CHAN * pSioChan /* ptr to SIO_CHAN describing this channel */
)
{
AT91_SIO_CHAN * pChan = (AT91_SIO_CHAN *)pSioChan;
if (pChan->channelMode == SIO_MODE_INT)
{
/* Enable Transmitter interrupts */
#ifndef AT91_USE_PDC
AT91_USART_REG_WRITE (pChan, AT91_US_IER, AT91_US_TXRDY);
#else
AT91_USART_REG_WRITE (pChan, AT91_US_IER, AT91_US_ENDTX);
#endif
return OK;
}
else
return ENOSYS;
}
/******************************************************************************
*
* at91SioPollOutput - 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 at91SioPollOutput
(
SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
char outChar /* char to output */
)
{
AT91_SIO_CHAN * pChan = (AT91_SIO_CHAN *)pSioChan;
UINT32 pollStatus;
AT91_USART_REG_READ (pChan, AT91_US_CSR, pollStatus);
/* is the transmitter ready to accept a character? */
if ((pollStatus & AT91_US_TXRDY) == 0)
return EAGAIN;
/* write out the character */
AT91_USART_REG_WRITE (pChan, AT91_US_THR, outChar); /* transmit character */
return OK;
}
/******************************************************************************
*
* at91SioPollInput - 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 at91SioPollInput
(
SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
char * thisChar /* pointer to where to return character */
)
{
AT91_SIO_CHAN * pChan = (AT91_SIO_CHAN *)pSioChan;
UINT32 pollStatus;
AT91_USART_REG_READ (pChan, AT91_US_CSR, pollStatus);
if ((pollStatus & AT91_US_RXRDY) == 0)
return EAGAIN;
/* got a character */
AT91_USART_REG_READ (pChan, AT91_US_RHR, *thisChar);
return OK;
}
/******************************************************************************
*
* at91SioCallbackInstall - 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 at91SioCallbackInstall
(
SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
int callbackType, /* type of callback */
STATUS (*callback)(), /* callback */
void * callbackArg /* parameter to callback */
)
{
AT91_SIO_CHAN * pChan = (AT91_SIO_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;
}
}
#endif /* INCLUDE_SERIAL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -