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 + -
显示快捷键?