summaryrefslogtreecommitdiffstats
path: root/bsps/shared/dev
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-03 07:20:11 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-04 10:13:28 +0200
commit27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a (patch)
treedef0664dcddc53fd5d599b455c64f76ca2293606 /bsps/shared/dev
parentbsps: Move config macros to RTEMS_BSP_CONFIGURE (diff)
downloadrtems-27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a.tar.bz2
bsps: Move libchip to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/shared/dev')
-rw-r--r--bsps/shared/dev/display/disp_fonts.h55
-rw-r--r--bsps/shared/dev/display/disp_hcms29xx.c932
-rw-r--r--bsps/shared/dev/display/font_hcms29xx.c1820
-rw-r--r--bsps/shared/dev/display/font_hcms29xx.h36
-rw-r--r--bsps/shared/dev/flash/am29lv160.c473
-rw-r--r--bsps/shared/dev/i2c/i2c-2b-eeprom.c177
-rw-r--r--bsps/shared/dev/i2c/i2c-ds1621.c128
-rw-r--r--bsps/shared/dev/i2c/i2c-sc620.c91
-rw-r--r--bsps/shared/dev/i2c/spi-flash-m25p40.c60
-rw-r--r--bsps/shared/dev/i2c/spi-fram-fm25l256.c60
-rw-r--r--bsps/shared/dev/i2c/spi-memdrv.c442
-rw-r--r--bsps/shared/dev/i2c/spi-sd-card.c1322
-rw-r--r--bsps/shared/dev/ide/ata.c1360
-rw-r--r--bsps/shared/dev/ide/ata_util.c215
-rw-r--r--bsps/shared/dev/ide/ide_controller.c200
-rw-r--r--bsps/shared/dev/rtc/README.ds16433
-rw-r--r--bsps/shared/dev/rtc/README.icm717048
-rw-r--r--bsps/shared/dev/rtc/README.m48t0844
-rw-r--r--bsps/shared/dev/rtc/README.m48t181
-rw-r--r--bsps/shared/dev/rtc/README.mc146818a1
-rw-r--r--bsps/shared/dev/rtc/STATUS33
-rw-r--r--bsps/shared/dev/rtc/ds1375.c461
-rw-r--r--bsps/shared/dev/rtc/icm7170.c168
-rw-r--r--bsps/shared/dev/rtc/icm7170_reg.c60
-rw-r--r--bsps/shared/dev/rtc/icm7170_reg2.c20
-rw-r--r--bsps/shared/dev/rtc/icm7170_reg4.c20
-rw-r--r--bsps/shared/dev/rtc/icm7170_reg8.c20
-rw-r--r--bsps/shared/dev/rtc/m48t08.c161
-rw-r--r--bsps/shared/dev/rtc/m48t08_reg.c60
-rw-r--r--bsps/shared/dev/rtc/m48t08_reg2.c20
-rw-r--r--bsps/shared/dev/rtc/m48t08_reg4.c20
-rw-r--r--bsps/shared/dev/rtc/m48t08_reg8.c20
-rw-r--r--bsps/shared/dev/rtc/mc146818a.c180
-rw-r--r--bsps/shared/dev/rtc/mc146818a_ioreg.c56
-rw-r--r--bsps/shared/dev/rtc/rtcprobe.c21
-rw-r--r--bsps/shared/dev/serial/README13
-rw-r--r--bsps/shared/dev/serial/README.mc6868183
-rw-r--r--bsps/shared/dev/serial/README.ns1655082
-rw-r--r--bsps/shared/dev/serial/README.xr886812
-rw-r--r--bsps/shared/dev/serial/README.z85c3074
-rw-r--r--bsps/shared/dev/serial/STATUS48
-rw-r--r--bsps/shared/dev/serial/mc68681.c776
-rw-r--r--bsps/shared/dev/serial/mc68681_baud.c124
-rw-r--r--bsps/shared/dev/serial/mc68681_p.h323
-rw-r--r--bsps/shared/dev/serial/mc68681_reg.c61
-rw-r--r--bsps/shared/dev/serial/mc68681_reg2.c20
-rw-r--r--bsps/shared/dev/serial/mc68681_reg4.c20
-rw-r--r--bsps/shared/dev/serial/mc68681_reg8.c20
-rw-r--r--bsps/shared/dev/serial/ns16550-context.c814
-rw-r--r--bsps/shared/dev/serial/ns16550.c875
-rw-r--r--bsps/shared/dev/serial/serprobe.c13
-rw-r--r--bsps/shared/dev/serial/z85c30.c893
-rw-r--r--bsps/shared/dev/serial/z85c30_p.h420
-rw-r--r--bsps/shared/dev/serial/z85c30_reg.c72
54 files changed, 13521 insertions, 0 deletions
diff --git a/bsps/shared/dev/display/disp_fonts.h b/bsps/shared/dev/display/disp_fonts.h
new file mode 100644
index 0000000000..39e909390a
--- /dev/null
+++ b/bsps/shared/dev/display/disp_fonts.h
@@ -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 */
diff --git a/bsps/shared/dev/display/disp_hcms29xx.c b/bsps/shared/dev/display/disp_hcms29xx.c
new file mode 100644
index 0000000000..5730b36ea9
--- /dev/null
+++ b/bsps/shared/dev/display/disp_hcms29xx.c
@@ -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;
+
diff --git a/bsps/shared/dev/display/font_hcms29xx.c b/bsps/shared/dev/display/font_hcms29xx.c
new file mode 100644
index 0000000000..e25cca2eca
--- /dev/null
+++ b/bsps/shared/dev/display/font_hcms29xx.c
@@ -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}
+};
diff --git a/bsps/shared/dev/display/font_hcms29xx.h b/bsps/shared/dev/display/font_hcms29xx.h
new file mode 100644
index 0000000000..8638fcf600
--- /dev/null
+++ b/bsps/shared/dev/display/font_hcms29xx.h
@@ -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 */
diff --git a/bsps/shared/dev/flash/am29lv160.c b/bsps/shared/dev/flash/am29lv160.c
new file mode 100644
index 0000000000..5cfaae4f24
--- /dev/null
+++ b/bsps/shared/dev/flash/am29lv160.c
@@ -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
+};
diff --git a/bsps/shared/dev/i2c/i2c-2b-eeprom.c b/bsps/shared/dev/i2c/i2c-2b-eeprom.c
new file mode 100644
index 0000000000..4a8b5fdb9c
--- /dev/null
+++ b/bsps/shared/dev/i2c/i2c-2b-eeprom.c
@@ -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;
diff --git a/bsps/shared/dev/i2c/i2c-ds1621.c b/bsps/shared/dev/i2c/i2c-ds1621.c
new file mode 100644
index 0000000000..51f64de679
--- /dev/null
+++ b/bsps/shared/dev/i2c/i2c-ds1621.c
@@ -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;
diff --git a/bsps/shared/dev/i2c/i2c-sc620.c b/bsps/shared/dev/i2c/i2c-sc620.c
new file mode 100644
index 0000000000..7b30ae56af
--- /dev/null
+++ b/bsps/shared/dev/i2c/i2c-sc620.c
@@ -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)
+};
diff --git a/bsps/shared/dev/i2c/spi-flash-m25p40.c b/bsps/shared/dev/i2c/spi-flash-m25p40.c
new file mode 100644
index 0000000000..075a4510b9
--- /dev/null
+++ b/bsps/shared/dev/i2c/spi-flash-m25p40.c
@@ -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;
diff --git a/bsps/shared/dev/i2c/spi-fram-fm25l256.c b/bsps/shared/dev/i2c/spi-fram-fm25l256.c
new file mode 100644
index 0000000000..086feb82bb
--- /dev/null
+++ b/bsps/shared/dev/i2c/spi-fram-fm25l256.c
@@ -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;
diff --git a/bsps/shared/dev/i2c/spi-memdrv.c b/bsps/shared/dev/i2c/spi-memdrv.c
new file mode 100644
index 0000000000..593029732e
--- /dev/null
+++ b/bsps/shared/dev/i2c/spi-memdrv.c
@@ -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,
+};
+
diff --git a/bsps/shared/dev/i2c/spi-sd-card.c b/bsps/shared/dev/i2c/spi-sd-card.c
new file mode 100644
index 0000000000..a343f7faa8
--- /dev/null
+++ b/bsps/shared/dev/i2c/spi-sd-card.c
@@ -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;
+}
diff --git a/bsps/shared/dev/ide/ata.c b/bsps/shared/dev/ide/ata.c
new file mode 100644
index 0000000000..7bb3f6ec73
--- /dev/null
+++ b/bsps/shared/dev/ide/ata.c
@@ -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;
+}
diff --git a/bsps/shared/dev/ide/ata_util.c b/bsps/shared/dev/ide/ata_util.c
new file mode 100644
index 0000000000..68e0f0bbe5
--- /dev/null
+++ b/bsps/shared/dev/ide/ata_util.c
@@ -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;
+}
diff --git a/bsps/shared/dev/ide/ide_controller.c b/bsps/shared/dev/ide/ide_controller.c
new file mode 100644
index 0000000000..912f9e3157
--- /dev/null
+++ b/bsps/shared/dev/ide/ide_controller.c
@@ -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);
+}
diff --git a/bsps/shared/dev/rtc/README.ds1643 b/bsps/shared/dev/rtc/README.ds1643
new file mode 100644
index 0000000000..a3a38605c8
--- /dev/null
+++ b/bsps/shared/dev/rtc/README.ds1643
@@ -0,0 +1,3 @@
+The Mostek M48T08 is compatible with the Dallas Semiconductor DS1643. Please
+use that driver.
+
diff --git a/bsps/shared/dev/rtc/README.icm7170 b/bsps/shared/dev/rtc/README.icm7170
new file mode 100644
index 0000000000..d4ecff570f
--- /dev/null
+++ b/bsps/shared/dev/rtc/README.icm7170
@@ -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.
+
diff --git a/bsps/shared/dev/rtc/README.m48t08 b/bsps/shared/dev/rtc/README.m48t08
new file mode 100644
index 0000000000..25c032e85e
--- /dev/null
+++ b/bsps/shared/dev/rtc/README.m48t08
@@ -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.
+
diff --git a/bsps/shared/dev/rtc/README.m48t18 b/bsps/shared/dev/rtc/README.m48t18
new file mode 100644
index 0000000000..0925c62115
--- /dev/null
+++ b/bsps/shared/dev/rtc/README.m48t18
@@ -0,0 +1 @@
+This is supported by the m48t08 driver.
diff --git a/bsps/shared/dev/rtc/README.mc146818a b/bsps/shared/dev/rtc/README.mc146818a
new file mode 100644
index 0000000000..e9a9c86447
--- /dev/null
+++ b/bsps/shared/dev/rtc/README.mc146818a
@@ -0,0 +1 @@
+This is supported by the mc146818a driver.
diff --git a/bsps/shared/dev/rtc/STATUS b/bsps/shared/dev/rtc/STATUS
new file mode 100644
index 0000000000..a6d5c41cd5
--- /dev/null
+++ b/bsps/shared/dev/rtc/STATUS
@@ -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.
+
diff --git a/bsps/shared/dev/rtc/ds1375.c b/bsps/shared/dev/rtc/ds1375.c
new file mode 100644
index 0000000000..4a23a0044b
--- /dev/null
+++ b/bsps/shared/dev/rtc/ds1375.c
@@ -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,
+};
diff --git a/bsps/shared/dev/rtc/icm7170.c b/bsps/shared/dev/rtc/icm7170.c
new file mode 100644
index 0000000000..1cc9e980f7
--- /dev/null
+++ b/bsps/shared/dev/rtc/icm7170.c
@@ -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
+};
diff --git a/bsps/shared/dev/rtc/icm7170_reg.c b/bsps/shared/dev/rtc/icm7170_reg.c
new file mode 100644
index 0000000000..747f1f218d
--- /dev/null
+++ b/bsps/shared/dev/rtc/icm7170_reg.c
@@ -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;
+}
diff --git a/bsps/shared/dev/rtc/icm7170_reg2.c b/bsps/shared/dev/rtc/icm7170_reg2.c
new file mode 100644
index 0000000000..179d76c6f5
--- /dev/null
+++ b/bsps/shared/dev/rtc/icm7170_reg2.c
@@ -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"
diff --git a/bsps/shared/dev/rtc/icm7170_reg4.c b/bsps/shared/dev/rtc/icm7170_reg4.c
new file mode 100644
index 0000000000..dada40961c
--- /dev/null
+++ b/bsps/shared/dev/rtc/icm7170_reg4.c
@@ -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"
diff --git a/bsps/shared/dev/rtc/icm7170_reg8.c b/bsps/shared/dev/rtc/icm7170_reg8.c
new file mode 100644
index 0000000000..a1fb1a5ea2
--- /dev/null
+++ b/bsps/shared/dev/rtc/icm7170_reg8.c
@@ -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"
diff --git a/bsps/shared/dev/rtc/m48t08.c b/bsps/shared/dev/rtc/m48t08.c
new file mode 100644
index 0000000000..3b600bd995
--- /dev/null
+++ b/bsps/shared/dev/rtc/m48t08.c
@@ -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
+};
diff --git a/bsps/shared/dev/rtc/m48t08_reg.c b/bsps/shared/dev/rtc/m48t08_reg.c
new file mode 100644
index 0000000000..2174496fda
--- /dev/null
+++ b/bsps/shared/dev/rtc/m48t08_reg.c
@@ -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;
+}
diff --git a/bsps/shared/dev/rtc/m48t08_reg2.c b/bsps/shared/dev/rtc/m48t08_reg2.c
new file mode 100644
index 0000000000..87d2041946
--- /dev/null
+++ b/bsps/shared/dev/rtc/m48t08_reg2.c
@@ -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"
diff --git a/bsps/shared/dev/rtc/m48t08_reg4.c b/bsps/shared/dev/rtc/m48t08_reg4.c
new file mode 100644
index 0000000000..2203249503
--- /dev/null
+++ b/bsps/shared/dev/rtc/m48t08_reg4.c
@@ -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"
diff --git a/bsps/shared/dev/rtc/m48t08_reg8.c b/bsps/shared/dev/rtc/m48t08_reg8.c
new file mode 100644
index 0000000000..83044d752b
--- /dev/null
+++ b/bsps/shared/dev/rtc/m48t08_reg8.c
@@ -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"
diff --git a/bsps/shared/dev/rtc/mc146818a.c b/bsps/shared/dev/rtc/mc146818a.c
new file mode 100644
index 0000000000..2720ce5e8a
--- /dev/null
+++ b/bsps/shared/dev/rtc/mc146818a.c
@@ -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
+};
diff --git a/bsps/shared/dev/rtc/mc146818a_ioreg.c b/bsps/shared/dev/rtc/mc146818a_ioreg.c
new file mode 100644
index 0000000000..4c438a516a
--- /dev/null
+++ b/bsps/shared/dev/rtc/mc146818a_ioreg.c
@@ -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
diff --git a/bsps/shared/dev/rtc/rtcprobe.c b/bsps/shared/dev/rtc/rtcprobe.c
new file mode 100644
index 0000000000..71472ffd7c
--- /dev/null
+++ b/bsps/shared/dev/rtc/rtcprobe.c
@@ -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;
+}
diff --git a/bsps/shared/dev/serial/README b/bsps/shared/dev/serial/README
new file mode 100644
index 0000000000..59bb9e90fa
--- /dev/null
+++ b/bsps/shared/dev/serial/README
@@ -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.
+
diff --git a/bsps/shared/dev/serial/README.mc68681 b/bsps/shared/dev/serial/README.mc68681
new file mode 100644
index 0000000000..e0966d0e10
--- /dev/null
+++ b/bsps/shared/dev/serial/README.mc68681
@@ -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.
+
diff --git a/bsps/shared/dev/serial/README.ns16550 b/bsps/shared/dev/serial/README.ns16550
new file mode 100644
index 0000000000..a0c31b5506
--- /dev/null
+++ b/bsps/shared/dev/serial/README.ns16550
@@ -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.
+
diff --git a/bsps/shared/dev/serial/README.xr88681 b/bsps/shared/dev/serial/README.xr88681
new file mode 100644
index 0000000000..89b661143f
--- /dev/null
+++ b/bsps/shared/dev/serial/README.xr88681
@@ -0,0 +1,2 @@
+The Exar XR88681 is an enhanced version of the Motorola MC68681 and is
+supported by the mc68681 driver.
diff --git a/bsps/shared/dev/serial/README.z85c30 b/bsps/shared/dev/serial/README.z85c30
new file mode 100644
index 0000000000..f6e0b8cb11
--- /dev/null
+++ b/bsps/shared/dev/serial/README.z85c30
@@ -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.
+
diff --git a/bsps/shared/dev/serial/STATUS b/bsps/shared/dev/serial/STATUS
new file mode 100644
index 0000000000..243b1a9de5
--- /dev/null
+++ b/bsps/shared/dev/serial/STATUS
@@ -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.
+
diff --git a/bsps/shared/dev/serial/mc68681.c b/bsps/shared/dev/serial/mc68681.c
new file mode 100644
index 0000000000..f4ddbd6a50
--- /dev/null
+++ b/bsps/shared/dev/serial/mc68681.c
@@ -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)
+ );
+}
diff --git a/bsps/shared/dev/serial/mc68681_baud.c b/bsps/shared/dev/serial/mc68681_baud.c
new file mode 100644
index 0000000000..0f8e87c2c2
--- /dev/null
+++ b/bsps/shared/dev/serial/mc68681_baud.c
@@ -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 */
+ },
+};
diff --git a/bsps/shared/dev/serial/mc68681_p.h b/bsps/shared/dev/serial/mc68681_p.h
new file mode 100644
index 0000000000..4623276303
--- /dev/null
+++ b/bsps/shared/dev/serial/mc68681_p.h
@@ -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_ */
diff --git a/bsps/shared/dev/serial/mc68681_reg.c b/bsps/shared/dev/serial/mc68681_reg.c
new file mode 100644
index 0000000000..fb92b8fcd3
--- /dev/null
+++ b/bsps/shared/dev/serial/mc68681_reg.c
@@ -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;
+}
diff --git a/bsps/shared/dev/serial/mc68681_reg2.c b/bsps/shared/dev/serial/mc68681_reg2.c
new file mode 100644
index 0000000000..0e0121eb40
--- /dev/null
+++ b/bsps/shared/dev/serial/mc68681_reg2.c
@@ -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"
diff --git a/bsps/shared/dev/serial/mc68681_reg4.c b/bsps/shared/dev/serial/mc68681_reg4.c
new file mode 100644
index 0000000000..e9dd94ce4b
--- /dev/null
+++ b/bsps/shared/dev/serial/mc68681_reg4.c
@@ -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"
diff --git a/bsps/shared/dev/serial/mc68681_reg8.c b/bsps/shared/dev/serial/mc68681_reg8.c
new file mode 100644
index 0000000000..402c2ffe1b
--- /dev/null
+++ b/bsps/shared/dev/serial/mc68681_reg8.c
@@ -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"
diff --git a/bsps/shared/dev/serial/ns16550-context.c b/bsps/shared/dev/serial/ns16550-context.c
new file mode 100644
index 0000000000..b42be96a26
--- /dev/null
+++ b/bsps/shared/dev/serial/ns16550-context.c
@@ -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
+};
diff --git a/bsps/shared/dev/serial/ns16550.c b/bsps/shared/dev/serial/ns16550.c
new file mode 100644
index 0000000000..b1e5892c15
--- /dev/null
+++ b/bsps/shared/dev/serial/ns16550.c
@@ -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 );
+}
diff --git a/bsps/shared/dev/serial/serprobe.c b/bsps/shared/dev/serial/serprobe.c
new file mode 100644
index 0000000000..7f8d392452
--- /dev/null
+++ b/bsps/shared/dev/serial/serprobe.c
@@ -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;
+}
diff --git a/bsps/shared/dev/serial/z85c30.c b/bsps/shared/dev/serial/z85c30.c
new file mode 100644
index 0000000000..55df9d3451
--- /dev/null
+++ b/bsps/shared/dev/serial/z85c30.c
@@ -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 );
+}
diff --git a/bsps/shared/dev/serial/z85c30_p.h b/bsps/shared/dev/serial/z85c30_p.h
new file mode 100644
index 0000000000..af2ed6507c
--- /dev/null
+++ b/bsps/shared/dev/serial/z85c30_p.h
@@ -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
diff --git a/bsps/shared/dev/serial/z85c30_reg.c b/bsps/shared/dev/serial/z85c30_reg.c
new file mode 100644
index 0000000000..6e7b5d3494
--- /dev/null
+++ b/bsps/shared/dev/serial/z85c30_reg.c
@@ -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);
+}