quicc_smc_serial.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,115 行 · 第 1/4 页
C
1,115 行
}
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
quicc_sxx_serial_getc(serial_channel *chan)
{
unsigned char c;
quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
while ((rxbd->ctrl & QUICC_BD_CTL_Ready) != 0) ;
c = rxbd->buffer[0];
rxbd->length = smc_chan->rxsize;
rxbd->ctrl |= QUICC_BD_CTL_Ready;
if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
rxbd = smc_chan->rbase;
} else {
rxbd++;
}
smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
return c;
}
// Set up the device characteristics; baud rate, etc.
static Cyg_ErrNo
quicc_sxx_serial_set_config(serial_channel *chan, cyg_uint32 key,
const void *xbuf, cyg_uint32 *len)
{
int res;
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;
quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
if ( *len < sizeof(cyg_serial_info_t) ) {
return -EINVAL;
}
*len = sizeof(cyg_serial_info_t);
if (smc_chan->type == _SMC_CHAN) {
res = quicc_smc_serial_config_port(chan, config, true);
} else {
res = quicc_scc_serial_config_port(chan, config, true);
}
if ( true != res )
return -EINVAL;
}
break;
default:
return -EINVAL;
}
return ENOERR;
}
// Enable the transmitter (interrupt) on the device
static void
quicc_sxx_serial_start_xmit(serial_channel *chan)
{
quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
cyg_drv_dsr_lock();
if (smc_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 (smc_chan->txbd->length != 0) {
// Make sure it gets started
quicc_sxx_serial_flush(smc_chan);
}
cyg_drv_dsr_unlock();
}
// Disable the transmitter on the device
static void
quicc_sxx_serial_stop_xmit(serial_channel *chan)
{
quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
// If anything is in the last buffer, need to get it started
if (smc_chan->txbd->length != 0) {
quicc_sxx_serial_flush(smc_chan);
}
}
// Serial I/O - low level interrupt handler (ISR)
static cyg_uint32
quicc_sxx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
cyg_drv_interrupt_mask(smc_chan->int_num);
return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Cause DSR to be run
}
// Serial I/O - high level interrupt handler (DSR)
static void
quicc_smc_serial_DSR(serial_channel *chan)
{
quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
volatile struct smc_regs *ctl = (volatile struct smc_regs *)smc_chan->ctl;
volatile struct cp_bufdesc *txbd;
volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
volatile struct smc_uart_pram *pram = (volatile struct smc_uart_pram *)smc_chan->pram;
struct cp_bufdesc *rxlast;
int i, cache_state;
if (ctl->smc_smce & QUICC_SMCE_TX) {
// Transmit interrupt
ctl->smc_smce = QUICC_SMCE_TX; // Reset interrupt state;
txbd = smc_chan->tbase; // First buffer
while (true) {
if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) {
txbd->length = 0;
txbd->ctrl &= ~QUICC_BD_CTL_Int; // Reset interrupt bit
}
if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
txbd = smc_chan->tbase;
break;
} else {
txbd++;
}
}
(chan->callbacks->xmt_char)(chan);
}
while (ctl->smc_smce & QUICC_SMCE_RX) {
// Receive interrupt
ctl->smc_smce = QUICC_SMCE_RX; // Reset interrupt state;
rxlast = (struct cp_bufdesc *) ((char *)eppc_base() + pram->rbptr);
while (rxbd != rxlast) {
if ((rxbd->ctrl & QUICC_BD_CTL_Ready) == 0) {
if((rxbd->ctrl & (QUICC_BD_CTL_Frame | QUICC_BD_CTL_Parity)) == 0) {
for (i = 0; i < rxbd->length; i++) {
(chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
}
} else {
// is this necessary?
rxbd->ctrl &= QUICC_BD_CTL_MASK;
// should we report the error?
}
// 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, smc_chan->rxsize); // Make sure no stale data
}
rxbd->length = 0;
rxbd->ctrl |= QUICC_BD_CTL_Ready;
}
if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
rxbd = smc_chan->rbase;
} else {
rxbd++;
}
}
smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
}
if (ctl->smc_smce & QUICC_SMCE_BSY) {
ctl->smc_smce = QUICC_SMCE_BSY; // Reset interrupt state;
}
cyg_drv_interrupt_acknowledge(smc_chan->int_num);
cyg_drv_interrupt_unmask(smc_chan->int_num);
}
static void
quicc_scc_serial_DSR(serial_channel *chan)
{
quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
volatile struct scc_regs *ctl = (volatile struct scc_regs *)smc_chan->ctl;
volatile struct cp_bufdesc *txbd;
volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
volatile struct uart_pram *pram = (volatile struct uart_pram *)smc_chan->pram;
struct cp_bufdesc *rxlast;
int i, cache_state;
if (ctl->scc_scce & QUICC_SCCE_TX) {
// Transmit interrupt
ctl->scc_scce = QUICC_SCCE_TX; // Reset interrupt state;
txbd = smc_chan->tbase; // First buffer
while (true) {
if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) {
txbd->length = 0;
txbd->ctrl &= ~QUICC_BD_CTL_Int; // Reset interrupt bit
}
if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
txbd = smc_chan->tbase;
break;
} else {
txbd++;
}
}
(chan->callbacks->xmt_char)(chan);
}
while (ctl->scc_scce & QUICC_SCCE_RX) {
// Receive interrupt
ctl->scc_scce = QUICC_SCCE_RX; // Reset interrupt state;
rxlast = (struct cp_bufdesc *) ((char *)eppc_base() + pram->rbptr);
while (rxbd != rxlast) {
if ((rxbd->ctrl & QUICC_BD_CTL_Ready) == 0) {
if((rxbd->ctrl & (QUICC_BD_CTL_Frame | QUICC_BD_CTL_Parity)) == 0) {
for (i = 0; i < rxbd->length; i++) {
(chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
}
} else {
// is this necessary?
rxbd->ctrl &= QUICC_BD_CTL_MASK;
// should we report the error?
}
// 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, smc_chan->rxsize); // Make sure no stale data
}
rxbd->length = 0;
rxbd->ctrl |= QUICC_BD_CTL_Ready;
}
if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
rxbd = smc_chan->rbase;
} else {
rxbd++;
}
}
smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
}
if (ctl->scc_scce & QUICC_SCCE_BSY) {
ctl->scc_scce = QUICC_SCCE_BSY; // Reset interrupt state;
}
cyg_drv_interrupt_acknowledge(smc_chan->int_num);
cyg_drv_interrupt_unmask(smc_chan->int_num);
}
static void
quicc_sxx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
quicc_sxx_serial_info *smc_chan = (quicc_sxx_serial_info *)chan->dev_priv;
if (smc_chan->type == _SMC_CHAN) {
quicc_smc_serial_DSR(chan);
} else {
quicc_scc_serial_DSR(chan);
}
}
void
show_rxbd(int dump_all)
{
#ifdef CYGDBG_DIAG_BUF
EPPC *eppc = eppc_base();
struct smc_uart_pram *pram = &eppc->pram[2].scc.pothers.smc_modem.psmc.u;
struct cp_bufdesc *rxbd = (struct cp_bufdesc *)((char *)eppc+pram->rbase);
int _enable = enable_diag_uart;
enable_diag_uart = 0;
#if 1
diag_printf("SMC Mask: %x, Events: %x, Rbase: %x, Rbptr: %x\n",
eppc->smc_regs[0].smc_smcm, eppc->smc_regs[0].smc_smce,
pram->rbase, pram->rbptr);
while (true) {
diag_printf("Rx BD: %x, ctl: %x, length: %d\n", rxbd, rxbd->ctrl, rxbd->length);
if (rxbd->ctrl & QUICC_BD_CTL_Wrap) break;
rxbd++;
}
#endif
enable_diag_uart = _enable;
if (dump_all) dump_diag_buf();
#endif // CYGDBG_DIAG_BUF
}
#endif // CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC
// ------------------------------------------------------------------------
// EOF powerpc/quicc_smc_serial.c
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?