📄 ebsa285_serial.c
字号:
{
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 + -