at91_serial.c

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

C
579
字号
    diag_printf("AT91 SERIAL init - dev: %x.%d\n", at91_chan->base, at91_chan->int_num);#endif    at91_chan->curbuf = 0;    at91_chan->flags = SIFLG_NONE;    at91_chan->stat = 0;    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices    if (chan->out_cbuf.len != 0) {        cyg_drv_interrupt_create(at91_chan->int_num,                                 4,                      // Priority                                 (cyg_addrword_t)chan,   // Data item passed to interrupt handler                                 at91_serial_ISR,                                 at91_serial_DSR,                                 &at91_chan->serial_interrupt_handle,                                 &at91_chan->serial_interrupt);        cyg_drv_interrupt_attach(at91_chan->serial_interrupt_handle);        cyg_drv_interrupt_unmask(at91_chan->int_num);    }    res = at91_serial_config_port(chan, &chan->config, true);    return res;}// This routine is called when the device is "looked" up (i.e. attached)static Cyg_ErrNo at91_serial_lookup(struct cyg_devtab_entry **tab,                   struct cyg_devtab_entry *sub_tab,                  const char *name){    serial_channel * const chan = (serial_channel *) (*tab)->priv;    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices    return ENOERR;}// Send a character to the device output buffer.// Return 'true' if character is sent to devicestatic boolat91_serial_putc_interrupt(serial_channel *chan, unsigned char c){    at91_serial_info * const at91_chan = (at91_serial_info *) chan->dev_priv;    const bool res = (at91_chan->flags & SIFLG_XMIT_BUSY) == 0;        if (res) {        const CYG_ADDRWORD base = at91_chan->base;        HAL_WRITE_UINT32(base + AT91_US_THR, c);        at91_chan->flags |= SIFLG_XMIT_BUSY;    }    return res;}#if (defined(CYGPKG_IO_SERIAL_ARM_AT91_SERIAL0) && CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE == 0) \ || (defined(CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1) && CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE == 0)static boolat91_serial_putc_polled(serial_channel *chan, unsigned char c){    at91_serial_info * const at91_chan = (at91_serial_info *) chan->dev_priv;    const CYG_ADDRWORD base = at91_chan->base;    CYG_WORD32 w;        while (HAL_READ_UINT32(base + AT91_US_CSR, w), (w & AT91_US_IER_TxRDY) == 0)        CYG_EMPTY_STATEMENT;    HAL_WRITE_UINT32(base + AT91_US_THR, c);    return true;}#endif// Fetch a character from the device input buffer, waiting if necessarystatic unsigned char at91_serial_getc_interrupt(serial_channel *chan){    at91_serial_info * const at91_chan = (at91_serial_info *) chan->dev_priv;    const CYG_ADDRWORD base = at91_chan->base;    CYG_WORD32 c;    // Read data    HAL_READ_UINT32(base + AT91_US_RHR, c);    return (unsigned char) c;}#if (defined(CYGPKG_IO_SERIAL_ARM_AT91_SERIAL0) && CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE == 0) \ || (defined(CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1) && CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE == 0)static unsigned char at91_serial_getc_polled(serial_channel *chan){    at91_serial_info * const at91_chan = (at91_serial_info *) chan->dev_priv;    const CYG_ADDRWORD base = at91_chan->base;    CYG_WORD32 c;    while (HAL_READ_UINT32(base + AT91_US_CSR, c), (c & AT91_US_IER_RxRDY) == 0)        CYG_EMPTY_STATEMENT;    // Read data    HAL_READ_UINT32(base + AT91_US_RHR, c);    return (unsigned char) c;}#endif// Set up the device characteristics; baud rate, etc.static Cyg_ErrNoat91_serial_set_config(serial_channel *chan, cyg_uint32 key,                       const void *xbuf, cyg_uint32 *len){    switch (key) {    case CYG_IO_SET_CONFIG_SERIAL_INFO:      {        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;        if ( *len < sizeof(cyg_serial_info_t) ) {            return -EINVAL;        }        *len = sizeof(cyg_serial_info_t);        if ( true != at91_serial_config_port(chan, config, false) )            return -EINVAL;      }      break;    default:        return -EINVAL;    }    return ENOERR;}// Enable the transmitter on the devicestatic voidat91_serial_start_xmit(serial_channel *chan){    at91_serial_info * const at91_chan = (at91_serial_info *) chan->dev_priv;    const CYG_ADDRWORD base = at91_chan->base;    unsigned char * chars;    xmt_req_reply_t res;        cyg_drv_dsr_lock();    if ((at91_chan->flags & SIFLG_XMIT_CONTINUE) == 0) {        res = (chan->callbacks->data_xmt_req)(chan, 0xffff, &at91_chan->transmit_size, &chars);        switch (res)        {            case CYG_XMT_OK:                HAL_WRITE_UINT32(base + AT91_US_TPR, (CYG_WORD32) chars);                HAL_WRITE_UINT32(base + AT91_US_TCR, at91_chan->transmit_size);                at91_chan->flags |= SIFLG_XMIT_CONTINUE;                HAL_WRITE_UINT32(base + AT91_US_IER, AT91_US_IER_ENDTX);                break;            case CYG_XMT_DISABLED:                (chan->callbacks->xmt_char)(chan);  // Kick transmitter                at91_chan->flags |= SIFLG_XMIT_CONTINUE;                HAL_WRITE_UINT32(base + AT91_US_IER, AT91_US_IER_TxRDY);                break;            default:                // No data or unknown error - can't do anything about it                break;        }    }    cyg_drv_dsr_unlock();}// Disable the transmitter on the devicestatic void at91_serial_stop_xmit(serial_channel *chan){    at91_serial_info * const at91_chan = (at91_serial_info *) chan->dev_priv;    const CYG_ADDRWORD base = at91_chan->base;    HAL_WRITE_UINT32(base + AT91_US_IDR, AT91_US_IER_TxRDY | AT91_US_IER_ENDTX);    at91_chan->flags &= ~SIFLG_XMIT_CONTINUE;}// Serial I/O - low level interrupt handler (ISR)static cyg_uint32 at91_serial_ISR(cyg_vector_t vector, cyg_addrword_t data){    serial_channel * const chan = (serial_channel *) data;    at91_serial_info * const at91_chan = (at91_serial_info *) chan->dev_priv;    const CYG_ADDRWORD base = at91_chan->base;    CYG_WORD32 stat, mask;    HAL_READ_UINT32(base + AT91_US_CSR, stat);    HAL_READ_UINT32(base + AT91_US_IMR, mask);    stat &= mask;    if (stat & (AT91_US_IER_ENDRX | AT91_US_IER_TIMEOUT)) {        cyg_uint32 x;        HAL_WRITE_UINT32(base + AT91_US_IDR, AT91_US_IER_ENDRX | AT91_US_IER_TIMEOUT);        HAL_WRITE_UINT32(base + AT91_US_RCR, 0);        HAL_WRITE_UINT32(base + AT91_US_RTO, 0);        HAL_READ_UINT32(base + AT91_US_RPR, x);        HAL_WRITE_UINT32(            base + AT91_US_RCR,            (CYG_ADDRESS) at91_chan->rcv_buffer[at91_chan->curbuf]                + at91_chan->rcv_chunk_size + RCVBUF_EXTRA - x        );    }    if (stat & (AT91_US_IER_TxRDY | AT91_US_IER_ENDTX))      HAL_WRITE_UINT32(base + AT91_US_IDR, AT91_US_IER_TxRDY | AT91_US_IER_ENDTX);    at91_chan->stat |= stat;    cyg_drv_interrupt_acknowledge(vector);    return CYG_ISR_CALL_DSR;}// Serial I/O - high level interrupt handler (DSR)static void       at91_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data){    serial_channel * const chan = (serial_channel *) data;    at91_serial_info * const at91_chan = (at91_serial_info *) chan->dev_priv;    const CYG_ADDRWORD base = at91_chan->base;    CYG_WORD32 stat;    cyg_drv_interrupt_mask(vector);        stat = at91_chan->stat;    at91_chan->stat = 0;    cyg_drv_interrupt_unmask(vector);        if (stat & (AT91_US_IER_ENDRX | AT91_US_IER_TIMEOUT)) {        const cyg_uint8 cb = at91_chan->curbuf, nb = cb ^ 0x01;        const cyg_uint8 * p = at91_chan->rcv_buffer[cb], * end;        at91_chan->curbuf = nb;        HAL_WRITE_UINT32(base + AT91_US_RCR, 0);        HAL_READ_UINT32(base + AT91_US_RPR, (CYG_ADDRESS) end);        HAL_WRITE_UINT32(base + AT91_US_RTO, RCV_TIMEOUT);	HAL_WRITE_UINT32(base + AT91_US_CR, AT91_US_CR_RSTATUS | AT91_US_CR_STTTO);        HAL_WRITE_UINT32(base + AT91_US_RPR, (CYG_ADDRESS) at91_chan->rcv_buffer[nb]);        HAL_WRITE_UINT32(base + AT91_US_RCR, at91_chan->rcv_chunk_size);        HAL_WRITE_UINT32(            base + AT91_US_IER,            AT91_US_IER_ENDRX | AT91_US_IER_TIMEOUT        );        while (p < end) {            rcv_req_reply_t res;            int space_avail;            unsigned char *space;            res = (chan->callbacks->data_rcv_req)(              chan,              end - at91_chan->rcv_buffer[cb],              &space_avail,              &space            );            switch (res)            {                case CYG_RCV_OK:                    memcpy(space, p, space_avail);                    (chan->callbacks->data_rcv_done)(chan, space_avail);                    p += space_avail;                    break;                case CYG_RCV_DISABLED:                    (chan->callbacks->rcv_char)(chan, *p++);                    break;                default:                    // Buffer full or unknown error, can't do anything about it                    // Discard data                    CYG_FAIL("Serial receiver buffer overflow");                    p = end;                    break;            }        }    }    if (stat & AT91_US_IER_TxRDY) {        at91_chan->flags &= ~SIFLG_XMIT_BUSY;        (chan->callbacks->xmt_char)(chan);        if (at91_chan->flags & SIFLG_XMIT_CONTINUE)            HAL_WRITE_UINT32(base + AT91_US_IER, AT91_US_IER_TxRDY);    }        if (stat & AT91_US_IER_ENDTX) {        (chan->callbacks->data_xmt_done)(chan, at91_chan->transmit_size);        if (at91_chan->flags & SIFLG_XMIT_CONTINUE) {            unsigned char * chars;            xmt_req_reply_t res;            res = (chan->callbacks->data_xmt_req)(chan, 0xffff, &at91_chan->transmit_size, &chars);            switch (res)            {                case CYG_XMT_OK:                    HAL_WRITE_UINT32(base + AT91_US_TPR, (CYG_WORD32) chars);                    HAL_WRITE_UINT32(base + AT91_US_TCR, at91_chan->transmit_size);                    at91_chan->flags |= SIFLG_XMIT_CONTINUE;                    HAL_WRITE_UINT32(base + AT91_US_IER, AT91_US_IER_ENDTX);                    break;                default:                    // No data or unknown error - can't do anything about it                    // CYG_XMT_DISABLED should not happen here!                    break;            }        }    }}#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?