]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - packages/devs/serial/generic/16x5x/v2_0/src/ser_16x5x.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / devs / serial / generic / 16x5x / v2_0 / src / ser_16x5x.c
index 243083fff673310a22661d2921a1184de8e573e3..7bf73c7c51c4a5e4eb9266676144f5e5852f893e 100644 (file)
@@ -10,6 +10,7 @@
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 // Copyright (C) 2003 Gary Thomas
+// Copyright (C) 2006 eCosCentric Limited
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -33,9 +34,6 @@
 //
 // This exception does not invalidate any other reasons why a work based on
 // this file might be covered by the GNU General Public License.
-//
-// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
-// at http://sources.redhat.com/ecos/ecos-license/
 // -------------------------------------------
 //####ECOSGPLCOPYRIGHTEND####
 //==========================================================================
@@ -184,6 +182,9 @@ static unsigned char select_parity[] = {
 typedef struct pc_serial_info {
     cyg_addrword_t base;
     int            int_num;
+#ifdef CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
+    int            int_prio;
+#endif // CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
     cyg_interrupt  serial_interrupt;
     cyg_handle_t   serial_interrupt_handle;
 #ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
@@ -194,6 +195,8 @@ typedef struct pc_serial_info {
         s16550,
         s16550a
     } deviceType;
+    unsigned tx_fifo_size;
+    volatile unsigned tx_fifo_avail;
 #endif
 } pc_serial_info;
 
@@ -235,7 +238,17 @@ serial_config_port(serial_channel *chan,
 {
     pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
     cyg_addrword_t base = ser_chan->base;
+    //
+    // If the device supports a dynamic per channel baudrate generator
+    // then we call the CYG_IO_SERIAL_GENERIC_16X5X_CHAN_BAUD_GENERATOR() 
+    // macro to get the baud divisor. The macro takes the serial channel data 
+    // pointer and the baudrate as parameters and returns the baud divisior
+    //
+#ifdef CYG_IO_SERIAL_GENERIC_16X5X_CHAN_BAUD_GENERATOR
+    unsigned short baud_divisor = CYG_IO_SERIAL_GENERIC_16X5X_CHAN_BAUD_GENERATOR(ser_chan, new_config->baud);
+#else
     unsigned short baud_divisor = select_baud[new_config->baud];
+#endif
     unsigned char _lcr, _ier;
     if (baud_divisor == 0) return false;  // Invalid configuration
 
@@ -304,10 +317,17 @@ serial_config_port(serial_channel *chan,
                 _fcr_thresh=FCR_RT14; break;
             }
             _fcr_thresh|=FCR_FE|FCR_CRF|FCR_CTF;
-            HAL_WRITE_UINT8(base+REG_fcr, _fcr_thresh); // Enable and clear FIFO
+            ser_chan->tx_fifo_size = 
+              CYGNUM_IO_SERIAL_GENERIC_16X5X_FIFO_TX_SIZE;
+            // Enable and clear FIFO
+            HAL_WRITE_UINT8(base+REG_fcr, _fcr_thresh); 
         }
-        else
+        else {
+            ser_chan->tx_fifo_size = 1;
             HAL_WRITE_UINT8(base+REG_fcr, 0); // make sure it's disabled
+        }
+
+        ser_chan->tx_fifo_avail = ser_chan->tx_fifo_size;
 #endif
         if (chan->out_cbuf.len != 0) {
             _ier = IER_RCV;
@@ -322,6 +342,10 @@ serial_config_port(serial_channel *chan,
 #endif
     HAL_WRITE_UINT8(base+REG_ier, _ier);
 
+#ifdef CYGPRI_IO_SERIAL_GENERIC_16X5X_PLF_INIT_HOOK
+    CYGPRI_IO_SERIAL_GENERIC_16X5X_PLF_INIT_HOOK( ser_chan, new_config );
+#endif
+
     if (new_config != &chan->config) {
         chan->config = *new_config;
     }
@@ -361,10 +385,21 @@ pc_serial_init(struct cyg_devtab_entry *tab)
 #endif
     // Really only required for interrupt driven devices
     (chan->callbacks->serial_init)(chan);
-
+    //
+    // If the device supports per channel interrupt priorities then
+    // we take the priority from the serial channel data. If it does
+    // not support per channel interrupt priority we fall back to
+    // the old method and use CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY
+    // to define the priority
+    //
+#ifdef CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
+    cyg_priority_t intprio = ser_chan->int_prio;
+#else 
+    cyg_priority_t intprio = CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY;
+#endif // CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
     if (chan->out_cbuf.len != 0) {
         cyg_drv_interrupt_create(ser_chan->int_num,
-                                 CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY,
+                                 intprio,
                                  (cyg_addrword_t)chan,
                                  pc_serial_ISR,
                                  pc_serial_DSR,
@@ -395,16 +430,26 @@ pc_serial_lookup(struct cyg_devtab_entry **tab,
 static bool
 pc_serial_putc(serial_channel *chan, unsigned char c)
 {
+#ifndef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
     cyg_uint8 _lsr;
+#endif
     pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
     cyg_addrword_t base = ser_chan->base;
 
+#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
+    if (ser_chan->tx_fifo_avail > 0) {
+        HAL_WRITE_UINT8(base+REG_thr, c);
+        --ser_chan->tx_fifo_avail;
+        return true;
+    }
+#else
     HAL_READ_UINT8(base+REG_lsr, _lsr);
     if (_lsr & LSR_THE) {
         // Transmit buffer is empty
         HAL_WRITE_UINT8(base+REG_thr, c);
         return true;
     }
+#endif
     // No space
     return false;
 }
@@ -495,6 +540,9 @@ pc_serial_start_xmit(serial_channel *chan)
     HAL_READ_UINT8(base+REG_ier, _ier);
     _ier |= IER_XMT;                    // Enable xmit interrupt
     HAL_WRITE_UINT8(base+REG_ier, _ier);
+#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_XMIT_REQUIRE_PRIME
+    (chan->callbacks->xmt_char)(chan);
+#endif
 }
 
 // Disable the transmitter on the device
@@ -549,6 +597,9 @@ pc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
             break;
         }
         case ISR_Tx:
+#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
+            ser_chan->tx_fifo_avail = ser_chan->tx_fifo_size;
+#endif
             (chan->callbacks->xmt_char)(chan);
             break;