📄 quicc_smc_serial.c
字号:
bool res; cyg_drv_dsr_lock(); // Avoid race condition testing pointers txbd = (struct cp_bufdesc *)((char *)eppc + smc_chan->pram->tbptr); txfirst = txbd; // Scan for a non-busy buffer while (txbd->ctrl & QUICC_BD_CTL_Ready) { // This buffer is busy, move to next one if (txbd->ctrl & QUICC_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 & (QUICC_BD_CTL_Ready|QUICC_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 quicc_smc_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 necessarystatic unsigned char quicc_smc_serial_getc(serial_channel *chan){ unsigned char c; quicc_smc_serial_info *smc_chan = (quicc_smc_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 bool quicc_smc_serial_set_config(serial_channel *chan, cyg_serial_info_t *config){ bool res = quicc_smc_serial_config_port(chan, config, false); // FIXME - The documentation says that you can't change the baud rate // again until at least two BRG input clocks have occurred. return res;}// Enable the transmitter (interrupt) on the devicestatic voidquicc_smc_serial_start_xmit(serial_channel *chan){ quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv; if (smc_chan->txbd->length == 0) { // See if there is anything to put in this buffer, just to get it going cyg_drv_dsr_lock(); (chan->callbacks->xmt_char)(chan); cyg_drv_dsr_unlock(); } if (smc_chan->txbd->length != 0) { // Make sure it gets started quicc_smc_serial_flush(smc_chan); } smc_chan->tx_enabled = true; cyg_drv_interrupt_unmask(smc_chan->int_num);}// Disable the transmitter on the devicestatic void quicc_smc_serial_stop_xmit(serial_channel *chan){ quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv; // If anything is in the last buffer, need to get it started if (smc_chan->txbd->length != 0) { quicc_smc_serial_flush(smc_chan); // Note: interrupt will get masked after this buffer finishes } else { cyg_drv_interrupt_mask(smc_chan->int_num); } smc_chan->tx_enabled = false;}// Serial I/O - low level interrupt handler (ISR)static cyg_uint32 quicc_smc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data){ serial_channel *chan = (serial_channel *)data; quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv; cyg_drv_interrupt_mask(smc_chan->int_num); return CYG_ISR_CALL_DSR; // Cause DSR to be run}// Serial I/O - high level interrupt handler (DSR)static void quicc_smc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data){ serial_channel *chan = (serial_channel *)data; quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv; volatile struct smc_regs *ctl = smc_chan->ctl; volatile struct cp_bufdesc *txbd; volatile struct cp_bufdesc *rxbd = smc_chan->rxbd; struct cp_bufdesc *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", ctl->smc_smce, _stime, _time); enable_diag_uart = 1;#endif // CYGDBG_DIAG_BUF if (ctl->smc_smce & QUICC_SMCE_TX) {#ifdef XX_CYGDBG_DIAG_BUF enable_diag_uart = 0; txbd = smc_chan->tbase; for (i = 0; i < CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_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 // 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) {#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 &= ~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() + smc_chan->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 & QUICC_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, 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++; } }#ifdef CYGDBG_DIAG_BUF enable_diag_uart = 1;#endif // CYGDBG_DIAG_BUF smc_chan->rxbd = (struct cp_bufdesc *)rxbd; } if (ctl->smc_smce & QUICC_SMCE_BSY) {#ifdef CYGDBG_DIAG_BUF enable_diag_uart = 0; diag_printf("RX BUSY interrupt\n"); enable_diag_uart = 1;#endif // CYGDBG_DIAG_BUF ctl->smc_smce = QUICC_SMCE_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", ctl->smc_smce, _stime, _time); enable_diag_uart = 1;#endif // CYGDBG_DIAG_BUF cyg_drv_interrupt_acknowledge(smc_chan->int_num); cyg_drv_interrupt_unmask(smc_chan->int_num);#ifdef CYGDBG_DIAG_BUF cyg_drv_isr_unlock();#endif // CYGDBG_DIAG_BUF}voidshow_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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -