changeset 2698:fd17f9bfa79f

* cdl/ser_powerpc_mpc555.cdl: Add HW queue option * src/mpc555_serial_with_ints.c: To help resolve an issue of characters being lost a software buffer has been added between the Rx ISR and DSR when no hardware queue is being used. A cdl option to enable support the hardware queue on the first serial port has been added. This enables 16 character hardware Tx and Rx buffers to be used which allows continuous transmission and reception of serial data and significantly improves performance.
author asl
date Tue, 23 Dec 2008 17:03:07 +0000
parents d6e76cd040e3
children 8d3a60779c64
files packages/devs/serial/powerpc/mpc555/current/ChangeLog packages/devs/serial/powerpc/mpc555/current/cdl/ser_powerpc_mpc555.cdl packages/devs/serial/powerpc/mpc555/current/src/mpc555_serial_with_ints.c
diffstat 3 files changed, 910 insertions(+), 254 deletions(-) [+]
line wrap: on
line diff
--- a/packages/devs/serial/powerpc/mpc555/current/ChangeLog
+++ b/packages/devs/serial/powerpc/mpc555/current/ChangeLog
@@ -1,3 +1,15 @@
+2008-12-23  Steven Clugston <steven.clugston@ncl.ac.uk>
+
+	* cdl/ser_powerpc_mpc555.cdl: Add HW queue option
+        * src/mpc555_serial_with_ints.c:
+        To help resolve an issue of characters being lost a software buffer
+        has been added between the Rx ISR and DSR when no hardware queue is 
+        being used.
+        A cdl option to enable support the hardware queue on the first serial 
+        port has been added. This enables 16 character hardware Tx and Rx 
+        buffers to be used which allows continuous transmission and reception
+        of serial data and significantly improves performance.
+
 2008-05-13  Steven Clugston  <steven.clugston@ncl.ac.uk>
 
 	* cdl/ser_powerpc_mpc555.cdl: Add line status
@@ -7,7 +19,7 @@ 2008-05-13  Steven Clugston  <steven.clu
 
 2008-04-06  Steven Clugston <steven.clugston@ncl.ac.uk>
 
-	* Refactored cme555 package to more generic mpc555
+	* Refactored package to more generic mpc555
 
 2003-02-24  Jonathan Larmour  <jifl@eCosCentric.com>
 
--- a/packages/devs/serial/powerpc/mpc555/current/cdl/ser_powerpc_mpc555.cdl
+++ b/packages/devs/serial/powerpc/mpc555/current/cdl/ser_powerpc_mpc555.cdl
@@ -73,6 +73,7 @@ cdl_component CYGPKG_IO_SERIAL_POWERPC_M
     flavor        bool
     default_value 0
     implements    CYGINT_IO_SERIAL_LINE_STATUS_HW
+    implements    CYGINT_IO_SERIAL_BLOCK_TRANSFER
     description   "
         This option includes the serial device driver for the mpc555
         PowerPC port A."
@@ -105,6 +106,17 @@ cdl_component CYGPKG_IO_SERIAL_POWERPC_M
             This option specifies the size of the internal buffers used for 
             the mpc555 PowerPC port A."
     }
+    cdl_option CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_A_USE_HWARE_QUEUE {
+        display       "Use hardware queue for mpc555 PowerPC serial port A"
+        flavor        bool
+        default_value 1
+        description   "
+            This option specifies if the QSCI 16-byte hardware queue   
+            is used for the mpc555 PowerPC port A. Using the queue 
+            makes block transfers possible. Select this option 
+            if you need to support continuous transmission and reception
+            without buffer overruns occurring."
+    }
 }
 
 cdl_component CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_B {
@@ -177,7 +189,6 @@ cdl_component CYGPKG_IO_SERIAL_POWERPC_M
                 the set of global flags if present."
         }
     }
-
 }
 
 # EOF ser_powerpc_mpc555.cdl
--- a/packages/devs/serial/powerpc/mpc555/current/src/mpc555_serial_with_ints.c
+++ b/packages/devs/serial/powerpc/mpc555/current/src/mpc555_serial_with_ints.c
@@ -60,49 +60,108 @@
 #include <cyg/io/serial.h>
 
 // Only build this driver for the MPC555 based boards
-#ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555
+#if defined (CYGPKG_IO_SERIAL_POWERPC_MPC555) && \
+   (defined (CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_A) || \
+    defined (CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_B))
 
 #include "mpc555_serial.h"
 
-//-----------------
+//---------------------------------------------------------------------------
 // Type definitions
-//-----------------
+//---------------------------------------------------------------------------
+#define MPC555_SCI_RX_BUFF_SIZE 256
+typedef struct st_sci_circbuf {
+  cyg_uint8 buf[MPC555_SCI_RX_BUFF_SIZE];
+  cyg_uint16 scsr[MPC555_SCI_RX_BUFF_SIZE];
+  cyg_uint8 fill_pos;
+  cyg_uint8 read_pos;
+} mpc555_sci_circbuf_t;
+
 typedef struct mpc555_serial_info {
-  CYG_ADDRWORD   base;                  // The base address of the serial port
-  CYG_WORD       tx_interrupt_num;      // trivial
-  CYG_WORD       rx_interrupt_num;      // trivial
-  cyg_priority_t tx_interrupt_priority; // trivial
-  cyg_priority_t rx_interrupt_priority; // trivial
-  bool           tx_interrupt_enable;   // tells if the transmit interrupt may be re-enabled
-  cyg_interrupt  tx_interrupt;          // the tx interrupt object
-  cyg_handle_t   tx_interrupt_handle;   // the tx interrupt handle
-  cyg_interrupt  rx_interrupt;          // the rx interrupt object
-  cyg_handle_t   rx_interrupt_handle;   // the rx interrupt handle
+  CYG_ADDRWORD   base;                 // The base address of the serial port
+  CYG_WORD       tx_interrupt_num;     // trivial
+  CYG_WORD       rx_interrupt_num;     // trivial
+  cyg_priority_t tx_interrupt_priority;// trivial
+  cyg_priority_t rx_interrupt_priority;// trivial
+  bool           tx_interrupt_enable;  // can the tx interrupt be re-enabled?
+  mpc555_sci_circbuf_t* rx_circbuf;    // rx buff for ISR to DSR data exchange
+  bool           use_queue;            // Use the queue when available?
+  CYG_WORD       rx_last_queue_pointer;// Keep track where queue read is upto
+  CYG_WORD       rx_interrupt_idle_line_num;             // trivial
+  CYG_WORD       tx_interrupt_queue_top_empty_num;       // trivial
+  CYG_WORD       tx_interrupt_queue_bot_empty_num;       // trivial
+  CYG_WORD       rx_interrupt_queue_top_full_num;        // trivial
+  CYG_WORD       rx_interrupt_queue_bot_full_num;        // trivial
+  cyg_priority_t rx_interrupt_idle_line_priority;        // trivial
+  cyg_priority_t tx_interrupt_queue_top_empty_priority;  // trivial
+  cyg_priority_t tx_interrupt_queue_bot_empty_priority;  // trivial
+  cyg_priority_t rx_interrupt_queue_top_full_priority;   // trivial
+  cyg_priority_t rx_interrupt_queue_bot_full_priority;   // trivial
+  cyg_interrupt  tx_interrupt;                 // the tx interrupt object
+  cyg_handle_t   tx_interrupt_handle;          // the tx interrupt handle
+  cyg_interrupt  rx_interrupt;                 // the rx interrupt object
+  cyg_handle_t   rx_interrupt_handle;          // the rx interrupt handle
+  cyg_interrupt  rx_idle_interrupt;            // the rx idle line isr object
+  cyg_handle_t   rx_idle_interrupt_handle;     // the rx idle line isr handle
+  cyg_interrupt  tx_queue_top_interrupt;       // the tx interrupt object
+  cyg_handle_t   tx_queue_top_interrupt_handle;// the tx interrupt handle
+  cyg_interrupt  tx_queue_bot_interrupt;       // the tx interrupt object
+  cyg_handle_t   tx_queue_bot_interrupt_handle;// the tx interrupt handle
+  cyg_interrupt  rx_queue_top_interrupt;       // the tx interrupt object
+  cyg_handle_t   rx_queue_top_interrupt_handle;// the tx interrupt handle
+  cyg_interrupt  rx_queue_bot_interrupt;       // the tx interrupt object
+  cyg_handle_t   rx_queue_bot_interrupt_handle;// the tx interrupt handle
 } mpc555_serial_info;
 
 //--------------------
 // Function prototypes
 //--------------------
-static bool mpc555_serial_init(struct cyg_devtab_entry * tab);
 static bool mpc555_serial_putc(serial_channel * chan, unsigned char c);
-static Cyg_ErrNo mpc555_serial_lookup(struct cyg_devtab_entry ** tab, 
-                                      struct cyg_devtab_entry * sub_tab,
-                                      const char * name);
 static unsigned char mpc555_serial_getc(serial_channel *chan);
 static Cyg_ErrNo mpc555_serial_set_config(serial_channel *chan, cyg_uint32 key,
                                           const void *xbuf, cyg_uint32 *len);
 static void mpc555_serial_start_xmit(serial_channel *chan);
 static void mpc555_serial_stop_xmit(serial_channel *chan);
+static Cyg_ErrNo mpc555_serial_lookup(struct cyg_devtab_entry ** tab, 
+                                      struct cyg_devtab_entry * sub_tab,
+                                      const char * name);
+static bool mpc555_serial_init(struct cyg_devtab_entry * tab);
 
 // The interrupt servers
 static cyg_uint32 mpc555_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data);
 static cyg_uint32 mpc555_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data);
-static void       mpc555_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
-static void       mpc555_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
+static void mpc555_serial_tx_DSR(cyg_vector_t vector, 
+                                 cyg_ucount32 count, 
+                                 cyg_addrword_t data);
+static void mpc555_serial_rx_DSR(cyg_vector_t vector, 
+                                 cyg_ucount32 count,
+                                 cyg_addrword_t data);
 
-//-------------------------------------------
+#ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_A
+static cyg_uint32 mpc555_serial_tx_queue_top_ISR(cyg_vector_t vector,
+                                                 cyg_addrword_t data);
+static cyg_uint32 mpc555_serial_tx_queue_bot_ISR(cyg_vector_t vector,
+                                                 cyg_addrword_t data);
+static cyg_uint32 mpc555_serial_rx_queue_top_ISR(cyg_vector_t vector,
+                                                 cyg_addrword_t data);
+static cyg_uint32 mpc555_serial_rx_queue_bot_ISR(cyg_vector_t vector,
+                                                 cyg_addrword_t data);
+static cyg_uint32 mpc555_serial_rx_idle_line_ISR(cyg_vector_t vector,
+                                                 cyg_addrword_t data);
+
+static void mpc555_serial_tx_queue_DSR(cyg_vector_t vector,
+                                       cyg_ucount32 count,
+                                       cyg_addrword_t data);
+static void mpc555_serial_rx_queue_DSR(cyg_vector_t vector,
+                                       cyg_ucount32 count,
+                                       cyg_addrword_t data);
+
+static int mpc555_serial_read_queue(serial_channel* chan, int start, int end);
+#endif
+
+//------------------------------------------------------------------------------
 // Register the device driver with the kernel
-//-------------------------------------------
+//------------------------------------------------------------------------------
 static SERIAL_FUNS(mpc555_serial_funs, 
                    mpc555_serial_putc, 
                    mpc555_serial_getc,
@@ -110,41 +169,100 @@ static SERIAL_FUNS(mpc555_serial_funs,
                    mpc555_serial_start_xmit,
                    mpc555_serial_stop_xmit);
 
-//-------------------
+//------------------------------------------------------------------------------
 // Device driver data
-//-------------------
+//------------------------------------------------------------------------------
 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_A
-static mpc555_serial_info mpc555_serial_info0 = {MPC555_SERIAL_BASE_A,
-                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX,
-                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX,
-                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX_PRIORITY,
-                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX_PRIORITY,
-                                                 false};
-#if CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BUFSIZE > 0
+#ifdef CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_A_USE_HWARE_QUEUE
+//static mpc555_sci_circbuf_t mpc555_serial_isr_to_dsr_buf0;
+
+static mpc555_serial_info mpc555_serial_info0 = {
+  MPC555_SERIAL_BASE_A,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX_PRIORITY,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX_PRIORITY,
+  false,
+  NULL, // Don't need software buffer
+  true, // Use queue
+  0,    // init queue pointer
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE, 
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQTHE,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQBHE,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQTHF,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQBHF,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE_PRIORITY,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQTHE_PRIORITY,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQBHE_PRIORITY,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQTHF_PRIORITY,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQBHF_PRIORITY};
+
 static unsigned char mpc555_serial_out_buf0[CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BUFSIZE]; 
 static unsigned char mpc555_serial_in_buf0[CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BUFSIZE];
 
-static SERIAL_CHANNEL_USING_INTERRUPTS(mpc555_serial_channel0,
-                                       mpc555_serial_funs,
-                                       mpc555_serial_info0,
-                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BAUD),
-                                       CYG_SERIAL_STOP_DEFAULT,
-                                       CYG_SERIAL_PARITY_DEFAULT,
-                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
-                                       CYG_SERIAL_FLAGS_DEFAULT,
-                                       &mpc555_serial_out_buf0[0],
-                                       sizeof(mpc555_serial_out_buf0),
-                                       &mpc555_serial_in_buf0[0],
-                                       sizeof(mpc555_serial_in_buf0));
-#else 
-static SERIAL_CHANNEL(mpc555_serial_channel0,
-                      mpc555_serial_funs,
-                      mpc555_serial_info0,
-                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BAUD),
-                      CYG_SERIAL_STOP_DEFAULT,
-                      CYG_SERIAL_PARITY_DEFAULT,
-                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
-                      CYG_SERIAL_FLAGS_DEFAULT);
+static SERIAL_CHANNEL_USING_INTERRUPTS(
+  mpc555_serial_channel0,
+  mpc555_serial_funs,
+  mpc555_serial_info0,
+  CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BAUD),
+  CYG_SERIAL_STOP_DEFAULT,
+  CYG_SERIAL_PARITY_DEFAULT,
+  CYG_SERIAL_WORD_LENGTH_DEFAULT,
+  CYG_SERIAL_FLAGS_DEFAULT,
+  &mpc555_serial_out_buf0[0],
+  sizeof(mpc555_serial_out_buf0),
+  &mpc555_serial_in_buf0[0],
+  sizeof(mpc555_serial_in_buf0));
+
+#elif CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BUFSIZE > 0
+static mpc555_sci_circbuf_t mpc555_serial_isr_to_dsr_buf0;
+
+static mpc555_serial_info mpc555_serial_info0 = {
+  MPC555_SERIAL_BASE_A,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX_PRIORITY,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX_PRIORITY,
+  false,
+  &mpc555_serial_isr_to_dsr_buf0,
+  false};
+
+static unsigned char mpc555_serial_out_buf0[CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BUFSIZE]; 
+static unsigned char mpc555_serial_in_buf0[CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BUFSIZE];
+
+static SERIAL_CHANNEL_USING_INTERRUPTS(
+  mpc555_serial_channel0,
+  mpc555_serial_funs,
+  mpc555_serial_info0,
+  CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BAUD),
+  CYG_SERIAL_STOP_DEFAULT,
+  CYG_SERIAL_PARITY_DEFAULT,
+  CYG_SERIAL_WORD_LENGTH_DEFAULT,
+  CYG_SERIAL_FLAGS_DEFAULT,
+  &mpc555_serial_out_buf0[0],
+  sizeof(mpc555_serial_out_buf0),
+  &mpc555_serial_in_buf0[0],
+  sizeof(mpc555_serial_in_buf0));
+#else
+static mpc555_serial_info mpc555_serial_info0 = {
+  MPC555_SERIAL_BASE_A,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX_PRIORITY,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX_PRIORITY,
+  false,
+  NULL,
+  false};
+ 
+static SERIAL_CHANNEL(
+  mpc555_serial_channel0,
+  mpc555_serial_funs,
+  mpc555_serial_info0,
+  CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BAUD),
+  CYG_SERIAL_STOP_DEFAULT,
+  CYG_SERIAL_PARITY_DEFAULT,
+  CYG_SERIAL_WORD_LENGTH_DEFAULT,
+  CYG_SERIAL_FLAGS_DEFAULT);
 #endif
 DEVTAB_ENTRY(mpc555_serial_io0,
              CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_A_NAME,
@@ -156,37 +274,55 @@ DEVTAB_ENTRY(mpc555_serial_io0,
 #endif // ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_A
 
 #ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_B
-static mpc555_serial_info mpc555_serial_info1 = {MPC555_SERIAL_BASE_B,
-                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX,
-                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
-                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX_PRIORITY,
-                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX_PRIORITY,
-                                                 false};
+
 #if CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_B_BUFSIZE > 0
+static mpc555_sci_circbuf_t mpc555_serial_isr_to_dsr_buf1;
+
+static mpc555_serial_info mpc555_serial_info1 = {
+  MPC555_SERIAL_BASE_B,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TX,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TX_PRIORITY,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX_PRIORITY,
+  false,
+  &mpc555_serial_isr_to_dsr_buf1,
+  false};
+
 static unsigned char mpc555_serial_out_buf1[CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_B_BUFSIZE]; 
 static unsigned char mpc555_serial_in_buf1[CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_B_BUFSIZE];
 
-static SERIAL_CHANNEL_USING_INTERRUPTS(mpc555_serial_channel1,
-                                       mpc555_serial_funs,
-                                       mpc555_serial_info1,
-                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_B_BAUD),
-                                       CYG_SERIAL_STOP_DEFAULT,
-                                       CYG_SERIAL_PARITY_DEFAULT,
-                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
-                                       CYG_SERIAL_FLAGS_DEFAULT,
-                                       &mpc555_serial_out_buf1[0],
-                                       sizeof(mpc555_serial_out_buf1),
-                                       &mpc555_serial_in_buf1[0],
-                                       sizeof(mpc555_serial_in_buf1));
+static SERIAL_CHANNEL_USING_INTERRUPTS(
+  mpc555_serial_channel1,
+  mpc555_serial_funs,
+  mpc555_serial_info1,
+  CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_B_BAUD),
+  CYG_SERIAL_STOP_DEFAULT,
+  CYG_SERIAL_PARITY_DEFAULT,
+  CYG_SERIAL_WORD_LENGTH_DEFAULT,
+  CYG_SERIAL_FLAGS_DEFAULT,
+  &mpc555_serial_out_buf1[0],
+  sizeof(mpc555_serial_out_buf1),
+  &mpc555_serial_in_buf1[0],
+  sizeof(mpc555_serial_in_buf1));
 #else
-static SERIAL_CHANNEL(mpc555_serial_channel1,
-                      mpc555_serial_funs,
-                      mpc555_serial_info1,
-                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_B_BAUD),
-                      CYG_SERIAL_STOP_DEFAULT,
-                      CYG_SERIAL_PARITY_DEFAULT,
-                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
-                      CYG_SERIAL_FLAGS_DEFAULT);
+static mpc555_serial_info mpc555_serial_info1 = {
+  MPC555_SERIAL_BASE_B,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX_PRIORITY,
+  CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX_PRIORITY,
+  false,
+  NULL,
+  false};
+static SERIAL_CHANNEL(
+  mpc555_serial_channel1,
+  mpc555_serial_funs,
+  mpc555_serial_info1,
+  CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_B_BAUD),
+  CYG_SERIAL_STOP_DEFAULT,
+  CYG_SERIAL_PARITY_DEFAULT,
+  CYG_SERIAL_WORD_LENGTH_DEFAULT,
+  CYG_SERIAL_FLAGS_DEFAULT);
 #endif
 DEVTAB_ENTRY(mpc555_serial_io1,
              CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_B_NAME,
@@ -197,90 +333,110 @@ DEVTAB_ENTRY(mpc555_serial_io1,
              &mpc555_serial_channel1);
 #endif // ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_B
 
-//-----------------------------
+//------------------------------------------------------------------------------
 // Device driver implementation
-//-----------------------------
+//------------------------------------------------------------------------------
 
 // The arbitration isr. 
-// I think this is the best place to implement it. The device driver is the only place
-// in the code where the knowledge is present about how the hardware is used
+// I think this is the best place to implement it.
+// The device driver is the only place in the code where the knowledge is 
+// present about how the hardware is used.
 //
-// Always check receive interrupts. Some rom monitor might be waiting for CTRL-C
-static cyg_uint32 hal_arbitration_isr_qsci(CYG_ADDRWORD a_vector, CYG_ADDRWORD a_data)
+// Always check receive interrupts. 
+// Some rom monitor might be waiting for CTRL-C
+static cyg_uint32 hal_arbitration_isr_qsci(CYG_ADDRWORD a_vector, 
+                                           CYG_ADDRWORD a_data)
 {
   cyg_uint16 status;
   cyg_uint16 control;
 
   HAL_READ_UINT16(CYGARC_REG_IMM_SC1SR, status);
   HAL_READ_UINT16(CYGARC_REG_IMM_SCC1R1, control);
-  if((status & CYGARC_REG_IMM_SCxSR_RDRF) && (control & CYGARC_REG_IMM_SCCxR1_RIE))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX);
-#ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_A // Do not waist time on unused hardware
-  if((status & CYGARC_REG_IMM_SCxSR_TDRE) && (control & CYGARC_REG_IMM_SCCxR1_TIE))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX);
-// Don't waist time on unused interrupts
-//  if((status & CYGARC_REG_IMM_SCxSR_TC) && (control & CYGARC_REG_IMM_SCCxR1_TCIE))
-//    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TXC);
-// Don't waist time on unused interrupts
-//  if((status & CYGARC_REG_IMM_SCxSR_IDLE) && (control & CYGARC_REG_IMM_SCCxR1_ILIE))
-//    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_IDLE);
+  if((status & CYGARC_REG_IMM_SCxSR_RDRF) && 
+      (control & CYGARC_REG_IMM_SCCxR1_RIE))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX);
+// Do not waist time on unused hardware
+#ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_A
+#ifdef CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_A_USE_HWARE_QUEUE
+  // Only one port supports queue mode
+  if((status & CYGARC_REG_IMM_SCxSR_IDLE) && 
+      (control & CYGARC_REG_IMM_SCCxR1_ILIE))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE);
+  HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, status);
+  HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1CR, control);
+  if((status & CYGARC_REG_IMM_QSCI1SR_QTHF) && 
+      (control & CYGARC_REG_IMM_QSCI1CR_QTHFI))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQTHF);
+  if((status & CYGARC_REG_IMM_QSCI1SR_QBHF) && 
+      (control & CYGARC_REG_IMM_QSCI1CR_QBHFI))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQBHF);
+  if((status & CYGARC_REG_IMM_QSCI1SR_QTHE) && 
+      (control & CYGARC_REG_IMM_QSCI1CR_QTHEI))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQTHE);
+  if((status & CYGARC_REG_IMM_QSCI1SR_QBHE) && 
+      (control & CYGARC_REG_IMM_QSCI1CR_QBHEI))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQBHE);
+// Only for SPI, leave fo future reference
+#if 0
+  HAL_READ_UINT16(CYGARC_REG_IMM_SPSR, status);
+  HAL_READ_UINT16(CYGARC_REG_IMM_SPCR2, control);
+  if((status & CYGARC_REG_IMM_SPSR_SPIF) && 
+      (control & CYGARC_REG_IMM_SPCR2_SPIFIE))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_FI);
+
+  HAL_READ_UINT16(CYGARC_REG_IMM_SPCR3, control);
+  if((status & CYGARC_REG_IMM_SPSR_MODF) && 
+      (control & CYGARC_REG_IMM_SPCR3_HMIE))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_MODF);
+
+  if((status & CYGARC_REG_IMM_SPSR_HALTA) && 
+      (control & CYGARC_REG_IMM_SPCR3_HMIE))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_HALTA);
 #endif
-
-  HAL_READ_UINT16(CYGARC_REG_IMM_SC2SR, status);
-  HAL_READ_UINT16(CYGARC_REG_IMM_SCC2R1, control);
-  if((status & CYGARC_REG_IMM_SCxSR_RDRF) && (control & CYGARC_REG_IMM_SCCxR1_RIE))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX);
-#ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_B // Do not waist time on unused hardware
-  if((status & CYGARC_REG_IMM_SCxSR_TDRE) && (control & CYGARC_REG_IMM_SCCxR1_TIE))
+#else  //No HW Queue
+  if((status & CYGARC_REG_IMM_SCxSR_TDRE) && 
+      (control & CYGARC_REG_IMM_SCCxR1_TIE))
     return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX);
 // Don't waist time on unused interrupts
+// Transmit complete interrupt enabled (not used)
 //  if((status & CYGARC_REG_IMM_SCxSR_TC) && (control & CYGARC_REG_IMM_SCCxR1_TCIE))
 //    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXC);
 // Don't waist time on unused interrupts
+// Idle-line interrupt enabled (not used)
 //  if((status & CYGARC_REG_IMM_SCxSR_IDLE) && (control & CYGARC_REG_IMM_SCCxR1_ILIE))
 //    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE);
-
-#if 0
-  // The driver doesn't use the queue operation of the hardware (It would need different code for serial 1 and 2
-  // since oly one port supports queue mode). So the following is not needed.
-  // Leave it there. It is easyer for later implementations to remove the comments than finding
-  // out how the hardware works again.
-  HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, status);
-  HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1CR, control);
-  if((status & CYGARC_REG_IMM_QSCI1SR_QTHF) && (control & CYGARC_REG_IMM_QSCI1CR_QTHFI))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQTHF);
-  if((status & CYGARC_REG_IMM_QSCI1SR_QBHF) && (control & CYGARC_REG_IMM_QSCI1CR_QBHFI))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQBHF);
-  if((status & CYGARC_REG_IMM_QSCI1SR_QTHE) && (control & CYGARC_REG_IMM_QSCI1CR_QTHEI))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQTHE);
-  if((status & CYGARC_REG_IMM_QSCI1SR_QBHE) && (control & CYGARC_REG_IMM_QSCI1CR_QBHEI))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQBHE);
+#endif // HW_QUEUE
+#endif // SERIAL_A
 
-  cyg_uint16 status;
-  cyg_uint16 control;
-
-  HAL_READ_UINT16(CYGARC_REG_IMM_SPSR, status);
-  HAL_READ_UINT16(CYGARC_REG_IMM_SPCR2, control);
-  if((status & CYGARC_REG_IMM_SPSR_SPIF) && (control & CYGARC_REG_IMM_SPCR2_SPIFIE))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_FI);
-
-  HAL_READ_UINT16(CYGARC_REG_IMM_SPCR3, control);
-  if((status & CYGARC_REG_IMM_SPSR_MODF) && (control & CYGARC_REG_IMM_SPCR3_HMIE))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_MODF);
-
-  if((status & CYGARC_REG_IMM_SPSR_HALTA) && (control & CYGARC_REG_IMM_SPCR3_HMIE))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_HALTA);
-#endif
-  
+  HAL_READ_UINT16(CYGARC_REG_IMM_SC2SR, status);
+  HAL_READ_UINT16(CYGARC_REG_IMM_SCC2R1, control);
+  if((status & CYGARC_REG_IMM_SCxSR_RDRF) && 
+      (control & CYGARC_REG_IMM_SCCxR1_RIE))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX);
+// Do not waist time on unused hardware
+#ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_B
+  if((status & CYGARC_REG_IMM_SCxSR_TDRE) && 
+      (control & CYGARC_REG_IMM_SCCxR1_TIE))
+    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TX);
+// Don't waist time on unused interrupts
+// Transmit complete interrupt enabled (not used)
+//  if((status & CYGARC_REG_IMM_SCxSR_TC) && (control & CYGARC_REG_IMM_SCCxR1_TCIE))
+//    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TXC);
+// Don't waist time on unused interrupts
+// Idle-line interrupt enabled (not used)
+//  if((status & CYGARC_REG_IMM_SCxSR_IDLE) && (control & CYGARC_REG_IMM_SCCxR1_ILIE))
+//    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI2_IDLE);
 #endif
 
   return 0;
 }
 
-//--------------------------------------------------------------------------------
-// Internal function to actually configure the hardware to desired baud rate, etc.
-//--------------------------------------------------------------------------------
-static bool mpc555_serial_config_port(serial_channel * chan, cyg_serial_info_t * new_config, bool init)
+//------------------------------------------------------------------------------
+// Internal function to configure the hardware to desired baud rate, etc.
+//------------------------------------------------------------------------------
+static bool mpc555_serial_config_port(serial_channel * chan, 
+                                      cyg_serial_info_t * new_config, 
+                                      bool init)
 {
   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)(chan->dev_priv);
 
@@ -307,7 +463,8 @@ static bool mpc555_serial_config_port(se
      (new_config->stop != CYGNUM_SERIAL_STOP_2))
     return false;    // Invalid stop bits selected
 
-  frame_length += select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5]; 
+  frame_length += select_word_length[new_config->word_length - 
+                                     CYGNUM_SERIAL_WORD_LENGTH_5]; 
   frame_length += select_stop_bits[new_config->stop];
   frame_length += select_parity[new_config->parity];
 
@@ -334,6 +491,21 @@ static bool mpc555_serial_config_port(se
   sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_ILIE);
   HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
 
+#ifdef CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_A_USE_HWARE_QUEUE
+  cyg_uint16 qsci1cr = 0;
+  if(mpc555_chan->use_queue){
+    HAL_READ_UINT16( CYGARC_REG_IMM_QSCI1SR, qsci1cr);
+    // disable queue
+    qsci1cr &= ~((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QTE);
+    qsci1cr &= ~((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QRE);
+    // disable queue interrupts    
+    qsci1cr &= ~((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QTHFI);
+    qsci1cr &= ~((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QBHFI);
+    qsci1cr &= ~((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QTHEI);
+    qsci1cr &= ~((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QBHEI);
+    HAL_WRITE_UINT16( CYGARC_REG_IMM_QSCI1SR, qsci1cr);
+  }
+#endif
   // Set databits, stopbits and parity.
   HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
 
@@ -342,8 +514,7 @@ static bool mpc555_serial_config_port(se
   else
     sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_M);
 
-  switch(new_config->parity)
-  {
+  switch(new_config->parity){
     case CYGNUM_SERIAL_PARITY_NONE:
       sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PE);
       break;
@@ -374,14 +545,38 @@ static bool mpc555_serial_config_port(se
   sccxr |= MPC555_SERIAL_SCCxR1_RE;
   HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
 
-  if(init) 
-  { // enable the receiver interrupt
+  if(init){ 
+#ifdef CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_A_USE_HWARE_QUEUE
+    HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
+    if(mpc555_chan->use_queue){
+      cyg_uint16 qsci1sr;
+      // enable read queue
+      qsci1cr |= ((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QRE);
+      // enable receive queue interrupts    
+      qsci1cr |= ((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QTHFI);
+      qsci1cr |= ((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QBHFI);
+      HAL_WRITE_UINT16( CYGARC_REG_IMM_QSCI1CR, qsci1cr);
+      // also enable idle line detect interrupt
+      sccxr |= MPC555_SERIAL_SCxSR_IDLE;
+      HAL_READ_UINT16( CYGARC_REG_IMM_QSCI1SR, qsci1sr);
+      qsci1sr &= ~((cyg_uint16)CYGARC_REG_IMM_QSCI1SR_QBHF);
+      qsci1sr &= ~((cyg_uint16)CYGARC_REG_IMM_QSCI1SR_QTHF);
+      HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1SR, qsci1sr);
+    }
+    else {
+      // enable the receiver interrupt
+      sccxr |= MPC555_SERIAL_SCCxR1_RIE;
+    }
+    HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
+#else
+    // enable the receiver interrupt
     HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
     sccxr |= MPC555_SERIAL_SCCxR1_RIE;
     HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
+#endif
   } 
-  else // Restore the old interrupt state
-  {
+  else {// Restore the old interrupt state
+  
     HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
     sccxr |= old_isrstate;
     HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
@@ -393,22 +588,20 @@ static bool mpc555_serial_config_port(se
   return true;
 }
 
-//--------------------------------------------------------------
+//------------------------------------------------------------------------------
 // Function to initialize the device.  Called at bootstrap time.
-//--------------------------------------------------------------
+//------------------------------------------------------------------------------
 static hal_mpc5xx_arbitration_data arbiter;
-
-static bool mpc555_serial_init(struct cyg_devtab_entry * tab)
-{
+static bool mpc555_serial_init(struct cyg_devtab_entry * tab){
    serial_channel * chan = (serial_channel *)tab->priv;
    mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
 
    if(!mpc555_serial_config_port(chan, &chan->config, true))
      return false;
 
-   (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
-   if(chan->out_cbuf.len != 0)
-   { 
+   // Really only required for interrupt driven devices
+   (chan->callbacks->serial_init)(chan);
+   if(chan->out_cbuf.len != 0){ 
      arbiter.priority = CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI;
      arbiter.data     = 0;
      arbiter.arbiter  = hal_arbitration_isr_qsci;
@@ -417,50 +610,106 @@ static bool mpc555_serial_init(struct cy
      hal_mpc5xx_remove_arbitration_isr(CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI);
      hal_mpc5xx_install_arbitration_isr(&arbiter); 
 
-     // Create the Tx interrupt, do not enable it yet
-     cyg_drv_interrupt_create(mpc555_chan->tx_interrupt_num,
-                              mpc555_chan->tx_interrupt_priority,
-                              (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
-                              mpc555_serial_tx_ISR,
-                              mpc555_serial_tx_DSR,
-                              &mpc555_chan->tx_interrupt_handle,
-                              &mpc555_chan->tx_interrupt);
-     cyg_drv_interrupt_attach(mpc555_chan->tx_interrupt_handle);
+     // if !(Chan_B && using queue) 
+     if(!mpc555_chan->use_queue){
+       mpc555_chan->rx_circbuf->fill_pos = 0;
+       mpc555_chan->rx_circbuf->read_pos = 0;
+     
+       // Create the Tx interrupt, do not enable it yet
+       cyg_drv_interrupt_create(mpc555_chan->tx_interrupt_num,
+                                mpc555_chan->tx_interrupt_priority,
+                                (cyg_addrword_t)chan,//Data item passed to isr
+                                mpc555_serial_tx_ISR,
+                                mpc555_serial_tx_DSR,
+                                &mpc555_chan->tx_interrupt_handle,
+                                &mpc555_chan->tx_interrupt);
+       cyg_drv_interrupt_attach(mpc555_chan->tx_interrupt_handle);
+  
+       // Create the Rx interrupt, this can be safely unmasked now
+       cyg_drv_interrupt_create(mpc555_chan->rx_interrupt_num,
+                                mpc555_chan->rx_interrupt_priority,
+                                (cyg_addrword_t)chan,
+                                mpc555_serial_rx_ISR,
+                                mpc555_serial_rx_DSR,
+                                &mpc555_chan->rx_interrupt_handle,
+                                &mpc555_chan->rx_interrupt);
+       cyg_drv_interrupt_attach(mpc555_chan->rx_interrupt_handle);
+       cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
+     }
+#ifdef CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_A_USE_HWARE_QUEUE
+     else {// Use HW queue
+       // Create the Tx interrupt, do not enable it yet
+       cyg_drv_interrupt_create(mpc555_chan->tx_interrupt_queue_top_empty_num,
+                                mpc555_chan->tx_interrupt_queue_top_empty_priority,
+                                (cyg_addrword_t)chan,//Data item passed to isr
+                                mpc555_serial_tx_queue_top_ISR,
+                                mpc555_serial_tx_queue_DSR,
+                                &mpc555_chan->tx_queue_top_interrupt_handle,
+                                &mpc555_chan->tx_queue_top_interrupt);
+       cyg_drv_interrupt_attach(mpc555_chan->tx_queue_top_interrupt_handle);
+
 
-     // Create the Rx interrupt, this can be safely unmasked now
-     cyg_drv_interrupt_create(mpc555_chan->rx_interrupt_num,
-                              mpc555_chan->rx_interrupt_priority,
-                              (cyg_addrword_t)chan,
-                              mpc555_serial_rx_ISR,
-                              mpc555_serial_rx_DSR,
-                              &mpc555_chan->rx_interrupt_handle,
-                              &mpc555_chan->rx_interrupt);
-     cyg_drv_interrupt_attach(mpc555_chan->rx_interrupt_handle);
-     cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
-    }
-
+       cyg_drv_interrupt_create(mpc555_chan->tx_interrupt_queue_bot_empty_num,
+                                mpc555_chan->tx_interrupt_queue_bot_empty_priority,
+                                (cyg_addrword_t)chan,//Data passed to isr
+                                mpc555_serial_tx_queue_bot_ISR,
+                                mpc555_serial_tx_queue_DSR,
+                                &mpc555_chan->tx_queue_bot_interrupt_handle,
+                                &mpc555_chan->tx_queue_bot_interrupt);
+       cyg_drv_interrupt_attach(mpc555_chan->tx_queue_bot_interrupt_handle);
+       
+       // Rx queue interrupts
+       cyg_drv_interrupt_create(mpc555_chan->rx_interrupt_queue_top_full_num,
+                                mpc555_chan->rx_interrupt_queue_top_full_priority,
+                                (cyg_addrword_t)chan,//Data item passed to isr
+                                mpc555_serial_rx_queue_top_ISR,
+                                mpc555_serial_rx_queue_DSR,
+                                &mpc555_chan->rx_queue_top_interrupt_handle,
+                                &mpc555_chan->rx_queue_top_interrupt);
+       cyg_drv_interrupt_attach(mpc555_chan->rx_queue_top_interrupt_handle);
+       
+       cyg_drv_interrupt_create(mpc555_chan->rx_interrupt_queue_bot_full_num,
+                                mpc555_chan->rx_interrupt_queue_bot_full_priority,
+                                (cyg_addrword_t)chan,//Data item passed to isr
+                                mpc555_serial_rx_queue_bot_ISR,
+                                mpc555_serial_rx_queue_DSR,
+                                &mpc555_chan->rx_queue_bot_interrupt_handle,
+                                &mpc555_chan->rx_queue_bot_interrupt);
+       cyg_drv_interrupt_attach(mpc555_chan->rx_queue_bot_interrupt_handle);
+       
+       cyg_drv_interrupt_create(mpc555_chan->rx_interrupt_idle_line_num,
+                                mpc555_chan->rx_interrupt_idle_line_priority,
+                                (cyg_addrword_t)chan,//Data item passed to isr
+                                mpc555_serial_rx_idle_line_ISR,
+                                mpc555_serial_rx_queue_DSR,
+                                &mpc555_chan->rx_idle_interrupt_handle,
+                                &mpc555_chan->rx_idle_interrupt);
+       cyg_drv_interrupt_attach(mpc555_chan->rx_idle_interrupt_handle);
+     }
+#endif // use queue
+   }
     return true;
 }
 
-//----------------------------------------------------------------------
+//----------------------------------------------------------------------------
 // This routine is called when the device is "looked" up (i.e. attached)
-//----------------------------------------------------------------------
+//----------------------------------------------------------------------------
 static Cyg_ErrNo mpc555_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
+  //Really only required for interrupt driven devices
+  (chan->callbacks->serial_init)(chan);
 
   return ENOERR;
 }
 
-//----------------------------------------------
+//----------------------------------------------------------------------------
 // Send a character to the device output buffer.
 // Return 'true' if character is sent to device
-//----------------------------------------------
-static bool mpc555_serial_putc(serial_channel * chan, unsigned char c)
-{
+//----------------------------------------------------------------------------
+static bool mpc555_serial_putc(serial_channel * chan, unsigned char c){
   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
   cyg_addrword_t port = mpc555_chan->base;
 
@@ -468,8 +717,8 @@ static bool mpc555_serial_putc(serial_ch
   cyg_uint16 scdr;
 
   HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
-  if(scsr & MPC555_SERIAL_SCxSR_TDRE)
-  { // Ok, we have space, write the character and return success
+  if(scsr & MPC555_SERIAL_SCxSR_TDRE){ 
+    // Ok, we have space, write the character and return success
     scdr = (cyg_uint16)c;
     HAL_WRITE_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
     return true;
@@ -479,11 +728,10 @@ static bool mpc555_serial_putc(serial_ch
     return false;
 }
 
-//---------------------------------------------------------------------
+//----------------------------------------------------------------------------
 // Fetch a character from the device input buffer, waiting if necessary
-//---------------------------------------------------------------------
-static unsigned char mpc555_serial_getc(serial_channel * chan)
-{
+//----------------------------------------------------------------------------
+static unsigned char mpc555_serial_getc(serial_channel * chan){
   unsigned char c;
   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
   cyg_addrword_t port = mpc555_chan->base;
@@ -502,23 +750,22 @@ static unsigned char mpc555_serial_getc(
   return c;
 }
 
-//---------------------------------------------------
+//----------------------------------------------------------------------------
 // Set up the device characteristics; baud rate, etc.
-//---------------------------------------------------
+//----------------------------------------------------------------------------
 static bool mpc555_serial_set_config(serial_channel * chan, cyg_uint32 key,
                                      const void *xbuf, cyg_uint32 * len)
 {
-  switch(key) {
-  case CYG_IO_SET_CONFIG_SERIAL_INFO:
-    {
+  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;
+      if(*len < sizeof(cyg_serial_info_t)){
+        return -EINVAL;
       }
       *len = sizeof(cyg_serial_info_t);
       if(true != mpc555_serial_config_port(chan, config, false))
-	return -EINVAL;
-    }
+        return -EINVAL;
+      }
     break;
   default:
     return -EINVAL;
@@ -526,37 +773,97 @@ static bool mpc555_serial_set_config(ser
   return ENOERR;
 }
 
-//-------------------------------------
+//------------------------------------------------------------------------------
 // Enable the transmitter on the device
-//-------------------------------------
+//------------------------------------------------------------------------------
 static void mpc555_serial_start_xmit(serial_channel * chan)
 {
   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
+#ifdef CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_A_USE_HWARE_QUEUE
+  cyg_addrword_t port = mpc555_chan->base;
+  if(mpc555_chan->use_queue){
+    cyg_uint16 qscicr;
+    cyg_uint16 qscisr;
+    cyg_uint16 scsr;
+    
+    int chars_avail;
+    unsigned char* chars;
+    int block_index = 0;
+    cyg_addrword_t i;
+    cyg_uint16 queue_transfer;
+ 
+    if(!(mpc555_chan->tx_interrupt_enable) && 
+       (chan->callbacks->data_xmt_req)(chan, 32, &chars_avail, &chars) 
+       == CYG_XMT_OK){
+      queue_transfer = (chars_avail > 16) ? 16 : chars_avail;
 
-  mpc555_chan->tx_interrupt_enable = true;
-  cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
+      HAL_READ_UINT16( CYGARC_REG_IMM_QSCI1CR, qscicr);
+      // Write QTSZ for first pass through the queue
+      qscicr &= ~(CYGARC_REG_IMM_QSCI1CR_QTSZ);
+      qscicr |= (CYGARC_REG_IMM_QSCI1CR_QTSZ & (queue_transfer - 1));
+      HAL_WRITE_UINT16( CYGARC_REG_IMM_QSCI1CR, qscicr);
+      // Read SC1SR to clear TC bit when followed by a write of sctq
+      HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
+      
+      for(i=0; i < queue_transfer; i++){
+        HAL_WRITE_UINT16(CYGARC_REG_IMM_SCTQ + (i * 2), chars[block_index]);
+        ++block_index;
+      }
+      chan->callbacks->data_xmt_done(chan, queue_transfer);
+
+      // clear QTHE and QBHE
+      HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
 
-  // No need to call xmt_char, this will generate an interrupt immediately.
+      qscisr &= ~(CYGARC_REG_IMM_QSCI1SR_QTHE);
+      HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
+      if(queue_transfer > 8){
+        qscisr &= ~(CYGARC_REG_IMM_QSCI1SR_QBHE);
+        HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
+      }
+
+      mpc555_chan->tx_interrupt_enable = true;
+
+      cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_queue_top_empty_num);
+      if(queue_transfer > 8){
+        cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_queue_bot_empty_num);
+      }
+
+      HAL_READ_UINT16( CYGARC_REG_IMM_QSCI1CR, qscicr);
+      qscicr |= ((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QTE);
+      HAL_WRITE_UINT16( CYGARC_REG_IMM_QSCI1CR, qscicr);
+    }
+  }
+  else { // no queue  
+   mpc555_chan->tx_interrupt_enable = true;
+   cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
+// No need to call xmt_char, this will generate an interrupt immediately.
+  }
+#else // No queue
+   mpc555_chan->tx_interrupt_enable = true;
+   cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
+// No need to call xmt_char, this will generate an interrupt immediately.
+#endif
 }
 
-//--------------------------------------
+//----------------------------------------------------------------------------
 // Disable the transmitter on the device
-//--------------------------------------
-static void mpc555_serial_stop_xmit(serial_channel * chan)
-{
+//----------------------------------------------------------------------------
+static void mpc555_serial_stop_xmit(serial_channel * chan){
   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
 
-  cyg_drv_dsr_lock();
-  mpc555_chan->tx_interrupt_enable = false;
-  cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_num);
-  cyg_drv_dsr_unlock();
+  if(!mpc555_chan->use_queue){
+    cyg_drv_dsr_lock();
+    mpc555_chan->tx_interrupt_enable = false;
+    cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_num);
+    cyg_drv_dsr_unlock();
+  }
 }
 
-//-----------------------------------------
+//----------------------------------------------------------------------------
 // The low level transmit interrupt handler
-//-----------------------------------------
-static cyg_uint32 mpc555_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data)
-{
+//----------------------------------------------------------------------------
+static cyg_uint32 mpc555_serial_tx_ISR(cyg_vector_t vector,
+                                       cyg_addrword_t data){
   serial_channel * chan = (serial_channel *)data;
   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
 
@@ -566,25 +873,107 @@ static cyg_uint32 mpc555_serial_tx_ISR(c
   return CYG_ISR_CALL_DSR; // cause the DSR to run
 }
 
-//----------------------------------------
+//----------------------------------------------------------------------------
 // The low level receive interrupt handler
-//----------------------------------------
-static cyg_uint32 mpc555_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
-{
+//----------------------------------------------------------------------------
+static cyg_uint32 mpc555_serial_rx_ISR(cyg_vector_t vector, 
+                                       cyg_addrword_t data){
   serial_channel * chan = (serial_channel *)data;
   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
 
   cyg_drv_interrupt_mask(mpc555_chan->rx_interrupt_num);
   cyg_drv_interrupt_acknowledge(mpc555_chan->rx_interrupt_num);
 
+  cyg_addrword_t port = mpc555_chan->base;
+  cyg_uint16 scdr;
+  cyg_uint16 scsr;
+
+  HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
+  // Always read out the received character, in order to clear receiver flags
+  HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
+  
+  mpc555_chan->rx_circbuf->scsr[mpc555_chan->rx_circbuf->fill_pos] = scsr;
+  mpc555_chan->rx_circbuf->buf[mpc555_chan->rx_circbuf->fill_pos] = (cyg_uint8)scdr;
+
+  if(mpc555_chan->rx_circbuf->fill_pos < MPC555_SCI_RX_BUFF_SIZE - 1){
+    mpc555_chan->rx_circbuf->fill_pos = mpc555_chan->rx_circbuf->fill_pos + 1;
+  }
+  else {
+    mpc555_chan->rx_circbuf->fill_pos = 0;
+  }
+  cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
+  return CYG_ISR_CALL_DSR; // cause the DSR to run
+}
+
+#ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_A
+//----------------------------------------------------------------------------
+// The low level queued receive interrupt handlers
+//----------------------------------------------------------------------------
+static cyg_uint32 mpc555_serial_rx_queue_top_ISR(cyg_vector_t vector, 
+                                                 cyg_addrword_t data){
+  serial_channel * chan = (serial_channel *)data;
+  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
+
+  cyg_drv_interrupt_mask(mpc555_chan->rx_interrupt_queue_top_full_num);
+  cyg_drv_interrupt_acknowledge(mpc555_chan->rx_interrupt_queue_top_full_num);
+
   return CYG_ISR_CALL_DSR; // cause the DSR to run
 }
 
-//------------------------------------------
+static cyg_uint32 mpc555_serial_rx_queue_bot_ISR(cyg_vector_t vector,
+                                                 cyg_addrword_t data){
+  serial_channel* chan = (serial_channel *)data;
+  mpc555_serial_info* mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
+
+  cyg_drv_interrupt_mask(mpc555_chan->rx_interrupt_queue_bot_full_num);
+  cyg_drv_interrupt_acknowledge(mpc555_chan->rx_interrupt_queue_bot_full_num);
+
+  return CYG_ISR_CALL_DSR; // cause the DSR to run
+}
+
+// This is used to flush the queue when the line falls idle
+static cyg_uint32 mpc555_serial_rx_idle_line_ISR(cyg_vector_t vector,
+                                                 cyg_addrword_t data){
+  serial_channel* chan = (serial_channel *)data;
+  mpc555_serial_info* mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
+
+  cyg_drv_interrupt_mask(mpc555_chan->rx_interrupt_idle_line_num);
+  cyg_drv_interrupt_acknowledge(mpc555_chan->rx_interrupt_idle_line_num);
+
+  return CYG_ISR_CALL_DSR; // cause the DSR to run
+}
+
+//----------------------------------------------------------------------------
+// The low level queued transmit interrupt handlers
+//----------------------------------------------------------------------------
+static cyg_uint32 mpc555_serial_tx_queue_top_ISR(cyg_vector_t vector,
+                                                 cyg_addrword_t data){
+  serial_channel * chan = (serial_channel *)data;
+  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
+
+  cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_queue_top_empty_num);
+  cyg_drv_interrupt_acknowledge(mpc555_chan->tx_interrupt_queue_top_empty_num);
+
+  return CYG_ISR_CALL_DSR; // cause the DSR to run
+}
+
+static cyg_uint32 mpc555_serial_tx_queue_bot_ISR(cyg_vector_t vector,
+                                                 cyg_addrword_t data){
+  serial_channel * chan = (serial_channel *)data;
+  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
+
+  cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_queue_bot_empty_num);
+  cyg_drv_interrupt_acknowledge(mpc555_chan->tx_interrupt_queue_bot_empty_num);
+
+  return CYG_ISR_CALL_DSR; // cause the DSR to run
+}
+#endif // SERIAL_A
+
+//----------------------------------------------------------------------------
 // The high level transmit interrupt handler
-//------------------------------------------
-static void mpc555_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
-{
+//----------------------------------------------------------------------------
+static void mpc555_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count,
+                                 cyg_addrword_t data){
   serial_channel * chan = (serial_channel *)data;
   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
 
@@ -593,63 +982,307 @@ static void mpc555_serial_tx_DSR(cyg_vec
     cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
 }
 
-//-----------------------------------------
+//----------------------------------------------------------------------------
 // The high level receive interrupt handler
-//-----------------------------------------
+//----------------------------------------------------------------------------
 #define MPC555_SERIAL_SCxSR_ERRORS (MPC555_SERIAL_SCxSR_OR | \
                                     MPC555_SERIAL_SCxSR_NF | \
                                     MPC555_SERIAL_SCxSR_FE | \
                                     MPC555_SERIAL_SCxSR_PF)
 
-static void mpc555_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
-{
+static void mpc555_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, 
+                                 cyg_addrword_t data){
   serial_channel * chan = (serial_channel *)data;
   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
-  cyg_addrword_t port = mpc555_chan->base;
-  cyg_uint16 scdr;
+//  cyg_addrword_t port = mpc555_chan->base;
+//  cyg_uint16 scdr;
   cyg_uint16 scsr;
 
 #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
   cyg_serial_line_status_t stat;
 #endif
 
-  HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
-  // Always read out the received character, in order to clear receiver flags
-  HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
-  
-  if(scsr & (cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS)
-  {
+
+  int i = mpc555_chan->rx_circbuf->read_pos;
+  while (i < mpc555_chan->rx_circbuf->fill_pos){
+     scsr = mpc555_chan->rx_circbuf->scsr[i];
+     if(scsr & (cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS){
 #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
-    if(scsr & MPC555_SERIAL_SCxSR_OR)
+       if(scsr & MPC555_SERIAL_SCxSR_OR){
+         stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;
+         (chan->callbacks->indicate_status)(chan, &stat);
+         // The current byte is still valid when OR is set
+         (chan->callbacks->rcv_char)(chan, mpc555_chan->rx_circbuf->buf[i]);
+       } 
+       else { // OR is never set with any other error bits
+         if(scsr & MPC555_SERIAL_SCxSR_NF){
+           stat.which = CYGNUM_SERIAL_STATUS_NOISEERR;
+           (chan->callbacks->indicate_status)(chan, &stat);
+         } 
+         if(scsr & MPC555_SERIAL_SCxSR_FE){
+           stat.which = CYGNUM_SERIAL_STATUS_FRAMEERR;
+           (chan->callbacks->indicate_status)(chan, &stat);
+         }   
+         if(scsr & MPC555_SERIAL_SCxSR_PF){
+           stat.which = CYGNUM_SERIAL_STATUS_PARITYERR;
+           (chan->callbacks->indicate_status)(chan, &stat);
+         }
+       }
+#endif
+     } 
+     else {
+       (chan->callbacks->rcv_char)(chan, mpc555_chan->rx_circbuf->buf[i]);
+     }
+     ++i;
+  } 
+
+    cyg_drv_isr_lock();
+    mpc555_chan->rx_circbuf->fill_pos = 0;
+    mpc555_chan->rx_circbuf->read_pos = 0;
+    cyg_drv_isr_unlock();
+}
+
+#ifdef CYGPKG_IO_SERIAL_POWERPC_MPC555_SERIAL_A
+//----------------------------------------------------------------------------
+// The high level queued transmit interrupt handler
+//----------------------------------------------------------------------------
+static void mpc555_serial_tx_queue_DSR(cyg_vector_t vector, cyg_ucount32 count, 
+                                       cyg_addrword_t data){
+  serial_channel * chan = (serial_channel *)data;
+  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
+  bool QTHE = false;
+  bool QBHE = false;
+  cyg_uint16 qscisr;
+  cyg_uint16 qscicr;
+  HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
+  QTHE = (qscisr & CYGARC_REG_IMM_QSCI1SR_QTHE) ? true : false;
+  QBHE = (qscisr & CYGARC_REG_IMM_QSCI1SR_QBHE) ? true : false;
+  
+  CYG_ASSERT(QTHE || QBHE,"In tx queue DSR for no reason");
+
+  HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1CR, qscicr);
+  int chars_avail;
+  unsigned char* chars;
+  int block_index = 0;
+  cyg_addrword_t i;
+  cyg_uint16 queue_transfer;
+  xmt_req_reply_t result = (chan->callbacks->data_xmt_req)(chan, 24, &chars_avail, &chars);
+  if(CYG_XMT_OK == result){
+    queue_transfer = (chars_avail > 8) ? 8 : chars_avail;
+    if(QTHE){
+      for(i=0; i < queue_transfer; i++){
+        HAL_WRITE_UINT16(CYGARC_REG_IMM_SCTQ + (i * 2), chars[block_index]);
+        ++block_index;
+      }
+      chan->callbacks->data_xmt_done(chan, queue_transfer);
+      // Clear QTHE
+      qscisr &= ~(CYGARC_REG_IMM_QSCI1SR_QTHE);
+      HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
+      
+      // Re-enable wrap QTWE
+      HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1CR, qscicr);
+      qscicr |= ((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QTWE);
+      HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1CR, qscicr);
+      HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1CR, qscicr);
+      // load QTSZ with how many chars *after* the next wrap
+      cyg_uint16 next_time = (chars_avail) > 16 ? 15 : chars_avail -1; 
+      qscicr &= ~(CYGARC_REG_IMM_QSCI1CR_QTSZ);
+      qscicr |= (CYGARC_REG_IMM_QSCI1CR_QTSZ & next_time);
+      HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1CR, qscicr);
+      cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_queue_top_empty_num);
+    }
+    else if(QBHE){
+      for(i=8; i < queue_transfer + 8; i++){
+        HAL_WRITE_UINT16(CYGARC_REG_IMM_SCTQ + (i * 2), chars[block_index]);
+        ++block_index;
+      }
+      chan->callbacks->data_xmt_done(chan, queue_transfer);
+      // Clear QBHE
+      qscisr &= ~(CYGARC_REG_IMM_QSCI1SR_QBHE);
+      HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
+      cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_queue_bot_empty_num);
+    }
+
+  }   
+  else if(CYG_XMT_EMPTY== result){
+    // No more data
+    cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_queue_top_empty_num);
+    cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_queue_bot_empty_num);
+    mpc555_chan->tx_interrupt_enable = false;
+
+    // Clear QTHE
+    HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
+    qscisr &= ~(CYGARC_REG_IMM_QSCI1SR_QTHE);
+    HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
+  }
+}
+
+//----------------------------------------------------------------------------
+// The high level queued receive interrupt handler
+//----------------------------------------------------------------------------
+static void mpc555_serial_rx_queue_DSR(cyg_vector_t vector, 
+                                       cyg_ucount32 count, cyg_addrword_t data){
+  serial_channel * chan = (serial_channel *)data;
+  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
+  cyg_addrword_t port = mpc555_chan->base;
+  cyg_uint16 scrq;
+  cyg_uint16 qscisr;
+  cyg_uint16 scsr;
+  cyg_uint16 scdr;
+  bool QTHF = false;
+  bool QBHF = false;
+  bool idle = false;
+  // Read status reg before reading any data otherwise NE flag will be lost
+  HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
+  HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
+  QTHF = (qscisr & CYGARC_REG_IMM_QSCI1SR_QTHF) ? true : false;
+  QBHF = (qscisr & CYGARC_REG_IMM_QSCI1SR_QBHF) ? true : false;
+  idle = (scsr & CYGARC_REG_IMM_SCxSR_IDLE)? true : false;
+  // The queue pointer is the next place to be filled by incomming data
+  cyg_uint16 queue_pointer = (qscisr & CYGARC_REG_IMM_QSCI1SR_QRPNT) >> 4;
+
+  int start;
+  int space_req = 0;
+  // Idle needs to be handled first as the IDLE bit will be cleared by a read of
+  // scsr followed by a read of scrq[0:16]
+
+  if(queue_pointer > mpc555_chan->rx_last_queue_pointer){
+    start = mpc555_chan->rx_last_queue_pointer;
+    space_req = mpc555_serial_read_queue(chan, start, queue_pointer - 1);
+  }
+  else {// Its wrapped around
+    if(mpc555_chan->rx_last_queue_pointer > queue_pointer){
+      space_req = mpc555_serial_read_queue(chan, mpc555_chan->rx_last_queue_pointer,15);
+      if(queue_pointer != 0){
+        mpc555_serial_read_queue(chan, 0,queue_pointer -1); 
+      }
+    }
+    else // No new data to read, do nothing here
     {
+    }
+  }
+
+  mpc555_chan->rx_last_queue_pointer = queue_pointer;
+    
+  if(CYGARC_REG_IMM_QSCI1SR_QOR & qscisr){
+    // Need to re-enable the queue
+    cyg_uint16 qscicr;
+    HAL_READ_UINT16( CYGARC_REG_IMM_QSCI1CR, qscicr);
+    qscicr |= ((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QRE);
+    HAL_WRITE_UINT16( CYGARC_REG_IMM_QSCI1CR, qscicr);
+    // Queue has overrun but data might not have been lost yet
+    if(scsr & MPC555_SERIAL_SCxSR_OR){  
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+      cyg_serial_line_status_t stat;
       stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;
-      (chan->callbacks->indicate_status)(chan, &stat);
-    } 
-    if(scsr & MPC555_SERIAL_SCxSR_NF)
-    {
+      (chan->callbacks->indicate_status)(chan, &stat);    
+#endif
+    }
+  }
+
+  if(scsr & (cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS){
+    // Special case for queue overrun handled above.
+    // Only data without FE or PF is allowed into the queue.
+    // Data with NE is allowed into the queue.
+    // If FE or PF have occured then the queue is disabled
+    // until they are cleared (by reading scsr then scdr).
+    
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+    cyg_serial_line_status_t stat;
+    if(scsr & MPC555_SERIAL_SCxSR_NF){
+      // Note if there is more than one frame in the queue
+      // it is not possible to tell which frame
+      // in the queue caused the noise error.
+      // The error has already been cleared by reading
+      // srsr then scrq[n], so no action is required here.
       stat.which = CYGNUM_SERIAL_STATUS_NOISEERR;
       (chan->callbacks->indicate_status)(chan, &stat);
     } 
-    if(scsr & MPC555_SERIAL_SCxSR_FE)
-    {
-      stat.which = CYGNUM_SERIAL_STATUS_FRAMEERR;
-      (chan->callbacks->indicate_status)(chan, &stat);
-    } 
-    if(scsr & MPC555_SERIAL_SCxSR_PF)
-    {
-      stat.which = CYGNUM_SERIAL_STATUS_PARITYERR;
-      (chan->callbacks->indicate_status)(chan, &stat);
+#endif 
+    if(scsr & (MPC555_SERIAL_SCxSR_FE | MPC555_SERIAL_SCxSR_PF)){
+      // This action needs to be taken clear the status bits so that
+      // the queue can be re-enabled.
+      HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
+      // Need to re-enable the queue
+      cyg_uint16 qscicr;
+      HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1CR, qscicr);
+      qscicr |= ((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QRE);
+      HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1CR, qscicr);
+      
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+      if(scsr & MPC555_SERIAL_SCxSR_FE){
+        stat.which = CYGNUM_SERIAL_STATUS_FRAMEERR;
+        (chan->callbacks->indicate_status)(chan, &stat);
+      }   
+      if(scsr & MPC555_SERIAL_SCxSR_PF){
+        stat.which = CYGNUM_SERIAL_STATUS_PARITYERR;
+        (chan->callbacks->indicate_status)(chan, &stat);
+      }
+#endif
     }
-#endif
+  }
+  if(QTHF){
+    qscisr &= ~((cyg_uint16)CYGARC_REG_IMM_QSCI1SR_QTHF);
+    HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
+    //cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_queue_top_full_num);
+  }
+  if(QBHF){
+    qscisr &= ~((cyg_uint16)CYGARC_REG_IMM_QSCI1SR_QBHF);
+    HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1SR, qscisr);
+    //cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_queue_bot_full_num);
   }
-  else
-  {
-    (chan->callbacks->rcv_char)(chan, (cyg_uint8)scdr);
+  if(idle){
+    if(idle && !space_req){
+      // The IDLE flag can be set sometimes when RE is set
+      // so a read of scrq is needed to clear it.
+      // If this occurs there should be no new data yet otherwise the
+      // condition is impossible to detect
+      HAL_READ_UINT16(CYGARC_REG_IMM_SCRQ, scrq);
+    }
+    HAL_READ_UINT16(CYGARC_REG_IMM_SCRQ, scrq);
+    //cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_idle_line_num);
   }
-
-  cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
+  // A bit lasy, but we don't know or care what the original ISR source
+  // was so to cover all bases re-enble them all
+  cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_queue_top_full_num);
+  cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_queue_bot_full_num);
+  cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_idle_line_num);
 }
 
+static int mpc555_serial_read_queue(serial_channel* chan, int start, int end)
+{
+  int block_index = 0;
+  cyg_uint16 scrq;
+  cyg_addrword_t i;
+  unsigned char* space;
+  int space_avail = 0;
+  int space_req = end - start + 1;
+  if((space_req > 0) && 
+     ((chan->callbacks->data_rcv_req)
+      (chan, space_req, &space_avail, &space) == CYG_RCV_OK)) {
+    CYG_ASSERT((start >= 0) && (start < 16),"rx queue read start point out of range");
+    CYG_ASSERT(start <= end,"rx queue read start and end points reversed");
+    for(i=start ;i < (start + space_avail); i++){
+      CYG_ASSERT((i >= 0) && (i < 16),"rx queue read out of range");
+      HAL_READ_UINT16(CYGARC_REG_IMM_SCRQ + (i * 2), scrq);
+      space[block_index] = scrq;
+      ++block_index;
+    } 
+    (chan->callbacks->data_rcv_done)(chan,space_avail);
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS    
+// If there's not enough room data will be lost.
+// There's no point calling rcv_char because the reader is blocked by this DSR.
+    if(space_avail < space_req){
+      cyg_serial_line_status_t stat;
+      stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;
+      (chan->callbacks->indicate_status)(chan, &stat); 
+    }
+#endif   
+  }
+  return space_req;
+}
+#endif // SERIAL_A
 #endif // CYGPKG_IO_SERIAL_POWERPC_MPC555
 
 // EOF mpc555_serial_with_ints.c
+