mn10300_serial.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,037 行 · 第 1/3 页

C
1,037
字号
    cr |= select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5];
    cr |= select_stop_bits[new_config->stop];
    cr |= select_parity[new_config->parity];

    cr |= LCR_RXE | LCR_TXE;        // enable Rx and Tx
    
#ifdef CYGPKG_HAL_MN10300_AM31
    if( mn10300_chan->is_serial2 )
    {
        // AM31 has an extra TX interrupt enable bit for serial 2.
        DISABLE_TRANSMIT_INTERRUPT(mn10300_chan);
    }
#endif        

    // Write CR into hardware
    HAL_WRITE_UINT16(mn10300_chan->base+SERIAL_CTR, cr);    

    sr = mn10300_read_sr(mn10300_chan);

    if (new_config != &chan->config) {
        chan->config = *new_config;
    }
    return true;
}

//-------------------------------------------------------------------------
// Function to initialize the device.  Called at bootstrap time.

bool mn10300_serial_init(struct cyg_devtab_entry *tab)
{
    serial_channel *chan = (serial_channel *)tab->priv;
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;

    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices

#ifndef CYGPKG_IO_SERIAL_MN10300_POLLED_MODE    
    if (chan->out_cbuf.len != 0) {
        // Install and enable the receive interrupt
        cyg_drv_interrupt_create(mn10300_chan->rx_int,
                                 4,                      // Priority - what goes here?
                                 (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
                                 mn10300_serial_rx_ISR,
                                 mn10300_serial_rx_DSR,
                                 &mn10300_chan->rx_interrupt_handle,
                                 &mn10300_chan->rx_interrupt);
        cyg_drv_interrupt_attach(mn10300_chan->rx_interrupt_handle);
        cyg_drv_interrupt_unmask(mn10300_chan->rx_int);

        // Install and enable the transmit interrupt
        cyg_drv_interrupt_create(mn10300_chan->tx_int,
                                 4,                      // Priority - what goes here?
                                 (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
                                 mn10300_serial_tx_ISR,
                                 mn10300_serial_tx_DSR,
                                 &mn10300_chan->tx_interrupt_handle,
                                 &mn10300_chan->tx_interrupt);
        cyg_drv_interrupt_attach(mn10300_chan->tx_interrupt_handle);
        cyg_drv_interrupt_mask(mn10300_chan->tx_int);
    }
#endif
    
    mn10300_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 
mn10300_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;
}

//-------------------------------------------------------------------------
// Return 'true' if character is sent to device

bool
mn10300_serial_putc(serial_channel *chan, unsigned char c)
{
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;
    cyg_uint8 sr = mn10300_read_sr( mn10300_chan);

    if( (sr & SR_TBF) == 0 )
    {
        HAL_WRITE_UINT8( mn10300_chan->base+SERIAL_TXB, c );

        return true;
    }
    else return false;
}

//-------------------------------------------------------------------------

unsigned char 
mn10300_serial_getc(serial_channel *chan)
{
    unsigned char c;
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;
    do
    {
        cyg_uint8 sr = mn10300_read_sr( mn10300_chan );

        if( (sr & SR_RBF) != 0 )
        {
            HAL_READ_UINT8( mn10300_chan->base+SERIAL_RXB, c );

            break;
        }
        
    } while(1);
    
    return c;
}

//-------------------------------------------------------------------------

static Cyg_ErrNo
mn10300_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 != mn10300_serial_config_port(chan, config, false) )
            return -EINVAL;
      }
      break;
    default:
        return -EINVAL;
    }
    return ENOERR;
}

//-------------------------------------------------------------------------
// Enable the transmitter on the device

static void
mn10300_serial_start_xmit(serial_channel *chan)
{
#ifndef CYGPKG_IO_SERIAL_MN10300_POLLED_MODE    
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;
    cyg_uint16 cr;

    HAL_READ_UINT16( mn10300_chan->base+SERIAL_CTR, cr );

    ENABLE_TRANSMIT_INTERRUPT(mn10300_chan);    

    HAL_WRITE_UINT16( mn10300_chan->base+SERIAL_CTR, cr );

    cyg_drv_interrupt_unmask(mn10300_chan->tx_int);
    
    (chan->callbacks->xmt_char)(chan);
#endif    
}

//-------------------------------------------------------------------------
// Disable the transmitter on the device

static void 
mn10300_serial_stop_xmit(serial_channel *chan)
{
#ifndef CYGPKG_IO_SERIAL_MN10300_POLLED_MODE    
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;
    cyg_uint16 cr;
    cyg_uint16 sr;

    // Wait until the transmitter has actually stopped before turning it off.
    
    do
    {
        sr = mn10300_read_sr( mn10300_chan );
        
    } while( sr & SR_TXF );
    
    HAL_READ_UINT16( mn10300_chan->base+SERIAL_CTR, cr );

    DISABLE_TRANSMIT_INTERRUPT(mn10300_chan);
    
    HAL_WRITE_UINT16( mn10300_chan->base+SERIAL_CTR, cr );

    cyg_drv_interrupt_mask(mn10300_chan->tx_int);
    
#endif    
}

//-------------------------------------------------------------------------
// Serial I/O - low level interrupt handlers (ISR)

#ifndef CYGPKG_IO_SERIAL_MN10300_POLLED_MODE

#ifdef CYG_HAL_MN10300_SERIAL_RX_FIFO

// This version of the RX ISR implements a simple receive FIFO. The
// MN10300 serial devices do not have hardware FIFOs (as found in
// 16550s for example), and it can be difficult at times to keep up
// with higher baud rates without overrunning. This ISR implements a
// software equivalent of the hardware FIFO, placing recieved
// characters into the FIFO as soon as they arrive. Whenever the DSR
// is run, it collects all the pending characters from the FIFO for
// delivery to the application. Neither the ISR or DSR disable
// interrupts, instead we rely on being able to write the head and
// tail pointers atomically, to implement lock-free synchronization.

static cyg_uint32 
mn10300_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;
    cyg_uint8 sr = mn10300_read_sr( mn10300_chan);

    while( (sr & SR_RBF) != 0 )
    {
        register cyg_int32 head = mn10300_chan->fifo_head;
        cyg_uint8 c;
        int i;
        HAL_READ_UINT8( mn10300_chan->base+SERIAL_RXB, c );

        mn10300_chan->fifo[head++] = c;

        if( head >= sizeof(mn10300_chan->fifo) )
            head = 0;

        mn10300_chan->fifo_head = head;

        sr = mn10300_read_sr( mn10300_chan);

    }

    cyg_drv_interrupt_acknowledge(mn10300_chan->rx_int);
    
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
}

#else

static cyg_uint32 
mn10300_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;
 
    cyg_drv_interrupt_mask(mn10300_chan->rx_int);
    cyg_drv_interrupt_acknowledge(mn10300_chan->rx_int);

    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
}

#endif

static cyg_uint32 
mn10300_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;

    cyg_drv_interrupt_mask(mn10300_chan->tx_int);
    cyg_drv_interrupt_acknowledge(mn10300_chan->tx_int);

    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
}

#endif

//-------------------------------------------------------------------------
// Serial I/O - high level interrupt handler (DSR)

#ifndef CYGPKG_IO_SERIAL_MN10300_POLLED_MODE

#ifdef CYG_HAL_MN10300_SERIAL_RX_FIFO

static void       
mn10300_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;
    register cyg_int32 head = mn10300_chan->fifo_head;
    register cyg_int32 tail = mn10300_chan->fifo_tail;
    
    while( head != tail )
    {
        cyg_uint8 c = mn10300_chan->fifo[tail++];

        if( tail >= sizeof(mn10300_chan->fifo) ) tail = 0;

        (chan->callbacks->rcv_char)(chan, c);
    }

    mn10300_chan->fifo_tail = tail;
}

#else

static void       
mn10300_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;
    cyg_uint8 sr = mn10300_read_sr( mn10300_chan);

    if( (sr & SR_RBF) != 0 )
    {
        cyg_uint8 rxb;
        HAL_READ_UINT8( mn10300_chan->base+SERIAL_RXB, rxb );

        (chan->callbacks->rcv_char)(chan, rxb);
    }

    cyg_drv_interrupt_unmask(mn10300_chan->rx_int);
}

#endif

static void       
mn10300_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;
    cyg_uint8 sr = mn10300_read_sr( mn10300_chan);

    if( (sr & SR_TBF) == 0 )
    {
        (chan->callbacks->xmt_char)(chan);
    }
    
    cyg_drv_interrupt_unmask(mn10300_chan->tx_int);
}

#endif

#endif // CYGPKG_IO_SERIAL_MN10300

//-------------------------------------------------------------------------
// EOF mn10300.c

⌨️ 快捷键说明

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