diff --git a/arch/c5471/include/serial.h b/arch/c5471/include/serial.h
index 2202a6450fb3bbaf2e74fbb50ddf193c7705460f..c10fa426913ea7021c20394f8611f4681f60c739 100644
--- a/arch/c5471/include/serial.h
+++ b/arch/c5471/include/serial.h
@@ -51,11 +51,7 @@
 #define TIOCSERGSTRUCT  0x5403  /* Get up_dev_t for port */
 
 /************************************************************
- * Private Data
- ************************************************************/
-
-/************************************************************
- * Private Functions
+ * Public Data
  ************************************************************/
 
 /************************************************************
diff --git a/arch/c5471/src/up_serial.c b/arch/c5471/src/up_serial.c
index 4b70ca4e227b2d32bec8cf6f1b9dee2c4158e359..4651b1242c672f82a50ec9dfc6e51fb14e53f57c 100644
--- a/arch/c5471/src/up_serial.c
+++ b/arch/c5471/src/up_serial.c
@@ -46,7 +46,7 @@
 #include <debug.h>
 #include <nuttx/irq.h>
 #include <nuttx/arch.h>
-#include <nuttx/fs.h>
+#include <nuttx/serial.h>
 #include <arch/serial.h>
 #include "c5471.h"
 #include "os_internal.h"
@@ -66,30 +66,19 @@
  * Private Types
  ************************************************************/
 
-/* This is the internal structure for each serial port's state. */
-
 struct uart_regs_s
 {
   uint32  ier;
   uint32  lcr;
   uint32  fcr;
+#ifdef CONFIG_UART_HWFLOWCONTROL
   uint32  efr;
   uint32  tcr;
-};
-
-struct uart_buffer_s
-{
-  sem_t  sem;    /* Used to control exclusive access to the buffer */
-  sint16 head;   /* Index to the head [IN] index in the buffer */
-  sint16 tail;   /* Index to the tail [OUT] index in the buffer */
-  sint16 size;   /* The allocated size of the buffer */
-  char  *buffer; /* Pointer to the allocated buffer memory */
+#endif
 };
 
 struct up_dev_s
 {
-  int                  open_count;	/* The number of times
-					* the device has been opened */
   unsigned int         uartbase;	/* Base address of UART
 					 * registers */
   unsigned int         baud_base;	/* Base baud for conversions */
@@ -105,54 +94,57 @@ struct up_dev_s
 #endif
   boolean              stopbits2;	/* TRUE: Configure with 2
 					 * stop bits instead of 1 */
-  boolean              xmitwaiting;	/* TRUE: User is waiting
-					 * for space in xmit.buffer */
-  boolean              recvwaiting;	/* TRUE: User is waiting
-					 * for space in recv.buffer */
-  boolean              isconsole;       /* TRUE: This is the serial console */
-  sem_t                closesem;	/* Looks out new opens while
-					 * close is in progress */
-  sem_t                xmitsem;		/* Used to wakeup user waiting
-					 * for space in xmit.buffer */
-  sem_t                recvsem;		/* Used to wakeup user waiting
-					 * for sapce in recv.buffer */
-  struct uart_buffer_s xmit;		/* Describes transmit buffer */
-  struct uart_buffer_s recv;		/* Describes receive buffer */
   struct uart_regs_s   regs;		/* Shadow copy of readonly regs */
 };
-typedef struct up_dev_s up_dev_t;
 
 /************************************************************
  * Private Function Prototypes
  ************************************************************/
 
-static int     up_open(struct file *filep);
-static int     up_close(struct file *filep);
-static ssize_t up_read(struct file *filep, char *buffer, size_t buflen);
-static ssize_t up_write(struct file *filep, const char *buffer, size_t buflen);
+static int     up_setup(struct uart_dev_s *dev);
+static void    up_shutdown(struct uart_dev_s *dev);
+static int     up_interrupt(int irq, void *context);
 static int     up_ioctl(struct file *filep, int cmd, unsigned long arg);
-static void    up_uartsetup(up_dev_t *dev);
+static int     up_receive(struct uart_dev_s *dev, unsigned int *status);
+static void    up_rxint(struct uart_dev_s *dev, boolean enable);
+static boolean up_rxfifonotempty(struct uart_dev_s *dev);
+static void    up_send(struct uart_dev_s *dev, int ch);
+static void    up_txint(struct uart_dev_s *dev, boolean enable);
+static boolean up_txfifonotfull(struct uart_dev_s *dev);
+static boolean up_txfifoempty(struct uart_dev_s *dev);
 
 /************************************************************
  * Private Variables
  ************************************************************/
 
-struct file_operations g_serialops =
-{
-  .open  = up_open,
-  .close = up_close,
-  .read  = up_read,
-  .write = up_write,
-  .ioctl = up_ioctl,
+struct uart_ops_s g_uart_ops =
+{
+  .setup          = up_setup,
+  .shutdown       = up_shutdown,
+  .handler        = up_interrupt,
+  .ioctl          = up_ioctl,
+  .receive        = up_receive,
+  .rxint          = up_rxint,
+  .rxfifonotempty = up_rxfifonotempty,
+  .send           = up_send,
+  .txint          = up_txint,
+  .txfifonotfull  = up_txfifonotfull,
+  .txfifoempty    = up_txfifoempty,
 };
 
+/* I/O buffers */
+
+static char g_irdarxbuffer[CONFIG_UART_IRDA_RXBUFSIZE];
+static char g_irdatxbuffer[CONFIG_UART_IRDA_TXBUFSIZE];
+static char g_modemrxbuffer[CONFIG_UART_IRDA_RXBUFSIZE];
+static char g_modemtxbuffer[CONFIG_UART_MODEM_TXBUFSIZE];
+
 /* This describes the state of the C5471 serial IRDA port. */
 
-static up_dev_t g_irdaport =
+static struct up_dev_s g_irdapriv =
 {
   .xmit_fifo_size = UART_IRDA_XMIT_FIFO_SIZE,
   .baud_base      = BASE_BAUD,
-  .irq            = C5471_IRQ_UART_IRDA,
   .uartbase       = UART_IRDA_BASE,
   .baud           = CONFIG_UART_IRDA_BAUD,
   .parity         = CONFIG_UART_IRDA_PARITY,
@@ -163,13 +155,29 @@ static up_dev_t g_irdaport =
   .stopbits2      = CONFIG_UART_IRDA_2STOP,
 };
 
+static uart_dev_t g_irdaport =
+{
+  .irq      = C5471_IRQ_UART_IRDA,
+  .recv     =
+  {
+    .size   = CONFIG_UART_IRDA_RXBUFSIZE,
+    .buffer = g_irdarxbuffer,
+  },
+  .xmit     =
+  {
+    .size   = CONFIG_UART_IRDA_TXBUFSIZE,
+    .buffer = g_irdatxbuffer,
+   },
+  .ops      = &g_uart_ops,
+  .priv     = &g_irdapriv,
+};
+
 /* This describes the state of the C5471 serial Modem port. */
 
-static up_dev_t g_modemport =
+static struct up_dev_s g_modempriv =
 {
   .xmit_fifo_size = UART_XMIT_FIFO_SIZE,
   .baud_base      = BASE_BAUD,
-  .irq            = C5471_IRQ_UART,
   .uartbase       = UART_MODEM_BASE,
   .baud           = CONFIG_UART_MODEM_BAUD,
   .parity         = CONFIG_UART_MODEM_PARITY,
@@ -180,128 +188,122 @@ static up_dev_t g_modemport =
   .stopbits2      = CONFIG_UART_MODEM_2STOP,
 };
 
-/* I/O buffers */
-
-static char g_irdarxbuffer[CONFIG_UART_IRDA_RXBUFSIZE];
-static char g_irdatxbuffer[CONFIG_UART_IRDA_TXBUFSIZE];
-static char g_modemrxbuffer[CONFIG_UART_IRDA_RXBUFSIZE];
-static char g_modemtxbuffer[CONFIG_UART_MODEM_TXBUFSIZE];
+static uart_dev_t g_modemport =
+{
+  .irq      = C5471_IRQ_UART,
+  .recv     =
+  {
+    .size   = CONFIG_UART_MODEM_RXBUFSIZE,
+    .buffer = g_modemrxbuffer,
+  },
+  .xmit     =
+  {
+    .size   = CONFIG_UART_MODEM_TXBUFSIZE,
+    .buffer = g_modemtxbuffer,
+  },
+  .ops      = &g_uart_ops,
+  .priv     = &g_modempriv,
+};
 
 /* Now, which one with be tty0/console and which tty1? */
 
 #ifdef CONFIG_SERIAL_IRDA_CONSOLE
 # define CONSOLE_DEV     g_irdaport
 # define TTYS0_DEV       g_irdaport
-# define TTYS0_RXBUFFER  g_irdarxbuffer
-# define TTYS0_RXBUFSIZE CONFIG_UART_IRDA_RXBUFSIZE
-# define TTYS0_TXBUFFER  g_irdatxbuffer
-# define TTYS0_TXBUFSIZE CONFIG_UART_IRDA_TXBUFSIZE
 # define TTYS1_DEV       g_modemport
-# define TTYS1_RXBUFFER  g_modemrxbuffer
-# define TTYS1_RXBUFSIZE CONFIG_UART_MODEM_RXBUFSIZE
-# define TTYS1_TXBUFFER  g_modemtxbuffer
-# define TTYS1_TXBUFSIZE CONFIG_UART_MODEM_TXBUFSIZE
 #else
 # define CONSOLE_DEV     g_modemport
 # define TTYS0_DEV       g_modemport
-# define TTYS0_RXBUFFER  g_modemrxbuffer
-# define TTYS0_RXBUFSIZE CONFIG_UART_MODEM_RXBUFSIZE
-# define TTYS0_TXBUFFER  g_modemtxbuffer
-# define TTYS0_TXBUFSIZE CONFIG_UART_MODEM_TXBUFSIZE
 # define TTYS1_DEV       g_irdaport
-# define TTYS1_RXBUFFER  g_irdarxbuffer
-# define TTYS1_RXBUFSIZE CONFIG_UART_IRDA_RXBUFSIZE
-# define TTYS1_TXBUFFER  g_irdatxbuffer
-# define TTYS1_TXBUFSIZE CONFIG_UART_IRDA_TXBUFSIZE
 #endif
 
 /************************************************************
  * Private Functions
  ************************************************************/
 
-static inline uint32 up_inserial(up_dev_t *dev, uint32 offset)
-{
-  return getreg32(dev->uartbase + offset);
-}
+/************************************************************
+ * Name: up_inserial
+ ************************************************************/
 
-static inline void up_serialout(up_dev_t *dev, uint32 offset, uint32 value)
+static inline uint32 up_inserial(struct up_dev_s *priv, uint32 offset)
 {
-  putreg32(value, dev->uartbase + offset);
+  return getreg32(priv->uartbase + offset);
 }
 
-static inline void up_serialreset(up_dev_t *dev)
-{
-  /* Both the IrDA and MODEM UARTs support RESET and UART mode. */
-
-  up_serialout(dev, UART_MDR_OFFS, MDR_RESET_MODE);
-  up_delay(5);
-  up_serialout(dev, UART_MDR_OFFS, MDR_UART_MODE);
-  up_delay(5);
-}
+/************************************************************
+ * Name: up_serialout
+ ************************************************************/
 
-static inline void up_disabletxint(up_dev_t *dev)
+static inline void up_serialout(struct up_dev_s *priv, uint32 offset, uint32 value)
 {
-  dev->regs.ier &= ~UART_IER_XmitInt;
-  up_serialout(dev, UART_IER_OFFS, dev->regs.ier);
+  putreg32(value, priv->uartbase + offset);
 }
 
-static inline void up_disablerxint(up_dev_t *dev)
-{
-  dev->regs.ier &= ~UART_IER_RecvInt;
-  up_serialout(dev, UART_IER_OFFS, dev->regs.ier);
-}
+/************************************************************
+ * Name: up_disableuartint
+ ************************************************************/
 
-static inline void up_enabletxint(up_dev_t *dev)
+static inline void up_disableuartint(struct up_dev_s *priv, uint16 *ier)
 {
-#ifndef CONFIG_SUPPRESS_SERIAL_INTS
-  dev->regs.ier |= UART_IER_XmitInt;
-  up_serialout(dev, UART_IER_OFFS, dev->regs.ier);
-#endif
+  if (ier)
+    {
+      *ier = priv->regs.ier & UART_IER_AllInts;
+    }
+  priv->regs.ier &= ~UART_IER_AllInts;
+  up_serialout(priv, UART_IER_OFFS, priv->regs.ier);
 }
 
-static inline void up_enablerxint(up_dev_t *dev)
-{
-#ifndef CONFIG_SUPPRESS_SERIAL_INTS
-  dev->regs.ier |= UART_IER_RecvInt;
-  up_serialout(dev, UART_IER_OFFS, dev->regs.ier);
-#endif
-}
+/************************************************************
+ * Name: up_restoreuartint
+ ************************************************************/
 
-static inline void up_disableuartint(up_dev_t *dev, uint16 *ier)
+static inline void up_restoreuartint(struct up_dev_s *priv, uint16 ier)
 {
-  *ier = dev->regs.ier & UART_IER_AllInts;
-  dev->regs.ier &= ~UART_IER_AllInts;
-  up_serialout(dev, UART_IER_OFFS, dev->regs.ier);
+  priv->regs.ier |= ier & (UART_IER_RecvInt|UART_IER_XmitInt);
+  up_serialout(priv, UART_IER_OFFS, priv->regs.ier);
 }
 
-static inline void up_restoreuartint(up_dev_t *dev, uint16 ier)
-{
-  dev->regs.ier |= ier & (UART_IER_RecvInt|UART_IER_XmitInt);
-  up_serialout(dev, UART_IER_OFFS, dev->regs.ier);
-}
+/************************************************************
+ * Name: up_waittxfifonotfull
+ ************************************************************/
 
-static inline void up_clearfifos(up_dev_t *dev)
+static inline void up_waittxfifonotfull(struct up_dev_s *priv)
 {
-  up_serialout(dev, UART_EFR_OFFS,  0x0010);           /* Enable fifo control */
-  up_serialout(dev, UART_TFCR_OFFS, 0);                /* Reset to 0 */
-  up_serialout(dev, UART_RFCR_OFFS, UART_FCR_RX_CLR);  /* Clear RX fifo */
-  up_serialout(dev, UART_TFCR_OFFS, UART_FCR_TX_CLR);  /* Clear TX fifo */
-  up_serialout(dev, UART_TFCR_OFFS, UART_FCR_FIFO_EN); /* Enable RX/TX fifos */
+  int tmp;
+
+  for (tmp = 1000 ; tmp > 0 ; tmp--)
+    {
+      if ((up_inserial(priv, UART_SSR_OFFS) & UART_SSR_TXFULL) == 0)
+        {
+          break;
+        }
+    }
 }
+/************************************************************
+ * Name: up_disablebreaks
+ ************************************************************/
 
-static inline void up_disablebreaks(up_dev_t *dev)
+static inline void up_disablebreaks(struct up_dev_s *priv)
 {
-  dev->regs.lcr &= ~UART_LCR_BOC;
-  up_serialout(dev, UART_LCR_OFFS, dev->regs.lcr);
+  priv->regs.lcr &= ~UART_LCR_BOC;
+  up_serialout(priv, UART_LCR_OFFS, priv->regs.lcr);
 }
 
-static inline void up_enablebreaks(up_dev_t *dev)
+/************************************************************
+ * Name: up_enablebreaks
+ ************************************************************/
+
+static inline void up_enablebreaks(struct up_dev_s *priv)
 {
-  dev->regs.lcr |= UART_LCR_BOC;
-  up_serialout(dev, UART_LCR_OFFS, dev->regs.lcr);
+  priv->regs.lcr |= UART_LCR_BOC;
+  up_serialout(priv, UART_LCR_OFFS, priv->regs.lcr);
 }
 
-static inline void up_setrate(up_dev_t *dev, unsigned int rate)
+/************************************************************
+ * Name: up_setrate
+ ************************************************************/
+
+static inline void up_setrate(struct up_dev_s *priv, unsigned int rate)
 {
   uint32 div_bit_rate;
 
@@ -334,328 +336,146 @@ static inline void up_setrate(up_dev_t *dev, unsigned int rate)
       break;
     }
 
-  up_serialout(dev, UART_DIV_BIT_RATE_OFFS, div_bit_rate);
-}
-
-static inline void up_setmode(up_dev_t *dev, uint16 mode)
-{
-  dev->regs.lcr &= 0xffffffe0;          /* clear original field, and... */
-  dev->regs.lcr |= (uint32)mode; /* Set new bits in that field. */
-  up_serialout(dev, UART_LCR_OFFS, dev->regs.lcr);
-}
-
-static inline void up_setrxtrigger(up_dev_t *dev, uint16 val)
-{
-  /* does val need to be shifted to the right spot? */
-  dev->regs.fcr = (dev->regs.fcr & 0xffffff3f) | (val & 0xc0);
-  up_serialout(dev, UART_RFCR_OFFS, dev->regs.fcr);
-}
-
-static inline void up_settxtrigger(up_dev_t *dev, uint16 val)
-{
-  /* does val need to be shifted to the right spot? */
-  dev->regs.fcr = (dev->regs.fcr & 0xffffffcf) | (val & 0x30);
-  up_serialout(dev, UART_RFCR_OFFS, dev->regs.fcr);
-}
-
-static inline void up_outserialchar(up_dev_t *dev, ubyte val)
-{
-  up_serialout(dev, UART_THR_OFFS, val);
+  up_serialout(priv, UART_DIV_BIT_RATE_OFFS, div_bit_rate);
 }
 
-static inline unsigned char up_inserialchar(up_dev_t *dev,
-                                           uint16 *status)
-{
-  uint32 rhr;
-  uint32 lsr;
-
-  /* Next, construct a 16bit status word that
-   * uses the high byte to hold the status bits
-   * associated with framing,parity,break and
-   * a low byte that holds error bits of LSR for
-   * conditions such as overflow, etc.
-   */
-
-  rhr = up_inserial(dev, UART_RHR_OFFS);
-  lsr = up_inserial(dev, UART_LSR_OFFS);
-
-  *status = (uint16)((rhr & 0x0000ff00) | (lsr & 0x000000ff));
-
-  return rhr & 0x000000ff;
-}
-
-static inline int up_errorcondition(uint16 status)
-{
-  return status & 0x0782;
-}
-
-static inline int up_parityerror(uint16 status)
-{
-  return status & 0x0100;
-}
-
-static inline int up_framingerror(uint16 status)
-{
-  return status & 0x0200;
-}
-
-static inline int up_overrunerror(uint16 status)
-{
-  return status & 0x0002;
-}
-
-static inline uint32 up_getintcause(up_dev_t *dev)
-{
-  return up_inserial(dev, UART_ISR_OFFS) & 0x0000003f;
-}
-
-static inline int up_xmitint(up_dev_t *dev,
-                                                uint32 cause)
-{
-  return (cause & 0x00000002) == 0x00000002;
-}
-
-static inline int up_recvint(up_dev_t *dev, uint32 cause)
-{
-  return (cause & 0x0000000c) == 0x00000004;
-}
-
-static inline int up_recvtimeoutint(up_dev_t *dev, uint32 cause)
-{
-  return (cause & 0x0000000c) == 0x0000000c;
-}
-
-static inline ubyte up_txfifoempty(up_dev_t *dev)
-{
-  return (up_inserial(dev, UART_LSR_OFFS) & UART_LSR_TREF) != 0;
-}
+/************************************************************
+ * Name: up_setup
+ *
+ * Description:
+ *   Configure the UART baud, bits, parity, fifos, etc. This
+ *   method is called the first time that the serial port is
+ *   opened.
+ *
+ ************************************************************/
 
-static inline ubyte up_txfifonotfull(up_dev_t *dev)
+static int up_setup(struct uart_dev_s *dev)
 {
-  return (up_inserial(dev, UART_SSR_OFFS) & UART_SSR_TXFULL) == 0;
-}
+#ifdef CONFIG_SUPPRESS_UART_CONFIG
+  struct up_dev_s *priv = dev->priv;
+  unsigned int cval;
 
-static inline void up_waittxfifonotfull(up_dev_t *dev)
-{
-  int tmp;
-  for (tmp = 1000 ; tmp > 0 ; tmp--)
+  if (priv->bits == 7)
     {
-      if (up_txfifonotfull(dev))
-        {
-          break;
-        }
+      cval = UART_LCR_7bits;
+    }
+  else
+    {
+      cval = UART_LCR_8bits;
     }
-}
-
-static inline ubyte up_rxfifonotempty(up_dev_t *dev)
-{
-  return up_inserial(dev, UART_LSR_OFFS) & UART_RX_FIFO_NOEMPTY;
-}
-
-static inline void serial_enable_hw_flow_control(up_dev_t *dev)
-{
-  /* Set the FIFO level triggers for flow control
-   * Halt = 48 bytes, resume = 12 bytes
-   */
-
-  dev->regs.tcr = (dev->regs.tcr & 0xffffff00) | 0x0000003c;
-  up_serialout(dev, UART_TCR_OFFS, dev->regs.tcr);
 
-  /* Enable RTS/CTS flow control */
+  if (priv->stopbits2)
+    {
+      cval |= UART_LCR_2stop;
+    }
 
-  dev->regs.efr |= 0x000000c0;
-  up_serialout(dev, UART_EFR_OFFS, dev->regs.efr);
-}
+  if (priv->parity == 1)   /* Odd parity */
+    {
+      cval |= (UART_LCR_ParEn|UART_LCR_ParOdd);
+    }
+  else if (priv->parity == 2)  /* Even parity */
+    {
+      cval |= (UART_LCR_ParEn|UART_LCR_ParEven);
+    }
 
-static inline void serial_disable_hw_flow_control(up_dev_t *dev)
-{
-  /* Disable RTS/CTS flow control */
+  /* Both the IrDA and MODEM UARTs support RESET and UART mode. */
 
-  dev->regs.efr &= 0xffffff3f;
-  up_serialout(dev, UART_EFR_OFFS, dev->regs.efr);
-}
+  up_serialout(priv, UART_MDR_OFFS, MDR_RESET_MODE);
+  up_delay(5);
+  up_serialout(priv, UART_MDR_OFFS, MDR_UART_MODE);
+  up_delay(5);
 
-static inline void up_saveregisters(up_dev_t *dev)
-{
-  dev->regs.ier = up_inserial(dev, UART_IER_OFFS);
-  dev->regs.lcr = up_inserial(dev, UART_LCR_OFFS);
+  priv->regs.ier = up_inserial(priv, UART_IER_OFFS);
+  priv->regs.lcr = up_inserial(priv, UART_LCR_OFFS);
 #ifdef CONFIG_UART_HWFLOWCONTROL
-  if (dev->flowcontrol)
+  if (priv->flowcontrol)
     {
-      dev->regs.efr = up_inserial(dev, UART_EFR_OFFS);
-      dev->regs.tcr = up_inserial(dev, UART_TCR_OFFS);
+      priv->regs.efr = up_inserial(priv, UART_EFR_OFFS);
+      priv->regs.tcr = up_inserial(priv, UART_TCR_OFFS);
     }
 #endif
-}
 
-/************************************************************
- * up_takesem
- ************************************************************/
+  up_disableuartint(priv, NULL);
 
-static void up_takesem(sem_t *sem)
-{
-  while (sem_wait(sem) != 0)
-    {
-      /* The only case that an error should occur here is if
-       * the wait was awakened by a signal.
-       */
+  up_serialout(priv, UART_EFR_OFFS,  0x0010);           /* Enable fifo control */
+  up_serialout(priv, UART_TFCR_OFFS, 0);                /* Reset to 0 */
+  up_serialout(priv, UART_RFCR_OFFS, UART_FCR_RX_CLR);  /* Clear RX fifo */
+  up_serialout(priv, UART_TFCR_OFFS, UART_FCR_TX_CLR);  /* Clear TX fifo */
+  up_serialout(priv, UART_TFCR_OFFS, UART_FCR_FIFO_EN); /* Enable RX/TX fifos */
 
-      ASSERT(*get_errno_ptr() == EINTR);
-    }
-}
+  up_disablebreaks(priv);
 
-/************************************************************
- * Name: up_givesem
- ************************************************************/
+  priv->regs.fcr = (priv->regs.fcr & 0xffffffcf) | (val & 0x30);
+  up_serialout(priv, UART_RFCR_OFFS, priv->regs.fcr);
 
-static inline void up_givesem(sem_t *sem)
-{
-  (void)sem_post(sem);
-}
+  priv->regs.fcr = (priv->regs.fcr & 0xffffff3f) | (val & 0xc0);
+  up_serialout(priv, UART_RFCR_OFFS, priv->regs.fcr);
 
-/************************************************************
- * Name: up_receivechars
- ************************************************************/
+  up_setrate(priv, priv->baud);
 
-/* Add chars to head of receive buffer.  up_read will take
- * characters from the tail of the buffer.
- */
-
-static void up_recvchars(up_dev_t *dev)
-{
-  uint16 status;
-  int nexthead = dev->recv.head + 1;
+  priv->regs.lcr &= 0xffffffe0;      /* clear original field, and... */
+  priv->regs.lcr |= (uint32)mode;    /* Set new bits in that field. */
+  up_serialout(priv, UART_LCR_OFFS, priv->regs.lcr);
 
-  if (nexthead >= dev->recv.size)
+#ifdef CONFIG_UART_HWFLOWCONTROL
+  if (priv->flowcontrol)
     {
-      nexthead = 0;
-    }
+      /* Set the FIFO level triggers for flow control
+       * Halt = 48 bytes, resume = 12 bytes
+       */
 
-  while (nexthead != dev->recv.tail && up_rxfifonotempty(dev))
-    {
-      dev->recv.buffer[dev->recv.head] = up_inserialchar(dev, &status);
+      priv->regs.tcr = (priv->regs.tcr & 0xffffff00) | 0x0000003c;
+      up_serialout(priv, UART_TCR_OFFS, priv->regs.tcr);
 
-      dev->recv.head = nexthead;
-      if (++nexthead >= dev->recv.size)
-        {
-           nexthead = 0;
-        }
+      /* Enable RTS/CTS flow control */
 
-      if (dev->recvwaiting)
-        {
-          dev->recvwaiting = FALSE;
-          up_givesem(&dev->recvsem);
-        }
+      priv->regs.efr |= 0x000000c0;
+      up_serialout(priv, UART_EFR_OFFS, priv->regs.efr);
     }
-}
-
-/************************************************************
- * up_xmitchars
- ************************************************************/
-
-/* Transmit characters from the tail of the xmit buffer while
- * up_write adds data to the head of the xmit buffer.
- */
-
-static void up_xmitchars(up_dev_t *dev)
-{
-  /* Send while we still have data & room in the fifo */
-
-  while (dev->xmit.head != dev->xmit.tail && up_txfifonotfull(dev))
+  else
     {
-      up_outserialchar(dev, dev->xmit.buffer[dev->xmit.tail]);
-
-      if (++(dev->xmit.tail) >= dev->xmit.size)
-        {
-          dev->xmit.tail = 0;
-        }
-
-      if (dev->xmitwaiting)
-        {
-          dev->xmitwaiting = FALSE;
-          up_givesem(&dev->xmitsem);
-        }
-    }
-
-  /* When all of the characters have been sent from the buffer
-   * disable the TX interrupt.
-   */
+      /* Disable RTS/CTS flow control */
 
-  if (dev->xmit.head == dev->xmit.tail)
-    {
-      up_disabletxint(dev);
+      priv->regs.efr &= 0xffffff3f;
+      up_serialout(priv, UART_EFR_OFFS, priv->regs.efr);
     }
+#endif
+#endif
+  return OK;
 }
 
 /************************************************************
- * Name: up_putxmitchar
+ * Name: up_shutdown
+ *
+ * Description:
+ *   Disable the UART.  This method is called when the serial port is closed
+ *
  ************************************************************/
 
-static void up_putxmitchar(up_dev_t *dev, int ch)
+static void up_shutdown(struct uart_dev_s *dev)
 {
-  int nexthead = dev->xmit.head + 1;
-  if (nexthead >= dev->xmit.size)
-    {
-      nexthead = 0;
-    }
-
-  for(;;)
-    {
-      if (nexthead != dev->xmit.tail)
-        {
-          dev->xmit.buffer[dev->xmit.head] = ch;
-          dev->xmit.head = nexthead;
-          return;
-        }
-      else
-        {
-#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_SERIAL_INTS)
-          /* Transfer some characters with interrupts disabled */
-
-          up_xmitchars(dev);
-
-          /* If we unsuccessful in making room in the buffer.
-           * then transmit the characters with interrupts
-           * enabled and wait for result.
-           */
-
-          if (nexthead == dev->xmit.tail)
-            {
-              /* Still no space */
-
-              up_waittxfifonotfull(dev);
-            }
-#else
-          /* Inform the interrupt level logic that we are waiting */
-
-          dev->xmitwaiting = TRUE;
-
-          /* Wait for some characters to be sent from the buffer
-           * with the TX interrupt enabled.  When the TX interrupt
-           * is enabled, up_xmitchars should execute and remove
-           * some of the data from the TX buffer.
-           */
-
-          up_enabletxint(dev);
-          up_takesem(&dev->xmitsem);
-          up_disabletxint(dev);
-#endif
-        }
-    }
+  struct up_dev_s *priv = (struct up_dev_s*)CONSOLE_DEV.priv;
+  up_disableuartint(priv, NULL);
 }
 
 /************************************************************
  * Name: up_interrupt
+ *
+ * Description:
+ *   This is the UART interrupt handler.  It will be invoked
+ *   when an interrupt received on the 'irq'  It should call
+ *   uart_transmitchars or uart_receivechar to perform the
+ *   appropriate data transfers.  The interrupt handling logic\
+ *   must be able to map the 'irq' number into the approprite
+ *   uart_dev_s structure in order to call these functions.
+ *
  ************************************************************/
 
-/* This routine is used to handle the "top half" processing for the
- * serial driver.
- */
-
 static int up_interrupt(int irq, void *context)
 {
-  up_dev_t         *dev;
-  volatile uint32 cause;
+  struct uart_dev_s *dev = NULL;
+  struct up_dev_s   *priv;
+  volatile uint32    cause;
 
   if (g_irdaport.irq == irq)
     {
@@ -669,10 +489,11 @@ static int up_interrupt(int irq, void *context)
     {
       PANIC(OSERR_INTERNAL);
     }
+  priv = (struct up_dev_s*)dev->priv;
 
-  cause = up_getintcause(dev);
+  cause = up_inserial(priv, UART_ISR_OFFS) & 0x0000003f;
 
-  if (up_recvtimeoutint(dev, cause))
+  if ((cause & 0x0000000c) == 0x0000000c)
     {
       uint32 ier_val = 0;
 
@@ -685,19 +506,19 @@ static int up_interrupt(int irq, void *context)
             * below.
             */
 
-           ier_val = up_inserial(dev, UART_IER_OFFS);
+           ier_val = up_inserial(priv, UART_IER_OFFS);
 
            /* Then disable all IrDA UART interrupts */
 
-           up_serialout(dev, UART_IER_OFFS, 0);
+           up_serialout(priv, UART_IER_OFFS, 0);
          }
 
       /* Receive characters from the RX fifo */
 
-      up_recvchars(dev);
+      uart_recvchars(dev);
 
       /* read UART_RHR to clear int condition
-       * toss = up_inserialchar(dev,&status);
+       * toss = up_inserialchar(priv,&status);
        */
 
       /* Is this an interrupt from the IrDA UART? */
@@ -706,261 +527,42 @@ static int up_interrupt(int irq, void *context)
          {
            /* Restore the IrDA UART interrupt enables */
 
-           up_serialout(dev, UART_IER_OFFS, ier_val);
+           up_serialout(priv, UART_IER_OFFS, ier_val);
          }
     }
-  else if (up_recvint(dev, cause))
+  else if ((cause & 0x0000000c) == 0x00000004)
     {
-      up_recvchars(dev);
+      uart_recvchars(dev);
     }
 
-  if (up_xmitint(dev, cause))
+  if ((cause & 0x00000002) != 0)
     {
-      up_xmitchars(dev);
+      uart_xmitchars(dev);
     }
 
   return OK;
 }
 
-/************************************************************
- * Name: up_uartsetup
- ************************************************************/
-
-static void up_uartsetup(up_dev_t *dev)
-{
-#ifdef CONFIG_SUPPRESS_UART_CONFIG
-  unsigned int cval;
-  uint16  mrs;
-
-  if (dev->bits == 7)
-    {
-      cval = UART_LCR_7bits;
-    }
-  else
-    {
-      cval = UART_LCR_8bits;
-    }
-
-  if (dev->stopbits2)
-    {
-      cval |= UART_LCR_2stop;
-    }
-
-  if (dev->parity == 1)   /* Odd parity */
-    {
-      cval |= (UART_LCR_ParEn|UART_LCR_ParOdd);
-    }
-  else if (dev->parity == 2)  /* Even parity */
-    {
-      cval |= (UART_LCR_ParEn|UART_LCR_ParEven);
-    }
-
-  up_serialreset(dev);
-  up_saveregisters(dev);
-  up_disableuartint(dev, &mrs);
-  up_clearfifos(dev);
-  up_disablebreaks(dev);
-  up_settxtrigger(dev, UART_FCR_FTL);
-  up_setrxtrigger(dev, UART_FCR_FTL);
-  up_setrate(dev, dev->baud);
-  up_setmode(dev, cval);
-
-#ifdef CONFIG_UART_HWFLOWCONTROL
-  if (dev->flowcontrol)
-    {
-      serial_enable_hw_flow_control(dev);
-    }
-  else
-#endif
-    {
-      serial_disable_hw_flow_control(dev);
-    }
-#endif
-}
-
-/************************************************************
- * shutdown
- ************************************************************/
-
-/* This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-
-static void shutdown(up_dev_t * dev)
-{
-  irqstate_t flags;
-  uint16 msr;
-
-  /* Free the IRQ */
-
-  flags = irqsave(); /* Disable interrupts */
-  up_disable_irq(dev->irq);
-  irq_detach(dev->irq);
-  up_disableuartint(dev, &msr);
-  irqrestore(flags);
-}
-
-/************************************************************
- * Name: up_irqwrite
- ************************************************************/
-
-static ssize_t up_irqwrite(up_dev_t *dev, const char *buffer, size_t buflen)
-{
-  ssize_t ret = buflen;
-
-  /* Force each character through the low level interface */
-
-  for (; buflen; buflen--)
-    {
-      int ch = *buffer++;
-      up_lowputc(ch);
-
-     /* If this is the console, then we should replace LF with LF-CR */
-
-      if (ch == '\n')
-        {
-          up_lowputc('\r');
-        }
-    }
-
-  return ret;
-}
-
-/************************************************************
- * Name: up_write
- ************************************************************/
-
-static ssize_t up_write(struct file *filep, const char *buffer, size_t buflen)
-{
-  struct inode *inode    = filep->f_inode;
-  up_dev_t     *dev      = inode->i_private;
-  ssize_t       ret      = buflen;
-
-  /* We may receive console writes through this path from
-   * interrupt handlers and from debug output in the IDLE task!
-   * In these cases, we will need to do things a little
-   * differently.
-   */
-
-  if (up_interrupt_context() || getpid() == 0)
-    {
-      if (dev->isconsole)
-        {
-          irqstate_t flags = irqsave();
-          ret = up_irqwrite(dev, buffer, buflen);
-          irqrestore(flags);
-          return ret;
-        }
-      else
-        {
-          return ERROR;
-        }
-    }
-
-  /* Only one user can be accessing dev->xmit.head at once */
-
-  up_takesem(&dev->xmit.sem);
-
-  /* Loop while we still have data to copy to the transmit buffer.
-   * we add data to the head of the buffer; up_xmitchars takes the
-   * data from the end of the buffer.
-   */
-
-  up_disabletxint(dev);
-  for (; buflen; buflen--)
-    {
-      int ch = *buffer++;
-
-      /* Put the character into the transmit buffer */
-
-      up_putxmitchar(dev, ch);
-
-     /* If this is the console, then we should replace LF with LF-CR */
-
-      if (dev->isconsole && ch == '\n')
-        {
-          up_putxmitchar(dev, '\r');
-        }
-    }
-
-  if (dev->xmit.head != dev->xmit.tail)
-    {
-#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_SERIAL_INTS)
-      up_xmitchars(dev);
-#else
-      up_enabletxint(dev);
-#endif
-    }
-
-  up_givesem(&dev->xmit.sem);
-  return ret;
-}
-
-/************************************************************
- * Name: up_read
- ************************************************************/
-
-static ssize_t up_read(struct file *filep, char *buffer, size_t buflen)
-{
-  struct inode *inode = filep->f_inode;
-  up_dev_t     *dev   = inode->i_private;
-  ssize_t       ret   = buflen;
-
-  /* Only one user can be accessing dev->recv.tail at once */
-
-  up_takesem(&dev->recv.sem);
-
-  /* Loop while we still have data to copy to the receive buffer.
-   * we add data to the head of the buffer; up_xmitchars takes the
-   * data from the end of the buffer.
-   */
-
-  up_disablerxint(dev);
-  while (buflen)
-    {
-      if (dev->recv.head != dev->recv.tail)
-        {
-          *buffer++ = dev->recv.buffer[dev->recv.tail];
-          buflen--;
-
-          if (++(dev->recv.tail) >= dev->recv.size)
-            {
-              dev->recv.tail = 0;
-            }
-        }
-      else
-        {
-          /* Wait for some characters to be sent from the buffer
-           * with the TX interrupt disabled.
-           */
-
-          dev->recvwaiting = TRUE;
-          up_enablerxint(dev);
-          up_takesem(&dev->recvsem);
-          up_disablerxint(dev);
-        }
-    }
-
-  up_enablerxint(dev);
-  up_givesem(&dev->recv.sem);
-  return ret;
-}
-
 /************************************************************
  * Name: up_ioctl
+ *
+ * Description:
+ *   All ioctl calls will be routed through this method
+ *
  ************************************************************/
 
 static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
 {
-  struct inode *inode = filep->f_inode;
-  up_dev_t     *dev   = inode->i_private;
-  int           ret   = OK;
+  struct inode      *inode = filep->f_inode;
+  struct uart_dev_s *dev   = inode->i_private;
+  struct up_dev_s   *priv  = (struct up_dev_s*)dev->priv;
+  int                ret    = OK;
 
   switch (cmd)
     {
     case TIOCSERGSTRUCT:
       {
-         up_dev_t *user = (up_dev_t*)arg;
+         struct up_dev_s *user = (struct up_dev_s*)arg;
          if (!user)
            {
              *get_errno_ptr() = EINVAL;
@@ -968,7 +570,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
            }
          else
            {
-             memcpy(user, dev, sizeof(up_dev_t));
+             memcpy(user, dev, sizeof(struct up_dev_s));
            }
        }
        break;
@@ -976,7 +578,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
     case TIOCSBRK:  /* BSD compatibility: Turn break on, unconditionally */
       {
         irqstate_t flags = irqsave();
-        up_enablebreaks(dev);
+        up_enablebreaks(priv);
         irqrestore(flags);
       }
       break;
@@ -985,7 +587,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
       {
         irqstate_t flags;
         flags = irqsave();
-        up_disablebreaks(dev);
+        up_disablebreaks(priv);
         irqrestore(flags);
       }
       break;
@@ -1000,146 +602,139 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
 }
 
 /************************************************************
- * Name: up_close
+ * Name: up_receive
  *
  * Description:
- *   This routine is called when the serial port gets closed.
- *   It waits for the last remaining data to be sent.
+ * Called (usually) from the interrupt level to receive one character from
+ * the UART.  Error bits associated with the receipt are provided in the
+ * the return 'status'.
  *
  ************************************************************/
 
-static int up_close(struct file *filep)
+static int up_receive(struct uart_dev_s *dev, unsigned int *status)
 {
-  struct inode *inode = filep->f_inode;
-  up_dev_t     *dev   = inode->i_private;
-
-  up_takesem(&dev->closesem);
-  if (dev->open_count > 1)
-    {
-      dev->open_count--;
-      up_givesem(&dev->closesem);
-      return OK;
-    }
+  struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+  uint32 rhr;
+  uint32 lsr;
 
-  /* There are no more references to the port */
+  /* Construct a 16bit status word that uses the high byte to
+   * hold the status bits associated with framing,parity,break
+   * and a low byte that holds error bits of LSR for
+   * conditions such as overflow, etc.
+   */
 
-  dev->open_count = 0;
+  rhr = up_inserial(priv, UART_RHR_OFFS);
+  lsr = up_inserial(priv, UART_LSR_OFFS);
 
-  /* Stop accepting input */
+  *status = (unsigned int)((rhr & 0x0000ff00) | (lsr & 0x000000ff));
 
-  up_disablerxint(dev);
+  return rhr & 0x000000ff;
+}
 
-  /* Now we wait for the transmit buffer to clear */
+/************************************************************
+ * Name: up_rxint
+ *
+ * Description:
+ *   Call to enable or disable RX interrupts
+ *
+ ************************************************************/
 
-  while (dev->xmit.head != dev->xmit.tail)
+static void up_rxint(struct uart_dev_s *dev, boolean enable)
+{
+  struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+  if (enable)
     {
-      usleep(500*1000);
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+      priv->regs.ier |= UART_IER_RecvInt;
+      up_serialout(priv, UART_IER_OFFS, priv->regs.ier);
+#endif
     }
-
-  /* And wait for the TX fifo to drain */
-
-  while (!up_txfifoempty(dev))
+  else
     {
-      usleep(500*1000);
+      priv->regs.ier &= ~UART_IER_RecvInt;
+      up_serialout(priv, UART_IER_OFFS, priv->regs.ier);
     }
-
-  /* That's it! */
-
-  shutdown(dev);
-  up_givesem(&dev->closesem);
-  return OK;
- }
+}
 
 /************************************************************
- * Name: up_open
+ * Name: up_rxfifonotempty
  *
  * Description:
- *   This routine is called whenever a serial port is opened.
+ *   Return TRUE if the receive fifo is not empty
  *
  ************************************************************/
 
-static int up_open(struct file *filep)
+static boolean up_rxfifonotempty(struct uart_dev_s *dev)
 {
-  struct inode *inode = filep->f_inode;
-  up_dev_t     *dev   = inode->i_private;
-  int           ret   = OK;
+  struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+  return up_inserial(priv, UART_LSR_OFFS) & UART_RX_FIFO_NOEMPTY;
+}
 
-  /* If the port is the middle of closing, wait until the close
-   * is finished
-   */
+/************************************************************
+ * Name: up_send
+ *
+ * Description:
+ *   This method will send one byte on the UART
+ *
+ ************************************************************/
 
-  up_takesem(&dev->closesem);
+static void up_send(struct uart_dev_s *dev, int ch)
+{
+  struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+  up_serialout(priv, UART_THR_OFFS, (ubyte)ch);
+}
 
-  /* Start up serial port */
+/************************************************************
+ * Name: up_txint
+ *
+ * Description:
+ *   Call to enable or disable TX interrupts
+ *
+ ************************************************************/
 
-  if (++dev->open_count == 1)
+static void up_txint(struct uart_dev_s *dev, boolean enable)
+{
+  struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+  if (enable)
     {
-      irqstate_t flags = irqsave();
-
-      /* If this is the console, then the UART has already
-       * been initialized.
-       */
-
-      if (!dev->isconsole)
-        {
-          up_uartsetup(dev);
-        }
-
-      /* But, in any event, we do have to configure for
-       * interrupt driven mode of operation.
-       */
-
-      /* Attache and enabled the IRQ */
-
 #ifndef CONFIG_SUPPRESS_SERIAL_INTS
-      ret = irq_attach(dev->irq, up_interrupt);
-      if (ret == OK)
+      priv->regs.ier |= UART_IER_XmitInt;
+      up_serialout(priv, UART_IER_OFFS, priv->regs.ier);
 #endif
-        {
-          /* Mark the io buffers empty */
-
-          dev->xmit.head = 0;
-          dev->xmit.tail = 0;
-          dev->recv.head = 0;
-          dev->recv.tail = 0;
-
-          /* Finally, enable interrupts */
-
-#ifndef CONFIG_SUPPRESS_SERIAL_INTS
-          up_enable_irq(dev->irq);
-#endif
-          up_enablerxint(dev);
-        }
-      irqrestore(flags);
     }
-
-  up_givesem(&dev->closesem);
-  return ret;
+  else
+    {
+      priv->regs.ier &= ~UART_IER_XmitInt;
+      up_serialout(priv, UART_IER_OFFS, priv->regs.ier);
+    }
 }
 
 /************************************************************
- * Name: up_devinit
+ * Name: up_txfifonotfull
+ *
+ * Description:
+ *   Return TRUE if the tranmsit fifo is not full
+ *
  ************************************************************/
 
-static void up_devinit(up_dev_t *dev,
-                       char *rxbuffer, int rxbufsize,
-                       char *txbuffer, int txbufsize)
+static boolean up_txfifonotfull(struct uart_dev_s *dev)
 {
-  /* Initialize fields in the dev structure that were not
-   * statically initialized.
-   */
-
-  sem_init(&dev->xmit.sem, 0, 1);
-  dev->xmit.size   = txbufsize;
-  dev->xmit.buffer = txbuffer;
+  struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+  return (up_inserial(priv, UART_SSR_OFFS) & UART_SSR_TXFULL) == 0;
+}
 
-  sem_init(&dev->recv.sem, 0, 1);
-  dev->recv.size   = rxbufsize;
-  dev->recv.buffer = rxbuffer;
+/************************************************************
+ * Name: up_txfifoempty
+ *
+ * Description:
+ *   Return TRUE if the transmit fifo is empty
+ *
+ ************************************************************/
 
-  sem_init(&dev->closesem, 0, 1);
-  sem_init(&dev->xmitsem, 0, 0);
-  sem_init(&dev->recvsem, 0, 0);
+static boolean up_txfifoempty(struct uart_dev_s *dev)
+{
+  struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+  return (up_inserial(priv, UART_LSR_OFFS) & UART_LSR_TREF) != 0;
 }
 
 /************************************************************
@@ -1158,19 +753,11 @@ static void up_devinit(up_dev_t *dev,
 
 void up_earlyserialinit(void)
 {
-  /* Set up default port setings */
-
-  up_devinit(&TTYS0_DEV,
-             TTYS0_RXBUFFER, TTYS0_RXBUFSIZE,
-             TTYS0_TXBUFFER, TTYS0_TXBUFSIZE);
-  up_devinit(&TTYS1_DEV,
-             TTYS1_RXBUFFER, TTYS1_RXBUFSIZE,
-             TTYS1_TXBUFFER, TTYS1_TXBUFSIZE);
-
-  /* Configure the console for use now */
+  up_disableuartint(TTYS0_DEV.priv, NULL);
+  up_disableuartint(TTYS1_DEV.priv, NULL);
 
   CONSOLE_DEV.isconsole = TRUE;
-  up_uartsetup(&CONSOLE_DEV);
+  up_setup(&CONSOLE_DEV);
 }
 
 /************************************************************
@@ -1184,9 +771,9 @@ void up_earlyserialinit(void)
 
 void up_serialinit(void)
 {
-  (void)register_inode("/dev/console", &g_serialops, 0666, &CONSOLE_DEV);
-  (void)register_inode("/dev/ttyS0", &g_serialops, 0666, &TTYS0_DEV);
-  (void)register_inode("/dev/ttyS1", &g_serialops, 0666, &TTYS1_DEV);
+  (void)uart_register("/dev/console", &CONSOLE_DEV);
+  (void)uart_register("/dev/ttyS0", &TTYS0_DEV);
+  (void)uart_register("/dev/ttyS1", &TTYS1_DEV);
 }
 
 /************************************************************
@@ -1200,11 +787,12 @@ void up_serialinit(void)
 
 int up_putc(int ch)
 {
+  struct up_dev_s *priv = (struct up_dev_s*)CONSOLE_DEV.priv;
   uint16  ier;
 
-  up_disableuartint(&CONSOLE_DEV, &ier);
-  up_waittxfifonotfull(&CONSOLE_DEV);
-  up_outserialchar(&CONSOLE_DEV, ch);
+  up_disableuartint(priv, &ier);
+  up_waittxfifonotfull(priv);
+  up_serialout(priv, UART_THR_OFFS, (ubyte)ch);
 
   /* Check for LF */
 
@@ -1212,12 +800,12 @@ int up_putc(int ch)
     {
       /* Add CR */
 
-      up_waittxfifonotfull(&CONSOLE_DEV);
-      up_outserialchar(&CONSOLE_DEV, '\r');
+      up_waittxfifonotfull(priv);
+      up_serialout(priv, UART_THR_OFFS, '\r');
     }
 
-  up_waittxfifonotfull(&CONSOLE_DEV);
-  up_restoreuartint(&CONSOLE_DEV, ier);
+  up_waittxfifonotfull(priv);
+  up_restoreuartint(priv, ier);
   return ch;
 }
 
diff --git a/drivers/Makefile b/drivers/Makefile
index 8d687a67c3364d70482bb1f7ba848029b63261b0..f992f583740b58802a8438da161bb221308b5fe1 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -40,7 +40,7 @@ MKDEP	= $(TOPDIR)/tools/mkdeps.sh
 ASRCS		= 
 AOBJS		= $(ASRCS:.S=$(OBJEXT))
 
-CSRCS		= dev_null.c
+CSRCS		= dev_null.c serial.c
 COBJS		= $(CSRCS:.c=$(OBJEXT))
 
 SRCS		= $(ASRCS) $(CSRCS)
diff --git a/drivers/serial.c b/drivers/serial.c
new file mode 100644
index 0000000000000000000000000000000000000000..fd0e5b1b7ddbb1fbe332791cb8efb92567092756
--- /dev/null
+++ b/drivers/serial.c
@@ -0,0 +1,578 @@
+/************************************************************************************
+ * serial.c
+ *
+ *   Copyright (C) 2007 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name Gregory Nutt nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/fs.h>
+#include <nuttx/serial.h>
+
+/************************************************************************************
+ * Definitions
+ ************************************************************************************/
+
+#ifdef CONFIG_HAVE_LOWPUTC
+# define uart_putc(ch) up_lowputc(ch);
+#else
+# define uart_putc(ch) up_putc(ch);
+#endif
+
+/************************************************************************************
+ * Private Types
+ ************************************************************************************/
+
+/************************************************************************************
+ * Private Function Prototypes
+ ************************************************************************************/
+
+static int     uart_open(struct file *filep);
+static int     uart_close(struct file *filep);
+static ssize_t uart_read(struct file *filep, char *buffer, size_t buflen);
+static ssize_t uart_write(struct file *filep, const char *buffer, size_t buflen);
+static int     uart_ioctl(struct file *filep, int cmd, unsigned long arg);
+
+/************************************************************************************
+ * Private Variables
+ ************************************************************************************/
+
+struct file_operations g_serialops =
+{
+  uart_open,  /* open */
+  uart_close, /* close */
+  uart_read,  /* read */
+  uart_write, /* write */
+  uart_ioctl  /* ioctl */
+};
+
+/************************************************************************************
+ * Private Functions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Name: uart_waittxfifonotfull
+ ************************************************************************************/
+
+#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_SERIAL_INTS)
+static inline void uart_waittxfifonotfull(uart_dev_t *dev)
+{
+  int tmp;
+  for (tmp = 1000 ; tmp > 0 ; tmp--)
+    {
+      if (uart_txfifonotfull(dev))
+        {
+          break;
+        }
+    }
+}
+#endif
+
+/************************************************************************************
+ * Name: uart_takesem
+ ************************************************************************************/
+
+static void uart_takesem(sem_t *sem)
+{
+  while (sem_wait(sem) != 0)
+    {
+      /* The only case that an error should occur here is if
+       * the wait was awakened by a signal.
+       */
+
+      ASSERT(*get_errno_ptr() == EINTR);
+    }
+}
+
+/************************************************************************************
+ * Name: uart_givesem
+ ************************************************************************************/
+
+static inline void uart_givesem(sem_t *sem)
+{
+  (void)sem_post(sem);
+}
+
+/************************************************************************************
+ * Name: uart_putxmitchar
+ ************************************************************************************/
+
+static void uart_putxmitchar(uart_dev_t *dev, int ch)
+{
+  int nexthead = dev->xmit.head + 1;
+  if (nexthead >= dev->xmit.size)
+    {
+      nexthead = 0;
+    }
+
+  for(;;)
+    {
+      if (nexthead != dev->xmit.tail)
+        {
+          dev->xmit.buffer[dev->xmit.head] = ch;
+          dev->xmit.head = nexthead;
+          return;
+        }
+      else
+        {
+#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_SERIAL_INTS)
+          /* Transfer some characters with interrupts disabled */
+
+          uart_xmitchars(dev);
+
+          /* If we unsuccessful in making room in the buffer.
+           * then transmit the characters with interrupts
+           * enabled and wait for result.
+           */
+
+          if (nexthead == dev->xmit.tail)
+            {
+              /* Still no space */
+
+              uart_waittxfifonotfull(dev);
+            }
+#else
+          /* Inform the interrupt level logic that we are waiting */
+
+          dev->xmitwaiting = TRUE;
+
+          /* Wait for some characters to be sent from the buffer
+           * with the TX interrupt enabled.  When the TX interrupt
+           * is enabled, uart_xmitchars should execute and remove
+           * some of the data from the TX buffer.
+           */
+
+          uart_enabletxint(dev);
+          uart_takesem(&dev->xmitsem);
+          uart_disabletxint(dev);
+#endif
+        }
+    }
+}
+
+/************************************************************************************
+ * Name: uart_irqwrite
+ ************************************************************************************/
+
+static ssize_t uart_irqwrite(uart_dev_t *dev, const char *buffer, size_t buflen)
+{
+  ssize_t ret = buflen;
+
+  /* Force each character through the low level interface */
+
+  for (; buflen; buflen--)
+    {
+      int ch = *buffer++;
+      uart_putc(ch);
+
+     /* If this is the console, then we should replace LF with LF-CR */
+
+      if (ch == '\n')
+        {
+          uart_putc('\r');
+        }
+    }
+
+  return ret;
+}
+
+/************************************************************************************
+ * Name: uart_write
+ ************************************************************************************/
+
+static ssize_t uart_write(struct file *filep, const char *buffer, size_t buflen)
+{
+  struct inode *inode    = filep->f_inode;
+  uart_dev_t   *dev      = inode->i_private;
+  ssize_t       ret      = buflen;
+
+  /* We may receive console writes through this path from
+   * interrupt handlers and from debug output in the IDLE task!
+   * In these cases, we will need to do things a little
+   * differently.
+   */
+
+  if (up_interrupt_context() || getpid() == 0)
+    {
+      if (dev->isconsole)
+        {
+          irqstate_t flags = irqsave();
+          ret = uart_irqwrite(dev, buffer, buflen);
+          irqrestore(flags);
+          return ret;
+        }
+      else
+        {
+          return ERROR;
+        }
+    }
+
+  /* Only one user can be accessing dev->xmit.head at once */
+
+  uart_takesem(&dev->xmit.sem);
+
+  /* Loop while we still have data to copy to the transmit buffer.
+   * we add data to the head of the buffer; uart_xmitchars takes the
+   * data from the end of the buffer.
+   */
+
+  uart_disabletxint(dev);
+  for (; buflen; buflen--)
+    {
+      int ch = *buffer++;
+
+      /* Put the character into the transmit buffer */
+
+      uart_putxmitchar(dev, ch);
+
+     /* If this is the console, then we should replace LF with LF-CR */
+
+      if (dev->isconsole && ch == '\n')
+        {
+          uart_putxmitchar(dev, '\r');
+        }
+    }
+
+  if (dev->xmit.head != dev->xmit.tail)
+    {
+#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_SERIAL_INTS)
+      uart_xmitchars(dev);
+#else
+      uart_enabletxint(dev);
+#endif
+    }
+
+  uart_givesem(&dev->xmit.sem);
+  return ret;
+}
+
+/************************************************************************************
+ * Name: uart_read
+ ************************************************************************************/
+
+static ssize_t uart_read(struct file *filep, char *buffer, size_t buflen)
+{
+  struct inode *inode = filep->f_inode;
+  uart_dev_t     *dev   = inode->i_private;
+  ssize_t       ret   = buflen;
+
+  /* Only one user can be accessing dev->recv.tail at once */
+
+  uart_takesem(&dev->recv.sem);
+
+  /* Loop while we still have data to copy to the receive buffer.
+   * we add data to the head of the buffer; uart_xmitchars takes the
+   * data from the end of the buffer.
+   */
+
+  uart_disablerxint(dev);
+  while (buflen)
+    {
+      if (dev->recv.head != dev->recv.tail)
+        {
+          *buffer++ = dev->recv.buffer[dev->recv.tail];
+          buflen--;
+
+          if (++(dev->recv.tail) >= dev->recv.size)
+            {
+              dev->recv.tail = 0;
+            }
+        }
+      else
+        {
+          /* Wait for some characters to be sent from the buffer
+           * with the TX interrupt disabled.
+           */
+
+          dev->recvwaiting = TRUE;
+          uart_enablerxint(dev);
+          uart_takesem(&dev->recvsem);
+          uart_disablerxint(dev);
+        }
+    }
+
+  uart_enablerxint(dev);
+  uart_givesem(&dev->recv.sem);
+  return ret;
+}
+
+/************************************************************************************
+ * Name: uart_ioctl
+ ************************************************************************************/
+
+static int uart_ioctl(struct file *filep, int cmd, unsigned long arg)
+{
+  struct inode *inode = filep->f_inode;
+  uart_dev_t   *dev   = inode->i_private;
+
+  return dev->ops->ioctl(filep, cmd, arg);
+}
+
+/************************************************************************************
+ * Name: uart_close
+ *
+ * Description:
+ *   This routine is called when the serial port gets closed.
+ *   It waits for the last remaining data to be sent.
+ *
+ ************************************************************************************/
+
+static int uart_close(struct file *filep)
+{
+  struct inode *inode = filep->f_inode;
+  uart_dev_t   *dev   = inode->i_private;
+  irqstate_t    flags;
+
+  uart_takesem(&dev->closesem);
+  if (dev->open_count > 1)
+    {
+      dev->open_count--;
+      uart_givesem(&dev->closesem);
+      return OK;
+    }
+
+  /* There are no more references to the port */
+
+  dev->open_count = 0;
+
+  /* Stop accepting input */
+
+  uart_disablerxint(dev);
+
+  /* Now we wait for the transmit buffer to clear */
+
+  while (dev->xmit.head != dev->xmit.tail)
+    {
+      usleep(500*1000);
+    }
+
+  /* And wait for the TX fifo to drain */
+
+  while (!uart_txfifoempty(dev))
+    {
+      usleep(500*1000);
+    }
+
+  /* Free the IRQ and disable the UART */
+
+  flags = irqsave(); /* Disable interrupts */
+  up_disable_irq(dev->irq);
+  irq_detach(dev->irq);
+  uart_shutdown(dev);
+  irqrestore(flags);
+
+  uart_givesem(&dev->closesem);
+  return OK;
+ }
+
+/************************************************************************************
+ * Name: uart_open
+ *
+ * Description:
+ *   This routine is called whenever a serial port is opened.
+ *
+ ************************************************************************************/
+
+static int uart_open(struct file *filep)
+{
+  struct inode *inode = filep->f_inode;
+  uart_dev_t     *dev   = inode->i_private;
+  int           ret   = OK;
+
+  /* If the port is the middle of closing, wait until the close
+   * is finished
+   */
+
+  uart_takesem(&dev->closesem);
+
+  /* Start up serial port */
+
+  if (++dev->open_count == 1)
+    {
+      irqstate_t flags = irqsave();
+
+      /* If this is the console, then the UART has already
+       * been initialized.
+       */
+
+      if (!dev->isconsole)
+        {
+          uart_setup(dev);
+        }
+
+      /* But, in any event, we do have to configure for
+       * interrupt driven mode of operation.
+       */
+
+      /* Attache and enabled the IRQ */
+
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+      ret = irq_attach(dev->irq, dev->ops->handler);
+      if (ret == OK)
+#endif
+        {
+          /* Mark the io buffers empty */
+
+          dev->xmit.head = 0;
+          dev->xmit.tail = 0;
+          dev->recv.head = 0;
+          dev->recv.tail = 0;
+
+          /* Finally, enable interrupts */
+
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+          up_enable_irq(dev->irq);
+#endif
+          uart_enablerxint(dev);
+        }
+      irqrestore(flags);
+    }
+
+  uart_givesem(&dev->closesem);
+  return ret;
+}
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Name: uart_register
+ *
+ * Description:
+ *   Register serial console and serial ports.
+ *
+ ************************************************************************************/
+
+int uart_register(const char *path, uart_dev_t *dev)
+{
+  sem_init(&dev->xmit.sem, 0, 1);
+  sem_init(&dev->recv.sem, 0, 1);
+  sem_init(&dev->closesem, 0, 1);
+  sem_init(&dev->xmitsem,  0, 0);
+  sem_init(&dev->recvsem,  0, 0);
+
+  dbg("Registering %s\n", path);
+  return register_inode(path, &g_serialops, 0666, dev);
+}
+
+/************************************************************************************
+ * Name: uart_xmitchars
+ *
+ * Description:
+ *   This function is called from the UART interrupt handler when an interrupt
+ *   is received indicating that there is more space in the transmit FIFO.  This
+ *   function will send characters from the tail of the xmit buffer while the driver
+ *   write() logic adds data to the head of the xmit buffer.
+ *
+ ************************************************************************************/
+
+void uart_xmitchars(uart_dev_t *dev)
+{
+  /* Send while we still have data & room in the fifo */
+
+  while (dev->xmit.head != dev->xmit.tail && uart_txfifonotfull(dev))
+    {
+      uart_send(dev, dev->xmit.buffer[dev->xmit.tail]);
+
+      if (++(dev->xmit.tail) >= dev->xmit.size)
+        {
+          dev->xmit.tail = 0;
+        }
+
+      if (dev->xmitwaiting)
+        {
+          dev->xmitwaiting = FALSE;
+          uart_givesem(&dev->xmitsem);
+        }
+    }
+
+  /* When all of the characters have been sent from the buffer
+   * disable the TX interrupt.
+   */
+
+  if (dev->xmit.head == dev->xmit.tail)
+    {
+      uart_disabletxint(dev);
+    }
+}
+
+/************************************************************************************
+ * Name: uart_receivechars
+ *
+ * Description:
+ *   This function is called from the UART interrupt handler when an interrupt
+ *   is received indicating that are bytes available in the receive fifo.  This
+ *   function will add chars to head of receive buffer.  Driver read() logic will take
+ *   characters from the tail of the buffer.
+ *
+ ************************************************************************************/
+
+void uart_recvchars(uart_dev_t *dev)
+{
+  unsigned int status;
+  int nexthead = dev->recv.head + 1;
+
+  if (nexthead >= dev->recv.size)
+    {
+      nexthead = 0;
+    }
+
+  while (nexthead != dev->recv.tail && uart_rxfifonotempty(dev))
+    {
+      dev->recv.buffer[dev->recv.head] = uart_receive(dev, &status);
+
+      dev->recv.head = nexthead;
+      if (++nexthead >= dev->recv.size)
+        {
+           nexthead = 0;
+        }
+
+      if (dev->recvwaiting)
+        {
+          dev->recvwaiting = FALSE;
+          uart_givesem(&dev->recvsem);
+        }
+    }
+}
+
diff --git a/include/nuttx/serial.h b/include/nuttx/serial.h
new file mode 100644
index 0000000000000000000000000000000000000000..7719fca6b43946d9f0a671e7fcfac734e7da2af5
--- /dev/null
+++ b/include/nuttx/serial.h
@@ -0,0 +1,241 @@
+/************************************************************************************
+ * serial.h
+ *
+ *   Copyright (C) 2007 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name Gregory Nutt nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+#ifndef __SERIAL_H
+#define __SERIAL_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+#include <semaphore.h>
+#include <nuttx/fs.h>
+
+/************************************************************************************
+ * Definitions
+ ************************************************************************************/
+
+#define uart_setup(dev)          dev->ops->setup(dev)
+#define uart_shutdown(dev)       dev->ops->shutdown(dev)
+#define uart_enabletxint(dev)    dev->ops->txint(dev, TRUE)
+#define uart_disabletxint(dev)   dev->ops->txint(dev, FALSE)
+#define uart_enablerxint(dev)    dev->ops->rxint(dev, TRUE)
+#define uart_disablerxint(dev)   dev->ops->rxint(dev, FALSE)
+#define uart_rxfifonotempty(dev) dev->ops->rxfifonotempty(dev)
+#define uart_txfifonotfull(dev)  dev->ops->txfifonotfull(dev)
+#define uart_txfifoempty(dev)    dev->ops->txfifoempty(dev)
+#define uart_send(dev,ch)        dev->ops->send(dev,ch)
+#define uart_receive(dev,s)      dev->ops->receive(dev,s)
+
+/************************************************************************************
+ * Private Types
+ ************************************************************************************/
+
+/* This structure defines one serial I/O buffer.  The serial infrastructure will
+ * initialize the 'sem' field but all other fields must be initialized by the
+ * caller of uart_register().
+ */
+
+struct uart_buffer_s
+{
+  sem_t     sem;    /* Used to control exclusive access to the buffer */
+  sint16    head;   /* Index to the head [IN] index in the buffer */
+  sint16    tail;   /* Index to the tail [OUT] index in the buffer */
+  sint16    size;   /* The allocated size of the buffer */
+  FAR char *buffer; /* Pointer to the allocated buffer memory */
+};
+
+/* This structure defines all of the operations providd by the architecture specific
+ * logic.  All fields must be provided with non-NULL function pointers by the
+ * caller of uart_register().
+ */
+
+struct uart_dev_s;
+struct uart_ops_s
+{
+  /* Configure the UART baud, bits, parity, fifos, etc. This method is called
+   * the first time that the serial port is opened.
+   */
+
+  int (*setup)(struct uart_dev_s *dev);
+
+  /* Disable the UART.  This method is called when the serial port is closed */
+
+  void (*shutdown)(struct uart_dev_s *dev);
+
+  /* This is the UART interrupt handler.  It will be invoked when an interrupt
+   * received on the 'irq'  It should call uart_transmitchars or uart_receivechar
+   * to perform the appropriate data transfers.  The interrupt handling logic\
+   * must be able to map the 'irq' number into the approprite uart_dev_s
+   * structure in order to call these functions.
+   */
+
+  int (*handler)(int irq, void *context);
+
+  /* All ioctl calls will be routed through this method */
+
+  int (*ioctl)(struct file *filep, int cmd, unsigned long arg);
+
+  /* Called (usually) from the interrupt level to receive one character from
+   * the UART.  Error bits associated with the receipt are provided in the
+   * the return 'status'.
+   */
+
+  int (*receive)(struct uart_dev_s *dev, unsigned int *status);
+
+  /* Call to enable or disable RX interrupts */
+
+  void (*rxint)(struct uart_dev_s *dev, boolean enable);
+
+  /* Return TRUE if the receive fifo is not empty */
+
+  boolean (*rxfifonotempty)(struct uart_dev_s *dev);
+
+  /* This method will send one byte on the UART */
+
+  void (*send)(struct uart_dev_s *dev, int ch);
+
+  /* Call to enable or disable TX interrupts */
+
+  void (*txint)(struct uart_dev_s *dev, boolean enable);
+
+  /* Return TRUE if the tranmsit fifo is not full.  This is used to
+   * determine if *send can be called.
+   */
+
+  boolean (*txfifonotfull)(struct uart_dev_s *dev);
+
+  /* Return TRUE if the transmit fifo is empty.  This is used when the
+   * driver needs to make sure that all characters are "drained" from
+   * the TX fifo.
+   */
+
+  boolean (*txfifoempty)(struct uart_dev_s *dev);
+};
+
+/* This is the device structure used by the driver.  The caller of
+ * uart_register() must allocate and initialize this structure.  The
+ * calling logic need only set all fields to zero except:
+ *
+ *   'irq', 'isconsole', 'xmit.buffer', 'rcv.buffer', the elements
+ *   of 'ops', and 'private'
+ *
+ * The common logic will initialize all semaphores.
+ */
+
+struct uart_dev_s
+{
+  int       open_count;			/* The number of times
+					* the device has been opened */
+  ubyte     irq;			/* IRQ associated with
+					 * this UART */
+  boolean   xmitwaiting;		/* TRUE: User is waiting
+					 * for space in xmit.buffer */
+  boolean   recvwaiting;		/* TRUE: User is waiting
+					 * for space in recv.buffer */
+  boolean   isconsole;			/* TRUE: This is the serial console */
+  sem_t     closesem;			/* Locks out new opens while
+					 * close is in progress */
+  sem_t     xmitsem;			/* Used to wakeup user waiting
+					 * for space in xmit.buffer */
+  sem_t     recvsem;			/* Used to wakeup user waiting
+					 * for sapce in recv.buffer */
+  struct uart_buffer_s xmit;		/* Describes transmit buffer */
+  struct uart_buffer_s recv;		/* Describes receive buffer */
+  const struct uart_ops_s *ops;		/* Arch-specifics operations */
+  void     *priv;			/* Used by the arch-specific logic */
+};
+typedef struct uart_dev_s uart_dev_t;
+
+/************************************************************************************
+ * Public Data
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/************************************************************************************
+ * Name: uart_register
+ *
+ * Description:
+ *   Register serial console and serial ports.
+ *
+ ************************************************************************************/
+
+EXTERN int uart_register(const char *path, uart_dev_t *dev);
+
+/************************************************************************************
+ * Name: uart_xmitchars
+ *
+ * Description:
+ *   This function is called from the UART interrupt handler when an interrupt
+ *   is received indicating that there is more space in the transmit FIFO.  This
+ *   function will send characters from the tail of the xmit buffer while the driver
+ *   write() logic adds data to the head of the xmit buffer.
+ *
+ ************************************************************************************/
+
+EXTERN void uart_xmitchars(uart_dev_t *dev);
+
+/************************************************************************************
+ * Name: uart_receivechars
+ *
+ * Description:
+ *   This function is called from the UART interrupt handler when an interrupt
+ *   is received indicating that are bytes available in the receive fifo.  This
+ *   function will add chars to head of receive buffer.  Driver read() logic will take
+ *   characters from the tail of the buffer.
+ *
+ ************************************************************************************/
+
+EXTERN void uart_recvchars(uart_dev_t *dev);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __SERIAL_H */