sh_scif_serial.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,079 行 · 第 1/3 页

C
1,079
字号
// 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 + =
减小字号Ctrl + -
显示快捷键?