// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2003 Gary Thomas
+// Copyright (C) 2006 eCosCentric Limited
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
-//
-// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
-// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
typedef struct pc_serial_info {
cyg_addrword_t base;
int int_num;
+#ifdef CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
+ int int_prio;
+#endif // CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
cyg_interrupt serial_interrupt;
cyg_handle_t serial_interrupt_handle;
#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
s16550,
s16550a
} deviceType;
+ unsigned tx_fifo_size;
+ volatile unsigned tx_fifo_avail;
#endif
} pc_serial_info;
{
pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
cyg_addrword_t base = ser_chan->base;
+ //
+ // If the device supports a dynamic per channel baudrate generator
+ // then we call the CYG_IO_SERIAL_GENERIC_16X5X_CHAN_BAUD_GENERATOR()
+ // macro to get the baud divisor. The macro takes the serial channel data
+ // pointer and the baudrate as parameters and returns the baud divisior
+ //
+#ifdef CYG_IO_SERIAL_GENERIC_16X5X_CHAN_BAUD_GENERATOR
+ unsigned short baud_divisor = CYG_IO_SERIAL_GENERIC_16X5X_CHAN_BAUD_GENERATOR(ser_chan, new_config->baud);
+#else
unsigned short baud_divisor = select_baud[new_config->baud];
+#endif
unsigned char _lcr, _ier;
if (baud_divisor == 0) return false; // Invalid configuration
_fcr_thresh=FCR_RT14; break;
}
_fcr_thresh|=FCR_FE|FCR_CRF|FCR_CTF;
- HAL_WRITE_UINT8(base+REG_fcr, _fcr_thresh); // Enable and clear FIFO
+ ser_chan->tx_fifo_size =
+ CYGNUM_IO_SERIAL_GENERIC_16X5X_FIFO_TX_SIZE;
+ // Enable and clear FIFO
+ HAL_WRITE_UINT8(base+REG_fcr, _fcr_thresh);
}
- else
+ else {
+ ser_chan->tx_fifo_size = 1;
HAL_WRITE_UINT8(base+REG_fcr, 0); // make sure it's disabled
+ }
+
+ ser_chan->tx_fifo_avail = ser_chan->tx_fifo_size;
#endif
if (chan->out_cbuf.len != 0) {
_ier = IER_RCV;
#endif
HAL_WRITE_UINT8(base+REG_ier, _ier);
+#ifdef CYGPRI_IO_SERIAL_GENERIC_16X5X_PLF_INIT_HOOK
+ CYGPRI_IO_SERIAL_GENERIC_16X5X_PLF_INIT_HOOK( ser_chan, new_config );
+#endif
+
if (new_config != &chan->config) {
chan->config = *new_config;
}
#endif
// Really only required for interrupt driven devices
(chan->callbacks->serial_init)(chan);
-
+ //
+ // If the device supports per channel interrupt priorities then
+ // we take the priority from the serial channel data. If it does
+ // not support per channel interrupt priority we fall back to
+ // the old method and use CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY
+ // to define the priority
+ //
+#ifdef CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
+ cyg_priority_t intprio = ser_chan->int_prio;
+#else
+ cyg_priority_t intprio = CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY;
+#endif // CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
if (chan->out_cbuf.len != 0) {
cyg_drv_interrupt_create(ser_chan->int_num,
- CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY,
+ intprio,
(cyg_addrword_t)chan,
pc_serial_ISR,
pc_serial_DSR,
static bool
pc_serial_putc(serial_channel *chan, unsigned char c)
{
+#ifndef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
cyg_uint8 _lsr;
+#endif
pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
cyg_addrword_t base = ser_chan->base;
+#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
+ if (ser_chan->tx_fifo_avail > 0) {
+ HAL_WRITE_UINT8(base+REG_thr, c);
+ --ser_chan->tx_fifo_avail;
+ return true;
+ }
+#else
HAL_READ_UINT8(base+REG_lsr, _lsr);
if (_lsr & LSR_THE) {
// Transmit buffer is empty
HAL_WRITE_UINT8(base+REG_thr, c);
return true;
}
+#endif
// No space
return false;
}
HAL_READ_UINT8(base+REG_ier, _ier);
_ier |= IER_XMT; // Enable xmit interrupt
HAL_WRITE_UINT8(base+REG_ier, _ier);
+#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_XMIT_REQUIRE_PRIME
+ (chan->callbacks->xmt_char)(chan);
+#endif
}
// Disable the transmitter on the device
break;
}
case ISR_Tx:
+#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
+ ser_chan->tx_fifo_avail = ser_chan->tx_fifo_size;
+#endif
(chan->callbacks->xmt_char)(chan);
break;