Index: bsps/shared/dev/display/disp_fonts.h
===================================================================
--- bsps/shared/dev/display/disp_fonts.h	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/display/disp_fonts.h	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,55 @@
+/*===============================================================*\
+| Project: display driver for HCMS29xx                            |
++-----------------------------------------------------------------+
+| File: disp_fonts.h                                              |
++-----------------------------------------------------------------+
+|                    Copyright (c) 2008                           |
+|                    Embedded Brains GmbH                         |
+|                    Obere Lagerstr. 30                           |
+|                    D-82178 Puchheim                             |
+|                    Germany                                      |
+|                    rtems@embedded-brains.de                     |
++-----------------------------------------------------------------+
+| The license and distribution terms for this file may be         |
+| found in the file LICENSE in this distribution or at            |
+| http://www.rtems.org/license/LICENSE.                           |
+|                                                                 |
++-----------------------------------------------------------------+
+| This file declares general data structures for font management  |
+\*===============================================================*/
+
+#ifndef DISP_FONTS_H
+#define DISP_FONTS_H
+
+#include <rtems.h>
+
+typedef int8_t disp_font_dimen;
+
+struct disp_font_bounding_box
+{
+  disp_font_dimen w, h, x, y;
+};
+
+struct disp_font_glyph
+{
+  struct disp_font_bounding_box bb;
+  disp_font_dimen wx, wy;
+  const unsigned char *bitmap;
+};
+
+struct disp_font_base
+{
+  int8_t trans;
+  struct disp_font_bounding_box fbb;
+  disp_font_dimen ascent, descent;
+  uint8_t default_char;
+  struct disp_font_glyph *latin1[256];
+};
+
+typedef struct disp_font_base *disp_font_t;
+
+/* Prototypes ------------------------------------------------- */
+
+/* End -------------------------------------------------------- */
+
+#endif /* not defined DISP_FONTS_H */
Index: bsps/shared/dev/display/disp_hcms29xx.c
===================================================================
--- bsps/shared/dev/display/disp_hcms29xx.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/display/disp_hcms29xx.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,932 @@
+/*===============================================================*\
+| Project: display driver for HCMS29xx                            |
++-----------------------------------------------------------------+
+| File: disp_hcms29xx.c                                           |
++-----------------------------------------------------------------+
+|                    Copyright (c) 2008                           |
+|                    Embedded Brains GmbH                         |
+|                    Obere Lagerstr. 30                           |
+|                    D-82178 Puchheim                             |
+|                    Germany                                      |
+|                    rtems@embedded-brains.de                     |
++-----------------------------------------------------------------+
+| The license and distribution terms for this file may be         |
+| found in the file LICENSE in this distribution or at            |
+| http://www.rtems.org/license/LICENSE.                           |
++-----------------------------------------------------------------+
+| this file contains the SPI based driver for a HCMS29xx 4 digit  |
+| alphanumeric LED display                                        |
+\*===============================================================*/
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <bsp.h>
+#include <rtems/libi2c.h>
+#include <libchip/disp_hcms29xx.h>
+#include "font_hcms29xx.h"
+#define FONT_BASE font_hcms29xx_base
+
+
+#define DISP_HCMS29XX_DIGIT_CNT (4)
+#define DISP_HCMS29XX_SEMA_NAME      rtems_build_name('D','4','I','Q')
+#define DISP_HCMS29XX_TRNS_SEMA_NAME rtems_build_name('D','4','T','R')
+#define DISP_HCMS29XX_TIMER_NAME     rtems_build_name('D','4','T','M')
+#define DISP_HCMS29XX_TASK_NAME      rtems_build_name('D','4','T','A')
+
+#define DISP_HCMS29XX_EVENT_TIMER  RTEMS_EVENT_1
+#define DISP_HCMS29XX_EVENT_NEWSTR RTEMS_EVENT_2
+
+
+static disp_font_t disp_hcms29xx_font_normal;
+static disp_font_t disp_hcms29xx_font_rotate;
+const rtems_libi2c_tfr_mode_t spi_disphcms29xx_tfr_mode = {
+  .baudrate = 1000000,
+  .bits_per_char = 8,
+  .lsb_first = true,
+  .clock_inv = true,
+  .clock_phs = true,
+  .idle_char = 0
+};
+
+static disp_hcms29xx_drv_t disp_hcms29xx_drv_tbl;
+
+/*=========================================
+ * font management functions
+ */
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code disp_hcms29xx_font_struct_size
+  (
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   compute size of font data structure tree                                |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+  disp_font_t            src,           /* source font                     */
+  size_t                *dst_size       /* destination: size of font struct*/
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+{
+
+  rtems_status_code rc = RTEMS_SUCCESSFUL;
+  size_t font_size = 0;
+  size_t glyph_idx;
+  /*
+   * check parameters
+   */
+  if ((rc == RTEMS_SUCCESSFUL) &&
+      (src == NULL)) {
+    rc = RTEMS_INVALID_ADDRESS;
+  }
+  if (rc == RTEMS_SUCCESSFUL) {
+    font_size =
+      sizeof(*src);                      /* font_base structure       */
+  }
+  glyph_idx = 0;
+  while ((rc == RTEMS_SUCCESSFUL) &&
+	 (glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0])))) {
+    if (src->latin1[glyph_idx] != NULL) {
+      font_size += sizeof(*(src->latin1[glyph_idx]))
+	+ (size_t) src->latin1[glyph_idx]->bb.w;
+    }
+    glyph_idx++;
+  }
+  *dst_size = font_size;
+
+  return rc;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static inline unsigned char disp_hcms29xx_bitswap
+  (
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   swap data bits in byte (7<->0 , 6<->1 etc)                              |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+  unsigned char byte
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+{
+  unsigned char result = 0;
+  int smsk,dmsk;
+  for (smsk =  0x01,dmsk=0x80;
+       smsk < 0x100;
+       smsk<<=1   ,dmsk>>=1) {
+    if ((byte & smsk) != 0) {
+      result |= (unsigned char) dmsk;
+    }
+  }
+  return result;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code disp_hcms29xx_copy_font
+  (
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   copy font data from source to dest font structure                       |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+  disp_font_t src,                      /* source font                     */
+  struct disp_font_base *dst,           /* ptr to destination font         */
+  int shift_cnt,                        /* shift count for font            */
+  bool do_rotate                        /* rotate font, if true            */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+{
+
+  rtems_status_code rc = RTEMS_SUCCESSFUL;
+  char *alloc_next = (char *)dst;
+  size_t glyph_idx = 0;
+  int glyph_size;
+  unsigned char byte;
+  int bcnt;
+
+  /*
+   * check parameters
+   */
+  if ((rc == RTEMS_SUCCESSFUL) &&
+      ((src == NULL) ||
+       (dst == NULL))) {
+    rc = RTEMS_INVALID_ADDRESS;
+  }
+  /*
+   * copy font_base structure
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    *dst = *src;
+    alloc_next += sizeof(*dst);
+  }
+  /*
+   * for all glyphs: assign own glyph memory
+   */
+  glyph_idx = 0;
+  while ((rc == RTEMS_SUCCESSFUL) &&
+	 glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0]))) {
+    if (src->latin1[glyph_idx] != NULL) {
+      /*
+       * allocate space for glyph
+       */
+      dst->latin1[glyph_idx] = (struct disp_font_glyph *)alloc_next;
+      alloc_next += sizeof(*(dst->latin1[glyph_idx]));
+      /*
+       * copy source values.
+       * Note: bitmap will be reassigned later
+       */
+      *(struct disp_font_glyph *)(dst->latin1[glyph_idx]) =
+	*(src->latin1[glyph_idx]);
+    }
+    else {
+      dst->latin1[glyph_idx] = NULL;
+    }
+    glyph_idx++;
+  }
+
+  /*
+   * for all glyphs: reassign bitmap
+   */
+  glyph_idx = 0;
+  while ((rc == RTEMS_SUCCESSFUL) &&
+	 glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0]))) {
+    if (src->latin1[glyph_idx] != NULL) {
+      glyph_size = src->latin1[glyph_idx]->bb.w;
+      /*
+       * allocate space for glyph_bitmap
+       */
+      dst->latin1[glyph_idx]->bitmap = (const unsigned char *) alloc_next;
+      alloc_next += glyph_size;
+      /*
+       * copy/transform bitmap
+       */
+      for (bcnt = 0;bcnt < glyph_size;bcnt++) {
+	if (do_rotate) {
+	  byte = src->latin1[glyph_idx]->bitmap[glyph_size - 1 - bcnt];
+	  byte = disp_hcms29xx_bitswap(byte);
+	}
+	else {
+	  byte = src->latin1[glyph_idx]->bitmap[bcnt];
+	}
+	if (shift_cnt < 0) {
+	  byte = byte >> shift_cnt;
+	}
+	else if (shift_cnt > 0) {
+	  byte = byte >> shift_cnt;
+	}
+	((unsigned char *)(dst->latin1[glyph_idx]->bitmap))[bcnt] = byte;
+      }
+    }
+    glyph_idx++;
+  }
+  return rc;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code disp_hcms29xx_alloc_copy_font
+  (
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   copy font data from source to dest font structure, alloc all data       |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+  const disp_font_t src,                /* source font                     */
+  disp_font_t *dst,                     /* ptr to destination font         */
+  int shift_cnt,                        /* shift count for font            */
+  bool do_rotate                        /* rotate font, if true            */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+{
+
+  rtems_status_code rc = RTEMS_SUCCESSFUL;
+  size_t src_size = 0;
+  /*
+   * check parameters
+   */
+  if ((rc == RTEMS_SUCCESSFUL) &&
+      ((src == NULL)
+       || (dst == NULL))) {
+    rc = RTEMS_INVALID_ADDRESS;
+  }
+  /*
+   * determine size of source data
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = disp_hcms29xx_font_struct_size(src,&src_size);
+  }
+  /*
+   * allocate proper data area
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    *dst = malloc(src_size);
+    if (*dst == NULL) {
+      rc = RTEMS_UNSATISFIED;
+    }
+  }
+  /*
+   * scan through source data, copy to dest
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = disp_hcms29xx_copy_font(src,*dst,shift_cnt,do_rotate);
+  }
+  return rc;
+}
+
+/*=========================================
+ * SPI communication functions
+ */
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code disp_hcms29xx_send_to_display
+  (
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   request access semaphore to SPI, prepare buffer descriptors, start      |
+|   transfer via SPI to display                                             |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+   disp_hcms29xx_drv_t *softc_ptr,
+   const volatile char *disp_buffer /* start of chars to display (4 chars or 'til \0)*/
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+{
+  rtems_status_code rc = RTEMS_SUCCESSFUL;
+  bool char_avail;
+  const struct disp_font_glyph *glyph_ptr;
+  disp_font_t curr_font;
+  int i, ret_cnt;
+  unsigned char c;
+
+  /*
+   * select device, set transfer mode, address device
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_libi2c_send_start(softc_ptr->disp_param.minor);
+  }
+  /*
+   * set transfer mode
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = -rtems_libi2c_ioctl(softc_ptr->disp_param.minor,
+			     RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
+			     &spi_disphcms29xx_tfr_mode);
+  }
+
+  /*
+   * address device
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_libi2c_send_addr(softc_ptr->disp_param.minor,true);
+  }
+
+  /*
+   * send data
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    curr_font =
+      softc_ptr->disp_param.rotate
+      ? disp_hcms29xx_font_rotate
+      : disp_hcms29xx_font_normal;
+
+    char_avail = true;
+    /*
+     * FIXME: for rotated display, write last character first...
+     * maybe we should copy everything to a common buffer and use
+     * ONE SPI transfer?
+     */
+    for (i = 0;
+	 ((rc == RTEMS_SUCCESSFUL) &&
+	  (i < DISP_HCMS29XX_DIGIT_CNT));
+	  i++) {
+      /* test for end of string... */
+      c = disp_buffer[i]; /* perform consistent read of disp_buffer */
+      if (char_avail && (c == '\0')) {
+	char_avail = false;
+      }
+      glyph_ptr = (char_avail
+		   ? curr_font->latin1[c]
+		   : NULL);
+      if (glyph_ptr == NULL) {
+	glyph_ptr = curr_font->latin1[' '];
+      }
+
+      /*
+       * send 5 bytes from (char *)glyph_ptr->bitmap to SPI
+       */
+      if (rc == RTEMS_SUCCESSFUL) {
+	ret_cnt = rtems_libi2c_write_bytes(softc_ptr->disp_param.minor,
+					   glyph_ptr->bitmap,5);
+	if (ret_cnt < 0) {
+	  rc = -ret_cnt;
+	}
+      }
+    }
+  }
+  /*
+   * finish transfer
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_libi2c_send_stop(softc_ptr->disp_param.minor);
+  }
+
+  return rc;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code disp_hcms29xx_send_to_control
+  (
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   request access semaphore to SPI, prepare buffer descriptors, start      |
+|   transfer via SPI to display                                             |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+   disp_hcms29xx_drv_t *softc_ptr,
+   int pwm,   /* value for pwm of LEDs, 0..15 */
+   int peak,  /* value for peak current for LEDs, 0..3 */
+   int sleep, /* value to make display "sleep" (0..1 */
+   int div,   /* divider for external osc input, unused here */
+   int chain  /* mode to drive other displays, unused here */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+{
+  rtems_status_code rc = RTEMS_SUCCESSFUL;
+  int run, ret_cnt;
+  uint8_t ctrl_buffer;
+
+  /* two accesses, control word 0 and 1 */
+  for (run = 0;
+       ((rc == RTEMS_SUCCESSFUL) && (run <= 1));
+       run++) {
+    if (rc == RTEMS_SUCCESSFUL) {
+      if (run == 0) {
+	ctrl_buffer =
+	  (0              << 7) |
+	  ((sleep & 0x01) << 6) |
+	  ((peak  & 0x03) << 4) |
+	  ((pwm & 0x0f)   << 0);
+      }
+      else {
+	ctrl_buffer =
+	  (1              << 7) |
+	  ((div   & 0x01) << 1) |
+	  ((chain & 0x01) << 0);
+      }
+      /*
+       * select device, set transfer mode, address device
+       */
+      if (rc == RTEMS_SUCCESSFUL) {
+	rc = rtems_libi2c_send_start(softc_ptr->disp_param.minor);
+      }
+      /*
+       * set transfer mode
+       */
+      if (rc == RTEMS_SUCCESSFUL) {
+	rc = -rtems_libi2c_ioctl(softc_ptr->disp_param.minor,
+				 RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
+				 &spi_disphcms29xx_tfr_mode);
+      }
+
+      /*
+       * address device
+       */
+      if (rc == RTEMS_SUCCESSFUL) {
+	rc = rtems_libi2c_send_addr(softc_ptr->disp_param.minor,true);
+      }
+
+      /*
+       * send 1 byte from ctrl_buffer
+       */
+      if (rc == RTEMS_SUCCESSFUL) {
+	ret_cnt = rtems_libi2c_write_bytes(softc_ptr->disp_param.minor,
+					   &ctrl_buffer,1);
+	if (ret_cnt < 0) {
+	  rc = -ret_cnt;
+	}
+      }
+    }
+  } /* next run ... */
+
+  /*
+   * finish transfer
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_libi2c_send_stop(softc_ptr->disp_param.minor);
+  }
+
+  return rc;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static rtems_timer_service_routine disp_hcms29xx_timer_sr
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   this task updates the string in the display                             |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+(
+ rtems_id id, /* ID of timer, not used  */
+ void * arg   /* calling arg: softc_ptr */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    <none used>                                                            |
+\*=========================================================================*/
+{
+  disp_hcms29xx_drv_t *softc_ptr = arg;
+
+  rtems_event_send(softc_ptr->disp_param.task_id, DISP_HCMS29XX_EVENT_TIMER);
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static rtems_task disp_hcms29xx_update_task
+  (
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   this task updates the string in the display                             |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+   rtems_task_argument argument 
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    <never exits>                                                          |
+\*=========================================================================*/
+{
+  rtems_event_set  my_events;
+  rtems_status_code rc = RTEMS_SUCCESSFUL;
+  int disp_offset = 0;
+  rtems_id disp_hcms29xx_timer_id;
+  disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
+
+  /*
+   * initialize display:
+   */
+  /*
+   * set control attributes for display
+   * maximum brightness...
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = disp_hcms29xx_send_to_control(softc_ptr,
+				       14,3,1,0,0);/* pwm/peak/nosleep/div/chain */
+  }
+
+  /*
+   * set display to blank
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = disp_hcms29xx_send_to_display(softc_ptr,
+				       "");
+  }
+
+  /*
+   * create timer for scrolling
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_timer_create(DISP_HCMS29XX_TIMER_NAME,
+			    &disp_hcms29xx_timer_id);
+  }
+
+  while (rc == RTEMS_SUCCESSFUL) {
+    /*
+     * wait for any event
+     */
+    rc = rtems_event_receive(DISP_HCMS29XX_EVENT_NEWSTR |
+			     DISP_HCMS29XX_EVENT_TIMER ,
+			     RTEMS_WAIT | RTEMS_EVENT_ANY,
+			     RTEMS_NO_TIMEOUT,
+			     &my_events);
+    if (my_events & DISP_HCMS29XX_EVENT_NEWSTR) {
+      /*
+       * fetch new string consistently into local buffer
+       */
+      if (rc == RTEMS_SUCCESSFUL) {
+	rc = rtems_semaphore_obtain(softc_ptr->disp_param.trns_sema_id,
+				    RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+      }
+      if (rc == RTEMS_SUCCESSFUL) {
+	strncpy(softc_ptr->disp_param.disp_buffer,
+		softc_ptr->disp_param.trns_buffer,
+		sizeof(softc_ptr->disp_param.disp_buffer));
+	softc_ptr->disp_param.disp_buffer[sizeof(softc_ptr->disp_param.disp_buffer)-1] = '\0';
+	softc_ptr->disp_param.disp_buf_cnt =
+	  (int) strlen(softc_ptr->disp_param.disp_buffer);
+      }
+      if (rc == RTEMS_SUCCESSFUL) {
+	rc = rtems_semaphore_release(softc_ptr->disp_param.trns_sema_id);
+      }
+      /*
+       * set initial offset to negative value
+       * to make string static for some ticks
+       */
+      disp_offset = -4;
+    }
+    if (my_events & DISP_HCMS29XX_EVENT_TIMER) {
+      /*
+       * increase disp_offset, if possible, otherwise reset it
+       */
+      if ((disp_offset < 0) ||
+	  (disp_offset < softc_ptr->disp_param.disp_buf_cnt-
+	   DISP_HCMS29XX_DIGIT_CNT/2)) {
+	disp_offset++;
+      }
+      else {
+	disp_offset = -4;
+      }
+    }
+    /*
+     * display string, starting from disp_offset
+     */
+    if (disp_offset < 0) {
+      rc = disp_hcms29xx_send_to_display(softc_ptr,
+					 softc_ptr->disp_param.disp_buffer);
+    }
+    else if (disp_offset
+	     < (softc_ptr->disp_param.disp_buf_cnt - DISP_HCMS29XX_DIGIT_CNT)) {
+      rc = disp_hcms29xx_send_to_display(softc_ptr,
+					 softc_ptr->disp_param.disp_buffer+disp_offset);
+    }
+    else {
+      rc = disp_hcms29xx_send_to_display(softc_ptr,
+					 softc_ptr->disp_param.disp_buffer
+					 + softc_ptr->disp_param.disp_buf_cnt
+					 - DISP_HCMS29XX_DIGIT_CNT);
+    }
+    /*
+     * activate timer, if needed
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      if (softc_ptr->disp_param.disp_buf_cnt > DISP_HCMS29XX_DIGIT_CNT) {
+	rc = rtems_timer_fire_after(disp_hcms29xx_timer_id,
+				    50,
+				    disp_hcms29xx_timer_sr,
+				    NULL);
+      }
+      else {
+	rc = rtems_timer_cancel(disp_hcms29xx_timer_id);
+      }
+    }
+  }
+  /*
+   * FIXME: display task is dead...
+   */
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code disp_hcms29xx_update
+  (
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   move given string to display task                                       |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+   disp_hcms29xx_drv_t *softc_ptr,
+   const char *src
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+{
+  rtems_status_code rc = RTEMS_SUCCESSFUL;
+
+  /*
+   * obtain trns semaphore
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_semaphore_obtain(softc_ptr->disp_param.trns_sema_id,
+				RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+  }
+  /*
+   * copy string...
+   */
+  strncpy(softc_ptr->disp_param.trns_buffer,src,
+	  sizeof(softc_ptr->disp_param.trns_buffer));
+  softc_ptr->disp_param.trns_buffer[sizeof(softc_ptr->disp_param.trns_buffer)-1] = '\0';
+
+  /*
+   * release trns semaphore
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_semaphore_release(softc_ptr->disp_param.trns_sema_id);
+  }
+
+  /*
+   * send event to task
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_event_send(softc_ptr->disp_param.task_id,
+			  DISP_HCMS29XX_EVENT_NEWSTR);
+  }
+
+  return rc;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+rtems_device_driver disp_hcms29xx_dev_initialize
+  (
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   prepare the display device driver to accept write calls                 |
+|   register device with its name                                           |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+  rtems_device_major_number  major,
+  rtems_device_minor_number  minor,
+  void                      *arg
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+/*
+ * Initialize and register the device
+ */
+{
+  rtems_status_code rc = RTEMS_SUCCESSFUL;
+  disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
+
+  /*
+   * initialize font management
+   * FIXME: check, that default glyph exists
+   * FIXME: check font size to be 5x7
+   */
+  /*
+   * translate font according to direction/baseline
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = disp_hcms29xx_alloc_copy_font(
+			       &FONT_BASE,
+			       &disp_hcms29xx_font_normal,
+			       FONT_BASE.descent, /* shift to visibility... */
+			       FALSE); /* do not rotate */
+  }
+  /* FIXME: translate font for rotation */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = disp_hcms29xx_alloc_copy_font(&FONT_BASE,
+			       &disp_hcms29xx_font_rotate,
+			       0, /* do not shift */
+			       true); /* rotate font */
+  }
+  /*
+   * create the trns_buffer semaphore
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_semaphore_create (DISP_HCMS29XX_TRNS_SEMA_NAME,1,
+				     RTEMS_PRIORITY
+				     |RTEMS_BINARY_SEMAPHORE
+				     |RTEMS_INHERIT_PRIORITY
+				     |RTEMS_NO_PRIORITY_CEILING
+				     |RTEMS_LOCAL,
+				     0,
+				     &softc_ptr->disp_param.trns_sema_id);
+  }
+
+  /*
+   * create and start display task
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_task_create(DISP_HCMS29XX_TASK_NAME,
+			   20,
+			   RTEMS_MINIMUM_STACK_SIZE,
+			   RTEMS_INTERRUPT_LEVEL(0) | RTEMS_TIMESLICE,
+			   RTEMS_DEFAULT_ATTRIBUTES,
+			   &softc_ptr->disp_param.task_id);
+  }
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_task_start(softc_ptr->disp_param.task_id,
+			  disp_hcms29xx_update_task,0);
+  }
+  return rc;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+rtems_device_driver disp_hcms29xx_dev_open
+(
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   open the display device                                                 |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+  rtems_device_major_number  major,
+  rtems_device_minor_number  minor,
+  void                      *arg
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+{
+  disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
+  /*
+   * ensure, that disp_hcms29xx device is assumed to be empty
+   */
+  softc_ptr->disp_param.dev_buf_cnt = 0;
+
+  return RTEMS_SUCCESSFUL;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+rtems_device_driver disp_hcms29xx_dev_write
+(
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   write to display device                                                 |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+  rtems_device_major_number  major,
+  rtems_device_minor_number  minor,
+  void                      *arg
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+{
+  rtems_libio_rw_args_t *args = arg;
+  uint32_t cnt;
+  disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
+
+  for (cnt = 0;cnt < args->count;cnt++) {
+    /*
+     * accumulate characters written into display dev buffer
+     */
+    if (((softc_ptr->disp_param.dev_buf_cnt > 0)
+	&&((args->buffer[cnt] == '\n')
+	   || (args->buffer[cnt] == '\0'))
+	 )
+	||( softc_ptr->disp_param.dev_buf_cnt >=
+	    (int) sizeof(softc_ptr->disp_param.dev_buffer) - 1)) {
+      softc_ptr->disp_param.dev_buffer[softc_ptr->disp_param.dev_buf_cnt] = '\0';
+      /*
+       * transfer string to display string, redisplay it...
+       */
+      disp_hcms29xx_update(softc_ptr,softc_ptr->disp_param.dev_buffer);
+      softc_ptr->disp_param.dev_buf_cnt = 0;
+    }
+    /*
+     * write to dev_buf, if '\n' occured or display device buffer is full
+     */
+    if ((args->buffer[cnt] != '\n') &&
+	(args->buffer[cnt] != '\0')) {
+      softc_ptr->disp_param.dev_buffer[softc_ptr->disp_param.dev_buf_cnt++] =
+	args->buffer[cnt];
+    }
+  }
+  args->bytes_moved = args->count;
+
+  return RTEMS_SUCCESSFUL;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+rtems_device_driver disp_hcms29xx_dev_close
+(
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   close the display device                                                |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+  rtems_device_major_number  major,
+  rtems_device_minor_number  minor,
+  void                      *arg
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    rtems_status_code                                                      |
+\*=========================================================================*/
+{
+
+  return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * driver operation tables
+ */
+static rtems_driver_address_table disp_hcms29xx_ops = {
+  .initialization_entry = disp_hcms29xx_dev_initialize,
+  .open_entry =           disp_hcms29xx_dev_open,
+  .write_entry =          disp_hcms29xx_dev_write,
+  .close_entry =          disp_hcms29xx_dev_close
+};
+
+
+static disp_hcms29xx_drv_t disp_hcms29xx_drv_tbl = {
+  {/* public fields */
+    .ops =         &disp_hcms29xx_ops, 
+    .size =        sizeof (disp_hcms29xx_drv_t),
+  },
+  { /* our private fields */
+    0,
+    { 0 },
+    0,
+    { 0 },
+    { 0 },
+    0,
+    0,
+    0,
+    false
+  }
+};
+
+rtems_libi2c_drv_t *disp_hcms29xx_driver_descriptor = 
+  &disp_hcms29xx_drv_tbl.libi2c_drv_entry;
+
Index: bsps/shared/dev/display/font_hcms29xx.c
===================================================================
--- bsps/shared/dev/display/font_hcms29xx.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/display/font_hcms29xx.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,1820 @@
+/*===============================================================*\
+| Project: display driver for HCMS29xx                            |
++-----------------------------------------------------------------+
+| File: font_hcms29xx.c                                           |
++-----------------------------------------------------------------+
+|                    Copyright (c) 2008                           |
+|                    Embedded Brains GmbH                         |
+|                    Obere Lagerstr. 30                           |
+|                    D-82178 Puchheim                             |
+|                    Germany                                      |
+|                    rtems@embedded-brains.de                     |
++-----------------------------------------------------------------+
+| The license and distribution terms for this file may be         |
+| found in the file LICENSE in this distribution or at            |
+| http://www.rtems.org/license/LICENSE.                           |
++-----------------------------------------------------------------+
+| This file defines the 5x7 bit font used in disp_hcms29xx        |
+\*===============================================================*/
+
+#include <stddef.h>
+#include "disp_fonts.h"
+
+const unsigned char bitmap_hp_fixed_5_7_0 [5] = {
+  0x08,
+  0x1c,
+  0x3e,
+  0x7f,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_0 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_0,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_1 [5] = {
+  0x30,
+  0x45,
+  0x48,
+  0x40,
+  0x30
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_1 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_1,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_2 [5] = {
+  0x45,
+  0x29,
+  0x11,
+  0x29,
+  0x45
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_2 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_2,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_3 [5] = {
+  0x7d,
+  0x09,
+  0x11,
+  0x21,
+  0x7d
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_3 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_3,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_4 [5] = {
+  0x7d,
+  0x09,
+  0x05,
+  0x05,
+  0x79
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_4 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_4,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_5 [5] = {
+  0x38,
+  0x44,
+  0x44,
+  0x38,
+  0x44
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_5 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_5,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_6 [5] = {
+  0x7e,
+  0x01,
+  0x29,
+  0x2e,
+  0x10
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_6 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_6,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_7 [5] = {
+  0x30,
+  0x4a,
+  0x4d,
+  0x49,
+  0x30
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_7 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_7,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_8 [5] = {
+  0x60,
+  0x50,
+  0x48,
+  0x50,
+  0x60
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_8 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_8,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_9 [5] = {
+  0x1e,
+  0x04,
+  0x04,
+  0x38,
+  0x40
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_9 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_9,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_10 [5] = {
+  0x3e,
+  0x49,
+  0x49,
+  0x49,
+  0x3e
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_10 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_10,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_11 [5] = {
+  0x62,
+  0x14,
+  0x08,
+  0x10,
+  0x60
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_11 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_11,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_12 [5] = {
+  0x40,
+  0x3c,
+  0x20,
+  0x20,
+  0x1c
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_12 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_12,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_13 [5] = {
+  0x08,
+  0x7c,
+  0x04,
+  0x7c,
+  0x02
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_13 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_13,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_14 [5] = {
+  0x38,
+  0x44,
+  0x44,
+  0x3c,
+  0x04
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_14 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_14,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_15 [5] = {
+  0x41,
+  0x63,
+  0x55,
+  0x49,
+  0x41
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_15 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_15,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_16 [5] = {
+  0x10,
+  0x08,
+  0x78,
+  0x08,
+  0x04
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_16 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_16,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_17 [5] = {
+  0x18,
+  0x24,
+  0x7e,
+  0x24,
+  0x18
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_17 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_17,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_18 [5] = {
+  0x5e,
+  0x61,
+  0x01,
+  0x61,
+  0x5e
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_18 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_18,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_19 [5] = {
+  0x78,
+  0x14,
+  0x15,
+  0x14,
+  0x78
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_19 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_19,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_20 [5] = {
+  0x38,
+  0x44,
+  0x45,
+  0x3c,
+  0x40
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_20 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_20,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_21 [5] = {
+  0x78,
+  0x15,
+  0x14,
+  0x15,
+  0x78
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_21 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_21,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_22 [5] = {
+  0x38,
+  0x45,
+  0x44,
+  0x3d,
+  0x40
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_22 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_22,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_23 [5] = {
+  0x3c,
+  0x43,
+  0x42,
+  0x43,
+  0x3c
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_23 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_23,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_24 [5] = {
+  0x38,
+  0x45,
+  0x44,
+  0x45,
+  0x38
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_24 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_24,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_25 [5] = {
+  0x3c,
+  0x41,
+  0x40,
+  0x41,
+  0x3c
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_25 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_25,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_26 [5] = {
+  0x38,
+  0x42,
+  0x40,
+  0x42,
+  0x38
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_26 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_26,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_27 [5] = {
+  0x08,
+  0x08,
+  0x2a,
+  0x1c,
+  0x08
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_27 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_27,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_28 [5] = {
+  0x20,
+  0x7e,
+  0x02,
+  0x02,
+  0x02
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_28 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_28,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_29 [5] = {
+  0x12,
+  0x19,
+  0x15,
+  0x12,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_29 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_29,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_30 [5] = {
+  0x48,
+  0x7e,
+  0x49,
+  0x41,
+  0x42
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_30 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_30,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_31 [5] = {
+  0x01,
+  0x12,
+  0x7c,
+  0x12,
+  0x01
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_31 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_31,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_32 [5] = {
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_32 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_32,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_33 [5] = {
+  0x00,
+  0x5f,
+  0x00,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_33 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_33,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_34 [5] = {
+  0x00,
+  0x03,
+  0x00,
+  0x03,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_34 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_34,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_35 [5] = {
+  0x14,
+  0x7f,
+  0x14,
+  0x7f,
+  0x14
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_35 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_35,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_36 [5] = {
+  0x24,
+  0x2a,
+  0x7f,
+  0x2a,
+  0x12
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_36 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_36,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_37 [5] = {
+  0x23,
+  0x13,
+  0x08,
+  0x64,
+  0x62
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_37 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_37,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_38 [5] = {
+  0x36,
+  0x49,
+  0x56,
+  0x20,
+  0x50
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_38 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_38,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_39 [5] = {
+  0x00,
+  0x0b,
+  0x07,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_39 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_39,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_40 [5] = {
+  0x00,
+  0x00,
+  0x3e,
+  0x41,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_40 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_40,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_41 [5] = {
+  0x00,
+  0x41,
+  0x3e,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_41 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_41,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_42 [5] = {
+  0x08,
+  0x2a,
+  0x1c,
+  0x2a,
+  0x08
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_42 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_42,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_43 [5] = {
+  0x08,
+  0x08,
+  0x3e,
+  0x08,
+  0x08
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_43 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_43,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_44 [5] = {
+  0x00,
+  0x58,
+  0x38,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_44 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_44,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_45 [5] = {
+  0x08,
+  0x08,
+  0x08,
+  0x08,
+  0x08
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_45 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_45,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_46 [5] = {
+  0x00,
+  0x30,
+  0x30,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_46 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_46,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_47 [5] = {
+  0x20,
+  0x10,
+  0x08,
+  0x04,
+  0x02
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_47 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_47,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_48 [5] = {
+  0x3e,
+  0x51,
+  0x49,
+  0x45,
+  0x3e
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_48 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_48,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_49 [5] = {
+  0x00,
+  0x42,
+  0x7f,
+  0x40,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_49 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_49,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_50 [5] = {
+  0x62,
+  0x51,
+  0x49,
+  0x49,
+  0x46
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_50 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_50,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_51 [5] = {
+  0x22,
+  0x41,
+  0x49,
+  0x49,
+  0x36
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_51 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_51,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_52 [5] = {
+  0x18,
+  0x14,
+  0x12,
+  0x7f,
+  0x10
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_52 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_52,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_53 [5] = {
+  0x27,
+  0x45,
+  0x45,
+  0x45,
+  0x39
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_53 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_53,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_54 [5] = {
+  0x3c,
+  0x4a,
+  0x49,
+  0x49,
+  0x30
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_54 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_54,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_55 [5] = {
+  0x01,
+  0x71,
+  0x09,
+  0x05,
+  0x03
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_55 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_55,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_56 [5] = {
+  0x36,
+  0x49,
+  0x49,
+  0x49,
+  0x36
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_56 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_56,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_57 [5] = {
+  0x06,
+  0x49,
+  0x49,
+  0x29,
+  0x1e
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_57 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_57,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_58 [5] = {
+  0x00,
+  0x36,
+  0x36,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_58 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_58,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_59 [5] = {
+  0x00,
+  0x5b,
+  0x3b,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_59 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_59,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_60 [5] = {
+  0x00,
+  0x08,
+  0x14,
+  0x22,
+  0x41
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_60 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_60,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_61 [5] = {
+  0x14,
+  0x14,
+  0x14,
+  0x14,
+  0x14
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_61 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_61,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_62 [5] = {
+  0x41,
+  0x22,
+  0x14,
+  0x08,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_62 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_62,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_63 [5] = {
+  0x02,
+  0x01,
+  0x51,
+  0x09,
+  0x06
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_63 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_63,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_64 [5] = {
+  0x3e,
+  0x41,
+  0x5d,
+  0x55,
+  0x1e
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_64 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_64,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_65 [5] = {
+  0x7e,
+  0x09,
+  0x09,
+  0x09,
+  0x7e
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_65 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_65,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_66 [5] = {
+  0x7e,
+  0x49,
+  0x49,
+  0x49,
+  0x36
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_66 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_66,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_67 [5] = {
+  0x3e,
+  0x41,
+  0x41,
+  0x41,
+  0x22
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_67 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_67,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_68 [5] = {
+  0x7f,
+  0x41,
+  0x41,
+  0x41,
+  0x3e
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_68 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_68,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_69 [5] = {
+  0x7f,
+  0x49,
+  0x49,
+  0x49,
+  0x41
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_69 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_69,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_70 [5] = {
+  0x7f,
+  0x09,
+  0x09,
+  0x09,
+  0x01
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_70 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_70,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_71 [5] = {
+  0x3e,
+  0x41,
+  0x41,
+  0x51,
+  0x32
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_71 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_71,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_72 [5] = {
+  0x7f,
+  0x08,
+  0x08,
+  0x08,
+  0x7f
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_72 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_72,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_73 [5] = {
+  0x00,
+  0x41,
+  0x7f,
+  0x41,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_73 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_73,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_74 [5] = {
+  0x20,
+  0x40,
+  0x40,
+  0x40,
+  0x3f
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_74 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_74,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_75 [5] = {
+  0x7f,
+  0x08,
+  0x14,
+  0x22,
+  0x41
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_75 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_75,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_76 [5] = {
+  0x7f,
+  0x40,
+  0x40,
+  0x40,
+  0x40
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_76 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_76,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_77 [5] = {
+  0x7f,
+  0x02,
+  0x0c,
+  0x02,
+  0x7f
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_77 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_77,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_78 [5] = {
+  0x7f,
+  0x04,
+  0x08,
+  0x10,
+  0x7f
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_78 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_78,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_79 [5] = {
+  0x3e,
+  0x41,
+  0x41,
+  0x41,
+  0x3e
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_79 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_79,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_80 [5] = {
+  0x7f,
+  0x09,
+  0x09,
+  0x09,
+  0x06
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_80 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_80,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_81 [5] = {
+  0x3e,
+  0x41,
+  0x51,
+  0x21,
+  0x5e
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_81 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_81,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_82 [5] = {
+  0x7f,
+  0x09,
+  0x19,
+  0x29,
+  0x46
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_82 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_82,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_83 [5] = {
+  0x26,
+  0x49,
+  0x49,
+  0x49,
+  0x32
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_83 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_83,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_84 [5] = {
+  0x01,
+  0x01,
+  0x7f,
+  0x01,
+  0x01
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_84 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_84,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_85 [5] = {
+  0x3f,
+  0x40,
+  0x40,
+  0x40,
+  0x3f
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_85 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_85,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_86 [5] = {
+  0x07,
+  0x18,
+  0x60,
+  0x18,
+  0x07
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_86 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_86,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_87 [5] = {
+  0x7f,
+  0x20,
+  0x18,
+  0x20,
+  0x7f
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_87 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_87,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_88 [5] = {
+  0x63,
+  0x14,
+  0x08,
+  0x14,
+  0x63
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_88 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_88,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_89 [5] = {
+  0x03,
+  0x04,
+  0x78,
+  0x04,
+  0x03
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_89 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_89,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_90 [5] = {
+  0x61,
+  0x51,
+  0x49,
+  0x45,
+  0x43
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_90 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_90,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_91 [5] = {
+  0x00,
+  0x00,
+  0x7f,
+  0x41,
+  0x41
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_91 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_91,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_92 [5] = {
+  0x02,
+  0x04,
+  0x08,
+  0x10,
+  0x20
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_92 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_92,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_93 [5] = {
+  0x41,
+  0x41,
+  0x7f,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_93 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_93,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_94 [5] = {
+  0x04,
+  0x02,
+  0x7f,
+  0x02,
+  0x04
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_94 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_94,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_95 [5] = {
+  0x40,
+  0x40,
+  0x40,
+  0x40,
+  0x40
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_95 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_95,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_96 [5] = {
+  0x00,
+  0x07,
+  0x0b,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_96 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_96,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_97 [5] = {
+  0x38,
+  0x44,
+  0x44,
+  0x3c,
+  0x40
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_97 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_97,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_98 [5] = {
+  0x7f,
+  0x48,
+  0x44,
+  0x44,
+  0x38
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_98 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_98,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_99 [5] = {
+  0x38,
+  0x44,
+  0x44,
+  0x44,
+  0x44
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_99 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_99,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_100 [5] = {
+  0x38,
+  0x44,
+  0x44,
+  0x48,
+  0x7f
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_100 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_100,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_101 [5] = {
+  0x38,
+  0x54,
+  0x54,
+  0x54,
+  0x08
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_101 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_101,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_102 [5] = {
+  0x08,
+  0x7e,
+  0x09,
+  0x02,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_102 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_102,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_103 [5] = {
+  0x08,
+  0x14,
+  0x54,
+  0x54,
+  0x3c
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_103 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_103,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_104 [5] = {
+  0x7f,
+  0x08,
+  0x04,
+  0x04,
+  0x78
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_104 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_104,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_105 [5] = {
+  0x00,
+  0x44,
+  0x7d,
+  0x40,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_105 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_105,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_106 [5] = {
+  0x20,
+  0x40,
+  0x44,
+  0x3d,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_106 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_106,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_107 [5] = {
+  0x00,
+  0x7f,
+  0x10,
+  0x28,
+  0x44
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_107 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_107,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_108 [5] = {
+  0x00,
+  0x41,
+  0x7f,
+  0x40,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_108 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_108,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_109 [5] = {
+  0x78,
+  0x04,
+  0x18,
+  0x04,
+  0x78
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_109 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_109,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_110 [5] = {
+  0x7c,
+  0x08,
+  0x04,
+  0x04,
+  0x78
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_110 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_110,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_111 [5] = {
+  0x38,
+  0x44,
+  0x44,
+  0x44,
+  0x38
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_111 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_111,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_112 [5] = {
+  0x7c,
+  0x14,
+  0x24,
+  0x24,
+  0x18
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_112 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_112,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_113 [5] = {
+  0x18,
+  0x24,
+  0x14,
+  0x7c,
+  0x40
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_113 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_113,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_114 [5] = {
+  0x00,
+  0x7c,
+  0x08,
+  0x04,
+  0x04
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_114 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_114,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_115 [5] = {
+  0x48,
+  0x54,
+  0x54,
+  0x54,
+  0x20
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_115 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_115,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_116 [5] = {
+  0x04,
+  0x3e,
+  0x44,
+  0x20,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_116 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_116,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_117 [5] = {
+  0x3c,
+  0x40,
+  0x40,
+  0x20,
+  0x7c
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_117 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_117,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_118 [5] = {
+  0x1c,
+  0x20,
+  0x40,
+  0x20,
+  0x1c
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_118 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_118,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_119 [5] = {
+  0x3c,
+  0x40,
+  0x30,
+  0x40,
+  0x3c
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_119 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_119,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_120 [5] = {
+  0x44,
+  0x28,
+  0x10,
+  0x28,
+  0x44
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_120 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_120,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_121 [5] = {
+  0x04,
+  0x48,
+  0x30,
+  0x08,
+  0x04
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_121 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_121,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_122 [5] = {
+  0x44,
+  0x64,
+  0x54,
+  0x4c,
+  0x44
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_122 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_122,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_123 [5] = {
+  0x00,
+  0x08,
+  0x36,
+  0x41,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_123 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_123,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_124 [5] = {
+  0x00,
+  0x00,
+  0x77,
+  0x00,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_124 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_124,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_125 [5] = {
+  0x00,
+  0x41,
+  0x36,
+  0x08,
+  0x00
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_125 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_125,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_126 [5] = {
+  0x08,
+  0x04,
+  0x08,
+  0x10,
+  0x08
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_126 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_126,
+};
+
+const unsigned char bitmap_hp_fixed_5_7_127 [5] = {
+  0x2a,
+  0x55,
+  0x2a,
+  0x55,
+  0x2a
+};
+struct disp_font_glyph glyph_hp_fixed_5_7_127 = {
+  {5,7,0,0},
+  5, 0, bitmap_hp_fixed_5_7_127,
+};
+
+const struct disp_font_base font_hcms29xx_base = {
+  1,               /* trans */
+  {5, 7, 0, -1},  /* fbb w, h, x, y */
+  7, 0,            /* ascent, descent */
+  0,               /* default_char */
+  {&glyph_hp_fixed_5_7_0,
+  &glyph_hp_fixed_5_7_1,
+  &glyph_hp_fixed_5_7_2,
+  &glyph_hp_fixed_5_7_3,
+  &glyph_hp_fixed_5_7_4,
+  &glyph_hp_fixed_5_7_5,
+  &glyph_hp_fixed_5_7_6,
+  &glyph_hp_fixed_5_7_7,
+  &glyph_hp_fixed_5_7_8,
+  &glyph_hp_fixed_5_7_9,
+  &glyph_hp_fixed_5_7_10,
+  &glyph_hp_fixed_5_7_11,
+  &glyph_hp_fixed_5_7_12,
+  &glyph_hp_fixed_5_7_13,
+  &glyph_hp_fixed_5_7_14,
+  &glyph_hp_fixed_5_7_15,
+  &glyph_hp_fixed_5_7_16,
+  &glyph_hp_fixed_5_7_17,
+  &glyph_hp_fixed_5_7_18,
+  &glyph_hp_fixed_5_7_19,
+  &glyph_hp_fixed_5_7_20,
+  &glyph_hp_fixed_5_7_21,
+  &glyph_hp_fixed_5_7_22,
+  &glyph_hp_fixed_5_7_23,
+  &glyph_hp_fixed_5_7_24,
+  &glyph_hp_fixed_5_7_25,
+  &glyph_hp_fixed_5_7_26,
+  &glyph_hp_fixed_5_7_27,
+  &glyph_hp_fixed_5_7_28,
+  &glyph_hp_fixed_5_7_29,
+  &glyph_hp_fixed_5_7_30,
+  &glyph_hp_fixed_5_7_31,
+  &glyph_hp_fixed_5_7_32,
+  &glyph_hp_fixed_5_7_33,
+  &glyph_hp_fixed_5_7_34,
+  &glyph_hp_fixed_5_7_35,
+  &glyph_hp_fixed_5_7_36,
+  &glyph_hp_fixed_5_7_37,
+  &glyph_hp_fixed_5_7_38,
+  &glyph_hp_fixed_5_7_39,
+  &glyph_hp_fixed_5_7_40,
+  &glyph_hp_fixed_5_7_41,
+  &glyph_hp_fixed_5_7_42,
+  &glyph_hp_fixed_5_7_43,
+  &glyph_hp_fixed_5_7_44,
+  &glyph_hp_fixed_5_7_45,
+  &glyph_hp_fixed_5_7_46,
+  &glyph_hp_fixed_5_7_47,
+  &glyph_hp_fixed_5_7_48,
+  &glyph_hp_fixed_5_7_49,
+  &glyph_hp_fixed_5_7_50,
+  &glyph_hp_fixed_5_7_51,
+  &glyph_hp_fixed_5_7_52,
+  &glyph_hp_fixed_5_7_53,
+  &glyph_hp_fixed_5_7_54,
+  &glyph_hp_fixed_5_7_55,
+  &glyph_hp_fixed_5_7_56,
+  &glyph_hp_fixed_5_7_57,
+  &glyph_hp_fixed_5_7_58,
+  &glyph_hp_fixed_5_7_59,
+  &glyph_hp_fixed_5_7_60,
+  &glyph_hp_fixed_5_7_61,
+  &glyph_hp_fixed_5_7_62,
+  &glyph_hp_fixed_5_7_63,
+  &glyph_hp_fixed_5_7_64,
+  &glyph_hp_fixed_5_7_65,
+  &glyph_hp_fixed_5_7_66,
+  &glyph_hp_fixed_5_7_67,
+  &glyph_hp_fixed_5_7_68,
+  &glyph_hp_fixed_5_7_69,
+  &glyph_hp_fixed_5_7_70,
+  &glyph_hp_fixed_5_7_71,
+  &glyph_hp_fixed_5_7_72,
+  &glyph_hp_fixed_5_7_73,
+  &glyph_hp_fixed_5_7_74,
+  &glyph_hp_fixed_5_7_75,
+  &glyph_hp_fixed_5_7_76,
+  &glyph_hp_fixed_5_7_77,
+  &glyph_hp_fixed_5_7_78,
+  &glyph_hp_fixed_5_7_79,
+  &glyph_hp_fixed_5_7_80,
+  &glyph_hp_fixed_5_7_81,
+  &glyph_hp_fixed_5_7_82,
+  &glyph_hp_fixed_5_7_83,
+  &glyph_hp_fixed_5_7_84,
+  &glyph_hp_fixed_5_7_85,
+  &glyph_hp_fixed_5_7_86,
+  &glyph_hp_fixed_5_7_87,
+  &glyph_hp_fixed_5_7_88,
+  &glyph_hp_fixed_5_7_89,
+  &glyph_hp_fixed_5_7_90,
+  &glyph_hp_fixed_5_7_91,
+  &glyph_hp_fixed_5_7_92,
+  &glyph_hp_fixed_5_7_93,
+  &glyph_hp_fixed_5_7_94,
+  &glyph_hp_fixed_5_7_95,
+  &glyph_hp_fixed_5_7_96,
+  &glyph_hp_fixed_5_7_97,
+  &glyph_hp_fixed_5_7_98,
+  &glyph_hp_fixed_5_7_99,
+  &glyph_hp_fixed_5_7_100,
+  &glyph_hp_fixed_5_7_101,
+  &glyph_hp_fixed_5_7_102,
+  &glyph_hp_fixed_5_7_103,
+  &glyph_hp_fixed_5_7_104,
+  &glyph_hp_fixed_5_7_105,
+  &glyph_hp_fixed_5_7_106,
+  &glyph_hp_fixed_5_7_107,
+  &glyph_hp_fixed_5_7_108,
+  &glyph_hp_fixed_5_7_109,
+  &glyph_hp_fixed_5_7_110,
+  &glyph_hp_fixed_5_7_111,
+  &glyph_hp_fixed_5_7_112,
+  &glyph_hp_fixed_5_7_113,
+  &glyph_hp_fixed_5_7_114,
+  &glyph_hp_fixed_5_7_115,
+  &glyph_hp_fixed_5_7_116,
+  &glyph_hp_fixed_5_7_117,
+  &glyph_hp_fixed_5_7_118,
+  &glyph_hp_fixed_5_7_119,
+  &glyph_hp_fixed_5_7_120,
+  &glyph_hp_fixed_5_7_121,
+  &glyph_hp_fixed_5_7_122,
+  &glyph_hp_fixed_5_7_123,
+  &glyph_hp_fixed_5_7_124,
+  &glyph_hp_fixed_5_7_125,
+  &glyph_hp_fixed_5_7_126,
+  &glyph_hp_fixed_5_7_127,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+   NULL}
+};
Index: bsps/shared/dev/display/font_hcms29xx.h
===================================================================
--- bsps/shared/dev/display/font_hcms29xx.h	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/display/font_hcms29xx.h	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,36 @@
+/*===============================================================*\
+| Project: display driver for HCMS29xx                            |
++-----------------------------------------------------------------+
+| File: font_hcms29xx.h                                           |
++-----------------------------------------------------------------+
+|                    Copyright (c) 2008                           |
+|                    Embedded Brains GmbH                         |
+|                    Obere Lagerstr. 30                           |
+|                    D-82178 Puchheim                             |
+|                    Germany                                      |
+|                    rtems@embedded-brains.de                     |
++-----------------------------------------------------------------+
+| The license and distribution terms for this file may be         |
+| found in the file LICENSE in this distribution or at            |
+| http://www.rtems.org/license/LICENSE.                           |
++-----------------------------------------------------------------+
+| This file declares the 5x7 bit font used in disp_hcms29xx       |
+\*===============================================================*/
+
+#ifndef FONT_HCMS29XX_H
+#define FONT_HCMS29XX_H
+
+#include "disp_fonts.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct disp_font_base font_hcms29xx_base;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not defined FONT_HCMS29XX_H */
Index: bsps/shared/dev/flash/am29lv160.c
===================================================================
--- bsps/shared/dev/flash/am29lv160.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/flash/am29lv160.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,473 @@
+/*
+ * RTEMS Project (http://www.rtems.org/)
+ *
+ * Copyright 2007 Chris Johns (chrisj@rtems.org)
+ */
+/**
+ * Provide flash support for the AM26LV160 device.
+ *
+ * The M29W160D is the same device.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <rtems.h>
+
+#include <libchip/am29lv160.h>
+
+#ifndef AM26LV160_ERROR_TRACE
+#define AM26LV160_ERROR_TRACE (0)
+#endif
+
+/**
+ * Boot blocks at the top
+ */
+const rtems_fdisk_segment_desc rtems_am29lv160t_segments[4] =
+{
+  {
+    .count =   31,
+    .segment = 0,
+    .offset =  0x00000000,
+    .size =    RTEMS_FDISK_KBYTES (64)
+  },
+  {
+    .count =   1,
+    .segment = 31,
+    .offset =  0x001f0000,
+    .size =    RTEMS_FDISK_KBYTES (32)
+  },
+  {
+    .count =   2,
+    .segment = 32,
+    .offset =  0x001f8000,
+    .size =    RTEMS_FDISK_KBYTES (8)
+  },
+  {
+    .count =   1,
+    .segment = 34,
+    .offset =  0x001fc000,
+    .size =    RTEMS_FDISK_KBYTES (16)
+  }
+};
+
+/**
+ * Boot blocks at the bottom.
+ */
+const rtems_fdisk_segment_desc rtems_am29lv160b_segments[] =
+{
+  {
+    .count =   1,
+    .segment = 0,
+    .offset =  0x00000000,
+    .size =    RTEMS_FDISK_KBYTES (16)
+  },
+  {
+  .  count =   2,
+    .segment = 1,
+    .offset =  0x00004000,
+    .size =    RTEMS_FDISK_KBYTES (8)
+  },
+  {
+    .count =   1,
+    .segment = 3,
+    .offset =  0x00008000,
+    .size =    RTEMS_FDISK_KBYTES (32)
+  },
+  {
+    .count =   31,
+    .segment = 4,
+    .offset =  0x00010000,
+    .size =    RTEMS_FDISK_KBYTES (64)
+  }
+};
+
+static int
+rtems_am29lv160_blank (const rtems_fdisk_segment_desc* sd,
+                       uint32_t                        device,
+                       uint32_t                        segment,
+                       uint32_t                        offset,
+                       uint32_t                        size)
+{
+  const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
+  volatile uint8_t*             seg_8 = ac->base;
+  volatile uint32_t*            seg_32;
+  uint32_t                      count;
+
+  offset += sd->offset + (segment - sd->segment) * sd->size;
+
+  seg_8 += offset;
+
+  count = offset & (sizeof (uint32_t) - 1);
+  size -= count;
+
+  while (count--)
+    if (*seg_8++ != 0xff)
+    {
+#if AM26LV160_ERROR_TRACE
+      printf ("AM26LV160: blank check error: %p = 0x%02x\n",
+              seg_8 - 1, *(seg_8 - 1));
+#endif
+      return EIO;
+    }
+
+  seg_32 = (volatile uint32_t*) seg_8;
+
+  count = size  / sizeof (uint32_t);
+  size -= count * sizeof (uint32_t);
+
+  while (count--)
+    if (*seg_32++ != 0xffffffff)
+    {
+#if AM26LV160_ERROR_TRACE
+      printf ("AM26LV160: blank check error: %p = 0x%08lx\n",
+              seg_32 - 1, *(seg_32 - 1));
+#endif
+      return EIO;
+    }
+
+  seg_8 = (volatile uint8_t*) seg_32;
+
+  while (size--)
+    if (*seg_8++ != 0xff)
+    {
+#if AM26LV160_ERROR_TRACE
+      printf ("AM26LV160: blank check error: %p = 0x%02x\n",
+              seg_8 - 1, *(seg_8 - 1));
+#endif
+      return EIO;
+    }
+
+  return 0;
+}
+
+static int
+rtems_am29lv160_verify (const rtems_fdisk_segment_desc* sd,
+                        uint32_t                        device,
+                        uint32_t                        segment,
+                        uint32_t                        offset,
+                        const void*                     buffer,
+                        uint32_t                        size)
+{
+  const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
+  const uint8_t*                addr = ac->base;
+
+  addr += (sd->offset + (segment - sd->segment) * sd->size) + offset;
+
+  if (memcmp (addr, buffer, size) != 0)
+    return EIO;
+
+  return 0;
+}
+
+static int
+rtems_am29lv160_toggle_wait_8 (volatile uint8_t* status)
+{
+  while (1)
+  {
+    volatile uint8_t status1 = *status;
+    volatile uint8_t status2 = *status;
+
+    if (((status1 ^ status2) & (1 << 6)) == 0)
+      return 0;
+
+    if ((status1 & (1 << 5)) != 0)
+    {
+      status1 = *status;
+      status2 = *status;
+
+      if (((status1 ^ status2) & (1 << 6)) == 0)
+        return 0;
+
+#if AM26LV160_ERROR_TRACE
+      printf ("AM26LV160: error bit detected: %p = 0x%04x\n",
+              status, status1);
+#endif
+
+      *status = 0xf0;
+      return EIO;
+    }
+  }
+}
+
+static int
+rtems_am29lv160_toggle_wait_16 (volatile uint16_t* status)
+{
+  while (1)
+  {
+    volatile uint16_t status1 = *status;
+    volatile uint16_t status2 = *status;
+
+    if (((status1 ^ status2) & (1 << 6)) == 0)
+      return 0;
+
+    if ((status1 & (1 << 5)) != 0)
+    {
+      status1 = *status;
+      status2 = *status;
+
+      if (((status1 ^ status2) & (1 << 6)) == 0)
+        return 0;
+
+#if AM26LV160_ERROR_TRACE
+      printf ("AM26LV160: error bit detected: %p = 0x%04x/0x%04x\n",
+              status, status1, status2);
+#endif
+
+      *status = 0xf0;
+      return EIO;
+    }
+  }
+}
+
+static int
+rtems_am29lv160_write_data_8 (volatile uint8_t* base,
+                              uint32_t          offset,
+                              const uint8_t*    data,
+                              uint32_t          size)
+{
+  volatile uint8_t*     seg = base + offset;
+  rtems_interrupt_level level;
+
+  /*
+   * Issue a reset.
+   */
+  *base = 0xf0;
+
+  while (size)
+  {
+    rtems_interrupt_disable (level);
+    *(base + 0xaaa) = 0xaa;
+    *(base + 0x555) = 0x55;
+    *(base + 0xaaa) = 0xa0;
+    *seg = *data++;
+    rtems_interrupt_enable (level);
+    if (rtems_am29lv160_toggle_wait_8 (seg++) != 0)
+      return EIO;
+    size--;
+  }
+
+  /*
+   * Issue a reset.
+   */
+  *base = 0xf0;
+
+  return 0;
+}
+
+static int
+rtems_am29lv160_write_data_16 (volatile uint16_t* base,
+                               uint32_t           offset,
+                               const uint16_t*    data,
+                               uint32_t           size)
+{
+  volatile uint16_t*    seg = base + (offset / 2);
+  rtems_interrupt_level level;
+
+  size /= 2;
+
+  /*
+   * Issue a reset.
+   */
+  *base = 0xf0;
+
+  while (size)
+  {
+    rtems_interrupt_disable (level);
+    *(base + 0x555) = 0xaa;
+    *(base + 0x2aa) = 0x55;
+    *(base + 0x555) = 0xa0;
+    *seg = *data++;
+    rtems_interrupt_enable (level);
+    if (rtems_am29lv160_toggle_wait_16 (seg++) != 0)
+      return EIO;
+    size--;
+  }
+
+  /*
+   * Issue a reset.
+   */
+  *base = 0xf0;
+
+  return 0;
+}
+
+static int
+rtems_am29lv160_read (const rtems_fdisk_segment_desc* sd,
+                      uint32_t                        device,
+                      uint32_t                        segment,
+                      uint32_t                        offset,
+                      void*                           buffer,
+                      uint32_t                        size)
+{
+  unsigned char* addr =
+    rtems_am29lv160_configuration[device].base +
+    sd->offset + ((segment - sd->segment) * sd->size) + offset;
+  memcpy (buffer, addr, size);
+  return 0;
+}
+
+/*
+ * @todo Fix the odd alignment and odd sizes.
+ */
+static int
+rtems_am29lv160_write (const rtems_fdisk_segment_desc* sd,
+                       uint32_t                        device,
+                       uint32_t                        segment,
+                       uint32_t                        offset,
+                       const void*                     buffer,
+                       uint32_t                        size)
+{
+  int ret = rtems_am29lv160_verify (sd, device, segment, offset, buffer, size);
+
+  if (ret != 0)
+  {
+    const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
+    uint32_t                      soffset;
+
+    soffset = offset + sd->offset + ((segment - sd->segment) * sd->size);
+
+    if (offset & 1)
+      printf ("rtems_am29lv160_write: offset is odd\n");
+
+    if (size & 1)
+      printf ("rtems_am29lv160_write: size is odd\n");
+
+    if (ac->bus_8bit)
+      ret = rtems_am29lv160_write_data_8 (ac->base, soffset, buffer, size);
+    else
+      ret = rtems_am29lv160_write_data_16 (ac->base, soffset, buffer, size);
+
+    /*
+     * Verify the write worked.
+     */
+    if (ret == 0)
+    {
+      ret = rtems_am29lv160_verify (sd, device, segment, offset, buffer, size);
+#if AM26LV160_ERROR_TRACE
+      if (ret)
+        printf ("AM26LV160: verify failed: %ld-%ld-%08lx: s=%ld\n",
+                device, segment, offset, size);
+#endif
+    }
+  }
+
+  return ret;
+}
+
+static int
+rtems_am29lv160_erase (const rtems_fdisk_segment_desc* sd,
+                       uint32_t                        device,
+                       uint32_t                        segment)
+{
+  int ret = rtems_am29lv160_blank (sd, device, segment, 0, sd->size);
+  if (ret != 0)
+  {
+    const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
+    uint32_t                      offset;
+    rtems_interrupt_level         level;
+
+    offset = sd->offset + ((segment - sd->segment) * sd->size);
+
+    if (ac->bus_8bit)
+    {
+      volatile uint8_t* base = ac->base;
+      volatile uint8_t* seg  = base + offset;
+
+      /*
+       * Issue a reset.
+       */
+      rtems_interrupt_disable (level);
+      *base = 0xf0;
+      *(base + 0xaaa) = 0xaa;
+      *(base + 0x555) = 0x55;
+      *(base + 0xaaa) = 0x80;
+      *(base + 0xaaa) = 0xaa;
+      *(base + 0x555) = 0x55;
+      *seg = 0x30;
+      rtems_interrupt_enable (level);
+
+      ret = rtems_am29lv160_toggle_wait_8 (seg);
+
+      /*
+       * Issue a reset.
+       */
+      *base = 0xf0;
+    }
+    else
+    {
+      volatile uint16_t* base = ac->base;
+      volatile uint16_t* seg  = base + (offset / 2);
+
+      /*
+       * Issue a reset.
+       */
+      rtems_interrupt_disable (level);
+      *base = 0xf0;
+      *(base + 0x555) = 0xaa;
+      *(base + 0x2aa) = 0x55;
+      *(base + 0x555) = 0x80;
+      *(base + 0x555) = 0xaa;
+      *(base + 0x2aa) = 0x55;
+      *seg = 0x30;
+      rtems_interrupt_enable (level);
+
+      ret = rtems_am29lv160_toggle_wait_16 (seg);
+
+      /*
+       * Issue a reset.
+       */
+      *base = 0xf0;
+    }
+
+    /*
+     * Check the erase worked.
+     */
+    if (ret == 0)
+    {
+      ret = rtems_am29lv160_blank (sd, device, segment, 0, sd->size);
+#if AM26LV160_ERROR_TRACE
+      if (ret)
+        printf ("AM26LV160: erase failed: %ld-%ld\n", device, segment);
+#endif
+    }
+  }
+
+  return ret;
+}
+
+static int
+rtems_am29lv160_erase_device (const rtems_fdisk_device_desc* dd,
+                              uint32_t                       device)
+{
+  uint32_t segment;
+
+  for (segment = 0; segment < dd->segment_count; segment++)
+  {
+    uint32_t seg_segment;
+
+    for (seg_segment = 0;
+         seg_segment < dd->segments[segment].count;
+         seg_segment++)
+    {
+      int ret = rtems_am29lv160_erase (&dd->segments[segment],
+                                       device,
+                                       segment + seg_segment);
+      if (ret)
+        return ret;
+    }
+  }
+
+  return 0;
+}
+
+const rtems_fdisk_driver_handlers rtems_am29lv160_handlers =
+{
+  .read =         rtems_am29lv160_read,
+  .write =        rtems_am29lv160_write,
+  .blank =        rtems_am29lv160_blank,
+  .verify =       rtems_am29lv160_verify,
+  .erase =        rtems_am29lv160_erase,
+  .erase_device = rtems_am29lv160_erase_device
+};
Index: bsps/shared/dev/i2c/i2c-2b-eeprom.c
===================================================================
--- bsps/shared/dev/i2c/i2c-2b-eeprom.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/i2c/i2c-2b-eeprom.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,177 @@
+/* Trivial i2c driver for reading "2-byte eeproms".
+ * On 'open' the read-pointer is reset to 0, subsequent
+ * read operations slurp data from there...
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ *     Till Straumann <strauman@slac.stanford.edu>, 2005,
+ * 	   Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ *     the Stanford Linear Accelerator Center, Stanford University,
+ * 	   under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software.  Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+
+#include <rtems.h>
+#include <rtems/libi2c.h>
+
+#include <libchip/i2c-2b-eeprom.h>
+#include <rtems/libio.h>
+
+#define EEPROM_PG_SZ	32
+#define ALGN(x)	(((uint32_t)(x) + EEPROM_PG_SZ) & ~(EEPROM_PG_SZ-1))
+
+static rtems_status_code
+send_file_ptr (rtems_device_minor_number minor, unsigned pos, int tout)
+{
+  int sc;
+  unsigned char bytes[2];
+
+  bytes[0] = (pos >> 8) & 0xff;
+  bytes[1] = (pos) & 0xff;
+
+  /* poll addressing the next page; if 'tout' is <=0 we only try once
+   * and return the status. If 'tout' is positive, we try 'tout' times
+   * and return RTEMS_TIMEOUT if it didnt work
+   */
+  while ((sc = rtems_libi2c_start_write_bytes (minor, bytes, 2)) < 0) {
+    if (--tout <= 0)
+      return tout ? -sc : RTEMS_TIMEOUT;
+    rtems_task_wake_after (1);
+  }
+  return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code
+i2c_2b_eeprom_write (rtems_device_major_number major,
+                     rtems_device_minor_number minor, void *arg)
+{
+  rtems_libio_rw_args_t *rwargs = arg;
+  unsigned off = rwargs->offset;
+  int cnt = rwargs->count;
+  unsigned char *buf = (unsigned char *)rwargs->buffer;
+  int sc;
+  unsigned end;
+  int l;
+
+  if (cnt <= 0)
+    return RTEMS_SUCCESSFUL;
+
+  if ((sc = send_file_ptr (minor, off, 0)))
+    return sc;
+
+  do {
+    /* write up to next page boundary */
+    end = ALGN (off);
+    l = end - off;
+    if (l > cnt)
+      l = cnt;
+
+    sc = rtems_libi2c_write_bytes (minor, buf, l);
+    if (sc < 0)
+      return -sc;
+
+    sc = rtems_libi2c_send_stop (minor);
+    if (sc)
+      return sc;
+
+    rwargs->bytes_moved += l;
+
+    buf += l;
+    cnt -= l;
+    off += l;
+
+    /* poll addressing the next page */
+    if ((sc = send_file_ptr (minor, off, 100)))
+      return sc;
+
+  } while (cnt > 0);
+
+  return rtems_libi2c_send_stop (minor);
+}
+
+static rtems_status_code
+i2c_2b_eeprom_read (rtems_device_major_number major,
+                    rtems_device_minor_number minor, void *arg)
+{
+  int sc;
+  rtems_libio_rw_args_t *rwargs = arg;
+
+  if (RTEMS_SUCCESSFUL != (sc = send_file_ptr (minor, rwargs->offset, 0)))
+    return -sc;
+
+  sc = rtems_libi2c_start_read_bytes(
+    minor,
+    (unsigned char *)rwargs->buffer,
+    rwargs->count
+  );
+
+  if (sc < 0) {
+    rwargs->bytes_moved = 0;
+    return -sc;
+  }
+  rwargs->bytes_moved = sc;
+
+  return rtems_libi2c_send_stop (minor);
+}
+
+static rtems_driver_address_table myops = {
+  .read_entry =  i2c_2b_eeprom_read,
+  .write_entry = i2c_2b_eeprom_write,
+};
+
+static rtems_libi2c_drv_t my_drv_tbl = {
+  .ops =         &myops,
+  .size =        sizeof (my_drv_tbl),
+};
+
+/* provide a second table for R/O access */
+static rtems_driver_address_table my_ro_ops = {
+  .read_entry =  i2c_2b_eeprom_read,
+};
+
+static rtems_libi2c_drv_t my_ro_drv_tbl = {
+  .ops =         &my_ro_ops,
+  .size =        sizeof (my_ro_drv_tbl),
+};
+
+
+rtems_libi2c_drv_t *i2c_2b_eeprom_driver_descriptor = &my_drv_tbl;
+rtems_libi2c_drv_t *i2c_2b_eeprom_ro_driver_descriptor = &my_ro_drv_tbl;
Index: bsps/shared/dev/i2c/i2c-ds1621.c
===================================================================
--- bsps/shared/dev/i2c/i2c-ds1621.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/i2c/i2c-ds1621.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,128 @@
+/* Trivial i2c driver for the maxim DS1621 temperature sensor;
+ * just implements reading constant conversions with 8-bit
+ * resolution.
+ * Demonstrates the implementation of a i2c high-level driver.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ *     Till Straumann <strauman@slac.stanford.edu>, 2005,
+ * 	   Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ *     the Stanford Linear Accelerator Center, Stanford University,
+ * 	   under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software.  Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+#include <rtems.h>
+#include <rtems/libi2c.h>
+
+#include <libchip/i2c-ds1621.h>
+
+#include <rtems/libio.h>
+
+
+static rtems_status_code
+ds1621_init (rtems_device_major_number major, rtems_device_minor_number minor,
+             void *arg)
+{
+  int sc;
+  unsigned char csr[2] = { DS1621_CMD_CSR_ACCESS, 0 }, cmd;
+
+  /* First start command acquires a lock for the bus */
+
+  /* Initialize; switch continuous conversion on */
+  sc = rtems_libi2c_start_write_bytes (minor, csr, 1);
+  if (sc < 0)
+    return -sc;
+
+  sc = rtems_libi2c_start_read_bytes (minor, csr + 1, 1);
+  if (sc < 0)
+    return -sc;
+
+  csr[1] &= ~DS1621_CSR_1SHOT;
+
+  sc = rtems_libi2c_start_write_bytes (minor, csr, 2);
+  if (sc < 0)
+    return -sc;
+
+  /* Start conversion */
+  cmd = DS1621_CMD_START_CONV;
+
+  sc = rtems_libi2c_start_write_bytes (minor, &cmd, 1);
+  if (sc < 0)
+    return -sc;
+
+  /* sending 'stop' relinquishes the bus mutex -- don't hold it
+   * across system calls!
+   */
+  return rtems_libi2c_send_stop (minor);
+}
+
+static rtems_status_code
+ds1621_read (rtems_device_major_number major, rtems_device_minor_number minor,
+             void *arg)
+{
+  int sc;
+  rtems_libio_rw_args_t *rwargs = arg;
+  unsigned char cmd = DS1621_CMD_READ_TEMP;
+
+  sc = rtems_libi2c_start_write_bytes (minor, &cmd, 1);
+  if (sc < 0)
+    return -sc;
+  if (sc < 1)
+    return RTEMS_IO_ERROR;
+  sc = rtems_libi2c_start_read_bytes(minor, (unsigned char *)rwargs->buffer, 1);
+  if (sc < 0) {
+    rwargs->bytes_moved = 0;
+    return -sc;
+  }
+  rwargs->bytes_moved = 1;
+  return rtems_libi2c_send_stop (minor);
+}
+
+static rtems_driver_address_table myops = {
+  .initialization_entry = ds1621_init,
+  .read_entry =           ds1621_read,
+};
+
+static rtems_libi2c_drv_t my_drv_tbl = {
+  .ops =                  &myops,
+  .size =                 sizeof (my_drv_tbl),
+};
+
+rtems_libi2c_drv_t *i2c_ds1621_driver_descriptor = &my_drv_tbl;
Index: bsps/shared/dev/i2c/i2c-sc620.c
===================================================================
--- bsps/shared/dev/i2c/i2c-sc620.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/i2c/i2c-sc620.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,91 @@
+/**
+ * @file
+ *
+ * @brief I2C Driver for SEMTECH SC620 Octal LED Driver
+ */
+
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Obere Lagerstr. 30
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <libchip/i2c-sc620.h>
+
+#include <rtems/libio.h>
+
+#define SC620_REG_COUNT 10
+
+static rtems_status_code i2c_sc620_write(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void *arg
+)
+{
+  rtems_status_code sc = RTEMS_IO_ERROR;
+  rtems_libio_rw_args_t *rw = arg;
+  unsigned char *buf = (unsigned char *) &rw->buffer[0];
+
+  if (rw->count == 2 && buf[0] < SC620_REG_COUNT) {
+    int rv;
+
+    rv = rtems_libi2c_start_write_bytes(
+      minor, buf, 2
+    );
+    if (rv == 2) {
+      sc = rtems_libi2c_send_stop(minor);
+    }
+  }
+
+  rw->bytes_moved = sc == RTEMS_SUCCESSFUL ? 2 : 0;
+
+  return sc;
+}
+
+static rtems_status_code i2c_sc620_read(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void *arg
+)
+{
+  rtems_status_code sc = RTEMS_IO_ERROR;
+  rtems_libio_rw_args_t *rw = arg;
+  unsigned char *buf = (unsigned char *) &rw->buffer[0];
+
+  if (rw->count == 1 && buf[0] < SC620_REG_COUNT) {
+    int rv;
+
+    rv = rtems_libi2c_start_write_bytes(minor, buf, 1);
+    if (rv == 1) {
+      sc = rtems_libi2c_send_addr(minor, 0);
+      if (sc == RTEMS_SUCCESSFUL) {
+        rv = rtems_libi2c_read_bytes(minor, buf, 1);
+        if (rv == 1) {
+          sc = rtems_libi2c_send_stop(minor);
+        }
+      }
+    }
+  }
+
+  rw->bytes_moved = sc == RTEMS_SUCCESSFUL ? 1 : 0;
+
+  return sc;
+}
+
+static rtems_driver_address_table i2c_sc620_ops = {
+  .read_entry =  i2c_sc620_read,
+  .write_entry = i2c_sc620_write
+};
+
+rtems_libi2c_drv_t i2c_sc620_driver = {
+  .ops = &i2c_sc620_ops,
+  .size = sizeof(i2c_sc620_driver)
+};
Index: bsps/shared/dev/i2c/spi-flash-m25p40.c
===================================================================
--- bsps/shared/dev/i2c/spi-flash-m25p40.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/i2c/spi-flash-m25p40.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,60 @@
+/*===============================================================*\
+| Project: SPI driver for M25P40 like spi flash device            |
++-----------------------------------------------------------------+
+|                    Copyright (c) 2007                           |
+|                    Embedded Brains GmbH                         |
+|                    Obere Lagerstr. 30                           |
+|                    D-82178 Puchheim                             |
+|                    Germany                                      |
+|                    rtems@embedded-brains.de                     |
++-----------------------------------------------------------------+
+| The license and distribution terms for this file may be         |
+| found in the file LICENSE in this distribution or at            |
+|                                                                 |
+| http://www.rtems.org/license/LICENSE.                           |
+|                                                                 |
++-----------------------------------------------------------------+
+\*===============================================================*/
+
+#include <rtems.h>
+#include <rtems/libi2c.h>
+
+#include <libchip/spi-flash-m25p40.h>
+#include <rtems/libio.h>
+
+
+static spi_memdrv_t spi_flash_m25p40_rw_drv_t = {
+  {/* public fields */
+    .ops =         &spi_memdrv_rw_ops, /* operations of general memdrv */
+    .size =        sizeof (spi_flash_m25p40_rw_drv_t),
+  },
+  { /* our private fields */
+    .baudrate =             2000000,
+    .erase_before_program = true,
+    .empty_state =          0xff,
+    .page_size =            256,     /* programming page size in bytes */
+    .sector_size =          0x10000, /* 64K - erase sector size in bytes */
+    .mem_size =             0x80000, /* 512K - total capacity in bytes */
+  }
+};
+
+rtems_libi2c_drv_t *spi_flash_m25p40_rw_driver_descriptor =
+&spi_flash_m25p40_rw_drv_t.libi2c_drv_entry;
+
+static spi_memdrv_t spi_flash_m25p40_ro_drv_t = {
+  {/* public fields */
+    .ops =         &spi_memdrv_ro_ops, /* operations of general memdrv */
+    .size =        sizeof (spi_flash_m25p40_ro_drv_t),
+  },
+  { /* our private fields */
+    .baudrate =             2000000,
+    .erase_before_program = true,
+    .empty_state =          0xff,
+    .page_size =            256,    /* programming page size in bytes */
+    .sector_size =          0x10000, /* 64K erase sector size in bytes */
+    .mem_size =             0x80000, /* 512K total capacity in bytes */
+  }
+};
+
+rtems_libi2c_drv_t *spi_flash_m25p40_ro_driver_descriptor =
+&spi_flash_m25p40_ro_drv_t.libi2c_drv_entry;
Index: bsps/shared/dev/i2c/spi-fram-fm25l256.c
===================================================================
--- bsps/shared/dev/i2c/spi-fram-fm25l256.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/i2c/spi-fram-fm25l256.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,60 @@
+/*===============================================================*\
+| Project: SPI driver for FM25L256 like spi fram device           |
++-----------------------------------------------------------------+
+|                    Copyright (c) 2008                           |
+|                    Embedded Brains GmbH                         |
+|                    Obere Lagerstr. 30                           |
+|                    D-82178 Puchheim                             |
+|                    Germany                                      |
+|                    rtems@embedded-brains.de                     |
++-----------------------------------------------------------------+
+| The license and distribution terms for this file may be         |
+| found in the file LICENSE in this distribution or at            |
+|                                                                 |
+| http://www.rtems.org/license/LICENSE.                           |
+|                                                                 |
++-----------------------------------------------------------------+
+\*===============================================================*/
+
+#include <rtems.h>
+#include <rtems/libi2c.h>
+
+#include <libchip/spi-fram-fm25l256.h>
+#include <rtems/libio.h>
+
+
+static spi_memdrv_t spi_fram_fm25l256_rw_drv_t = {
+  {/* public fields */
+    .ops =         &spi_memdrv_rw_ops, /* operations of general memdrv */
+    .size =        sizeof (spi_fram_fm25l256_rw_drv_t),
+  },
+  { /* our private fields */
+    .baudrate =             2000000,
+    .erase_before_program = false,
+    .empty_state =          0xff,
+    .page_size =            0x8000, /* 32K programming page size in bytes */
+    .sector_size =          1,      /* erase sector size in bytes */
+    .mem_size =             0x8000, /* 32K total capacity in bytes */
+  }
+};
+
+rtems_libi2c_drv_t *spi_fram_fm25l256_rw_driver_descriptor =
+&spi_fram_fm25l256_rw_drv_t.libi2c_drv_entry;
+
+static spi_memdrv_t spi_fram_fm25l256_ro_drv_t = {
+  {/* public fields */
+    .ops =         &spi_memdrv_ro_ops, /* operations of general memdrv */
+    .size =        sizeof (spi_fram_fm25l256_ro_drv_t),
+  },
+  { /* our private fields */
+    .baudrate =             2000000,
+    .erase_before_program = false,
+    .empty_state =          0xff,
+    .page_size =            0x8000, /* 32k programming page size in bytes */
+    .sector_size =          1,      /* erase sector size in bytes */
+    .mem_size =             0x8000, /* 32k total capacity in bytes */
+  }
+};
+
+rtems_libi2c_drv_t *spi_fram_fm25l256_ro_driver_descriptor =
+&spi_fram_fm25l256_ro_drv_t.libi2c_drv_entry;
Index: bsps/shared/dev/i2c/spi-memdrv.c
===================================================================
--- bsps/shared/dev/i2c/spi-memdrv.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/i2c/spi-memdrv.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,442 @@
+/*===============================================================*\
+| Project: SPI driver for spi memory devices                      |
++-----------------------------------------------------------------+
+|                    Copyright (c) 2008                           |
+|                    Embedded Brains GmbH                         |
+|                    Obere Lagerstr. 30                           |
+|                    D-82178 Puchheim                             |
+|                    Germany                                      |
+|                    rtems@embedded-brains.de                     |
++-----------------------------------------------------------------+
+| The license and distribution terms for this file may be         |
+| found in the file LICENSE in this distribution or at            |
+|                                                                 |
+| http://www.rtems.org/license/LICENSE.                           |
+|                                                                 |
++-----------------------------------------------------------------+
+\*===============================================================*/
+/*
+ * FIXME: currently, this driver only supports read/write accesses
+ * erase accesses are to be completed
+ */
+
+
+#include <rtems.h>
+#include <rtems/libi2c.h>
+
+#include <libchip/spi-memdrv.h>
+#include <rtems/libio.h>
+
+#define SPI_MEM_CMD_WREN  0x06
+#define SPI_MEM_CMD_WRDIS 0x04
+#define SPI_MEM_CMD_RDID  0x9F
+#define SPI_MEM_CMD_RDSR  0x05
+#define SPI_MEM_CMD_WRSR  0x01
+#define SPI_MEM_CMD_READ  0x03
+#define SPI_MEM_CMD_PP    0x02  /* page program                       */
+#define SPI_MEM_CMD_SE    0xD8  /* sector erase                       */
+#define SPI_MEM_CMD_BE    0xC7  /* bulk erase                         */
+#define SPI_MEM_CMD_DP    0xB9  /* deep power down                    */
+#define SPI_MEM_CMD_RES   0xAB  /* release from deep power down       */
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code spi_memdrv_minor2param_ptr
+(
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   translate given minor device number to param pointer                    |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+ rtems_device_minor_number minor,                /* minor number of device */
+ spi_memdrv_param_t **param_ptr                  /* ptr to param ptr       */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    o = ok or error code                                                   |
+\*=========================================================================*/
+{
+  rtems_status_code   rc = RTEMS_SUCCESSFUL;
+  spi_memdrv_t *drv_ptr;
+
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = -rtems_libi2c_ioctl(minor,
+			     RTEMS_LIBI2C_IOCTL_GET_DRV_T,
+			     &drv_ptr);
+  }
+  if ((rc == RTEMS_SUCCESSFUL) &&
+      (drv_ptr->libi2c_drv_entry.size != sizeof(spi_memdrv_t))) {
+    rc = RTEMS_INVALID_SIZE;
+  }
+  if (rc == RTEMS_SUCCESSFUL) {
+    *param_ptr = &(drv_ptr->spi_memdrv_param);
+  }
+  return rc;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+static rtems_status_code spi_memdrv_wait_ms
+(
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   wait a certain interval given in ms                                     |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+ int ms                                  /* time to wait in milliseconds   */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    o = ok or error code                                                   |
+\*=========================================================================*/
+{
+  rtems_interval   ticks_per_second;
+
+  ticks_per_second = rtems_clock_get_ticks_per_second();
+  (void) rtems_task_wake_after(ticks_per_second * ms / 1000);
+  return 0;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+rtems_status_code spi_memdrv_write
+(
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   write a block of data to flash                                          |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+ rtems_device_major_number major,        /* major device number            */
+ rtems_device_minor_number minor,        /* minor device number            */
+ void                      *arg          /* ptr to write argument struct   */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    o = ok or error code                                                   |
+\*=========================================================================*/
+{
+  rtems_status_code          rc = RTEMS_SUCCESSFUL;
+  rtems_libio_rw_args_t *rwargs = arg;
+  off_t                     off = rwargs->offset;
+  int                       cnt = rwargs->count;
+  unsigned char            *buf = (unsigned char *)rwargs->buffer;
+  int                bytes_sent = 0;
+  int                  curr_cnt;
+  unsigned char       cmdbuf[4];
+  int                   ret_cnt = 0;
+  int                  cmd_size;
+  spi_memdrv_param_t  *mem_param_ptr;
+  rtems_libi2c_tfr_mode_t tfr_mode = {
+    .baudrate =      20000000, /* maximum bits per second                   */
+    .bits_per_char = 8,        /* how many bits per byte/word/longword?     */
+    .lsb_first =     FALSE,    /* FALSE: send MSB first                     */
+    .clock_inv =     FALSE,    /* FALSE: non-inverted clock (high active)   */
+    .clock_phs =     FALSE     /* FALSE: clock starts in middle of data tfr */
+  } ;
+
+  /*
+   * get mem parameters
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = spi_memdrv_minor2param_ptr(minor,&mem_param_ptr);
+  }
+  /*
+   * check arguments
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    if ((cnt <= 0)                      ||
+	(cnt > mem_param_ptr->mem_size) ||
+	(off > (mem_param_ptr->mem_size-cnt))) {
+      rc = RTEMS_INVALID_SIZE;
+    }
+    else if (buf == NULL) {
+      rc = RTEMS_INVALID_ADDRESS;
+    }
+  }
+  while ((rc == RTEMS_SUCCESSFUL) &&
+	 (cnt > bytes_sent)) {
+    curr_cnt = cnt - bytes_sent;
+    if ((mem_param_ptr->page_size > 0) &&
+	(off              / mem_param_ptr->page_size) !=
+	((off+curr_cnt+1) / mem_param_ptr->page_size)) {
+      curr_cnt = mem_param_ptr->page_size - (off % mem_param_ptr->page_size);
+    }
+    /*
+     * select device, set transfer mode, address device
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      rc = rtems_libi2c_send_start(minor);
+    }
+    /*
+     * set transfer mode
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      tfr_mode.baudrate = mem_param_ptr->baudrate;
+      rc = -rtems_libi2c_ioctl(minor,
+			       RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
+			       &tfr_mode);
+    }
+
+    /*
+     * address device
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      rc = rtems_libi2c_send_addr(minor,TRUE);
+    }
+
+    /*
+     * send write_enable command
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      cmdbuf[0] = SPI_MEM_CMD_WREN;
+      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,1);
+      if (ret_cnt < 0) {
+	rc = -ret_cnt;
+      }
+    }
+    /*
+     * terminate transfer
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      rc = rtems_libi2c_send_stop(minor);
+    }
+    /*
+     * select device, set transfer mode
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      rc = rtems_libi2c_send_start(minor);
+    }
+
+    /*
+     * address device
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      rc = rtems_libi2c_send_addr(minor,TRUE);
+    }
+
+    /*
+     * set transfer mode
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      rc = -rtems_libi2c_ioctl(minor,
+			       RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
+			       &tfr_mode);
+    }
+    /*
+     * send "page program" command and address
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      cmdbuf[0] = SPI_MEM_CMD_PP;
+      if (mem_param_ptr->mem_size > 0x10000 /* 256*256 */) {
+	cmdbuf[1] = (off >> 16) & 0xff;
+	cmdbuf[2] = (off >>  8) & 0xff;
+	cmdbuf[3] = (off >>  0) & 0xff;
+	cmd_size  = 4;
+      }
+      else if (mem_param_ptr->mem_size > 256) {
+	cmdbuf[1] = (off >>  8) & 0xff;
+	cmdbuf[2] = (off >>  0) & 0xff;
+	cmd_size  = 3;
+      }
+      else {
+	cmdbuf[1] = (off >>  0) & 0xff;
+	cmd_size  = 1;
+      }
+
+      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,cmd_size);
+      if (ret_cnt < 0) {
+	rc = -ret_cnt;
+      }
+    }
+    /*
+     * send write data
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      ret_cnt = rtems_libi2c_write_bytes(minor,buf,curr_cnt);
+      if (ret_cnt < 0) {
+	rc = -ret_cnt;
+      }
+    }
+    /*
+     * terminate transfer
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      rc = rtems_libi2c_send_stop(minor);
+    }
+    /*
+     * wait proper time for data to store: 5ms
+     * FIXME: select proper interval or poll, until device is finished
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      rc = spi_memdrv_wait_ms(5);
+    }
+    /*
+     * adjust bytecount to be sent and pointers
+     */
+    bytes_sent += curr_cnt;
+    off        += curr_cnt;
+    buf        += curr_cnt;
+  }
+  rwargs->bytes_moved = bytes_sent;
+  return rc;
+}
+
+/*=========================================================================*\
+| Function:                                                                 |
+\*-------------------------------------------------------------------------*/
+rtems_status_code spi_memdrv_read
+(
+/*-------------------------------------------------------------------------*\
+| Purpose:                                                                  |
+|   read a block of data from flash                                         |
++---------------------------------------------------------------------------+
+| Input Parameters:                                                         |
+\*-------------------------------------------------------------------------*/
+ rtems_device_major_number major,        /* major device number            */
+ rtems_device_minor_number minor,        /* minor device number            */
+ void                      *arg          /* ptr to read argument struct    */
+)
+/*-------------------------------------------------------------------------*\
+| Return Value:                                                             |
+|    o = ok or error code                                                   |
+\*=========================================================================*/
+{
+  rtems_status_code rc = RTEMS_SUCCESSFUL;
+  rtems_libio_rw_args_t *rwargs = arg;
+  off_t                     off = rwargs->offset;
+  int                       cnt = rwargs->count;
+  unsigned char            *buf = (unsigned char *)rwargs->buffer;
+  unsigned char         cmdbuf[4];
+  int                   ret_cnt = 0;
+  int                  cmd_size;
+  spi_memdrv_param_t  *mem_param_ptr;
+  rtems_libi2c_tfr_mode_t tfr_mode = {
+    .baudrate =      20000000, /* maximum bits per second                   */
+    .bits_per_char = 8,        /* how many bits per byte/word/longword?     */
+    .lsb_first =     FALSE,    /* FALSE: send MSB first                     */
+    .clock_inv =     FALSE,    /* FALSE: non-inverted clock (high active)   */
+    .clock_phs =     FALSE     /* FALSE: clock starts in middle of data tfr */
+  };
+
+  /*
+   * get mem parameters
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = spi_memdrv_minor2param_ptr(minor,&mem_param_ptr);
+  }
+  /*
+   * check arguments
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    if ((cnt <= 0)                      ||
+	(cnt > mem_param_ptr->mem_size) ||
+	(off > (mem_param_ptr->mem_size-cnt))) {
+      rc = RTEMS_INVALID_SIZE;
+    }
+    else if (buf == NULL) {
+      rc = RTEMS_INVALID_ADDRESS;
+    }
+  }
+  /*
+   * select device, set transfer mode, address device
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_libi2c_send_start(minor);
+  }
+  /*
+   * set transfer mode
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    tfr_mode.baudrate = mem_param_ptr->baudrate;
+    rc = -rtems_libi2c_ioctl(minor,
+			     RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
+			     &tfr_mode);
+  }
+  /*
+   * address device
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_libi2c_send_addr(minor,TRUE);
+  }
+
+  if (off >= mem_param_ptr->mem_size) {
+    /*
+     * HACK: beyond size of memory array? then read status register instead
+     */
+    /*
+     * send read status register command
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      cmdbuf[0] = SPI_MEM_CMD_RDSR;
+      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,1);
+      if (ret_cnt < 0) {
+	rc = -ret_cnt;
+      }
+    }
+  }
+  else {
+    /*
+     * send read command and address
+     */
+    if (rc == RTEMS_SUCCESSFUL) {
+      cmdbuf[0] = SPI_MEM_CMD_READ;
+      if (mem_param_ptr->mem_size > 0x10000 /* 256*256 */) {
+	cmdbuf[1] = (off >> 16) & 0xff;
+	cmdbuf[2] = (off >>  8) & 0xff;
+	cmdbuf[3] = (off >>  0) & 0xff;
+	cmd_size  = 4;
+      }
+      else if (mem_param_ptr->mem_size > 256) {
+	cmdbuf[1] = (off >>  8) & 0xff;
+	cmdbuf[2] = (off >>  0) & 0xff;
+	cmd_size  = 3;
+      }
+      else {
+	cmdbuf[1] = (off >>  0) & 0xff;
+	cmd_size  = 1;
+      }
+      ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,cmd_size);
+      if (ret_cnt < 0) {
+	rc = -ret_cnt;
+      }
+    }
+  }
+  /*
+   * fetch read data
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    ret_cnt = rtems_libi2c_read_bytes (minor,buf,cnt);
+    if (ret_cnt < 0) {
+      rc = -ret_cnt;
+    }
+  }
+
+  /*
+   * terminate transfer
+   */
+  if (rc == RTEMS_SUCCESSFUL) {
+    rc = rtems_libi2c_send_stop(minor);
+  }
+  rwargs->bytes_moved = (rc == RTEMS_SUCCESSFUL) ? ret_cnt : 0;
+
+  return rc;
+}
+
+/*
+ * driver operation tables
+ */
+rtems_driver_address_table spi_memdrv_rw_ops = {
+  .read_entry =  spi_memdrv_read,
+  .write_entry = spi_memdrv_write
+};
+
+rtems_driver_address_table spi_memdrv_ro_ops = {
+  .read_entry =  spi_memdrv_read,
+};
+
Index: bsps/shared/dev/i2c/spi-sd-card.c
===================================================================
--- bsps/shared/dev/i2c/spi-sd-card.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/i2c/spi-sd-card.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,1322 @@
+/**
+ * @file
+ *
+ * @brief SD Card LibI2C driver.
+ */
+
+/*
+ * Copyright (c) 2008
+ * Embedded Brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * rtems@embedded-brains.de
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <rtems.h>
+#include <rtems/libi2c.h>
+#include <rtems/libio.h>
+#include <rtems/diskdevs.h>
+#include <rtems/blkdev.h>
+
+#include <libchip/spi-sd-card.h>
+
+#include <rtems/status-checks.h>
+
+/**
+ * @name Integer to and from Byte-Stream Converter
+ * @{
+ */
+
+static inline uint16_t sd_card_get_uint16( const uint8_t *s)
+{
+	return (uint16_t) ((s [0] << 8) | s [1]);
+}
+
+static inline uint32_t sd_card_get_uint32( const uint8_t *s)
+{
+	return ((uint32_t) s [0] << 24) | ((uint32_t) s [1] << 16) | ((uint32_t) s [2] << 8) | (uint32_t) s [3];
+}
+
+static inline void sd_card_put_uint16( uint16_t v, uint8_t *s)
+{
+	*s++ = (uint8_t) (v >> 8);
+	*s   = (uint8_t) (v);
+}
+
+static inline void sd_card_put_uint32( uint32_t v, uint8_t *s)
+{
+	*s++ = (uint8_t) (v >> 24);
+	*s++ = (uint8_t) (v >> 16);
+	*s++ = (uint8_t) (v >> 8);
+	*s   = (uint8_t) (v);
+}
+
+/** @} */
+
+#define SD_CARD_BUSY_TOKEN 0
+
+#define SD_CARD_BLOCK_SIZE_DEFAULT 512
+
+#define SD_CARD_COMMAND_RESPONSE_START 7
+
+/**
+ * @name Commands
+ * @{
+ */
+
+#define SD_CARD_CMD_GO_IDLE_STATE 0
+#define SD_CARD_CMD_SEND_OP_COND 1
+#define SD_CARD_CMD_SEND_IF_COND 8
+#define SD_CARD_CMD_SEND_CSD 9
+#define SD_CARD_CMD_SEND_CID 10
+#define SD_CARD_CMD_STOP_TRANSMISSION 12
+#define SD_CARD_CMD_SEND_STATUS 13
+#define SD_CARD_CMD_SET_BLOCKLEN 16
+#define SD_CARD_CMD_READ_SINGLE_BLOCK 17
+#define SD_CARD_CMD_READ_MULTIPLE_BLOCK 18
+#define SD_CARD_CMD_SET_BLOCK_COUNT 23
+#define SD_CARD_CMD_WRITE_BLOCK 24
+#define SD_CARD_CMD_WRITE_MULTIPLE_BLOCK 25
+#define SD_CARD_CMD_PROGRAM_CSD 27
+#define SD_CARD_CMD_SET_WRITE_PROT 28
+#define SD_CARD_CMD_CLR_WRITE_PROT 29
+#define SD_CARD_CMD_SEND_WRITE_PROT 30
+#define SD_CARD_CMD_TAG_SECTOR_START 32
+#define SD_CARD_CMD_TAG_SECTOR_END 33
+#define SD_CARD_CMD_UNTAG_SECTOR 34
+#define SD_CARD_CMD_TAG_ERASE_GROUP_START 35
+#define SD_CARD_CMD_TAG_ERASE_GROUP_END 36
+#define SD_CARD_CMD_UNTAG_ERASE_GROUP 37
+#define SD_CARD_CMD_ERASE 38
+#define SD_CARD_CMD_LOCK_UNLOCK 42
+#define SD_CARD_CMD_APP_CMD 55
+#define SD_CARD_CMD_GEN_CND 56
+#define SD_CARD_CMD_READ_OCR 58
+#define SD_CARD_CMD_CRC_ON_OFF 59
+
+/** @} */
+
+/**
+ * @name Application Commands
+ * @{
+ */
+
+#define SD_CARD_ACMD_SD_SEND_OP_COND 41
+
+/** @} */
+
+/**
+ * @name Command Flags
+ * @{
+ */
+
+#define SD_CARD_FLAG_HCS 0x40000000U
+
+#define SD_CARD_FLAG_VHS_2_7_TO_3_3 0x00000100U
+
+#define SD_CARD_FLAG_CHECK_PATTERN 0x000000aaU
+
+/** @} */
+
+/**
+ * @name Command Fields
+ * @{
+ */
+
+#define SD_CARD_COMMAND_SET_COMMAND( c, cmd) (c) [1] = (uint8_t) (0x40 + ((cmd) & 0x3f))
+
+#define SD_CARD_COMMAND_SET_ARGUMENT( c, arg) sd_card_put_uint32( (arg), &((c) [2]))
+
+#define SD_CARD_COMMAND_SET_CRC7( c, crc7) ((c) [6] = ((crc7) << 1) | 1U)
+
+#define SD_CARD_COMMAND_GET_CRC7( c) ((c) [6] >> 1)
+
+/** @} */
+
+/**
+ * @name Response Fields
+ * @{
+ */
+
+#define SD_CARD_IS_RESPONSE( r) (((r) & 0x80) == 0)
+
+#define SD_CARD_IS_ERRORLESS_RESPONSE( r) (((r) & 0x7e) == 0)
+
+#define SD_CARD_IS_NOT_IDLE_RESPONSE( r) (((r) & 0x81) == 0)
+
+#define SD_CARD_IS_DATA_ERROR( r) (((r) & 0xe0) == 0)
+
+#define SD_CARD_IS_DATA_REJECTED( r) (((r) & 0x1f) != 0x05)
+
+/** @} */
+
+/**
+ * @name Card Identification
+ * @{
+ */
+
+#define SD_CARD_CID_SIZE 16
+
+#define SD_CARD_CID_GET_MID( cid) ((cid) [0])
+#define SD_CARD_CID_GET_OID( cid) sd_card_get_uint16( cid + 1)
+#define SD_CARD_CID_GET_PNM( cid, i) ((char) (cid) [3 + (i)])
+#define SD_CARD_CID_GET_PRV( cid) ((cid) [9])
+#define SD_CARD_CID_GET_PSN( cid) sd_card_get_uint32( cid + 10)
+#define SD_CARD_CID_GET_MDT( cid) ((cid) [14])
+#define SD_CARD_CID_GET_CRC7( cid) ((cid) [15] >> 1)
+
+/** @} */
+
+/**
+ * @name Card Specific Data
+ * @{
+ */
+
+#define SD_CARD_CSD_SIZE 16
+
+#define SD_CARD_CSD_GET_CSD_STRUCTURE( csd) ((csd) [0] >> 6)
+#define SD_CARD_CSD_GET_SPEC_VERS( csd) (((csd) [0] >> 2) & 0xf)
+#define SD_CARD_CSD_GET_TAAC( csd) ((csd) [1])
+#define SD_CARD_CSD_GET_NSAC( csd) ((uint32_t) (csd) [2])
+#define SD_CARD_CSD_GET_TRAN_SPEED( csd) ((csd) [3])
+#define SD_CARD_CSD_GET_C_SIZE( csd) ((((uint32_t) (csd) [6] & 0x3) << 10) + (((uint32_t) (csd) [7]) << 2) + ((((uint32_t) (csd) [8]) >> 6) & 0x3))
+#define SD_CARD_CSD_GET_C_SIZE_MULT( csd) ((((csd) [9] & 0x3) << 1) + (((csd) [10] >> 7) & 0x1))
+#define SD_CARD_CSD_GET_READ_BLK_LEN( csd) ((uint32_t) (csd) [5] & 0xf)
+#define SD_CARD_CSD_GET_WRITE_BLK_LEN( csd) ((((uint32_t) (csd) [12] & 0x3) << 2) + ((((uint32_t) (csd) [13]) >> 6) & 0x3))
+#define SD_CARD_CSD_1_GET_C_SIZE( csd) ((((uint32_t) (csd) [7] & 0x3f) << 16) + (((uint32_t) (csd) [8]) << 8) + (uint32_t) (csd) [9])
+
+/** @} */
+
+#define SD_CARD_INVALIDATE_RESPONSE_INDEX( e) e->response_index = SD_CARD_COMMAND_SIZE
+
+/**
+ * @name Data Start and Stop Tokens
+ * @{
+ */
+
+#define SD_CARD_START_BLOCK_SINGLE_BLOCK_READ 0xfe
+#define SD_CARD_START_BLOCK_MULTIPLE_BLOCK_READ 0xfe
+#define SD_CARD_START_BLOCK_SINGLE_BLOCK_WRITE 0xfe
+#define SD_CARD_START_BLOCK_MULTIPLE_BLOCK_WRITE 0xfc
+#define SD_CARD_STOP_TRANSFER_MULTIPLE_BLOCK_WRITE 0xfd
+
+/** @} */
+
+/**
+ * @name Card Specific Data Functions
+ * @{
+ */
+
+static inline uint32_t sd_card_block_number( const uint8_t *csd)
+{
+	uint32_t size = SD_CARD_CSD_GET_C_SIZE( csd);
+	uint32_t mult = 1U << (SD_CARD_CSD_GET_C_SIZE_MULT( csd) + 2);
+	return (size + 1) * mult;
+}
+
+static inline uint32_t sd_card_capacity( const uint8_t *csd)
+{
+	uint32_t block_size = 1U << SD_CARD_CSD_GET_READ_BLK_LEN( csd);
+	return sd_card_block_number( csd) * block_size;
+}
+
+static inline uint32_t sd_card_transfer_speed( const uint8_t *csd)
+{
+	uint32_t s = SD_CARD_CSD_GET_TRAN_SPEED( csd);
+	uint32_t e = s & 0x7;
+	uint32_t m = s >> 3;
+	switch (e) {
+		case 0: s = 10000; break;
+		case 1: s = 100000; break;
+		case 2: s = 1000000; break;
+		case 3: s = 10000000; break;
+		default: s = 0; break;
+	}
+	switch (m) {
+		case 1: s *= 10; break;
+		case 2: s *= 12; break;
+		case 3: s *= 13; break;
+		case 4: s *= 15; break;
+		case 5: s *= 20; break;
+		case 6: s *= 25; break;
+		case 7: s *= 30; break;
+		case 8: s *= 35; break;
+		case 9: s *= 40; break;
+		case 10: s *= 45; break;
+		case 11: s *= 50; break;
+		case 12: s *= 55; break;
+		case 13: s *= 60; break;
+		case 14: s *= 70; break;
+		case 15: s *= 80; break;
+		default: s *= 0; break;
+	}
+	return s;
+}
+
+static inline uint32_t sd_card_access_time( const uint8_t *csd)
+{
+	uint32_t ac = SD_CARD_CSD_GET_TAAC( csd);
+	uint32_t e = ac & 0x7;
+	uint32_t m = ac >> 3;
+	switch (e) {
+		case 0: ac = 1; break;
+		case 1: ac = 10; break;
+		case 2: ac = 100; break;
+		case 3: ac = 1000; break;
+		case 4: ac = 10000; break;
+		case 5: ac = 100000; break;
+		case 6: ac = 1000000; break;
+		case 7: ac = 10000000; break;
+		default: ac = 0; break;
+	}
+	switch (m) {
+		case 1: ac *= 10; break;
+		case 2: ac *= 12; break;
+		case 3: ac *= 13; break;
+		case 4: ac *= 15; break;
+		case 5: ac *= 20; break;
+		case 6: ac *= 25; break;
+		case 7: ac *= 30; break;
+		case 8: ac *= 35; break;
+		case 9: ac *= 40; break;
+		case 10: ac *= 45; break;
+		case 11: ac *= 50; break;
+		case 12: ac *= 55; break;
+		case 13: ac *= 60; break;
+		case 14: ac *= 70; break;
+		case 15: ac *= 80; break;
+		default: ac *= 0; break;
+	}
+	return ac / 10;
+}
+
+static inline uint32_t sd_card_max_access_time( const uint8_t *csd, uint32_t transfer_speed)
+{
+	uint64_t ac = sd_card_access_time( csd);
+	uint32_t ac_100ms = transfer_speed / 80;
+	uint32_t n = SD_CARD_CSD_GET_NSAC( csd) * 100;
+	/* ac is in ns, transfer_speed in bps, max_access_time in bytes.
+	   max_access_time is 100 times typical access time (taac+nsac) */
+	ac = ac * transfer_speed / 80000000;
+	ac = ac + 100*n;
+	if ((uint32_t)ac > ac_100ms)
+		return ac_100ms;
+	else
+		return (uint32_t)ac;
+}
+
+/** @} */
+
+/**
+ * @name CRC functions
+ *
+ * Based on http://en.wikipedia.org/wiki/Computation_of_CRC
+ *
+ * @{
+ */
+
+static uint8_t sd_card_compute_crc7 (uint8_t *data, size_t len)
+{
+	uint8_t e, f, crc;
+	size_t i;
+
+	crc = 0;
+	for (i = 0; i < len; i++) {
+		e   = crc ^ data[i];
+		f   = e ^ (e >> 4) ^ (e >> 7);
+		crc = (f << 1) ^ (f << 4);
+	}
+	return crc >> 1;
+}
+
+static uint16_t sd_card_compute_crc16 (uint8_t *data, size_t len)
+{
+	uint8_t s, t;
+	uint16_t crc;
+	size_t i;
+
+	crc = 0;
+	for (i = 0; i < len; i++) {
+		s = data[i] ^ (crc >> 8);
+		t = s ^ (s >> 4);
+		crc = (crc << 8) ^ t ^ (t << 5) ^ (t << 12);
+	}
+	return crc;
+}
+
+/** @} */
+
+/**
+ * @name Communication Functions
+ * @{
+ */
+
+static inline int sd_card_query( sd_card_driver_entry *e, uint8_t *in, int n)
+{
+	return rtems_libi2c_read_bytes( e->bus, in, n);
+}
+
+static int sd_card_wait( sd_card_driver_entry *e)
+{
+	int rv = 0;
+	int r = 0;
+	int n = 2;
+	/* For writes, the timeout is 2.5 times that of reads; since we
+	   don't know if it is a write or read, assume write.
+	   FIXME should actually look at R2W_FACTOR for non-HC cards. */
+	int retries = e->n_ac_max * 25 / 10;
+	/* n_ac_max/100 is supposed to be the average waiting time. To
+	   approximate this, we start with waiting n_ac_max/150 and
+	   gradually increase the waiting time. */
+	int wait_time_bytes = (retries + 149) / 150;
+	while (e->busy) {
+		/* Query busy tokens */
+		rv = sd_card_query( e, e->response, n);
+		RTEMS_CHECK_RV( rv, "Busy");
+
+		/* Search for non busy tokens */
+		for (r = 0; r < n; ++r) {
+			if (e->response [r] != SD_CARD_BUSY_TOKEN) {
+				e->busy = false;
+				return 0;
+			}
+		}
+		retries -= n;
+		if (retries <= 0) {
+			return -RTEMS_TIMEOUT;
+		}
+
+		if (e->schedule_if_busy) {
+			uint64_t wait_time_us = wait_time_bytes;
+			wait_time_us *= 8000000;
+			wait_time_us /= e->transfer_mode.baudrate;
+			rtems_task_wake_after( RTEMS_MICROSECONDS_TO_TICKS(wait_time_us));
+			retries -= wait_time_bytes;
+			wait_time_bytes = wait_time_bytes * 15 / 10;
+		} else {
+			n = SD_CARD_COMMAND_SIZE;
+		}
+	}
+	return 0;
+}
+
+static int sd_card_send_command( sd_card_driver_entry *e, uint32_t command, uint32_t argument)
+{
+	int rv = 0;
+	rtems_libi2c_read_write_t rw = {
+		.rd_buf = e->response,
+		.wr_buf = e->command,
+		.byte_cnt = SD_CARD_COMMAND_SIZE
+	};
+	int r = 0;
+	uint8_t crc7;
+
+	SD_CARD_INVALIDATE_RESPONSE_INDEX( e);
+
+	/* Wait until card is not busy */
+	rv = sd_card_wait( e);
+	RTEMS_CHECK_RV( rv, "Wait");
+
+	/* Write command and read response */
+	SD_CARD_COMMAND_SET_COMMAND( e->command, command);
+	SD_CARD_COMMAND_SET_ARGUMENT( e->command, argument);
+	crc7 = sd_card_compute_crc7( e->command + 1, 5);
+	SD_CARD_COMMAND_SET_CRC7( e->command, crc7);
+	rv = rtems_libi2c_ioctl( e->bus, RTEMS_LIBI2C_IOCTL_READ_WRITE, &rw);
+	RTEMS_CHECK_RV( rv, "Write command and read response");
+
+	/* Check respose */
+	for (r = SD_CARD_COMMAND_RESPONSE_START; r < SD_CARD_COMMAND_SIZE; ++r) {
+		RTEMS_DEBUG_PRINT( "Token [%02u]: 0x%02x\n", r, e->response [r]);
+		e->response_index = r;
+		if (SD_CARD_IS_RESPONSE( e->response [r])) {
+			if (SD_CARD_IS_ERRORLESS_RESPONSE( e->response [r])) {
+				return 0;
+			} else {
+				RTEMS_SYSLOG_ERROR( "Command error [%02i]: 0x%02" PRIx8 "\n", r, e->response [r]);
+				goto sd_card_send_command_error;
+			}
+		} else if (e->response [r] != SD_CARD_IDLE_TOKEN) {
+			RTEMS_SYSLOG_ERROR( "Unexpected token [%02i]: 0x%02" PRIx8 "\n", r, e->response [r]);
+			goto sd_card_send_command_error;
+		}
+	}
+
+	RTEMS_SYSLOG_ERROR( "Timeout\n");
+
+sd_card_send_command_error:
+
+	RTEMS_SYSLOG_ERROR( "Response:");
+	for (r = 0; r < SD_CARD_COMMAND_SIZE; ++r) {
+		if (e->response_index == r) {
+			RTEMS_SYSLOG_PRINT( " %02" PRIx8 ":[%02" PRIx8 "]", e->command [r], e->response [r]);
+		} else {
+			RTEMS_SYSLOG_PRINT( " %02" PRIx8 ":%02" PRIx8 "", e->command [r], e->response [r]);
+		}
+	}
+	RTEMS_SYSLOG_PRINT( "\n");
+
+	return -RTEMS_IO_ERROR;
+}
+
+static int sd_card_send_register_command( sd_card_driver_entry *e, uint32_t command, uint32_t argument, uint32_t *reg)
+{
+	int rv = 0;
+	uint8_t crc7;
+
+	rv = sd_card_send_command( e, command, argument);
+	RTEMS_CHECK_RV( rv, "Send command");
+
+	if (e->response_index + 5 > SD_CARD_COMMAND_SIZE) {
+		/*
+		 * TODO: If this happens in the wild we need to implement a
+		 * more sophisticated response query.
+		 */
+		RTEMS_SYSLOG_ERROR( "Unexpected response position\n");
+		return -RTEMS_IO_ERROR;
+	}
+
+	crc7 = sd_card_compute_crc7( e->response + e->response_index, 5);
+	if (crc7 != SD_CARD_COMMAND_GET_CRC7( e->response + e->response_index) &&
+		SD_CARD_COMMAND_GET_CRC7( e->response + e->response_index) != 0x7f) {
+		RTEMS_SYSLOG_ERROR( "CRC check failed on register command\n");
+		return -RTEMS_IO_ERROR;
+	}
+
+	*reg = sd_card_get_uint32( e->response + e->response_index + 1);
+
+	return 0;
+}
+
+static int sd_card_stop_multiple_block_read( sd_card_driver_entry *e)
+{
+	int rv = 0;
+	uint8_t crc7;
+
+	SD_CARD_COMMAND_SET_COMMAND( e->command, SD_CARD_CMD_STOP_TRANSMISSION);
+	SD_CARD_COMMAND_SET_ARGUMENT( e->command, 0);
+	/*crc7 = sd_card_compute_crc7( e->command + 1, 5);*/
+	crc7 = 0x30;	/* Help compiler - command and argument are constants */
+	SD_CARD_COMMAND_SET_CRC7( e->command, crc7);
+	rv = rtems_libi2c_write_bytes( e->bus, e->command, SD_CARD_COMMAND_SIZE);
+	RTEMS_CHECK_RV( rv, "Write stop transfer token");
+
+	return 0;
+}
+
+static int sd_card_stop_multiple_block_write( sd_card_driver_entry *e)
+{
+	int rv = 0;
+	uint8_t stop_transfer [3] = { SD_CARD_IDLE_TOKEN, SD_CARD_STOP_TRANSFER_MULTIPLE_BLOCK_WRITE, SD_CARD_IDLE_TOKEN };
+
+	/* Wait until card is not busy */
+	rv = sd_card_wait( e);
+	RTEMS_CHECK_RV( rv, "Wait");
+
+	/* Send stop token */
+	rv = rtems_libi2c_write_bytes( e->bus, stop_transfer, 3);
+	RTEMS_CHECK_RV( rv, "Write stop transfer token");
+
+	/* Card is now busy */
+	e->busy = true;
+
+	return 0;
+}
+
+static int sd_card_read( sd_card_driver_entry *e, uint8_t start_token, uint8_t *in, int n)
+{
+	int rv = 0;
+
+	/* Discard command response */
+	int r = e->response_index + 1;
+
+	/* Standard response size */
+	int response_size = SD_CARD_COMMAND_SIZE;
+
+	/* Where the response is stored */
+	uint8_t *response = e->response;
+
+	/* Data input index */
+	int i = 0;
+
+	/* CRC check of data */
+	uint16_t crc16;
+
+	/* Maximum number of tokens to read. */
+	int retries = e->n_ac_max;
+
+	SD_CARD_INVALIDATE_RESPONSE_INDEX( e);
+
+	while (true) {
+		RTEMS_DEBUG_PRINT( "Search from %u to %u\n", r, response_size - 1);
+
+		/* Search the data start token in in current response buffer */
+		retries -= (response_size - r);
+		while (r < response_size) {
+			RTEMS_DEBUG_PRINT( "Token [%02u]: 0x%02x\n", r, response [r]);
+			if (response [r] == start_token) {
+				/* Discard data start token */
+				++r;
+				goto sd_card_read_start;
+			} else if (SD_CARD_IS_DATA_ERROR( response [r])) {
+				RTEMS_SYSLOG_ERROR( "Data error token [%02i]: 0x%02" PRIx8 "\n", r, response [r]);
+				return -RTEMS_IO_ERROR;
+			} else if (response [r] != SD_CARD_IDLE_TOKEN) {
+				RTEMS_SYSLOG_ERROR( "Unexpected token [%02i]: 0x%02" PRIx8 "\n", r, response [r]);
+				return -RTEMS_IO_ERROR;
+			}
+			++r;
+		}
+
+		if (retries <= 0) {
+			RTEMS_SYSLOG_ERROR( "Timeout\n");
+			return -RTEMS_IO_ERROR;
+		}
+
+		if (e->schedule_if_busy)
+			rtems_task_wake_after( RTEMS_YIELD_PROCESSOR);
+
+		/* Query more.  We typically have to wait between 10 and 100
+		   bytes.  To reduce overhead, read the response in chunks of
+		   50 bytes - this doesn't introduce too much copy overhead
+		   but does allow SPI DMA transfers to work efficiently. */
+		response = in;
+		response_size = 50;
+		if (response_size > n)
+			response_size = n;
+		rv = sd_card_query( e, response, response_size);
+		RTEMS_CHECK_RV( rv, "Query data start token");
+
+		/* Reset start position */
+		r = 0;
+	}
+
+sd_card_read_start:
+
+	/* Read data */
+	while (r < response_size && i < n) {
+		in [i++] = response [r++];
+	}
+
+	/* Read more data? */
+	if (i < n) {
+		rv = sd_card_query( e, &in [i], n - i);
+		RTEMS_CHECK_RV( rv, "Read data");
+		i += rv;
+	}
+
+	/* Read CRC 16 and N_RC */
+	rv = sd_card_query( e, e->response, 3);
+	RTEMS_CHECK_RV( rv, "Read CRC 16");
+
+	crc16 = sd_card_compute_crc16 (in, n);
+	if ((e->response[0] != ((crc16 >> 8) & 0xff)) ||
+	    (e->response[1] != (crc16 & 0xff))) {
+		RTEMS_SYSLOG_ERROR( "CRC check failed on read\n");
+		return -RTEMS_IO_ERROR;
+	}
+
+	return i;
+}
+
+static int sd_card_write( sd_card_driver_entry *e, uint8_t start_token, uint8_t *out, int n)
+{
+	int rv = 0;
+	uint8_t crc16_bytes [2] = { 0, 0 };
+	uint16_t crc16;
+
+	/* Data output index */
+	int o = 0;
+
+	/* Wait until card is not busy */
+	rv = sd_card_wait( e);
+	RTEMS_CHECK_RV( rv, "Wait");
+
+	/* Write data start token */
+	rv = rtems_libi2c_write_bytes( e->bus, &start_token, 1);
+	RTEMS_CHECK_RV( rv, "Write data start token");
+
+	/* Write data */
+	o = rtems_libi2c_write_bytes( e->bus, out, n);
+	RTEMS_CHECK_RV( o, "Write data");
+
+	/* Write CRC 16 */
+	crc16 = sd_card_compute_crc16(out, n);
+	crc16_bytes[0] = (crc16>>8) & 0xff;
+	crc16_bytes[1] = (crc16) & 0xff;
+	rv = rtems_libi2c_write_bytes( e->bus, crc16_bytes, 2);
+	RTEMS_CHECK_RV( rv, "Write CRC 16");
+
+	/* Read data response */
+	rv = sd_card_query( e, e->response, 2);
+	RTEMS_CHECK_RV( rv, "Read data response");
+	if (SD_CARD_IS_DATA_REJECTED( e->response [0])) {
+		RTEMS_SYSLOG_ERROR( "Data rejected: 0x%02" PRIx8 "\n", e->response [0]);
+		return -RTEMS_IO_ERROR;
+	}
+
+	/* Card is now busy */
+	e->busy = true;
+
+	return o;
+}
+
+static inline rtems_status_code sd_card_start( sd_card_driver_entry *e)
+{
+	rtems_status_code sc = RTEMS_SUCCESSFUL;
+	int rv = 0;
+
+	sc = rtems_libi2c_send_start( e->bus);
+	RTEMS_CHECK_SC( sc, "Send start");
+
+	rv = rtems_libi2c_ioctl( e->bus, RTEMS_LIBI2C_IOCTL_SET_TFRMODE, &e->transfer_mode);
+	RTEMS_CHECK_RV_SC( rv, "Set transfer mode");
+
+	sc = rtems_libi2c_send_addr( e->bus, 1);
+	RTEMS_CHECK_SC( sc, "Send address");
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static inline rtems_status_code sd_card_stop( sd_card_driver_entry *e)
+{
+	rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+	sc = rtems_libi2c_send_stop( e->bus);
+	RTEMS_CHECK_SC( sc, "Send stop");
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code sd_card_init( sd_card_driver_entry *e)
+{
+	rtems_status_code sc = RTEMS_SUCCESSFUL;
+	int rv = 0;
+	uint8_t block [SD_CARD_BLOCK_SIZE_DEFAULT];
+	uint32_t transfer_speed = 0;
+	uint32_t read_block_size = 0;
+	uint32_t write_block_size = 0;
+	uint8_t csd_structure = 0;
+	uint64_t capacity = 0;
+	uint8_t crc7;
+
+	/* Assume first that we have a SD card and not a MMC card */
+	bool assume_sd = true;
+
+	/*
+	 * Assume high capacity until proven wrong (applies to SD and not yet
+	 * existing MMC).
+	 */
+	bool high_capacity = true;
+
+	bool do_cmd58 = true;
+	uint32_t cmd_arg = 0;
+	uint32_t if_cond_test = SD_CARD_FLAG_VHS_2_7_TO_3_3 | SD_CARD_FLAG_CHECK_PATTERN;
+	uint32_t if_cond_reg = if_cond_test;
+
+	/* Start */
+	sc = sd_card_start( e);
+	RTEMS_CLEANUP_SC( sc, sd_card_driver_init_cleanup, "Start");
+
+	/* Wait until card is not busy */
+	rv = sd_card_wait( e);
+	RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Wait");
+
+	/* Send idle tokens for at least 74 clock cycles with active chip select */
+	memset( block, SD_CARD_IDLE_TOKEN, SD_CARD_BLOCK_SIZE_DEFAULT);
+	rv = rtems_libi2c_write_bytes( e->bus, block, SD_CARD_BLOCK_SIZE_DEFAULT);
+	RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Active chip select delay");
+
+	/* Stop */
+	sc = sd_card_stop( e);
+	RTEMS_CHECK_SC( sc, "Stop");
+
+	/* Start with inactive chip select */
+	sc = rtems_libi2c_send_start( e->bus);
+	RTEMS_CHECK_SC( sc, "Send start");
+
+	/* Set transfer mode */
+	rv = rtems_libi2c_ioctl( e->bus, RTEMS_LIBI2C_IOCTL_SET_TFRMODE, &e->transfer_mode);
+	RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Set transfer mode");
+
+	/* Send idle tokens with inactive chip select */
+	rv = sd_card_query( e, e->response, SD_CARD_COMMAND_SIZE);
+	RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Inactive chip select delay");
+
+	/* Activate chip select */
+	sc = rtems_libi2c_send_addr( e->bus, 1);
+	RTEMS_CLEANUP_SC( sc, sd_card_driver_init_cleanup, "Send address");
+
+	/* Stop multiple block write */
+	sd_card_stop_multiple_block_write( e);
+
+	/* Get card status */
+	sd_card_send_command( e, SD_CARD_CMD_SEND_STATUS, 0);
+
+	/* Stop multiple block read */
+	sd_card_stop_multiple_block_read( e);
+
+	/* Switch to SPI mode */
+	rv = sd_card_send_command( e, SD_CARD_CMD_GO_IDLE_STATE, 0);
+	RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Send: SD_CARD_CMD_GO_IDLE_STATE");
+
+	/*
+	 * Get interface condition, CMD8.  This is new for SD 2.x and enables
+	 * getting the High Capacity Support flag HCS and checks that the
+	 * voltage is right.  Some MMCs accept this command but will still fail
+	 * on ACMD41.  SD 1.x cards will fails this command and do not support
+	 * HCS (> 2G capacity).
+	 */
+	rv = sd_card_send_register_command( e, SD_CARD_CMD_SEND_IF_COND, if_cond_reg, &if_cond_reg);
+
+	/*
+	 * Regardless of whether CMD8 above passes or fails, send ACMD41.  If
+	 * card is MMC it will fail.  But older SD < 2.0 (which fail CMD8) will
+	 * always stay "idle" if cmd_arg is non-zero, so set to 0 above on
+	 * fail.
+	 */
+	if (rv < 0) {
+		/* Failed CMD8, so SD 1.x or MMC */
+		cmd_arg = 0;
+	} else {
+		cmd_arg = SD_CARD_FLAG_HCS;
+	}
+
+	/* Enable CRC */
+	sd_card_send_command( e, SD_CARD_CMD_CRC_ON_OFF, 1);
+
+	/* Initialize card */
+	while (true) {
+		if (assume_sd) {
+			/* This command (CMD55) supported by SD and (most?) MMCs */
+			rv = sd_card_send_command( e, SD_CARD_CMD_APP_CMD, 0);
+			if (rv < 0) {
+				RTEMS_SYSLOG( "CMD55 failed.  Assume MMC and try CMD1\n");
+				assume_sd = false;
+				continue;
+			}
+
+			/*
+			 * This command (ACMD41) only supported by SD.  Always
+			 * fails if MMC.
+			 */
+			rv = sd_card_send_command( e, SD_CARD_ACMD_SD_SEND_OP_COND, cmd_arg);
+			if (rv < 0) {
+				/*
+				 * This *will* fail for MMC.  If fails, bad/no
+				 * card or card is MMC, do CMD58 then CMD1.
+				 */
+				RTEMS_SYSLOG( "ACMD41 failed.  Assume MMC and do CMD58 (once) then CMD1\n");
+				assume_sd = false;
+				cmd_arg = SD_CARD_FLAG_HCS;
+				do_cmd58 = true;
+				continue;
+			} else {
+				/*
+				 * Passed ACMD41 so SD.  It is now save to
+				 * check if_cond_reg from CMD8.  Reject the
+				 * card in case of a indicated bad voltage.
+				 */
+				if (if_cond_reg != if_cond_test) {
+					RTEMS_CLEANUP_RV_SC( -1, sc, sd_card_driver_init_cleanup, "Bad voltage for SD");
+				}
+			}
+		} else {
+			/*
+			 * Does not seem to be SD card.  Do init for MMC.
+			 * First send CMD58 once to enable check for HCS
+			 * (similar to CMD8 of SD) with bits 30:29 set to 10b.
+			 * This will work for MMC >= 4.2.  Older cards (<= 4.1)
+			 * may may not respond to CMD1 unless CMD58 is sent
+			 * again with zero argument.
+			 */
+			if (do_cmd58) {
+				rv = sd_card_send_command( e, SD_CARD_CMD_READ_OCR, cmd_arg);
+				RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Failed CMD58 for MMC");
+
+				/* A one-shot call */
+				do_cmd58 = false;
+			}
+
+			/* Do CMD1 */
+			rv = sd_card_send_command( e, SD_CARD_CMD_SEND_OP_COND, 0);
+			if (rv < 0) {
+				if (cmd_arg != 0) {
+					/*
+					 * Send CMD58 again with zero argument
+					 * value.  Proves card is not
+					 * high_capacity.
+					 */
+					cmd_arg = 0;
+					do_cmd58 = true;
+					high_capacity = false;
+					continue;
+				}
+
+				RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Failed to initialize MMC");
+			}
+		}
+
+		/*
+		 * Not idle?
+		 *
+		 * This hangs forever if the card remains not idle and sends
+		 * always a valid response.
+		 */
+		if (SD_CARD_IS_NOT_IDLE_RESPONSE( e->response [e->response_index])) {
+			break;
+		}
+
+		/* Invoke the scheduler */
+		rtems_task_wake_after( RTEMS_YIELD_PROCESSOR);
+	}
+
+	/* Now we know if we are SD or MMC */
+	if (assume_sd) {
+		if (cmd_arg == 0) {
+			/* SD is < 2.0 so never high capacity (<= 2G) */
+			high_capacity = 0;
+		} else {
+			uint32_t reg = 0;
+
+			/*
+			 * SD is definitely 2.x.  Now need to send CMD58 to get
+			 * the OCR to see if the HCS bit is set (capacity > 2G)
+			 * or if bit is off (capacity <= 2G, standard
+			 * capacity).
+			 */
+			rv = sd_card_send_register_command( e, SD_CARD_CMD_READ_OCR, 0, &reg);
+			RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Failed CMD58 for SD 2.x");
+
+			/* Check HCS bit of OCR */
+			high_capacity = (reg & SD_CARD_FLAG_HCS) != 0;
+		}
+	} else {
+		/*
+		 * Card is MMC.  Unless already proven to be not HCS (< 4.2)
+		 * must do CMD58 again to check the OCR bits 30:29.
+		 */
+		if (high_capacity) {
+			uint32_t reg = 0;
+
+			/*
+			 * The argument should still be correct since was never
+			 * set to 0
+			 */
+			rv = sd_card_send_register_command( e, SD_CARD_CMD_READ_OCR, cmd_arg, &reg);
+			RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Failed CMD58 for MMC 4.2");
+
+			/* Check HCS bit of the OCR */
+			high_capacity = (reg & SD_CARD_FLAG_HCS) != 0;
+		}
+	}
+
+	/* Card Identification */
+	if (e->verbose) {
+		rv = sd_card_send_command( e, SD_CARD_CMD_SEND_CID, 0);
+		RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Send: SD_CARD_CMD_SEND_CID");
+		rv = sd_card_read( e, SD_CARD_START_BLOCK_SINGLE_BLOCK_READ, block, SD_CARD_CID_SIZE);
+		RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Read: SD_CARD_CMD_SEND_CID");
+		RTEMS_SYSLOG( "*** Card Identification ***\n");
+		RTEMS_SYSLOG( "Manufacturer ID          : %" PRIu8 "\n", SD_CARD_CID_GET_MID( block));
+		RTEMS_SYSLOG( "OEM/Application ID       : %" PRIu16 "\n", SD_CARD_CID_GET_OID( block));
+		RTEMS_SYSLOG(
+			"Product name             : %c%c%c%c%c%c\n",
+			SD_CARD_CID_GET_PNM( block, 0),
+			SD_CARD_CID_GET_PNM( block, 1),
+			SD_CARD_CID_GET_PNM( block, 2),
+			SD_CARD_CID_GET_PNM( block, 3),
+			SD_CARD_CID_GET_PNM( block, 4),
+			SD_CARD_CID_GET_PNM( block, 5)
+		);
+		RTEMS_SYSLOG( "Product revision         : %" PRIu8 "\n", SD_CARD_CID_GET_PRV( block));
+		RTEMS_SYSLOG( "Product serial number    : %" PRIu32 "\n", SD_CARD_CID_GET_PSN( block));
+		RTEMS_SYSLOG( "Manufacturing date       : %" PRIu8 "\n", SD_CARD_CID_GET_MDT( block));
+		RTEMS_SYSLOG( "7-bit CRC checksum       : %" PRIu8 "\n",  SD_CARD_CID_GET_CRC7( block));
+		crc7 = sd_card_compute_crc7( block, 15);
+		if (crc7 != SD_CARD_CID_GET_CRC7( block))
+			RTEMS_SYSLOG( "  Failed! (computed %02" PRIx8 ")\n", crc7);
+	}
+
+	/* Card Specific Data */
+
+	/* Read CSD */
+	rv = sd_card_send_command( e, SD_CARD_CMD_SEND_CSD, 0);
+	RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Send: SD_CARD_CMD_SEND_CSD");
+	rv = sd_card_read( e, SD_CARD_START_BLOCK_SINGLE_BLOCK_READ, block, SD_CARD_CSD_SIZE);
+	RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Read: SD_CARD_CMD_SEND_CSD");
+
+	crc7 = sd_card_compute_crc7( block, 15);
+	if (crc7 != SD_CARD_CID_GET_CRC7( block)) {
+		RTEMS_SYSLOG( "SD_CARD_CMD_SEND_CSD CRC failed\n");
+		sc = RTEMS_IO_ERROR;
+		goto sd_card_driver_init_cleanup;
+	}
+	
+	/* CSD Structure */
+	csd_structure = SD_CARD_CSD_GET_CSD_STRUCTURE( block);
+
+	/* Transfer speed and access time */
+	transfer_speed = sd_card_transfer_speed( block);
+	e->transfer_mode.baudrate = transfer_speed;
+	e->n_ac_max = sd_card_max_access_time( block, transfer_speed);
+
+	/* Block sizes and capacity */
+	if (csd_structure == 0 || !assume_sd) {
+		/* Treat MMC same as CSD Version 1.0 */
+
+		read_block_size = 1U << SD_CARD_CSD_GET_READ_BLK_LEN( block);
+		e->block_size_shift = SD_CARD_CSD_GET_WRITE_BLK_LEN( block);
+		write_block_size = 1U << e->block_size_shift;
+		if (read_block_size < write_block_size) {
+			RTEMS_SYSLOG_ERROR( "Read block size smaller than write block size\n");
+			return -RTEMS_IO_ERROR;
+		}
+		e->block_size = write_block_size;
+		e->block_number = sd_card_block_number( block);
+		capacity = sd_card_capacity( block);
+	} else if (csd_structure == 1) {
+		uint32_t c_size = SD_CARD_CSD_1_GET_C_SIZE( block);
+
+		/* Block size is fixed in CSD Version 2.0 */
+		e->block_size_shift = 9;
+		e->block_size = 512;
+
+		e->block_number = (c_size + 1) * 1024;
+		capacity = (c_size + 1) * 512 * 1024;
+		read_block_size = 512;
+		write_block_size = 512;
+
+		/* Timeout is fixed at 100ms in CSD Version 2.0 */
+		e->n_ac_max = transfer_speed / 80;
+	} else {
+		RTEMS_DO_CLEANUP_SC( RTEMS_IO_ERROR, sc, sd_card_driver_init_cleanup, "Unexpected CSD Structure number");
+	}
+
+	/* Print CSD information */
+	if (e->verbose) {
+		RTEMS_SYSLOG( "*** Card Specific Data ***\n");
+		RTEMS_SYSLOG( "CSD structure            : %" PRIu8 "\n", SD_CARD_CSD_GET_CSD_STRUCTURE( block));
+		RTEMS_SYSLOG( "Spec version             : %" PRIu8 "\n", SD_CARD_CSD_GET_SPEC_VERS( block));
+		RTEMS_SYSLOG( "Access time [ns]         : %" PRIu32 "\n", sd_card_access_time( block));
+		RTEMS_SYSLOG( "Access time [N]          : %" PRIu32 "\n", SD_CARD_CSD_GET_NSAC( block)*100);
+		RTEMS_SYSLOG( "Max access time [N]      : %" PRIu32 "\n", e->n_ac_max);
+		RTEMS_SYSLOG( "Max read block size [B]  : %" PRIu32 "\n", read_block_size);
+		RTEMS_SYSLOG( "Max write block size [B] : %" PRIu32 "\n", write_block_size);
+		RTEMS_SYSLOG( "Block size [B]           : %" PRIu32 "\n", e->block_size);
+		RTEMS_SYSLOG( "Block number             : %" PRIu32 "\n", e->block_number);
+		RTEMS_SYSLOG( "Capacity [B]             : %" PRIu64 "\n", capacity);
+		RTEMS_SYSLOG( "Max transfer speed [b/s] : %" PRIu32 "\n", transfer_speed);
+	}
+
+	if (high_capacity) {
+		/* For high capacity cards the address is in blocks */
+		e->block_size_shift = 0;
+	} else if (e->block_size_shift == 10) {
+		/*
+		 * Low capacity 2GByte cards with reported block size of 1024
+		 * need to be set back to block size of 512 per 'Simplified
+		 * Physical Layer Specification Version 2.0' section 4.3.2.
+		 * Otherwise, CMD16 fails if set to 1024.
+		 */
+		e->block_size_shift = 9;
+		e->block_size = 512;
+		e->block_number *= 2;
+	}
+
+	/* Set read block size */
+	rv = sd_card_send_command( e, SD_CARD_CMD_SET_BLOCKLEN, e->block_size);
+	RTEMS_CLEANUP_RV_SC( rv, sc, sd_card_driver_init_cleanup, "Send: SD_CARD_CMD_SET_BLOCKLEN");
+
+	/* Stop */
+	sc = sd_card_stop( e);
+	RTEMS_CHECK_SC( sc, "Stop");
+
+	return RTEMS_SUCCESSFUL;
+
+sd_card_driver_init_cleanup:
+
+	/* Stop */
+	sd_card_stop( e);
+
+	return sc;
+}
+/** @} */
+
+/**
+ * @name Disk Driver Functions
+ * @{
+ */
+
+static int sd_card_disk_block_read( sd_card_driver_entry *e, rtems_blkdev_request *r)
+{
+	rtems_status_code sc = RTEMS_SUCCESSFUL;
+	int rv = 0;
+	uint32_t start_address = RTEMS_BLKDEV_START_BLOCK (r) << e->block_size_shift;
+	uint32_t i = 0;
+
+#ifdef DEBUG
+	/* Check request */
+	if (r->bufs[0].block >= e->block_number) {
+		RTEMS_SYSLOG_ERROR( "Start block number out of range");
+		return -RTEMS_INTERNAL_ERROR;
+	} else if (r->bufnum > e->block_number - RTEMS_BLKDEV_START_BLOCK (r)) {
+		RTEMS_SYSLOG_ERROR( "Block count out of range");
+		return -RTEMS_INTERNAL_ERROR;
+	}
+#endif /* DEBUG */
+
+	/* Start */
+	sc = sd_card_start( e);
+	RTEMS_CLEANUP_SC_RV( sc, rv, sd_card_disk_block_read_cleanup, "Start");
+
+	if (r->bufnum == 1) {
+#ifdef DEBUG
+		/* Check buffer */
+		if (r->bufs [0].length != e->block_size) {
+			RTEMS_DO_CLEANUP_RV( -RTEMS_INTERNAL_ERROR, rv, sd_card_disk_block_read_cleanup, "Buffer and disk block size are not equal");
+		}
+		RTEMS_DEBUG_PRINT( "[01:01]: buffer = 0x%08x, size = %u\n", r->bufs [0].buffer, r->bufs [0].length);
+#endif /* DEBUG */
+
+		/* Single block read */
+		rv = sd_card_send_command( e, SD_CARD_CMD_READ_SINGLE_BLOCK, start_address);
+		RTEMS_CLEANUP_RV( rv, sd_card_disk_block_read_cleanup, "Send: SD_CARD_CMD_READ_SINGLE_BLOCK");
+		rv = sd_card_read( e, SD_CARD_START_BLOCK_SINGLE_BLOCK_READ, (uint8_t *) r->bufs [0].buffer, (int) e->block_size);
+		RTEMS_CLEANUP_RV( rv, sd_card_disk_block_read_cleanup, "Read: SD_CARD_CMD_READ_SINGLE_BLOCK");
+	} else {
+		/* Start multiple block read */
+		rv = sd_card_send_command( e, SD_CARD_CMD_READ_MULTIPLE_BLOCK, start_address);
+		RTEMS_CLEANUP_RV( rv, sd_card_disk_block_read_stop_cleanup, "Send: SD_CARD_CMD_READ_MULTIPLE_BLOCK");
+
+		/* Multiple block read */
+		for (i = 0; i < r->bufnum; ++i) {
+#ifdef DEBUG
+			/* Check buffer */
+			if (r->bufs [i].length != e->block_size) {
+				RTEMS_DO_CLEANUP_RV( -RTEMS_INTERNAL_ERROR, rv, sd_card_disk_block_read_stop_cleanup, "Buffer and disk block size are not equal");
+			}
+			RTEMS_DEBUG_PRINT( "[%02u:%02u]: buffer = 0x%08x, size = %u\n", i + 1, r->bufnum, r->bufs [i].buffer, r->bufs [i].length);
+#endif /* DEBUG */
+
+			rv = sd_card_read( e, SD_CARD_START_BLOCK_MULTIPLE_BLOCK_READ, (uint8_t *) r->bufs [i].buffer, (int) e->block_size);
+			RTEMS_CLEANUP_RV( rv, sd_card_disk_block_read_stop_cleanup, "Read block");
+		}
+
+		/* Stop multiple block read */
+		rv = sd_card_stop_multiple_block_read( e);
+		RTEMS_CLEANUP_RV( rv, sd_card_disk_block_read_cleanup, "Stop multiple block read");
+	}
+
+	/* Stop */
+	sc = sd_card_stop( e);
+	RTEMS_CHECK_SC_RV( sc, "Stop");
+
+	/* Done */
+	rtems_blkdev_request_done( r, RTEMS_SUCCESSFUL);
+
+	return 0;
+
+sd_card_disk_block_read_stop_cleanup:
+
+	/* Stop multiple block read */
+	sd_card_stop_multiple_block_read( e);
+
+sd_card_disk_block_read_cleanup:
+
+	/* Stop */
+	sd_card_stop( e);
+
+	/* Done */
+	rtems_blkdev_request_done( r, RTEMS_IO_ERROR);
+
+	return 0;
+}
+
+static int sd_card_disk_block_write( sd_card_driver_entry *e, rtems_blkdev_request *r)
+{
+	rtems_status_code sc = RTEMS_SUCCESSFUL;
+	int rv = 0;
+	uint32_t start_address = RTEMS_BLKDEV_START_BLOCK (r) << e->block_size_shift;
+	uint32_t i = 0;
+
+#ifdef DEBUG
+	/* Check request */
+	if (r->bufs[0].block >= e->block_number) {
+		RTEMS_SYSLOG_ERROR( "Start block number out of range");
+		return -RTEMS_INTERNAL_ERROR;
+	} else if (r->bufnum > e->block_number - RTEMS_BLKDEV_START_BLOCK (r)) {
+		RTEMS_SYSLOG_ERROR( "Block count out of range");
+		return -RTEMS_INTERNAL_ERROR;
+	}
+#endif /* DEBUG */
+
+	/* Start */
+	sc = sd_card_start( e);
+	RTEMS_CLEANUP_SC_RV( sc, rv, sd_card_disk_block_write_cleanup, "Start");
+
+	if (r->bufnum == 1) {
+#ifdef DEBUG
+		/* Check buffer */
+		if (r->bufs [0].length != e->block_size) {
+			RTEMS_DO_CLEANUP_RV( -RTEMS_INTERNAL_ERROR, rv, sd_card_disk_block_write_cleanup, "Buffer and disk block size are not equal");
+		}
+		RTEMS_DEBUG_PRINT( "[01:01]: buffer = 0x%08x, size = %u\n", r->bufs [0].buffer, r->bufs [0].length);
+#endif /* DEBUG */
+
+		/* Single block write */
+		rv = sd_card_send_command( e, SD_CARD_CMD_WRITE_BLOCK, start_address);
+		RTEMS_CLEANUP_RV( rv, sd_card_disk_block_write_cleanup, "Send: SD_CARD_CMD_WRITE_BLOCK");
+		rv = sd_card_write( e, SD_CARD_START_BLOCK_SINGLE_BLOCK_WRITE, (uint8_t *) r->bufs [0].buffer, (int) e->block_size);
+		RTEMS_CLEANUP_RV( rv, sd_card_disk_block_write_cleanup, "Write: SD_CARD_CMD_WRITE_BLOCK");
+	} else {
+		/* Start multiple block write */
+		rv = sd_card_send_command( e, SD_CARD_CMD_WRITE_MULTIPLE_BLOCK, start_address);
+		RTEMS_CLEANUP_RV( rv, sd_card_disk_block_write_stop_cleanup, "Send: SD_CARD_CMD_WRITE_MULTIPLE_BLOCK");
+
+		/* Multiple block write */
+		for (i = 0; i < r->bufnum; ++i) {
+#ifdef DEBUG
+			/* Check buffer */
+			if (r->bufs [i].length != e->block_size) {
+				RTEMS_DO_CLEANUP_RV( -RTEMS_INTERNAL_ERROR, rv, sd_card_disk_block_write_stop_cleanup, "Buffer and disk block size are not equal");
+			}
+			RTEMS_DEBUG_PRINT( "[%02u:%02u]: buffer = 0x%08x, size = %u\n", i + 1, r->bufnum, r->bufs [i].buffer, r->bufs [i].length);
+#endif /* DEBUG */
+
+			rv = sd_card_write( e, SD_CARD_START_BLOCK_MULTIPLE_BLOCK_WRITE, (uint8_t *) r->bufs [i].buffer, (int) e->block_size);
+			RTEMS_CLEANUP_RV( rv, sd_card_disk_block_write_stop_cleanup, "Write block");
+		}
+
+		/* Stop multiple block write */
+		rv = sd_card_stop_multiple_block_write( e);
+		RTEMS_CLEANUP_RV( rv, sd_card_disk_block_write_cleanup, "Stop multiple block write");
+	}
+
+	/* Get card status */
+	rv = sd_card_send_command( e, SD_CARD_CMD_SEND_STATUS, 0);
+	RTEMS_CHECK_RV( rv, "Send: SD_CARD_CMD_SEND_STATUS");
+
+	/* Stop */
+	sc = sd_card_stop( e);
+	RTEMS_CHECK_SC_RV( sc, "Stop");
+
+	/* Done */
+	rtems_blkdev_request_done( r, RTEMS_SUCCESSFUL);
+
+	return 0;
+
+sd_card_disk_block_write_stop_cleanup:
+
+	/* Stop multiple block write */
+	sd_card_stop_multiple_block_write( e);
+
+sd_card_disk_block_write_cleanup:
+
+	/* Get card status */
+	rv = sd_card_send_command( e, SD_CARD_CMD_SEND_STATUS, 0);
+	RTEMS_CHECK_RV( rv, "Send: SD_CARD_CMD_SEND_STATUS");
+
+	/* Stop */
+	sd_card_stop( e);
+
+	/* Done */
+	rtems_blkdev_request_done( r, RTEMS_IO_ERROR);
+
+	return 0;
+}
+
+static int sd_card_disk_ioctl( rtems_disk_device *dd, uint32_t req, void *arg)
+{
+	RTEMS_DEBUG_PRINT( "sd_card_disk_ioctl minor = %u, req = 0x%08x, arg = %p\n",
+	                (unsigned)rtems_filesystem_dev_minor_t(dd->dev), (unsigned)req, arg);
+	if (req == RTEMS_BLKIO_REQUEST) {
+		rtems_device_minor_number minor = rtems_disk_get_minor_number( dd);
+		sd_card_driver_entry *e = &sd_card_driver_table [minor];
+		rtems_blkdev_request *r = (rtems_blkdev_request *) arg;
+		int (*f)( sd_card_driver_entry *, rtems_blkdev_request *);
+		uint32_t retries = e->retries;
+		int result;
+
+		switch (r->req) {
+			case RTEMS_BLKDEV_REQ_READ:
+				f = sd_card_disk_block_read;
+				break;
+			case RTEMS_BLKDEV_REQ_WRITE:
+				f = sd_card_disk_block_write;
+				break;
+			default:
+				errno = EINVAL;
+				return -1;
+		}
+		do {
+			result = f( e, r);
+		} while (retries-- > 0 && result != 0);
+		return result;
+
+	} else if (req == RTEMS_BLKIO_CAPABILITIES) {
+		*(uint32_t *) arg = RTEMS_BLKDEV_CAP_MULTISECTOR_CONT;
+		return 0;
+	} else {
+		return rtems_blkdev_ioctl( dd, req, arg );
+	}
+}
+
+static rtems_status_code sd_card_disk_init( rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+	/* Initialize disk IO */
+	sc = rtems_disk_io_initialize();
+	RTEMS_CHECK_SC( sc, "Initialize RTEMS disk IO");
+
+	for (minor = 0; minor < sd_card_driver_table_size; ++minor) {
+		sd_card_driver_entry *e = &sd_card_driver_table [minor];
+		dev_t dev = rtems_filesystem_make_dev_t( major, minor);
+		uint32_t retries = e->retries;
+
+		/* Initialize SD Card */
+		do {
+			sc = sd_card_init( e);
+		} while (retries-- > 0 && sc != RTEMS_SUCCESSFUL);
+		RTEMS_CHECK_SC( sc, "Initialize SD Card");
+
+		/* Create disk device */
+		sc = rtems_disk_create_phys( dev, e->block_size, e->block_number, sd_card_disk_ioctl, NULL, e->device_name);
+		RTEMS_CHECK_SC( sc, "Create disk device");
+	}
+
+	return RTEMS_SUCCESSFUL;
+}
+
+/** @} */
+
+static const rtems_driver_address_table sd_card_disk_ops = {
+	.initialization_entry = sd_card_disk_init,
+	.open_entry = rtems_blkdev_generic_open,
+	.close_entry = rtems_blkdev_generic_close,
+	.read_entry = rtems_blkdev_generic_read,
+	.write_entry = rtems_blkdev_generic_write,
+	.control_entry = rtems_blkdev_generic_ioctl
+};
+
+rtems_status_code sd_card_register( void)
+{
+	rtems_status_code sc = RTEMS_SUCCESSFUL;
+	rtems_device_major_number major = 0;
+
+	sc = rtems_io_register_driver( 0, &sd_card_disk_ops, &major);
+	RTEMS_CHECK_SC( sc, "Register disk SD Card driver");
+
+	return RTEMS_SUCCESSFUL;
+}
Index: bsps/shared/dev/ide/ata.c
===================================================================
--- bsps/shared/dev/ide/ata.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/ide/ata.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,1360 @@
+/*
+ * ata.c
+ *
+ * ATA RTEMS driver. ATA driver is hardware independant implementation of
+ * ATA-2 standard, working draft X3T10/0948D, revision 4c. ATA driver bases
+ * on RTEMS IDE controller driver.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Authors: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ */
+#include <errno.h>
+#include <rtems/chain.h>
+#include <assert.h>
+#include <string.h> /* for "memset" declaration */
+
+#include <rtems/diskdevs.h>
+#include <rtems/blkdev.h>
+#include <libchip/ide_ctrl_io.h>
+#include <libchip/ide_ctrl_cfg.h>
+#include <libchip/ata_internal.h>
+#include <libchip/ata.h>
+
+#define ATA_DEBUG 0
+
+#if ATA_DEBUG
+#include <stdio.h>
+bool ata_trace;
+#define ata_printf if (ata_trace) printf
+#endif
+
+#if CPU_SIMPLE_VECTORED_INTERRUPTS != TRUE
+#include <rtems/irq.h>
+#define ATA_IRQ_CHAIN_MAX_CNT 4 /* support up to 4 ATA devices */
+typedef struct {
+  rtems_irq_number name;
+  rtems_chain_control irq_chain;
+} ata_irq_chain_t;
+
+ata_irq_chain_t ata_irq_chain[ATA_IRQ_CHAIN_MAX_CNT];
+int ata_irq_chain_cnt = 0;
+#endif
+
+static rtems_id ata_lock;
+static void
+rtems_ata_lock (void)
+{
+  rtems_status_code sc = rtems_semaphore_obtain (ata_lock,
+                                                 RTEMS_WAIT,
+                                                 RTEMS_NO_TIMEOUT);
+  if (sc != RTEMS_SUCCESSFUL)
+    rtems_fatal_error_occurred (RTEMS_INTERNAL_ERROR);
+}
+
+static void
+rtems_ata_unlock (void)
+{
+  rtems_status_code sc = rtems_semaphore_release (ata_lock);
+  if (sc != RTEMS_SUCCESSFUL)
+    rtems_fatal_error_occurred (RTEMS_INTERNAL_ERROR);
+}
+
+#define RTEMS_ATA_LOCK_ATTRIBS \
+  (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \
+   RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
+
+/* FIXME: case if ATA device is FLASH device need more attention */
+#undef ATA_DEV_IS_FLASH_DISK
+
+/* Array indexed by controllers minor number */
+static ata_ide_ctrl_t ata_ide_ctrls[IDE_CTRL_MAX_MINOR_NUMBER];
+
+/*
+ * Mapping from ATA-minor numbers to
+ * controller-minor and device on this controller.
+ */
+static ata_ide_dev_t ata_devs[2 * IDE_CTRL_MAX_MINOR_NUMBER];
+static int ata_devs_number;
+
+/* Flag meaning that ATA driver has already been initialized */
+static bool ata_initialized = false;
+
+
+/* task and queue used for asynchronous I/O operations */
+static rtems_id ata_task_id;
+static rtems_id ata_queue_id;
+
+#if CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE
+/* Mapping of interrupt vectors to devices */
+static rtems_chain_control ata_int_vec[ATA_MAX_RTEMS_INT_VEC_NUMBER + 1];
+#endif
+
+static void
+ata_process_request(rtems_device_minor_number ctrl_minor);
+
+static void
+ata_add_to_controller_queue(rtems_device_minor_number  ctrl_minor,
+                            ata_req_t                 *areq);
+
+/*
+ * read/write, open/close and ioctl are provided by general block device
+ * driver. Only initialization and ata-specific ioctl are here.
+ */
+
+/* ata_io_data_request --
+ *     Form read/write request for an ATA device and enqueue it to
+ *     IDE controller.
+ *
+ * PARAMETERS:
+ *     device - device identifier
+ *     req    - read/write request from block device driver
+ *
+ * RETURNS:
+ *     RTEMS_SUCCESSFUL on success, or error code if
+ *     error occured
+ */
+static rtems_status_code
+ata_io_data_request(dev_t device, rtems_blkdev_request *req)
+{
+    ata_req_t                 *areq; /* ATA request */
+    rtems_device_minor_number  rel_minor; /* relative minor which indexes
+                                           * ata_devs array
+                                           */
+    rtems_device_minor_number  ctrl_minor;
+    uint8_t                    dev;
+
+    rel_minor = (rtems_filesystem_dev_minor_t(device)) /
+                ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE;
+
+    /* get controller which serves the ATA device */
+    ctrl_minor = ata_devs[rel_minor].ctrl_minor;
+
+    /* get ATA device identifier (0 or 1) */
+    dev = ata_devs[rel_minor].device;
+
+    areq = malloc(sizeof(ata_req_t));
+    if (areq == NULL)
+    {
+        rtems_blkdev_request_done(req, RTEMS_NO_MEMORY);
+        return RTEMS_SUCCESSFUL;
+    }
+
+    areq->breq = req;
+    areq->cnt = req->bufnum;
+    areq->cbuf = 0;
+    areq->pos = 0;
+
+    /* set up registers masks */
+    areq->regs.to_write = ATA_REGISTERS_POSITION;
+    areq->regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
+
+    /* choose device on the controller for which the command will be issued */
+    areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] =
+                                    (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS);
+
+    /* Find ATA command and its type */
+    if (ATA_DEV_INFO(ctrl_minor, dev).mode_active & ATA_MODES_DMA)
+    {
+        /* XXX: never has been tested */
+        areq->type = ATA_COMMAND_TYPE_DMA;
+        if (req->req == RTEMS_BLKDEV_REQ_READ)
+            areq->regs.regs[IDE_REGISTER_COMMAND] = ATA_COMMAND_READ_DMA;
+        else
+            areq->regs.regs[IDE_REGISTER_COMMAND] = ATA_COMMAND_WRITE_DMA;
+    }
+    else
+    {
+        if (req->req == RTEMS_BLKDEV_REQ_READ)
+        {
+            areq->type = ATA_COMMAND_TYPE_PIO_IN;
+            areq->regs.regs[IDE_REGISTER_COMMAND] = ATA_COMMAND_READ_SECTORS;
+#if ATA_DEBUG
+            ata_printf("ata_io_data_request: type: READ: %lu, %lu cmd:%02x\n",
+                       req->bufs[0].block, req->bufnum,
+                       areq->regs.regs[IDE_REGISTER_COMMAND]);
+#endif
+        }
+        else
+        {
+            areq->type = ATA_COMMAND_TYPE_PIO_OUT;
+            areq->regs.regs[IDE_REGISTER_COMMAND] = ATA_COMMAND_WRITE_SECTORS;
+#if ATA_DEBUG
+            ata_printf("ata_io_data_request: type: WRITE: %lu, %lu cmd:%02x\n",
+                       req->bufs[0].block, req->bufnum,
+                       areq->regs.regs[IDE_REGISTER_COMMAND]);
+#endif
+        }
+    }
+
+    /*
+     * Fill position registers
+     */
+    if (ATA_DEV_INFO(ctrl_minor, dev).lba_avaible)
+    {
+        uint32_t start = req->bufs[0].block;
+        areq->regs.regs[IDE_REGISTER_LBA0] = (uint8_t)start;
+        areq->regs.regs[IDE_REGISTER_LBA1] = (uint8_t)(start >> 8);
+        areq->regs.regs[IDE_REGISTER_LBA2] = (uint8_t)(start >> 16);
+        /* Set as the head register write above */
+        areq->regs.regs[IDE_REGISTER_LBA3] |= (uint8_t) (start >> 24);
+        areq->regs.regs[IDE_REGISTER_LBA3] |= IDE_REGISTER_LBA3_L;
+    }
+    else
+    {
+        uint32_t   count = req->bufs[0].block;
+
+        areq->regs.regs[IDE_REGISTER_SECTOR_NUMBER] =
+                        (count % ATA_DEV_INFO(ctrl_minor, dev).sectors) + 1;
+
+        /* now count = number of tracks: */
+        count /= ATA_DEV_INFO(ctrl_minor, dev).sectors;
+        areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] |=
+                          (count / ATA_DEV_INFO(ctrl_minor, dev).cylinders);
+
+        /* now count = number of cylinders */
+        count %= ATA_DEV_INFO(ctrl_minor, dev).cylinders;
+        areq->regs.regs[IDE_REGISTER_CYLINDER_LOW] = (uint8_t)count;
+        areq->regs.regs[IDE_REGISTER_CYLINDER_HIGH] = (uint8_t)(count >> 8);
+        areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &=
+                                                ~IDE_REGISTER_DEVICE_HEAD_L;
+    }
+
+    /*
+     * Fill sector count register. We have a number of buffers (bufnum) which
+     * can be of a specific length (bufs[0].length / ATA_SECTOR_SIZE).
+     */
+    areq->regs.regs[IDE_REGISTER_SECTOR_COUNT] =
+      areq->breq->bufnum * (areq->breq->bufs[0].length / ATA_SECTOR_SIZE);
+
+    /* add request to the queue of awaiting requests to the controller */
+    ata_add_to_controller_queue(ctrl_minor, areq);
+
+    return RTEMS_SUCCESSFUL;
+}
+
+/* ata_non_data_request --
+ *     Form and serve request of NON DATA type for an ATA device.
+ *     Processing of NON DATA request is SYNChronous operation.
+ *
+ * PARAMETERS:
+ *     device - device identifier
+ *     cmd    - command
+ *     argp   - arguments for command
+ *
+ * RETURNS:
+ *     RTEMS_SUCCESSFUL on success, or error code if
+ *     error occured
+ */
+static rtems_status_code
+ata_non_data_request(dev_t device, uint32_t cmd, void *argp)
+{
+    rtems_status_code          rc;
+    ata_req_t                 *areq;       /* ATA request */
+    rtems_device_minor_number  rel_minor; /* relative minor which indexes
+                                           * ata_devs array
+                                           */
+    rtems_device_minor_number  ctrl_minor;
+    uint8_t                    dev;
+    ata_queue_msg_t            msg;
+
+    rel_minor = (rtems_filesystem_dev_minor_t(device)) /
+                ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE;
+
+    /* get controller which serves the ATA device */
+    ctrl_minor = ata_devs[rel_minor].ctrl_minor;
+
+    /* get ATA device identifier (0 or 1) */
+    dev = ata_devs[rel_minor].device;
+
+    /* form the request */
+    areq = malloc(sizeof(ata_req_t));
+    if (areq == NULL)
+    {
+        return RTEMS_NO_MEMORY;
+    }
+    memset(areq, 0, sizeof(ata_req_t));
+
+    areq->type = ATA_COMMAND_TYPE_NON_DATA;
+    areq->regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
+    areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] |=
+                                    (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS);
+    areq->breq = NULL;
+    areq->regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_ERROR);
+
+    /*
+     * depending on command fill command register and additional registers
+     * which are needed for command execution
+     */
+    switch(cmd)
+    {
+        case ATAIO_SET_MULTIPLE_MODE:
+            areq->regs.regs[IDE_REGISTER_COMMAND] =
+                                                ATA_COMMAND_SET_MULTIPLE_MODE;
+            areq->regs.to_write |=
+                               ATA_REGISTERS_VALUE(IDE_REGISTER_SECTOR_COUNT);
+            areq->regs.regs[IDE_REGISTER_SECTOR_COUNT] = *(uint8_t*)argp;
+            break;
+
+        default:
+            free(areq);
+            return RTEMS_INVALID_NUMBER;
+            break;
+    }
+
+    rc = rtems_semaphore_create(rtems_build_name('I', 'D', 'E', 'S'),
+                                0,
+                                RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE |
+                                RTEMS_NO_INHERIT_PRIORITY |
+                                RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
+                                0,
+                                &(areq->sema));
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        free(areq);
+        return rc;
+    }
+
+    ata_add_to_controller_queue(ctrl_minor, areq);
+
+    /* wait for request processing... */
+    rc = rtems_semaphore_obtain(areq->sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+    if (rc != RTEMS_SUCCESSFUL)
+    {
+        free(areq);
+        return rc;
+    }
+
+    rtems_semaphore_delete(areq->sema);
+
+    /*
+     * if no error occurred and if necessary, update internal ata driver data
+     * structures to reflect changes (in device configuration, for example)
+     */
+    if (areq->status == RTEMS_SUCCESSFUL)
+    {
+        switch(cmd)
+        {
+            case ATAIO_SET_MULTIPLE_MODE:
+              /* invalid operation now */
+            default:
+                rc = RTEMS_INVALID_NUMBER;
+                break;
+        }
+    }
+    else
+    {
+        /* XXX: should be correct error processing: for ex, may be
+         * ABRT and then we should return RTEMS_NOT_IMPLEMENTED
+         */
+        rc = RTEMS_IO_ERROR;
+    }
+
+    /* tell ata driver that controller ready to serve next request */
+    ATA_SEND_EVT(msg, ATA_MSG_SUCCESS_EVT, ctrl_minor, 0);
+
+    return rc;
+}
+
+/* ata_process_request --
+ *     Get first request from controller's queue and process it.
+ *
+ * PARAMETERS:
+ *     ctrl_minor - controller identifier
+ *
+ * RETURNS:
+ *     NONE
+ */
+static void
+ata_process_request(rtems_device_minor_number ctrl_minor)
+{
+    ata_req_t       *areq;
+    uint16_t         byte; /* emphasize that only 8 low bits is meaningful */
+    ata_queue_msg_t  msg;
+    uint8_t          i;
+#if 0
+    uint8_t          dev;
+#endif
+    uint16_t         val;
+    ISR_Level        level;
+
+    /* if no requests to controller then do nothing */
+    if (rtems_chain_is_empty(&ata_ide_ctrls[ctrl_minor].reqs))
+        return;
+
+    /* get first request in the controller's queue */
+    _ISR_Local_disable(level);
+    areq = (ata_req_t *)rtems_chain_first(&ata_ide_ctrls[ctrl_minor].reqs);
+    _ISR_Local_enable(level);
+
+#if 0
+    /* get ATA device identifier (0 or 1) */
+    dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
+           IDE_REGISTER_DEVICE_HEAD_DEV;
+#endif
+
+    /* execute device select protocol */
+    ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD,
+                                  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
+
+    do {
+        ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
+    } while ((byte & IDE_REGISTER_STATUS_BSY) ||
+             (!(byte & IDE_REGISTER_STATUS_DRDY)));
+
+    /* fill in all  necessary registers on the controller */
+    for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
+    {
+        uint32_t   reg = (1 << i);
+        if (areq->regs.to_write & reg)
+            ide_controller_write_register(ctrl_minor, i, areq->regs.regs[i]);
+    }
+
+#if ATA_DEBUG
+    ata_printf("ata_process_request: type: %d\n", areq->type);
+#endif
+
+    /* continue to execute ATA protocols depending on type of request */
+    if (areq->type == ATA_COMMAND_TYPE_PIO_OUT)
+    {
+        do {
+            ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS,
+                                         &byte);
+        } while (byte & IDE_REGISTER_STATUS_BSY);
+
+        if (byte & IDE_REGISTER_STATUS_DRQ)
+        {
+            if (areq->cnt)
+            {
+              int ccbuf = areq->cbuf;
+              ide_controller_write_data_block(ctrl_minor,
+                                              areq->breq->bufs[0].length * areq->cnt,
+                                              areq->breq->bufs, &areq->cbuf,
+                                              &areq->pos);
+              ccbuf = areq->cbuf - ccbuf;
+              areq->cnt -= ccbuf;
+            }
+        }
+        else
+        {
+            if (IDE_Controller_Table[ctrl_minor].int_driven == false)
+            {
+                ide_controller_read_register(
+                    ctrl_minor,
+                    IDE_REGISTER_ALTERNATE_STATUS_OFFSET,
+                    &val);
+                ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS,
+                                             &val);
+
+                ATA_SEND_EVT(msg, ATA_MSG_ERROR_EVT, ctrl_minor,
+                             RTEMS_IO_ERROR);
+            }
+        }
+    }
+
+    if (IDE_Controller_Table[ctrl_minor].int_driven == false)
+    {
+        do {
+            ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS,
+                                         &byte);
+        } while (byte & IDE_REGISTER_STATUS_BSY);
+
+        ATA_SEND_EVT(msg, ATA_MSG_GEN_EVT, ctrl_minor, 0);
+    }
+}
+
+/* ata_request_done --
+ *     Extract request from controller queue, execute callback if necessary
+ *     and process next request for the controller.
+ *
+ * PARAMETERS:
+ *     areq       - ATA request
+ *     ctrl_minor - controller identifier
+ *     status     - status with which request has been done
+ *     error      - error, if status != RTEMS_SUCCESSFUL
+ *
+ * RETURNS:
+ *     NONE
+ */
+static inline void
+ata_request_done(ata_req_t *areq, rtems_device_minor_number ctrl_minor,
+                 rtems_status_code status)
+{
+    assert(areq);
+
+#if ATA_DEBUG
+    ata_printf("ata_request_done: entry\n");
+#endif
+
+    ATA_EXEC_CALLBACK(areq, status);
+    rtems_chain_extract(&areq->link);
+
+    if (!rtems_chain_is_empty(&ata_ide_ctrls[ctrl_minor].reqs))
+    {
+        free(areq);
+        ata_process_request(ctrl_minor);
+        return;
+    }
+
+    free(areq);
+
+#if ATA_DEBUG
+    ata_printf("ata_request_done: exit\n");
+#endif
+}
+
+/* ata_non_data_request_done --
+ *     Set up request status and release request's semaphore.
+ *
+ * PARAMETERS:
+ *     areq       - ATA request
+ *     ctrl_minor - controller identifier
+ *     status     - status with which request has been done
+ *     error      - error, if status != RTEMS_SUCCESSFUL
+ *
+ * RETURNS:
+ *     NONE
+ */
+static inline void
+ata_non_data_request_done(ata_req_t *areq,
+                          rtems_device_minor_number ctrl_minor,
+                          rtems_status_code status, int info)
+{
+#if ATA_DEBUG
+    ata_printf("ata_non_data_request_done: entry\n");
+#endif
+
+    areq->status = status;
+    areq->info = info;
+    rtems_semaphore_release(areq->sema);
+}
+
+
+/* ata_add_to_controller_queue --
+ *     Add request to the controller's queue.
+ *
+ * PARAMETERS:
+ *     ctrl_minor - controller identifier
+ *     areq       - ATA request
+ *
+ * RETURNS:
+ *     NONE
+ */
+static void
+ata_add_to_controller_queue(rtems_device_minor_number  ctrl_minor,
+                            ata_req_t                 *areq)
+{
+    rtems_ata_lock();
+
+    rtems_chain_append(&ata_ide_ctrls[ctrl_minor].reqs, &areq->link);
+    if (rtems_chain_has_only_one_node(&ata_ide_ctrls[ctrl_minor].reqs))
+    {
+
+        ata_queue_msg_t msg;
+
+#if ATA_DEBUG_DOES_NOT_WORK_WITH_QEMU
+	uint16_t      val;
+        /*
+         * read IDE_REGISTER_ALTERNATE_STATUS instead IDE_REGISTER_STATUS
+         * to prevent clearing of pending interrupt
+         */
+        ide_controller_read_register(ctrl_minor,
+                                     IDE_REGISTER_ALTERNATE_STATUS,
+                                     &val);
+        if (val & IDE_REGISTER_STATUS_BSY)
+            return;
+#endif
+        ATA_SEND_EVT(msg, ATA_MSG_PROCESS_NEXT_EVT, ctrl_minor, 0);
+    }
+
+    rtems_ata_unlock();
+}
+
+
+/* ata_interrupt_handler --
+ *     ATA driver interrrupt handler. If interrrupt happend it mapped it to
+ *     controller (controllerS, if a number of controllers share one int line)
+ *     and generates ATA event(s).
+ *
+ * PARAMETERS:
+ *     vec - interrupt vector
+ *
+ * RETURNS:
+ *     NONE
+ */
+#if CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE
+static rtems_isr ata_interrupt_handler(rtems_vector_number vec)
+{
+    rtems_chain_node *the_node = rtems_chain_first(&ata_int_vec[vec]);
+    ata_queue_msg_t  msg;
+    uint16_t         byte; /* emphasize that only 8 low bits is meaningful */
+
+    for ( ; !rtems_chain_is_tail(&ata_int_vec[vec], the_node) ; )
+    {
+        /* if (1) - is temporary hack - currently I don't know how to identify
+         * controller which asserted interrupt if few controllers share one
+         * interrupt line
+         */
+        if (1)
+        {
+            msg.ctrl_minor = ((ata_int_st_t *)the_node)->ctrl_minor;
+            ide_controller_read_register(msg.ctrl_minor, IDE_REGISTER_STATUS,
+                                         &byte);
+            ATA_SEND_EVT(msg, ATA_MSG_GEN_EVT, msg.ctrl_minor, 0);
+        }
+        the_node = the_node->next;
+    }
+}
+#else
+static void ata_interrupt_handler(rtems_irq_hdl_param handle)
+{
+  uintptr_t ata_irq_chain_index = (uintptr_t) handle;
+    rtems_chain_node *the_node =
+      rtems_chain_last(&ata_irq_chain[ata_irq_chain_index].irq_chain);
+    ata_queue_msg_t  msg;
+    uint16_t       byte; /* emphasize that only 8 low bits is meaningful */
+
+
+    for ( ; !rtems_chain_is_tail(&ata_irq_chain[ata_irq_chain_index].irq_chain,
+			   the_node) ; )
+    {
+        /* if (1) - is temporary hack - currently I don't know how to identify
+         * controller which asserted interrupt if few controllers share one
+         * interrupt line
+         */
+        if (1)
+        {
+            msg.ctrl_minor = ((ata_int_st_t *)the_node)->ctrl_minor;
+            ide_controller_read_register(msg.ctrl_minor, IDE_REGISTER_STATUS,
+                                         &byte);
+            ATA_SEND_EVT(msg, ATA_MSG_GEN_EVT, msg.ctrl_minor, 0);
+        }
+        the_node = the_node->next;
+    }
+}
+
+static void ata_interrupt_on(const rtems_irq_connect_data *ptr)
+  {
+
+    /* enable ATA device interrupt */
+    ide_controller_write_register(0,
+                                  IDE_REGISTER_DEVICE_CONTROL_OFFSET,
+                                  0x00
+                                 );
+  }
+
+
+static void ata_interrupt_off(const rtems_irq_connect_data *ptr)
+  {
+
+    /* disable ATA device interrupt */
+    ide_controller_write_register(0,
+                                  IDE_REGISTER_DEVICE_CONTROL_OFFSET,
+                                  IDE_REGISTER_DEVICE_CONTROL_nIEN
+                                 );
+  }
+
+
+static int ata_interrupt_isOn(const rtems_irq_connect_data *ptr)
+  {
+  uint16_t byte; /* emphasize that only 8 low bits is meaningful */
+
+    /* return int. status od ATA device */
+    ide_controller_read_register(0,
+                                IDE_REGISTER_DEVICE_CONTROL_OFFSET,
+                                &byte
+                                );
+
+    return !(byte & IDE_REGISTER_DEVICE_CONTROL_nIEN);
+  }
+
+
+static rtems_irq_connect_data ata_irq_data =
+  {
+
+    0, /* filled out before use... */
+    ata_interrupt_handler,/* filled out before use... */
+    NULL,
+    ata_interrupt_on,
+    ata_interrupt_off,
+    ata_interrupt_isOn
+  };
+#endif
+
+/* ata_pio_in_protocol --
+ *     ATA PIO_IN protocol implementation, see specification
+ *
+ * PARAMETERS:
+ *     ctrl_minor - controller identifier
+ *     areq       - ATA request
+ *
+ * RETURNS:
+ *     NONE
+ */
+static inline void
+ata_pio_in_protocol(rtems_device_minor_number ctrl_minor, ata_req_t *areq)
+{
+    uint16_t        val;
+#if 0
+    uint8_t         dev;
+#endif
+    ata_queue_msg_t msg;
+
+#if 0
+    dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
+           IDE_REGISTER_DEVICE_HEAD_DEV;
+#endif
+
+    if (areq->cnt)
+    {
+      int ccbuf = areq->cbuf;
+      ide_controller_read_data_block(ctrl_minor,
+                                     areq->breq->bufs[0].length * areq->cnt,
+                                     areq->breq->bufs, &areq->cbuf, &areq->pos);
+      ccbuf = areq->cbuf - ccbuf;
+      areq->cnt -= ccbuf;
+    }
+
+    if (areq->cnt == 0)
+    {
+        ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL);
+    }
+    else if (IDE_Controller_Table[ctrl_minor].int_driven == false)
+    {
+        do {
+           ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
+        } while (val & IDE_REGISTER_STATUS_BSY);
+
+        ATA_SEND_EVT(msg, ATA_MSG_GEN_EVT, ctrl_minor, 0);
+    }
+}
+
+/* ata_pio_out_protocol --
+ *     ATA PIO_OUT protocol implementation, see specification
+ *
+ * PARAMETERS:
+ *     ctrl_minor - controller identifier
+ *     areq       - ATA request
+ *
+ * RETURNS:
+ *     NONE
+ */
+static inline void
+ata_pio_out_protocol(rtems_device_minor_number ctrl_minor, ata_req_t *areq)
+{
+    uint16_t        val;
+#if 0
+    uint8_t         dev;
+#endif
+    ata_queue_msg_t msg;
+
+#if ATA_DEBUG
+    ata_printf("ata_pio_out_protocol:\n");
+#endif
+
+#if 0
+    dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
+           IDE_REGISTER_DEVICE_HEAD_DEV;
+#endif
+
+    if (areq->cnt == 0)
+    {
+        ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL);
+    }
+    else
+    {
+        if (areq->cnt)
+        {
+          int ccbuf = areq->cbuf;
+          ide_controller_write_data_block(ctrl_minor,
+                                          areq->breq->bufs[0].length * areq->cnt,
+                                          areq->breq->bufs, &areq->cbuf,
+                                          &areq->pos);
+          ccbuf = areq->cbuf - ccbuf;
+          areq->cnt -= ccbuf;
+        }
+        if (IDE_Controller_Table[ctrl_minor].int_driven == false)
+        {
+            do {
+                ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS,
+                                             &val);
+            } while (val & IDE_REGISTER_STATUS_BSY);
+
+            ATA_SEND_EVT(msg, ATA_MSG_GEN_EVT, ctrl_minor, 0);
+        }
+  }
+}
+
+/* ata_queue_task --
+ *     Task which manages ATA driver events queue.
+ *
+ * PARAMETERS:
+ *     arg - ignored
+ *
+ * RETURNS:
+ *     NONE
+ *
+ * NOTES:
+ *     should be non-preemptive
+ */
+static rtems_task
+ata_queue_task(rtems_task_argument arg)
+{
+    ata_queue_msg_t            msg;
+    size_t                     size;
+    ata_req_t                 *areq;
+    rtems_device_minor_number  ctrl_minor;
+    uint16_t                   val;
+    uint16_t                   val1;
+    rtems_status_code          rc;
+    ISR_Level                  level;
+
+    rtems_ata_lock();
+
+    while (1)
+    {
+        rtems_ata_unlock();
+
+        /* get event which has happend */
+        rc = rtems_message_queue_receive(ata_queue_id, &msg, &size, RTEMS_WAIT,
+                                         RTEMS_NO_TIMEOUT);
+        if (rc != RTEMS_SUCCESSFUL)
+            rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
+
+        /* get controller on which event has happend */
+        ctrl_minor = msg.ctrl_minor;
+
+        rtems_ata_lock();
+
+        /* get current request to the controller */
+        _ISR_Local_disable(level);
+        areq = (ata_req_t *)rtems_chain_first(&ata_ide_ctrls[ctrl_minor].reqs);
+        _ISR_Local_enable(level);
+
+        switch(msg.type)
+        {
+            case ATA_MSG_PROCESS_NEXT_EVT:
+                /* process next request in the controller queue */
+                ata_process_request(ctrl_minor);
+                break;
+
+            case ATA_MSG_SUCCESS_EVT:
+                /*
+                 * finish processing of current request with successful
+                 * status and start processing of the next request in the
+                 * controller queue
+                 */
+                ata_request_done(areq, ctrl_minor, RTEMS_SUCCESSFUL);
+                break;
+
+            case ATA_MSG_ERROR_EVT:
+                /*
+                 * finish processing of current request with error
+                 * status and start processing of the next request in the
+                 * controller queue
+                 */
+                ata_request_done(areq, ctrl_minor, RTEMS_IO_ERROR);
+                break;
+
+            case ATA_MSG_GEN_EVT:
+                /*
+                 * continue processing of the current request to the
+                 * controller according to current request state and
+                 * ATA protocol
+                 */
+                ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS,
+                                           &val);
+                /* process error case */
+                if (val & IDE_REGISTER_STATUS_ERR)
+                {
+                    ide_controller_read_register(ctrl_minor,
+                                                 IDE_REGISTER_ERROR,
+                                                 &val);
+                    if (val & (IDE_REGISTER_ERROR_UNC |
+                               IDE_REGISTER_ERROR_ICRC |
+                               IDE_REGISTER_ERROR_IDNF |
+                               IDE_REGISTER_ERROR_NM |
+                               IDE_REGISTER_ERROR_MED))
+                    {
+                        if (areq->type == ATA_COMMAND_TYPE_NON_DATA)
+                            ata_non_data_request_done(areq, ctrl_minor,
+                                                      RTEMS_UNSATISFIED,
+                                                      RTEMS_IO_ERROR);
+                        else
+                            ata_request_done(areq, ctrl_minor, RTEMS_IO_ERROR);
+                        break;
+                    }
+                }
+
+                switch(areq->type)
+                {
+                    case ATA_COMMAND_TYPE_PIO_IN:
+                        ata_pio_in_protocol(ctrl_minor, areq);
+                        break;
+
+                    case ATA_COMMAND_TYPE_PIO_OUT:
+                        ata_pio_out_protocol(ctrl_minor, areq);
+                        break;
+
+                    case ATA_COMMAND_TYPE_NON_DATA:
+                        ide_controller_read_register(ctrl_minor,
+                                                      IDE_REGISTER_ERROR,
+                                                     &val1);
+                        ata_non_data_request_done(areq, ctrl_minor,
+                                                  RTEMS_SUCCESSFUL,
+                                                  val1);
+                        break;
+
+                    default:
+#if ATA_DEBUG
+                        ata_printf("ata_queue_task: non-supported command type\n");
+#endif
+                        ata_request_done(areq, ctrl_minor, RTEMS_IO_ERROR);
+                        break;
+                }
+                break;
+
+            default:
+#if ATA_DEBUG
+                ata_printf("ata_queue_task: internal error\n");
+                rtems_task_delete (RTEMS_SELF);
+#endif
+                rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
+                break;
+        }
+    }
+}
+
+/* ata_ioctl --
+ *     ATA driver ioctl interface.
+ *
+ * PARAMETERS:
+ *     device - device identifier
+ *     cmd    - command
+ *     argp   - arguments
+ *
+ * RETURNS:
+ *     depend on 'cmd'
+ */
+static int
+ata_ioctl(rtems_disk_device *dd, uint32_t cmd, void *argp)
+{
+    dev_t                     device = rtems_disk_get_device_identifier(dd);
+    rtems_status_code         status;
+    rtems_device_minor_number rel_minor;
+
+    rel_minor = (rtems_filesystem_dev_minor_t(device)) /
+                ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE;
+
+    /*
+     * in most cases this means that device 'device' is not an registred ATA
+     * device
+     */
+    if (ata_devs[rel_minor].device == ATA_UNDEFINED_VALUE)
+    {
+        errno = ENODEV;
+        return -1;
+    }
+
+    switch (cmd)
+    {
+        case RTEMS_BLKIO_REQUEST:
+            status = ata_io_data_request(device, (rtems_blkdev_request *)argp);
+            break;
+
+        case ATAIO_SET_MULTIPLE_MODE:
+            status = ata_non_data_request(device, cmd, argp);
+            break;
+
+        case RTEMS_BLKIO_CAPABILITIES:
+            *((uint32_t*) argp)  = RTEMS_BLKDEV_CAP_MULTISECTOR_CONT;
+            status = RTEMS_SUCCESSFUL;
+            break;
+
+        default:
+            return rtems_blkdev_ioctl (dd, cmd, argp);
+            break;
+    }
+
+    if (status != RTEMS_SUCCESSFUL)
+    {
+        errno = EIO;
+        return -1;
+    }
+    return 0;
+}
+
+static void ata_execute_device_diagnostic(
+  rtems_device_minor_number ctrl_minor,
+  uint16_t *sector_buffer
+)
+{
+#if ATA_EXEC_DEVICE_DIAGNOSTIC
+  ata_req_t areq;
+  blkdev_request1 breq;
+
+  ata_breq_init(&breq, sector_buffer);
+
+  /*
+   * Issue EXECUTE DEVICE DIAGNOSTIC ATA command for explore is
+   * there any ATA device on the controller.
+   *
+   * This command may fail and it assumes we have a master device and may
+   * be a slave device. I think the identify command will handle
+   * detection better than this method.
+   */
+  memset(&areq, 0, sizeof(ata_req_t));
+  areq.type = ATA_COMMAND_TYPE_NON_DATA;
+  areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
+  areq.regs.regs[IDE_REGISTER_COMMAND] =
+                            ATA_COMMAND_EXECUTE_DEVICE_DIAGNOSTIC;
+  areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_ERROR);
+
+  areq.breq = (rtems_blkdev_request *)&breq;
+
+  /*
+   * Process the request. Special processing of requests on
+   * initialization phase is needed because at this moment there
+   * is no multitasking enviroment
+   */
+  ata_process_request_on_init_phase(ctrl_minor, &areq);
+
+  /*
+   * check status of I/O operation
+   */
+  if (breq.req.status == RTEMS_SUCCESSFUL)
+  {
+    /* disassemble returned diagnostic codes */
+    if (areq.info == ATA_DEV0_PASSED_DEV1_PASSED_OR_NOT_PRSNT)
+    {
+      printk("ATA: ctrl:%d: primary, secondary\n", ctrl_minor);
+      ATA_DEV_INFO(ctrl_minor,0).present = true;
+      ATA_DEV_INFO(ctrl_minor,1).present = true;
+    }
+    else if (areq.info == ATA_DEV0_PASSED_DEV1_FAILED)
+    {
+      printk("ATA: ctrl:%d: primary\n", ctrl_minor);
+      ATA_DEV_INFO(ctrl_minor,0).present = true;
+      ATA_DEV_INFO(ctrl_minor,1).present = false;
+    }
+    else if (areq.info < ATA_DEV1_PASSED_DEV0_FAILED)
+    {
+      printk("ATA: ctrl:%d: secondary\n", ctrl_minor);
+      ATA_DEV_INFO(ctrl_minor,0).present = false;
+      ATA_DEV_INFO(ctrl_minor,1).present = true;
+    }
+    else
+    {
+      printk("ATA: ctrl:%d: none\n", ctrl_minor);
+      ATA_DEV_INFO(ctrl_minor, 0).present = false;
+      ATA_DEV_INFO(ctrl_minor, 1).present = false;
+    }
+
+    /* refine the returned codes */
+    if (ATA_DEV_INFO(ctrl_minor, 1).present)
+    {
+      uint16_t ec = 0;
+      ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &ec);
+      if (ec & ATA_DEV1_PASSED_DEV0_FAILED)
+      {
+        printk("ATA: ctrl:%d: secondary inforced\n", ctrl_minor);
+        ATA_DEV_INFO(ctrl_minor, 1).present = true;
+      }
+      else
+      {
+        printk("ATA: ctrl:%d: secondary removed\n", ctrl_minor);
+        ATA_DEV_INFO(ctrl_minor, 1).present = false;
+      }
+    }
+  }
+  else
+#endif
+  {
+    ATA_DEV_INFO(ctrl_minor, 0).present = true;
+    ATA_DEV_INFO(ctrl_minor,1).present = true;
+  }
+}
+
+/*
+ * ata_initialize --
+ *     Initializes all ATA devices found on initialized IDE controllers.
+ *
+ * PARAMETERS:
+ *     major - device major number
+ *     minor - device minor number
+ *     args   - arguments
+ *
+ * RETURNS:
+ *     RTEMS_SUCCESSFUL on success, or error code if
+ *     error occured
+ */
+rtems_device_driver
+rtems_ata_initialize(rtems_device_major_number major,
+                     rtems_device_minor_number minor_arg,
+                     void *args)
+{
+    uint32_t           ctrl_minor;
+    rtems_status_code  status;
+    uint16_t          *buffer;
+    int                i, dev = 0;
+    char               name[ATA_MAX_NAME_LENGTH];
+    dev_t              device;
+    ata_int_st_t      *int_st;
+
+#if CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE
+    rtems_isr_entry    old_isr;
+#else
+    int ata_irq_chain_use;
+#endif
+
+    if (ata_initialized)
+        return RTEMS_SUCCESSFUL;
+
+    /* initialization of disk devices library */
+    status = rtems_disk_io_initialize();
+    if (status != RTEMS_SUCCESSFUL)
+        return status;
+
+    status = rtems_semaphore_create (rtems_build_name ('A', 'T', 'A', 'L'),
+                                     1, RTEMS_ATA_LOCK_ATTRIBS, 0,
+                                     &ata_lock);
+    if (status != RTEMS_SUCCESSFUL)
+        return status;
+
+    /* create queue for asynchronous requests handling */
+    status = rtems_message_queue_create(
+                 rtems_build_name('A', 'T', 'A', 'Q'),
+                 ATA_DRIVER_MESSAGE_QUEUE_SIZE,
+                 sizeof(ata_queue_msg_t),
+                 RTEMS_FIFO | RTEMS_LOCAL,
+                 &ata_queue_id);
+    if (status != RTEMS_SUCCESSFUL)
+    {
+        rtems_disk_io_done();
+        return status;
+    }
+
+    /*
+     * create ATA driver task, see comments for task implementation for
+     * details
+     */
+    status = rtems_task_create(
+                 rtems_build_name ('A', 'T', 'A', 'T'),
+                 ((rtems_ata_driver_task_priority > 0)
+		  ? rtems_ata_driver_task_priority
+		  : ATA_DRIVER_TASK_DEFAULT_PRIORITY),
+                 ATA_DRIVER_TASK_STACK_SIZE,
+                 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR |
+                 RTEMS_INTERRUPT_LEVEL(0),
+                 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
+                 &ata_task_id);
+    if (status != RTEMS_SUCCESSFUL)
+    {
+        rtems_message_queue_delete(ata_queue_id);
+        rtems_disk_io_done();
+        return status;
+    }
+
+    /*
+     * start ATA driver task. Actually the task will not start immediately -
+     * it will start only after multitasking support will be started
+     */
+    status = rtems_task_start(ata_task_id, ata_queue_task, 0);
+    if (status != RTEMS_SUCCESSFUL)
+    {
+        rtems_task_delete(ata_task_id);
+        rtems_message_queue_delete(ata_queue_id);
+        rtems_disk_io_done();
+        return status;
+    }
+
+    buffer = (uint16_t*)malloc(ATA_SECTOR_SIZE);
+    if (buffer == NULL)
+    {
+        rtems_task_delete(ata_task_id);
+        rtems_message_queue_delete(ata_queue_id);
+        rtems_disk_io_done();
+        return RTEMS_NO_MEMORY;
+    }
+
+    ata_devs_number = 0;
+
+    for (i = 0; i < (2 * IDE_CTRL_MAX_MINOR_NUMBER); i++)
+        ata_devs[i].device = ATA_UNDEFINED_VALUE;
+
+#if CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE
+    /* prepare ATA driver for handling  interrupt driven devices */
+    for (i = 0; i < ATA_MAX_RTEMS_INT_VEC_NUMBER; i++)
+        rtems_chain_initialize_empty(&ata_int_vec[i]);
+#else
+    for (i = 0; i < ATA_IRQ_CHAIN_MAX_CNT; i++) {
+      rtems_chain_initialize_empty(&(ata_irq_chain[i].irq_chain));
+    }
+#endif
+
+    /*
+     * during ATA driver initialization EXECUTE DEVICE DIAGNOSTIC and
+     * IDENTIFY DEVICE ATA command should be issued; for these purposes ATA
+     * requests should be formed; ATA requests contain block device request,
+     * so form block device request first
+     */
+
+    /*
+     * for each presented IDE controller execute EXECUTE DEVICE DIAGNOSTIC
+     * ATA command; for each found device execute IDENTIFY DEVICE ATA
+     * command
+     */
+    for (ctrl_minor = 0; ctrl_minor < IDE_Controller_Count; ctrl_minor++)
+    if (IDE_Controller_Table[ctrl_minor].status == IDE_CTRL_INITIALIZED)
+    {
+        rtems_chain_initialize_empty(&ata_ide_ctrls[ctrl_minor].reqs);
+
+        if (IDE_Controller_Table[ctrl_minor].int_driven == true)
+        {
+            int_st = malloc(sizeof(ata_int_st_t));
+            if (int_st == NULL)
+            {
+                free(buffer);
+                rtems_task_delete(ata_task_id);
+                rtems_message_queue_delete(ata_queue_id);
+                rtems_disk_io_done();
+                return RTEMS_NO_MEMORY;
+            }
+
+            int_st->ctrl_minor = ctrl_minor;
+#if CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE
+            status = rtems_interrupt_catch(
+                         ata_interrupt_handler,
+                         IDE_Controller_Table[ctrl_minor].int_vec,
+                         &old_isr);
+#else
+	    /*
+	     * FIXME: check existing entries. if they use the same
+	     * IRQ name, then append int_st to respective chain
+	     * otherwise, use new ata_irq_chain entry
+	     */
+	    ata_irq_chain_use = -1;
+	    for (i = 0;
+		 ((i < ata_irq_chain_cnt) &&
+		  (ata_irq_chain_use < 0));i++) {
+	      if (ata_irq_chain[i].name ==
+		  IDE_Controller_Table[ctrl_minor].int_vec) {
+		ata_irq_chain_use = i;
+	      }
+	    }
+	    if (ata_irq_chain_use < 0) {
+	      /*
+	       * no match found, try to use new channel entry
+	       */
+	      if (ata_irq_chain_cnt < ATA_IRQ_CHAIN_MAX_CNT) {
+		ata_irq_chain_use = ata_irq_chain_cnt++;
+
+		ata_irq_chain[ata_irq_chain_use].name =
+		  IDE_Controller_Table[ctrl_minor].int_vec;
+		ata_irq_data.name   =
+		  IDE_Controller_Table[ctrl_minor].int_vec;
+		ata_irq_data.hdl    = ata_interrupt_handler;
+		ata_irq_data.handle = (rtems_irq_hdl_param) (uintptr_t) ctrl_minor;
+
+		status = ((0 == BSP_install_rtems_irq_handler(&ata_irq_data))
+			  ? RTEMS_INVALID_NUMBER
+			  : RTEMS_SUCCESSFUL);
+	      }
+	      else {
+		status = RTEMS_TOO_MANY;
+	      }
+	    }
+#endif
+            if (status != RTEMS_SUCCESSFUL)
+            {
+                free(int_st);
+                free(buffer);
+                rtems_task_delete(ata_task_id);
+                rtems_message_queue_delete(ata_queue_id);
+                rtems_disk_io_done();
+                return status;
+            }
+#if CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE
+            rtems_chain_append(
+                &ata_int_vec[IDE_Controller_Table[ctrl_minor].int_vec],
+                &int_st->link);
+#else
+            rtems_chain_append(
+		&(ata_irq_chain[ata_irq_chain_use].irq_chain),
+                &int_st->link);
+#endif
+
+            /* disable interrupts */
+            ide_controller_write_register(ctrl_minor,
+                                          IDE_REGISTER_DEVICE_CONTROL_OFFSET,
+                                          IDE_REGISTER_DEVICE_CONTROL_nIEN);
+        }
+
+        ata_execute_device_diagnostic(ctrl_minor, buffer);
+
+        /* for each found ATA device obtain it configuration */
+        for (dev = 0; dev < 2; dev++)
+        if (ATA_DEV_INFO(ctrl_minor, dev).present)
+        {
+            status = ata_identify_device(
+               ctrl_minor,
+               dev,
+               buffer,
+               &ATA_DEV_INFO(ctrl_minor, dev));
+            if (status != RTEMS_SUCCESSFUL)
+               continue;
+
+	    /*
+	     * choose most appropriate ATA device data I/O speed supported
+	     * by the controller
+	     */
+	    status = ide_controller_config_io_speed(
+               ctrl_minor,
+               ATA_DEV_INFO(ctrl_minor, dev).modes_available);
+	    if (status != RTEMS_SUCCESSFUL)
+               continue;
+
+            /*
+             * Ok, let register new ATA device in the system
+             */
+            ata_devs[ata_devs_number].ctrl_minor = ctrl_minor;
+            ata_devs[ata_devs_number].device = dev;
+
+            /* The space leaves a hole for the character. */
+            strcpy(name, "/dev/hd ");
+            name[7] = 'a' + 2 * ctrl_minor + dev;
+
+            device = rtems_filesystem_make_dev_t(
+                         major,
+                         (ata_devs_number *
+                          ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE));
+            status = rtems_disk_create_phys(device, ATA_SECTOR_SIZE,
+                ATA_DEV_INFO(ctrl_minor, dev).lba_avaible ?
+                ATA_DEV_INFO(ctrl_minor, dev).lba_sectors :
+                (ATA_DEV_INFO(ctrl_minor, dev).heads *
+                 ATA_DEV_INFO(ctrl_minor, dev).cylinders *
+                 ATA_DEV_INFO(ctrl_minor, dev).sectors),
+                ata_ioctl, NULL, name);
+            if (status != RTEMS_SUCCESSFUL)
+            {
+                ata_devs[ata_devs_number].device = ATA_UNDEFINED_VALUE;
+                continue;
+            }
+            ata_devs_number++;
+        }
+        if (IDE_Controller_Table[ctrl_minor].int_driven == true)
+        {
+            ide_controller_write_register(ctrl_minor,
+                                          IDE_REGISTER_DEVICE_CONTROL_OFFSET,
+                                          0x00);
+        }
+    }
+
+    free(buffer);
+    ata_initialized = true;
+    return RTEMS_SUCCESSFUL;
+}
Index: bsps/shared/dev/ide/ata_util.c
===================================================================
--- bsps/shared/dev/ide/ata_util.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/ide/ata_util.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2010 embedded brains GmbH.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Authors: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <libchip/ide_ctrl_io.h>
+#include <libchip/ide_ctrl_cfg.h>
+#include <libchip/ata_internal.h>
+
+/* ata_process_request_on_init_phase --
+ *     Process the ATA request during system initialization. Request
+ *     processing is syncronous and doesn't use multiprocessing enviroment.
+ *
+ * PARAMETERS:
+ *     ctrl_minor - controller identifier
+ *     areq       - ATA request
+ *
+ * RETURNS:
+ *     NONE
+ */
+void
+ata_process_request_on_init_phase(rtems_device_minor_number  ctrl_minor,
+                                  ata_req_t                 *areq)
+{
+    uint16_t           byte;/* emphasize that only 8 low bits is meaningful */
+    uint8_t            i;
+#if 0
+    uint8_t            dev;
+#endif
+    uint16_t           val, val1;
+    volatile unsigned  retries;
+
+    assert(areq);
+
+#if 0
+    dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
+           IDE_REGISTER_DEVICE_HEAD_DEV;
+#endif
+
+    ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD,
+                                  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
+
+	retries = 0;
+    do {
+        ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
+        /* If device (on INIT, i.e. it should be idle) is neither
+         * busy nor ready something's fishy, i.e., there is probably
+         * no device present.
+         * I'd like to do a proper timeout but don't know of a portable
+         * timeout routine (w/o using multitasking / rtems_task_wake_after())
+         */
+        if ( ! (byte & (IDE_REGISTER_STATUS_BSY | IDE_REGISTER_STATUS_DRDY))) {
+            retries++;
+            if ( 10000 == retries ) {
+              /* probably no drive connected */
+              areq->breq->status = RTEMS_UNSATISFIED;
+              return;
+            }
+        }
+    } while ((byte & IDE_REGISTER_STATUS_BSY) ||
+             (!(byte & IDE_REGISTER_STATUS_DRDY)));
+
+    for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
+    {
+        uint32_t   reg = (1 << i);
+        if (areq->regs.to_write & reg)
+            ide_controller_write_register(ctrl_minor, i,
+                                          areq->regs.regs[i]);
+    }
+
+    do {
+        ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
+    } while (byte & IDE_REGISTER_STATUS_BSY);
+
+    ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
+    ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &val1);
+
+    if (val & IDE_REGISTER_STATUS_ERR)
+    {
+        areq->breq->status = RTEMS_IO_ERROR;
+        return;
+    }
+
+    switch(areq->type)
+    {
+        case ATA_COMMAND_TYPE_PIO_IN:
+            if (areq->cnt)
+            {
+              int ccbuf = areq->cbuf;
+              ide_controller_read_data_block(ctrl_minor,
+                                             areq->breq->bufs[0].length * areq->cnt,
+                                             areq->breq->bufs, &areq->cbuf,
+                                             &areq->pos);
+              ccbuf = areq->cbuf - ccbuf;
+              areq->cnt -= ccbuf;
+            }
+            if (areq->cnt == 0)
+            {
+                areq->breq->status = RTEMS_SUCCESSFUL;
+            }
+            else
+            {
+                /*
+                 * this shouldn't happend on the initialization
+                 * phase!
+                 */
+                rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
+            }
+            break;
+
+        case ATA_COMMAND_TYPE_NON_DATA:
+            areq->breq->status = RTEMS_SUCCESSFUL;
+            areq->info = val1;
+            break;
+
+        default:
+            areq->breq->status = RTEMS_IO_ERROR;
+            break;
+    }
+}
+
+void ata_breq_init(blkdev_request1 *breq, uint16_t *sector_buffer)
+{
+  memset(breq, 0, sizeof(*breq));
+
+  breq->req.done_arg = breq;
+  breq->req.bufnum = 1;
+  breq->req.bufs [0].length = ATA_SECTOR_SIZE;
+  breq->req.bufs [0].buffer = sector_buffer;
+}
+
+rtems_status_code ata_identify_device(
+  rtems_device_minor_number ctrl_minor,
+  int dev,
+  uint16_t *sector_buffer,
+  ata_dev_t *device_entry
+)
+{
+  ata_req_t areq;
+  blkdev_request1 breq;
+
+  ata_breq_init(&breq, sector_buffer);
+
+  /*
+   * Issue DEVICE IDENTIFY ATA command and get device
+   * configuration
+   */
+  memset(&areq, 0, sizeof(ata_req_t));
+  areq.type = ATA_COMMAND_TYPE_PIO_IN;
+  areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
+  areq.regs.regs [IDE_REGISTER_COMMAND] = ATA_COMMAND_IDENTIFY_DEVICE;
+  areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
+  areq.breq = (rtems_blkdev_request *)&breq;
+  areq.cnt = breq.req.bufnum;
+  areq.regs.regs [IDE_REGISTER_DEVICE_HEAD] |=
+    dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS;
+
+  /*
+   * Process the request. Special processing of requests on
+   * initialization phase is needed because at this moment there
+   * is no multitasking enviroment
+   */
+  ata_process_request_on_init_phase(ctrl_minor, &areq);
+
+  /* check status of I/O operation */
+  if (breq.req.status != RTEMS_SUCCESSFUL) {
+    return RTEMS_IO_ERROR;
+  }
+
+  /*
+   * Parse returned device configuration and fill in ATA internal
+   * device info structure
+   */
+  device_entry->cylinders =
+      CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS]);
+  device_entry->heads =
+      CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS]);
+  device_entry->sectors =
+      CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS]);
+  device_entry->lba_sectors =
+      CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS1]);
+  device_entry->lba_sectors <<= 16;
+  device_entry->lba_sectors += CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS0]);
+  device_entry->lba_avaible =
+      (CF_LE_W(sector_buffer[ATA_IDENT_WORD_CAPABILITIES]) >> 9) & 0x1;
+
+  if ((CF_LE_W(sector_buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) &
+       ATA_IDENT_BIT_VALID) == 0) {
+    /* no "supported modes" info -> use default */
+    device_entry->mode_active = ATA_MODES_PIO3;
+  } else {
+    device_entry->modes_available =
+      ((CF_LE_W(sector_buffer[64]) & 0x1) ? ATA_MODES_PIO3 : 0) |
+      ((CF_LE_W(sector_buffer[64]) & 0x2) ? ATA_MODES_PIO4 : 0) |
+      ((CF_LE_W(sector_buffer[63]) & 0x1) ? ATA_MODES_DMA0 : 0) |
+      ((CF_LE_W(sector_buffer[63]) & 0x2) ?
+       ATA_MODES_DMA0 | ATA_MODES_DMA1 : 0) |
+      ((CF_LE_W(sector_buffer[63]) & 0x4) ?
+       ATA_MODES_DMA0 | ATA_MODES_DMA1 | ATA_MODES_DMA2 : 0);
+    if (device_entry->modes_available == 0) {
+      return RTEMS_IO_ERROR;
+    }
+  }
+
+  return RTEMS_SUCCESSFUL;
+}
Index: bsps/shared/dev/ide/ide_controller.c
===================================================================
--- bsps/shared/dev/ide/ide_controller.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/ide/ide_controller.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,200 @@
+/*
+ * ide_controller.c
+ *
+ * This is generic rtems driver for IDE controllers.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Authors: Alexandra Kossovsky <sasha@oktet.ru>
+ *          Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ *
+ */
+
+#define IDE_CONTROLLER_TRACE 0
+
+#include <rtems/chain.h>
+#include <errno.h>
+#include <rtems/blkdev.h>
+
+#include <libchip/ide_ctrl.h>
+#include <libchip/ide_ctrl_cfg.h>
+#include <libchip/ide_ctrl_io.h>
+
+#if IDE_CONTROLLER_TRACE
+int ide_controller_trace = 1;
+#endif
+
+/*
+ * ide_controller_initialize --
+ *     Initializes all configured IDE controllers. Controllers configuration
+ *     table is provided by BSP
+ *
+ * PARAMETERS:
+ *     major     - device major number
+ *     minor_arg - device minor number
+ *     args      - arguments
+ *
+ * RETURNS:
+ *     RTEMS_SUCCESSFUL on success, or error code if
+ *     error occured
+ */
+rtems_device_driver
+ide_controller_initialize(rtems_device_major_number  major,
+                          rtems_device_minor_number  minor_arg,
+                          void                      *args)
+{
+    unsigned long       minor;
+
+    /* FIXME: may be it should be done on compilation phase */
+    if (IDE_Controller_Count > IDE_CTRL_MAX_MINOR_NUMBER)
+        rtems_fatal_error_occurred(RTEMS_TOO_MANY);
+
+    for (minor=0; minor < IDE_Controller_Count; minor++)
+    {
+        IDE_Controller_Table[minor].status = IDE_CTRL_NON_INITIALIZED;
+
+        if ((IDE_Controller_Table[minor].probe == NULL ||
+             IDE_Controller_Table[minor].probe(minor)) &&
+            (IDE_Controller_Table[minor].fns->ctrl_probe == NULL ||
+             IDE_Controller_Table[minor].fns->ctrl_probe(minor)))
+        {
+            dev_t  dev;
+            dev = rtems_filesystem_make_dev_t( major, minor );
+            if (mknod(IDE_Controller_Table[minor].name,
+                      0777 | S_IFBLK, dev ) < 0)
+                rtems_fatal_error_occurred(errno);
+            IDE_Controller_Table[minor].fns->ctrl_initialize(minor);
+            IDE_Controller_Table[minor].status = IDE_CTRL_INITIALIZED;
+        }
+    }
+    return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * ide_controller_read_data_block --
+ *     Read data block via controller's data register
+ *
+ * PARAMETERS:
+ *     minor      - minor number of controller
+ *     block_size - number of bytes to read
+ *     bufs       - set of buffers to store data
+ *     cbuf       - number of current buffer from the set
+ *     pos        - position inside current buffer 'cbuf'
+ *
+ * RETURNS:
+ *     NONE
+ */
+void
+ide_controller_read_data_block(rtems_device_minor_number  minor,
+                               uint32_t                   block_size,
+                               rtems_blkdev_sg_buffer    *bufs,
+                               uint32_t                  *cbuf,
+                               uint32_t                  *pos)
+{
+#if IDE_CONTROLLER_TRACE
+    if (ide_controller_trace)
+        printk ("IDE data block read: %d:%d\n", *cbuf, bufs[*cbuf].block);
+#endif
+    IDE_Controller_Table[minor].fns->ctrl_read_block(minor, block_size, bufs,
+                                                     cbuf, pos);
+}
+
+/*
+ * ide_controller_write_data_block --
+ *     Write data block via controller's data register
+ *
+ * PARAMETERS:
+ *     minor      - minor number of controller
+ *     block_size - number of bytes to write
+ *     bufs       - set of buffers which store data
+ *     cbuf       - number of current buffer from the set
+ *     pos        - position inside current buffer 'cbuf'
+ *
+ * RETURNS:
+ *     NONE
+ */
+void
+ide_controller_write_data_block(rtems_device_minor_number  minor,
+                                uint32_t                   block_size,
+                                rtems_blkdev_sg_buffer    *bufs,
+                                uint32_t                  *cbuf,
+                                uint32_t                  *pos)
+
+{
+#if IDE_CONTROLLER_TRACE
+    if (ide_controller_trace)
+        printk ("IDE data block write: %d:%d\n", *cbuf, bufs[*cbuf].block);
+#endif
+    IDE_Controller_Table[minor].fns->ctrl_write_block(minor, block_size, bufs,
+                                                      cbuf, pos);
+}
+
+/*
+ * ide_controller_read_register --
+ *     Read controller's register
+ *
+ * PARAMETERS:
+ *     minor - minor number of controller
+ *     reg   - register to read
+ *     value - placeholder for result
+ *
+ * RETURNS
+ *     NONE
+ */
+void
+ide_controller_read_register(rtems_device_minor_number  minor,
+                             int                        reg,
+                             uint16_t                  *value)
+{
+    IDE_Controller_Table[minor].fns->ctrl_reg_read(minor, reg, value);
+#if IDE_CONTROLLER_TRACE
+    if (ide_controller_trace)
+        printk ("IDE read reg: %d => %04x\n", reg, *value);
+#endif
+}
+
+/*
+ * ide_controller_write_register --
+ *     Write controller's register
+ *
+ * PARAMETERS:
+ *     minor - minor number of controller
+ *     reg   - register to write
+ *     value - value to write
+ *
+ * RETURNS:
+ *     NONE
+ */
+void
+ide_controller_write_register(rtems_device_minor_number minor, int reg,
+                              uint16_t   value)
+{
+#if IDE_CONTROLLER_TRACE
+    if (ide_controller_trace)
+        printk ("IDE write reg: %d => %04x\n", reg, value);
+#endif
+    IDE_Controller_Table[minor].fns->ctrl_reg_write(minor, reg, value);
+}
+
+/*
+ * ide_controller_config_io_speed --
+ *     Set controller's speed of IO operations
+ *
+ * PARAMETERS:
+ *     minor           - minor number of controller
+ *     modes_available - speeds available
+ *
+ * RETURNS:
+ *     RTEMS_SUCCESSFUL on success, or error code if
+ *     error occured
+ */
+rtems_status_code
+ide_controller_config_io_speed(int minor, uint16_t modes_available)
+{
+    return IDE_Controller_Table[minor].fns->ctrl_config_io_speed(
+               minor,
+               modes_available);
+}
Index: bsps/shared/dev/rtc/README.ds1643
===================================================================
--- bsps/shared/dev/rtc/README.ds1643	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/README.ds1643	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,3 @@
+The Mostek M48T08 is compatible with the Dallas Semiconductor DS1643.  Please
+use that driver.
+
Index: bsps/shared/dev/rtc/README.icm7170
===================================================================
--- bsps/shared/dev/rtc/README.icm7170	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/README.icm7170	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,48 @@
+
+Configuration Table Use
+=======================
+
+sDeviceName
+
+   The name of this device.
+
+deviceType
+
+   This field must be RTC_ICM7170.
+
+pDeviceFns
+
+   The device interface control table.  This must be icm7170_fns.
+
+deviceProbe
+
+   This is the address of the routine which probes to see if the device
+   is present.
+
+pDeviceParams
+
+    This field specifies the clock frequency.  It may be one of the
+    following:
+        ICM7170_AT_32_KHZ
+        ICM7170_AT_1_MHZ
+        ICM7170_AT_2_MHZ
+        ICM7170_AT_4_MHZ
+
+ulCtrlPort1
+
+   This field is the base address of the RTC area of the chip.
+
+ulCtrlPort2
+
+   This field is ignored.
+
+ulDataPort
+
+   This field is ignored.
+
+
+getRegister
+setRegister
+
+   These follow standard conventions.
+
Index: bsps/shared/dev/rtc/README.m48t08
===================================================================
--- bsps/shared/dev/rtc/README.m48t08	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/README.m48t08	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,44 @@
+
+Configuration Table Use
+=======================
+
+sDeviceName
+
+   The name of this device.
+
+deviceType
+
+   This field must be RTC_M48T08.
+
+pDeviceFns
+
+   The device interface control table.  This must be m48t08_fns.
+
+deviceProbe
+
+   This is the address of the routine which probes to see if the device
+   is present.
+
+pDeviceParams
+
+    This is ignored and should be NULL.
+
+ulCtrlPort1
+
+   This field is the base address of the RTC area of the chip.  The
+   NVRAM portion of the chip is ignored.
+
+ulCtrlPort2
+
+   This field is ignored.
+
+ulDataPort
+
+   This field is ignored.
+
+
+getRegister
+setRegister
+
+   These follow standard conventions.
+
Index: bsps/shared/dev/rtc/README.m48t18
===================================================================
--- bsps/shared/dev/rtc/README.m48t18	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/README.m48t18	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,1 @@
+This is supported by the m48t08 driver.
Index: bsps/shared/dev/rtc/README.mc146818a
===================================================================
--- bsps/shared/dev/rtc/README.mc146818a	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/README.mc146818a	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,1 @@
+This is supported by the mc146818a driver.
Index: bsps/shared/dev/rtc/STATUS
===================================================================
--- bsps/shared/dev/rtc/STATUS	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/STATUS	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,33 @@
+General
+=======
+
++ It would be nice to utilize the interrupt capabilities of some
+  RTC parts.  This could be used to trigger checking the software
+  clock against the hardware clock.
+
++ The periodic capability of most RTCs is not suitable for use
+  as a general purpose flexible clock tick source.  For example,
+  many RTCs generate only a handful of periods with 100 Hz being the
+  most frequent. 
+
++ The tick field is not set on get.  Anything smaller than a second
+  is ignored on set and get operations.
+
++ Day of week is ignored since RTEMS does not set it internally.
+
++ There is no attempt in RTEMS to know about time zones.
+
+Harris ICM7170
+==============
+
++ Tested on a DMV177.
+
++ Interrupt capabilities are ignored.
+
+Mostek 48T08
+============
+
++ Untested.
+
++ NVRAM is ignored.
+
Index: bsps/shared/dev/rtc/ds1375.c
===================================================================
--- bsps/shared/dev/rtc/ds1375.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/ds1375.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,461 @@
+/* Driver for the Maxim 1375 i2c RTC (TOD only; very simple...) */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ *
+ *     Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ *      Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The software was produced by
+ *     the Stanford Linear Accelerator Center, Stanford University,
+ *      under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software.  Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+/* This driver uses the file-system interface to the i2c bus */
+
+#include <unistd.h> /* write, read, close */
+
+#include <rtems.h>
+#include <rtems/bspIo.h>
+#include <rtems/rtc.h>
+#include <rtems/score/sysstate.h>
+#include <libchip/rtc.h>
+#include <libchip/ds1375-rtc.h>
+
+#include <sys/fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+
+#define STATIC static
+#undef  DEBUG
+
+/* The RTC driver routines are possibly called during
+ * system initialization -- that would be prior to opening
+ * the console. At this point it is not safe to use stdio
+ * (printf, perror etc.).
+ * Our file descriptors may even be 0..2
+ */
+#define STDIOSAFE(fmt,args...)        \
+  do {                                \
+    if ( _System_state_Is_up( _System_state_Get() ) ) { \
+      fprintf(stderr,fmt,args);   \
+    } else {                        \
+      printk(fmt,args);           \
+    }                               \
+  } while (0)
+
+
+STATIC uint8_t ds1375_bcd2bin(uint8_t x)
+{
+  uint8_t h = x & 0xf0;
+
+  /* 8*hi + 2*hi + lo */
+  return ( h >> 1 ) + ( h >> 3 ) + ( x & 0xf );
+}
+
+STATIC uint8_t ds1375_bin2bcd(uint8_t x)
+{
+  uint8_t h = x/10;
+
+  return ( h << 4 ) + ( x - ( ( h << 3 ) + ( h << 1 ) ) );
+}
+
+/*
+ * Register Definitions and Access Macros
+ *
+ * The xxx_REG macros are offsets into the register files
+ * The xxx_OFF macros are offsets into a in-memory buffer
+ *             starting at the seconds (for the 1375 both,
+ *             _REG and _OFF happen to be identical).
+ */
+#define DS1375_SEC_REG  0x0
+#define DS1375_SEC_OFF  (DS1375_SEC_REG-DS1375_SEC_REG)
+/* Extract seconds and convert to binary */
+#define DS1375_SEC(x)  ds1375_bcd2bin( ((x)[DS1375_SEC_OFF]) & 0x7f )
+
+#define DS1375_MIN_REG  0x1
+#define DS1375_MIN_OFF  (DS1375_MIN_REG-DS1375_SEC_REG)
+/* Extract minutes and convert to binary */
+#define DS1375_MIN(x)  ds1375_bcd2bin( ((x)[DS1375_MIN_OFF]) & 0x7f )
+
+#define DS1375_HR_REG  0x2
+#define DS1375_HR_OFF  (DS1375_HR_REG-DS1375_SEC_REG)
+#define DS1375_HR_1224  (1<<6)
+#define DS1375_HR_AMPM  (1<<5)
+/* Are hours in AM/PM representation ?   */
+#define DS1375_IS_AMPM(x)  (DS1375_HR_1224 & ((x)[DS1375_HR_OFF]))
+/* Are we PM ?                           */
+#define DS1375_IS_PM(x)    (DS1375_HR_AMPM & ((x)[DS1375_HR_OFF]))
+/* Extract hours (12h mode) and convert to binary */
+#define DS1375_HR_12(x)  ds1375_bcd2bin( ((x)[DS1375_HR_OFF]) & 0x1f )
+/* Extract hours (24h mode) and convert to binary */
+#define DS1375_HR_24(x)  ds1375_bcd2bin( ((x)[DS1375_HR_OFF]) & 0x3f )
+
+#define DS1375_DAY_REG  0x3
+#define DS1375_DAY_OFF  (DS1375_DAY_REG-DS1375_SEC_REG)
+#define DS1375_DAT_REG  0x4
+#define DS1375_DAT_OFF  (DS1375_DAT_REG-DS1375_SEC_REG)
+/* Extract date and convert to binary    */
+#define DS1375_DAT(x)  ds1375_bcd2bin( ((x)[DS1375_DAT_OFF]) & 0x3f )
+#define DS1375_MON_REG  0x5
+#define DS1375_MON_OFF  (DS1375_MON_REG-DS1375_SEC_REG)
+#define DS1375_MON_CTRY    (1<<7)
+/* Is century bit set ?                  */
+#define DS1375_IS_CTRY(x)  (((x)[DS1375_MON_OFF]) & DS1375_MON_CTRY)
+/* Extract month and convert to binary   */
+#define DS1375_MON(x)  ds1375_bcd2bin( ((x)[DS1375_MON_OFF]) & 0x1f )
+
+#define DS1375_YR_REG  0x6
+#define DS1375_YR_OFF  (DS1375_YR_REG-DS1375_SEC_REG)
+/* Extract year and convert to binary    */
+#define DS1375_YR(x)  ds1375_bcd2bin( ((x)[DS1375_YR_OFF]) & 0xff )
+
+/* CR Register and bit definitions       */
+#define DS1375_CR_REG  0xe
+#define DS1375_CR_ECLK    (1<<7)
+#define DS1375_CR_CLKSEL1  (1<<6)
+#define DS1375_CR_CLKSEL0  (1<<5)
+#define DS1375_CR_RS2    (1<<4)
+#define DS1375_CR_RS1    (1<<3)
+#define DS1375_CR_INTCN    (1<<2)
+#define DS1375_CR_A2IE    (1<<1)
+#define DS1375_CR_A1IE    (1<<0)
+
+#define DS1375_CSR_REG  0xf
+
+/* User SRAM (8 bytes)                   */
+#define DS1375_RAM    0x10  /* start of 8 bytes user ram */
+
+/* Access Primitives                     */
+
+STATIC int rd_bytes(
+  int      fd,
+  uint32_t off,
+  uint8_t *buf,
+  int      len
+)
+{
+  uint8_t ptr = off;
+
+  return 1 == write( fd, &ptr, 1 ) && len == read( fd, buf, len ) ? 0 : -1;
+}
+
+STATIC int wr_bytes(
+  int      fd,
+  uint32_t off,
+  uint8_t *buf,
+  int      len
+)
+{
+  uint8_t d[ len + 1 ];
+
+  /* Must not break up writing of the register pointer and
+   * the data to-be-written into multiple write() calls
+   * because every 'write()' operation sends START and
+   * the chip interprets the first byte after START as
+   * the register pointer.
+   */
+
+  d[0] = off;
+  memcpy( d + 1, buf, len );
+
+  return len + 1 == write( fd, d, len + 1 ) ? 0 : -1;
+}
+
+/* Helpers                               */
+
+static int getfd(
+  int minor
+)
+{
+  return open( (const char *)RTC_Table[minor].ulCtrlPort1, O_RDWR );
+}
+
+/* Driver Access Functions               */
+
+STATIC void ds1375_initialize(
+  int minor
+)
+{
+  int     fd;
+  uint8_t cr;
+
+  if ( ( fd = getfd( minor ) ) >= 0 ) {
+    if ( 0 == rd_bytes( fd, DS1375_CR_REG, &cr, 1 ) ) {
+      /* make sure clock is enabled */
+      if ( ! ( DS1375_CR_ECLK & cr ) ) {
+        cr |= DS1375_CR_ECLK;
+        wr_bytes( fd, DS1375_CR_REG, &cr, 1 );
+      }
+    }
+    close( fd );
+  }
+
+}
+
+STATIC int ds1375_get_time(
+  int                minor,
+  rtems_time_of_day *time
+)
+{
+  int   rval = -1;
+  int   fd;
+  uint8_t  buf[DS1375_YR_REG + 1 - DS1375_SEC_REG];
+
+  if ( time && ( ( fd = getfd( minor ) ) >= 0 ) ) {
+    if ( 0 == rd_bytes( fd, DS1375_SEC_REG, buf, sizeof(buf) ) ) {
+      time->year    =  DS1375_IS_CTRY( buf ) ? 2000 : 1900;
+      time->year  +=  DS1375_YR ( buf );
+      time->month  =  DS1375_MON( buf );
+      time->day    =  DS1375_DAT( buf );  /* DAY is weekday */
+
+      if ( DS1375_IS_AMPM( buf ) ) {
+        time->hour   = DS1375_HR_12 ( buf );
+        if ( DS1375_IS_PM( buf ) )
+          time->hour += 12;
+      } else {
+        time->hour   = DS1375_HR_24 ( buf );
+      }
+
+      time->minute =  DS1375_MIN( buf );
+      time->second =  DS1375_SEC( buf );
+      time->ticks  = 0;
+      rval = 0;
+    }
+    close( fd );
+  }
+  return rval;
+}
+
+STATIC int ds1375_set_time(
+  int                      minor,
+  const rtems_time_of_day *time
+)
+{
+  int       rval = -1;
+  int       fd   = -1;
+  time_t    secs;
+  struct tm tm;
+  uint8_t   buf[DS1375_YR_REG + 1 - DS1375_SEC_REG];
+  uint8_t   cr = 0xff;
+
+  /*
+   * The clock hardware maintains the day-of-week as a separate counter
+   * so we must compute it ourselves (rtems_time_of_day doesn't come
+   * with a day of week).
+   */
+  secs = _TOD_To_seconds( time );
+  /* we're only interested in tm_wday... */
+  gmtime_r( &secs, &tm );
+
+  buf[DS1375_SEC_OFF] = ds1375_bin2bcd( time->second );
+  buf[DS1375_MIN_OFF] = ds1375_bin2bcd( time->minute );
+  /* bin2bcd(hour) implicitly selects 24h mode since ms-bit is clear */
+  buf[DS1375_HR_OFF]  = ds1375_bin2bcd( time->hour   );
+  buf[DS1375_DAY_OFF] = tm.tm_wday + 1;
+  buf[DS1375_DAT_OFF] = ds1375_bin2bcd( time->day    );
+  buf[DS1375_MON_OFF] = ds1375_bin2bcd( time->month  );
+
+  if ( time->year >= 2000 ) {
+    buf[DS1375_YR_OFF]   = ds1375_bin2bcd( time->year - 2000 );
+    buf[DS1375_MON_OFF] |= DS1375_MON_CTRY;
+  } else {
+    buf[DS1375_YR_OFF]   = ds1375_bin2bcd( time->year - 1900 );
+  }
+
+  /*
+   * Stop clock; update registers and restart. This is slightly
+   * slower than just writing everyting but if we did that we
+   * could get inconsistent registers if this routine would not
+   * complete in less than 1s (says the datasheet) and we don't
+   * know if we are going to be pre-empted for some time...
+   */
+  if ( ( fd = getfd( minor ) ) < 0 ) {
+    goto cleanup;
+  }
+
+  if ( rd_bytes( fd, DS1375_CR_REG, &cr, 1 ) )
+    goto cleanup;
+
+  cr &= ~DS1375_CR_ECLK;
+
+  /* This stops the clock */
+  if ( wr_bytes( fd, DS1375_CR_REG, &cr, 1 ) )
+    goto cleanup;
+
+  /* write new contents */
+  if ( wr_bytes( fd, DS1375_SEC_REG, buf, sizeof(buf) ) )
+    goto cleanup;
+
+  rval = 0;
+
+cleanup:
+  if ( fd >= 0 ) {
+    if ( ! ( DS1375_CR_ECLK & cr ) ) {
+      /* start clock; this handles some cases of failure
+       * after stopping the clock by restarting it again
+       */
+      cr |= DS1375_CR_ECLK;
+      if ( wr_bytes( fd, DS1375_CR_REG, &cr, 1 ) )
+        rval = -1;
+    }
+    close( fd );
+  }
+  return rval;
+}
+
+/* Debugging / Testing                   */
+
+#ifdef DEBUG
+
+/* Don't forget to set "TZ" when using these test routines */
+
+/* What is rtems_time_of_day good for ? Why not use std types ? */
+
+uint32_t
+ds1375_get_time_tst()
+{
+rtems_time_of_day rtod;
+time_t            secs;
+
+  ds1375_get_time( 0, &rtod );
+  secs = _TOD_To_seconds( &rtod );
+  printf( "%s\n", ctime( &secs ) );
+  return secs;
+}
+
+int
+ds1375_set_time_tst( const char *datstr, rtems_time_of_day *prt )
+{
+struct tm         tm;
+time_t            secs;
+rtems_time_of_day rt;
+
+  if ( !datstr )
+    return -1;
+
+  if ( ! strptime( datstr, "%Y-%m-%d/%T", &tm ) )
+    return -2;
+
+  if ( ! prt )
+    prt = &rt;
+
+  secs = mktime( &tm );
+
+  /* convert to UTC */
+  gmtime_r( &secs, &tm );
+
+  printf("Y: %"PRIu32" ",  (prt->year    = tm.tm_year + 1900) );
+  printf("M: %"PRIu32" ",  (prt->month   = tm.tm_mon  +    1) );
+  printf("D: %"PRIu32" ",  (prt->day     = tm.tm_mday       ) );
+  printf("h: %"PRIu32" ",  (prt->hour    = tm.tm_hour       ) );
+  printf("m: %"PRIu32" ",  (prt->minute  = tm.tm_min        ) );
+  printf("s: %"PRIu32"\n", (prt->second  = tm.tm_sec        ) );
+  prt->ticks = 0;
+
+  return ( prt == &rt ) ? ds1375_set_time( 0, &rt ) : 0;
+}
+
+#endif
+
+
+uint32_t
+rtc_ds1375_get_register( uintptr_t port, uint8_t reg )
+{
+int      fd;
+uint8_t  v;
+uint32_t rval = -1;
+
+  if ( ( fd = open( (const char*)port, O_RDWR ) ) >= 0 ) {
+
+    if ( 0 == rd_bytes( fd, reg, &v, 1 ) ) {
+      rval = v;
+    }
+    close( fd );
+  }
+
+  return rval;
+}
+
+void
+rtc_ds1375_set_register( uintptr_t port, uint8_t reg, uint32_t value )
+{
+int     fd;
+uint8_t v = value;
+
+  if ( ( fd = open( (const char*)port, O_RDWR ) ) >= 0 ) {
+    wr_bytes( fd, reg, &v, 1 );
+    close( fd );
+  }
+
+}
+
+bool rtc_ds1375_device_probe(
+ int minor
+)
+{
+  int fd;
+
+  if ( ( fd = getfd( minor ) ) < 0 ) {
+    STDIOSAFE( "ds1375_probe (open): %s\n", strerror( errno ) );
+    return false;
+  }
+
+  /* Try to set file pointer */
+  if ( 0 != wr_bytes( fd, DS1375_SEC_REG, 0, 0 ) ) {
+    STDIOSAFE( "ds1375_probe (wr_bytes): %s\n", strerror( errno ) );
+    close( fd );
+    return false;
+  }
+
+  if ( close( fd ) ) {
+    STDIOSAFE( "ds1375_probe (close): %s\n", strerror( errno ) );
+    return false;
+  }
+
+  return true;
+}
+
+rtc_fns rtc_ds1375_fns = {
+  .deviceInitialize = ds1375_initialize,
+  .deviceGetTime =    ds1375_get_time,
+  .deviceSetTime =    ds1375_set_time,
+};
Index: bsps/shared/dev/rtc/icm7170.c
===================================================================
--- bsps/shared/dev/rtc/icm7170.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/icm7170.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,168 @@
+/*
+ *  This file interfaces with the real-time clock found in
+ *  a Harris ICM7170
+ *
+ *  Year 2K Notes:
+ *
+ *  This chip only uses a two digit field to store the year.  This
+ *  code uses the RTEMS Epoch as a pivot year.  This lets us map the
+ *  two digit year field as follows:
+ *
+ *    + two digit years 0-87 are mapped to 2000-2087.
+ *    + two digit years 88-99 are mapped to 1988-1999.
+ *
+ *  This is less than the time span supported by RTEMS.
+ *
+ *  COPYRIGHT (c) 1989-1999.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <libchip/rtc.h>
+#include <libchip/icm7170.h>
+
+/*
+ *  Control register bits
+ */
+
+/* XXX */
+
+/*
+ *  icm7170_initialize
+ */
+
+static void icm7170_initialize(
+  int minor
+)
+{
+  uintptr_t      icm7170;
+  setRegister_f  setReg;
+  uintptr_t      clock;
+
+  icm7170 = RTC_Table[ minor ].ulCtrlPort1;
+  setReg = RTC_Table[ minor ].setRegister;
+
+  /*
+   *  Initialize the RTC with the proper clock frequency
+   */
+
+  clock = (uintptr_t) RTC_Table[ minor ].pDeviceParams;
+  (*setReg)( icm7170, ICM7170_CONTROL, 0x0c | clock );
+}
+
+/*
+ *  icm7170_get_time
+ */
+
+static int icm7170_get_time(
+  int                minor,
+  rtems_time_of_day *time
+)
+{
+  uint32_t       icm7170;
+  getRegister_f  getReg;
+  uint32_t       year;
+
+  icm7170 = RTC_Table[ minor ].ulCtrlPort1;
+  getReg = RTC_Table[ minor ].getRegister;
+
+  /*
+   *  Put the RTC into read mode
+   */
+
+  (void) (*getReg)( icm7170, ICM7170_COUNTER_HUNDREDTHS );
+
+  /*
+   *  Now get the time
+   */
+
+
+  year = (*getReg)( icm7170, ICM7170_YEAR );
+  if ( year < 88 )
+    year += 2000;
+  else
+    year += 1900;
+
+  time->year   = year;
+  time->month  = (*getReg)( icm7170, ICM7170_MONTH );
+  time->day    = (*getReg)( icm7170, ICM7170_DATE );
+  time->hour   = (*getReg)( icm7170, ICM7170_HOUR );
+  time->minute = (*getReg)( icm7170, ICM7170_MINUTE );
+  time->second = (*getReg)( icm7170, ICM7170_SECOND );
+
+  time->ticks  = 0;
+
+  /*
+   *  Put the RTC back into normal mode.
+   */
+
+  (void) (*getReg)( icm7170, ICM7170_COUNTER_HUNDREDTHS );
+
+  return 0;
+}
+
+/*
+ *  icm7170_set_time
+ */
+
+static int icm7170_set_time(
+  int                minor,
+  const rtems_time_of_day *time
+)
+{
+  uintptr_t      icm7170;
+  setRegister_f  setReg;
+  uint32_t       year;
+  uintptr_t      clock;
+
+  icm7170 = RTC_Table[ minor ].ulCtrlPort1;
+  setReg = RTC_Table[ minor ].setRegister;
+  clock = (uintptr_t) RTC_Table[ minor ].pDeviceParams;
+
+  year = time->year;
+
+  if ( year >= 2088 )
+    rtems_fatal_error_occurred( RTEMS_INVALID_NUMBER );
+
+  if ( year >= 2000 )
+    year -= 2000;
+  else
+    year -= 1900;
+
+  (*setReg)( icm7170, ICM7170_CONTROL, 0x04 | clock );
+
+  (*setReg)( icm7170, ICM7170_YEAR,    year );
+  (*setReg)( icm7170, ICM7170_MONTH,   time->month );
+  (*setReg)( icm7170, ICM7170_DATE,    time->day );
+  (*setReg)( icm7170, ICM7170_HOUR,    time->hour );
+  (*setReg)( icm7170, ICM7170_MINUTE,  time->minute );
+  (*setReg)( icm7170, ICM7170_SECOND,  time->second );
+
+  /*
+   *  This is not really right.
+   */
+
+  (*setReg)( icm7170, ICM7170_DAY_OF_WEEK,  1 );
+
+  /*
+   *  Put the RTC back into normal mode.
+   */
+
+  (*setReg)( icm7170, ICM7170_CONTROL, 0x0c | clock );
+
+  return 0;
+}
+
+/*
+ *  Driver function table
+ */
+
+rtc_fns icm7170_fns = {
+  icm7170_initialize,
+  icm7170_get_time,
+  icm7170_set_time
+};
Index: bsps/shared/dev/rtc/icm7170_reg.c
===================================================================
--- bsps/shared/dev/rtc/icm7170_reg.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/icm7170_reg.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,60 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the icm7170 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are only byte-aligned (no address gaps)
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <libchip/rtc.h>
+#include <libchip/icm7170.h>
+
+#ifndef _ICM7170_MULTIPLIER
+#define _ICM7170_MULTIPLIER 1
+#define _ICM7170_NAME(_X) _X
+#define _ICM7170_TYPE uint8_t
+#endif
+
+#define CALCULATE_REGISTER_ADDRESS( _base, _reg ) \
+  (_ICM7170_TYPE *)((_base) + ((_reg) * _ICM7170_MULTIPLIER ))
+
+/*
+ *  ICM7170 Get Register Routine
+ */
+
+uint32_t   _ICM7170_NAME(icm7170_get_register)(
+  uintptr_t   ulCtrlPort,
+  uint8_t     ucRegNum
+)
+{
+  _ICM7170_TYPE *port;
+
+  port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
+
+  return *port;
+}
+
+/*
+ *  ICM7170 Set Register Routine
+ */
+
+void  _ICM7170_NAME(icm7170_set_register)(
+  uintptr_t   ulCtrlPort,
+  uint8_t     ucRegNum,
+  uint32_t    ucData
+)
+{
+  _ICM7170_TYPE *port;
+
+  port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
+
+  *port = ucData;
+}
Index: bsps/shared/dev/rtc/icm7170_reg2.c
===================================================================
--- bsps/shared/dev/rtc/icm7170_reg2.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/icm7170_reg2.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,20 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the icm7170 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are on 16-bit boundaries
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#define _ICM7170_MULTIPLIER 2
+#define _ICM7170_NAME(_X) _X##_2
+#define _ICM7170_TYPE uint8_t
+
+#include "icm7170_reg.c"
Index: bsps/shared/dev/rtc/icm7170_reg4.c
===================================================================
--- bsps/shared/dev/rtc/icm7170_reg4.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/icm7170_reg4.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,20 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the icm7170 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are on 32-bit boundaries
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#define _ICM7170_MULTIPLIER 4
+#define _ICM7170_NAME(_X) _X##_4
+#define _ICM7170_TYPE uint8_t
+
+#include "icm7170_reg.c"
Index: bsps/shared/dev/rtc/icm7170_reg8.c
===================================================================
--- bsps/shared/dev/rtc/icm7170_reg8.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/icm7170_reg8.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,20 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the icm7170 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are on 64-bit boundaries
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#define _ICM7170_MULTIPLIER 8
+#define _ICM7170_NAME(_X) _X##_8
+#define _ICM7170_TYPE uint8_t
+
+#include "icm7170_reg.c"
Index: bsps/shared/dev/rtc/m48t08.c
===================================================================
--- bsps/shared/dev/rtc/m48t08.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/m48t08.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,161 @@
+/*
+ *  This file interfaces with the real-time clock found in
+ *  a Mostek M48T08 or M48T18 or compatibles.
+ *
+ *  Year 2K Notes:
+ *
+ *  This chip only uses a two digit field to store the year.  This
+ *  code uses the RTEMS Epoch as a pivot year.  This lets us map the
+ *  two digit year field as follows:
+ *
+ *    + two digit years 0-87 are mapped to 2000-2087.
+ *    + two digit years 88-99 are mapped to 1988-1999.
+ *
+ *  This is less than the time span supported by RTEMS.
+ *
+ *  COPYRIGHT (c) 1989-1999.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <libchip/rtc.h>
+#include <libchip/m48t08.h>
+
+/*
+ *  Control register bits
+ */
+
+#define M48T08_CONTROL_WRITE  0x80
+#define M48T08_CONTROL_READ   0x40
+#define M48T08_CONTROL_SIGN   0x20
+
+/*
+ *  m48t08_initialize
+ */
+
+static void m48t08_initialize(
+  int minor
+)
+{
+}
+
+/*
+ *  m48t08_get_time
+ */
+
+#define From_BCD( _x ) ((((_x) >> 4) * 10) + ((_x) & 0x0F))
+#define To_BCD( _x )   ((((_x) / 10) << 4) + ((_x) % 10))
+
+static int m48t08_get_time(
+  int                minor,
+  rtems_time_of_day *time
+)
+{
+  uint32_t       m48t08;
+  getRegister_f  getReg;
+  setRegister_f  setReg;
+  uint8_t        controlReg;
+  uint32_t       value1;
+  uint32_t       value2;
+
+  m48t08 = RTC_Table[ minor ].ulCtrlPort1;
+  getReg = RTC_Table[ minor ].getRegister;
+  setReg = RTC_Table[ minor ].setRegister;
+
+  /*
+   *  Put the RTC into read mode
+   */
+
+  controlReg = (*getReg)( m48t08, M48T08_CONTROL );
+  (*setReg)( m48t08, M48T08_CONTROL, controlReg | M48T08_CONTROL_READ );
+
+  value1 = (*getReg)( m48t08, M48T08_YEAR );
+  value2 = From_BCD( value1 );
+  if ( value2 < 88 )
+    time->year = 2000 + value2;
+  else
+    time->year = 1900 + value2;
+
+  value1 = (*getReg)( m48t08, M48T08_MONTH );
+  time->month = From_BCD( value1 );
+
+  value1 = (*getReg)( m48t08, M48T08_DATE );
+  time->day = From_BCD( value1 );
+
+  value1 = (*getReg)( m48t08, M48T08_HOUR );
+  time->hour = From_BCD( value1 );
+
+  value1 = (*getReg)( m48t08, M48T08_MINUTE );
+  time->minute = From_BCD( value1 );
+
+  value1 = (*getReg)( m48t08, M48T08_SECOND );
+  time->second = From_BCD( value1 );
+
+  time->ticks  = 0;
+
+  /*
+   *  Put the RTC back into normal mode.
+   */
+
+  (*setReg)( m48t08, M48T08_CONTROL, controlReg );
+
+  return 0;
+}
+
+/*
+ *  m48t08_set_time
+ */
+
+static int m48t08_set_time(
+  int                minor,
+  const rtems_time_of_day *time
+)
+{
+  uint32_t       m48t08;
+  getRegister_f  getReg;
+  setRegister_f  setReg;
+  uint8_t        controlReg;
+
+  m48t08 = RTC_Table[ minor ].ulCtrlPort1;
+  getReg = RTC_Table[ minor ].getRegister;
+  setReg = RTC_Table[ minor ].setRegister;
+
+  /*
+   *  Put the RTC into read mode
+   */
+
+  controlReg = (*getReg)( m48t08, M48T08_CONTROL );
+  (*setReg)( m48t08, M48T08_CONTROL, controlReg | M48T08_CONTROL_WRITE );
+
+  if ( time->year >= 2088 )
+    rtems_fatal_error_occurred( RTEMS_INVALID_NUMBER );
+
+  (*setReg)( m48t08, M48T08_YEAR,    To_BCD(time->year % 100) );
+  (*setReg)( m48t08, M48T08_MONTH,   To_BCD(time->month) );
+  (*setReg)( m48t08, M48T08_DATE,    To_BCD(time->day) );
+  (*setReg)( m48t08, M48T08_HOUR,    To_BCD(time->hour) );
+  (*setReg)( m48t08, M48T08_MINUTE,  To_BCD(time->minute) );
+  (*setReg)( m48t08, M48T08_SECOND,  To_BCD(time->second) );
+
+  /*
+   *  Put the RTC back into normal mode.
+   */
+
+  (*setReg)( m48t08, M48T08_CONTROL, controlReg );
+
+  return 0;
+}
+
+/*
+ *  Driver function table
+ */
+
+rtc_fns m48t08_fns = {
+  m48t08_initialize,
+  m48t08_get_time,
+  m48t08_set_time
+};
Index: bsps/shared/dev/rtc/m48t08_reg.c
===================================================================
--- bsps/shared/dev/rtc/m48t08_reg.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/m48t08_reg.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,60 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the m48t08 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are only byte-aligned (no address gaps)
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <libchip/rtc.h>
+#include <libchip/m48t08.h>
+
+#ifndef _M48T08_MULTIPLIER
+#define _M48T08_MULTIPLIER 1
+#define _M48T08_NAME(_X) _X
+#define _M48T08_TYPE uint8_t
+#endif
+
+#define CALCULATE_REGISTER_ADDRESS( _base, _reg ) \
+  (_M48T08_TYPE *)((_base) + ((_reg) * _M48T08_MULTIPLIER ))
+
+/*
+ *  M48T08 Get Register Routine
+ */
+
+uint32_t   _M48T08_NAME(m48t08_get_register)(
+  uintptr_t   ulCtrlPort,
+  uint8_t     ucRegNum
+)
+{
+  _M48T08_TYPE *port;
+
+  port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
+
+  return *port;
+}
+
+/*
+ *  M48T08 Set Register Routine
+ */
+
+void  _M48T08_NAME(m48t08_set_register)(
+  uintptr_t   ulCtrlPort,
+  uint8_t     ucRegNum,
+  uint32_t    ucData
+)
+{
+  _M48T08_TYPE *port;
+
+  port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
+
+  *port = ucData;
+}
Index: bsps/shared/dev/rtc/m48t08_reg2.c
===================================================================
--- bsps/shared/dev/rtc/m48t08_reg2.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/m48t08_reg2.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,20 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the m48t08 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are on 16-bit boundaries
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#define _M48T08_MULTIPLIER 2
+#define _M48T08_NAME(_X) _X##_2
+#define _M48T08_TYPE uint8_t
+
+#include "m48t08_reg.c"
Index: bsps/shared/dev/rtc/m48t08_reg4.c
===================================================================
--- bsps/shared/dev/rtc/m48t08_reg4.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/m48t08_reg4.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,20 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the m48t08 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are on 32-bit boundaries
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#define _M48T08_MULTIPLIER 4
+#define _M48T08_NAME(_X) _X##_4
+#define _M48T08_TYPE uint8_t
+
+#include "m48t08_reg.c"
Index: bsps/shared/dev/rtc/m48t08_reg8.c
===================================================================
--- bsps/shared/dev/rtc/m48t08_reg8.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/m48t08_reg8.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,20 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the m48t08 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are on 64-bit boundaries
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#define _M48T08_MULTIPLIER 8
+#define _M48T08_NAME(_X) _X##_8
+#define _M48T08_TYPE uint8_t
+
+#include "m48t08_reg.c"
Index: bsps/shared/dev/rtc/mc146818a.c
===================================================================
--- bsps/shared/dev/rtc/mc146818a.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/mc146818a.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,180 @@
+/*
+ *  This file interfaces with the real-time clock found in
+ *  a Motorola MC146818A (common on PC hardware)
+ *
+ *  Year 2K Notes:
+ *
+ *  This chip only uses a two digit field to store the year.  This
+ *  code uses the RTEMS Epoch as a pivot year.  This lets us map the
+ *  two digit year field as follows:
+ *
+ *    + two digit years 0-87 are mapped to 2000-2087.
+ *    + two digit years 88-99 are mapped to 1988-1999.
+ *
+ *  This is less than the time span supported by RTEMS.
+ *
+ *  COPYRIGHT (c) 1989-1999.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+#include <rtems.h>
+#include <libchip/rtc.h>
+#include <libchip/mc146818a.h>
+
+#define From_BCD( _x ) ((((_x) >> 4) * 10) + ((_x) & 0x0F))
+#define To_BCD( _x )   ((((_x) / 10) << 4) + ((_x) % 10))
+
+/*
+ * See if chip is present
+ */
+bool mc146818a_probe(
+  int minor
+)
+{
+  uint32_t     mc146818a;
+  getRegister_f  getReg;
+  uint32_t     value;
+
+  /*
+   * Verify that chip is present and that time is valid
+   */
+  mc146818a = RTC_Table[ minor ].ulCtrlPort1;
+  getReg = RTC_Table[ minor ].getRegister;
+  value = (*getReg)( mc146818a, MC146818A_STATUSD );
+  if ((value == 0) || (value == 0xFF))
+    return false;
+  return true;
+}
+
+/*
+ * Initialize chip
+ */
+static void mc146818a_initialize(
+  int minor
+)
+{
+  uintptr_t      mc146818a;
+  setRegister_f  setReg;
+
+  mc146818a = RTC_Table[ minor ].ulCtrlPort1;
+  setReg = RTC_Table[ minor ].setRegister;
+
+  (*setReg)(
+    mc146818a,
+    MC146818A_STATUSA,
+    MC146818ASA_DIVIDER|MC146818ASA_1024
+  );
+  (*setReg)(
+    mc146818a,
+    MC146818A_STATUSB,
+    MC146818ASB_24HR
+  );
+}
+
+/*
+ * Read time from chip
+ */
+static int mc146818a_get_time(
+  int                minor,
+  rtems_time_of_day *time
+)
+{
+  uintptr_t             mc146818a;
+  getRegister_f         getReg;
+  uint32_t              value;
+  rtems_interrupt_level level;
+
+  mc146818a = RTC_Table[ minor ].ulCtrlPort1;
+  getReg = RTC_Table[ minor ].getRegister;
+
+  /*
+   * No time if power failed
+   */
+  if (((*getReg)( mc146818a, MC146818A_STATUSD ) & MC146818ASD_PWR) == 0)
+    return -1;
+
+  /*
+   * Wait for time update to complete
+   */
+  rtems_interrupt_disable( level );
+  while (((*getReg)( mc146818a, MC146818A_STATUSA ) & MC146818ASA_TUP) != 0) {
+      rtems_interrupt_flash( level );
+  }
+
+  /*
+   * Read the time (we have at least 244 usec to do this)
+   */
+  value = (*getReg)( mc146818a, MC146818A_YEAR );
+  value = From_BCD( value );
+  if ( value < 88 )
+    time->year = 2000 + value;
+  else
+    time->year = 1900 + value;
+
+  value = (*getReg)( mc146818a, MC146818A_MONTH );
+  time->month = From_BCD( value );
+
+  value = (*getReg)( mc146818a, MC146818A_DAY );
+  time->day = From_BCD( value );
+
+  value = (*getReg)( mc146818a, MC146818A_HRS );
+  time->hour = From_BCD( value );
+
+  value = (*getReg)( mc146818a, MC146818A_MIN );
+  time->minute = From_BCD( value );
+
+  value = (*getReg)( mc146818a, MC146818A_SEC );
+  rtems_interrupt_enable( level );
+  time->second = From_BCD( value );
+  time->ticks  = 0;
+
+  return 0;
+}
+
+/*
+ * Set time into chip
+ */
+static int mc146818a_set_time(
+  int                      minor,
+  const rtems_time_of_day *time
+)
+{
+  uint32_t     mc146818a;
+  setRegister_f  setReg;
+
+  mc146818a = RTC_Table[ minor ].ulCtrlPort1;
+  setReg = RTC_Table[ minor ].setRegister;
+
+  /*
+   * Stop the RTC
+   */
+  (*setReg)( mc146818a, MC146818A_STATUSB, MC146818ASB_HALT|MC146818ASB_24HR );
+
+  if ( time->year >= 2088 )
+    rtems_fatal_error_occurred( RTEMS_INVALID_NUMBER );
+
+  (*setReg)( mc146818a, MC146818A_YEAR,  To_BCD(time->year % 100) );
+  (*setReg)( mc146818a, MC146818A_MONTH, To_BCD(time->month) );
+  (*setReg)( mc146818a, MC146818A_DAY,   To_BCD(time->day) );
+  (*setReg)( mc146818a, MC146818A_HRS,   To_BCD(time->hour) );
+  (*setReg)( mc146818a, MC146818A_MIN,   To_BCD(time->minute) );
+  (*setReg)( mc146818a, MC146818A_SEC,   To_BCD(time->second) );
+
+  /*
+   * Restart the RTC
+   */
+  (*setReg)( mc146818a, MC146818A_STATUSB, MC146818ASB_24HR );
+  return 0;
+}
+
+/*
+ *  Driver function table
+ */
+rtc_fns mc146818a_fns = {
+  mc146818a_initialize,
+  mc146818a_get_time,
+  mc146818a_set_time
+};
Index: bsps/shared/dev/rtc/mc146818a_ioreg.c
===================================================================
--- bsps/shared/dev/rtc/mc146818a_ioreg.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/mc146818a_ioreg.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,56 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the MC146818A chip if accesses to the chip are as follows:
+ *
+ *    + registers are in I/O space
+ *    + registers are accessed as bytes
+ *    + registers are only byte-aligned (no address gaps)
+ */
+
+/*
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <libchip/rtc.h>
+#include <libchip/mc146818a.h>
+
+/*
+ *  At this point, not all CPUs or BSPs have defined in/out port routines.
+ */
+#if defined(__i386__) || defined(__PPC__)
+#if defined(inport_byte)
+uint32_t mc146818a_get_register(
+  uintptr_t  ulCtrlPort,
+  uint8_t    ucRegNum
+)
+{
+  uint8_t   val;
+  uint8_t   tmp;
+
+  (void) tmp;                 /* eliminate warning for set but not used */
+
+  outport_byte( ulCtrlPort, ucRegNum );
+  inport_byte( 0x84, tmp );   /* Hack a delay to give chip time to settle */
+  inport_byte( ulCtrlPort+1, val );
+  inport_byte( 0x84, tmp );   /* Hack a delay to give chip time to settle */
+  return val;
+}
+
+void  mc146818a_set_register(
+  uintptr_t  ulCtrlPort,
+  uint8_t    ucRegNum,
+  uint32_t   ucData
+)
+{
+  outport_byte( ulCtrlPort, ucRegNum );
+  outport_byte( ulCtrlPort+1, (uint8_t)ucData );
+}
+#endif
+#endif
Index: bsps/shared/dev/rtc/rtcprobe.c
===================================================================
--- bsps/shared/dev/rtc/rtcprobe.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/rtc/rtcprobe.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,21 @@
+/*
+ *  This file contains the default Real-Time Clock probe routine.
+ *
+ *  COPYRIGHT (c) 1989-1999.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <libchip/rtc.h>
+
+
+bool rtc_probe(
+  int minor
+)
+{
+  return true;
+}
Index: bsps/shared/dev/serial/README
===================================================================
--- bsps/shared/dev/serial/README	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/README	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,13 @@
+This is the serial controller portion of the libchip library.  This 
+directory contains the source code for reusable console driver
+support code.  Each individual driver is configured using the
+console_tbl data structure.  This structure is defined and explained
+in the console.h file.
+
+The reusable chip drivers do not directly access the serial controller.
+They access the registers on the controller via a set of up to four 
+functions which are provided by the BSP.  These functins set and get
+general registers and data buffers.  Some chips can access the data
+buffers as general registers and thus the driver may not require
+those interface routines.
+
Index: bsps/shared/dev/serial/README.mc68681
===================================================================
--- bsps/shared/dev/serial/README.mc68681	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/README.mc68681	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,83 @@
+Configuration Table Use
+=======================
+
+sDeviceName
+
+   The name of this device.
+
+deviceType
+
+   This field must be SERIAL_MC68681.
+
+pDeviceFns
+
+   The device interface control table.  This may be:
+      + mc68681_fns for interrupt driven IO
+      + mc68681_fns_polled for polled IO
+
+deviceProbe
+
+   This is the address of the routine which probes to see if the device
+   is present.
+
+pDeviceFlow
+
+   This field is ignored as hardware flow control is not currently supported.
+
+ulMargin
+
+    This is currently unused.
+
+ulHysteresis
+
+    This is currently unused.
+
+pDeviceParams
+
+    This is set to the default settings.
+
+ulCtrlPort1
+
+   This field is the base address of the entire DUART.
+
+ulCtrlPort2
+
+   This field is the base address of the port specific registers.
+
+ulDataPort
+
+   This field is bit mapped as follows:
+     bit 0:  baud rate set a or b
+     bit 1-2: BRG selection ("Select Extend bit")
+
+   Note: If both ports on single DUART are not configured for the same
+         baud rate set, then unexpected results will occur.
+
+   Note: On the Exar 88c681, if a standard clock of 3.6864 Mhz is used
+         and the "Select Extend bit" is 0 (disabled), then the default
+         MC68681 baud rate table is selected.
+
+getRegister
+setRegister
+
+   These follow standard conventions.
+
+getData
+setData
+
+   These are unused since the TX and RX data registers can be accessed
+   as regular registers.
+
+ulClock
+
+   This is a pointer to a baud rate mapping table.  If set to
+   mc68681_baud_rate_table, then the CSR/ACR/X bit mappings shown
+   in the 68681 and 88681 manuals are used.  Otherwise, the board
+   specific baud rate mapping is used.
+
+   NULL is not a valid value.
+
+ulIntVector
+
+   This is the interrupt vector number associated with this chip.
+
Index: bsps/shared/dev/serial/README.ns16550
===================================================================
--- bsps/shared/dev/serial/README.ns16550	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/README.ns16550	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,82 @@
+Status
+======
+
+There are no known problems with this driver.
+
+Configuration Table Use
+=======================
+
+sDeviceName
+
+   The name of this device.
+
+deviceType
+
+   This field must be SERIAL_NS16550.
+
+pDeviceFns
+
+   The device interface control table.  This may be:
+      + ns16550_fns for interrupt driven IO
+      + ns16550_fns_polled for polled IO
+
+deviceProbe
+
+   This is the address of the routine which probes to see if the device
+   is present.
+
+pDeviceFlow
+
+   This field is ignored as hardware flow control is not currently supported.
+
+ulMargin
+
+    This is currently unused.
+
+ulHysteresis
+
+    This is currently unused.
+
+pDeviceParams
+
+    This is set to the default settings.  At this point, it is the default
+    baud rate cast as a (void *).
+
+ulCtrlPort1
+
+   This field is the base address of this port on the UART.
+
+ulCtrlPort2
+
+   This field is unused for the NS16550.
+
+ulDataPort
+
+   This field is the base address of this port on the UART. 
+
+getRegister
+setRegister
+
+   These follow standard conventions.
+
+getData
+setData
+
+   These are unused since the TX and RX data registers can be accessed
+   as regular registers.
+
+ulClock
+
+   This is the clock constant which is divided by the desired baud
+   to get the value programmed into the part.  The formula for this
+   for 9600 baud is:
+
+      chip_divisor_value = ulClock / 9600.
+
+   NOTE: When ulClock is 0, the correct value for a PC (115,200) is
+   used.
+
+ulIntVector
+
+   This is the interrupt vector number associated with this chip.
+
Index: bsps/shared/dev/serial/README.xr88681
===================================================================
--- bsps/shared/dev/serial/README.xr88681	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/README.xr88681	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,2 @@
+The Exar XR88681 is an enhanced version of the Motorola MC68681 and is
+supported by the mc68681 driver.
Index: bsps/shared/dev/serial/README.z85c30
===================================================================
--- bsps/shared/dev/serial/README.z85c30	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/README.z85c30	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,74 @@
+Configuration Table Use
+=======================
+
+sDeviceName
+
+   The name of this device.
+
+deviceType
+
+   This field must be SERIAL_Z85C30.
+
+pDeviceFns
+
+   The device interface control table.  This may be:
+      + z85c30_fns for interrupt driven IO
+      + z85c30_fns_polled for polled IO
+
+deviceProbe
+
+   This is the address of the routine which probes to see if the device
+   is present.
+
+pDeviceFlow
+
+   This field is set to one of the following values:
+      + NULL for no hardware flow control
+      + z85c30_flow_RTSCTS for RTS/CTS based flow control
+      + z85c30_flow_DTRCTS for DTR/CTS based flow control
+
+ulMargin
+
+    This is currently unused.
+
+ulHysteresis
+
+    This is currently unused.
+
+pDeviceParams
+
+    This is set to the default settings.
+
+ulCtrlPort1
+
+   This field is the address of the control register for this port.
+
+ulCtrlPort2
+
+   This field is the address of the control register for chip.
+
+ulDataPort
+
+   This field is the address of the data register for this port.
+
+getRegister
+setRegister
+
+   These follow standard conventions.
+
+getData
+setData
+
+   These follow standard conventions.
+
+ulClock
+
+   This is the clock speed of the baud rate clock.
+   NULL, then the CSR/ACR/X bit mappings shown in the 68681 and 88681
+   manuals are used.  Otherwise, the board specific baud rate mapping
+   is used.
+
+ulIntVector
+
+   This is the interrupt vector number associated with this chip.
+
Index: bsps/shared/dev/serial/STATUS
===================================================================
--- bsps/shared/dev/serial/STATUS	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/STATUS	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,48 @@
+General
+=======
+
++ Hardware flow control is not currently supported.  Some of the chip
+  drivers (in particular the z8530) have support for hardware flow control
+  but this has not been tested in the libchip context.  There will need
+  to be a way to totally disabled hardware flow control which is not
+  currently in this.
+
++ "ulClockSpeed" configuration item field to become a pointer to a table
+  of chip specific information.  For example, the z8530 should specify
+  clock speed and clock divisor setting.
+
++ A termios structure should be included to specify  the initial settings.
+  Right now all drivers default to 9600, 8N1.
+ 
++ Need to switch to passing pointers rather than a minor number to 
+  functions which are strictly internal to each chip driver.  This
+  should be a performance win.
+
++ Need a test which prompts you for termios settings and tests them.  Until
+  this happens, testing for the variety of settings possible will be limited.
+  This test should be able to test any serial port while prompts come to the
+  console.
+
+MC68681
+=======
+
++ Works interrupt and polled.
+
++ Hardware flow control not included.
+
+NS16650
+=======
+
++ ns16550_set-attributes function is untested.
+
++ Hardware flow control included but is currently disabled in ISR.
+
+Z85C30
+======
+
++ Works polled and interrupt.
+
++ Hardware flow control included but is currently disabled in ISR.
+
++ Needs to support mode where more specific vectors are generated.
+
Index: bsps/shared/dev/serial/mc68681.c
===================================================================
--- bsps/shared/dev/serial/mc68681.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/mc68681.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,776 @@
+/*
+ *  This file contains the termios TTY driver for the Motorola MC68681.
+ *
+ *  This part is available from a number of secondary sources.
+ *  In particular, we know about the following:
+ *
+ *     + Exar 88c681 and 68c681
+ *
+ *  COPYRIGHT (c) 1989-1999.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/score/sysstate.h>
+#include <stdlib.h>
+
+#include <libchip/serial.h>
+#include <libchip/mc68681.h>
+#include <libchip/sersupp.h>
+#include "mc68681_p.h"
+
+/*
+ * Flow control is only supported when using interrupts
+ */
+
+const console_fns mc68681_fns =
+{
+  libchip_serial_default_probe,   /* deviceProbe */
+  mc68681_open,                   /* deviceFirstOpen */
+  NULL,                           /* deviceLastClose */
+  NULL,                           /* deviceRead */
+  mc68681_write_support_int,      /* deviceWrite */
+  mc68681_initialize_interrupts,  /* deviceInitialize */
+  mc68681_write_polled,           /* deviceWritePolled */
+  mc68681_set_attributes,         /* deviceSetAttributes */
+  true                            /* deviceOutputUsesInterrupts */
+};
+
+const console_fns mc68681_fns_polled =
+{
+  libchip_serial_default_probe,        /* deviceProbe */
+  mc68681_open,                        /* deviceFirstOpen */
+  mc68681_close,                       /* deviceLastClose */
+  mc68681_inbyte_nonblocking_polled,   /* deviceRead */
+  mc68681_write_support_polled,        /* deviceWrite */
+  mc68681_init,                        /* deviceInitialize */
+  mc68681_write_polled,                /* deviceWritePolled */
+  mc68681_set_attributes,              /* deviceSetAttributes */
+  false,                               /* deviceOutputUsesInterrupts */
+};
+
+
+#if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE)
+  extern void set_vector( rtems_isr_entry, rtems_vector_number, int );
+#endif
+
+/*
+ *  Console Device Driver Entry Points
+ */
+
+/*
+ *  mc68681_baud_rate
+ *
+ *  This routine returns the proper ACR bit and baud rate field values
+ *  based on the requested baud rate.  The baud rate set to be used
+ *  must be configured by the user.
+ */
+
+MC68681_STATIC int mc68681_baud_rate(
+  int           minor,
+  int           baud,
+  unsigned int *baud_mask_p,
+  unsigned int *acr_bit_p,
+  unsigned int *command
+);
+
+/*
+ *  mc68681_set_attributes
+ *
+ *  This function sets the DUART channel to reflect the requested termios
+ *  port settings.
+ */
+
+MC68681_STATIC int mc68681_set_attributes(
+  int minor,
+  const struct termios *t
+)
+{
+  uint32_t               pMC68681_port;
+  uint32_t               pMC68681;
+  unsigned int           mode1;
+  unsigned int           mode2;
+  unsigned int           baud_mask;
+  unsigned int           acr_bit;
+  unsigned int           cmd = 0;
+  setRegister_f          setReg;
+  rtems_interrupt_level  Irql;
+
+  pMC68681      = Console_Port_Tbl[minor]->ulCtrlPort1;
+  pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
+  setReg        = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   *  Set the baud rate
+   */
+
+  if (mc68681_baud_rate( minor, t->c_cflag, &baud_mask, &acr_bit, &cmd ) == -1)
+    return -1;
+
+  baud_mask |=  baud_mask << 4;
+  acr_bit   <<= 7;
+
+  /*
+   *  Parity
+   */
+
+  mode1 = 0;
+  mode2 = 0;
+
+  if (t->c_cflag & PARENB) {
+    if (t->c_cflag & PARODD)
+      mode1 |= 0x04;
+    /* else
+		mode1 |= 0x04; */
+  } else {
+   mode1 |= 0x10;
+  }
+
+  /*
+   *  Character Size
+   */
+
+  if (t->c_cflag & CSIZE) {
+    switch (t->c_cflag & CSIZE) {
+      case CS5:  break;
+      case CS6:  mode1 |= 0x01;  break;
+      case CS7:  mode1 |= 0x02;  break;
+      case CS8:  mode1 |= 0x03;  break;
+    }
+  } else {
+    mode1 |= 0x03;       /* default to 9600,8,N,1 */
+  }
+
+  /*
+   *  Stop Bits
+   */
+
+  if (t->c_cflag & CSTOPB) {
+    mode2 |= 0x0F;                      /* 2 stop bits */
+  } else {
+    if ((t->c_cflag & CSIZE) == CS5)    /* CS5 and 1 stop bits not supported */
+      return -1;
+    mode2 |= 0x07;                      /* 1 stop bit */
+  }
+
+ /*
+  *   Hardware Flow Control
+  */
+
+  if(t->c_cflag & CRTSCTS) {
+	  mode1 |= 0x80; /* Enable Rx RTS Control */
+	  mode2 |= 0x10; /* Enable CTS Enable Tx */
+  }
+
+
+  rtems_interrupt_disable(Irql);
+    (*setReg)( pMC68681, MC68681_AUX_CTRL_REG, acr_bit );
+    (*setReg)( pMC68681_port, MC68681_CLOCK_SELECT, baud_mask );
+    if ( cmd ) {
+      (*setReg)( pMC68681_port, MC68681_COMMAND, cmd );         /* RX */
+      (*setReg)( pMC68681_port, MC68681_COMMAND, cmd | 0x20 );  /* TX */
+    }
+    (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_MR_PTR );
+    (*setReg)( pMC68681_port, MC68681_MODE, mode1 );
+    (*setReg)( pMC68681_port, MC68681_MODE, mode2 );
+  rtems_interrupt_enable(Irql);
+  return 0;
+}
+
+/*
+ *  mc68681_initialize_context
+ *
+ *  This function sets the default values of the per port context structure.
+ */
+
+MC68681_STATIC void mc68681_initialize_context(
+  int               minor,
+  mc68681_context  *pmc68681Context
+)
+{
+  int          port;
+  unsigned int pMC68681;
+  unsigned int pMC68681_port;
+
+  pMC68681      = Console_Port_Tbl[minor]->ulCtrlPort1;
+  pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
+
+  pmc68681Context->mate = -1;
+
+  for (port=0 ; port<Console_Port_Count ; port++ ) {
+    if ( Console_Port_Tbl[port]->ulCtrlPort1 == pMC68681 &&
+         Console_Port_Tbl[port]->ulCtrlPort2 != pMC68681_port ) {
+      pmc68681Context->mate = port;
+      pmc68681Context->imr  = 0;
+      break;
+    }
+  }
+
+}
+
+/*
+ *  mc68681_init
+ *
+ *  This function initializes the DUART to a quiecsent state.
+ */
+
+MC68681_STATIC void mc68681_init(int minor)
+{
+  uint32_t                pMC68681_port;
+  mc68681_context        *pmc68681Context;
+  setRegister_f           setReg;
+
+  pmc68681Context = (mc68681_context *) malloc(sizeof(mc68681_context));
+
+  Console_Port_Data[minor].pDeviceContext = (void *)pmc68681Context;
+
+  mc68681_initialize_context( minor, pmc68681Context );
+
+  pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
+  setReg        = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   *  Reset everything and leave this port disabled.
+   */
+
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_RX );
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_TX );
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_ERROR );
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_BREAK );
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_STOP_BREAK );
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_TX );
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_RX );
+
+
+  (*setReg)( pMC68681_port, MC68681_MODE_REG_1A, 0x00 );
+  (*setReg)( pMC68681_port, MC68681_MODE_REG_2A, 0x02 );
+
+  /*
+   *  Disable interrupts on RX and TX for this port
+   */
+
+  mc68681_enable_interrupts( minor, MC68681_IMR_DISABLE_ALL );
+}
+
+/*
+ *  mc68681_open
+ *
+ *  This function opens a port for communication.
+ *
+ *  Default state is 9600 baud, 8 bits, No parity, and 1 stop bit.
+ */
+
+MC68681_STATIC int mc68681_open(
+  int      major,
+  int      minor,
+  void    *arg
+)
+{
+  uint32_t               pMC68681;
+  uint32_t               pMC68681_port;
+  unsigned int           baud;
+  unsigned int           acr_bit;
+  unsigned int           vector;
+  unsigned int           command = 0;
+  rtems_interrupt_level  Irql;
+  setRegister_f          setReg;
+  int			 status;
+
+
+  pMC68681      = Console_Port_Tbl[minor]->ulCtrlPort1;
+  pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
+  setReg        = Console_Port_Tbl[minor]->setRegister;
+  vector        = Console_Port_Tbl[minor]->ulIntVector;
+
+  /* XXX default baud rate should be from configuration table */
+
+  status = mc68681_baud_rate( minor, B9600, &baud, &acr_bit, &command );
+  if (status < 0) rtems_fatal_error_occurred (RTEMS_NOT_DEFINED);
+
+  /*
+   *  Set the DUART channel to a default useable state
+   */
+
+  rtems_interrupt_disable(Irql);
+    (*setReg)( pMC68681, MC68681_AUX_CTRL_REG, acr_bit << 7 );
+    (*setReg)( pMC68681_port, MC68681_CLOCK_SELECT, baud );
+    if ( command ) {
+      (*setReg)( pMC68681_port, MC68681_COMMAND, command );         /* RX */
+      (*setReg)( pMC68681_port, MC68681_COMMAND, command | 0x20 );  /* TX */
+    }
+    (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_MR_PTR );
+    (*setReg)( pMC68681_port, MC68681_MODE, 0x13 );
+    (*setReg)( pMC68681_port, MC68681_MODE, 0x07 );
+  rtems_interrupt_enable(Irql);
+
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_ENABLE_TX );
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_ENABLE_RX );
+
+  (*setReg)( pMC68681, MC68681_INTERRUPT_VECTOR_REG, vector );
+
+  return RTEMS_SUCCESSFUL;
+}
+
+/*
+ *  mc68681_close
+ *
+ *  This function shuts down the requested port.
+ */
+
+MC68681_STATIC int mc68681_close(
+  int      major,
+  int      minor,
+  void    *arg
+)
+{
+  uint32_t        pMC68681_port;
+  setRegister_f   setReg;
+
+  pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
+  setReg        = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   *  Disable interrupts from this channel and then disable it totally.
+   */
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_TX );
+  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_RX );
+
+  return(RTEMS_SUCCESSFUL);
+}
+
+/*
+ *  mc68681_write_polled
+ *
+ *  This routine polls out the requested character.
+ */
+
+MC68681_STATIC void mc68681_write_polled(
+  int   minor,
+  char  cChar
+)
+{
+  uint32_t                pMC68681_port;
+  unsigned char           ucLineStatus;
+  int                     iTimeout;
+  getRegister_f           getReg;
+  setRegister_f           setReg;
+
+  pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
+  getReg        = Console_Port_Tbl[minor]->getRegister;
+  setReg        = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   * wait for transmitter holding register to be empty
+   */
+  iTimeout = 1000;
+  ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
+  while ((ucLineStatus & (MC68681_TX_READY|MC68681_TX_EMPTY)) == 0) {
+
+    if ((ucLineStatus & 0xF0))
+      (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_ERROR );
+
+    /*
+     * Yield while we wait
+     */
+
+#if 0
+     if(_System_state_Is_up(_System_state_Get())) {
+       rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
+     }
+#endif
+     ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
+     if(!--iTimeout) {
+       break;
+     }
+  }
+
+  /*
+   * transmit character
+   */
+
+  (*setReg)(pMC68681_port, MC68681_TX_BUFFER, cChar);
+}
+
+/*
+ *  mc68681_isr
+ *
+ *  This is the single interrupt entry point which parcels interrupts
+ *  out to the various ports.
+ */
+
+MC68681_STATIC rtems_isr mc68681_isr(
+  rtems_vector_number vector
+)
+{
+  int     minor;
+
+  for(minor=0 ; minor<Console_Port_Count ; minor++) {
+    if(Console_Port_Tbl[minor]->ulIntVector == vector &&
+       Console_Port_Tbl[minor]->deviceType == SERIAL_MC68681 ) {
+      mc68681_process(minor);
+    }
+  }
+}
+
+/*
+ *  mc68681_initialize_interrupts
+ *
+ *  This routine initializes the console's receive and transmit
+ *  ring buffers and loads the appropriate vectors to handle the interrupts.
+ */
+
+MC68681_STATIC void mc68681_initialize_interrupts(int minor)
+{
+  mc68681_init(minor);
+
+  Console_Port_Data[minor].bActive = FALSE;
+
+#if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE)
+  set_vector(mc68681_isr, Console_Port_Tbl[minor]->ulIntVector, 1);
+#endif
+
+  mc68681_enable_interrupts(minor,MC68681_IMR_ENABLE_ALL_EXCEPT_TX);
+}
+
+/*
+ *  mc68681_write_support_int
+ *
+ *  Console Termios output entry point when using interrupt driven output.
+ */
+
+MC68681_STATIC ssize_t mc68681_write_support_int(
+  int         minor,
+  const char *buf,
+  size_t      len
+)
+{
+  uint32_t        Irql;
+  uint32_t        pMC68681_port;
+  setRegister_f   setReg;
+
+  pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
+  setReg        = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   *  We are using interrupt driven output and termios only sends us
+   *  one character at a time.
+   */
+
+  if ( !len )
+    return 0;
+
+  /*
+   *  Put the character out and enable interrupts if necessary.
+   */
+
+  rtems_interrupt_disable(Irql);
+    if ( Console_Port_Data[minor].bActive == FALSE ) {
+      Console_Port_Data[minor].bActive = TRUE;
+      mc68681_enable_interrupts(minor, MC68681_IMR_ENABLE_ALL);
+    }
+    (*setReg)(pMC68681_port, MC68681_TX_BUFFER, *buf);
+  rtems_interrupt_enable(Irql);
+
+  return 0;
+}
+
+/*
+ *  mc68681_write_support_polled
+ *
+ *  Console Termios output entry point when using polled output.
+ *
+ */
+
+MC68681_STATIC ssize_t mc68681_write_support_polled(
+  int         minor,
+  const char *buf,
+  size_t      len
+)
+{
+  int nwrite = 0;
+
+  /*
+   * poll each byte in the string out of the port.
+   */
+  while (nwrite < len) {
+    /*
+     * transmit character
+     */
+    mc68681_write_polled(minor, *buf++);
+    nwrite++;
+  }
+
+  /*
+   * return the number of bytes written.
+   */
+  return nwrite;
+}
+
+/*
+ *  mc68681_inbyte_nonblocking_polled
+ *
+ *  Console Termios polling input entry point.
+ */
+
+MC68681_STATIC int mc68681_inbyte_nonblocking_polled(
+  int minor
+)
+{
+  uint32_t             pMC68681_port;
+  unsigned char        ucLineStatus;
+  unsigned char        cChar;
+  getRegister_f        getReg;
+
+  pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
+  getReg        = Console_Port_Tbl[minor]->getRegister;
+
+  ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
+  if(ucLineStatus & MC68681_RX_READY) {
+    cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
+    return (int)cChar;
+  } else {
+    return -1;
+  }
+}
+
+/*
+ *  mc68681_baud_rate
+ */
+
+MC68681_STATIC int mc68681_baud_rate(
+  int           minor,
+  int           baud,
+  unsigned int *baud_mask_p,
+  unsigned int *acr_bit_p,
+  unsigned int *command
+)
+{
+  unsigned int           baud_mask;
+  unsigned int           acr_bit;
+  int                    status;
+  int                    is_extended;
+  int                    baud_requested;
+  mc68681_baud_table_t  *baud_tbl;
+
+  baud_mask = 0;
+  acr_bit = 0;
+  status = 0;
+
+  if (Console_Port_Tbl[minor]->ulDataPort & MC68681_DATA_BAUD_RATE_SET_2)
+  {
+    acr_bit = 1;
+  }
+
+  is_extended = 0;
+
+  switch (Console_Port_Tbl[minor]->ulDataPort & MC68681_XBRG_MASK) {
+    case MC68681_XBRG_IGNORED:
+      *command = 0x00;
+      break;
+    case MC68681_XBRG_ENABLED:
+      *command = 0x80;
+      is_extended = 1;
+      break;
+    case MC68681_XBRG_DISABLED:
+      *command = 0x90;
+      break;
+  }
+
+  baud_requested = baud;
+  if (!baud_requested)
+    baud_requested = B9600;              /* default to 9600 baud */
+
+  baud_requested = rtems_termios_baud_to_index( baud_requested );
+  if (baud_requested == -1)
+    return -1;
+
+  baud_tbl = (mc68681_baud_table_t *)
+     ((uintptr_t)Console_Port_Tbl[minor]->ulClock);
+  if (!baud_tbl)
+    rtems_fatal_error_occurred(RTEMS_INVALID_ADDRESS);
+
+  if ( is_extended )
+    baud_mask = (unsigned int)baud_tbl[ acr_bit + 2 ][ baud_requested ];
+  else
+    baud_mask = baud_tbl[ acr_bit ][ baud_requested ];
+
+  if ( baud_mask == MC68681_BAUD_NOT_VALID )
+    status = -1;
+
+  /*
+   *  upper nibble is receiver and lower nibble is transmitter
+   */
+
+  *baud_mask_p = (baud_mask << 4) | baud_mask;
+  *acr_bit_p   = acr_bit;
+  return status;
+}
+
+/*
+ *  mc68681_process
+ *
+ *  This routine is the per port console interrupt handler.
+ */
+
+MC68681_STATIC void mc68681_process(
+  int  minor
+)
+{
+  uint32_t                pMC68681;
+  uint32_t                pMC68681_port;
+  volatile uint8_t        ucLineStatus;
+  volatile uint8_t        ucISRStatus;
+  char                    cChar;
+  getRegister_f           getReg;
+
+  pMC68681      = Console_Port_Tbl[minor]->ulCtrlPort1;
+  pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
+  getReg        = Console_Port_Tbl[minor]->getRegister;
+
+  /* Get ISR at the beginning of the IT routine */
+  ucISRStatus = (*getReg)(pMC68681, MC68681_INTERRUPT_STATUS_REG);
+
+  /* Get good ISR a or b channel */
+  if (pMC68681 != pMC68681_port){
+    ucISRStatus >>= 4;
+  }
+
+  /* See if is usefull to call rtems_termios_dequeue */
+  if(Console_Port_Data[minor].bActive == FALSE) {
+		ucISRStatus = ucISRStatus & ~MC68681_IR_TX_READY;
+  }
+
+  /*
+   * Deal with any received characters
+   */
+  while(true) {
+    ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
+    if(!(ucLineStatus & MC68681_RX_READY)) {
+      break;
+    }
+    /*
+     *  If there is a RX error, then dump all the data.
+     */
+    if ( ucLineStatus & MC68681_RX_ERRORS ) {
+      do {
+        cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
+        ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
+      } while ( ucLineStatus & MC68681_RX_READY );
+      continue;
+    }
+    cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
+    rtems_termios_enqueue_raw_characters(
+      Console_Port_Data[minor].termios_data,
+      &cChar,
+      1
+    );
+  }
+
+  /*
+   *  Deal with the transmitter
+   */
+
+  if (ucISRStatus & MC68681_IR_TX_READY) {
+    if (!rtems_termios_dequeue_characters(
+          Console_Port_Data[minor].termios_data, 1)) {
+	  /* If no more char to send, disable TX interrupt */
+      Console_Port_Data[minor].bActive = FALSE;
+      mc68681_enable_interrupts(minor, MC68681_IMR_ENABLE_ALL_EXCEPT_TX);
+    }
+  }
+}
+
+/*
+ *  mc68681_build_imr
+ *
+ *  This function returns the value for the interrupt mask register for this
+ *  DUART.  Since this is a shared register, we must look at the other port
+ *  on this chip to determine whether or not it is using interrupts.
+ */
+
+MC68681_STATIC unsigned int mc68681_build_imr(
+  int  minor,
+  int  enable_flag
+)
+{
+  int              mate;
+  int              is_a;
+  unsigned int     mask;
+  unsigned int     mate_mask;
+  unsigned int     pMC68681;
+  unsigned int     pMC68681_port;
+  mc68681_context *pmc68681Context;
+  mc68681_context *mateContext;
+
+  pMC68681        = Console_Port_Tbl[minor]->ulCtrlPort1;
+  pMC68681_port   = Console_Port_Tbl[minor]->ulCtrlPort2;
+  pmc68681Context = (mc68681_context *) Console_Port_Data[minor].pDeviceContext;
+  mate            = pmc68681Context->mate;
+
+  mask = 0;
+  mate_mask = 0;
+
+  is_a = (pMC68681 == pMC68681_port);
+
+  /*
+   *  If there is a mate for this port, get its IMR mask.
+   */
+
+  if ( mate != -1 ) {
+    mateContext = Console_Port_Data[mate].pDeviceContext;
+
+    if (mateContext)
+      mate_mask = mateContext->imr;
+  }
+
+  /*
+   *  Calculate this port's IMR mask and save it in the context area.
+   */
+
+  if ( Console_Port_Tbl[minor]->pDeviceFns->deviceOutputUsesInterrupts )
+    mask = enable_flag;
+
+  pmc68681Context->imr = mask;
+
+  /*
+   *  Now return the full IMR value
+   */
+
+  if (is_a)
+    return (mate_mask << 4) | mask;
+
+  return (mask << 4) | mate_mask;
+}
+
+/*
+ *  mc68681_enable_interrupts
+ *
+ *  This function enables specific interrupt sources on the DUART.
+ */
+
+MC68681_STATIC void mc68681_enable_interrupts(
+  int minor,
+  int imr_mask
+)
+{
+  uint32_t              pMC68681;
+  setRegister_f         setReg;
+
+  pMC68681 = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg   = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   *  Enable interrupts on RX and TX -- not break
+   */
+
+  (*setReg)(
+     pMC68681,
+     MC68681_INTERRUPT_MASK_REG,
+     mc68681_build_imr(minor, imr_mask)
+  );
+}
Index: bsps/shared/dev/serial/mc68681_baud.c
===================================================================
--- bsps/shared/dev/serial/mc68681_baud.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/mc68681_baud.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,124 @@
+/*
+ *  MC68681 Default Baud Rate Table
+ */
+
+#include <rtems.h>
+#include <libchip/serial.h>
+#include <libchip/mc68681.h>
+
+/* major index of 0 : ACR[7] = 0, X = 0 -- 68c681 only has these */
+/* major index of 1 : ACR[7] = 1, X = 0 -- 68c681 only has these */
+/* major index of 2 : ACR[7] = 0, X = 1 */
+/* major index of 3 : ACR[7] = 1, X = 1 */
+
+/* mc68681_baud_table_t mc68681_baud_rate_table[4] = { */
+mc68681_baud_t mc68681_baud_rate_table[4][RTEMS_TERMIOS_NUMBER_BAUD_RATES] = {
+  { /* ACR[7] = 0, X = 0 */
+    MC68681_BAUD_NOT_VALID,    /* B0 */
+    0x00,                      /* B50 */
+    MC68681_BAUD_NOT_VALID,    /* B75 */
+    0x01,                      /* B110 */
+    0x02,                      /* B134 */
+    MC68681_BAUD_NOT_VALID,    /* B150 */
+    0x03,                      /* B200 */
+    0x04,                      /* B300 */
+    0x05,                      /* B600 */
+    0x06,                      /* B1200 */
+    MC68681_BAUD_NOT_VALID,    /* B1800 */
+    0x08,                      /* B2400 */
+    0x09,                      /* B4800 */
+    0x0B,                      /* B9600 */
+    MC68681_BAUD_NOT_VALID,    /* B19200 */
+    0x0C,                      /* B38400 */
+    MC68681_BAUD_NOT_VALID,    /* B7200 */
+    MC68681_BAUD_NOT_VALID,    /* B14400 */
+    MC68681_BAUD_NOT_VALID,    /* B28800 */
+    MC68681_BAUD_NOT_VALID,    /* B57600 */
+    MC68681_BAUD_NOT_VALID,    /* B76800 */
+    MC68681_BAUD_NOT_VALID,    /* B115200 */
+    MC68681_BAUD_NOT_VALID,    /* B230400 */
+    MC68681_BAUD_NOT_VALID,    /* B460800 */
+    MC68681_BAUD_NOT_VALID     /* B921600 */
+  },
+  { /* ACR[7] = 1, X = 0 */
+    MC68681_BAUD_NOT_VALID,    /* B0 */
+    MC68681_BAUD_NOT_VALID,    /* B50 */
+    0x00,                      /* B75 */
+    0x01,                      /* B110 */
+    0x02,                      /* B134 */
+    0x03,                      /* B150 */
+    MC68681_BAUD_NOT_VALID,    /* B200 */
+    0x04,                      /* B300 */
+    0x05,                      /* B600 */
+    0x06,                      /* B1200 */
+    0x0A,                      /* B1800 */
+    0x08,                      /* B2400 */
+    0x09,                      /* B4800 */
+    0x0B,                      /* B9600 */
+    0x0C,                      /* B19200 */
+    MC68681_BAUD_NOT_VALID,    /* B38400 */
+    MC68681_BAUD_NOT_VALID,    /* B7200 */
+    MC68681_BAUD_NOT_VALID,    /* B14400 */
+    MC68681_BAUD_NOT_VALID,    /* B28800 */
+    MC68681_BAUD_NOT_VALID,    /* B57600 */
+    MC68681_BAUD_NOT_VALID,    /* B76800 */
+    MC68681_BAUD_NOT_VALID,    /* B115200 */
+    MC68681_BAUD_NOT_VALID,    /* B230400 */
+    MC68681_BAUD_NOT_VALID,    /* B460800 */
+    MC68681_BAUD_NOT_VALID     /* B921600 */
+  },
+  { /* ACR[7] = 0, X = 1 */
+    MC68681_BAUD_NOT_VALID,    /* B0 */
+    MC68681_BAUD_NOT_VALID,    /* B50 */
+    0x00,                      /* B75 */
+    0x01,                      /* B110 */
+    0x02,                      /* B134 */
+    0x03,                      /* B150 */
+    MC68681_BAUD_NOT_VALID,    /* B200 */
+    MC68681_BAUD_NOT_VALID,    /* B300 */
+    MC68681_BAUD_NOT_VALID,    /* B600 */
+    MC68681_BAUD_NOT_VALID,    /* B1200 */
+    0x0A,                      /* B1800 */
+    MC68681_BAUD_NOT_VALID,    /* B2400 */
+    0x08,                      /* B4800 */
+    0x0B,                      /* B9600 */
+    0x0C,                      /* B19200 */
+    MC68681_BAUD_NOT_VALID,    /* B38400 */
+    MC68681_BAUD_NOT_VALID,    /* B7200 */
+    MC68681_BAUD_NOT_VALID,    /* B14400 */
+    MC68681_BAUD_NOT_VALID,    /* B28800 */
+    0x07,                      /* B57600 */
+    MC68681_BAUD_NOT_VALID,    /* B76800 */
+    0x08,                      /* B115200 */
+    MC68681_BAUD_NOT_VALID,    /* B230400 */
+    MC68681_BAUD_NOT_VALID,    /* B460800 */
+    MC68681_BAUD_NOT_VALID     /* B921600 */
+  },
+  { /* ACR[7] = 1, X = 1 */
+    MC68681_BAUD_NOT_VALID,    /* B0 */
+    0x00,                      /* B50 */
+    MC68681_BAUD_NOT_VALID,    /* B75 */
+    0x01,                      /* B110 */
+    0x02,                      /* B134 */
+    MC68681_BAUD_NOT_VALID,    /* B150 */
+    0x03,                      /* B200 */
+    MC68681_BAUD_NOT_VALID,    /* B300 */
+    MC68681_BAUD_NOT_VALID,    /* B600 */
+    MC68681_BAUD_NOT_VALID,    /* B1200 */
+    MC68681_BAUD_NOT_VALID,    /* B1800 */
+    MC68681_BAUD_NOT_VALID,    /* B2400 */
+    0x09,                      /* B4800 */
+    0x0B,                      /* B9600 */
+    MC68681_BAUD_NOT_VALID,    /* B19200 */
+    0x0C,                      /* B38400 */
+    MC68681_BAUD_NOT_VALID,    /* B7200 */
+    MC68681_BAUD_NOT_VALID,    /* B14400 */
+    MC68681_BAUD_NOT_VALID,    /* B28800 */
+    0x07,                      /* B57600 */
+    MC68681_BAUD_NOT_VALID,    /* B76800 */
+    0x08,                      /* B115200 */
+    MC68681_BAUD_NOT_VALID,    /* B230400 */
+    MC68681_BAUD_NOT_VALID,    /* B460800 */
+    MC68681_BAUD_NOT_VALID     /* B921600 */
+  },
+};
Index: bsps/shared/dev/serial/mc68681_p.h
===================================================================
--- bsps/shared/dev/serial/mc68681_p.h	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/mc68681_p.h	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,323 @@
+/*
+ *
+ *  COPYRIGHT (c) 1989-1999.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef _MC68681_P_H_
+#define _MC68681_P_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ *  Define MC68681_STATIC to nothing while debugging so the entry points
+ *  will show up in the symbol table.
+ */
+
+#define MC68681_STATIC
+
+/* #define MC68681_STATIC static */
+
+/*
+ * mc68681 register offsets Read/Write Addresses
+ */
+
+#define MC68681_MODE_REG_1A  0  /* MR1A-MR Prior to Read */
+#define MC68681_MODE_REG_2A  0  /* MR2A-MR After Read    */
+
+#define MC68681_COUNT_MODE_CURRENT_MSB       6  /* CTU   */
+#define MC68681_COUNTER_TIMER_UPPER_REG      6  /* CTU   */
+#define MC68681_COUNT_MODE_CURRENT_LSB       7  /* CTL   */
+#define MC68681_COUNTER_TIMER_LOWER_REG      7  /* CTL   */
+#define MC68681_INTERRUPT_VECTOR_REG        12  /* IVR   */
+
+#define MC68681_MODE_REG_1B  8  /* MR1B-MR Prior to Read */
+#define MC68681_MODE_REG_2B  8  /* MR2BA-MR After Read   */
+
+/*
+ * mc68681 register offsets Read Only  Addresses
+ */
+
+#define MC68681_STATUS_REG_A                 1  /* SRA   */
+#define MC68681_MASK_ISR_REG                 2  /* MISR  */
+#define MC68681_RECEIVE_BUFFER_A             3  /* RHRA  */
+#define MC68681_INPUT_PORT_CHANGE_REG        4  /* IPCR  */
+#define MC68681_INTERRUPT_STATUS_REG         5  /* ISR   */
+#define MC68681_STATUS_REG_B                 9  /* SRB   */
+#define MC68681_RECEIVE_BUFFER_B            11  /* RHRB  */
+#define MC68681_INPUT_PORT                  13  /* IP    */
+#define MC68681_START_COUNT_CMD             14  /* SCC   */
+#define MC68681_STOP_COUNT_CMD              15  /* STC   */
+
+/*
+ * mc68681 register offsets Write Only  Addresses
+ */
+
+#define MC68681_CLOCK_SELECT_REG_A           1  /* CSRA  */
+#define MC68681_COMMAND_REG_A                2  /* CRA   */
+#define MC68681_TRANSMIT_BUFFER_A            3  /* THRA  */
+#define MC68681_AUX_CTRL_REG                 4  /* ACR   */
+#define MC68681_INTERRUPT_MASK_REG           5  /* IMR   */
+#define MC68681_CLOCK_SELECT_REG_B           9  /* CSRB  */
+#define MC68681_COMMAND_REG_B               10  /* CRB   */
+#define MC68681_TRANSMIT_BUFFER_B           11  /* THRB  */
+#define MC68681_OUTPUT_PORT_CONFIG_REG      13  /* OPCR  */
+#define MC68681_OUTPUT_PORT_SET_REG         14  /* SOPBC */
+#define MC68681_OUTPUT_PORT_RESET_BITS      15  /* COPBC */
+
+/*
+ *  DUART Command Register Definitions:
+ *
+ *  MC68681_COMMAND_REG_A,MC68681_COMMAND_REG_B
+ */
+
+#define MC68681_MODE_REG_ENABLE_RX                          0x01
+#define MC68681_MODE_REG_DISABLE_RX                         0x02
+#define MC68681_MODE_REG_ENABLE_TX                          0x04
+#define MC68681_MODE_REG_DISABLE_TX                         0x08
+#define MC68681_MODE_REG_RESET_MR_PTR                       0x10
+#define MC68681_MODE_REG_RESET_RX                           0x20
+#define MC68681_MODE_REG_RESET_TX                           0x30
+#define MC68681_MODE_REG_RESET_ERROR                        0x40
+#define MC68681_MODE_REG_RESET_BREAK                        0x50
+#define MC68681_MODE_REG_START_BREAK                        0x60
+#define MC68681_MODE_REG_STOP_BREAK                         0x70
+#define MC68681_MODE_REG_SET_RX_BRG                         0x80
+#define MC68681_MODE_REG_CLEAR_RX_BRG                       0x90
+#define MC68681_MODE_REG_SET_TX_BRG                         0xa0
+#define MC68681_MODE_REG_CLEAR_TX_BRG                       0xb0
+#define MC68681_MODE_REG_SET_STANDBY                        0xc0
+#define MC68681_MODE_REG_SET_ACTIVE                         0xd0
+
+/*
+ * Mode Register Definitions
+ *
+ *  MC68681_MODE_REG_1A
+ *  MC68681_MODE_REG_1B
+ */
+
+#define MC68681_5BIT_CHARS                                  0x00
+#define MC68681_6BIT_CHARS                                  0x01
+#define MC68681_7BIT_CHARS                                  0x02
+#define MC68681_8BIT_CHARS                                  0x03
+
+#define MC68681_ODD_PARITY                                  0x00
+#define MC68681_EVEN_PARITY                                 0x04
+
+#define MC68681_WITH_PARITY                                 0x00
+#define MC68681_FORCE_PARITY                                0x08
+#define MC68681_NO_PARITY                                   0x10
+#define MC68681_MULTI_DROP                                  0x18
+
+#define MC68681_ERR_MODE_CHAR                               0x00
+#define MC68681_ERR_MODE_BLOCK                              0x20
+
+#define MC68681_RX_INTR_RX_READY                            0x00
+#define MC68681_RX_INTR_FFULL                               0x40
+
+#define MC68681_NO_RX_RTS_CTL                               0x00
+#define MC68681_RX_RTS_CTRL                                 0x80
+
+/*
+ * Mode Register Definitions
+ *
+ *  MC68681_MODE_REG_2A
+ *  MC68681_MODE_REG_2B
+ */
+
+#define MC68681_STOP_BIT_LENGTH__563                        0x00
+#define MC68681_STOP_BIT_LENGTH__625                        0x01
+#define MC68681_STOP_BIT_LENGTH__688                        0x02
+#define MC68681_STOP_BIT_LENGTH__75                         0x03
+#define MC68681_STOP_BIT_LENGTH__813                        0x04
+#define MC68681_STOP_BIT_LENGTH__875                        0x05
+#define MC68681_STOP_BIT_LENGTH__938                        0x06
+#define MC68681_STOP_BIT_LENGTH_1                           0x07
+#define MC68681_STOP_BIT_LENGTH_1_563                       0x08
+#define MC68681_STOP_BIT_LENGTH_1_625                       0x09
+#define MC68681_STOP_BIT_LENGTH_1_688                       0x0a
+#define MC68681_STOP_BIT_LENGTH_1_75                        0x0b
+#define MC68681_STOP_BIT_LENGTH_1_813                       0x0c
+#define MC68681_STOP_BIT_LENGTH_1_875                       0x0d
+#define MC68681_STOP_BIT_LENGTH_1_938                       0x0e
+#define MC68681_STOP_BIT_LENGTH_2                           0x0f
+
+#define MC68681_CTS_ENABLE_TX                               0x10
+#define MC68681_TX_RTS_CTRL                                 0x20
+
+#define MC68681_CHANNEL_MODE_NORMAL                         0x00
+#define MC68681_CHANNEL_MODE_ECHO                           0x40
+#define MC68681_CHANNEL_MODE_LOCAL_LOOP                     0x80
+#define MC68681_CHANNEL_MODE_REMOTE_LOOP                    0xc0
+
+/*
+ * Status Register Definitions
+ *
+ *    MC68681_STATUS_REG_A,  MC68681_STATUS_REG_B
+ */
+
+#define MC68681_RX_READY                                    0x01
+#define MC68681_FFULL                                       0x02
+#define MC68681_TX_READY                                    0x04
+#define MC68681_TX_EMPTY                                    0x08
+#define MC68681_OVERRUN_ERROR                               0x10
+#define MC68681_PARITY_ERROR                                0x20
+#define MC68681_FRAMING_ERROR                               0x40
+#define MC68681_RECEIVED_BREAK                              0x80
+
+#define MC68681_RX_ERRORS \
+  (MC68681_OVERRUN_ERROR|MC68681_PARITY_ERROR| \
+   MC68681_FRAMING_ERROR|MC68681_RECEIVED_BREAK)
+
+/*
+ * Interupt Status Register Definitions.
+ *
+ * MC68681_INTERRUPT_STATUS_REG
+ */
+
+/*
+ *  Interupt Mask Register Definitions
+ *
+ *  MC68681_INTERRUPT_MASK_REG
+ */
+
+/* These are passed to mc68681_build_imr */
+#define MC68681_IR_TX_READY                                 0x01
+#define MC68681_IR_RX_READY                                 0x02
+#define MC68681_IR_BREAK                                    0x04
+#define MC68681_IMR_ENABLE_ALL                              0x07
+#define MC68681_IMR_DISABLE_ALL                             0x00
+#define MC68681_IMR_ENABLE_ALL_EXCEPT_TX                    0x06
+
+#define MC68681_IR_TX_READY_A                               0x01
+#define MC68681_IR_RX_READY_A                               0x02
+#define MC68681_IR_BREAK_A                                  0x04
+#define MC68681_IR_COUNTER_READY                            0x08
+#define MC68681_IR_TX_READY_B                               0x10
+#define MC68681_IR_RX_READY_B                               0x20
+#define MC68681_IR_BREAK_B                                  0x40
+#define MC68681_IR_INPUT_PORT_CHANGE                        0x80
+
+/*
+ * Status Register Definitions.
+ *
+ * MC68681_STATUS_REG_A,MC68681_STATUS_REG_B
+ */
+
+#define MC68681_STATUS_RXRDY                                0x01
+#define MC68681_STATUS_FFULL                                0x02
+#define MC68681_STATUS_TXRDY                                0x04
+#define MC68681_STATUS_TXEMT                                0x08
+#define MC68681_STATUS_OVERRUN_ERROR                        0x10
+#define MC68681_STATUS_PARITY_ERROR                         0x20
+#define MC68681_STATUS_FRAMING_ERROR                        0x40
+#define MC68681_STATUS_RECEIVED_BREAK                       0x80
+
+/*
+ * Definitions for the Interrupt Vector Register:
+ *
+ * MC68681_INTERRUPT_VECTOR_REG
+ */
+
+#define  MC68681_INTERRUPT_VECTOR_INIT                      0x0f
+
+/*
+ * Definitions for the Auxiliary Control Register
+ *
+ * MC68681_AUX_CTRL_REG
+ */
+
+#define MC68681_AUX_BRG_SET1                                0x00
+#define MC68681_AUX_BRG_SET2                                0x80
+
+/*
+ *  Per chip context control
+ */
+
+typedef struct _mc68681_context
+{
+  int            mate;
+  unsigned char  imr;
+} mc68681_context;
+
+/*
+ * Driver functions
+ */
+MC68681_STATIC void mc68681_initialize_context(
+  int               minor,
+  mc68681_context  *pmc68681Context
+);
+
+MC68681_STATIC bool mc68681_probe(int minor);
+
+MC68681_STATIC int mc68681_set_attributes(
+  int minor,
+  const struct termios *t
+);
+
+MC68681_STATIC void mc68681_init(int minor);
+
+MC68681_STATIC int mc68681_open(
+  int major,
+  int minor,
+  void  * arg
+);
+
+MC68681_STATIC int mc68681_close(
+  int major,
+  int minor,
+  void  * arg
+);
+
+MC68681_STATIC void mc68681_write_polled(
+  int   minor,
+  char  cChar
+);
+
+MC68681_STATIC void mc68681_initialize_interrupts(int minor);
+
+MC68681_STATIC ssize_t mc68681_write_support_int(
+  int   minor,
+  const char *buf,
+  size_t len
+);
+
+MC68681_STATIC ssize_t mc68681_write_support_polled(
+  int   minor,
+  const char *buf,
+  size_t   len
+  );
+
+MC68681_STATIC int mc68681_inbyte_nonblocking_polled(
+  int minor
+);
+
+MC68681_STATIC unsigned int mc68681_build_imr(
+  int  minor,
+  int  enable_flag
+);
+
+MC68681_STATIC void mc68681_process(
+  int  minor
+);
+
+MC68681_STATIC void mc68681_enable_interrupts(
+  int minor,
+  int imr_mask
+);
+
+MC68681_STATIC rtems_isr mc68681_isr(
+  rtems_vector_number vector
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MC68681_P_H_ */
Index: bsps/shared/dev/serial/mc68681_reg.c
===================================================================
--- bsps/shared/dev/serial/mc68681_reg.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/mc68681_reg.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,61 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the mc68681 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are only byte-aligned (no address gaps)
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+
+#include <libchip/serial.h>
+#include <libchip/mc68681.h>
+
+#ifndef _MC68681_MULTIPLIER
+#define _MC68681_MULTIPLIER 1
+#define _MC68681_NAME(_X) _X
+#define _MC68681_TYPE uint8_t
+#endif
+
+#define CALCULATE_REGISTER_ADDRESS( _base, _reg ) \
+  (_MC68681_TYPE *)((_base) + ((_reg) * _MC68681_MULTIPLIER ))
+
+/*
+ *  MC68681 Get Register Routine
+ */
+
+uint8_t   _MC68681_NAME(mc68681_get_register)(
+  uintptr_t   ulCtrlPort,
+  uint8_t     ucRegNum
+)
+{
+  _MC68681_TYPE *port;
+
+  port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
+
+  return *port;
+}
+
+/*
+ *  MC68681 Set Register Routine
+ */
+
+void  _MC68681_NAME(mc68681_set_register)(
+  uintptr_t   ulCtrlPort,
+  uint8_t     ucRegNum,
+  uint8_t     ucData
+)
+{
+  _MC68681_TYPE *port;
+
+  port = CALCULATE_REGISTER_ADDRESS( ulCtrlPort, ucRegNum );
+
+  *port = ucData;
+}
Index: bsps/shared/dev/serial/mc68681_reg2.c
===================================================================
--- bsps/shared/dev/serial/mc68681_reg2.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/mc68681_reg2.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,20 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the mc68681 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are on 16-bit boundaries
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#define _MC68681_MULTIPLIER 2
+#define _MC68681_NAME(_X) _X##_2
+#define _MC68681_TYPE uint8_t
+
+#include "mc68681_reg.c"
Index: bsps/shared/dev/serial/mc68681_reg4.c
===================================================================
--- bsps/shared/dev/serial/mc68681_reg4.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/mc68681_reg4.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,20 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the mc68681 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are on 32-bit boundaries
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#define _MC68681_MULTIPLIER 4
+#define _MC68681_NAME(_X) _X##_4
+#define _MC68681_TYPE uint8_t
+
+#include "mc68681_reg.c"
Index: bsps/shared/dev/serial/mc68681_reg8.c
===================================================================
--- bsps/shared/dev/serial/mc68681_reg8.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/mc68681_reg8.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,20 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the mc68681 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *    + registers are on 64-bit boundaries
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#define _MC68681_MULTIPLIER 8
+#define _MC68681_NAME(_X) _X##_8
+#define _MC68681_TYPE uint8_t
+
+#include "mc68681_reg.c"
Index: bsps/shared/dev/serial/ns16550-context.c
===================================================================
--- bsps/shared/dev/serial/ns16550-context.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/ns16550-context.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,814 @@
+/**
+ *  @file
+ *  
+ *  This file contains the TTY driver for the National Semiconductor NS16550.
+ *
+ *  This part is widely cloned and second sourced.  It is found in a number
+ *  of "Super IO" controllers.
+ *
+ *  This driver uses the termios pseudo driver.
+ */
+
+/*
+ *  COPYRIGHT (c) 1998 by Radstone Technology
+ *
+ *  THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
+ *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
+ *  AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
+ *
+ *  You are hereby granted permission to use, copy, modify, and distribute
+ *  this file, provided that this notice, plus the above copyright notice
+ *  and disclaimer, appears in all copies. Radstone Technology will provide
+ *  no support for this code.
+ *
+ *  COPYRIGHT (c) 1989-2012.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdlib.h>
+
+#include <rtems/bspIo.h>
+
+#include <bsp.h>
+
+#include <libchip/ns16550.h>
+#include <libchip/ns16550_p.h>
+
+#if defined(BSP_FEATURE_IRQ_EXTENSION)
+  #include <bsp/irq.h>
+#elif defined(BSP_FEATURE_IRQ_LEGACY)
+  #include <bsp/irq.h>
+#elif defined(__PPC__) || defined(__i386__)
+  #include <bsp/irq.h>
+  #define BSP_FEATURE_IRQ_LEGACY
+  #ifdef BSP_SHARED_HANDLER_SUPPORT
+    #define BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
+  #endif
+#endif
+
+static uint32_t NS16550_GetBaudDivisor(ns16550_context *ctx, uint32_t baud)
+{
+  uint32_t clock = ctx->clock;
+  uint32_t baudDivisor = (clock != 0 ? clock : 115200) / (baud * 16);
+
+  if (ctx->has_fractional_divider_register) {
+    uint32_t fractionalDivider = 0x10;
+    uint32_t err = baud;
+    uint32_t mulVal;
+    uint32_t divAddVal;
+
+    clock /= 16 * baudDivisor;
+    for (mulVal = 1; mulVal < 16; ++mulVal) {
+      for (divAddVal = 0; divAddVal < mulVal; ++divAddVal) {
+        uint32_t actual = (mulVal * clock) / (mulVal + divAddVal);
+        uint32_t newErr = actual > baud ? actual - baud : baud - actual;
+
+        if (newErr < err) {
+          err = newErr;
+          fractionalDivider = (mulVal << 4) | divAddVal;
+        }
+      }
+    }
+
+    (*ctx->set_reg)(
+      ctx->port,
+      NS16550_FRACTIONAL_DIVIDER,
+      fractionalDivider
+    );
+  }
+
+  return baudDivisor;
+}
+
+/*
+ *  ns16550_enable_interrupts
+ *
+ *  This routine initializes the port to have the specified interrupts masked.
+ */
+static void ns16550_enable_interrupts(
+  ns16550_context *ctx,
+  int              mask
+)
+{
+  (*ctx->set_reg)(ctx->port, NS16550_INTERRUPT_ENABLE, mask);
+}
+
+static void ns16550_clear_and_set_interrupts(
+  ns16550_context *ctx,
+  uint8_t          clear,
+  uint8_t          set
+)
+{
+  rtems_interrupt_lock_context lock_context;
+  ns16550_get_reg get_reg = ctx->get_reg;
+  ns16550_set_reg set_reg = ctx->set_reg;
+  uintptr_t port = ctx->port;
+  uint8_t val;
+
+  rtems_termios_device_lock_acquire(&ctx->base, &lock_context);
+  val = (*get_reg)(port, NS16550_INTERRUPT_ENABLE);
+  val &= ~clear;
+  val |= set;
+  (*set_reg)(port, NS16550_INTERRUPT_ENABLE, val);
+  rtems_termios_device_lock_release(&ctx->base, &lock_context);
+}
+
+/*
+ *  ns16550_probe
+ */
+
+bool ns16550_probe(rtems_termios_device_context *base)
+{
+  ns16550_context        *ctx = (ns16550_context *) base;
+  uintptr_t               pNS16550;
+  uint8_t                 ucDataByte;
+  uint32_t                ulBaudDivisor;
+  ns16550_set_reg         setReg;
+  ns16550_get_reg         getReg;
+
+  ctx->modem_control = SP_MODEM_IRQ;
+
+  pNS16550 = ctx->port;    
+  setReg   = ctx->set_reg;
+  getReg   = ctx->get_reg;
+
+  /* Clear the divisor latch, clear all interrupt enables,
+   * and reset and
+   * disable the FIFO's.
+   */
+
+  (*setReg)(pNS16550, NS16550_LINE_CONTROL, 0x0);
+  ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR );
+
+  /* Set the divisor latch and set the baud rate. */
+
+  ulBaudDivisor = NS16550_GetBaudDivisor(ctx, ctx->initial_baud);
+  ctx->baud_divisor = ulBaudDivisor;
+  ucDataByte = SP_LINE_DLAB;
+  (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
+
+  /* XXX */
+  (*setReg)(pNS16550,NS16550_TRANSMIT_BUFFER,(uint8_t)(ulBaudDivisor & 0xffU));
+  (*setReg)(
+    pNS16550,NS16550_INTERRUPT_ENABLE,
+    (uint8_t)(( ulBaudDivisor >> 8 ) & 0xffU )
+  );
+
+  /* Clear the divisor latch and set the character size to eight bits */
+  /* with one stop bit and no parity checking. */
+  ucDataByte = EIGHT_BITS;
+  ctx->line_control = ucDataByte;
+  (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
+
+  /* Enable and reset transmit and receive FIFOs. TJA     */
+  ucDataByte = SP_FIFO_ENABLE;
+  (*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
+
+  ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST;
+  (*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
+
+  ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR);
+
+  /* Set data terminal ready. */
+  /* And open interrupt tristate line */
+  (*setReg)(pNS16550, NS16550_MODEM_CONTROL,ctx->modem_control);
+
+  (*getReg)(pNS16550, NS16550_LINE_STATUS );
+  (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER );
+
+  return true;
+}
+
+static size_t ns16550_write_to_fifo(
+  const ns16550_context *ctx,
+  const char *buf,
+  size_t len
+)
+{
+  uintptr_t port = ctx->port;
+  ns16550_set_reg set = ctx->set_reg;
+  size_t out = len > SP_FIFO_SIZE ? SP_FIFO_SIZE : len;
+  size_t i;
+
+  for (i = 0; i < out; ++i) {
+    (*set)(port, NS16550_TRANSMIT_BUFFER, buf[i]);
+  }
+
+  return out;
+}
+
+/**
+ * @brief Process interrupt.
+ */
+static void ns16550_isr(void *arg)
+{
+  rtems_termios_tty *tty = arg;
+  ns16550_context *ctx = rtems_termios_get_device_context(tty);
+  uintptr_t port = ctx->port;
+  ns16550_get_reg get = ctx->get_reg;
+  int i = 0;
+  char buf [SP_FIFO_SIZE];
+
+  /* Iterate until no more interrupts are pending */
+  do {
+    /* Fetch received characters */
+    for (i = 0; i < SP_FIFO_SIZE; ++i) {
+      if ((get( port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
+        buf [i] = (char) get(port, NS16550_RECEIVE_BUFFER);
+      } else {
+        break;
+      }
+    }
+
+    /* Enqueue fetched characters */
+    rtems_termios_enqueue_raw_characters(tty, buf, i);
+
+    /* Do transmit */
+    if (ctx->out_total > 0
+        && (get(port, NS16550_LINE_STATUS) & SP_LSR_THOLD) != 0) {
+      size_t current = ctx->out_current;
+
+      ctx->out_buf += current;
+      ctx->out_remaining -= current;
+
+      if (ctx->out_remaining > 0) {
+        ctx->out_current =
+          ns16550_write_to_fifo(ctx, ctx->out_buf, ctx->out_remaining);
+      } else {
+        rtems_termios_dequeue_characters(tty, ctx->out_total);
+      }
+    }
+  } while ((get( port, NS16550_INTERRUPT_ID) & SP_IID_0) == 0);
+}
+
+static void ns16550_isr_task(void *arg)
+{
+  rtems_termios_tty *tty = arg;
+  ns16550_context *ctx = rtems_termios_get_device_context(tty);
+  uint8_t status = (*ctx->get_reg)(ctx->port, NS16550_LINE_STATUS);
+
+  if ((status & SP_LSR_RDY) != 0) {
+    ns16550_clear_and_set_interrupts(ctx, SP_INT_RX_ENABLE, 0);
+    rtems_termios_rxirq_occured(tty);
+  }
+
+  if (ctx->out_total > 0 && (status & SP_LSR_THOLD) != 0) {
+    size_t current = ctx->out_current;
+
+    ctx->out_buf += current;
+    ctx->out_remaining -= current;
+
+    if (ctx->out_remaining > 0) {
+      ctx->out_current =
+        ns16550_write_to_fifo(ctx, ctx->out_buf, ctx->out_remaining);
+    } else {
+      size_t done = ctx->out_total;
+
+      ctx->out_total = 0;
+      ns16550_clear_and_set_interrupts(ctx, SP_INT_TX_ENABLE, 0);
+      rtems_termios_dequeue_characters(tty, done);
+    }
+  }
+}
+
+static int ns16550_read_task(rtems_termios_device_context *base)
+{
+  ns16550_context *ctx = (ns16550_context *) base;
+  uintptr_t port = ctx->port;
+  ns16550_get_reg get = ctx->get_reg;
+  char buf[SP_FIFO_SIZE];
+  int i;
+
+  for (i = 0; i < SP_FIFO_SIZE; ++i) {
+    if ((get(port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
+      buf[i] = (char) get(port, NS16550_RECEIVE_BUFFER);
+    } else {
+      break;
+    }
+  }
+
+  rtems_termios_enqueue_raw_characters(ctx->tty, buf, i);
+  ns16550_clear_and_set_interrupts(ctx, 0, SP_INT_RX_ENABLE);
+
+  return -1;
+}
+
+/*
+ *  ns16550_initialize_interrupts
+ *
+ *  This routine initializes the port to operate in interrupt driver mode.
+ */
+static void ns16550_initialize_interrupts(
+  struct rtems_termios_tty *tty,
+  ns16550_context          *ctx,
+  void                    (*isr)(void *)
+)
+{
+  #ifdef BSP_FEATURE_IRQ_EXTENSION
+    {
+      rtems_status_code sc = RTEMS_SUCCESSFUL;
+      sc = rtems_interrupt_handler_install(
+        ctx->irq,
+        "NS16550",
+        RTEMS_INTERRUPT_SHARED,
+        isr,
+        tty
+      );
+      if (sc != RTEMS_SUCCESSFUL) {
+        /* FIXME */
+        printk( "%s: Error: Install interrupt handler\n", __func__);
+        rtems_fatal_error_occurred( 0xdeadbeef);
+      }
+    }
+  #elif defined(BSP_FEATURE_IRQ_LEGACY)
+    {
+      int rv = 0;
+      #ifdef BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
+        rtems_irq_connect_data cd = {
+          ctx->irq,
+          isr,
+          tty,
+          NULL,
+          NULL,
+          NULL,
+          NULL
+        };
+        rv = BSP_install_rtems_shared_irq_handler( &cd);
+      #else
+        rtems_irq_connect_data cd = {
+          ctx->irq,
+          isr,
+          tty,
+          NULL,
+          NULL,
+          NULL
+        };
+        rv = BSP_install_rtems_irq_handler( &cd);
+      #endif
+      if (rv == 0) {
+        /* FIXME */
+        printk( "%s: Error: Install interrupt handler\n", __func__);
+        rtems_fatal_error_occurred( 0xdeadbeef);
+      }
+    }
+  #endif
+}
+
+/*
+ *  ns16550_open
+ */
+
+static bool ns16550_open(
+  struct rtems_termios_tty      *tty,
+  rtems_termios_device_context  *base,
+  struct termios                *term,
+  rtems_libio_open_close_args_t *args
+)
+{
+  ns16550_context *ctx = (ns16550_context *) base;
+
+  ctx->tty = tty;
+
+  /* Set initial baud */
+  rtems_termios_set_initial_baud(tty, ctx->initial_baud);
+
+  if (tty->handler.mode == TERMIOS_IRQ_DRIVEN) {
+    ns16550_initialize_interrupts(tty, ctx, ns16550_isr);
+    ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
+  } else if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
+    ns16550_initialize_interrupts(tty, ctx, ns16550_isr_task);
+    ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
+  }
+
+  return true;
+}
+
+static void ns16550_cleanup_interrupts(
+  struct rtems_termios_tty *tty,
+  ns16550_context          *ctx,
+  void                    (*isr)(void *)
+)
+{
+  #if defined(BSP_FEATURE_IRQ_EXTENSION)
+    rtems_status_code sc = RTEMS_SUCCESSFUL;
+    sc = rtems_interrupt_handler_remove(
+      ctx->irq,
+      isr,
+      tty
+    );
+    if (sc != RTEMS_SUCCESSFUL) {
+      /* FIXME */
+      printk("%s: Error: Remove interrupt handler\n", __func__);
+      rtems_fatal_error_occurred(0xdeadbeef);
+    }
+  #elif defined(BSP_FEATURE_IRQ_LEGACY)
+    int rv = 0;
+    rtems_irq_connect_data cd = {
+      .name = ctx->irq,
+      .hdl = isr,
+      .handle = tty
+    };
+    rv = BSP_remove_rtems_irq_handler(&cd);
+    if (rv == 0) {
+      /* FIXME */
+      printk("%s: Error: Remove interrupt handler\n", __func__);
+      rtems_fatal_error_occurred(0xdeadbeef);
+    }
+  #endif
+}
+
+/*
+ *  ns16550_close
+ */
+
+static void ns16550_close(
+  struct rtems_termios_tty      *tty,
+  rtems_termios_device_context  *base,
+  rtems_libio_open_close_args_t *args
+)
+{
+  ns16550_context *ctx = (ns16550_context *) base;
+
+  ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR);
+
+  if (tty->handler.mode == TERMIOS_IRQ_DRIVEN) {
+    ns16550_cleanup_interrupts(tty, ctx, ns16550_isr);
+  } else if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
+    ns16550_cleanup_interrupts(tty, ctx, ns16550_isr_task);
+  }
+}
+
+/**
+ * @brief Polled write for NS16550.
+ */
+void ns16550_polled_putchar(rtems_termios_device_context *base, char out)
+{
+  ns16550_context *ctx = (ns16550_context *) base;
+  uintptr_t port = ctx->port;
+  ns16550_get_reg get = ctx->get_reg;
+  ns16550_set_reg set = ctx->set_reg;
+  uint32_t status = 0;
+  rtems_interrupt_lock_context lock_context;
+
+  /* Save port interrupt mask */
+  uint32_t interrupt_mask = get( port, NS16550_INTERRUPT_ENABLE);
+
+  /* Disable port interrupts */
+  ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR);
+
+  while (true) {
+    /* Try to transmit the character in a critical section */
+    rtems_termios_device_lock_acquire(&ctx->base, &lock_context);
+
+    /* Read the transmitter holding register and check it */
+    status = get( port, NS16550_LINE_STATUS);
+    if ((status & SP_LSR_THOLD) != 0) {
+      /* Transmit character */
+      set( port, NS16550_TRANSMIT_BUFFER, out);
+
+      /* Finished */
+      rtems_termios_device_lock_release(&ctx->base, &lock_context);
+      break;
+    } else {
+      rtems_termios_device_lock_release(&ctx->base, &lock_context);
+    }
+
+    /* Wait for transmitter holding register to be empty */
+    do {
+      status = get( port, NS16550_LINE_STATUS);
+    } while ((status & SP_LSR_THOLD) == 0);
+  }
+
+  /* Restore port interrupt mask */
+  set( port, NS16550_INTERRUPT_ENABLE, interrupt_mask);
+}
+
+/*
+ * These routines provide control of the RTS and DTR lines
+ */
+
+/*
+ *  ns16550_assert_RTS
+ */
+
+static void ns16550_assert_RTS(rtems_termios_device_context *base)
+{
+  ns16550_context             *ctx = (ns16550_context *) base;
+  rtems_interrupt_lock_context lock_context;
+
+  /*
+   * Assert RTS
+   */
+  rtems_termios_device_lock_acquire(base, &lock_context);
+  ctx->modem_control |= SP_MODEM_RTS;
+  (*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL, ctx->modem_control);
+  rtems_termios_device_lock_release(base, &lock_context);
+}
+
+/*
+ *  ns16550_negate_RTS
+ */
+
+static void ns16550_negate_RTS(rtems_termios_device_context *base)
+{
+  ns16550_context             *ctx = (ns16550_context *) base;
+  rtems_interrupt_lock_context lock_context;
+
+  /*
+   * Negate RTS
+   */
+  rtems_termios_device_lock_acquire(base, &lock_context);
+  ctx->modem_control &= ~SP_MODEM_RTS;
+  (*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL, ctx->modem_control);
+  rtems_termios_device_lock_release(base, &lock_context);
+}
+
+/*
+ * These flow control routines utilise a connection from the local DTR
+ * line to the remote CTS line
+ */
+
+/*
+ *  ns16550_assert_DTR
+ */
+
+static void ns16550_assert_DTR(rtems_termios_device_context *base)
+{
+  ns16550_context             *ctx = (ns16550_context *) base;
+  rtems_interrupt_lock_context lock_context;
+
+  /*
+   * Assert DTR
+   */
+  rtems_termios_device_lock_acquire(base, &lock_context);
+  ctx->modem_control |= SP_MODEM_DTR;
+  (*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL, ctx->modem_control);
+  rtems_termios_device_lock_release(base, &lock_context);
+}
+
+/*
+ *  ns16550_negate_DTR
+ */
+
+static void ns16550_negate_DTR(rtems_termios_device_context *base)
+{
+  ns16550_context             *ctx = (ns16550_context *) base;
+  rtems_interrupt_lock_context lock_context;
+
+  /*
+   * Negate DTR
+   */
+  rtems_termios_device_lock_acquire(base, &lock_context);
+  ctx->modem_control &=~SP_MODEM_DTR;
+  (*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL,ctx->modem_control);
+  rtems_termios_device_lock_release(base, &lock_context);
+}
+
+/*
+ *  ns16550_set_attributes
+ *
+ *  This function sets the channel to reflect the requested termios
+ *  port settings.
+ */
+
+static bool ns16550_set_attributes(
+  rtems_termios_device_context *base,
+  const struct termios         *t
+)
+{
+  ns16550_context        *ctx = (ns16550_context *) base;
+  uint32_t                pNS16550;
+  uint32_t                ulBaudDivisor;
+  uint8_t                 ucLineControl;
+  uint32_t                baud_requested;
+  ns16550_set_reg         setReg;
+
+  pNS16550 = ctx->port;
+  setReg   = ctx->set_reg;
+
+  /*
+   *  Calculate the baud rate divisor
+   *
+   *  Assert ensures there is no division by 0.
+   */
+
+  baud_requested = rtems_termios_baud_to_number(t->c_ospeed);
+  _Assert( baud_requested != 0 );
+
+  ulBaudDivisor = NS16550_GetBaudDivisor(ctx, baud_requested);
+
+  ucLineControl = 0;
+
+  /*
+   *  Parity
+   */
+
+  if (t->c_cflag & PARENB) {
+    ucLineControl |= SP_LINE_PAR;
+    if (!(t->c_cflag & PARODD))
+      ucLineControl |= SP_LINE_ODD;
+  }
+
+  /*
+   *  Character Size
+   */
+
+  if (t->c_cflag & CSIZE) {
+    switch (t->c_cflag & CSIZE) {
+      case CS5:  ucLineControl |= FIVE_BITS;  break;
+      case CS6:  ucLineControl |= SIX_BITS;   break;
+      case CS7:  ucLineControl |= SEVEN_BITS; break;
+      case CS8:  ucLineControl |= EIGHT_BITS; break;
+    }
+  } else {
+    ucLineControl |= EIGHT_BITS;               /* default to 9600,8,N,1 */
+  }
+
+  /*
+   *  Stop Bits
+   */
+
+  if (t->c_cflag & CSTOPB) {
+    ucLineControl |= SP_LINE_STOP;              /* 2 stop bits */
+  } else {
+    ;                                           /* 1 stop bit */
+  }
+
+  /*
+   *  Now actually set the chip
+   */
+
+  if (ulBaudDivisor != ctx->baud_divisor || ucLineControl != ctx->line_control) {
+    rtems_interrupt_lock_context lock_context;
+
+    ctx->baud_divisor = ulBaudDivisor;
+    ctx->line_control = ucLineControl;
+
+    rtems_termios_device_lock_acquire(base, &lock_context);
+
+    /*
+     *  Set the baud rate
+     *
+     *  NOTE: When the Divisor Latch Access Bit (DLAB) is set to 1,
+     *        the transmit buffer and interrupt enable registers
+     *        turn into the LSB and MSB divisor latch registers.
+     */
+
+    (*setReg)(pNS16550, NS16550_LINE_CONTROL, SP_LINE_DLAB);
+    (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, ulBaudDivisor&0xff);
+    (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, (ulBaudDivisor>>8)&0xff);
+
+    /*
+     *  Now write the line control
+     */
+    (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
+
+    rtems_termios_device_lock_release(base, &lock_context);
+  }
+
+  return true;
+}
+
+/**
+ * @brief Transmits up to @a len characters from @a buf.
+ *
+ * This routine is invoked either from task context with disabled interrupts to
+ * start a new transmission process with exactly one character in case of an
+ * idle output state or from the interrupt handler to refill the transmitter.
+ *
+ * Returns always zero.
+ */
+static void ns16550_write_support_int(
+  rtems_termios_device_context *base,
+  const char                   *buf,
+  size_t                        len
+)
+{
+  ns16550_context *ctx = (ns16550_context *) base;
+
+  ctx->out_total = len;
+
+  if (len > 0) {
+    ctx->out_remaining = len;
+    ctx->out_buf = buf;
+    ctx->out_current = ns16550_write_to_fifo(ctx, buf, len);
+
+    ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR);
+  } else {
+    ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
+  }
+}
+
+static void ns16550_write_support_task(
+  rtems_termios_device_context *base,
+  const char                   *buf,
+  size_t                        len
+)
+{
+  ns16550_context *ctx = (ns16550_context *) base;
+
+  ctx->out_total = len;
+
+  if (len > 0) {
+    ctx->out_remaining = len;
+    ctx->out_buf = buf;
+    ctx->out_current = ns16550_write_to_fifo(ctx, buf, len);
+
+    ns16550_clear_and_set_interrupts(ctx, 0, SP_INT_TX_ENABLE);
+  }
+}
+
+/*
+ *  ns16550_write_support_polled
+ *
+ *  Console Termios output entry point.
+ *
+ */
+
+static void ns16550_write_support_polled(
+  rtems_termios_device_context *base,
+  const char                   *buf,
+  size_t                        len
+)
+{
+  size_t nwrite = 0;
+
+  /*
+   * poll each byte in the string out of the port.
+   */
+  while (nwrite < len) {
+    /*
+     * transmit character
+     */
+    ns16550_polled_putchar(base, *buf++);
+    nwrite++;
+  }
+}
+
+/*
+ *  Debug gets() support
+ */
+int ns16550_polled_getchar(rtems_termios_device_context *base)
+{
+  ns16550_context     *ctx = (ns16550_context *) base;
+  uint32_t             pNS16550;
+  unsigned char        ucLineStatus;
+  uint8_t              cChar;
+  ns16550_get_reg      getReg;
+
+  pNS16550 = ctx->port;
+  getReg   = ctx->get_reg;
+
+  ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
+  if (ucLineStatus & SP_LSR_RDY) {
+    cChar = (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER);
+    return (int)cChar;
+  }
+  return -1;
+}
+
+/*
+ * Flow control is only supported when using interrupts
+ */
+
+const rtems_termios_device_flow ns16550_flow_rtscts = {
+  .stop_remote_tx = ns16550_negate_RTS,
+  .start_remote_tx = ns16550_assert_RTS
+};
+
+const rtems_termios_device_flow ns16550_flow_dtrcts = {
+  .stop_remote_tx = ns16550_negate_DTR,
+  .start_remote_tx = ns16550_assert_DTR
+};
+
+const rtems_termios_device_handler ns16550_handler_interrupt = {
+  .first_open = ns16550_open,
+  .last_close = ns16550_close,
+  .poll_read = NULL,
+  .write = ns16550_write_support_int,
+  .set_attributes = ns16550_set_attributes,
+  .mode = TERMIOS_IRQ_DRIVEN
+};
+
+const rtems_termios_device_handler ns16550_handler_polled = {
+  .first_open = ns16550_open,
+  .last_close = ns16550_close,
+  .poll_read = ns16550_polled_getchar,
+  .write = ns16550_write_support_polled,
+  .set_attributes = ns16550_set_attributes,
+  .mode = TERMIOS_POLLED
+};
+
+const rtems_termios_device_handler ns16550_handler_task = {
+  .first_open = ns16550_open,
+  .last_close = ns16550_close,
+  .poll_read = ns16550_read_task,
+  .write = ns16550_write_support_task,
+  .set_attributes = ns16550_set_attributes,
+  .mode = TERMIOS_TASK_DRIVEN
+};
Index: bsps/shared/dev/serial/ns16550.c
===================================================================
--- bsps/shared/dev/serial/ns16550.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/ns16550.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,875 @@
+/**
+ *  @file
+ *
+ *  This file contains the TTY driver for the National Semiconductor NS16550.
+ *
+ *  This part is widely cloned and second sourced.  It is found in a number
+ *  of "Super IO" controllers.
+ *
+ *  This driver uses the termios pseudo driver.
+ */
+
+/*
+ *  COPYRIGHT (c) 1998 by Radstone Technology
+ *
+ *  THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
+ *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
+ *  AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
+ *
+ *  You are hereby granted permission to use, copy, modify, and distribute
+ *  this file, provided that this notice, plus the above copyright notice
+ *  and disclaimer, appears in all copies. Radstone Technology will provide
+ *  no support for this code.
+ *
+ *  COPYRIGHT (c) 1989-2012.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdlib.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/ringbuf.h>
+#include <rtems/bspIo.h>
+#include <rtems/termiostypes.h>
+
+#include <libchip/serial.h>
+#include <libchip/sersupp.h>
+
+#include <bsp.h>
+
+#include <libchip/ns16550_p.h>
+#include <libchip/ns16550.h>
+
+#if defined(BSP_FEATURE_IRQ_EXTENSION)
+  #include <bsp/irq.h>
+#elif defined(BSP_FEATURE_IRQ_LEGACY)
+  #include <bsp/irq.h>
+#elif defined(__PPC__) || defined(__i386__)
+  #include <bsp/irq.h>
+  #define BSP_FEATURE_IRQ_LEGACY
+  #ifdef BSP_SHARED_HANDLER_SUPPORT
+    #define BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
+  #endif
+#endif
+
+typedef struct {
+  uint8_t ucModemCtrl;
+  int transmitFifoChars;
+} NS16550Context;
+
+/*
+ * Driver functions
+ */
+
+NS16550_STATIC void ns16550_init(int minor);
+
+NS16550_STATIC int ns16550_open(
+  int major,
+  int minor,
+  void  * arg
+);
+
+NS16550_STATIC int ns16550_close(
+  int major,
+  int minor,
+  void  * arg
+);
+
+NS16550_STATIC void ns16550_write_polled(
+  int   minor,
+  char  cChar
+);
+
+NS16550_STATIC int ns16550_assert_RTS(
+  int minor
+);
+
+NS16550_STATIC int ns16550_negate_RTS(
+  int minor
+);
+
+NS16550_STATIC int ns16550_assert_DTR(
+  int minor
+);
+
+NS16550_STATIC int ns16550_negate_DTR(
+  int minor
+);
+
+NS16550_STATIC void ns16550_initialize_interrupts(int minor);
+
+NS16550_STATIC void ns16550_cleanup_interrupts(int minor);
+
+NS16550_STATIC ssize_t ns16550_write_support_int(
+  int   minor,
+  const char *buf,
+  size_t len
+);
+
+NS16550_STATIC ssize_t ns16550_write_support_polled(
+  int   minor,
+  const char *buf,
+  size_t len
+  );
+
+int ns16550_inbyte_nonblocking_polled(
+  int minor
+);
+
+NS16550_STATIC void ns16550_enable_interrupts(
+  console_tbl *c,
+  int         mask
+);
+
+NS16550_STATIC int ns16550_set_attributes(
+  int                   minor,
+  const struct termios *t
+);
+
+#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
+  NS16550_STATIC void ns16550_isr(void *arg);
+#endif
+
+RTEMS_INTERRUPT_LOCK_DEFINE(static, ns16550_lock, "NS16550")
+
+/*
+ * Flow control is only supported when using interrupts
+ */
+
+const console_flow ns16550_flow_RTSCTS = {
+  ns16550_negate_RTS,             /* deviceStopRemoteTx */
+  ns16550_assert_RTS              /* deviceStartRemoteTx */
+};
+
+const console_flow ns16550_flow_DTRCTS = {
+  ns16550_negate_DTR,             /* deviceStopRemoteTx */
+  ns16550_assert_DTR              /* deviceStartRemoteTx */
+};
+
+const console_fns ns16550_fns = {
+  libchip_serial_default_probe,   /* deviceProbe */
+  ns16550_open,                   /* deviceFirstOpen */
+  ns16550_close,                  /* deviceLastClose */
+  NULL,                           /* deviceRead */
+  ns16550_write_support_int,      /* deviceWrite */
+  ns16550_init,                   /* deviceInitialize */
+  ns16550_write_polled,           /* deviceWritePolled */
+  ns16550_set_attributes,         /* deviceSetAttributes */
+  true                            /* deviceOutputUsesInterrupts */
+};
+
+const console_fns ns16550_fns_polled = {
+  libchip_serial_default_probe,        /* deviceProbe */
+  ns16550_open,                        /* deviceFirstOpen */
+  ns16550_close,                       /* deviceLastClose */
+  ns16550_inbyte_nonblocking_polled,   /* deviceRead */
+  ns16550_write_support_polled,        /* deviceWrite */
+  ns16550_init,                        /* deviceInitialize */
+  ns16550_write_polled,                /* deviceWritePolled */
+  ns16550_set_attributes,              /* deviceSetAttributes */
+  false                                /* deviceOutputUsesInterrupts */
+};
+
+static uint32_t NS16550_GetBaudDivisor(const console_tbl *c, uint32_t baud)
+{
+  uint32_t clock = c->ulClock;
+  uint32_t baudDivisor = (clock != 0 ? clock : 115200) / (baud * 16);
+
+  if (c->deviceType == SERIAL_NS16550_WITH_FDR) {
+    uint32_t fractionalDivider = 0x10;
+    uint32_t err = baud;
+    uint32_t mulVal;
+    uint32_t divAddVal;
+
+    clock /= 16 * baudDivisor;
+    for (mulVal = 1; mulVal < 16; ++mulVal) {
+      for (divAddVal = 0; divAddVal < mulVal; ++divAddVal) {
+        uint32_t actual = (mulVal * clock) / (mulVal + divAddVal);
+        uint32_t newErr = actual > baud ? actual - baud : baud - actual;
+
+        if (newErr < err) {
+          err = newErr;
+          fractionalDivider = (mulVal << 4) | divAddVal;
+        }
+      }
+    }
+
+    (*c->setRegister)(
+      c->ulCtrlPort1,
+      NS16550_FRACTIONAL_DIVIDER,
+      fractionalDivider
+    );
+  }
+
+  return baudDivisor;
+}
+
+/*
+ *  ns16550_init
+ */
+
+void ns16550_init(int minor)
+{
+  uintptr_t               pNS16550;
+  uint8_t                 ucDataByte;
+  uint32_t                ulBaudDivisor;
+  NS16550Context        *pns16550Context;
+  setRegister_f           setReg;
+  getRegister_f           getReg;
+  console_tbl             *c = Console_Port_Tbl [minor];
+
+  pns16550Context=(NS16550Context *)malloc(sizeof(NS16550Context));
+
+  if (pns16550Context == NULL) {
+    printk( "%s: Error: Not enough memory\n", __func__);
+    rtems_fatal_error_occurred( 0xdeadbeef);
+  }
+
+  Console_Port_Data[minor].pDeviceContext=(void *)pns16550Context;
+  pns16550Context->ucModemCtrl=SP_MODEM_IRQ;
+
+  pNS16550 = c->ulCtrlPort1;
+  setReg   = c->setRegister;
+  getReg   = c->getRegister;
+
+  /* Clear the divisor latch, clear all interrupt enables,
+   * and reset and
+   * disable the FIFO's.
+   */
+
+  (*setReg)(pNS16550, NS16550_LINE_CONTROL, 0x0);
+  ns16550_enable_interrupts( c, NS16550_DISABLE_ALL_INTR );
+
+  /* Set the divisor latch and set the baud rate. */
+
+  ulBaudDivisor = NS16550_GetBaudDivisor(c, (uintptr_t) c->pDeviceParams);
+  ucDataByte = SP_LINE_DLAB;
+  (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
+
+  /* XXX */
+  (*setReg)(pNS16550,NS16550_TRANSMIT_BUFFER,(uint8_t)(ulBaudDivisor & 0xffU));
+  (*setReg)(
+    pNS16550,NS16550_INTERRUPT_ENABLE,
+    (uint8_t)(( ulBaudDivisor >> 8 ) & 0xffU )
+  );
+
+  /* Clear the divisor latch and set the character size to eight bits */
+  /* with one stop bit and no parity checking. */
+  ucDataByte = EIGHT_BITS;
+  (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
+
+  /* Enable and reset transmit and receive FIFOs. TJA     */
+  ucDataByte = SP_FIFO_ENABLE;
+  (*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
+
+  ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST;
+  (*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
+
+  ns16550_enable_interrupts(c, NS16550_DISABLE_ALL_INTR);
+
+  /* Set data terminal ready. */
+  /* And open interrupt tristate line */
+  (*setReg)(pNS16550, NS16550_MODEM_CONTROL,pns16550Context->ucModemCtrl);
+
+  (*getReg)(pNS16550, NS16550_LINE_STATUS );
+  (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER );
+}
+
+/*
+ *  ns16550_open
+ */
+
+int ns16550_open(
+  int major,
+  int minor,
+  void *arg
+)
+{
+  rtems_libio_open_close_args_t *oc = (rtems_libio_open_close_args_t *) arg;
+  struct rtems_termios_tty *tty = (struct rtems_termios_tty *) oc->iop->data1;
+  console_tbl *c = Console_Port_Tbl [minor];
+  console_data *d = &Console_Port_Data [minor];
+
+  d->termios_data = tty;
+
+  /* Assert DTR */
+  if (c->pDeviceFlow != &ns16550_flow_DTRCTS) {
+    ns16550_assert_DTR( minor);
+  }
+
+  /* Set initial baud */
+  rtems_termios_set_initial_baud( tty, (intptr_t) c->pDeviceParams);
+
+  if (c->pDeviceFns->deviceOutputUsesInterrupts) {
+    ns16550_initialize_interrupts( minor);
+    ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
+  }
+
+  return RTEMS_SUCCESSFUL;
+}
+
+/*
+ *  ns16550_close
+ */
+
+int ns16550_close(
+  int      major,
+  int      minor,
+  void    * arg
+)
+{
+  console_tbl *c = Console_Port_Tbl [minor];
+
+  /*
+   * Negate DTR
+   */
+  if (c->pDeviceFlow != &ns16550_flow_DTRCTS) {
+    ns16550_negate_DTR(minor);
+  }
+
+  ns16550_enable_interrupts(c, NS16550_DISABLE_ALL_INTR);
+
+  if (c->pDeviceFns->deviceOutputUsesInterrupts) {
+    ns16550_cleanup_interrupts(minor);
+  }
+
+  return(RTEMS_SUCCESSFUL);
+}
+
+/**
+ * @brief Polled write for NS16550.
+ */
+void ns16550_outch_polled(console_tbl *c, char out)
+{
+  uintptr_t port = c->ulCtrlPort1;
+  getRegister_f get = c->getRegister;
+  setRegister_f set = c->setRegister;
+  uint32_t status = 0;
+  rtems_interrupt_lock_context lock_context;
+
+  /* Save port interrupt mask */
+  uint32_t interrupt_mask = get( port, NS16550_INTERRUPT_ENABLE);
+
+  /* Disable port interrupts */
+  ns16550_enable_interrupts( c, NS16550_DISABLE_ALL_INTR);
+
+  while (true) {
+    /* Try to transmit the character in a critical section */
+    rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
+
+    /* Read the transmitter holding register and check it */
+    status = get( port, NS16550_LINE_STATUS);
+    if ((status & SP_LSR_THOLD) != 0) {
+      /* Transmit character */
+      set( port, NS16550_TRANSMIT_BUFFER, out);
+
+      /* Finished */
+      rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
+      break;
+    } else {
+      rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
+    }
+
+    /* Wait for transmitter holding register to be empty */
+    do {
+      status = get( port, NS16550_LINE_STATUS);
+    } while ((status & SP_LSR_THOLD) == 0);
+  }
+
+  /* Restore port interrupt mask */
+  set( port, NS16550_INTERRUPT_ENABLE, interrupt_mask);
+}
+
+void ns16550_write_polled(int minor, char out)
+{
+  console_tbl *c = Console_Port_Tbl [minor];
+
+  ns16550_outch_polled( c, out );
+}
+
+/*
+ * These routines provide control of the RTS and DTR lines
+ */
+
+/*
+ *  ns16550_assert_RTS
+ */
+
+NS16550_STATIC int ns16550_assert_RTS(int minor)
+{
+  uint32_t                pNS16550;
+  rtems_interrupt_lock_context lock_context;
+  NS16550Context        *pns16550Context;
+  setRegister_f           setReg;
+
+  pns16550Context=(NS16550Context *) Console_Port_Data[minor].pDeviceContext;
+
+  pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg   = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   * Assert RTS
+   */
+  rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
+  pns16550Context->ucModemCtrl|=SP_MODEM_RTS;
+  (*setReg)(pNS16550, NS16550_MODEM_CONTROL, pns16550Context->ucModemCtrl);
+  rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
+  return 0;
+}
+
+/*
+ *  ns16550_negate_RTS
+ */
+
+NS16550_STATIC int ns16550_negate_RTS(int minor)
+{
+  uint32_t                pNS16550;
+  rtems_interrupt_lock_context lock_context;
+  NS16550Context        *pns16550Context;
+  setRegister_f           setReg;
+
+  pns16550Context=(NS16550Context *) Console_Port_Data[minor].pDeviceContext;
+
+  pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg   = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   * Negate RTS
+   */
+  rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
+  pns16550Context->ucModemCtrl&=~SP_MODEM_RTS;
+  (*setReg)(pNS16550, NS16550_MODEM_CONTROL, pns16550Context->ucModemCtrl);
+  rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
+  return 0;
+}
+
+/*
+ * These flow control routines utilise a connection from the local DTR
+ * line to the remote CTS line
+ */
+
+/*
+ *  ns16550_assert_DTR
+ */
+
+NS16550_STATIC int ns16550_assert_DTR(int minor)
+{
+  uint32_t                pNS16550;
+  rtems_interrupt_lock_context lock_context;
+  NS16550Context        *pns16550Context;
+  setRegister_f           setReg;
+
+  pns16550Context=(NS16550Context *) Console_Port_Data[minor].pDeviceContext;
+
+  pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg   = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   * Assert DTR
+   */
+  rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
+  pns16550Context->ucModemCtrl|=SP_MODEM_DTR;
+  (*setReg)(pNS16550, NS16550_MODEM_CONTROL, pns16550Context->ucModemCtrl);
+  rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
+  return 0;
+}
+
+/*
+ *  ns16550_negate_DTR
+ */
+
+NS16550_STATIC int ns16550_negate_DTR(int minor)
+{
+  uint32_t                pNS16550;
+  rtems_interrupt_lock_context lock_context;
+  NS16550Context        *pns16550Context;
+  setRegister_f           setReg;
+
+  pns16550Context=(NS16550Context *) Console_Port_Data[minor].pDeviceContext;
+
+  pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg   = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   * Negate DTR
+   */
+  rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
+  pns16550Context->ucModemCtrl&=~SP_MODEM_DTR;
+  (*setReg)(pNS16550, NS16550_MODEM_CONTROL,pns16550Context->ucModemCtrl);
+  rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
+  return 0;
+}
+
+/*
+ *  ns16550_set_attributes
+ *
+ *  This function sets the channel to reflect the requested termios
+ *  port settings.
+ */
+
+int ns16550_set_attributes(
+  int                   minor,
+  const struct termios *t
+)
+{
+  uint32_t                pNS16550;
+  uint32_t                ulBaudDivisor;
+  uint8_t                 ucLineControl;
+  uint32_t                baud_requested;
+  setRegister_f           setReg;
+  rtems_interrupt_lock_context lock_context;
+  const console_tbl      *c = Console_Port_Tbl [minor];
+
+  pNS16550 = c->ulCtrlPort1;
+  setReg   = c->setRegister;
+
+  /*
+   *  Calculate the baud rate divisor
+   *
+   *  Assert ensures there is no division by 0.
+   */
+
+  baud_requested = rtems_termios_baud_to_number(t->c_ospeed);
+  _Assert( baud_requested != 0 );
+  ulBaudDivisor = NS16550_GetBaudDivisor(c, baud_requested);
+
+  ucLineControl = 0;
+
+  /*
+   *  Parity
+   */
+
+  if (t->c_cflag & PARENB) {
+    ucLineControl |= SP_LINE_PAR;
+    if (!(t->c_cflag & PARODD))
+      ucLineControl |= SP_LINE_ODD;
+  }
+
+  /*
+   *  Character Size
+   */
+
+  if (t->c_cflag & CSIZE) {
+    switch (t->c_cflag & CSIZE) {
+      case CS5:  ucLineControl |= FIVE_BITS;  break;
+      case CS6:  ucLineControl |= SIX_BITS;   break;
+      case CS7:  ucLineControl |= SEVEN_BITS; break;
+      case CS8:  ucLineControl |= EIGHT_BITS; break;
+    }
+  } else {
+    ucLineControl |= EIGHT_BITS;               /* default to 9600,8,N,1 */
+  }
+
+  /*
+   *  Stop Bits
+   */
+
+  if (t->c_cflag & CSTOPB) {
+    ucLineControl |= SP_LINE_STOP;              /* 2 stop bits */
+  } else {
+    ;                                           /* 1 stop bit */
+  }
+
+  /*
+   *  Now actually set the chip
+   */
+
+  rtems_interrupt_lock_acquire(&ns16550_lock, &lock_context);
+
+    /*
+     *  Set the baud rate
+     *
+     *  NOTE: When the Divisor Latch Access Bit (DLAB) is set to 1,
+     *        the transmit buffer and interrupt enable registers
+     *        turn into the LSB and MSB divisor latch registers.
+     */
+
+    (*setReg)(pNS16550, NS16550_LINE_CONTROL, SP_LINE_DLAB);
+    (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, ulBaudDivisor&0xff);
+    (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, (ulBaudDivisor>>8)&0xff);
+
+    /*
+     *  Now write the line control
+     */
+    (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
+
+  rtems_interrupt_lock_release(&ns16550_lock, &lock_context);
+
+  return 0;
+}
+
+#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
+
+/**
+ * @brief Process interrupt.
+ */
+NS16550_STATIC void ns16550_process( int minor)
+{
+  console_tbl *c = Console_Port_Tbl [minor];
+  console_data *d = &Console_Port_Data [minor];
+  NS16550Context *ctx = d->pDeviceContext;
+  uint32_t port = c->ulCtrlPort1;
+  getRegister_f get = c->getRegister;
+  int i;
+  char buf [SP_FIFO_SIZE];
+
+  /* Iterate until no more interrupts are pending */
+  do {
+    /* Fetch received characters */
+    i = 0;
+    while ((get(port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
+      buf[i++] = (char) get(port, NS16550_RECEIVE_BUFFER);
+      if (i == SP_FIFO_SIZE) {
+        /* Enqueue fetched characters */
+        rtems_termios_enqueue_raw_characters( d->termios_data, buf, i);
+        i = 0;
+      }
+    }
+
+    if (i > 0)
+      rtems_termios_enqueue_raw_characters( d->termios_data, buf, i);
+
+    /* Check if we can dequeue transmitted characters */
+    if (ctx->transmitFifoChars > 0
+        && (get( port, NS16550_LINE_STATUS) & SP_LSR_THOLD) != 0) {
+      /* Dequeue transmitted characters */
+      rtems_termios_dequeue_characters(
+        d->termios_data,
+        ctx->transmitFifoChars
+      );
+    }
+  } while ((get( port, NS16550_INTERRUPT_ID) & SP_IID_0) == 0);
+}
+#endif
+
+/**
+ * @brief Transmits up to @a len characters from @a buf.
+ *
+ * This routine is invoked either from task context with disabled interrupts to
+ * start a new transmission process with exactly one character in case of an
+ * idle output state or from the interrupt handler to refill the transmitter.
+ *
+ * Returns always zero.
+ */
+ssize_t ns16550_write_support_int(
+  int minor,
+  const char *buf,
+  size_t len
+)
+{
+  console_tbl *c = Console_Port_Tbl [minor];
+  console_data *d = &Console_Port_Data [minor];
+  NS16550Context *ctx = d->pDeviceContext;
+  uint32_t port = c->ulCtrlPort1;
+  setRegister_f set = c->setRegister;
+  int i = 0;
+  int out = len > SP_FIFO_SIZE ? SP_FIFO_SIZE : len;
+
+  for (i = 0; i < out; ++i) {
+    set( port, NS16550_TRANSMIT_BUFFER, buf [i]);
+  }
+
+  ctx->transmitFifoChars = out;
+
+  if (out > 0) {
+    ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR);
+  } else {
+    ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
+  }
+
+  return 0;
+}
+
+/*
+ *  ns16550_enable_interrupts
+ *
+ *  This routine initializes the port to have the specified interrupts masked.
+ */
+NS16550_STATIC void ns16550_enable_interrupts(
+  console_tbl *c,
+  int         mask
+)
+{
+  uint32_t       pNS16550;
+  setRegister_f  setReg;
+
+  pNS16550 = c->ulCtrlPort1;
+  setReg   = c->setRegister;
+
+  (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, mask);
+}
+
+#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
+  void ns16550_isr(void *arg)
+  {
+    int minor = (intptr_t) arg;
+
+    ns16550_process( minor);
+  }
+#endif
+
+/*
+ *  ns16550_initialize_interrupts
+ *
+ *  This routine initializes the port to operate in interrupt driver mode.
+ */
+NS16550_STATIC void ns16550_initialize_interrupts( int minor)
+{
+#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
+  console_tbl *c = Console_Port_Tbl [minor];
+#endif
+
+  #ifdef BSP_FEATURE_IRQ_EXTENSION
+    {
+      rtems_status_code sc = RTEMS_SUCCESSFUL;
+      sc = rtems_interrupt_handler_install(
+        c->ulIntVector,
+        "NS16550",
+        RTEMS_INTERRUPT_SHARED,
+        ns16550_isr,
+        (void *) (intptr_t) minor
+      );
+      if (sc != RTEMS_SUCCESSFUL) {
+        /* FIXME */
+        printk( "%s: Error: Install interrupt handler\n", __func__);
+        rtems_fatal_error_occurred( 0xdeadbeef);
+      }
+    }
+  #elif defined(BSP_FEATURE_IRQ_LEGACY)
+    {
+      int rv = 0;
+      #ifdef BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
+        rtems_irq_connect_data cd = {
+          c->ulIntVector,
+          ns16550_isr,
+          (void *) minor,
+          NULL,
+          NULL,
+          NULL,
+          NULL
+        };
+        rv = BSP_install_rtems_shared_irq_handler( &cd);
+      #else
+        rtems_irq_connect_data cd = {
+          c->ulIntVector,
+          ns16550_isr,
+          (void *) minor,
+          NULL,
+          NULL,
+          NULL
+        };
+        rv = BSP_install_rtems_irq_handler( &cd);
+      #endif
+      if (rv == 0) {
+        /* FIXME */
+        printk( "%s: Error: Install interrupt handler\n", __func__);
+        rtems_fatal_error_occurred( 0xdeadbeef);
+      }
+    }
+  #endif
+}
+
+NS16550_STATIC void ns16550_cleanup_interrupts(int minor)
+{
+  #if defined(BSP_FEATURE_IRQ_EXTENSION)
+    rtems_status_code sc = RTEMS_SUCCESSFUL;
+    console_tbl *c = Console_Port_Tbl [minor];
+    sc = rtems_interrupt_handler_remove(
+      c->ulIntVector,
+      ns16550_isr,
+      (void *) (intptr_t) minor
+    );
+    if (sc != RTEMS_SUCCESSFUL) {
+      /* FIXME */
+      printk("%s: Error: Remove interrupt handler\n", __func__);
+      rtems_fatal_error_occurred(0xdeadbeef);
+    }
+  #elif defined(BSP_FEATURE_IRQ_LEGACY)
+    int rv = 0;
+    console_tbl *c = Console_Port_Tbl [minor];
+    rtems_irq_connect_data cd = {
+      .name = c->ulIntVector,
+      .hdl = ns16550_isr,
+      .handle = (void *) minor
+    };
+    rv = BSP_remove_rtems_irq_handler(&cd);
+    if (rv == 0) {
+      /* FIXME */
+      printk("%s: Error: Remove interrupt handler\n", __func__);
+      rtems_fatal_error_occurred(0xdeadbeef);
+    }
+  #endif
+}
+
+/*
+ *  ns16550_write_support_polled
+ *
+ *  Console Termios output entry point.
+ *
+ */
+
+ssize_t ns16550_write_support_polled(
+  int         minor,
+  const char *buf,
+  size_t      len
+)
+{
+  int nwrite = 0;
+
+  /*
+   * poll each byte in the string out of the port.
+   */
+  while (nwrite < len) {
+    /*
+     * transmit character
+     */
+    ns16550_write_polled(minor, *buf++);
+    nwrite++;
+  }
+
+  /*
+   * return the number of bytes written.
+   */
+  return nwrite;
+}
+
+/*
+ *  Debug gets() support
+ */
+int ns16550_inch_polled(
+  console_tbl *c
+)
+{
+  uint32_t             pNS16550;
+  unsigned char        ucLineStatus;
+  uint8_t              cChar;
+  getRegister_f        getReg;
+
+  pNS16550 = c->ulCtrlPort1;
+  getReg   = c->getRegister;
+
+  ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
+  if (ucLineStatus & SP_LSR_RDY) {
+    cChar = (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER);
+    return (int)cChar;
+  }
+  return -1;
+}
+
+/*
+ *  ns16550_inbyte_nonblocking_polled
+ *
+ *  Console Termios polling input entry point.
+ */
+int ns16550_inbyte_nonblocking_polled(int minor)
+{
+  console_tbl *c = Console_Port_Tbl [minor];
+
+  return ns16550_inch_polled( c );
+}
Index: bsps/shared/dev/serial/serprobe.c
===================================================================
--- bsps/shared/dev/serial/serprobe.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/serprobe.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,13 @@
+#include <rtems.h>
+#include <libchip/serial.h>
+#include <libchip/sersupp.h>
+
+bool libchip_serial_default_probe(int minor)
+{
+  /*
+   * If the configuration dependent probe has located the device then
+   * assume it is there
+   */
+
+  return true;
+}
Index: bsps/shared/dev/serial/z85c30.c
===================================================================
--- bsps/shared/dev/serial/z85c30.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/z85c30.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,893 @@
+/*
+ *  This file contains the console driver chip level routines for the
+ *  Zilog z85c30 chip.
+ *
+ *  The Zilog Z8530 is also available as:
+ *
+ *    + Intel 82530
+ *    + AMD ???
+ *
+ *  COPYRIGHT (c) 1998 by Radstone Technology
+ *
+ *
+ * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
+ * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
+ *
+ * You are hereby granted permission to use, copy, modify, and distribute
+ * this file, provided that this notice, plus the above copyright notice
+ * and disclaimer, appears in all copies. Radstone Technology will provide
+ * no support for this code.
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/score/sysstate.h>
+#include <stdlib.h>
+
+#include <libchip/serial.h>
+#include <libchip/sersupp.h>
+#include "z85c30_p.h"
+
+/*
+ * Flow control is only supported when using interrupts
+ */
+
+const console_flow z85c30_flow_RTSCTS = {
+  z85c30_negate_RTS,    /* deviceStopRemoteTx */
+  z85c30_assert_RTS     /* deviceStartRemoteTx */
+};
+
+const console_flow z85c30_flow_DTRCTS = {
+  z85c30_negate_DTR,    /* deviceStopRemoteTx */
+  z85c30_assert_DTR     /* deviceStartRemoteTx */
+};
+
+/*
+ * Exported driver function table
+ */
+
+const console_fns z85c30_fns = {
+  libchip_serial_default_probe,  /* deviceProbe */
+  z85c30_open,                   /* deviceFirstOpen */
+  NULL,                          /* deviceLastClose */
+  NULL,                          /* deviceRead */
+  z85c30_write_support_int,      /* deviceWrite */
+  z85c30_initialize_interrupts,  /* deviceInitialize */
+  z85c30_write_polled,           /* deviceWritePolled */
+  NULL,                          /* deviceSetAttributes */
+  true                           /* deviceOutputUsesInterrupts */
+};
+
+const console_fns z85c30_fns_polled = {
+  libchip_serial_default_probe,      /* deviceProbe */
+  z85c30_open,                       /* deviceFirstOpen */
+  z85c30_close,                      /* deviceLastClose */
+  z85c30_inbyte_nonblocking_polled,  /* deviceRead */
+  z85c30_write_support_polled,       /* deviceWrite */
+  z85c30_init,                       /* deviceInitialize */
+  z85c30_write_polled,               /* deviceWritePolled */
+  NULL,                              /* deviceSetAttributes */
+  false                              /* deviceOutputUsesInterrupts */
+};
+
+#if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE)
+  extern void set_vector( rtems_isr_entry, rtems_vector_number, int );
+#endif
+
+/*
+ *  z85c30_initialize_port
+ *
+ *  initialize a z85c30 Port
+ */
+
+Z85C30_STATIC void z85c30_initialize_port(
+  int minor
+)
+{
+  uintptr_t       ulCtrlPort;
+  uintptr_t       ulBaudDivisor;
+  setRegister_f   setReg;
+
+  ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg   = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   * Using register 4
+   * Set up the clock rate is 16 times the data
+   * rate, 8 bit sync char, 1 stop bit, no parity
+   */
+
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR4, SCC_WR4_1_STOP | SCC_WR4_16_CLOCK );
+
+  /*
+   * Set up for 8 bits/character on receive with
+   * receiver disable via register 3
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR3, SCC_WR3_RX_8_BITS );
+
+  /*
+   * Set up for 8 bits/character on transmit
+   * with transmitter disable via register 5
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR5, SCC_WR5_TX_8_BITS );
+
+  /*
+   * Clear misc control bits
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR10, 0x00 );
+
+  /*
+   * Setup the source of the receive and xmit
+   * clock as BRG output and the transmit clock
+   * as the output source for TRxC pin via register 11
+   */
+  (*setReg)(
+    ulCtrlPort,
+    SCC_WR0_SEL_WR11,
+    SCC_WR11_OUT_BR_GEN | SCC_WR11_TRXC_OI |
+      SCC_WR11_TX_BR_GEN | SCC_WR11_RX_BR_GEN
+  );
+
+  ulBaudDivisor = Z85C30_Baud(
+    (uint32_t) Console_Port_Tbl[minor]->ulClock,
+    (uint32_t) ((uintptr_t)Console_Port_Tbl[minor]->pDeviceParams)
+  );
+
+  /*
+   * Setup the lower 8 bits time constants=1E.
+   * If the time constans=1E, then the desire
+   * baud rate will be equilvalent to 9600, via register 12.
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR12, ulBaudDivisor & 0xff );
+
+  /*
+   * using register 13
+   * Setup the upper 8 bits time constant
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR13, (ulBaudDivisor>>8) & 0xff );
+
+  /*
+   * Enable the baud rate generator enable with clock from the
+   * SCC's PCLK input via register 14.
+   */
+  (*setReg)(
+    ulCtrlPort,
+    SCC_WR0_SEL_WR14,
+    SCC_WR14_BR_EN | SCC_WR14_BR_SRC | SCC_WR14_NULL
+  );
+
+  /*
+   * We are only interested in CTS state changes
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR15, SCC_WR15_CTS_IE );
+
+  /*
+   * Reset errors
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT );
+
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_ERR_RST );
+
+  /*
+   * Enable the receiver via register 3
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR3, SCC_WR3_RX_8_BITS | SCC_WR3_RX_EN );
+
+  /*
+   * Enable the transmitter pins set via register 5.
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR5, SCC_WR5_TX_8_BITS | SCC_WR5_TX_EN );
+
+  /*
+   * Disable interrupts
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR1, 0 );
+
+  /*
+   * Reset TX CRC
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_TX_CRC );
+
+  /*
+   * Reset interrupts
+   */
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT );
+}
+
+/*
+ *  z85c30_open
+ */
+
+Z85C30_STATIC int z85c30_open(
+  int   major,
+  int   minor,
+  void *arg
+)
+{
+
+  z85c30_initialize_port(minor);
+
+  /*
+   * Assert DTR
+   */
+
+  if (Console_Port_Tbl[minor]->pDeviceFlow !=&z85c30_flow_DTRCTS) {
+    z85c30_assert_DTR(minor);
+  }
+
+  return(RTEMS_SUCCESSFUL);
+}
+
+/*
+ *  z85c30_close
+ */
+
+Z85C30_STATIC int z85c30_close(
+  int   major,
+  int   minor,
+  void *arg
+)
+{
+  /*
+   * Negate DTR
+   */
+
+  if (Console_Port_Tbl[minor]->pDeviceFlow !=&z85c30_flow_DTRCTS) {
+    z85c30_negate_DTR(minor);
+  }
+
+  return(RTEMS_SUCCESSFUL);
+}
+
+/*
+ *  z85c30_init
+ */
+
+Z85C30_STATIC void z85c30_init(int minor)
+{
+  uintptr_t        ulCtrlPort;
+  z85c30_context  *pz85c30Context;
+  setRegister_f    setReg;
+  getRegister_f    getReg;
+
+  ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg     = Console_Port_Tbl[minor]->setRegister;
+  getReg     = Console_Port_Tbl[minor]->getRegister;
+
+  pz85c30Context = (z85c30_context *)malloc(sizeof(z85c30_context));
+
+  Console_Port_Data[minor].pDeviceContext = (void *)pz85c30Context;
+
+  pz85c30Context->ucModemCtrl = SCC_WR5_TX_8_BITS | SCC_WR5_TX_EN;
+
+  if ( ulCtrlPort == Console_Port_Tbl[minor]->ulCtrlPort2 ) {
+    /*
+     * This is channel A
+     */
+    /*
+     * Ensure port state machine is reset
+     */
+    (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
+
+    (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR9, SCC_WR9_CH_A_RST);
+
+  } else {
+    /*
+     * This is channel B
+     */
+    /*
+     * Ensure port state machine is reset
+     */
+    (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
+
+    (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR9, SCC_WR9_CH_B_RST);
+  }
+}
+
+/*
+ * These routines provide control of the RTS and DTR lines
+ */
+
+/*
+ *  z85c30_assert_RTS
+ */
+
+Z85C30_STATIC int z85c30_assert_RTS(int minor)
+{
+  rtems_interrupt_level  Irql;
+  z85c30_context        *pz85c30Context;
+  setRegister_f          setReg;
+
+  setReg = Console_Port_Tbl[minor]->setRegister;
+
+  pz85c30Context = (z85c30_context *) Console_Port_Data[minor].pDeviceContext;
+
+  /*
+   * Assert RTS
+   */
+
+  rtems_interrupt_disable(Irql);
+    pz85c30Context->ucModemCtrl|=SCC_WR5_RTS;
+    (*setReg)(
+      Console_Port_Tbl[minor]->ulCtrlPort1,
+      SCC_WR0_SEL_WR5,
+      pz85c30Context->ucModemCtrl
+    );
+  rtems_interrupt_enable(Irql);
+  return 0;
+}
+
+/*
+ *  z85c30_negate_RTS
+ */
+
+Z85C30_STATIC int z85c30_negate_RTS(int minor)
+{
+  rtems_interrupt_level  Irql;
+  z85c30_context        *pz85c30Context;
+  setRegister_f          setReg;
+
+  setReg = Console_Port_Tbl[minor]->setRegister;
+
+  pz85c30Context = (z85c30_context *) Console_Port_Data[minor].pDeviceContext;
+
+  /*
+   * Negate RTS
+   */
+
+  rtems_interrupt_disable(Irql);
+    pz85c30Context->ucModemCtrl&=~SCC_WR5_RTS;
+    (*setReg)(
+      Console_Port_Tbl[minor]->ulCtrlPort1,
+      SCC_WR0_SEL_WR5,
+      pz85c30Context->ucModemCtrl
+    );
+  rtems_interrupt_enable(Irql);
+  return 0;
+}
+
+/*
+ * These flow control routines utilise a connection from the local DTR
+ * line to the remote CTS line
+ */
+
+/*
+ *  z85c30_assert_DTR
+ */
+
+Z85C30_STATIC int z85c30_assert_DTR(int minor)
+{
+  rtems_interrupt_level  Irql;
+  z85c30_context        *pz85c30Context;
+  setRegister_f          setReg;
+
+  setReg = Console_Port_Tbl[minor]->setRegister;
+
+  pz85c30Context = (z85c30_context *) Console_Port_Data[minor].pDeviceContext;
+
+  /*
+   * Assert DTR
+   */
+
+  rtems_interrupt_disable(Irql);
+    pz85c30Context->ucModemCtrl|=SCC_WR5_DTR;
+    (*setReg)(
+      Console_Port_Tbl[minor]->ulCtrlPort1,
+      SCC_WR0_SEL_WR5,
+      pz85c30Context->ucModemCtrl
+  );
+  rtems_interrupt_enable(Irql);
+  return 0;
+}
+
+/*
+ *  z85c30_negate_DTR
+ */
+
+Z85C30_STATIC int z85c30_negate_DTR(int minor)
+{
+  rtems_interrupt_level  Irql;
+  z85c30_context        *pz85c30Context;
+  setRegister_f          setReg;
+
+  setReg = Console_Port_Tbl[minor]->setRegister;
+
+  pz85c30Context = (z85c30_context *) Console_Port_Data[minor].pDeviceContext;
+
+  /*
+   * Negate DTR
+   */
+
+  rtems_interrupt_disable(Irql);
+    pz85c30Context->ucModemCtrl&=~SCC_WR5_DTR;
+    (*setReg)(
+      Console_Port_Tbl[minor]->ulCtrlPort1,
+      SCC_WR0_SEL_WR5,
+      pz85c30Context->ucModemCtrl
+  );
+  rtems_interrupt_enable(Irql);
+  return 0;
+}
+
+/*
+ *  z85c30_set_attributes
+ *
+ *  This function sets the SCC channel to reflect the requested termios
+ *  port settings.
+ */
+
+Z85C30_STATIC int z85c30_set_attributes(
+  int                   minor,
+  const struct termios *t
+)
+{
+  uintptr_t              ulCtrlPort;
+  uint32_t               ulBaudDivisor;
+  uint32_t               wr3;
+  uint32_t               wr4;
+  uint32_t               wr5;
+  int                    baud_requested;
+  uint32_t               baud_number;
+  setRegister_f          setReg;
+  rtems_interrupt_level  Irql;
+
+  ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg     = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   *  Calculate the baud rate divisor
+   *
+   *  Assert ensures there is no division by 0.
+   */
+
+  baud_requested = t->c_ospeed;
+  if (!baud_requested)
+    baud_requested = B9600;              /* default to 9600 baud */
+
+  baud_number = (uint32_t) rtems_termios_baud_to_number( baud_requested );
+  _Assert( baud_number != 0 );
+
+  ulBaudDivisor = Z85C30_Baud(
+    (uint32_t) Console_Port_Tbl[minor]->ulClock,
+    baud_number
+  );
+
+  wr3 = SCC_WR3_RX_EN;
+  wr4 = SCC_WR4_16_CLOCK;
+  wr5 = SCC_WR5_TX_EN;
+
+  /*
+   *  Parity
+   */
+
+  if (t->c_cflag & PARENB) {
+    wr4 |= SCC_WR4_PAR_EN;
+    if (!(t->c_cflag & PARODD))
+      wr4 |= SCC_WR4_PAR_EVEN;
+  }
+
+  /*
+   *  Character Size
+   */
+
+  if (t->c_cflag & CSIZE) {
+    switch (t->c_cflag & CSIZE) {
+      case CS5:   break;
+      case CS6:  wr3 |= SCC_WR3_RX_6_BITS;  wr5 |= SCC_WR5_TX_6_BITS;  break;
+      case CS7:  wr3 |= SCC_WR3_RX_7_BITS;  wr5 |= SCC_WR5_TX_7_BITS;  break;
+      case CS8:  wr3 |= SCC_WR3_RX_8_BITS;  wr5 |= SCC_WR5_TX_8_BITS;  break;
+    }
+  } else {
+    wr3 |= SCC_WR3_RX_8_BITS;       /* default to 9600,8,N,1 */
+    wr5 |= SCC_WR5_TX_8_BITS;       /* default to 9600,8,N,1 */
+  }
+
+  /*
+   *  Stop Bits
+   */
+
+  if (t->c_cflag & CSTOPB) {
+    wr4 |= SCC_WR4_2_STOP;                      /* 2 stop bits */
+  } else {
+    wr4 |= SCC_WR4_1_STOP;                      /* 1 stop bits */
+  }
+
+  /*
+   *  Now actually set the chip
+   */
+
+  rtems_interrupt_disable(Irql);
+    (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR4, wr4 );
+    (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR3, wr3 );
+    (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR5, wr5 );
+
+    /*
+     * Setup the lower 8 bits time constants=1E.
+     * If the time constans=1E, then the desire
+     * baud rate will be equilvalent to 9600, via register 12.
+     */
+
+    (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR12, ulBaudDivisor & 0xff );
+
+    /*
+     * using register 13
+     * Setup the upper 8 bits time constant
+     */
+
+    (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR13, (ulBaudDivisor>>8) & 0xff );
+
+  rtems_interrupt_enable(Irql);
+
+  return 0;
+}
+
+/*
+ *  z85c30_process
+ *
+ *  This is the per port ISR handler.
+ */
+
+Z85C30_STATIC void z85c30_process(
+  int        minor,
+  uint8_t    ucIntPend
+)
+{
+  uint32_t            ulCtrlPort;
+  volatile uint8_t    z85c30_status;
+  char                cChar;
+  setRegister_f       setReg;
+  getRegister_f       getReg;
+
+  ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg     = Console_Port_Tbl[minor]->setRegister;
+  getReg     = Console_Port_Tbl[minor]->getRegister;
+
+  /*
+   * Deal with any received characters
+   */
+
+  while (ucIntPend&SCC_RR3_B_RX_IP)
+  {
+    z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
+    if (!Z85C30_Status_Is_RX_character_available(z85c30_status)) {
+      break;
+    }
+
+    /*
+     * Return the character read.
+     */
+
+    cChar = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD8);
+
+    rtems_termios_enqueue_raw_characters(
+      Console_Port_Data[minor].termios_data,
+      &cChar,
+      1
+    );
+  }
+
+  /*
+   *  There could be a race condition here if there is not yet a TX
+   *  interrupt pending but the buffer is empty.  This condition has
+   *  been seen before on other z8530 drivers but has not been seen
+   *  with this one.  The typical solution is to use "vector includes
+   *  status" or to only look at the interrupts actually pending
+   *  in RR3.
+   */
+
+  while (true) {
+    z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
+    if (!Z85C30_Status_Is_TX_buffer_empty(z85c30_status)) {
+      /*
+       * We'll get another interrupt when
+       * the transmitter holding reg. becomes
+       * free again and we are clear to send
+       */
+      break;
+    }
+
+#if 0
+    if (!Z85C30_Status_Is_CTS_asserted(z85c30_status)) {
+      /*
+       * We can't transmit yet
+       */
+      (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_TX_INT);
+      /*
+       * The next state change of CTS will wake us up
+       */
+      break;
+    }
+#endif
+
+    rtems_termios_dequeue_characters(Console_Port_Data[minor].termios_data, 1);
+    if (rtems_termios_dequeue_characters(
+         Console_Port_Data[minor].termios_data, 1)) {
+      if (Console_Port_Tbl[minor]->pDeviceFlow != &z85c30_flow_RTSCTS) {
+        z85c30_negate_RTS(minor);
+      }
+      Console_Port_Data[minor].bActive = FALSE;
+      z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR_EXCEPT_TX);
+      (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_TX_INT);
+      break;
+    }
+
+  }
+
+  if (ucIntPend & SCC_RR3_B_EXT_IP) {
+    /*
+     * Clear the external status interrupt
+     */
+    (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT);
+    z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
+  }
+
+  /*
+   * Reset interrupts
+   */
+  (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_HI_IUS);
+}
+
+/*
+ *  z85c30_isr
+ *
+ *  This is the ISR handler for each Z8530.
+ */
+
+Z85C30_STATIC rtems_isr z85c30_isr(
+  rtems_vector_number vector
+)
+{
+  int                 minor;
+  uint32_t            ulCtrlPort;
+  volatile uint8_t    ucIntPend;
+  volatile uint8_t    ucIntPendPort;
+  getRegister_f       getReg;
+
+  for (minor=0;minor<Console_Port_Count;minor++) {
+    if(Console_Port_Tbl[minor]->ulIntVector == vector &&
+       Console_Port_Tbl[minor]->deviceType == SERIAL_Z85C30 ) {
+      ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort2;
+      getReg     = Console_Port_Tbl[minor]->getRegister;
+      do {
+        ucIntPend = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD3);
+
+          /*
+           * If this is channel A select channel A status
+           */
+
+          if (ulCtrlPort == Console_Port_Tbl[minor]->ulCtrlPort1) {
+            ucIntPendPort = ucIntPend >> 3;
+            ucIntPendPort &= 7;
+          } else {
+            ucIntPendPort = ucIntPend &= 7;
+          }
+
+          if (ucIntPendPort) {
+            z85c30_process(minor, ucIntPendPort);
+          }
+      } while (ucIntPendPort);
+    }
+  }
+}
+
+/*
+ *  z85c30_enable_interrupts
+ *
+ *  This routine enables the specified interrupts for this minor.
+ */
+
+Z85C30_STATIC void z85c30_enable_interrupts(
+  int minor,
+  int interrupt_mask
+)
+{
+  uint32_t       ulCtrlPort;
+  setRegister_f  setReg;
+
+  ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg     = Console_Port_Tbl[minor]->setRegister;
+
+  (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR1, interrupt_mask);
+}
+
+/*
+ *  z85c30_initialize_interrupts
+ *
+ *  This routine initializes the port to use interrupts.
+ */
+
+Z85C30_STATIC void z85c30_initialize_interrupts(
+  int minor
+)
+{
+  uint32_t       ulCtrlPort1;
+  setRegister_f  setReg;
+
+  ulCtrlPort1 = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg      = Console_Port_Tbl[minor]->setRegister;
+
+
+  z85c30_init(minor);
+
+  Console_Port_Data[minor].bActive=FALSE;
+
+  z85c30_initialize_port( minor );
+
+  if (Console_Port_Tbl[minor]->pDeviceFlow != &z85c30_flow_RTSCTS) {
+    z85c30_negate_RTS(minor);
+  }
+
+#if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE)
+  set_vector(z85c30_isr, Console_Port_Tbl[minor]->ulIntVector, 1);
+#endif
+
+  z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR_EXCEPT_TX);
+
+  (*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR2, 0);              /* XXX vector */
+  (*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR9, SCC_WR9_MIE);
+
+  /*
+   * Reset interrupts
+   */
+
+  (*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT);
+}
+
+/*
+ *  z85c30_write_support_int
+ *
+ *  Console Termios output entry point.
+ *
+ */
+
+Z85C30_STATIC ssize_t z85c30_write_support_int(
+  int   minor,
+  const char *buf,
+  size_t len)
+{
+  uint32_t       Irql;
+  uint32_t       ulCtrlPort;
+  setRegister_f  setReg;
+
+  ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
+  setReg     = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   *  We are using interrupt driven output and termios only sends us
+   *  one character at a time.
+   */
+
+  if ( !len )
+    return 0;
+
+  /*
+   *  Put the character out and enable interrupts if necessary.
+   */
+
+  if (Console_Port_Tbl[minor]->pDeviceFlow != &z85c30_flow_RTSCTS) {
+    z85c30_assert_RTS(minor);
+  }
+  rtems_interrupt_disable(Irql);
+    if ( Console_Port_Data[minor].bActive == FALSE) {
+      Console_Port_Data[minor].bActive = TRUE;
+      z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR);
+    }
+    (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR8, *buf);
+  rtems_interrupt_enable(Irql);
+
+  return 0;
+}
+
+/*
+ *  z85c30_inbyte_nonblocking_polled
+ *
+ *  This routine polls for a character.
+ */
+
+Z85C30_STATIC int z85c30_inbyte_nonblocking_polled(
+  int  minor
+)
+{
+  volatile uint8_t    z85c30_status;
+  uint32_t            ulCtrlPort;
+  getRegister_f       getReg;
+
+  ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
+  getReg     = Console_Port_Tbl[minor]->getRegister;
+
+  /*
+   * return -1 if a character is not available.
+   */
+  z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
+  if (!Z85C30_Status_Is_RX_character_available(z85c30_status)) {
+    return -1;
+  }
+
+  /*
+   * Return the character read.
+   */
+
+  return (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD8);
+}
+
+/*
+ *  z85c30_write_support_polled
+ *
+ *  Console Termios output entry point.
+ *
+ */
+
+Z85C30_STATIC ssize_t z85c30_write_support_polled(
+  int   minor,
+  const char *buf,
+  size_t len)
+{
+  int nwrite=0;
+
+  /*
+   * poll each byte in the string out of the port.
+   */
+  while (nwrite < len) {
+    z85c30_write_polled(minor, *buf++);
+    nwrite++;
+  }
+
+  /*
+   * return the number of bytes written.
+   */
+  return nwrite;
+}
+
+/*
+ *  z85c30_write_polled
+ *
+ *  This routine transmits a character using polling.
+ */
+
+Z85C30_STATIC void z85c30_write_polled(
+  int   minor,
+  char  cChar
+)
+{
+  volatile uint8_t   z85c30_status;
+  uint32_t           ulCtrlPort;
+  getRegister_f      getReg;
+  setRegister_f      setReg;
+
+  ulCtrlPort = Console_Port_Tbl[minor]->ulCtrlPort1;
+  getReg     = Console_Port_Tbl[minor]->getRegister;
+  setReg     = Console_Port_Tbl[minor]->setRegister;
+
+  /*
+   * Wait for the Transmit buffer to indicate that it is empty.
+   */
+
+  z85c30_status = (*getReg)( ulCtrlPort, SCC_WR0_SEL_RD0 );
+
+  while (!Z85C30_Status_Is_TX_buffer_empty(z85c30_status)) {
+    /*
+     * Yield while we wait
+     */
+#if 0
+    if (_System_state_Is_up(_System_state_Get())) {
+      rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
+    }
+#endif
+    z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
+  }
+
+  /*
+   * Write the character.
+   */
+
+  (*setReg)( ulCtrlPort, SCC_WR0_SEL_WR8, cChar );
+}
Index: bsps/shared/dev/serial/z85c30_p.h
===================================================================
--- bsps/shared/dev/serial/z85c30_p.h	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/z85c30_p.h	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,420 @@
+/*
+ *  This include file contains all private driver definitions for the
+ *  Zilog z85c30.
+ *
+ *  COPYRIGHT (c) 1998 by Radstone Technology
+ *
+ *
+ * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
+ * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
+ *
+ * You are hereby granted permission to use, copy, modify, and distribute
+ * this file, provided that this notice, plus the above copyright notice
+ * and disclaimer, appears in all copies. Radstone Technology will provide
+ * no support for this code.
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may in
+ *  the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef __Z85C30_P_H
+#define __Z85C30_P_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ *  Define Z85C30_STATIC to nothing while debugging so the entry points
+ *  will show up in the symbol table.
+ */
+
+#define Z85C30_STATIC
+
+/* #define Z85C30_STATIC static */
+
+/* bit values for write register 0 */
+/* command register */
+
+#define SCC_WR0_SEL_WR0   0x00
+#define SCC_WR0_SEL_WR1   0x01
+#define SCC_WR0_SEL_WR2   0x02
+#define SCC_WR0_SEL_WR3   0x03
+#define SCC_WR0_SEL_WR4   0x04
+#define SCC_WR0_SEL_WR5   0x05
+#define SCC_WR0_SEL_WR6   0x06
+#define SCC_WR0_SEL_WR7   0x07
+#define SCC_WR0_SEL_WR8   0x08
+#define SCC_WR0_SEL_WR9   0x09
+#define SCC_WR0_SEL_WR10  0x0a
+#define SCC_WR0_SEL_WR11  0x0b
+#define SCC_WR0_SEL_WR12  0x0c
+#define SCC_WR0_SEL_WR13  0x0d
+#define SCC_WR0_SEL_WR14  0x0e
+#define SCC_WR0_SEL_WR15  0x0f
+#define SCC_WR0_SEL_RD0   0x00
+#define SCC_WR0_SEL_RD1   0x01
+#define SCC_WR0_SEL_RD2   0x02
+#define SCC_WR0_SEL_RD3   0x03
+#define SCC_WR0_SEL_RD4   0x04
+#define SCC_WR0_SEL_RD5   0x05
+#define SCC_WR0_SEL_RD6   0x06
+#define SCC_WR0_SEL_RD7   0x07
+#define SCC_WR0_SEL_RD8   0x08
+#define SCC_WR0_SEL_RD9   0x09
+#define SCC_WR0_SEL_RD10  0x0a
+#define SCC_WR0_SEL_RD11  0x0b
+#define SCC_WR0_SEL_RD12  0x0c
+#define SCC_WR0_SEL_RD13  0x0d
+#define SCC_WR0_SEL_RD14  0x0e
+#define SCC_WR0_SEL_RD15  0x0f
+#define SCC_WR0_NULL_CODE 0x00
+#define SCC_WR0_RST_INT   0x10
+#define SCC_WR0_SEND_ABORT  0x18
+#define SCC_WR0_EN_INT_RX 0x20
+#define SCC_WR0_RST_TX_INT  0x28
+#define SCC_WR0_ERR_RST   0x30
+#define SCC_WR0_RST_HI_IUS  0x38
+#define SCC_WR0_RST_RX_CRC  0x40
+#define SCC_WR0_RST_TX_CRC  0x80
+#define SCC_WR0_RST_TX_UND  0xc0
+
+/* write register 2 */
+/* interrupt vector */
+
+/* bit values for write register 1 */
+/* tx/rx interrupt and data transfer mode definition */
+
+#define SCC_WR1_EXT_INT_EN  0x01
+#define SCC_WR1_TX_INT_EN   0x02
+#define SCC_WR1_PARITY      0x04
+#define SCC_WR1_RX_INT_DIS  0x00
+#define SCC_WR1_RX_INT_FIR  0x08
+#define SCC_WR1_INT_ALL_RX  0x10
+#define SCC_WR1_RX_INT_SPE  0x18
+#define SCC_WR1_RDMA_RECTR  0x20
+#define SCC_WR1_RDMA_FUNC   0x40
+#define SCC_WR1_RDMA_EN     0x80
+
+#define SCC_ENABLE_ALL_INTR \
+    (SCC_WR1_EXT_INT_EN | SCC_WR1_TX_INT_EN | SCC_WR1_INT_ALL_RX)
+
+#define SCC_DISABLE_ALL_INTR 0x00
+
+#define SCC_ENABLE_ALL_INTR_EXCEPT_TX \
+    (SCC_WR1_EXT_INT_EN | SCC_WR1_INT_ALL_RX)
+
+/* bit values for write register 3 */
+/* receive parameters and control */
+
+#define SCC_WR3_RX_EN   0x01
+#define SCC_WR3_SYNC_CHAR 0x02
+#define SCC_WR3_ADR_SEARCH  0x04
+#define SCC_WR3_RX_CRC_EN 0x08
+#define SCC_WR3_ENTER_HUNT  0x10
+#define SCC_WR3_AUTO_EN   0x20
+#define SCC_WR3_RX_5_BITS 0x00
+#define SCC_WR3_RX_7_BITS 0x40
+#define SCC_WR3_RX_6_BITS 0x80
+#define SCC_WR3_RX_8_BITS 0xc0
+
+/* bit values for write register 4 */
+/* tx/rx misc parameters and modes */
+
+#define SCC_WR4_PAR_EN    0x01
+#define SCC_WR4_PAR_EVEN  0x02
+#define SCC_WR4_SYNC_EN   0x00
+#define SCC_WR4_1_STOP    0x04
+#define SCC_WR4_2_STOP    0x0c
+#define SCC_WR4_8_SYNC    0x00
+#define SCC_WR4_16_SYNC   0x10
+#define SCC_WR4_SDLC    0x20
+#define SCC_WR4_EXT_SYNC  0x30
+#define SCC_WR4_1_CLOCK   0x00
+#define SCC_WR4_16_CLOCK  0x40
+#define SCC_WR4_32_CLOCK  0x80
+#define SCC_WR4_64_CLOCK  0xc0
+
+/* bit values for write register 5 */
+/* transmit parameter and controls */
+
+#define SCC_WR5_TX_CRC_EN 0x01
+#define SCC_WR5_RTS   0x02
+#define SCC_WR5_SDLC    0x04
+#define SCC_WR5_TX_EN   0x08
+#define SCC_WR5_SEND_BRK  0x10
+
+#define SCC_WR5_TX_5_BITS 0x00
+#define SCC_WR5_TX_7_BITS 0x20
+#define SCC_WR5_TX_6_BITS 0x40
+#define SCC_WR5_TX_8_BITS 0x60
+#define SCC_WR5_DTR   0x80
+
+/* write register 6 */
+/* sync chars or sdlc address field */
+
+/* write register 7 */
+/* sync char or sdlc flag */
+
+/* write register 8 */
+/* transmit buffer */
+
+/* bit values for write register 9 */
+/* master interrupt control */
+
+#define SCC_WR9_VIS   0x01
+#define SCC_WR9_NV    0x02
+#define SCC_WR9_DLC   0x04
+#define SCC_WR9_MIE   0x08
+#define SCC_WR9_STATUS_HI 0x10
+#define SCC_WR9_NO_RST    0x00
+#define SCC_WR9_CH_B_RST  0x40
+#define SCC_WR9_CH_A_RST  0x80
+#define SCC_WR9_HDWR_RST  0xc0
+
+/* bit values for write register 10 */
+/* misc tx/rx control bits */
+
+#define SCC_WR10_6_BIT_SYNC 0x01
+#define SCC_WR10_LOOP_MODE  0x02
+#define SCC_WR10_ABORT_UND  0x04
+#define SCC_WR10_MARK_IDLE  0x08
+#define SCC_WR10_ACT_POLL 0x10
+#define SCC_WR10_NRZ    0x00
+#define SCC_WR10_NRZI   0x20
+#define SCC_WR10_FM1    0x40
+#define SCC_WR10_FM0    0x60
+#define SCC_WR10_CRC_PRESET 0x80
+
+/* bit values for write register 11 */
+/* clock mode control */
+
+#define SCC_WR11_OUT_XTAL 0x00
+#define SCC_WR11_OUT_TX_CLK 0x01
+#define SCC_WR11_OUT_BR_GEN 0x02
+#define SCC_WR11_OUT_DPLL 0x03
+#define SCC_WR11_TRXC_OI  0x04
+#define SCC_WR11_TX_RTXC  0x00
+#define SCC_WR11_TX_TRXC  0x08
+#define SCC_WR11_TX_BR_GEN  0x10
+#define SCC_WR11_TX_DPLL  0x18
+#define SCC_WR11_RX_RTXC  0x00
+#define SCC_WR11_RX_TRXC  0x20
+#define SCC_WR11_RX_BR_GEN  0x40
+#define SCC_WR11_RX_DPLL  0x60
+#define SCC_WR11_RTXC_XTAL  0x80
+
+/* write register 12 */
+/* lower byte of baud rate generator time constant */
+
+/* write register 13 */
+/* upper byte of baud rate generator time constant */
+
+/* bit values for write register 14 */
+/* misc control bits */
+
+#define SCC_WR14_BR_EN    0x01
+#define SCC_WR14_BR_SRC   0x02
+#define SCC_WR14_DTR_FUNC 0x04
+#define SCC_WR14_AUTO_ECHO  0x08
+#define SCC_WR14_LCL_LOOP 0x10
+#define SCC_WR14_NULL   0x00
+#define SCC_WR14_SEARCH   0x20
+#define SCC_WR14_RST_CLK  0x40
+#define SCC_WR14_DIS_DPLL 0x60
+#define SCC_WR14_SRC_BR   0x80
+#define SCC_WR14_SRC_RTXC 0xa0
+#define SCC_WR14_FM_MODE  0xc0
+#define SCC_WR14_NRZI   0xe0
+
+/* bit values for write register 15 */
+/* external/status interrupt control */
+
+#define SCC_WR15_ZERO_CNT 0x02
+#define SCC_WR15_CD_IE    0x08
+#define SCC_WR15_SYNC_IE  0x10
+#define SCC_WR15_CTS_IE   0x20
+#define SCC_WR15_TX_UND_IE  0x40
+#define SCC_WR15_BREAK_IE 0x80
+
+/* bit values for read register 0 */
+/* tx/rx buffer status and external status  */
+
+#define SCC_RR0_RX_AVAIL  0x01
+#define SCC_RR0_ZERO_CNT  0x02
+#define SCC_RR0_TX_EMPTY  0x04
+#define SCC_RR0_CD    0x08
+#define SCC_RR0_SYNC    0x10
+#define SCC_RR0_CTS   0x20
+#define SCC_RR0_TX_UND    0x40
+#define SCC_RR0_BREAK   0x80
+
+/* bit values for read register 1 */
+
+#define SCC_RR1_ALL_SENT  0x01
+#define SCC_RR1_RES_CD_2  0x02
+#define SCC_RR1_RES_CD_1  0x01
+#define SCC_RR1_RES_CD_0  0x08
+#define SCC_RR1_PAR_ERR   0x10
+#define SCC_RR1_RX_OV_ERR 0x20
+#define SCC_RR1_CRC_ERR   0x40
+#define SCC_RR1_END_FRAME 0x80
+
+/* read register 2 */
+/* interrupt vector */
+
+/* bit values for read register 3 */
+/* interrupt pending register */
+
+#define SCC_RR3_B_EXT_IP  0x01
+#define SCC_RR3_B_TX_IP   0x02
+#define SCC_RR3_B_RX_IP   0x04
+#define SCC_RR3_A_EXT_IP  0x08
+#define SCC_RR3_A_TX_IP   0x10
+#define SCC_RR3_A_RX_IP   0x20
+
+/* read register 8 */
+/* receive data register */
+
+/* bit values for read register 10 */
+/* misc status bits */
+
+#define SCC_RR10_ON_LOOP  0x02
+#define SCC_RR10_LOOP_SEND  0x10
+#define SCC_RR10_2_CLK_MIS  0x40
+#define SCC_RR10_1_CLK_MIS  0x80
+
+/* read register 12 */
+/* lower byte of time constant */
+
+/* read register 13 */
+/* upper byte of time constant */
+
+/* bit values for read register 15 */
+/* external/status ie bits */
+
+#define SCC_RR15_ZERO_CNT 0x02
+#define SCC_RR15_CD_IE    0x08
+#define SCC_RR15_SYNC_IE  0x10
+#define SCC_RR15_CTS_IE   0x20
+#define SCC_RR15_TX_UND_IE  0x40
+#define SCC_RR15_BREAK_IE 0x80
+
+typedef struct _z85c30_context
+{
+  uint8_t   ucModemCtrl;
+} z85c30_context;
+
+/*
+ * The following macro calculates the Baud constant. For the Z85C30 chip.
+ *
+ * Note: baud constant = ((clock frequency / Clock_X) / (2 * Baud Rate)) - 2
+ *       eg ((10,000,000 / 16) / (2 * Baud Rate)) - 2
+ */
+
+#define Z85C30_Baud( _clock, _baud_rate  )   \
+  ( ((_clock) /(  16 * 2 * _baud_rate))  - 2)
+
+#define Z85C30_Status_Is_RX_character_available(_status) \
+  ((_status) & SCC_RR0_RX_AVAIL)
+
+#define Z85C30_Status_Is_TX_buffer_empty(_status) \
+  ((_status) & SCC_RR0_TX_EMPTY)
+
+#define Z85C30_Status_Is_CTS_asserted(_status) \
+  ((_status) & SCC_RR0_CTS)
+
+#define Z85C30_Status_Is_break_abort(_status) \
+  ((_status) & SCC_RR0_BREAK)
+
+/*
+ * Private routines
+ */
+
+Z85C30_STATIC void z85c30_initialize_port(
+  int minor
+);
+
+Z85C30_STATIC void z85c30_init(int minor);
+
+Z85C30_STATIC int z85c30_set_attributes(
+  int                   minor,
+  const struct termios *t
+);
+
+Z85C30_STATIC int z85c30_open(
+  int major,
+  int minor,
+  void  * arg
+);
+
+Z85C30_STATIC int z85c30_close(
+  int major,
+  int minor,
+  void  * arg
+);
+
+Z85C30_STATIC void z85c30_write_polled(
+  int   minor,
+  char  cChar
+);
+
+Z85C30_STATIC int z85c30_assert_RTS(
+  int minor
+);
+
+Z85C30_STATIC int z85c30_negate_RTS(
+  int minor
+);
+
+Z85C30_STATIC int z85c30_assert_DTR(
+  int minor
+);
+
+Z85C30_STATIC int z85c30_negate_DTR(
+  int minor
+);
+
+Z85C30_STATIC void z85c30_initialize_interrupts(int minor);
+
+Z85C30_STATIC ssize_t z85c30_write_support_int(
+  int   minor,
+  const char *buf,
+  size_t len
+);
+
+Z85C30_STATIC ssize_t z85c30_write_support_polled(
+  int   minor,
+  const char *buf,
+  size_t len
+);
+
+Z85C30_STATIC int z85c30_inbyte_nonblocking_polled(
+  int minor
+);
+
+Z85C30_STATIC void z85c30_enable_interrupts(
+  int minor,
+  int interrupt_mask
+);
+
+Z85C30_STATIC void z85c30_process(
+  int        minor,
+  uint8_t    ucIntPend
+);
+
+Z85C30_STATIC rtems_isr z85c30_isr(
+  rtems_vector_number vector
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: bsps/shared/dev/serial/z85c30_reg.c
===================================================================
--- bsps/shared/dev/serial/z85c30_reg.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
+++ bsps/shared/dev/serial/z85c30_reg.c	(revision 27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a)
@@ -0,0 +1,72 @@
+/*
+ *  This file contains a typical set of register access routines which may be
+ *  used with the z85c30 chip if accesses to the chip are as follows:
+ *
+ *    + registers are accessed as bytes
+ *
+ *  COPYRIGHT (c) 1989-1997.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+
+#include <libchip/z85c30.h>
+
+#ifndef _Z85C30_MULTIPLIER
+#define _Z85C30_MULTIPLIER 1
+#define _Z85C30_NAME(_X) _X
+#define _Z85C30_TYPE uint8_t
+#endif
+
+/*
+ *  Z85C30 Get Register Routine
+ */
+
+uint8_t   _Z85C30_NAME(z85c30_get_register)(
+  uintptr_t   ulCtrlPort,
+  uint8_t     ucRegNum
+)
+{
+  _Z85C30_TYPE          *port;
+  uint8_t                data;
+  rtems_interrupt_level  level;
+
+  port = (_Z85C30_TYPE *)ulCtrlPort;
+
+  rtems_interrupt_disable(level);
+
+    if(ucRegNum) {
+      *port = ucRegNum;
+    }
+    data = *port;
+  rtems_interrupt_enable(level);
+
+  return data;
+}
+
+/*
+ *  Z85C30 Set Register Routine
+ */
+
+void _Z85C30_NAME(z85c30_set_register)(
+  uintptr_t   ulCtrlPort,
+  uint8_t     ucRegNum,
+  uint8_t     ucData
+)
+{
+  _Z85C30_TYPE          *port;
+  rtems_interrupt_level  level;
+
+  port = (_Z85C30_TYPE *)ulCtrlPort;
+
+  rtems_interrupt_disable(level);
+    if(ucRegNum) {
+      *port = ucRegNum;
+    }
+    *port = ucData;
+  rtems_interrupt_enable(level);
+}
