mpc8xxx_serial.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,017 行 · 第 1/3 页
C
1,017 行
TxBD,
CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_TxNUM,
CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_TxSIZE,
&mpc8xxx_scc3_txbuf[0],
RxBD,
CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_RxNUM,
CYGNUM_IO_SERIAL_POWERPC_MPC8XXX_SCC3_RxSIZE,
&mpc8xxx_scc3_rxbuf[0]
);
}
#endif
(chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
if (chan->out_cbuf.len != 0) {
cyg_drv_interrupt_create(smc_chan->int_num,
0, // Priority - unused (but asserted)
(cyg_addrword_t)chan, // Data item passed to interrupt handler
mpc8xxx_sxx_serial_ISR,
mpc8xxx_sxx_serial_DSR,
&smc_chan->serial_interrupt_handle,
&smc_chan->serial_interrupt);
cyg_drv_interrupt_attach(smc_chan->serial_interrupt_handle);
cyg_drv_interrupt_unmask(smc_chan->int_num);
}
if (smc_chan->type == _SMC_CHAN) {
mpc8xxx_smc_serial_config_port(chan, &chan->config, true);
} else {
mpc8xxx_scc_serial_config_port(chan, &chan->config, true);
}
if (cache_state)
HAL_DCACHE_ENABLE();
return true;
}
// This routine is called when the device is "looked" up (i.e. attached)
static Cyg_ErrNo
mpc8xxx_sxx_serial_lookup(struct cyg_devtab_entry **tab,
struct cyg_devtab_entry *sub_tab,
const char *name)
{
serial_channel *chan = (serial_channel *)(*tab)->priv;
(chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
return ENOERR;
}
// Force the current transmit buffer to be sent
static void
mpc8xxx_sxx_serial_flush(mpc8xxx_sxx_serial_info *smc_chan)
{
volatile struct cp_bufdesc *txbd = smc_chan->txbd;
int cache_state;
HAL_DCACHE_IS_ENABLED(cache_state);
if (cache_state) {
HAL_DCACHE_FLUSH(txbd->buffer, smc_chan->txsize);
}
if ((txbd->length > 0) &&
((txbd->ctrl & (_BD_CTL_Ready|_BD_CTL_Int)) == 0)) {
txbd->ctrl |= _BD_CTL_Ready|_BD_CTL_Int; // Signal buffer ready
if (txbd->ctrl & _BD_CTL_Wrap) {
txbd = smc_chan->tbase;
} else {
txbd++;
}
smc_chan->txbd = txbd;
}
}
// Send a character to the device output buffer.
// Return 'true' if character is sent to device
static bool
mpc8xxx_sxx_serial_putc(serial_channel *chan, unsigned char c)
{
mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
volatile struct cp_bufdesc *txbd, *txfirst;
volatile t_Smc_Pram *pram = (volatile t_Smc_Pram *)smc_chan->pram;
bool res;
cyg_drv_dsr_lock(); // Avoid race condition testing pointers
txbd = (struct cp_bufdesc *)((char *)IMM + pram->tbptr);
txfirst = txbd;
// Scan for a non-busy buffer
while (txbd->ctrl & _BD_CTL_Ready) {
// This buffer is busy, move to next one
if (txbd->ctrl & _BD_CTL_Wrap) {
txbd = smc_chan->tbase;
} else {
txbd++;
}
if (txbd == txfirst) break; // Went all the way around
}
smc_chan->txbd = txbd;
if ((txbd->ctrl & (_BD_CTL_Ready|_BD_CTL_Int)) == 0) {
// Transmit buffer is not full/busy
txbd->buffer[txbd->length++] = c;
if (txbd->length == smc_chan->txsize) {
// This buffer is now full, tell SMC to start processing it
mpc8xxx_sxx_serial_flush(smc_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
mpc8xxx_sxx_serial_getc(serial_channel *chan)
{
unsigned char c;
mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
while ((rxbd->ctrl & _BD_CTL_Ready) != 0) ;
c = rxbd->buffer[0];
rxbd->length = smc_chan->rxsize;
rxbd->ctrl |= _BD_CTL_Ready;
if (rxbd->ctrl & _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
mpc8xxx_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;
mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_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 = mpc8xxx_smc_serial_config_port(chan, config, true);
} else {
res = mpc8xxx_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
mpc8xxx_sxx_serial_start_xmit(serial_channel *chan)
{
mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_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
mpc8xxx_sxx_serial_flush(smc_chan);
}
cyg_drv_dsr_unlock();
}
// Disable the transmitter on the device
static void
mpc8xxx_sxx_serial_stop_xmit(serial_channel *chan)
{
mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
// If anything is in the last buffer, need to get it started
if (smc_chan->txbd->length != 0) {
mpc8xxx_sxx_serial_flush(smc_chan);
}
}
// Serial I/O - low level interrupt handler (ISR)
static cyg_uint32
mpc8xxx_sxx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_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
mpc8xxx_smc_serial_DSR(serial_channel *chan)
{
mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
volatile struct smc_regs_8260 *ctl = (volatile struct smc_regs_8260 *)smc_chan->ctl;
volatile struct cp_bufdesc *txbd;
volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
volatile t_Smc_Pram *pram = (volatile t_Smc_Pram *)smc_chan->pram;
struct cp_bufdesc *rxlast;
int i, cache_state;
if (ctl->smc_smce & SMCE_Tx) {
// Transmit interrupt
ctl->smc_smce = SMCE_Tx; // Reset interrupt state;
txbd = smc_chan->tbase; // First buffer
while (true) {
if ((txbd->ctrl & (_BD_CTL_Ready|_BD_CTL_Int)) == _BD_CTL_Int) {
txbd->length = 0;
txbd->ctrl &= ~_BD_CTL_Int; // Reset interrupt bit
}
if (txbd->ctrl & _BD_CTL_Wrap) {
txbd = smc_chan->tbase;
break;
} else {
txbd++;
}
}
(chan->callbacks->xmt_char)(chan);
}
while (ctl->smc_smce & SMCE_Rx) {
// Receive interrupt
ctl->smc_smce = SMCE_Rx; // Reset interrupt state;
rxlast = (struct cp_bufdesc *) (
(char *)IMM + pram->rbptr );
while (rxbd != rxlast) {
if ((rxbd->ctrl & _BD_CTL_Ready) == 0) {
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, smc_chan->rxsize); // Make sure no stale data
}
rxbd->length = 0;
rxbd->ctrl |= _BD_CTL_Ready;
}
if (rxbd->ctrl & _BD_CTL_Wrap) {
rxbd = smc_chan->rbase;
} else {
rxbd++;
}
}
smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
}
if (ctl->smc_smce & SMCE_Bsy) {
ctl->smc_smce = SMCE_Bsy; // Reset interrupt state;
}
cyg_drv_interrupt_acknowledge(smc_chan->int_num);
cyg_drv_interrupt_unmask(smc_chan->int_num);
}
static void
mpc8xxx_scc_serial_DSR(serial_channel *chan)
{
mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
volatile struct scc_regs_8260 *ctl = (volatile struct scc_regs_8260 *)smc_chan->ctl;
volatile struct cp_bufdesc *txbd;
volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
volatile t_Smc_Pram *pram = (volatile t_Smc_Pram *)smc_chan->pram;
struct cp_bufdesc *rxlast;
int i, cache_state;
if (ctl->scce & SCCE_Tx) {
// Transmit interrupt
ctl->scce = SCCE_Tx; // Reset interrupt state;
txbd = smc_chan->tbase; // First buffer
while (true) {
if ((txbd->ctrl & (_BD_CTL_Ready|_BD_CTL_Int)) == _BD_CTL_Int) {
txbd->length = 0;
txbd->ctrl &= ~_BD_CTL_Int; // Reset interrupt bit
}
if (txbd->ctrl & _BD_CTL_Wrap) {
txbd = smc_chan->tbase;
break;
} else {
txbd++;
}
}
(chan->callbacks->xmt_char)(chan);
}
while (ctl->scce & SCCE_Rx) {
// Receive interrupt
ctl->scce = SCCE_Rx; // Reset interrupt state;
rxlast = (struct cp_bufdesc *) ((char *)IMM + pram->rbptr);
while (rxbd != rxlast) {
if ((rxbd->ctrl & _BD_CTL_Ready) == 0) {
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, smc_chan->rxsize); // Make sure no stale data
}
rxbd->length = 0;
rxbd->ctrl |= _BD_CTL_Ready;
}
if (rxbd->ctrl & _BD_CTL_Wrap) {
rxbd = smc_chan->rbase;
} else {
rxbd++;
}
}
smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
}
if (ctl->scce & SCCE_Bsy) {
ctl->scce = SCCE_Bsy; // Reset interrupt state;
}
cyg_drv_interrupt_acknowledge(smc_chan->int_num);
cyg_drv_interrupt_unmask(smc_chan->int_num);
}
static void
mpc8xxx_sxx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
mpc8xxx_sxx_serial_info *smc_chan = (mpc8xxx_sxx_serial_info *)chan->dev_priv;
if (smc_chan->type == _SMC_CHAN) {
mpc8xxx_smc_serial_DSR(chan);
} else {
mpc8xxx_scc_serial_DSR(chan);
}
}
// ------------------------------------------------------------------------
// EOF powerpc/mpc8xxx_smc_serial.c
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?