public inbox for ecos-patches@sourceware.org
 help / color / mirror / Atom feed
* mpc555 serial driver hardware queue support
@ 2008-09-02 17:30 Steven Clugston
  2008-12-23 17:08 ` Andrew Lunn
  0 siblings, 1 reply; 3+ messages in thread
From: Steven Clugston @ 2008-09-02 17:30 UTC (permalink / raw)
  To: ecos-patches

[-- Attachment #1: Type: text/plain, Size: 2827 bytes --]

Hi

There is a problem/shortcoming of the MPC555 serial driver that I've
discussed previously on the list that in its current implementation it
cannot cope with continuous concurrent reception and transmission of
characters as with the serial_echo.c test program. If a continuous
stream of characters are sent from a PC with something like a 16x5x chip
or superIO chip, then characters are almost immediately lost as the Rx
DSR is not run in time. I have added a sort of software circular buffer
between the ISR and DSR to allow a nominal number (say 256) of
characters to be buffered. This fixes or reduces the problem for
applications which require a serial packet of less than the buffer size
to be received, provided there is a rest period between packets.

For a continuous data stream, this buffer will eventually overflow no
matter how big it is made, so I have also separately implemented support
for the hardware serial queue facility on the mpc555. Unfortunately this
is only available on the first serial port (SCI1) on this chip (newer
5xx chips have it on both). It is available as a cdl option so that it
can be disabled and the old behaviour is restored. There are two
16-character buffers or queues, one for Rx and one for Tx. There are
half empty/full interrupts and full/empty interrupts as well as an Rx
line idle interrupt to flush the buffer/queue when there is a gap or
absence of incoming data.

I tried various methods for implementing this including separate DSRs
for the interrupt sources, a combined DSR that deals with each interrupt
source, but only reliable way I could get it to work is by using a
combined DSR which doesn't care what the actual ISR source was. The
trouble is that the status information is often lost by the time the DSR
is reached as reading from certain registers clears the contents. Also
DSRs seem to be run in the opposite order to which they are posted which
makes it even harder to work out what part of the queue to read/write.
The final implementation is perhaps the least elegant but nonetheless
works. It just reads/writes whatever data is available at the time of
the DSR running and subsequent DSR instances that have been posted just
drop through if there is no data left to read by the time they run.

I've tested this extensively but perhaps not exhaustively (all of the
type of parity/noise errors etc not fully tested as its perhaps
difficult to contrive these).

It seems to work well communicating with 16x5x chips, but some superIO
chips are able to trip it up after an extended period of time, not sure
wh this is.

Also I have experienced trouble when transmitting to USB-Serial adapters
(prolific etc). 
On the whole this works many times better than the existing driver as it
stands.

Steven Clugston

[-- Attachment #2: mpc555_serial.tar.gz --]
[-- Type: application/x-gzip, Size: 13473 bytes --]

[-- Attachment #3: mpc555_serialdiff.txt --]
[-- Type: text/plain, Size: 53384 bytes --]

Index: ecos/packages/devs/serial/powerpc/mpc555/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/serial/powerpc/mpc555/current/ChangeLog,v
retrieving revision 1.2
diff -r1.2 ChangeLog
0a1,13
> 2008-09-02  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.
> 
10c23
< 	* Refactored cme555 package to more generic mpc555
---
> 	* Refactored package to more generic mpc555
52a66,68
> //
> // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
> // at http://sources.redhat.com/ecos/ecos-license/
Index: ecos/packages/devs/serial/powerpc/mpc555/current/cdl/ser_powerpc_mpc555.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/serial/powerpc/mpc555/current/cdl/ser_powerpc_mpc555.cdl,v
retrieving revision 1.2
diff -r1.2 ser_powerpc_mpc555.cdl
75a76
>     implements    CYGINT_IO_SERIAL_BLOCK_TRANSFER
107a109,119
>     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 occuring."
>     }
113c125
<     default_value 1
---
>     default_value 0
Index: ecos/packages/devs/serial/powerpc/mpc555/current/src/mpc555_serial_with_ints.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/serial/powerpc/mpc555/current/src/mpc555_serial_with_ints.c,v
retrieving revision 1.2
diff -r1.2 mpc555_serial_with_ints.c
69a70,78
> #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;
> 
77,80c86,113
<   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
---
>   mpc555_sci_circbuf_t* rx_circbuf;     // rx buffer for ISR to DSR data exchange
>   bool           use_queue;             // Whether to use the queue when available
>   CYG_WORD       rx_last_queue_pointer; // Keep track of where has been read in the queue already
>   bool           rx_idle;               // Whether to use the queue when available
>   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 detection interrupt object
>   cyg_handle_t   rx_idle_interrupt_handle;        // the rx idle line detection interrupt 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
102a136,145
> 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 bool       mpc555_serial_read_queue(serial_channel* chan, int start, int end);
116a160,161
> #ifdef CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_A_USE_HWARE_QUEUE
> 
118,121c163,208
<                                                  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,
---
>                                                  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
>                                                  false,// init idle flag
>                                                  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));
> 
> #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,
123c210
< #if CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_A_BUFSIZE > 0
---
> 
139c226,235
< #else 
---
> #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};
>  
158a255,258
> 
> #if CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_B_BUFSIZE > 0
> static mpc555_sci_circbuf_t mpc555_serial_isr_to_dsr_buf1;
> 
160,163c260,265
<                                                  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,
---
>                                                  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,
165c267
< #if CYGNUM_IO_SERIAL_POWERPC_MPC555_SERIAL_B_BUFSIZE > 0
---
> 
181a284,291
> 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};
217,231d326
<     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);
< #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))
233,247c328,333
< #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))
<     return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_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_SCI1_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_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.
---
> // 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);
258,261c344,345
< 
<   cyg_uint16 status;
<   cyg_uint16 control;
< 
---
> // Only for SPI
> #if 0
274c358,387
<   
---
> #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);
> #endif
> #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);
336c449,464
< 
---
> #ifdef CYGDAT_IO_SERIAL_POWERPC_MPC555_SERIAL_A_USE_HWARE_QUEUE
>   cyg_uint16 qsci1cr;
>   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
378c506,533
<   { // enable the receiver interrupt
---
>   { 
> #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 qsci1cr;
>       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
381a537
> #endif
409c565,566
<    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
---
>    // Really only required for interrupt driven devices
>    (chan->callbacks->serial_init)(chan);
420,440c577,655
<      // 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);
< 
<      // 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);
<     }
---
>      // 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 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);
>   
>        // 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);
>      }
>      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 interrupt handler
>                                 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);
> 
> 
>        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 item passed to interrupt handler
>                                 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 interrupt handler
>                                 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 interrupt handler
>                                 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 interrupt handler
>                                 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);
> 
>      }
>    }
515,516c730,732
<       if(*len < sizeof(cyg_serial_info_t)) {
< 	return -EINVAL;
---
>       if(*len < sizeof(cyg_serial_info_t))
>       {
>         return -EINVAL;
534a751,785
>   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;
> 
>       HAL_READ_UINT16( CYGARC_REG_IMM_QSCI1CR, qscicr);
>       // Write QTSZ for first pass thro 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);
536,537c787,801
<   mpc555_chan->tx_interrupt_enable = true;
<   cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
---
>       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);
>       }
539c803,815
<   // No need to call xmt_char, this will generate an interrupt immediately.
---
>       HAL_READ_UINT16( CYGARC_REG_IMM_QSCI1CR, qscicr);
>       qscicr |= ((cyg_uint16)CYGARC_REG_IMM_QSCI1CR_QTE);
>       HAL_WRITE_UINT16( CYGARC_REG_IMM_QSCI1CR, qscicr);
>     }
> 
>     //mpc555_serial_stop_xmit(chan);
>   }
>   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.
>   }
549,552c825,831
<   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();
>   }
579a859,939
>   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
> }
> 
> //------------------------------------------------
> // 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);
> 
608,609c968,969
<   cyg_addrword_t port = mpc555_chan->base;
<   cyg_uint16 scdr;
---
> //  cyg_addrword_t port = mpc555_chan->base;
> //  cyg_uint16 scdr;
616,620c976,978
<   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)
621a980,982
>      scsr = mpc555_chan->rx_circbuf->scsr[i];
>      if(scsr & (cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS)
>      {
623c984,1075
<     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();
> }
> 
> //-------------------------------------------------
> // 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)
624a1077,1169
>       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 qscicr;
>   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_avail;
>   int space_req;
>   // 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;
>     mpc555_serial_read_queue(chan, start, queue_pointer - 1);
>   }
>   else // Its wrapped around
>   {
>     if(mpc555_chan->rx_last_queue_pointer > queue_pointer)
>     {
>       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;
626,627c1171,1185
<       (chan->callbacks->indicate_status)(chan, &stat);
<     } 
---
>       (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;
629a1188,1192
>       // 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.
633c1196,1197
<     if(scsr & MPC555_SERIAL_SCxSR_FE)
---
> #endif 
>     if(scsr & (MPC555_SERIAL_SCxSR_FE | MPC555_SERIAL_SCxSR_PF))
635,638c1199,1232
<       stat.which = CYGNUM_SERIAL_STATUS_FRAMEERR;
<       (chan->callbacks->indicate_status)(chan, &stat);
<     } 
<     if(scsr & 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);
>       // Queue needs to be re-initialised here
>       
> #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
>     }
>   }
>   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);
>   }
>   if(idle)
>   {
>     if(idle && !space_req)
640,641c1234,1236
<       stat.which = CYGNUM_SERIAL_STATUS_PARITYERR;
<       (chan->callbacks->indicate_status)(chan, &stat);
---
>       // The IDLE flag can be set sometimes when RE is set
>       // so a read of scrq is needed to clear it 
>       HAL_READ_UINT16(CYGARC_REG_IMM_SCRQ, scrq);
643c1238,1267
< #endif
---
>     HAL_READ_UINT16(CYGARC_REG_IMM_SCRQ, scrq);
>     //cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_idle_line_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 bool 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;
>   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);
647c1271
<     (chan->callbacks->rcv_char)(chan, (cyg_uint8)scdr);
---
>     return false;
649,650c1273,1283
< 
<   cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
---
> #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 true;
655a1289
> 
Index: ecos/packages/hal/powerpc/cme555/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/powerpc/cme555/current/ChangeLog,v
retrieving revision 1.6
diff -r1.6 ChangeLog
0a1,4
> 2008-09-02  Steven Clugston  <steven.clugston@ncl.ac.uk>
> 
> 	* src/hal_diag.c: Changed confusing SCI0/1 comments to SCI1/2
>  
Index: ecos/packages/hal/powerpc/cme555/current/src/hal_diag.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/powerpc/cme555/current/src/hal_diag.c,v
retrieving revision 1.2
diff -r1.2 hal_diag.c
88,89c88,89
< #define CYG_DEV_SERIAL_BASE_A    0x305008 // SCI0
< #define CYG_DEV_SERIAL_BASE_B    0x305020 // SCI1
---
> #define CYG_DEV_SERIAL_BASE_A    0x305008 // SCI1
> #define CYG_DEV_SERIAL_BASE_B    0x305020 // SCI2
276c276
<       CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX,
---
>       CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
282c282
<       CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
---
>       CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX,
Index: ecos/packages/hal/powerpc/ec555/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/powerpc/ec555/current/ChangeLog,v
retrieving revision 1.10
diff -r1.10 ChangeLog
0a1,4
> 2008-09-02  Steven Clugston  <steven.clugston@ncl.ac.uk>
> 
> 	* src/hal_diag.c: Changed confusing SCI0/1 comments to SCI1/2
>  
Index: ecos/packages/hal/powerpc/ec555/current/src/hal_diag.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/powerpc/ec555/current/src/hal_diag.c,v
retrieving revision 1.3
diff -r1.3 hal_diag.c
88,89c88,89
< #define CYG_DEV_SERIAL_BASE_A    0x305008 // SCI0
< #define CYG_DEV_SERIAL_BASE_B    0x305020 // SCI1
---
> #define CYG_DEV_SERIAL_BASE_A    0x305008 // SCI1
> #define CYG_DEV_SERIAL_BASE_B    0x305020 // SCI2
276c276
<       CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX,
---
>       CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
280c280
<       CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
---
>       CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX,
Index: ecos/packages/hal/powerpc/mpc5xx/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/powerpc/mpc5xx/current/ChangeLog,v
retrieving revision 1.7
diff -r1.7 ChangeLog
0a1,10
> 2008-09-02  Steven Clusgton  <steven.clugston@ncl.ac.uk>
> 
>     * include/var_intr.h:
>     * include/var_intr.c: 
> 
>     Changed confusing SCI0/1 naming to SCI1/2 to be consistent with actual 
>     register names. 
>     Removed some SCI related interrupt acknowledges so that the status 
>     is preserved for the DSR.
> 
Index: ecos/packages/hal/powerpc/mpc5xx/current/include/var_intr.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/powerpc/mpc5xx/current/include/var_intr.h,v
retrieving revision 1.5
diff -r1.5 var_intr.h
189,196c189,196
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX       31  // SCI 0 transmit
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TXC      32  // SCI 0 transmit complete
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX       33  // SCI 0 receiver full
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI0_IDLE     34  // SCI 0 idle line detected
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX       35  // SCI 1 transmit
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXC      36  // SCI 1 transmit complete
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX       37  // SCI 1 receiver full
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE     38  // SCI 1 idle line detected
---
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX       31  // SCI 1 transmit
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXC      32  // SCI 1 transmit complete
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX       33  // SCI 1 receiver full
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE     34  // SCI 1 idle line detected
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TX       35  // SCI 2 transmit
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TXC      36  // SCI 2 transmit complete
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX       37  // SCI 2 receiver full
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI2_IDLE     38  // SCI 2 idle line detected
473c473
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX:
483c483
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TXC:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXC:
493c493
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX:
503c503
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_IDLE:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE:
513c513
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TX:
523c523
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXC:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TXC:
533c533
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX:
543c543
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_IDLE:
1147c1147
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX:
1157c1157
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TXC:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXC:
1167c1167
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX:
1177c1177
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_IDLE:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE:
1187c1187
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TX:
1197c1197
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXC:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TXC:
1207c1207
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX:
1217c1217
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE:
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_IDLE:
1822,1837d1821
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX:
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TXC:
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX:
<         // Nothing needs to be done here
<         break;
< 
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_IDLE:
<     {
<         cyg_uint16 scxsr;
<    
<         HAL_READ_UINT16(CYGARC_REG_IMM_SC1SR, scxsr);
<         scxsr &= ~(CYGARC_REG_IMM_SCxSR_IDLE);
<         HAL_WRITE_UINT16(CYGARC_REG_IMM_SC1SR, scxsr);
<         break;
<     }
< 
1841c1825,1826
<         // nothing needs to be done here
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE:
>     // Nothing needs to be done here
1844,1850c1829,1833
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE:
<     {
<         cyg_uint16 scxsr;
<    
<         HAL_READ_UINT16(CYGARC_REG_IMM_SC2SR, scxsr);
<         scxsr &= ~(CYGARC_REG_IMM_SCxSR_IDLE);
<         HAL_WRITE_UINT16(CYGARC_REG_IMM_SC2SR, scxsr);
---
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TX:
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TXC:
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX:
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_IDLE:
>         // nothing needs to be done here
1852d1834
<     }
1875,1883d1856
<     {
<         cyg_uint16 qsci1sr;
< 
<         HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, qsci1sr);
<         qsci1sr &= ~(CYGARC_REG_IMM_QSCI1SR_QTHE);
<         HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1SR, qsci1sr);
<         break;
<     }
< 
1885,1890d1857
<     {
<         cyg_uint16 qsci1sr;
< 
<         HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, qsci1sr);
<         qsci1sr &= ~(CYGARC_REG_IMM_QSCI1SR_QBHE);
<         HAL_WRITE_UINT16(CYGARC_REG_IMM_QSCI1SR, qsci1sr);
1892d1858
<     }
2390c2356
<         rtcsc &= ~(CYGARC_REG_IMM_RTCSC_ALR); // accidently. Just do wahat is asked.
---
>         rtcsc &= ~(CYGARC_REG_IMM_RTCSC_ALR); // accidently. Just do what is asked.
2459,2462d2424
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX:
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TXC:
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX:
<     case CYGNUM_HAL_INTERRUPT_IMB3_SCI0_IDLE:
2466a2429,2432
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TX:
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TXC:
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX:
>     case CYGNUM_HAL_INTERRUPT_IMB3_SCI2_IDLE:
2745,2748d2710
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX_PRIORITY      CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TXC_PRIORITY     CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX_PRIORITY      CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI 
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI0_IDLE_PRIORITY    CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI
2751,2752c2713,2718
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX_PRIORITY      CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI
< #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE_PRIORITY    CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI 
---
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX_PRIORITY      CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI 
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE_PRIORITY    CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TX_PRIORITY      CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI2_TXC_PRIORITY     CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX_PRIORITY      CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI
> #define CYGNUM_HAL_INTERRUPT_IMB3_SCI2_IDLE_PRIORITY    CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI 
Index: ecos/packages/hal/powerpc/mpc5xx/current/src/var_intr.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/powerpc/mpc5xx/current/src/var_intr.c,v
retrieving revision 1.5
diff -r1.5 var_intr.c
172c172
< 	    isr_ret = hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX);
---
> 	    isr_ret = hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX);
182c182
< 	    isr_ret = hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX);
---
> 	    isr_ret = hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX);
389,390c389,390
<   HAL_INTERRUPT_SET_LEVEL(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX, CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI);	
<   HAL_INTERRUPT_SET_LEVEL(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX, CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI);	
---
>   HAL_INTERRUPT_SET_LEVEL(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX, CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI);	
>   HAL_INTERRUPT_SET_LEVEL(CYGNUM_HAL_INTERRUPT_IMB3_SCI2_RX, CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI);	

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: mpc555 serial driver hardware queue support
  2008-09-02 17:30 mpc555 serial driver hardware queue support Steven Clugston
@ 2008-12-23 17:08 ` Andrew Lunn
  0 siblings, 0 replies; 3+ messages in thread
From: Andrew Lunn @ 2008-12-23 17:08 UTC (permalink / raw)
  To: Steven Clugston; +Cc: ecos-patches

[-- Attachment #1: Type: text/plain, Size: 2736 bytes --]

On Tue, Sep 02, 2008 at 06:25:54PM +0100, Steven Clugston wrote:
> Hi
> 
> There is a problem/shortcoming of the MPC555 serial driver that I've
> discussed previously on the list that in its current implementation it
> cannot cope with continuous concurrent reception and transmission of
> characters as with the serial_echo.c test program. If a continuous
> stream of characters are sent from a PC with something like a 16x5x chip
> or superIO chip, then characters are almost immediately lost as the Rx
> DSR is not run in time. I have added a sort of software circular buffer
> between the ISR and DSR to allow a nominal number (say 256) of
> characters to be buffered. This fixes or reduces the problem for
> applications which require a serial packet of less than the buffer size
> to be received, provided there is a rest period between packets.
> 
> For a continuous data stream, this buffer will eventually overflow no
> matter how big it is made, so I have also separately implemented support
> for the hardware serial queue facility on the mpc555. Unfortunately this
> is only available on the first serial port (SCI1) on this chip (newer
> 5xx chips have it on both). It is available as a cdl option so that it
> can be disabled and the old behaviour is restored. There are two
> 16-character buffers or queues, one for Rx and one for Tx. There are
> half empty/full interrupts and full/empty interrupts as well as an Rx
> line idle interrupt to flush the buffer/queue when there is a gap or
> absence of incoming data.
> 
> I tried various methods for implementing this including separate DSRs
> for the interrupt sources, a combined DSR that deals with each interrupt
> source, but only reliable way I could get it to work is by using a
> combined DSR which doesn't care what the actual ISR source was. The
> trouble is that the status information is often lost by the time the DSR
> is reached as reading from certain registers clears the contents. Also
> DSRs seem to be run in the opposite order to which they are posted which
> makes it even harder to work out what part of the queue to read/write.
> The final implementation is perhaps the least elegant but nonetheless
> works. It just reads/writes whatever data is available at the time of
> the DSR running and subsequent DSR instances that have been posted just
> drop through if there is no data left to read by the time they run.
> 
> I've tested this extensively but perhaps not exhaustively (all of the
> type of parity/noise errors etc not fully tested as its perhaps
> difficult to contrive these).

This patch has been going back and forth for a while, and has now
reached the state it can be committed. Attached is what has been
committed.

        Andrew

[-- Attachment #2: devs_serial_mpc555.diff --]
[-- Type: text/x-diff, Size: 65815 bytes --]

Index: devs/serial/powerpc/mpc555/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/serial/powerpc/mpc555/current/ChangeLog,v
retrieving revision 1.2
diff -u -r1.2 ChangeLog
--- devs/serial/powerpc/mpc555/current/ChangeLog	2 Sep 2008 05:56:02 -0000	1.2
+++ devs/serial/powerpc/mpc555/current/ChangeLog	23 Dec 2008 16:58:04 -0000
@@ -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-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>
 
Index: devs/serial/powerpc/mpc555/current/cdl/ser_powerpc_mpc555.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/serial/powerpc/mpc555/current/cdl/ser_powerpc_mpc555.cdl,v
retrieving revision 1.2
diff -u -r1.2 ser_powerpc_mpc555.cdl
--- devs/serial/powerpc/mpc555/current/cdl/ser_powerpc_mpc555.cdl	2 Sep 2008 05:56:02 -0000	1.2
+++ devs/serial/powerpc/mpc555/current/cdl/ser_powerpc_mpc555.cdl	23 Dec 2008 16:58:04 -0000
@@ -73,6 +73,7 @@
     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 @@
             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 @@
                 the set of global flags if present."
         }
     }
-
 }
 
 # EOF ser_powerpc_mpc555.cdl
Index: devs/serial/powerpc/mpc555/current/src/mpc555_serial_with_ints.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/serial/powerpc/mpc555/current/src/mpc555_serial_with_ints.c,v
retrieving revision 1.2
diff -u -r1.2 mpc555_serial_with_ints.c
--- devs/serial/powerpc/mpc555/current/src/mpc555_serial_with_ints.c	2 Sep 2008 05:56:02 -0000	1.2
+++ devs/serial/powerpc/mpc555/current/src/mpc555_serial_with_ints.c	23 Dec 2008 16:58:05 -0000
@@ -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 @@
                    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 @@
 #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 @@
              &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);
-#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))
+  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))
-    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_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_SCI1_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_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.
+// 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))
+  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))
+  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))
+  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))
+  if((status & CYGARC_REG_IMM_QSCI1SR_QBHE) && 
+      (control & CYGARC_REG_IMM_QSCI1CR_QBHEI))
     return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQBHE);
-
-  cyg_uint16 status;
-  cyg_uint16 control;
-
+// 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))
+  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))
+  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))
+  if((status & CYGARC_REG_IMM_SPSR_HALTA) && 
+      (control & CYGARC_REG_IMM_SPCR3_HMIE))
     return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_HALTA);
 #endif
-  
+#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);
+#endif // HW_QUEUE
+#endif // SERIAL_A
+
+  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 @@
      (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 @@
   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 @@
   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 @@
   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 @@
   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 @@
      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);
-
-     // 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);
-    }
-
+     // 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);
+
+
+       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 @@
   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 @@
     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 @@
   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 @@
   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;
+
+      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);
+
+      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_num);
+      mpc555_chan->tx_interrupt_enable = true;
 
-  // No need to call xmt_char, this will generate an interrupt immediately.
+      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 @@
   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 @@
     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
+    }
   }
-  else
-  {
-    (chan->callbacks->rcv_char)(chan, (cyg_uint8)scdr);
+  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);
   }
-
-  cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_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);
+  }
+  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);
+  }
+  // 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
+

^ permalink raw reply	[flat|nested] 3+ messages in thread

* RE: mpc555 serial driver hardware queue support
       [not found] <EMEW-k86AXsa7aa3e8cc07bf545d377dd51ae376f1f-20080907093350.GB22058@lunn.ch>
@ 2008-12-08 11:01 ` Steven Clugston
  0 siblings, 0 replies; 3+ messages in thread
From: Steven Clugston @ 2008-12-08 11:01 UTC (permalink / raw)
  To: ecos-patches

[-- Attachment #1: Type: text/plain, Size: 5439 bytes --]


-----Original Message-----
From: Andrew Lunn [mailto:andrew@lunn.ch] 
Sent: 07 September 2008 10:34
To: Steven Clugston
Subject: Re: mpc555 serial driver hardware queue support


On Fri, Sep 05, 2008 at 02:07:01PM +0100, Steven Clugston wrote:
> 
> -----Original Message-----
> From: Andrew Lunn [mailto:andrew@lunn.ch]
> Sent: 05 September 2008 07:26
> To: Steven Clugston
> Subject: Re: mpc555 serial driver hardware queue support
> 
> 
> >> I've run out of time today, so I'll pick this up tomorrow and
> >> hopefully resolve it.
> 
> >No rush. Take your time. Look how long it took me to pick up this
> thread after your assignment took place.
> >
> >      Andrew
> 
> 
> Andrew,
> 
> I've made the common ISR change and tested it. Also new in this diff 
> I've modified var_intr.h to correct the interrupt priority defines. 
> I've checked in the hardware manual to confirm that the lowest 
> interrupt number does infact have the highest priority. There are some

> asserts which where inconsistent with this which I've corrected as 
> well.

> I have some new problems now. Attached is the file
mpc555_serial_with_ints.c. It contains your patch plus i wrapped a lot
of the long lines. I personally don't like lines longer than 80
characters.
>
> I then started compiler testing. I picked an arbitrary target which
uses this driver, the ec555.
>
> rm -fr *
> ecosconfig new ec555
> emacs ecos.ecc and set CYGPKG_IO_SERIAL_DEVICES to 1
> ecosconfig tree
> make -s
> headers finished
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c: In function `mpc555_serial_start_xmit':
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:772: structure has no member named
`data_xmt_req'
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:790: structure has no member named
`data_xmt_done'
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c: In function `mpc555_serial_common_ISR':
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:860: warning: unused variable
`mpc555_chan'
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c: In function
`mpc555_serial_tx_queue_DSR':
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:1005: structure has no member named
`data_xmt_req'
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:1016: structure has no member named
`data_xmt_done'
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:1040: structure has no member named
`data_xmt_done'
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c: In function
`mpc555_serial_rx_queue_DSR':
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:1073: warning: unused variable `qscicr'
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:1089: warning: unused variable
`space_avail'
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c: In function `mpc555_serial_read_queue':
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:1216: structure has no member named
`data_rcv_req'
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:1229: structure has no member named
`data_rcv_done'
> /home/lunn/eCos/work/install/include/cyg/hal/hal_arbiter.h: At top
level:
>
/home/lunn/eCos/anoncvs-clean/packages/devs/serial/powerpc/mpc555/curren
t/src/mpc555_serial_with_ints.c:846: warning: `mpc555_serial_tx_ISR'
defined but not used
>
> The first error is because you use the callback data_xmt_req.  This
only exists when using block transfers. If
CYGINT_IO_SERIAL_BLOCK_TRANSFER is disabled, >which is the default, this
does not exist.
>
> Please could you do some more testing with other configurations and
fix any problems you find.
>
>    Thanks
>        Andrew

Hi Andrew

There was a condition where it was possible in cdl to select the
hardware serial drivers package but not actually select either of the
two serial devices so CYGINT_IO_SERIAL_BLOCK_TRANSFER was never set.
Although this is not a useful selection it is still possible, so I have
#ifdef'd the relevant places to prevent compile errors. I've also added
a trivial fix to re-enable the serial hardware queue after a frame error
occurs which happens repeatably when something is sent at the wrong baud
rate.

I've tested various permutations of different configurations and all
seem to compile and run on my board.

I've wrapped most of the long lines where it is not completely
detremental to code readability.
I also dislike sprawling code that's over 80 chars long, but I was
trying to respect the original code style, or minimise the changes to
it.

Is there an official, or defacto eCos code style?

Thanks,

Steven

[-- Attachment #2: mpc555_serial.tar.gz --]
[-- Type: application/x-gzip, Size: 11742 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2008-12-23 17:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-09-02 17:30 mpc555 serial driver hardware queue support Steven Clugston
2008-12-23 17:08 ` Andrew Lunn
     [not found] <EMEW-k86AXsa7aa3e8cc07bf545d377dd51ae376f1f-20080907093350.GB22058@lunn.ch>
2008-12-08 11:01 ` Steven Clugston

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).