⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ebsa285_serial.c

📁 基于ecos的redboot
💻 C
📖 第 1 页 / 共 2 页
字号:
{
    int dummy, h, m, l;
    
    // Make sure everything is off
    *SA110_UART_CONTROL_REGISTER = SA110_UART_DISABLED | SA110_SIR_DISABLED;
    
    // Read the RXStat to drain the fifo
    dummy = *SA110_UART_RXSTAT;

    // Set the baud rate - this also turns the uart on.
    // 
    // Note that the ordering of these writes is critical,
    // and the writes to the H_BAUD_CONTROL and CONTROL_REGISTER
    // are necessary to force the UART to update its register
    // contents.

    l = bauds[new_config->baud].divisor_low;   // zeros in unused slots here
    m = bauds[new_config->baud].divisor_high;  // and here
    h = SA110_UART_BREAK_DISABLED    |      
        select_stop_bits[new_config->stop] |   // -1s in unused slots for these
        select_parity[new_config->parity]  |   // and these
        SA110_UART_FIFO_ENABLED |              // and these below
        select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5];

    if ( 0 != (l + m) && h >= 0 && h < 256 ) {
        *SA110_UART_L_BAUD_CONTROL = l;
        *SA110_UART_M_BAUD_CONTROL = m;
        *SA110_UART_H_BAUD_CONTROL = h;
        init = true; // AOK
    }
    else if ( init ) {
        // put in some sensible defaults
        *SA110_UART_L_BAUD_CONTROL   = 0x13; // bp->divisor_low;
        *SA110_UART_M_BAUD_CONTROL   = 0x00; // bp->divisor_high;
        *SA110_UART_H_BAUD_CONTROL = SA110_UART_BREAK_DISABLED    |
            SA110_UART_PARITY_DISABLED   |
            SA110_UART_STOP_BITS_ONE     |
            SA110_UART_FIFO_ENABLED      |
            SA110_UART_DATA_LENGTH_8_BITS;
    }

    // All set, re-enable the device:
    *SA110_UART_CONTROL_REGISTER = SA110_UART_ENABLED | SA110_SIR_DISABLED;

    if (init && new_config != &chan->config) {
        // record the new setup
        chan->config = *new_config;
    }
    // All done
    return init;
}

// Function to initialize the device.  Called at bootstrap time.
static bool 
ebsa285_serial_init(struct cyg_devtab_entry *tab)
{
    serial_channel *chan = (serial_channel *)tab->priv;
    ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
#ifdef CYGDBG_IO_INIT
    diag_printf("EBSA285 SERIAL init - dev: %x\n", ebsa285_chan);
#endif
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
    if (chan->out_cbuf.len != 0) {

        // first for rx
        cyg_drv_interrupt_create(ebsa285_chan->rx.int_num,
                                 99,                   // Priority - unused
                                 (cyg_addrword_t)chan, //  Data item passed to interrupt handler
                                 ebsa285_serial_rx_ISR,
                                 ebsa285_serial_rx_DSR,
                                 &ebsa285_chan->rx.serial_interrupt_handle,
                                 &ebsa285_chan->rx.serial_interrupt);
        cyg_drv_interrupt_attach(ebsa285_chan->rx.serial_interrupt_handle);
        cyg_drv_interrupt_unmask(ebsa285_chan->rx.int_num);

        // then for tx
        cyg_drv_interrupt_create(ebsa285_chan->tx.int_num,
                                 99,                   // Priority - unused
                                 (cyg_addrword_t)chan, //  Data item passed to interrupt handler
                                 ebsa285_serial_tx_ISR,
                                 ebsa285_serial_tx_DSR,
                                 &ebsa285_chan->tx.serial_interrupt_handle,
                                 &ebsa285_chan->tx.serial_interrupt);
        cyg_drv_interrupt_attach(ebsa285_chan->tx.serial_interrupt_handle);
        // DO NOT cyg_drv_interrupt_unmask(ebsa285_chan->tx.int_num);
        ebsa285_chan->tx_active = 0;
    }
    (void)ebsa285_serial_config_port(chan, &chan->config, true);
    return true;
}

// This routine is called when the device is "looked" up (i.e. attached)
static Cyg_ErrNo 
ebsa285_serial_lookup(struct cyg_devtab_entry **tab, 
                  struct cyg_devtab_entry *sub_tab,
                  const char *name)
{
    serial_channel *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 device
static bool
ebsa285_serial_putc(serial_channel *chan, unsigned char c)
{
    if ((*SA110_UART_FLAG_REGISTER & SA110_TX_FIFO_STATUS_MASK) == SA110_TX_FIFO_BUSY)
        return false; // No space
    
    *SA110_UART_DATA_REGISTER = c; // Transmit buffer is empty
    return true;
}

// Fetch a character from the device input buffer, waiting if necessary
static unsigned char 
ebsa285_serial_getc(serial_channel *chan)
{
    unsigned char c;
    while ((*SA110_UART_FLAG_REGISTER & SA110_RX_FIFO_STATUS_MASK) == SA110_RX_FIFO_EMPTY)
        ; // wait for char
    c = (char)(*SA110_UART_DATA_REGISTER & 0xFF);
    // no error checking... no way to return the info
    return c;
}

// Set up the device characteristics; baud rate, etc.
static Cyg_ErrNo
ebsa285_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 != ebsa285_serial_config_port(chan, config, false) )
            return -EINVAL;
      }
      break;
    default:
        return -EINVAL;
    }
    return ENOERR;
}

// Enable the transmitter on the device (nope, already in use by hal_diag)
static void
ebsa285_serial_start_xmit(serial_channel *chan)
{
    ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
    ebsa285_chan->tx_active = 1;
    cyg_drv_interrupt_unmask(ebsa285_chan->tx.int_num);
}

// Disable the transmitter on the device (nope, remains in use by hal_diag)
static void 
ebsa285_serial_stop_xmit(serial_channel *chan)
{
    ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
    cyg_drv_interrupt_mask(ebsa285_chan->tx.int_num);
    ebsa285_chan->tx_active = 0;
}

// Serial I/O - low level interrupt handlers (ISR)
static cyg_uint32 
ebsa285_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
    cyg_drv_interrupt_mask(ebsa285_chan->rx.int_num);
    cyg_drv_interrupt_acknowledge(ebsa285_chan->rx.int_num);
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
}

static cyg_uint32 
ebsa285_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
    cyg_drv_interrupt_mask(ebsa285_chan->tx.int_num);
    cyg_drv_interrupt_acknowledge(ebsa285_chan->tx.int_num);
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
}

// Serial I/O - high level interrupt handlers (DSR)
static void       
ebsa285_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
    if ((*SA110_UART_FLAG_REGISTER & SA110_RX_FIFO_STATUS_MASK) != SA110_RX_FIFO_EMPTY) {
        char c;
        int status;
        c = (char)(*SA110_UART_DATA_REGISTER & 0xFF);
        status = *SA110_UART_RXSTAT;
        if ( 0 == (status & (SA110_UART_FRAMING_ERROR_MASK |
                             SA110_UART_PARITY_ERROR_MASK  |
                             SA110_UART_OVERRUN_ERROR_MASK)) )
            (chan->callbacks->rcv_char)(chan, c);
    }
    cyg_drv_interrupt_unmask(ebsa285_chan->rx.int_num);
}

static void       
ebsa285_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
    if ((*SA110_UART_FLAG_REGISTER & SA110_TX_FIFO_STATUS_MASK) != SA110_TX_FIFO_BUSY) {
        (chan->callbacks->xmt_char)(chan);
    }
    if ( ebsa285_chan->tx_active ) // it might be halted in callback above
        cyg_drv_interrupt_unmask(ebsa285_chan->tx.int_num);
}
#endif // CYGPKG_IO_SERIAL_ARM_EBSA285

// ------------------------------------------------------------------------
// EOF ebsa285_serial.c

⌨️ 快捷键说明

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