This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: patch - at91 serial drivers assumed realtime response for DSR routines


So here's my version of the AT91 serial driver. It
utilizes the DMA hardware to achieve reliable operation
at higher baud rates. I tested it sending and receiving
at 115200 baud with the program running at a clock speed
of 40 MHz from slow memory (flash /w 4 wait states), and
it runs fine. The old driver failed miserably under these
conditions.

diff -ru packages-orig/devs/serial/arm/at91/current/ChangeLog packages/devs/serial/arm/at91/current/ChangeLog
--- packages-orig/devs/serial/arm/at91/current/ChangeLog	2003-10-17 11:55:44.000000000 +0200
+++ packages/devs/serial/arm/at91/current/ChangeLog	2003-10-23 11:17:37.000000000 +0200
@@ -1,3 +1,9 @@
+2003-10-23  Thomas Koeller  <thomas.koeller@baslerweb.com>
+
+	* src/at91_serial.c:
+	* cdl/ser_arm_at91.cdl: Major rewrite to achieve reliable
+	operation at higher baud rates.
+
 2003-10-16  Nick Garnett  <nickg@balti.calivar.com>
 
 	* src/at91_serial.c (at91_serial_config_port): Added update of
diff -ru packages-orig/devs/serial/arm/at91/current/cdl/ser_arm_at91.cdl packages/devs/serial/arm/at91/current/cdl/ser_arm_at91.cdl
--- packages-orig/devs/serial/arm/at91/current/cdl/ser_arm_at91.cdl	2003-02-24 15:12:18.000000000 +0100
+++ packages/devs/serial/arm/at91/current/cdl/ser_arm_at91.cdl	2003-10-21 15:16:49.000000000 +0200
@@ -61,7 +61,9 @@
     include_files ; # none _exported_ whatsoever
     description   "
            This option enables the serial device drivers for the
-           Atmel AT91 (EB40)."
+           Atmel AT91."
+    
+    implements    CYGINT_IO_SERIAL_BLOCK_TRANSFER
 
     compile       -library=libextras.a   at91_serial.c
 
diff -ru packages-orig/devs/serial/arm/at91/current/src/at91_serial.c packages/devs/serial/arm/at91/current/src/at91_serial.c
--- packages-orig/devs/serial/arm/at91/current/src/at91_serial.c	2003-10-17 11:55:45.000000000 +0200
+++ packages/devs/serial/arm/at91/current/src/at91_serial.c	2003-10-23 11:12:57.000000000 +0200
@@ -41,7 +41,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):     gthomas
-// Contributors:  gthomas
+// Contributors:  gthomas, tkoeller
 // Date:          2001-07-24
 // Purpose:       Atmel AT91/EB40 Serial I/O module (interrupt driven version)
 // Description: 
@@ -50,6 +50,8 @@
 //
 //==========================================================================
 
+#include <pkgconf/hal.h>
+#include <pkgconf/infra.h>
 #include <pkgconf/system.h>
 #include <pkgconf/io_serial.h>
 #include <pkgconf/io.h>
@@ -61,24 +63,41 @@
 #include <cyg/io/devtab.h>
 #include <cyg/io/serial.h>
 #include <cyg/infra/diag.h>
+#include <cyg/infra/cyg_type.h>
+
+externC void * memcpy( void *, const void *, size_t );
 
 #ifdef CYGPKG_IO_SERIAL_ARM_AT91
 
 #include "at91_serial.h"
 
+#define RX_BUFFER_SIZE 32
+
+#define SIFLG_NONE          0x00
+#define SIFLG_TX_READY      0x01
+#define SIFLG_XMIT_BUSY     0x02
+#define SIFLG_XMIT_CONTINUE 0x04
+
 typedef struct at91_serial_info {
     CYG_ADDRWORD   base;
     CYG_WORD       int_num;
+    CYG_WORD       stat;
+    int            transmit_size;
     cyg_interrupt  serial_interrupt;
     cyg_handle_t   serial_interrupt_handle;
+    cyg_uint8      rcv_buffer[2][RX_BUFFER_SIZE];
+    cyg_uint8      curbuf;
+    cyg_uint8      flags;
 } at91_serial_info;
 
 static bool at91_serial_init(struct cyg_devtab_entry *tab);
-static bool at91_serial_putc(serial_channel *chan, unsigned char c);
+static bool at91_serial_putc_interrupt(serial_channel *chan, unsigned char c);
+static bool at91_serial_putc_polled(serial_channel *chan, unsigned char c);
 static Cyg_ErrNo at91_serial_lookup(struct cyg_devtab_entry **tab, 
                                     struct cyg_devtab_entry *sub_tab,
                                     const char *name);
-static unsigned char at91_serial_getc(serial_channel *chan);
+static unsigned char at91_serial_getc_interrupt(serial_channel *chan);
+static unsigned char at91_serial_getc_polled(serial_channel *chan);
 static Cyg_ErrNo at91_serial_set_config(serial_channel *chan, cyg_uint32 key,
                                         const void *xbuf, cyg_uint32 *len);
 static void at91_serial_start_xmit(serial_channel *chan);
@@ -87,23 +106,40 @@
 static cyg_uint32 at91_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
 static void       at91_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
 
-static SERIAL_FUNS(at91_serial_funs, 
-                   at91_serial_putc, 
-                   at91_serial_getc,
+#if (defined(CYGPKG_IO_SERIAL_ARM_AT91_SERIAL0) && CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE > 0) \
+ || (defined(CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1) && CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE > 0)
+static SERIAL_FUNS(at91_serial_funs_interrupt, 
+                   at91_serial_putc_interrupt, 
+                   at91_serial_getc_interrupt,
+                   at91_serial_set_config,
+                   at91_serial_start_xmit,
+                   at91_serial_stop_xmit
+    );
+#endif
+
+#if (defined(CYGPKG_IO_SERIAL_ARM_AT91_SERIAL0) && CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE == 0) \
+ || (defined(CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1) && CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE == 0)
+static SERIAL_FUNS(at91_serial_funs_polled, 
+                   at91_serial_putc_polled, 
+                   at91_serial_getc_polled,
                    at91_serial_set_config,
                    at91_serial_start_xmit,
                    at91_serial_stop_xmit
     );
+#endif
 
 #ifdef CYGPKG_IO_SERIAL_ARM_AT91_SERIAL0
-static at91_serial_info at91_serial_info0 = {(CYG_ADDRWORD)AT91_USART0,
-                                             CYGNUM_HAL_INTERRUPT_USART0};
+static at91_serial_info at91_serial_info0 = {
+    base     : (CYG_ADDRWORD)AT91_USART0,
+    int_num  : CYGNUM_HAL_INTERRUPT_USART0
+};
+
 #if CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE > 0
 static unsigned char at91_serial_out_buf0[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE];
 static unsigned char at91_serial_in_buf0[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE];
 
 static SERIAL_CHANNEL_USING_INTERRUPTS(at91_serial_channel0,
-                                       at91_serial_funs, 
+                                       at91_serial_funs_interrupt, 
                                        at91_serial_info0,
                                        CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BAUD),
                                        CYG_SERIAL_STOP_DEFAULT,
@@ -115,7 +151,7 @@
     );
 #else
 static SERIAL_CHANNEL(at91_serial_channel0,
-                      at91_serial_funs, 
+                      at91_serial_funs_polled, 
                       at91_serial_info0,
                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BAUD),
                       CYG_SERIAL_STOP_DEFAULT,
@@ -136,14 +172,17 @@
 #endif //  CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1
 
 #ifdef CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1
-static at91_serial_info at91_serial_info1 = {(CYG_ADDRWORD)AT91_USART1,
-                                              CYGNUM_HAL_INTERRUPT_USART1};
+static at91_serial_info at91_serial_info1 = {
+    base     : (CYG_ADDRWORD)AT91_USART1,
+    int_num  : CYGNUM_HAL_INTERRUPT_USART1
+};
+
 #if CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE > 0
 static unsigned char at91_serial_out_buf1[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE];
 static unsigned char at91_serial_in_buf1[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE];
 
 static SERIAL_CHANNEL_USING_INTERRUPTS(at91_serial_channel1,
-                                       at91_serial_funs, 
+                                       at91_serial_funs_interrupt, 
                                        at91_serial_info1,
                                        CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BAUD),
                                        CYG_SERIAL_STOP_DEFAULT,
@@ -155,7 +194,7 @@
     );
 #else
 static SERIAL_CHANNEL(at91_serial_channel1,
-                      at91_serial_funs, 
+                      at91_serial_funs_polled, 
                       at91_serial_info1,
                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BAUD),
                       CYG_SERIAL_STOP_DEFAULT,
@@ -179,8 +218,8 @@
 static bool
 at91_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
 {
-    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
-    CYG_ADDRWORD base = at91_chan->base;
+    at91_serial_info * const at91_chan = (at91_serial_info *)chan->dev_priv;
+    const CYG_ADDRWORD base = at91_chan->base;
     cyg_uint32 parity = select_parity[new_config->parity];
     cyg_uint32 word_length = select_word_length[new_config->word_length-CYGNUM_SERIAL_WORD_LENGTH_5];
     cyg_uint32 stop_bits = select_stop_bits[new_config->stop];
@@ -192,22 +231,22 @@
     }
 
     // Reset device
-    HAL_WRITE_UINT32(base+AT91_US_CR, AT91_US_CR_RxRESET | AT91_US_CR_TxRESET);
+    HAL_WRITE_UINT32(base + AT91_US_CR, AT91_US_CR_RxRESET | AT91_US_CR_TxRESET);
 
     // Configuration
-    HAL_WRITE_UINT32(base+AT91_US_MR, parity | word_length | stop_bits);
+    HAL_WRITE_UINT32(base + AT91_US_MR, parity | word_length | stop_bits);
 
     // Baud rate
-    HAL_WRITE_UINT32(base+AT91_US_BRG, AT91_US_BAUD(select_baud[new_config->baud]));
+    HAL_WRITE_UINT32(base + AT91_US_BRG, AT91_US_BAUD(select_baud[new_config->baud]));
 
     // Disable all interrupts
-    HAL_WRITE_UINT32(base+AT91_US_IDR, 0xFFFFFFFF);
+    HAL_WRITE_UINT32(base + AT91_US_IDR, 0xFFFFFFFF);
 
-    // Enable Rx interrupts
-    HAL_WRITE_UINT32(base+AT91_US_IER, AT91_US_IER_RxRDY);
+    // Start receiver
+    HAL_WRITE_UINT32(base + AT91_US_IER, AT91_US_IER_RxRDY);
 
     // Enable RX and TX
-    HAL_WRITE_UINT32(base+AT91_US_CR, AT91_US_CR_RxENAB | AT91_US_CR_TxENAB);
+    HAL_WRITE_UINT32(base + AT91_US_CR, AT91_US_CR_RxENAB | AT91_US_CR_TxENAB | AT91_US_CR_RSTATUS);
 
     if (new_config != &chan->config) {
         chan->config = *new_config;
@@ -220,13 +259,16 @@
 static bool 
 at91_serial_init(struct cyg_devtab_entry *tab)
 {
-    serial_channel *chan = (serial_channel *)tab->priv;
-    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
+    serial_channel * const chan = (serial_channel *)tab->priv;
+    at91_serial_info * const at91_chan = (at91_serial_info *)chan->dev_priv;
     int res;
 
 #ifdef CYGDBG_IO_INIT
     diag_printf("AT91 SERIAL init - dev: %x.%d\n", at91_chan->base, at91_chan->int_num);
 #endif
+    at91_chan->curbuf = 0;
+    at91_chan->flags = SIFLG_NONE;
+    at91_chan->stat = 0;
     (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
     if (chan->out_cbuf.len != 0) {
         cyg_drv_interrupt_create(at91_chan->int_num,
@@ -249,7 +291,7 @@
                   struct cyg_devtab_entry *sub_tab,
                   const char *name)
 {
-    serial_channel *chan = (serial_channel *)(*tab)->priv;
+    serial_channel * const chan = (serial_channel *)(*tab)->priv;
 
     (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
     return ENOERR;
@@ -258,41 +300,63 @@
 // Send a character to the device output buffer.
 // Return 'true' if character is sent to device
 static bool
-at91_serial_putc(serial_channel *chan, unsigned char c)
+at91_serial_putc_interrupt(serial_channel *chan, unsigned char c)
 {
-    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
-    CYG_ADDRWORD base = at91_chan->base;
-    cyg_uint32 stat;
-
-    // Check status
-    HAL_READ_UINT32(base+AT91_US_CSR, stat);
-
-    // Send character if possible
-    if ((stat & AT91_US_CSR_TxRDY) != 0) {
-        HAL_WRITE_UINT32(base+AT91_US_THR, c);
-        return true;
-    } else {
-        return false;  // Couldn't send, tx was busy
+    at91_serial_info * const at91_chan = (at91_serial_info *)chan->dev_priv;
+    const bool res = (at91_chan->flags & SIFLG_XMIT_BUSY) == 0;
+    
+    if (res) {
+        const CYG_ADDRWORD base = at91_chan->base;
+        HAL_WRITE_UINT32(base + AT91_US_THR, c);
+        at91_chan->flags |= SIFLG_XMIT_BUSY;
     }
+    return res;
+}
+
+static bool
+at91_serial_putc_polled(serial_channel *chan, unsigned char c)
+{
+    at91_serial_info * const at91_chan = (at91_serial_info *)chan->dev_priv;
+    const CYG_ADDRWORD base = at91_chan->base;
+    CYG_WORD32 w;
+    
+    while (HAL_READ_UINT32(base + AT91_US_CSR, w), (w & AT91_US_IER_TxRDY) == 0)
+        CYG_EMPTY_STATEMENT;
+    HAL_WRITE_UINT32(base + AT91_US_THR, c);
+    return true;
 }
 
 // Fetch a character from the device input buffer, waiting if necessary
 static unsigned char 
-at91_serial_getc(serial_channel *chan)
+at91_serial_getc_interrupt(serial_channel *chan)
 {
-    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
-    CYG_ADDRWORD base = at91_chan->base;
-    cyg_uint32 c;
+    at91_serial_info * const at91_chan = (at91_serial_info *)chan->dev_priv;
+    const CYG_ADDRWORD base = at91_chan->base;
+    CYG_WORD32 c;
 
     // Read data
-    HAL_READ_UINT32(base+AT91_US_RHR, c);
-    return c;
+    HAL_READ_UINT32(base + AT91_US_RHR, c);
+    return (unsigned char) c;
+}
+
+static unsigned char 
+at91_serial_getc_polled(serial_channel *chan)
+{
+    at91_serial_info * const at91_chan = (at91_serial_info *)chan->dev_priv;
+    const CYG_ADDRWORD base = at91_chan->base;
+    CYG_WORD32 c;
+
+    while (HAL_READ_UINT32(base + AT91_US_CSR, c), (c & AT91_US_IER_RxRDY) == 0)
+        CYG_EMPTY_STATEMENT;
+    // Read data
+    HAL_READ_UINT32(base + AT91_US_RHR, c);
+    return (unsigned char) c;
 }
 
 // Set up the device characteristics; baud rate, etc.
 static Cyg_ErrNo
 at91_serial_set_config(serial_channel *chan, cyg_uint32 key,
-                         const void *xbuf, cyg_uint32 *len)
+                       const void *xbuf, cyg_uint32 *len)
 {
     switch (key) {
     case CYG_IO_SET_CONFIG_SERIAL_INFO:
@@ -316,57 +380,152 @@
 static void
 at91_serial_start_xmit(serial_channel *chan)
 {
-    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
-    CYG_ADDRWORD base = at91_chan->base;
-
-    (chan->callbacks->xmt_char)(chan);  // Kick transmitter (if necessary)
-    HAL_WRITE_UINT32(base+AT91_US_IER, AT91_US_IER_TxRDY);
+    at91_serial_info * const at91_chan = (at91_serial_info *)chan->dev_priv;
+    const CYG_ADDRWORD base = at91_chan->base;
+    unsigned char * chars;
+    xmt_req_reply_t res;
+    
+    cyg_drv_dsr_lock();
+    if ((at91_chan->flags & SIFLG_XMIT_CONTINUE) == 0) {
+        res = (chan->callbacks->data_xmt_req)(chan, 0xffff, &at91_chan->transmit_size, &chars);
+        switch (res)
+        {
+            case CYG_XMT_OK:
+                HAL_WRITE_UINT32(base + AT91_US_TPR, (CYG_WORD32) chars);
+                HAL_WRITE_UINT32(base + AT91_US_TCR, at91_chan->transmit_size);
+                at91_chan->flags |= SIFLG_XMIT_CONTINUE;
+                HAL_WRITE_UINT32(base + AT91_US_IER, AT91_US_IER_ENDTX);
+                break;
+            case CYG_XMT_DISABLED:
+                (chan->callbacks->xmt_char)(chan);  // Kick transmitter
+                at91_chan->flags |= SIFLG_XMIT_CONTINUE;
+                HAL_WRITE_UINT32(base + AT91_US_IER, AT91_US_IER_TxRDY);
+                break;
+            default:
+                // No data or unknown error - can't do anything about it
+                break;
+        }
+    }
+    cyg_drv_dsr_unlock();
 }
 
 // Disable the transmitter on the device
 static void 
 at91_serial_stop_xmit(serial_channel *chan)
 {
-    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
-    CYG_ADDRWORD base = at91_chan->base;
-
-    HAL_WRITE_UINT32(base+AT91_US_IDR, AT91_US_IER_TxRDY);
+    at91_serial_info * const at91_chan = (at91_serial_info *)chan->dev_priv;
+    const CYG_ADDRWORD base = at91_chan->base;
+    HAL_WRITE_UINT32(base + AT91_US_IDR, AT91_US_IER_TxRDY | AT91_US_IER_ENDTX);
+    at91_chan->flags &= ~SIFLG_XMIT_CONTINUE;
 }
 
 // Serial I/O - low level interrupt handler (ISR)
 static cyg_uint32 
 at91_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
 {
-    cyg_drv_interrupt_mask(vector);
+    serial_channel * const chan = (serial_channel *)data;
+    at91_serial_info * const at91_chan = (at91_serial_info *)chan->dev_priv;
+    const CYG_ADDRWORD base = at91_chan->base;
+    CYG_WORD32 stat, mask;
+
+    HAL_READ_UINT32(base + AT91_US_CSR, stat);
+    HAL_READ_UINT32(base + AT91_US_IMR, mask);
+    stat &= mask;
+    HAL_WRITE_UINT32(base + AT91_US_IDR, stat);
+
+    if (stat & AT91_US_IER_RxRDY) {
+        const cyg_uint8 cb = at91_chan->curbuf ^ 0x01;
+        CYG_WORD32 c;
+
+        HAL_READ_UINT32(base + AT91_US_RHR, c);
+        at91_chan->rcv_buffer[cb][0] = (cyg_uint8) c;
+        HAL_WRITE_UINT32(base + AT91_US_RPR,
+                         (CYG_WORD32) at91_chan->rcv_buffer[cb] + 1);
+        HAL_WRITE_UINT32(base + AT91_US_RCR, RX_BUFFER_SIZE - 1);
+        at91_chan->curbuf = cb;
+    }
+
+    at91_chan->stat |= stat;
     cyg_drv_interrupt_acknowledge(vector);
-    return (CYG_ISR_CALL_DSR|CYG_ISR_HANDLED);  // Cause DSR to be run
+    return CYG_ISR_CALL_DSR;
 }
 
 // Serial I/O - high level interrupt handler (DSR)
 static void       
 at91_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
 {
-    serial_channel *chan = (serial_channel *)data;
-    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
-    CYG_ADDRWORD base = at91_chan->base;
-    cyg_uint32 stat, c;
+    serial_channel * const chan = (serial_channel *)data;
+    at91_serial_info * const at91_chan = (at91_serial_info *)chan->dev_priv;
+    const CYG_ADDRWORD base = at91_chan->base;
+    CYG_WORD32 stat;
+
+    cyg_drv_interrupt_mask(vector);    
+    stat = at91_chan->stat;
+    at91_chan->stat = 0;
+    cyg_drv_interrupt_unmask(vector);    
 
-    // Check status
-    HAL_READ_UINT32(base+AT91_US_IMR, stat);
-
-    if (stat & (AT91_US_IER_TxRDY)) {
+    if (stat & AT91_US_IER_TxRDY) {
+        at91_chan->flags &= ~SIFLG_XMIT_BUSY;
         (chan->callbacks->xmt_char)(chan);
+        if (at91_chan->flags & SIFLG_XMIT_CONTINUE)
+            HAL_WRITE_UINT32(base + AT91_US_IER, AT91_US_IER_TxRDY);
     }
-    if (stat & (AT91_US_IER_RxRDY)) {
-        while (true) {
-            HAL_READ_UINT32(base+AT91_US_CSR, stat);
-            if ((stat & AT91_US_CSR_RxRDY) == 0) {
-                break;
+    
+    if (stat & AT91_US_IER_ENDTX) {
+        (chan->callbacks->data_xmt_done)(chan, at91_chan->transmit_size);
+        if (at91_chan->flags & SIFLG_XMIT_CONTINUE) {
+            unsigned char * chars;
+            xmt_req_reply_t res;
+
+            res = (chan->callbacks->data_xmt_req)(chan, 0xffff, &at91_chan->transmit_size, &chars);
+
+            switch (res)
+            {
+                case CYG_XMT_OK:
+                    HAL_WRITE_UINT32(base + AT91_US_TPR, (CYG_WORD32) chars);
+                    HAL_WRITE_UINT32(base + AT91_US_TCR, at91_chan->transmit_size);
+                    at91_chan->flags |= SIFLG_XMIT_CONTINUE;
+                    HAL_WRITE_UINT32(base + AT91_US_IER, AT91_US_IER_ENDTX);
+                    break;
+                default:
+                    // No data or unknown error - can't do anything about it
+                    // CYG_XMT_DISABLED should not happen here!
+                    break;
+            }
+        }
+    }
+
+    if (stat & AT91_US_IER_RxRDY) {
+        const cyg_uint8 cb = at91_chan->curbuf;
+        const cyg_uint8 * p, * end;
+
+        HAL_WRITE_UINT32(base + AT91_US_RCR, 0);
+        HAL_READ_UINT32(base + AT91_US_RPR, (CYG_WORD32) end);
+        HAL_WRITE_UINT32(base + AT91_US_IER, AT91_US_IER_RxRDY);
+        
+        p = at91_chan->rcv_buffer[cb];
+        while (p < end) {
+            rcv_req_reply_t res;
+            int space_avail;
+            unsigned char *space;
+
+            res = (chan->callbacks->data_rcv_req)(chan, end - at91_chan->rcv_buffer[cb],
+                                                  &space_avail, &space);
+            switch (res)
+            {
+                case CYG_RCV_OK:
+                    memcpy(space, p, space_avail);
+                    (chan->callbacks->data_rcv_done)(chan, space_avail);
+                    p += space_avail;
+                    break;
+                case CYG_RCV_DISABLED:
+                    (chan->callbacks->rcv_char)(chan, *p++);
+                    break;
+                default:
+                    // Buffer full or unknown error, can't do anything about it
+                    break;
             }
-            HAL_READ_UINT32(base+AT91_US_RHR, c);
-            (chan->callbacks->rcv_char)(chan, c);
         }
     }
-    cyg_drv_interrupt_unmask(vector);
 }
 #endif

--------------------------------------------------

Thomas Koeller, Software Development

Basler Vision Technologies
An der Strusbek 60-62
22926 Ahrensburg
Germany

Tel +49 (4102) 463-162
Fax +49 (4102) 463-239

mailto:thomas.koeller@baslerweb.com
http://www.baslerweb.com

==============================


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]