?? sh_scif_serial.c
字號:
// Enable the transmitter on the devicestatic voidsh_scif_start_xmit(serial_channel *chan){ cyg_uint8 _scr; sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv; xmt_req_reply_t _block_status = CYG_XMT_DISABLED; if (sh_chan->tx_enabled) return;#ifdef CYGINT_IO_SERIAL_SH_SCIF_DMA // Check if the engine is already running. If so, return. Note // that there will never be a race on this flag - the caller of // this function is respecting a per-channel lock. if (sh_chan->dma_xmt_running) return; // If the channel uses DMA, try to start a DMA job for this - // but handle the case where the job doesn't start by falling // back to the FIFO/interrupt based code. if (sh_chan->dma_enable) { _block_status = sh_scif_start_dma_xmt(chan); CYG_ASSERT(_block_status != CYG_XMT_EMPTY, "start_xmit called with empty buffers!"); sh_chan->dma_xmt_running = (CYG_XMT_OK == _block_status) ? true : false; }#endif // CYGINT_IO_SERIAL_SH_SCIF_DMA if (CYG_XMT_DISABLED == _block_status) { // Mask interrupts while changing the CR since a rx // interrupt or another thread doing the same in the // middle of this would result in a bad CR state. cyg_drv_isr_lock(); { HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); _scr |= CYGARC_REG_SCIF_SCSCR_TIE; // Enable xmit interrupt#ifdef CYGINT_IO_SERIAL_SH_SCIF_IRDA if (sh_chan->irda_mode) { // Enable transmitter - this automatically disables // the receiver in the hardware. Doing it explicitly // (like for async RX/TX below) causes more spurious // characters to be read when re-enabling the // receiver. _scr |= CYGARC_REG_SCIF_SCSCR_TE; }#endif#ifdef CYGINT_IO_SERIAL_SH_SCIF_ASYNC_RXTX if (sh_chan->async_rxtx_mode) { // Enable transmitter _scr |= CYGARC_REG_SCIF_SCSCR_TE; // Disable receiver _scr &= ~CYGARC_REG_SCIF_SCSCR_RE; }#endif HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); sh_chan->tx_enabled = true; } cyg_drv_isr_unlock(); }}// Disable the transmitter on the devicestatic void sh_scif_stop_xmit(serial_channel *chan){ cyg_uint8 _scr; sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv; // In IrDA and async mode the transmitter needs to be disabled, so // wait for transmission to complete within reason: disable it // after 0.1s if (0#ifdef CYGINT_IO_SERIAL_SH_SCIF_IRDA || sh_chan->irda_mode#endif#if defined(CYGINT_IO_SERIAL_SH_SCIF_ASYNC_RXTX) || sh_chan->async_rxtx_mode#endif ) { cyg_uint16 sr; int i = 1000; do { HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, sr); if (sr & CYGARC_REG_SCIF_SCSSR_TEND) break; HAL_DELAY_US(100); } while (i-- > 0); } // Mask interrupts while changing the CR since a rx interrupt or // another thread doing the same in the middle of this would // result in a bad CR state. cyg_drv_isr_lock(); { HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); _scr &= ~CYGARC_REG_SCIF_SCSCR_TIE; // Disable xmit interrupt#ifdef CYGINT_IO_SERIAL_SH_SCIF_IRDA if (sh_chan->irda_mode) {#ifdef CYGHWR_IO_SERIAL_SH_SCIF_IRDA_TXRX_COMPENSATION // In IrDA mode there will be generated spurious RX // events when the TX unit is switched on. Eat that // character. cyg_uint8 _junk; cyg_uint16 _sr; HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCFRDR, _junk); // Clear buffer full flag (read back first) HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr); HAL_WRITE_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, CYGARC_REG_SCIF_SCSSR_CLEARMASK & ~(CYGARC_REG_SCIF_SCSSR_RDF|CYGARC_REG_SCIF_SCSSR_DR));#endif // Disable transmitter _scr &= ~CYGARC_REG_SCIF_SCSCR_TE; }#endif#ifdef CYGINT_IO_SERIAL_SH_SCIF_ASYNC_RXTX if (sh_chan->async_rxtx_mode) { // Enable receiver again _scr |= CYGARC_REG_SCIF_SCSCR_RE; // Disable transmitter _scr &= ~CYGARC_REG_SCIF_SCSCR_TE; }#endif HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); } cyg_drv_isr_unlock();#ifdef CYGINT_IO_SERIAL_SH_SCIF_DMA // If the channel uses DMA, stop the DMA engine. if (sh_chan->dma_xmt_running) sh_scif_stop_dma_xmt(chan); else // dangling else!#endif // CYGINT_IO_SERIAL_SH_SCIF_DMA sh_chan->tx_enabled = false;}// Serial I/O - low level tx interrupt handler (ISR)static cyg_uint32 sh_scif_tx_ISR(cyg_vector_t vector, cyg_addrword_t data){ serial_channel *chan = (serial_channel *)data; sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv; cyg_uint8 _scr; HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); _scr &= ~CYGARC_REG_SCIF_SCSCR_TIE; // mask out tx interrupts HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); return CYG_ISR_CALL_DSR; // Cause DSR to be run}// Serial I/O - high level tx interrupt handler (DSR)static void sh_scif_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data){ serial_channel *chan = (serial_channel *)data; sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv; xmt_req_reply_t _block_status = CYG_XMT_DISABLED; cyg_uint16 _fdr, _sr; int _space, _chars_avail; unsigned char* _chars; CYG_ADDRWORD _base = sh_chan->ctrl_base; // Always check if we're supposed to be enabled; the driver runs // with DSRs disabled, and a DSR may have been posted (but not // executed) before the interrupt was masked. if (!sh_chan->tx_enabled) return;#ifdef CYGHWR_SH_SCIF_FLOW_DSRDTR CYGHWR_SH_SCIF_FLOW_DSRDTR_TX(chan);#endif // How many chars can we stuff into the FIFO? HAL_READ_UINT16(_base+SCIF_SCFDR, _fdr); _space = 16 - ((_fdr & CYGARC_REG_SCIF_SCFDR_TCOUNT_MASK) >> CYGARC_REG_SCIF_SCFDR_TCOUNT_shift); // Try to do the transfer most efficiently _block_status = (chan->callbacks->data_xmt_req)(chan, _space, &_chars_avail, &_chars); if (CYG_XMT_OK == _block_status) { // Transfer the data in block(s). do { int i = _chars_avail; while (i--) { HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCFTDR, *_chars++); _space--; } (chan->callbacks->data_xmt_done)(chan, _chars_avail); } while (_space > 0 && (CYG_XMT_OK == (chan->callbacks->data_xmt_req)(chan, _space, &_chars_avail, &_chars))); } else if (CYG_XMT_DISABLED == _block_status) { // Transfer char-by-char, but stop if the transmitter // gets disabled. while (_space-- && sh_chan->tx_enabled) (chan->callbacks->xmt_char)(chan); } // Clear FIFO-empty/transmit end flags (read back sr first) HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr); HAL_WRITE_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, CYGARC_REG_SCIF_SCSSR_CLEARMASK & ~CYGARC_REG_SCIF_SCSSR_TDFE); if (sh_chan->tx_enabled) { cyg_uint8 _scr; HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); _scr |= CYGARC_REG_SCIF_SCSCR_TIE; // unmask tx interrupts HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); }}// Serial I/O - low level RX interrupt handler (ISR)static cyg_uint32 sh_scif_rx_ISR(cyg_vector_t vector, cyg_addrword_t data){ serial_channel *chan = (serial_channel *)data; sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv; cyg_uint8 _scr; HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); _scr &= ~CYGARC_REG_SCIF_SCSCR_RIE; // mask rx interrupts HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); return CYG_ISR_CALL_DSR; // Cause DSR to be run}// Serial I/O - high level rx interrupt handler (DSR)static void sh_scif_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data){ serial_channel *chan = (serial_channel *)data; sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv; cyg_uint8 _scr; cyg_uint16 _fdr, _sr; int _avail, _space_avail; unsigned char* _space; rcv_req_reply_t _block_status; HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCFDR, _fdr); HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr); _avail = _fdr & CYGARC_REG_SCIF_SCFDR_RCOUNT_MASK; if (_avail > 0) { _block_status = (chan->callbacks->data_rcv_req)(chan, _avail, &_space_avail, &_space); if (CYG_RCV_OK == _block_status) { // Transfer the data in block(s). do { int i = _space_avail; while(i--) { cyg_uint8 _c; HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCFRDR, _c); *_space++ = _c; _avail--; } (chan->callbacks->data_rcv_done)(chan, _space_avail); } while (_avail > 0 && (CYG_RCV_OK == (chan->callbacks->data_rcv_req)(chan, _avail, &_space_avail, &_space))); } else { // Transfer the data char-by-char both for CYG_RCV_FULL // and CYG_RCV_DISABLED, leaving all policy decisions with // the IO driver. while(_avail--) { cyg_uint8 _c; HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCFRDR, _c); (chan->callbacks->rcv_char)(chan, _c); } } } else { CYG_ASSERT(_avail > 0, "No data to be read in RX DSR"); } // Clear buffer full flag (read back first) HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr); HAL_WRITE_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, CYGARC_REG_SCIF_SCSSR_CLEARMASK & ~(CYGARC_REG_SCIF_SCSSR_RDF|CYGARC_REG_SCIF_SCSSR_DR)); HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); _scr |= CYGARC_REG_SCIF_SCSCR_RIE; // unmask rx interrupts HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr);}// Serial I/O - low level error interrupt handler (ISR)static cyg_uint32 sh_scif_er_ISR(cyg_vector_t vector, cyg_addrword_t data){ serial_channel *chan = (serial_channel *)data; sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv; cyg_uint8 _scr; HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); _scr &= ~CYGARC_REG_SCIF_SCSCR_RIE; // mask rx interrupts HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); return CYG_ISR_CALL_DSR; // Cause DSR to be run}// Serial I/O - high level error interrupt handler (DSR)static void sh_scif_er_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data){ serial_channel *chan = (serial_channel *)data; sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv; cyg_uint16 _ssr, _ssr_mask;#ifdef SCIF_SC2SSR cyg_uint8 _ssr2;#endif cyg_uint8 _scr;#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS cyg_serial_line_status_t stat;#endif HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _ssr); _ssr_mask = CYGARC_REG_SCIF_SCSSR_CLEARMASK; // Clear the ER bit _ssr_mask &= ~CYGARC_REG_SCIF_SCSSR_ER;#ifdef SCIF_SC2SSR HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SC2SSR, _ssr2); if (_ssr2 & CYGARC_REG_SCIF_SC2SSR_ORER) { _ssr2 &= ~CYGARC_REG_SCIF_SC2SSR_ORER; HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SC2SSR, _ssr2); stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR; (chan->callbacks->indicate_status)(chan, &stat ); }#endif if (_ssr & CYGARC_REG_SCIF_SCSSR_FER) { // _ssr_mask &= ~CYGARC_REG_SCIF_SCSSR_FER; // FER is read-only#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS stat.which = CYGNUM_SERIAL_STATUS_FRAMEERR; (chan->callbacks->indicate_status)(chan, &stat );#endif } if (_ssr & CYGARC_REG_SCIF_SCSSR_PER) { // _ssr_mask &= ~CYGARC_REG_SCIF_SCSSR_PER; // PER is read-only#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS stat.which = CYGNUM_SERIAL_STATUS_PARITYERR; (chan->callbacks->indicate_status)(chan, &stat );#endif } if (_ssr & CYGARC_REG_SCIF_SCSSR_BRK) { _ssr_mask &= ~CYGARC_REG_SCIF_SCSSR_BRK;#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS stat.which = CYGNUM_SERIAL_STATUS_BREAK; (chan->callbacks->indicate_status)(chan, &stat );#endif } HAL_WRITE_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _ssr_mask); HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr); _scr |= CYGARC_REG_SCIF_SCSCR_RIE; // unmask rx interrupts HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCSCR, _scr);}#endif // ifdef CYGDAT_IO_SERIAL_SH_SCIF_INL
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -