quicc2_scc_serial.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 852 行 · 第 1/3 页
C
852 行
int cache_state;
HAL_DCACHE_IS_ENABLED(cache_state);
if (cache_state) {
HAL_DCACHE_FLUSH(txbd->buffer, scc_chan->txsize);
}
if ((txbd->length > 0) &&
((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == 0)) {
txbd->ctrl |= QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int; // Signal buffer ready
if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
txbd = scc_chan->tbase;
} else {
txbd++;
}
scc_chan->txbd = (scc_bd *) txbd;
}
}
// Send a character to the device output buffer.
// Return 'true' if character is sent to device
static bool
quicc2_scc_serial_putc(serial_channel *chan, unsigned char c)
{
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
volatile struct scc_bd *txbd, *txfirst;
bool res;
cyg_drv_dsr_lock(); // Avoid race condition testing pointers
txbd = (scc_bd *)(QUICC2_VADS_IMM_BASE + ((int) scc_chan->scc_pram->tbptr));
txfirst = txbd;
// Scan for a non-busy buffer
while (txbd->ctrl & QUICC2_BD_CTL_Ready) {
// This buffer is busy, move to next one
if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
txbd = scc_chan->tbase;
} else {
txbd++;
}
if (txbd == txfirst) break; // Went all the way around
}
scc_chan->txbd = (scc_bd *) txbd;
if ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == 0) {
// Transmit buffer is not full/busy
txbd->buffer[txbd->length++] = c;
if (txbd->length == scc_chan->txsize) {
// This buffer is now full, tell SCC to start processing it
quicc2_scc_serial_flush(scc_chan);
}
res = true;
} else {
// No space
res = false;
}
cyg_drv_dsr_unlock();
return res;
}
// Fetch a character from the device input buffer, waiting if necessary
static unsigned char
quicc2_scc_serial_getc(serial_channel *chan)
{
unsigned char c;
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
volatile scc_bd *rxbd = scc_chan->rxbd;
while ((rxbd->ctrl & QUICC2_BD_CTL_Ready) != 0) ; // WAIT ...
c = rxbd->buffer[0];
rxbd->length = scc_chan->rxsize;
rxbd->ctrl |= QUICC2_BD_CTL_Ready;
if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
rxbd = scc_chan->rbase;
} else {
rxbd++;
}
scc_chan->rxbd = (scc_bd *) rxbd;
return c;
}
// Set up the device characteristics; baud rate, etc.
static Cyg_ErrNo
quicc2_scc_serial_set_config(serial_channel *chan, cyg_uint32 key,
const void *xbuf, cyg_uint32 *len)
{
switch (key) {
case CYG_IO_SET_CONFIG_SERIAL_INFO:
{
// FIXME - The documentation says that you can't change the baud rate
// again until at least two BRG input clocks have occurred.
cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
if ( *len < sizeof(cyg_serial_info_t) ) {
return -EINVAL;
}
*len = sizeof(cyg_serial_info_t);
if ( true != quicc2_scc_serial_config_port(chan, config, false) )
return -EINVAL;
}
break;
default:
return -EINVAL;
}
return ENOERR;
}
// Enable the transmitter (interrupt) on the device
static void
quicc2_scc_serial_start_xmit(serial_channel *chan)
{
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
cyg_drv_dsr_lock();
if (scc_chan->txbd->length == 0) {
// See if there is anything to put in this buffer, just to get it going
(chan->callbacks->xmt_char)(chan);
}
if (scc_chan->txbd->length != 0) {
// Make sure it gets started
quicc2_scc_serial_flush(scc_chan);
}
cyg_drv_dsr_unlock();
}
// Disable the transmitter on the device
static void
quicc2_scc_serial_stop_xmit(serial_channel *chan)
{
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
// If anything is in the last buffer, need to get it started
if (scc_chan->txbd->length != 0) {
quicc2_scc_serial_flush(scc_chan);
}
}
// Serial I/O - low level interrupt handler (ISR)
static cyg_uint32
quicc2_scc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
cyg_drv_interrupt_mask(scc_chan->int_vector);
return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Cause DSR to be run
}
// Serial I/O - high level interrupt handler (DSR)
static void
quicc2_scc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
volatile struct scc_regs_8260 *regs = scc_chan->scc_regs;
volatile scc_bd *txbd;
volatile scc_bd *rxbd = scc_chan->rxbd;
scc_bd *rxlast;
int i, cache_state;
#ifdef CYGDBG_DIAG_BUF
int _time, _stime;
externC cyg_tick_count_t cyg_current_time(void);
cyg_drv_isr_lock();
enable_diag_uart = 0;
HAL_CLOCK_READ(&_time);
_stime = (int)cyg_current_time();
diag_printf("DSR start - CE: %x, time: %x.%x\n",
regs->scce, _stime, _time);
enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
if (regs->scce & QUICC2_SCCE_TX) { // Tx Event
#ifdef XX_CYGDBG_DIAG_BUF
enable_diag_uart = 0;
txbd = scc_chan->tbase;
for (i = 0; i < CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM; i++, txbd++) {
diag_printf("Tx BD: %x, length: %d, ctl: %x\n", txbd, txbd->length, txbd->ctrl);
}
enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
regs->scce = QUICC2_SCCE_TX; // Reset Tx Event
txbd = scc_chan->tbase; // First buffer
while (true) {
if ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == QUICC2_BD_CTL_Int) {
#ifdef XX_CYGDBG_DIAG_BUF
enable_diag_uart = 0;
HAL_CLOCK_READ(&_time);
_stime = (int)cyg_current_time();
diag_printf("TX Done - Tx: %x, length: %d, time: %x.%x\n",
txbd, txbd->length, _stime, _time);
enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
txbd->length = 0;
txbd->ctrl &= ~QUICC2_BD_CTL_Int; // Reset interrupt bit
}
if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
txbd = scc_chan->tbase;
break;
} else {
txbd++;
}
}
(chan->callbacks->xmt_char)(chan);
}
while (regs->scce & QUICC2_SCCE_RX) { // Rx Event
regs->scce = QUICC2_SCCE_RX; // Reset interrupt state;
rxlast = (scc_bd *) ((char *)QUICC2_VADS_IMM_BASE + scc_chan->scc_pram->rbptr );
#ifdef CYGDBG_DIAG_BUF
enable_diag_uart = 0;
HAL_CLOCK_READ(&_time);
_stime = (int)cyg_current_time();
diag_printf("Scan RX - rxbd: %x, rbptr: %x, time: %x.%x\n",
rxbd, rxlast, _stime, _time);
#endif // CYGDBG_DIAG_BUF
while (rxbd != rxlast) {
if ((rxbd->ctrl & QUICC2_BD_CTL_Ready) == 0) {
#ifdef CYGDBG_DIAG_BUF
diag_printf("rxbuf: %x, flags: %x, length: %d\n",
rxbd, rxbd->ctrl, rxbd->length);
diag_dump_buf(rxbd->buffer, rxbd->length);
#endif // CYGDBG_DIAG_BUF
for (i = 0; i < rxbd->length; i++) {
(chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
}
// Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
HAL_DCACHE_IS_ENABLED(cache_state);
if (cache_state) {
HAL_DCACHE_INVALIDATE(rxbd->buffer, scc_chan->rxsize); // Make sure no stale data
}
rxbd->length = 0;
rxbd->ctrl |= QUICC2_BD_CTL_Ready;
}
if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
rxbd = scc_chan->rbase;
} else {
rxbd++;
}
}
#ifdef CYGDBG_DIAG_BUF
enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
scc_chan->rxbd = (scc_bd *) rxbd;
}
if (regs->scce & QUICC2_SCCE_BSY) {
#ifdef CYGDBG_DIAG_BUF
enable_diag_uart = 0;
diag_printf("RX BUSY interrupt\n");
enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
regs->scce = QUICC2_SCCE_BSY; // Reset interrupt state;
}
#ifdef CYGDBG_DIAG_BUF
enable_diag_uart = 0;
HAL_CLOCK_READ(&_time);
_stime = (int)cyg_current_time();
diag_printf("DSR done - CE: %x, time: %x.%x\n",
regs->scce, _stime, _time);
enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
cyg_drv_interrupt_acknowledge(scc_chan->int_vector);
cyg_drv_interrupt_unmask(scc_chan->int_vector);
#ifdef CYGDBG_DIAG_BUF
cyg_drv_isr_unlock();
#endif // CYGDBG_DIAG_BUF
}
#endif // CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
// ------------------------------------------------------------------------
// EOF powerpc/quicc2_scc_serial.c
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?