[PATCH 023/111] LEON: added new drivers to the LEON2/LEON3 BSPs

Daniel Hellstrom daniel at gaisler.com
Thu Feb 26 16:38:25 UTC 2015


Most drivers use the Driver Manager for device probing, they
work on AMBA-over-PCI systems if PCI is big-endian.

New APIs:
 * GPIO Library, interfaced to GRGPIO
 * GENIRQ, Generic interrupt service implementation helper

New GRLIB Drivers:
 * ACTEL 1553 RT, user interface is similar to 1553 BRM driver
 * GR1553 (1553 BC, RT and BM core)
 * AHBSTAT (AHB error status core)
 * GRADCDAC (Core interfacing to ADC/DAC hardware)
 * GRGPIO (GPIO port accessed from GPIO Library)
 * MCTRL (Memory controller settings configuration)
 * GRETH (10/100/1000 Ethernet driver using Driver manager)
 * GRPWM (Pulse Width Modulation core)
 * SPICTRL (SPI master interface)
 * GRSPW_ROUTER (SpaceWire Router AMBA configuration interface)
 * GRCTM (SpaceCraft on-board Time Management core)
 * SPWCUC (Time distribution over SpaceWire)
 * GRTC (SpaceCraft up-link Tele core)
 * GRTM (SpaceCraft down-link Tele Metry core)

GR712RC ASIC specific interfaces:
 * GRASCS
 * CANMUX (select between OCCAN and SATCAN)
 * SATCAN
 * SLINK
---
 c/src/lib/libbsp/sparc/Makefile.am                 |   65 +-
 c/src/lib/libbsp/sparc/leon2/Makefile.am           |   61 +
 c/src/lib/libbsp/sparc/leon2/include/bsp.h         |    1 +
 c/src/lib/libbsp/sparc/leon2/preinstall.am         |   77 +
 c/src/lib/libbsp/sparc/leon3/Makefile.am           |   66 +-
 c/src/lib/libbsp/sparc/leon3/include/bsp.h         |    1 +
 c/src/lib/libbsp/sparc/leon3/preinstall.am         |   93 +
 c/src/lib/libbsp/sparc/shared/1553/b1553rt.c       |  859 +++++++++
 c/src/lib/libbsp/sparc/shared/1553/gr1553b.c       |  305 +++
 c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c      | 1674 +++++++++++++++++
 c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c      |  519 ++++++
 c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c      | 1256 +++++++++++++
 c/src/lib/libbsp/sparc/shared/amba/ahbstat.c       |  206 ++
 c/src/lib/libbsp/sparc/shared/analog/gradcdac.c    |  578 ++++++
 c/src/lib/libbsp/sparc/shared/ascs/grascs.c        |  615 ++++++
 c/src/lib/libbsp/sparc/shared/can/canmux.c         |  197 ++
 c/src/lib/libbsp/sparc/shared/can/satcan.c         |  714 +++++++
 c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c       |  265 +++
 c/src/lib/libbsp/sparc/shared/gpio/grgpio.c        |  437 +++++
 c/src/lib/libbsp/sparc/shared/include/ahbstat.h    |   73 +
 c/src/lib/libbsp/sparc/shared/include/b1553rt.h    |   74 +
 c/src/lib/libbsp/sparc/shared/include/canmux.h     |   32 +
 .../sparc/shared/include/drvmgr/ambapp_bus.h       |   34 +-
 c/src/lib/libbsp/sparc/shared/include/genirq.h     |  107 ++
 c/src/lib/libbsp/sparc/shared/include/gpiolib.h    |   90 +
 c/src/lib/libbsp/sparc/shared/include/gr1553b.h    |  365 ++++
 c/src/lib/libbsp/sparc/shared/include/gr1553bc.h   |  250 +++
 .../libbsp/sparc/shared/include/gr1553bc_list.h    |  707 +++++++
 c/src/lib/libbsp/sparc/shared/include/gr1553bm.h   |  204 ++
 c/src/lib/libbsp/sparc/shared/include/gr1553rt.h   |  434 +++++
 c/src/lib/libbsp/sparc/shared/include/gradcdac.h   |  227 +++
 c/src/lib/libbsp/sparc/shared/include/grascs.h     |   92 +
 c/src/lib/libbsp/sparc/shared/include/grctm.h      |  168 ++
 c/src/lib/libbsp/sparc/shared/include/greth.h      |  145 ++
 c/src/lib/libbsp/sparc/shared/include/grgpio.h     |   25 +
 c/src/lib/libbsp/sparc/shared/include/grpwm.h      |  127 ++
 c/src/lib/libbsp/sparc/shared/include/grslink.h    |  148 ++
 .../lib/libbsp/sparc/shared/include/grspw_router.h |  104 +
 c/src/lib/libbsp/sparc/shared/include/grtc.h       |  152 ++
 c/src/lib/libbsp/sparc/shared/include/grtm.h       |  241 +++
 c/src/lib/libbsp/sparc/shared/include/satcan.h     |  142 ++
 c/src/lib/libbsp/sparc/shared/include/spictrl.h    |  126 ++
 c/src/lib/libbsp/sparc/shared/include/spwcuc.h     |  188 ++
 c/src/lib/libbsp/sparc/shared/irq/genirq.c         |  241 +++
 c/src/lib/libbsp/sparc/shared/mem/mctrl.c          |  210 +++
 c/src/lib/libbsp/sparc/shared/net/README           |    7 +
 c/src/lib/libbsp/sparc/shared/net/greth.c          | 1424 ++++++++++++++
 c/src/lib/libbsp/sparc/shared/pwm/grpwm.c          |  847 +++++++++
 c/src/lib/libbsp/sparc/shared/slink/grslink.c      |  661 +++++++
 c/src/lib/libbsp/sparc/shared/spi/spictrl.c        | 1008 ++++++++++
 c/src/lib/libbsp/sparc/shared/spw/grspw_router.c   |  549 ++++++
 c/src/lib/libbsp/sparc/shared/time/grctm.c         |  409 ++++
 c/src/lib/libbsp/sparc/shared/time/spwcuc.c        |  369 ++++
 c/src/lib/libbsp/sparc/shared/tmtc/grtc.c          | 1962 ++++++++++++++++++++
 c/src/lib/libbsp/sparc/shared/tmtc/grtm.c          | 1587 ++++++++++++++++
 55 files changed, 21513 insertions(+), 5 deletions(-)
 create mode 100644 c/src/lib/libbsp/sparc/shared/1553/b1553rt.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/1553/gr1553b.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/amba/ahbstat.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/analog/gradcdac.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/ascs/grascs.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/can/canmux.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/can/satcan.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/gpio/grgpio.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/ahbstat.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/b1553rt.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/canmux.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/genirq.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/gpiolib.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/gr1553b.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/gr1553bc.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/gr1553bc_list.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/gr1553bm.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/gr1553rt.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/gradcdac.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/grascs.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/grctm.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/greth.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/grgpio.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/grpwm.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/grslink.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/grspw_router.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/grtc.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/grtm.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/satcan.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/spictrl.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/spwcuc.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/irq/genirq.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/mem/mctrl.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/net/README
 create mode 100644 c/src/lib/libbsp/sparc/shared/net/greth.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/pwm/grpwm.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/slink/grslink.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/spi/spictrl.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/spw/grspw_router.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/time/grctm.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/time/spwcuc.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/tmtc/grtc.c
 create mode 100644 c/src/lib/libbsp/sparc/shared/tmtc/grtm.c

diff --git a/c/src/lib/libbsp/sparc/Makefile.am b/c/src/lib/libbsp/sparc/Makefile.am
index cbd2a14..13411cc 100644
--- a/c/src/lib/libbsp/sparc/Makefile.am
+++ b/c/src/lib/libbsp/sparc/Makefile.am
@@ -12,11 +12,15 @@ EXTRA_DIST += shared/start/start.S
 # Interrupt
 EXTRA_DIST += shared/irq/irq-shared.c
 EXTRA_DIST += shared/irq/bsp_isr_handler.c
+EXTRA_DIST += shared/irq/genirq.c
+EXTRA_DIST += shared/include/genirq.h
 
 # AMBA Plug&Play bus
+EXTRA_DIST += shared/include/ahbstat.h
 EXTRA_DIST += shared/include/ambapp.h
 EXTRA_DIST += shared/include/ambapp_ids.h
 EXTRA_DIST += shared/include/grlib.h
+EXTRA_DIST += shared/amba/ahbstat.c
 EXTRA_DIST += shared/amba/ambapp.c
 EXTRA_DIST += shared/amba/ambapp_alloc.c
 EXTRA_DIST += shared/amba/ambapp_count.c
@@ -58,9 +62,11 @@ EXTRA_DIST += shared/pci/gr_tmtc_1553.c
 # DEBUG
 EXTRA_DIST += shared/include/debug_defs.h
 
-# SpaceWire (GRSPW)
+# SpaceWire
 EXTRA_DIST += shared/spw/grspw.c
+EXTRA_DIST += shared/spw/grspw_router.c
 EXTRA_DIST += shared/include/grspw.h
+EXTRA_DIST += shared/include/grspw_router.h
 
 # UART
 EXTRA_DIST += shared/uart/cons.c
@@ -75,14 +81,58 @@ EXTRA_DIST += shared/can/grcan.c
 EXTRA_DIST += shared/include/occan.h
 EXTRA_DIST += shared/include/grcan.h
 
+# MEM
+EXTRA_DIST += shared/mem/mctrl.c
+
 # MIL-STD-B1553 (Core1553BRM)
 EXTRA_DIST += shared/1553/b1553brm.c
+EXTRA_DIST += shared/1553/b1553rt.c
 EXTRA_DIST += shared/include/b1553brm.h
+EXTRA_DIST += shared/include/b1553rt.h
+
+# MIL-STD-B1553 (GR1553B)
+EXTRA_DIST += shared/1553/gr1553b.c
+EXTRA_DIST += shared/1553/gr1553bc.c
+EXTRA_DIST += shared/1553/gr1553bm.c
+EXTRA_DIST += shared/1553/gr1553rt.c
+EXTRA_DIST += shared/include/gr1553b.h
+EXTRA_DIST += shared/include/gr1553bc.h
+EXTRA_DIST += shared/include/gr1553bc_list.h
+EXTRA_DIST += shared/include/gr1553bm.h
+EXTRA_DIST += shared/include/gr1553rt.h
 
 # I2C-master (I2CMST)
 EXTRA_DIST += shared/i2c/i2cmst.c
 EXTRA_DIST += shared/include/i2cmst.h
 
+# SPI
+EXTRA_DIST += shared/spi/spictrl.c
+EXTRA_DIST += shared/include/spictrl.h
+
+# TIME
+EXTRA_DIST += shared/time/spwcuc.c
+EXTRA_DIST += shared/time/grctm.c
+EXTRA_DIST += shared/include/spwcuc.h
+EXTRA_DIST += shared/include/grctm.h
+
+# GPIO
+EXTRA_DIST += shared/gpio/grgpio.c
+EXTRA_DIST += shared/gpio/gpiolib.c
+EXTRA_DIST += shared/include/grgpio.h
+EXTRA_DIST += shared/include/gpiolib.h
+
+# PWM
+EXTRA_DIST += shared/pwm/grpwm.c
+EXTRA_DIST += shared/include/grpwm.h
+
+# ADC and DAC
+EXTRA_DIST += shared/analog/gradcdac.c
+EXTRA_DIST += shared/include/gradcdac.h
+
+# GRETH
+EXTRA_DIST += shared/net/greth.c
+EXTRA_DIST += shared/include/greth.h
+
 # Network configuration
 EXTRA_DIST += shared/net/network_interface_add.c
 EXTRA_DIST += shared/include/network_interface_add.h
@@ -96,6 +146,19 @@ EXTRA_DIST += shared/drvmgr/leon2_amba_bus.c
 EXTRA_DIST += shared/include/drvmgr/ambapp_bus_grlib.h
 EXTRA_DIST += shared/include/drvmgr/ambapp_bus.h
 EXTRA_DIST += shared/include/drvmgr/leon2_amba_bus.h
+# GR712
+EXTRA_DIST += shared/ascs/grascs.c
+EXTRA_DIST += shared/include/grascs.h
+EXTRA_DIST += shared/can/satcan.c
+EXTRA_DIST += shared/include/satcan.h
+EXTRA_DIST += shared/slink/grslink.c
+EXTRA_DIST += shared/include/grslink.h
+
+# TMTC
+EXTRA_DIST += shared/tmtc/grtc.c
+EXTRA_DIST += shared/include/grtc.h
+EXTRA_DIST += shared/tmtc/grtm.c
+EXTRA_DIST += shared/include/grtm.h
 
 include $(top_srcdir)/../../../automake/subdirs.am
 include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/lib/libbsp/sparc/leon2/Makefile.am b/c/src/lib/libbsp/sparc/leon2/Makefile.am
index 3f29d46..dba1923 100644
--- a/c/src/lib/libbsp/sparc/leon2/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon2/Makefile.am
@@ -58,6 +58,8 @@ libbsp_a_SOURCES += console/console.c console/debugputs.c
 libbsp_a_SOURCES += clock/ckinit.c
 libbsp_a_SOURCES += ../../shared/clockdrv_shell.h
 # IRQ
+include_HEADERS += ../../sparc/shared/include/genirq.h
+libbsp_a_SOURCES += ../../sparc/shared/irq/genirq.c
 include_bsp_HEADERS += \
     ../../shared/include/irq-generic.h \
     ../../shared/include/irq-info.h \
@@ -76,6 +78,7 @@ libbsp_a_SOURCES += \
 include_HEADERS += ../../sparc/shared/include/ambapp.h
 include_HEADERS += ../../sparc/shared/include/ambapp_ids.h
 include_HEADERS += ../../sparc/shared/include/grlib.h
+include_HEADERS += ../../sparc/shared/include/ahbstat.h
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_alloc.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_count.c
@@ -86,6 +89,7 @@ libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_parent.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_old.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_names.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_show.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ahbstat.c
 
 # Clock Driver and Timer Library
 include_HEADERS += ../../sparc/shared/include/tlib.h
@@ -114,7 +118,20 @@ libbsp_a_SOURCES +=  ../../sparc/shared/pci/gr_rasta_tmtc.c
 
 # B1553BRM
 include_HEADERS += ../../sparc/shared/include/b1553brm.h
+include_HEADERS += ../../sparc/shared/include/b1553rt.h
 libbsp_a_SOURCES += ../../sparc/shared/1553/b1553brm.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/b1553rt.c
+
+# GR1553B
+include_HEADERS += ../../sparc/shared/include/gr1553b.h
+include_HEADERS += ../../sparc/shared/include/gr1553bc.h
+include_HEADERS += ../../sparc/shared/include/gr1553bc_list.h
+include_HEADERS += ../../sparc/shared/include/gr1553bm.h
+include_HEADERS += ../../sparc/shared/include/gr1553rt.h
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553b.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553bc.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553bm.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553rt.c
 
 # CAN
 include_HEADERS += ../../sparc/shared/include/occan.h
@@ -124,7 +141,9 @@ libbsp_a_SOURCES += ../../sparc/shared/can/occan.c \
 
 # SpaceWire
 include_HEADERS += ../../sparc/shared/include/grspw.h
+include_HEADERS += ../../sparc/shared/include/grspw_router.h
 libbsp_a_SOURCES += ../../sparc/shared/spw/grspw.c
+libbsp_a_SOURCES += ../../sparc/shared/spw/grspw_router.c
 
 # UART (RAW)
 include_HEADERS += ../../sparc/shared/include/apbuart.h
@@ -134,9 +153,42 @@ libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c
 include_HEADERS += ../../sparc/shared/include/i2cmst.h
 libbsp_a_SOURCES += ../../sparc/shared/i2c/i2cmst.c
 
+# SPI
+include_HEADERS += ../../sparc/shared/include/spictrl.h
+libbsp_a_SOURCES += ../../sparc/shared/spi/spictrl.c
+
+# TIME
+include_HEADERS += ../../sparc/shared/include/spwcuc.h
+include_HEADERS += ../../sparc/shared/include/grctm.h
+libbsp_a_SOURCES += ../../sparc/shared/time/spwcuc.c
+libbsp_a_SOURCES += ../../sparc/shared/time/grctm.c
+
+# GPIO
+include_HEADERS += ../../sparc/shared/include/grgpio.h
+include_HEADERS += ../../sparc/shared/include/gpiolib.h
+libbsp_a_SOURCES += ../../sparc/shared/gpio/grgpio.c
+libbsp_a_SOURCES += ../../sparc/shared/gpio/gpiolib.c
+
+# PWM
+include_HEADERS += ../../sparc/shared/include/grpwm.h
+libbsp_a_SOURCES += ../../sparc/shared/pwm/grpwm.c
+
+# ADC and DAC
+include_HEADERS += ../../sparc/shared/include/gradcdac.h
+libbsp_a_SOURCES += ../../sparc/shared/analog/gradcdac.c
+
+# Memory controllers
+libbsp_a_SOURCES += ../../sparc/shared/mem/mctrl.c
+
 # timer
 libbsp_a_SOURCES += timer/timer.c
 
+# TM/TC
+include_HEADERS += ../../sparc/shared/include/grtc.h
+include_HEADERS += ../../sparc/shared/include/grtm.h
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtc.c
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtm.c
+
 # Driver Manager
 include_drvmgrdir = $(includedir)/drvmgr
 include_drvmgr_HEADERS = ../../sparc/shared/include/drvmgr/ambapp_bus.h
@@ -166,6 +218,14 @@ leon_open_eth_rel_CPPFLAGS +=  -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
 leon_open_eth_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
 endif
 
+if HAS_NETWORKING
+noinst_PROGRAMS += leon_greth.rel
+leon_greth_rel_SOURCES = ../../sparc/shared/net/greth.c
+include_HEADERS += ../../sparc/shared/include/greth.h
+leon_greth_rel_CPPFLAGS = $(AM_CPPFLAGS)
+leon_greth_rel_CPPFLAGS += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
+leon_greth_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
 # BSP Network configuration
 include_HEADERS += ../../sparc/shared/include/network_interface_add.h
 libbsp_a_SOURCES += ../../sparc/shared/net/network_interface_add.c
@@ -178,6 +238,7 @@ libbsp_a_LIBADD = \
     ../../../libcpu/@RTEMS_CPU@/syscall.rel
 
 if HAS_NETWORKING
+libbsp_a_LIBADD += leon_greth.rel
 libbsp_a_LIBADD += leon_open_eth.rel
 libbsp_a_LIBADD += leon_smc91111.rel
 endif
diff --git a/c/src/lib/libbsp/sparc/leon2/include/bsp.h b/c/src/lib/libbsp/sparc/leon2/include/bsp.h
index d669d89..29e3169 100644
--- a/c/src/lib/libbsp/sparc/leon2/include/bsp.h
+++ b/c/src/lib/libbsp/sparc/leon2/include/bsp.h
@@ -227,6 +227,7 @@ int cchip1_register(void);
  */
 #define AMBAPPBUS_INFO_AVAIL          /* AMBAPP Bus driver */
 #define GPTIMER_INFO_AVAIL            /* GPTIMER Timer driver */
+#define GRETH_INFO_AVAIL              /* GRETH Ethernet driver */
 
 #ifdef __cplusplus
 }
diff --git a/c/src/lib/libbsp/sparc/leon2/preinstall.am b/c/src/lib/libbsp/sparc/leon2/preinstall.am
index 11dae63..cfcd389 100644
--- a/c/src/lib/libbsp/sparc/leon2/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon2/preinstall.am
@@ -81,6 +81,10 @@ $(PROJECT_INCLUDE)/bsp/gnatcommon.h: ../shared/include/gnatcommon.h $(PROJECT_IN
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gnatcommon.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gnatcommon.h
 
+$(PROJECT_INCLUDE)/genirq.h: ../../sparc/shared/include/genirq.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/genirq.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/genirq.h
+
 $(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h
@@ -105,6 +109,10 @@ $(PROJECT_INCLUDE)/grlib.h: ../../sparc/shared/include/grlib.h $(PROJECT_INCLUDE
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grlib.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/grlib.h
 
+$(PROJECT_INCLUDE)/ahbstat.h: ../../sparc/shared/include/ahbstat.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/ahbstat.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/ahbstat.h
+
 $(PROJECT_INCLUDE)/tlib.h: ../../sparc/shared/include/tlib.h $(PROJECT_INCLUDE)/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tlib.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/tlib.h
@@ -133,6 +141,30 @@ $(PROJECT_INCLUDE)/b1553brm.h: ../../sparc/shared/include/b1553brm.h $(PROJECT_I
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553brm.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553brm.h
 
+$(PROJECT_INCLUDE)/b1553rt.h: ../../sparc/shared/include/b1553rt.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553rt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553rt.h
+
+$(PROJECT_INCLUDE)/gr1553b.h: ../../sparc/shared/include/gr1553b.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553b.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553b.h
+
+$(PROJECT_INCLUDE)/gr1553bc.h: ../../sparc/shared/include/gr1553bc.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bc.h
+
+$(PROJECT_INCLUDE)/gr1553bc_list.h: ../../sparc/shared/include/gr1553bc_list.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bc_list.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bc_list.h
+
+$(PROJECT_INCLUDE)/gr1553bm.h: ../../sparc/shared/include/gr1553bm.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bm.h
+
+$(PROJECT_INCLUDE)/gr1553rt.h: ../../sparc/shared/include/gr1553rt.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553rt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553rt.h
+
 $(PROJECT_INCLUDE)/occan.h: ../../sparc/shared/include/occan.h $(PROJECT_INCLUDE)/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/occan.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/occan.h
@@ -145,6 +177,10 @@ $(PROJECT_INCLUDE)/grspw.h: ../../sparc/shared/include/grspw.h $(PROJECT_INCLUDE
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw.h
 
+$(PROJECT_INCLUDE)/grspw_router.h: ../../sparc/shared/include/grspw_router.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw_router.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw_router.h
+
 $(PROJECT_INCLUDE)/apbuart.h: ../../sparc/shared/include/apbuart.h $(PROJECT_INCLUDE)/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart.h
@@ -153,6 +189,42 @@ $(PROJECT_INCLUDE)/i2cmst.h: ../../sparc/shared/include/i2cmst.h $(PROJECT_INCLU
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/i2cmst.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/i2cmst.h
 
+$(PROJECT_INCLUDE)/spictrl.h: ../../sparc/shared/include/spictrl.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spictrl.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/spictrl.h
+
+$(PROJECT_INCLUDE)/spwcuc.h: ../../sparc/shared/include/spwcuc.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spwcuc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/spwcuc.h
+
+$(PROJECT_INCLUDE)/grctm.h: ../../sparc/shared/include/grctm.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grctm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grctm.h
+
+$(PROJECT_INCLUDE)/grgpio.h: ../../sparc/shared/include/grgpio.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grgpio.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grgpio.h
+
+$(PROJECT_INCLUDE)/gpiolib.h: ../../sparc/shared/include/gpiolib.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gpiolib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gpiolib.h
+
+$(PROJECT_INCLUDE)/grpwm.h: ../../sparc/shared/include/grpwm.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grpwm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grpwm.h
+
+$(PROJECT_INCLUDE)/gradcdac.h: ../../sparc/shared/include/gradcdac.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gradcdac.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gradcdac.h
+
+$(PROJECT_INCLUDE)/grtc.h: ../../sparc/shared/include/grtc.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grtc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grtc.h
+
+$(PROJECT_INCLUDE)/grtm.h: ../../sparc/shared/include/grtm.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grtm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grtm.h
+
 $(PROJECT_INCLUDE)/drvmgr/$(dirstamp):
 	@$(MKDIR_P) $(PROJECT_INCLUDE)/drvmgr
 	@: > $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
@@ -166,6 +238,11 @@ $(PROJECT_INCLUDE)/drvmgr/leon2_amba_bus.h: ../../sparc/shared/include/drvmgr/le
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/leon2_amba_bus.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/leon2_amba_bus.h
 
+if HAS_NETWORKING
+$(PROJECT_INCLUDE)/greth.h: ../../sparc/shared/include/greth.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/greth.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/greth.h
+
 $(PROJECT_INCLUDE)/network_interface_add.h: ../../sparc/shared/include/network_interface_add.h $(PROJECT_INCLUDE)/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/network_interface_add.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/network_interface_add.h
diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am
index dae3ecc..4517ee3 100644
--- a/c/src/lib/libbsp/sparc/leon3/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am
@@ -55,6 +55,7 @@ include_HEADERS += include/amba.h
 include_HEADERS += ../../sparc/shared/include/ambapp.h
 include_HEADERS += ../../sparc/shared/include/ambapp_ids.h
 include_HEADERS += ../../sparc/shared/include/grlib.h
+include_HEADERS += ../../sparc/shared/include/ahbstat.h
 libbsp_a_SOURCES += amba/amba.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_alloc.c
@@ -66,6 +67,7 @@ libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_parent.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_old.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_names.c
 libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_show.c
+libbsp_a_SOURCES += ../../sparc/shared/amba/ahbstat.c
 
 # Clock Driver and Timer Library
 include_HEADERS += ../../sparc/shared/include/tlib.h
@@ -86,12 +88,14 @@ include_HEADERS += ../../sparc/shared/include/cons.h
 libbsp_a_SOURCES += console/printk_support.c
 
 # IRQ
+include_HEADERS += ../../sparc/shared/include/genirq.h
 include_bsp_HEADERS += \
     ../../shared/include/irq-generic.h \
     ../../shared/include/irq-info.h \
     include/bsp/irq.h
 libbsp_a_SOURCES += \
     startup/eirq.c \
+    ../../sparc/shared/irq/genirq.c  \
     ../../sparc/shared/irq/irq-shared.c \
     ../../sparc/shared/irq/bsp_isr_handler.c \
     ../../shared/src/irq-default-handler.c \
@@ -124,7 +128,20 @@ libbsp_a_SOURCES +=  ../../sparc/shared/pci/gr_tmtc_1553.c
 
 # B1553BRM
 include_HEADERS += ../../sparc/shared/include/b1553brm.h
+include_HEADERS += ../../sparc/shared/include/b1553rt.h
 libbsp_a_SOURCES += ../../sparc/shared/1553/b1553brm.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/b1553rt.c
+
+# GR1553B
+include_HEADERS += ../../sparc/shared/include/gr1553b.h
+include_HEADERS += ../../sparc/shared/include/gr1553bc.h
+include_HEADERS += ../../sparc/shared/include/gr1553bc_list.h
+include_HEADERS += ../../sparc/shared/include/gr1553bm.h
+include_HEADERS += ../../sparc/shared/include/gr1553rt.h
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553b.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553bc.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553bm.c
+libbsp_a_SOURCES += ../../sparc/shared/1553/gr1553rt.c
 
 # CAN
 include_HEADERS += ../../sparc/shared/include/occan.h \
@@ -134,7 +151,9 @@ libbsp_a_SOURCES += ../../sparc/shared/can/occan.c \
 
 # SpaceWire
 include_HEADERS += ../../sparc/shared/include/grspw.h
+include_HEADERS += ../../sparc/shared/include/grspw_router.h
 libbsp_a_SOURCES += ../../sparc/shared/spw/grspw.c
+libbsp_a_SOURCES += ../../sparc/shared/spw/grspw_router.c
 
 # UART
 include_HEADERS += ../../sparc/shared/include/apbuart.h \
@@ -146,6 +165,33 @@ libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c \
 include_HEADERS += ../../sparc/shared/include/i2cmst.h
 libbsp_a_SOURCES += ../../sparc/shared/i2c/i2cmst.c
 
+# SPI
+include_HEADERS += ../../sparc/shared/include/spictrl.h
+libbsp_a_SOURCES += ../../sparc/shared/spi/spictrl.c
+
+# TIME
+include_HEADERS += ../../sparc/shared/include/spwcuc.h
+include_HEADERS += ../../sparc/shared/include/grctm.h
+libbsp_a_SOURCES += ../../sparc/shared/time/spwcuc.c
+libbsp_a_SOURCES += ../../sparc/shared/time/grctm.c
+
+# GPIO
+include_HEADERS += ../../sparc/shared/include/grgpio.h
+include_HEADERS += ../../sparc/shared/include/gpiolib.h
+libbsp_a_SOURCES += ../../sparc/shared/gpio/grgpio.c
+libbsp_a_SOURCES += ../../sparc/shared/gpio/gpiolib.c
+
+# PWM
+include_HEADERS += ../../sparc/shared/include/grpwm.h
+libbsp_a_SOURCES += ../../sparc/shared/pwm/grpwm.c
+
+# ADC and DAC
+include_HEADERS += ../../sparc/shared/include/gradcdac.h
+libbsp_a_SOURCES += ../../sparc/shared/analog/gradcdac.c
+
+# Memory controllers
+libbsp_a_SOURCES += ../../sparc/shared/mem/mctrl.c
+
 # timer
 libbsp_a_SOURCES += timer/timer.c
 libbsp_a_SOURCES += timer/watchdog.c
@@ -156,6 +202,22 @@ libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c
 libbsp_a_SOURCES += include/cache_.h
 libbsp_a_CPPFLAGS = -I$(srcdir)/include
 
+# GR712
+include_HEADERS += ../../sparc/shared/include/grascs.h
+include_HEADERS += ../../sparc/shared/include/satcan.h 
+include_HEADERS += ../../sparc/shared/include/canmux.h
+include_HEADERS += ../../sparc/shared/include/grslink.h
+libbsp_a_SOURCES += ../../sparc/shared/ascs/grascs.c
+libbsp_a_SOURCES += ../../sparc/shared/can/satcan.c
+libbsp_a_SOURCES += ../../sparc/shared/can/canmux.c
+libbsp_a_SOURCES += ../../sparc/shared/slink/grslink.c
+
+# TM/TC
+include_HEADERS += ../../sparc/shared/include/grtc.h
+include_HEADERS += ../../sparc/shared/include/grtm.h
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtc.c
+libbsp_a_SOURCES += ../../sparc/shared/tmtc/grtm.c
+
 # Driver Manager 
 include_drvmgrdir = $(includedir)/drvmgr
 include_drvmgr_HEADERS = ../../sparc/shared/include/drvmgr/ambapp_bus_grlib.h
@@ -185,7 +247,9 @@ endif
 
 if HAS_NETWORKING
 noinst_PROGRAMS += leon_greth.rel
-leon_greth_rel_SOURCES = leon_greth/leon_greth.c
+libbsp_a_SOURCES += leon_greth/leon_greth.c
+leon_greth_rel_SOURCES = ../../sparc/shared/net/greth.c
+include_HEADERS += ../../sparc/shared/include/greth.h
 leon_greth_rel_CPPFLAGS = $(AM_CPPFLAGS)
 leon_greth_rel_CPPFLAGS += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
 leon_greth_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
diff --git a/c/src/lib/libbsp/sparc/leon3/include/bsp.h b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
index d302418..0be33a9 100644
--- a/c/src/lib/libbsp/sparc/leon3/include/bsp.h
+++ b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
@@ -257,6 +257,7 @@ extern const unsigned char LEON3_irq_to_cpu[32];
 #define AMBAPPBUS_INFO_AVAIL          /* AMBAPP Bus driver */
 #define APBUART_INFO_AVAIL            /* APBUART Console driver */
 #define GPTIMER_INFO_AVAIL            /* GPTIMER Timer driver */
+#define GRETH_INFO_AVAIL              /* GRETH Ethernet driver */
 
 #ifdef __cplusplus
 }
diff --git a/c/src/lib/libbsp/sparc/leon3/preinstall.am b/c/src/lib/libbsp/sparc/leon3/preinstall.am
index 41f7d6d..29fd095 100644
--- a/c/src/lib/libbsp/sparc/leon3/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon3/preinstall.am
@@ -105,6 +105,10 @@ $(PROJECT_INCLUDE)/grlib.h: ../../sparc/shared/include/grlib.h $(PROJECT_INCLUDE
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grlib.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/grlib.h
 
+$(PROJECT_INCLUDE)/ahbstat.h: ../../sparc/shared/include/ahbstat.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/ahbstat.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/ahbstat.h
+
 $(PROJECT_INCLUDE)/tlib.h: ../../sparc/shared/include/tlib.h $(PROJECT_INCLUDE)/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tlib.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/tlib.h
@@ -113,6 +117,10 @@ $(PROJECT_INCLUDE)/cons.h: ../../sparc/shared/include/cons.h $(PROJECT_INCLUDE)/
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/cons.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/cons.h
 
+$(PROJECT_INCLUDE)/genirq.h: ../../sparc/shared/include/genirq.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/genirq.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/genirq.h
+
 $(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h
@@ -153,6 +161,30 @@ $(PROJECT_INCLUDE)/b1553brm.h: ../../sparc/shared/include/b1553brm.h $(PROJECT_I
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553brm.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553brm.h
 
+$(PROJECT_INCLUDE)/b1553rt.h: ../../sparc/shared/include/b1553rt.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/b1553rt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/b1553rt.h
+
+$(PROJECT_INCLUDE)/gr1553b.h: ../../sparc/shared/include/gr1553b.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553b.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553b.h
+
+$(PROJECT_INCLUDE)/gr1553bc.h: ../../sparc/shared/include/gr1553bc.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bc.h
+
+$(PROJECT_INCLUDE)/gr1553bc_list.h: ../../sparc/shared/include/gr1553bc_list.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bc_list.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bc_list.h
+
+$(PROJECT_INCLUDE)/gr1553bm.h: ../../sparc/shared/include/gr1553bm.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553bm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553bm.h
+
+$(PROJECT_INCLUDE)/gr1553rt.h: ../../sparc/shared/include/gr1553rt.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gr1553rt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gr1553rt.h
+
 $(PROJECT_INCLUDE)/occan.h: ../../sparc/shared/include/occan.h $(PROJECT_INCLUDE)/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/occan.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/occan.h
@@ -165,6 +197,10 @@ $(PROJECT_INCLUDE)/grspw.h: ../../sparc/shared/include/grspw.h $(PROJECT_INCLUDE
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw.h
 
+$(PROJECT_INCLUDE)/grspw_router.h: ../../sparc/shared/include/grspw_router.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grspw_router.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grspw_router.h
+
 $(PROJECT_INCLUDE)/apbuart.h: ../../sparc/shared/include/apbuart.h $(PROJECT_INCLUDE)/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart.h
@@ -177,10 +213,62 @@ $(PROJECT_INCLUDE)/i2cmst.h: ../../sparc/shared/include/i2cmst.h $(PROJECT_INCLU
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/i2cmst.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/i2cmst.h
 
+$(PROJECT_INCLUDE)/spictrl.h: ../../sparc/shared/include/spictrl.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spictrl.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/spictrl.h
+
+$(PROJECT_INCLUDE)/spwcuc.h: ../../sparc/shared/include/spwcuc.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/spwcuc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/spwcuc.h
+
+$(PROJECT_INCLUDE)/grctm.h: ../../sparc/shared/include/grctm.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grctm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grctm.h
+
+$(PROJECT_INCLUDE)/grgpio.h: ../../sparc/shared/include/grgpio.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grgpio.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grgpio.h
+
+$(PROJECT_INCLUDE)/gpiolib.h: ../../sparc/shared/include/gpiolib.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gpiolib.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gpiolib.h
+
+$(PROJECT_INCLUDE)/grpwm.h: ../../sparc/shared/include/grpwm.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grpwm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grpwm.h
+
+$(PROJECT_INCLUDE)/gradcdac.h: ../../sparc/shared/include/gradcdac.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/gradcdac.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/gradcdac.h
+
 $(PROJECT_INCLUDE)/watchdog.h: include/watchdog.h $(PROJECT_INCLUDE)/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/watchdog.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/watchdog.h
 
+$(PROJECT_INCLUDE)/grascs.h: ../../sparc/shared/include/grascs.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grascs.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grascs.h
+
+$(PROJECT_INCLUDE)/satcan.h: ../../sparc/shared/include/satcan.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/satcan.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/satcan.h
+
+$(PROJECT_INCLUDE)/canmux.h: ../../sparc/shared/include/canmux.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/canmux.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/canmux.h
+
+$(PROJECT_INCLUDE)/grslink.h: ../../sparc/shared/include/grslink.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grslink.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grslink.h
+
+$(PROJECT_INCLUDE)/grtc.h: ../../sparc/shared/include/grtc.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grtc.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grtc.h
+
+$(PROJECT_INCLUDE)/grtm.h: ../../sparc/shared/include/grtm.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/grtm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/grtm.h
+
 $(PROJECT_INCLUDE)/drvmgr/$(dirstamp):
 	@$(MKDIR_P) $(PROJECT_INCLUDE)/drvmgr
 	@: > $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
@@ -195,6 +283,11 @@ $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h: ../../sparc/shared/include/drvmgr/ambapp
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/ambapp_bus.h
 
 if HAS_NETWORKING
+$(PROJECT_INCLUDE)/greth.h: ../../sparc/shared/include/greth.h $(PROJECT_INCLUDE)/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/greth.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/greth.h
+endif
+if HAS_NETWORKING
 $(PROJECT_INCLUDE)/network_interface_add.h: ../../sparc/shared/include/network_interface_add.h $(PROJECT_INCLUDE)/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/network_interface_add.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/network_interface_add.h
diff --git a/c/src/lib/libbsp/sparc/shared/1553/b1553rt.c b/c/src/lib/libbsp/sparc/shared/1553/b1553rt.c
new file mode 100644
index 0000000..3dfb403
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/b1553rt.c
@@ -0,0 +1,859 @@
+/*
+ *  B1553RT driver implmenetation
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <b1553rt.h>
+#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
+
+/* Uncomment for debug output */
+/*#define DEBUG 1*/
+
+/*
+  #define FUNCDEBUG 1*/
+/*#undef DEBUG*/
+#undef FUNCDEBUG
+
+/* EVENT_QUEUE_SIZE sets the size of the event queue
+ */
+#define EVENT_QUEUE_SIZE           1024  
+
+
+#define INDEX(x) ( x&(EVENT_QUEUE_SIZE-1) )
+
+#if 0
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...) 
+#endif
+
+#ifdef FUNCDEBUG
+#define FUNCDBG(x...) printk(x)
+#else
+#define FUNCDBG(x...) 
+#endif
+
+#define READ_DMA(address) _READ16((unsigned int)address)
+
+static __inline__ unsigned short _READ16(unsigned int addr) {
+    unsigned short tmp;
+    asm(" lduha [%1]1, %0 "
+        : "=r"(tmp)
+        : "r"(addr)
+	);
+    return tmp;
+}
+
+static rtems_device_driver rt_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver rt_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define RT_DRIVER_TABLE_ENTRY { rt_initialize, rt_open, rt_close, rt_read, rt_write, rt_control }
+
+static rtems_driver_address_table b1553rt_driver = RT_DRIVER_TABLE_ENTRY;
+
+typedef struct { 
+
+    struct drvmgr_dev *dev; /* Driver manager device */
+    char devName[32];     /* Device Name */
+
+    struct rt_reg *regs;
+    unsigned int ctrl_copy; /* Local copy of config register */
+
+    unsigned int cfg_freq;
+
+    unsigned int memarea_base;
+    unsigned int memarea_base_remote;
+
+    volatile unsigned short *mem;
+
+    /* Received events waiting to be read */
+    struct rt_msg *rt_event;
+    unsigned int head, tail;
+
+    int rx_blocking;
+
+    rtems_id rx_sem, tx_sem, dev_sem;
+    int minor;
+    int irqno;
+
+#ifdef DEBUG    		
+    unsigned int log[EVENT_QUEUE_SIZE*4];
+    unsigned int log_i;
+#endif
+
+    unsigned int status;
+    rtems_id event_id; /* event that may be signalled upon errors, needs to be set through ioctl command RT_SET_EVENTID */
+
+} rt_priv;
+
+static void b1553rt_interrupt(void *arg);
+static rtems_device_driver rt_init(rt_priv *rt);
+
+#define OFS(ofs) (((unsigned int)&ofs & 0x1ffff)>>1)
+
+static int b1553rt_driver_io_registered = 0;
+static rtems_device_major_number b1553rt_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int b1553rt_register_io(rtems_device_major_number *m);
+int b1553rt_device_init(rt_priv *pDev);
+
+int b1553rt_init2(struct drvmgr_dev *dev);
+int b1553rt_init3(struct drvmgr_dev *dev);
+int b1553rt_remove(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops b1553rt_ops = 
+{
+    .init = {NULL, b1553rt_init2, b1553rt_init3, NULL},
+    .remove = b1553rt_remove,
+    .info = NULL
+};
+
+struct amba_dev_id b1553rt_ids[] = 
+{
+    {VENDOR_GAISLER, GAISLER_B1553RT},
+    {0, 0}		/* Mark end of table */
+};
+
+struct amba_drv_info b1553rt_drv_info =
+{
+    {
+	DRVMGR_OBJ_DRV,				/* Driver */
+        NULL,					/* Next driver */
+        NULL,					/* Device list */
+        DRIVER_AMBAPP_GAISLER_B1553RT_ID,	/* Driver ID */
+        "B1553RT_DRV",				/* Driver Name */
+        DRVMGR_BUS_TYPE_AMBAPP,			/* Bus Type */
+        &b1553rt_ops,
+        NULL,					/* Funcs */
+        0,					/* No devices yet */
+	0,
+
+    },
+    &b1553rt_ids[0]
+};
+
+void b1553rt_register_drv (void)
+{
+    DBG("Registering B1553RT driver\n");
+    drvmgr_drv_register(&b1553rt_drv_info.general);
+}
+
+int b1553rt_init2(struct drvmgr_dev *dev)
+{
+    rt_priv *priv;
+
+    DBG("B1553RT[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+    priv = dev->priv = malloc(sizeof(rt_priv));
+    if ( !priv )
+        return DRVMGR_NOMEM;
+    memset(priv, 0, sizeof(*priv));
+    priv->dev = dev;
+
+    /* This core will not find other cores, so we wait for init2() */
+
+    return DRVMGR_OK;
+}
+
+int b1553rt_init3(struct drvmgr_dev *dev)
+{
+    rt_priv *priv;
+    char prefix[32];
+    rtems_status_code status;
+
+    priv = dev->priv;
+
+    /* Do initialization */
+
+    if ( b1553rt_driver_io_registered == 0) {
+        /* Register the I/O driver only once for all cores */
+        if ( b1553rt_register_io(&b1553rt_driver_io_major) ) {
+            /* Failed to register I/O driver */
+            dev->priv = NULL;
+            return DRVMGR_FAIL;
+        }
+
+        b1553rt_driver_io_registered = 1;
+    }
+
+    /* I/O system registered and initialized 
+     * Now we take care of device initialization.
+     */
+
+    if ( b1553rt_device_init(priv) ) {
+        return DRVMGR_FAIL;
+    }
+
+    /* Get Filesystem name prefix */
+    prefix[0] = '\0';
+    if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+        /* Failed to get prefix, make sure of a unique FS name
+         * by using the driver minor.
+         */
+        sprintf(priv->devName, "/dev/b1553rt%d", dev->minor_drv);
+    } else {
+        /* Got special prefix, this means we have a bus prefix
+         * And we should use our "bus minor"
+         */
+        sprintf(priv->devName, "/dev/%sb1553rt%d", prefix, dev->minor_bus);
+    }
+
+    /* Register Device */
+    status = rtems_io_register_name(priv->devName, b1553rt_driver_io_major, dev->minor_drv);
+    if (status != RTEMS_SUCCESSFUL) {
+        return DRVMGR_FAIL;
+    }
+
+    return DRVMGR_OK;
+}
+
+int b1553rt_remove(struct drvmgr_dev *dev)
+{
+    /* Stop more tasks to open driver */
+
+    /* Throw out all tasks using this driver */
+
+    /* Unregister I/O node */
+
+    /* Unregister and disable Interrupt */
+
+    /* Free device memory */
+
+    /* Return sucessfully */
+
+    return DRVMGR_FAIL;
+}
+
+/******************* Driver Implementation ***********************/
+
+int b1553rt_register_io(rtems_device_major_number *m)
+{
+    rtems_status_code r;
+
+    if ((r = rtems_io_register_driver(0, &b1553rt_driver, m)) == RTEMS_SUCCESSFUL) {
+        DBG("B1553RT driver successfully registered, major: %d\n", *m);
+    } else {
+        switch(r) {
+        case RTEMS_TOO_MANY:
+            printk("B1553RT rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+            return -1;
+        case RTEMS_INVALID_NUMBER:  
+            printk("B1553RT rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+            return -1;
+        case RTEMS_RESOURCE_IN_USE:
+            printk("B1553RT rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+            return -1;
+        default:
+            printk("B1553RT rtems_io_register_driver failed\n");
+            return -1;
+        }
+    }
+    return 0;
+}
+
+int b1553rt_device_init(rt_priv *pDev)
+{
+    struct amba_dev_info *ambadev;
+    struct ambapp_core *pnpinfo;
+    union drvmgr_key_value *value;
+    unsigned int mem;
+    unsigned int sys_freq_hz;
+
+    /* Get device information from AMBA PnP information */
+    ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+    if ( ambadev == NULL ) {
+        return -1;
+    }
+    pnpinfo = &ambadev->info;
+    pDev->irqno = pnpinfo->irq;
+    pDev->regs = (struct rt_reg *)pnpinfo->apb_slv->start;
+    pDev->minor = pDev->dev->minor_drv;
+
+#ifdef DEBUG
+    pDev->log_i = 0;	
+    memset(pDev->log,0,sizeof(pDev->log));
+    printf("LOG: 0x%x\n", &pDev->log[0]);
+    printf("LOG_I: 0x%x\n", &pDev->log_i);
+#endif	
+
+    /* Get memory configuration from bus resources */
+    value = drvmgr_dev_key_get(pDev->dev, "dmaBaseAdr", KEY_TYPE_POINTER);
+    if (value)
+        mem = (unsigned int)value->ptr;
+
+    if (value && (mem & 1)) {
+        /* Remote address, address as RT looks at it. */
+
+        /* Translate the base address into an address that the the CPU can understand */
+        pDev->memarea_base = mem & ~1;
+        drvmgr_translate_check(pDev->dev, DMAMEM_TO_CPU,
+                                (void *)pDev->memarea_base_remote,
+                                (void **)&pDev->memarea_base,
+                                4 * 1024);
+    } else {
+        if (!value) {
+            /* Use dynamically allocated memory,
+             * 4k DMA memory + 4k for alignment 
+             */
+            mem = (char *)malloc(4 * 1024 * 2);
+            if ( !mem ){
+                printk("RT: Failed to allocate HW memory\n\r");
+                return -1;
+            }
+            /* align memory to 4k boundary */
+            pDev->memarea_base = (mem + 0xfff) & ~0xfff;
+        } else {
+            pDev->memarea_base = mem;
+        }
+
+        /* Translate the base address into an address that the RT core can understand */
+        drvmgr_translate_check(pDev->dev, CPUMEM_TO_DMA,
+                               (void *)pDev->memarea_base,
+                               (void **)&pDev->memarea_base_remote,
+                               4 * 1024);
+    }
+
+    /* clear the used memory */
+    memset((char *)pDev->memarea_base, 0, 4 * 1024);
+
+    /* Set base address of all descriptors */
+    pDev->memarea_base = (unsigned int)mem;
+    pDev->mem = (volatile unsigned short *)pDev->memarea_base;
+
+    pDev->rt_event = NULL;
+
+    /* The RT is always clocked at the same frequency as the bus 
+     * If the frequency doesnt match it is defaulted to 24MHz, 
+     * user can always override it.
+     */
+    pDev->cfg_freq = RT_FREQ_24MHZ;
+
+    /* Get frequency in Hz */
+    if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &sys_freq_hz) == 0 ) {
+        if ( sys_freq_hz == 20000000 ) {
+            pDev->cfg_freq = RT_FREQ_20MHZ;
+        } else if ( sys_freq_hz == 16000000 ) {
+            pDev->cfg_freq = RT_FREQ_16MHZ;
+        } else if ( sys_freq_hz == 12000000 ) {
+            pDev->cfg_freq = RT_FREQ_12MHZ;
+        }
+    }
+
+    value = drvmgr_dev_key_get(pDev->dev, "coreFreq", KEY_TYPE_INT);
+    if ( value ) {
+        pDev->cfg_freq = value->i & RT_FREQ_MASK;
+    }
+
+    /* RX Semaphore created with count = 0 */
+    if ( rtems_semaphore_create(rtems_build_name('R', 'T', '0', '0' + pDev->minor),
+                                0,
+                                RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, 
+                                0,
+                                &pDev->rx_sem) != RTEMS_SUCCESSFUL ) {
+        printk("RT: Failed to create rx semaphore\n");
+        return RTEMS_INTERNAL_ERROR;
+    }
+
+    /* Device Semaphore created with count = 1 */
+    if ( rtems_semaphore_create(rtems_build_name('R', 'T', '0', '0' + pDev->minor),
+                                1,
+                                RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, 
+                                0,
+                                &pDev->dev_sem) != RTEMS_SUCCESSFUL ){
+        printk("RT: Failed to create device semaphore\n");
+        return RTEMS_INTERNAL_ERROR;
+    }
+
+    /* Default to RT-mode */
+    rt_init(pDev);
+
+    return 0;
+}
+
+static int odd_parity(unsigned int data)
+{
+    unsigned int i=0;
+
+    while(data)
+    {
+        i++;
+        data &= (data - 1);
+    } 
+
+    return !(i&1);
+}
+
+static void start_operation(rt_priv *rt)
+{
+
+}
+
+static void stop_operation(rt_priv *rt)
+{
+
+}
+
+static void set_extmdata_en(rt_priv *rt, int extmdata)
+{
+    if ( extmdata )
+        extmdata = 1;    
+    rt->ctrl_copy = (rt->ctrl_copy & ~(1<<16)) | (extmdata<<16);
+    rt->regs->ctrl = rt->ctrl_copy;
+}
+
+static void set_vector_word(rt_priv *rt, unsigned short vword)
+{
+    rt->regs->vword = vword;
+}
+
+/* Set clock speed */
+static void set_clkspd(rt_priv *rt, int spd)
+{
+    rt->ctrl_copy = (rt->ctrl_copy & ~0xC0) | (spd<<6);
+    rt->regs->ctrl = rt->ctrl_copy;
+    asm volatile("nop"::);
+    rt->regs->ctrl = rt->ctrl_copy | (1<<20);
+}
+
+static void set_rtaddr(rt_priv *rt, int addr)
+{
+    rt->ctrl_copy = (rt->ctrl_copy & ~0x3F00) | (addr << 8) | (odd_parity(addr)<<13);
+    rt->regs->ctrl = rt->ctrl_copy;
+}
+
+static void set_broadcast_en(rt_priv *rt, int data)
+{
+    rt->ctrl_copy = (rt->ctrl_copy & ~0x40000) | (data<<18);
+    rt->regs->ctrl = rt->ctrl_copy;
+}
+
+static rtems_device_driver rt_init(rt_priv *rt)
+{
+    rt->rx_blocking = 1;
+
+    if ( rt->rt_event )
+        free(rt->rt_event);
+    rt->rt_event = NULL;
+
+    rt->rt_event = (struct rt_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct rt_msg));
+
+    if (rt->rt_event == NULL) {
+        DBG("RT driver failed to allocated memory.");
+        return RTEMS_NO_MEMORY;
+    }
+
+    rt->ctrl_copy = rt->regs->ctrl & 0x3F00; /* Keep rtaddr and rtaddrp */
+    rt->ctrl_copy |= 0x3C0D0; /* broadcast disabled, extmdata=1, writetsw = writecmd = 1 */
+    rt->regs->ctrl = rt->ctrl_copy; 
+
+    /* Set Clock speed */
+    set_clkspd(rt, rt->cfg_freq);
+
+    rt->regs->addr = rt->memarea_base_remote;
+    rt->regs->ipm  = 0x70000; /* Enable RT RX, MEM Failure and AHB Error interrupts */
+
+    DBG("B1553RT DMA_AREA: 0x%x\n", (unsigned int)rt->mem);
+
+    return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver rt_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+    return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver rt_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) {
+    rt_priv *rt;
+    struct drvmgr_dev *dev;
+
+    FUNCDBG("rt_open\n");
+
+    if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+        DBG("Wrong minor %d\n", minor);
+        return RTEMS_UNSATISFIED;
+    }
+    rt = (rt_priv *)dev->priv;
+
+    if (rtems_semaphore_obtain(rt->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) {
+        DBG("rt_open: resource in use\n");
+        return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+    }
+
+    /* Set defaults */
+    rt->event_id = 0;
+
+    start_operation(rt);
+
+    /* Register interrupt routine */
+    if (drvmgr_interrupt_register(rt->dev, 0, "b1553rt", b1553rt_interrupt, rt)) {
+        rtems_semaphore_release(rt->dev_sem);
+        return -1;
+    }
+
+
+    return RTEMS_SUCCESSFUL;
+}
+ 
+static rtems_device_driver rt_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+    rt_priv *rt;
+    struct drvmgr_dev *dev;
+
+    FUNCDBG("rt_close");
+
+    if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+        return RTEMS_UNSATISFIED;
+    }
+    rt = (rt_priv *)dev->priv;
+
+    drvmgr_interrupt_unregister(rt->dev, 0, b1553rt_interrupt, rt);
+
+    stop_operation(rt);
+    rtems_semaphore_release(rt->dev_sem);
+
+    return RTEMS_SUCCESSFUL;
+}
+ 
+static int get_messages(rt_priv *rt, void *buf, unsigned int msg_count)
+{
+
+    struct rt_msg *dest = (struct rt_msg *) buf;
+    int count = 0;
+
+    if (rt->head == rt->tail) {
+        return 0;
+    }
+
+    do {
+
+        DBG("rt read - head: %d, tail: %d\n", rt->head, rt->tail);
+        dest[count++] = rt->rt_event[INDEX(rt->tail++)];
+
+    } while (rt->head != rt->tail && count < msg_count);
+
+    return count;
+
+}
+static rtems_device_driver rt_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+    rtems_libio_rw_args_t *rw_args;
+    int count = 0;
+    rt_priv *rt;
+    struct drvmgr_dev *dev;
+
+    if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+        return RTEMS_UNSATISFIED;
+    }
+    rt = (rt_priv *)dev->priv;
+
+    rw_args = (rtems_libio_rw_args_t *) arg;
+
+    FUNCDBG("rt_read [%i,%i]: buf: 0x%x, len: %i\n",major, minor, (unsigned int)rw_args->buffer, rw_args->count);
+
+    while ( (count = get_messages(rt,rw_args->buffer, rw_args->count)) == 0 ) {
+
+        if (rt->rx_blocking) {
+            rtems_semaphore_obtain(rt->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+        } else {
+            /* Translates to EBUSY */
+            return RTEMS_RESOURCE_IN_USE;
+        }
+    }
+
+    rw_args->bytes_moved = count;
+    return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver rt_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+    rtems_libio_rw_args_t *rw_args;
+    struct rt_msg *source;
+    rt_priv *rt;
+    struct drvmgr_dev *dev;
+    unsigned int descriptor, suba, wc;
+
+    if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+        return RTEMS_UNSATISFIED;
+    }
+    rt = (rt_priv *)dev->priv;
+
+    rw_args = (rtems_libio_rw_args_t *) arg;
+
+    if ( rw_args->count != 1 ) {
+        return RTEMS_INVALID_NAME;
+    }
+
+    source = (struct rt_msg *) rw_args->buffer;
+
+    descriptor = source[0].desc & 0x7F;
+    suba       = descriptor-32;
+    wc         = source[0].miw >> 11;
+    wc         = wc ? wc : 32;
+
+    FUNCDBG("rt_write [%i,%i]: buf: 0x%x\n",major, minor, (unsigned int)rw_args->buffer);
+
+    memcpy((void *)&rt->mem[0x400 + suba*32], &source[0].data[0], wc*2);
+
+    rw_args->bytes_moved = 1; 
+
+    return RTEMS_SUCCESSFUL;
+
+}
+
+static rtems_device_driver rt_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+    rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+    unsigned int *data = ioarg->buffer;
+
+    rt_priv *rt;
+    struct drvmgr_dev *dev;
+
+    FUNCDBG("rt_control[%d]: [%i,%i]\n", minor, major, minor);
+
+    if ( drvmgr_get_dev(&b1553rt_drv_info.general, minor, &dev) ) {
+        return RTEMS_UNSATISFIED;
+    }
+    rt = (rt_priv *)dev->priv;
+
+    if (!ioarg) {
+        DBG("rt_control: invalid argument\n");
+        return RTEMS_INVALID_NAME;
+    }
+
+    ioarg->ioctl_return = 0;
+    switch (ioarg->command) {
+
+    case RT_SET_ADDR:   
+        set_rtaddr(rt, data[0]);
+        break;
+
+    case RT_SET_BCE:
+        set_broadcast_en(rt, data[0]);
+        break;
+
+    case RT_SET_VECTORW:
+        set_vector_word(rt, data[0]);
+        break;
+
+    case RT_SET_EXTMDATA:
+        set_extmdata_en(rt, data[0]);
+        break;
+
+    case RT_RX_BLOCK: 
+        rt->rx_blocking     = data[0];   
+        break;
+
+    case RT_CLR_STATUS:
+        rt->status = 0;
+        break;
+
+    case RT_GET_STATUS: /* copy status */
+        if ( !ioarg->buffer )
+            return RTEMS_INVALID_NAME;
+            
+        *(unsigned int *)ioarg->buffer = rt->status;
+        break;
+
+    case RT_SET_EVENTID:
+        rt->event_id = (rtems_id)ioarg->buffer;
+        break;
+
+    default:
+        return RTEMS_NOT_IMPLEMENTED;
+    }
+
+    return RTEMS_SUCCESSFUL;
+}
+
+static void b1553rt_interrupt(void *arg)
+{
+    rt_priv *rt = arg;
+    unsigned short descriptor;
+    int signal_event=0, wake_rx_task=0;
+    unsigned int event_status=0;
+    unsigned int wc, irqv, cmd, tsw, suba, tx, miw, i;
+    unsigned int ipend;
+
+    #define SET_ERROR_DESCRIPTOR(descriptor) (event_status = (event_status & 0x0000ffff) | descriptor<<16)
+    ipend = rt->regs->ipm;
+
+    if (ipend == 0) {
+      /* IRQ mask has been cleared, we must have been reset */
+      /* Restore ctrl registers */
+      rt->regs->ctrl = rt->ctrl_copy;
+      rt->regs->addr = rt->memarea_base_remote;
+      rt->regs->ipm = 0x70000;
+      /* Send reset mode code event */
+      if (rt->head - rt->tail != EVENT_QUEUE_SIZE) {
+	miw = (8<<11);
+	descriptor = 64 + 32 + 8;
+	rt->rt_event[INDEX(rt->head)].miw = miw;
+	rt->rt_event[INDEX(rt->head)].time = 0;
+	rt->rt_event[INDEX(rt->head)].desc = descriptor;
+	rt->head++;
+      }
+    }
+
+    if ( ipend & 0x1 ) {
+      /* RT IRQ */
+      if (rt->head - rt->tail != EVENT_QUEUE_SIZE) {
+
+        irqv = rt->regs->irq;
+        cmd  = irqv >> 7;
+        wc   = cmd & 0x1F;       /* word count / mode code  */
+        suba = irqv & 0x1F;      /* sub address (0-31) */
+        tx   = (irqv >> 5) & 1;   
+ 
+        /* read status word */
+        tsw = READ_DMA(&rt->mem[tx*0x3E0+suba]); 
+
+        /* Build Message Information Word (B1553BRM-style) */
+        miw = (wc<<11) | (tsw&RT_TSW_BUS)>>4 | !(tsw&RT_TSW_OK)>>7 | (tsw&RT_TSW_ILL)>>5 | 
+            (tsw&RT_TSW_PAR)>>5 | (tsw&RT_TSW_MAN)>>7;
+
+        descriptor = (tx << 5) | suba;
+
+        /* Mode codes */
+        if (suba == 0 || suba == 31) {
+            descriptor = 64 + (tx*32) + wc;
+        }
+          
+        /* Data received or transmitted */
+        if (descriptor < 64) {
+            wc = wc ? wc : 32;   /* wc = 0 means 32 words transmitted */
+        }
+        /* RX Mode code */
+        else if (descriptor < 96) {
+            wc = (wc>>4);
+        }
+        /* TX Mode code */
+        else if (descriptor < 128) {
+            wc = (wc>>4);
+        }
+
+        /* Copy to event queue */
+        rt->rt_event[INDEX(rt->head)].miw  = miw;
+        rt->rt_event[INDEX(rt->head)].time = 0;
+
+        for (i = 0; i < wc; i++) {
+            rt->rt_event[INDEX(rt->head)].data[i] = READ_DMA(&rt->mem[tx*0x400 + suba*32 + i]);
+        }
+        rt->rt_event[INDEX(rt->head)].desc = descriptor;
+        rt->head++;
+
+
+        /* Handle errors */
+        if ( tsw & RT_TSW_ILL){
+            FUNCDBG("RT: RT_ILLCMD\n\r");
+            rt->status |= RT_ILLCMD_IRQ;
+            event_status |= RT_ILLCMD_IRQ;
+            SET_ERROR_DESCRIPTOR(descriptor);
+            signal_event=1;
+        }
+            
+        if ( !(tsw & RT_TSW_OK) ) {
+            FUNCDBG("RT: RT_MERR_IRQ\n\r");
+            rt->status |= RT_MERR_IRQ;
+            event_status |= RT_MERR_IRQ;
+            SET_ERROR_DESCRIPTOR(descriptor);
+            signal_event=1;
+        }
+	
+      }
+      else {
+        /* Indicate overrun */
+        rt->rt_event[INDEX(rt->head)].desc |= 0x8000;
+      }
+    }
+
+    if ( ipend & 0x2 ) {
+      /* Memory failure IRQ */
+      FUNCDBG("B1553RT: Memory failure\n");
+			event_status |= RT_DMAF_IRQ;
+			signal_event=1;
+    }
+
+    if ( ipend & 0x4 ) {
+      /* AHB Error */
+      FUNCDBG("B1553RT: AHB ERROR\n");
+			event_status |= RT_DMAF_IRQ;
+			signal_event=1;
+    }
+
+#ifdef DEBUG            
+    rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = descriptor; 
+    rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = cmd;
+    rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = miw;
+    rt->log[rt->log_i++ % EVENT_QUEUE_SIZE] = tsw;
+#endif
+
+    wake_rx_task = 1;
+
+    /* Wake any blocked rx thread only on receive interrupts */
+    if ( wake_rx_task ) {
+        rtems_semaphore_release(rt->rx_sem);
+    }
+
+    /* Copy current mask to status mask */
+    if ( event_status ) {
+        if ( event_status & 0xffff0000 )
+            rt->status &= 0x0000ffff;
+        rt->status |= event_status;
+    }
+
+    /* signal event once */
+    if ( signal_event && (rt->event_id != 0) ) {
+        rtems_event_send(rt->event_id, event_status);
+    }
+
+}
+
+void b1553rt_print_dev(struct drvmgr_dev *dev, int options)
+{
+    rt_priv *pDev = dev->priv;
+    struct amba_dev_info *devinfo;
+
+    devinfo = (struct amba_dev_info *)pDev->dev->businfo;
+
+    /* Print */
+    printf("--- B1553RT[%d] %s ---\n", pDev->minor, pDev->devName);
+    printf(" REGS:            0x%x\n", (unsigned int)pDev->regs);
+    printf(" IRQ:             %d\n", pDev->irqno);
+
+}
+
+void b1553rt_print(int options)
+{
+    struct amba_drv_info *drv = &b1553rt_drv_info;
+    struct drvmgr_dev *dev;
+
+    dev = drv->general.dev;
+    while(dev) {
+        b1553rt_print_dev(dev, options);
+        dev = dev->next_in_drv;
+    }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553b.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553b.c
new file mode 100644
index 0000000..26d7b40
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553b.c
@@ -0,0 +1,305 @@
+/*  GR1553B driver, used by BC, RT and/or BM driver
+ *
+ *  COPYRIGHT (c) 2010.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <gr1553b.h>
+
+/* Driver Manager interface for BC, RT, BM, BRM, BC-BM and RT-BM */
+
+#define GR1553B_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553B_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#define FEAT_BC 0x1
+#define FEAT_RT 0x2
+#define FEAT_BM 0x4
+
+#define ALLOC_BC 0x1
+#define ALLOC_RT 0x2
+#define ALLOC_BM 0x4
+
+struct gr1553_device {
+	struct drvmgr_dev *dev;
+	int features;
+	int alloc;
+};
+
+struct gr1553_device_feature {
+	struct gr1553_device_feature *next;
+	struct gr1553_device *dev;
+	int minor;
+};
+
+/* Device lists */
+struct gr1553_device_feature *gr1553_bm_root = NULL;
+struct gr1553_device_feature *gr1553_rt_root = NULL;
+struct gr1553_device_feature *gr1553_bc_root = NULL;
+
+/* Driver registered */
+int gr1553_driver_registerd = 0;
+
+/* Add 'feat' to linked list pointed to by 'root'. A minor is also assigned. */
+void gr1553_list_add
+	(
+	struct gr1553_device_feature **root,
+	struct gr1553_device_feature *feat
+	)
+{
+	int minor;
+	struct gr1553_device_feature *curr;
+
+	if ( *root == NULL ) {
+		*root = feat;
+		feat->next = NULL;
+		feat->minor = 0;
+		return;
+	}
+
+	minor = 0;
+retry_new_minor:
+	curr = *root;
+	while ( curr->next ) {
+		if ( curr->minor == minor ) {
+			minor++;
+			goto retry_new_minor;
+		}
+		curr = curr->next;
+	}
+
+	feat->next = NULL;
+	feat->minor = minor;
+	curr->next = feat;
+}
+
+struct gr1553_device_feature *gr1553_list_find
+	(
+	struct gr1553_device_feature *root,
+	int minor
+	)
+{
+	struct gr1553_device_feature *curr = root;
+	while ( curr ) {
+		if ( curr->minor == minor ) {
+			return curr;
+		}
+		curr = curr->next;
+	}
+	return NULL;
+}
+
+struct drvmgr_dev **gr1553_bc_open(int minor)
+{
+	struct gr1553_device_feature *feat;
+	
+	feat = gr1553_list_find(gr1553_bc_root, minor);
+	if ( feat == NULL )
+		return NULL;
+
+	/* Only possible to allocate is RT and BC is free,
+	 * this is beacuse it is not possible to use the
+	 * RT and the BC at the same time.
+	 */
+	if ( feat->dev->alloc & (ALLOC_BC|ALLOC_RT) )
+		return NULL;
+
+	/* Alloc BC device */
+	feat->dev->alloc |= ALLOC_BC;
+
+	return &feat->dev->dev;
+}
+
+void gr1553_bc_close(struct drvmgr_dev **dev)
+{
+	struct gr1553_device *d = (struct gr1553_device *)dev;
+
+	d->alloc &= ~ALLOC_BC;
+}
+
+struct drvmgr_dev **gr1553_rt_open(int minor)
+{
+	struct gr1553_device_feature *feat;
+
+	feat = gr1553_list_find(gr1553_rt_root, minor);
+	if ( feat == NULL )
+		return NULL;
+
+	/* Only possible to allocate is RT and BC is free,
+	 * this is beacuse it is not possible to use the
+	 * RT and the BC at the same time.
+	 */
+	if ( feat->dev->alloc & (ALLOC_BC|ALLOC_RT) )
+		return NULL;
+
+	/* Alloc RT device */
+	feat->dev->alloc |= ALLOC_RT;
+
+	return &feat->dev->dev;
+}
+
+void gr1553_rt_close(struct drvmgr_dev **dev)
+{
+	struct gr1553_device *d = (struct gr1553_device *)dev;
+
+	d->alloc &= ~ALLOC_RT;
+}
+
+struct drvmgr_dev **gr1553_bm_open(int minor)
+{
+	struct gr1553_device_feature *feat;
+	
+	feat = gr1553_list_find(gr1553_bm_root, minor);
+	if ( feat == NULL )
+		return NULL;
+
+	/* Only possible to allocate is RT and BC is free,
+	 * this is beacuse it is not possible to use the
+	 * RT and the BC at the same time.
+	 */
+	if ( feat->dev->alloc & ALLOC_BM )
+		return NULL;
+
+	/* Alloc BM device */
+	feat->dev->alloc |= ALLOC_BM;
+
+	return &feat->dev->dev;
+}
+
+void gr1553_bm_close(struct drvmgr_dev **dev)
+{
+	struct gr1553_device *d = (struct gr1553_device *)dev;
+
+	d->alloc &= ~ALLOC_BM;
+}
+
+int gr1553_init2(struct drvmgr_dev *dev)
+{
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	struct gr1553b_regs *regs;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)dev->businfo;
+	if ( ambadev == NULL ) {
+		return DRVMGR_FAIL;
+	}
+	pnpinfo = &ambadev->info;
+	regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+	/* Stop IRQ */
+	GR1553B_WRITE_REG(&regs->imask, 0);
+	GR1553B_WRITE_REG(&regs->irq, 0xffffffff);
+	/* Stop BC if not already stopped (just in case) */
+	GR1553B_WRITE_REG(&regs->bc_ctrl, 0x15520204);
+	/* Stop RT rx (just in case) */
+	GR1553B_WRITE_REG(&regs->rt_cfg, 0x15530000);
+	/* Stop BM logging (just in case) */
+	GR1553B_WRITE_REG(&regs->bm_ctrl, 0);
+
+	return DRVMGR_OK;
+}
+
+/* Register the different functionalities that the
+ * core supports.
+ */
+int gr1553_init3(struct drvmgr_dev *dev)
+{
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	struct gr1553_device *priv;
+	struct gr1553_device_feature *feat;
+	struct gr1553b_regs *regs;
+
+	priv = malloc(sizeof(struct gr1553_device));
+	if ( priv == NULL )
+		return DRVMGR_NOMEM;
+	priv->dev = dev;
+	priv->alloc = 0;
+	priv->features = 0;
+	dev->priv = NULL; /* Let higher level driver handle this */
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)dev->businfo;
+	if ( ambadev == NULL ) {
+		return DRVMGR_FAIL;
+	}
+	pnpinfo = &ambadev->info;
+	regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+	if ( GR1553B_READ_REG(&regs->bm_stat) & GR1553B_BM_STAT_BMSUP ) {
+		priv->features |= FEAT_BM;
+		feat = malloc(sizeof(struct gr1553_device_feature));
+		feat->dev = priv;
+		/* Init Minor and Next */
+		gr1553_list_add(&gr1553_bm_root, feat);
+	}
+
+	if ( GR1553B_READ_REG(&regs->bc_stat) & GR1553B_BC_STAT_BCSUP ) {
+		priv->features |= FEAT_BC;
+		feat = malloc(sizeof(struct gr1553_device_feature));
+		feat->dev = priv;
+		/* Init Minor and Next */
+		gr1553_list_add(&gr1553_bc_root, feat);
+	}
+
+	if ( GR1553B_READ_REG(&regs->rt_stat) & GR1553B_RT_STAT_RTSUP ) {
+		priv->features |= FEAT_RT;
+		feat = malloc(sizeof(struct gr1553_device_feature));
+		feat->dev = priv;
+		/* Init Minor and Next */
+		gr1553_list_add(&gr1553_rt_root, feat);
+	}
+
+	return DRVMGR_OK;
+}
+
+struct drvmgr_drv_ops gr1553_ops =
+{
+	{NULL, gr1553_init2, gr1553_init3, NULL},
+	NULL,
+	NULL
+};
+
+struct amba_dev_id gr1553_ids[] =
+{
+	{VENDOR_GAISLER, GAISLER_GR1553B},
+	{0, 0}	/* Mark end of table */
+};
+
+struct amba_drv_info gr1553_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,			/* Driver */
+		NULL,				/* Next driver */
+		NULL,				/* Device list */
+		DRIVER_AMBAPP_GAISLER_GR1553B_ID,/* Driver ID */
+		"GR1553_DRV",			/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,		/* Bus Type */
+		&gr1553_ops,
+		NULL,				/* Funcs */
+		0,				/* No devices yet */
+		0,
+	},
+	&gr1553_ids[0]
+};
+
+/* Multiple drivers may call this function. The drivers that depends on
+ * this driver:
+ *  - BM driver
+ *  - BC driver
+ *  - RT driver
+ */
+void gr1553_register(void)
+{
+	if ( gr1553_driver_registerd == 0 ) {
+		gr1553_driver_registerd = 1;
+	        drvmgr_drv_register(&gr1553_drv_info.general);
+	}
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c
new file mode 100644
index 0000000..4133200
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553bc.c
@@ -0,0 +1,1674 @@
+/*  GR1553B BC driver
+ *
+ *  COPYRIGHT (c) 2010.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <gr1553b.h>
+#include <gr1553bc.h>
+
+#define GR1553BC_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
+#define GR1553BC_READ_MEM(adr) (*(volatile uint32_t *)(adr))
+
+#define GR1553BC_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
+#define GR1553BC_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/* Needed by list for data pinter and BD translation */
+struct gr1553bc_priv {
+	struct drvmgr_dev **pdev;
+	struct gr1553b_regs *regs;
+	struct gr1553bc_list *list;
+	struct gr1553bc_list *alist;
+	int started;
+
+	/* IRQ log management */
+	void *irq_log_p;
+	uint32_t *irq_log_base;
+	uint32_t *irq_log_curr;
+	uint32_t *irq_log_end;
+	uint32_t *irq_log_base_hw;
+
+	/* Standard IRQ handler function */
+	bcirq_func_t irq_func;
+	void *irq_data;
+};
+
+
+/*************** LIST HANDLING ROUTINES ***************/
+
+/* This marks that the jump is a jump to next Minor.
+ * It is important that it sets one of the two LSB
+ * so that we can separate it from a JUMP-IRQ function,
+ * function pointers must be aligned to 4bytes.
+ *
+ * This marker is used to optimize the INDICATION process,
+ * from a descriptor pointer we can step to next Jump that
+ * has this MARKER set, then we know that the MID is stored
+ * there.
+ *
+ * The marker is limited to 1 byte.
+ */
+#define NEXT_MINOR_MARKER 0x01
+
+/* To separate ASYNC list from SYNC list we mark them differently, but with 
+ * LSB always set. This can be used to get the list the descriptor is a part
+ * of.
+ */
+#define NEXT_MINOR_MARKER_ASYNC 0x80
+
+struct gr1553bc_list_cfg gr1553bc_def_cfg =
+{
+	.rt_timeout = 
+		{
+			20, 20, 20, 20,
+			20, 20, 20, 20,
+			20, 20, 20, 20,
+			20, 20, 20, 20,
+			20, 20, 20, 20,
+			20, 20, 20, 20,
+			20, 20, 20, 20,
+			20, 20, 20			
+		},
+	.bc_timeout = 30,
+	.tropt_irq_on_err = 0,
+	.tropt_pause_on_err = 0,
+	.async_list = 0,
+};
+
+int gr1553bc_list_alloc(struct gr1553bc_list **list, int max_major)
+{
+	int size;
+	struct gr1553bc_list *l;
+
+	size = sizeof(struct gr1553bc_list) + max_major * sizeof(void *);
+	l = malloc(size);
+	if ( l == NULL )
+		return -1;
+	memset(l, 0, size);
+
+	l->major_cnt = max_major;
+	*list = l;
+
+	/* Set default options:
+	 *  - RT timeout tolerance 20us
+	 *  - Global transfer options used when generating transfer descriptors
+	 *  - No BC device, note that this only works when no translation is
+	 *    required
+	 */
+	if ( gr1553bc_list_config(l, &gr1553bc_def_cfg, NULL) ) {
+		free(l);
+		return -1;
+	}
+
+	return 0;
+}
+
+void gr1553bc_list_free(struct gr1553bc_list *list)
+{
+	gr1553bc_list_table_free(list);
+	free(list);
+}
+
+int gr1553bc_list_config
+	(
+	struct gr1553bc_list *list,
+	struct gr1553bc_list_cfg *cfg,
+	void *bc
+	)
+{
+	int timeout, i, tropts;
+
+	/* RT Time Tolerances */
+	for (i=0; i<31; i++) {
+		/* 0=14us, 1=18us ... 0xf=74us 
+		 * round upwards: 15us will be 18us
+		 */
+		timeout = ((cfg->rt_timeout[i] + 1)  - 14) / 4;
+		if ( (timeout > 0xf) || (timeout < 0) )
+			return -1;
+		list->rt_timeout[i] = timeout;
+	}
+	timeout = ((cfg->bc_timeout + 1) - 14) / 4;
+	if ( timeout > 0xf )
+		return -1;
+	list->rt_timeout[i] = timeout;
+
+	/* Transfer descriptor generation options */
+	tropts = 0;
+	if ( cfg->tropt_irq_on_err )
+		tropts |= 1<<28;
+	if ( cfg->tropt_pause_on_err )
+		tropts |= 1<<26;
+	list->tropts = tropts;
+
+	list->async_list = cfg->async_list;
+	list->bc = bc;
+
+	return 0;
+}
+
+void gr1553bc_list_link_major(
+	struct gr1553bc_major *major,
+	struct gr1553bc_major *next
+	)
+{
+	if ( major ) {
+		major->next = next;
+		if ( next ) {
+			major->minors[major->cfg->minor_cnt-1]->next = 
+				next->minors[0];
+		} else {
+			major->minors[major->cfg->minor_cnt-1]->next = NULL;
+		}
+	}
+}
+
+int gr1553bc_list_set_major(
+	struct gr1553bc_list *list,
+	struct gr1553bc_major *major,
+	int no)
+{
+	struct gr1553bc_major *prev, *next;
+
+	if ( no >= list->major_cnt )
+		return -1;
+
+	list->majors[no] = major;
+
+	/* Link previous Major frame with this one */
+	if ( no > 0 ) {
+		prev = list->majors[no-1];
+	} else {
+		/* First Major is linked with last major */
+		prev = list->majors[list->major_cnt-1];
+	}
+
+	/* Link to next Major if not the last one and if there is 
+	 * a next major
+	 */
+	if ( no == list->major_cnt-1 ) {
+		/* The last major, assume that it is connected with the first */
+		next = list->majors[0];
+	} else {
+		next = list->majors[no+1];
+	}
+
+	/* Link previous frame to jump into this */
+	gr1553bc_list_link_major(prev, major);
+
+	/* Link This frame to jump into the next */
+	gr1553bc_list_link_major(major, next);
+
+	return 0;
+}
+
+/* Translate Descriptor address from CPU-address to Hardware Address */
+static inline union gr1553bc_bd *gr1553bc_bd_cpu2hw
+	(
+	struct gr1553bc_list *list,
+	union gr1553bc_bd *bd
+	)
+{
+	return (union gr1553bc_bd *)(((unsigned int)bd - list->table_cpu) +
+		list->table_hw);
+}
+
+/* Translate Descriptor address from HW-address to CPU Address */
+static inline union gr1553bc_bd *gr1553bc_bd_hw2cpu
+	(
+	struct gr1553bc_list *list,
+	union gr1553bc_bd *bd
+	)
+{
+	return (union gr1553bc_bd *)(((unsigned int)bd - list->table_hw) +
+		list->table_cpu);
+}
+
+int gr1553bc_minor_table_size(struct gr1553bc_minor *minor)
+{
+	struct gr1553bc_minor_cfg *mincfg = minor->cfg;
+	int slot_cnt;
+
+	/* SLOTS + JUMP */
+	slot_cnt = mincfg->slot_cnt + 1;
+	if ( mincfg->timeslot ) {
+		/* time management requires 1 extra slot */
+		slot_cnt++;
+	}
+
+	return slot_cnt * GR1553BC_BD_SIZE;
+}
+
+int gr1553bc_list_table_size(struct gr1553bc_list *list)
+{
+	struct gr1553bc_major *major;
+	int i, j, minor_cnt, size;
+
+	size = 0;
+	for (i=0; i<list->major_cnt; i++) {
+		major = list->majors[i];
+		minor_cnt = major->cfg->minor_cnt;
+		for (j=0; j<minor_cnt; j++) {
+			/* 128-bit Alignment required by HW */
+			size += (GR1553BC_BD_ALIGN - 
+				(size & (GR1553BC_BD_ALIGN-1))) &
+				~(GR1553BC_BD_ALIGN-1);
+
+			/* Size required by descriptors */
+			size += gr1553bc_minor_table_size(major->minors[j]);
+		}
+	}
+
+	return size;
+}
+
+int gr1553bc_list_table_alloc
+	(
+	struct gr1553bc_list *list,
+	void *bdtab_custom
+	)
+{
+	struct gr1553bc_major *major;
+	int i, j, minor_cnt, size;
+	unsigned int table;
+	struct gr1553bc_priv *bcpriv = list->bc;
+
+	/* Free previous allocated descriptor table */
+	gr1553bc_list_table_free(list);
+
+	/* Remember user's settings for uninitialization */
+	list->_table_custom = bdtab_custom;
+
+	/* Get Size required for descriptors */
+	size = gr1553bc_list_table_size(list);
+
+	if ((unsigned int)bdtab_custom & 0x1) {
+		/* Address given in Hardware accessible address, we
+		 * convert it into CPU-accessible address.
+		 */
+		list->table_hw = (unsigned int)bdtab_custom & ~0x1;
+		list->_table = bdtab_custom;
+		drvmgr_translate_check(
+			*bcpriv->pdev,
+			DMAMEM_TO_CPU,
+			(void *)list->table_hw,
+			(void **)&list->table_cpu,
+			size);
+	} else {
+		if (bdtab_custom == NULL) {
+			/* Allocate descriptors */
+			list->_table = malloc(size + (GR1553BC_BD_ALIGN-1));
+			if ( list->_table == NULL )
+				return -1;
+		} else {
+			/* Custom address, given in CPU-accessible address */
+			list->_table = bdtab_custom;
+		}
+		/* 128-bit Alignment required by HW */
+		list->table_cpu =
+			(((unsigned int)list->_table + (GR1553BC_BD_ALIGN-1)) &
+			~(GR1553BC_BD_ALIGN-1));
+
+		/* We got CPU accessible descriptor table address, now we
+		 * translate that into an address that the Hardware can
+		 * understand
+		 */
+		if (bcpriv) {
+			drvmgr_translate_check(
+				*bcpriv->pdev,
+				CPUMEM_TO_DMA,
+				(void *)list->table_cpu,
+				(void **)&list->table_hw,
+				size
+				);
+		} else {
+			list->table_hw = list->table_cpu;
+		}
+	}
+
+	/* Write End-Of-List all over the descriptor table here,
+	 * For debugging/safety?
+	 */
+
+	/* Assign descriptors to all minor frames. The addresses is
+	 * CPU-accessible addresses.
+	 */
+	table = list->table_cpu;
+	for (i=0; i<list->major_cnt; i++) {
+		major = list->majors[i];
+		minor_cnt = major->cfg->minor_cnt;
+		for (j=0; j<minor_cnt; j++) {
+			/* 128-bit Alignment required by HW */
+			table = (table + (GR1553BC_BD_ALIGN-1)) &
+				~(GR1553BC_BD_ALIGN-1);
+			major->minors[j]->bds = (union gr1553bc_bd *)table;
+
+			/* Calc size required by descriptors */
+			table += gr1553bc_minor_table_size(major->minors[j]);
+		}
+	}
+
+	return 0;
+}
+
+void gr1553bc_list_table_free(struct gr1553bc_list *list)
+{
+	if ( (list->_table_custom == NULL) && list->_table ) {
+		free(list->_table);
+	}
+	list->_table = NULL;
+	list->_table_custom = NULL;
+	list->table_cpu = 0;
+	list->table_hw = 0;
+}
+
+/* Init descriptor table provided by each minor frame,
+ * we link them together using unconditional JUMP.
+ */
+int gr1553bc_list_table_build(struct gr1553bc_list *list)
+{
+	struct gr1553bc_major *major;
+	struct gr1553bc_minor *minor;
+	struct gr1553bc_minor_cfg *mincfg;
+	int i, j, k, minor_cnt, marker;
+	union gr1553bc_bd *bds, *hwbd;
+
+	marker = NEXT_MINOR_MARKER;
+	if ( list->async_list )
+		marker |= NEXT_MINOR_MARKER_ASYNC;
+
+	/* Create Major linking */
+	for (i=0; i<list->major_cnt; i++) {
+		major = list->majors[i];
+		minor_cnt = major->cfg->minor_cnt;
+		for (j=0; j<minor_cnt; j++) {
+			minor = major->minors[j];
+			mincfg = minor->cfg;
+			bds = minor->bds;
+
+			/* BD[0..SLOTCNT-1] = message slots
+			 * BD[SLOTCNT+0] = END 
+			 * BD[SLOTCNT+1] = JUMP
+			 *
+			 * or if no optional time slot handling:
+			 *
+			 * BD[0..SLOTCNT-1] = message slots
+			 * BD[SLOTCNT] = JUMP
+			 */
+
+			/* BD[0..SLOTCNT-1] */
+			for (k=0; k<mincfg->slot_cnt; k++) {
+				gr1553bc_bd_tr_init(
+					&bds[k].tr,
+					GR1553BC_TR_DUMMY_0,
+					GR1553BC_TR_DUMMY_1,
+					0,
+					0);
+			}
+
+			/* BD[SLOTCNT] (OPTIONAL)
+			 * If a minor frame is configured to be executed in
+			 * certain time (given a time slot), this descriptor
+			 * sums up all unused time. The time slot is
+			 * decremented when messages are inserted into the
+			 * minor frame and increased when messages are removed.
+			 */
+			if ( mincfg->timeslot > 0 ) {
+				gr1553bc_bd_tr_init(
+					&bds[k].tr,
+					GR1553BC_TR_DUMMY_0 | (mincfg->timeslot >> 2),
+					GR1553BC_TR_DUMMY_1,
+					0,
+					0);
+				k++;
+			}
+
+			/* Last descriptor is a jump to next minor frame, to a
+			 * synchronization point. If chain ends here, the list
+			 * is marked with a "end-of-list" marker.
+			 *
+			 */
+			if ( minor->next ) {
+				/* Translate CPU address of BD into HW address */
+				hwbd = gr1553bc_bd_cpu2hw(
+					list,
+					&minor->next->bds[0]
+					);
+				gr1553bc_bd_init(
+					&bds[k],
+					0xf,
+					GR1553BC_UNCOND_JMP,
+					(uint32_t)hwbd,
+					((GR1553BC_ID(i,j,k) << 8) | marker),
+					0
+					);
+			} else {
+				gr1553bc_bd_init(
+					&bds[k],
+					0xf,
+					GR1553BC_TR_EOL,
+					0,
+					((GR1553BC_ID(i,j,k) << 8) | marker),
+					0);
+			}
+		}
+	}
+
+	return 0;
+}
+
+void gr1553bc_bd_init(
+	union gr1553bc_bd *bd,
+	unsigned int flags,
+	uint32_t word0,
+	uint32_t word1,
+	uint32_t word2,
+	uint32_t word3
+	)
+{
+	struct gr1553bc_bd_raw *raw = &bd->raw;
+
+	if ( flags & 0x1 ) {
+		if ( (flags & KEEP_TIMESLOT) &&
+		     ((word0 & GR1553BC_BD_TYPE) == 0) ) {
+			/* Don't touch timeslot previously allocated */
+			word0 &= ~GR1553BC_TR_TIME;
+			word0 |= GR1553BC_READ_MEM(&raw->words[0]) & 
+					GR1553BC_TR_TIME;
+		}
+		GR1553BC_WRITE_MEM(&raw->words[0], word0);
+	}
+	if ( flags & 0x2 )
+		GR1553BC_WRITE_MEM(&raw->words[1], word1);
+	if ( flags & 0x4 )
+		GR1553BC_WRITE_MEM(&raw->words[2], word2);
+	if ( flags & 0x8 )
+		GR1553BC_WRITE_MEM(&raw->words[3], word3);
+}
+
+/* Alloc a Major frame according to the configuration structure */
+int gr1553bc_major_alloc_skel
+	(
+	struct gr1553bc_major **major,
+	struct gr1553bc_major_cfg *cfg
+	)
+{
+	struct gr1553bc_major *maj;
+	struct gr1553bc_minor *minor;
+	int size, i;
+
+	if ( (cfg == NULL) || (major == NULL) || (cfg->minor_cnt <= 0) )
+		return -1;
+
+	/* Allocate Major Frame description, but no descriptors */
+	size = sizeof(struct gr1553bc_major) + cfg->minor_cnt * 
+		(sizeof(struct gr1553bc_minor) + sizeof(void *));
+	maj = (struct gr1553bc_major *)malloc(size);
+	if ( maj == NULL )
+		return -1;
+
+	maj->cfg = cfg;
+	maj->next = NULL;
+
+	/* Create links between minor frames, and from minor frames 
+	 * to configuration structure.
+	 */
+	minor = (struct gr1553bc_minor *)&maj->minors[cfg->minor_cnt];
+	for (i=0; i<cfg->minor_cnt; i++, minor++) {
+		maj->minors[i] = minor;
+		minor->next = minor + 1;
+		minor->cfg = &cfg->minor_cfgs[i];
+		minor->alloc = 0;
+		minor->bds = NULL;
+	}
+	/* last Minor should point to next Major frame's first minor,
+	 * we do that somewhere else.
+	 */
+	(minor - 1)->next = NULL;
+
+	*major = maj;
+
+	return 0;
+}
+
+struct gr1553bc_major *gr1553bc_major_from_id
+	(
+	struct gr1553bc_list *list,
+	int mid
+	)
+{
+	int major_no;
+
+	/* Find Minor Frame from MID */
+	major_no = GR1553BC_MAJID_FROM_ID(mid);
+
+	if ( major_no >= list->major_cnt )
+		return NULL;
+	return list->majors[major_no];
+}
+
+struct gr1553bc_minor *gr1553bc_minor_from_id
+	(
+	struct gr1553bc_list *list,
+	int mid
+	)
+{
+	int minor_no;
+	struct gr1553bc_major *major;
+
+	/* Get Major from ID */
+	major = gr1553bc_major_from_id(list, mid);
+	if ( major == NULL )
+		return NULL;
+
+	/* Find Minor Frame from MID */
+	minor_no = GR1553BC_MINID_FROM_ID(mid);
+
+	if ( minor_no >= major->cfg->minor_cnt )
+		return NULL;
+	return major->minors[minor_no];
+}
+
+union gr1553bc_bd *gr1553bc_slot_bd
+	(
+	struct gr1553bc_list *list,
+	int mid
+	)
+{
+	struct gr1553bc_minor *minor;
+	int slot_no;
+
+	/*** look up BD ***/
+
+	/* Get minor */
+	minor = gr1553bc_minor_from_id(list, mid);
+	if ( minor == NULL )
+		return NULL;
+
+	/* Get Slot */
+	slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+	if ( slot_no >= 0xff )
+		slot_no = 0;
+
+	/* Get BD address */
+	return &minor->bds[slot_no];
+}
+
+int gr1553bc_minor_first_avail(struct gr1553bc_minor *minor)
+{
+	int slot_num;
+	uint32_t alloc;
+
+	alloc = minor->alloc;
+	if ( alloc == 0xffffffff ) {
+		/* No free */
+		return -1;
+	}
+	slot_num = 0;
+	while ( alloc & 1 ) {
+		alloc = alloc >> 1;
+		slot_num++;
+	}
+	if ( slot_num >= minor->cfg->slot_cnt ) {
+		/* no free */
+		return -1;
+	}
+	return slot_num;
+}
+
+int gr1553bc_slot_alloc(
+	struct gr1553bc_list *list,
+	int *mid,
+	int timeslot,
+	union gr1553bc_bd **bd
+	)
+{
+	struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, *mid);
+
+	return gr1553bc_slot_alloc2(minor, mid, timeslot, bd);
+}
+
+/* Same as gr1553bc_slot_alloc but identifies a minor instead of list.
+ * The major/minor part of MID is ignored.
+ */
+int gr1553bc_slot_alloc2(
+	struct gr1553bc_minor *minor,
+	int *mid,
+	int timeslot,
+	union gr1553bc_bd **bd
+	)
+{
+	int slot_no;
+	uint32_t set0;
+	int timefree;
+	struct gr1553bc_bd_tr *trbd;
+	struct gr1553bc_minor_cfg *mincfg;
+
+	if ( minor == NULL )
+		return -1;
+
+	mincfg = minor->cfg;
+
+	/* Find first free slot if not a certain slot is requested */
+	slot_no = GR1553BC_SLOTID_FROM_ID(*mid);
+	if ( slot_no == 0xff ) {
+		slot_no = gr1553bc_minor_first_avail(minor);
+		if ( slot_no < 0 )
+			return -1;
+	} else {
+		/* Allocate a certain slot, check that it is free */
+		if ( slot_no >= mincfg->slot_cnt )
+			return -1;
+		if ( (1<<slot_no) & minor->alloc )
+			return -1;
+	}
+
+	/* Ok, we got our slot. Lets allocate time for slot if requested by user
+	 * and time management is enabled for this Minor Frame.
+	 */
+	if ( timeslot > 0 ) {
+		/* Make timeslot on a 4us boundary (time resolution of core) */
+		timeslot = (timeslot + 0x3) >> 2;
+
+		if ( mincfg->timeslot ) {
+			/* Subtract requested time from free time */
+			trbd = &minor->bds[mincfg->slot_cnt].tr;
+			set0 = GR1553BC_READ_MEM(&trbd->settings[0]);
+			timefree = set0 & GR1553BC_TR_TIME;
+			if ( timefree < timeslot ) {
+				/* Not enough time left to schedule slot in minor */
+				return -1;
+			}
+			/* Store back the time left */
+			timefree -= timeslot;
+			set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
+			GR1553BC_WRITE_MEM(&trbd->settings[0], set0);
+			/* Note: at the moment the minor frame can be executed faster
+			 *       than expected, we hurry up writing requested 
+			 *       descriptor.
+			 */
+		}
+	}
+
+	/* Make the allocated descriptor be an empty slot with the
+	 * timeslot requested.
+	 */
+	trbd = &minor->bds[slot_no].tr;
+	gr1553bc_bd_tr_init(
+		trbd,
+		GR1553BC_TR_DUMMY_0 | timeslot,
+		GR1553BC_TR_DUMMY_1,
+		0,
+		0);
+
+	/* Allocate slot */
+	minor->alloc |= 1<<slot_no;
+
+	if ( bd )
+		*bd = (union gr1553bc_bd *)trbd;
+	*mid = GR1553BC_ID_SET_SLOT(*mid, slot_no);
+
+	return 0;
+}
+
+/* Return time slot freed (if time is managed by driver), negative on error */
+int gr1553bc_slot_free(struct gr1553bc_list *list, int mid)
+{
+	struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, mid);
+
+	return gr1553bc_slot_free2(minor, mid);
+}
+
+/* Return time slot freed (if time is managed by driver), negative on error */
+int gr1553bc_slot_free2(struct gr1553bc_minor *minor, int mid)
+{
+	union gr1553bc_bd *bd;
+	struct gr1553bc_bd_tr *endbd;
+	struct gr1553bc_minor_cfg *mincfg;
+	int slot_no, timeslot, timefree;
+	uint32_t word0, set0;
+
+	if ( minor == NULL )
+		return -1;
+
+	slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+
+	if ( (minor->alloc & (1<<slot_no)) == 0 )
+		return -1;
+
+	bd = &minor->bds[slot_no];
+
+	/* If the driver handles time for this minor frame, return
+	 * time if previuosly requested.
+	 */
+	timeslot = 0;
+	mincfg = minor->cfg;
+	if ( mincfg->timeslot > 0 ) {
+		/* Find out if message slot had time allocated */
+		word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
+		if ( word0 & GR1553BC_BD_TYPE ) {
+			/* Condition ==> no time slot allocated */
+		} else {
+			/* Transfer descriptor, may have time slot */
+			timeslot = word0 & GR1553BC_TR_TIME;
+			if ( timeslot > 0 ) {
+				/* Return previously allocated time to END
+				 * TIME descriptor.
+				 */
+				endbd = &minor->bds[mincfg->slot_cnt].tr;
+				set0 = GR1553BC_READ_MEM(&endbd->settings[0]);
+				timefree = set0 & GR1553BC_TR_TIME;
+				timefree += timeslot;
+				set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
+				GR1553BC_WRITE_MEM(&endbd->settings[0], set0);
+				/* Note: at the moment the minor frame can be
+				 *       executed slower than expected, the
+				 *       timeslot is at two locations.
+				 */
+			}
+		}
+	}
+
+	/* Make slot an empty message */
+	gr1553bc_bd_tr_init(
+		&bd->tr,
+		GR1553BC_TR_DUMMY_0,
+		GR1553BC_TR_DUMMY_1,
+		0,
+		0);
+
+	/* unallocate descriptor */
+	minor->alloc &= ~(1<<slot_no);
+
+	/* Return time freed in microseconds */
+	return timeslot << 2;
+}
+
+int gr1553bc_list_freetime(struct gr1553bc_list *list, int mid)
+{
+	struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, mid);
+
+	return gr1553bc_minor_freetime(minor);
+}
+
+int gr1553bc_minor_freetime(struct gr1553bc_minor *minor)
+{
+	struct gr1553bc_bd_tr *endbd;
+	struct gr1553bc_minor_cfg *mincfg;
+	int timefree;
+	uint32_t set0;
+
+	if ( minor == NULL )
+		return -1;
+
+	/* If the driver handles time for this minor frame, return
+	 * time if previuosly requested.
+	 */
+	timefree = 0;
+	mincfg = minor->cfg;
+	if ( mincfg->timeslot > 0 ) {
+		/* Return previously allocated time to END
+		 * TIME descriptor.
+		 */
+		endbd = &minor->bds[mincfg->slot_cnt].tr;
+		set0 = GR1553BC_READ_MEM(&endbd->settings[0]);
+		timefree = (set0 & GR1553BC_TR_TIME) << 2;
+	}
+
+	/* Return time freed */
+	return timefree;
+}
+
+int gr1553bc_slot_raw
+	(
+	struct gr1553bc_list *list,
+	int mid,
+	unsigned int flags,
+	uint32_t word0,
+	uint32_t word1,
+	uint32_t word2,
+	uint32_t word3
+	)
+{
+	struct gr1553bc_minor *minor;
+	union gr1553bc_bd *bd;
+	int slot_no;
+
+	minor = gr1553bc_minor_from_id(list, mid);
+	if ( minor == NULL )
+		return -1;
+
+	/* Get Slot */
+	slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+	if ( slot_no >= minor->cfg->slot_cnt ) {
+		return -1;
+	}
+
+	/* Get descriptor */
+	bd = &minor->bds[slot_no];
+
+	/* Build empty descriptor. */
+	gr1553bc_bd_init(
+		bd,
+		flags,
+		word0,
+		word1,
+		word2,
+		word3);
+
+	return 0;
+}
+
+/* Create unconditional IRQ customly defined location
+ * The IRQ is disabled, enable it with gr1553bc_slot_irq_enable().
+ */
+int gr1553bc_slot_irq_prepare
+	(
+	struct gr1553bc_list *list,
+	int mid,
+	bcirq_func_t func,
+	void *data
+	)
+{
+	union gr1553bc_bd *bd;
+	int slot_no, to_mid;
+
+	/* Build unconditional IRQ descriptor. The padding is used 
+	 * for identifying the MINOR frame and function and custom data.
+	 *
+	 * The IRQ is disabled at first, a unconditional jump to next
+	 * descriptor in table.
+	 */
+
+	/* Get BD address of jump destination */
+	slot_no = GR1553BC_SLOTID_FROM_ID(mid);
+	to_mid = GR1553BC_ID_SET_SLOT(mid, slot_no + 1);
+	bd = gr1553bc_slot_bd(list, to_mid);
+	if ( bd == NULL )
+		return -1;
+	bd = gr1553bc_bd_cpu2hw(list, bd);
+
+	return gr1553bc_slot_raw(
+		list,
+		mid,
+		0xF,
+		GR1553BC_UNCOND_JMP,
+		(uint32_t)bd,
+		(uint32_t)func,
+		(uint32_t)data
+		);
+}
+
+/* Enable previously prepared unconditional IRQ */
+int gr1553bc_slot_irq_enable(struct gr1553bc_list *list, int mid)
+{
+	/* Leave word1..3 untouched:
+	 *  1. Unconditional Jump address
+	 *  2. Function
+	 *  3. Custom Data
+	 *
+	 * Since only one bit is changed in word0 (Condition word),
+	 * no hardware/software races will exist ==> it is safe
+	 * to enable/disable IRQ at any time independent of where
+	 * hardware is in table.
+	 */
+	return gr1553bc_slot_raw(
+		list,
+		mid,
+		0x1,	/* change only WORD0 */
+		GR1553BC_UNCOND_IRQ,
+		0,
+		0,
+		0);
+}
+
+/* Disable unconditional IRQ point, changed to unconditional JUMP
+ * to descriptor following.
+ * After disabling it it can be enabled again, or freed.
+ */
+int gr1553bc_slot_irq_disable(struct gr1553bc_list *list, int mid)
+{
+	return gr1553bc_slot_raw(
+		list,
+		mid,
+		0x1,	/* change only WORD0, JUMP address already set */
+		GR1553BC_UNCOND_JMP,
+		0,
+		0,
+		0);
+}
+
+int gr1553bc_slot_empty(struct gr1553bc_list *list, int mid)
+{
+	return gr1553bc_slot_raw(
+		list,
+		mid,
+		0xF | KEEP_TIMESLOT,
+		GR1553BC_TR_DUMMY_0,
+		GR1553BC_TR_DUMMY_1,
+		0,
+		0);
+}
+
+int gr1553bc_slot_exttrig(struct gr1553bc_list *list, int mid)
+{
+	return gr1553bc_slot_raw(
+		list,
+		mid,
+		0xF | KEEP_TIMESLOT,
+		GR1553BC_TR_DUMMY_0 | GR1553BC_TR_EXTTRIG,
+		GR1553BC_TR_DUMMY_1,
+		0,
+		0);
+}
+
+int gr1553bc_slot_jump
+	(
+	struct gr1553bc_list *list,
+	int mid,
+	uint32_t condition,
+	int to_mid
+	)
+{
+	union gr1553bc_bd *bd;
+
+	/* Get BD address */
+	bd = gr1553bc_slot_bd(list, to_mid);
+	if ( bd == NULL )
+		return -1;
+	/* Convert into an address that the HW understand */
+	bd = gr1553bc_bd_cpu2hw(list, bd);
+
+	return gr1553bc_slot_raw(
+		list,
+		mid,
+		0xF,
+		condition,
+		(uint32_t)bd,
+		0,
+		0);
+}
+
+int gr1553bc_slot_transfer(
+	struct gr1553bc_list *list,
+	int mid,
+	int options,
+	int tt,
+	uint16_t *dptr)
+{
+	uint32_t set0, set1;
+	union gr1553bc_bd *bd;
+	int rx_rtadr, tx_rtadr, timeout;
+
+	/* Get BD address */
+	bd = gr1553bc_slot_bd(list, mid);
+	if ( bd == NULL )
+		return -1;
+
+	/* Translate Data pointer from CPU-local to 1553-core accessible
+	 * address if user wants that. This may be useful for AMBA-over-PCI
+	 * cores.
+	 */
+	if ( (unsigned int)dptr & 0x1 ) {
+		struct gr1553bc_priv *bcpriv = list->bc;
+
+		drvmgr_translate(
+			*bcpriv->pdev,
+			CPUMEM_TO_DMA,
+			(void *)((unsigned int)dptr & ~0x1),
+			(void **)&dptr);
+	}
+
+	/* It is assumed that the descriptor has already been initialized
+	 * as a empty slot (Dummy bit set), so to avoid races the dummy
+	 * bit is cleared last.
+	 *
+	 * If we knew that the write would do a burst (for example over SpW)
+	 * it would be safe to write in order.
+	 */
+
+	/* Preserve timeslot */
+	set0 = GR1553BC_READ_MEM(&bd->tr.settings[0]);
+	set0 &= GR1553BC_TR_TIME;
+	set0 |= options & 0x61f00000;
+	set0 |= list->tropts; /* Global options */
+
+	/* Set transfer type, bus and let RT tolerance table descide
+	 * responce tolerance.
+	 *
+	 * If a destination address is specified the longest timeout
+	 * tolerance is taken.
+	 */
+	rx_rtadr = (tt >> 22) & 0x1f;
+	tx_rtadr = (tt >> 12) & 0x1f;
+	if ( (tx_rtadr != 0x1f) &&
+	     (list->rt_timeout[rx_rtadr] < list->rt_timeout[tx_rtadr]) ) {
+		timeout = list->rt_timeout[tx_rtadr];
+	} else {
+		timeout = list->rt_timeout[rx_rtadr];
+	}
+	set1 = ((timeout & 0xf) << 27) | (tt & 0x27ffffff) | ((options & 0x3)<<30);
+
+	GR1553BC_WRITE_MEM(&bd->tr.settings[0], set0);
+	GR1553BC_WRITE_MEM(&bd->tr.dptr, (uint32_t)dptr);
+	/* Write UNUSED BIT, when cleared it Indicates that BC has written it */
+	GR1553BC_WRITE_MEM(&bd->tr.status, 0x80000000);
+	GR1553BC_WRITE_MEM(&bd->tr.settings[1], set1);
+
+	return 0;
+}
+
+int gr1553bc_slot_update
+	(
+	struct gr1553bc_list *list,
+	int mid,
+	uint16_t *dptr,
+	unsigned int *stat
+	)
+{
+	union gr1553bc_bd *bd;
+	unsigned int status;
+	unsigned int dataptr = (unsigned int)dptr;
+
+	/* Get BD address */
+	bd = gr1553bc_slot_bd(list, mid);
+	if ( bd == NULL )
+		return -1;
+
+	/* Write new Data Pointer if needed */
+	if ( dataptr ) {
+		struct gr1553bc_priv *bcpriv = list->bc;
+
+		/* Translate Data pointer from CPU-local to 1553-core accessible
+		 * address if user wants that. This may be useful for AMBA-over-PCI
+		 * cores.
+		 */
+		if ( dataptr & 0x1 ) {
+			drvmgr_translate(
+				*bcpriv->pdev,
+				CPUMEM_TO_DMA,
+				(void *)(dataptr & ~0x1),
+				(void **)&dptr
+				);
+		}
+
+		/* Update Data Pointer */
+		GR1553BC_WRITE_MEM(&bd->tr.dptr, dataptr);
+	}
+
+	/* Get status of transfer descriptor */
+	if ( stat ) {
+		status = *stat;
+		*stat = GR1553BC_READ_MEM(&bd->tr.status);
+		if ( status ) {
+			/* Clear status fields user selects, then
+			 * or bit31 if user wants that. The bit31 
+			 * may be used to indicate if the BC has
+			 * performed the access.
+			 */
+			status = (*stat & (status & 0xffffff)) |
+				 (status & (1<<31));
+			GR1553BC_WRITE_MEM(&bd->tr.status, status);
+		}
+	}
+
+	return 0;
+}
+
+int gr1553bc_slot_dummy(
+	struct gr1553bc_list *list,
+	int mid,
+	unsigned int *dummy)
+{
+	union gr1553bc_bd *bd;
+	unsigned int set1, new_set1;
+
+	/* Get BD address */
+	bd = gr1553bc_slot_bd(list, mid);
+	if ( bd == NULL )
+		return -1;
+	/* Update the Dummy Bit */
+	set1 = GR1553BC_READ_MEM(&bd->tr.settings[1]);
+	new_set1 = (set1 & ~GR1553BC_TR_DUMMY_1) | (*dummy & GR1553BC_TR_DUMMY_1);
+	GR1553BC_WRITE_MEM(&bd->tr.settings[1], new_set1);
+
+	*dummy = set1;
+
+	return 0;
+}
+
+/* Find MID from Descriptor pointer */
+int gr1553bc_mid_from_bd(
+	union gr1553bc_bd *bd,
+	int *mid,
+	int *async
+	)
+{
+	int i, bdmid, slot_no;
+	uint32_t word0, word2;
+
+	/* Find Jump to next Minor Frame or End-Of-List,
+	 * at those locations we have stored a MID
+	 *
+	 * GR1553BC_SLOT_MAX+2 = Worst case, BD is max distance from jump
+	 *                       descriptor. 2=END and Jump descriptors.
+	 */
+	for (i=0; i<GR1553BC_SLOT_MAX+2; i++) {
+		word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
+		if ( word0 & GR1553BC_BD_TYPE ) {
+			if ( word0 == GR1553BC_UNCOND_JMP ) {
+				/* May be a unconditional IRQ set by user. In
+				 * that case the function is stored in WORD3,
+				 * functions must be aligned to 4 byte boudary.
+				 */
+				word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
+				if ( word2 & NEXT_MINOR_MARKER ) {
+					goto found_mid;
+				}
+			} else if ( word0 == GR1553BC_TR_EOL ) {
+				/* End-Of-List, does contain a MID */
+				word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
+				goto found_mid;
+			}
+		}
+		bd++;
+	}
+
+	return -1;
+
+found_mid:
+	/* Get MID of JUMP descriptor */
+	bdmid = word2 >> 8;
+	/* Subtract distance from JUMP descriptor to find MID 
+	 * of requested BD.
+	 */
+	slot_no = GR1553BC_SLOTID_FROM_ID(bdmid);
+	slot_no -= i;
+	bdmid = GR1553BC_ID_SET_SLOT(bdmid, slot_no);
+
+	if ( mid )
+		*mid = bdmid;
+
+	/* Determine which list BD belongs to: async or sync */
+	if ( async )
+		*async = word2 & NEXT_MINOR_MARKER_ASYNC;
+
+	return 0;
+}
+
+/*************** END OF LIST HANDLING ROUTINES ***************/
+
+/*************** DEVICE HANDLING ROUTINES ***************/
+
+void gr1553bc_device_init(struct gr1553bc_priv *priv);
+void gr1553bc_device_uninit(struct gr1553bc_priv *priv);
+void gr1553bc_isr(void *data);
+
+/*** GR1553BC driver ***/
+
+void gr1553bc_register(void)
+{
+	/* The BC driver rely on the GR1553B Driver */
+	gr1553_register();
+}
+
+void gr1553bc_isr_std(union gr1553bc_bd *bd, void *data)
+{
+	/* Do nothing */
+}
+
+/* Take a GR1553BC hardware device identified by minor.
+ * A pointer is returned that is used internally by the GR1553BC
+ * driver, it is used as an input paramter 'bc' to all other
+ * functions that manipulate the hardware.
+ */
+void *gr1553bc_open(int minor)
+{
+	struct drvmgr_dev **pdev = NULL;
+	struct gr1553bc_priv *priv = NULL;
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	void *irq_log_p = NULL;
+
+	/* Allocate requested device */
+	pdev = gr1553_bc_open(minor);
+	if ( pdev == NULL )
+		goto fail;
+
+	irq_log_p = malloc(GR1553BC_IRQLOG_SIZE*2);
+	if ( irq_log_p == NULL )
+		goto fail;
+
+	priv = malloc(sizeof(struct gr1553bc_priv));
+	if ( priv == NULL )
+		goto fail;
+	memset(priv, 0, sizeof(struct gr1553bc_priv));
+
+	/* Init BC device */
+	priv->pdev = pdev;
+	(*pdev)->priv = priv;
+	priv->irq_log_p = irq_log_p;
+	priv->started = 0;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)(*pdev)->businfo;
+	pnpinfo = &ambadev->info;
+	priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+	gr1553bc_device_init(priv);
+
+	/* Register ISR handler (unmask at IRQ controller) */
+	if ( drvmgr_interrupt_register(*priv->pdev, 0, "gr1553bc",
+	     gr1553bc_isr, priv) ) {
+		goto fail;
+	}
+
+	return priv;
+
+fail:
+	if ( pdev )
+		gr1553_bc_close(pdev);
+	if ( irq_log_p )
+		free(irq_log_p);
+	if ( priv )
+		free(priv);
+	return NULL;
+}
+
+void gr1553bc_close(void *bc)
+{
+	struct gr1553bc_priv *priv = bc;
+
+	/* Stop Hardware */
+	gr1553bc_stop(bc, 0x3);
+
+	gr1553bc_device_uninit(priv);
+
+	/* Remove interrupt handler (mask IRQ at IRQ controller) */
+	drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553bc_isr, priv);
+
+	/* Free device */
+	gr1553_bc_close(priv->pdev);
+	free(priv->irq_log_p);
+	free(priv);
+}
+
+/* Return Current Minor frame number */
+int gr1553bc_indication(void *bc, int async, int *mid)
+{
+	struct gr1553bc_priv *priv = bc;
+	union gr1553bc_bd *bd;
+
+	/* Get current descriptor pointer */
+	if ( async ) {
+		bd = (union gr1553bc_bd *)
+			GR1553BC_READ_REG(&priv->regs->bc_aslot);
+		bd = gr1553bc_bd_hw2cpu(priv->alist, bd);
+	} else {
+		bd = (union gr1553bc_bd *)
+			GR1553BC_READ_REG(&priv->regs->bc_slot);
+		bd = gr1553bc_bd_hw2cpu(priv->list, bd);
+	}
+
+	return gr1553bc_mid_from_bd(bd, mid, NULL);
+}
+
+/* Start major frame processing, wait for TimerManager tick or start directly */
+int gr1553bc_start(void *bc, struct gr1553bc_list *list, struct gr1553bc_list *list_async)
+{
+	struct gr1553bc_priv *priv = bc;
+	union gr1553bc_bd *bd = NULL, *bd_async = NULL;
+	uint32_t ctrl, irqmask;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	if ( (list == NULL) && (list_async == NULL) )
+		return 0;
+
+	/* Find first descriptor in list, the descriptor
+	 * first to be executed.
+	 */
+	ctrl = GR1553BC_KEY;
+	if ( list ) {
+		bd = gr1553bc_slot_bd(list, GR1553BC_ID(0,0,0));
+		if ( bd == NULL )
+			return -1;
+		bd = gr1553bc_bd_cpu2hw(list, bd);
+		ctrl |= GR1553B_BC_ACT_SCSRT;
+	}
+	if ( list_async ) {
+		bd_async = gr1553bc_slot_bd(list_async, GR1553BC_ID(0,0,0));
+		if ( bd_async == NULL )
+			return -1;
+		bd_async = gr1553bc_bd_cpu2hw(list_async, bd_async);
+		ctrl |= GR1553B_BC_ACT_ASSRT;
+	}
+
+	/* Do "hot-swapping" of lists */
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	if ( list ) {
+		priv->list = list;
+		GR1553BC_WRITE_REG(&priv->regs->bc_bd, (uint32_t)bd);
+	}
+	if ( list_async ) {
+		priv->alist = list_async;
+		GR1553BC_WRITE_REG(&priv->regs->bc_abd, (uint32_t)bd_async);
+	}
+
+	/* If not enabled before, we enable it now. */
+	GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+
+	/* Enable IRQ */
+	if ( priv->started == 0 ) {
+		priv->started = 1;
+		irqmask = GR1553BC_READ_REG(&priv->regs->imask);
+		irqmask |= GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE;
+		GR1553BC_WRITE_REG(&priv->regs->imask, irqmask);
+	}
+
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return 0;
+}
+
+/* Pause GR1553 BC transfers */
+int gr1553bc_pause(void *bc)
+{
+	struct gr1553bc_priv *priv = bc;
+	uint32_t ctrl;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	/* Do "hot-swapping" of lists */
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	ctrl = GR1553BC_KEY | GR1553B_BC_ACT_SCSUS;
+	GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return 0;
+}
+
+/* Restart GR1553 BC transfers, after being paused */
+int gr1553bc_restart(void *bc)
+{
+	struct gr1553bc_priv *priv = bc;
+	uint32_t ctrl;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	ctrl = GR1553BC_KEY | GR1553B_BC_ACT_SCSRT;
+	GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return 0;
+}
+
+/* Stop BC transmission */
+int gr1553bc_stop(void *bc, int options)
+{
+	struct gr1553bc_priv *priv = bc;
+	uint32_t ctrl;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	ctrl = GR1553BC_KEY;
+	if ( options & 0x1 )
+		ctrl |= GR1553B_BC_ACT_SCSTP;
+	if ( options & 0x2 )
+		ctrl |= GR1553B_BC_ACT_ASSTP;
+
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
+	priv->started = 0;
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return 0;
+}
+
+/* Reset software and BC hardware into a known "unused/init" state */
+void gr1553bc_device_init(struct gr1553bc_priv *priv)
+{
+/* RESET HARDWARE REGISTERS */
+	/* Stop BC if not already stopped */
+	GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
+
+	/* Since RT can not be used at the same time as BC, we stop 
+	 * RT rx, it should already be stopped...
+	 */
+	GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
+
+	/* Clear some registers */
+	GR1553BC_WRITE_REG(&priv->regs->bc_bd, 0);
+	GR1553BC_WRITE_REG(&priv->regs->bc_abd, 0);
+	GR1553BC_WRITE_REG(&priv->regs->bc_timer, 0);
+	GR1553BC_WRITE_REG(&priv->regs->bc_wake, 0);
+	GR1553BC_WRITE_REG(&priv->regs->bc_irqptr, 0);
+	GR1553BC_WRITE_REG(&priv->regs->bc_busmsk, 0);
+
+/* PUT SOFTWARE INTO INITIAL STATE */
+	priv->list = NULL;
+	priv->alist = NULL;
+
+	priv->irq_log_base = (uint32_t *)
+		(((uint32_t)priv->irq_log_p + (GR1553BC_IRQLOG_SIZE-1)) & 
+		~(GR1553BC_IRQLOG_SIZE-1));
+	/* Translate into a hardware accessible address */
+	drvmgr_translate_check(
+		*priv->pdev,
+		CPUMEM_TO_DMA,
+		(void *)priv->irq_log_base,
+		(void **)&priv->irq_log_base_hw,
+		GR1553BC_IRQLOG_SIZE);
+	priv->irq_log_curr = priv->irq_log_base;
+	priv->irq_log_end = &priv->irq_log_base[GR1553BC_IRQLOG_CNT-1];
+	priv->irq_func = gr1553bc_isr_std;
+	priv->irq_data = NULL;
+
+	GR1553BC_WRITE_REG(&priv->regs->bc_irqptr,(uint32_t)priv->irq_log_base_hw);
+}
+
+void gr1553bc_device_uninit(struct gr1553bc_priv *priv)
+{
+	uint32_t irqmask;
+
+	/* Stop BC if not already stopped */
+	GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
+
+	/* Since RT can not be used at the same time as BC, we stop 
+	 * RT rx, it should already be stopped...
+	 */
+	GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
+
+	/* Turn off IRQ generation */
+	irqmask=GR1553BC_READ_REG(&priv->regs->imask);
+	irqmask&=~(GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE);
+	GR1553BC_WRITE_REG(&priv->regs->irq, irqmask);
+}
+
+/* Interrupt handler */
+void gr1553bc_isr(void *arg)
+{
+	struct gr1553bc_priv *priv = arg;
+	uint32_t *curr, *pos, word0, word2;
+	union gr1553bc_bd *bd;
+	bcirq_func_t func;
+	void *data;
+	int handled, irq;
+
+	/* Did core make IRQ */
+	irq = GR1553BC_READ_REG(&priv->regs->irq);
+	irq &= (GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE);
+	if ( irq == 0 )
+		return; /* Shared IRQ: some one else may have caused the IRQ */
+
+	/* Clear handled IRQs */
+	GR1553BC_WRITE_REG(&priv->regs->irq, irq);
+
+	/* DMA error. This IRQ does not affect the IRQ log. 
+	 * We let standard IRQ handle handle it.
+	 */
+	if ( irq & GR1553B_IRQEN_BCDE ) {
+		priv->irq_func(NULL, priv->irq_data);
+	}
+
+	/* Get current posistion in hardware */
+	pos = (uint32_t *)GR1553BC_READ_REG(&priv->regs->bc_irqptr);
+	/* Convertin into CPU address */
+	pos = priv->irq_log_base +
+		((unsigned int)pos - (unsigned int)priv->irq_log_base_hw)/4;
+
+	/* Step in IRQ log until we reach the end. */
+	handled = 0;
+	curr = priv->irq_log_curr;
+	while ( curr != pos ) {
+		bd = (union gr1553bc_bd *)(GR1553BC_READ_MEM(curr) & ~1);
+		GR1553BC_WRITE_MEM(curr, 0x2); /* Mark Handled */
+
+		/* Convert Descriptor in IRQ log into CPU address. In order
+		 * to convert we must know which list the descriptor belongs
+		 * to, we compare the address of the bd to the ASYNC list
+		 * descriptor table area.
+		 */
+		if ( priv->alist && ((unsigned int)bd>=priv->alist->table_hw) &&
+		     ((unsigned int)bd <
+		     (priv->alist->table_hw + priv->alist->table_size))) {
+		     	/* BD in async list */
+			bd = gr1553bc_bd_hw2cpu(priv->alist, bd);
+		} else {
+			/* BD in sync list */
+			bd = gr1553bc_bd_hw2cpu(priv->list, bd);
+		}
+
+		/* Handle Descriptor that cased IRQ 
+		 *
+		 * If someone have inserted an IRQ descriptor and tied
+		 * that to a custom function we call that function, otherwise
+		 * we let the standard IRQ handle handle it.
+		 */
+		word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
+		if ( word0 == GR1553BC_UNCOND_IRQ ) {
+			word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
+			if ( (word2 & 0x3) == 0 ) {
+				func = (bcirq_func_t)(word2 & ~0x3);
+				data = (void *)
+					GR1553BC_READ_MEM(&bd->raw.words[3]);
+				func(bd, data);
+				handled = 1;
+			}
+		}
+
+		if ( handled == 0 ) {
+			/* Let standard IRQ handle handle it */
+			priv->irq_func(bd, priv->irq_data);
+		} else {
+			handled = 0;
+		}
+
+		/* Increment to next entry in IRQ LOG */
+		if ( curr == priv->irq_log_end )
+			curr = priv->irq_log_base;
+		else
+			curr++;
+	}
+	priv->irq_log_curr = curr;
+}
+
+int gr1553bc_irq_setup
+	(
+	void *bc,
+	bcirq_func_t func,
+	void *data
+	)
+{
+	struct gr1553bc_priv *priv = bc;
+
+	if ( func == NULL )
+		priv->irq_func = gr1553bc_isr_std;
+	else
+		priv->irq_func = func;
+	priv->irq_data = data;
+
+	return 0;
+}
+
+void gr1553bc_ext_trig(void *bc, int trig)
+{
+	struct gr1553bc_priv *priv = bc;
+	unsigned int trigger;
+
+	if ( trig )
+		trigger = GR1553B_BC_ACT_SETT;
+	else
+		trigger = GR1553B_BC_ACT_CLRT;
+
+	GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | trigger);
+}
+
+void gr1553bc_status(void *bc, struct gr1553bc_status *status)
+{
+	struct gr1553bc_priv *priv = bc;
+
+	status->status = GR1553BC_READ_REG(&priv->regs->bc_stat);
+	status->time = GR1553BC_READ_REG(&priv->regs->bc_timer);
+}
+
+/*** DEBUGGING HELP FUNCTIONS ***/
+
+#include <stdio.h>
+
+void gr1553bc_show_list(struct gr1553bc_list *list, int options)
+{
+	struct gr1553bc_major *major;
+	struct gr1553bc_minor *minor;
+	int i, j, minor_cnt, timefree;
+
+	printf("LIST\n");
+	printf("  major cnt: %d\n", list->major_cnt);
+	for (i=0; i<32; i++) {
+		printf("  RT[%d] timeout: %d\n", i, 14+(list->rt_timeout[i]*4));
+	}
+
+	for (i=0; i<list->major_cnt; i++) {
+		major = list->majors[i];
+		minor_cnt = major->cfg->minor_cnt;
+		printf(" MAJOR[%d]\n", i);
+		printf("   minor count: %d\n", minor_cnt);
+
+		for (j=0; j<minor_cnt; j++) {
+			minor = major->minors[j];
+
+			printf("   MINOR[%d]\n", j);
+			printf("     bd:        0x%08x (HW:0x%08x)\n",
+				(unsigned int)&minor->bds[0],
+				(unsigned int)gr1553bc_bd_cpu2hw(list,
+							&minor->bds[0]));
+			printf("     slot cnt:  %d\n", minor->cfg->slot_cnt);
+			if ( minor->cfg->timeslot ) {
+				timefree = gr1553bc_minor_freetime(minor);
+				printf("     timefree:  %d\n", timefree);
+				printf("     timetotal: %d\n",
+					minor->cfg->timeslot);
+			} else {
+				printf("     no time mgr\n");
+			}
+		}
+	}
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c
new file mode 100644
index 0000000..1ce731e
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c
@@ -0,0 +1,519 @@
+/*  GR1553B BM driver
+ *
+ *  COPYRIGHT (c) 2010.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <gr1553b.h>
+#include <gr1553bm.h>
+
+
+#define GR1553BM_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553BM_READ_MEM(adr) (*(volatile uint32_t *)(adr))
+
+#define GR1553BM_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553BM_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+struct gr1553bm_priv {
+	struct drvmgr_dev **pdev;
+	struct gr1553b_regs *regs;
+
+	void *buffer;
+	unsigned int buffer_base_hw;
+	unsigned int buffer_base;
+	unsigned int buffer_end;
+	unsigned int buffer_size;
+	unsigned int read_pos;
+	int started;
+	struct gr1553bm_config cfg;
+
+	/* Time updated by IRQ when 24-bit Time counter overflows */
+	volatile uint64_t time;
+};
+
+void gr1553bm_isr(void *data);
+
+/* Default Driver configuration */
+struct gr1553bm_config gr1553bm_default_config =
+{
+	/* Highest resolution, use Time overflow IRQ to track */
+	.time_resolution = 0,
+	.time_ovf_irq = 1,
+
+	/* No filtering, log all */
+	.filt_error_options = GR1553BM_ERROPTS_ALL,
+	.filt_rtadr = 0xffffffff,
+	.filt_subadr = 0xffffffff,
+	.filt_mc = 0x0007ffff,
+
+	/* 128Kbyte dynamically allocated buffer. */
+	.buffer_size = 128*1024,
+	.buffer_custom = NULL,
+};
+
+void gr1553bm_register(void)
+{
+	/* The BM driver rely on the GR1553B Driver */
+	gr1553_register();
+}
+
+static void gr1553bm_hw_start(struct gr1553bm_priv *priv)
+{
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	/* Enable IRQ source and mark running state */
+	IRQ_GLOBAL_DISABLE(oldLevel);
+
+	priv->started = 1;
+
+	/* Clear old IRQ flags */
+	priv->regs->irq = GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF;
+
+	/* Unmask IRQ sources */
+	if ( priv->cfg.time_ovf_irq ) {
+		priv->regs->imask |= GR1553B_IRQEN_BMDE | GR1553B_IRQEN_BMTOE;
+	} else {
+		priv->regs->imask |= GR1553B_IRQEN_BMDE;
+	}
+
+	/* Start logging */
+	priv->regs->bm_ctrl =
+		(priv->cfg.filt_error_options & 
+		(GR1553B_BM_CTRL_MANL|GR1553B_BM_CTRL_UDWL|GR1553B_BM_CTRL_IMCL))
+		| GR1553B_BM_CTRL_BMEN;
+
+	IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+static void gr1553bm_hw_stop(struct gr1553bm_priv *priv)
+{
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	IRQ_GLOBAL_DISABLE(oldLevel);
+
+	/* Stop Logging */
+	priv->regs->bm_ctrl = 0;
+
+	/* Stop IRQ source */
+	priv->regs->imask &= ~(GR1553B_IRQEN_BMDE|GR1553B_IRQEN_BMTOE);
+
+	/* Clear IRQ flags */
+	priv->regs->irq = GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF;
+
+	priv->started = 0;
+
+	IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+/* Open device by number */
+void *gr1553bm_open(int minor)
+{
+	struct drvmgr_dev **pdev = NULL;
+	struct gr1553bm_priv *priv = NULL;
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+
+	/* Allocate requested device */
+	pdev = gr1553_bm_open(minor);
+	if ( pdev == NULL )
+		goto fail;
+
+	priv = malloc(sizeof(struct gr1553bm_priv));
+	if ( priv == NULL )
+		goto fail;
+	memset(priv, 0, sizeof(struct gr1553bm_priv));
+
+	/* Init BC device */
+	priv->pdev = pdev;
+	(*pdev)->priv = priv;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)(*pdev)->businfo;
+	pnpinfo = &ambadev->info;
+	priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+	/* Start with default configuration */
+	priv->cfg = gr1553bm_default_config;
+
+	/* Unmask IRQs */
+	gr1553bm_hw_stop(priv);
+
+	return priv;
+
+fail:
+	if ( pdev )
+		gr1553_bm_close(pdev);
+	if ( priv )
+		free(priv);
+	return NULL;
+}
+
+/* Close previously */
+void gr1553bm_close(void *bm)
+{
+	struct gr1553bm_priv *priv = bm;
+
+	if ( priv->started ) {
+		gr1553bm_stop(bm);
+	}
+
+	if ( (priv->cfg.buffer_custom == NULL) && priv->buffer )
+		free(priv->buffer);
+
+	gr1553_bm_close(priv->pdev);
+	free(priv);
+}
+
+/* Configure the BM driver */
+int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
+{
+	struct gr1553bm_priv *priv = bm;
+
+	if ( priv->started )
+		return -1;
+
+	/* Check Config validity? */
+/*#warning IMPLEMENT.*/
+
+	/* Free old buffer if dynamically allocated */
+	if ( (priv->cfg.buffer_custom == NULL) && priv->buffer ) {
+		free(priv->buffer);
+		priv->buffer = NULL;
+	}
+	priv->buffer_size = cfg->buffer_size & ~0x7; /* on 8 byte bounadry */
+	if ((unsigned int)cfg->buffer_custom & 1) {
+		/* Custom Address Given in Remote address. We need
+		 * to convert it intoTranslate into Hardware a
+		 * hardware accessible address
+		 */
+		priv->buffer_base_hw = (unsigned int)cfg->buffer_custom & ~1;
+		priv->buffer = cfg->buffer_custom;
+		drvmgr_translate_check(
+			*priv->pdev,
+			DMAMEM_TO_CPU,
+			(void *)priv->buffer_base_hw,
+			(void **)&priv->buffer_base,
+			priv->buffer_size);
+	} else {
+		if (cfg->buffer_custom == NULL) {
+			/* Allocate new buffer dynamically */
+			priv->buffer = malloc(priv->buffer_size + 8);
+			if (priv->buffer == NULL)
+				return -1;
+		} else {
+			/* Address given in CPU accessible address, no
+			 * translation required.
+			 */
+			priv->buffer = cfg->buffer_custom;
+		}
+		/* Align to 16 bytes */
+		priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) &
+					~(8-1);
+		/* Translate address of buffer base into address that Hardware must
+		 * use to access the buffer.
+		 */
+		drvmgr_translate_check(
+			*priv->pdev,
+			CPUMEM_TO_DMA,
+			(void *)priv->buffer_base,
+			(void **)&priv->buffer_base_hw,
+			priv->buffer_size);
+		
+	}
+
+	/* Copy valid config */
+	priv->cfg = *cfg;
+
+	return 0;
+}
+
+/* Start logging */
+int gr1553bm_start(void *bm)
+{
+	struct gr1553bm_priv *priv = bm;
+
+	if ( priv->started )
+		return -1;
+	if ( priv->buffer == NULL )
+		return -2;
+
+	/* Start at Time = 0 */
+	priv->regs->bm_ttag = 
+		priv->cfg.time_resolution << GR1553B_BM_TTAG_RES_BIT;
+
+	/* Configure Filters */
+	priv->regs->bm_adr = priv->cfg.filt_rtadr;
+	priv->regs->bm_subadr = priv->cfg.filt_subadr;
+	priv->regs->bm_mc = priv->cfg.filt_mc;
+
+	/* Set up buffer */
+	priv->regs->bm_start = priv->buffer_base_hw;
+	priv->regs->bm_end = priv->buffer_base_hw + priv->cfg.buffer_size - 4;
+	priv->regs->bm_pos = priv->buffer_base_hw;
+	priv->read_pos = priv->buffer_base;
+	priv->buffer_end = priv->buffer_base + priv->cfg.buffer_size;
+
+	/* Register ISR handler and unmask IRQ source at IRQ controller */
+	if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553bm", gr1553bm_isr, priv))
+		return -3;
+
+	/* Start hardware and set priv->started */
+	gr1553bm_hw_start(priv);
+
+	return 0;
+}
+
+/* Stop logging */
+void gr1553bm_stop(void *bm)
+{
+	struct gr1553bm_priv *priv = bm;
+
+	/* Stop Hardware */
+	gr1553bm_hw_stop(priv);
+
+	/* At this point the hardware must be stopped and IRQ 
+	 * sources unmasked.
+	 */
+
+	/* Unregister ISR handler and unmask 1553 IRQ source at IRQ ctrl */
+	drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553bm_isr, priv);
+}
+
+int gr1553bm_started(void *bm)
+{
+	return ((struct gr1553bm_priv *)bm)->started;
+}
+
+/* Get 64-bit 1553 Time.
+ *
+ * Update software time counters and return the current time.
+ */
+void gr1553bm_time(void *bm, uint64_t *time)
+{
+	struct gr1553bm_priv *priv = bm;
+	unsigned int hwtime, hwtime2;
+
+resample:
+	if ( priv->started && (priv->cfg.time_ovf_irq == 0) ) {
+		/* Update Time overflow counter. The carry bit from Time counter
+		 * is located in IRQ Flag.
+		 *
+		 * When IRQ is not used this function must be called often
+		 * enough to avoid that the Time overflows and the carry
+		 * bit is already set. The frequency depends on the Time
+		 * resolution.
+		 */
+		if ( priv->regs->irq & GR1553B_IRQ_BMTOF ) {
+			/* Clear carry bit */
+			priv->regs->irq = GR1553B_IRQ_BMTOF;
+			priv->time += (GR1553B_BM_TTAG_VAL + 1);
+		}
+	}
+
+	/* Report current Time, even if stopped */
+	hwtime = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
+	if ( time )
+		*time = priv->time | hwtime;
+
+	if ( priv->cfg.time_ovf_irq ) {
+		/* Detect wrap around */
+		hwtime2 = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
+		if ( hwtime > hwtime2 ) {
+			/* priv->time and hwtime may be out of sync if
+			 * IRQ updated priv->time just after bm_ttag was read 
+			 * here, we resample if we detect inconsistancy.
+			 */
+			goto resample;
+		}
+	}
+}
+
+/* Number of entries available in DMA buffer */
+int gr1553bm_available(void *bm, int *nentries)
+{
+	struct gr1553bm_priv *priv = bm;
+	unsigned int top, bot, pos;
+
+	if ( !priv->started )
+		return -1;
+
+	/* Get BM posistion in log */
+	pos = priv->regs->bm_pos;
+
+	/* Convert into CPU accessible address */
+	pos = priv->buffer_base + (pos - priv->buffer_base_hw);
+
+	if ( pos >= priv->read_pos ) {
+		top = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
+		bot = 0;
+	} else {
+		top = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
+		bot = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
+	}
+
+	if ( nentries )
+		*nentries = top+bot;
+
+	return 0;
+}
+
+/* Read a maximum number of entries from LOG buffer. */
+int gr1553bm_read(void *bm, struct gr1553bm_entry *dst, int *max)
+{
+	struct gr1553bm_priv *priv = bm;
+	unsigned int dest, pos, left, newPos, len;
+	unsigned int topAdr, botAdr, topLen, botLen;
+
+	if ( !priv || !priv->started )
+		return -1;
+
+	left = *max;
+	pos = priv->regs->bm_pos & ~0x7;
+
+	/* Convert into CPU accessible address */
+	pos = priv->buffer_base + (pos - priv->buffer_base_hw);
+
+	if ( (pos == priv->read_pos) || (left < 1) ) {
+		/* No data available */
+		*max = 0;
+		return 0;
+	}
+	newPos = 0;
+
+	/* Addresses and lengths of BM log buffer */
+	if ( pos >= priv->read_pos ) {
+		/* Read Top only */
+		topAdr = priv->read_pos;
+		botAdr = 0;
+		topLen = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
+		botLen = 0;
+	} else {
+		/* Read Top and Bottom */
+		topAdr = priv->read_pos;
+		botAdr = priv->buffer_base;
+		topLen = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
+		botLen = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
+	}
+
+	dest = (unsigned int)dst;
+	if ( topLen > 0 ) {
+		/* Copy from top area first */
+		if ( topLen > left ) {
+			len = left;
+			left = 0;
+		} else {
+			len = topLen;
+			left -= topLen;
+		}
+		newPos = topAdr + (len * sizeof(struct gr1553bm_entry));
+		if ( newPos >= priv->buffer_end )
+			newPos -= priv->buffer_size;
+		if ( priv->cfg.copy_func ) {
+			dest += priv->cfg.copy_func(
+				dest,			/*Optional Destination*/
+				(void *)topAdr, 	/* DMA start address */
+				len,			/* Number of entries */
+				priv->cfg.copy_func_arg /* Custom ARG */
+				);
+		} else {
+			memcpy(	(void *)dest,
+				(void *)topAdr,
+				len * sizeof(struct gr1553bm_entry));
+			dest += len * sizeof(struct gr1553bm_entry);
+		}
+	}
+
+	if ( (botLen > 0) && (left > 0) ) {
+		/* Copy bottom area last */
+		if ( botLen > left ) {
+			len = left;
+			left = 0;
+		} else {
+			len = botLen;
+			left -= botLen;
+		}
+		newPos = botAdr + (len * sizeof(struct gr1553bm_entry));
+
+		if ( priv->cfg.copy_func ) {
+			priv->cfg.copy_func(
+				dest,			/*Optional Destination*/
+				(void *)botAdr,		/* DMA start address */
+				len,			/* Number of entries */
+				priv->cfg.copy_func_arg /* Custom ARG */
+				);
+		} else {
+			memcpy(	(void *)dest,
+				(void *)botAdr,
+				len * sizeof(struct gr1553bm_entry));
+		}
+	}
+
+	/* Remember last read posistion in buffer */
+	/*printf("New pos: 0x%08x (0x%08x), %d\n", newPos, priv->read_pos, *max - left);*/
+	priv->read_pos = newPos;
+
+	/* Return number of entries read */
+	*max = *max - left;
+
+	return 0;
+}
+
+/* Note: This is a shared interrupt handler, with BC/RT driver
+ *       we must determine the cause of IRQ before handling it.
+ */
+void gr1553bm_isr(void *data)
+{
+	struct gr1553bm_priv *priv = data;
+	uint32_t irqflag;
+
+	/* Get Causes */
+	irqflag = priv->regs->irq & (GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF);
+
+	/* Check spurious IRQs */
+	if ( (irqflag == 0) || (priv->started == 0) )
+		return;
+
+	if ( (irqflag & GR1553B_IRQ_BMTOF) && priv->cfg.time_ovf_irq ) {
+		/* 1553 Time Over flow. Time is 24-bits */
+		priv->time += (GR1553B_BM_TTAG_VAL + 1);
+
+		/* Clear cause handled */
+		priv->regs->irq = GR1553B_IRQ_BMTOF;
+	}
+
+	if ( irqflag & GR1553B_IRQ_BMD ) {
+		/* BM DMA ERROR. Fatal error, we stop BM hardware and let
+		 * user take care of it. From now on all calls will result
+		 * in an error because the BM is stopped (priv->started=0).
+		 */
+
+		/* Clear cause handled */
+		priv->regs->irq = GR1553B_IRQ_BMD;
+
+		if ( priv->cfg.dma_error_isr )
+			priv->cfg.dma_error_isr(data, priv->cfg.dma_error_arg);
+
+		gr1553bm_hw_stop(priv);
+	}
+}
diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c
new file mode 100644
index 0000000..ff05ce5
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c
@@ -0,0 +1,1256 @@
+/*  GR1553B RT driver
+ *
+ *  COPYRIGHT (c) 2010.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gr1553b.h>
+#include <gr1553rt.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#define GR1553RT_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553RT_READ_MEM(adr) (*(volatile uint32_t *)(adr))
+
+#define GR1553RT_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (val)
+#define GR1553RT_READ_REG(adr) (*(volatile uint32_t *)(adr))
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/* Software representation of one hardware descriptor */
+struct gr1553rt_sw_bd {
+	unsigned short this_next;/* Next entry or this entry. 0xffff: no next */
+	unsigned char listid;	/* ListID of List the descriptor is attached */
+	char unused;
+} __attribute__((packed));
+
+/* Software description of a subaddress */
+struct gr1553rt_subadr {
+	/* RX LIST */
+	unsigned char rxlistid;
+	/* TX LIST */
+	unsigned char txlistid;
+};
+
+struct gr1553rt_irqerr {
+	gr1553rt_irqerr_t func;
+	void *data;
+};
+
+struct gr1553rt_irqmc {
+	gr1553rt_irqmc_t func;
+	void *data;
+};
+
+struct gr1553rt_irq {
+	gr1553rt_irq_t func;
+	void *data;
+};
+
+struct gr1553rt_priv {
+	/* Pointer to Hardware registers */
+	struct gr1553b_regs *regs;
+
+	/* Software State */
+	int started;
+	struct gr1553rt_cfg cfg;
+
+	/* Handle to GR1553B RT device layer */
+	struct drvmgr_dev **pdev;
+
+	/* Each Index represents one RT Subaddress. 31 = Broadcast */
+	struct gr1553rt_subadr subadrs[32];
+
+	/* Pointer to array of Software's description of a hardware
+	 * descriptor.
+	 */
+#if (RTBD_MAX == 0)
+	struct gr1553rt_sw_bd *swbds;
+#else
+	struct gr1553rt_sw_bd swbds[RTBD_MAX];
+#endif
+
+	/* List of Free descriptors */
+	unsigned short swbd_free;
+	int swbd_free_cnt;
+
+	/* Hardware SubAddress descriptors given for CPU and Hardware */
+	void *satab_buffer;
+	struct gr1553rt_sa *sas_cpu;	/* Translated for CPU */
+	struct gr1553rt_sa *sas_hw;	/* Translated for Hardware */
+
+	/* Hardware descriptors address given for CPU and hardware */
+	void *bd_buffer;
+	int bds_cnt;			/* Number of descriptors */
+	struct gr1553rt_bd *bds_cpu;	/* Translated for CPU */
+	struct gr1553rt_bd *bds_hw;	/* Translated for Hardware */
+
+
+	/* Event Log buffer in */
+	void *evlog_buffer;
+	unsigned int *evlog_cpu_next;	/* Next LOG entry to be handled */
+	unsigned int *evlog_cpu_base;	/* First Entry in LOG */
+	unsigned int *evlog_cpu_end;	/* Last+1 Entry in LOG */
+	unsigned int *evlog_hw_base;	/* Translated for Hardware */
+
+	/* Each Index represents a LIST ID */
+	struct gr1553rt_list *lists[RTLISTID_MAX];
+
+	/* IRQ handlers, one per SUBADDRESS */
+	struct gr1553rt_irq irq_rx[32];
+	struct gr1553rt_irq irq_tx[32];
+
+	/* ISR called when an ERROR IRQ is received */
+	struct gr1553rt_irqerr irq_err;
+
+	/* ISR called when an Mode Code is received */
+	struct gr1553rt_irqmc irq_mc;
+};
+
+void gr1553rt_sw_init(struct gr1553rt_priv *priv);
+void gr1553rt_sw_free(struct gr1553rt_priv *priv);
+int gr1553rt_sw_alloc(struct gr1553rt_priv *priv);
+
+/* Assign and ID to the list. An LIST ID is needed before scheduling list
+ * on an RT subaddress.
+ *
+ * Only 64 lists can be registered at a time on the same device.
+ */
+int gr1553rt_list_reg(struct gr1553rt_list *list)
+{
+	struct gr1553rt_priv *priv = list->rt;
+	int i;
+
+	/* Find first free list ID */
+	for ( i=0; i<RTLISTID_MAX; i++) {
+		if ( priv->lists[i] == NULL ) {
+			priv->lists[i] = list;
+			list->listid = i;
+			return i;
+		}
+	}
+
+	/* No available LIST IDs */
+	list->listid = -1;
+
+	return -1;
+}
+
+/* Unregister List from device */
+void gr1553rt_list_unreg(struct gr1553rt_list *list)
+{
+	struct gr1553rt_priv *priv = list->rt;
+
+	priv->lists[list->listid] = NULL;
+	list->listid = -1;
+}
+
+static int gr1553rt_bdid(void *rt, struct gr1553rt_sw_bd *bd)
+{
+	struct gr1553rt_priv *priv = rt;
+	
+	unsigned short index;
+
+	/* Get Index of Software BD */
+	index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) / 
+		sizeof(struct gr1553rt_sw_bd);
+
+	return index;
+}
+
+void gr1553rt_bd_alloc_init(void *rt, int count)
+{
+	struct gr1553rt_priv *priv = rt;
+	int i;
+
+	for (i=0; i<count-1; i++) {
+		priv->swbds[i].this_next = i+1;
+	}
+	priv->swbds[count-1].this_next = 0xffff;
+	priv->swbd_free = 0;
+	priv->swbd_free_cnt = count;
+}
+
+/* Allocate a Chain of descriptors */
+int gr1553rt_bd_alloc(void *rt, struct gr1553rt_sw_bd **bd, int cnt)
+{
+	struct gr1553rt_priv *priv = rt;
+	struct gr1553rt_sw_bd *curr;
+	int i;
+
+	if ((priv->swbd_free_cnt < cnt) || (cnt <= 0)) {
+		*bd = NULL;
+		return -1;
+	}
+
+	*bd = &priv->swbds[priv->swbd_free];
+	for (i=0; i<cnt; i++) {
+		if ( i == 0) {
+			curr = &priv->swbds[priv->swbd_free];
+		} else {
+			curr = &priv->swbds[curr->this_next];
+		}
+		if ( curr->this_next == 0xffff ) {
+			*bd = NULL;
+			return -1;
+		}
+	}
+	priv->swbd_free = curr->this_next;
+	priv->swbd_free_cnt -= cnt;
+	curr->this_next = 0xffff; /* Mark end of chain on last entry */
+
+	return 0;
+}
+
+void gr1553rt_bd_free(void *rt, struct gr1553rt_sw_bd *bd)
+{
+	struct gr1553rt_priv *priv = rt;
+	unsigned short index;
+
+	/* Get Index of Software BD */
+	index = gr1553rt_bdid(priv, bd);
+
+	/* Insert first in list */
+	bd->this_next = priv->swbd_free;
+	priv->swbd_free = index;
+	priv->swbd_free_cnt++;
+}
+
+int gr1553rt_list_init
+	(
+	void *rt,
+	struct gr1553rt_list **plist,
+	struct gr1553rt_list_cfg *cfg
+	)
+{
+	struct gr1553rt_priv *priv = rt;
+	int i, size;
+	struct gr1553rt_sw_bd *swbd;
+	unsigned short index;
+	struct gr1553rt_list *list;
+
+	/* The user may provide a pre allocated LIST, or
+	 * let the driver handle allocation by using malloc()
+	 *
+	 * If the IN/OUT plist argument points to NULL a list
+	 * dynamically allocated here.
+	 */
+	list = *plist;
+	if ( list == NULL ) {
+		/* Dynamically allocate LIST */
+		size = offsetof(struct gr1553rt_list, bds) +
+			(cfg->bd_cnt * sizeof(unsigned short));
+		list = (struct gr1553rt_list *)malloc(size);
+		if ( list == NULL )
+			return -1;
+		*plist = list;
+	}
+
+	list->rt = rt;
+	list->subadr = -1;
+	list->listid = gr1553rt_list_reg(list);
+	if ( list->listid == -1 )
+		return -2; /* Too many lists */
+	list->cfg = cfg;
+	list->bd_cnt = cfg->bd_cnt;
+
+	/* Allocate all BDs needed by list */
+	if ( gr1553rt_bd_alloc(rt, &swbd, list->bd_cnt) ) {
+		return -3; /* Too few descriptors */
+	}
+
+	/* Get ID/INDEX of Software BDs */
+	index = gr1553rt_bdid(rt, swbd);
+	list->bds[0] = index;
+	for (i=1; i<list->bd_cnt; i++) {
+		list->bds[i] = priv->swbds[list->bds[i-1]].this_next;
+	}
+
+	/* Now that the next pointer has fullfilled it's job and not
+	 * needed anymore, we use it as list entry pointer instead.
+	 * The this_next pointer is a list entry number.
+	 */
+	for (i=0; i<list->bd_cnt; i++) {
+		priv->swbds[list->bds[i]].this_next = i;
+	}
+
+	return 0;
+}
+
+int gr1553rt_bd_init(
+	struct gr1553rt_list *list,
+	unsigned short entry_no,
+	unsigned int flags,
+	uint16_t *dptr,
+	unsigned short next
+	)
+{
+	struct gr1553rt_priv *priv;
+	unsigned short bdid;
+	struct gr1553rt_bd *bd;
+	unsigned int nextbd, dataptr;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	if ( entry_no >= list->bd_cnt )
+		return -1;
+
+	/* Find Descriptor */
+	bdid = list->bds[entry_no];
+	priv = list->rt;
+	bd = &priv->bds_cpu[bdid];
+
+	if ( next == 0xfffe ) {
+		next = entry_no + 1;
+		if ( next >= list->bd_cnt )
+			next = 0;
+	}
+
+	/* Find next descriptor in address space that the
+	 * Hardware understand.
+	 */
+	if ( next >= 0xffff ) {
+		nextbd = 0x3; /* End of list */
+	} else if ( next >= list->bd_cnt ) {
+		return -1;
+	} else {
+		bdid = list->bds[next];
+		nextbd = (unsigned int)&priv->bds_hw[bdid];
+	}
+
+	dataptr = (unsigned int)dptr;
+	if ( dataptr & 1 ) {
+		/* Translate address from CPU-local into remote */
+		dataptr &= ~1;
+		drvmgr_translate(
+			*priv->pdev,
+			CPUMEM_TO_DMA,
+			(void *)dataptr,
+			(void **)&dataptr
+			);
+	}
+
+	/* Get current status, and clear */
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	bd->ctrl = flags & GR1553RT_BD_FLAGS_IRQEN;
+	bd->dptr = (unsigned int)dptr;
+	bd->next = nextbd;
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return 0;	
+}
+
+int gr1553rt_bd_update(
+	struct gr1553rt_list *list,
+	int entry_no,
+	unsigned int *status,
+	uint16_t **dptr
+	)
+{
+	struct gr1553rt_priv *priv;
+	unsigned short bdid;
+	struct gr1553rt_bd *bd;
+	unsigned int tmp, dataptr;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	if ( entry_no >= list->bd_cnt )
+		return -1;
+
+	/* Find Descriptor */
+	bdid = list->bds[entry_no];
+	priv = list->rt;
+	bd = &priv->bds_cpu[bdid];
+
+	/* Prepare translation if needed */
+	if ( dptr && (dataptr=(unsigned int)*dptr) ) {
+		if ( dataptr & 1 ) {
+			/* Translate address from CPU-local into remote. May
+			 * be used when RT core is accessed over the PCI bus.
+			 */
+			dataptr &= ~1;
+			drvmgr_translate(
+				*priv->pdev,
+				CPUMEM_TO_DMA,
+				(void *)dataptr,
+				(void **)&dataptr
+				);
+		}
+	}
+
+	/* Get current status, and clear */
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	/* READ/WRITE Status/Control word */
+	if ( status ) {
+		tmp = bd->ctrl;
+		if ( *status ) {
+			bd->ctrl = *status;
+		}
+		*status = tmp;
+	}
+	/* READ/WRITE Data-Pointer word */
+	if ( dptr ) {
+		tmp = bd->dptr;
+		if ( dataptr ) {
+			bd->dptr = dataptr;
+		}
+		*dptr = (uint16_t *)tmp;
+	}
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return 0;
+}
+
+int gr1553rt_irq_err
+	(
+	void *rt,
+	gr1553rt_irqerr_t func,
+	void *data
+	)
+{
+	struct gr1553rt_priv *priv = rt;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	priv->irq_err.func = func;
+	priv->irq_err.data = data;
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return 0;
+}
+
+int gr1553rt_irq_mc
+	(
+	void *rt,
+	gr1553rt_irqmc_t func,
+	void *data
+	)
+{
+	struct gr1553rt_priv *priv = rt;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	priv->irq_mc.func = func;
+	priv->irq_mc.data = data;
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return 0;
+}
+
+int gr1553rt_irq_sa
+	(
+	void *rt,
+	int subadr,
+	int tx,
+	gr1553rt_irq_t func,
+	void *data
+	)
+{
+	struct gr1553rt_priv *priv = rt;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	if ( tx ) {
+		priv->irq_tx[subadr].func = func;
+		priv->irq_tx[subadr].data = data;
+	} else {
+		priv->irq_rx[subadr].func = func;
+		priv->irq_rx[subadr].data = data;
+	}
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return 0;
+}
+
+/* GR1553-RT Interrupt Service Routine */
+void gr1553rt_isr(void *data)
+{
+	struct gr1553rt_priv *priv = data;
+	unsigned int firstirq, lastpos;
+	int index;
+	unsigned int *last, *curr, entry, hwbd;
+	int type, samc, mcode, subadr;
+	int listid;
+	struct gr1553rt_irq *isr;
+	struct gr1553rt_irqerr *isrerr;
+	struct gr1553rt_irqmc *isrmc;
+	unsigned int irq;
+
+	/* Ack IRQ before reading current write pointer, but after
+	 * reading current IRQ pointer. This is because RT_EVIRQ
+	 * may be updated after we ACK the IRQ source.
+	 */
+	irq = priv->regs->irq &
+		(GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD|GR1553B_IRQ_RTEV);
+	if ( irq == 0 )
+		return;
+
+	firstirq = priv->regs->rt_evirq;
+	priv->regs->irq = irq;
+	lastpos = priv->regs->rt_evlog;
+
+	/* Quit if nothing has been added to the log */
+	if ( lastpos == firstirq )
+		return;
+
+	if ( irq & (GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD) ) {
+		isrerr = &priv->irq_err;
+		if ( isrerr->func ) {
+			isrerr->func(irq, isrerr->data);
+		}
+
+		/* Stop Hardware and enter non-started mode. This will
+		 * make all future calls to driver result in an error.
+		 */
+		gr1553rt_stop(priv);
+	}
+
+	/* Step between first log entry causing an IRQ to last
+	 * entry. Each entry that has caused an IRQ will be handled
+	 * by calling user-defined function.
+	 *
+	 * We convert hardware addresses into CPU accessable addresses
+	 * first.
+	 */
+	index = (firstirq - (unsigned int)priv->evlog_hw_base) /
+		sizeof(unsigned int);
+	curr = priv->evlog_cpu_base + index;
+	index = (lastpos - (unsigned int)priv->evlog_hw_base) /
+		sizeof(unsigned int);
+	last = priv->evlog_cpu_base + index;
+
+	do {
+		/* Process one entry */
+		entry = *curr;
+
+		if ( entry & 0x80000000 ) {
+			/* Entry caused IRQ */
+			type = (entry >> 29) & 0x3;
+			samc = (entry >> 24) & 0x1f;
+			if ( (type & 0x2) == 0 ) {
+				/* Transmit/Receive Data */
+				subadr = samc;
+				if ( type ) {
+					/* Receive */
+					listid = priv->subadrs[subadr].rxlistid;
+					hwbd = priv->sas_cpu[subadr].rxptr;
+					isr = &priv->irq_rx[subadr];
+				} else {
+					/* Transmit */
+					listid = priv->subadrs[subadr].txlistid;
+					hwbd = priv->sas_cpu[subadr].txptr;
+					isr = &priv->irq_tx[subadr];
+				}
+
+				index = ((unsigned int)hwbd - (unsigned int)
+					priv->bds_hw)/sizeof(struct gr1553rt_bd);
+
+				/* Call user ISR of RX/TX transfer */
+				if ( isr->func ) {
+					isr->func(
+						priv->lists[listid],
+						entry,
+						priv->swbds[index].this_next,
+						isr->data
+						);
+				}
+			} else if ( type == 0x2) {
+				/* Modecode */
+				mcode = samc;
+				isrmc = &priv->irq_mc;
+
+				/* Call user ISR of ModeCodes RX/TX */
+				if ( isrmc->func ) {
+					isrmc->func(
+						mcode,
+						entry,
+						isrmc->data
+						);
+				}
+			} else {
+				/* ERROR OF SOME KIND, EVLOG OVERWRITTEN? */
+				exit(-1);
+			}
+		}
+
+		/* Calc next entry posistion */
+		curr++;
+		if ( curr == priv->evlog_cpu_end )
+			curr = priv->evlog_cpu_base;
+
+	} while ( curr != last );
+}
+
+int gr1553rt_indication(void *rt, int subadr, int *txeno, int *rxeno)
+{
+	struct gr1553rt_priv *priv = rt;
+	struct gr1553rt_sa *sa;
+	unsigned int bd, index;
+
+	/*  Sub address valid */
+	if ( (subadr < 0) || (subadr > 31) )
+		return -1;
+
+	/* Get SubAddress Descriptor address as accessed from CPU */
+	sa = &priv->sas_cpu[subadr];
+
+	/* Indication of TX descriptor? */
+	if ( txeno ) {
+		bd = sa->txptr;
+		/* Get Index of Hardware BD */
+		index = ((unsigned int)bd - (unsigned int)&priv->bds_hw[0]) /
+			sizeof(struct gr1553rt_bd);
+		*txeno = priv->swbds[index].this_next;
+	}
+
+	/* Indication of RX descriptor? */
+	if ( rxeno ) {
+		bd = sa->rxptr;
+		/* Get Index of Hardware BD */
+		index = ((unsigned int)bd - (unsigned int)&priv->bds_hw[0]) /
+			sizeof(struct gr1553rt_bd);
+		*rxeno = priv->swbds[index].this_next;
+	}
+
+	return 0;
+}
+
+#if 0
+int gr1553rt_bd_irq(
+	struct gr1553rt_list *list,
+	unsigned short entry_no,
+	void (*func)(struct gr1553rt_list *list, int entry, void *data),
+	void *data
+	)
+{
+	struct gr1553rt_priv *priv = list->rt;
+	int irqid;
+	int ret;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	if ( entry_no == 0xffff ) {
+		/* Default interrupt for all list entries without
+		 * assigned IRQ function.
+		 */
+		list->irqs[0].func = func;
+		list->irqs[0].data = data;
+		return 0;
+	}
+
+	if ( entry_no >= list->bd_cnt ) {
+		return -1;
+	}
+
+	bdid = list->bds[entry_no];
+	irqid = priv->swbds[bdid].irqid;
+
+	ret = 0;
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	if ( (irqid != 0) && (func == 0) ) {
+		/* Unassign IRQ function */
+		list->irqs[irqid].func = NULL;
+		list->irqs[irqid].data = NULL;
+		irqid = 0; /* Disable IRQ (default handler) */
+	} else if ( priv->swbds[bdid].irqid != 0 ) {
+		/* reassign IRQ function */
+		list->irqs[irqid].func = func;
+		list->irqs[irqid].data = data;
+	} else {
+		/* Find free IRQ spot. If no free irqid=0 (general IRQ) */
+		ret = -1;
+		for (i=0; i<list->cfg->maxirq; i++) {
+			if ( list->irqs[i].func == NULL ) {
+				irqid = i;
+				list->irqs[i].func = func;
+				list->irqs[i].data = data;
+				ret = 0;
+				break;
+			}
+		}
+	}
+	priv->swbds[bdid].irqid = irqid;
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return ret;
+}
+#endif
+
+void gr1553rt_hw_stop(struct gr1553rt_priv *priv);
+
+void gr1553rt_register(void)
+{
+	/* The RT driver rely on the GR1553B Driver */
+	gr1553_register();
+}
+
+void *gr1553rt_open(int minor)
+{
+	struct drvmgr_dev **pdev = NULL;
+	struct gr1553rt_priv *priv = NULL;
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+
+	/* Allocate requested device */
+	pdev = gr1553_rt_open(minor);
+	if ( pdev == NULL )
+		goto fail;
+
+	priv = malloc(sizeof(struct gr1553rt_priv));
+	if ( priv == NULL )
+		goto fail;
+	memset(priv, 0, sizeof(struct gr1553rt_priv));
+
+	/* Assign a device private to RT device */
+	priv->pdev = pdev;
+	(*pdev)->priv = priv;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)(*pdev)->businfo;
+	pnpinfo = &ambadev->info;
+	priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
+
+	/* Start with default configuration */
+	/*priv->cfg = gr1553rt_default_config;*/
+
+	/* Unmask IRQs and so */
+	gr1553rt_hw_stop(priv);
+
+	/* Register ISR handler. hardware mask IRQ, so it is safe to unmask
+	 * at IRQ controller.
+	 */
+	if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553rt", gr1553rt_isr, priv))
+		goto fail;
+
+	return priv;
+
+fail:
+	if ( pdev )
+		gr1553_rt_close(pdev);
+	if ( priv )
+		free(priv);
+	return NULL;
+}
+
+void gr1553rt_close(void *rt)
+{
+	struct gr1553rt_priv *priv = rt;
+
+	if ( priv->started ) {
+		gr1553rt_stop(priv);
+	}
+
+	/* Remove ISR handler */
+	drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553rt_isr, priv);
+
+	/* Free dynamically allocated buffers if any */
+	gr1553rt_sw_free(priv);
+
+	/* Return RT/BC device */
+	gr1553_rt_close(priv->pdev);
+}
+
+/* Stop Hardware and disable IRQ */
+void gr1553rt_hw_stop(struct gr1553rt_priv *priv)
+{
+	uint32_t irqmask;
+
+	/* Disable RT */
+	GR1553RT_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
+
+	/* Stop BC if not already stopped: BC can not be used simultaneously
+	 * as the RT anyway 
+	 */
+	GR1553RT_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
+
+	/* Turn off RT IRQ generation */
+	irqmask=GR1553RT_READ_REG(&priv->regs->imask);
+	irqmask&=~(GR1553B_IRQEN_RTEVE|GR1553B_IRQEN_RTDE);
+	GR1553RT_WRITE_REG(&priv->regs->irq, irqmask);
+}
+
+/* Free dynamically allocated buffers, if any */
+void gr1553rt_sw_free(struct gr1553rt_priv *priv)
+{
+	/* Event log */
+	if ( (priv->cfg.evlog_buffer == NULL) && priv->evlog_buffer ) {
+		free(priv->evlog_buffer);
+		priv->evlog_buffer = NULL;
+	}
+
+	/* RX/TX Descriptors */
+	if ( (priv->cfg.bd_buffer == NULL) && priv->bd_buffer ) {
+		free(priv->bd_buffer);
+		priv->bd_buffer = NULL;
+	}
+
+#if (RTBD_MAX == 0)
+	if ( priv->swbds ) {
+		free(priv->swbds);
+		priv->swbds = NULL;
+	}
+#endif
+
+	/* Sub address table */
+	if ( (priv->cfg.satab_buffer == NULL) && priv->satab_buffer ) {
+		free(priv->satab_buffer);
+		priv->satab_buffer = NULL;
+	}
+}
+
+/* Free dynamically allocated buffers, if any */
+int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
+{
+	int size;
+
+	/* Allocate Event log */
+	if ((unsigned int)priv->cfg.evlog_buffer & 1) {
+		/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
+		priv->evlog_hw_base = (unsigned int *)
+			((unsigned int)priv->cfg.evlog_buffer & ~0x1);
+		priv->evlog_buffer = priv->cfg.evlog_buffer;
+		drvmgr_translate_check(
+			*priv->pdev,
+			DMAMEM_TO_CPU,
+			(void *)priv->evlog_hw_base,
+			(void **)&priv->evlog_cpu_base,
+			priv->cfg.evlog_size
+			);
+	} else {
+		if (priv->cfg.evlog_buffer == NULL) {
+			priv->evlog_buffer = malloc(priv->cfg.evlog_size * 2);
+			if (priv->evlog_buffer == NULL)
+				return -1;
+		} else {
+			/* Addess already CPU-LOCAL */
+			priv->evlog_buffer = priv->cfg.evlog_buffer;
+		}
+		/* Align to SIZE bytes boundary */
+		priv->evlog_cpu_base = (unsigned int *)
+			(((unsigned int)priv->evlog_buffer +
+			(priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1));
+
+		drvmgr_translate_check(
+			*priv->pdev,
+			CPUMEM_TO_DMA,
+			(void *)priv->evlog_cpu_base,
+			(void **)&priv->evlog_hw_base,
+			priv->cfg.evlog_size
+			);
+	}
+	priv->evlog_cpu_end = priv->evlog_cpu_base +
+				priv->cfg.evlog_size/sizeof(unsigned int *);
+
+	/* Allocate Transfer Descriptors */
+	priv->bds_cnt = priv->cfg.bd_count;
+	size = priv->bds_cnt * sizeof(struct gr1553rt_bd);
+	if ((unsigned int)priv->cfg.bd_buffer & 1) {
+		/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
+		priv->bds_hw = (unsigned int)priv->cfg.bd_buffer & ~0x1;
+		priv->bd_buffer = priv->cfg.bd_buffer;
+		drvmgr_translate_check(
+			*priv->pdev,
+			DMAMEM_TO_CPU,
+			(void *)priv->bds_hw,
+			(void **)&priv->bds_cpu,
+			size
+			);
+	} else {
+		if ( priv->cfg.bd_buffer == NULL ) {
+			priv->bd_buffer = malloc(size + 0xf);
+			if (priv->bd_buffer == NULL)
+				return -1;
+		} else {
+			/* Addess already CPU-LOCAL */
+			priv->bd_buffer	= priv->cfg.bd_buffer;
+		}
+		/* Align to 16 bytes boundary */
+		priv->bds_cpu = (struct gr1553rt_bd *)
+				(((unsigned int)priv->bd_buffer + 0xf) & ~0xf);
+
+		/* Translate from CPU address to hardware address */
+		drvmgr_translate_check(
+			*priv->pdev,
+			CPUMEM_TO_DMA,
+			(void *)priv->bds_cpu,
+			(void **)&priv->bds_hw,
+			size
+			);
+	}
+
+#if (RTBD_MAX == 0)
+	/* Allocate software description of */
+	priv->swbds = malloc(priv->cfg.bd_count * sizeof(struct gr1553rt_sw_bd));
+	if ( priv->swbds == NULL ) {
+		return -1;
+	}
+#endif
+
+	/* Allocate Sub address table */
+	if ((unsigned int)priv->cfg.satab_buffer & 1) {
+		/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
+		priv->sas_hw = (unsigned int)priv->cfg.satab_buffer & ~0x1;
+		priv->satab_buffer = priv->cfg.satab_buffer;
+		drvmgr_translate_check(
+			*priv->pdev,
+			DMAMEM_TO_CPU,
+			(void *)priv->sas_hw,
+			(void **)&priv->sas_cpu,
+			16 * 32);
+	} else {
+		if (priv->cfg.satab_buffer == NULL) {
+			priv->satab_buffer = malloc((16 * 32) * 2);
+			if (priv->satab_buffer == NULL)
+				return -1;
+		} else {
+			/* Addess already CPU-LOCAL */
+			priv->satab_buffer = priv->cfg.satab_buffer;
+		}
+		/* Align to 512 bytes boundary */
+		priv->sas_cpu = (struct gr1553rt_sa *)
+				(((unsigned int)priv->satab_buffer + 0x1ff) &
+				~0x1ff);
+
+		/* Translate Address from CPU-LOCAL to HARDWARE (REMOTE) */
+		drvmgr_translate_check(
+			*priv->pdev,
+			CPUMEM_TO_DMA,
+			(void *)priv->sas_cpu,
+			(void **)&priv->sas_hw,
+			16 * 32);
+	}
+
+	return 0;
+}
+
+void gr1553rt_sw_init(struct gr1553rt_priv *priv)
+{
+	int i;
+
+	/* Clear Sub Address table */
+	memset(priv->sas_cpu, 0, 512);
+
+	/* Clear Transfer descriptors */
+	memset(priv->bds_cpu, 0, priv->bds_cnt * 16);
+
+	/* Clear the Event log */
+	memset(priv->evlog_cpu_base, 0, priv->cfg.evlog_size);
+
+	/* Init descriptor allocation algorithm */
+	gr1553rt_bd_alloc_init(priv, priv->bds_cnt);
+
+	/* Init table used to convert from sub address to list.
+	 * Currently non assigned.
+	 */
+	for (i=0; i<32; i++) {
+		priv->subadrs[i].rxlistid = 0xff;
+		priv->subadrs[i].txlistid = 0xff;
+	}
+
+	/* Clear all previous IRQ handlers */
+	for (i=0; i<32; i++) {
+		priv->irq_rx[i].func = NULL;
+		priv->irq_tx[i].data = NULL;
+	}
+	priv->irq_err.func = NULL;
+	priv->irq_err.data = NULL;
+	priv->irq_mc.func = NULL;
+	priv->irq_mc.data = NULL;
+
+	/* Clear LIST to LISTID table */
+	for (i=0; i<RTLISTID_MAX; i++) {
+		priv->lists[i] = NULL;
+	}
+}
+
+int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
+{
+	struct gr1553rt_priv *priv = rt;
+
+	if ( priv->started )
+		return -1;
+
+	/*** Free dynamically allocated buffers ***/
+
+	gr1553rt_sw_free(priv);
+
+	/*** Check new config ***/
+	if ( cfg->rtaddress > 30 )
+		return -1;
+	if ( (cfg->evlog_size & (cfg->evlog_size-1)) != 0)
+		return -1; /* SIZE: Not aligned to a power of 2 */
+	if ( ((unsigned int)priv->cfg.evlog_buffer & (cfg->evlog_size-1)) != 0 )
+		return -1; /* Buffer: Not aligned to size */
+#if (RTBD_MAX > 0)
+	if ( cfg->bd_count > RTBD_MAX )
+		return -1;
+#endif
+
+	/*** Make new config current ***/
+	priv->cfg = *cfg;
+
+	/*** Adapt to new config ***/
+
+	if ( gr1553rt_sw_alloc(priv) != 0 ) 
+		return -1;
+
+	gr1553rt_sw_init(priv);
+
+	return 0;
+}
+
+int gr1553rt_start(void *rt)
+{
+	struct gr1553rt_priv *priv = rt;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	if ( priv->started )
+		return -1;
+
+	/*** Initialize software Pointers and stuff ***/
+
+	if ( !priv->satab_buffer || !priv->bd_buffer || !priv->evlog_buffer )
+		return -2;
+
+	priv->evlog_cpu_next = priv->evlog_cpu_base;
+
+	/*** Initialize Registers ***/
+
+	/* Subaddress table base */
+	priv->regs->rt_tab = (unsigned int)priv->sas_hw;
+
+	/* Mode code configuration */
+	priv->regs->rt_mcctrl = priv->cfg.modecode;
+
+	/* RT Time Tag resolution */
+	priv->regs->rt_ttag = priv->cfg.time_res << 16;
+
+	/* Event LOG base and size */
+	priv->regs->rt_evsz = ~(priv->cfg.evlog_size - 1);
+	priv->regs->rt_evlog = (unsigned int)priv->evlog_hw_base;
+	priv->regs->rt_evirq = 0;
+
+	/* Clear and old IRQ flag and Enable IRQ */
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	priv->regs->irq = GR1553B_IRQ_RTEV|GR1553B_IRQ_RTD|GR1553B_IRQ_RTTE;
+	priv->regs->imask |= GR1553B_IRQEN_RTEVE | GR1553B_IRQEN_RTDE |
+			GR1553B_IRQEN_RTTEE;
+
+	/* Enable and Set RT address */
+	priv->regs->rt_cfg = GR1553RT_KEY |
+			(priv->cfg.rtaddress << GR1553B_RT_CFG_RTADDR_BIT) |
+			GR1553B_RT_CFG_RTEN;
+
+	/* Tell software RT is started */
+	priv->started = 1;
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return 0;
+}
+
+void gr1553rt_stop(void *rt)
+{
+	struct gr1553rt_priv *priv = rt;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	IRQ_GLOBAL_DISABLE(oldLevel);
+
+	/* Stop Hardware */
+	gr1553rt_hw_stop(priv);
+
+	/* Software state */
+	priv->started = 0;
+
+	IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+void gr1553rt_sa_schedule(
+	void *rt,
+	int subadr,
+	int tx,
+	struct gr1553rt_list *list
+	)
+{
+	struct gr1553rt_priv *priv = rt;
+	unsigned short bdid;
+	struct gr1553rt_bd *bd;
+
+	if ( !list || (list->listid == -1) )
+		return;
+
+	/* Get Hardware address of first descriptor in list */
+	bdid = list->bds[0];
+	if ( bdid == 0xffff )
+		return;
+	bd = &priv->bds_hw[bdid];
+
+	list->subadr = subadr;
+
+	/* Update Sub address table */
+	if ( tx ) {
+		list->subadr |= 0x100;
+		priv->subadrs[subadr].txlistid = list->listid;
+		priv->sas_cpu[subadr].txptr = (unsigned int)bd;
+	} else {
+		priv->subadrs[subadr].rxlistid = list->listid;
+		priv->sas_cpu[subadr].rxptr = (unsigned int)bd;
+	}
+}
+
+void gr1553rt_sa_setopts(
+	void *rt,
+	int subadr,
+	unsigned int mask,
+	unsigned int options
+	)
+{
+	struct gr1553rt_priv *priv = rt;
+	unsigned int ctrl;
+
+	if ( (subadr > 31) || (priv->sas_cpu == NULL) )
+		return;
+
+	ctrl = priv->sas_cpu[subadr].ctrl;
+	priv->sas_cpu[subadr].ctrl = (ctrl & ~mask) | options;
+}
+
+void gr1553rt_set_vecword(void *rt, unsigned int mask, unsigned int words)
+{
+	struct gr1553rt_priv *priv = rt;
+	unsigned int vword;
+
+	if ( mask == 0 )
+		return;
+
+	vword = priv->regs->rt_statw;
+
+	priv->regs->rt_statw = (vword & ~mask) | (words & mask);
+}
+
+void gr1553rt_set_bussts(void *rt, unsigned int mask, unsigned int sts)
+{
+	struct gr1553rt_priv *priv = rt;
+	unsigned int stat;
+
+	stat = priv->regs->rt_stat2;
+	priv->regs->rt_stat2 = (stat & ~mask) | (mask & sts);
+}
+
+void gr1553rt_status(void *rt, struct gr1553rt_status *status)
+{
+	struct gr1553rt_priv *priv = rt;
+	struct gr1553b_regs *regs = priv->regs;
+	unsigned int tmp;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	IRQ_GLOBAL_DISABLE(oldLevel);
+	status->status = regs->rt_stat;
+	status->bus_status = regs->rt_stat2;
+
+	tmp = regs->rt_sync;
+	status->synctime = tmp >> 16;
+	status->syncword = tmp & 0xffff;
+
+	tmp = regs->rt_ttag;
+	status->time_res = tmp >> 16;
+	status->time = tmp & 0xffff;
+
+	IRQ_GLOBAL_ENABLE(oldLevel);
+}
+
+void gr1553rt_list_sa(struct gr1553rt_list *list, int *subadr, int *tx)
+{
+	int sa, trt;
+
+	if ( list->subadr == -1 ) {
+		sa = -1;
+		trt = -1;
+	} else {
+		sa = list->subadr & 0xff;
+		trt = (list->subadr & 0x100) >> 8;
+	}
+
+	if ( subadr )
+		*subadr = sa;
+	if ( tx )
+		*tx = trt;
+}
+
+int gr1553rt_evlog_read(void *rt, unsigned int *dst, int max)
+{
+	struct gr1553rt_priv *priv = rt;
+	int cnt, top, bot, left;
+	unsigned int *hwpos;
+
+	/* Get address of hardware's current working entry */
+	hwpos = (unsigned int *)priv->regs->rt_evlog;
+
+	/* Convert into CPU address */
+	hwpos = (unsigned int *)
+		((unsigned int)hwpos - (unsigned int)priv->evlog_hw_base +
+		(unsigned int)priv->evlog_cpu_base);
+
+	if ( priv->evlog_cpu_next == hwpos )
+		return 0;
+
+	if ( priv->evlog_cpu_next > hwpos ) {
+		top = (unsigned int)priv->evlog_cpu_end -
+			(unsigned int)priv->evlog_cpu_next;
+		bot = (unsigned int)hwpos - (unsigned int)priv->evlog_cpu_base;
+	} else {
+		top = (unsigned int)hwpos - (unsigned int)priv->evlog_cpu_next;
+		bot = 0;
+	}
+	top = top / 4;
+	bot = bot / 4;
+
+	left = max;
+	if ( top > 0 ) {
+		if ( top > left ) {
+			cnt = left;
+		} else {
+			cnt = top;
+		}
+		memcpy(dst, priv->evlog_cpu_next, cnt*4);
+		dst += cnt;
+		left -= cnt;
+	}
+
+	if ( (bot > 0) && (left > 0) ) {
+		if ( bot > left ) {
+			cnt = left;
+		} else {
+			cnt = bot;
+		}
+		memcpy(dst, priv->evlog_cpu_base, cnt*4);
+		left -= cnt;
+	}
+
+	cnt = max - left;
+	priv->evlog_cpu_next += cnt;
+	if ( priv->evlog_cpu_next >= priv->evlog_cpu_end ) {
+		priv->evlog_cpu_next = (unsigned int *)
+			((unsigned int)priv->evlog_cpu_base +
+			((unsigned int)priv->evlog_cpu_next -
+			 (unsigned int)priv->evlog_cpu_end ));
+	}
+
+	return max - left;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c b/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c
new file mode 100644
index 0000000..0fe96cd
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ahbstat.c
@@ -0,0 +1,206 @@
+/*  AHB Status register driver
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdint.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#include <ahbstat.h>
+
+void ahbstat_isr(void *arg);
+
+/* AHB fail interrupt callback to user. This function is declared weak so that
+ * the user can define a function pointer variable containing the address
+ * responsible for handling errors
+ *
+ * minor              Index of AHBSTAT hardware
+ * regs               Register address of AHBSTAT
+ * status             AHBSTAT status register at IRQ
+ * failing_address    AHBSTAT Failing address register at IRQ
+ *
+ * * User return 
+ *  0: print error onto terminal with printk and reenable AHBSTAT
+ *  1: just re-enable AHBSTAT
+ *  2: just print error
+ *  3: do nothing, let user do custom handling
+ */
+int (*ahbstat_error)(
+	int minor,
+	struct ahbstat_regs *regs,
+	uint32_t status,
+	uint32_t failing_address
+	) __attribute__((weak)) = NULL;
+
+#define AHBSTAT_STS_CE_BIT 9
+#define AHBSTAT_STS_NE_BIT 8
+#define AHBSTAT_STS_HW_BIT 7
+#define AHBSTAT_STS_HM_BIT 3
+#define AHBSTAT_STS_HS_BIT 0
+
+#define AHBSTAT_STS_CE (1 << AHBSTAT_STS_CE_BIT)
+#define AHBSTAT_STS_NE (1 << AHBSTAT_STS_NE_BIT)
+#define AHBSTAT_STS_HW (1 << AHBSTAT_STS_HW_BIT)
+#define AHBSTAT_STS_HM (0xf << AHBSTAT_STS_HM_BIT)
+#define AHBSTAT_STS_HS (0x7 << AHBSTAT_STS_HS_BIT)
+
+struct ahbstat_priv {
+	struct drvmgr_dev *dev;
+	struct ahbstat_regs *regs;
+	int minor;
+	uint32_t last_status;
+	uint32_t last_address;
+};
+
+int ahbstat_init2(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops ahbstat_ops =
+{
+	.init = {NULL, ahbstat_init2, NULL, NULL},
+	.remove = NULL,
+	.info = NULL
+};
+
+struct amba_dev_id ahbstat_ids[] =
+{
+	{VENDOR_GAISLER, GAISLER_AHBSTAT},
+	{0, 0}		/* Mark end of table */
+};
+
+struct amba_drv_info ahbstat_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,			/* Driver */
+		NULL,				/* Next driver */
+		NULL,				/* Device list */
+		DRIVER_AMBAPP_GAISLER_AHBSTAT_ID,/* Driver ID */
+		"AHBSTAT_DRV",			/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,		/* Bus Type */
+		&ahbstat_ops,
+		NULL,				/* Funcs */
+		0,				/* No devices yet */
+		sizeof(struct ahbstat_priv),
+	},
+	&ahbstat_ids[0]
+};
+
+void ahbstat_register_drv (void)
+{
+	drvmgr_drv_register(&ahbstat_drv_info.general);
+}
+
+int ahbstat_init2(struct drvmgr_dev *dev)
+{
+	struct ahbstat_priv *priv;
+	struct amba_dev_info *ambadev;
+
+	priv = dev->priv;
+	if (!priv)
+		return DRVMGR_NOMEM;
+	priv->dev = dev;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)dev->businfo;
+	if (ambadev == NULL)
+		return DRVMGR_FAIL;
+	priv->regs = (struct ahbstat_regs *)ambadev->info.apb_slv->start;
+	priv->minor = dev->minor_drv;
+
+	/* Initialize hardware */
+	priv->regs->status = 0;
+
+	/* Install IRQ handler */
+	drvmgr_interrupt_register(dev, 0, "ahbstat", ahbstat_isr, priv);
+
+	return DRVMGR_OK;
+}
+
+void ahbstat_isr(void *arg)
+{
+	struct ahbstat_priv *priv = arg;
+	uint32_t fadr, status;
+	int rc;
+
+	/* Get hardware status */
+	status = priv->regs->status;
+	if ((status & AHBSTAT_STS_NE) == 0)
+		return;
+
+	/* IRQ generated by AHBSTAT core... handle it here */
+
+	/* Get Failing address */
+	fadr = priv->regs->failing;
+
+	priv->last_status = status;
+	priv->last_address = fadr;
+
+	/* Let user handle error, default to print the error and reenable HW
+	 *
+	 * User return 
+	 *  0: print error and reenable AHBSTAT
+	 *  1: just reenable AHBSTAT
+	 *  2: just print error reenable
+	 *  3: do nothing
+	 */
+	rc = 0;
+	if (ahbstat_error != NULL)
+		rc = ahbstat_error(priv->minor, priv->regs, status, fadr);
+
+	if ((rc & 0x1) == 0) {
+		printk("\n### AHBSTAT: %s %s error of size %lu by master %d"
+			" at 0x%08lx\n",
+			status & AHBSTAT_STS_CE ? "single" : "non-correctable",
+			status & AHBSTAT_STS_HW ? "write" : "read",
+			(status & AHBSTAT_STS_HS) >> AHBSTAT_STS_HS_BIT,
+			(status & AHBSTAT_STS_HM) >> AHBSTAT_STS_HM_BIT,
+			fadr);
+	}
+
+	if ((rc & 0x2) == 0) {
+		/* Trigger new interrupts */
+		priv->regs->status = 0;
+	}
+}
+
+/* Get Last received AHB Error
+ *
+ * Return
+ *   0: No error received
+ *   1: Error Received, last status and address stored into argument pointers
+ *  -1: No such AHBSTAT device
+ */
+int ahbstat_last_error(int minor, uint32_t *status, uint32_t *address)
+{
+	struct drvmgr_dev *dev;
+	struct ahbstat_priv *priv;
+
+	if (drvmgr_get_dev(&ahbstat_drv_info.general, minor, &dev)) {
+		return -1;
+	}
+	priv = (struct ahbstat_priv *)dev->priv;
+
+	*status = priv->last_status;
+	*address = priv->last_address;
+
+	return (priv->last_status & AHBSTAT_STS_NE) >> AHBSTAT_STS_NE_BIT;
+}
+
+/* Get AHBSTAT registers address from minor. NULL returned if no such device */
+struct ahbstat_regs *ahbstat_get_regs(int minor)
+{
+	struct drvmgr_dev *dev;
+	struct ahbstat_priv *priv;
+
+	if (drvmgr_get_dev(&ahbstat_drv_info.general, minor, &dev)) {
+		return NULL;
+	}
+	priv = (struct ahbstat_priv *)dev->priv;
+
+	return priv->regs;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/analog/gradcdac.c b/c/src/lib/libbsp/sparc/shared/analog/gradcdac.c
new file mode 100644
index 0000000..4b8e636
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/analog/gradcdac.c
@@ -0,0 +1,578 @@
+/*  ADC / DAC (GRADCDAC) interface implementation
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <gradcdac.h>
+
+/****************** DEBUG Definitions ********************/
+#define DBG_IOCTRL 1
+#define DBG_TX 2
+#define DBG_RX 4
+
+#define DEBUG_FLAGS (DBG_IOCTRL | DBG_RX | DBG_TX )
+/* Uncomment for debug output */
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+#include <debug_defs.h>
+
+struct gradcdac_priv {
+	struct gradcdac_regs *regs;	/* Must be first */
+	struct drvmgr_dev *dev;
+	char devName[48];
+
+	unsigned int freq;
+	int irqno;
+	int minor;
+
+	void (*isr_adc)(void *cookie, void *arg);
+	void (*isr_dac)(void *cookie, void *arg);
+	void *isr_adc_arg;
+	void *isr_dac_arg;
+
+	int open;
+};
+
+/* Global variables */
+
+/* Print Info routines */
+void gradcdac_print(void *cookie);
+
+int gradcdac_init2(struct drvmgr_dev *dev);
+int gradcdac_init3(struct drvmgr_dev *dev);
+int gradcadc_device_init(struct gradcdac_priv *pDev);
+void gradcdac_adc_interrupt(void *arg);
+void gradcdac_dac_interrupt(void *arg);
+
+struct drvmgr_drv_ops gradcdac_ops = 
+{
+	.init = {NULL, gradcdac_init2, gradcdac_init3, NULL},
+	.remove = NULL,
+	.info = NULL
+};
+
+struct amba_dev_id gradcdac_ids[] = 
+{
+	{VENDOR_GAISLER, GAISLER_GRADCDAC},
+	{0, 0}		/* Mark end of table */
+};
+
+struct amba_drv_info gradcdac_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,				/* Driver */
+		NULL,					/* Next driver */
+		NULL,					/* Device list */
+		DRIVER_AMBAPP_GAISLER_GRADCDAC_ID,	/* Driver ID */
+		"GRADCDAC_DRV",				/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,			/* Bus Type */
+		&gradcdac_ops,
+		NULL,					/* Funcs */
+		0,					/* No devices yet */
+		0,
+	},
+	&gradcdac_ids[0]
+};
+
+void gradcdac_register_drv (void)
+{
+	DBG("Registering GRADCDAC driver\n");
+	drvmgr_drv_register(&gradcdac_drv_info.general);
+}
+
+int gradcdac_init2(struct drvmgr_dev *dev)
+{
+	struct gradcdac_priv *priv;
+
+	DBG("GRADCDAC[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+	priv = dev->priv = malloc(sizeof(struct gradcdac_priv));
+	if ( !priv )
+		return DRVMGR_NOMEM;
+	memset(priv, 0, sizeof(*priv));
+	priv->dev = dev;
+
+	/* This core will not find other cores, so we wait for init2() */
+
+	return DRVMGR_OK;
+}
+
+
+int gradcdac_init3(struct drvmgr_dev *dev)
+{
+	struct gradcdac_priv *priv = dev->priv;
+	char prefix[32];
+
+	if ( !priv )
+		return DRVMGR_FAIL;
+
+	if ( gradcadc_device_init(priv) ) {
+		free(dev->priv);
+		dev->priv = NULL;
+		return DRVMGR_FAIL;
+	}
+
+	/* Get Filesystem name prefix */
+	prefix[0] = '\0';
+	if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+		/* Failed to get prefix, make sure of a unique FS name
+		 * by using the driver minor.
+		 */
+		sprintf(priv->devName, "/dev/gradcdac%d", dev->minor_drv);
+	} else {
+		/* Got special prefix, this means we have a bus prefix
+		 * And we should use our "bus minor"
+		 */
+		sprintf(priv->devName, "/dev/%sgradcdac%d", prefix, dev->minor_bus);
+	}
+
+	return DRVMGR_OK;
+}
+
+void gradcdac_print_dev(struct gradcdac_priv *pDev)
+{
+	printf("======= GRADCDAC %p =======\n", pDev->regs);
+	printf(" Minor:          %d\n", pDev->minor);
+	printf(" Dev Name:       %s\n", pDev->devName);
+	printf(" RegBase:        %p\n", pDev->regs);
+	printf(" IRQ:            %d and %d\n", pDev->irqno, pDev->irqno+1);
+	printf(" Core Freq:      %d kHz\n", pDev->freq / 1000);
+	printf(" Opened:         %s\n", pDev->open ? "YES" : "NO");
+
+	printf(" CONFIG:         0x%x\n", pDev->regs->config);
+	printf(" STATUS:         0x%x\n", pDev->regs->status);
+}
+
+void gradcdac_print(void *cookie)
+{
+	struct drvmgr_dev *dev;
+	struct gradcdac_priv *pDev;
+
+	if ( cookie ) {
+		gradcdac_print_dev(cookie);
+		return;
+	}
+
+	/* Show all */
+	dev = gradcdac_drv_info.general.dev;
+	while (dev) {
+		pDev = (struct gradcdac_priv *)dev->priv;
+		gradcdac_print_dev(pDev);
+		dev = dev->next_in_drv;
+	}
+}
+
+void gradcdac_hw_reset(struct gradcdac_regs *regs)
+{
+	/* Reset core */
+	regs->config = 0;
+	regs->adrdir = 0;
+	regs->adrout = 0;
+	regs->data_dir = 0;
+	regs->data_out = 0;
+}
+	
+/* Device initialization called once on startup */
+int gradcadc_device_init(struct gradcdac_priv *pDev)
+{
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+	if ( ambadev == NULL ) {
+		return -1;
+	}
+	pnpinfo = &ambadev->info;
+	pDev->irqno = pnpinfo->irq;
+	pDev->regs = (struct gradcdac_regs *)pnpinfo->apb_slv->start;
+	pDev->minor = pDev->dev->minor_drv;
+
+	/* Reset Hardware before attaching IRQ handler */
+	gradcdac_hw_reset(pDev->regs);
+
+	pDev->open = 0;
+	
+	/* Get frequency in Hz */
+	if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &pDev->freq) ) {
+		return -1;
+	}
+
+	DBG("GRADCDAC frequency: %d Hz\n", pDev->freq);
+
+	return 0;
+}
+
+void gradcdac_dac_interrupt(void *arg)
+{
+	struct gradcdac_priv *pDev = arg;
+	if ( pDev->isr_dac ) 
+		pDev->isr_dac(pDev, pDev->isr_dac_arg);
+}
+
+void gradcdac_adc_interrupt(void *arg)
+{
+	struct gradcdac_priv *pDev = arg;
+	if ( pDev->isr_adc ) 
+		pDev->isr_adc(pDev, pDev->isr_adc_arg);
+}
+
+void *gradcdac_open(char *devname)
+{
+	struct gradcdac_priv *pDev;
+	struct drvmgr_dev *dev;
+
+	/* Find device by name */
+	dev = gradcdac_drv_info.general.dev;
+	while ( dev ) {
+		pDev = (struct gradcdac_priv *)dev->priv;
+		if ( pDev ) {
+			if ( strncmp(pDev->devName, devname, sizeof(pDev->devName)) == 0 ) {
+				/* Found matching device name */
+				break;
+			}
+		}
+		dev = dev->next_in_drv;
+	}
+
+	if ( !dev )
+		return NULL;
+
+	/* is device busy/taken? */
+	if  ( pDev->open )
+		return NULL;
+
+	/* Mark device taken */
+	pDev->open = 1;
+
+	return pDev;
+}
+
+void gradcdac_set_config(void *cookie, struct gradcdac_config *cfg)
+{
+	struct gradcdac_priv *pDev = cookie;
+	unsigned int config=0;
+
+	config = (cfg->dac_ws<<GRADCDAC_CFG_DACWS_BIT)&GRADCDAC_CFG_DACWS;
+
+	if ( cfg->wr_pol )
+		config |= GRADCDAC_CFG_WRPOL;
+
+	config |= (cfg->dac_dw<<GRADCDAC_CFG_DACDW_BIT)&GRADCDAC_CFG_DACDW;
+
+	config |= (cfg->adc_ws<<GRADCDAC_CFG_ADCWS_BIT)&GRADCDAC_CFG_ADCWS;
+
+	if ( cfg->rc_pol )
+		config |= GRADCDAC_CFG_RCPOL;
+
+	config |= (cfg->cs_mode<<GRADCDAC_CFG_CSMODE_BIT)&GRADCDAC_CFG_CSMODE;
+
+	if ( cfg->cs_pol )
+		config |= GRADCDAC_CFG_CSPOL;
+
+	if ( cfg->ready_mode )
+		config |= GRADCDAC_CFG_RDYMODE;
+
+	if ( cfg->ready_pol )
+		config |= GRADCDAC_CFG_RDYPOL;
+
+	if ( cfg->trigg_pol )
+		config |= GRADCDAC_CFG_TRIGPOL;
+
+	config |= (cfg->trigg_mode<<GRADCDAC_CFG_TRIGMODE_BIT)&GRADCDAC_CFG_TRIGMODE;
+
+	config |= (cfg->adc_dw<<GRADCDAC_CFG_ADCDW_BIT)&GRADCDAC_CFG_ADCDW;
+
+	/* Write config */
+	pDev->regs->config = config;
+}
+
+void gradcdac_get_config(void *cookie, struct gradcdac_config *cfg)
+{
+	struct gradcdac_priv *pDev = cookie;
+	unsigned int config;
+
+	if ( !cfg )
+		return;
+
+	/* Get config */
+	config = pDev->regs->config;
+	
+	cfg->dac_ws =  (config&GRADCDAC_CFG_DACWS)>>GRADCDAC_CFG_DACWS_BIT;
+
+	cfg->wr_pol = (config&GRADCDAC_CFG_WRPOL)>>GRADCDAC_CFG_WRPOL_BIT;
+
+	cfg->dac_dw = (config&GRADCDAC_CFG_DACDW)>>GRADCDAC_CFG_DACDW_BIT;
+
+	cfg->adc_ws = (config&GRADCDAC_CFG_ADCWS)>>GRADCDAC_CFG_ADCWS_BIT;
+
+	cfg->rc_pol = (config&GRADCDAC_CFG_RCPOL)>>GRADCDAC_CFG_RCPOL_BIT;
+		
+	cfg->cs_mode = (config&GRADCDAC_CFG_CSMODE)>>GRADCDAC_CFG_CSMODE_BIT;
+
+	cfg->cs_pol = (config&GRADCDAC_CFG_CSPOL)>>GRADCDAC_CFG_CSPOL_BIT;
+		
+	cfg->ready_mode = (config&GRADCDAC_CFG_RDYMODE)>>GRADCDAC_CFG_RDYMODE_BIT;
+	
+	cfg->ready_pol = (config&GRADCDAC_CFG_RDYPOL)>>GRADCDAC_CFG_RDYPOL_BIT;
+	
+	cfg->trigg_pol = (config&GRADCDAC_CFG_TRIGPOL)>>GRADCDAC_CFG_TRIGPOL_BIT;
+
+	cfg->trigg_mode = (config&GRADCDAC_CFG_TRIGMODE)>>GRADCDAC_CFG_TRIGMODE_BIT;
+	
+	cfg->adc_dw = (config&GRADCDAC_CFG_ADCDW)>>GRADCDAC_CFG_ADCDW_BIT;
+}
+
+void gradcdac_set_cfg(void *cookie, unsigned int config)
+{
+	struct gradcdac_priv *pDev = cookie;
+	pDev->regs->config = config;
+}
+
+unsigned int gradcdac_get_cfg(void *cookie)
+{
+	struct gradcdac_priv *pDev = cookie;
+	return pDev->regs->config;
+}
+
+unsigned int gradcdac_get_status(void *cookie)
+{
+	struct gradcdac_priv *pDev = cookie;
+	return pDev->regs->status;
+}
+
+/* Install IRQ handler for ADC and/or DAC interrupt.
+ * The installed IRQ handler(ISR) must read the status 
+ * register to clear the pending interrupt avoiding multiple
+ * entries to the ISR caused by the same IRQ.
+ *
+ * \param adc  1=ADC interrupt, 2=ADC interrupt, 3=ADC and DAC interrupt
+ * \param isr  Interrupt service routine called when IRQ is fired
+ * \param arg  custom argument passed to ISR when called.
+ */
+int gradcdac_install_irq_handler(void *cookie, int adc, void (*isr)(void *cookie, void *arg), void *arg)
+{
+	struct gradcdac_priv *pDev = cookie;
+
+	if ( (adc > 3) || !adc )
+		return -1;
+
+	if ( adc & GRADCDAC_ISR_ADC ){
+		pDev->isr_adc_arg = arg;
+		pDev->isr_adc = isr;
+		drvmgr_interrupt_register(pDev->dev, GRADCDAC_IRQ_ADC, "gradcdac_adc", gradcdac_adc_interrupt, pDev);
+	}
+
+	if ( adc & GRADCDAC_ISR_DAC ){
+		pDev->isr_dac_arg = arg;
+		pDev->isr_dac = isr;
+		drvmgr_interrupt_register(pDev->dev, GRADCDAC_IRQ_DAC, "gradcdac_dac", gradcdac_dac_interrupt, pDev);
+	}
+
+	return 0;
+}
+
+void gradcdac_uninstall_irq_handler(void *cookie, int adc)
+{
+	struct gradcdac_priv *pDev = cookie;
+
+	if ( (adc > 3) || !adc )
+		return;
+
+	if ( adc & GRADCDAC_ISR_ADC ){
+		drvmgr_interrupt_unregister(pDev->dev, GRADCDAC_IRQ_ADC, gradcdac_adc_interrupt, pDev);
+		pDev->isr_adc = NULL;
+		pDev->isr_adc_arg = NULL;
+	}
+
+	if ( adc & GRADCDAC_ISR_DAC ){
+		drvmgr_interrupt_unregister(pDev->dev, GRADCDAC_IRQ_DAC, gradcdac_dac_interrupt, pDev);
+		pDev->isr_dac = NULL;
+		pDev->isr_dac_arg = NULL;
+	}
+}
+
+/* Make the ADC circuitry initialize a analogue to digital
+ * conversion. The result can be read out by gradcdac_adc_convert_try
+ * or gradcdac_adc_convert.
+ */
+void gradcdac_adc_convert_start(void *cookie)
+{
+	struct gradcdac_priv *pDev = cookie;
+
+	/* Write to ADC Data Input register to start a conversion */
+	pDev->regs->adc_din = 0;
+}
+
+/* Tries to read the conversion result. If the circuitry is busy 
+ * converting the function return a non-zero value, if the conversion 
+ * has successfully finished the function return zero.
+ *
+ * \param digital_value the resulting converted value is placed here
+ * \return zero     = ADC conversion complete, digital_value contain current conversion result
+ *         positive = ADC busy, digital_value contain previous conversion result
+ *         negative = Conversion request failed.
+ */
+int gradcdac_adc_convert_try(void *cookie, unsigned short *digital_value)
+{
+	struct gradcdac_priv *pDev = cookie;
+	unsigned int status;
+
+	status = pDev->regs->status;
+
+	if ( digital_value ){
+		*digital_value = pDev->regs->adc_din;
+	}
+
+	if ( gradcdac_ADC_isOngoing(status) )
+		return 1;
+
+	if ( gradcdac_ADC_isCompleted(status) )
+		return 0;
+
+	/* Failure */
+	return -1;
+}
+
+/* Waits until the ADC circuity has finished a digital to analogue 
+ * conversion. The Waiting is implemented as a busy loop utilizing
+ * 100% CPU load.
+ */
+int gradcdac_adc_convert(void *cookie, unsigned short *digital_value)
+{
+	struct gradcdac_priv *pDev = cookie;
+	unsigned int status;
+
+	do {
+		status=gradcdac_get_status(pDev);
+	}while ( gradcdac_ADC_isOngoing(status) );
+
+	if ( digital_value )
+		*digital_value = pDev->regs->adc_din;
+
+	if ( gradcdac_ADC_isCompleted(status) )
+		return 0;
+
+	return -1;
+}
+
+/* Try to make the DAC circuitry initialize a digital to analogue 
+ * conversion. If the circuitry is busy by a previous conversion
+ * the function return a non-zero value, if the conversion is
+ * successfully initialized the function return zero.
+ */
+int gradcdac_dac_convert_try(void *cookie, unsigned short digital_value)
+{
+	struct gradcdac_priv *pDev = cookie;
+	unsigned int status = pDev->regs->status;
+
+	if ( gradcdac_DAC_isOngoing(status) )
+		return -1;
+
+	/* Force a new conversion */
+	pDev->regs->dac_dout = digital_value;
+
+	/* Return success */
+	return 0;
+}
+
+/* Initializes a digital to analogue conversion by waiting until 
+ * previous conversions is finished before proceeding with the
+ * conversion. The Waiting is implemented as a busy loop utilizing
+ * 100% CPU load.
+ */
+void gradcdac_dac_convert(void *cookie, unsigned short digital_value)
+{
+	struct gradcdac_priv *pDev = cookie;
+	unsigned int status;
+	
+	do {
+		status = gradcdac_get_status(pDev);
+	}while( gradcdac_DAC_isOngoing(status) );
+	
+	pDev->regs->dac_dout = digital_value;
+}
+
+unsigned int gradcdac_get_adrinput(void *cookie)
+{
+	struct gradcdac_priv *pDev = cookie;
+	return pDev->regs->adrin;
+}
+
+void gradcdac_set_adrinput(void *cookie, unsigned int input)
+{
+	struct gradcdac_priv *pDev = cookie;
+	pDev->regs->adrin = input;
+}
+
+unsigned int gradcdac_get_adroutput(void *cookie)
+{
+	struct gradcdac_priv *pDev = cookie;
+	return pDev->regs->adrout;
+}
+
+void gradcdac_set_adroutput(void *cookie, unsigned int output)
+{
+	struct gradcdac_priv *pDev = cookie;
+	pDev->regs->adrout = output;
+}
+
+unsigned int gradcdac_get_adrdir(void *cookie)
+{
+	struct gradcdac_priv *pDev = cookie;
+	return pDev->regs->adrdir;
+}
+
+void gradcdac_set_adrdir(void *cookie, unsigned int dir)
+{
+	struct gradcdac_priv *pDev = cookie;
+	pDev->regs->adrdir = dir;
+}
+
+unsigned int gradcdac_get_datainput(void *cookie)
+{
+	struct gradcdac_priv *pDev = cookie;
+	return pDev->regs->data_in;
+}
+
+void gradcdac_set_datainput(void *cookie, unsigned int input)
+{
+	struct gradcdac_priv *pDev = cookie;
+	pDev->regs->data_in = input;
+}
+
+unsigned int gradcdac_get_dataoutput(void *cookie)
+{
+	struct gradcdac_priv *pDev = cookie;
+	return pDev->regs->data_out;
+}
+
+void gradcdac_set_dataoutput(void *cookie, unsigned int output)
+{
+	struct gradcdac_priv *pDev = cookie;
+	pDev->regs->data_out = output;
+}
+
+unsigned int gradcdac_get_datadir(void *cookie)
+{
+	struct gradcdac_priv *pDev = cookie;
+	return pDev->regs->data_dir;
+}
+
+void gradcdac_set_datadir(void *cookie, unsigned int dir)
+{
+	struct gradcdac_priv *pDev = cookie;
+	pDev->regs->data_dir = dir;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/ascs/grascs.c b/c/src/lib/libbsp/sparc/shared/ascs/grascs.c
new file mode 100644
index 0000000..a201970
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/ascs/grascs.c
@@ -0,0 +1,615 @@
+/*  This file contains the GRASCS RTEMS driver
+ *
+ *  COPYRIGHT (c) 2008.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <bsp.h>
+#include <ambapp.h>
+#include <grascs.h>
+
+#ifndef GAISLER_ASCS
+#define GAISLER_ASCS 0x043
+#endif
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+typedef struct {
+  volatile unsigned int cmd;
+  volatile unsigned int clk;
+  volatile unsigned int sts;
+  volatile unsigned int tcd;
+  volatile unsigned int tmd;
+} GRASCS_regs;
+
+typedef struct {
+  unsigned char tmconf;
+  unsigned char usconf;
+  unsigned char nslaves;
+  unsigned char dbits;
+  int clkfreq;
+} GRASCS_caps;
+
+typedef struct {
+  GRASCS_regs *regs; /* Pointer to core registers */
+  GRASCS_caps *caps; /* Pointer to capability struct */
+  rtems_id tcsem1, tcsem2;
+  rtems_id tmsem1, tmsem2;
+  volatile char running;
+  int tcptr;
+  int tmptr;
+  int tcwords;
+  int tmwords;
+} GRASCS_cfg;
+
+static GRASCS_cfg *cfg = NULL;
+
+/*------------------------------------*/
+/* Start of internal helper functions */ 
+/*------------------------------------*/
+
+/* Function: ASCS_getaddr
+   Arguments: base: Core's register base address
+              irq: Core's irq
+   Return values: 0 if successful, -1 if core is not found
+   Description: Assigns core's register base address and
+     irq to arguments. Uses AMBA plug and play to find the
+     core.
+*/
+static int ASCS_get_addr(int *base, int *irq) {
+
+  struct ambapp_apb_info core;
+  
+  if(ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_ASCS, &core) == 1) {
+    *base = core.start;
+    *irq = core.irq;
+    DBG("ASCS_get_addr: Registerd ASCS core at 0x%x with irq %i\n",core.start, core.irq);
+    return 0;
+  }
+  DBG("ASCS_get_addr: Failed to detect core\n");
+  return -1;  
+}
+
+/* Function: ASCS_calc_clkreg
+   Arguments: sysfreq: System clock frequency in kHz
+              etrfreq: ETR frequency in Hz
+   Return values: Value of core's CLK-register
+   Description: Calculates value of core's CLK-register. See
+     GRASCS IP core documentation for details.
+*/
+static int ASCS_calc_clkreg(int sysfreq, int etrfreq) {
+
+  if(cfg->caps->usconf)
+    return 1000000/etrfreq;
+  else
+    return sysfreq*1000/etrfreq;
+}
+
+/* Function: ASCS_get_sysfreq
+   Arguments: - 
+   Return values: System clock frequency in kHz, -1 if failed
+   Description: Uses AMBA plug and play to lookup system frequency
+*/
+static int ASCS_get_sysfreq(void) {
+
+  struct ambapp_apb_info gpt;
+  struct gptimer_regs *tregs;
+  int tmp;
+
+  if(ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_GPTIMER, &gpt) == 1) {
+    tregs = (struct gptimer_regs *) gpt.start;
+    tmp = (tregs->scaler_reload + 1)*1000;
+    DBG("ASCS_get_sysfreq: Detected system frequency %i kHz\n",tmp);
+    if((tmp < GRASCS_MIN_SFREQ) || (tmp > GRASCS_MAX_SFREQ)) {
+      DBG("ASCS_get_sysfreq: System frequency is invalid for ASCS core\n");
+      return -1;
+    }
+    else
+      return (tregs->scaler_reload + 1)*1000;
+  }
+  DBG("ASCS_get_sysfreq: Failed to detect system frequency\n");
+  return -1;
+}
+
+/* Function: ASCS_irqhandler
+   Arguments: v: not used
+   Return values: -
+   Description: Determines the source of the interrupt, clears the
+                appropriate bits in the core's STS register and releases
+		the associated semaphore
+*/
+static rtems_isr ASCS_irqhandler(rtems_vector_number v) {
+
+  if(cfg->regs->sts & GRASCS_STS_TCDONE) {
+    /* Clear TC done bit */
+    cfg->regs->sts |= GRASCS_STS_TCDONE;    
+
+    if(--cfg->tcwords == 0)
+      /* No more TCs to perform right now */
+      rtems_semaphore_release(cfg->tcsem2);
+    else {
+      /* Block not sent yet, start next TC */
+      if(cfg->caps->dbits == 8) {
+	cfg->tcptr++;
+	cfg->regs->tcd = *((unsigned char*)cfg->tcptr);
+      }
+      else if(cfg->caps->dbits == 16) {
+	cfg->tcptr += 2;
+	cfg->regs->tcd = *((unsigned short int*)cfg->tcptr);
+      }
+      else {
+	cfg->tcptr += 4;
+	cfg->regs->tcd = *((unsigned int*)cfg->tcptr);
+      }
+    }
+  }
+
+  if(cfg->regs->sts & GRASCS_STS_TMDONE) {
+    /* Clear TM done bit */
+    cfg->regs->sts |= GRASCS_STS_TMDONE;
+
+    /* Store received data */
+    if(cfg->caps->dbits == 8) {
+      *((unsigned char*)cfg->tmptr) = (unsigned char)(cfg->regs->tmd & 0xFF);
+      cfg->tmptr++;
+    }
+    else if(cfg->caps->dbits == 16) {
+      *((unsigned short int*)cfg->tmptr) = (unsigned short int)(cfg->regs->tmd & 0xFFFF);
+      cfg->tmptr += 2;
+    }
+    else {
+      *((unsigned int*)cfg->tmptr) = cfg->regs->tmd;
+      cfg->tmptr += 4;
+    }
+    
+    if(--cfg->tmwords == 0)
+      /* No more TMs to perform right now */
+      rtems_semaphore_release(cfg->tmsem2);
+    else
+      /* Block not received yet, start next TM */
+      cfg->regs->cmd |= GRASCS_CMD_SENDTM;      
+  }
+}
+
+/*---------------------------*/
+/* Start of driver interface */
+/*---------------------------*/
+
+/* Function: ASCS_init
+   Arguments: -
+   Return values: 0 if successful, -1 if unsuccessful
+   Description: Initializes the ASCS core
+*/
+int ASCS_init(void) {
+
+  int base, irq, tmp;
+
+  DBG("ASCS_init: Starting initialization of ASCS core\n");
+  
+  /* Allocate memory for config, status and capability struct */
+  if((cfg = (GRASCS_cfg*)malloc(sizeof(GRASCS_cfg))) == NULL) {
+    DBG("ASCS_init: Could not allocate memory for cfg struc\n");
+    return -1;
+  }
+  
+  if((cfg->caps = (GRASCS_caps*)calloc(1,sizeof(GRASCS_caps))) == NULL) {
+    DBG("ASCS_init: Could not allocate memory for caps struc\n");
+    goto init_error1;
+  }
+    
+  /* Create semaphores for blocking ASCS_TC/TM functions */
+  if(rtems_semaphore_create(rtems_build_name('A','S','C','0'),1,
+			    (RTEMS_FIFO|RTEMS_BINARY_SEMAPHORE|
+			     RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
+			     RTEMS_NO_PRIORITY_CEILING), 0,
+			    &cfg->tcsem1) != RTEMS_SUCCESSFUL) {
+    DBG("ASCS_init: Failed to create semaphore ASC0\n");
+    goto init_error2;
+  }
+  if(rtems_semaphore_create(rtems_build_name('A','S','C','1'),1,
+			    (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
+			     RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
+			     RTEMS_NO_PRIORITY_CEILING), 0,
+			    &cfg->tmsem1) != RTEMS_SUCCESSFUL) {
+    DBG("ASCS_init: Failed to create semaphore ASC1\n");
+    goto init_error2;
+  }
+  if(rtems_semaphore_create(rtems_build_name('A','S','C','2'),0,
+			    (RTEMS_FIFO|RTEMS_BINARY_SEMAPHORE|
+			     RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
+			     RTEMS_NO_PRIORITY_CEILING), 0,
+			    &cfg->tcsem2) != RTEMS_SUCCESSFUL) {
+    DBG("ASCS_init: Failed to create semaphore ASC2\n");
+    goto init_error2;
+  }
+  if(rtems_semaphore_create(rtems_build_name('A','S','C','3'),0,
+			    (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
+			     RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
+			     RTEMS_NO_PRIORITY_CEILING), 0,
+			    &cfg->tmsem2) != RTEMS_SUCCESSFUL) {
+    DBG("ASCS_init: Failed to create semaphore ASC3\n");
+    goto init_error2;
+  }
+
+  /* Set pointer to core registers */
+  if(ASCS_get_addr(&base, &irq) == -1)
+    goto init_error2;
+
+  cfg->regs = (GRASCS_regs*)base;
+  
+  /* Read core capabilities */
+  tmp = cfg->regs->sts;
+  cfg->caps->dbits = ((tmp >> GRASCS_STS_DBITS_BITS) & 0x1F) + 1;
+  cfg->caps->nslaves = ((tmp >> GRASCS_STS_NSLAVES_BITS) & 0xF) + 1;
+  cfg->caps->tmconf = (tmp >> GRASCS_STS_TMCONF_BITS) & 0x1;
+  cfg->caps->usconf = (tmp >> GRASCS_STS_USCONF_BITS) & 0x1;
+
+  /* Reset and configure core */
+  cfg->running = 0;
+  cfg->regs->cmd |= GRASCS_CMD_RESET;
+  if((tmp = ASCS_get_sysfreq()) == -1)
+    goto init_error2;
+  cfg->caps->clkfreq = tmp;
+  while(ASCS_iface_status())
+    ;  
+  cfg->regs->clk = ASCS_calc_clkreg(tmp, GRASCS_DEFAULT_ETRFREQ);
+  cfg->regs->cmd = GRASCS_CMD_US1C;
+  cfg->regs->cmd |= (tmp/1000 << GRASCS_CMD_US1_BITS) | GRASCS_CMD_US1C |
+    GRASCS_CMD_TCDONE | GRASCS_CMD_TMDONE;
+
+  /* Register interrupt routine */
+  set_vector(ASCS_irqhandler,irq+0x10,2);
+  
+  return 0;
+
+ init_error2:
+  free(cfg->caps);
+ init_error1:
+  free(cfg);
+  return -1;
+}
+
+/* Function: ASCS_input_select
+   Arguments: slave: The number of the slave that is active,
+              numbered from 0-15
+   Return values: 0 if successful, -GRASCS_ERROR_CAPFAULT if slave value
+                  is negative or too big, -GRASCS_ERROR_TRANSACTIVE if
+		  a TM is active.
+   Description: Sets the slave_sel bits in the core's CMD register.
+                they are used to choose which slave the core listens
+		to when performing a TM. The bits can't be set
+		during a TM, and the function will in such a case fail.
+*/
+int ASCS_input_select(int slave) {
+
+  if((slave < 0) || (slave > cfg->caps->nslaves)) {
+    /* Slave number is negative or too big */
+    DBG("ASCS_input_select: Wrong slave number\n");
+    return -GRASCS_ERROR_CAPFAULT;
+  }
+    
+  if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
+     RTEMS_SUCCESSFUL) {
+    /* Can't change active slave during a TM */
+    DBG("ASCS_input_select: Transaction active\n");
+    return -GRASCS_ERROR_TRANSACTIVE;
+  }
+  
+  cfg->regs->cmd = ((cfg->regs->cmd &= ~GRASCS_CMD_SLAVESEL) |
+		    (slave << GRASCS_CMD_SLAVESEL_BITS));
+
+  rtems_semaphore_release(cfg->tmsem1);
+  return 0;
+}
+
+/* Function: ASCS_etr_select
+   Arguments: src: The source of the ETR signal, valid values are
+                   0-GRASCS_MAX_TMS (0 = internal source, 1-GRASCS_MAX_TMS =
+		   external time markers 1-GRASCS_MAX_TMS).
+	      freq: ETR frequency in Hz. Valid values are
+	            GRASCS_MIN_ETRFREQ-GRASCS_MAX_ETRFREQ
+   Return values: 0 if successful, -GRASCS_ERROR_CAPFAULT if src or freq values
+                  are invalid, -GRASCS_ERROR_STARTSTOP if synchronization interface
+		  isn't stopped.
+   Description: Changes the source for the ETR signal. The frequency of source signal
+                is assumed to be the same as the frequency of the freq input
+*/
+int ASCS_etr_select(int etr, int freq) {
+  
+  if((etr < 0) || (etr > GRASCS_MAX_TMS) || ((cfg->caps->tmconf == 0) && (etr > 0)) ||
+     (freq < GRASCS_MIN_ETRFREQ) || (freq > GRASCS_MAX_ETRFREQ)) {
+    /* ETR source value or frequency is invalid */
+    DBG("ASCS_etr_select: Wrong etr src number or wrong frequency\n");
+    return -GRASCS_ERROR_CAPFAULT;
+  }
+  
+  if(cfg->regs->sts & GRASCS_STS_ERUNNING) {
+    /* Synchronization interface is running */
+    DBG("ASCS_etr_select: Synch interface is running\n");
+    return -GRASCS_ERROR_STARTSTOP;
+  }
+  
+  cfg->regs->clk = ASCS_calc_clkreg(cfg->caps->clkfreq,freq);
+  cfg->regs->cmd = ((cfg->regs->cmd &= ~GRASCS_CMD_ETRCTRL) |
+		    (etr << GRASCS_CMD_ETRCTRL_BITS));
+
+  return 0;
+}
+
+/* Function: ASCS_start
+   Arguments: -
+   Return values: -
+   Description: Enables the serial interface. 
+*/
+void ASCS_start(void) {
+  
+  /* Set register and internal status to running */
+  cfg->regs->cmd |= GRASCS_CMD_STARTSTOP;
+  cfg->running = 1;
+}
+
+/* Function: ASCS_stop
+   Arguments: -
+   Return values: -
+   Description: Disables the serial interface. This function will
+                block until possible calls to TC_send(_block) and
+		TM_recv(_block) has returned in order to be sure
+		that started transactions will be performed.
+*/
+void ASCS_stop(void) {
+
+  /* Set internal status to stopped */
+  cfg->running = 0;
+
+  /* Obtain semaphores to avoid possible situation where a
+     TC_send(_block) or TM_recv(_block) is aborted and driver is
+     waiting forever for an interrupt */
+  rtems_semaphore_obtain(cfg->tcsem1,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+  rtems_semaphore_obtain(cfg->tmsem1,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+
+  /* Change actual register value */
+  cfg->regs->cmd &= ~GRASCS_CMD_STARTSTOP;
+
+  /* Release the semaphores */
+  rtems_semaphore_release(cfg->tcsem1);
+  rtems_semaphore_release(cfg->tmsem1);
+}
+
+/* Function: ASCS_iface_status
+   Arguments: - 
+   Return values: 0 if both serial interface and synch interface is stopped,
+                  1 if serial interface is running buth synch interface is
+		  stopped, 2 if serial interface is stopped but synch interface
+		  is running, 3 if both serial and synch interface is running
+   Description: Reads the core's STS register and reports the status of the
+                serial and synch interfaces
+*/
+int ASCS_iface_status(void) {
+
+  return ((cfg->regs->sts & 0x3) & (0x2 | cfg->running));
+}
+
+/* Function: ASCS_TC_send
+   Arguments: word: Pointer to a word that should be sent
+   Return values: 0 on success
+                  -GRASCS_ERROR_STARTSTOP if serial interface is stopped,
+		  -GRASCS_ERROR_TRANSACTIVE if another TC is in progress.
+   Description: Start a TC and sends the data that word points to.
+*/
+int ASCS_TC_send(int *word) {
+
+  int retval;
+
+  if(rtems_semaphore_obtain(cfg->tcsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
+     RTEMS_SUCCESSFUL) {
+    /* Can't start a TC_send if another TC_send of TC_send_block is
+       in progress */
+    DBG("ASCS_TC_send: Could not obtain semaphore, transcation probably in progress\n");
+    return -GRASCS_ERROR_TRANSACTIVE;
+  }
+    
+  if(!cfg->running) {
+    /* Can't start a TC if serial interface isn't started */
+    DBG("ASCS_TC_send: Serial interface is not started\n");
+    retval = -GRASCS_ERROR_STARTSTOP;
+  }
+  else {
+    /* Start the transfer */
+    cfg->tcwords = 1;
+    if(cfg->caps->dbits == 8)
+      cfg->regs->tcd = *((unsigned char*)word);
+    else if(cfg->caps->dbits == 16)
+      cfg->regs->tcd = *((unsigned short int*)((int)word & ~1));
+    else
+      cfg->regs->tcd = *((unsigned int*)((int)word & ~3));
+    
+    /* Wait until transfer is complete */
+    rtems_semaphore_obtain(cfg->tcsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+    retval = 0;
+  }
+
+  rtems_semaphore_release(cfg->tcsem1);
+  
+  return retval;
+}
+
+/* Function: ASCS_TC_send_block
+   Arguments: block: Pointer to the start of a datablock that
+                     should be sent.
+	      ntrans: Number of transfers needed to transfer
+	              the block.
+   Return values: 0 if successfull, -GRASCS_ERROR_STARTSTOP if TC
+                  couldn't be started because serial interface is
+                  stopped, -GRASCS_ERROR_TRANSACTIVE if TC couldn't
+		  be started because another TC isn't done yet.
+   Description: Starts ntrans TCs and sends the data that starts at the
+                address that block points to. The size of each
+		transaction will vary depending on whether the core is
+		configured for 8, 16, or 32 bits data transfers.
+*/
+int ASCS_TC_send_block(int *block, int ntrans) {
+
+  int retval;
+
+  if(rtems_semaphore_obtain(cfg->tcsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
+     RTEMS_SUCCESSFUL) {
+    /* Can't start a TC_send_block if another TC_send of TC_send_block is
+       in progress */
+    DBG("ASCS_TC_send_block: Could not obtain semaphore, transcation probably in progress\n");
+    return -GRASCS_ERROR_TRANSACTIVE;
+  }
+
+  if(!cfg->running) {
+    /* Can't start a TC if serial interface isn't started */
+    DBG("ASCS_TC_send_block: Serial interface is not started\n");
+    retval = -GRASCS_ERROR_STARTSTOP;
+  }
+  else {
+    /* Start the first transfer */
+    cfg->tcwords = ntrans;
+    if(cfg->caps->dbits == 8) {
+      cfg->tcptr = (int)block;
+      cfg->regs->tcd = *((unsigned char*)cfg->tcptr);
+    }
+    else if(cfg->caps->dbits == 16) {
+      cfg->tcptr = (int)block & ~1;
+      cfg->regs->tcd = *((unsigned short int*)cfg->tcptr);
+    }
+    else {
+      cfg->tcptr = (int)block & ~3;
+      cfg->regs->tcd = *((unsigned int*)cfg->tcptr);
+    }
+        
+    /* Wait until all transfers are complete */
+    rtems_semaphore_obtain(cfg->tcsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+    retval = 0;
+  }
+  
+  rtems_semaphore_release(cfg->tcsem1);
+
+  return retval;
+}
+
+/* Function: ASCS_TC_sync_start
+   Arguments: -
+   Return values: -
+   Description: Starts synchronization interface. Might
+     be delayed if a TM is in progress. SW can poll
+     ASCS_iface_status() to find out when synch interface is
+     started. First ETR pulse can be delay up to one ETR
+     period depending on the source of the ETR and
+     activity on the TM line.
+*/
+void ASCS_TC_sync_start(void) {
+  
+  cfg->regs->cmd |= GRASCS_CMD_ESTARTSTOP;
+}
+
+/* Function: ASCS_TC_sync_stop
+   Arguments: -
+   Return values: -
+   Description: Stops the synchronization interface. Might
+     be delayed for 1 us if a ETR pulse is being generated. SW
+     can determine when synch interface has stopped by polling
+     ASCS_iface_status().
+*/
+void ASCS_TC_sync_stop(void) {
+  
+  cfg->regs->cmd &= ~GRASCS_CMD_ESTARTSTOP;
+}
+
+/* Function: ASCS_TM_recv
+   Arguments: word: Pointer to where the received word should be
+                    placed
+   Return values: 0 if successful, -GRASCS_ERROR_STARTSTOP if serial
+                  interface isn't started, -GRASCS_ERROR_TRANSACTIVE
+		  if another TM is in progress
+   Description: Starts a TM and stores the incoming data in word.
+*/
+int ASCS_TM_recv(int *word) {
+
+  int retval;
+
+  if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
+     RTEMS_SUCCESSFUL) {
+    /* Can't start a TM_recv if another TM_recv of TM_recv_block is
+       in progress */
+    DBG("ASCS_TM_recv: Could not obtain semaphore, transaction probably in progress\n");
+    return -GRASCS_ERROR_TRANSACTIVE;
+  }
+
+  if(!cfg->running) {
+    /* Can't start a TM if serial interface isn't started */
+    DBG("ASCS_TM_recv: Serial interface is not started\n");
+    retval = -GRASCS_ERROR_STARTSTOP;
+  }
+  else {
+    /* Start transfer */
+    cfg->tmwords = 1;
+    cfg->tmptr = (int)word;
+    cfg->regs->cmd |= GRASCS_CMD_SENDTM;
+    
+    /* Wait until transfer finishes */
+    rtems_semaphore_obtain(cfg->tmsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+    retval = 0;
+  }
+
+  rtems_semaphore_release(cfg->tmsem1);
+
+  return retval;
+}
+
+/* Function: ASCS_TM_recv_block
+   Arguments: block: Pointer to where the received datablock
+                     should be stored.
+	      ntrans: Number of transfers needed to transfer
+	              the block.
+   Return values: 0 if successful, -GRASCS_ERROR_STARTSTOP if serial
+                  interface isn't started, -GRASCS_ERROR_TRANSACTIVE if
+		  a performed TM hasn't been processed yet
+   Description: Starts ntrans TMs and stores the data at the address
+                that block points to. The size of each transaction
+		will vary depending on whether the core is
+		configured for 8, 16, or 32 bits data transfers.
+*/
+int ASCS_TM_recv_block(int *block, int ntrans) {
+
+  int retval;
+
+  if(rtems_semaphore_obtain(cfg->tmsem1,RTEMS_NO_WAIT,RTEMS_NO_TIMEOUT) !=
+     RTEMS_SUCCESSFUL) {
+    /* Can't start a TM_recv_block if another TM_recv of TM_recv_block is
+       in progress */
+    DBG("ASCS_TM_recv_block: Could not obtain semaphore, transaction probably in progress\n");
+    return -GRASCS_ERROR_TRANSACTIVE;
+  }
+
+  if(!cfg->running) {
+    /* Can't start a TM if serial interface isn't started */
+    DBG("ASCS_TM_recv_block: Serial interface is not started\n");
+    retval = -GRASCS_ERROR_STARTSTOP;
+  }
+  else {
+    /* Start transfer */
+    cfg->tmwords = ntrans;
+    cfg->tmptr = (int)block;
+    cfg->regs->cmd |= GRASCS_CMD_SENDTM;
+    
+    /* Wait until transfer finishes */
+    rtems_semaphore_obtain(cfg->tmsem2,RTEMS_WAIT,RTEMS_NO_TIMEOUT);
+    retval = 0;
+  }
+
+  rtems_semaphore_release(cfg->tmsem1);
+
+  return retval;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/can/canmux.c b/c/src/lib/libbsp/sparc/shared/can/canmux.c
new file mode 100644
index 0000000..0884d91
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/can/canmux.c
@@ -0,0 +1,197 @@
+/*
+ *  CAN_MUX driver. Present in GR712RC.
+ *
+ *  COPYRIGHT (c) 2008.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <bsp.h>
+#include <rtems/bspIo.h> /* printk */
+
+#include <canmux.h>
+#include <ambapp.h>
+
+#ifndef GAISLER_CANMUX
+#define GAISLER_CANMUX 0x081
+#endif
+
+#if !defined(CANMUX_DEVNAME) 
+ #undef CANMUX_DEVNAME
+ #define CANMUX_DEVNAME "/dev/canmux"
+#endif
+
+/* Enable debug output? */
+/* #define DEBUG */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...) 
+#endif
+
+#define BUSA_SELECT (1 << 0)
+#define BUSB_SELECT (1 << 1)
+
+struct canmux_priv {
+	volatile unsigned int *muxreg;
+	rtems_id devsem;
+	int open;
+};
+
+static struct canmux_priv *priv;
+
+static rtems_device_driver canmux_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver canmux_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver canmux_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver canmux_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver canmux_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver canmux_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg);
+
+
+static rtems_device_driver canmux_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t*)arg;
+	
+	DBG("CAN_MUX:  IOCTL %d\n\r", ioarg->command);
+
+	ioarg->ioctl_return = 0;
+	switch(ioarg->command) {
+	case CANMUX_IOC_BUSA_SATCAN: *priv->muxreg &= ~BUSA_SELECT; break;
+	case CANMUX_IOC_BUSA_OCCAN1: *priv->muxreg |= BUSA_SELECT;  break;
+	case CANMUX_IOC_BUSB_SATCAN: *priv->muxreg &= ~BUSB_SELECT; break;
+	case CANMUX_IOC_BUSB_OCCAN2: *priv->muxreg |= BUSB_SELECT; break;
+	default: return RTEMS_NOT_DEFINED;
+	}
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver canmux_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t*)arg;
+	
+	rw_args->bytes_moved = 0;
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver canmux_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t*)arg;
+	
+	rw_args->bytes_moved = 0;
+	
+	return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver canmux_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	DBG("CAN_MUX: Closing %d\n\r",minor);
+
+	priv->open = 0;
+	return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver canmux_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	DBG("CAN_MUX: Opening %d\n\r",minor);
+	
+	rtems_semaphore_obtain(priv->devsem,RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+	if (priv->open) {
+		rtems_semaphore_release(priv->devsem);
+		return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+	}
+	priv->open = 1;
+	rtems_semaphore_release(priv->devsem);
+
+	DBG("CAN_MUX: Opening %d success\n\r",minor);
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver canmux_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	struct ambapp_apb_info d;
+	char fs_name[20];
+	rtems_status_code status;
+
+	DBG("CAN_MUX: Initialize..\n\r");
+
+	strcpy(fs_name, CANMUX_DEVNAME);
+	
+	/* Find core and initialize register pointer */
+	if (!ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_CANMUX, &d)) {
+		printk("CAN_MUX: Failed to find CAN_MUX core\n\r");
+		return -1;
+	}
+	
+	status = rtems_io_register_name(fs_name, major, minor);
+	if (RTEMS_SUCCESSFUL != status)
+		rtems_fatal_error_occurred(status);
+
+	/* Create private structure */
+	if ((priv = malloc(sizeof(struct canmux_priv))) == NULL) {
+		printk("CAN_MUX driver could not allocate memory for priv structure\n\r");
+		return -1;
+	}
+	
+	priv->muxreg = (unsigned int*)d.start;
+
+	status = rtems_semaphore_create(
+		rtems_build_name('M', 'd', 'v', '0'),
+		1,
+		RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+		RTEMS_NO_PRIORITY_CEILING,
+		0, 
+		&priv->devsem);
+	if (status != RTEMS_SUCCESSFUL) {
+		printk("CAN_MUX: Failed to create dev semaphore (%d)\n\r", status);
+		free(priv);
+		return RTEMS_UNSATISFIED;
+	}
+	
+	priv->open = 0;
+
+	return RTEMS_SUCCESSFUL;
+}
+
+
+#define CANMUX_DRIVER_TABLE_ENTRY { canmux_initialize, canmux_open, canmux_close, canmux_read, canmux_write, canmux_ioctl }
+
+static rtems_driver_address_table canmux_driver = CANMUX_DRIVER_TABLE_ENTRY;
+
+int canmux_register(void)
+{
+	rtems_status_code r;
+	rtems_device_major_number m;
+
+	DBG("CAN_MUX: canmux_register called\n\r");
+
+	if ((r = rtems_io_register_driver(0, &canmux_driver, &m)) == RTEMS_SUCCESSFUL) {
+		DBG("CAN_MUX driver successfully registered, major: %d\n\r", m);
+	} else {
+		switch(r) {
+		case RTEMS_TOO_MANY:
+			printk("CAN_MUX rtems_io_register_driver failed: RTEMS_TOO_MANY\n\r"); break;
+		case RTEMS_INVALID_NUMBER:  
+			printk("CAN_MUX rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n\r"); break;
+		case RTEMS_RESOURCE_IN_USE:
+			printk("CAN_MUX rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n\r"); break;
+		default:
+			printk("CAN_MUX rtems_io_register_driver failed\n\r");
+		}
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/can/satcan.c b/c/src/lib/libbsp/sparc/shared/can/satcan.c
new file mode 100644
index 0000000..36c6bb9
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/can/satcan.c
@@ -0,0 +1,714 @@
+/*
+ *  SatCAN FPGA driver
+ * 
+ *  COPYRIGHT (c) 2008.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <bsp.h>
+#include <rtems/bspIo.h> /* printk */
+
+#include <satcan.h>
+#include <ambapp.h>
+
+#ifndef GAISLER_SATCAN
+#define GAISLER_SATCAN 0x080
+#endif
+
+#if !defined(SATCAN_DEVNAME) 
+ #undef SATCAN_DEVNAME
+ #define SATCAN_DEVNAME "/dev/satcan"
+#endif
+
+/* Enable debug output? */
+/* #define DEBUG */ 
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...) 
+#endif
+
+
+/* Defines related to DMA */
+#define ALIGN_2KMEM 32*1024
+#define ALIGN_8KMEM 128*1024
+
+#define OFFSET_2K_LOW_POS 15
+#define OFFSET_8K_LOW_POS 17
+
+#define DMA_2K_DATA_SELECT (1 << 14)
+#define DMA_8K_DATA_SELECT (1 << 16)
+
+#define DMA_2K_DATA_OFFSET 16*1024
+#define DMA_8K_DATA_OFFSET 64*1024
+
+/* Core register structures and defines */
+
+/* Indexes to SatCAN registers in satcan array are declared in satcan.h*/
+/* Fields for some of the SatCAN FPGA registers */
+
+/* CmdReg0 */
+#define CAN_TODn_Int_sel   (1 << 5)
+
+/* CmdReg1 */
+#define Sel_2k_8kN         (1 << 0)
+
+/* Read FIFO */
+#define FIFO_Full          (1 << 8)
+#define FIFO_Empty         (1 << 9)
+
+/* DMA Ch_Enable */
+#define DMA_AutoInitDmaTx  (1 << 3)
+#define DMA_EnTx2          (1 << 2)
+#define DMA_EnTx1          (1 << 1)
+#define DMA_EnRx           (1 << 0)
+
+/* SatCAN wrapper register fields */
+#define CTRL_BT_P     9
+#define CTRL_NODENO_P 5
+#define CTRL_DIS      (1 << 2)
+#define CTRL_DPS_P    1
+#define CTRL_RST      (1 << 0)
+
+#define IRQ_AHB       (1 << 8)
+#define IRQ_PPS       (1 << 7)
+#define IRQ_M5        (1 << 6)
+#define IRQ_M4        (1 << 5)
+#define IRQ_M3        (1 << 4)
+#define IRQ_M2        (1 << 3)
+#define IRQ_M1        (1 << 2)
+#define IRQ_SYNC      (1 << 1)
+#define IRQ_CAN       (1 << 0)
+
+#define MSK_AHB       (1 << 8)
+#define MSK_PPS       (1 << 7)
+#define MSK_M5        (1 << 6)
+#define MSK_M4        (1 << 5)
+#define MSK_M3        (1 << 4)
+#define MSK_M2        (1 << 3)
+#define MSK_M1        (1 << 2)
+#define MSK_SYNC      (1 << 1)
+#define MSK_CAN       (1 << 0)
+
+
+
+struct satcan_regs {
+	volatile unsigned int satcan[32];
+	volatile unsigned int ctrl;
+	volatile unsigned int irqpend;
+	volatile unsigned int irqmask;
+	volatile unsigned int membase;
+};
+
+
+struct satcan_priv {
+	/* config */
+	void           *dmaptr;
+	unsigned char  *alptr;
+	satcan_config  *cfg;
+	
+	/* driver state */
+	rtems_id       devsem;
+	rtems_id       txsem;
+	int            open;
+	int            txactive;
+	int            dmaen;
+	int            doff;
+	rtems_interval timeout;
+	int            dmamode;
+};
+
+static struct satcan_regs *regs;
+static struct satcan_priv *priv;
+
+static rtems_device_driver satcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver satcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver satcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver satcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver satcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver satcan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg);
+
+
+/*
+ * almalloc: allocate memory area of size sz aligned on sz boundary 
+ * alptr: Utilized to return aligned pointer
+ * ptr:   Unaligned pointer
+ * sz:    Size of memory area
+ */
+static void almalloc(unsigned char **alptr, void **ptr, int sz)
+{
+  *ptr = calloc(1,2*sz);
+  *alptr = (unsigned char *) (((int)*ptr+sz) & ~(sz-1));
+}
+
+static rtems_isr satcan_interrupt_handler(rtems_vector_number v)
+{
+	unsigned int irq;
+	unsigned int fifo;
+	
+	irq = regs->irqpend;
+	
+	if (irq & IRQ_AHB && priv->cfg->ahb_irq_callback) {
+		priv->cfg->ahb_irq_callback();
+	}
+	if (irq & IRQ_PPS && priv->cfg->pps_irq_callback) {
+		priv->cfg->pps_irq_callback();
+	}
+	if (irq & IRQ_M5 && priv->cfg->m5_irq_callback) {
+		priv->cfg->m5_irq_callback();
+	}
+	if (irq & IRQ_M4 && priv->cfg->m4_irq_callback) {
+		priv->cfg->m4_irq_callback();
+	}
+	if (irq & IRQ_M3 && priv->cfg->m3_irq_callback) {
+		priv->cfg->m3_irq_callback();
+	}
+	if (irq & IRQ_M2 && priv->cfg->m2_irq_callback) {
+		priv->cfg->m2_irq_callback();
+	}
+	if (irq & IRQ_M1 && priv->cfg->m1_irq_callback) {
+		priv->cfg->m1_irq_callback();
+	}
+	if (irq & IRQ_SYNC && priv->cfg->sync_irq_callback) {
+		priv->cfg->sync_irq_callback();
+	}
+	if (irq & IRQ_CAN) {
+		fifo = regs->satcan[SATCAN_FIFO];
+		if (!(fifo & FIFO_Empty) && priv->txactive &&
+		    (((fifo & 0xff) == SATCAN_IRQ_EOD1) || ((fifo & 0xff) == SATCAN_IRQ_EOD2))) { 
+			rtems_semaphore_release(priv->txsem);
+		}
+		if (priv->cfg->can_irq_callback)
+			priv->cfg->can_irq_callback(fifo);
+	}
+}
+
+
+
+static rtems_device_driver satcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t*)arg;
+	int *value;
+	rtems_interval *timeout;
+	satcan_regmod *regmod;
+
+	DBG("SatCAN:  IOCTL %d\n\r", ioarg->command);
+
+	ioarg->ioctl_return = 0;
+	switch(ioarg->command) {
+	case SATCAN_IOC_DMA_2K:
+		DBG("SatCAN: ioctl: setting 2K DMA mode\n\r");
+		free(priv->dmaptr);
+		almalloc(&priv->alptr, &priv->dmaptr, ALIGN_2KMEM);
+		if (priv->dmaptr == NULL) {
+			printk("SatCAN: Failed to allocate DMA memory\n\r");
+			return RTEMS_NO_MEMORY;
+		}
+
+		regs->membase = (unsigned int)priv->alptr;
+		regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> OFFSET_2K_LOW_POS;
+		regs->satcan[SATCAN_CMD1] = regs->satcan[SATCAN_CMD1] | Sel_2k_8kN;
+		break;
+
+	case SATCAN_IOC_DMA_8K:
+		DBG("SatCAN: ioctl: setting 8K DMA mode\n\r");
+		free(priv->dmaptr);
+		almalloc(&priv->alptr, &priv->dmaptr, ALIGN_8KMEM);
+		if (priv->dmaptr == NULL) {
+			printk("SatCAN: Failed to allocate DMA memory\n\r");
+			return RTEMS_NO_MEMORY;
+		}
+		
+		regs->membase = (unsigned int)priv->alptr;
+		regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> OFFSET_8K_LOW_POS;
+		regs->satcan[SATCAN_CMD1] = regs->satcan[SATCAN_CMD1] & ~Sel_2k_8kN;
+		break;
+		
+	case SATCAN_IOC_GET_REG:
+		/* Get regmod structure from argument */
+		regmod = (satcan_regmod*)ioarg->buffer;
+		DBG("SatCAN: ioctl: getting register %d\n\r", regmod->reg);
+		if (regmod->reg < 0)
+			return RTEMS_INVALID_NAME;
+		else if (regmod->reg <= SATCAN_FILTER_STOP)
+			regmod->val = regs->satcan[regmod->reg];
+		else if (regmod->reg == SATCAN_WCTRL)
+			regmod->val = regs->ctrl;
+		else if (regmod->reg == SATCAN_WIPEND)
+			regmod->val = regs->irqpend;
+		else if (regmod->reg == SATCAN_WIMASK)
+			regmod->val = regs->irqmask;
+		else if (regmod->reg == SATCAN_WAHBADDR)
+			regmod->val = regs->membase;
+		else
+			return RTEMS_INVALID_NAME;
+		break;
+
+	case SATCAN_IOC_SET_REG:
+		/* Get regmod structure from argument */
+		regmod = (satcan_regmod*)ioarg->buffer;
+		DBG("SatCAN: ioctl: setting register %d, value %x\n\r", 
+		    regmod->reg, regmod->val);
+		if (regmod->reg < 0)
+			return RTEMS_INVALID_NAME;
+		else if (regmod->reg <= SATCAN_FILTER_STOP)
+			regs->satcan[regmod->reg] = regmod->val;
+		else if (regmod->reg == SATCAN_WCTRL)
+			regs->ctrl = regmod->val;
+		else if (regmod->reg == SATCAN_WIPEND)
+			regs->irqpend = regmod->val;
+		else if (regmod->reg == SATCAN_WIMASK)
+			regs->irqmask = regmod->val;
+		else if (regmod->reg == SATCAN_WAHBADDR)
+			regs->membase = regmod->val;
+		else
+			return RTEMS_INVALID_NAME;
+		break;
+
+	case SATCAN_IOC_OR_REG:
+		/* Get regmod structure from argument */
+		regmod = (satcan_regmod*)ioarg->buffer;
+		DBG("SatCAN: ioctl: or:ing register %d, with value %x\n\r",
+		    regmod->reg, regmod->val);
+		if (regmod->reg < 0)
+			return RTEMS_INVALID_NAME;
+		else if (regmod->reg <= SATCAN_FILTER_STOP)
+			regs->satcan[regmod->reg] |= regmod->val;
+		else if (regmod->reg == SATCAN_WCTRL)
+			regs->ctrl |= regmod->val;
+		else if (regmod->reg == SATCAN_WIPEND)
+			regs->irqpend |= regmod->val;
+		else if (regmod->reg == SATCAN_WIMASK)
+			regs->irqmask |= regmod->val;
+		else if (regmod->reg == SATCAN_WAHBADDR)
+			regs->membase |= regmod->val;
+		else
+			return RTEMS_INVALID_NAME;
+		break;
+
+	case SATCAN_IOC_AND_REG:
+		/* Get regmod structure from argument */
+		regmod = (satcan_regmod*)ioarg->buffer;
+		DBG("SatCAN: ioctl: masking register %d, with value %x\n\r",
+		    regmod->reg, regmod->val);
+		if (regmod->reg < 0)
+			return RTEMS_INVALID_NAME;
+		else if (regmod->reg <= SATCAN_FILTER_STOP)
+			regs->satcan[regmod->reg] &= regmod->val;
+		else if (regmod->reg == SATCAN_WCTRL)
+			regs->ctrl &= regmod->val;
+		else if (regmod->reg == SATCAN_WIPEND)
+			regs->irqpend &= regmod->val;
+		else if (regmod->reg == SATCAN_WIMASK)
+			regs->irqmask &= regmod->val;
+		else if (regmod->reg == SATCAN_WAHBADDR)
+			regs->membase &= regmod->val;
+		else
+			return RTEMS_INVALID_NAME;
+		break;
+
+	case SATCAN_IOC_EN_TX1_DIS_TX2:
+		priv->dmaen = SATCAN_DMA_ENABLE_TX1;
+		break;
+
+	case SATCAN_IOC_EN_TX2_DIS_TX1:
+		priv->dmaen = SATCAN_DMA_ENABLE_TX2;
+		break;
+
+	case SATCAN_IOC_GET_DMA_MODE:
+		value = (int*)ioarg->buffer;
+		*value = priv->dmamode;
+		break;
+		
+	case SATCAN_IOC_SET_DMA_MODE:
+		value = (int*)ioarg->buffer;
+		if (*value != SATCAN_DMA_MODE_USER && *value != SATCAN_DMA_MODE_SYSTEM) {
+			DBG("SatCAN: ioctl: invalid DMA mode\n\r");
+			return RTEMS_INVALID_NAME;
+		}
+		priv->dmamode = *value;
+		break;
+
+	case SATCAN_IOC_ACTIVATE_DMA:
+		if (priv->dmamode != SATCAN_DMA_MODE_USER) {
+			DBG("SatCAN: ioctl: ACTIVATE_DMA: not in user mode\n\r");
+			return RTEMS_INVALID_NAME;
+		}
+		value = (int*)ioarg->buffer;
+		if (*value != SATCAN_DMA_ENABLE_TX1 && *value != SATCAN_DMA_ENABLE_TX2) {
+			DBG("SatCAN: ioctl: ACTIVATE_DMA: Illegal channel\n\r");
+			return RTEMS_INVALID_NAME;
+		}
+		regs->satcan[SATCAN_DMA] |= *value << 1;
+		break;
+
+	case SATCAN_IOC_DEACTIVATE_DMA:
+		if (priv->dmamode != SATCAN_DMA_MODE_USER) {
+			DBG("SatCAN: ioctl: DEACTIVATE_DMA: not in user mode\n\r");
+			return RTEMS_INVALID_NAME;
+		}
+		value = (int*)ioarg->buffer;
+		if (*value != SATCAN_DMA_ENABLE_TX1 && *value != SATCAN_DMA_ENABLE_TX2) {
+			DBG("SatCAN: ioctl: DEACTIVATE_DMA: Illegal channel\n\r");
+			return RTEMS_INVALID_NAME;
+		}
+		regs->satcan[SATCAN_DMA] &= ~(*value << 1);
+		break;	
+
+	case SATCAN_IOC_GET_DOFFSET:
+		value = (int*)ioarg->buffer;
+		*value = priv->doff;
+		break;
+	
+	case SATCAN_IOC_SET_DOFFSET:
+		value = (int*)ioarg->buffer;
+		priv->doff = *value;
+		break;
+		
+	case SATCAN_IOC_GET_TIMEOUT:
+		timeout = (rtems_interval*)ioarg->buffer;
+		*timeout = priv->timeout;
+		break;
+
+	case SATCAN_IOC_SET_TIMEOUT:
+		timeout = (rtems_interval*)ioarg->buffer;
+		priv->timeout = *timeout;
+		break;
+
+	default:
+		return RTEMS_NOT_DEFINED;
+	}
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver satcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	int i;
+	int doff;
+	int msgindex;
+	int messages;
+	rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg;
+	satcan_msg *msgs;
+	rtems_status_code status;
+	
+	DBG("SatCAN: Writing %d bytes from %p\n\r",rw_args->count,rw_args->buffer);
+
+	if ((rw_args->count < sizeof(satcan_msg)) || (!rw_args->buffer)) {
+		DBG("SatCAN: write: returning EINVAL\n\r");
+		return RTEMS_INVALID_NAME; /* EINVAL */
+	}
+
+	messages = rw_args->count / sizeof(satcan_msg);
+	msgs = (satcan_msg*)rw_args->buffer;
+
+	/* Check that size matches any number of satcan_msg */
+	if (rw_args->count % sizeof(satcan_msg)) {
+		DBG("SatCAN: write: count can not be evenly divided with satcan_msg size\n\r");
+		return RTEMS_INVALID_NAME; /* EINVAL */
+	}
+
+
+	/* DMA channel must be set if we are in system DMA mode */
+	DBG("SatCAN: write: dma channel select is %x\n\r", priv->dmaen);
+	if (!priv->dmaen && priv->dmamode == SATCAN_DMA_MODE_SYSTEM)
+		return RTEMS_INVALID_NAME; /* EINVAL */
+
+	/* DMA must not be active */
+	if (regs->satcan[SATCAN_DMA] & (DMA_EnTx1 | DMA_EnTx2 | DMA_AutoInitDmaTx)) {
+		DBG("SatCAN: write: DMA was active\n\r");
+		rw_args->bytes_moved = 0;
+		return RTEMS_IO_ERROR; /* EIO */
+	}		
+
+	doff = regs->satcan[SATCAN_CMD1] & Sel_2k_8kN ? DMA_2K_DATA_OFFSET : DMA_8K_DATA_OFFSET;
+
+	for (msgindex = 0; msgindex < messages; msgindex++) {
+		/* Place header in DMA area */
+		for (i = 0; i < SATCAN_HEADER_SIZE; i++) {
+			priv->alptr[priv->doff+8*msgindex+i] = msgs[msgindex].header[i];
+		}
+
+		/* Place data in DMA area */
+		for (i = 0; i < SATCAN_PAYLOAD_SIZE; i++)
+			priv->alptr[priv->doff+doff+8*msgindex+i] = msgs[msgindex].payload[i];
+	}
+
+	if ((priv->dmaen & SATCAN_DMA_ENABLE_TX1) ||  priv->dmamode == SATCAN_DMA_MODE_USER) {
+		regs->satcan[SATCAN_DMA_TX_1_CUR] = 0;
+		regs->satcan[SATCAN_DMA_TX_1_END] = messages<<3; 
+	}
+
+	if ((priv->dmaen & SATCAN_DMA_ENABLE_TX2) || priv->dmamode == SATCAN_DMA_MODE_USER) {
+		regs->satcan[SATCAN_DMA_TX_2_CUR] = 0;
+		regs->satcan[SATCAN_DMA_TX_2_END] = messages<<3; 
+	}
+
+	/* If we are in DMA user mode we are done here, otherwise we block */
+	if (priv->dmamode == SATCAN_DMA_MODE_SYSTEM) {
+		priv->txactive = 1;
+
+		/* Enable DMA */
+		regs->satcan[SATCAN_DMA] |= priv->dmaen << 1;
+		
+		/* Wait for TX interrupt */
+		status = rtems_semaphore_obtain(priv->txsem, RTEMS_WAIT, priv->timeout);
+		
+		priv->txactive = 0;
+
+		/* Disable activated Tx DMA */
+		regs->satcan[SATCAN_DMA] &= ~(priv->dmaen << 1);
+
+		if (status != RTEMS_SUCCESSFUL) {
+			rw_args->bytes_moved = 0;
+			return status;
+		}
+	}
+
+	rw_args->bytes_moved = rw_args->count;
+	
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver satcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	char *buf;
+	int i;
+	int canid;
+	int messages;
+	rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t*)arg;
+	satcan_msg *ret;
+
+	/* Check that there is room for the return */
+	if (rw_args->count < sizeof(satcan_msg)) {
+		DBG("SatCAN: read: length of buffer must be at least %d, current is %d\n\r",
+		    sizeof(satcan_msg) + sizeof(int), rw_args->count);
+		return RTEMS_INVALID_NAME; /* -EINVAL */
+	}
+	
+	/* Check that size matches any number of satcan_msg */
+	if (rw_args->count % sizeof(satcan_msg)) {
+		DBG("SatCAN: read: count can not be evenly divided with satcan_msg size\n\r");
+		return RTEMS_INVALID_NAME; /* EINVAL */
+	}
+	
+	messages = rw_args->count / sizeof(satcan_msg);
+	ret = (satcan_msg*)rw_args->buffer;
+
+	DBG("SatCAN: read: reading %d messages to %p\n\r", messages, ret);
+	
+	for (i = 0; i < messages; i++) {
+		canid = (ret[i].header[1] << 8) | ret[i].header[0];
+	
+		/* Copy message header from DMA header area to buffer */
+		buf = (char*)((int)priv->alptr | (canid << 3));
+		memcpy(ret[i].header, buf, SATCAN_HEADER_SIZE);
+
+		DBG("SatCAN: read: copied header from %p to %p\n\r", buf, ret[i].header);
+
+		/* Clear New Message Marker */
+		buf[SATCAN_HEADER_NMM_POS] = 0;
+		
+		/* Copy message payload from DMA data area to buffer */
+		buf = (char*)((int)buf | 
+			      (regs->satcan[SATCAN_CMD1] & Sel_2k_8kN ? DMA_2K_DATA_SELECT : DMA_8K_DATA_SELECT));
+		memcpy(ret[i].payload, buf, SATCAN_PAYLOAD_SIZE);
+	
+		DBG("SatCAN: read: copied payload from %p to %p\n\r", buf, ret[i].payload);
+	}
+	rw_args->bytes_moved = rw_args->count;
+
+	return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver satcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	DBG("SatCAN: Closing %d\n\r",minor);
+
+	if (priv->open) {
+		regs->irqmask = 0;
+		regs->satcan[SATCAN_INT_EN] = 0;
+		regs->satcan[SATCAN_RX] = 0;
+		regs->satcan[SATCAN_DMA] = 0;
+		priv->open = 0;
+		priv->dmaen = 0;
+		priv->doff = 0;
+		priv->timeout = RTEMS_NO_TIMEOUT;
+		priv->dmamode = SATCAN_DMA_MODE_SYSTEM;
+	}
+
+	return RTEMS_SUCCESSFUL;
+}
+
+
+static rtems_device_driver satcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	DBG("SatCAN: Opening %d\n\r",minor);
+	
+	rtems_semaphore_obtain(priv->devsem,RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+	if (priv->open) {
+		rtems_semaphore_release(priv->devsem);
+		return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+	}
+	priv->open = 1;
+	rtems_semaphore_release(priv->devsem);
+
+	/* Enable AHB and CAN IRQs in wrapper and EOD1, EOD2 and CAN critical  IRQs in SatCAN core */
+	regs->irqmask = MSK_AHB | MSK_CAN;
+	regs->satcan[SATCAN_INT_EN] = ((1 << SATCAN_IRQ_EOD1) | (1 << SATCAN_IRQ_EOD2) |
+				       (1 << SATCAN_IRQ_CRITICAL));
+
+	/* Select can_int as IRQ source */
+	regs->satcan[SATCAN_CMD0] = CAN_TODn_Int_sel;
+	/* CAN RX DMA Enable */
+	regs->satcan[SATCAN_DMA] = 1;
+	/* CAN RX Enable */
+	regs->satcan[SATCAN_RX] = 1;
+
+	DBG("SatCAN: Opening %d success\n\r",minor);
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver satcan_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	struct ambapp_ahb_info d;
+	char fs_name[20];
+	rtems_status_code status;
+
+	DBG("SatCAN: Initialize..\n\r");
+
+	strcpy(fs_name, SATCAN_DEVNAME);
+
+	/* Find core and initialize register pointer */
+	if (!ambapp_find_ahbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_SATCAN, &d)) {
+		printk("SatCAN: Failed to find SatCAN core\n\r");
+		return -1;
+	}
+
+	status = rtems_io_register_name(fs_name, major, minor);
+	if (RTEMS_SUCCESSFUL != status)
+		rtems_fatal_error_occurred(status);
+
+	regs = (struct satcan_regs*)d.start[0];
+		
+	/* Set node number and DPS */
+	regs->ctrl |= ((priv->cfg->nodeno & 0xf) << 5) | (priv->cfg->dps << 1);
+
+	/* Reset core */
+	regs->ctrl |= CTRL_RST;
+
+	/* Allocate DMA area */
+	almalloc(&priv->alptr, &priv->dmaptr, ALIGN_2KMEM);
+	if (priv->dmaptr == NULL) {
+		printk("SatCAN: Failed to allocate DMA memory\n\r");
+		free(priv->cfg);
+		free(priv);
+		return -1; 
+	}
+	
+	/* Wait until core reset has completed */
+	while (regs->ctrl & CTRL_RST)
+		;
+
+	/* Initialize core registers, default is 2K messages */
+	regs->membase = (unsigned int)priv->alptr;
+	regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> 15;
+	
+	DBG("regs->membase = %x\n\r", (unsigned int)priv->alptr);
+	DBG("regs->satcan[SATCAN_RAM_BASE] = %x\n\r", (unsigned int)priv->alptr >> 15);
+
+	status = rtems_semaphore_create(
+		rtems_build_name('S', 'd', 'v', '0'),
+		1,
+		RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+		RTEMS_NO_PRIORITY_CEILING,
+		0, 
+		&priv->devsem);
+	if (status != RTEMS_SUCCESSFUL) {
+		printk("SatCAN: Failed to create dev semaphore (%d)\n\r", status);
+		free(priv->cfg);
+		free(priv);
+		return RTEMS_UNSATISFIED;
+	}
+	status = rtems_semaphore_create(
+		rtems_build_name('S', 't', 'x', '0'),
+		0, 
+		RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
+		RTEMS_NO_PRIORITY_CEILING,
+		0, 
+		&priv->txsem);
+	if (status != RTEMS_SUCCESSFUL) {
+	  printk("SatCAN: Failed to create tx semaphore (%d)\n\r", status);
+	  free(priv->cfg);
+	  free(priv);
+	  return RTEMS_UNSATISFIED;
+	}
+
+	priv->txactive = 0;
+	priv->open = 0;
+	priv->dmaen = 0;
+	priv->doff = 0;
+	priv->timeout = RTEMS_NO_TIMEOUT;
+	priv->dmamode = SATCAN_DMA_MODE_SYSTEM;
+
+	/* Register interrupt handler */
+	set_vector(satcan_interrupt_handler, d.irq+0x10, 2);
+
+	return RTEMS_SUCCESSFUL;
+}
+
+
+
+#define SATCAN_DRIVER_TABLE_ENTRY { satcan_initialize, satcan_open, satcan_close, satcan_read, satcan_write, satcan_ioctl }
+
+static rtems_driver_address_table satcan_driver = SATCAN_DRIVER_TABLE_ENTRY;
+
+int satcan_register(satcan_config *conf)
+{
+	rtems_status_code r;
+	rtems_device_major_number m;
+
+	DBG("SatCAN: satcan_register called\n\r");
+
+	/* Create private structure */
+	if ((priv = malloc(sizeof(struct satcan_priv))) == NULL) {
+		printk("SatCAN driver could not allocate memory for priv structure\n\r");
+		return -1;
+	}
+
+	DBG("SatCAN: Creating local copy of config structure\n\r");
+	if ((priv->cfg = malloc(sizeof(satcan_config))) == NULL) {
+		printk("SatCAN driver could not allocate memory for cfg structure\n\r");
+		return 1;
+	}
+	memcpy(priv->cfg, conf, sizeof(satcan_config));
+
+	if ((r = rtems_io_register_driver(0, &satcan_driver, &m)) == RTEMS_SUCCESSFUL) {
+		DBG("SatCAN driver successfully registered, major: %d\n\r", m);
+	} else {
+		switch(r) {
+		case RTEMS_TOO_MANY:
+			printk("SatCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n\r"); break;
+		case RTEMS_INVALID_NUMBER:  
+			printk("SatCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n\r"); break;
+		case RTEMS_RESOURCE_IN_USE:
+			printk("SatCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n\r"); break;
+		default:
+			printk("SatCAN rtems_io_register_driver failed\n\r");
+		}
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c b/c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c
new file mode 100644
index 0000000..22f1baa
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c
@@ -0,0 +1,265 @@
+/*  GPIOLIB interface implementation
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpiolib.h>
+
+struct gpiolib_port;
+
+struct gpiolib_port {
+	struct gpiolib_port	*next;
+	int			minor;
+	struct gpiolib_drv	*drv;
+	void			*handle;
+
+	int			open;
+};
+
+/* Root of GPIO Ports */
+struct gpiolib_port *gpiolib_ports;
+
+/* Number of GPIO ports registered */
+static int port_nr;
+
+/* 1 if libraray initialized */
+static int gpiolib_initied = 0;
+
+/* Insert a port first in ports list */
+void gpiolib_list_add(struct gpiolib_port *port)
+{
+	port->next = gpiolib_ports;
+	gpiolib_ports = port;
+}
+
+struct gpiolib_port *gpiolib_find(int minor)
+{
+	struct gpiolib_port *p;
+
+	p = gpiolib_ports;
+	while ( p && (p->minor != minor) ) {
+		p = p->next;
+	}
+	return p;
+}
+
+struct gpiolib_port *gpiolib_find_by_name(char *name)
+{
+	struct gpiolib_port *p;
+	struct gpiolib_info info;
+	int (*get_info)(void *, struct gpiolib_info *);
+
+	p = gpiolib_ports;
+	while ( p ) {
+		get_info = p->drv->ops->get_info;
+		if ( get_info && (get_info(p->handle, &info) == 0) ) {
+			if ( strncmp(name, (char *)&info.devName[0], 64) == 0 ) {
+				break;
+			}
+		}
+		p = p->next;
+	}
+	return p;
+}
+
+void gpiolib_list_remove(struct gpiolib_port *port)
+{
+	
+}
+
+int gpiolib_drv_register(struct gpiolib_drv *drv, void *handle)
+{
+	struct gpiolib_port *port;
+
+	if ( !drv || !drv->ops )
+		return -1;
+
+	port = malloc(sizeof(*port));
+	if ( port == NULL )
+		return -1;
+
+	memset(port, 0, sizeof(*port));
+	port->handle = handle;
+	port->minor = port_nr++;
+	port->drv = drv;
+
+	gpiolib_list_add(port);
+
+	return 0;
+}
+
+void gpiolib_show(int port, void *handle)
+{
+	struct gpiolib_port *p;
+
+	if ( port == -1 ) {
+		p = gpiolib_ports;
+		while (p != NULL) {
+			if ( p->drv->ops->show )
+				p->drv->ops->show(p->handle);
+			p = p->next;
+		}
+	} else {
+		if ( handle ) {
+			p = handle;
+		} else {
+			p = gpiolib_find(port);
+		}
+		if ( p == NULL ) {
+			printf("PORT %d NOT FOUND\n", port);
+			return;
+		}
+		if ( p->drv->ops->show )
+			p->drv->ops->show(p->handle);
+	}
+}
+
+void *gpiolib_open_internal(int port, char *devName)
+{
+	struct gpiolib_port *p;
+
+	if ( gpiolib_initied == 0 )
+		return NULL;
+
+	/* Find */
+	if ( port >= 0 ) {
+		p = gpiolib_find(port);
+	} else {
+		p = gpiolib_find_by_name(devName);
+	}
+	if ( p == NULL )
+		return NULL;
+
+	if ( p->open )
+		return NULL;
+
+	p->open = 1;
+	return p;
+}
+
+void *gpiolib_open(int port)
+{
+	return gpiolib_open_internal(port, NULL);
+}
+
+void *gpiolib_open_by_name(char *devName)
+{
+	return gpiolib_open_internal(-1, devName);
+}
+
+void gpiolib_close(void *handle)
+{
+	struct gpiolib_port *p = handle;
+
+	if ( p && p->open ) {
+		p->open = 0;
+	}
+}
+
+int gpiolib_set_config(void *handle, struct gpiolib_config *cfg)
+{
+	struct gpiolib_port *port = handle;
+
+	if ( !port || !cfg )
+		return -1;
+
+	if ( !port->drv->ops->config )
+		return -1;
+
+	return port->drv->ops->config(port->handle, cfg);
+}
+
+int gpiolib_set(void *handle, int dir, int outval)
+{
+	struct gpiolib_port *port = handle;
+
+	if ( !port )
+		return -1;
+
+	if ( !port->drv->ops->set )
+		return -1;
+
+	return port->drv->ops->set(port->handle, dir, outval);	
+}
+
+int gpiolib_get(void *handle, int *inval)
+{
+	struct gpiolib_port *port = handle;
+
+	if ( !port || !inval)
+		return -1;
+
+	if ( !port->drv->ops->get )
+		return -1;
+
+	return port->drv->ops->get(port->handle, inval);
+}
+
+/*** IRQ Functions ***/
+int gpiolib_irq_register(void *handle, void *func, void *arg)
+{
+	struct gpiolib_port *port = handle;
+
+	if ( !port )
+		return -1;
+
+	if ( !port->drv->ops->irq_register )
+		return -1;
+
+	return port->drv->ops->irq_register(port->handle, func, arg);
+}
+
+int gpiolib_irq_opts(void *handle, unsigned int options)
+{
+	struct gpiolib_port *port = handle;
+
+	if ( !port )
+		return -1;
+
+	if ( !port->drv->ops->irq_opts )
+		return -1;
+
+	return port->drv->ops->irq_opts(port->handle, options);
+}
+
+int gpiolib_irq_clear(void *handle)
+{
+	return gpiolib_irq_opts(handle, GPIOLIB_IRQ_CLEAR);
+}
+
+int gpiolib_irq_force(void *handle)
+{
+	return gpiolib_irq_opts(handle, GPIOLIB_IRQ_FORCE);
+}
+
+int gpiolib_irq_enable(void *handle)
+{
+	return gpiolib_irq_opts(handle, GPIOLIB_IRQ_ENABLE);
+}
+
+int gpiolib_irq_disable(void *handle)
+{
+	return gpiolib_irq_opts(handle, GPIOLIB_IRQ_DISABLE);
+}
+
+/*** Initialization ***/
+int gpiolib_initialize(void)
+{
+	if ( gpiolib_initied != 0 )
+		return 0;
+
+	/* Initialize Libarary */
+	port_nr = 0;
+	gpiolib_ports = 0;
+	gpiolib_initied = 1;
+	return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/gpio/grgpio.c b/c/src/lib/libbsp/sparc/shared/gpio/grgpio.c
new file mode 100644
index 0000000..92e9657
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/gpio/grgpio.c
@@ -0,0 +1,437 @@
+/*  GRGPIO GPIO Driver interface.
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grgpio.h>
+#include <gpiolib.h>
+#include <ambapp.h>
+#include <grlib.h>
+
+/*#define DEBUG 1*/
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#define STATIC
+#else
+#define DBG(x...) 
+#define STATIC static
+#endif
+
+struct grgpio_isr {
+	drvmgr_isr isr;
+	void *arg;
+};
+
+struct grgpio_priv {
+	struct drvmgr_dev	*dev;
+	struct grgpio_regs		*regs;
+	int				irq;
+	int				minor;
+
+	/* Driver implementation */
+	int				port_cnt;
+	unsigned char			port_handles[32];
+	struct grgpio_isr		isrs[32];
+	struct gpiolib_drv		gpiolib_desc;
+	unsigned int			bypass;
+	unsigned int			imask;
+};
+
+/******************* Driver Manager Part ***********************/
+
+int grgpio_device_init(struct grgpio_priv *priv);
+
+int grgpio_init1(struct drvmgr_dev *dev);
+int grgpio_init2(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops grgpio_ops = 
+{
+	.init = {grgpio_init1, NULL, NULL, NULL},
+	.remove = NULL,
+	.info = NULL
+};
+
+struct amba_dev_id grgpio_ids[] = 
+{
+	{VENDOR_GAISLER, GAISLER_GPIO},
+	{0, 0}		/* Mark end of table */
+};
+
+struct amba_drv_info grgpio_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,				/* Driver */
+		NULL,					/* Next driver */
+		NULL,					/* Device list */
+		DRIVER_AMBAPP_GAISLER_GRGPIO_ID,	/* Driver ID */
+		"GRGPIO_DRV",				/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,			/* Bus Type */
+		&grgpio_ops,
+		NULL,					/* Funcs */
+		0,					/* No devices yet */
+		0,
+	},
+	&grgpio_ids[0]
+};
+
+void grgpio_register_drv (void)
+{
+	DBG("Registering GRGPIO driver\n");
+	drvmgr_drv_register(&grgpio_drv_info.general);
+}
+
+/* Register GRGPIO pins as quick as possible to the GPIO library,
+ * other drivers may depend upon them in INIT LEVEL 2.
+ * Note that since IRQ may not be available in init1, it is assumed
+ * that the GPIOLibrary does not request IRQ routines until LEVEL 2.
+ */
+int grgpio_init1(struct drvmgr_dev *dev)
+{
+	struct grgpio_priv *priv;
+	int status, port;
+
+	DBG("GRGPIO[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+	/* This core will not find other cores, but other driver may depend upon 
+	 * the GPIO library to function. So, we set up GPIO right away.
+	 */
+
+	/* Initialize library if not already done */
+	status = gpiolib_initialize();
+	if ( status < 0 )
+		return DRVMGR_FAIL;
+
+	priv = dev->priv = malloc(sizeof(struct grgpio_priv));
+	if ( !priv )
+		return DRVMGR_NOMEM;
+	memset(priv, 0, sizeof(*priv));
+	priv->dev = dev;
+
+	if ( grgpio_device_init(priv) ) {
+		free(dev->priv);
+		dev->priv = NULL;
+		return DRVMGR_FAIL;
+	}
+
+	/* Register all ports available on this core as GPIO port to 
+	 * upper layer
+	 */
+	for(port=0; port<priv->port_cnt; port++) {
+		priv->port_handles[port] = port;
+		gpiolib_drv_register(&priv->gpiolib_desc,
+					&priv->port_handles[port]);
+	}
+
+	return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+/* Find port from handle, returns -1 if not found */
+int grgpio_find_port(void *handle, struct grgpio_priv **priv)
+{
+	unsigned char portnr;
+	
+	portnr = *(unsigned char *)handle;
+	if ( portnr > 31 )
+		return -1;
+	*priv = (struct grgpio_priv *)
+		(((unsigned int)handle - portnr*sizeof(unsigned char)) - 
+		offsetof(struct grgpio_priv, port_handles));
+	return portnr;
+}
+
+int grgpio_gpiolib_open(void *handle)
+{
+	struct grgpio_priv *priv;
+	int portnr;
+
+	portnr = grgpio_find_port(handle, &priv);
+	if ( portnr < 0 ) {
+		DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
+		return -1;
+	}
+	DBG("GRGPIO[0x%08x][%d]: OPENING\n", priv->regs, portnr);
+
+	/* Open the device, nothing to be done... */
+
+	return 0;
+}
+
+int grgpio_grpiolib_config(void *handle, struct gpiolib_config *cfg)
+{
+	struct grgpio_priv *priv;
+	int portnr;
+	unsigned int mask;
+
+	portnr = grgpio_find_port(handle, &priv);
+	if ( portnr < 0 ) {
+		return -1;
+	}
+	DBG("GRGPIO[0x%08x][%d]: CONFIG\n", priv->regs, portnr);
+
+	/* Configure the device. And check that operation is supported,
+	 * not all I/O Pins have IRQ support.
+	 */
+	mask = (1<<portnr);
+
+	/* Return error when IRQ not supported by this I/O Line and it
+	 * is beeing enabled by user.
+	 */
+	if ( ((mask & priv->imask) == 0) && cfg->mask )
+		return -1;
+
+	priv->regs->imask &= ~mask; /* Disable interrupt temporarily */
+
+	/* Configure settings before enabling interrupt */
+	priv->regs->ipol = (priv->regs->ipol & ~mask) | (cfg->irq_polarity ? mask : 0);
+	priv->regs->iedge = (priv->regs->iedge & ~mask) | (cfg->irq_level ? 0 : mask);
+	priv->regs->imask |= cfg->mask ? mask : 0;
+
+	return 0;
+}
+
+int grgpio_grpiolib_get(void *handle, int *inval)
+{
+	struct grgpio_priv *priv;
+	int portnr;
+
+	portnr = grgpio_find_port(handle, &priv);
+	if ( portnr < 0 ) {
+		return -1;
+	}
+	DBG("GRGPIO[0x%08x][%d]: GET\n", priv->regs, portnr);
+
+	/* Get current status of the port */
+	if ( inval )
+		*inval = (priv->regs->data >> portnr) & 0x1;
+
+	return 0;
+}
+
+int grgpio_grpiolib_irq_opts(void *handle, unsigned int options)
+{
+	struct grgpio_priv *priv;
+	int portnr;
+	drvmgr_isr isr;
+	void *arg;
+
+	portnr = grgpio_find_port(handle, &priv);
+	if ( portnr < 0 ) {
+		return -1;
+	}
+	DBG("GRGPIO[0x%08x][%d]: IRQ OPTS 0x%x\n", priv->regs, portnr, options);
+
+	if ( options & GPIOLIB_IRQ_FORCE )
+		return -1;
+
+	isr = priv->isrs[portnr].isr;
+	arg = priv->isrs[portnr].arg;
+
+	if ( options & GPIOLIB_IRQ_DISABLE ) {
+		/* Disable interrupt at interrupt controller */
+		if ( drvmgr_interrupt_unregister(priv->dev, portnr, isr, arg) ) {
+			return -1;
+		}
+	}
+	if ( options & GPIOLIB_IRQ_CLEAR ) {
+		/* Clear interrupt at interrupt controller */
+		if ( drvmgr_interrupt_clear(priv->dev, portnr) ) {
+			return -1;
+		}
+	}
+	if ( options & GPIOLIB_IRQ_ENABLE ) {
+		/* Enable interrupt at interrupt controller */
+		if ( drvmgr_interrupt_register(priv->dev, portnr, "grgpio", isr, arg) ) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int grgpio_grpiolib_irq_register(void *handle, void *func, void *arg)
+{
+	struct grgpio_priv *priv;
+	int portnr;
+
+	portnr = grgpio_find_port(handle, &priv);
+	if ( portnr < 0 ) {
+		DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
+		return -1;
+	}
+	DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
+
+	/* Since the user doesn't provide the ISR and argument, we must... */
+	priv->isrs[portnr].isr = func;
+	priv->isrs[portnr].arg = arg;
+
+	return 0;
+}
+
+int grgpio_grpiolib_set(void *handle, int dir, int outval)
+{
+	struct grgpio_priv *priv;
+	int portnr;
+	unsigned int mask;
+
+	portnr = grgpio_find_port(handle, &priv);
+	if ( portnr < 0 ) {
+		DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
+		return -1;
+	}
+	DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
+
+	/* Set Direction and Output */
+	mask = 1<<portnr;
+	priv->regs->dir = (priv->regs->dir & ~mask) | (dir ? mask : 0);
+	priv->regs->output = (priv->regs->output & ~mask) | (outval ? mask : 0);
+
+	return 0;
+}
+
+int grgpio_gpiolib_show(void *handle)
+{
+	struct grgpio_priv *priv;
+	int portnr, i, regs[7];
+	volatile unsigned int *reg;
+
+	portnr = grgpio_find_port(handle, &priv);
+	if ( portnr < 0 ) {
+		DBG("GRGPIO: FAILED SHOWING HANDLE 0x%08x\n", handle);
+		return -1;
+	}
+	for (i=0, reg=&priv->regs->data; i<7; i++, reg++) {
+		regs[i] = ( *reg >> portnr) & 1;
+	}
+	printf("GRGPIO[%p] PORT[%d]: IN/OUT/DIR: [%d,%d,%d], MASK/POL/EDGE: [%d,%d,%d], BYPASS: %d\n",
+		priv->regs, portnr, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6]);
+	return 0;
+}
+
+int grgpio_gpiolib_get_info(void *handle, struct gpiolib_info *pinfo)
+{
+	struct grgpio_priv *priv;
+	int portnr;
+	char prefix[48];
+	struct drvmgr_dev *dev;
+
+	if ( !pinfo )
+		return -1;
+
+	portnr = grgpio_find_port(handle, &priv);
+	if ( portnr < 0 ) {
+		DBG("GRGPIO: FAILED GET_INFO HANDLE 0x%08x\n", handle);
+		return -1;
+	}
+
+	/* Get Filesystem name prefix */
+	dev = priv->dev;
+	prefix[0] = '\0';
+	if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+		/* Failed to get prefix, make sure of a unique FS name
+		 * by using the driver minor.
+		 */
+		snprintf(pinfo->devName, 64, "/dev/grgpio%d/%d", dev->minor_drv, portnr);
+	} else {
+		/* Got special prefix, this means we have a bus prefix
+		 * And we should use our "bus minor"
+		 */
+		snprintf(pinfo->devName, 64, "/dev/%sgrgpio%d/%d", prefix, dev->minor_bus, portnr);
+	}
+
+	return 0;
+}
+
+static struct gpiolib_drv_ops grgpio_gpiolib_ops = 
+{
+	.config		= grgpio_grpiolib_config,
+	.get		= grgpio_grpiolib_get,
+	.irq_opts	= grgpio_grpiolib_irq_opts,
+	.irq_register	= grgpio_grpiolib_irq_register,
+	.open		= grgpio_gpiolib_open,
+	.set		= grgpio_grpiolib_set,
+	.show		= grgpio_gpiolib_show,
+	.get_info	= grgpio_gpiolib_get_info,
+};
+
+int grgpio_device_init(struct grgpio_priv *priv)
+{
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	union drvmgr_key_value *value;
+	unsigned int mask;
+	int port_cnt;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)priv->dev->businfo;
+	if ( ambadev == NULL ) {
+		return -1;
+	}
+	pnpinfo = &ambadev->info;
+	priv->irq = pnpinfo->irq;
+	priv->regs = (struct grgpio_regs *)pnpinfo->apb_slv->start;
+
+	DBG("GRGPIO: 0x%08x irq %d\n", (unsigned int)priv->regs, priv->irq);
+
+	/* Mask all Interrupts */
+	priv->regs->imask = 0;
+
+	/* Make IRQ Rising edge triggered default */
+	priv->regs->ipol = 0xfffffffe;
+	priv->regs->iedge = 0xfffffffe;
+
+	/* Read what I/O lines have IRQ support */
+	priv->imask = priv->regs->ipol;
+
+	/* Let the user configure the port count, this might be needed
+	 * when the GPIO lines must not be changed (assigned during bootup)
+	 */
+	value = drvmgr_dev_key_get(priv->dev, "nBits", KEY_TYPE_INT);
+	if ( value ) {
+		priv->port_cnt = value->i;
+	} else {
+		/* Auto detect number of GPIO ports */
+		priv->regs->dir = 0;
+		priv->regs->output = 0xffffffff;
+		mask = priv->regs->output;
+		priv->regs->output = 0;
+
+		for(port_cnt=0; port_cnt<32; port_cnt++)
+			if ( (mask & (1<<port_cnt)) == 0 )
+				break;
+		priv->port_cnt = port_cnt;
+	}
+
+	/* Let the user configure the BYPASS register, this might be needed
+	 * to select which cores can do I/O on a pin.
+	 */
+	value = drvmgr_dev_key_get(priv->dev, "bypass", KEY_TYPE_INT);
+	if ( value ) {
+		priv->bypass = value->i;
+	} else {
+		priv->bypass = 0;
+	}
+	priv->regs->bypass = priv->bypass;
+
+	/* Prepare GPIOLIB layer */
+	priv->gpiolib_desc.ops = &grgpio_gpiolib_ops;
+
+	return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/include/ahbstat.h b/c/src/lib/libbsp/sparc/shared/include/ahbstat.h
new file mode 100644
index 0000000..8f0576c
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/ahbstat.h
@@ -0,0 +1,73 @@
+/*  AHBSTAT driver interface
+ *
+ *  COPYRIGHT (c) 2011.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __AHBSTAT_H__
+#define __AHBSTAT_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* AHBSTAT Registers layout */
+struct ahbstat_regs {
+	volatile uint32_t status;
+	volatile uint32_t failing;
+};
+
+/* AHB fail interrupt callback to user. This function is declared weak so that
+ * the user can define a function pointer variable containing the address
+ * responsible for handling errors
+ *
+ * minor              Index of AHBSTAT hardware
+ * regs               Register address of AHBSTAT
+ * status             AHBSTAT status register at IRQ
+ * failing_address    AHBSTAT Failing address register at IRQ
+ *
+ * * User return 
+ *  0: print error onto terminal with printk and reenable AHBSTAT
+ *  1: just re-enable AHBSTAT
+ *  2: just print error
+ *  3: do nothing, let user do custom handling
+ */
+extern int (*ahbstat_error)(
+	int minor,
+	struct ahbstat_regs *regs,
+	uint32_t status,
+	uint32_t failing_address);
+
+/* Get Last received AHB Error
+ *
+ * \param minor    Index used to indentify a specific AHBSTAT core
+ * \param status   Status register at time of error IRQ was recevied
+ * \param address  Failing address register at time of error IRQ
+ *
+ * Return
+ *   0: No error received
+ *   1: Error Received, last status and address stored into argument pointers
+ *  -1: No such AHBSTAT device
+ */
+extern int ahbstat_last_error(int minor, uint32_t *status, uint32_t *address);
+
+/* Get AHBSTAT registers address from minor. Can also be used to check if
+ * AHBSTAT hardware is present.
+ *
+ * Return 
+ *   NULL       returned if no such device
+ *   non-zero   Address to AHBSTAT register
+ */
+extern struct ahbstat_regs *ahbstat_get_regs(int minor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/b1553rt.h b/c/src/lib/libbsp/sparc/shared/include/b1553rt.h
new file mode 100644
index 0000000..94b5afd
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/b1553rt.h
@@ -0,0 +1,74 @@
+/*  B1553RT driver interface
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Aeroflex Gaisler AB
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __B1553RT_H__
+#define __B1553RT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rt_reg {
+    volatile unsigned int stat;            /* 0x00 */
+    volatile unsigned int ctrl;            /* 0x04 */
+    volatile unsigned int vword;           /* 0x08 */
+    volatile unsigned int irq;             /* 0x0C */
+    volatile unsigned int addr;            /* 0x10 */
+		volatile unsigned int ipm;             /* 0x14 */
+};
+
+
+struct rt_msg {
+    unsigned short miw;
+    unsigned short time;
+    unsigned short data[32];
+    unsigned short desc;
+};
+
+#define RT_FREQ_12MHZ 0
+#define RT_FREQ_16MHZ 1
+#define RT_FREQ_20MHZ 2
+#define RT_FREQ_24MHZ 3
+#define RT_FREQ_MASK 0x3
+
+/* IOCTLs */
+#define RT_SET_ADDR    3
+#define RT_SET_BCE     5
+#define RT_RX_BLOCK    8
+#define RT_CLR_STATUS  12
+#define RT_GET_STATUS  13
+#define RT_SET_EVENTID 14
+
+#define RT_SET_VECTORW 32
+#define RT_SET_EXTMDATA 33
+
+#define RT_ILLCMD_IRQ  128   
+#define RT_MERR_IRQ       2048
+#define RT_DMAF_IRQ       32768                /* DMA Fail irq */
+
+#define RT_TSW_OK  (1<<14)
+#define RT_TSW_BUS (1<<13)
+#define RT_TSW_BC  (1<<12)
+#define RT_TSW_LPBKERRB  (1<<11)
+#define RT_TSW_LPBKERRA  (1<<10)
+#define RT_TSW_ILL  (1<<9)
+#define RT_TSW_MEM  (1<<8)
+#define RT_TSW_MAN  (1<<7)
+#define RT_TSW_PAR  (1<<6)
+#define RT_TSW_WC   (1<<5)
+
+void b1553rt_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RT_H__ */
+
diff --git a/c/src/lib/libbsp/sparc/shared/include/canmux.h b/c/src/lib/libbsp/sparc/shared/include/canmux.h
new file mode 100644
index 0000000..476c3b8
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/canmux.h
@@ -0,0 +1,32 @@
+/*
+ *  Header file for RTEMS CAN_MUX driver 
+ *
+ *  COPYRIGHT (c) 2008.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __CANMUX_H__
+#define __CANMUX_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Driver interface */
+int canmux_register(void);
+
+/* ioctl calls */
+#define CANMUX_IOC_BUSA_SATCAN 1
+#define CANMUX_IOC_BUSA_OCCAN1 2
+#define CANMUX_IOC_BUSB_SATCAN 3
+#define CANMUX_IOC_BUSB_OCCAN2 4
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CANMUX_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
index c8fca24..687bafd 100644
--- a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
@@ -1,7 +1,7 @@
 /*  General part of a AMBA Plug & Play bus driver.
  *
  *  COPYRIGHT (c) 2008.
- *  Cobham Gaisler AB
+ *  Cobham Gaisler AB.
  *
  *  This is the general part of the different AMBA Plug & Play
  *  drivers. The drivers are wrappers around this driver, making
@@ -28,8 +28,36 @@ extern "C" {
 	DRIVER_ID(DRVMGR_BUS_TYPE_AMBAPP, ((((vendor) & 0xff) << 16) | ((device) & 0xfff)))
 
 /*** Gaisler Hardware Device Driver IDs ***/
-#define DRIVER_AMBAPP_GAISLER_APBUART_ID       DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_APBUART)
-#define DRIVER_AMBAPP_GAISLER_GPTIMER_ID       DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GPTIMER)
+#define DRIVER_AMBAPP_GAISLER_AHBSTAT_ID	DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_AHBSTAT)
+#define DRIVER_AMBAPP_GAISLER_APBUART_ID	DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_APBUART)
+#define DRIVER_AMBAPP_GAISLER_B1553BRM_ID	DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_B1553BRM)
+#define DRIVER_AMBAPP_GAISLER_B1553RT_ID	DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_B1553RT)
+#define DRIVER_AMBAPP_GAISLER_GPTIMER_ID	DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GPTIMER)
+#define DRIVER_AMBAPP_GAISLER_GR1553B_ID	DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GR1553B)
+#define DRIVER_AMBAPP_GAISLER_GRADCDAC_ID	DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRADCDAC)
+#define DRIVER_AMBAPP_GAISLER_GRAES_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRAESDMA)
+#define DRIVER_AMBAPP_GAISLER_GRCAN_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRCAN)
+#define DRIVER_AMBAPP_GAISLER_GRCTM_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRCTM)
+#define DRIVER_AMBAPP_GAISLER_GRETH_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_ETHMAC)
+#define DRIVER_AMBAPP_GAISLER_GRGPIO_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GPIO)
+#define DRIVER_AMBAPP_GAISLER_GRPCI2_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRPCI2)
+#define DRIVER_AMBAPP_GAISLER_GRPCI_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_PCIFBRG)
+#define DRIVER_AMBAPP_GAISLER_GRPWM_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRPWM)
+#define DRIVER_AMBAPP_GAISLER_GRPWRX_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_PW2APB)
+#define DRIVER_AMBAPP_GAISLER_GRSPW_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_SPW)
+#define DRIVER_AMBAPP_GAISLER_GRTC_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRTC)
+#define DRIVER_AMBAPP_GAISLER_GRTM_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GRTM)
+#define DRIVER_AMBAPP_GAISLER_I2CMST_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_I2CMST)
+#define DRIVER_AMBAPP_GAISLER_OCCAN_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_CANAHB)
+#define DRIVER_AMBAPP_GAISLER_PCIF_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_PCIF)
+#define DRIVER_AMBAPP_GAISLER_PCITRACE_ID	DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_PCITRACE)
+#define DRIVER_AMBAPP_GAISLER_SPICTRL_ID	DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_SPICTRL)
+#define DRIVER_AMBAPP_GAISLER_SPWCUC_ID		DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_SPWCUC)
+#define DRIVER_AMBAPP_GAISLER_SPW_ROUTER_ID	DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_SPW_ROUTER)
+
+/*** ESA Hardware Device Driver IDs ***/
+#define DRIVER_AMBAPP_ESA_MCTRL_ID		DRIVER_AMBAPP_ID(VENDOR_ESA, ESA_MCTRL)
+#define DRIVER_AMBAPP_MCTRL_ID			DRIVER_AMBAPP_ESA_MCTRL_ID
 
 struct amba_dev_id {
 	unsigned short		vendor;
diff --git a/c/src/lib/libbsp/sparc/shared/include/genirq.h b/c/src/lib/libbsp/sparc/shared/include/genirq.h
new file mode 100644
index 0000000..1b83698
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/genirq.h
@@ -0,0 +1,107 @@
+/* General Shared Interrupt handling function interface 
+ *
+ * The functions does not manipulate the IRQ controller or the 
+ * interrupt level of the CPU. It simply helps the caller with
+ * managing shared interrupts where multiple interrupt routines
+ * share on interrupt vector/number.
+ *
+ * COPYRIGHT (c) 2008.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GENIRQ_H__
+#define __GENIRQ_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*genirq_handler)(void *arg);
+typedef void* genirq_t;
+
+struct genirq_stats {
+	unsigned int	irq_cnt;
+};
+
+/* Initialize the genirq interface. Must be the first function
+ * called.
+ *
+ * Returns zero on success, otherwise failure.
+ */
+extern genirq_t genirq_init(int number_of_irqs);
+
+/* Free the dynamically allocated memory that the genirq interface has 
+ * allocated.
+ *
+ * Returns zero on success, otherwise failure.
+ */
+extern void genirq_destroy(genirq_t d);
+
+/* Check IRQ number validity 
+ * 
+ * Returns zero for valid IRQ numbers, -1 of invalid IRQ numbers.
+ */
+extern int genirq_check(genirq_t d, int irq);
+
+/* Register shared interrupt handler.
+ *
+ * \param irq    The interrupt number to register ISR on
+ * \param isr    The interrupt service routine called upon IRQ
+ * \param arg    The argument given to isr() when called.
+ *
+ * Return Values
+ * -1  = Failed
+ * 0   = Handler registered Successfully, first handler on this IRQ
+ * 1   = Handler registered Successfully, _not_ first handler on this IRQ
+ */
+extern int genirq_register(genirq_t d, int irq, genirq_handler isr, void *arg);
+
+/* Unregister an previous registered interrupt handler 
+ *
+ * Return Values
+ *  -1 = ISR not registered before
+ *  0  = ISR unregistered
+ *  1  = Unable to unregister enabled ISR
+ */
+extern int genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg);
+
+/* Enables IRQ only for this isr[arg] combination. Records if this 
+ * is the first interrupt enable, only then must interrupts be enabled
+ * on the interrupt controller.
+ *
+ * IRQs must be disabled before entering this function.
+ *
+ * Return values
+ *  -1 = Failure, for example isr[arg] not registered on this irq
+ *  0  = IRQ must be enabled, it is the first IRQ handler to be enabled
+ *  1  = IRQ has already been enabled, either by isr[arg] or by another handler
+ */
+extern int genirq_enable(genirq_t d, int irq, genirq_handler isr, void *arg);
+
+/* Disables IRQ only for this isr[arg] combination. Records if this 
+ * is the only interrupt handler that is enabled on this IRQ, only then
+ * must interrupts be disabled on the interrupt controller.
+ *
+ * IRQs must be disabled before entering this function.
+ *
+ * Return values
+ *  -1 = Failure, for example isr[arg] not registered on this irq
+ *  0  = IRQ must be disabled, no ISR are enabled for this IRQ
+ *  1  = ISR has already been disabled, or other ISRs are still enabled
+ */
+extern int genirq_disable(genirq_t d, int irq, genirq_handler isr, void *arg);
+
+/* Must be called by user when an IRQ has fired, the argument 'irq' 
+ * is the IRQ number of the IRQ which was fired.
+ */
+extern void genirq_doirq(genirq_t d, int irq);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gpiolib.h b/c/src/lib/libbsp/sparc/shared/include/gpiolib.h
new file mode 100644
index 0000000..466a131
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gpiolib.h
@@ -0,0 +1,90 @@
+/*  GPIO Library interface
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GPIOLIB_H__
+#define __GPIOLIB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* GPIO Config of one GPIO port */
+struct gpiolib_config {
+	char		mask;		/* 0=Masked/1=Unmasked IRQ */
+	char		irq_level;	/* Edge or Level triggered IRQ */
+	char		irq_polarity;	/* Polarity of IRQ */
+};
+
+#define GPIOLIB_IRQ_EDGE 0
+#define GPIOLIB_IRQ_LEVEL 1
+
+#define GPIOLIB_IRQ_POL_LOW 0
+#define GPIOLIB_IRQ_POL_HIGH 1
+
+/* Libarary initialize function must be called befor any other */
+extern int gpiolib_initialize(void);
+
+/*** User Interface ***/
+
+extern void *gpiolib_open(int port);
+extern void *gpiolib_open_by_name(char *devName);
+extern void gpiolib_close(void *handle);
+
+/* Show the current status one or all GPIO ports in the system. 
+ * Int port is port nunber, if port = -1 selects all ports.
+ * 
+ * If port != -1, handle is used to get port.
+ * If port != -1, handle == NULL, then port is used as port number
+ */
+extern void gpiolib_show(int port, void *handle);
+
+extern int gpiolib_set_config(void *handle, struct gpiolib_config *cfg);
+extern int gpiolib_set(void *handle, int dir, int val);
+extern int gpiolib_get(void *handle, int *inval);
+extern int gpiolib_irq_clear(void *handle);
+extern int gpiolib_irq_enable(void *handle);
+extern int gpiolib_irq_disable(void *handle);
+extern int gpiolib_irq_force(void *handle);
+extern int gpiolib_irq_register(void *handle, void *func, void *arg);
+
+/*** Driver Interface ***/
+
+struct gpiolib_info {
+	char		devName[64];
+};
+
+struct gpiolib_drv_ops {
+	int		(*config)(void *handle, struct gpiolib_config *cfg);
+	int		(*get)(void *handle, int *val);
+	int		(*irq_opts)(void *handle, unsigned int options);
+	int		(*irq_register)(void *handle, void *func, void *arg);
+	int		(*open)(void *handle);
+	int		(*set)(void *handle, int dir, int outval);
+	int		(*show)(void *handle);
+	int		(*get_info)(void *handle, struct gpiolib_info *pinfo);
+};
+
+#define GPIOLIB_IRQ_ENABLE  0x01
+#define GPIOLIB_IRQ_DISABLE 0x02
+#define GPIOLIB_IRQ_CLEAR   0x04
+#define GPIOLIB_IRQ_FORCE   0x08
+
+struct gpiolib_drv {
+	struct gpiolib_drv_ops	*ops;
+};
+
+/* Register a GPIO port */
+extern int gpiolib_drv_register(struct gpiolib_drv *drv, void *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr1553b.h b/c/src/lib/libbsp/sparc/shared/include/gr1553b.h
new file mode 100644
index 0000000..33a79bf
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr1553b.h
@@ -0,0 +1,365 @@
+/* GR1553B driver, used by BC, RT and/or BM driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * OVERVIEW
+ * ========
+ * This driver controls the GR1553B device regardless of interfaces supported
+ * (BC, RT and/or BM). The device can be located at an on-chip AMBA or an
+ * AMBA-over-PCI bus. This driver provides an interface for the BC, RT and BM
+ * drivers to use. Since the different interfaces are accessed over the same
+ * register interface on the same core, the other drivers must share a GR1553B
+ * device. Any combination of interface functionality is supported, but the RT 
+ * and BC functionality can nnot be used simultaneously due to hardware
+ * limitation.
+ *
+ */
+
+#ifndef __GR1553B_H__
+#define __GR1553B_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The GR1553B registers */
+struct gr1553b_regs {
+	/* Common Registers */
+	volatile unsigned int irq; /* 0x00 IRQ register */
+	volatile unsigned int imask;	/* 0x04 IRQ enable mask */
+	int unused0[(0x10-0x08)/4];
+	volatile unsigned int hwcfg;	/* 0x10 HW config register */
+
+	int unused1[(0x40-0x14)/4];	/* Padding */
+
+	/* BC Registers */
+	volatile unsigned int bc_stat;	/* 0x40 BC status */
+	volatile unsigned int bc_ctrl;	/* 0x44 BC Action register */
+	volatile unsigned int bc_bd;	/* 0x48 BC transfer list pointer */
+	volatile unsigned int bc_abd;	/* 0x4c BC async list pointer */
+	volatile unsigned int bc_timer;	/* 0x50 BC timer register */
+	volatile unsigned int bc_wake;	/* 0x54 BC wakeup control register */
+	volatile unsigned int bc_irqptr;/* 0x58 BC transfer IRQ pointer */
+	volatile unsigned int bc_busmsk;/* 0x5C BC per-RT bus mask register */
+
+	int unused2[(0x68-0x60)/4];	/* Padding */
+
+	volatile unsigned int bc_slot;	/* 0x48 BC Current BD pointer */
+	volatile unsigned int bc_aslot;	/* 0x4c BC Current async BD pointer */
+
+	int unused3[(0x80-0x70)/4];	/* Padding */
+
+	/* RT Registers */
+	volatile unsigned int rt_stat;	/* 0x80 RT status */
+	volatile unsigned int rt_cfg;	/* 0x84 RT config register */
+	volatile unsigned int rt_stat2;	/* 0x88 RT bus status bits */
+	volatile unsigned int rt_statw;	/* 0x8c RT status words */
+	volatile unsigned int rt_sync;	/* 0x90 RT bus synchronize */
+	volatile unsigned int rt_tab;	/* 0x94 RT subaddress table base */
+	volatile unsigned int rt_mcctrl;/* 0x98 RT valid mode code mask */
+	int unused4[(0xa4-0x9c)/4];
+	volatile unsigned int rt_ttag;	/* 0xa4 RT time tag register */
+	int unused5;			/* 0xa8 RESERVED */
+	volatile unsigned int rt_evsz;	/* 0xac RT event log end pointer */
+	volatile unsigned int rt_evlog;	/* 0xb0 RT event log position */
+	volatile unsigned int rt_evirq;	/* 0xb4 RT event log IRQ position */
+
+	int unused6[(0xc0-0xb8)/4];	/* Padding */
+
+	/* BM Registers */
+	volatile unsigned int bm_stat;	/* 0xc0 BM status */
+	volatile unsigned int bm_ctrl;	/* 0xc4 BM control register */
+	volatile unsigned int bm_adr;	/* 0xc8 BM address filter */
+	volatile unsigned int bm_subadr;/* 0xcc BM subaddress filter */
+	volatile unsigned int bm_mc;	/* 0xd0 BM mode code filter */
+	volatile unsigned int bm_start;	/* 0xd4 BM log start address */
+	volatile unsigned int bm_end;	/* 0xd8 BM log size/alignment mask */
+	volatile unsigned int bm_pos;	/* 0xdc BM log position */
+	volatile unsigned int bm_ttag;	/* 0xe0 BM time tag register */
+};
+
+#define GR1553BC_KEY 0x15520000
+#define GR1553RT_KEY 0x15530000
+
+/* IRQ Definitions */
+#define GR1553BC_IRQLOG_SIZE 64
+#define GR1553BC_IRQLOG_CNT (GR1553BC_IRQLOG_SIZE/sizeof(uint32_t))
+
+/*** IRQ Flag Register ***/
+#define GR1553B_IRQ_BCEV_BIT	0
+#define GR1553B_IRQ_BCD_BIT	1
+#define GR1553B_IRQ_BCWK_BIT	2
+#define GR1553B_IRQ_RTEV_BIT	8
+#define GR1553B_IRQ_RTD_BIT	9
+#define GR1553B_IRQ_RTTE_BIT	10
+#define GR1553B_IRQ_BMD_BIT	16
+#define GR1553B_IRQ_BMTOF_BIT   17
+
+#define GR1553B_IRQ_BCEV	(1<<GR1553B_IRQ_BCEV_BIT)
+#define GR1553B_IRQ_BCD		(1<<GR1553B_IRQ_BCD_BIT)
+#define GR1553B_IRQ_BCWK	(1<<GR1553B_IRQ_BCWK_BIT)
+#define GR1553B_IRQ_RTEV	(1<<GR1553B_IRQ_RTEV_BIT)
+#define GR1553B_IRQ_RTD		(1<<GR1553B_IRQ_RTD_BIT)
+#define GR1553B_IRQ_RTTE	(1<<GR1553B_IRQ_RTTE_BIT)
+#define GR1553B_IRQ_BMD		(1<<GR1553B_IRQ_BMD_BIT)
+#define GR1553B_IRQ_BMTOF       (1<<GR1553B_IRQ_BMTOF_BIT)
+
+/*** IRQ Enable Register ***/
+#define GR1553B_IRQEN_BCEVE_BIT	0
+#define GR1553B_IRQEN_BCDE_BIT	1
+#define GR1553B_IRQEN_BCWKE_BIT	2
+#define GR1553B_IRQEN_RTEVE_BIT	8
+#define GR1553B_IRQEN_RTDE_BIT	9
+#define GR1553B_IRQEN_RTTEE_BIT	10
+#define GR1553B_IRQEN_BMDE_BIT	16
+#define GR1553B_IRQEN_BMTOE_BIT	17
+
+#define GR1553B_IRQEN_BCEVE	(1<<GR1553B_IRQEN_BCEVE_BIT)
+#define GR1553B_IRQEN_BCDE	(1<<GR1553B_IRQEN_BCDE_BIT)
+#define GR1553B_IRQEN_BCWKE	(1<<GR1553B_IRQEN_BCWKE_BIT)
+#define GR1553B_IRQEN_RTEVE	(1<<GR1553B_IRQEN_RTEVE_BIT)
+#define GR1553B_IRQEN_RTDE	(1<<GR1553B_IRQEN_RTDE_BIT)
+#define GR1553B_IRQEN_RTTEE	(1<<GR1553B_IRQEN_RTTEE_BIT)
+#define GR1553B_IRQEN_BMDE	(1<<GR1553B_IRQEN_BMDE_BIT)
+#define GR1553B_IRQEN_BMTOE	(1<<GR1553B_IRQEN_BMTOE_BIT)
+
+/*** BC Status Register ***/
+#define GR1553B_BC_STAT_SCST_BIT	0
+#define GR1553B_BC_STAT_SCADL_BIT	3
+#define GR1553B_BC_STAT_ASST_BIT	8
+#define GR1553B_BC_STAT_ASADL_BIT	11
+#define GR1553B_BC_STAT_BCSUP_BIT	31
+
+#define GR1553B_BC_STAT_SCST		(0x3<<GR1553B_BC_STAT_SCST_BIT)
+#define GR1553B_BC_STAT_SCADL		(0x1f<<GR1553B_BC_STAT_SCADL_BIT)
+#define GR1553B_BC_STAT_ASST		(0x3<<GR1553B_BC_STAT_ASST_BIT)
+#define GR1553B_BC_STAT_ASADL		(0x1f<<GR1553B_BC_STAT_ASADL_BIT)
+#define GR1553B_BC_STAT_BCSUP		(1<<GR1553B_BC_STAT_BCSUP_BIT)
+
+/*** BC Action Register ***/
+#define GR1553B_BC_ACT_SCSRT_BIT	0
+#define GR1553B_BC_ACT_SCSUS_BIT	1
+#define GR1553B_BC_ACT_SCSTP_BIT	2
+#define GR1553B_BC_ACT_SETT_BIT		3
+#define GR1553B_BC_ACT_CLRT_BIT		4
+#define GR1553B_BC_ACT_ASSRT_BIT	8
+#define GR1553B_BC_ACT_ASSTP_BIT	9
+#define GR1553B_BC_ACT_BCKEY_BIT	16
+
+#define GR1553B_BC_ACT_SCSRT		(1<<GR1553B_BC_ACT_SCSRT_BIT)
+#define GR1553B_BC_ACT_SCSUS		(1<<GR1553B_BC_ACT_SCSUS_BIT)
+#define GR1553B_BC_ACT_SCSTP		(1<<GR1553B_BC_ACT_SCSTP_BIT)
+#define GR1553B_BC_ACT_SETT		(1<<GR1553B_BC_ACT_SETT_BIT)
+#define GR1553B_BC_ACT_CLRT		(1<<GR1553B_BC_ACT_CLRT_BIT)
+#define GR1553B_BC_ACT_ASSRT		(1<<GR1553B_BC_ACT_ASSRT_BIT)
+#define GR1553B_BC_ACT_ASSTP		(1<<GR1553B_BC_ACT_ASSTP_BIT)
+#define GR1553B_BC_ACT_BCKEY		(0xffff<<GR1553B_BC_ACT_BCKEY_BIT)
+
+/*** BC Timer Register ***/
+#define GR1553B_BC_TIMER_SCTM_BIT	0
+
+#define GR1553B_BC_TIMER_SCTM		(0xffffff<<GR1553B_BC_TIMER_SCTM_BIT)
+
+/*** BC Wake-up control Register ***/
+#define GR1553B_BC_WAKE_TIME_BIT	0
+#define GR1553B_BC_WAKE_WKEN_BIT	31
+
+#define GR1553B_BC_WAKE_TIME		(0xffffff<<GR1553B_BC_WAKE_TIME_BIT)
+#define GR1553B_BC_WAKE_WKEN		(1<GR1553B_BC_WAKE_WKEN_BIT)
+
+/*** RT status Register ***/
+#define GR1553B_RT_STAT_RUN_BIT		0
+#define GR1553B_RT_STAT_SHDB_BIT	1
+#define GR1553B_RT_STAT_SHDA_BIT	2
+#define GR1553B_RT_STAT_ACT_BIT		3
+#define GR1553B_RT_STAT_RTSUP_BIT	31
+
+#define GR1553B_RT_STAT_RUN		(1<<GR1553B_RT_STAT_RUN_BIT)
+#define GR1553B_RT_STAT_SHDB		(1<<GR1553B_RT_STAT_SHDB_BIT)
+#define GR1553B_RT_STAT_SHDA		(1<<GR1553B_RT_STAT_SHDA_BIT)
+#define GR1553B_RT_STAT_ACT		(1<<GR1553B_RT_STAT_ACT_BIT)
+#define GR1553B_RT_STAT_RTSUP		(1<<GR1553B_RT_STAT_RTSUP_BIT)
+
+
+/*** RT Config Register ***/
+#define GR1553B_RT_CFG_RTEN_BIT		0
+#define GR1553B_RT_CFG_RTADDR_BIT	1
+#define GR1553B_RT_CFG_RTKEY_BIT	16
+
+#define GR1553B_RT_CFG_RTEN		(1<<GR1553B_RT_CFG_RTEN_BIT)
+#define GR1553B_RT_CFG_RTADDR		(1<<GR1553B_RT_CFG_RTADDR_BIT)
+#define GR1553B_RT_CFG_RTKEY		(0xffff<<GR1553B_RT_CFG_RTKEY_BIT)
+
+/*** RT Bus Status Register ***/
+#define GR1553B_RT_STAT2_RTEN_BIT	0
+#define GR1553B_RT_STAT2_DBCA_BIT	1
+#define GR1553B_RT_STAT2_SSF_BIT	2
+#define GR1553B_RT_STAT2_BUSY_BIT	3
+#define GR1553B_RT_STAT2_SREQ_BIT	4
+
+#define GR1553B_RT_STAT2_RTEN		(1<<GR1553B_RT_STAT2_RTEN_BIT)
+#define GR1553B_RT_STAT2_DBCA		(1<<GR1553B_RT_STAT2_DBCA_BIT)
+#define GR1553B_RT_STAT2_SSF		(1<<GR1553B_RT_STAT2_SSF_BIT)
+#define GR1553B_RT_STAT2_BUSY		(1<<GR1553B_RT_STAT2_BUSY_BIT)
+#define GR1553B_RT_STAT2_SREQ		(1<<GR1553B_RT_STAT2_RTEN_BIT)
+
+/*** RT Status Words Register ***/
+#define GR1553B_RT_STATW_VECW_BIT	0
+#define GR1553B_RT_STATW_BITW_BIT	16
+
+#define GR1553B_RT_STATW_VECW		(0xffff<<GR1553B_RT_STATW_VECW_BIT)
+#define GR1553B_RT_STATW_BITW		(0xffff<<GR1553B_RT_STATW_BITW_BIT)
+
+/*** RT Sync Register ***/
+#define GR1553B_RT_SYNC_SYD_BIT		0
+#define GR1553B_RT_SYNC_SYTM_BIT	16
+
+#define GR1553B_RT_SYNC_SYD		(0xffff<<GR1553B_RT_SYNC_SYD_BIT)
+#define GR1553B_RT_SYNC_SYTM		(0xffff<<GR1553B_RT_SYNC_SYTM_BIT)
+
+/*** RT Sub adress table Register ***/
+#define GR1553B_RT_TAB_SATB_BIT		0
+
+#define GR1553B_RT_TAB_SATB		(0xffff<<GR1553B_RT_TAB_SATB_BIT)
+
+/*** RT Mode code control Register ***/
+#define GR1553B_RT_MCCTRL_S_BIT		0
+#define GR1553B_RT_MCCTRL_SB_BIT	2
+#define GR1553B_RT_MCCTRL_SD_BIT	4
+#define GR1553B_RT_MCCTRL_SDB_BIT	6
+#define GR1553B_RT_MCCTRL_TS_BIT	8
+#define GR1553B_RT_MCCTRL_TSB_BIT	10
+#define GR1553B_RT_MCCTRL_TVW_BIT	12
+#define GR1553B_RT_MCCTRL_TBW_BIT	14
+#define GR1553B_RT_MCCTRL_DBC_BIT	16
+#define GR1553B_RT_MCCTRL_IST_BIT	18
+#define GR1553B_RT_MCCTRL_ISTB_BIT	20
+#define GR1553B_RT_MCCTRL_ITF_BIT	22
+#define GR1553B_RT_MCCTRL_ITFB_BIT	24
+#define GR1553B_RT_MCCTRL_RRT_BIT	26
+#define GR1553B_RT_MCCTRL_RRTB_BIT	28
+
+#define GR1553B_RT_MCCTRL_S	(1<<GR1553B_RT_MCCTRL_S_BIT)
+#define GR1553B_RT_MCCTRL_SB	(1<<GR1553B_RT_MCCTRL_SB_BIT)
+#define GR1553B_RT_MCCTRL_SD	(1<<GR1553B_RT_MCCTRL_SD_BIT)
+#define GR1553B_RT_MCCTRL_SDB	(1<<GR1553B_RT_MCCTRL_SDB_BIT)
+#define GR1553B_RT_MCCTRL_TS	(1<<GR1553B_RT_MCCTRL_TS_BIT)
+#define GR1553B_RT_MCCTRL_TSB	(1<<GR1553B_RT_MCCTRL_TSB_BIT)
+#define GR1553B_RT_MCCTRL_TVW	(1<<GR1553B_RT_MCCTRL_TVW_BIT)
+#define GR1553B_RT_MCCTRL_TBW	(1<<GR1553B_RT_MCCTRL_TBW_BIT)
+#define GR1553B_RT_MCCTRL_DBC	(1<<GR1553B_RT_MCCTRL_DBC_BIT)
+#define GR1553B_RT_MCCTRL_IST	(1<<GR1553B_RT_MCCTRL_IST_BIT)
+#define GR1553B_RT_MCCTRL_ISTB	(1<<GR1553B_RT_MCCTRL_ISTB_BIT)
+#define GR1553B_RT_MCCTRL_ITF	(1<<GR1553B_RT_MCCTRL_ITF_BIT)
+#define GR1553B_RT_MCCTRL_ITFB	(1<<GR1553B_RT_MCCTRL_ITFB_BIT)
+#define GR1553B_RT_MCCTRL_RRT	(1<<GR1553B_RT_MCCTRL_RRT_BIT)
+#define GR1553B_RT_MCCTRL_RRTB	(1<<GR1553B_RT_MCCTRL_RRTB_BIT)
+
+/*** RT Time Tag control Register ***/
+#define GR1553B_RT_TTAG_TVAL_BIT	0
+#define GR1553B_RT_TTAG_TRES_BIT	16
+
+#define GR1553B_RT_TTAG_TVAL		(0xffff<<GR1553B_RT_TTAG_TVAL_BIT)
+#define GR1553B_RT_TTAG_TRES		(0xffff<<GR1553B_RT_TTAG_TRES_BIT)
+
+/*** BM Control Register ***/
+#define GR1553B_BM_STAT_BMSUP_BIT	31
+
+#define GR1553B_BM_STAT_BMSUP		(1<<GR1553B_BM_STAT_BMSUP_BIT)
+
+/*** BM Control Register ***/
+#define GR1553B_BM_CTRL_BMEN_BIT	0
+#define GR1553B_BM_CTRL_MANL_BIT	1
+#define GR1553B_BM_CTRL_UDWL_BIT	2
+#define GR1553B_BM_CTRL_IMCL_BIT	3
+
+#define GR1553B_BM_CTRL_BMEN	(1<<GR1553B_BM_CTRL_BMEN_BIT)
+#define GR1553B_BM_CTRL_MANL	(1<<GR1553B_BM_CTRL_MANL_BIT)
+#define GR1553B_BM_CTRL_UDWL	(1<<GR1553B_BM_CTRL_UDWL_BIT)
+#define GR1553B_BM_CTRL_IMCL	(1<<GR1553B_BM_CTRL_IMCL_BIT)
+
+/*** BM RT Mode code filter Register ***/
+#define GR1553B_BM_MC_S_BIT	0
+#define GR1553B_BM_MC_SB_BIT	1
+#define GR1553B_BM_MC_SD_BIT	2
+#define GR1553B_BM_MC_SDB_BIT	3
+#define GR1553B_BM_MC_TS_BIT	4
+#define GR1553B_BM_MC_TSB_BIT	5
+#define GR1553B_BM_MC_TVW_BIT	6
+#define GR1553B_BM_MC_TBW_BIT	7
+#define GR1553B_BM_MC_DBC_BIT	8
+#define GR1553B_BM_MC_IST_BIT	9
+#define GR1553B_BM_MC_ISTB_BIT	10
+#define GR1553B_BM_MC_ITF_BIT	11
+#define GR1553B_BM_MC_ITFB_BIT	12
+#define GR1553B_BM_MC_RRT_BIT	13
+#define GR1553B_BM_MC_RRTB_BIT	14
+#define GR1553B_BM_MC_TSW_BIT	15
+#define GR1553B_BM_MC_TLC_BIT	16
+#define GR1553B_BM_MC_STS_BIT	17
+#define GR1553B_BM_MC_STSB_BIT	18
+
+#define GR1553B_BM_MC_S		(1<<GR1553B_BM_MC_S_BIT)
+#define GR1553B_BM_MC_SB	(1<<GR1553B_BM_MC_SB_BIT)
+#define GR1553B_BM_MC_SD	(1<<GR1553B_BM_MC_SD_BIT)
+#define GR1553B_BM_MC_SDB	(1<<GR1553B_BM_MC_SDB_BIT)
+#define GR1553B_BM_MC_TS	(1<<GR1553B_BM_MC_TS_BIT)
+#define GR1553B_BM_MC_TSB	(1<<GR1553B_BM_MC_TSB_BIT)
+#define GR1553B_BM_MC_TVW	(1<<GR1553B_BM_MC_TVW_BIT)
+#define GR1553B_BM_MC_TBW	(1<<GR1553B_BM_MC_TBW_BIT)
+#define GR1553B_BM_MC_DBC	(1<<GR1553B_BM_MC_DBC_BIT)
+#define GR1553B_BM_MC_IST	(1<<GR1553B_BM_MC_IST_BIT)
+#define GR1553B_BM_MC_ISTB	(1<<GR1553B_BM_MC_ISTB_BIT)
+#define GR1553B_BM_MC_ITF	(1<<GR1553B_BM_MC_ITF_BIT)
+#define GR1553B_BM_MC_ITFB	(1<<GR1553B_BM_MC_ITFB_BIT)
+#define GR1553B_BM_MC_RRT	(1<<GR1553B_BM_MC_RRT_BIT)
+#define GR1553B_BM_MC_RRTB	(1<<GR1553B_BM_MC_RRTB_BIT)
+#define GR1553B_BM_MC_TSW	(1<<GR1553B_BM_MC_TSW_BIT)
+#define GR1553B_BM_MC_TLC	(1<<GR1553B_BM_MC_TLC_BIT)
+#define GR1553B_BM_MC_STS	(1<<GR1553B_BM_MC_STS_BIT)
+#define GR1553B_BM_MC_STSB	(1<<GR1553B_BM_MC_STSB_BIT)
+
+/*** BM RT Mode code filter Register ***/
+#define GR1553B_BM_TTAG_VAL_BIT	0
+#define GR1553B_BM_TTAG_RES_BIT	24
+
+#define GR1553B_BM_TTAG_VAL		(0xffffff<<GR1553B_BM_TTAG_VAL_BIT)
+#define GR1553B_BM_TTAG_RES		(0xff<<GR1553B_BM_TTAG_RES_BIT)
+
+/* Register GR1553B driver */
+extern void gr1553_register(void);
+
+/*** BC Device allocation ***/
+/* Allocate a BC device. Minor is assigned to a device in the order
+ * they are registered to the driver.
+ */
+extern struct drvmgr_dev **gr1553_bc_open(int minor);
+/* Free a BC device previously allocated */
+extern void gr1553_bc_close(struct drvmgr_dev **dev);
+
+/*** RT Device allocation ***/
+/* Allocate a BC device. Minor is assigned to a device in the order
+ * they are registered to the driver.
+ */
+extern struct drvmgr_dev **gr1553_rt_open(int minor);
+/* Free a BC device previously allocated */
+extern void gr1553_rt_close(struct drvmgr_dev **dev);
+
+/*** BM Device allocation ***/
+/* Allocate a BC device. Minor is assigned to a device in the order
+ * they are registered to the driver.
+ */
+extern struct drvmgr_dev **gr1553_bm_open(int minor);
+/* Free a BC device previously allocated */
+extern void gr1553_bm_close(struct drvmgr_dev **dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GR1553B_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr1553bc.h b/c/src/lib/libbsp/sparc/shared/include/gr1553bc.h
new file mode 100644
index 0000000..cb71b92
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr1553bc.h
@@ -0,0 +1,250 @@
+/* GR1553B BC driver
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * OVERVIEW
+ * ========
+ * This driver controls the BC device, located at an on-chip AMBA or an
+ * AMBA-over-PCI bus. The driver operates the BC device and provides you
+ * with interrupt services and core control. The driver start execution of
+ * a synchronuos and/or an asynchronous BC descriptor List. The list contains
+ * a descriptor table and a software description to make some operations
+ * possible, for example translate descriptor-address into descriptor-number.
+ *
+ * BC descriptors are generated by the list API, available in gr1553bc_list.h.
+ *
+ * See gr1553bc_list.h for more information.
+ */
+
+#ifndef __GR1553BC_H__
+#define __GR1553BC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declaration */
+struct gr1553bc_list;
+struct gr1553bc_major;
+struct gr1553bc_minor;
+struct gr1553bc_minor_cfg;
+struct gr1553bc_major_cfg;
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <stdint.h>
+#include <gr1553bc_list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Register GR1553B driver needed by BC driver */
+extern void gr1553bc_register(void);
+
+/* A BC descriptor accessed as is */
+struct gr1553bc_bd_raw {
+	volatile uint32_t words[4];
+};
+
+/* A BC descriptor accessed as a transfer descriptor */
+struct gr1553bc_bd_tr {
+	volatile uint32_t settings[2];
+	volatile uint32_t dptr;
+	volatile uint32_t status;
+};
+
+/* A BC descriptor accessed as a conditional descriptor */
+struct gr1553bc_bd_cond {
+	volatile uint32_t cond;
+	volatile uint32_t bdptr;
+	volatile uint32_t padding[2];
+};
+
+/* A BC descriptor accessed any way */
+union gr1553bc_bd {
+	struct gr1553bc_bd_raw raw;
+	struct gr1553bc_bd_tr tr;
+	struct gr1553bc_bd_cond cond;
+};
+
+/* Current state of the BC hardware */
+struct gr1553bc_status {
+	unsigned int status;
+	unsigned int time;
+};
+
+#define KEEP_TIMESLOT 0x10
+/* Initialize a BC descriptor. The words written is controllable by
+ * the flags argument.
+ * 
+ * flags:
+ *  bit[N=0..3]: 1 = set BD wordN according to argument wordN,
+ *               0 = do not modify BD wordN
+ *
+ *  If bit KEEP_TIMESLOT is set the time slot of word0 is preserved,
+ *  this bit only have an affect when the descriptor is a transfer
+ *  descriptor.
+ */
+extern void gr1553bc_bd_init(
+	union gr1553bc_bd *bd,
+	unsigned int flags,
+	uint32_t word0,
+	uint32_t word1,
+	uint32_t word2,
+	uint32_t word3
+	);
+
+/* Initialize a Transfer descriptor
+ *
+ * Arguments:
+ *	struct gr1553bc_bd_tr *bd
+ * 	uint32_t setting0
+ *	uint32_t setting1
+ *	uint32_t data
+ *	uint32_t status
+ */
+#define gr1553bc_bd_tr_init(bd, set0, set1, data, status) \
+		gr1553bc_bd_init((union gr1553bc_bd *)bd,\
+					0xf, set0, set1, data, status)
+/* Initializa a Condition descriptor
+ *
+ * Arguments:
+ *	struct gr1553bc_bd_cond *bd
+ * 	uint32_t cond
+ *	uint32_t jump_adr
+ */
+#define gr1553bc_bd_cond_init(bd, cond, jump_adr) \
+		gr1553bc_bd_init((union gr1553bc_bd *)bd, \
+					0xf, cond, jump_adr, 0, 0)
+
+/* Size of a descriptor */
+#define GR1553BC_BD_SIZE sizeof(struct gr1553bc_bd_raw)
+
+/* Alignment of a descriptor */
+#define GR1553BC_BD_ALIGN 16
+
+/* End of list marker */
+#define GR1553BC_TR_EOL 0x80ffffff
+
+#define GR1553BC_BD_TYPE	0x80000000
+
+/* Condition descriptor bits */
+#define GR1553BC_UNCOND_JMP	0x820000ff
+#define GR1553BC_UNCOND_IRQ	0x860000ff
+#define GR1553BC_UNCOND_NOJMP	0x82000000
+
+/* Transfer descriptor bits */
+#define GR1553BC_TR_DUMMY_0	0x00000000
+#define GR1553BC_TR_DUMMY_1	0x80000000
+
+#define GR1553BC_TR_TIME	0x0000ffff
+
+#define GR1553BC_TR_EXTTRIG	0x40000000
+
+/* Take a GR1553BC hardware device identified by instance index (minor).
+ * A pointer is returned that is used internally by the GR1553BC
+ * driver, it is used as an input paramter 'bc' to all other
+ * functions that manipulate the hardware.
+ */
+extern void *gr1553bc_open(int minor);
+
+extern void gr1553bc_close(void *bc);
+
+/* Stores Current Major/Minor frame number and the Slot number executing
+ * into the location indicated by 'mid'. There may be two lists executing
+ * in "parallel", the 'async' argument select for which list the MID is 
+ * looked up, the Syncronous (async=0) list or the Asynchronous (async=1) 
+ * list.
+ *
+ */
+extern int gr1553bc_indication(void *bc, int async, int *mid);
+
+/* Trigger external time sync by writing to the BC action register.
+ * This may be good for debugging or if the time management is 
+ * implemented in software.
+ *
+ * if trig=0 the external trigger memory is cleared.
+ * if trig!=0 the external trigger memory is set.
+ */
+extern void gr1553bc_ext_trig(void *bc, int trig);
+
+/* Configure the GR1553BC driver */
+/*extern int gr1553bc_config(struct gr1553bc_config *cfg);*/
+
+/* Start major frame processing. At least one list pointer must be 
+ * non-zero to affect BC operation. The BC communication is enabled
+ * depending on list and Interrupts are enabled. This function can
+ * be called multiple times.
+ *
+ * If a list is already executing it will be replaced with the new
+ * list.
+ *
+ * list        - Schedule Transfer List
+ * list_async  - Asynchronous list
+ */
+extern int gr1553bc_start
+	(
+	void *bc,
+	struct gr1553bc_list *list,
+	struct gr1553bc_list *list_async
+	);
+
+/* Pause GR1553B BC scheduled transfers.
+ *
+ * Does not affect asynchronous operation.
+ */
+extern int gr1553bc_pause(void *bc);
+
+/* Restart GR1553B BC scheduled transfers, after being paused 
+ *
+ * Does not affect asynchronous operation.
+ */
+extern int gr1553bc_restart(void *bc);
+
+/* Stop BC transmission.
+ *
+ * OPTIONS
+ *   bit0 - 1=STOP schedule list
+ *   bit1 - 1=STOP asynchronous list
+ */
+extern int gr1553bc_stop(void *bc, int options);
+
+/* Standard IRQ function setup. IRQ can be generated by condition descriptors
+ * or by transfer descriptors or by errors.
+ *
+ * Condition descriptors are inserted into the list by user, each condition
+ * may have a custom function and data assigned to it, see 
+ * gr1553bc_slot_irq_prepare(). IRQs generated by condition descriptors are
+ * not handled by this function.
+ *
+ * Transfer descriptors can generate IRQ if enabled by user.
+ *
+ * IRQs generated by transfer descriptors or by BC errors (DMA error etc.)
+ * is handled by this standard ISR handler.
+ */
+extern int gr1553bc_irq_setup
+	(
+	void *bc,
+	bcirq_func_t func,
+	void *data
+	);
+
+/* Get Current BC hardware state/status. The Status is stored into the
+ * area pointed to by status. See "struct gr1553bc_status" for more
+ * info.
+ */
+extern void gr1553bc_status(void *bc, struct gr1553bc_status *status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GR1553BC_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr1553bc_list.h b/c/src/lib/libbsp/sparc/shared/include/gr1553bc_list.h
new file mode 100644
index 0000000..24f5281
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr1553bc_list.h
@@ -0,0 +1,707 @@
+/*
+ *  GR1553B BC driver, Descriptor LIST handling
+ *
+ *  COPYRIGHT (c) 2010.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GR1553BC_LIST_H__
+#define __GR1553BC_LIST_H__
+
+/*!\file doc/gr1553bc_list.h
+ * \brief GR1553B BC driver
+ *
+ * \section OVERVIEW
+ *
+ * The BC device driver can schedule synchronous and asynchronous lists
+ * of descriptors. The list contains a descriptor table and a software
+ * description to make some operations possible, for example translate
+ * descriptor-address into descriptor-number.
+ *
+ * This is the LIST API. It provides functionality to create and manage
+ * a BC descriptor list.
+ *
+ * A list is built up by the following build blocks:
+ *  - Major Frame (Consists of N Minor Frames)
+ *  - Minor Frame (Consists of up to 32 1553 Message Slots)
+ *  - Message Slot (Transfer/Condition BC descriptor)
+ *
+ * The user can configure lists with different configuration of number of
+ * Major Frames, Minor Frame and messages slots within a Minor Frame. The
+ * List manages a strait descriptor table (may be changed) and a Frame/Slot
+ * tree in order to easily find it's way through all descriptor created.
+ *
+ * Each Minor frame consist of up to 32 message slot and 2 message slots
+ * for time management and descriptor find operations. The list can manage
+ * time slots per minor frame, for example a minor frame may be programmed
+ * to take 8ms and when the user allocate a message slot within that Minor
+ * frame the time spcified will be subtracted from the 8ms, and when the
+ * message slot is freed the time will be returned to the Minor frame again.
+ *
+ * A Major, Minor and Message Slots are identified using a MID (Message-ID).
+ * The MID is a way for the user to avoid using pointers are talk with the
+ * list API in an easier way. For example a condition Slot that should jump
+ * to a transfer slot can be created by knowing "MID and Jump-To-MID". When
+ * allocating a Slot (with or without time) the user may specify a certain
+ * Slot or a Minor frame, when a Minor frame is given then the API will find
+ * a free Slot as early in the Minor Frame as possible and return it to the
+ * user.
+ *
+ * A MID can be created using the macros:
+ *   GR1553BC_ID(major,minor,slot)      - ID of a SLOT
+ *   GR1553BC_MINOR_ID(major,minor)     - ID of a MINOR (Slot=0xff)
+ *   GR1553BC_MAJOR_ID(major)           - ID of a Major (Minor=0xff,Slot=0xff)
+ *
+ * The typical approach create lists is in the following order:
+ *   -# gr1553bc_list_alloc(&list, MAJOR_CNT)
+ *   -# gr1553bc_list_config(list, &listcfg)
+ *   -# Create all Major Frames and Minor frame, for each major frame:
+ *       a) gr1553bc_major_alloc_skel(&major, &major_minor_cfg)
+ *       b) gr1553bc_list_set_major(list, &major, MAJOR_NUM)
+ *   -# link end Major Frames together:
+ *       a) gr1553bc_list_set_major(&major7, &major0)   // Connect Major frames
+ *   -# gr1553bc_list_table_alloc()   (Allocate Descriptor Table)
+ *   -# gr1553bc_list_table_build()   (Build Descriptor Table from Majors/Minors)
+ *   -# Allocate and initialize Descriptors pre defined before starting:
+ *      -## gr1553bc_slot_alloc(list, &MID, TIME_REQUIRED, ..)
+ *      -## gr1553bc_slot_transfer(MID, ...)
+ *   -# START BC HARDWARE BY SHCDULING ABOVE LIST
+ *   -# Operate on List
+ *
+ *
+ * \section bc_list_update Changing a scheduled BC list (during BC-runtime)
+ *
+ *  One can use the INDICATION service to avoid modifying
+ *  a descriptor currently in use by the BC core. One can also in most cases
+ *  do descriptor initialization in three steps: Init Descriptor as Dummy 
+ *  with and allocated time (often done before starting/scheduling list),
+ *  then modify transfer options and data-pointers, then clear the Dummy
+ *  bit in one atomic data store. This approach will avoid potential races
+ *  between software has hardware.
+ *
+ *
+ * \section bc_memory_setup Custom Memory Setup
+ *
+ *  For designs where dynamically memory is not an option, or the driver
+ *  is used on a AMBA-over-PCI bus (where malloc() does not work), the
+ *  API allows the user to provide custom addresses for descriptor table
+ *  and object descriptions (lists, major frames, minor frames). Custom
+ *  descriptor table is probably the most interesting thing for most, it
+ *  is setup with gr1553bc_list_table_alloc(list, CUSTOM_ADDRESS).
+ *
+ *  Object descriptions are normally allocated during initialization
+ *  procedure by providing the API with a object configuration, for 
+ *  example a Major Frame configuration enables the API to allocate
+ *  the software description of a Major Frame with all it's Minor frames.
+ *
+ *
+ * \section major Major Frame
+ *
+ *  Consists of multiple Minor frames. A Major frame may be connected/linked
+ *  with another Major frame, this will result in a Jump Slot from last
+ *  Minor frame in the first Major to the first Minor in the second Major.
+ *
+ *
+ * \section minor Minor Frame
+ *
+ *  Consists of up to 32 Message Slots. The services are Time-Management and
+ *  Slot allocation.
+ *
+ *  Time-Management is optional.
+ *
+ *  Time-Slot-Management can be enabled per Minor frame. A Minor frame can be
+ *  assigned a time in microseconds. The BC will not continue to the next
+ *  Minor frame until the time has passed. It is managed by adding an extra
+ *  Dummy Message Slot with the total minor frame time. Each time a message
+ *  Slot is allocated (with a certain time: Slot-Time) the Slot-Time will
+ *  be decremented from the total time of the Minor frame. This way the
+ *  sum of the Message Slot will always sum up to the total time of the
+ *  Minor configuration. When a message slot is freed, the Dymmy Message
+ *  Slot's Slot-Time is incremented with the freed Slot-Time.
+ *
+ *  A Message Slot can be allocated by identifying a specific free Slot
+ *  by the MID (Message-ID) or by letting the API allocate the first free
+ *  Slot in the Minor Frame (Set MID Slot-ID to 0xff to identify Minor
+ *  Frame).
+ *
+ *
+ * \section slot Message Slot
+ *
+ *  The GR1553B BC core supports two Slot (Descriptor) Types:
+ *   - Transfer descriptor
+ *   - Condition descriptor (Jump, unconditional-IRQ)
+ *
+ *  See the hardware manual for a detail description of a descriptor (Slot).
+ *
+ *  The BC Core is unaware of lists, it steps through executing each 
+ *  descriptor as the encountered, Conditionals resulting in jumps may
+ *  let us to create more complex arrangements of buffer descriptos (BDs)
+ *  which we call list.
+ *
+ *  Transfer BDs (TBDs) may have a time slot assigned, the BC core will wait
+ *  until the time has expired before executing the next descriptor. Time
+ *  slots are handled by a Minor frame in the list.
+ *
+ *  A Message Slot is allocated using the gr1553bc_slot_alloc() function,
+ *  and configured by calling one of the below functions:
+ *   - gr1553bc_slot_irq_prepare   [unconditional IRQ slot]
+ *   - gr1553bc_slot_jump          [unconditional jump]
+ *   - gr1553bc_slot_exttrig       [Dummy transfer, wait for EXTERNAL-TRIGGER]
+ *   - gr1553bc_slot_transfer      [Transfer descriptor]
+ *   - gr1553bc_slot_empty         [Create Dummy Transfer descriptor]
+ *   - gr1553bc_slot_raw           [Custom Descriptor handling]
+ *
+ *   - gr1553bc_slot_dummy         [Set existing Transfer descriptor to Dummy]
+ *   - gr1553bc_slot_update        [Update DataPointer|Status of a TBD]
+ *
+ *
+ * \section bc_IRQ Interrupt Handling
+ *
+ * There are different types of interrupts, Error IRQs or transfer IRQs. The
+ * Error IRQs are handled by the driver can a callback function is called. 
+ *
+ * Transfer Descriptors can be programmed to generate interrupt, and
+ * condition descriptors can be programmed to generate interrupt
+ * unconditionaly (there exists more conditional types). When a Transfer
+ * descriptor causes IRQ the general ISR callback of the BC driver is 
+ * called to let the user handle the interrupt. When a condition descriptor
+ * causes an IRQ a custom IRQ handler is called (if assigned).
+ *
+ * Transfers descriptor IRQ is enabled by configuring the descriptor.
+ *
+ * The API provides functions for placing unconditional IRQ points anywhere
+ * in the list. The order:
+ *   -# gr1553bc_slot_alloc(&MID, TIME=0, ..)
+ *   -# gr1553bc_slot_irq_prepare(MID, funcISR, data)
+ *   -# gr1553bc_slot_irq_enable(MID)
+ * 
+ * \verbatim
+ *  void funcISR(*bd, *data)
+ *  {
+ *    // HANDLE ONE OR MULTIPLE DESCRIPTORS (MULTIPLE IN THIS EXAMPLE):
+ *    int MID;
+ *    gr1553bc_mid_from_bd(bd,&MID,NULL);
+ *    printf("IRQ ON %06x\n", MID);
+ *  }
+ * \endverbatim
+ *
+ * \ingroup GR1553BC
+ */
+
+#include <stdint.h>
+#include <gr1553bc.h>
+
+/**** CONFIGURATION OPTIONS ****/
+
+/* Define GR1553BC_TIMESLOT to make driver take care of time
+ * management of minor frames.
+ */
+#define GR1553BC_TIMESLOT
+
+#define GR1553BC_MINOR_MAX 256
+#define GR1553BC_SLOT_MAX 32
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct gr1553bc_list;
+struct gr1553bc_major;
+struct gr1553bc_minor;
+struct gr1553bc_minor_cfg;
+struct gr1553bc_major_cfg;
+
+struct gr1553bc_minor_cfg {
+	int slot_cnt;
+	int timeslot;		/* Total time of minor frame in us */
+};
+
+struct gr1553bc_major_cfg {
+	int minor_cnt;				/* Number of Minor Frames */
+	struct gr1553bc_minor_cfg minor_cfgs[1];
+};
+
+struct gr1553bc_list_cfg {
+	unsigned char rt_timeout[31];	/* Number of us timeout tolerance per RT */
+	unsigned char bc_timeout;	/* Number of us timeout tolerance of 
+					 * broadcast transfers */
+	int tropt_irq_on_err;		/* Generate IRQ on transfer error */
+	int tropt_pause_on_err;		/* Pause list on transfer error */
+	int async_list;			/* Set to non-zero if asyncronous list*/
+};
+
+/* Default Configuration */
+extern struct gr1553bc_list_cfg gr1553bc_def_cfg;
+
+/* Complete list of all major frames */
+struct gr1553bc_list {
+	void *_table_custom;		/* Config option given by user */
+	void *_table;			/* address of allocated bd-table */
+	unsigned int table_hw;		/* Descriptor table base HW-ADR */
+	unsigned int table_cpu;		/* Descriptor table base CPU-ADR */
+	int table_size;			/* Descriptor Table Size */
+	void *bc;			/* BC HW, needed for adr translation */
+	unsigned char rt_timeout[32];	/* Tolerance per RT, default 20us
+					 * Note: 31 is for Broadcast */
+	uint32_t tropts;		/* Transfer descriptor options:
+					 *  On transfer error the following bits
+					 *  do affect:
+					 *  - bit28 1=Generate IRQ
+					 *  - bit26 1=Pause transfer list
+					 *  
+					 */
+	int async_list;			/* async list or not */
+	int major_cnt;			/* Number of Major frames */
+	struct gr1553bc_major *majors[1];	/* Var-Array of Major Pointers*/
+};
+
+/* Alloc a List with a maximum number of Major frames supported */
+extern int gr1553bc_list_alloc(struct gr1553bc_list **list, int max_major);
+
+/* Free List if allocated with gr1553bc_list_alloc() */
+extern void gr1553bc_list_free(struct gr1553bc_list *list);
+
+/* Configure Global List parameters 
+ *
+ * \param list    List to be configured and initialized.
+ * \param cfg     List Configuration
+ * \param bc      The BC hardware device description
+ *                  (only needed for address translation)
+ */
+extern int gr1553bc_list_config
+	(
+	struct gr1553bc_list *list,
+	struct gr1553bc_list_cfg *cfg,
+	void *bc
+	);
+
+/* Link a 'major' Major frame with next major frame 
+ * The links affected:
+ *   - major->next
+ *   - major->minor[LAST]->next
+ */
+extern void gr1553bc_list_link_major(
+	struct gr1553bc_major *major,
+	struct gr1553bc_major *next
+	);
+
+/* Link in a Major frame into a BC list.
+ * Calls gr1553bc_list_link_major() to link major frame with major-1 and
+ * major+1. If ending or starting major frame the frame is wrapped around.
+ */
+extern int gr1553bc_list_set_major(
+	struct gr1553bc_list *list,
+	struct gr1553bc_major *major,
+	int no);
+
+/* Calculate the size required in the descriptor table by one minor frame. */
+extern int gr1553bc_minor_table_size(struct gr1553bc_minor *minor);
+
+/* Calculate the size required for the descriptor table.
+ */
+extern int gr1553bc_list_table_size(struct gr1553bc_list *list);
+
+/* Allocate an empty descriptor table from list description suitable for
+ * the BC given by 'bc'.
+ *
+ * \param bdtab_custom   Custom Descriptor Allocation options:
+ *                         ZERO: Dynamically allocated by Driver (CPU near RAM)
+ *                         Non-Zero: Use provided address as BASE of BD-TABLE
+ *                         Non-Zero with LSB set: Same as Non-Zero but address
+ *                          is given as HW address (used with AMBA-over-PCI to
+ *                          to specify RAM location on PCI board).
+ */
+extern int gr1553bc_list_table_alloc
+	(
+	struct gr1553bc_list *list,
+	void *bdtab_custom
+	);
+
+/* Free descriptor table allocated with gr1553bc_list_table_alloc() */
+extern void gr1553bc_list_table_free(struct gr1553bc_list *list);
+
+/* Build an empty descriptor table from list description, 
+ * the minor frames will be linked together.
+ */
+extern int gr1553bc_list_table_build(struct gr1553bc_list *list);
+
+/* Major Frame */
+struct gr1553bc_major {
+	struct gr1553bc_major *next;		/* Next Major Frame */
+	struct gr1553bc_major_cfg *cfg;		/* User Config of Major frame */
+	struct gr1553bc_minor *minors[1];	/* Minor frames */
+};
+
+/* Minor Frame */
+struct gr1553bc_minor {
+	struct gr1553bc_minor *next;	/* Next Minor Frame */
+	struct gr1553bc_minor_cfg *cfg;	/* User Config of Minor frame */
+	uint32_t alloc;			/* Descripts allocated */
+
+	/* Note: THIS POINTER MUST BE ALIGNED ON A 128-bit BOUNDARY */
+	union gr1553bc_bd *bds;	/* Descriptors for this minor frame (CPU ADRS)*/
+};
+
+/* Alloc a Major/Minor frame skeleton according to the configuration structure. 
+ * The descriptor table is not allocated.
+ */
+extern int gr1553bc_major_alloc_skel
+	(
+	struct gr1553bc_major **major,
+	struct gr1553bc_major_cfg *cfg
+	);
+
+/* Unique Message/Descriptor ID. Can be used to identify a Major or Minor 
+ * Frame, or a Slot.
+ *
+ * - If minor_num is 0xff, the ID identifies a Major Frame
+ * - If slot_num is 0xff, the ID identifies a Minor Frame
+ * - If non of the above is true, the ID identifies a specific Slot
+ */
+#define GR1553BC_ID(major_num, minor_num, slot_num) \
+		((((major_num)<<16)&0xff0000) | (((minor_num)<<8)&0xff00) | \
+		((slot_num) & 0xff))
+#define GR1553BC_MINOR_ID(major_num, minor_num) \
+		GR1553BC_ID(major_num, minor_num, 0xff)
+#define GR1553BC_MAJOR_ID(major_num) \
+		GR1553BC_ID(major_num, 0xff, 0xff)
+
+#define GR1553BC_MAJID_FROM_ID(mid) (((mid) >> 16) & 0xff)
+#define GR1553BC_MINID_FROM_ID(mid) (((mid) >> 8) & 0xff)
+#define GR1553BC_SLOTID_FROM_ID(mid) ((mid) & 0xff)
+#define GR1553BC_ID_SET_SLOT(mid, slot_num) (((mid) & ~0xff) | ((slot_num) & 0xff))
+
+extern struct gr1553bc_major *gr1553bc_major_from_id
+	(
+	struct gr1553bc_list *list,
+	int mid
+	);
+
+extern struct gr1553bc_minor *gr1553bc_minor_from_id
+	(
+	struct gr1553bc_list *list,
+	int mid
+	);
+
+/* Get free time left of minor frame identified by MID 'mid' */
+extern int gr1553bc_list_freetime(struct gr1553bc_list *list, int mid);
+
+/* Get free time left of minor frame */
+extern int gr1553bc_minor_freetime(struct gr1553bc_minor *minor);
+
+/* Allocate a time slot on a minor frame, major/minor frame is identified 
+ * by MID. The 'mid' is a input/ouput parameter, the resulting slot taken
+ * will be placed in 'mid', a pointer to the allocated descriptor is stored
+ * into bd.
+ *
+ * Major/Minor must be specified by MID, if slot is specified that slot will
+ * be allocated, if slot is 0xff, then the first free slot is allocated.
+ *
+ * The function fails (return negative) if timeslot is longer than remaining
+ * time in minor frame, if no more slots are available in minor frame, if 
+ * MID points to a bad major/minor or major/minor/slot.
+ */
+extern int gr1553bc_slot_alloc(
+	struct gr1553bc_list *list,
+	int *mid,
+	int timeslot,
+	union gr1553bc_bd **bd
+	);
+/* Same as gr1553bc_slot_alloc but identifies a minor instead of list.
+ * The major/minor part of MID is ignored.
+ */
+extern int gr1553bc_slot_alloc2(
+	struct gr1553bc_minor *minor,
+	int *mid,
+	int timeslot,
+	union gr1553bc_bd **bd
+	);
+
+/* Free message slot and the time associated with it. The time taken by the
+ * message slot is added to the END TIME descriptor, if managed by the driver
+ * for this minor frame. The descriptor will be 
+ */
+extern int gr1553bc_slot_free(struct gr1553bc_list *list, int mid);
+extern int gr1553bc_slot_free2(struct gr1553bc_minor *minor, int mid);
+
+/* Find MID from Descriptor pointer
+ *
+ * In the end of each minor frame is a unconditional jump 
+ * to next minor frame descriptor. The hardware does not
+ * use the last 8 bytes of conditional descriptors, in the
+ * padding area a MID is stored so that we can lookup the
+ * MID of a descriptor. This function finds the jump
+ * descriptor and subtracs the offset from it.
+ *
+ * A faster way of looking up can be implemented if the
+ * list is symertical, however in the current setup we
+ * allow different numbers of slots in minor frames, and
+ * different number of minor frames in a major frame.
+ *
+ * \param bd     IN: Descriptor to lookup MID of (CPU address of BD)
+ * \param mid    OUT: Pointer to where Message-ID (Slot-ID) will be stored
+ * \param async  OUT: Function will store non-zero value if BD belogs to 
+ *                    async list.
+ */
+extern int gr1553bc_mid_from_bd(
+	union gr1553bc_bd *bd,
+	int *mid,
+	int *async
+	);
+
+/********** TRANSFER DESCRIPTOR MANIPULATION **********/
+
+/* Get pointer to descriptor entry from MID. */
+extern union gr1553bc_bd *gr1553bc_slot_bd
+	(
+	struct gr1553bc_list *list,
+	int mid
+	);
+
+/* IRQ function */
+typedef void (*bcirq_func_t)(union gr1553bc_bd *bd, void *data);
+
+/* Create unconditional IRQ customly defined location.
+ * The IRQ is disabled, enable it with gr1553bc_slot_irq_enable().
+ */
+extern int gr1553bc_slot_irq_prepare
+	(
+	struct gr1553bc_list *list,
+	int mid,
+	bcirq_func_t func,
+	void *data
+	);
+
+/* Enable previously prepared unconditional IRQ */
+extern int gr1553bc_slot_irq_enable(struct gr1553bc_list *list, int mid);
+
+/* Disable unconditional IRQ point, changed to unconditional JUMP
+ * to descriptor following.
+ * After disabling it it can be enabled again, or freed.
+ */
+extern int gr1553bc_slot_irq_disable(struct gr1553bc_list *list, int mid);
+
+/* Create custom jump to descriptor, conditional or unconditional, see 
+ * hardware manual for conditions.
+ *
+ * set conditional to GR1553BC_UNCOND_JMP for unconditional jump.
+ */
+extern int gr1553bc_slot_jump
+	(
+	struct gr1553bc_list *list,
+	int mid,
+	uint32_t condition,
+	int to_mid
+	);
+
+/* Create a dummy transfer, paused until external trigger is set. The
+ * Slot is will have the dummy bit set, no transfer will take place.
+ */
+extern int gr1553bc_slot_exttrig(struct gr1553bc_list *list, int mid);
+
+/* Create a transfer on a previous allocated descriptor. It is assumed
+ * that the descriptor has been initialized empty before calling this
+ * function, this is to avoid races.
+ *
+ * The settings that are controlled on a global level (and not
+ * by this function):
+ *  - IRQ after transfer error
+ *  - IRQ after transfer (not supported, insert separate IRQ slot after this)
+ *  - Pause schedule after transfer error
+ *  - Pause schedule after transfer (not supported)
+ *  - slot time optional (set when MID allocated), otherwise 0
+ *  - (OPTIONAL) Dummy Bit, set using slot_empty() or ..._TT_DUMMY
+ *  - RT timeout tolerance (managed per RT)
+ *
+ *  Input Parameters:
+ *  - Retry Mode			(options)
+ *  - Number of retires			(options)
+ *  - Bus selection (A or B)		(options)
+ *  - dummy bit				(options)
+ *  - transfer type			(tt)
+ *  - rt src/dst address		(tt)
+ *  - RT subaddress			(tt)
+ *  - word count			(tt)
+ *  - mode code				(tt)
+ *  - data pointer			(dptr)
+ *
+ *
+ * See macros defined in this header file for creating transfer types (tt)
+ * and word count etc.
+ *
+ * See macros defined in this header file for creating the mask of options.
+ *
+ * Note that if bit0 (LSB) of dptr is set, then the address is translated into
+ * hardware address, otherwise the dptr is assumed to be accessible from the
+ * 1553 core. This is an option only for AMBA-over-PCI.
+ */
+extern int gr1553bc_slot_transfer(
+	struct gr1553bc_list *list,
+	int mid,
+	int options,
+	int tt,
+	uint16_t *dptr);
+
+/* Remove or set dummy bit of a transfer descriptor
+ * Bit31 of *dummy is written to the dummy bit, the 
+ * old descriptor value is stored into *dummy.
+ */
+extern int gr1553bc_slot_dummy(
+	struct gr1553bc_list *list,
+	int mid,
+	unsigned int *dummy);
+
+/* Make a slot empty (BC will not generate bus transfers), time slot 
+ * allocated is untouched (if assigned).
+ */
+extern int gr1553bc_slot_empty(struct gr1553bc_list *list, int mid);
+
+/* Transfer descriptor status and/or update Transfer descriptor data pointer.
+ *
+ * Read and/or write Status of a slot. Writing the status word may be
+ * used by software to indicate that result has been handled, or bit 31
+ * may be written 1 telling software that when it reaches 0, then BC
+ * has executed the request.
+ *
+ * Operation:
+ *  bd->status = *stat & (bd->status 0xffffff) | (*stat & 0x80000000);
+ *  *stat = Value of bd->status before rewrite.
+ *
+ * Note that the status word is not written when *stat is zero.
+ *
+ * Note that if bit0 (LSB) of dptr is set, then the address is translated into
+ * hardware address, otherwise the dptr is assumed to be accessible from the
+ * 1553 core. This is an option only for AMBA-over-PCI.
+ */
+extern int gr1553bc_slot_update(
+	struct gr1553bc_list *list,
+	int mid,
+	uint16_t *dptr,
+	unsigned int *stat);
+
+/* Modify a transfer descriptor in any way,
+ * 
+ * flags:
+ *  bit[N=0..3]: 1 = set BD wordN according to argument wordN,
+ *               0 = do not modify BD wordN
+ */
+extern int gr1553bc_slot_raw
+	(
+	struct gr1553bc_list *list,
+	int mid,
+	unsigned int flags,
+	uint32_t word0,
+	uint32_t word1,
+	uint32_t word2,
+	uint32_t word3
+	);
+
+
+/***** Macros to create BC Transfer Types (tt) for gr1553bc_slot_transfer() *****/
+
+/* WRITE TO RT (BC-to-RT) */
+#define GR1553BC_BC2RT(rtadr, subadr, word_count) \
+		((rtadr<<11) | (subadr<<5) | (0x1f<<21) | (0<<10) | \
+		((word_count>=32) ? 0 : word_count))
+
+/* READ FROM RT (RT-to-BC) */
+#define GR1553BC_RT2BC(rtadr, subadr, word_count) \
+		((rtadr<<11) | (subadr<<5) | (0x1f<<21) | (1<<10) | \
+		((word_count>=32) ? 0 : word_count))
+
+/* RT(TX) WRITE TO RT(RX) (RT-to-RT) */
+#define GR1553BC_RT2RT(tx_rtadr, tx_subadr, rx_rtadr, rx_subadr, word_count) \
+		((rx_rtadr<<11) | (rx_subadr<<5) | \
+		(tx_rtadr<<21) | (tx_subadr<<16) | \
+		(0<<10) | \
+		((word_count>=32) ? 0 : word_count))
+
+/* Mode command without data. (BC-to-RT)
+ * Mode code: 0,1,2,3,4,5,6,7 or 8.
+ */
+#define GR1553BC_MC_NODATA(rtadr, modecode) \
+		((rtadr<<11) | (0x1f<<5) | (0x1f<<21) | \
+		(modecode<<0) | (1<<10))
+
+/* Mode command with 4 byte data (RT-to-BC)
+ * Mode code: 16, 18 or 19.
+ */
+#define GR1553BC_MC_RT2BC(rtadr, modecode) \
+		((rtadr<<11) | (0x1f<<5) | (0x1f<<21) | \
+		(modecode<<0) | (1<<10))
+
+/* Mode command with 4 byte data (BC-to-RT)
+ * Mode code: 17, 20 or 21.
+ */
+#define GR1553BC_MC_BC2RT(rtadr, modecode) \
+		((rtadr<<11) | (0x1f<<5) | (0x1f<<21) | \
+		(modecode<<0) | (0<<10))
+
+/* Broadcast to all RTs, to a specific subaddress (BC-to-RTs) */
+#define GR1553BC_BC_BC2RT(subadr, word_count) \
+		((0x1f<<11) | (subadr<<5) | (0x1f<<21) | \
+		(0<<10) | \
+		((word_count>=32) ? 0 : word_count))
+
+/* Request RT to broadcast to all RTs, to a specific subaddress (RT-to-RTs) */
+#define GR1553BC_BC_RT2RT(tx_rtadr, tx_subadr, rx_subadr, word_count) \
+		((0x1f<<11) | (rx_subadr<<5) | \
+		(tx_rtadr<<21) | (tx_subadr<<16) | \
+		(0<<10) | \
+		((word_count>=32) ? 0 : word_count))
+
+/* Broadcast mode command without data (BC-to-RTs) 
+ * Mode code: 1,3,4,5,6,7 or 8
+ */
+#define GR1553BC_BC_MC_NODATA(modecode) \
+		((0x1f<<11) | (0x1f<<5) | (0x1f<<21) | \
+		((modecode)<<0) | (1<<10))
+
+/* Broadcast mode command with 4 byte data (BC-to-RTs)
+ * Mode code: 17, 20 or 21
+ */
+#define GR1553BC_BC_MC_BC2RT(modecode) \
+		((0x1f<<11) | (0x1f<<5) | (0x1f<<21) | \
+		((modecode)<<0) | (0<<10))
+
+
+/***** Macros to create BC options (options) for gr1553bc_slot_transfer() *****/
+
+/* Dummy (BC does no bus trasactions) */
+#define GR1553BC_OPT_DUMMY (1<<1)
+
+/* Retry modes */
+#define GR1553BC_RETRY_SAME	0x0	/* Retry on the same bus only */
+#define GR1553BC_RETRY_ALTER	0x1	/* Retry alternating on both busses */
+#define GR1553BC_RETRY_ATTEMPT	0x2	/* Many attepts first on original 
+					 * bus then on other bus */
+/* Number of retires supported */
+#define GR1553BC_RETRY_CNT_MAX	6
+
+/* Dummy bit: No transfer
+ * Bus bit: 0=A, 1=B
+ * Exttrig bit: Wait for external trigger (used for timesync)
+ * Exclusive bit: 1=Don't allow other messages in this time slot.
+ */
+#define GR1553BC_OPTIONS(dummy, exttrig, exclusive, retrymode, nretry, bus) \
+		((((exttrig) & 0x1) << 30) | (((exclusive) & 0x1) << 29) | \
+		((retrymode) << 23) | ((nretry) << 20) | \
+		((bus) & 1) | (((dummy) & 0x1) << 1))
+
+#define GR1553BC_OPTIONS_BUSA GR1553BC_OPTIONS(0,0,0,GR1553BC_RETRY_SAME,0,0)
+#define GR1553BC_OPTIONS_BUSB GR1553BC_OPTIONS(0,0,0,GR1553BC_RETRY_SAME,0,1)
+#define GR1553BC_OPTIONS_BUSA_DUM GR1553BC_OPTIONS(1,0,0,GR1553BC_RETRY_SAME,0,0)
+#define GR1553BC_OPTIONS_BUSB_DUM GR1553BC_OPTIONS(1,0,0,GR1553BC_RETRY_SAME,0,1)
+
+/* Show parts of a list - this is for debugging only */
+extern void gr1553bc_show_list(struct gr1553bc_list *list, int options);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GR1553BC_LIST_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr1553bm.h b/c/src/lib/libbsp/sparc/shared/include/gr1553bm.h
new file mode 100644
index 0000000..3d1aecc
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr1553bm.h
@@ -0,0 +1,204 @@
+/*  GR1553B BM driver
+ *
+ *  COPYRIGHT (c) 2010.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GR1553BM_H__
+#define __GR1553BM_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Register GR1553B driver needed by BM driver */
+extern void gr1553bm_register(void);
+
+struct gr1553bm_entry {
+	uint32_t time;	/* bit31=1, bit 30=0 */
+	uint32_t data;	/* bit31=0, bit 30=0 */
+};
+
+#define GR1553BM_ERROPTS_MANL 0x02
+#define GR1553BM_ERROPTS_UDWL 0x04
+#define GR1553BM_ERROPTS_IMCL 0x08
+#define GR1553BM_ERROPTS_ALL  0x0e
+
+/* Function used to implement a custom copy routine.
+ * Returns number of bytes the desctionation address 
+ * should be incremented with.
+ *
+ * \param dst        Optional Destination address
+ * \param src        Source DMA address
+ * \param nentires   Number of entries to be processed.
+ * \param data       Custom Data (set by config)
+ */
+typedef int (*bmcopy_func_t)(
+	unsigned int dst,
+	struct gr1553bm_entry *src,
+	int nentries,
+	void *data
+	);
+
+/* IRQ function callback, called on BM DMA error */
+typedef void (*bmisr_func_t)(void *bm, void *data);
+
+/* BM driver configuration */
+struct gr1553bm_config {
+
+	/*** Time options ***/
+
+	/* 8-bit time resolution, the BM will update the time according
+	 * to this setting. 0 will make the time tag be of highest
+	 * resolution (no division), 1 will make the BM increment the
+	 * time tag once for two time ticks (div with 2), etc.
+	 */
+	uint8_t time_resolution;
+
+	/* Enable Time Overflow IRQ handling. Setting this to 1 
+	 * makes the driver to update the 64-bit time by it self,
+	 * it will use time overflow IRQ to detect when the 64-bit
+	 * time counter must be incremented.
+	 *
+	 * If set to zero, the driver expect the user to call
+	 * gr1553bm_time() regularly, it must be called more often
+	 * than the time overflows to avoid an incorrect time.
+	 */
+	int time_ovf_irq;
+
+
+
+	/*** Filtering options ***/
+
+	/* Bus error log options 
+	 *
+	 * bit0,4-31 = reserved, set to zero
+	 * Bit1 = Enables logging of Invalid mode code errors
+	 * Bit2 = Enables logging of Unexpected Data errors
+	 * Bit3 = Enables logging of Manchester/parity errors
+	 */
+	unsigned int filt_error_options;
+
+	/* RT Address filtering bit mask. Each bit enables (if set)
+	 * logging of a certain RT sub address. Bit 31 enables logging
+	 * of broadcast messages.
+	 */
+	unsigned int filt_rtadr;
+
+	/* RT Subaddress filtering bit mask, bit definition:
+	 *  31:     Enables logging of mode commands on subadr 31
+	 *  1..30:  BitN enables/disables logging of RT subadr N
+	 *  0:      Enables logging of mode commands on subadr 0
+	 */
+	unsigned int filt_subadr;
+
+	/* Mode code Filter, is written into "BM RT Mode code filter"
+	 * register, please see hardware manual for bit declarations.
+	 */
+	unsigned int filt_mc;
+
+
+
+	/*** Buffer options ***/
+
+	/* Size of buffer in bytes, must be aligned to 8-byte 
+	 * The size is limited to max 4Mb.
+	 */
+	unsigned int buffer_size;
+
+	/* Custom buffer, must be aligned to 8-byte and be of buffer_size
+	 * length. If NULL dynamic memory allocation is used.
+	 */
+	void *buffer_custom;
+
+	/* Custom Copy function, may be used to implement a more 
+	 * effective way of copying the DMA buffer. For example
+	 * the DMA log may need to be compressed before copied
+	 * onto a storage, this function can be used to avoid an
+	 * extra copy.
+	 */
+	bmcopy_func_t copy_func;
+
+	/* Optional Custom Data passed on to copy_func() */
+	void *copy_func_arg;
+
+
+
+	/*** Interrupt options ***/
+
+	/* Custom DMA error function, note that this function is called
+	 * from Interrupt Context. Set to NULL to disable this callback.
+	 */
+	bmisr_func_t dma_error_isr;
+
+	/* Optional Custom Data passed on to dma_error_isr() */
+	void *dma_error_arg;
+};
+
+/* Open BM device by instance number (minor)
+ *
+ * The return value is used as input parameter in all other function calls
+ * in the A
+ */
+extern void *gr1553bm_open(int minor);
+
+/* Close previously opened Bm device */
+extern void gr1553bm_close(void *bm);
+
+/* Configure the BM driver before starting */
+extern int gr1553bm_config(void *bm, struct gr1553bm_config *cfg);
+
+/* Start logging */
+extern int gr1553bm_start(void *bm);
+
+/* Get 64-bit 1553 Time. Low 24-bit time is acquired from BM hardware,
+ * the MSB is taken from a software counter internal to the driver. The
+ * counter is incremented every time the Time overflows by:
+ *  - using "Time overflow" IRQ if enabled in user configuration
+ *  - by checking IRQ flag (IRQ disabled), it is required that user
+ *    calls this function before the next time overflow.
+ *
+ * The BM timer is limited to 24-bits, in order to handle overflows
+ * correctly and maintain a valid time an Interrupt handler is used
+ * or this function must be called when IRQ is not used.
+ *
+ * Update software time counters and return the current time.
+ */
+extern void gr1553bm_time(void *bm, uint64_t *time);
+
+/* Return zero when logging has not been started, non-zero when logging
+ * has been started
+ */
+extern int gr1553bm_started(void *bm);
+
+/* Check how many entries are currently stored in the BM Log DMA-area */
+extern int gr1553bm_available(void *bm, int *nentries);
+
+/* Stop logging */
+extern void gr1553bm_stop(void *bm);
+
+/* Read a maximum number of entries from LOG buffer. This function
+ * must be 
+ *
+ * Arguments
+ *  bm           - Private pointer returned by gr1553bm_open()
+ *  dst          - Address where log data is written
+ *  max          - (IN/OUT) Maximum number of entires, when successfull
+ *                 the number of entries actually written is stored
+ *                 into the address of max.
+ *
+ * Result
+ *  0   = success
+ *  -1  = fail. (may be due to BM logging not started)
+ */
+extern int gr1553bm_read(void *bm, struct gr1553bm_entry *dst, int *max);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GR1553BM_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/gr1553rt.h b/c/src/lib/libbsp/sparc/shared/include/gr1553rt.h
new file mode 100644
index 0000000..a1f174c
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gr1553rt.h
@@ -0,0 +1,434 @@
+/*  GR1553B RT driver
+ *
+ *  COPYRIGHT (c) 2010.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GR1553RT_H__
+#define __GR1553RT_H__
+
+/* CONFIG OPTION: Maximum number of LIST IDs supported.
+ *                There are two lists per RT subaddress, one for RX one
+ *                for TX.
+ */
+#define RTLISTID_MAX 64
+
+/* CONFIG OPTION: Maximum number of Interrupt handlers per device supported 
+ * max is 256 supported, and minimum is 1.
+ */
+#define RTISR_MAX 64
+
+/* CONFIG OPTION: Maximum number of transfer (RX/TX) descriptors supported.
+ *
+ * Set this option to zero to allow flexible number of descriptors,
+ * requires dynamically allocation of driver structures.
+ */
+/*#define RTBD_MAX 4096*/
+#define RTBD_MAX 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Register GR1553B driver needed by RT driver */
+extern void gr1553rt_register(void);
+
+struct gr1553rt_list;
+
+/* Descriptor read/written by hardware.
+ *
+ * Must be aligned to 16 byte boundary 
+ */
+struct gr1553rt_bd {
+	volatile unsigned int	ctrl;	/* 0x00 Control/Status word */
+	volatile unsigned int	dptr;	/* 0x04 Data Pointer */
+	volatile unsigned int	next;	/* 0x08 Next Descriptor in list */
+	volatile unsigned int	unused;	/* 0x0C UNUSED BY HARDWARE */
+};
+
+/* Sub address table entry, the hardware access */
+struct gr1553rt_sa {
+	volatile unsigned int ctrl;	/* 0x00 SUBADDRESS CONTROL WORD */
+	volatile unsigned int txptr;	/* 0x04 TRANSMIT BD POINTER */
+	volatile unsigned int rxptr;	/* 0x08 RECEIVE BD POINTER */
+	volatile unsigned int unused;	/* 0x0C UNUSED BY HARDWARE */
+};
+
+/* Configuration of a RT-SubAddress-List */
+struct gr1553rt_list_cfg {
+	unsigned int bd_cnt;		/* Number of hw-descriptors in list */
+};
+
+/* A TX or RX subaddress descriptor list */
+struct gr1553rt_list {
+	short listid;			/* ID/NUMBER of List. -1 unassigned */
+	short subadr;			/* SubAddress. -1 when not scheduled */
+	void *rt;			/* Scheduled on Device */
+	struct gr1553rt_list_cfg *cfg;	/* List configuration */
+	int bd_cnt;			/* Number of Descriptors */
+
+	/* !!Must be last in data structure!! 
+	 * !!Array must at least be of length bd_cnt!!
+	 */
+	unsigned short bds[1];		/* Array of BDIDs, -1 unused/end */
+};
+
+/* GR1553B-RT Driver configuration options used when calling gr1553rt_config().
+ *
+ * Note that if not custom addresses are given the driver will dynamically
+ *      allocate memory for buffers.
+ * Note that if custom addresses with the LSB set, the address will be
+ *      interpreted as a address accessible by hardware, and translated
+ *      into an address used by CPU.
+ */
+struct gr1553rt_cfg {
+	unsigned char rtaddress;	/* RT Address 0..30 */
+
+	/*** MODE CODE CONFIG ***/
+	unsigned int modecode;		/* Mode codes enable/disable/IRQ/EV-Log.
+					 * Each modecode has a 2-bit cfg field.
+					 * See Mode Code Control Register in
+					 * hardware manual.
+					 */
+
+	/*** TIME CONFIG ***/
+	unsigned short time_res;	/* Time tag resolution in us */
+
+	/*** SUBADDRESS TABLE CONFIG ***/
+	void *satab_buffer;		/* Optional Custom buffer. Must be 
+					 * At least 16*32 bytes, and be aligned
+					 * to 10-bit (1KB) boundary. Set to NULL
+					 * to make driver allocate buffer.
+					 */
+
+	/*** EVENT LOG CONFIG ***/
+	void *evlog_buffer;		/* Optional Custom buffer */
+	int evlog_size;			/* Length, must be a multiple of 2.
+					 * If set to ZERO event log is disabled
+					 */
+
+	/*** TRANSFER DESCRIPTOR CONFIG ***/
+	int bd_count;			/* Number of transfer descriptors shared
+					 * by all RX/TX sub-addresses */
+	void *bd_buffer;		/* Optional Custom descriptor area.
+					 * Must hold bd_count*32 bytes.
+					 * If NULL, descriptors will be 	
+					 * allocated dynamically. */
+};
+
+/* GR1553B-RT status indication, copied from the RT registers and stored
+ * here. Used when calling the gr1553rt_status() function.
+ */
+struct gr1553rt_status {
+	unsigned int status;		/* RT Status word */
+	unsigned int bus_status;	/* BUS Status */
+	unsigned short synctime;	/* Time Tag of last sync with data */
+	unsigned short syncword;	/* Data of last mode code synchronize
+					 * with data. */
+	unsigned short time_res;	/* Time resolution (set by config) */
+	unsigned short time;		/* Current Time Tag */
+};
+
+/* ISR callback definition for ERRORs detected in the GR1553B-RT interrupt
+ * handler.
+ *
+ * \param err    Inidicate Error type. The IRQ flag register bit mask:
+ *                 Bit 9  - RT DMA ERROR
+ *                 Bit 10 - RT Table access error
+ * \param data   Custom data assigned by user
+ */
+typedef void (*gr1553rt_irqerr_t)(int err, void *data);
+
+/* ISR callback definition for modecodes that are configured to generate
+ * an IRQ. The callback is called from within the GR1553B-RT interrupt
+ * handler.
+ *
+ * \param mcode  Mode code that caused this IRQ
+ * \param entry  The raw Eventlog Entry
+ * \param data   Custom data assigned by user
+ */
+typedef void (*gr1553rt_irqmc_t)(int mcode, unsigned int entry, void *data);
+
+/* Transfer ISR callback definition. Called from GR1553B-RT interrupt handler
+ * when an interrupt has been generated and a event logged due to a 1553
+ * transfer to this RT.
+ *
+ * \param list     List (Subaddress/TransferType) that caused IRQ
+ * \param entry    The raw Eventlog Entry
+ * \param bd_next  Next Descriptor-entry index in the list (Subaddress/tr-type)
+ *                 This can be used to process all descriptors upto entry_next.
+ * \param data     Custom data assigned by user
+ */
+typedef void (*gr1553rt_irq_t)(
+	struct gr1553rt_list *list, 
+	unsigned int entry,
+	int bd_next,
+	void *data
+	);
+
+/* Configure a list according to configuration. Assign the list
+ * to a device, however not to a RT sub address yet. The rt
+ * is stored within list.
+ *
+ * \param rt       RT Device driver identification, stored within list.
+ * \param list     The list to configure
+ * \param cfg      Configuration for list. Pointer to configuration is
+ *                 stored within list for later use.
+ */
+extern int gr1553rt_list_init
+	(
+	void *rt,
+	struct gr1553rt_list **plist,
+	struct gr1553rt_list_cfg *cfg
+	);
+
+/* Assign an Error Interrupt handler. Before the handler is called the 
+ * RT hardware is stopped/disabled. The handler is optional, if not assigned
+ * the ISR will still stop the RT upon error.
+ *
+ * Errors detected by the interrupt handler:
+ *  - DMA error
+ *  - Subaddress table access error
+ *
+ * \param func     ISR called when an error causes an interrupt.
+ * \param data     Custom data given as an argument when calling ISR
+ */
+extern int gr1553rt_irq_err
+	(
+	void *rt,
+	gr1553rt_irqerr_t func,
+	void *data
+	);
+
+/* Assign a ModeCode Interrupt handler callback. Called when a 1553 modecode
+ * transfer is logged and cause an IRQ. The modecode IRQ generation is
+ * configured from "struct gr1553rt_cfg" when calling gr1553rt_config().
+ *
+ * \param func     ISR called when a modecode causes an interrupt.
+ * \param data     Custom data given as an argument when calling ISR
+ */
+extern int gr1553rt_irq_mc
+	(
+	void *rt,
+	gr1553rt_irqmc_t func,
+	void *data
+	);
+
+/* Assign transfer interrupt handler callback. Called when a RX or TX
+ * transfer is logged and cause an interrupt, the function is called
+ * from the GR1553B-RT driver's ISR, in interrupt context.
+ *
+ * The callback can be installed per subaddress and transfer type.
+ * Subaddress 0 and 31 are not valid (gr1553rt_irq_mc() for modecodes).
+ *
+ * \param subadr   Select subaddress (1-30)
+ * \param tx       1=TX subaddress, 0=RX subaddress
+ * \param func     ISR called when subaddress of spcified transfer type
+ *                 causes an interrupt.
+ * \param data     Custom data given as an argument when calling ISR
+ */
+extern int gr1553rt_irq_sa
+	(
+	void *rt,
+	int subadr,
+	int tx,
+	gr1553rt_irq_t func,
+	void *data
+	);
+
+#define GR1553RT_BD_FLAGS_IRQEN (1<<30)
+/* Initialize a descriptor entry in a list. This is typically done
+ * prior to scheduling the list.
+ *
+ * \param entry_no  Entry number in list (descriptor index in list)
+ * \param flags     Enable IRQ when descriptor is accessed by setting 
+ *                  argument GR1553RT_BD_FLAGS_IRQEN. Enabling IRQ on a
+ *                  descriptor basis will override SA-table IRQ config.
+ * \param dptr      Data Pointer to RX or TX operation. The LSB indicate
+ *                  if the address must be translated into Hardware address
+ *                  - this is useful when a buffer close to CPU is used
+ *                  as a data pointer and the RT core is located over PCI.
+ * \param next      Next Entry in list. Set to 0xffff for end of list. Set
+ *                  0xfffe for next entry in list, wrap around to entry
+ *                  zero if entry_no is last descriptor in list (circular).
+ */
+extern int gr1553rt_bd_init(
+	struct gr1553rt_list *list,
+	unsigned short entry_no,
+	unsigned int flags,
+	uint16_t *dptr,
+	unsigned short next
+	);
+
+/* Manipulate/Read Control/Status and Data Pointer words of a buffer descriptor.
+ * If status is zero, the control/status word is accessed. If dptr is non-zero
+ * the data pointer word is accessed.
+ *
+ * \param list       The list that the descriptor is located at
+ *
+ * \param entry_no   The descriptor number accessed
+ *
+ * \param status     IN/OUT. If zero no effect. If pointer is non-zero the
+ *                   value pointed to:
+ *                   IN: Written to Control/Status
+ *                   OUT: the value of the Control/Status word before writing.
+ *
+ * \param dptr       IN/OUT. If zero no effect. If pointer is non-zero, the
+ *                   value pointed to:
+ *                   IN: non-zero: Descriptor data pointer will be updated with
+ *                       this value. Note that the LSB indicate if the address
+ *                       must be translated into hardware-aware address.
+ *                   OUT: The old data pointer is stored here.
+ */
+extern int gr1553rt_bd_update(
+	struct gr1553rt_list *list,
+	int entry_no,
+	unsigned int *status,
+	uint16_t **dptr
+	);
+
+/* Get the next/current descriptor processed of a RT sub-address.
+ *
+ * \param subadr  RT Subaddress
+ * \param txeno   Pointer to where TX descriptor number is stored.
+ * \param rxeno   Pointer to where RX descriptor number is stored.
+ */
+extern int gr1553rt_indication(void *rt, int subadr, int *txeno, int *rxeno);
+
+/* Take a GR1553RT hardware device identified by minor.
+ * A pointer is returned that is used internally by the GR1553RT
+ * driver, it is used as an input parameter 'rt' to all other
+ * functions that manipulate the hardware.
+ *
+ * This function initializes the RT hardware to a stopped/disable level.
+ */
+extern void *gr1553rt_open(int minor);
+
+/* Close and stop/disable the RT hardware. */
+extern void gr1553rt_close(void *rt);
+
+/* Configure the RT. The RT device must be configured once before
+ * started. A started RT device can not be configured.
+ *
+ * \param rt    The RT to configure
+ * \param cfg   Configuration parameters
+ */
+extern int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg);
+
+/* Schedule a RX or TX list on a sub address. If a list has already been
+ * schduled on the subaddress and on the same transfer type (RX/TX), the 
+ * old list is replaced with the list given here.
+ *
+ * \param subadr   Subaddress to schedule list on
+ * \param tx       Subaddress transfer type: 1=TX, 0=RX
+ * \param list     Preconfigued RT list scheduled
+ */
+extern void gr1553rt_sa_schedule(
+	void *rt,
+	int subadr,
+	int tx,
+	struct gr1553rt_list *list
+	);
+
+/* Set SubAdress options. One may for example Enable or Disable a sub 
+ * address RX and/or TX. See hardware manual for SA-Table configuration
+ * options.
+ *
+ * \param subadr   SubAddress to configure
+ * \param mask     Bit mask of option-bits written to subaddress config
+ * \param options  The new options written to subaddress config.
+ *
+ */
+extern void gr1553rt_sa_setopts(
+	void *rt,
+	int subadr,
+	unsigned int mask,
+	unsigned int options
+	);
+
+/* Get The Subaddress and transfer type of a scheduled list. Normally the
+ * application knows which subaddress the list is for.
+ *
+ * \param list     List to lookup information for
+ * \param subadr   Pointer to where the subaddress is stored
+ * \param tx       Transfer type is stored here. 1=TX, 0=RX.
+ */
+extern void gr1553rt_list_sa(
+	struct gr1553rt_list *list,
+	int *subadr,
+	int *tx
+	);
+
+/* Start RT Communication
+ *
+ * Interrupts will be enabled. The RT enabled and the "RT-run-time" 
+ * part of the API will be opened for the user and parts that need the
+ * RT to be stopped are no longer available. After the RT has been
+ * started the configuration function can not be called.
+ */
+extern int gr1553rt_start(void *rt);
+
+/* Get Status of the RT core. See data structure gr1553rt_status for more
+ * information about the result. It can be used to read out:
+ *  - time information
+ *  - sync information
+ *  - bus & RT status
+ *
+ * \param status   Pointer to where the status words will be stored. They
+ *                 are stored according to the gr1553rt_status data structure.
+ */
+extern void gr1553rt_status(void *rt, struct gr1553rt_status *status);
+
+/* Stop RT communication. Only possible to stop an already started RT device.
+ * Interrupts are disabled and the RT Enable bit cleared.
+ */
+extern void gr1553rt_stop(void *rt);
+
+/* Set RT vector and/or bit word.
+ *
+ *  - Vector Word is used in response to "Transmit vector word" BC commands
+ *  - Bit Word is used in response to "Transmit bit word" BC commands
+ *
+ *
+ * \param mask     Bit-Mask, bits that are 1 will result in that bit in the
+ *                 words register being overwritten with the value of words
+ * \param words    Bits 31..16: Bit Word. Bits 15..0: Vector Word.
+ *
+ * Operation:
+ *  hw_words = (hw_words & ~mask) | (words & mask)
+ */
+extern void gr1553rt_set_vecword(
+	void *rt,
+	unsigned int mask,
+	unsigned int words
+	);
+
+/* Set selectable bits of the "Bus Status Register". The bits written
+ * is determined by the "mask" bit-mask. Operation:
+ *
+ * bus_status = (bus_status & ~mask) | (sts & mask)
+ * 
+ */
+extern void gr1553rt_set_bussts(void *rt, unsigned int mask, unsigned int sts);
+
+/* Read up to MAX number of entries in eventlog log. 
+ *
+ * \param dst   Destination address for event log entries
+ * \param max   Maximal number of event log entries that an be stored into dst
+ *
+ * Return
+ *  negative   Failure
+ *  zero       No entries available at the moment
+ *  positive   Number of entries copied into dst
+ */
+extern int gr1553rt_evlog_read(void *rt, unsigned int *dst, int max);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/gradcdac.h b/c/src/lib/libbsp/sparc/shared/include/gradcdac.h
new file mode 100644
index 0000000..b0f246a
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/gradcdac.h
@@ -0,0 +1,227 @@
+/*  ADC / DAC (GRADCDAC) interface
+/*
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GRADCDAC_H__
+#define __GRADCDAC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct gradcdac_regs {
+	volatile unsigned int config;      /* 0x00 Configuration Register */
+	volatile unsigned int status;      /* 0x04 Status Register */
+	int unused0[2];
+	volatile unsigned int adc_din;     /* 0x10 ADC Data Input Register */
+	volatile unsigned int dac_dout;    /* 0x14 DAC Data Output Register */
+	int unused1[2];
+	volatile unsigned int adrin;       /* 0x20 Address Input Register */
+	volatile unsigned int adrout;      /* 0x24 Address Output Register */
+	volatile unsigned int adrdir;      /* 0x28 Address Direction Register */
+	int unused2[1];
+	volatile unsigned int data_in;     /* 0x30 Data Input Register  */
+	volatile unsigned int data_out;    /* 0x34 Data Output Register */
+	volatile unsigned int data_dir;    /* 0x38 Data Direction Register */
+};
+
+#define GRADCDAC_CFG_DACWS    0x00f80000
+#define GRADCDAC_CFG_WRPOL    0x00040000
+#define GRADCDAC_CFG_DACDW    0x00030000
+#define GRADCDAC_CFG_ADCWS    0x0000f800
+#define GRADCDAC_CFG_RCPOL    0x00000400
+#define GRADCDAC_CFG_CSMODE   0x00000300
+#define GRADCDAC_CFG_CSPOL    0x00000080
+#define GRADCDAC_CFG_RDYMODE  0x00000040
+#define GRADCDAC_CFG_RDYPOL   0x00000020
+#define GRADCDAC_CFG_TRIGPOL  0x00000010
+#define GRADCDAC_CFG_TRIGMODE 0x0000000c
+#define GRADCDAC_CFG_ADCDW    0x00000003
+
+#define GRADCDAC_CFG_DACWS_BIT    19
+#define GRADCDAC_CFG_WRPOL_BIT    18
+#define GRADCDAC_CFG_DACDW_BIT    16
+#define GRADCDAC_CFG_ADCWS_BIT    11
+#define GRADCDAC_CFG_RCPOL_BIT    10
+#define GRADCDAC_CFG_CSMODE_BIT    8
+#define GRADCDAC_CFG_CSPOL_BIT     7
+#define GRADCDAC_CFG_RDYMODE_BIT   6
+#define GRADCDAC_CFG_RDYPOL_BIT    5
+#define GRADCDAC_CFG_TRIGPOL_BIT   4
+#define GRADCDAC_CFG_TRIGMODE_BIT  2
+#define GRADCDAC_CFG_ADCDW_BIT     0
+
+#define GRADCDAC_STATUS_DACNO   0x40
+#define GRADCDAC_STATUS_DACRDY  0x20
+#define GRADCDAC_STATUS_DACON   0x10
+#define GRADCDAC_STATUS_ADCTO   0x08
+#define GRADCDAC_STATUS_ADCNO   0x04
+#define GRADCDAC_STATUS_ADCRDY  0x02
+#define GRADCDAC_STATUS_ADCON   0x01
+
+#define GRADCDAC_STATUS_DACNO_BIT  6
+#define GRADCDAC_STATUS_DACRDY_BIT 5
+#define GRADCDAC_STATUS_DACON_BIT  4
+#define GRADCDAC_STATUS_ADCTO_BIT  3
+#define GRADCDAC_STATUS_ADCNO_BIT  2
+#define GRADCDAC_STATUS_ADCRDY_BIT 1
+#define GRADCDAC_STATUS_ADCON_BIT  0
+
+#define GRADCDAC_IRQ_DAC 1
+#define GRADCDAC_IRQ_ADC 0
+
+struct gradcdac_config {
+	unsigned char dac_ws;
+	char wr_pol;
+	unsigned char dac_dw;
+	unsigned char adc_ws;
+	char rc_pol;
+	unsigned char cs_mode;
+	char cs_pol;
+	char ready_mode;
+	char ready_pol;
+	char trigg_pol;
+	unsigned char trigg_mode;
+	unsigned char adc_dw;
+};
+
+extern void *gradcdac_open(char *devname);
+
+extern void gradcdac_set_config(void *cookie, struct gradcdac_config *cfg);
+
+extern void gradcdac_get_config(void *cookie, struct gradcdac_config *cfg);
+
+extern void gradcdac_set_cfg(void *cookie, unsigned int config);
+
+extern unsigned int gradcdac_get_cfg(void *cookie);
+
+extern unsigned int gradcdac_get_status(void *cookie);
+
+static int __inline__ gradcdac_DAC_ReqRej(unsigned int status)
+{
+	return (status & GRADCDAC_STATUS_DACNO);
+}
+
+static int __inline__ gradcdac_DAC_isCompleted(unsigned int status)
+{
+	return (status & GRADCDAC_STATUS_DACRDY);
+}
+
+static int __inline__ gradcdac_DAC_isOngoing(unsigned int status)
+{
+	return (status & GRADCDAC_STATUS_DACON);
+}
+
+static int __inline__ gradcdac_ADC_isTimeouted(unsigned int status)
+{
+	return (status & GRADCDAC_STATUS_ADCTO);
+}
+
+static int __inline__ gradcdac_ADC_ReqRej(unsigned int status)
+{
+	return (status & GRADCDAC_STATUS_ADCNO);
+}
+
+static int __inline__ gradcdac_ADC_isCompleted(unsigned int status)
+{
+	return (status & GRADCDAC_STATUS_ADCRDY);
+}
+
+static int __inline__ gradcdac_ADC_isOngoing(unsigned int status)
+{
+	return (status & GRADCDAC_STATUS_ADCON);
+}
+
+#define GRADCDAC_ISR_BOTH 3
+#define GRADCDAC_ISR_DAC 2
+#define GRADCDAC_ISR_ADC 1
+
+/* Install IRQ handler for ADC and/or DAC interrupt.
+ * The installed IRQ handler(ISR) must read the status 
+ * register to clear the pending interrupt avoiding multiple
+ * entries to the ISR caused by the same IRQ.
+ *
+ * \param adc  1=ADC interrupt, 2=ADC interrupt, 3=ADC and DAC interrupt
+ * \param isr  Interrupt service routine called when IRQ is fired
+ * \param arg  custom argument passed to ISR when called.
+ */
+extern int gradcdac_install_irq_handler
+	(void *cookie, int adc, void (*isr)(void *cookie, void *arg), void *arg);
+
+extern void gradcdac_uninstall_irq_handler(void *cookie, int adc);
+
+/* Make the ADC circuitry initialize a analogue to digital
+ * conversion. The result can be read out by gradcdac_adc_convert_try
+ * or gradcdac_adc_convert.
+ */
+extern void gradcdac_adc_convert_start(void *cookie);
+
+/* Tries to read the conversion result. If the circuitry is busy 
+ * converting the function return a non-zero value, if the conversion 
+ * has successfully finished the function return zero.
+ *
+ * \param digital_value the resulting converted value is placed here
+ * \return zero     = ADC conversion complete, digital_value contain current conversion result
+ *         positive = ADC busy, digital_value contain previous conversion result
+ *         negative = Conversion request failed.
+ */
+extern int gradcdac_adc_convert_try(void *cookie, unsigned short *digital_value);
+
+/* Waits until the ADC circuity has finished a digital to analogue 
+ * conversion. The Waiting is implemented as a busy loop utilizing
+ * 100% CPU load.
+ *
+ * \return zero     = Conversion ok
+ *         negative = Conversion request failed.
+ */
+extern int gradcdac_adc_convert(void *cookie, unsigned short *digital_value);
+
+/* Try to make the DAC circuitry initialize a digital to analogue 
+ * conversion. If the circuitry is busy by a previous conversion
+ * the function return a non-zero value, if the conversion is
+ * successfully initialized the function return zero.
+ */
+extern int gradcdac_dac_convert_try(void *cookie, unsigned short digital_value);
+
+/* Initializes a digital to analogue conversion by waiting until 
+ * previous conversions is finished before procceding with the
+ * conversion. The Waiting is implemented as a busy loop utilizing
+ * 100% CPU load.
+ */
+extern void gradcdac_dac_convert(void *cookie, unsigned short digital_value);
+
+extern unsigned int gradcdac_get_adrinput(void *cookie);
+extern void gradcdac_set_adrinput(void *cookie, unsigned int input);
+
+extern unsigned int gradcdac_get_adroutput(void *cookie);
+extern void gradcdac_set_adroutput(void *cookie, unsigned int output);
+
+extern unsigned int gradcdac_get_adrdir(void *cookie);
+extern void gradcdac_set_adrdir(void *cookie, unsigned int dir);
+
+extern unsigned int gradcdac_get_datainput(void *cookie);
+extern void gradcdac_set_datainput(void *cookie, unsigned int input);
+
+extern unsigned int gradcdac_get_dataoutput(void *cookie);
+extern void gradcdac_set_dataoutput(void *cookie, unsigned int output);
+
+extern unsigned int gradcdac_get_datadir(void *cookie);
+extern void gradcdac_set_datadir(void *cookie, unsigned int dir);
+
+/* Show one or all GRADCDAC cores. If cookie is NULL all GRADCDAC's are shown */
+extern void grAdcDacShow(void *cookie);
+
+/* Register Driver routine */
+extern void gradcdac_register_drv (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grascs.h b/c/src/lib/libbsp/sparc/shared/include/grascs.h
new file mode 100644
index 0000000..5a082ce
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grascs.h
@@ -0,0 +1,92 @@
+/*
+ * Header file for GRASCS RTEMS driver
+ *
+ * COPYRIGHT (c) 2008.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GRASCS_H__
+#define __GRASCS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Minimum and maximum system frequency */
+#define GRASCS_MIN_SFREQ 10000
+#define GRASCS_MAX_SFREQ 255000
+
+/* Default, minimum and maximum ETR pulse frequency */
+#define GRASCS_DEFAULT_ETRFREQ 10
+#define GRASCS_MIN_ETRFREQ 1
+#define GRASCS_MAX_ETRFREQ 100
+
+/* Maximum number of external time markers */
+#define GRASCS_MAX_TMS 6
+
+/* Error codes */
+#define GRASCS_ERROR_STARTSTOP 1 /* Serial/synch interface is running/stopped */
+#define GRASCS_ERROR_TRANSACTIVE 2 /* Busy with transaction */
+#define GRASCS_ERROR_CAPFAULT 3 /* Core capabilities prohibit request */
+
+/* Command register */
+#define GRASCS_CMD_RESET (1 << 0)
+#define GRASCS_CMD_STARTSTOP (1 << 1)
+#define GRASCS_CMD_ESTARTSTOP (1 << 2)
+#define GRASCS_CMD_SENDTM (1 << 3)
+#define GRASCS_CMD_ETRCTRL (7 << 4)
+#define GRASCS_CMD_ETRCTRL_BITS 4
+#define GRASCS_CMD_SLAVESEL (15 << 8)
+#define GRASCS_CMD_SLAVESEL_BITS 8
+#define GRASCS_CMD_TCDONE (1 << 12)
+#define GRASCS_CMD_TMDONE (1 << 13)
+#define GRASCS_CMD_US1 (255 << 16)
+#define GRASCS_CMD_US1_BITS 16
+#define GRASCS_CMD_US1C (1 << 24)
+
+/* Clock scale register */
+#define GRASCS_CLK_ETRFREQ_BITS 12
+
+/* Status register */
+#define GRASCS_STS_RUNNING (1 << 0)
+#define GRASCS_STS_ERUNNING (1 << 1)
+#define GRASCS_STS_TCDONE (1 << 4)
+#define GRASCS_STS_TMDONE (1 << 5)
+#define GRASCS_STS_DBITS_BITS 8
+#define GRASCS_STS_NSLAVES_BITS 13
+#define GRASCS_STS_USCONF_BITS 18
+#define GRASCS_STS_TMCONF_BITS 19
+
+extern int ASCS_init();
+
+extern int ASCS_input_select(int slave);
+
+extern int ASCS_etr_select(int etr, int freq);
+
+extern void ASCS_start(void);
+
+extern void ASCS_stop(void);
+
+extern int ASCS_iface_status(void);
+
+extern int ASCS_TC_send(int *word);
+
+extern int ASCS_TC_send_block(int *block, int ntrans);
+
+extern void ASCS_TC_sync_start(void);
+
+extern void ASCS_TC_sync_stop(void);
+
+extern int ASCS_TM_recv(int *word);
+
+extern int ASCS_TM_recv_block(int *block, int ntrans);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grctm.h b/c/src/lib/libbsp/sparc/shared/include/grctm.h
new file mode 100644
index 0000000..731e4c5
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grctm.h
@@ -0,0 +1,168 @@
+/*  GRCTM - CCSDS Time Manager - register driver interface.
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GRCTM_H__
+#define __GRCTM_H__
+
+#define DAT0_IRQ    0x1
+#define DAT1_IRQ    0x2
+#define DAT2_IRQ    0x4
+#define PULSE0_IRQ  0x10
+#define PULSE1_IRQ  0x20
+#define PULSE2_IRQ  0x40
+#define PULSE3_IRQ  0x80
+#define PULSE4_IRQ  0x100
+#define PULSE5_IRQ  0x200
+#define PULSE6_IRQ  0x400
+#define PULSE7_IRQ  0x800
+
+struct grctm_regs {
+	volatile unsigned int grr;
+	volatile unsigned int gcr;
+	volatile unsigned int gsr;
+	volatile unsigned int unused[2];
+	volatile unsigned int pfr;
+	volatile unsigned int etcr;
+	volatile unsigned int etfr;
+	volatile unsigned int dcr0;
+	volatile unsigned int dfr0;
+	volatile unsigned int dcr1;
+	volatile unsigned int dfr1;
+	volatile unsigned int dcr2;
+	volatile unsigned int dfr2;
+	volatile unsigned int stcr;
+	volatile unsigned int stfr;
+	volatile unsigned int pdr[8];
+	volatile unsigned int pimsr;
+	volatile unsigned int pimr;
+	volatile unsigned int pisr;
+	volatile unsigned int pir;
+	volatile unsigned int imr;
+	volatile unsigned int picr;
+	volatile unsigned int unused1[2];
+	volatile unsigned int etir;
+	volatile unsigned int fsir;
+	volatile unsigned int serconf;
+	volatile unsigned int unused2;
+	volatile unsigned int twsc;
+	volatile unsigned int twadj;
+	volatile unsigned int twtx;
+	volatile unsigned int twrx;
+};
+
+struct grctm_stats {
+
+	/* IRQ Stats */
+	unsigned int nirqs;
+	unsigned int pulse;
+};
+
+/* Function ISR callback prototype */
+typedef void (*grctm_isr_t)(unsigned int pimr, void *data);
+
+/* Open a GRCTM device by minor number. */
+extern void *grctm_open(int minor);
+
+/* Close a previously opened GRCTM device */
+extern void grctm_close(void *spwcuc);
+
+/* Hardware Reset of GRCTM */
+extern int grctm_reset(void *grctm);
+
+/* Enable Interrupts at Interrupt controller */
+extern void grctm_int_enable(void *grctm);
+
+/* Disable Interrupts at Interrupt controller */
+extern void grctm_int_disable(void *grctm);
+
+/* Clear Statistics gathered by the driver */
+extern void grctm_clr_stats(void *grctm);
+
+/* Get Statistics gathered by the driver */
+extern void grctm_get_stats(void *grctm, struct grctm_stats *stats);
+
+/* Register an Interrupt handler and custom data, the function call is
+ * removed by setting func to NULL.
+ */
+extern void grctm_int_register(void *grctm, grctm_isr_t func, void *data);
+
+/* Enable external synchronisation (from spwcuc) */
+extern void grctm_enable_ext_sync(void *grctm);
+
+/* Disable external synchronisation (from spwcuc) */
+extern void grctm_disable_ext_sync(void *grctm);
+
+/* Enable TimeWire synchronisation */
+extern void grctm_enable_tw_sync(void *grctm);
+
+/* Disable TimeWire synchronisation */
+extern void grctm_disable_tw_sync(void *grctm);
+
+/* Disable frequency synthesizer from driving ET */
+extern void grctm_disable_fs(void *grctm);
+
+/* Enable frequency synthesizer to drive ET */
+extern void grctm_enable_fs(void *grctm);
+
+/* Return elapsed coarse time */
+extern unsigned int grctm_get_et_coarse(void *grctm);
+
+/* Return elapsed fine time */
+extern unsigned int grctm_get_et_fine(void *grctm);
+
+/* Return elapsed time (coarse and fine) */
+extern unsigned long long grctm_get_et(void *grctm);
+
+/* Return 1 if specified datation has been latched */
+extern int grctm_is_dat_latched(void *grctm, int dat);
+
+/* Set triggering edge of datation input */
+extern void grctm_set_dat_edge(void *grctm, int dat, int edge);
+
+/* Return latched datation coarse time */
+extern unsigned int grctm_get_dat_coarse(void *grctm, int dat);
+
+/* Return latched datation fine time */
+extern unsigned int grctm_get_dat_fine(void *grctm, int dat);
+
+/* Return latched datation ET */
+extern unsigned long long grctm_get_dat_et(void *grctm, int dat);
+
+/* Return current pulse configuration */
+extern unsigned int grctm_get_pulse_reg(void *grctm, int pulse);
+
+/* Set pulse register */
+extern void grctm_set_pulse_reg(void *grctm, int pulse, unsigned int val);
+
+/* Configure pulse: pp = period, pw = width, pl = level, en = enable */
+extern void grctm_cfg_pulse(void *grctm, int pulse, int pp, int pw, int pl, int en);
+
+/* Enable pulse output */
+extern void grctm_enable_pulse(void *grctm, int pulse);
+
+/* Disable pulse output */
+extern void grctm_disable_pulse(void *grctm, int pulse);
+
+/* Clear interrupts */
+extern void grctm_clear_irqs(void *grctm, int irqs);
+
+/* Enable interrupts */
+extern void grctm_enable_irqs(void *grctm, int irqs);
+
+/* Set Frequency synthesizer increment */
+void grctm_set_fs_incr(void *grctm, int incr);
+
+/* Set ET increment */
+void grctm_set_et_incr(void *grctm, int incr);
+
+/* Register the GRCTM driver to Driver Manager */
+extern void grctm_register(void);
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/greth.h b/c/src/lib/libbsp/sparc/shared/include/greth.h
new file mode 100644
index 0000000..c0c3b9a
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/greth.h
@@ -0,0 +1,145 @@
+/*
+ * Cobham Gaisler ethernet MAC driver
+ * adapted from Opencores driver by Marko Isomaki
+ *
+ * The license and distribution terms for this file may be
+ * found in found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GRETH_H__
+#define __GRETH_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Ethernet configuration registers */
+
+typedef struct _greth_regs {
+   volatile uint32_t ctrl;         /* Ctrl Register */
+   volatile uint32_t status;       /* Status Register */
+   volatile uint32_t mac_addr_msb; /* Bit 47-32 of MAC address */
+   volatile uint32_t mac_addr_lsb; /* Bit 31-0 of MAC address */
+   volatile uint32_t mdio_ctrl;    /* MDIO control and status */
+   volatile uint32_t txdesc;       /* Transmit descriptor pointer */
+   volatile uint32_t rxdesc;       /* Receive descriptor pointer */
+} greth_regs;
+
+#define GRETH_TOTAL_BD           128
+#define GRETH_MAXBUF_LEN         1520
+                                
+/* Tx BD */                     
+#define GRETH_TXD_ENABLE      0x0800 /* Tx BD Enable */
+#define GRETH_TXD_WRAP        0x1000 /* Tx BD Wrap (last BD) */
+#define GRETH_TXD_IRQ         0x2000 /* Tx BD IRQ Enable */
+#define GRETH_TXD_MORE        0x20000 /* Tx BD More (more descs for packet) */
+#define GRETH_TXD_IPCS        0x40000 /* Tx BD insert ip chksum */
+#define GRETH_TXD_TCPCS       0x80000 /* Tx BD insert tcp chksum */
+#define GRETH_TXD_UDPCS       0x100000 /* Tx BD insert udp chksum */
+
+#define GRETH_TXD_UNDERRUN    0x4000 /* Tx BD Underrun Status */
+#define GRETH_TXD_RETLIM      0x8000 /* Tx BD Retransmission Limit Status */
+#define GRETH_TXD_LATECOL     0x10000 /* Tx BD Late Collision */
+
+#define GRETH_TXD_STATS       (GRETH_TXD_UNDERRUN            | \
+                               GRETH_TXD_RETLIM              | \
+                               GRETH_TXD_LATECOL)
+
+#define GRETH_TXD_CS          (GRETH_TXD_IPCS            | \
+                               GRETH_TXD_TCPCS           | \
+                               GRETH_TXD_UDPCS)
+                                
+/* Rx BD */                     
+#define GRETH_RXD_ENABLE      0x0800 /* Rx BD Enable */
+#define GRETH_RXD_WRAP        0x1000 /* Rx BD Wrap (last BD) */
+#define GRETH_RXD_IRQ         0x2000 /* Rx BD IRQ Enable */
+
+#define GRETH_RXD_DRIBBLE     0x4000 /* Rx BD Dribble Nibble Status */                                
+#define GRETH_RXD_TOOLONG     0x8000 /* Rx BD Too Long Status */
+#define GRETH_RXD_CRCERR      0x10000 /* Rx BD CRC Error Status */
+#define GRETH_RXD_OVERRUN     0x20000 /* Rx BD Overrun Status */
+#define GRETH_RXD_LENERR      0x40000 /* Rx BD Length Error */
+#define GRETH_RXD_ID          0x40000 /* Rx BD IP Detected */
+#define GRETH_RXD_IR          0x40000 /* Rx BD IP Chksum Error */
+#define GRETH_RXD_UD          0x40000 /* Rx BD UDP Detected*/
+#define GRETH_RXD_UR          0x40000 /* Rx BD UDP Chksum Error */
+#define GRETH_RXD_TD          0x40000 /* Rx BD TCP Detected */
+#define GRETH_RXD_TR          0x40000 /* Rx BD TCP Chksum Error */
+
+
+#define GRETH_RXD_STATS       (GRETH_RXD_OVERRUN             | \
+                               GRETH_RXD_DRIBBLE             | \
+                               GRETH_RXD_TOOLONG             | \
+                               GRETH_RXD_CRCERR)
+
+/* CTRL Register */
+#define GRETH_CTRL_TXEN         0x00000001 /* Transmit Enable */
+#define GRETH_CTRL_RXEN         0x00000002 /* Receive Enable  */
+#define GRETH_CTRL_TXIRQ        0x00000004 /* Transmit Enable */
+#define GRETH_CTRL_RXIRQ        0x00000008 /* Receive Enable  */
+#define GRETH_CTRL_FULLD        0x00000010 /* Full Duplex */
+#define GRETH_CTRL_PRO          0x00000020 /* Promiscuous (receive all) */
+#define GRETH_CTRL_RST          0x00000040 /* Reset MAC */
+
+/* Status Register */
+#define GRETH_STATUS_RXERR      0x00000001 /* Receive Error */
+#define GRETH_STATUS_TXERR      0x00000002 /* Transmit Error IRQ */
+#define GRETH_STATUS_RXIRQ      0x00000004 /* Receive Frame IRQ */
+#define GRETH_STATUS_TXIRQ      0x00000008 /* Transmit Error IRQ */
+#define GRETH_STATUS_RXAHBERR   0x00000010 /* Receiver AHB Error */
+#define GRETH_STATUS_TXAHBERR   0x00000020 /* Transmitter AHB Error */
+
+/* MDIO Control  */
+#define GRETH_MDIO_WRITE        0x00000001 /* MDIO Write */
+#define GRETH_MDIO_READ         0x00000002 /* MDIO Read */
+#define GRETH_MDIO_LINKFAIL     0x00000004 /* MDIO Link failed */
+#define GRETH_MDIO_BUSY         0x00000008 /* MDIO Link Busy */
+#define GRETH_MDIO_REGADR       0x000007C0 /* Register Address */
+#define GRETH_MDIO_PHYADR       0x0000F800 /* PHY address */
+#define GRETH_MDIO_DATA         0xFFFF0000 /* MDIO DATA */
+
+
+/* MII registers */
+#define GRETH_MII_EXTADV_1000FD 0x00000200
+#define GRETH_MII_EXTADV_1000HD 0x00000100
+#define GRETH_MII_EXTPRT_1000FD 0x00000800
+#define GRETH_MII_EXTPRT_1000HD 0x00000400
+
+#define GRETH_MII_100T4         0x00000200
+#define GRETH_MII_100TXFD       0x00000100
+#define GRETH_MII_100TXHD       0x00000080
+#define GRETH_MII_10FD          0x00000040
+#define GRETH_MII_10HD          0x00000020
+
+
+/* Attach routine */
+
+void greth_register_drv(void);
+
+/* PHY data */
+struct phy_device_info 
+{
+   int vendor;
+   int device;
+   int rev;
+   
+   int adv;
+   int part;
+
+   int extadv;
+   int extpart;
+};
+
+/*
+#ifdef CPU_U32_FIX
+void ipalign(struct mbuf *m);
+#endif
+
+*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/c/src/lib/libbsp/sparc/shared/include/grgpio.h b/c/src/lib/libbsp/sparc/shared/include/grgpio.h
new file mode 100644
index 0000000..8fcd1ff
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grgpio.h
@@ -0,0 +1,25 @@
+/*
+ *  GRGPIO GPIO Driver interface.
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GRGPIO_H__
+#define __GRGPIO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void grgpio_register_drv (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grpwm.h b/c/src/lib/libbsp/sparc/shared/include/grpwm.h
new file mode 100644
index 0000000..c0c2fdd
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grpwm.h
@@ -0,0 +1,127 @@
+/*
+ *  GRPWM PWM Driver interface.
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GRPWM_H__
+#define __GRPWM_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void grpwm_register_drv (void);
+
+#define GRPWM_IOCTL_GET_CAP	1	/* Get Capabilities */
+#define GRPWM_IOCTL_SET_CONFIG	2	/* Configure one PWM Channel */
+#define GRPWM_IOCTL_SET_SCALER	3	/* Set one scaler */
+#define GRPWM_IOCTL_UPDATE	4	/* Set current period and compare value */
+#define GRPWM_IOCTL_IRQ		5	/* Set up IRQ handling */
+
+/*** Argument for GRPWM_IOCTL_GET_CAP ***/
+
+/* The Capability of the PWM core */
+struct grpwm_ioctl_cap {
+	int		channel_cnt;	/* Number of channels */
+	unsigned int	pwm;		/* Capability1 register */
+	unsigned int	wave;		/* Capability2 register, Wave form capabilities of last PWM channel, otherwise 0 */
+};
+
+/*** Argument for GRPWM_IOCTL_GET_CONFIG and GRPWM_IOCTL_SET_CONFIG ***/
+
+/* Config One PWM */
+struct grpwm_ioctl_config {
+	unsigned int	channel;	/* Select channel to configure */
+
+	/* Specific for one PWM channel */
+	unsigned int	options;	/* PWM options */
+	unsigned char	dbscaler;	/* value greater than 15 disable Dead band */
+	unsigned char	scaler_index;	/* Select scaler used by PWM channel */
+
+	/* IRQ Setup */
+	unsigned char	irqscaler;	/* IRQ scaler */
+	void		*isr_arg;	/* Argument of IRQ handler */
+	void		(*isr)(int channel, void *arg);	/* Interrupt service routine for this PWM Channel */
+
+	/* Waveform set up */
+	int		wave_activate;		/* Enables Waveform functionality */
+	unsigned int	wave_synccfg;		/* Bits [29,30,31] is written into Wave-Config register */
+	unsigned int	wave_sync;		/* Sets sync compare register */
+	unsigned int	*wave_data;		/* If not NULL, the Wave RAM is filled with data */
+	unsigned int	wave_data_length;	/* Length of Wave RAM Data, Also used for wstopaddr */
+};
+
+#define GRPWM_CONFIG_OPTION_FLIP		0x04000000	/* Set this to Flip PWM output pair */
+#define GRPWM_CONFIG_OPTION_DEAD_BAND		0x00200000	/* Dead Band enable */
+#define GRPWM_CONFIG_OPTION_SYMMETRIC		0x00000040	/* If not defined, asymmetric */
+#define GRPWM_CONFIG_OPTION_ASYMMERTIC		0
+#define GRPWM_CONFIG_OPTION_DUAL		0x00000020	/* Dual Compare Enable */
+#define GRPWM_CONFIG_OPTION_PAIR		0x00000004	/* PWM Pair Enable */
+#define GRPWM_CONFIG_OPTION_SINGLE		0x00000000	/* PWM Pair Disable */
+#define GRPWM_CONFIG_OPTION_POLARITY_HIGH	0x00000002	/* PWM Polarity HIGH */
+#define GRPWM_CONFIG_OPTION_POLARITY_LOW	0x00000000	/* PWM Polarity LOW */
+
+#define GRPWM_CONFIG_OPTION_MASK ( \
+	GRPWM_CONFIG_OPTION_DEAD_BAND | GRPWM_CONFIG_OPTION_SYMMETRIC | \
+	GRPWM_CONFIG_OPTION_DUAL | GRPWM_CONFIG_OPTION_PAIR | \
+	GRPWM_CONFIG_OPTION_POLARITY_HIGH \
+	)
+
+/*** Argument for GPPWM_IOCTL_SET_SCALER ***/
+
+struct grpwm_ioctl_scaler {
+	unsigned int index_mask;/* Scaler update index mask, bit 0 = Scaler 0, bit 1 = Scaler 1 */
+	unsigned int values[8];	/* Scaler update values, values[N] is stored into scaler N, if mask & 1<<N is set */
+};
+
+/*** Argument for GRPWM_IOCTL_UPDATE ***/
+
+#define GRPWM_UPDATE_OPTION_ENABLE	0x01	/* Enable the PWM core */
+#define GRPWM_UPDATE_OPTION_DISABLE	0x02	/* Disable the PWM core */
+#define GRPWM_UPDATE_OPTION_PERIOD	0x04	/* Update period register */
+#define GRPWM_UPDATE_OPTION_COMP	0x08	/* Update Compare register */
+#define GRPWM_UPDATE_OPTION_DBCOMP	0x10	/* Update Dead band register */
+#define GRPWM_UPDATE_OPTION_FIX		0x20	/* Update fix output pins (bypass PWM) */
+
+/* FIX PIN bit-mask */
+#define GRPWM_UPDATE_FIX_ENABLE		1	/* Enable force ouput */
+#define GRPWM_UPDATE_FIX_DISABLE	0	/* Disable force ouput */
+#define GRPWM_UPDATE_FIX_0_LOW		0	/* PIN 0 OUPUT: LOW */
+#define GRPWM_UPDATE_FIX_0_HIGH		2	/* PIN 0 OUPUT: HIGH */
+#define GRPWM_UPDATE_FIX_1_LOW		0	/* PIN 1 OUPUT: LOW */
+#define GRPWM_UPDATE_FIX_1_HIGH		4	/* PIN 1 OUPUT: HIGH */
+
+struct grpwm_ioctl_update_chan {
+	unsigned int	options;	/* Select what is updated */
+	unsigned int	period;		/* Period register content */
+	unsigned int	compare;	/* Compare register content */
+	unsigned int	dbcomp;		/* Dead band register content */
+	unsigned char	fix;		/* Bit-mask that select output on one or two PWM
+					 * output pins. Depends on PAIR config value.
+					 */
+};
+struct grpwm_ioctl_update {
+	unsigned char			chanmask; /* Bit Mask select channels */
+	struct grpwm_ioctl_update_chan	channels[8]; /*  */
+};
+
+/*** Argument for GPPWM_IOCTL_IRQ ***/
+
+#define GRPWM_IRQ_DISABLE	0	/* Disable IRQ */
+#define GRPWM_IRQ_PERIOD	1	/* Enable IRQ on period match */
+#define GRPWM_IRQ_COMPARE	3	/* Enable IRQ on Compare Match */
+#define GRPWM_IRQ_CLEAR		0x10	/* Clear any pending IRQ on GRPWM and IRQ controller */
+
+#define GRPWM_IRQ_CHAN		0x100	/* Channel N is selected, by adding 0x100*N */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grslink.h b/c/src/lib/libbsp/sparc/shared/include/grslink.h
new file mode 100644
index 0000000..840cc0b
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grslink.h
@@ -0,0 +1,148 @@
+/*
+ * Header file for RTEMS GRSLINK SLINK master driver 
+ * 
+ * COPYRIGHT (c) 2009.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GRSLINK_H__
+#define __GRSLINK_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**** Configuration ****/
+/* Collect statistics ? */
+#define SLINK_COLLECT_STATISTICS
+
+/* Frequency of SLINK SCLK */
+#define SLINK_FREQ_HZ 6000000
+/* Number of queues used in driver */
+#define SLINK_NUMQUEUES 4
+
+/* The four values below are only used in the demo software */
+#define SLINK_CORE_REGBASE 0x80000600
+#define SLINK_CORE_IRQ 6
+#define IRQ_CNTRL_REG 0x80000200
+#define IRQ_CNTRL_MASK_OFFSET 0x40
+
+/* 
+ * Structure returned by SLINK_statistics if SLINK_COLLECT_STATISTCS has
+ * been defined
+ */
+typedef struct {
+	unsigned int parerr;     /* Number of parity errors */
+	unsigned int recov;      /* Number of receive overflows */
+	unsigned int reads;      /* Number of completed READs */
+	unsigned int writes;     /* Number of performed WRITES */
+	unsigned int sequences;  /* Number of started SEQUENCEs */
+	unsigned int seqcomp;    /* Number of completed SEQUENCEs */
+	unsigned int interrupts; /* Number of INTERRUPT transfers */
+	unsigned int lostwords;  /* Number of lost words due to full queue */
+} SLINK_stats;
+
+/**** SLINK status codes ****/
+#define SLINK_ABORTED   0
+#define SLINK_QFULL     1
+#define SLINK_ACTIVE    2
+#define SLINK_AMBAERR   3
+#define SLINK_COMPLETED 4
+#define SLINK_PARERR    5
+#define SLINK_ROV       6 /* Only used internally in driver */
+
+/**** SLINK master register fields *****/
+/* Control register */
+#define SLINK_C_SLEN_POS 16
+#define SLINK_C_SRO  (1 << 8)
+#define SLINK_C_SCN_POS 4
+#define SLINK_C_PAR  (1 << 3)
+#define SLINK_C_AS   (1 << 2)
+#define SLINK_C_SE   (1 << 1)
+#define SLINK_C_SLE  (1 << 0)
+
+/* Status register fields */
+#define SLINK_S_SI_POS 16
+#define SLINK_S_PERR (1 << 7)
+#define SLINK_S_AERR (1 << 6)
+#define SLINK_S_ROV  (1 << 5)
+#define SLINK_S_RNE  (1 << 4)
+#define SLINK_S_TNF  (1 << 3)
+#define SLINK_S_SC   (1 << 2)
+#define SLINK_S_SA   (1 << 1)
+#define SLINK_S_SRX  (1 << 0)
+
+/* Mask register fields */
+#define SLINK_M_PERRE (1 << 7)
+#define SLINK_M_AERRE (1 << 6)
+#define SLINK_M_ROVE  (1 << 5)
+#define SLINK_M_RNEE  (1 << 4)
+#define SLINK_M_TNFE  (1 << 3)
+#define SLINK_M_SCE   (1 << 2)
+#define SLINK_M_SAE   (1 << 1)
+#define SLINK_M_SRXE  (1 << 0)
+
+/**** Macros ****/
+/* Get channel field from received SLINK word */
+#define SLINK_WRD_CHAN(x) ((x >> 16) & 0xF)
+/* Get IO card # from received SLINK word */
+#define SLINK_WRD_CARDNUM(x) ((x >> 21) & 0x3)
+/* Get data part from SLINK word */
+#define SLINK_WRD_PAYLOAD(x) (x & 0xFFFF)
+
+/* Checks status value to see if transmit queue has free slot */
+#define SLINK_STS_TRANSFREE(x) (x & SLINK_S_TNF)
+/* Get Sequence Index value */
+#define SLINK_STS_SI(x) ((x >> 16) & 0xFF)
+
+/**** Function declarations, driver interface ****/
+/* Initializes the SLINK core */
+int SLINK_init(unsigned int nullwrd, int parity, int qsize,
+	       void (*interrupt_trans_handler)(int),
+	       void (*sequence_callback)(int));
+
+/* Enables the core */
+void SLINK_start(void);
+
+/* Disables the core */
+void SLINK_stop(void);
+
+/* Reads one word */
+int SLINK_read(int data, int channel, int *reply);
+
+/* Writes one word */
+int SLINK_write(int data, int channel);
+
+/* Peforms a SEQUENCE */
+int SLINK_seqstart(int *a, int *b, int n, int channel, int reconly);
+
+/* Aborts a SEQUENCE */
+void SLINK_seqabort(void);
+
+/* Status of current or last SEQUENCE */
+int SLINK_seqstatus(void);
+
+/* Number of words transferred in last SEQUENCE */
+int SLINK_seqwrds(void);
+
+/* Returns value of core's status register */
+int SLINK_hwstatus(void);
+
+/* Returns number of elements in queue associated with IO card */
+int SLINK_queuestatus(int iocard);
+
+/* Take first element from queue for IO card # 'iocard' */
+int SLINK_dequeue(int iocard, int *elem);
+
+/* Returns structure containing core driver statistics */
+SLINK_stats *SLINK_statistics(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRSLINK_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/grspw_router.h b/c/src/lib/libbsp/sparc/shared/include/grspw_router.h
new file mode 100644
index 0000000..c3b186f
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grspw_router.h
@@ -0,0 +1,104 @@
+/*
+ * GRSPW ROUTER APB-Register Driver.
+ * 
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GRSPW_ROUTER_H__
+#define __GRSPW_ROUTER_H__
+
+/* Hardware Information */
+struct router_hw_info {
+	unsigned char nports_spw;
+	unsigned char nports_amba;
+	unsigned char nports_fifo;
+	char timers_avail;
+	char pnp_avail;
+	unsigned char ver_major;
+	unsigned char ver_minor;
+	unsigned char ver_patch;
+	unsigned char iid;
+};
+
+#define ROUTER_FLG_CFG		0x01
+#define ROUTER_FLG_IID		0x02
+#define ROUTER_FLG_IDIV		0x04
+#define ROUTER_FLG_TPRES	0x08
+#define ROUTER_FLG_TRLD		0x10
+#define ROUTER_FLG_ALL		0x1f	/* All Above Flags */
+
+struct router_config {
+	unsigned int flags; /* Determine what configuration should be updated */
+
+	/* Router Configuration Register */
+	unsigned int config;
+
+	/* Set Instance ID */
+	unsigned char iid;
+
+	/* SpaceWire Link Initialization Clock Divisor */
+	unsigned char idiv;
+
+	/* Timer Prescaler and Reload */
+	unsigned int timer_prescaler;
+	unsigned int timer_reload[32];
+};
+
+/* Logical routing table */
+struct router_routes {
+	unsigned int route[224];
+};
+
+/* Port Setup, see register definitions for "Port setup register" */
+struct router_ps {
+	unsigned int ps[31]; /* Port Setup for ports 1-31 */
+	unsigned int ps_logical[224]; /* Port setup for locgical addresses 32-255 */
+};
+
+/* Set/Get Port Control/Status */
+#define ROUTER_PORTFLG_SET_CTRL	0x01
+#define ROUTER_PORTFLG_GET_CTRL	0x02
+#define ROUTER_PORTFLG_SET_STS	0x04
+#define ROUTER_PORTFLG_GET_STS	0x08
+struct router_port {
+	unsigned int flag;
+	int port;
+	unsigned int ctrl;
+	unsigned int sts;
+};
+
+/* Get Hardware support/information available */
+#define GRSPWR_IOCTL_HWINFO	0x01	/* OUT:    struct router_hw_info */
+
+/* Router Configuration */
+#define GRSPWR_IOCTL_CFG_SET	0x02	/* IN:     struct router_config */
+#define GRSPWR_IOCTL_CFG_GET	0x03	/* OUT:    struct router_config */
+
+/* Routes */
+#define GRSPWR_IOCTL_ROUTES_SET	0x04	/* IN:     struct router_routes */
+#define GRSPWR_IOCTL_ROUTES_GET	0x05	/* OUT:    struct router_routes */
+
+/* Port Setup */
+#define GRSPWR_IOCTL_PS_SET	0x06	/* IN:     struct router_ps */
+#define GRSPWR_IOCTL_PS_GET	0x07	/* OUT:    struct router_ps */
+
+/* Set configuration write enable */
+#define GRSPWR_IOCTL_WE_SET	0x08	/* INT:    int */
+
+/* Set/Get Port Control/Status */
+#define GRSPWR_IOCTL_PORT	0x09	/* IN/OUT: struct router_port */
+
+/* Set Router Configuration/Status Register */
+#define GRSPWR_IOCTL_CFGSTS_SET	0x0a	/* IN:     unsigned int */
+/* Get Router Configuration/Status Register */
+#define GRSPWR_IOCTL_CFGSTS_GET	0x0b	/* OUT:    unsigned int */
+
+/* Get Current Time-Code Register */
+#define GRSPWR_IOCTL_TC_GET	0x0c	/* OUT:    unsigned int */
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/grtc.h b/c/src/lib/libbsp/sparc/shared/include/grtc.h
new file mode 100644
index 0000000..ee1c806
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grtc.h
@@ -0,0 +1,152 @@
+/* GRTC Telecommand (TC) decoder driver interface
+ *
+ * COPYRIGHT (c) 2007.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GRTC_H__
+#define __GRTC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRTC_IOC_UNUSED			0
+
+/* Driver operation controlling commands */
+#define GRTC_IOC_START			1
+#define GRTC_IOC_STOP			2
+#define GRTC_IOC_ISSTARTED		3
+#define GRTC_IOC_SET_BLOCKING_MODE	4	/* Raw mode only */
+#define GRTC_IOC_SET_TIMEOUT		5	/* Raw mode only */
+
+#define GRTC_IOC_ADD_BUFF		16	/* Frame mode only */
+#define GRTC_IOC_RECV			17	/* Frame mode only */
+
+/* Available only in STOPPED mode */
+#define GRTC_IOC_SET_MODE		32	/* Set frame mode (ioctl) or raw mode (read) */
+#define GRTC_IOC_SET_BUF_PARAM		33
+#define GRTC_IOC_SET_CONFIG		34
+#define GRTC_IOC_POOLS_SETUP		35	/* Frame mode only */
+
+/* Available in both running and stopped mode */
+#define GRTC_IOC_GET_CONFIG		64
+#define GRTC_IOC_GET_BUF_PARAM		65
+#define GRTC_IOC_GET_HW_STATUS		66
+#define GRTC_IOC_ASSIGN_FRM_POOL	67
+#define GRTC_IOC_GET_CLCW_ADR		68	/* Get address of CLCWRx1 */
+#define GRTC_IOC_GET_STATS		69	/* Get statistics, note that most of the stats are only avilable in FRAME mode */
+#define GRTC_IOC_CLR_STATS		70	/* Clear statistics */
+
+/* Available only in RUNNING mode */
+
+/* Args to GRTC_IOC_GET_BUF_PARAMS */
+#define GRTC_BUF_MAXLEN (0x100*1024)
+#define GRTC_BUF_MASK 0xfffffc00
+struct grtc_ioc_buf_params {
+	unsigned int	length;		/* Length of new buffer in multiples of 1kbyte blocks */
+	void		*custom_buffer;	/* If set zero driver will allocate with malloc, set LSB to 1 to indicate remote address */
+};
+
+/* Args to GRTC_IOC_SET_BLOCKING_MODE */
+enum {
+	GRTC_BLKMODE_POLL	= 0,	/* Never block (polling mode) */
+	GRTC_BLKMODE_BLK	= 1,	/* Block until at least 1 byte can be read */
+	GRTC_BLKMODE_COMPLETE	= 2	/* Block until all data requested has be read */
+};
+
+/* Argument of GRTC_IOC_SET_CONFIG and GRTC_IOC_GET_CONFIG 
+ * Pointer to:
+ */
+struct grtc_ioc_config {
+	int		psr_enable;
+	int		nrzm_enable;
+	int		pss_enable;
+	int		crc_calc;	/* Enable Software CRC calculation (only Frame mode) */
+};
+
+/* Argument of GRTC_IOC_GET_HW_STATUS:
+ * Pointer to a grtc_ioc_hw_status structure that will be filled
+ * in by driver.
+ */
+struct grtc_ioc_hw_status {
+	unsigned int	sir;
+	unsigned int	far;
+	unsigned int	clcw1;
+	unsigned int	clcw2;
+	unsigned int	phir;
+	unsigned int	str;
+};
+
+struct grtc_hdr {
+	unsigned short	flags_scid;
+	unsigned short	vc_len;
+	unsigned char	seqnum;
+} __attribute__((packed));
+
+/* Frame pool, all frames in pool have the same buffer length (frame mode only) */
+struct grtc_frame {
+	struct grtc_frame	*next;		/* Next frame in list */
+	unsigned short		len;		/* Length of frame extracted */
+	unsigned short		reserved;	/* Reserved */
+	struct grtc_frame_pool	*pool;		/* The frame pool this frame belongs to */
+	
+	/* The Frame content */
+	struct grtc_hdr		hdr;		/* Primary Header */
+	unsigned char		data[3];	/* Frame payload */
+} __attribute__((packed));
+
+/* GRTC_IOC_RECV argument, single linked list of received frames */
+struct grtc_list {
+	struct grtc_frame	*head;		/* First frame in list */
+	struct grtc_frame	*tail;		/* Last frame in list */
+	int			cnt;		/* Number of frames in list */
+};
+
+struct grtc_ioc_pools_setup {
+	unsigned int	pool_cnt;		/* Number of pools */
+	unsigned int	pool_frame_len[1];	/* Array of 'pool_cnt' length: Frame length of frames in a pool 
+						 * Lengths must be sorted, starting with the smallest frame pool.
+						 */
+};
+
+struct grtc_ioc_assign_frm_pool {
+	unsigned int		frame_len;	/* The length of the pool to insert the frame into */
+	struct grtc_frame	*frames;	/* Frames to assign to a pool */
+};
+
+enum {
+	GRTC_MODE_RAW   = 0,
+	GRTC_MODE_FRAME = 1
+};
+
+/* TC driver stats collected during receiving. The statistics is only available 
+ * in FRAME mode. In RAW mode the user interprets the incoming frames and is 
+ * therefore responsible for generating the staticstics.
+ */
+struct grtc_ioc_stats {
+	unsigned long long	frames_recv;		/* Total number of non-erroneous frames received */
+	/* Errors related to incoming data */
+	unsigned int		err;			/* total number of errors */
+	unsigned int		err_hdr;		/* number of errors in Header */
+	unsigned int		err_payload;		/* Number of errors in payload */
+	unsigned int		err_ending;		/* Number of errors in end (Filler, end marker) */
+	unsigned int		err_abandoned;		/* Number of abandoned frames, NOT IMPLEMENTED */
+	/* Errors related to the handling of incoming frames */
+	unsigned int		dropped;		/* Number of dropped frames TC driver */
+	unsigned int		dropped_no_buf;		/* Number of dropped frame caused by no buffers were available */
+	unsigned int		dropped_too_long;	/* Number of dropped frames that was larger than any buffer available for driver */
+};
+
+/* Register GRTC driver at driver manager */
+void grtc_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRTC_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/grtm.h b/c/src/lib/libbsp/sparc/shared/include/grtm.h
new file mode 100644
index 0000000..c2cf9ef
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grtm.h
@@ -0,0 +1,241 @@
+/* GRTM Telemetry (TM) driver interface
+ * 
+ * COPYRIGHT (c) 2007.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __GRTM_H__
+#define __GRTM_H__
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRTM_IOC_UNUSED			0
+
+/* Driver operation controlling commands */
+#define GRTM_IOC_START			1
+#define GRTM_IOC_STOP			2
+#define GRTM_IOC_ISSTARTED		3
+#define GRTM_IOC_SET_BLOCKING_MODE	4
+#define GRTM_IOC_SET_TIMEOUT		5
+
+/* Available only in STOPPED mode */
+#define GRTM_IOC_SET_CONFIG		32
+
+/* Available in both running and stopped mode */
+#define GRTM_IOC_RECLAIM		64
+#define GRTM_IOC_GET_CONFIG		65
+#define GRTM_IOC_GET_HW_IMPL		66
+#define GRTM_IOC_GET_HW_STATUS		67	/* Not implemented */
+#define GRTM_IOC_GET_OCFREG		68
+#define GRTM_IOC_GET_STATS		69
+#define GRTM_IOC_CLR_STATS		70
+
+/* Available only in RUNNING mode */
+#define GRTM_IOC_SEND			96
+
+/* Args to GRTC_IOC_SET_BLOCKING_MODE */
+enum {
+	GRTM_BLKMODE_POLL	= 0,	/* Never block (polling mode) */
+	GRTM_BLKMODE_BLK	= 1,	/* Block until at least 1 byte can be read */
+};
+
+/* Reed Solomon Encoder implemented */
+enum {
+	GRTM_RS_IMPL_NONE	= 0,
+	GRTM_RS_IMPL_E16	= 1,	/* E16 */
+	GRTM_RS_IMPL_E8		= 2,	/* E8 */
+	GRTM_RS_IMPL_BOTH	= 3	/* Both E8 and E16 */
+
+};
+
+struct grtm_ioc_hw {
+	char		cs;		/* Sub Carrier */
+	char		sp;		/* Split-Phase Level */
+	char		ce;
+	char		nrz;
+	char		psr;
+	char		te;
+	unsigned char	rsdep;
+	unsigned char	rs;
+	char		aasm;
+	char		fecf;
+	char		ocf;
+	char		evc;
+	char		idle;
+	char		fsh;
+	char		mcg;
+	char		iz;
+	char		fhec;
+	char		aos;
+	char		cif;
+	char		ocfb;
+	
+	unsigned short	blk_size;	/* Block Size */
+	unsigned short	fifo_size;	/* FIFO Size */
+	
+};
+
+/* Driver Mode */
+enum {
+	GRTM_MODE_TM		= 0,	/* TM */
+	GRTM_MODE_AOS		= 1	/* AOS */
+};
+
+/* Physical layer Options */
+#define GRTM_IOC_PHY_SCF	(1<<15)		/* Sub Carrier Fall */
+#define GRTM_IOC_PHY_SF		(1<<31)		/* Symbol Fall */
+
+/* Coding Sub-layer Options */
+#define GRTM_IOC_CODE_SC	(1<<0)		/* Enable Sub Carrier modulation */
+#define GRTM_IOC_CODE_SP	(1<<1)		/* Enable Split-Phase (SP) level modulation */
+#define GRTM_IOC_CODE_CE	(1<<5)		/* Enable Convolutional Encoding */
+#define GRTM_IOC_CODE_NRZ	(1<<6)		/* Enable Non-Return-to-Zero mark encoding */
+#define GRTM_IOC_CODE_PSR	(1<<7)		/* Enable Pseudo-Randomizer */
+#define GRTM_IOC_CODE_RS8	(1<<11)		/* Reed-solomon Encoder to use: 0=E16, 1=E8 */
+#define GRTM_IOC_CODE_RS	(1<<15)		/* Enable Reed-Solomon Encoder */
+#define GRTM_IOC_CODE_AASM	(1<<16)		/* Enable Alternative attached synchronization marker */
+#define GRTM_IOC_CODE_ALL	(GRTM_IOC_CODE_SC|GRTM_IOC_CODE_SP|GRTM_IOC_CODE_CE| \
+				GRTM_IOC_CODE_NRZ|GRTM_IOC_CODE_PSR|GRTM_IOC_CODE_RS8|\
+				GRTM_IOC_CODE_RS|GRTM_IOC_CODE_AASM)
+
+enum {
+	GRTM_CERATE_00		= 0,	/* Rate 1/2, no puncturing */
+	GRTM_CERATE_02		= 2,	/* Rate 1/2, punctured */
+	GRTM_CERATE_04		= 4,	/* Rate 2/3, punctured */
+	GRTM_CERATE_05		= 5,	/* Rate 3/4, punctured */
+	GRTM_CERATE_06		= 6,	/* Rate 5/6, punctured */
+	GRTM_CERATE_07		= 7,	/* Rate 7/8, punctured */
+};
+
+/* Options for Generating all frames */
+#define GRTM_IOC_ALL_FHEC	0x01	/* Enable Frame Header Error Control (Only AOS) */
+#define GRTM_IOC_ALL_FECF	0x02	/* Enable Transfer Frame CRC */
+#define GRTM_IOC_ALL_IZ		0x04	/* Enable Insert Zone */
+#define GRTM_IOC_ALL_ALL	(GRTM_IOC_ALL_FHEC|GRTM_IOC_ALL_FECF|GRTM_IOC_ALL_IZ)
+
+/* Master Frame Generation Options */
+#define GRTM_IOC_MF_OW		0x01	/* Over Write OCF bits 16 and 17 */
+#define GRTM_IOC_MF_OCF		0x02	/* Enable Operation Control Field (OCF) for master channel */
+#define GRTM_IOC_MF_FSH		0x04	/* Enable MC_FSH for master channel */
+#define GRTM_IOC_MF_MC		0x08	/* Enable Master channel counter generation */
+#define GRTM_IOC_MF_ALL		(GRTM_IOC_MF_OW|GRTM_IOC_MF_OCF|GRTM_IOC_MF_FSH|GRTM_IOC_MF_MC)
+
+/* Idle Frames Generation Options */
+#define GRTM_IOC_IDLE_MC 	0x01	/* Enable Master Channel (MC) counter generation (TM Only) */
+#define GRTM_IOC_IDLE_VCC	0x02	/* Enable Virtual Channel counter cycle generation (AOS Only)*/
+#define GRTM_IOC_IDLE_FSH	0x04	/* Enable Frame Secondary Header (FSH) for idle frames (TM Only) */
+#define GRTM_IOC_IDLE_EVC	0x08	/* Enable Extended Virtual Channel Counter Generation */
+#define GRTM_IOC_IDLE_OCF	0x10	/* Enable OCF/CLCW in idle frame */
+#define GRTM_IOC_IDLE_EN	0x20	/* Enable Idle frame generation */
+#define GRTM_IOC_IDLE_ALL	(GRTM_IOC_IDLE_MC|GRTM_IOC_IDLE_VCC|GRTM_IOC_IDLE_FSH| \
+				GRTM_IOC_IDLE_EVC|GRTM_IOC_IDLE_OCF|GRTM_IOC_IDLE_EN)
+
+/* Argument of GRTM_IOC_SET_CONFIG and GRTM_IOC_GET_CONFIG.
+ * Driver and Hardware configuration.
+ *
+ * Pointer to:
+ */
+struct grtm_ioc_config {
+
+	/* Mode AOS or TM */
+	unsigned char	mode;		/* 0=TM, 1=AOS */
+
+	unsigned short	frame_length;	/* Length of every frame transmitted */
+	unsigned short	limit;		/* Number of data bytes fetched by DMA before transmission starts */
+	unsigned int	as_marker;	/* Attached Synchronization Marker */
+	
+	/* Physical layer options */
+	unsigned short	phy_subrate;	/* Sub Carrier rate - sub carrier devision factor - 1 */
+	unsigned short	phy_symbolrate;	/* Symbol Rate division factor - 1 */
+	unsigned char	phy_opts;	/* Mask of GRTM_IOC_PHY_XXXX */
+
+	/* Coding sub-layer Options */
+	unsigned char	code_rsdep;	/* Coding sub-layer Reed-Solomon interleave depth (3-bit) */
+	unsigned char	code_ce_rate;	/* Convolutional encoding rate, select one of GRTM_CERATE_00 ... GRTM_CERATE_07 */
+	unsigned char	code_csel;	/*   */
+	unsigned int	code_opts;	/* Mask of GRTM_IOC_CODE_XXXX */
+
+	/* All Frames Generation */
+	unsigned char	all_izlen;	/* FSH/IZ Length (5-bit) */
+	unsigned char	all_opts;	/* Mask of GRTM_IOC_ALL_XXXX */
+
+	/* Master Frame Generation */
+	unsigned char	mf_opts;	/* Mask of GRTM_IOC_MF_XXXX */
+
+	/* Idle frame Generation */
+	unsigned short	idle_scid;
+	unsigned char	idle_vcid;
+	unsigned char	idle_opts;	/* Mask of GRTM_IOC_IDLE_XXXX */
+
+	/* Interrupt options */
+	unsigned int	enable_cnt;	/* Number of frames in between Interrupt is generated, Zero disables interrupt */
+	int		isr_desc_proc;	/* Enable ISR to process descriptors */
+	int		blocking;	/* Blocking mode select (POLL,BLK..) */
+	rtems_interval	timeout;	/* Blocking mode timeout */
+};
+
+struct grtm_frame;
+
+struct grtm_list {
+	struct grtm_frame *head;	/* First Frame in list */
+	struct grtm_frame *tail;	/* Last Frame in list */
+};
+
+#define GRTM_FLAGS_SENT		0x01
+#define GRRM_FLAGS_ERR		0x02
+
+#define GRTM_FLAGS_TRANSLATE	(1<<31)	/* Translate frame payload address from CPU address to remote bus (the bus GRTM is resident on) */
+#define GRTM_FLAGS_TRANSLATE_AND_REMEMBER	(1<<30) /* As GRTM_FLAGS_TRANSLATE, however if the translated payload address equals the payload address
+							 * the GRTM_FLAGS_TRANSLATE_AND_REMEMBER bit is cleared and the GRTM_FLAGS_TRANSLATE bit is set */
+#define GRTM_FLAGS_COPY_DATA	(1<<29)	/* Where available: Transfer Frame payload to target, may be used for SpaceWire, where the GRTM driver transfer 
+					 * the payload to a buffer on the SpaceWire target. 
+					 */
+
+#define GRTM_FLAGS_TS		(1<<9)
+#define GRTM_FLAGS_MCB		(1<<8)
+#define GRTM_FLAGS_FSHB		(1<<7)
+#define GRTM_FLAGS_OCFB		(1<<6)
+#define GRTM_FLAGS_FHECB	(1<<5)
+#define GRTM_FLAGS_IZB		(1<<4)
+#define GRTM_FLAGS_FECFB	(1<<3)
+
+#define GRTM_FLAGS_MASK		(GRTM_FLAGS_TS|GRTM_FLAGS_MCB|GRTM_FLAGS_FSHB|\
+				 GRTM_FLAGS_OCFB|GRTM_FLAGS_FHECB|GRTM_FLAGS_IZB|\
+				 GRTM_FLAGS_FECFB)
+
+/* The GRTM software representation of a Frame */
+struct grtm_frame {
+	/* Options and status */
+	unsigned int		flags;		/* bypass options, and sent/error status */
+	
+	struct grtm_frame	*next;		/* Next packet in chain */
+
+	unsigned int		*payload;	/* The Headers and Payload,  Frame data and header must be word aligned */
+};
+
+#define FRAME_SIZE(payloadlen)	(sizeof(struct grtm_frame)+payloadlen)
+
+struct grtm_ioc_stats {
+	unsigned long long	frames_sent;
+	unsigned int		err_underrun;
+	unsigned int		err_tx;
+	unsigned int		err_ahb;
+	unsigned int		err_transfer_frame;
+};
+
+/* Register GRTM driver at driver manager */
+void grtm_register_drv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRTM_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/satcan.h b/c/src/lib/libbsp/sparc/shared/include/satcan.h
new file mode 100644
index 0000000..3f2f0c4
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/satcan.h
@@ -0,0 +1,142 @@
+/*
+ * Header file for RTEMS SATCAN FPGA driver
+ *
+ * COPYRIGHT (c) 2009.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __SATCAN_H__
+#define __SATCAN_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Config structure passed to SatCAN_init(..) */
+typedef struct {
+	/* Configuration */
+	int nodeno;
+	int dps;
+	/* Callback functions */
+	void (*ahb_irq_callback)(void);
+	void (*pps_irq_callback)(void);
+	void (*m5_irq_callback)(void);
+	void (*m4_irq_callback)(void);
+	void (*m3_irq_callback)(void);
+	void (*m2_irq_callback)(void);
+	void (*m1_irq_callback)(void);
+	void (*sync_irq_callback)(void);
+	void (*can_irq_callback)(unsigned int fifo);
+} satcan_config;
+
+#define SATCAN_HEADER_SIZE    4
+#define SATCAN_HEADER_NMM_POS 3
+#define SATCAN_PAYLOAD_SIZE   8
+
+/* SatCAN message */
+typedef struct {
+	unsigned char header[SATCAN_HEADER_SIZE];   /* Header of SatCAN message */
+	unsigned char payload[SATCAN_PAYLOAD_SIZE]; /* Payload of SatCAN message */
+} satcan_msg;
+
+/* SatCAN modify register structure */
+typedef struct {
+	unsigned int reg;
+	unsigned int val;
+} satcan_regmod;
+
+/* Driver interface */
+int satcan_register(satcan_config *conf);
+
+/* SatCAN interrupt IDs */
+#define SATCAN_IRQ_NONACT_TO_ACT    0
+#define SATCAN_IRQ_ACTIVE_TO_NONACT 1
+#define SATCAN_IRQ_STR1_TO_DPS      2
+#define SATCAN_IRQ_DPS_TO_STR1      3
+#define SATCAN_IRQ_STR2_TO_DPS      4
+#define SATCAN_IRQ_DPS_TO_STR2      5
+#define SATCAN_IRQ_STR3_TO_DPS      6
+#define SATCAN_IRQ_DPS_TO_STR3      7
+#define SATCAN_IRQ_PLD1_TO_DPS      8
+#define SATCAN_IRQ_DPS_TO_PLD1      9
+#define SATCAN_IRQ_PLD2_TO_DPS      10
+#define SATCAN_IRQ_DPS_TO_PLD2      11
+#define SATCAN_IRQ_SYNC             16
+#define SATCAN_IRQ_TIME_MARKER1     17
+#define SATCAN_IRQ_TIME_MARKER2     18
+#define SATCAN_IRQ_TIME_MARKER3     19
+#define SATCAN_IRQ_TIME_MARKER4     20
+#define SATCAN_IRQ_TIME_MARKER5     21
+#define SATCAN_IRQ_EOD1             22
+#define SATCAN_IRQ_EOD2             23
+#define SATCAN_IRQ_TOD              24
+#define SATCAN_IRQ_CRITICAL         25
+
+/* IOC */
+#define SATCAN_IOC_DMA_2K           1  /* Use DMA area for 2K messages */
+#define SATCAN_IOC_DMA_8K           2  /* Use DMA area for 8K messages */
+#define SATCAN_IOC_GET_REG          3  /* Provides direct read access to all core registers */
+#define SATCAN_IOC_SET_REG          4  /* Provides direct write access to all core registers */
+#define SATCAN_IOC_OR_REG           5  /* Provides direct read access to all core registers */
+#define SATCAN_IOC_AND_REG          6  /* Provides direct write access to all core registers */
+#define SATCAN_IOC_EN_TX1_DIS_TX2   7  /* Enable DMA TX channel 1, Disable DMA TX channel 2 */
+#define SATCAN_IOC_EN_TX2_DIS_TX1   8  /* Enable DMA TX channel 2, Disable DMA TX channel 1 */
+#define SATCAN_IOC_GET_DMA_MODE     9  /* Returns the current DMA mode */
+#define SATCAN_IOC_SET_DMA_MODE     10 /* Sets the DMA mode  */
+#define SATCAN_IOC_ACTIVATE_DMA     11 /* Directly activate DMA channel */
+#define SATCAN_IOC_DEACTIVATE_DMA   12 /* Directly deactivate DMA channel */
+#define SATCAN_IOC_DMA_STATUS       13 /* Returns status of directly activated DMA */
+#define SATCAN_IOC_GET_DOFFSET      14 /* Get TX DMA offset */ 
+#define SATCAN_IOC_SET_DOFFSET      15 /* Set TX DMA offset */
+#define SATCAN_IOC_GET_TIMEOUT      16 /* Set TX DMA timeout */
+#define SATCAN_IOC_SET_TIMEOUT      17 /* Get TX DMA timeout */
+
+
+/* Values used to select core register with IOC_SET_REG/IOC_GET_REG */ 
+#define SATCAN_SWRES        0  /* Software reset */
+#define SATCAN_INT_EN       1  /* Interrupt enable */
+#define SATCAN_FIFO         3  /* FIFO read */
+#define SATCAN_FIFO_RES     4  /* FIFO reset */
+#define SATCAN_TSTAMP       5  /* Current time stamp */
+#define SATCAN_CMD0         6  /* Command register 0 */
+#define SATCAN_CMD1         7  /* Command register 1 */
+#define SATCAN_START_CTC    8  /* Start cycle time counter */
+#define SATCAN_RAM_BASE     9  /* RAM offset address */
+#define SATCAN_STOP_CTC     10 /* Stop cycle time counter / DPS active status */
+#define SATCAN_DPS_ACT      10 /* Stop cycle time counter / DPS active status */
+#define SATCAN_PLL_RST      11 /* DPLL reset */
+#define SATCAN_PLL_CMD      12 /* DPLL command */
+#define SATCAN_PLL_STAT     13 /* DPLL status */
+#define SATCAN_PLL_OFF      14 /* DPLL offset */
+#define SATCAN_DMA          15 /* DMA channel enable */
+#define SATCAN_DMA_TX_1_CUR 16 /* DMA channel 1 TX current address */
+#define SATCAN_DMA_TX_1_END 17 /* DMA channel 1 TX end address */
+#define SATCAN_DMA_TX_2_CUR 18 /* DMA channel 2 TX current address */
+#define SATCAN_DMA_TX_2_END 19 /* DMA channel 2 TX end address */
+#define SATCAN_RX           20 /* CAN RX enable / Filter start ID */
+#define SATCAN_FILTER_START 20 /* CAN RX enable / Filter start ID */
+#define SATCAN_FILTER_SETUP 21 /* Filter setup / Filter stop ID */
+#define SATCAN_FILTER_STOP  21 /* Filter setup / Filter stop ID */
+#define SATCAN_WCTRL        32 /* Wrapper status/control register */
+#define SATCAN_WIPEND       33 /* Wrapper interrupt pending register */
+#define SATCAN_WIMASK       34 /* Wrapper interrupt mask register */
+#define SATCAN_WAHBADDR     35 /* Wrapper AHB address register */
+
+
+/* Values used to communicate DMA mode */
+#define SATCAN_DMA_MODE_USER   0
+#define SATCAN_DMA_MODE_SYSTEM 1
+
+/* Values used to directly activate DMA channel */
+#define SATCAN_DMA_ENABLE_TX1  1
+#define SATCAN_DMA_ENABLE_TX2  2
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SATCAN_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/include/spictrl.h b/c/src/lib/libbsp/sparc/shared/include/spictrl.h
new file mode 100644
index 0000000..aba6dcf
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/spictrl.h
@@ -0,0 +1,126 @@
+/*
+ *  SPICTRL SPI Driver interface.
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __SPICTRL_H__
+#define __SPICTRL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void spictrl_register_drv (void);
+
+/*** REGISTER LAYOUT ***/
+struct spictrl_regs {
+	volatile unsigned int capability;	/* 0x00 */
+	volatile unsigned int resv[7];		/* 0x04 */
+	volatile unsigned int mode;		/* 0x20 */
+	volatile unsigned int event;		/* 0x24 */
+	volatile unsigned int mask;		/* 0x28 */
+	volatile unsigned int command;		/* 0x2c */
+	volatile unsigned int tx;		/* 0x30 */
+	volatile unsigned int rx;		/* 0x34 */
+	volatile unsigned int slvsel;		/* 0x38 */
+	volatile unsigned int am_slvsel;	/* 0x3c */
+	volatile unsigned int am_cfg;		/* 0x40 */
+	volatile unsigned int am_period;	/* 0x44 */
+	int reserved0[2];
+	volatile unsigned int am_mask[4];	/* 0x50-0x5C */
+	int reserved1[(0x200-0x60)/4];
+	volatile unsigned int am_tx[128];	/* 0x200-0x3FC */
+	volatile unsigned int am_rx[128];	/* 0x400-0x5FC */
+};
+
+/* -- About automated periodic transfer mode --
+ *
+ * Core must support this feature.
+ *
+ * The SPI core must be configured in periodic mode before
+ * writing the data into the transfer FIFO which will be used
+ * mutiple times in different transfers, it will also make
+ * the receive FIFO to be updated.
+ *
+ * In periodic mode the following sequence is performed,
+ *   1. start()
+ *   2. ioctl(CONFIG, &config)    - Enable periodic mode
+ *   3. set_address()
+ *   4. write()                   - Fills TX FIFO, this has some constraints
+ *   5. ioctl(START)              - Starts the periodic transmission of the TX FIFO
+ *   6. read()                    - Read one response of the tranistted data. It will 
+ *                                  hang until data is available. If hanging is not an
+ *                                  options use ioctl(STATUS)
+ *   7. go back to 6.
+ *
+ *   8. ioctl(STOP)               - Stop to set up a new periodic or normal transfer
+ *   9. stop()
+ *
+ * Note that the the read length must equal the total write length.
+ */
+
+/* Custom SPICTRL driver ioctl commands */
+#define SPICTRL_IOCTL_PERIOD_START	5000	/* Start automated periodic transfer mode */
+#define SPICTRL_IOCTL_PERIOD_STOP	5001	/* Stop to SPI core from doing periodic transfers */
+#define SPICTRL_IOCTL_CONFIG		5002	/* Configure Periodic transfer mode (before calling write() and START) */
+#define SPICTRL_IOCTL_STATUS		5003	/* Get status */
+
+#define SPICTRL_IOCTL_PERIOD_READ	5005	/* Write transmit registers and mask register 
+						 * (only in automatic periodic mode) 
+						 * Note that it is probably prefferred to read
+						 * the received words using the read() using
+						 * operations instead.
+						 */
+#define SPICTRL_IOCTL_PERIOD_WRITE	5006	/* Read receive registers and mask register 
+						 * (only in automatic periodic mode) */
+#define SPICTRL_IOCTL_REGS		5007	/* Get SPICTRL Register */
+
+/* SPICTRL_IOCTL_CONFIG argument */
+struct spictrl_ioctl_config {
+	int		clock_gap;	/* Clock GAP between */
+	unsigned int	flags;		/* Normal mode flags */
+	int		periodic_mode;	/* 1=Enables Automated periodic transfers if supported by hardware */
+	unsigned int	period;		/* Number of clocks between automated transfers are started */
+	unsigned int	period_flags;	/* Options */
+	unsigned int	period_slvsel;	/* Slave Select when transfer is not active, default is 0xffffffff */
+};
+#define SPICTRL_FLAGS_TAC		0x10
+
+#define SPICTRL_PERIOD_FLAGS_ERPT	0x80	/* Trigger start-period from external signal */
+#define SPICTRL_PERIOD_FLAGS_SEQ	0x40
+#define SPICTRL_PERIOD_FLAGS_STRICT	0x20
+#define SPICTRL_PERIOD_FLAGS_OVTB	0x10
+#define SPICTRL_PERIOD_FLAGS_OVDB	0x08
+#define SPICTRL_PERIOD_FLAGS_ASEL	0x04
+#define SPICTRL_PERIOD_FLAGS_EACT	0x01
+
+/* SPICTRL_IOCTL_PERIOD_READ and SPICTRL_IOCTL_PERIOD_WRITE Argument data structure 
+ *
+ * Note that the order of reading the mask registers are different for read/write
+ *      operation. See options notes.
+ */
+struct spictrl_period_io {
+	int options;	/* READ: bit0=Read Mask Registers into masks[].
+			 *       bit1=Read Receive registers according to masks[]
+			 *            (after reading masks).
+			 *
+			 * WRITE: bit0=Update Mask accoring to masks[].
+			 *        bit1=Update Transmit registers according to masks[].
+			 *             (before reading masks)
+			 */
+	unsigned int masks[4];
+
+	void *data;	/* Data read sequentially according to masks[] bit. */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/spwcuc.h b/c/src/lib/libbsp/sparc/shared/include/spwcuc.h
new file mode 100644
index 0000000..dfef80e
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/spwcuc.h
@@ -0,0 +1,188 @@
+/*  SPWCUC - SpaceWire - CCSDS unsegmented Code Transfer Protocol GRLIB core
+ *  register driver interface.
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __SPWCUC_H__
+#define __SPWCUC_H__
+
+#define PKT_INIT_IRQ       0x1
+#define PKT_ERR_IRQ        0x2
+#define PKT_RX_IRQ         0x4
+#define WRAP_ERR_IRQ       0x8
+#define WRAP_IRQ           0x10
+#define SYNC_ERR_IRQ       0x20
+#define SYNC_IRQ           0x40
+#define TOL_ERR_IRQ        0x80
+#define TICK_RX_ERR_IRQ    0x100
+#define TICK_RX_WRAP_IRQ   0x200
+#define TICK_RX_IRQ        0x400
+#define TICK_TX_WRAP_IRQ   0x800
+#define TICK_TX_IRQ        0x1000
+
+/* SPWCUC Register layout */
+struct spwcuc_regs {
+	volatile unsigned int config;        /* 00 */
+	volatile unsigned int status;        /* 04 */
+	volatile unsigned int control;       /* 08 */
+	volatile unsigned int unused0;       /* 0c */
+	volatile unsigned int dla;           /* 10 */
+	volatile unsigned int pid;           /* 14 */
+	volatile unsigned int offset;        /* 18 */
+	volatile unsigned int unused1;       /* 1c */
+	volatile unsigned int pkt_ct;        /* 20 */
+	volatile unsigned int pkt_ft;        /* 24 */   
+	volatile unsigned int pkt_pf_crc;    /* 28 */
+	volatile unsigned int unused2;       /* 2c */
+	volatile unsigned int etct;          /* 30 */
+	volatile unsigned int etft;          /* 34 */
+	volatile unsigned int etct_next;     /* 38 */
+	volatile unsigned int etft_next;     /* 3c */
+	volatile unsigned int unused3[8];    /* 40-5c */
+	volatile unsigned int pimsr;         /* 60 */
+	volatile unsigned int pimr;          /* 64 */
+	volatile unsigned int pisr;          /* 68 */
+	volatile unsigned int pir;           /* 6c */
+	volatile unsigned int imr;           /* 70 */
+	volatile unsigned int picr;          /* 74 */
+};
+
+struct spwcuc_cfg {
+	unsigned char sel_out;         /* Bits 3-0 enable time code transmission on respective output */
+	unsigned char sel_in;          /* Select SpW to receive time codes on, 0-3 */
+	unsigned char mapping;         /* Define mapping of time code time info into T-field, 0-31 */
+	unsigned char tolerance;       /* Define SpaceWire time code reception tolerance, 0-31 */
+	unsigned char tid;             /* Define CUC P-Field time code identification, 1 = Level 1, 2 = Level 2 */
+	unsigned char ctf;             /* If 1 check time code flags to be all zero */
+	unsigned char cp;              /* If 1 check P-Field time code id against tid */
+
+	unsigned char txen;            /* Enable SpaceWire time code transmission */
+	unsigned char rxen;            /* Enable SpaceWire time code reception */
+	unsigned char pktsyncen;       /* Enable SpaceWire time CUC packet sync */
+	unsigned char pktiniten;       /* Enable SpaceWire time CUC packet init */
+	unsigned char pktrxen;         /* Enable SpaceWire time CUC packet reception */
+
+	unsigned char dla;             /* SpaceWire destination logical address */ 
+	unsigned char dla_mask;        /* SpaceWire destination logical address mask */ 
+	unsigned char pid;             /* SpaceWire protocol ID */
+	
+	unsigned int offset;           /* Packet reception offset */
+};
+
+/* SPWCUC Statistics gathered by driver */
+struct spwcuc_stats {
+
+	/* IRQ Stats */
+	unsigned int nirqs;
+	unsigned int tick_tx;
+	unsigned int tick_tx_wrap;
+	unsigned int tick_rx;
+	unsigned int tick_rx_wrap;
+	unsigned int tick_rx_error;
+	unsigned int tolerr;
+	unsigned int sync;
+	unsigned int syncerr;
+	unsigned int wrap;
+	unsigned int wraperr;
+	unsigned int pkt_rx;
+	unsigned int pkt_err;
+	unsigned int pkt_init;
+};
+
+/* Function ISR callback prototype
+ *
+ * pimr    - PIMR/PIR register of the SPWCUC core read by ISR
+ * data    - Custom data provided by user
+ */
+typedef void (*spwcuc_isr_t)(unsigned int pimr, void *data);
+
+/* Open a SPWCUC device by minor number. A SPWCUC device can only by opened
+ * once. The handle returned must be used as the input parameter 'spwcuc' in 
+ * the rest of the calls in the function interface.
+ */
+extern void *spwcuc_open(int minor);
+
+/* Close a previously opened SPWCUC device */
+extern void spwcuc_close(void *spwcuc);
+
+/* Reset SPWCUC Core */
+extern int spwcuc_reset(void *spwcuc);
+
+/* Enable Interrupts at Interrupt controller */
+extern void spwcuc_int_enable(void *spwcuc);
+
+/* Disable Interrupts at Interrupt controller */
+extern void spwcuc_int_disable(void *spwcuc);
+
+/* Clear Statistics gathered by the driver */
+extern void spwcuc_clr_stats(void *spwcuc);
+
+/* Get Statistics gathered by the driver. The statistics are stored into
+ * the location pointed to by 'stats'.
+ */
+extern void spwcuc_get_stats(void *spwcuc, struct spwcuc_stats *stats);
+
+/* Register an Interrupt handler and custom data, the function call is
+ * removed by setting func to NULL.
+ *
+ * The driver's interrupt handler is installed on open(), however the user
+ * callback called from the driver's ISR is installed using this function.
+ */
+extern void spwcuc_int_register(void *spwcuc, spwcuc_isr_t func, void *data);
+
+/* Configure the spwcuc core. The configuration is taken from the data
+ * structure pointed to by 'cfg'. See data structure spwcuc_cfg fields.
+ */
+extern void spwcuc_config(void *spwcuc, struct spwcuc_cfg *cfg);
+
+/* Return elapsed coarse time */
+extern unsigned int spwcuc_get_et_coarse(void *spwcuc);
+
+/* Return elapsed fine time */
+extern unsigned int spwcuc_get_et_fine(void *spwcuc);
+
+/* Return elapsed time (coarse and fine) 64-bit value */
+extern unsigned long long spwcuc_get_et(void *spwcuc);
+
+/* Return next elapsed coarse time (for use when sending SpW time packet) */
+extern unsigned int spwcuc_get_next_et_coarse(void *spwcuc);
+
+/* Return next elapsed fine time (for use when sending SpW time packet) */
+extern unsigned int spwcuc_get_next_et_fine(void *spwcuc);
+
+/* Return next elapsed time (for use when sending SpW time packet) */
+extern unsigned long long spwcuc_get_next_et(void *spwcuc);
+
+/* Force/Set the elapsed time (coarse 32-bit and fine 24-bit) by writing the
+ * T-Field Time Packet Registers then the FORCE bit.
+ */
+extern void spwcuc_force_et(void *spwcuc, unsigned long long time);
+
+/* Return received (from time packet) elapsed coarse time */
+extern unsigned int spwcuc_get_tp_et_coarse(void *spwcuc);
+
+/* Return received (from time packet) elapsed fine time */
+extern unsigned int spwcuc_get_tp_et_fine(void *spwcuc);
+
+/* Return received (from time packet) elapsed time (coarse and fine) */
+extern unsigned long long spwcuc_get_tp_et(void *spwcuc);
+
+/* Clear interrupts */
+extern void spwcuc_clear_irqs(void *spwcuc, int irqs);
+
+/* Enable interrupts */
+extern void spwcuc_enable_irqs(void *spwcuc, int irqs);
+
+/* Get Register */
+extern struct spwcuc_regs *spwcuc_get_regs(void *spwcuc);
+
+/* Register the SPWCUC Driver to the Driver Manager */
+extern void spwcuc_register(void);
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/irq/genirq.c b/c/src/lib/libbsp/sparc/shared/irq/genirq.c
new file mode 100644
index 0000000..782ebf8
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/irq/genirq.c
@@ -0,0 +1,241 @@
+/*
+ * Generic interrupt helpers mainly for GRLIB PCI peripherals
+ * 
+ * COPYRIGHT (c) 2008.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <string.h>
+#include <genirq.h>
+
+struct genirq_handler_entry {
+	struct genirq_handler_entry	*next;		/* Next ISR entry for this IRQ number */
+	genirq_handler			isr;		/* ISR function called upon IRQ */
+	void				*arg;		/* custom argument to ISR */
+	int				enabled;	/* Inidicates if IRQ is enabled */
+};
+
+struct genirq_irq_entry {
+	struct genirq_handler_entry	*head;
+	struct genirq_stats		stats;
+};
+
+struct genirq_priv {
+	/* Maximum number of interrupt */
+	int				genirq_max;
+	/* IRQ Table index N reflect IRQ number N */
+	struct genirq_irq_entry		genirq_table[1]; /* Length depends on */
+};
+
+genirq_t genirq_init(int number_of_irqs)
+{
+	int size;
+	struct genirq_priv *priv;
+
+	size = sizeof(int) +
+	       number_of_irqs * sizeof(struct genirq_irq_entry);
+
+	priv = (struct genirq_priv *)malloc(size);
+	if ( !priv )
+		return NULL;
+	memset(priv, 0, size);
+	priv->genirq_max = number_of_irqs - 1;
+	return priv;
+}
+
+void genirq_destroy(genirq_t d)
+{
+	struct genirq_priv *priv = d;
+	struct genirq_irq_entry *irqentry;
+	struct genirq_handler_entry *isrentry, *tmp;
+	int i;
+
+	/* Free all registered interrupts */
+	for ( i=0; i<priv->genirq_max; i++) {
+		irqentry = &priv->genirq_table[i];
+		isrentry = irqentry->head;
+		while ( isrentry ) {
+			tmp = isrentry;
+			isrentry = isrentry->next;
+			free(tmp);
+		}
+	}
+
+	free(priv);
+}
+
+int genirq_check(genirq_t d, int irq)
+{
+	struct genirq_priv *priv = d;
+
+	if ( (irq <= 0) || (irq > priv->genirq_max) )
+		return -1;
+	else
+		return 0;
+}
+
+int genirq_register(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+	struct genirq_priv *priv = d;
+	struct genirq_irq_entry *irqentry;
+	struct genirq_handler_entry *isrentry, *newentry;
+	rtems_interrupt_level level;
+	
+	if ( genirq_check(d, irq) )
+		return -1;
+
+	newentry = malloc(sizeof(*newentry));
+	if ( !newentry )
+		return -1;
+
+	/* Initialize ISR entry */
+	newentry->isr     = isr;
+	newentry->arg     = arg;
+	newentry->enabled = 0;
+
+	rtems_interrupt_disable(level);
+
+	/* Insert new ISR entry first into table */
+	irqentry = &priv->genirq_table[irq];
+	isrentry = irqentry->head;
+	irqentry->head = newentry;
+	newentry->next = isrentry;
+
+	rtems_interrupt_enable(level);
+
+	if ( isrentry )
+		return 1; /* This is the first handler on this IRQ */
+	return 0;
+}
+
+int genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+	struct genirq_priv *priv = d;
+	struct genirq_irq_entry *irqentry;
+	struct genirq_handler_entry *isrentry, **prev;
+	rtems_interrupt_level level;
+	int ret;
+
+	if ( genirq_check(d, irq) )
+		return -1;
+
+	/* Remove isr[arg] from ISR list */
+	irqentry = &priv->genirq_table[irq];
+	ret = -1;
+
+	rtems_interrupt_disable(level);
+
+	prev = &irqentry->head;
+	isrentry = irqentry->head;
+	while ( isrentry ) {
+		if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) {
+			/* Found ISR, remove it from list */
+			if ( isrentry->enabled ) {
+				/* Can not remove enabled ISRs, disable first */
+				ret = 1;
+				break;
+			}
+			*prev = isrentry->next;
+			ret = 0;
+			break;
+		}
+		prev = &isrentry->next;
+		isrentry = isrentry->next;
+	}
+
+	rtems_interrupt_enable(level);
+
+	return ret;
+}
+
+/* Enables or Disables ISR handler. Internal function to reduce footprint
+ * of enable/disable functions.
+ *
+ * \param action 1=enable, 0=disable ISR
+ */
+int genirq_set_active(struct genirq_priv *priv, int irq, genirq_handler isr, void *arg, int action)
+{
+	struct genirq_irq_entry *irqentry;
+	struct genirq_handler_entry *isrentry, *e = NULL;
+	int enabled;
+
+	if ( genirq_check(priv, irq) )
+		return -1;
+
+	/* Find isr[arg] in ISR list */
+	irqentry = &priv->genirq_table[irq];
+	enabled = 0;
+
+	isrentry = irqentry->head;
+	while ( isrentry ) {
+		if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) {
+			/* Found ISR */
+			if ( isrentry->enabled == action ) {
+				/* The ISR is already enabled or disabled 
+				 * depending on request, neccessary actions
+				 * were taken last time the same action was
+				 * requested.
+				 */
+				return 1;
+			}
+			e = isrentry;
+		} else {
+			enabled += isrentry->enabled;
+		}
+		isrentry = isrentry->next;
+	}
+
+	if ( !e )
+		return -1;
+
+	e->enabled = action;
+
+	return enabled;
+}
+
+int genirq_enable(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+	struct genirq_priv *priv = d;
+	return genirq_set_active(priv, irq, isr, arg, 1);
+}
+
+int genirq_disable(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+	struct genirq_priv *priv = d;
+	return genirq_set_active(priv, irq, isr, arg, 0);
+}
+
+void genirq_doirq(genirq_t d, int irq)
+{
+	struct genirq_priv *priv = d;
+	struct genirq_irq_entry *irqentry;
+	struct genirq_handler_entry *isrentry;
+	int enabled;
+
+	irqentry = &priv->genirq_table[irq];
+	irqentry->stats.irq_cnt++;
+	
+	enabled = 0;
+
+	isrentry = irqentry->head;
+	while ( isrentry ) {
+		if ( isrentry->enabled ) {
+			enabled = 1;
+			/* Call the ISR */
+			isrentry->isr(isrentry->arg);
+		}
+		isrentry = isrentry->next;
+	}
+
+	/* Was the IRQ an IRQ without source? */
+	if ( enabled == 0 ) {
+		/* This should not happen */
+		printk("Spurious IRQ happened on IRQ %d\n", irq);
+	}
+}
diff --git a/c/src/lib/libbsp/sparc/shared/mem/mctrl.c b/c/src/lib/libbsp/sparc/shared/mem/mctrl.c
new file mode 100644
index 0000000..b61d218
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/mem/mctrl.c
@@ -0,0 +1,210 @@
+/*  Memory Controller driver (FTMTRL, MCTRL)
+ * 
+ *  COPYRIGHT (c) 2008.
+ *  Cobham Gaisler AB.
+ *
+ *  This file contains the driver for the MCTRL memory controller.
+ *  The driver sets the memory configuration registers (MCFG1, MCFG2, MCFG3)
+ *  during driver initialization
+ *
+ *  The license and distribution terms for this file may be
+ *  found in found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+/******************* Driver manager interface ***********************/
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+
+#define MEMSET(priv, start, c, length) memset((void *)start, c, length)
+
+#define DBG(args...)
+/*#define DBG(args...) printk(args)*/
+
+struct mctrl_regs {
+	unsigned int	mcfg[8];
+};
+
+struct mctrl_priv;
+
+struct mctrl_ops {
+	void (*mcfg_set)(struct mctrl_priv *priv, int index, void *regs, unsigned int regval);
+};
+
+struct mctrl_priv {
+	struct drvmgr_dev	*dev;
+	void			*regs;
+	unsigned int		mcfg[8];	/* The wanted memory configuration */
+	unsigned int		configured;	/* Determines what mcfgs was configured by user */
+	struct mctrl_ops	*ops;		/* Operation may depend on hardware */
+};
+
+static int mctrl_init1(struct drvmgr_dev *dev);
+static int mctrl_remove(struct drvmgr_dev *dev);
+
+/* Standard MCFG registers */
+static void mctrl_set_std(struct mctrl_priv *priv, int index, void *regs, unsigned int regval);
+
+struct mctrl_ops std_mctrl_ops = 
+{
+	mctrl_set_std
+};
+
+struct drvmgr_drv_ops mctrl_ops = 
+{
+	.init = {mctrl_init1, NULL, NULL, NULL},
+	.remove = mctrl_remove,
+	.info = NULL
+};
+
+struct amba_dev_id mctrl_ids[] = 
+{
+	{VENDOR_ESA, ESA_MCTRL},
+	{VENDOR_GAISLER, GAISLER_FTMCTRL},
+	{VENDOR_GAISLER, GAISLER_FTSRCTRL},
+	{0, 0}		/* Mark end of table */
+};
+
+struct amba_drv_info mctrl_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,			/* Driver */
+		NULL,				/* Next driver */
+		NULL,				/* Device list */
+		DRIVER_AMBAPP_MCTRL_ID,		/* Driver ID */
+		"MCTRL_DRV",			/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,		/* Bus Type */
+		&mctrl_ops,
+		NULL,				/* Funcs */
+		0,				/* No devices yet */
+		0,
+	},
+	&mctrl_ids[0]
+};
+
+void mctrl_register_drv (void)
+{
+	DBG("Registering MCTRL driver\n");
+	drvmgr_drv_register(&mctrl_drv_info.general);
+}
+
+static int mctrl_init1(struct drvmgr_dev *dev)
+{
+	struct mctrl_priv *priv;
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	int i;
+	char res_name[16];
+	union drvmgr_key_value *value;
+	unsigned int start, length;
+
+	DBG("MCTRL[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+	priv = dev->priv = malloc(sizeof(struct mctrl_priv));
+	if ( !priv )
+		return DRVMGR_NOMEM;
+	memset(priv, 0, sizeof(*priv));
+	priv->dev = dev;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)priv->dev->businfo;
+	if ( ambadev == NULL ) {
+		return DRVMGR_FAIL;
+	}
+	pnpinfo = &ambadev->info;
+	if ( pnpinfo->apb_slv == NULL ) {
+		/* LEON2 PnP systems are missing the APB interface */
+		priv->regs = (void *)0x80000000;
+	} else {
+		priv->regs = (void *)pnpinfo->apb_slv->start;
+	}
+
+	/* Depending on Hardware selection write/read routines */
+	switch ( pnpinfo->vendor ) {
+		case VENDOR_ESA:
+		switch ( pnpinfo->device ) {
+			case ESA_MCTRL:
+			default:
+				priv->ops = &std_mctrl_ops;
+		}
+		break;
+
+		case VENDOR_GAISLER:
+		switch ( pnpinfo->device ) {
+			case GAISLER_FTMCTRL:
+			case GAISLER_FTSRCTRL:
+			default:
+				priv->ops = &std_mctrl_ops;
+		}
+		break;
+
+		default:
+		priv->ops = &std_mctrl_ops;
+		break;
+	}
+
+	/* Find user configuration from bus resources */
+	priv->configured = 0;
+	strcpy(res_name, "mcfgX");
+	for(i=0; i<8; i++) {
+		res_name[4] = '1' + i;
+		value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+		if ( value ) {
+			priv->mcfg[i] = value->i;
+			priv->configured |= (1<<i);
+		}
+	}
+
+	/* Init hardware registers right away, other devices may depend on it in init2(), also
+	 * the washing depend on it.
+	 */
+	for ( i=0; i<8; i++) {
+		if ( priv->configured & (1<<i) ) {
+			DBG("Setting MCFG%d to 0x%08x\n", i+1, priv->mcfg[i]);
+			priv->ops->mcfg_set(priv, i, priv->regs, priv->mcfg[i]);
+		}
+	}
+
+	/* Wash memory partitions if user wants */
+	for (i=0; i<9; i++) {
+		strcpy(res_name, "washXStart");
+		res_name[4] = '0' + i;
+		value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+		if ( value ) {
+			start = value->i;
+			strcpy(res_name, "washXLength");
+			res_name[4] = '0' + i;
+			value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT);
+			if ( value ) {
+				length = value->i;
+
+				if ( length > 0 ) {
+					DBG("MCTRL: Washing 0x%08x-0x%08x\n", start, start+length-1);
+
+					MEMSET(priv, (void *)start, 0, length);
+				}
+			}
+		}
+	}
+
+	return DRVMGR_OK;
+}
+
+static int mctrl_remove(struct drvmgr_dev *dev)
+{
+	/* Nothing to be done */
+	DBG("Removing %s\n", dev->name);
+	return DRVMGR_OK;
+}
+
+/* Standard Operations */
+static void mctrl_set_std(struct mctrl_priv *priv, int index, void *regs, unsigned int regval)
+{
+	struct mctrl_regs *pregs = regs;
+
+	/* Store new value */
+	pregs->mcfg[index] = regval;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/net/README b/c/src/lib/libbsp/sparc/shared/net/README
new file mode 100644
index 0000000..3ef086f
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/net/README
@@ -0,0 +1,7 @@
+A non Driver Manager GRETH driver is located in libchip/network/greth.c. This
+version requires the driver manager.
+
+network_interface_add is used to assign IP/NETMASK and MAC address to
+GRETH interfaces dynamically according to in which order devices are
+registered. The function takes the settings from the user defined
+interface_configs[] array, defined in the project configuration.
diff --git a/c/src/lib/libbsp/sparc/shared/net/greth.c b/c/src/lib/libbsp/sparc/shared/net/greth.c
new file mode 100644
index 0000000..31eeade
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/net/greth.c
@@ -0,0 +1,1424 @@
+/*
+ * Gaisler Research ethernet MAC driver
+ * adapted from Opencores driver by Marko Isomaki
+ *
+ *  The license and distribution terms for this file may be
+ *  found in found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ *
+ *
+ *  2008-12-10, Converted to driver manager and added support for
+ *              multiple GRETH cores. <daniel at gaisler.com>
+ *  2007-09-07, Ported GBIT support from 4.6.5
+ */
+#include <rtems.h>
+#define _KERNEL
+#define CPU_U32_FIX
+#include <bsp.h>
+
+#ifdef GRETH_SUPPORTED
+
+#include <inttypes.h>
+#include <errno.h>
+#include <rtems/bspIo.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <greth.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <ambapp.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#ifdef malloc
+#undef malloc
+#endif
+#ifdef free
+#undef free
+#endif
+
+#if defined(__m68k__)
+extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
+#else
+extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
+#endif
+
+
+/* #define GRETH_DEBUG */
+
+#ifdef GRETH_DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...)
+#endif
+
+#ifdef CPU_U32_FIX
+extern void ipalign(struct mbuf *m);
+#endif
+
+/* Used when reading from memory written by GRETH DMA unit */
+#ifndef GRETH_MEM_LOAD
+#define GRETH_MEM_LOAD(addr) (*(volatile unsigned int *)(addr))
+#endif
+
+/*
+ * Number of OCs supported by this driver
+ */
+#define NOCDRIVER	1
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet including CRC
+ */
+#define RBUF_SIZE 1518
+
+#define	ET_MINLEN 64		/* minimum message length */
+
+/*
+ * RTEMS event used by interrupt handler to signal driver tasks.
+ * This must not be any of the events used by the network task synchronization.
+ */
+#define INTERRUPT_EVENT	RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ * This must not be the same as INTERRUPT_EVENT.
+ */
+#define START_TRANSMIT_EVENT	RTEMS_EVENT_2
+
+ /* event to send when tx buffers become available */
+#define GRETH_TX_WAIT_EVENT  RTEMS_EVENT_3
+
+#if (MCLBYTES < RBUF_SIZE)
+# error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+/* 4s Autonegotiation Timeout */
+#ifndef GRETH_AUTONEGO_TIMEOUT_MS
+#define GRETH_AUTONEGO_TIMEOUT_MS 4000
+#endif
+const struct timespec greth_tan = {
+   GRETH_AUTONEGO_TIMEOUT_MS/1000,
+   GRETH_AUTONEGO_TIMEOUT_MS*1000000
+};
+
+/* For optimizing the autonegotiation time */
+#define GRETH_AUTONEGO_PRINT_TIME
+
+/* Ethernet buffer descriptor */
+
+typedef struct _greth_rxtxdesc {
+   volatile uint32_t ctrl; /* Length and status */
+   uint32_t *addr;         /* Buffer pointer */
+} greth_rxtxdesc;
+
+
+/*
+ * Per-device data
+ */
+struct greth_softc
+{
+
+   struct arpcom arpcom;
+   struct drvmgr_dev *dev;		/* Driver manager device */
+   char devName[32];
+
+   greth_regs *regs;
+   int minor;
+   int phyaddr;  /* PHY Address configured by user (or -1 to autodetect) */
+
+   int acceptBroadcast;
+   rtems_id daemonTid;
+   
+   unsigned int tx_ptr;
+   unsigned int tx_dptr;
+   unsigned int tx_cnt;
+   unsigned int rx_ptr;
+   unsigned int txbufs;
+   unsigned int rxbufs;
+   greth_rxtxdesc *txdesc;
+   greth_rxtxdesc *rxdesc;
+   unsigned int txdesc_remote;
+   unsigned int rxdesc_remote;
+   struct mbuf **rxmbuf;
+   struct mbuf **txmbuf;
+   rtems_vector_number vector;
+   
+   /* TX descriptor interrupt generation */
+   int tx_int_gen;
+   int tx_int_gen_cur;
+   struct mbuf *next_tx_mbuf;
+   int max_fragsize;
+   
+   /*Status*/
+   struct phy_device_info phydev;
+   int fd;
+   int sp;
+   int gb;
+   int gbit_mac;
+   int auto_neg;
+   struct timespec auto_neg_time;
+
+   /*
+    * Statistics
+    */
+   unsigned long rxInterrupts;
+   
+   unsigned long rxPackets;
+   unsigned long rxLengthError;
+   unsigned long rxNonOctet;
+   unsigned long rxBadCRC;
+   unsigned long rxOverrun;
+   
+   unsigned long txInterrupts;
+   
+   unsigned long txDeferred;
+   unsigned long txHeartbeat;
+   unsigned long txLateCollision;
+   unsigned long txRetryLimit;
+   unsigned long txUnderrun;
+
+};
+
+int greth_process_tx_gbit(struct greth_softc *sc);
+int greth_process_tx(struct greth_softc *sc);
+
+static char *almalloc(int sz, int alignment)
+{
+        char *tmp;
+        tmp = calloc(1, sz + (alignment-1));
+        tmp = (char *) (((int)tmp+alignment) & ~(alignment -1));
+        return(tmp);
+}
+
+/* GRETH interrupt handler */
+
+void greth_interrupt (void *arg)
+{
+        uint32_t status;
+        uint32_t ctrl;
+        rtems_event_set events = 0;
+        struct greth_softc *greth = arg;
+        
+        /* read and clear interrupt cause */
+        status = greth->regs->status;
+        greth->regs->status = status;
+        ctrl = greth->regs->ctrl;
+        
+        /* Frame received? */
+        if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
+        {
+                greth->rxInterrupts++;
+                /* Stop RX-Error and RX-Packet interrupts */
+                ctrl &= ~GRETH_CTRL_RXIRQ;
+                events |= INTERRUPT_EVENT;
+        }
+        
+        if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
+        {
+                greth->txInterrupts++;
+                ctrl &= ~GRETH_CTRL_TXIRQ;
+                events |= GRETH_TX_WAIT_EVENT;
+        }
+        
+        /* Clear interrupt sources */
+        greth->regs->ctrl = ctrl;
+        
+        /* Send the event(s) */
+        if ( events )
+            rtems_event_send (greth->daemonTid, events);
+}
+
+static uint32_t read_mii(struct greth_softc *sc, uint32_t phy_addr, uint32_t reg_addr)
+{
+    while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
+    sc->regs->mdio_ctrl = (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_READ;
+    while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
+    if (!(sc->regs->mdio_ctrl & GRETH_MDIO_LINKFAIL))
+        return((sc->regs->mdio_ctrl >> 16) & 0xFFFF);
+    else {
+	printf("greth: failed to read mii\n");
+	return (0);
+    }
+}
+
+static void write_mii(struct greth_softc *sc, uint32_t phy_addr, uint32_t reg_addr, uint32_t data)
+{
+    while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
+    sc->regs->mdio_ctrl =
+     ((data & 0xFFFF) << 16) | (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_WRITE;
+    while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
+}
+
+static void print_init_info(struct greth_softc *sc) 
+{
+    printf("greth: driver attached\n");
+    if ( sc->auto_neg == -1 ){
+        printf("Auto negotiation timed out. Selecting default config\n");
+    }
+    printf("**** PHY ****\n");
+    printf("Vendor: %x   Device: %x   Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
+    printf("Current Operating Mode: ");
+    if (sc->gb) {
+        printf("1000 Mbit ");
+    } else if (sc->sp) {
+        printf("100 Mbit ");
+    } else {
+        printf("10 Mbit ");
+    }
+    if (sc->fd) {
+        printf("Full Duplex\n");
+    } else {
+        printf("Half Duplex\n");
+    }
+#ifdef GRETH_AUTONEGO_PRINT_TIME
+    if ( sc->auto_neg ) {
+        printf("Autonegotiation Time: %dms\n", sc->auto_neg_time.tv_sec * 1000 +
+               sc->auto_neg_time.tv_nsec / 1000000);
+    }
+#endif
+}
+
+
+/*
+ * Initialize the ethernet hardware
+ */
+static void
+greth_initialize_hardware (struct greth_softc *sc)
+{
+    struct mbuf *m;
+    int i;
+    int phyaddr;
+    int phyctrl;
+    int phystatus;
+    int tmp1;
+    int tmp2;
+    struct timespec tstart, tnow;
+
+    greth_regs *regs;
+
+    regs = sc->regs;
+    
+    /* Reset the controller.  */
+    sc->rxInterrupts = 0;
+    sc->rxPackets = 0;
+
+    regs->ctrl = 0;
+    regs->ctrl = GRETH_CTRL_RST;	/* Reset ON */
+    regs->ctrl = 0;			/* Reset OFF */
+    
+    /* Check if mac is gbit capable*/
+    sc->gbit_mac = (regs->ctrl >> 27) & 1;
+    
+    /* Get the phy address which assumed to have been set
+       correctly with the reset value in hardware*/
+    if ( sc->phyaddr == -1 ) {
+        phyaddr = (regs->mdio_ctrl >> 11) & 0x1F;
+    } else {
+        phyaddr = sc->phyaddr;
+    }
+
+    /* get phy control register default values */
+    while ((phyctrl = read_mii(sc, phyaddr, 0)) & 0x8000) {}
+    
+    /* reset PHY and wait for completion */
+    write_mii(sc, phyaddr, 0, 0x8000 | phyctrl);
+
+    while ((read_mii(sc, phyaddr, 0)) & 0x8000) {}
+    
+    /* Check if PHY is autoneg capable and then determine operating mode, 
+       otherwise force it to 10 Mbit halfduplex */
+    sc->gb = 0;
+    sc->fd = 0;
+    sc->sp = 0;
+    sc->auto_neg = 0;
+    _Timespec_Set_to_zero(&sc->auto_neg_time);
+    if ((phyctrl >> 12) & 1) {
+            /*wait for auto negotiation to complete*/
+            sc->auto_neg = 1;
+            if (rtems_clock_get_uptime(&tstart) != RTEMS_SUCCESSFUL)
+                    printk("rtems_clock_get_uptime failed\n");
+            while (!(((phystatus = read_mii(sc, phyaddr, 1)) >> 5) & 1)) {
+                    if (rtems_clock_get_uptime(&tnow) != RTEMS_SUCCESSFUL)
+                            printk("rtems_clock_get_uptime failed\n");
+                    _Timespec_Subtract(&tstart, &tnow, &sc->auto_neg_time);
+                    if (_Timespec_Greater_than(&sc->auto_neg_time, &greth_tan)) {
+                            sc->auto_neg = -1; /* Failed */
+                            tmp1 = read_mii(sc, phyaddr, 0);
+                            sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
+                            sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
+                            sc->fd = (phyctrl >> 8) & 1;
+                            goto auto_neg_done;
+                    }
+                    /* Wait about 30ms, time is PHY dependent */
+                    rtems_task_wake_after(rtems_clock_get_ticks_per_second()/32);
+            }
+            sc->phydev.adv = read_mii(sc, phyaddr, 4);
+            sc->phydev.part = read_mii(sc, phyaddr, 5);
+            if ((phystatus >> 8) & 1) {
+                    sc->phydev.extadv = read_mii(sc, phyaddr, 9);
+                    sc->phydev.extpart = read_mii(sc, phyaddr, 10);
+                       if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000FD) &&
+                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000FD)) {
+                               sc->gb = 1;
+                               sc->fd = 1;
+                       }
+                       if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000HD) &&
+                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000HD)) {
+                               sc->gb = 1;
+                               sc->fd = 0;
+                       }
+            }
+            if ((sc->gb == 0) || ((sc->gb == 1) && (sc->gbit_mac == 0))) {
+                    if ( (sc->phydev.adv & GRETH_MII_100TXFD) &&
+                         (sc->phydev.part & GRETH_MII_100TXFD)) {
+                            sc->sp = 1;
+                            sc->fd = 1;
+                    }
+                    if ( (sc->phydev.adv & GRETH_MII_100TXHD) &&
+                         (sc->phydev.part & GRETH_MII_100TXHD)) {
+                            sc->sp = 1;
+                            sc->fd = 0;
+                    }
+                    if ( (sc->phydev.adv & GRETH_MII_10FD) &&
+                         (sc->phydev.part & GRETH_MII_10FD)) {
+                            sc->fd = 1;
+                    }
+            }
+    }
+auto_neg_done:
+    sc->phydev.vendor = 0;
+    sc->phydev.device = 0;
+    sc->phydev.rev = 0;
+    phystatus = read_mii(sc, phyaddr, 1);
+    
+    /*Read out PHY info if extended registers are available */
+    if (phystatus & 1) {  
+            tmp1 = read_mii(sc, phyaddr, 2);
+            tmp2 = read_mii(sc, phyaddr, 3);
+
+            sc->phydev.vendor = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F);
+            sc->phydev.rev = tmp2 & 0xF;
+            sc->phydev.device = (tmp2 >> 4) & 0x3F;
+    }
+
+    /* Force to 10 mbit half duplex if the 10/100 MAC is used with a 1000 PHY*/
+    /*check if marvell 88EE1111 PHY. Needs special reset handling */
+    if ((phystatus & 1) && (sc->phydev.vendor == 0x005043) && (sc->phydev.device == 0x0C)) {
+            if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) {
+                    write_mii(sc, phyaddr, 0, sc->sp << 13);
+                    write_mii(sc, phyaddr, 0, 0x8000);
+                    sc->gb = 0;
+                    sc->sp = 0;
+                    sc->fd = 0;
+            }
+    } else {
+            if (((sc->gb) && !(sc->gbit_mac))  || !((phyctrl >> 12) & 1)) {
+                    write_mii(sc, phyaddr, 0, sc->sp << 13);
+                    sc->gb = 0;
+                    sc->sp = 0;
+                    sc->fd = 0;
+            }
+    }
+    while ((read_mii(sc, phyaddr, 0)) & 0x8000) {}
+
+    regs->ctrl = 0;
+    regs->ctrl = GRETH_CTRL_RST;	/* Reset ON */
+    regs->ctrl = 0;
+
+    /* Initialize rx/tx descriptor table pointers. Due to alignment we 
+     * always allocate maximum table size.
+     */
+    sc->txdesc = (greth_rxtxdesc *) almalloc(0x800, 0x400);
+    sc->rxdesc = (greth_rxtxdesc *) &sc->txdesc[128];
+    sc->tx_ptr = 0;
+    sc->tx_dptr = 0;
+    sc->tx_cnt = 0;
+    sc->rx_ptr = 0;
+
+    /* Translate the Descriptor DMA table base address into an address that
+     * the GRETH core can understand
+     */
+    drvmgr_translate_check(
+        sc->dev,
+        CPUMEM_TO_DMA,
+        (void *)sc->txdesc,
+        (void **)&sc->txdesc_remote,
+        0x800);
+    sc->rxdesc_remote = sc->txdesc_remote + 0x400;
+    regs->txdesc = (int) sc->txdesc_remote;
+    regs->rxdesc = (int) sc->rxdesc_remote;
+
+    sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf));
+    sc->txmbuf = calloc(sc->txbufs, sizeof(*sc->txmbuf));
+
+    for (i = 0; i < sc->txbufs; i++)
+      {
+        sc->txdesc[i].ctrl = 0;
+        if (!(sc->gbit_mac)) {
+            drvmgr_translate_check(
+                sc->dev, 
+                CPUMEM_TO_DMA,
+                (void *)malloc(GRETH_MAXBUF_LEN),
+                (void **)&sc->txdesc[i].addr,
+                GRETH_MAXBUF_LEN);
+        }
+#ifdef GRETH_DEBUG
+              /* printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr); */
+#endif
+      }
+    for (i = 0; i < sc->rxbufs; i++)
+      {
+         MGETHDR (m, M_WAIT, MT_DATA);
+          MCLGET (m, M_WAIT);
+          if (sc->gbit_mac)
+                  m->m_data += 2;
+	  m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+          sc->rxmbuf[i] = m;
+          drvmgr_translate_check(
+            sc->dev,
+            CPUMEM_TO_DMA,
+            (void *)mtod(m, uint32_t *),
+            (void **)&sc->rxdesc[i].addr,
+            GRETH_MAXBUF_LEN);
+          sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
+#ifdef GRETH_DEBUG
+/* 	  printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr); */
+#endif
+      }
+    sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP;
+
+    /* set ethernet address.  */
+    regs->mac_addr_msb = 
+      sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1];
+    regs->mac_addr_lsb = 
+      sc->arpcom.ac_enaddr[2] << 24 | sc->arpcom.ac_enaddr[3] << 16 |
+      sc->arpcom.ac_enaddr[4] << 8 | sc->arpcom.ac_enaddr[5];
+
+    if ( sc->rxbufs < 10 ) {
+        sc->tx_int_gen = sc->tx_int_gen_cur = 1;
+    }else{
+        sc->tx_int_gen = sc->tx_int_gen_cur = sc->txbufs/2;
+    }
+    sc->next_tx_mbuf = NULL;
+    
+    if ( !sc->gbit_mac )
+        sc->max_fragsize = 1;
+
+    /* clear all pending interrupts */
+    regs->status = 0xffffffff;
+
+    /* install interrupt handler */
+    drvmgr_interrupt_register(sc->dev, 0, "greth", greth_interrupt, sc);
+
+    regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
+
+    print_init_info(sc);
+}
+
+#ifdef CPU_U32_FIX
+
+/*
+ * Routine to align the received packet so that the ip header
+ * is on a 32-bit boundary. Necessary for cpu's that do not
+ * allow unaligned loads and stores and when the 32-bit DMA
+ * mode is used.
+ *
+ * Transfers are done on word basis to avoid possibly slow byte
+ * and half-word writes.
+ */
+
+void ipalign(struct mbuf *m)
+{
+  unsigned int *first, *last, data;
+  unsigned int tmp = 0;
+
+  if ((((int) m->m_data) & 2) && (m->m_len)) {
+    last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3);
+    first = (unsigned int *) (((int) m->m_data) & ~3);
+		/* tmp = *first << 16; */
+		asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(first) );
+		tmp = tmp << 16;
+    first++;
+    do {
+			/* When snooping is not available the LDA instruction must be used
+			 * to avoid the cache to return an illegal value.
+			 ** Load with forced cache miss
+			 * data = *first; 
+			 */
+      asm volatile (" lda [%1] 1, %0\n" : "=r"(data) : "r"(first) );
+      *first = tmp | (data >> 16);
+      tmp = data << 16;
+      first++;
+    } while (first <= last);
+
+    m->m_data = (caddr_t)(((int) m->m_data) + 2);
+  }
+}
+#endif
+
+void
+greth_Daemon (void *arg)
+{
+    struct ether_header *eh;
+    struct greth_softc *dp = (struct greth_softc *) arg;
+    struct ifnet *ifp = &dp->arpcom.ac_if;
+    struct mbuf *m;
+    unsigned int len, len_status, bad;
+    rtems_event_set events;
+    rtems_interrupt_level level;
+    int first;
+		int tmp;
+		unsigned int addr;
+    
+    for (;;)
+      {
+        rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
+                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
+                                    RTEMS_NO_TIMEOUT, &events);
+        
+        if ( events & GRETH_TX_WAIT_EVENT ){
+            /* TX interrupt.
+             * We only end up here when all TX descriptors has been used,
+             * and 
+             */
+            if ( dp->gbit_mac )
+                greth_process_tx_gbit(dp);
+            else
+                greth_process_tx(dp);
+            
+            /* If we didn't get a RX interrupt we don't process it */
+            if ( (events & INTERRUPT_EVENT) == 0 )
+                continue;
+        }
+        
+        
+#ifdef GRETH_ETH_DEBUG
+    printf ("r\n");
+#endif
+    first=1;
+    /* Scan for Received packets */
+again:
+    while (!((len_status =
+		    GRETH_MEM_LOAD(&dp->rxdesc[dp->rx_ptr].ctrl)) & GRETH_RXD_ENABLE))
+	    {
+                    bad = 0;
+                    if (len_status & GRETH_RXD_TOOLONG)
+                    {
+                            dp->rxLengthError++;
+                            bad = 1;
+                    }
+                    if (len_status & GRETH_RXD_DRIBBLE)
+                    {
+                            dp->rxNonOctet++;
+                            bad = 1;
+                    }
+                    if (len_status & GRETH_RXD_CRCERR)
+                    {
+                            dp->rxBadCRC++;
+                            bad = 1;
+                    }
+                    if (len_status & GRETH_RXD_OVERRUN)
+                    {
+                            dp->rxOverrun++;
+                            bad = 1;
+                    }
+                    if (len_status & GRETH_RXD_LENERR)
+                    {
+                            dp->rxLengthError++;
+                            bad = 1;
+                    }
+                    if (!bad)
+                    {
+                            /* pass on the packet in the receive buffer */
+                            len = len_status & 0x7FF;
+                            m = dp->rxmbuf[dp->rx_ptr];
+#ifdef GRETH_DEBUG
+                            int i;
+                            printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len);
+                            for (i=0; i<len; i++)
+                                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
+                            printf("\n");
+#endif
+                            m->m_len = m->m_pkthdr.len =
+                                    len - sizeof (struct ether_header);
+
+                            eh = mtod (m, struct ether_header *);
+
+                            m->m_data += sizeof (struct ether_header);
+#ifdef CPU_U32_FIX
+                            if(!dp->gbit_mac) {
+                                    /* OVERRIDE CACHED ETHERNET HEADER FOR NON-SNOOPING SYSTEMS */
+                                    addr = (unsigned int)eh;
+                                    asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+                                    addr+=4;
+                                    asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+                                    addr+=4;
+                                    asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+                                    addr+=4;
+                                    asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
+
+                                    ipalign(m);	/* Align packet on 32-bit boundary */
+                            }
+#endif
+/*
+                            if(!(dp->gbit_mac) && !CPU_SPARC_HAS_SNOOPING) {
+                                    rtems_cache_invalidate_entire_data();
+                            }
+*/
+                            ether_input (ifp, eh, m);
+                            MGETHDR (m, M_WAIT, MT_DATA);
+                            MCLGET (m, M_WAIT);
+                            if (dp->gbit_mac)
+                                    m->m_data += 2;
+                            dp->rxmbuf[dp->rx_ptr] = m;
+                            m->m_pkthdr.rcvif = ifp;
+                            drvmgr_translate_check(
+                                dp->dev,
+                                CPUMEM_TO_DMA,
+                                (void *)mtod (m, uint32_t *),
+                                (void **)&dp->rxdesc[dp->rx_ptr].addr,
+                                GRETH_MAXBUF_LEN);
+                            dp->rxPackets++;
+                    }
+                    if (dp->rx_ptr == dp->rxbufs - 1) {
+                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP;
+                    } else {
+                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
+                    }
+                    rtems_interrupt_disable(level);
+                    dp->regs->ctrl |= GRETH_CTRL_RXEN;
+                    rtems_interrupt_enable(level);
+                    dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
+            }
+        
+        /* Always scan twice to avoid deadlock */
+        if ( first ){
+            first=0;
+            rtems_interrupt_disable(level);
+            dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
+            rtems_interrupt_enable(level);
+            goto again;
+        }
+
+      }
+    
+}
+
+static int inside = 0;
+static int
+sendpacket (struct ifnet *ifp, struct mbuf *m)
+{
+    struct greth_softc *dp = ifp->if_softc;
+    unsigned char *temp;
+    struct mbuf *n;
+    unsigned int len;
+    rtems_interrupt_level level;
+        
+    /*printf("Send packet entered\n");*/
+    if (inside) printf ("error: sendpacket re-entered!!\n");
+    inside = 1;
+    
+    /*
+     * Is there a free descriptor available?
+     */
+    if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){
+            /* No. */
+            inside = 0;
+            return 1;
+    }
+    
+    /* Remember head of chain */
+    n = m;
+
+    len = 0;
+    temp = (unsigned char *) GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].addr);
+    drvmgr_translate(dp->dev, CPUMEM_FROM_DMA, (void *)temp, (void **)&temp);
+#ifdef GRETH_DEBUG
+    printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
+#endif
+    for (;;)
+    {
+#ifdef GRETH_DEBUG
+            int i;
+            printf("MBUF: 0x%08x : ", (int) m->m_data);
+            for (i=0;i<m->m_len;i++)
+                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
+            printf("\n");
+#endif
+            len += m->m_len;
+            if (len <= RBUF_SIZE)
+                    memcpy ((void *) temp, (char *) m->m_data, m->m_len);
+            temp += m->m_len;
+            if ((m = m->m_next) == NULL)
+                    break;
+    }
+    
+    m_freem (n);
+    
+    /* don't send long packets */
+
+    if (len <= GRETH_MAXBUF_LEN) {
+            if (dp->tx_ptr < dp->txbufs-1) {
+                    dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len;
+            } else {
+                    dp->txdesc[dp->tx_ptr].ctrl = 
+                            GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
+            }
+            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
+            rtems_interrupt_disable(level);
+            dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
+            rtems_interrupt_enable(level);
+            
+    }
+    inside = 0;
+    
+    return 0;
+}
+
+
+int
+sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
+{
+        struct greth_softc *dp = ifp->if_softc;
+        unsigned int len;
+        
+        unsigned int ctrl;
+        int frags;
+        struct mbuf *mtmp;
+        int int_en;
+        rtems_interrupt_level level;
+
+        if (inside) printf ("error: sendpacket re-entered!!\n");
+        inside = 1;
+        
+        len = 0;
+#ifdef GRETH_DEBUG
+        printf("TXD: 0x%08x\n", (int) m->m_data);
+#endif
+        /* Get number of fragments too see if we have enough
+         * resources.
+         */
+        frags=1;
+        mtmp=m;
+        while(mtmp->m_next){
+            frags++;
+            mtmp = mtmp->m_next;
+        }
+
+        if ( frags > dp->max_fragsize ) 
+            dp->max_fragsize = frags;
+        
+        if ( frags > dp->txbufs ){
+            inside = 0;
+            printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
+            return -1;
+        }
+        
+        if ( frags > (dp->txbufs-dp->tx_cnt) ){
+            inside = 0;
+            /* Return number of fragments */
+            return frags;
+        }
+        
+        
+        /* Enable interrupt from descriptor every tx_int_gen
+         * descriptor. Typically every 16 descriptor. This
+         * is only to reduce the number of interrupts during
+         * heavy load.
+         */
+        dp->tx_int_gen_cur-=frags;
+        if ( dp->tx_int_gen_cur <= 0 ){
+            dp->tx_int_gen_cur = dp->tx_int_gen;
+            int_en = GRETH_TXD_IRQ;
+        }else{
+            int_en = 0;
+        }
+        
+        /* At this stage we know that enough descriptors are available */
+        for (;;)
+        {
+                
+#ifdef GRETH_DEBUG
+            int i;
+            printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
+            for (i=0; i<m->m_len; i++)
+                printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
+            printf("\n");
+#endif
+            len += m->m_len;
+            drvmgr_translate_check(
+                dp->dev,
+                CPUMEM_TO_DMA,
+                (void *)(uint32_t *)m->m_data,
+                (void **)&dp->txdesc[dp->tx_ptr].addr,
+                m->m_len);
+
+            /* Wrap around? */
+            if (dp->tx_ptr < dp->txbufs-1) {
+                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS;
+            }else{
+                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | GRETH_TXD_WRAP;
+            }
+
+            /* Enable Descriptor */  
+            if ((m->m_next) == NULL) {
+                dp->txdesc[dp->tx_ptr].ctrl = ctrl | int_en | m->m_len;
+                break;
+            }else{
+                dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_MORE | ctrl | int_en | m->m_len;
+            }
+
+            /* Next */
+            dp->txmbuf[dp->tx_ptr] = m;
+            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
+            dp->tx_cnt++;
+            m = m->m_next;
+        }
+        dp->txmbuf[dp->tx_ptr] = m;
+        dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
+        dp->tx_cnt++;
+      
+        /* Tell Hardware about newly enabled descriptor */
+        rtems_interrupt_disable(level);
+        dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
+        rtems_interrupt_enable(level);
+
+        inside = 0;
+               
+        return 0;
+}
+
+int greth_process_tx_gbit(struct greth_softc *sc)
+{
+    struct ifnet *ifp = &sc->arpcom.ac_if;
+    struct mbuf *m;
+    rtems_interrupt_level level;
+    int first=1;
+    
+    /*
+     * Send packets till queue is empty
+     */
+    for (;;){
+        /* Reap Sent packets */
+        while((sc->tx_cnt > 0) && !(GRETH_MEM_LOAD(&sc->txdesc[sc->tx_dptr].ctrl) & GRETH_TXD_ENABLE)) {
+            m_free(sc->txmbuf[sc->tx_dptr]);
+            sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
+            sc->tx_cnt--;
+        }
+        
+        if ( sc->next_tx_mbuf ){
+            /* Get packet we tried but faild to transmit last time */
+            m = sc->next_tx_mbuf;
+            sc->next_tx_mbuf = NULL; /* Mark packet taken */
+        }else{
+            /*
+             * Get the next mbuf chain to transmit from Stack.
+             */
+            IF_DEQUEUE (&ifp->if_snd, m);
+            if (!m){
+                /* Hardware has sent all schedule packets, this
+                 * makes the stack enter at greth_start next time
+                 * a packet is to be sent.
+                 */
+                ifp->if_flags &= ~IFF_OACTIVE;
+                break;
+            }
+        }
+
+        /* Are there free descriptors available? */
+        /* Try to send packet, if it a negative number is returned. */
+        if ( (sc->tx_cnt >= sc->txbufs) || sendpacket_gbit(ifp, m) ){
+            /* Not enough resources */
+             
+            /* Since we have taken the mbuf out of the "send chain"
+             * we must remember to use that next time we come back.
+             * or else we have dropped a packet.
+             */
+            sc->next_tx_mbuf = m;
+            
+            /* Not enough resources, enable interrupt for transmissions
+             * this way we will be informed when more TX-descriptors are 
+             * available.
+             */
+            if ( first ){
+                first = 0;
+                rtems_interrupt_disable(level);
+                ifp->if_flags |= IFF_OACTIVE;
+                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
+                rtems_interrupt_enable(level);
+                
+                /* We must check again to be sure that we didn't 
+                 * miss an interrupt (if a packet was sent just before
+                 * enabling interrupts)
+                 */
+                continue;
+            }
+            
+            return -1;
+        }else{
+            /* Sent Ok, proceed to process more packets if available */
+        }
+    }
+    return 0;
+}
+
+int greth_process_tx(struct greth_softc *sc)
+{
+    struct ifnet *ifp = &sc->arpcom.ac_if;
+    struct mbuf *m;
+    rtems_interrupt_level level;
+    int first=1;
+    
+    /*
+     * Send packets till queue is empty
+     */
+    for (;;){
+        if ( sc->next_tx_mbuf ){
+            /* Get packet we tried but failed to transmit last time */
+            m = sc->next_tx_mbuf;
+            sc->next_tx_mbuf = NULL; /* Mark packet taken */
+        }else{
+            /*
+             * Get the next mbuf chain to transmit from Stack.
+             */
+            IF_DEQUEUE (&ifp->if_snd, m);
+            if (!m){
+                /* Hardware has sent all schedule packets, this
+                 * makes the stack enter at greth_start next time
+                 * a packet is to be sent.
+                 */
+                ifp->if_flags &= ~IFF_OACTIVE;
+                break;
+            }
+        }
+
+        /* Try to send packet, failed if it a non-zero number is returned. */
+        if ( sendpacket(ifp, m) ){
+            /* Not enough resources */
+             
+            /* Since we have taken the mbuf out of the "send chain"
+             * we must remember to use that next time we come back.
+             * or else we have dropped a packet.
+             */
+            sc->next_tx_mbuf = m;
+            
+            /* Not enough resources, enable interrupt for transmissions
+             * this way we will be informed when more TX-descriptors are 
+             * available.
+             */
+            if ( first ){
+                first = 0;
+                rtems_interrupt_disable(level);
+                ifp->if_flags |= IFF_OACTIVE;
+                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
+                rtems_interrupt_enable(level);
+                
+                /* We must check again to be sure that we didn't 
+                 * miss an interrupt (if a packet was sent just before
+                 * enabling interrupts)
+                 */
+                continue;
+            }
+            
+            return -1;
+        }else{
+            /* Sent Ok, proceed to process more packets if available */
+        }
+    }
+    return 0;
+}
+
+static void
+greth_start (struct ifnet *ifp)
+{
+    struct greth_softc *sc = ifp->if_softc;
+    
+    if ( ifp->if_flags & IFF_OACTIVE )
+            return;
+    
+    if ( sc->gbit_mac ){
+        /* No use trying to handle this if we are waiting on GRETH
+         * to send the previously scheduled packets.
+         */
+        
+        greth_process_tx_gbit(sc);
+    }else{
+        greth_process_tx(sc);
+    }
+    
+}
+
+/*
+ * Initialize and start the device
+ */
+static void
+greth_init (void *arg)
+{
+    struct greth_softc *sc = arg;
+    struct ifnet *ifp = &sc->arpcom.ac_if;
+
+    if (sc->daemonTid == 0)
+      {
+
+	  /*
+	   * Start driver tasks
+	   */
+	  sc->daemonTid = rtems_bsdnet_newproc ("DCrxtx", 4096,
+						  greth_Daemon, sc);
+
+	  /*
+	   * Set up GRETH hardware
+	   */
+      greth_initialize_hardware (sc);
+          
+      }
+
+    /*
+     * Tell the world that we're running.
+     */
+    ifp->if_flags |= IFF_RUNNING;
+
+}
+
+/*
+ * Stop the device
+ */
+static void
+greth_stop (struct greth_softc *sc)
+{
+    struct ifnet *ifp = &sc->arpcom.ac_if;
+
+    ifp->if_flags &= ~IFF_RUNNING;
+
+    sc->regs->ctrl = 0;		        /* RX/TX OFF */
+    sc->regs->ctrl = GRETH_CTRL_RST;	/* Reset ON */
+    sc->regs->ctrl = 0;	         	/* Reset OFF */
+    
+    sc->next_tx_mbuf = NULL;
+}
+
+
+/*
+ * Show interface statistics
+ */
+static void
+greth_stats (struct greth_softc *sc)
+{
+  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
+  printf ("      Rx Packets:%-8lu", sc->rxPackets);
+  printf ("          Length:%-8lu", sc->rxLengthError);
+  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
+  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
+  printf ("         Overrun:%-8lu", sc->rxOverrun);
+  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
+  printf ("      Maximal Frags:%-8d", sc->max_fragsize);
+  printf ("      GBIT MAC:%-8d", sc->gbit_mac);
+}
+
+/*
+ * Driver ioctl handler
+ */
+static int
+greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
+{
+    struct greth_softc *sc = ifp->if_softc;
+    int error = 0;
+
+    switch (command)
+      {
+      case SIOCGIFADDR:
+      case SIOCSIFADDR:
+	  ether_ioctl (ifp, command, data);
+	  break;
+
+      case SIOCSIFFLAGS:
+	  switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
+	    {
+	    case IFF_RUNNING:
+		greth_stop (sc);
+                break;
+
+	    case IFF_UP:
+		greth_init (sc);
+		break;
+
+	    case IFF_UP | IFF_RUNNING:
+		greth_stop (sc);
+		greth_init (sc);
+		break;
+       default:
+		break;
+	    }
+	  break;
+
+      case SIO_RTEMS_SHOW_STATS:
+	  greth_stats (sc);
+	  break;
+
+	  /*
+	   * FIXME: All sorts of multicast commands need to be added here!
+	   */
+      default:
+	  error = EINVAL;
+	  break;
+      }
+
+    return error;
+}
+
+/*
+ * Attach an GRETH driver to the system
+ */
+int
+greth_interface_driver_attach (
+    struct rtems_bsdnet_ifconfig *config,
+    int attach
+    )
+{
+    struct greth_softc *sc;
+    struct ifnet *ifp;
+    int mtu;
+    int unitNumber;
+    char *unitName;
+    
+      /* parse driver name */
+    if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
+	return 0;
+
+    sc = config->drv_ctrl;
+    ifp = &sc->arpcom.ac_if;
+#ifdef GRETH_DEBUG
+    printf("GRETH[%d]: %s, sc %p, dev %p on %s\n", unitNumber, config->ip_address, sc, sc->dev, sc->dev->parent->dev->name);
+#endif
+    if (config->hardware_address)
+      {
+	  memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
+		  ETHER_ADDR_LEN);
+      }
+    else
+      {
+	  memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
+      }
+
+    if (config->mtu)
+	mtu = config->mtu;
+    else
+	mtu = ETHERMTU;
+
+    sc->acceptBroadcast = !config->ignore_broadcast;
+
+    /*
+     * Set up network interface values
+     */
+    ifp->if_softc = sc;
+    ifp->if_unit = unitNumber;
+    ifp->if_name = unitName;
+    ifp->if_mtu = mtu;
+    ifp->if_init = greth_init;
+    ifp->if_ioctl = greth_ioctl;
+    ifp->if_start = greth_start;
+    ifp->if_output = ether_output;
+    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+    if (ifp->if_snd.ifq_maxlen == 0)
+	ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+    /*
+     * Attach the interface
+     */
+    if_attach (ifp);
+    ether_ifattach (ifp);
+
+#ifdef GRETH_DEBUG
+    printf ("GRETH : driver has been attached\n");
+#endif
+    return 1;
+}
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int greth_register_io(rtems_device_major_number *m);
+int greth_device_init(struct greth_softc *sc);
+int network_interface_add(struct rtems_bsdnet_ifconfig *interface);
+
+#ifdef GRETH_INFO_AVAIL
+static int greth_info(
+	struct drvmgr_dev *dev,
+	void (*print_line)(void *p, char *str),
+	void *p, int argc, char *argv[]);
+#define GRETH_INFO_FUNC greth_info
+#else
+#define GRETH_INFO_FUNC NULL
+#endif
+
+int greth_init2(struct drvmgr_dev *dev);
+int greth_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops greth_ops = 
+{
+	.init	=
+		{
+			NULL,
+			greth_init2,
+			greth_init3,
+			NULL
+		},
+	.remove = NULL,
+	.info = GRETH_INFO_FUNC,
+};
+
+struct amba_dev_id greth_ids[] = 
+{
+	{VENDOR_GAISLER, GAISLER_ETHMAC},
+	{0, 0}		/* Mark end of table */
+};
+
+struct amba_drv_info greth_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,			/* Driver */
+		NULL,				/* Next driver */
+		NULL,				/* Device list */
+		DRIVER_AMBAPP_GAISLER_GRETH_ID,	/* Driver ID */
+		"GRETH_DRV",			/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,		/* Bus Type */
+		&greth_ops,
+		NULL,				/* Funcs */
+		0,				/* No devices yet */
+		0,
+	},
+	&greth_ids[0]
+};
+
+void greth_register_drv (void)
+{
+	DBG("Registering GRETH driver\n");
+	drvmgr_drv_register(&greth_drv_info.general);
+}
+
+int greth_init2(struct drvmgr_dev *dev)
+{
+	struct greth_softc *priv;
+
+	DBG("GRETH[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+	priv = dev->priv = malloc(sizeof(struct greth_softc));
+	if ( !priv )
+		return DRVMGR_NOMEM;
+	memset(priv, 0, sizeof(*priv));
+	priv->dev = dev;
+
+	/* This core will not find other cores, so we wait for init3() */
+
+	return DRVMGR_OK;
+}
+
+int greth_init3(struct drvmgr_dev *dev)
+{
+    struct greth_softc *sc;
+    struct rtems_bsdnet_ifconfig *ifp;
+    rtems_status_code status;
+
+    sc = dev->priv;
+    sprintf(sc->devName, "gr_eth%d", (dev->minor_drv+1));
+
+    /* Init GRETH device */
+    if ( greth_device_init(sc) ) {
+        printk("GRETH: Failed to init device\n");
+        return DRVMGR_FAIL;
+    }
+
+    /* Register GRETH device as an Network interface */
+    ifp = malloc(sizeof(struct rtems_bsdnet_ifconfig));
+    memset(ifp, 0, sizeof(*ifp));
+
+    ifp->name = sc->devName;
+    ifp->drv_ctrl = sc;
+    ifp->attach = greth_interface_driver_attach;
+
+    status = network_interface_add(ifp);
+    if (status != 0) {
+        return DRVMGR_FAIL;
+    }
+
+    return DRVMGR_OK;
+}
+
+int greth_device_init(struct greth_softc *sc)
+{
+    struct amba_dev_info *ambadev;
+    struct ambapp_core *pnpinfo;
+    union drvmgr_key_value *value;
+
+    /* Get device information from AMBA PnP information */
+    ambadev = (struct amba_dev_info *)sc->dev->businfo;
+    if ( ambadev == NULL ) {
+        return -1;
+    }
+    pnpinfo = &ambadev->info;
+    sc->regs = (greth_regs *)pnpinfo->apb_slv->start;
+    sc->minor = sc->dev->minor_drv;
+
+    /* clear control register and reset NIC 
+     * This should be done as quick as possible during startup, this is to
+     * stop DMA transfers after a reboot.
+     */
+    sc->regs->ctrl = 0;
+    sc->regs->ctrl = GRETH_CTRL_RST;
+    sc->regs->ctrl = 0;
+
+    /* Configure driver by overriding default config with the bus resources 
+     * configured by the user
+     */
+    sc->txbufs = 32;
+    sc->rxbufs = 32;
+    sc->phyaddr = -1;
+
+    value = drvmgr_dev_key_get(sc->dev, "txDescs", KEY_TYPE_INT);
+    if ( value && (value->i <= 128) )
+        sc->txbufs = value->i;
+
+    value = drvmgr_dev_key_get(sc->dev, "rxDescs", KEY_TYPE_INT);
+    if ( value && (value->i <= 128) )
+        sc->rxbufs = value->i;
+
+    value = drvmgr_dev_key_get(sc->dev, "phyAdr", KEY_TYPE_INT);
+    if ( value && (value->i < 32) )
+        sc->phyaddr = value->i;
+
+    return 0;
+}
+
+#ifdef GRETH_INFO_AVAIL
+static int greth_info(
+	struct drvmgr_dev *dev,
+	void (*print_line)(void *p, char *str),
+	void *p, int argc, char *argv[])
+{
+	struct greth_softc *sc;
+	char buf[64];
+
+	if (dev->priv == NULL)
+		return -DRVMGR_EINVAL;
+	sc = dev->priv;
+
+	sprintf(buf, "IFACE NAME:  %s", sc->devName);
+	print_line(p, buf);
+	sprintf(buf, "GBIT MAC:    %s", sc->gbit_mac ? "YES" : "NO");
+	print_line(p, buf);
+
+	return DRVMGR_OK;
+}
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/pwm/grpwm.c b/c/src/lib/libbsp/sparc/shared/pwm/grpwm.c
new file mode 100644
index 0000000..753a680
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pwm/grpwm.c
@@ -0,0 +1,847 @@
+/*
+ *  GRPWM PWM Driver interface.
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB,
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grpwm.h>
+#include <ambapp.h>
+
+/* #define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#define STATIC
+#else
+#define DBG(x...) 
+#define STATIC static
+#endif
+
+/*** REGISTER LAYOUT ***/
+
+/* PWM Channel specific registers */
+struct grpwm_pwm_regs {
+	volatile unsigned int period;		/* 0x00 */
+	volatile unsigned int comp;		/* 0x04 */
+	volatile unsigned int dbcomp;		/* 0x08 */
+	volatile unsigned int ctrl;		/* 0x0C */
+};
+
+/* Core common registers */	
+struct grpwm_regs {
+	volatile unsigned int ctrl;		/* 0x00 */
+	volatile unsigned int scaler;		/* 0x04 */
+	volatile unsigned int ipend;		/* 0x08 */
+	volatile unsigned int cap1;		/* 0x0C */
+	volatile unsigned int cap2;		/* 0x10 */
+	volatile unsigned int wctrl;		/* 0x14 */
+	int reserved0[2];
+	struct grpwm_pwm_regs pwms[8];		/* 0x20 */
+	int reserved1[(0x8000-0xA0)/4];		/* 0xA0-0x7FFC */
+	volatile unsigned int wram[0x8000/4];	/* 0x8000-0xFFFC */
+};
+
+/*** REGISTER BIT LAYOUT ***/
+
+/* CTRL REGISTER - 0x0 */
+#define GRPWM_CTRL_EN_BIT	0
+#define GRPWM_CTRL_SCSEL_BIT	8
+#define GRPWM_CTRL_NOUP_BIT	12
+#define GRPWM_CTRL_EN		(1<<GRPWM_CTRL_EN_BIT)
+#define GRPWM_CTRL_SCSEL	(0x7<<GRPWM_CTRL_SCSEL_BIT)
+#define GRPWM_CTRL_NOUP		(0xff<<GRPWM_CTRL_NOUP_BIT)
+
+
+/* CAPABILITY1 REGISTER - 0x0C */
+#define GRPWM_CAP_NPWM_BIT	0
+#define GRPWM_CAP_PBITS_BIT	3
+#define GRPWM_CAP_SBITS_BIT	8
+#define GRPWM_CAP_NSC_BIT	13
+#define GRPWM_CAP_DBB_BIT	16
+#define GRPWM_CAP_DBSC_BIT	21
+#define GRPWM_CAP_ASY_BIT	22
+#define GRPWM_CAP_SYM_BIT	23
+#define GRPWM_CAP_SEP_BIT	25
+#define GRPWM_CAP_DCM_BIT	27
+
+#define GRPWM_CAP_NPWM	(0x7<<GRPWM_CAP_NPWM_BIT)
+#define GRPWM_CAP_PBITS	(0x1f<<GRPWM_CAP_PBITS_BIT)
+#define GRPWM_CAP_SBITS	(0x1f<<GRPWM_CAP_SBITS_BIT)
+#define GRPWM_CAP_NSC	(0x7<<GRPWM_CAP_NSC_BIT)
+#define GRPWM_CAP_DBB	(0x1f<<GRPWM_CAP_DBB_BIT)
+#define GRPWM_CAP_DBSC	(1<<GRPWM_CAP_DBSC_BIT)
+#define GRPWM_CAP_ASY	(1<<GRPWM_CAP_ASY_BIT)
+#define GRPWM_CAP_SYM	(1<<GRPWM_CAP_SYM_BIT)
+#define GRPWM_CAP_SEP	(0x3<<GRPWM_CAP_SEP_BIT)
+#define GRPWM_CAP_DCM	(1<<GRPWM_CAP_DCM_BIT)
+
+/* CAPABILITY2 REGISTER - 0x10 */
+#define GRPWM_CAP2_WPWM_BIT	0
+#define GRPWM_CAP2_WDBITS_BIT	1
+#define GRPWM_CAP2_WABITS_BIT	6
+#define GRPWM_CAP2_WSYNC_BIT	10
+
+#define GRPWM_CAP2_WPWM		(0x1<<GRPWM_CAP2_WPWM_BIT)
+#define GRPWM_CAP2_WDBITS	(0x1f<<GRPWM_CAP2_WDBITS_BIT)
+#define GRPWM_CAP2_WABITS	(0xf<<GRPWM_CAP2_WABITS_BIT)
+#define GRPWM_CAP2_WSYNC	(1<<GRPWM_CAP2_WSYNC_BIT)
+
+/* WAVE FORM CONFIG REGISTER - 0x14 */
+#define GRPWM_WCTRL_STOP_BIT		0
+#define GRPWM_WCTRL_WSYNC_BIT		16
+#define GRPWM_WCTRL_WSEN_BIT		29
+#define GRPWM_WCTRL_WSYNCCFG_BIT	30
+
+#define GRPWM_WCTRL_STOP	(0x1fff<<GRPWM_WCTRL_STOP_BIT)
+#define GRPWM_WCTRL_WSYNC	(0x1fff<<GRPWM_WCTRL_WSYNC_BIT)
+#define GRPWM_WCTRL_WSEN	(0x1<<GRPWM_WCTRL_WSEN_BIT)
+#define GRPWM_WCTRL_WSYNCCFG	(0x3<<GRPWM_WCTRL_WSYNCCFG_BIT)
+
+
+/* PWM CONTROL REGISTER - 0x2C, 0x3C... */
+#define GRPWM_PCTRL_EN_BIT	0
+#define GRPWM_PCTRL_POL_BIT	1
+#define GRPWM_PCTRL_PAIR_BIT	2
+#define GRPWM_PCTRL_FIX_BIT	3
+#define GRPWM_PCTRL_METH_BIT	6
+#define GRPWM_PCTRL_DCEN_BIT	8
+#define GRPWM_PCTRL_WEN_BIT	9
+#define GRPWM_PCTRL_SCSEL_BIT	10
+#define GRPWM_PCTRL_IEN_BIT	13
+#define GRPWM_PCTRL_IT_BIT	14
+#define GRPWM_PCTRL_ISC_BIT	15
+#define GRPWM_PCTRL_DBEN_BIT	21
+#define GRPWM_PCTRL_DBSC_BIT	22
+#define GRPWM_PCTRL_FLIP_BIT	26
+
+#define GRPWM_PCTRL_EN		(0x1<<GRPWM_PCTRL_EN_BIT)
+#define GRPWM_PCTRL_POL		(0x1<<GRPWM_PCTRL_POL_BIT)
+#define GRPWM_PCTRL_PAIR	(0x1<<GRPWM_PCTRL_PAIR_BIT)
+#define GRPWM_PCTRL_FIX		(0x7<<GRPWM_PCTRL_FIX_BIT)
+#define GRPWM_PCTRL_METH	(0x1<<GRPWM_PCTRL_METH_BIT)
+#define GRPWM_PCTRL_DCEN	(0x1<<GRPWM_PCTRL_DCEN_BIT)
+#define GRPWM_PCTRL_WEN		(0x1<<GRPWM_PCTRL_WEN_BIT)
+#define GRPWM_PCTRL_SCSEL	(0x7<<GRPWM_PCTRL_SCSEL_BIT)
+#define GRPWM_PCTRL_IEN		(0x1<<GRPWM_PCTRL_IEN_BIT)
+#define GRPWM_PCTRL_IT		(0x1<<GRPWM_PCTRL_IT_BIT)
+#define GRPWM_PCTRL_ISC		(0x3f<<GRPWM_PCTRL_ISC_BIT)
+#define GRPWM_PCTRL_DBEN	(0x1<<GRPWM_PCTRL_DBEN_BIT)
+#define GRPWM_PCTRL_DBSC	(0xf<<GRPWM_PCTRL_DBSC_BIT)
+#define GRPWM_PCTRL_FLIP	(0xf<<GRPWM_PCTRL_FLIP_BIT)
+
+/*** DRIVER PRIVATE STRUCTURE ***/
+struct grpwm_priv {
+	struct drvmgr_dev	*dev;
+	struct grpwm_regs		*regs;
+	char				devName[32];
+	int				irq;
+	int				open;
+
+	/* Driver implementation */
+	char				nscalers;	/* Number of scalers */
+	char				wave;		/* If Wave form is available */
+	int				wlength;	/* Wave Form RAM Length */
+	int				channel_cnt;
+	struct grpwm_chan_priv		*channels[8];
+	rtems_id			dev_sem;
+};
+
+struct grpwm_chan_priv {
+	struct grpwm_priv		*common;
+	struct grpwm_pwm_regs		*pwmregs;
+	/* IRQ */
+	int				irqindex;
+	void				(*isr)(int channel, void *arg);
+	void				*isr_arg;
+};
+
+/******************* Driver Manager Part ***********************/
+
+int grpwm_device_init(struct grpwm_priv *priv);
+int grpwm_register_io(rtems_device_major_number *m);
+static int grpwm_driver_io_registered = 0;
+static rtems_device_major_number grpwm_driver_io_major = 0;
+
+int grpwm_init2(struct drvmgr_dev *dev);
+int grpwm_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops grpwm_ops = 
+{
+	.init = {NULL, grpwm_init2, grpwm_init3, NULL},
+	.remove = NULL,
+	.info = NULL
+};
+
+struct amba_dev_id grpwm_ids[] = 
+{
+	{VENDOR_GAISLER, GAISLER_GRPWM},
+	{0, 0}		/* Mark end of table */
+};
+
+struct amba_drv_info grpwm_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,				/* Driver */
+		NULL,					/* Next driver */
+		NULL,					/* Device list */
+		DRIVER_AMBAPP_GAISLER_GRPWM_ID,		/* Driver ID */
+		"GRPWM_DRV",				/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,			/* Bus Type */
+		&grpwm_ops,
+		NULL,					/* Funcs */
+		0,					/* No devices yet */
+		0,
+	},
+	&grpwm_ids[0]
+};
+
+void grpwm_register_drv (void)
+{
+	DBG("Registering GRPWM driver\n");
+	drvmgr_drv_register(&grpwm_drv_info.general);
+}
+
+int grpwm_init2(struct drvmgr_dev *dev)
+{
+	struct grpwm_priv *priv;
+
+	DBG("GRPWM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+	priv = dev->priv = malloc(sizeof(struct grpwm_priv));
+	if ( !priv )
+		return DRVMGR_NOMEM;
+	memset(priv, 0, sizeof(*priv));
+	priv->dev = dev;
+
+	/* This core will not find other cores, so we wait for init2() */
+
+	return DRVMGR_OK;
+}
+
+int grpwm_init3(struct drvmgr_dev *dev)
+{
+	struct grpwm_priv *priv = dev->priv;
+	char prefix[32];
+	rtems_status_code status;
+
+	if ( !priv )
+		return DRVMGR_FAIL;
+
+	if ( grpwm_driver_io_registered == 0) {
+		/* Register the I/O driver only once for all cores */
+		if ( grpwm_register_io(&grpwm_driver_io_major) ) {
+			/* Failed to register I/O driver */
+			dev->priv = NULL;
+			return DRVMGR_FAIL;
+		}
+
+		grpwm_driver_io_registered = 1;
+	}
+
+	/* I/O system registered and initialized 
+	 * Now we take care of device initialization.
+	 */
+	if ( grpwm_device_init(priv) ) {
+		free(dev->priv);
+		dev->priv = NULL;
+		return DRVMGR_FAIL;
+	}
+
+	/* Get Filesystem name prefix */
+	prefix[0] = '\0';
+	if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+		/* Failed to get prefix, make sure of a unique FS name
+		 * by using the driver minor.
+		 */
+		sprintf(priv->devName, "/dev/grpwm%d", dev->minor_drv);
+	} else {
+		/* Got special prefix, this means we have a bus prefix
+		 * And we should use our "bus minor"
+		 */
+		sprintf(priv->devName, "/dev/%sgrpwm%d", prefix, dev->minor_bus);
+	}
+
+	/* Register Device */
+	status = rtems_io_register_name(priv->devName, grpwm_driver_io_major,
+			dev->minor_drv);
+	if (status != RTEMS_SUCCESSFUL) {
+		return DRVMGR_FAIL;
+	}
+
+	return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static rtems_device_driver grpwm_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor, void *arg);
+static rtems_device_driver grpwm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grpwm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define GRPWM_DRIVER_TABLE_ENTRY { grpwm_initialize, grpwm_open, grpwm_close, grpwm_read, grpwm_write, grpwm_ioctl }
+
+static rtems_driver_address_table grpwm_driver = GRPWM_DRIVER_TABLE_ENTRY;
+
+int grpwm_register_io(rtems_device_major_number *m)
+{
+	rtems_status_code r;
+
+	if ((r = rtems_io_register_driver(0, &grpwm_driver, m)) == RTEMS_SUCCESSFUL) {
+		DBG("GRPWM driver successfully registered, major: %d\n", *m);
+	} else {
+		switch(r) {
+		case RTEMS_TOO_MANY:
+			DBG("GRPWM rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+			return -1;
+		case RTEMS_INVALID_NUMBER:  
+			DBG("GRPWM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+			return -1;
+		case RTEMS_RESOURCE_IN_USE:
+			DBG("GRPWM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+			return -1;
+		default:
+			DBG("GRPWM rtems_io_register_driver failed\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+void grpwm_scaler_set(struct grpwm_regs *regs, int scaler, unsigned int value)
+{
+	/* Select scaler */
+	regs->ctrl = (regs->ctrl & ~GRPWM_CTRL_SCSEL) | (scaler << GRPWM_CTRL_SCSEL_BIT);
+	/* Write scaler */
+	regs->scaler = value;
+}
+
+/* Write Wave form RAM */
+void grpwm_write_wram(struct grpwm_regs *regs, unsigned int *data, int length)
+{
+	unsigned int *end;
+	volatile unsigned int *pos;
+
+	pos = &regs->wram[0];
+
+	/* Write RAM */
+	if ( data ) {
+		end = data + length;
+		while ( data < end ) {
+			*pos++ = *data++;
+		}
+	} else {
+		while( length > 0 ) {
+			*pos++ = 0;
+			length -= 4;
+		}
+	}
+}
+
+void grpwm_hw_reset(struct grpwm_priv *priv)
+{
+	int i;
+	struct grpwm_chan_priv *pwm;
+	struct grpwm_regs *regs = priv->regs;
+
+	/* Disable Core */
+	regs->ctrl = 0;
+
+	/* Clear all registers */
+	regs->ipend = 0xffffffff;
+	regs->wctrl = 0;
+
+	/* Init all PWM channels */
+	for (i=0; i<priv->channel_cnt; i++) {
+		pwm = priv->channels[i];
+		pwm->pwmregs->ctrl = 0;
+		pwm->pwmregs->period = 0;
+		pwm->pwmregs->comp = 0;
+		pwm->pwmregs->dbcomp = 0;
+		pwm->pwmregs->ctrl = 0; /* Twice because METH and POL requires EN=0 */
+	}
+
+	/* Clear RAM */
+	if ( priv->wave ) {
+		grpwm_write_wram(regs, NULL, priv->wlength);
+	}
+
+	/* Set max scaler */
+	for (i=0; i<priv->nscalers; i++) {
+		grpwm_scaler_set(regs, i, 0xffffffff);
+	}
+}
+
+/* Update one Channel but leaves the "Hold update" bit set 
+ *
+ * A bit mask of updated bits are returned.
+ */
+unsigned int grpwm_update_prepare_channel(
+	struct grpwm_priv *priv,
+	int channel,
+	struct grpwm_ioctl_update_chan *up
+	)
+{
+	struct grpwm_chan_priv *pwm;
+	struct grpwm_pwm_regs *pwmregs;
+	unsigned int ctrl;
+	unsigned int ret;
+
+	pwm = priv->channels[channel];
+	pwmregs = pwm->pwmregs;
+
+	/* Read channel control register */
+	ctrl = pwmregs->ctrl;
+	ret = 0;
+
+	if ( up->options & GRPWM_UPDATE_OPTION_DISABLE ) {
+		ctrl &= ~GRPWM_PCTRL_EN;
+		pwmregs->ctrl = ctrl;
+		ret |= GRPWM_PCTRL_EN;
+	}
+
+	/* Hold the updates */
+	if ( up->options & (GRPWM_UPDATE_OPTION_PERIOD|
+		GRPWM_UPDATE_OPTION_COMP|GRPWM_UPDATE_OPTION_DBCOMP) )  {
+
+		if ( up->options & (GRPWM_UPDATE_OPTION_PERIOD) )  {
+			DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->period, up->period);
+			pwmregs->period = up->period;
+		}
+		if ( up->options & (GRPWM_UPDATE_OPTION_COMP) )  {
+			DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->comp, up->compare);
+			pwmregs->comp = up->compare;
+		}
+		if ( up->options & (GRPWM_UPDATE_OPTION_DBCOMP) )  {
+			DBG("GRPWM: UPDATING 0x%x: 0x%x\n", &pwmregs->dbcomp, up->dbcomp);
+			pwmregs->dbcomp = up->dbcomp;
+		}
+	}
+
+	if ( up->options & GRPWM_UPDATE_OPTION_ENABLE ) {
+		ret |= GRPWM_PCTRL_EN;
+		pwmregs->ctrl = ctrl | GRPWM_PCTRL_EN;
+	}
+	return ret;
+}
+
+void grpwm_update_active(struct grpwm_priv *priv, int enable)
+{
+	unsigned int ctrl;
+	int i;
+
+	ctrl = priv->regs->ctrl;
+
+	/* Make all "Update Hold" bits be cleared */
+	ctrl &= ~GRPWM_CTRL_NOUP;
+
+	/* A change in any of the Channel enable/disable bits? */
+	if ( enable ) {
+		ctrl &= ~GRPWM_CTRL_EN;
+		for(i=0; i<priv->channel_cnt; i++) {
+			ctrl |= priv->regs->pwms[i].ctrl & GRPWM_CTRL_EN;
+		}
+	}
+	priv->regs->ctrl = ctrl;
+}
+
+/* Configure the hardware of a channel according to this */
+rtems_status_code grpwm_config_channel(
+	struct grpwm_priv *priv,
+	int channel,
+	struct grpwm_ioctl_config *cfg
+	)
+{
+	struct grpwm_chan_priv *pwm;
+	unsigned int pctrl, wctrl=0;
+
+	pwm = priv->channels[channel];
+	if ( pwm->pwmregs->ctrl & GRPWM_PCTRL_EN_BIT ) {
+		return RTEMS_RESOURCE_IN_USE;
+	}
+	if ( cfg->options & ~GRPWM_CONFIG_OPTION_MASK ) {
+		return RTEMS_INVALID_NAME;
+	}
+	if ( (cfg->options & GRPWM_CONFIG_OPTION_DUAL) && 
+	     ((priv->regs->cap1 & GRPWM_CAP_DCM) == 0) ) {
+		return RTEMS_INVALID_NAME;
+	}
+	/* IRQ set up */
+	pwm->isr_arg = cfg->isr_arg;
+	pwm->isr = cfg->isr;
+
+	pctrl = cfg->options |
+		(cfg->dbscaler << GRPWM_PCTRL_DBSC_BIT) |
+		(cfg->irqscaler << GRPWM_PCTRL_ISC_BIT) |
+		(cfg->scaler_index << GRPWM_PCTRL_SCSEL_BIT);
+
+	/* Set Wave form gerneration if available */
+	if ( !priv->wave || (priv->channel_cnt != (channel+1)) ) {
+		/* Wave Form not available for this channel (or core) */
+		if ( cfg->wave_activate || cfg->wave_data || cfg->wave_data_length ) {
+			return RTEMS_INVALID_NAME;
+		}
+	} else if ( cfg->wave_activate ) {
+		/* Enable Wave form generation */
+		DBG("GRPWM: ENABLING WAVE FORM GENERATION 0x%x\n", cfg->wave_data_length);
+
+		if ( cfg->wave_data ) {
+			grpwm_write_wram(priv->regs, cfg->wave_data, cfg->wave_data_length);
+		}
+
+		/* Write length register, and let user control Wave-Sync functionality */
+		wctrl = (((cfg->wave_data_length-1) << GRPWM_WCTRL_STOP_BIT) & GRPWM_WCTRL_STOP);
+		wctrl |= cfg->wave_synccfg & (GRPWM_WCTRL_WSYNCCFG|GRPWM_WCTRL_WSEN);
+		wctrl |= (cfg->wave_sync << 16) & 0x1fff0000;
+		priv->regs->wctrl = wctrl;
+
+		/* Enable Wave form */
+		pctrl |= GRPWM_PCTRL_WEN;
+	}
+
+	DBG("GRPWM: CONFIG: 0x%x, WAVE CONFIG: 0x%x\n", pctrl, wctrl);
+
+	pwm->pwmregs->ctrl = pctrl;
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static void grpwm_isr(void *arg)
+{
+	unsigned int ipend;
+	struct grpwm_chan_priv *pwm = arg;
+	struct grpwm_priv *priv = pwm->common;
+	int i;
+
+	/* Get current pending interrupts */
+	ipend = priv->regs->ipend;
+
+	for (i=0; i<priv->channel_cnt; i++) {
+		if ( ipend & (1<<i) ) {
+			pwm = priv->channels[i];
+			if ( pwm->isr ) {
+				pwm->isr(i, pwm->isr_arg);
+			}
+		}
+	}
+	priv->regs->ipend = ipend;
+}
+
+static rtems_device_driver grpwm_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor, void *arg)
+{
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grpwm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	struct grpwm_priv *priv;
+	rtems_device_driver ret;
+	struct drvmgr_dev *dev;
+
+	if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) {
+		DBG("Wrong minor %d\n", minor);
+		return RTEMS_INVALID_NAME;
+	}
+	priv = (struct grpwm_priv *)dev->priv;
+
+	/* Wait until we get semaphore */
+	if ( rtems_semaphore_obtain(priv->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) !=
+	     RTEMS_SUCCESSFUL ){
+		return RTEMS_INTERNAL_ERROR;
+	}
+
+	/* is device busy/taken? */
+	if  ( priv->open ) {
+		ret=RTEMS_RESOURCE_IN_USE;
+		goto out;
+	}
+
+	/* Mark device taken */
+	priv->open = 1;
+
+	ret = RTEMS_SUCCESSFUL;
+out:
+	rtems_semaphore_release(priv->dev_sem);
+	return ret;
+}
+
+static rtems_device_driver grpwm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	struct grpwm_priv *priv;
+	struct drvmgr_dev *dev;
+
+	if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) {
+		return RTEMS_INVALID_NAME;
+	}
+	priv = (struct grpwm_priv *)dev->priv;
+
+	/* Reset Hardware */
+	grpwm_hw_reset(priv);
+
+	/* Mark Device closed */
+	priv->open = 0;
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grpwm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	return RTEMS_UNSATISFIED;
+}
+
+static rtems_device_driver grpwm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	return RTEMS_UNSATISFIED;
+}
+
+static rtems_device_driver grpwm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+
+	struct grpwm_priv *priv;
+	struct drvmgr_dev *dev;
+	rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+
+	if ( drvmgr_get_dev(&grpwm_drv_info.general, minor, &dev) ) {
+		return RTEMS_INVALID_NAME;
+	}
+	priv = (struct grpwm_priv *)dev->priv;
+
+	if (!ioarg)
+		return RTEMS_INVALID_NAME;
+
+	ioarg->ioctl_return = 0;
+	switch(ioarg->command) {
+		default: /* Not a valid command */
+			return RTEMS_NOT_DEFINED;
+
+		case GRPWM_IOCTL_GET_CAP:
+		{
+			struct grpwm_ioctl_cap *cap = (void *)ioarg->buffer;
+			if ( cap == NULL )
+				return RTEMS_INVALID_NAME;
+
+			/* Copy Capability registers to user */
+			cap->channel_cnt = priv->channel_cnt;
+			cap->pwm = priv->regs->cap1;
+			cap->wave = priv->regs->cap2;
+			break;
+		}
+		case GRPWM_IOCTL_SET_CONFIG:
+		{
+			struct grpwm_ioctl_config *cfg = (void *)ioarg->buffer;
+			if ( cfg == NULL )
+				return RTEMS_INVALID_NAME;
+			if ( cfg->channel >= priv->channel_cnt )
+				return RTEMS_INVALID_NAME;
+
+			return grpwm_config_channel(priv, cfg->channel, cfg);
+		}
+		case GRPWM_IOCTL_SET_SCALER:
+		{
+			unsigned int invalid_mask;
+			int i;
+			struct grpwm_ioctl_scaler *sc = ioarg->buffer;
+
+			if ( sc == NULL )
+				return RTEMS_INVALID_NAME;
+
+			/* Test if caller reqest to set a scaler not existing */
+			invalid_mask = ~((1 << priv->nscalers) - 1);
+			if ( invalid_mask & sc->index_mask ) {
+				return RTEMS_INVALID_NAME;
+			}
+
+			/* Set scalers requested */
+			for (i=0; i<priv->nscalers; i++) {
+				if ( sc->index_mask & (1<<i) ) {
+					/* Update Scaler 'i' */
+					grpwm_scaler_set(priv->regs, i, sc->values[i]);
+				}
+			}
+			break;
+		}
+		case GRPWM_IOCTL_UPDATE:
+		{
+			struct grpwm_ioctl_update *up = ioarg->buffer;
+			unsigned int invalid_mask, pctrl = 0;
+			int i;
+
+			if ( up == NULL )
+				return RTEMS_INVALID_NAME;
+
+			/* Test if caller reqest to set a scaler not existing */
+			invalid_mask = ~((1 << priv->channel_cnt) - 1);
+			if ( invalid_mask & up->chanmask ) {
+				return RTEMS_INVALID_NAME;
+			}
+
+			/* In order for the changes to take effect at the same time, the "Hold update"
+			 * bits is set for all PWM channels that will be updated. The hold update bits
+			 * will be cleared at the same time for all channels.
+			 */
+			priv->regs->ctrl = (priv->regs->ctrl & ~GRPWM_CTRL_NOUP) | 
+				(up->chanmask << GRPWM_CTRL_NOUP_BIT);
+
+			for (i=0; i<priv->channel_cnt; i++) {
+				if ( up->chanmask & (1<<i) ) {
+					/* Prepare update channel 'i' */
+					pctrl |= grpwm_update_prepare_channel(priv, i, &up->channels[i]);
+				}
+			}
+
+			/* 1. Update all channels requested, 
+			 * 2. Enable the core if at least one channel is enabled
+			 * 3. Disable the core if all channels are disabled
+			 */
+			grpwm_update_active(priv, (pctrl & GRPWM_PCTRL_EN));
+
+			break;
+		}
+		case GRPWM_IOCTL_IRQ:
+		{
+			unsigned int data = (unsigned int)ioarg->buffer;
+			int channel = (data >> 8) & 0x7;
+			struct grpwm_chan_priv *pwm;
+			unsigned int pctrl;
+
+			pwm = priv->channels[channel];
+
+			if ( data & GRPWM_IRQ_CLEAR ) {
+				priv->regs->ipend |= (1<<channel);
+				drvmgr_interrupt_clear(priv->dev, pwm->irqindex);
+			}
+			if ( (data & 0x3) && !pwm->isr ) {
+				/* Enable IRQ but no ISR */
+				return RTEMS_INVALID_NAME;
+			}
+			pctrl = pwm->pwmregs->ctrl & ~(GRPWM_PCTRL_IEN|GRPWM_PCTRL_IT);
+			pctrl |= ((data & 0x3) << GRPWM_PCTRL_IEN_BIT);
+			pwm->pwmregs->ctrl = pctrl;
+			break;
+		}
+	}
+
+	return RTEMS_SUCCESSFUL;
+}
+
+#define MAX_CHANNEL 8
+char grpwm_irqindex_lookup[8][MAX_CHANNEL] = 
+{
+/* Channel       1  2  3  4  5  6  7  8 */
+/* npwm 1 */	{0, 0, 0, 0, 0, 0, 0, 0},
+/* npwm 2 */	{0, 1, 0, 0, 0, 0, 0, 0},
+/* npwm 3 */	{0, 0, 0, 0, 0, 0, 0, 0},
+/* npwm 4 */	{0, 0, 0, 1, 0, 0, 0, 0},
+/* npwm 5 */	{0, 0, 0, 1, 2, 0, 0, 0},
+/* npwm 6 */	{0, 0, 0, 1, 1, 1, 0, 0},
+/* npwm 7 */	{0, 0, 0, 1, 1, 1, 2, 0},
+/* npwm 8 */	{0, 0, 0, 1, 1, 1, 2, 3}
+};
+
+int grpwm_device_init(struct grpwm_priv *priv)
+{
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	int mask, i, sepirq;
+	unsigned int wabits;
+	struct grpwm_chan_priv *pwm;
+	struct grpwm_regs *regs;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)priv->dev->businfo;
+	if ( ambadev == NULL ) {
+		return -1;
+	}
+	pnpinfo = &ambadev->info;
+	priv->irq = pnpinfo->irq;
+	regs = priv->regs = (struct grpwm_regs *)pnpinfo->apb_slv->start;
+
+	DBG("GRPWM: 0x%08x irq %d\n", (unsigned int)regs, priv->irq);
+
+	/* Disable Core */
+	regs->ctrl = 0;
+
+	/* Clear all registers */
+	regs->ipend = 0xffffffff;
+	regs->wctrl = 0;
+
+	/* Find the number of PWM channels */
+	priv->channel_cnt = 1 + ((regs->cap1 & GRPWM_CAP_NPWM) >> GRPWM_CAP_NPWM_BIT);
+	pwm = malloc(sizeof(*pwm)*priv->channel_cnt);
+	if ( !pwm )
+		return -1;
+	memset(pwm, 0, sizeof(*pwm)*priv->channel_cnt);
+
+	/* Init all PWM channels */
+	sepirq = ((regs->cap1 & GRPWM_CAP_SEP) >> GRPWM_CAP_SEP_BIT);
+	for (i=0; i<priv->channel_cnt; i++, pwm++) {
+		priv->channels[i] = pwm;
+		pwm->common = priv;
+		pwm->pwmregs = &regs->pwms[i];
+		if ( sepirq == 0 ) {
+			pwm->irqindex = 0;
+		} else if ( sepirq == 1 ) {
+			pwm->irqindex = i;
+		} else {
+			pwm->irqindex = grpwm_irqindex_lookup[priv->channel_cnt][i];
+		}
+	}
+
+	/* Detect if Wave Form capability is availble for last PWM channel */
+	if ( regs->cap2 & GRPWM_CAP2_WPWM ) {
+		priv->wave = 1;
+
+		/* Clear RAM */
+		wabits = (regs->cap2 & GRPWM_CAP2_WABITS) >> GRPWM_CAP2_WABITS_BIT;
+		priv->wlength = 1 << wabits;
+	}
+	priv->nscalers = 1 + ((regs->cap1 & GRPWM_CAP_NSC) >> GRPWM_CAP_NSC_BIT);
+
+	grpwm_hw_reset(priv);
+
+	/* Device Semaphore created with count = 1 */
+	if ( rtems_semaphore_create(rtems_build_name('G', 'P', 'W', 'M'),
+		1,
+		RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+		RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+		0,
+		&priv->dev_sem) != RTEMS_SUCCESSFUL ) {
+		return -1;
+	}
+
+	/* Register interrupt handler for all PWM channels */
+	mask = 0;
+	for (i=0; i<priv->channel_cnt; i++) {
+		pwm = priv->channels[i];
+		if ( (mask & (1 << pwm->irqindex)) == 0 ) {
+			/* Not registered interrupt handler for this IRQ index before,
+			 * we do it now.
+			 */
+			mask |= (1 << pwm->irqindex);
+			drvmgr_interrupt_register(
+				priv->dev,
+				pwm->irqindex,
+				"grpwm",
+				grpwm_isr,
+				pwm);
+		}
+	}
+
+	return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/slink/grslink.c b/c/src/lib/libbsp/sparc/shared/slink/grslink.c
new file mode 100644
index 0000000..0c3d086
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/slink/grslink.c
@@ -0,0 +1,661 @@
+/*
+ * This file contains the RTEMS GRSLINK SLINK master driver
+ *
+ * COPYRIGHT (c) 2009.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * Comments concerning current driver implementation:
+ *
+ * The SLINK specification says that there are three IO cards that are capable 
+ * of transmitting data. But these IO cards can have the address range 0 to 3, 
+ * and an 'For information only' comment explains that the current 
+ * implementation has receive buffers for ".. x 4 (IO cards)".
+ * Because of this the driver has four queues, one for each IO card 0 - 3. 
+ * When the addressing convention used for the IO cards is known, the number of
+ * queues may be lowered to three.
+ *
+ */
+
+#include <stdlib.h>
+
+#include <bsp.h>
+#include <grslink.h>
+#include <ambapp.h>
+
+#ifndef GAISLER_SLINK
+#define GAISLER_SLINK 0x02F
+#endif
+
+/* Enable debug output? */
+/* #define DEBUG */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...) 
+#endif
+
+/* Bits and fields in SLINK transmit word */
+#define SLINK_RW (1 << 23)
+#define SLINK_CHAN_POS 16
+
+/* Local types */
+typedef struct {
+	volatile unsigned int clockscale;
+	volatile unsigned int ctrl;
+	volatile unsigned int nullwrd;
+	volatile unsigned int sts;
+	volatile unsigned int msk;
+	volatile unsigned int abase;
+	volatile unsigned int bbase;
+	volatile unsigned int td;
+	volatile unsigned int rd;
+} SLINK_regs;
+
+typedef struct {
+	char readstat;         /* Status of READ operation */
+	char seqstat;          /* Status of SEQUENCE operation */
+	unsigned char scnt;    /* Number of SEQUENCE words transferred */
+} SLINK_status;
+
+typedef struct {
+	int size;
+	unsigned int *buf;
+	unsigned int *first;
+	unsigned int *last;
+	unsigned int *max;
+	int full;
+} SLINK_queue;
+
+typedef struct {
+	SLINK_regs    *reg;     /* Pointer to core registers */
+	SLINK_status  *status;  /* Driver status information */
+	void          (*slink_irq_handler)(int); /* Handler for INTERRUPT */
+	void          (*slink_seq_change)(int); /* Callback on SEQUENCE change */
+	int           rword;    /* Placeholder for READ response */
+	rtems_id      read_sem; /* Semaphore for blocking SLINK_read */
+	SLINK_queue   *queues;  /* Receive queues */
+#ifdef SLINK_COLLECT_STATISTICS
+	SLINK_stats   *stats;   /* Core statistics, optional */
+#endif
+} SLINK_cfg;
+
+
+static SLINK_cfg *cfg = NULL;
+
+/**** SLINK driver queues for unsolicited and INTERRUPT requests ****/
+
+/* Function: SLINK_createqueues
+ * Arguments: size: Number of elements in each queue
+ * Returns: 0 on success, -1 on failure
+ * Description: Creates SLINK_NUMQUEUES queues, one for each IO card 
+ * that can send data. The pointers to the queues is saved in the driver 
+ * config structure.
+ */
+static int SLINK_createqueues(int size)
+{
+	SLINK_queue *q;
+	int i, j;
+
+	if ((q = malloc(SLINK_NUMQUEUES*sizeof(SLINK_queue))) == NULL)
+		goto slink_qiniterr1;
+		
+	for (i = 0; i < SLINK_NUMQUEUES; i++) {
+		q[i].size = size;
+		if ((q[i].buf = malloc(size*sizeof(int))) == NULL)
+			goto slink_qiniterr2;
+		q[i].first = q[i].last = q[i].buf;
+		q[i].max = q[i].buf + (size-1);
+		q[i].full = 0;
+	}
+
+       	cfg->queues = q;
+
+	return 0;
+	
+ slink_qiniterr2:
+	for (j = 0; j < i; j++)
+		free(q[i].buf);
+	free(q);
+ slink_qiniterr1:
+	return -1;
+}
+
+/*
+ * Function: SLINK_destroyqueues
+ * Arguments: None
+ * Returns: Nothing
+ * Description: Frees the memory occupied by the queues in cfg->queues
+ */
+/*
+  static void SLINK_destroyqueues(void)
+  {
+        int i;
+	
+	for(i = 0; i < SLINK_NUMQUEUES; i++)
+		free(cfg->queues[i].buf);
+
+	free(cfg->queues);
+}
+*/
+
+/*
+ * Function: SLINK_enqueue
+ * Arguments: Received SLINK word
+ * Returns: Nothing
+ * Description: 
+ */
+static void SLINK_enqueue(unsigned int slink_wrd)
+{
+	SLINK_queue *ioq = cfg->queues + SLINK_WRD_CARDNUM(slink_wrd); 
+
+	if (!ioq->full && SLINK_WRD_CARDNUM(slink_wrd) < SLINK_NUMQUEUES) {
+		*ioq->last = slink_wrd;
+		ioq->last = (ioq->last >= ioq->max) ? ioq->buf : ioq->last+1;
+		ioq->full = ioq->last == ioq->first;
+		return;
+	}
+#ifdef SLINK_COLLECT_STATISTICS
+	cfg->stats->lostwords++;
+#endif
+}
+
+/**** SLINK driver helper functions ****/
+
+/*
+ * Function: SLINK_getaddr
+ * Arguments: amba_conf 
+ *            base: assigned to base of core registers
+ *            irq: assigned to core irq lines
+ * Returns: Base address and IRQ via arguments, 0 if core is found, else -1
+ * Description: See above.
+ */
+static int SLINK_getaddr(int *base, int *irq)
+{	
+	struct ambapp_apb_info c;
+
+	if (ambapp_find_apbslv(&ambapp_plb,VENDOR_GAISLER,GAISLER_SLINK,&c) == 1) {
+		*base = c.start;
+		*irq = c.irq;
+		return 0;
+	}
+	return -1;
+}
+
+/* Function: SLINK_calcscaler
+ * Arguments: sysfreq: System frequency in Hz
+ * Returns: Clock scaler register value
+ * Description: Calculates value for SLINK clock scaler register to attain
+ * a SLINK bus frequency as close to 6 MHz as possible. Please see the IP core 
+ * documentation for a description of how clock scaling is implemented. 
+ */
+static int SLINK_calcscaler(int sysfreq)
+{
+	int fact = sysfreq / SLINK_FREQ_HZ;
+	return ((fact/2-1) << 16) | (fact % 2 ? fact/2 : fact/2-1);  
+}
+
+
+/*
+ * Function: SLINK_getsysfreq
+ * Arguments: None
+ * Returns: System frequency in Hz, or 0 if system timer is not found.
+ * Description: Looks at the timer to determine system frequency. Makes use
+ * of AMBA Plug'n'Play. 
+ */
+static int SLINK_getsysfreq(void)
+{
+	struct ambapp_apb_info t;
+	struct gptimer_regs *tregs;
+		
+	if (ambapp_find_apbslv(&ambapp_plb,VENDOR_GAISLER,GAISLER_GPTIMER,&t)==1) {
+		tregs = (struct gptimer_regs *)t.start;
+		DBG("SLINK_getsysfreq returning %d\n", 
+		    (tregs->scaler_reload+1)*1000*1000);
+		return (tregs->scaler_reload+1)*1000*1000;
+	}
+	return 0;
+}
+
+/*
+ * Function: SLINK_interrupt_handler
+ * Arguments: v: not used
+ * Returns: Nothing
+ * Description: Interrupt handles checks RNE, SEQUENCE and error status
+ * bits. Reads word from receive queue and distinguishes between INTERRUPT,
+ * READ responses and SLAVE-WORD-SEND. When an INTERRUPT transfer is detected
+ * the handler calls the user specified slink_irq_handler with the received
+ * word. READ responses are saved and given to SLINK_read via a private
+ * variable. SLAVE-WORD-SEND transfers are placed in the IO card's receive
+ * queue.
+ */
+static rtems_isr SLINK_interrupt_handler(rtems_vector_number v)
+{
+	unsigned int sts;
+	unsigned int wrd;
+
+	/* Read all words from Receive queue */
+	while ((sts = cfg->reg->sts) & SLINK_S_RNE) {
+
+		/* Read first word in receive queue */
+		wrd = cfg->reg->rd;
+	
+		/* Check channel value to determine action */
+		switch (SLINK_WRD_CHAN(wrd)) {
+		case 0: /* Interrupt */
+			cfg->slink_irq_handler(wrd);
+#ifdef SLINK_COLLECT_STATISTICS
+			cfg->stats->interrupts++;
+#endif
+			break;
+		case 3: /* Read response, if no active READ, fall-through */
+			if (cfg->status->readstat == SLINK_ACTIVE) {
+				rtems_semaphore_release(cfg->read_sem);
+				cfg->status->readstat = SLINK_COMPLETED;
+				cfg->rword = wrd;
+				break;
+			}
+		default: /* Unsolicited request */
+			SLINK_enqueue(wrd);
+			break;
+		}
+	}
+
+	/* Check sequence operation */
+	if (sts & SLINK_S_SC) {
+		/* SEQUENCE completed */
+		cfg->status->seqstat = SLINK_COMPLETED;
+		if (cfg->slink_seq_change)
+			cfg->slink_seq_change(SLINK_COMPLETED);
+#ifdef SLINK_COLLECT_STATISTICS
+		cfg->stats->seqcomp++;
+#endif
+	} else if (sts & SLINK_S_SA) {
+		/* SEQUENCE aborted */
+		cfg->status->seqstat = SLINK_ABORTED;
+		cfg->status->scnt = (sts >> SLINK_S_SI_POS);
+		if (cfg->slink_seq_change)
+			cfg->slink_seq_change(SLINK_ABORTED);
+	}
+
+	/* Check error conditions */
+	if (sts & SLINK_S_PERR) {
+		/* 
+		   Parity error detected, set seqstat if there is an ongoing 
+		   sequence so that the calling application can decide if the
+		   sequence should be aborted 
+		*/
+		if (cfg->status->seqstat == SLINK_ACTIVE) {
+			cfg->status->seqstat = SLINK_PARERR;
+			if (cfg->slink_seq_change)
+				cfg->slink_seq_change(SLINK_PARERR);
+		}
+		/* Abort READ operation */
+		if (cfg->status->readstat == SLINK_ACTIVE) {
+			cfg->status->readstat = SLINK_PARERR;
+			rtems_semaphore_release(cfg->read_sem);
+		}
+#ifdef SLINK_COLLECT_STATISTICS
+		cfg->stats->parerr++;
+#endif
+	} 
+	if (sts & SLINK_S_AERR) {
+		/* AMBA error response, sequence aborted */
+		cfg->status->seqstat = SLINK_AMBAERR;
+		cfg->status->scnt = sts >> SLINK_S_SI_POS;
+		if (cfg->slink_seq_change)
+			cfg->slink_seq_change(SLINK_AMBAERR);
+	}
+	if (sts & SLINK_S_ROV) {
+		/* Receive overflow, abort any ongoing READ */ 
+		if (cfg->status->readstat == SLINK_ACTIVE) {
+			cfg->status->readstat = SLINK_ROV;
+			rtems_semaphore_release(cfg->read_sem);
+		}
+#ifdef SLINK_COLLECT_STATISICS
+		cfg->status->recov++;
+#endif
+	}
+
+	/* Clear processed bits */
+	cfg->reg->sts = sts;
+}
+
+/**** SLINK driver interface starts here ****/
+
+/* Function: SLINK_init
+ * Arguments: nullwrd: NULL word
+ *            parity: Even (0) or Odd (1) parity
+ *            interrupt_trans_handler: Function that handles interrupt requests
+ *            sequence_callback: Callback on SEQUENCE status changes
+ *            qsize: Size of each receive queue
+ * Returns: 0 on success, -1 on failure
+ * Description: Initializes the SLINK core
+ */
+int SLINK_init(unsigned int nullwrd, int parity, int qsize,
+	       void (*interrupt_trans_handler)(int),
+	       void (*sequence_callback)(int))
+{
+	int base;
+	int irq;
+	rtems_status_code st;
+
+	/* Allocate private config structure */
+	if (cfg == NULL && (cfg = malloc(sizeof(SLINK_cfg))) == NULL) {
+		DBG("SLINK_init: Could not allocate cfg structure\n");
+		goto slink_initerr1;
+	}
+	
+	/* Create simple binary semaphore for blocking SLINK_read */
+	st = rtems_semaphore_create(rtems_build_name('S', 'L', 'R', '0'), 0, 
+				    (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
+				     RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
+				     RTEMS_NO_PRIORITY_CEILING), 0,
+				    &cfg->read_sem);
+	if (st != RTEMS_SUCCESSFUL) {
+		DBG("SLINK_init: Could not create semaphore\n");
+		goto slink_initerr1;
+	}
+  
+	/* Initialize pointer to SLINK core registers and get IRQ line */
+	if (SLINK_getaddr(&base, &irq) == -1) {
+		DBG("SLINK_init: Could not find core\n");
+		goto slink_initerr2;
+	}
+	cfg->reg = (SLINK_regs*)base;
+
+	/* Allocate status structure and initialize members */
+	if ((cfg->status = calloc(1, sizeof(SLINK_status))) == NULL) {
+		DBG("SLINK_init: Could not allocate status structure\n");
+		goto slink_initerr2;
+	}
+	cfg->status->seqstat = SLINK_COMPLETED;
+	cfg->status->readstat = SLINK_COMPLETED;
+
+#ifdef SLINK_COLLECT_STATISTICS
+	/* Allocate statistics structure and initialize members */
+	if ((cfg->stats = calloc(1, sizeof(SLINK_stats))) == NULL) {
+		DBG("SLINK_init: Could not allocate statistics structure\n");
+		goto slink_initerr3;
+	}
+#endif
+
+	/* Allocate and initialize queues */
+	if (SLINK_createqueues(qsize) == -1) {
+		DBG("SLINK_init: Could not create queues\n");
+		goto slink_initerr3;
+	}
+
+	/* Configure core registers */
+	cfg->reg->clockscale = SLINK_calcscaler(SLINK_getsysfreq());
+	cfg->reg->ctrl = parity ? SLINK_C_PAR : 0;
+	cfg->reg->nullwrd = nullwrd;
+	cfg->reg->msk = (SLINK_M_PERRE | SLINK_M_AERRE | SLINK_M_ROVE |
+			 SLINK_M_RNEE | SLINK_M_SAE | SLINK_M_SCE);
+
+	/* Set-up INTERRUPT transfer handling */
+	cfg->slink_irq_handler = interrupt_trans_handler;
+
+	/* Save SEQUENCE callback */
+	cfg->slink_seq_change = sequence_callback;
+
+	/* Set-up IRQ handling */
+	set_vector(SLINK_interrupt_handler,irq+0x10,2);
+	
+	return 0;
+
+ slink_initerr3:
+	free(cfg->status);
+ slink_initerr2:
+	free(cfg);
+ slink_initerr1:
+	return -1;
+}
+
+/* Function: SLINK_start
+ * Description: Enables the core
+ */
+void SLINK_start(void)
+{   
+	if (cfg != NULL)
+		cfg->reg->ctrl |= SLINK_C_SLE;
+}
+
+/* Function: SLINK_stop
+ * Description: Disables the core
+ */
+void SLINK_stop(void)
+{
+	if (cfg != NULL)
+		cfg->reg->ctrl &= ~SLINK_C_SLE;
+}
+
+/*
+ * Function: SLINK_read
+ * Arguments: data: Payload of data word
+ *            channel: -
+ *            reply: Reply from IO card
+ * Returns: 0 on success
+ *          -(SLINK_PARERR, SLINK_ROV) on error or -SLINK_QFULL if transmit queue
+ *          is full and software should try again.
+ * Description: Reads one word and returns the response in *reply unless there
+ *              is an error. This function blocks until the READ operation is
+ *              completed or aborted.
+ */
+int SLINK_read(int data, int channel, int *reply)
+{	
+	DBG("SLINK_read: called..");
+
+	if (cfg->reg->sts & SLINK_S_TNF) {
+		cfg->status->readstat = SLINK_ACTIVE;
+		cfg->reg->td = SLINK_RW | channel << SLINK_CHAN_POS | data;
+	} else {
+		DBG("queue FULL\n");
+		return -SLINK_QFULL; /* Transmit queue full */
+	}
+
+	/* Block until the operation has completed or has been aborted */
+	rtems_semaphore_obtain(cfg->read_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+
+	if (cfg->status->readstat == SLINK_COMPLETED) {
+		*reply = cfg->rword; 
+#ifdef SLINK_COLLECT_STATISTICS
+		cfg->stats->reads++;
+#endif       
+		DBG("returning 0\n");
+		return 0;
+	} else {
+		DBG("returning error code\n");
+		return -cfg->status->readstat;
+	}
+}
+
+/*
+ * Function: SLINK_write
+ * Arguments: data: Payload of SLINK data word
+ *            channel: Channel value (bits 22 downto 16) of receive 
+ *                     register word
+ * Returns: 0 if command was placed in transmit queue
+ *          -SLINK_QFULL if transmit queue was full (software should retry)
+ * Description: See above.
+ */
+int SLINK_write(int data, int channel)
+{ 
+	if (cfg->reg->sts & SLINK_S_TNF) {
+		cfg->reg->td = channel << SLINK_CHAN_POS | data;
+#ifdef SLINK_COLLECT_STATISTICS
+		cfg->stats->writes++;
+#endif
+		return 0;
+	}
+
+	return -SLINK_QFULL;	
+}
+
+/*
+ * Function: SLINK_sequence
+ * Arguments: a: Array containing sequence commands
+ *            b: Array where SEQUENCE responses will be stored
+ *            n: Number of commands in a array
+ *            channel: Sequence Channel Number
+ *            reconly: Set to 1 if the SEQUENCE operation is receive only
+ * Returns: 0 if SEQUENCE could be started (SUCCESS)
+ *          -1 if SEQUNCE was not started due to ongoing SEQUENCE
+ */
+int SLINK_seqstart(int *a, int *b, int n, int channel, int reconly)
+{  
+	/* Only start a new SEQUENCE of the former SEQUENCE has completed */
+	if (cfg->status->seqstat == SLINK_ACTIVE || 
+	    cfg->status->seqstat == SLINK_PARERR)
+		return -1;
+
+	/* Tell core about arrays */
+	cfg->reg->abase = (int)a;
+	cfg->reg->bbase = (int)b;
+	
+	/* As far as software is concerned the sequence is now active */
+	cfg->status->seqstat = SLINK_ACTIVE;
+
+	/* Enable SEQUENCE operation with SCN = channel and SLEN = n-1 */
+        if (reconly == 1) {
+           cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) | SLINK_C_SRO |
+                             (channel << SLINK_C_SCN_POS) |
+                             SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
+        } else {
+           cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) |
+                             (channel << SLINK_C_SCN_POS) |
+                             SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
+        }
+
+#ifdef SLINK_COLLECT_STATISTICS
+	cfg->stats->sequences++;
+#endif
+
+	return 0;
+}
+
+
+/* Function: SLINK_seqabort
+ * Description: This function aborts an ongoing SEQUENCE. Software can tell
+ * when the SEQUENCE is aborted by polling SLINK_seqstat().
+ */
+void SLINK_seqabort(void)
+{
+	cfg->reg->ctrl = cfg->reg->ctrl | SLINK_C_AS;
+}
+
+
+/*
+ * Function: SLINK_seqstatus
+ * Returns: The current or status of the SEQUENCE operation:
+ *          SLINK_COMPLETED, SLINK_ACTIVE, SLINK_PARERR, SLINK_AMBAERR,
+ *          SLINK_ABORTED (these are defined in grslink.h)
+ * Description: Meaning of returned values:
+ *              SLINK_ABORTED: Aborted before all operations completed.
+ *              SLINK_ACTIVE: The core is busy processing the SEQUENCE
+ *              SLINK_AMBAERR: The last SEQUENCE was aborted by an AMBA ERROR
+ *              SLINK_COMPLETED: All words were transferred in the last SEQUENCE
+ *              SLINK_PARERR: Parity error detected. Software may want to abort
+ *
+ *              If the SEQUENCE was aborted SLINK_seqwrds() can be used to
+ *              determine the number of completed operations.
+ */
+int SLINK_seqstatus(void)
+{
+	return cfg->status->seqstat;
+}
+
+/*
+ * Function: SLINK_seqwrds
+ * Returns: -1 for ongoing sequence
+ *          0 if all words were transferred in the last sequence
+ *          number of words if the last SEQUENCE did not complete 
+ *          (SLINK_AMBAERR or SLINK_ABORTED is reported ny SLINK_seqstatus()) 
+ */
+int SLINK_seqwrds(void)
+{
+	switch (cfg->status->seqstat) {
+	case SLINK_COMPLETED: return 0;
+	case SLINK_ACTIVE | SLINK_PARERR: return -1;
+	default: return cfg->status->scnt;
+	}
+}
+
+/* 
+ * Function: SLINK_hwstatus
+ * Returns: The SLINK core's status register. The register values can be 
+ *          interpreted with the help of macros defined in grslink.h.
+ */
+int SLINK_hwstatus(void)
+{
+	return cfg->reg->sts;
+}
+
+/*
+ * Function: SLINK_queuestatus
+ * Arguments: iocard: Queue which to check status for
+ * Returns: Number of elements in queue or -1 on non-existent queue
+ * Description: SLINK_queuestatus(queue) returns the number of elements in
+ *              queue 'iocard'
+ */
+int SLINK_queuestatus(int iocard)
+{	
+	unsigned int first, last;
+	SLINK_queue *ioq;
+	
+	if (iocard >= SLINK_NUMQUEUES)
+		return -1;
+
+	ioq = cfg->queues + iocard;
+
+	if (ioq->full)
+		return ioq->size;
+	if (ioq->first == ioq->last)
+		return 0;
+
+	first = ((unsigned int)ioq->first)/sizeof(unsigned int);
+	last = ((unsigned int)ioq->last)/sizeof(unsigned int);
+	
+	return first < last ? last - first : ioq->size - first + last; 
+}
+
+/*
+ * Function: SLINK_dequeue
+ * Arguments: iocard: IO card number
+ *            elem: First element in IO card queue
+ * Returns: 0 on success or -1 on empty or non-existent queue
+ * Description: 
+ */
+int SLINK_dequeue(int iocard, int *elem)
+{	
+	if (iocard >= SLINK_NUMQUEUES)
+		return -1;
+	
+	SLINK_queue *ioq = cfg->queues + iocard;
+	
+	if (ioq->last != ioq->first || ioq->full) {
+		*elem = *ioq->first;
+		ioq->first = (ioq->first >= ioq->max) ? ioq->buf : ioq->first+1;
+		ioq->full = 0;
+		return 0;
+	}
+	return -1;
+}
+
+/*
+ * Function: SLINK_statistics
+ * Returns: If the core has statistics colletion enabled this function returns
+ * a pointer to a struct containing statistics information, otherwise NULL.
+ */
+SLINK_stats *SLINK_statistics(void)
+{
+#ifdef SLINK_COLLECT_STATISTICS
+	return cfg->stats;
+#else
+	return NULL;
+#endif
+}
diff --git a/c/src/lib/libbsp/sparc/shared/spi/spictrl.c b/c/src/lib/libbsp/sparc/shared/spi/spictrl.c
new file mode 100644
index 0000000..b149a95
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/spi/spictrl.c
@@ -0,0 +1,1008 @@
+/*
+ *  SPICTRL SPI driver implmenetation
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <spictrl.h>
+#include <ambapp.h>
+
+#include <rtems/libi2c.h>
+
+/*#define DEBUG 1*/
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#define STATIC
+#else
+#define DBG(x...) 
+#define STATIC static
+#endif
+
+/*** CAPABILITY REGISTER 0x00 ***/
+#define SPICTRL_CAP_SSSZ_BIT	24
+#define SPICTRL_CAP_AMODE_BIT	18
+#define SPICTRL_CAP_ASELA_BIT	17
+#define SPICTRL_CAP_SSEN_BIT	16
+#define SPICTRL_CAP_FDEPTH_BIT	8
+#define SPICTRL_CAP_REV_BIT	0
+
+#define SPICTRL_CAP_SSSZ	(0xff << SPICTRL_CAP_SSSZ_BIT)
+#define SPICTRL_CAP_AMODE	(1<<SPICTRL_CAP_AMODE_BIT)
+#define SPICTRL_CAP_ASELA	(1<<SPICTRL_CAP_ASELA_BIT)
+#define SPICTRL_CAP_SSEN	(1 << SPICTRL_CAP_SSEN_BIT)
+#define SPICTRL_CAP_FDEPTH	(0xff << SPICTRL_CAP_FDEPTH_BIT)
+#define SPICTRL_CAP_REV		(0xff << SPICTRL_CAP_REV_BIT)
+
+/*** MODE REGISTER 0x20 ***/
+#define SPICTRL_MODE_AMEN_BIT	31
+#define SPICTRL_MODE_LOOP_BIT	30
+#define SPICTRL_MODE_CPOL_BIT	29
+#define SPICTRL_MODE_CPHA_BIT	28
+#define SPICTRL_MODE_DIV16_BIT	27
+#define SPICTRL_MODE_REV_BIT	26
+#define SPICTRL_MODE_MS_BIT	25
+#define SPICTRL_MODE_EN_BIT	24
+#define SPICTRL_MODE_LEN_BIT	20
+#define SPICTRL_MODE_PM_BIT	16
+#define SPICTRL_MODE_ASEL_BIT	14
+#define SPICTRL_MODE_FACT_BIT	13
+#define SPICTRL_MODE_CG_BIT	7
+#define SPICTRL_MODE_TAC_BIT	4
+
+#define SPICTRL_MODE_AMEN	(1 << SPICTRL_MODE_AMEN_BIT)
+#define SPICTRL_MODE_LOOP	(1 << SPICTRL_MODE_LOOP_BIT)
+#define SPICTRL_MODE_CPOL	(1 << SPICTRL_MODE_CPOL_BIT)
+#define SPICTRL_MODE_CPHA	(1 << SPICTRL_MODE_CPHA_BIT)
+#define SPICTRL_MODE_DIV16	(1 << SPICTRL_MODE_DIV16_BIT)
+#define SPICTRL_MODE_REV	(1 << SPICTRL_MODE_REV_BIT)
+#define SPICTRL_MODE_MS		(1 << SPICTRL_MODE_MS_BIT)
+#define SPICTRL_MODE_EN		(1 << SPICTRL_MODE_EN_BIT)
+#define SPICTRL_MODE_LEN	(0xf << SPICTRL_MODE_LEN_BIT)
+#define SPICTRL_MODE_PM		(0xf << SPICTRL_MODE_PM_BIT)
+#define SPICTRL_MODE_ASEL	(1 << SPICTRL_MODE_ASEL_BIT)
+#define SPICTRL_MODE_FACT	(1 << SPICTRL_MODE_FACT_BIT)
+#define SPICTRL_MODE_CG		(0x1f << SPICTRL_MODE_CG_BIT)
+#define SPICTRL_MODE_TAC	(0x1 << SPICTRL_MODE_TAC_BIT)
+
+/*** EVENT REGISTER 0x24 ***/
+#define SPICTRL_EVENT_AT_BIT	15
+#define SPICTRL_EVENT_LT_BIT	14
+#define SPICTRL_EVENT_OV_BIT	12
+#define SPICTRL_EVENT_UN_BIT	11
+#define SPICTRL_EVENT_MME_BIT	10
+#define SPICTRL_EVENT_NE_BIT	9
+#define SPICTRL_EVENT_NF_BIT	8
+
+#define SPICTRL_EVENT_AT	(1 << SPICTRL_EVENT_AT_BIT)
+#define SPICTRL_EVENT_LT	(1 << SPICTRL_EVENT_LT_BIT)
+#define SPICTRL_EVENT_OV	(1 << SPICTRL_EVENT_OV_BIT)
+#define SPICTRL_EVENT_UN	(1 << SPICTRL_EVENT_UN_BIT)
+#define SPICTRL_EVENT_MME	(1 << SPICTRL_EVENT_MME_BIT)
+#define SPICTRL_EVENT_NE	(1 << SPICTRL_EVENT_NE_BIT)
+#define SPICTRL_EVENT_NF	(1 << SPICTRL_EVENT_NF_BIT)
+
+/*** MASK REGISTER 0x28 ***/
+#define SPICTRL_MASK_ATE_BIT	15
+#define SPICTRL_MASK_LTE_BIT	14
+#define SPICTRL_MASK_OVE_BIT	12
+#define SPICTRL_MASK_UNE_BIT	11
+#define SPICTRL_MASK_MMEE_BIT	10
+#define SPICTRL_MASK_NEE_BIT	9
+#define SPICTRL_MASK_NFE_BIT	8
+
+#define SPICTRL_MASK_ATE	(1 << SPICTRL_MASK_ATE_BIT)
+#define SPICTRL_MASK_LTE	(1 << SPICTRL_MASK_LTE_BIT)
+#define SPICTRL_MASK_OVE	(1 << SPICTRL_MASK_OVE_BIT)
+#define SPICTRL_MASK_UNE	(1 << SPICTRL_MASK_UNE_BIT)
+#define SPICTRL_MASK_MMEE	(1 << SPICTRL_MASK_MMEE_BIT)
+#define SPICTRL_MASK_NEE	(1 << SPICTRL_MASK_NEE_BIT)
+#define SPICTRL_MASK_NFE	(1 << SPICTRL_MASK_NFE_BIT)
+
+/*** COMMAND REGISTER 0x2c ***/
+#define SPICTRL_CMD_LST_BIT	22
+#define SPICTRL_CMD_LST		(1 << SPICTRL_CMD_LST_BIT)
+
+/*** TRANSMIT REGISTER 0x30 ***/
+#define SPICTRL_TX_TDATA_BIT	0
+#define SPICTRL_TX_TDATA	0xffffffff
+
+/*** RECEIVE REGISTER 0x34 ***/
+#define SPICTRL_RX_RDATA_BIT	0
+#define SPICTRL_RX_RDATA	0xffffffff
+
+/*** SLAVE SELECT REGISTER 0x38 - VARIABLE ***/
+
+/*** AM CONFIGURATION REGISTER 0x40 ***/
+#define SPICTRL_AMCFG_ERPT_BIT		6
+#define SPICTRL_AMCFG_SEQ_BIT		5
+#define SPICTRL_AMCFG_STRICT_BIT	4
+#define SPICTRL_AMCFG_OVTB_BIT		3
+#define SPICTRL_AMCFG_OVDB_BIT		2
+#define SPICTRL_AMCFG_ACT_BIT		1
+#define SPICTRL_AMCFG_EACT_BIT		0
+
+#define SPICTRL_AMCFG_ERPT	(1<<SPICTRL_AMCFG_ERPT_BIT)
+#define SPICTRL_AMCFG_SEQ	(1<<SPICTRL_AMCFG_SEQ_BIT)
+#define SPICTRL_AMCFG_STRICT	(1<<SPICTRL_AMCFG_STRICT_BIT)
+#define SPICTRL_AMCFG_OVTB	(1<<SPICTRL_AMCFG_OVTB_BIT)
+#define SPICTRL_AMCFG_OVDB	(1<<SPICTRL_AMCFG_OVDB_BIT)
+#define SPICTRL_AMCFG_ACT	(1<<SPICTRL_AMCFG_ACT_BIT)
+#define SPICTRL_AMCFG_EACT	(1<<SPICTRL_AMCFG_EACT_BIT)
+
+struct spictrl_priv {
+	rtems_libi2c_bus_t		i2clib_desc;
+	struct drvmgr_dev	*dev;
+	struct spictrl_regs		*regs;
+	int				irq;
+	int				minor;
+	unsigned int			core_freq_hz;
+
+	/* Driver */
+	int				fdepth;
+	int				bits_per_char;
+	int				lsb_first;
+	int				txshift;
+	int				rxshift;
+	unsigned int			idle_char;
+	int				(*slvSelFunc)(void *regs, uint32_t addr, int select);
+	
+	/* Automated Periodic transfers */
+	int				periodic_started;
+	struct spictrl_ioctl_config	periodic_cfg;
+};
+
+/******************* Driver Manager Part ***********************/
+
+int spictrl_device_init(struct spictrl_priv *priv);
+
+int spictrl_init2(struct drvmgr_dev *dev);
+int spictrl_init3(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops spictrl_ops = 
+{
+	.init = {NULL, spictrl_init2, spictrl_init3, NULL},
+	.remove = NULL,
+	.info = NULL
+};
+
+struct amba_dev_id spictrl_ids[] =
+{
+	{VENDOR_GAISLER, GAISLER_SPICTRL},
+	{0, 0}		/* Mark end of table */
+};
+
+struct amba_drv_info spictrl_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,				/* Driver */
+		NULL,					/* Next driver */
+		NULL,					/* Device list */
+		DRIVER_AMBAPP_GAISLER_SPICTRL_ID,	/* Driver ID */
+		"SPICTRL_DRV",				/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,			/* Bus Type */
+		&spictrl_ops,
+		NULL,					/* Funcs */
+		0,					/* No devices yet */
+		0,
+	},
+	&spictrl_ids[0]
+};
+
+void spictrl_register_drv (void)
+{
+	DBG("Registering SPICTRL driver\n");
+	drvmgr_drv_register(&spictrl_drv_info.general);
+}
+
+int spictrl_init2(struct drvmgr_dev *dev)
+{
+	struct spictrl_priv *priv;
+
+	DBG("SPICTRL[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+	priv = dev->priv = malloc(sizeof(struct spictrl_priv));
+	if ( !priv )
+		return DRVMGR_NOMEM;
+	memset(priv, 0, sizeof(*priv));
+	priv->dev = dev;
+
+	/* This core will not find other cores, so we wait for init2() */
+
+	return DRVMGR_OK;
+}
+
+int spictrl_init3(struct drvmgr_dev *dev)
+{
+	struct spictrl_priv *priv;
+	char prefix[32];
+	char devName[32];
+	int rc;
+
+	priv = (struct spictrl_priv *)dev->priv;
+
+	/* Do initialization */
+
+	/* Initialize i2c library */
+	rc = rtems_libi2c_initialize();
+	if (rc != 0) {
+		DBG("SPICTRL: rtems_libi2c_initialize failed, exiting...\n");
+		free(dev->priv);
+		dev->priv = NULL;
+		return DRVMGR_FAIL;
+	}
+
+	/* I/O system registered and initialized 
+	 * Now we take care of device initialization.
+	 */
+
+	/* Get frequency */
+	if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->core_freq_hz) ) {
+		return DRVMGR_FAIL;
+	}
+
+	if ( spictrl_device_init(priv) ) {
+		free(dev->priv);
+		dev->priv = NULL;
+		return DRVMGR_FAIL;
+	}
+
+	/* Get Filesystem name prefix */
+	prefix[0] = '\0';
+	if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+		/* Failed to get prefix, make sure of a unique FS name
+		 * by using the driver minor.
+		 */
+		sprintf(devName, "/dev/spi%d", dev->minor_drv+1);
+	} else {
+		/* Got special prefix, this means we have a bus prefix
+		 * And we should use our "bus minor"
+		 */
+		sprintf(devName, "/dev/%sspi%d", prefix, dev->minor_bus+1);
+	}
+
+	/* Register Bus for this Device */
+	rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc);
+	if (rc < 0) {
+		DBG("SPICTRL: rtems_libi2c_register_bus(%s) failed\n", devName);
+		free(dev->priv);
+		dev->priv = NULL;
+		return DRVMGR_FAIL;
+	}
+	priv->minor = rc;
+
+	return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl,
+					     uint32_t addr, int rw);
+
+/* Set as high frequency of SCK as possible but not higher than 
+ * requested frequency (freq).
+ */
+int spictrl_set_freq(struct spictrl_priv *priv, unsigned int freq)
+{
+	unsigned int core_freq_hz = priv->core_freq_hz;
+	unsigned int lowest_freq_possible, result;
+	unsigned int div, div16, pm, fact;
+
+	/* Lowest possible when DIV16 is set and PM is 0xf */
+	lowest_freq_possible = core_freq_hz / (16 * 4 * (0xf + 1));
+
+	if ( freq < lowest_freq_possible ) {
+		DBG("SPICTRL: TOO LOW FREQ %u, CORE FREQ %u, LOWEST FREQ %u\n", 
+			freq, core_freq_hz, lowest_freq_possible);
+		return -1;
+	}
+
+	div = ((core_freq_hz / 2) + (freq-1)) / freq;
+	DBG("SPICTRL: DIV=%d, FREQ=%d\n", div, freq);
+
+	/* Is DIV16 neccessary? */
+	if ( div > 16 ) {
+		div = (div + (16 - 1)) / 16;
+		div16 = 1;
+	} else {
+		div16 = 0;
+	}
+
+	if ( div > 0xf ) {
+		fact = 0; /* FACT adds an factor /2 */
+		div = (div + (2 - 1)) / 2;
+	} else {
+		fact = 1;
+	}
+
+	pm = div-1;
+
+	/* Update hardware */
+	priv->regs->mode = 
+		(priv->regs->mode & ~(SPICTRL_MODE_PM|SPICTRL_MODE_DIV16|SPICTRL_MODE_FACT)) | 
+		(pm << SPICTRL_MODE_PM_BIT) | (div16 << SPICTRL_MODE_DIV16_BIT) |
+		(fact << SPICTRL_MODE_FACT_BIT);
+
+	result = core_freq_hz / (2 * (fact ? 1 : 2) * (div) * (div16 ? 16 : 1) );
+	DBG("SPICTRL: Effective bit rate %u (requested %u), PM: %x, FACT: %d, div16: %x, core_freq: %u\n", result, freq, pm, fact, div16, core_freq_hz);
+
+	return 0;
+}
+
+/* Start Automated Periodic transfers, after this call read can be done */
+int spictrl_start_periodic(struct spictrl_priv *priv)
+{
+	struct spictrl_ioctl_config *cfg = &priv->periodic_cfg;
+	unsigned int am_cfg;
+
+	/* Clear the events */
+	priv->regs->event = 0xffffffff;
+
+	/* Enable core */
+	priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS;
+
+	/* Update hardware config from flags and period */
+	priv->regs->am_period = cfg->period;
+
+	/* Remove SPICTRL_PERIOD_FLAGS_ASEL and ACT bit and shift into posistion */
+	am_cfg = (cfg->period_flags & 0x1f8) >> 1;
+	priv->regs->am_cfg = am_cfg;
+
+	/* Start automated periodic transfers */
+	if ( cfg->period_flags & SPICTRL_PERIOD_FLAGS_EACT ) {
+		/* Enable external triggering */
+		priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_EACT;
+	} else {
+		/* Activate periodic transfers */
+		priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_ACT;
+	}
+
+	return 0;
+}
+
+/* Stop Automated Periodic transfers */
+void spictrl_stop_periodic(struct spictrl_priv *priv)
+{
+	priv->regs->am_cfg = 0;
+}
+
+/* Return the status of the SPI controller (the event register), 
+ * it may be needed in periodic mode to look at the Not Full bit (NF)
+ * in order not to hang in an infinte loop when read is called.
+ */
+unsigned int spictrl_status(struct spictrl_priv *priv)
+{
+	return priv->regs->event;
+}
+
+int spictrl_read_periodic(struct spictrl_priv *priv, struct spictrl_period_io *rarg)
+{
+	int i, rxi, rxshift, bits_per_char, reg;
+	unsigned int rx_word, mask;
+	void *rxbuf;
+
+	if ( rarg->options & 0x1 ) {
+		/* Read mask registers */
+		for (i=0; i<4; i++) {
+			rarg->masks[i] = priv->regs->am_mask[i];
+		}
+	}
+
+	if ( rarg->options & 0x2 ) {
+		/* Read receive registers (after updating masks so that the caller can
+		 * read current buffer without knowning of actual register mask).
+		 */
+
+		/* If not started we could be hanging here forever. */
+		if ( !priv->periodic_started )
+			return -1;
+
+		rxshift = priv->rxshift;
+		bits_per_char = priv->bits_per_char;
+		rx_word = 0;
+
+		rxbuf = rarg->data;
+		if ( !rxbuf ) {
+			/* If no data pointer specified we cannot copy data... */
+			return -1;
+		}
+
+		/* Wait until all data is available (if started) */
+		while ( (priv->regs->event & SPICTRL_EVENT_NE) == 0 ) {
+			;
+		}
+
+		rxi = 0;
+		for (i=0; i<4; i++) {
+			mask = rarg->masks[i];
+			reg = 0;
+			while ( mask ) {
+				if ( mask & 1 ) {
+					/* Update Register */
+					rx_word = priv->regs->am_rx[i*32 + reg] >> rxshift;
+
+					if ( bits_per_char <= 8 ) {
+						*((unsigned char *)rxbuf + rxi) = rx_word;
+					} else if ( bits_per_char <= 16 ) {
+						*((unsigned short *)rxbuf + rxi) = rx_word;
+					} else {
+						*((unsigned int *)rxbuf + rxi) = rx_word;
+					}
+					rxi++;
+				}
+
+				mask = mask>>1;
+				reg++;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int spictrl_write_periodic(struct spictrl_priv *priv, struct spictrl_period_io *warg)
+{
+	int i, txi, txshift, bits_per_char, reg;
+	unsigned int tx_word, mask;
+	void *txbuf;
+
+	if ( warg->options & 0x2 ) {
+
+		/* Make sure core is enabled, otherwise TX registers writes are lost */
+		priv->regs->mode |= SPICTRL_MODE_EN;
+
+		/* Update Transmit registers (before updating masks so that we do not
+		 * transmit invalid data)
+		 */
+
+		txshift = priv->txshift;
+		bits_per_char = priv->bits_per_char;
+		tx_word = 0;
+
+		txbuf = warg->data;
+		if ( !txbuf ) {
+			/* If no data pointer specified we fill up with
+			 * idle chars.
+			 */
+			tx_word = priv->idle_char << txshift;
+		}
+
+		txi = 0;
+		for (i=0; i<4; i++) {
+			mask = warg->masks[i];
+			reg = 0;
+			while ( mask ) {
+				if ( mask & 1 ) {
+					if ( txbuf ) {
+						if ( bits_per_char <= 8 ) {
+							tx_word = *((unsigned char *)txbuf + txi);
+						} else if ( bits_per_char <= 16 ) {
+							tx_word = *((unsigned short *)txbuf + txi);
+						} else {
+							tx_word = *((unsigned int *)txbuf + txi);
+						}
+						tx_word = tx_word << txshift;
+						txi++;
+					}
+
+					/* Update Register */
+					DBG("WRITE 0x%08x to 0x%08x\n", tx_word, &priv->regs->am_tx[i*32 + reg]);
+					priv->regs->am_tx[i*32 + reg] = tx_word;
+				}
+
+				mask = mask>>1;
+				reg++;
+			}
+		}
+	}
+
+	if ( warg->options & 0x1 ) {
+		/* Update mask registers */
+		for (i=0; i<4; i++) {
+			DBG("WRITE 0x%08x to 0x%08x (MSK%d)\n", warg->masks[i], &priv->regs->am_mask[i], i);
+			priv->regs->am_mask[i] = warg->masks[i];
+		}
+	}
+
+	return 0;
+}
+
+int spictrl_read_write(struct spictrl_priv *priv, void *rxbuf, void *txbuf, int len)
+{
+	unsigned int tx_word, rx_word, tmp;
+	int txshift = priv->txshift;
+	int rxshift = priv->rxshift;
+	int txi, rxi, bits_per_char;
+	int length;
+
+	/* Use IOCTL for periodic reads. The FIFO is not supported in automated 
+	 * periodic mode 
+	 */
+	if ( priv->periodic_cfg.periodic_mode ) {
+		return -1;
+	}
+
+	bits_per_char = priv->bits_per_char;
+	tx_word = 0;
+	if ( !txbuf ) {
+		tx_word = priv->idle_char << txshift;
+	}
+
+	/* Clear the events */
+	priv->regs->event = 0xffffffff;
+
+	/* Enable core */
+	priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS;
+
+	length = len;
+	if ( bits_per_char > 8 ) {
+		length = length / 2;
+		if ( bits_per_char > 16 )
+			length = length / 2;
+	}
+	DBG("SPICTRL: LENGTH = %d, Bits/Char: %d, Shift: %d, %d\n", length, bits_per_char, txshift, rxshift);
+
+	txi=0;
+	rxi=0;
+	while ( (rxi < length) || (txi < length) ) {
+		/* Get transmit word */
+		if ( length > txi ) {
+			if ( txbuf ) {
+				if ( bits_per_char <= 8 ) {
+					tx_word = *((unsigned char *)txbuf + txi);
+				} else if ( bits_per_char <= 16 ) {
+					tx_word = *((unsigned short *)txbuf + txi);
+				} else {
+					tx_word = *((unsigned int *)txbuf + txi);
+				}
+				tx_word = tx_word << txshift;
+			}
+
+			/* Wait for SPICTRL to get ready for another TX char */
+			while ( (priv->regs->event & SPICTRL_EVENT_NF) == 0 ) {
+				/* Wait for all chars to transmit */
+/* Could implement waiting for SPICTRL IRQ here */
+			}
+
+			DBG("SPICTRL: Writing 0x%x\n", tx_word);
+
+			/* Transmit word */
+			priv->regs->tx = tx_word;
+			txi++;
+		}
+
+		/* Read */
+		while ( priv->regs->event & SPICTRL_EVENT_NE ) {
+			/* Read to avoid overrun */
+			tmp = priv->regs->rx;
+			DBG("SPICTRL: Read 0x%x\n", tmp);
+
+			if ( rxbuf && (length > rxi) ) {
+				/* Copy word to user buffer */
+				rx_word = (tmp >> rxshift);
+
+				DBG("SPICTRL: Receiving 0x%x (0x%x, %d)\n", rx_word, tmp, rxshift);
+
+				if ( bits_per_char <= 8 ) {
+					*((unsigned char *)rxbuf + rxi) = rx_word;
+				} else if ( bits_per_char <= 16 ) {
+					*((unsigned short *)rxbuf + rxi) = rx_word;
+				} else {
+					*((unsigned int *)rxbuf + rxi) = rx_word;
+				}
+
+			}
+			rxi++;
+		}
+	}
+
+	return len;
+}
+
+
+STATIC rtems_status_code spictrl_libi2c_init(rtems_libi2c_bus_t *bushdl)
+{
+	struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+
+	DBG("SPICTRL: spictrl_libi2c_init\n");
+
+	/* Disable SPICTTRL, Select Master mode */
+	priv->regs->mode = SPICTRL_MODE_MS;
+
+	/* Mask all Interrupts */
+	priv->regs->mask = 0;
+
+	/* Select no slave */
+	priv->regs->slvsel = 0xffffffff;
+
+	/* Clear all events */
+	priv->regs->event = 0xffffffff;
+
+	return 0;
+}
+
+/* Nothing to be done in start */
+STATIC rtems_status_code spictrl_libi2c_send_start(rtems_libi2c_bus_t *bushdl)
+{
+	DBG("SPICTRL: spictrl_libi2c_send_start\n");
+
+	return 0;
+}
+
+/* Inactivate all chip selects, indicates "End of command" */
+STATIC rtems_status_code spictrl_libi2c_send_stop(rtems_libi2c_bus_t *bushdl)
+{
+	struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+
+	priv->regs->slvsel = 0xffffffff;
+
+	if ( priv->slvSelFunc ) {
+		/* unslect all */
+		return priv->slvSelFunc(priv->regs, -1, 0);
+	}
+
+	DBG("SPICTRL: spictrl_libi2c_send_stop\n");
+	return 0;
+}
+
+/* Select Slave address by selecting apropriate chip select */
+STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl,
+					     uint32_t addr, int rw)
+{
+	struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+
+	DBG("SPICTRL: spictrl_libi2c_send_addr, %d\n", addr);
+
+	if ( priv->slvSelFunc ) {
+		/* Let user set spi select using for example GPIO */
+		return priv->slvSelFunc(priv->regs, addr, 1);
+	} else if ( priv->regs->capability & SPICTRL_CAP_SSEN ) {
+		int slaves;
+
+		/* Maximum number of slaves the core support */
+		slaves = (priv->regs->capability & SPICTRL_CAP_SSSZ) >> SPICTRL_CAP_SSSZ_BIT;
+
+		if ( addr > slaves )
+			return -1;
+
+		if ( (priv->regs->capability & SPICTRL_CAP_ASELA) &&
+		     (priv->periodic_cfg.period_flags & SPICTRL_PERIOD_FLAGS_ASEL) ) {
+		     	/* When automatic slave select is supported by hardware and
+			 * enabled by configuration the SPI address is determined by 
+			 * the automatic slave select register and the "idle" slave
+			 * select register is set by configuration.
+			 */
+			priv->regs->am_slvsel = ~(1<<(addr-1));
+			priv->regs->slvsel = priv->periodic_cfg.period_slvsel;
+			/* Enable automatic slave select */
+			priv->regs->mode |= SPICTRL_MODE_ASEL;
+		} else {
+			/* Normal mode */
+			priv->regs->slvsel = ~(1<<(addr-1));
+		}
+	}
+
+	return 0;
+}
+
+/* Read a number of bytes */
+STATIC int spictrl_libi2c_read_bytes(rtems_libi2c_bus_t *bushdl, 
+				unsigned char *bytes, int nbytes)
+{
+	struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+	int ret;
+
+	DBG("SPICTRL: spictrl_libi2c_read_bytes %d\n", nbytes);
+	ret = spictrl_read_write(priv, bytes, NULL, nbytes);
+	if ( ret < 0 ) {
+		printf("SPICTRL: Error Reading\n");
+	} 
+#ifdef DEBUG
+	else {
+		int i;
+		for(i=0; i<nbytes; i+=16) {
+			DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", 
+				bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
+			DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 
+				bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
+		}
+	}
+#endif
+	return ret;
+}
+
+/* Write a number of bytes */
+STATIC int spictrl_libi2c_write_bytes(rtems_libi2c_bus_t *bushdl, 
+				unsigned char *bytes, int nbytes)
+{
+	struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+
+#ifdef DEBUG
+	int i;
+	DBG("SPICTRL: spictrl_libi2c_write_bytes: %d\n", nbytes);
+
+	for(i=0; i<nbytes; i+=16) {
+		DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", 
+			bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
+		DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 
+			bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
+	}
+#endif
+
+	return spictrl_read_write(priv, NULL, bytes, nbytes);
+}
+
+/* Configure the interface and do simultaneous READ/WRITE operations */
+STATIC int spictrl_libi2c_ioctl(
+	rtems_libi2c_bus_t * bushdl, 
+	int   cmd,
+	void *buffer)
+{
+	struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
+	int ret;
+
+	DBG("SPICTRL: spictrl_libi2c_ioctl(%d, 0x%x)\n", cmd, (unsigned int)buffer);
+
+	switch (cmd) {
+		case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
+		{
+			rtems_libi2c_tfr_mode_t *trf_mode = buffer;
+			unsigned int mode;
+
+			/* Must disable core to write new values */
+			priv->regs->mode &= ~SPICTRL_MODE_EN;
+
+			/* Change bit frequency */
+			if ( spictrl_set_freq(priv, trf_mode->baudrate) ) {
+				/* Unable to set such a low frequency. */
+				return -1;
+			}
+
+			/* Set Clock Polarity, Clock Phase, Reverse mode and Word Length */
+			mode = (priv->regs->mode & 
+				~(SPICTRL_MODE_CPOL|SPICTRL_MODE_CPHA|SPICTRL_MODE_REV|SPICTRL_MODE_LEN));
+			if ( trf_mode->clock_inv ) 
+				mode |= SPICTRL_MODE_CPOL;
+			if ( trf_mode->clock_phs ) 
+				mode |= SPICTRL_MODE_CPHA;
+			if ( trf_mode->lsb_first == 0 )
+				mode |= SPICTRL_MODE_REV; /* Set Reverse mode (MSB first) */
+
+			if ( (trf_mode->bits_per_char < 4) || 
+				((trf_mode->bits_per_char > 16) && (trf_mode->bits_per_char != 32)) )
+				return -1;
+			if ( trf_mode->bits_per_char == 32 ) {
+				priv->txshift = 0;
+				priv->rxshift = 0;
+			} else {
+				mode |= (trf_mode->bits_per_char-1) << SPICTRL_MODE_LEN_BIT;
+				if ( trf_mode->lsb_first == 0 ) {
+					/* REV bit 1 */
+					priv->txshift = 32 - trf_mode->bits_per_char;
+					priv->rxshift = 16;
+				} else {
+					/* REV bit 0 */
+					priv->txshift = 0;
+					priv->rxshift = 16 - trf_mode->bits_per_char;
+				}
+			}
+
+			priv->bits_per_char = trf_mode->bits_per_char;
+			priv->lsb_first = trf_mode->lsb_first;
+			priv->idle_char = trf_mode->idle_char;
+
+			/* Update hardware */
+			priv->regs->mode = mode;
+
+			return 0;
+		}
+
+		case RTEMS_LIBI2C_IOCTL_READ_WRITE:
+		{
+			rtems_libi2c_read_write_t *arg = buffer;
+
+			DBG("SPICTRL: IOCTL READ/WRITE, RX: 0x%x, TX: 0x%x, len: %d\n", arg->rd_buf, arg->wr_buf, arg->byte_cnt);
+#ifdef DEBUG
+			/* Printf out what is going to be transmitted */
+			if ( arg->wr_buf ) {
+				unsigned char *bytes = (unsigned char *)arg->wr_buf;
+				int i;
+				for(i=0; i<arg->byte_cnt; i+=16) {
+					DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", 
+						bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
+					DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 
+						bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
+				}
+			}
+#endif
+
+			ret = spictrl_read_write(priv, arg->rd_buf, (unsigned char *)arg->wr_buf,
+				arg->byte_cnt);
+#ifdef DEBUG
+			/* Printf out what was read */
+			if ( arg->rd_buf ) {
+				unsigned char *bytes = (unsigned char *)arg->rd_buf;
+				int i;
+				for(i=0; i<arg->byte_cnt; i+=16) {
+					DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", 
+						bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
+					DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 
+						bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
+				}
+			}
+#endif
+			return ret;
+		}
+
+		/* Enable Periodic mode */
+		case SPICTRL_IOCTL_CONFIG:
+		{
+			struct spictrl_ioctl_config *cfg;
+
+			DBG("SPICTRL: Configuring Periodic mode\n");
+
+			if ( priv->periodic_started ) {
+				DBG("SPICTRL: Periodic mode already started, too late to configure\n");
+				return -1;
+			}
+
+			cfg = buffer;
+			if ( cfg == NULL ) {
+				memset(&priv->periodic_cfg, 0, sizeof(priv->periodic_cfg));
+			} else {
+				priv->periodic_cfg = *cfg;
+			}
+			cfg = &priv->periodic_cfg;
+			if ( cfg->periodic_mode ) {
+				/* Enable Automated Periodic mode */
+				priv->regs->mode |= SPICTRL_MODE_AMEN;
+
+				/* Check that hardware has support for periodic mode */
+				if ( (priv->regs->mode & SPICTRL_MODE_AMEN) == 0 ) {
+					priv->periodic_cfg.periodic_mode = 0;
+					DBG("SPICTRL: Periodic mode not supported by hardware\n");
+					return -1;
+				}
+			} else {
+				/* Disable Periodic mode */
+				priv->regs->mode &= ~SPICTRL_MODE_AMEN;
+			}
+			priv->periodic_started = 0;
+
+			/* Set clockgap and TAC */
+			priv->regs->mode = (priv->regs->mode & ~(SPICTRL_MODE_CG|SPICTRL_MODE_TAC)) |
+			                   (cfg->clock_gap << SPICTRL_MODE_CG_BIT) |
+					   (cfg->flags & SPICTRL_MODE_TAC);
+			return 0;
+		}
+		case SPICTRL_IOCTL_PERIOD_START:
+		{
+			if ( !priv->periodic_cfg.periodic_mode || priv->periodic_started ) {
+				return -1;
+			}
+			if ( spictrl_start_periodic(priv) == 0 ) {
+				priv->periodic_started = 1;
+				return 0;
+			} else
+				return -1;
+		}
+		case SPICTRL_IOCTL_PERIOD_STOP:
+		{
+			if ( !priv->periodic_cfg.periodic_mode || !priv->periodic_started ) {
+				return -1;
+			}
+			spictrl_stop_periodic(priv);
+			priv->periodic_started = 0;
+			return 0;
+		}
+		case SPICTRL_IOCTL_STATUS:
+		{
+			if ( !buffer )
+				return 0;
+			*(unsigned int *)buffer = spictrl_status(priv);
+			return 0;
+		}
+
+		case SPICTRL_IOCTL_PERIOD_WRITE:
+		{
+			if ( !priv->periodic_cfg.periodic_mode || !buffer ) {
+				return -1;
+			}
+			if ( spictrl_write_periodic(priv, (struct spictrl_period_io *)
+			                            buffer) == 0 ) {
+				return 0;
+			} else
+				return -1;
+		}
+
+		case SPICTRL_IOCTL_PERIOD_READ:
+		{
+			if ( !priv->periodic_cfg.periodic_mode || !buffer ) {
+				return -1;
+			}
+			if ( spictrl_read_periodic(priv, (struct spictrl_period_io *)
+			                            buffer) == 0 ) {
+				return 0;
+			} else
+				return -1;
+		}
+
+		case SPICTRL_IOCTL_REGS:
+		{
+			/* Copy Register Base Address to user space */
+			if ( !buffer ) {
+				return -1;
+			}
+			*(struct spictrl_regs **)buffer = priv->regs;
+			return 0;
+		}
+
+		default:
+			/* Unknown IOCTL */
+			return -1;
+	}
+
+	return 0;
+}
+
+STATIC rtems_libi2c_bus_ops_t spictrl_libi2c_ops =
+{
+	.init		= spictrl_libi2c_init,
+	.send_start	= spictrl_libi2c_send_start,
+	.send_stop	= spictrl_libi2c_send_stop,
+	.send_addr	= spictrl_libi2c_send_addr,
+	.read_bytes	= spictrl_libi2c_read_bytes,
+	.write_bytes	= spictrl_libi2c_write_bytes,
+	.ioctl		= spictrl_libi2c_ioctl
+};
+
+int spictrl_device_init(struct spictrl_priv *priv)
+{
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	union drvmgr_key_value *value;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)priv->dev->businfo;
+	if ( ambadev == NULL ) {
+		return -1;
+	}
+	pnpinfo = &ambadev->info;
+	priv->irq = pnpinfo->irq;
+	priv->regs = (struct spictrl_regs *)pnpinfo->apb_slv->start;
+	priv->fdepth = (priv->regs->capability & SPICTRL_CAP_FDEPTH) >> SPICTRL_CAP_FDEPTH_BIT;
+
+	DBG("SPCTRL: 0x%x irq %d, FIFO: %d\n", (unsigned int)priv->regs, priv->irq, priv->fdepth);
+
+	/* Mask all Interrupts */
+	priv->regs->mask = 0;
+
+	/* Disable SPICTTRL */
+	priv->regs->mode = 0;
+
+	/* Get custom */
+	value = drvmgr_dev_key_get(priv->dev, "slvSelFunc", KEY_TYPE_POINTER);
+	if ( value ) {
+		priv->slvSelFunc = value->ptr;
+	}
+
+	/* Prepare I2C layer */
+	priv->i2clib_desc.ops = &spictrl_libi2c_ops;
+	priv->i2clib_desc.size = sizeof(spictrl_libi2c_ops);
+	return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/spw/grspw_router.c b/c/src/lib/libbsp/sparc/shared/spw/grspw_router.c
new file mode 100644
index 0000000..f33ad37
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/spw/grspw_router.c
@@ -0,0 +1,549 @@
+/* GRSPW ROUTER APB-Register Driver.
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grspw_router.h>
+
+#define ROUTER_DBG(args...)
+
+#define REG_READ(adr) (*(volatile unsigned int *)(adr))
+#define REG_WRITE(adr, value) (*(volatile unsigned int *)(adr) = (value))
+
+struct router_regs {
+	unsigned int resv1;		/* 0x000 */
+	unsigned int psetup[255];	/* 0x004 */
+	unsigned int resv2[32];		/* 0x400 */
+	unsigned int routes[224];	/* 0x480 */
+	unsigned int pctrl[32];		/* 0x800 */
+	unsigned int psts[32];		/* 0x880 */
+	unsigned int treload[32];	/* 0x900 */
+	unsigned int resv3[32];		/* 0x980 */
+	unsigned int cfgsts;		/* 0xA00 */
+	unsigned int timecode;		/* 0xA04 */
+	unsigned int ver;		/* 0xA08 */
+	unsigned int idiv;		/* 0xA0C */
+	unsigned int cfgwe;		/* 0xA10 */
+	unsigned int tprescaler;	/* 0xA14 */
+	unsigned int resv4[123];	/* 0xA18 */
+	unsigned int charo[31];		/* 0xC04 */
+	unsigned int resv5;		/* 0xC80 */
+	unsigned int chari[31];		/* 0xC84 */
+	unsigned int resv6;		/* 0xD00 */
+	unsigned int pkto[31];		/* 0xD04 */
+	unsigned int resv7;		/* 0xD80 */
+	unsigned int pkti[31];		/* 0xD84 */
+};
+
+struct router_priv {
+	char devName[32];
+	struct drvmgr_dev *dev;
+	struct router_regs *regs;
+	int minor;
+	int open;
+	struct router_hw_info hwinfo;
+	int nports;
+};
+
+static rtems_device_driver router_initialize(
+        rtems_device_major_number  major,
+        rtems_device_minor_number  minor,
+        void                    * arg
+        );
+
+static rtems_device_driver router_open(
+        rtems_device_major_number major,
+        rtems_device_minor_number minor,
+        void                    * arg
+        );
+
+static rtems_device_driver router_close(
+        rtems_device_major_number major,
+        rtems_device_minor_number minor,
+        void                    * arg
+        );
+
+static rtems_device_driver router_control(
+        rtems_device_major_number major,
+        rtems_device_minor_number minor,
+        void                    * arg
+        );
+
+#define ROUTER_DRIVER_TABLE_ENTRY \
+  { router_initialize, \
+    router_open, \
+    router_close, \
+    NULL, \
+    NULL, \
+    router_control }
+
+void router_hwinfo(struct router_priv *priv, struct router_hw_info *hwinfo);
+
+static rtems_driver_address_table router_driver = ROUTER_DRIVER_TABLE_ENTRY;
+static int router_driver_io_registered = 0;
+static rtems_device_major_number router_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+int router_register_io(rtems_device_major_number *m);
+
+int router_init2(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops router_ops = 
+{
+	.init = {NULL,  router_init2, NULL, NULL},
+	.remove = NULL,
+	.info = NULL
+};
+
+struct amba_dev_id router_ids[] = 
+{
+	{VENDOR_GAISLER, GAISLER_SPW_ROUTER},
+	{0, 0}		/* Mark end of table */
+};
+
+struct amba_drv_info router_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,			/* Driver */
+		NULL,				/* Next driver */
+		NULL,				/* Device list */
+		DRIVER_AMBAPP_GAISLER_SPW_ROUTER_ID,/* Driver ID */
+		"ROUTER_DRV",			/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,		/* Bus Type */
+		&router_ops,
+		NULL,				/* Funcs */
+		0,				/* No devices yet */
+		sizeof(struct router_priv),	/* Let DRVMGR allocate for us */
+	},
+	&router_ids[0],
+};
+
+void router_register_drv (void)
+{
+	drvmgr_drv_register(&router_drv_info.general);
+}
+
+int router_init2(struct drvmgr_dev *dev)
+{
+	struct router_priv *priv = dev->priv;
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	char prefix[32];
+	rtems_status_code status;
+
+	if ( priv == NULL )
+		return DRVMGR_NOMEM;
+	priv->dev = dev;
+
+	/* Do initialization */
+	if ( router_driver_io_registered == 0) {
+		/* Register the I/O driver only once for all cores */
+		if ( router_register_io(&router_driver_io_major) ) {
+			/* Failed to register I/O driver */
+			return DRVMGR_FAIL;
+		}
+
+		router_driver_io_registered = 1;
+	}
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)priv->dev->businfo;
+	if ( ambadev == NULL ) {
+		return DRVMGR_FAIL;
+	}
+	pnpinfo = &ambadev->info;
+	priv->regs = (struct router_regs *)pnpinfo->ahb_slv->start[0];
+	priv->minor = dev->minor_drv;
+
+	/* Register character device in registered region */
+	router_hwinfo(priv, &priv->hwinfo);
+	priv->open = 0;
+	priv->nports = priv->hwinfo.nports_spw + priv->hwinfo.nports_amba +
+			priv->hwinfo.nports_fifo;
+	if ( (priv->nports < 2) || (priv->nports > 32) )
+		return DRVMGR_FAIL;
+
+	/* Get Filesystem name prefix */
+	prefix[0] = '\0';
+	if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+		/* Failed to get prefix, make sure of a unique FS name
+		 * by using the driver minor.
+		 */
+		sprintf(priv->devName, "/dev/router%d", dev->minor_drv);
+	} else {
+		/* Got special prefix, this means we have a bus prefix
+		 * And we should use our "bus minor"
+		 */
+		sprintf(priv->devName, "/dev/%srouter%d", prefix, dev->minor_bus);
+	}
+
+	/* Register Device */
+	status = rtems_io_register_name(priv->devName, router_driver_io_major, dev->minor_drv);
+	if (status != RTEMS_SUCCESSFUL) {
+		return DRVMGR_FAIL;
+	}
+
+	return DRVMGR_OK;
+}
+
+int router_register_io(rtems_device_major_number *m)
+{
+	rtems_status_code r;
+
+	if ((r = rtems_io_register_driver(0, &router_driver, m)) == RTEMS_SUCCESSFUL) {
+		ROUTER_DBG("ROUTER driver successfully registered, major: %d\n", *m);
+	} else {
+		switch(r) {
+		case RTEMS_TOO_MANY:
+			printk("ROUTER rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+			return -1;
+		case RTEMS_INVALID_NUMBER:  
+			printk("ROUTER rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+			return -1;
+		case RTEMS_RESOURCE_IN_USE:
+			printk("ROUTER rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+			return -1;
+		default:
+			printk("ROUTER rtems_io_register_driver failed\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static rtems_device_driver router_initialize(
+	rtems_device_major_number major,
+	rtems_device_minor_number minor,
+	void *arg
+	)
+{
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver router_open(
+	rtems_device_major_number major,
+	rtems_device_minor_number minor,
+	void                    * arg
+	)
+{
+	struct router_priv *priv;
+	struct drvmgr_dev *dev;
+
+	if ( drvmgr_get_dev(&router_drv_info.general, minor, &dev) ) {
+		ROUTER_DBG("Wrong minor %d\n", minor);
+		return RTEMS_INVALID_NAME;
+	}
+	priv = (struct router_priv *)dev->priv;
+
+	if ( !priv || priv->open ) {
+		return RTEMS_RESOURCE_IN_USE;
+	}
+
+	priv->open = 1;
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver router_close(
+        rtems_device_major_number major,
+        rtems_device_minor_number minor,
+        void                    * arg
+        )
+{
+	struct router_priv *priv;
+	struct drvmgr_dev *dev;
+
+	if ( drvmgr_get_dev(&router_drv_info.general, minor, &dev) ) {
+		ROUTER_DBG("Wrong minor %d\n", minor);
+		return RTEMS_INVALID_NAME;
+	}
+	priv = (struct router_priv *)dev->priv;
+
+	priv->open = 0;
+
+	return RTEMS_SUCCESSFUL;
+}
+
+void router_hwinfo(struct router_priv *priv, struct router_hw_info *hwinfo)
+{
+	unsigned int tmp;
+
+	tmp = REG_READ(&priv->regs->cfgsts);
+	hwinfo->nports_spw   = (tmp >> 27) & 0x1f;
+	hwinfo->nports_amba  = (tmp >> 22) & 0x1f;
+	hwinfo->nports_fifo  = (tmp >> 17) & 0x1f;
+	hwinfo->timers_avail = (tmp >>  1) & 0x1;
+	hwinfo->pnp_avail    = (tmp >>  0) & 0x1;
+
+	tmp = REG_READ(&priv->regs->ver);
+	hwinfo->ver_major   = (tmp >> 24) & 0xff;
+	hwinfo->ver_minor   = (tmp >> 16) & 0xff;
+	hwinfo->ver_patch   = (tmp >>  8) & 0xff;
+	hwinfo->iid         = (tmp >>  0) & 0xff;
+}
+
+int router_config_set(struct router_priv *priv, struct router_config *cfg)
+{
+	int i;
+
+	if ( (cfg->flags & (ROUTER_FLG_TPRES|ROUTER_FLG_TRLD)) &&
+	     !priv->hwinfo.timers_avail ) {
+		return RTEMS_NOT_IMPLEMENTED;
+	}
+
+	/* Write only configuration bits in Config register */
+	if ( cfg->flags & ROUTER_FLG_CFG ) {
+		REG_WRITE(&priv->regs->cfgsts, cfg->config & ~0x4);
+	}
+
+	/* Write Instance ID to Version Register */
+	if ( cfg->flags & ROUTER_FLG_IID ) {
+		REG_WRITE(&priv->regs->ver, cfg->iid);
+	}
+
+	/* Write startup-clock-divisor Register */
+	if ( cfg->flags & ROUTER_FLG_IDIV ) {
+		REG_WRITE(&priv->regs->idiv, cfg->idiv);
+	}
+
+	/* Write Timer Prescaler Register */
+	if ( cfg->flags & ROUTER_FLG_TPRES ) {
+		REG_WRITE(&priv->regs->tprescaler, cfg->timer_prescaler);
+	}
+
+	/* Write Timer Reload Register */
+	if ( cfg->flags & ROUTER_FLG_TRLD ) {
+		for (i=0; i<=priv->nports; i++)
+			REG_WRITE(&priv->regs->treload[i], cfg->timer_reload[i]);
+	}
+
+	return 0;
+}
+
+int router_config_read(struct router_priv *priv, struct router_config *cfg)
+{
+	int i;
+
+	cfg->config = REG_READ(&priv->regs->cfgsts) & ~0xffff0007;
+	cfg->iid = REG_READ(&priv->regs->ver) & 0xff;
+	cfg->idiv = REG_READ(&priv->regs->idiv) & 0xff;
+	cfg->timer_prescaler = REG_READ(&priv->regs->tprescaler);
+	for (i=0; i<=priv->nports; i++)
+		cfg->timer_reload[i] = REG_READ(&priv->regs->treload[i]);
+
+	return 0;
+}
+
+int router_routes_set(struct router_priv *priv, struct router_routes *routes)
+{
+	int i;
+	for (i=0; i<224; i++)
+		REG_WRITE(&priv->regs->routes[i], routes->route[i]);
+	return 0;
+}
+
+int router_routes_read(struct router_priv *priv, struct router_routes *routes)
+{
+	int i;
+	for (i=0; i<224; i++)
+		routes->route[i] = REG_READ(&priv->regs->routes[i]);
+	return 0;
+}
+
+int router_ps_set(struct router_priv *priv, struct router_ps *ps)
+{
+	int i;
+	unsigned int *p = &ps->ps[0];
+	for (i=0; i<255; i++,p++) 
+		REG_WRITE(&priv->regs->psetup[i], *p);
+	return 0;
+}
+
+int router_ps_read(struct router_priv *priv, struct router_ps *ps)
+{
+	int i;
+	unsigned int *p = &ps->ps[0];
+	for (i=0; i<255; i++,p++) 
+		REG_WRITE(&priv->regs->psetup[i], *p);
+	return 0;
+}
+
+int router_we_set(struct router_priv *priv, int we)
+{
+	REG_WRITE(&priv->regs->cfgwe, we & 0x1);
+	return 0;
+}
+
+int router_port_ctrl(struct router_priv *priv, struct router_port *port)
+{
+	unsigned int ctrl, sts;
+
+	if ( port->port > priv->nports )
+		return RTEMS_INVALID_NAME;
+
+	ctrl = port->ctrl;
+	if ( port->flag & ROUTER_PORTFLG_GET_CTRL ) {
+		ctrl = REG_READ(&priv->regs->pctrl[port->port]);
+	}
+	sts = port->sts;
+	if ( port->flag & ROUTER_PORTFLG_GET_STS ) {
+		sts = REG_READ(&priv->regs->psts[port->port]);
+	}
+
+	if ( port->flag & ROUTER_PORTFLG_SET_CTRL ) {
+		REG_WRITE(&priv->regs->pctrl[port->port], port->ctrl);
+	}
+	if ( port->flag & ROUTER_PORTFLG_SET_STS ) {
+		REG_WRITE(&priv->regs->psts[port->port], port->sts);
+	}
+
+	port->ctrl = ctrl;
+	port->sts = sts;
+	return 0;
+}
+
+int router_cfgsts_set(struct router_priv *priv, unsigned int cfgsts)
+{
+	REG_WRITE(&priv->regs->cfgsts, cfgsts);
+	return 0;
+}
+
+int router_cfgsts_read(struct router_priv *priv, unsigned int *cfgsts)
+{
+	*cfgsts = REG_READ(&priv->regs->cfgsts);
+	return 0;
+}
+
+int router_tc_read(struct router_priv *priv, unsigned int *tc)
+{
+	*tc = REG_READ(&priv->regs->timecode);
+	return 0;
+}
+
+static rtems_device_driver router_control(
+	rtems_device_major_number major,
+	rtems_device_minor_number minor,
+	void                    * arg
+	)
+{
+	struct router_priv *priv;
+	struct drvmgr_dev *dev;
+	rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
+	void *argp = (void *)ioarg->buffer;
+
+	if ( drvmgr_get_dev(&router_drv_info.general, minor, &dev) ) {
+		ROUTER_DBG("Wrong minor %d\n", minor);
+		return RTEMS_INVALID_NAME;
+	}
+	priv = (struct router_priv *)dev->priv;
+
+	ioarg->ioctl_return = 0;
+	switch (ioarg->command) {
+
+	/* Get Hardware support/information available */
+	case GRSPWR_IOCTL_HWINFO:
+	{
+		struct router_hw_info *hwinfo = argp;
+		router_hwinfo(priv, hwinfo);
+		break;
+	}
+
+	/* Set Router Configuration */
+	case GRSPWR_IOCTL_CFG_SET:
+	{
+		struct router_config *cfg = argp;
+		return router_config_set(priv, cfg);
+	}
+
+	/* Read Router Configuration */
+	case GRSPWR_IOCTL_CFG_GET:
+	{
+		struct router_config *cfg = argp;
+		router_config_read(priv, cfg);
+		break;
+	}
+
+	/* Routes */
+	case GRSPWR_IOCTL_ROUTES_SET:
+	{
+		struct router_routes *routes = argp;
+		return router_routes_set(priv, routes);
+	}
+
+	case GRSPWR_IOCTL_ROUTES_GET:
+	{
+		struct router_routes *routes = argp;
+		router_routes_read(priv, routes);
+		break;
+	}
+
+	/* Port Setup */
+	case GRSPWR_IOCTL_PS_SET:
+	{
+		struct router_ps *ps = argp;
+		return router_ps_set(priv, ps);
+	}
+
+	case GRSPWR_IOCTL_PS_GET:
+	{
+		struct router_ps *ps = argp;
+		router_ps_read(priv, ps);
+		break;
+	}
+
+	/* Set configuration write enable */
+	case GRSPWR_IOCTL_WE_SET:
+	{
+		return router_we_set(priv, (int)argp);
+	}
+
+	/* Set/Get Port Control/Status */
+	case GRSPWR_IOCTL_PORT:
+	{
+		struct router_port *port = argp;
+		int result;
+		if ( (result=router_port_ctrl(priv, port)) )
+			return result;
+		break;
+	}
+
+	/* Set Router Configuration/Status Register */
+	case GRSPWR_IOCTL_CFGSTS_SET:
+	{
+		return router_cfgsts_set(priv, (int)argp);
+	}
+
+	/* Get Router Configuration/Status Register */
+	case GRSPWR_IOCTL_CFGSTS_GET:
+	{
+		unsigned int *cfgsts = argp;
+		router_cfgsts_read(priv, cfgsts);
+		break;
+	}
+
+	/* Get Current Time-Code Register */
+	case GRSPWR_IOCTL_TC_GET:
+	{
+		unsigned int *tc = argp;
+		router_tc_read(priv, tc);
+		break;
+	}
+
+	default: return RTEMS_NOT_IMPLEMENTED;
+	}
+
+	return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/time/grctm.c b/c/src/lib/libbsp/sparc/shared/time/grctm.c
new file mode 100644
index 0000000..3185e13
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/time/grctm.c
@@ -0,0 +1,409 @@
+/*  GRCTM - CCSDS Time Manager - register driver interface.
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <stdlib.h>
+
+#include <grctm.h>
+
+/* Private structure of GRCTM driver */
+struct grctm_priv {
+	struct drvmgr_dev *dev;
+	struct grctm_regs *regs;
+	int open;
+
+	grctm_isr_t user_isr;
+	void *user_isr_arg;
+
+	struct grctm_stats stats;
+};
+
+void grctm_isr(void *data);
+
+struct amba_drv_info grctm_drv_info;
+
+void *grctm_open(int minor)
+{
+	struct grctm_priv *priv;
+	struct drvmgr_dev *dev;
+
+	/* Get Device from Minor */
+	if ( drvmgr_get_dev(&grctm_drv_info.general, minor, &dev) ) {
+		return NULL;
+	}
+
+	priv = dev->priv;
+	if ( (priv == NULL) || priv->open )
+		return NULL;
+
+	/* Set initial state of software */
+	priv->open = 1;
+
+	/* Clear Statistics */
+	grctm_clr_stats(priv);
+	priv->user_isr = NULL;
+	priv->user_isr_arg = NULL;
+
+	return priv;
+}
+
+void grctm_close(void *grctm)
+{
+	struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+	if ( priv->open == 0 )
+		return;
+
+	/* Reset Hardware */
+	grctm_reset(priv);
+
+	priv->open = 0;
+}
+
+/* Hardware Reset of GRCTM */
+int grctm_reset(void *grctm)
+{
+	struct grctm_priv *priv = grctm;
+	struct grctm_regs *r = priv->regs;
+
+	r->grr = 0x55000001;
+
+	int i = 1000;
+	while ((r->grr & 1) && i > 0) {
+		i--;
+	}
+
+	return i ? 0 : -1;
+}
+
+void grctm_int_enable(void *grctm)
+{
+	struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+	/* Register and Enable Interrupt at Interrupt controller */
+	drvmgr_interrupt_register(priv->dev, 0, "grctm", grctm_isr, priv);
+}
+
+void grctm_int_disable(void *grctm)
+{
+	struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+	/* Enable Interrupt at Interrupt controller */
+	drvmgr_interrupt_unregister(priv->dev, 0, grctm_isr, priv);
+}
+
+void grctm_clr_stats(void *grctm)
+{
+	struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+	memset(&priv->stats, 0, sizeof(priv->stats));
+}
+
+void grctm_get_stats(void *grctm, struct grctm_stats *stats)
+{
+	struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+	memcpy(stats, &priv->stats, sizeof(priv->stats));
+}
+
+/* Enable external synchronisation (from grctm) */
+void grctm_enable_ext_sync(void *grctm)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->gcr |= 0x55<<24 | 1<<9;
+}
+
+/* Disable external synchronisation (from grctm) */
+void grctm_disable_ext_sync(void *grctm)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->gcr &= ~((0xAA<<24) | 1<<9);
+}
+
+/* Enable TimeWire synchronisation */
+void grctm_enable_tw_sync(void *grctm)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->gcr |= 0x55<<24 | 1<<8;
+}
+
+/* Disable TimeWire synchronisation */
+void grctm_disable_tw_sync(void *grctm)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->gcr &= ~((0xAA<<24) | 1<<8);
+}
+
+/* Disable frequency synthesizer from driving ET */
+void grctm_disable_fs(void *grctm)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->gcr |= 0x55<<24 | 1<<7;
+}
+
+/* Enable frequency synthesizer to drive ET */
+void grctm_enable_fs(void *grctm)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->gcr &= ~((0xAA<<24) | 1<<7);
+}
+
+/* Return elapsed coarse time */
+unsigned int grctm_get_et_coarse(void *grctm)
+{
+	struct grctm_priv *priv = grctm;
+
+	return priv->regs->etcr;
+}
+
+/* Return elapsed fine time */
+unsigned int grctm_get_et_fine(void *grctm)
+{
+	struct grctm_priv *priv = grctm;
+
+	return (priv->regs->etfr & 0xffffff00) >> 8;
+}
+
+/* Return elapsed time (coarse and fine) */
+unsigned long long grctm_get_et(void *grctm)
+{
+	return (((unsigned long)grctm_get_et_coarse(grctm)) << 24) | grctm_get_et_fine(grctm);
+}
+
+
+/* Return 1 if specified datation has been latched */
+int grctm_is_dat_latched(void *grctm, int dat)
+{
+	struct grctm_priv *priv = grctm;
+
+	return (priv->regs->gsr >> dat) & 1;
+}
+
+/* Set triggering edge of datation input */
+void grctm_set_dat_edge(void *grctm, int dat, int edge)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->gcr &= ~((0xAA<<24) | 1 << (10+dat));
+	priv->regs->gcr |= 0x55<<24 | (edge&1) << (10+dat);
+}
+
+/* Return latched datation coarse time */
+unsigned int grctm_get_dat_coarse(void *grctm, int dat)
+{
+	struct grctm_priv *priv = grctm;
+
+	switch (dat) {
+	case 0 : return priv->regs->dcr0; 
+	case 1 : return priv->regs->dcr1;
+	case 2 : return priv->regs->dcr2;
+	default: return -1;
+	}
+}
+
+/* Return latched datation fine time */
+unsigned int grctm_get_dat_fine(void *grctm, int dat)
+{
+	struct grctm_priv *priv = grctm;
+
+	switch (dat) {
+	case 0 : return (priv->regs->dfr0 & 0xffffff00) >> 8; 
+	case 1 : return (priv->regs->dfr1 & 0xffffff00) >> 8;
+	case 2 : return (priv->regs->dfr2 & 0xffffff00) >> 8;
+	default: return -1;
+	}
+}
+
+
+/* Return latched datation ET */
+unsigned long long grctm_get_dat_et(void *grctm, int dat)
+{
+	return (((unsigned long)grctm_get_dat_coarse(grctm, dat)) << 24) | 
+		grctm_get_dat_fine(grctm, dat);
+}
+
+
+/* Return current pulse configuration */
+unsigned int grctm_get_pulse_reg(void *grctm, int pulse)
+{
+	struct grctm_priv *priv = grctm;
+
+	return priv->regs->pdr[pulse];
+}
+
+/* Set pulse register */
+void grctm_set_pulse_reg(void *grctm, int pulse, unsigned int val)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->pdr[pulse] = val;
+}
+
+/* Configure pulse: pp = period, pw = width, pl = level, en = enable */
+void grctm_cfg_pulse(void *grctm, int pulse, int pp, int pw, int pl, int en)
+{
+	grctm_set_pulse_reg(grctm, pulse, (pp&0xf)<<20 | (pw&0xf)<<16 | (pl&1)<<10 | (en&1)<<1);
+}
+
+/* Enable pulse output */
+void grctm_enable_pulse(void *grctm, int pulse)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->pdr[pulse] |= 0x2;
+}
+
+/* Disable pulse output */
+void grctm_disable_pulse(void *grctm, int pulse)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->pdr[pulse] &= ~0x2;
+}
+
+/* Clear interrupts */
+void grctm_clear_irqs(void *grctm, int irqs)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->picr = irqs;
+}
+
+/* Enable interrupts */
+void grctm_enable_irqs(void *grctm, int irqs)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->imr  = irqs;
+}
+
+/* Set Frequency synthesizer increment */
+void grctm_set_fs_incr(void *grctm, int incr)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->fsir  = incr;
+}
+
+/* Set ET increment */
+void grctm_set_et_incr(void *grctm, int incr)
+{
+	struct grctm_priv *priv = grctm;
+
+	priv->regs->etir  = incr;
+}
+
+
+void grctm_isr(void *data)
+{
+	struct grctm_priv *priv = data;
+	struct grctm_stats *stats = &priv->stats;
+	unsigned int pimr = priv->regs->pimr;
+
+	if ( pimr == 0 )
+		return;
+
+	stats->nirqs++;
+	if (pimr & PULSE0_IRQ )
+		stats->pulse++;
+
+	/* Let user Handle Interrupt */
+	if ( priv->user_isr )
+		priv->user_isr(pimr, priv->user_isr_arg);
+}
+
+struct grctm_regs *grctm_get_regs(void *grctm)
+{
+	struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+	return priv->regs;
+}
+
+void grctm_int_register(void *grctm, grctm_isr_t func, void *data)
+{
+	struct grctm_priv *priv = (struct grctm_priv *)grctm;
+
+	priv->user_isr = func;
+	priv->user_isr_arg = data;
+}
+
+/*** INTERFACE TO DRIVER MANAGER ***/
+
+int grctm_init2(struct drvmgr_dev *dev)
+{
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	struct grctm_priv *priv;
+	struct grctm_regs *regs;
+
+	priv = (struct grctm_priv *)malloc(sizeof(*priv));
+	if ( priv == NULL )
+		return -1;
+	memset(priv, 0, sizeof(*priv));
+	priv->dev = dev;
+	dev->priv = priv;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)dev->businfo;
+	if ( ambadev == NULL ) {
+		return -1;
+	}
+	pnpinfo = &ambadev->info;
+	regs = (struct grctm_regs *)pnpinfo->ahb_slv->start[0];
+
+	priv->regs = regs;
+
+	grctm_reset(priv);
+
+	return 0;
+}
+
+struct drvmgr_drv_ops grctm_ops =
+{
+	{NULL, grctm_init2, NULL, NULL},
+	NULL,
+	NULL
+};
+
+struct amba_dev_id grctm_ids[] =
+{
+	{VENDOR_GAISLER, GAISLER_GRCTM},
+	{0, 0}	/* Mark end of table */
+};
+
+struct amba_drv_info grctm_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,			/* Driver */
+		NULL,				/* Next driver */
+		NULL,				/* Device list */
+		DRIVER_AMBAPP_GAISLER_GRCTM_ID,	/* Driver ID */
+		"GRCTM_DRV",			/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,		/* Bus Type */
+		&grctm_ops,
+		NULL,				/* Funcs */
+		0,				/* No devices yet */
+		0,
+	},
+	&grctm_ids[0]
+};
+
+/* Register the grctm Driver */
+void grctm_register(void)
+{
+	drvmgr_drv_register(&grctm_drv_info.general);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/time/spwcuc.c b/c/src/lib/libbsp/sparc/shared/time/spwcuc.c
new file mode 100644
index 0000000..738ec1a
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/time/spwcuc.c
@@ -0,0 +1,369 @@
+/*  SPWCUC - SpaceWire - CCSDS unsegmented Code Transfer Protocol GRLIB core
+ *  register driver interface.
+ *
+ *  COPYRIGHT (c) 2009.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <stdlib.h>
+ 
+#include <spwcuc.h>
+
+/* Private structure of SPWCUC driver. */
+struct spwcuc_priv {
+	struct drvmgr_dev *dev;
+	struct spwcuc_regs *regs;
+	int open;
+	
+	spwcuc_isr_t user_isr;
+	void *user_isr_arg;
+
+	struct spwcuc_stats stats;
+};
+
+void spwcuc_isr(void *data);
+
+struct amba_drv_info spwcuc_drv_info;
+
+/* Hardware Reset of SPWCUC */
+int spwcuc_hw_reset(struct spwcuc_priv *priv)
+{
+	struct spwcuc_regs *r = priv->regs;
+	int i = 1000;
+
+	r->control = 1;
+
+	while ((r->control & 1) && i > 0) {
+		i--;
+	}
+
+	spwcuc_clear_irqs(priv, -1);
+
+	return i ? 0 : -1;
+}
+
+int spwcuc_reset(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	return spwcuc_hw_reset(priv);
+}
+
+void *spwcuc_open(int minor)
+{
+	struct spwcuc_priv *priv;
+	struct drvmgr_dev *dev;
+
+	/* Get Device from Minor */
+	if ( drvmgr_get_dev(&spwcuc_drv_info.general, minor, &dev) ) {
+		return NULL;
+	}
+
+	priv = dev->priv;
+	if ( (priv == NULL) || priv->open )
+		return NULL;
+
+	/* Set initial state of software */
+	priv->open = 1;
+
+	/* Clear Statistics */
+	spwcuc_clr_stats(priv);
+	priv->user_isr = NULL;
+	priv->user_isr_arg = NULL;
+
+	return priv;
+}
+
+void spwcuc_close(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	if ( priv->open == 0 )
+		return;
+
+	/* Reset Hardware */
+	spwcuc_hw_reset(priv);
+
+	priv->open = 0;	
+}
+
+void spwcuc_int_enable(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	/* Register and Enable Interrupt at Interrupt controller */
+	drvmgr_interrupt_register(priv->dev, 0, "spwcuc", spwcuc_isr, priv);
+}
+
+void spwcuc_int_disable(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	/* Enable Interrupt at Interrupt controller */
+	drvmgr_interrupt_unregister(priv->dev, 0, spwcuc_isr, priv);
+}
+
+void spwcuc_clr_stats(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	memset(&priv->stats, 0, sizeof(priv->stats));
+}
+
+void spwcuc_get_stats(void *spwcuc, struct spwcuc_stats *stats)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	memcpy(stats, &priv->stats, sizeof(priv->stats));
+}
+
+/* Configure the spwcuc core */
+void spwcuc_config(void *spwcuc, struct spwcuc_cfg *cfg)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+	struct spwcuc_regs *r = priv->regs;
+
+	r->config = (cfg->sel_out & 0x1f)   << 28 |
+         	    (cfg->sel_in & 0x1f)    << 24 |
+		    (cfg->mapping & 0x1f)   << 16 |
+		    (cfg->tolerance & 0x1f) << 8  |
+		    (cfg->tid & 0x7)        << 4  |
+  		    (cfg->ctf & 1)          << 1  |
+		    (cfg->cp & 1);
+
+	r->control = (cfg->txen & 1)      << 1 |
+		     (cfg->rxen & 1)      << 2 |
+		     (cfg->pktsyncen & 1) << 3 |
+		     (cfg->pktiniten & 1) << 4 |
+		     (cfg->pktrxen & 1)   << 5;
+
+	r->dla = (cfg->dla_mask & 0xff)<<8 | (cfg->dla & 0xff);
+
+	r->pid = cfg->pid;
+
+	r->offset = cfg->offset;
+}
+
+/* Return elapsed coarse time */
+unsigned int spwcuc_get_et_coarse(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	return priv->regs->etct;
+}
+
+/* Return elapsed fine time */
+unsigned int spwcuc_get_et_fine(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	return (priv->regs->etft & 0xffffff) >> 8;
+}
+
+/* Return elapsed time (coarse and fine) */
+unsigned long long spwcuc_get_et(void *spwcuc)
+{
+	return (((unsigned long long)spwcuc_get_et_coarse(spwcuc)) << 24) | spwcuc_get_et_fine(spwcuc);
+}
+
+/* Return next elapsed coarse time (for use when sending SpW time packet) */
+unsigned int spwcuc_get_next_et_coarse(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	return priv->regs->etct_next;
+}
+
+/* Return next elapsed fine time (for use when sending SpW time packet) */
+unsigned int spwcuc_get_next_et_fine(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	return (priv->regs->etft_next & 0xffffff) >> 8;
+}
+
+/* Return next elapsed time (for use when sending SpW time packet) */
+unsigned long long spwcuc_get_next_et(void *spwcuc)
+{
+	return (((unsigned long long)spwcuc_get_next_et_coarse(spwcuc)) << 24) | spwcuc_get_next_et_fine(spwcuc);
+}
+
+/* Force/Set the elapsed time (coarse 32-bit and fine 24-bit) by writing the
+ * T-Field Time Packet Registers then the FORCE, NEW and INIT bits. 
+ * The latter three are needed for the ET to be set with the new value.
+ */
+void spwcuc_force_et(void *spwcuc, unsigned long long time)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+	struct spwcuc_regs *regs = priv->regs;
+
+	regs->etft_next = (time & 0xffffff) << 8;
+	regs->etct_next = (time >> 24) & 0xffffffff;
+	regs->pkt_pf_crc = (1 << 29) | (1 << 30) | (1 << 31);
+}
+
+/* Return received (from time packet) elapsed coarse time */
+unsigned int spwcuc_get_tp_et_coarse(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	return priv->regs->pkt_ct;
+}
+
+/* Return received (from time packet) elapsed fine time */
+unsigned int spwcuc_get_tp_et_fine(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	return (priv->regs->pkt_ft & 0xffffff) >> 8;
+}
+
+/* Return received (from time packet) elapsed time (coarse and fine) */
+unsigned long long spwcuc_get_tp_et(void *spwcuc)
+{
+	return (((unsigned long long)spwcuc_get_tp_et_coarse(spwcuc)) << 24) | spwcuc_get_tp_et_fine(spwcuc);
+}
+
+/* Clear interrupts */
+void spwcuc_clear_irqs(void *spwcuc, int irqs)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	priv->regs->picr = irqs;
+}
+
+/* Enable interrupts */
+void spwcuc_enable_irqs(void *spwcuc, int irqs)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	priv->regs->imr  = irqs;
+}
+
+struct spwcuc_regs *spwcuc_get_regs(void *spwcuc)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	return priv->regs;
+}
+
+void spwcuc_int_register(void *spwcuc, spwcuc_isr_t func, void *data)
+{
+	struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
+
+	priv->user_isr = func;
+	priv->user_isr_arg = data;
+}
+
+void spwcuc_isr(void *data)
+{
+	struct spwcuc_priv *priv = data;
+	struct spwcuc_stats *stats = &priv->stats;
+	unsigned int pimr = priv->regs->pimr;
+
+	stats->nirqs++;
+
+	if (pimr & PKT_INIT_IRQ)
+		stats->pkt_init++;
+	if (pimr & PKT_ERR_IRQ)
+		stats->pkt_err++;
+	if (pimr & PKT_RX_IRQ)
+		stats->pkt_rx++;
+	if (pimr & WRAP_ERR_IRQ)
+		stats->wraperr++;
+	if (pimr & WRAP_IRQ)
+		stats->wrap++;
+	if (pimr & SYNC_ERR_IRQ)
+		stats->syncerr++;
+	if (pimr & SYNC_IRQ)
+		stats->sync++;
+	if (pimr & TOL_ERR_IRQ)
+		stats->tolerr++;
+	if (pimr & TICK_RX_ERR_IRQ)
+		stats->tick_rx_error++;
+	if (pimr & TICK_RX_WRAP_IRQ)
+		stats->tick_rx_wrap++;
+	if (pimr & TICK_RX_IRQ)
+		stats->tick_rx++;
+	if (pimr & TICK_TX_WRAP_IRQ)
+		stats->tick_tx_wrap++;
+	if (pimr & TICK_TX_IRQ)
+		stats->tick_tx++;
+
+	/* Let user Handle Interrupt */
+	if ( priv->user_isr )
+		priv->user_isr(pimr, priv->user_isr_arg);
+}
+
+/*** INTERFACE TO DRIVER MANAGER ***/
+
+int spwcuc_init2(struct drvmgr_dev *dev)
+{
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	struct spwcuc_priv *priv;
+	struct spwcuc_regs *regs;
+
+	priv = (struct spwcuc_priv *)malloc(sizeof(*priv));
+	if ( priv == NULL )
+		return -1;
+	memset(priv, 0, sizeof(*priv));
+	priv->dev = dev;
+	dev->priv = priv;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)dev->businfo;
+	if ( ambadev == NULL ) {
+		return -1;
+	}
+	pnpinfo = &ambadev->info;
+	regs = (struct spwcuc_regs *)pnpinfo->apb_slv->start;
+
+	priv->regs = regs;
+
+	spwcuc_hw_reset(priv);
+
+	return 0;
+}
+
+struct drvmgr_drv_ops spwcuc_ops =
+{
+	{NULL, spwcuc_init2, NULL, NULL},
+	NULL,
+	NULL
+};
+
+struct amba_dev_id spwcuc_ids[] =
+{
+	{VENDOR_GAISLER, GAISLER_SPWCUC},
+	{0, 0}	/* Mark end of table */
+};
+
+struct amba_drv_info spwcuc_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,			/* Driver */
+		NULL,				/* Next driver */
+		NULL,				/* Device list */
+		DRIVER_AMBAPP_GAISLER_SPWCUC_ID,/* Driver ID */
+		"SPWCUC_DRV",			/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,		/* Bus Type */
+		&spwcuc_ops,
+		NULL,				/* Funcs */
+		0,				/* No devices yet */
+		0,
+	},
+	&spwcuc_ids[0]
+};
+
+/* Register the SPWCUC Driver */
+void spwcuc_register(void)
+{
+	drvmgr_drv_register(&spwcuc_drv_info.general);
+}
diff --git a/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c b/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c
new file mode 100644
index 0000000..3794e95
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c
@@ -0,0 +1,1962 @@
+/* GRTC Telecommand decoder driver
+ *
+ *  COPYRIGHT (c) 2007.
+ *  Cobham Gaisler AB.
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <ambapp.h>
+#include <grtc.h>
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+
+#include <debug_defs.h>
+
+#ifdef DEBUG_ERROR
+#define DEBUG_ERR_LOG(device,error) grtc_log_error(device,error)
+#else
+#define DEBUG_ERR_LOG(device,error)
+#endif
+
+/* GRTC register map */
+struct grtc_regs {
+	volatile unsigned int	grst;	/* Global Reset Register (GRR 0x00) */
+	volatile unsigned int	gctrl;	/* Global Control Register (GCR 0x04) */
+	int unused0;
+	volatile unsigned int	sir;	/* Spacecraft Identifier Register (SIR 0x0c) */	
+	volatile unsigned int	far;	/* Frame Acceptance Report Register (FAR 0x10) */
+
+	volatile unsigned int	clcw1;	/* CLCW Register 1 (CLCWR1 0x14) */
+	volatile unsigned int	clcw2;	/* CLCW Register 2 (CLCWR2 0x18) */
+	volatile unsigned int	phir;	/* Physical Interface Register (PHIR 0x1c) */
+	volatile unsigned int	cor;	/* Control Register (COR 0x20) */
+
+	volatile unsigned int	str;	/* Status Register (STR 0x24) */
+	volatile unsigned int	asr;	/* Address Space Register (ASR 0x28) */
+	volatile unsigned int	rp;	/* Receive Read Pointer Register (RRP 0x2c) */
+	volatile unsigned int	wp;	/* Receive Write Pointer Register (RWP 0x30) */
+
+	int unused1[(0x60-0x34)/4];
+
+	volatile unsigned int	pimsr;	/* Pending Interrupt Masked Status Register (PIMSR 0x60) */
+	volatile unsigned int	pimr;	/* Pending Interrupt Masked Register (PIMR 0x64) */
+	volatile unsigned int	pisr;	/* Pending Interrupt Status Register (PISR 0x68) */
+	volatile unsigned int	pir;	/* Pending Interrupt Register (PIR 0x6c) */
+	volatile unsigned int	imr;	/* Interrupt Mask Register (IMR 0x70) */
+	volatile unsigned int	picr;	/* Pending Interrupt Clear Register (PICR 0x74) */
+};
+
+/* Security Byte */
+#define GRTC_SEB		0x55000000
+
+/* Global Reset Register (GRR 0x00) */
+#define GRTC_GRR_SRST		0x1
+#define GRTC_GRR_SRST_BIT	0
+
+/* Global Control Register (GCR 0x04) */
+#define GRTC_GCR_PSR_BIT	10
+#define GRTC_GCR_NRZM_BIT	11
+#define GRTC_GCR_PSS_BIT	12
+
+#define GRTC_GCR_PSR		(1<<GRTC_GCR_PSR_BIT)
+#define GRTC_GCR_NRZM		(1<<GRTC_GCR_NRZM_BIT)
+#define GRTC_GCR_PSS		(1<<GRTC_GCR_PSS_BIT)
+
+/* Spacecraft Identifier Register (SIR 0x0c) */	
+
+
+/* Frame Acceptance Report Register (FAR 0x10) */
+#define GRTC_FAR_SCI_BIT	10
+#define GRTC_FAR_CSEC_BIT	11
+#define GRTC_FAR_CAC_BIT	12
+#define GRTC_FAR_SSD_BIT	13
+
+#define GRTC_FAR_SCI		(0x7<<GRTC_FAR_SCI_BIT)
+#define GRTC_FAR_CSEC		(0x7<<GRTC_FAR_CSEC_BIT)
+#define GRTC_FAR_CAC		(0x3f<<GRTC_FAR_CAC_BIT)
+#define GRTC_FAR_SSD		(1<<GRTC_FAR_SSD_BIT)
+
+/* CLCW Register 1 (CLCWR1 0x14) */
+/* CLCW Register 2 (CLCWR2 0x18) */
+#define GRTC_CLCW_RVAL_BIT	0
+#define GRTC_CLCW_RTYPE_BIT	8
+#define GRTC_CLCW_FBCO_BIT	9
+#define GRTC_CLCW_RTMI_BIT	11
+#define GRTC_CLCW_WAIT_BIT	12
+#define GRTC_CLCW_LOUT_BIT	13
+#define GRTC_CLCW_NBLO_BIT	14
+#define GRTC_CLCW_NRFA_BIT	15
+#define GRTC_CLCW_VCI_BIT	18
+#define GRTC_CLCW_CIE_BIT	24
+#define GRTC_CLCW_STAF_BIT	26
+#define GRTC_CLCW_VNUM_BIT	29
+#define GRTC_CLCW_CWTY_BIT	31
+
+#define GRTC_CLCW_RVAL		(0xff<<GRTC_CLCW_RVAL_BIT)
+#define GRTC_CLCW_RTYPE		(1<<GRTC_CLCW_RTYPE_BIT)
+#define GRTC_CLCW_FBCO		(0x3<<GRTC_CLCW_FBCO_BIT)
+#define GRTC_CLCW_RTMI		(0x3<<GRTC_CLCW_RTMI_BIT)
+#define GRTC_CLCW_WAIT		(1<<GRTC_CLCW_WAIT_BIT)
+#define GRTC_CLCW_LOUT		(1<<GRTC_CLCW_LOUT_BIT)
+#define GRTC_CLCW_NBLO		(1<<GRTC_CLCW_NBLO_BIT)
+#define GRTC_CLCW_NRFA		(1<<GRTC_CLCW_NRFA_BIT)
+#define GRTC_CLCW_VCI		(0x3f<<GRTC_CLCW_VCI_BIT)
+#define GRTC_CLCW_CIE		(0x3<<GRTC_CLCW_CIE_BIT)
+#define GRTC_CLCW_STAF		(0x3<<GRTC_CLCW_STAF_BIT)
+#define GRTC_CLCW_VNUM		(0x3<<GRTC_CLCW_VNUM_BIT)
+#define GRTC_CLCW_CWTY		(1<<GRTC_CLCW_CWTY_BIT)
+
+/* Physical Interface Register (PIR 0x1c) */
+#define GRTC_PIR_BLO_BIT	0
+#define GRTC_PIR_RFA_BIT	8
+
+#define GRTC_PIR_BLO		(0xff<<GRTC_PIR_BLO_BIT)
+#define GRTC_PIR_RFA		(0xff<<GRTC_PIR_RFA_BIT)
+
+/* Control Register (COR 0x20) */
+#define GRTC_COR_RE_BIT		0
+#define GRTC_COR_CRST_BIT	9
+
+#define GRTC_COR_RE		(1<<GRTC_COR_RE_BIT)
+#define GRTC_COR_CRST		(1<<GRTC_COR_CRST_BIT)
+
+/* Status Register (STR 0x24) */
+#define GRTC_STR_CR_BIT		0
+#define GRTC_STR_OV_BIT		4
+#define GRTC_STR_RFF_BIT	7
+#define GRTC_STR_RBF_BIT	10
+
+#define GRTC_STR_CR		(1<<GRTC_STR_CR_BIT)
+#define GRTC_STR_OV		(1<<GRTC_STR_OV_BIT)
+#define GRTC_STR_RFF		(1<<GRTC_STR_RFF_BIT)
+#define GRTC_STR_RBF		(1<<GRTC_STR_RBF_BIT)
+
+/* Address Space Register (ASR 0x28) */
+#define GRTC_ASR_RXLEN_BIT	0
+#define GRTC_ASR_BUFST_BIT	10
+
+#define GRTC_ASR_RXLEN		(0xff<<GRTC_ASR_RXLEN_BIT)
+#define GRTC_ASR_BUFST		(0x3fffff<<GRTC_ASR_BUFST_BIT)
+
+/* Receive Read Pointer Register (RRP 0x2c) */
+#define GRTC_RRP_PTR_BIT	0
+
+#define GRTC_RRP_PTR		(0xffffff<<GRTC_RRP_PTR_BIT)
+
+/* Receive Write Pointer Register (RWP 0x30) */
+#define GRTC_RWP_PTR_BIT	0
+
+#define GRTC_RWP_PTR		(0xffffff<<GRTC_RWP_PTR_BIT)
+
+/* Pending Interrupt Masked Status Register (PIMSR 0x60) */
+/* Pending Interrupt Masked Register (PIMR 0x64) */
+/* Pending Interrupt Status Register (PISR 0x68) */
+/* Pending Interrupt Register (PIR 0x6c) */
+/* Interrupt Mask Register (IMR 0x70) */
+/* Pending Interrupt Clear Register (PICR 0x74) */
+#define GRTC_INT_RFA_BIT	0
+#define GRTC_INT_BLO_BIT	1
+#define GRTC_INT_FAR_BIT	2
+#define GRTC_INT_CR_BIT		3
+#define GRTC_INT_RBF_BIT	4
+#define GRTC_INT_OV_BIT		5
+#define GRTC_INT_CS_BIT		6
+
+#define GRTC_INT_RFA		(1<<GRTC_INT_RFA_BIT)
+#define GRTC_INT_BLO		(1<<GRTC_INT_BLO_BIT)
+#define GRTC_INT_FAR		(1<<GRTC_INT_FAR_BIT)
+#define GRTC_INT_CR		(1<<GRTC_INT_CR_BIT)
+#define GRTC_INT_OV		(1<<GRTC_INT_OV_BIT)
+#define GRTC_INT_CS		(1<<GRTC_INT_CS_BIT)
+
+#define GRTC_INT_ALL		(GRTC_INT_RFA|GRTC_INT_BLO|GRTC_INT_FAR|GRTC_INT_CR|GRTC_INT_OV|GRTC_INT_CS)
+
+#define READ_REG(address)	(*(volatile unsigned int *)address)
+
+/* Driver functions */
+static rtems_device_driver grtc_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor, void *arg);
+static rtems_device_driver grtc_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define GRTC_DRIVER_TABLE_ENTRY { grtc_initialize, grtc_open, grtc_close, grtc_read, grtc_write, grtc_ioctl }
+
+static rtems_driver_address_table grtc_driver = GRTC_DRIVER_TABLE_ENTRY;
+
+enum {
+	FRM_STATE_NONE = 0,		/* not started */
+	FRM_STATE_HDR = 1,		/* Reading Header (Frame length isn't known) */
+	FRM_STATE_ALLOC = 2,		/* Allocate Frame to hold data */
+	FRM_STATE_PAYLOAD = 3,		/* Reading Payload (Frame length is known) */
+	FRM_STATE_FILLER = 4,		/* Check filler */
+	FRM_STATE_DROP = 5		/* error, drop data until end marker */
+};
+
+/* Frame pool, all frames in pool have the same buffer length (frame mode only) */
+struct grtc_frame_pool {
+	unsigned int		frame_len;	/* Maximal length of frame (payload+hdr+crc..) */
+	unsigned int		frame_cnt;	/* Current number of frames in pool (in frms) */
+	struct grtc_frame	*frms;		/* Chain of frames in pool (this is the pool) */
+};
+
+struct grtc_priv {
+	struct drvmgr_dev		*dev;		/* Driver manager device */
+	char			devName[32];	/* Device Name */
+	struct grtc_regs	*regs;		/* TC Hardware Register MAP */
+	int			irq;		/* IRQ number of TC core */
+
+	int			major;		/* Driver major */
+	int			minor;		/* Device Minor */
+
+	int			open;		/* Device has been opened by user */
+	int			running;	/* TC receiver running */
+	int			mode;		/* RAW or FRAME mode */
+	int			overrun_condition;	/* Overrun condition */
+	int			blocking;	/* Blocking/polling mode */
+	rtems_interval		timeout;	/* Timeout in blocking mode */
+	int			wait_for_nbytes;/* Number of bytes to wait for in blocking mode */
+
+	struct grtc_ioc_config	config;
+
+/* RAW MODE ONLY */
+	/* Buffer allocation (user provided or driver allocated using malloc) */
+	void			*buf;
+	void			*buf_remote;
+	void			*_buf;
+	int			buf_custom;	/* 0=no custom buffer, 1=custom buffer (don't free it...) */
+	unsigned int		len;
+
+/* FRAME MODE ONLY */
+	/* Frame management when user provides buffers. */
+	int			pool_cnt;	/* Number of Pools */
+	struct grtc_frame_pool	*pools;		/* Array of pools */
+
+	struct grtc_list	ready;		/* Ready queue (received frames) */
+
+	/* Frame read data (Frame mode only) */
+	int			frame_state;
+	int			filler;
+	unsigned char		hdr[5] __attribute__((aligned(2)));
+	struct grtc_frame	*frm;		/* Frame currently beeing copied */
+	int			frmlen;
+
+	struct grtc_ioc_stats	stats;		/* Statistics */
+
+	rtems_id sem_rx;
+
+#ifdef DEBUG_ERROR	
+	/* Buffer read/write state */
+	unsigned int rp;
+	unsigned int 	wp;
+
+	/* Debugging */
+	int last_error[128];
+	int last_error_cnt;
+#endif
+};
+
+/* Prototypes */
+static void grtc_hw_reset(struct grtc_priv *priv);
+static void grtc_interrupt(void *arg);
+
+/* Common Global Variables */
+static rtems_id grtc_dev_sem;
+static int grtc_driver_io_registered = 0;
+static rtems_device_major_number grtc_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+static int grtc_register_io(rtems_device_major_number *m);
+static int grtc_device_init(struct grtc_priv *pDev);
+
+static int grtc_init2(struct drvmgr_dev *dev);
+static int grtc_init3(struct drvmgr_dev *dev);
+
+static struct drvmgr_drv_ops grtc_ops = 
+{
+	{NULL, grtc_init2, grtc_init3, NULL},
+	NULL,
+	NULL,
+};
+
+static struct amba_dev_id grtc_ids[] = 
+{
+	{VENDOR_GAISLER, GAISLER_GRTC},
+	{0, 0}		/* Mark end of table */
+};
+
+static struct amba_drv_info grtc_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,			/* Driver */
+		NULL,				/* Next driver */
+		NULL,				/* Device list */
+		DRIVER_AMBAPP_GAISLER_GRTC_ID,	/* Driver ID */
+		"GRTC_DRV",			/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,		/* Bus Type */
+		&grtc_ops,
+		NULL,				/* Funcs */
+		0,				/* No devices yet */
+		sizeof(struct grtc_priv),
+	},
+	&grtc_ids[0]
+};
+
+void grtc_register_drv (void)
+{
+	DBG("Registering GRTC driver\n");
+	drvmgr_drv_register(&grtc_drv_info.general);
+}
+
+static int grtc_init2(struct drvmgr_dev *dev)
+{
+	struct grtc_priv *priv;
+
+	DBG("GRTC[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+	priv = dev->priv;
+	if ( !priv )
+		return DRVMGR_NOMEM;
+	priv->dev = dev;
+
+	/* This core will not find other cores, so we wait for init2() */
+
+	return DRVMGR_OK;
+}
+
+static int grtc_init3(struct drvmgr_dev *dev)
+{
+	struct grtc_priv *priv;
+	char prefix[32];
+	rtems_status_code status;
+
+	priv = dev->priv;
+
+	/* Do initialization */
+
+	if ( grtc_driver_io_registered == 0) {
+		/* Register the I/O driver only once for all cores */
+		if ( grtc_register_io(&grtc_driver_io_major) ) {
+			/* Failed to register I/O driver */
+			dev->priv = NULL;
+			return DRVMGR_FAIL;
+		}
+
+		grtc_driver_io_registered = 1;
+	}
+	
+	/* I/O system registered and initialized 
+	 * Now we take care of device initialization.
+	 */
+	if ( grtc_device_init(priv) ) {
+		return DRVMGR_FAIL;
+	}
+
+	/* Get Filesystem name prefix */
+	prefix[0] = '\0';
+	if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+		/* Failed to get prefix, make sure of a unique FS name
+		 * by using the driver minor.
+		 */
+		sprintf(priv->devName, "/dev/grtc%d", dev->minor_drv);
+	} else {
+		/* Got special prefix, this means we have a bus prefix
+		 * And we should use our "bus minor"
+		 */
+		sprintf(priv->devName, "/dev/%sgrtc%d", prefix, dev->minor_bus);
+	}
+
+	/* Register Device */
+	status = rtems_io_register_name(priv->devName, grtc_driver_io_major, dev->minor_drv);
+	if (status != RTEMS_SUCCESSFUL) {
+		return DRVMGR_FAIL;
+	}
+
+	return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static int grtc_register_io(rtems_device_major_number *m)
+{
+	rtems_status_code r;
+
+	if ((r = rtems_io_register_driver(0, &grtc_driver, m)) == RTEMS_SUCCESSFUL) {
+		DBG("GRTC driver successfully registered, major: %d\n", *m);
+	} else {
+		switch(r) {
+		case RTEMS_TOO_MANY:
+			printk("GRTC rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+			return -1;
+		case RTEMS_INVALID_NUMBER:  
+			printk("GRTC rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+			return -1;
+		case RTEMS_RESOURCE_IN_USE:
+			printk("GRTC rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+			return -1;
+		default:
+			printk("GRTC rtems_io_register_driver failed\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int grtc_device_init(struct grtc_priv *pDev)
+{
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+	if ( ambadev == NULL ) {
+		return -1;
+	}
+	pnpinfo = &ambadev->info;
+	pDev->irq = pnpinfo->irq;
+	pDev->regs = (struct grtc_regs *)pnpinfo->ahb_slv->start[0];
+	pDev->minor = pDev->dev->minor_drv;
+	pDev->open = 0;
+	pDev->running = 0;
+
+	/* Create Binary RX Semaphore with count = 0 */
+	if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'C', '0' + pDev->minor),
+		0,
+		RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+		RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, 
+		0,
+		&pDev->sem_rx) != RTEMS_SUCCESSFUL ) {
+		return -1;
+	}
+
+	/* Reset Hardware before attaching IRQ handler */
+	grtc_hw_reset(pDev);
+
+	return 0;
+}
+
+static void grtc_hw_reset(struct grtc_priv *priv)
+{
+	/* Reset Core */
+	priv->regs->grst = GRTC_SEB | GRTC_GRR_SRST;
+}
+
+static void grtc_hw_get_defaults(struct grtc_priv *pDev, struct grtc_ioc_config *config)
+{
+	unsigned int gcr = READ_REG(&pDev->regs->gctrl);
+
+	config->psr_enable	= (gcr & GRTC_GCR_PSR)	? 1:0;
+	config->nrzm_enable	= (gcr & GRTC_GCR_NRZM)	? 1:0;
+	config->pss_enable	= (gcr & GRTC_GCR_PSS)	? 1:0;
+	
+	config->crc_calc	= 0;
+}
+
+/* bufsize is given in bytes */
+static int __inline__ grtc_hw_data_avail_upper(unsigned int rrp, unsigned rwp, unsigned int bufsize)
+{
+	if ( rrp == rwp )
+		return 0;
+
+	if ( rwp > rrp ) {
+		return rwp-rrp;
+	}
+
+	return (bufsize-rrp);
+}
+
+/* bufsize is given in bytes */
+static int __inline__ grtc_hw_data_avail_lower(unsigned int rrp, unsigned rwp, unsigned int bufsize)
+{
+	if ( rrp == rwp )
+		return 0;
+
+	if ( rwp > rrp ) {
+		return 0;
+	}
+
+	return rwp;
+}
+
+/* bufsize is given in bytes */
+static int __inline__ grtc_hw_data_avail(unsigned int rrp, unsigned rwp, unsigned int bufsize)
+{
+	if ( rrp == rwp )
+		return 0;
+
+	if ( rwp > rrp ) {
+		return rwp-rrp;
+	}
+
+	return rwp+(bufsize-rrp);
+}
+
+/* Reads as much as possiböe but not more than 'max' bytes from the TC receive buffer.
+ * Number of bytes put into 'buf' is returned.
+ */
+static int grtc_hw_read_try(struct grtc_priv *pDev, char *buf, int max)
+{
+	struct grtc_regs *regs = pDev->regs;
+	unsigned int rp, wp, asr, bufmax, rrp, rwp;
+	unsigned int upper, lower;
+	unsigned int count, cnt, left;
+
+	FUNCDBG();
+
+	if ( max < 1 )
+		return 0;
+	
+	rp = READ_REG(&regs->rp);
+	asr = READ_REG(&regs->asr);
+	bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+	bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+	wp = READ_REG(&regs->wp);
+	
+	/* Relative rp and wp */
+	rrp = rp - (asr & GRTC_ASR_BUFST);
+	rwp = wp - (asr & GRTC_ASR_BUFST);
+	
+	lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax);
+	upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax);
+	
+	DBG("grtc_hw_read_try: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+	DBG("grtc_hw_read_try: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+		rp,rrp,wp,rwp,bufmax,pDev->buffer);
+	
+	if ( (upper+lower) == 0 )
+		return 0;
+	
+	/* Count bytes will be read */
+	count = (upper+lower) > max ? max : (upper+lower);
+	left = count;
+	
+	/* Read from upper part of data buffer */
+	if ( upper > 0 ){
+		if ( left < upper ){
+			cnt = left;
+		}else{
+			cnt = upper;	/* Read all upper data available */
+		}
+		DBG("grtc_hw_read_try: COPYING %d from upper\n",cnt);
+		/* Convert from Remote address (RP) into CPU Local address */
+		memcpy(buf, (void *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf), cnt);
+		buf += cnt;
+		left -= cnt;
+	}
+
+	/* Read from lower part of data buffer */
+	if ( left > 0 ){
+		if ( left < lower ){
+			cnt = left;
+		}else{
+			cnt = lower;	/* Read all lower data available */
+		}
+		DBG("grtc_hw_read_try: COPYING %d from lower\n",cnt);
+		memcpy(buf, (void *)pDev->buf, cnt);
+		buf += cnt;
+		left -= cnt;
+	}
+	
+	/* Update hardware RP pointer to tell hardware about new space available */
+	if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+		regs->rp = (rp+count-bufmax);
+	} else {
+		regs->rp = rp+count;
+	}
+
+	return count;
+}
+
+/* Reads as much as possiböe but not more than 'max' bytes from the TC receive buffer.
+ * Number of bytes put into 'buf' is returned.
+ */
+static int grtc_data_avail(struct grtc_priv *pDev)
+{
+	unsigned int rp, wp, asr, bufmax, rrp, rwp;
+	struct grtc_regs *regs = pDev->regs;
+
+	FUNCDBG();
+
+	rp = READ_REG(&regs->rp);
+	asr = READ_REG(&regs->asr);
+	bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+	bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+	wp = READ_REG(&regs->wp);
+
+	/* Relative rp and wp */
+	rrp = rp - (asr & GRTC_ASR_BUFST);
+	rwp = wp - (asr & GRTC_ASR_BUFST);
+
+	return grtc_hw_data_avail(rrp,rwp,bufmax);
+}
+
+static void *grtc_memalign(unsigned int boundary, unsigned int length, void *realbuf)
+{
+	*(int *)realbuf = (int)malloc(length+(~GRTC_ASR_BUFST)+1);
+	DBG("GRTC: Alloced %d (0x%x) bytes, requested: %d\n",length+(~GRTC_ASR_BUFST)+1,length+(~GRTC_ASR_BUFST)+1,length);
+	return (void *)(((*(unsigned int *)realbuf)+(~GRTC_ASR_BUFST)+1) & ~(boundary-1));
+}
+
+static int grtc_start(struct grtc_priv *pDev)
+{
+	struct grtc_regs *regs = pDev->regs;
+	unsigned int tmp;
+
+	if ( !pDev->buf || (((unsigned int)pDev->buf & ~GRTC_ASR_BUFST) != 0) ||
+	     (pDev->len>(1024*0x100)) || (pDev->len<1024) || ((pDev->len & (1024-1)) != 0) 
+	   ) {
+		DBG("GRTC: start: buffer not properly allocated(0x%x,0x%x,0x%x,0x%x)\n",pDev->buf,pDev->len,((unsigned int)pDev->buf & ~GRTC_ASR_BUFST),(pDev->len & ~(1024-1)));
+		return RTEMS_NO_MEMORY;
+	}
+
+	memset(pDev->buf,0,pDev->len);
+
+	/* Software init */
+	pDev->overrun_condition = 0;
+#ifdef DEBUG_ERROR
+	pDev->last_error_cnt = 0;
+	memset(&pDev->last_error[0],0,128*sizeof(int));
+#endif
+	memset(&pDev->stats,0,sizeof(struct grtc_ioc_stats));
+
+	/* Reset the receiver */
+	regs->cor = GRTC_SEB | GRTC_COR_CRST;
+	if ( READ_REG(&regs->cor) & GRTC_COR_CRST ){
+		/* Reset Failed */
+		DBG("GRTC: start: Reseting receiver failed\n");
+		return RTEMS_IO_ERROR;
+	}
+
+	/* Set operating modes */
+	tmp = 0;
+	if ( pDev->config.psr_enable )
+		tmp |= GRTC_GCR_PSR;
+	if ( pDev->config.nrzm_enable )
+		tmp |= GRTC_GCR_NRZM;
+	if ( pDev->config.pss_enable )
+		tmp |= GRTC_GCR_PSS;
+	regs->gctrl = GRTC_SEB | tmp;
+
+	/* Clear any pending interrupt */
+	tmp = READ_REG(&regs->pir);
+	regs->picr = GRTC_INT_ALL;
+
+	/* Unmask only the Overrun interrupt */
+	regs->imr = GRTC_INT_OV;
+
+	/* Set up DMA registers
+	 * 1. Let hardware know about our DMA area (size and location)
+	 * 2. Set DMA read/write posistions to zero.
+	 */
+	regs->asr = (unsigned int)pDev->buf_remote | ((pDev->len>>10)-1);
+	regs->rp = (unsigned int)pDev->buf_remote;
+
+	/* Mark running before enabling the receiver, we could receive 
+	 * an interrupt directly after enabling the receiver and it would 
+	 * then interpret the interrupt as spurious (see interrupt handler)
+	 */
+	pDev->running = 1;
+
+	/* Enable receiver */
+	regs->cor = GRTC_SEB | GRTC_COR_RE;
+
+	DBG("GRTC: STARTED\n");
+
+	return 0;
+}
+
+static void grtc_stop(struct grtc_priv *pDev)
+{
+	struct grtc_regs *regs = pDev->regs;
+	unsigned int tmp;
+	
+	/* Disable the receiver */
+	regs->cor = GRTC_SEB;
+	
+	/* disable all interrupts and clear them */
+	regs->imr = 0;
+	tmp = READ_REG(&regs->pir);
+	regs->picr = GRTC_INT_ALL;
+	
+	DBG("GRTC: STOPPED\n");
+	
+	/* Flush semaphores in case a thread is stuck waiting for CLTUs (RX data) */
+	rtems_semaphore_flush(pDev->sem_rx);
+}
+
+/* Wait until 'count' bytes are available in receive buffer, or until 
+ * the timeout expires. 
+ */
+static int grtc_wait_data(struct grtc_priv *pDev, int count, rtems_interval timeout)
+{
+	int avail;
+	int ret;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	FUNCDBG();
+
+	if ( count < 1 )
+		return 0;
+
+	IRQ_GLOBAL_DISABLE(oldLevel);
+
+	/* Enable interrupts when receiving CLTUs, Also clear old pending CLTUs store
+	 * interrupts.
+	 */
+	pDev->regs->picr = GRTC_INT_CS;
+	pDev->regs->imr = READ_REG(&pDev->regs->imr) | GRTC_INT_CS;
+	
+	avail = grtc_data_avail(pDev);
+	if ( avail < count ) {
+		/* Wait for interrupt. */
+
+		IRQ_GLOBAL_ENABLE(oldLevel);
+
+		if ( timeout == 0 ){
+			timeout = RTEMS_NO_TIMEOUT;
+		}
+		ret = rtems_semaphore_obtain(pDev->sem_rx,RTEMS_WAIT,timeout);
+		/* RTEMS_SUCCESSFUL  = interrupt signaled data is available
+		 * RTEMS_TIMEOUT     = timeout expired, probably not enough data available
+		 * RTEMS_UNSATISFIED = driver has been closed or an error (overrun) occured
+		 *                     which should cancel this operation.
+		 * RTEMS_OBJECT_WAS_DELETED, RTEMS_INVALID_ID = driver error.
+		 */
+		IRQ_GLOBAL_DISABLE(oldLevel);
+	}else{
+		ret = RTEMS_SUCCESSFUL;	
+	}
+
+	/* Disable interrupts when receiving CLTUs */
+	pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRTC_INT_CS;
+
+	IRQ_GLOBAL_ENABLE(oldLevel);
+
+	return ret;
+}
+
+static rtems_device_driver grtc_open(
+	rtems_device_major_number major, 
+	rtems_device_minor_number minor, 
+	void *arg)
+{
+	struct grtc_priv *pDev;
+	struct drvmgr_dev *dev;
+
+	FUNCDBG();
+
+	if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+		DBG("Wrong minor %d\n", minor);
+		return RTEMS_INVALID_NUMBER;
+	}
+	pDev = (struct grtc_priv *)dev->priv;
+
+	/* Wait until we get semaphore */
+	if ( rtems_semaphore_obtain(grtc_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){
+		return RTEMS_INTERNAL_ERROR;
+	}
+
+	/* Is device in use? */
+	if ( pDev->open ){
+		rtems_semaphore_release(grtc_dev_sem);
+		return RTEMS_RESOURCE_IN_USE;
+	}
+
+	/* Mark device taken */
+	pDev->open = 1;
+	
+	rtems_semaphore_release(grtc_dev_sem);
+
+	DBG("grtc_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev);
+
+	/* Set defaults */
+	pDev->buf = NULL;
+	pDev->_buf = NULL;
+	pDev->buf_custom = 0;
+	pDev->buf_remote = 0;
+	pDev->len = 0;
+	pDev->timeout = 0; /* no timeout */
+	pDev->blocking = 0; /* polling mode */
+	pDev->mode = GRTC_MODE_RAW; /* Always default to Raw mode */
+	pDev->ready.head = NULL;
+	pDev->ready.tail = NULL;
+	pDev->ready.cnt = 0;
+
+	pDev->running = 0;
+
+	memset(&pDev->config,0,sizeof(pDev->config));
+
+	/* The core has been reset when we execute here, so it is possible
+	 * to read out defualts from core.
+	 */
+	grtc_hw_get_defaults(pDev,&pDev->config);
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtc_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	struct grtc_priv *pDev;
+	struct drvmgr_dev *dev; 
+
+	FUNCDBG();
+
+	if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+		return RTEMS_INVALID_NUMBER;
+	}
+	pDev = (struct grtc_priv *)dev->priv;
+
+	if ( pDev->running ){
+		grtc_stop(pDev);
+		pDev->running = 0;
+	}
+	
+	/* Reset core */
+	grtc_hw_reset(pDev);
+	
+	/* Mark not open */
+	pDev->open = 0;
+	
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtc_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	struct grtc_priv *pDev;
+	struct drvmgr_dev *dev;
+	int count;
+	int left;
+	int timedout;
+	int err;
+	rtems_interval timeout;
+	rtems_libio_rw_args_t *rw_args;
+
+	FUNCDBG();
+
+	if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+		return RTEMS_INVALID_NUMBER;
+	}
+	pDev = (struct grtc_priv *)dev->priv;
+
+	if ( !pDev->running && !pDev->overrun_condition ) {
+		return RTEMS_RESOURCE_IN_USE;
+	}
+
+	if ( pDev->mode != GRTC_MODE_RAW ) {
+		return RTEMS_NOT_DEFINED;
+	}
+
+	rw_args = (rtems_libio_rw_args_t *) arg;
+	left = rw_args->count;
+	timedout = 0;
+	timeout = pDev->timeout;
+
+read_from_buffer:
+	/* Read maximally rw_args->count bytes from receive buffer */
+	count = grtc_hw_read_try(pDev,rw_args->buffer,left);
+	
+	left -= count;
+
+	DBG("READ %d bytes from DMA, left: %d\n",count,left);
+
+	if ( !timedout && !pDev->overrun_condition && ((count < 1) || ((count < rw_args->count) && (pDev->blocking == GRTC_BLKMODE_COMPLETE))) ){
+		/* didn't read anything (no data available) or we want to wait for all bytes requested.
+		 * 
+		 * Wait for data to arrive only in blocking mode
+		 */
+		if ( pDev->blocking ) {
+			if ( (err=grtc_wait_data(pDev,left,timeout)) != RTEMS_SUCCESSFUL ){
+				/* Some kind of error, closed, overrun etc. */
+				if ( err == RTEMS_TIMEOUT ){
+					/* Got a timeout, we try to read as much as possible */
+					timedout = 1;
+					goto read_from_buffer;
+				}
+				return err;
+			}
+			goto read_from_buffer;
+		}
+		/* Non-blocking mode and no data read. */
+		return RTEMS_TIMEOUT;
+	}
+	
+	/* Tell caller how much was read. */
+	
+	DBG("READ returning %d bytes, left: %d\n",rw_args->count-left,left);
+	
+	rw_args->bytes_moved = rw_args->count - left;
+	if ( rw_args->bytes_moved == 0 ){
+		return RTEMS_TIMEOUT;
+	}
+	
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtc_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	FUNCDBG();
+	return RTEMS_NOT_IMPLEMENTED;
+}
+
+static int grtc_pool_add_frms(struct grtc_frame *frms)
+{
+	struct grtc_frame *frm, *next;
+	
+	/* Add frames to pools */
+	frm = frms;
+	while(frm){
+
+		if ( !frm->pool ) {
+			/* */
+			DBG("GRTC: Frame not assigned to a pool\n");
+			return -1;
+		}
+		next = frm->next; /* Remember next frame to process */
+		
+		DBG("GRTC: adding frame 0x%x to pool %d (%d)\n",frm,frm->pool->frame_len,frm->pool->frame_cnt);
+		
+		/* Insert Frame into pool */
+		frm->next = frm->pool->frms;
+		frm->pool->frms = frm;
+		frm->pool->frame_cnt++;
+
+		frm = next;
+	}
+	
+	return 0;
+}
+
+static struct grtc_frame *grtc_pool_get_frm(struct grtc_priv *pDev, int frame_len, int *error)
+{
+	struct grtc_frame *frm;
+	struct grtc_frame_pool *pool;
+	int i;
+	
+	/* Loop through all pools until a pool is found
+	 * with a matching (or larger) frame length
+	 */
+	pool = pDev->pools;
+	for (i=0; i<pDev->pool_cnt; i++,pool++) {
+		if ( pool->frame_len >= frame_len ) {
+			/* Found a good pool ==> get frame */
+			frm = pool->frms;
+			if ( !frm ) {
+				/* not enough frames available for this 
+				 * frame length, we try next
+				 *
+				 * If this is a severe error add your handling
+				 * code here.
+				 */
+#if 0
+				if ( error )
+					*error = 0;
+				return 0;
+#endif
+				continue;
+			}
+			
+			/* Got a frame, the frame is taken out of the 
+			 * pool for usage.
+			 */
+			pool->frms = frm->next;
+			pool->frame_cnt--;
+			return frm;
+		}
+	}
+	
+	if ( error )
+		*error = 1;
+
+	/* Didn't find any frames */
+	return NULL;
+}
+
+/* Return number of bytes processed, Stops at the first occurance 
+ * of the pattern given in 'pattern'
+ */
+static int grtc_scan(unsigned short *src, int max, unsigned char pattern, int *found)
+{
+	unsigned short tmp = 0;
+	unsigned int left = max;
+
+	while ( (left>1) && (((tmp=*src) & 0x00ff) != pattern) ) {
+		src++;
+		left-=2;
+	}
+	if ( (tmp & 0xff) == pattern ) {
+		*found = 1;
+	} else {
+		*found = 0;
+	}
+	return max-left;
+}
+
+static int grtc_copy(unsigned short *src, unsigned char *buf, int cnt)
+{
+	unsigned short tmp;
+	int left = cnt;
+	
+	while ( (left>0) && ((((tmp=*src) & 0x00ff) == 0x00) || ((tmp & 0x00ff) == 0x01)) ) {
+		*buf++ = tmp>>8;
+		src++;
+		left--;
+	}
+	
+	return cnt-left;
+}
+
+
+static int grtc_hw_find_frm(struct grtc_priv *pDev)
+{
+	struct grtc_regs *regs = pDev->regs;
+	unsigned int rp, wp, asr, bufmax, rrp, rwp;
+	unsigned int upper, lower;
+	unsigned int count, cnt;
+	int found;
+
+	FUNCDBG();
+	
+	rp = READ_REG(&regs->rp);
+	asr = READ_REG(&regs->asr);
+	wp = READ_REG(&regs->wp);
+
+	/* Quick Check for most common case where Start of frame is at next 
+	 * data byte.
+	 */	
+	if ( rp != wp ) {
+		/* At least 1 byte in buffer */
+		if ( ((*(unsigned short *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf)) & 0x00ff) == 0x01 ) {
+			return 0;
+		}
+	}
+	
+	bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+	bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+	
+	/* Relative rp and wp */
+	rrp = rp - (asr & GRTC_ASR_BUFST);
+	rwp = wp - (asr & GRTC_ASR_BUFST);
+	
+	lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax);
+	upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax);
+	
+	DBG("grtc_hw_find_frm: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+	DBG("grtc_hw_find_frm: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+		rp,rrp,wp,rwp,bufmax,pDev->buf_remote);
+	
+	if ( (upper+lower) == 0 )
+		return 1;
+
+	/* Count bytes will be read */
+	count = 0;
+	found = 0;
+	
+	/* Read from upper part of data buffer */
+	if ( upper > 0 ){
+		cnt = grtc_scan((unsigned short *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf), upper, 0x01, &found);
+		count = cnt;
+		if ( found ) {
+			DBG("grtc_hw_find_frm: SCANNED upper %d bytes until found\n",cnt);
+			goto out;
+		}
+		
+		DBG("grtc_hw_find_frm: SCANNED all upper %d bytes, not found\n",cnt);
+	}
+	
+	/* Read from lower part of data buffer */
+	if ( lower > 0 ){
+		cnt = grtc_scan((unsigned short *)pDev->buf, lower, 0x01, &found);
+		count += cnt;
+
+		if ( found ) {
+			DBG("grtc_hw_find_frm: SCANNED lower %d bytes until found\n",cnt);
+			goto out;
+		}
+		
+		DBG("grtc_hw_find_frm: SCANNED all lower %d bytes, not found\n",cnt);
+	}
+
+out:
+	/* Update hardware RP pointer to tell hardware about new space available */
+	if ( count > 0 ) {
+		if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+			regs->rp = (rp+count-bufmax);
+		} else {
+			regs->rp = rp+count;
+		}
+	}
+	if ( found )
+		return 0;
+	return 1;
+
+}
+
+static int grtc_check_ending(unsigned short *src, int max, int end)
+{
+	while ( max > 0 ) {
+		/* Check Filler */
+		if ( *src != 0x5500 ) {
+			/* Filler is wrong */
+			return -1;
+		}
+		src++;
+		max-=2;
+	}
+	
+	/* Check ending (at least */
+	if ( end ) {
+		if ( (*src & 0x00ff) != 0x02 ) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int grtc_hw_check_ending(struct grtc_priv *pDev, int max)
+{
+	struct grtc_regs *regs = pDev->regs;
+	unsigned int rp, wp, asr, bufmax, rrp, rwp;
+	unsigned int upper, lower;
+	unsigned int count, cnt, left;
+	int tot;
+
+	FUNCDBG();
+
+	if ( max < 1 )
+		return 0;
+	max = max*2;
+	max += 2; /* Check ending also (2 byte extra) */
+
+	rp = READ_REG(&regs->rp);
+	asr = READ_REG(&regs->asr);
+	bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+	bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+	wp = READ_REG(&regs->wp);
+
+	/* Relative rp and wp */
+	rrp = rp - (asr & GRTC_ASR_BUFST);
+	rwp = wp - (asr & GRTC_ASR_BUFST);
+
+	lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax);
+	upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax);
+	
+	DBG("grtc_hw_check_ending: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+	DBG("grtc_hw_check_ending: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+		rp,rrp,wp,rwp,bufmax,pDev->buf_remote);
+	
+	if ( (upper+lower) < max )
+		return 0;
+	
+	/* Count bytes will be read */
+	count = max;
+	left = count;
+	tot = 0;
+	
+	/* Read from upper part of data buffer */
+	if ( upper > 0 ){
+		if ( left <= upper ){
+			cnt = left;
+			if ( grtc_check_ending((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), cnt-2, 1) ) {
+				return -1;
+			}
+		}else{
+			cnt = upper;	/* Read all upper data available */
+			if ( grtc_check_ending((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), cnt, 0) ) {
+				return -1;
+			}
+		}
+		left -= cnt;
+	}
+	
+	/* Read from lower part of data buffer */
+	if ( left > 0 ){
+		cnt = left;
+		if ( grtc_check_ending((unsigned short *)pDev->buf, cnt-2, 1) ) {
+			return -1;
+		}
+		left -= cnt;
+	}
+
+	/* Update hardware RP pointer to tell hardware about new space available */
+	if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+		regs->rp = (rp+count-bufmax);
+	} else {
+		regs->rp = rp+count;
+	}
+
+	return 0;	
+}
+
+/* Copies Data from DMA area to buf, the control bytes are stripped. For
+ * every data byte, in the DMA area, one control byte is stripped.
+ */
+static int grtc_hw_copy(struct grtc_priv *pDev, unsigned char *buf, int max, int partial)
+{
+	struct grtc_regs *regs = pDev->regs;
+	unsigned int rp, wp, asr, bufmax, rrp, rwp;
+	unsigned int upper, lower;
+	unsigned int count, cnt, left;
+	int ret, tot, tmp;
+
+	FUNCDBG();
+
+	if ( max < 1 )
+		return 0;
+
+	rp = READ_REG(&regs->rp);
+	asr = READ_REG(&regs->asr);
+	bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT;
+	bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */
+	wp = READ_REG(&regs->wp);
+
+	/* Relative rp and wp */
+	rrp = rp - (asr & GRTC_ASR_BUFST);
+	rwp = wp - (asr & GRTC_ASR_BUFST);
+
+	lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax) >> 1;
+	upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax) >> 1;
+
+	DBG("grtc_hw_copy: AVAIL: Lower: %d, Upper: %d\n",lower,upper);
+	DBG("grtc_hw_copy: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n",
+		rp,rrp,wp,rwp,bufmax,pDev->buf_remote);
+
+	if ( (upper+lower) == 0 || (!partial && ((upper+lower)<max) ) )
+		return 0;
+
+	/* Count bytes will be read */
+	count = (upper+lower) > max ? max : (upper+lower);
+	left = count;
+	tot = 0;
+
+	/* Read from upper part of data buffer */
+	if ( upper > 0 ){
+		if ( left < upper ){
+			cnt = left;
+		}else{
+			cnt = upper;	/* Read all upper data available */
+		}
+		DBG("grtc_hw_copy: COPYING %d from upper\n",cnt);
+		if ( (tot=grtc_copy((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), buf, cnt)) != cnt ) {
+			/* Failed to copy due to an receive error */
+			DBG("grtc_hw_copy(upper): not all in DMA buffer (%d)\n",tot);
+			count = tot;
+			ret = -1;
+			goto out;
+		}
+		buf += cnt;
+		left -= cnt;
+	}
+	
+	/* Read from lower part of data buffer */
+	if ( left > 0 ){
+		if ( left < lower ){
+			cnt = left;
+		}else{
+			cnt = lower;	/* Read all lower data available */
+		}
+		DBG("grtc_hw_copy: COPYING %d from lower\n",cnt);
+		if ( (tmp=grtc_copy((unsigned short *)pDev->buf, buf, cnt)) != cnt ) {
+			/* Failed to copy due to an receive error */
+			DBG("grtc_hw_copy(lower): not all in DMA buffer (%d)\n",tot);
+			count = tot+tmp;
+			ret = -1;
+			goto out;
+		}
+		buf += cnt;
+		left -= cnt;
+	}
+	ret = count;
+
+out:
+	count = count*2;
+	/* Update hardware RP pointer to tell hardware about new space available */
+	if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){
+		regs->rp = (rp+count-bufmax);
+	} else {
+		regs->rp = rp+count;
+	}
+
+	return ret;
+}
+
+#ifdef DEBUG_ERROR
+void grtc_log_error(struct grtc_priv *pDev, int err)
+{
+	/* Stop Receiver */
+	*(volatile unsigned int *)&pDev->regs->cor = 0x55000000;
+	*(volatile unsigned int *)&pDev->regs->cor = 0x55000000;
+	pDev->last_error[pDev->last_error_cnt] = err;
+	if ( ++pDev->last_error_cnt > 128 )
+		pDev->last_error_cnt = 0;
+}
+#endif
+
+/* Read one frame from DMA buffer 
+ * 
+ * Return Values
+ *  Zero - nothing more to process
+ *  1 - more to process, no free frames
+ *  2 - more to process, frame received
+ *  negative - more to process, frame dropped
+ */
+static int process_dma(struct grtc_priv *pDev)
+{
+	int ret, err;
+	int left, total_len;
+	unsigned char *dst;
+	struct grtc_frame *frm;
+
+	switch( pDev->frame_state ) {
+		case FRM_STATE_NONE:
+		DBG2("FRAME_STATE_NONE\n");
+	
+		/* Find Start of next frame by searching for 0x01 */
+		ret = grtc_hw_find_frm(pDev);
+		if ( ret != 0 ) {
+			/* Frame start not found */
+			return 0;
+		}
+		
+		/* Start of frame found, Try to copy header */
+		pDev->frm = NULL;
+		pDev->frame_state = FRM_STATE_HDR;
+
+		case FRM_STATE_HDR:
+		DBG2("FRAME_STATE_HDR\n");
+		
+		/* Wait for all of header to be in place by setting partial to 0 */
+		ret = grtc_hw_copy(pDev,pDev->hdr,5,0);
+		if ( ret < 0 ) {
+			/* Error copying header, restart scanning for new frame */
+			DEBUG_ERR_LOG(pDev,1);
+			pDev->stats.err++;
+			pDev->stats.err_hdr++;
+			DBG("FRAME_STATE_HDR: copying failed %d\n",ret);
+			pDev->frame_state = FRM_STATE_NONE;
+			return -1;
+		} else if ( ret != 5 ) {
+			DBG("FRAME_STATE_HDR: no header (%d)\n",ret);
+			/* Not all bytes available, come back later */
+			return 0;
+		}
+
+		/* The complete header has been copied, parse it */
+		pDev->frmlen = ((*(unsigned short *)&pDev->hdr[2]) & 0x3ff)+1;
+		if ( pDev->frmlen < 5 ) {
+			/* Error: frame length is not correct */
+			pDev->stats.err++;
+			pDev->stats.err_hdr++;
+			DBG("FRAME_STATE_HDR: frame length error: %d\n", pDev->frmlen);
+			pDev->frame_state = FRM_STATE_NONE;
+			return -1;
+		}
+		pDev->frame_state = FRM_STATE_ALLOC;
+
+		case FRM_STATE_ALLOC:
+		DBG2("FRAME_STATE_ALLOC\n");
+		/* Header has been read, allocate a frame to put payload and header into */
+		
+		/* Allocate Frame matching Frame length */
+		err = 0;
+		frm = grtc_pool_get_frm(pDev,pDev->frmlen,&err);
+		if ( !frm ) {
+			/* Couldn't find frame  */
+			DEBUG_ERR_LOG(pDev,2);
+			pDev->stats.dropped++;
+			DBG2("No free frames\n");
+			if ( err == 0 ){
+				/* Frame length exist in pool configuration, but no
+				 * frames are available for that frame length.
+				 */
+				DEBUG_ERR_LOG(pDev,3);
+				pDev->stats.dropped_no_buf++;
+				return 1;
+			} else {
+				/* Frame length of incoming frame is larger than the
+				 * frame length in any of the configured frame pools.
+				 * 
+				 * This may be because of an corrupt header. We simply
+				 * scan for the end of frame marker in the DMA buffer
+				 * so we can drop the frame.
+				 */
+				DEBUG_ERR_LOG(pDev,4);
+				pDev->stats.dropped_too_long++;
+				pDev->frame_state = FRM_STATE_NONE;
+				return -2;
+			}
+		}
+		frm->len = 5; /* Only header currenlty in frame */
+
+		/* Copy Frame Header into frame structure */
+		*((unsigned char *)&frm->hdr + 0) = pDev->hdr[0];
+		*((unsigned char *)&frm->hdr + 1) = pDev->hdr[1];
+		*((unsigned char *)&frm->hdr + 2) = pDev->hdr[2];
+		*((unsigned char *)&frm->hdr + 3) = pDev->hdr[3];
+		*((unsigned char *)&frm->hdr + 4) = pDev->hdr[4];
+
+		/* Calc Total and Filler byte count in frame */
+		total_len = pDev->frmlen / 7;
+		total_len = total_len * 7;
+		if ( pDev->frmlen != total_len )
+			total_len += 7;
+
+		pDev->filler = total_len - pDev->frmlen;
+
+		pDev->frame_state = FRM_STATE_PAYLOAD;
+		pDev->frm = frm;
+
+		case FRM_STATE_PAYLOAD:
+		DBG2("FRAME_STATE_PAYLOAD\n");
+		/* Parts of payload and the complete header has been read */
+		frm = pDev->frm;
+
+		dst = (unsigned char *)&frm->data[frm->len-5];
+		left = pDev->frmlen-frm->len;
+
+		ret = grtc_hw_copy(pDev,dst,left,1);
+		if ( ret < 0 ) {
+			DEBUG_ERR_LOG(pDev,5);
+			/* Error copying header, restart scanning for new frame */
+			pDev->frame_state = FRM_STATE_NONE;
+			frm->next = NULL;
+			grtc_pool_add_frms(frm);
+			pDev->frm = NULL;
+			pDev->stats.err++;
+			pDev->stats.err_payload++;
+			return -1;
+		} else if ( ret != left ) {
+			/* Not all bytes available, come back later */
+			frm->len += ret;
+			return 0;
+		}
+		frm->len += ret;
+		pDev->frame_state = FRM_STATE_FILLER;
+
+		case FRM_STATE_FILLER:
+		DBG2("FRAME_STATE_FILLER\n");
+		/* check filler data */
+		frm = pDev->frm;
+
+		ret = grtc_hw_check_ending(pDev,pDev->filler);
+		if ( ret != 0 ) {
+			/* Error in frame, drop frame */
+			DEBUG_ERR_LOG(pDev,6);
+			pDev->frame_state = FRM_STATE_NONE;
+			frm->next = NULL;
+			grtc_pool_add_frms(frm);
+			pDev->frm = NULL;
+			pDev->stats.err++;
+			pDev->stats.err_ending++;
+			return -1;
+		}
+
+		/* A complete frame received, put it into received frame queue */
+		if ( pDev->ready.head ) {
+			/* Queue not empty */
+			pDev->ready.tail->next = frm;
+		} else {
+			/* Queue empty */
+			pDev->ready.head = frm;
+		}
+		pDev->ready.tail = frm;
+		frm->next = NULL;
+		pDev->ready.cnt++;
+		pDev->stats.frames_recv++;
+
+		pDev->frame_state = FRM_STATE_NONE;
+		frm->next = NULL;
+		return 2;
+
+#if 0
+		case FRM_STATE_DROP:
+		DBG2("FRAME_STATE_DROP\n");
+		break;
+#endif
+
+		default:
+		printk("GRTC: internal error\n");
+		pDev->frame_state = FRM_STATE_NONE;
+		break;
+	}
+	
+	return 0;
+}
+
+static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	struct grtc_priv *pDev;
+	struct drvmgr_dev *dev;
+	rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+	unsigned int *data = ioarg->buffer;
+	int status,frm_len,i,ret;
+	struct grtc_ioc_buf_params *buf_arg;
+	struct grtc_ioc_config *cfg;
+	struct grtc_ioc_hw_status *hwregs;
+	struct grtc_ioc_pools_setup *pocfg;
+	struct grtc_ioc_assign_frm_pool *poassign;
+	struct grtc_frame *frm, *frms;
+	struct grtc_frame_pool *pool;
+	struct grtc_list *frmlist;
+	struct grtc_ioc_stats *stats;
+	unsigned int mem;
+	
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	FUNCDBG();
+
+	if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) {
+		return RTEMS_INVALID_NUMBER;
+	}
+	pDev = (struct grtc_priv *)dev->priv;
+
+	if (!ioarg)
+		return RTEMS_INVALID_NAME;
+
+	ioarg->ioctl_return = 0;
+	switch(ioarg->command) {
+		case GRTC_IOC_START:
+		if ( pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+		}
+		if ( (status=grtc_start(pDev)) != RTEMS_SUCCESSFUL ){
+			return status;
+		}
+		/* Register ISR and Unmask interrupt */
+		drvmgr_interrupt_register(pDev->dev, 0, "grtc", grtc_interrupt, pDev);
+
+		/* Read and write are now open... */
+		break;
+
+		case GRTC_IOC_STOP:
+		if ( !pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE;
+		}
+		drvmgr_interrupt_unregister(pDev->dev, 0, grtc_interrupt, pDev);
+		grtc_stop(pDev);
+		pDev->running = 0;
+		break;
+
+		case GRTC_IOC_ISSTARTED:
+		if ( !pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE;
+		}
+		break;
+
+		case GRTC_IOC_SET_BLOCKING_MODE:
+		if ( (unsigned int)data > GRTC_BLKMODE_COMPLETE ) {
+			return RTEMS_INVALID_NAME;
+		}
+		DBG("GRTC: Set blocking mode: %d\n",(unsigned int)data);
+		pDev->blocking = (unsigned int)data;
+		break;
+
+		case GRTC_IOC_SET_TIMEOUT:
+		DBG("GRTC: Timeout: %d\n",(unsigned int)data);
+		pDev->timeout = (rtems_interval)data;
+		break;
+
+		case GRTC_IOC_SET_BUF_PARAM:
+		if ( pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+		}
+
+		buf_arg = (struct grtc_ioc_buf_params *)data;
+		if ( !buf_arg ) {
+			return RTEMS_INVALID_NAME;
+		}
+
+		DBG("GRTC: IOC_SET_BUF_PARAM: Len: 0x%x, Custom Buffer: 0x%x\n",buf_arg->length,buf_arg->custom_buffer);
+
+		/* Check alignment need, skip bit 0 since that bit only indicates remote address or not */
+		if ( (unsigned int)buf_arg->custom_buffer & (~GRTC_BUF_MASK) & (~0x1) ) {
+			return RTEMS_INVALID_NAME;
+		}
+
+		if ( buf_arg->length > 0x100 ){
+			DBG("GRTC: Too big buffer requested\n");
+			return RTEMS_INVALID_NAME;
+		}
+
+		/* If current buffer allocated by driver we must free it */
+		if ( !pDev->buf_custom && pDev->buf ){
+			free(pDev->_buf);
+			pDev->_buf = NULL;
+		}
+		pDev->buf = NULL;
+		pDev->len = buf_arg->length*1024;
+
+		if (pDev->len <= 0)
+			break;
+		mem = (unsigned int)buf_arg->custom_buffer;
+		pDev->buf_custom = mem;
+
+		if (mem & 1) {
+			/* Remote address given, the address is as the GRTC
+			 * core looks at it. Translate the base address into
+			 * an address that the CPU can understand.
+			 */
+			pDev->buf_remote = (void *)(mem & ~0x1);
+			drvmgr_translate_check(pDev->dev, DMAMEM_TO_CPU,
+						(void *)pDev->buf_remote,
+						(void **)&pDev->buf,
+						pDev->len);
+		} else {
+			if (mem == 0) {
+				pDev->buf = grtc_memalign((~GRTC_ASR_BUFST)+1,pDev->len,&pDev->_buf);
+				DBG("grtc_ioctl: SETBUF: new buf: 0x%x(0x%x), Len: %d\n",pDev->buf,pDev->_buf,pDev->len);
+				if (!pDev->buf){
+					pDev->len = 0;
+					pDev->buf_custom = 0;
+					pDev->_buf = NULL;
+					pDev->buf_remote = 0;
+					DBG("GRTC: Failed to allocate memory\n");
+					return RTEMS_NO_MEMORY;
+				}
+			} else{
+				pDev->buf = buf_arg->custom_buffer;
+			}
+
+			/* Translate into a remote address so that GRTC core
+			 * on a remote AMBA bus (for example over the PCI bus)
+			 * gets a valid address
+			 */
+			drvmgr_translate_check(pDev->dev, CPUMEM_TO_DMA,
+						(void *)pDev->buf,
+						(void **)&pDev->buf_remote,
+						pDev->len);
+		}
+		break;
+
+		case GRTC_IOC_GET_BUF_PARAM:
+		if ( pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+		}
+
+		buf_arg = (struct grtc_ioc_buf_params *)data;
+		if ( !buf_arg ) {
+			return RTEMS_INVALID_NAME;
+		}
+
+		buf_arg->length = pDev->len >> 10; /* Length in 1kByte blocks */
+		if ( pDev->buf_custom )
+			buf_arg->custom_buffer =(void *)pDev->buf;
+		else
+			buf_arg->custom_buffer = 0; /* Don't reveal internal driver buffer */
+		break;
+
+		case GRTC_IOC_SET_CONFIG:
+		cfg = (struct grtc_ioc_config *)data;
+		if ( !cfg ) {
+			return RTEMS_INVALID_NAME;
+		}
+		
+		if ( pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE;
+		}
+
+		pDev->config = *cfg;
+		break;
+
+		case GRTC_IOC_GET_CONFIG:
+		cfg = (struct grtc_ioc_config *)data;
+		if ( !cfg ) {
+			return RTEMS_INVALID_NAME;
+		}
+
+		*cfg = pDev->config;
+		break;
+
+		case GRTC_IOC_GET_HW_STATUS:
+		hwregs = (struct grtc_ioc_hw_status *)data;
+		if ( !hwregs ) {
+			return RTEMS_INVALID_NAME;
+		}
+		/* We disable interrupt in order to get a snapshot of the registers */
+		IRQ_GLOBAL_DISABLE(oldLevel);
+		hwregs->sir	= READ_REG(&pDev->regs->sir);
+		hwregs->far	= READ_REG(&pDev->regs->far);
+		hwregs->clcw1	= READ_REG(&pDev->regs->clcw1);
+		hwregs->clcw2	= READ_REG(&pDev->regs->clcw2);
+		hwregs->phir	= READ_REG(&pDev->regs->phir);
+		hwregs->str	= READ_REG(&pDev->regs->str);
+		IRQ_GLOBAL_ENABLE(oldLevel);
+		break;
+
+		case GRTC_IOC_GET_STATS:
+		stats = (struct grtc_ioc_stats *)data;
+		if ( !stats ) {
+			return RTEMS_INVALID_NAME;
+		}
+		memcpy(stats,&pDev->stats,sizeof(struct grtc_ioc_stats));
+		break;
+
+		case GRTC_IOC_CLR_STATS:
+		memset(&pDev->stats,0,sizeof(struct grtc_ioc_stats));
+		break;
+		
+		case GRTC_IOC_SET_MODE:
+		if ( pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE;
+		}
+		if ( (int)data == GRTC_MODE_FRAME ) {
+			pDev->mode = GRTC_MODE_FRAME;
+		} else if ( (int)data == GRTC_MODE_RAW ) {
+			pDev->mode = GRTC_MODE_RAW;
+		} else {
+			return RTEMS_INVALID_NAME;
+		}
+		break;
+		
+		case GRTC_IOC_POOLS_SETUP:
+		if ( pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE;
+		}
+		pocfg = (struct grtc_ioc_pools_setup *)data;
+		if ( (pDev->mode != GRTC_MODE_FRAME) || !pocfg ) {
+			return RTEMS_INVALID_NAME;
+		}
+		
+		/* Check that list is sorted */
+		frm_len = 0;
+		for(i=0;i<pocfg->pool_cnt;i++){
+			if ( pocfg->pool_frame_len[i] <= frm_len ) {
+				return RTEMS_INVALID_NAME;
+			}
+			frm_len = pocfg->pool_frame_len[i];
+		}
+		
+		/* Ok, we trust user. The pool descriptions are allocated
+		 * but not frames, that the user must do self.
+		 */
+		if ( pDev->pools ) {
+			free(pDev->pools);
+		}
+		pDev->pools = malloc(pocfg->pool_cnt * sizeof(struct grtc_frame_pool));
+		if ( !pDev->pools ) {
+			pDev->pool_cnt = 0;
+			return RTEMS_NO_MEMORY;
+		}
+		pDev->pool_cnt = pocfg->pool_cnt;
+		for (i=0;i<pocfg->pool_cnt;i++) {
+			pDev->pools[i].frame_len = pocfg->pool_frame_len[i];
+			pDev->pools[i].frame_cnt = 0;
+			pDev->pools[i].frms = NULL;
+		}
+		break;
+
+		case GRTC_IOC_ASSIGN_FRM_POOL:
+		if ( pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE;
+		}
+
+		if ( (pDev->mode != GRTC_MODE_FRAME) ) {
+			return RTEMS_INVALID_NAME;
+		}
+
+		poassign = (struct grtc_ioc_assign_frm_pool *)data;
+		if ( !poassign ) {
+			return RTEMS_INVALID_NAME;
+		}
+		
+		/* Find pool to assign the frames to */
+		pool = NULL;
+		for(i=0; i<pDev->pool_cnt; i++) {
+			if ( pDev->pools[i].frame_len == poassign->frame_len ) {
+				pool = &pDev->pools[i];
+				break;
+			}
+		}
+		if ( !pool ) {
+			/* No Pool matching frame length */
+			return RTEMS_INVALID_NAME;
+		}
+		
+		/* Assign frames to pool */
+		frm = poassign->frames;
+		while(frm){
+			frm->pool = pool;	/* Assign Frame to pool */
+			frm = frm->next;
+		}
+		break;
+
+		case GRTC_IOC_ADD_BUFF:
+		frms = (struct grtc_frame *)data;
+
+		if ( (pDev->mode != GRTC_MODE_FRAME) ) {
+			return RTEMS_NOT_DEFINED;
+		}
+		if ( !frms ) {
+			return RTEMS_INVALID_NAME;
+		}
+
+		/* Add frames to respicative pools */
+		if ( grtc_pool_add_frms(frms) ) {
+			return RTEMS_INVALID_NAME;
+		}
+		break;
+
+		/* Try to read as much data as possible from DMA area and
+		 * put it into free frames.
+		 *
+		 * If receiver is in stopped mode, let user only read previously
+		 * received frames.
+		 */
+		case GRTC_IOC_RECV:
+
+		if ( (pDev->mode != GRTC_MODE_FRAME) ) {
+			return RTEMS_NOT_DEFINED;
+		}
+
+		while ( pDev->running && ((ret=process_dma(pDev) == 2) || (ret == -1)) ) {
+			/* Frame received or dropped, process next frame */
+		}
+
+		/* Take frames out from ready queue and put them to user */
+		frmlist = (struct grtc_list *)data;
+		if ( !frmlist ) {
+			return RTEMS_INVALID_NAME;
+		}
+
+		frmlist->head = pDev->ready.head;
+		frmlist->tail = pDev->ready.tail;
+		frmlist->cnt = pDev->ready.cnt;
+		
+		/* Empty list */
+		pDev->ready.head = NULL;
+		pDev->ready.tail = NULL;
+		pDev->ready.cnt = 0;
+		break;
+		
+		case GRTC_IOC_GET_CLCW_ADR:
+		if ( !data ) {
+			return RTEMS_INVALID_NAME;
+		}
+		*data = (unsigned int)&pDev->regs->clcw1;
+		break;
+
+		default:
+		return RTEMS_NOT_DEFINED;
+	}
+	return RTEMS_SUCCESSFUL;
+}
+
+static void grtc_interrupt(void *arg)
+{
+	struct grtc_priv *pDev = arg;
+	struct grtc_regs *regs = pDev->regs;
+	unsigned int status;
+
+	/* Clear interrupt by reading it */
+	status = READ_REG(&regs->pisr);
+	
+	/* Spurious Interrupt? */
+	if ( !pDev->running )
+		return;
+
+	if ( status & GRTC_INT_OV ){
+		
+		/* Stop core (Disable receiver, interrupts), set overrun condition, 
+		 * Flush semaphore if thread waiting for data in grtc_wait_data(). 
+		 */
+		pDev->overrun_condition = 1;
+
+		grtc_stop(pDev);
+
+		/* No need to handle the reset of interrupts, we are still */
+		goto out;
+	}
+
+	if ( status & GRTC_INT_CS ){
+		if ( (pDev->blocking==GRTC_BLKMODE_COMPLETE) && pDev->timeout ){
+			/* Signal to thread only if enough data is available */
+			if ( pDev->wait_for_nbytes > grtc_data_avail(pDev) ){
+				/* Not enough data available */
+				goto procceed_processing_interrupts;
+			}
+			
+			/* Enough data is available which means that we should wake 
+			 * up thread sleeping.
+			 */
+		}
+		
+		/* Disable further CLTUs Stored interrupts, no point until thread waiting for them
+		 * say it want to wait for more.
+		 */
+		regs->imr = READ_REG(&regs->imr) & ~GRTC_INT_CS;
+		
+		/* Signal Semaphore to wake waiting thread in read() */
+		rtems_semaphore_release(pDev->sem_rx);
+	}
+	
+procceed_processing_interrupts:
+
+	if ( status & GRTC_INT_CR ){
+	
+	}
+
+	if ( status & GRTC_INT_FAR ){
+	
+	}
+
+	if ( status & GRTC_INT_BLO ){
+	
+	}
+
+	if ( status & GRTC_INT_RFA ){
+	
+	}
+out:
+	if ( status )
+		regs->picr = status;
+}
+
+static rtems_device_driver grtc_initialize(
+  rtems_device_major_number major, 
+  rtems_device_minor_number unused,
+  void *arg
+  )
+{
+	/* Device Semaphore created with count = 1 */
+	if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'T', 'C'),
+		1,
+		RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+		0,
+		&grtc_dev_sem) != RTEMS_SUCCESSFUL ) {
+		return RTEMS_INTERNAL_ERROR;
+	}
+
+	return RTEMS_SUCCESSFUL;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/tmtc/grtm.c b/c/src/lib/libbsp/sparc/shared/tmtc/grtm.c
new file mode 100644
index 0000000..de1df72
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/tmtc/grtm.c
@@ -0,0 +1,1587 @@
+/* GRTM CCSDS Telemetry Encoder driver
+ *
+ * COPYRIGHT (c) 2007.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <rtems/bspIo.h>
+
+#include <drvmgr/drvmgr.h>
+#include <ambapp.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grtm.h>
+
+#ifndef IRQ_GLOBAL_PREPARE
+ #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
+#endif
+
+#ifndef IRQ_GLOBAL_DISABLE
+ #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
+#endif
+
+#ifndef IRQ_GLOBAL_ENABLE
+ #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
+#endif
+
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+
+#include <debug_defs.h>
+
+/* GRTM register map */
+struct grtm_regs {
+	volatile unsigned int	dma_ctrl;	/* DMA Control Register (0x00) */
+	volatile unsigned int	dma_status;	/* DMA Status Register (0x04) */
+	volatile unsigned int	dma_len;	/* DMA Length Register (0x08) */	
+	volatile unsigned int	dma_bd;		/* DMA Descriptor Pointer Register (0x0c) */
+
+	volatile unsigned int	dma_cfg;	/* DMA Configuration Register (0x10) */
+	volatile unsigned int	revision;	/* GRTM Revision Register (0x14) */
+
+	int unused0[(0x80-0x18)/4];
+
+	volatile unsigned int	ctrl;		/* TM Control Register (0x80) */
+	volatile unsigned int	status;		/* TM Status Register (0x84) */
+	volatile unsigned int	cfg;		/* TM Configuration Register (0x88) */
+	volatile unsigned int	size;		/* TM Size Register (0x8c) */
+
+	volatile unsigned int	phy;		/* TM Physical Layer Register (0x90) */
+	volatile unsigned int	code;		/* TM Coding Sub-Layer Register (0x94) */
+	volatile unsigned int	asmr;		/* TM Attached Synchronization Marker Register (0x98) */
+
+	int unused1;
+
+	volatile unsigned int	all_frm;	/* TM All Frames Generation Register (0xa0) */
+	volatile unsigned int	mst_frm;	/* TM Master Channel Frame Generation Register (0xa4) */
+	volatile unsigned int	idle_frm;	/* TM Idle Frame Generation Register (0xa8) */
+
+	int unused2[(0xc0-0xac)/4];
+
+	volatile unsigned int	fsh[4];		/* TM FSH/Insert Zone Registers (0xc0..0xcc) */
+
+	volatile unsigned int	ocf;		/* TM Operational Control Field Register (0xd0) */
+};
+
+/* DMA Control Register (0x00) */
+#define GRTM_DMA_CTRL_EN_BIT	0
+#define GRTM_DMA_CTRL_IE_BIT	1
+#define GRTM_DMA_CTRL_TXRST_BIT	2
+#define GRTM_DMA_CTRL_RST_BIT	3
+#define GRTM_DMA_CTRL_TFIE_BIT	4
+
+#define GRTM_DMA_CTRL_EN	(1<<GRTM_DMA_CTRL_EN_BIT)
+#define GRTM_DMA_CTRL_IE	(1<<GRTM_DMA_CTRL_IE_BIT)
+#define GRTM_DMA_CTRL_TXRST	(1<<GRTM_DMA_CTRL_TXRST_BIT)
+#define GRTM_DMA_CTRL_RST	(1<<GRTM_DMA_CTRL_RST_BIT)
+#define GRTM_DMA_CTRL_TFIE	(1<<GRTM_DMA_CTRL_TFIE_BIT)
+
+/* DMA Status Register (0x04) */
+#define GRTM_DMA_STS_TE_BIT	0
+#define GRTM_DMA_STS_TI_BIT	1
+#define GRTM_DMA_STS_TA_BIT	2
+#define GRTM_DMA_STS_TFF_BIT	3
+#define GRTM_DMA_STS_TFS_BIT	4
+
+#define GRTM_DMA_STS_TE		(1<<GRTM_DMA_STS_TE_BIT)
+#define GRTM_DMA_STS_TI		(1<<GRTM_DMA_STS_TI_BIT)
+#define GRTM_DMA_STS_TA		(1<<GRTM_DMA_STS_TA_BIT)
+#define GRTM_DMA_STS_TFF	(1<<GRTM_DMA_STS_TFF_BIT)
+#define GRTM_DMA_STS_TFS	(1<<GRTM_DMA_STS_TFS_BIT)
+#define GRTM_DMA_STS_ALL	0x1f
+
+/* DMA Length Register (0x08) */
+#define GRTM_DMA_LEN_LEN_BIT	0
+#define GRTM_DMA_LEN_LIM_BIT	16
+
+#define GRTM_DMA_LEN_LEN	(0x7ff<<GRTM_DMA_LEN_LEN_BIT)
+#define GRTM_DMA_LEN_LIM	(0x3ff<<GRTM_DMA_LEN_LIM_BIT)
+
+/* DMA Descriptor Pointer Register (0x0c) */
+#define GRTM_DMA_BD_INDEX_BIT	0
+#define GRTM_DMA_BD_BASE_BIT	10
+
+#define GRTM_DMA_BD_INDEX	(0x3ff<<GRTM_DMA_BD_INDEX_BIT)
+#define GRTM_DMA_BD_BASE	(0xfffffc<<GRTM_DMA_BD_BASE_BIT)
+
+/* DMA Configuration Register (0x10) */
+#define GRTM_DMA_CFG_BLKSZ_BIT	0
+#define GRTM_DMA_CFG_FIFOSZ_BIT	16
+
+#define GRTM_DMA_CFG_BLKSZ	(0xffff<<GRTM_DMA_CFG_BLKSZ_BIT)
+#define GRTM_DMA_CFG_FIFOSZ	(0xffff<<GRTM_DMA_CFG_FIFOSZ_BIT)
+
+/* TM Control Register (0x80) */
+#define GRTM_CTRL_EN_BIT	0
+
+#define GRTM_CTRL_EN		(1<<GRTM_CTRL_EN_BIT)
+
+/* TM Status Register (0x84) - Unused */
+
+/* TM Configuration Register (0x88) */
+#define GRTM_CFG_SC_BIT		0
+#define GRTM_CFG_SP_BIT		1
+#define GRTM_CFG_CE_BIT		2
+#define GRTM_CFG_NRZ_BIT	3
+#define GRTM_CFG_PSR_BIT	4
+#define GRTM_CFG_TE_BIT		5
+#define GRTM_CFG_RSDEP_BIT	6
+#define GRTM_CFG_RS_BIT		9
+#define GRTM_CFG_AASM_BIT	11
+#define GRTM_CFG_FECF_BIT	12
+#define GRTM_CFG_OCF_BIT	13
+#define GRTM_CFG_EVC_BIT	14
+#define GRTM_CFG_IDLE_BIT	15
+#define GRTM_CFG_FSH_BIT	16
+#define GRTM_CFG_MCG_BIT	17
+#define GRTM_CFG_IZ_BIT		18
+#define GRTM_CFG_FHEC_BIT	19
+#define GRTM_CFG_AOS_BIT	20
+#define GRTM_CFG_CIF_BIT	21
+#define GRTM_CFG_OCFB_BIT	22
+
+#define GRTM_CFG_SC		(1<<GRTM_CFG_SC_BIT)
+#define GRTM_CFG_SP		(1<<GRTM_CFG_SP_BIT)
+#define GRTM_CFG_CE		(1<<GRTM_CFG_CE_BIT)
+#define GRTM_CFG_NRZ		(1<<GRTM_CFG_NRZ_BIT)
+#define GRTM_CFG_PSR		(1<<GRTM_CFG_PSR_BIT)
+#define GRTM_CFG_TE		(1<<GRTM_CFG_TE_BIT)
+#define GRTM_CFG_RSDEP		(0x7<<GRTM_CFG_RSDEP_BIT)
+#define GRTM_CFG_RS		(0x3<<GRTM_CFG_RS_BIT)
+#define GRTM_CFG_AASM		(1<<GRTM_CFG_AASM_BIT)
+#define GRTM_CFG_FECF		(1<<GRTM_CFG_FECF_BIT)
+#define GRTM_CFG_OCF		(1<<GRTM_CFG_OCF_BIT)
+#define GRTM_CFG_EVC		(1<<GRTM_CFG_EVC_BIT)
+#define GRTM_CFG_IDLE		(1<<GRTM_CFG_IDLE_BIT)
+#define GRTM_CFG_FSH		(1<<GRTM_CFG_FSH_BIT)
+#define GRTM_CFG_MCG		(1<<GRTM_CFG_MCG_BIT)
+#define GRTM_CFG_IZ		(1<<GRTM_CFG_IZ_BIT)
+#define GRTM_CFG_FHEC		(1<<GRTM_CFG_FHEC_BIT)
+#define GRTM_CFG_AOS		(1<<GRTM_CFG_AOS_BIT)
+#define GRTM_CFG_CIF		(1<<GRTM_CFG_CIF_BIT)
+#define GRTM_CFG_OCFB		(1<<GRTM_CFG_OCFB_BIT)
+
+/* TM Size Register (0x8c) */
+#define GRTM_SIZE_BLKSZ_BIT	0
+#define GRTM_SIZE_FIFOSZ_BIT	8
+#define GRTM_SIZE_LEN_BIT	20
+
+#define GRTM_SIZE_BLKSZ		(0xff<<GRTM_SIZE_BLKSZ_BIT)
+#define GRTM_SIZE_FIFOSZ	(0xfff<<GRTM_SIZE_FIFOSZ_BIT)
+#define GRTM_SIZE_LEN		(0xfff<<GRTM_SIZE_LEN_BIT)
+
+/* TM Physical Layer Register (0x90) */
+#define GRTM_PHY_SUB_BIT	0
+#define GRTM_PHY_SCF_BIT	15
+#define GRTM_PHY_SYM_BIT	16
+#define GRTM_PHY_SF_BIT		31
+
+#define GRTM_PHY_SUB		(0x7fff<<GRTM_PHY_SUB_BIT)
+#define GRTM_PHY_SCF		(1<<GRTM_PHY_SCF_BIT)
+#define GRTM_PHY_SYM		(0x7fff<<GRTM_PHY_SYM_BIT)
+#define GRTM_PHY_SF		(1<<GRTM_PHY_SF_BIT)
+
+/* TM Coding Sub-Layer Register (0x94) */
+#define GRTM_CODE_SC_BIT	0
+#define GRTM_CODE_SP_BIT	1
+#define GRTM_CODE_CERATE_BIT	2
+#define GRTM_CODE_CE_BIT	5
+#define GRTM_CODE_NRZ_BIT	6
+#define GRTM_CODE_PSR_BIT	7
+#define GRTM_CODE_RS8_BIT	11
+#define GRTM_CODE_RSDEP_BIT	12
+#define GRTM_CODE_RS_BIT	15
+#define GRTM_CODE_AASM_BIT	16
+#define GRTM_CODE_CSEL_BIT	17
+
+#define GRTM_CODE_SC		(1<<GRTM_CODE_SC_BIT)
+#define GRTM_CODE_SP		(1<<GRTM_CODE_SP_BIT)
+#define GRTM_CODE_CERATE	(0x7<<GRTM_CODE_CERATE_BIT)
+#define GRTM_CODE_CE		(1<<GRTM_CODE_CE_BIT)
+#define GRTM_CODE_NRZ		(1<<GRTM_CODE_NRZ_BIT)
+#define GRTM_CODE_PSR		(1<<GRTM_CODE_PSR_BIT)
+#define GRTM_CODE_RS8		(1<<GRTM_CODE_RS8_BIT)
+#define GRTM_CODE_RSDEP		(0x7<<GRTM_CODE_RSDEP_BIT)
+#define GRTM_CODE_RS		(1<<GRTM_CODE_RS_BIT)
+#define GRTM_CODE_AASM		(1<<GRTM_CODE_AASM_BIT)
+#define GRTM_CODE_CSEL		(0x3<<GRTM_CODE_CSEL_BIT)
+
+/* TM Attached Synchronization Marker Register (0x98) */
+#define GRTM_ASM_BIT		0
+
+#define GRTM_ASM		0xffffffff
+
+/* TM All Frames Generation Register (0xa0) */
+#define GRTM_ALL_LEN_BIT	0
+#define GRTM_ALL_VER_BIT	12
+#define GRTM_ALL_FHEC_BIT	14
+#define GRTM_ALL_FECF_BIT	15
+#define GRTM_ALL_IZ_BIT		16
+#define GRTM_ALL_IZLEN_BIT	17
+
+#define GRTM_ALL_LEN		(0x7ff<<GRTM_ALL_LEN_BIT)
+#define GRTM_ALL_VER		(0x3<<GRTM_ALL_VER_BIT)
+#define GRTM_ALL_FHEC		(1<<GRTM_ALL_FHEC_BIT)
+#define GRTM_ALL_FECF		(1<<GRTM_ALL_FECF_BIT)
+#define GRTM_ALL_IZ		(1<<GRTM_ALL_IZ_BIT)
+#define GRTM_ALL_IZLEN		(0x1f<<GRTM_ALL_IZLEN_BIT)
+
+/* TM Master Channel Frame Generation Register (0xa4) */
+#define GRTM_MST_OW_BIT		0
+#define GRTM_MST_OCF_BIT	1
+#define GRTM_MST_FSH_BIT	2
+#define GRTM_MST_MC_BIT		3
+#define GRTM_MST_MCCNTR_BIT	24
+
+#define GRTM_MST_OW		(1<<GRTM_MST_OW_BIT)
+#define GRTM_MST_OCF		(1<<GRTM_MST_OCF_BIT)
+#define GRTM_MST_FSH		(1<<GRTM_MST_FSH_BIT)
+#define GRTM_MST_MC		(0xff<<GRTM_MST_MC_BIT)
+
+/* TM Idle Frame Generation Register (0xa8) */
+#define GRTM_IDLE_SCID_BIT	0
+#define GRTM_IDLE_VCID_BIT	10
+#define GRTM_IDLE_MC_BIT	16
+#define GRTM_IDLE_VCC_BIT	17
+#define GRTM_IDLE_FSH_BIT	18
+#define GRTM_IDLE_EVC_BIT	19
+#define GRTM_IDLE_OCF_BIT	20
+#define GRTM_IDLE_IDLE_BIT	21
+#define GRTM_IDLE_MCCNTR_BIT	24
+
+#define GRTM_IDLE_SCID		(0x3ff<<GRTM_IDLE_SCID_BIT)
+#define GRTM_IDLE_VCID		(0x3f<<GRTM_IDLE_VCID_BIT)
+#define GRTM_IDLE_MC		(1<<GRTM_IDLE_MC_BIT)
+#define GRTM_IDLE_VCC		(1<<GRTM_IDLE_VCC_BIT)
+#define GRTM_IDLE_FSH		(1<<GRTM_IDLE_FSH_BIT)
+#define GRTM_IDLE_EVC		(1<<GRTM_IDLE_EVC_BIT)
+#define GRTM_IDLE_OCF		(1<<GRTM_IDLE_OCF_BIT)
+#define GRTM_IDLE_IDLE		(1<<GRTM_IDLE_IDLE_BIT)
+#define GRTM_IDLE_MCCNTR	(0xff<<GRTM_IDLE_MCCNTR_BIT)
+
+/* TM FSH/Insert Zone Registers (0xc0..0xcc) */
+#define GRTM_FSH_DATA_BIT	0
+
+#define GRTM_FSH_DATA		0xffffffff
+
+
+/* TM Operational Control Field Register (0xd0) */
+#define GRTM_OCF_CLCW_BIT	0
+
+#define GRTM_OCF_CLCW		0xffffffff
+
+
+/* GRTM Revision 0 */
+#define GRTM_REV0_DMA_CTRL_TXRDY_BIT	5
+#define GRTM_REV0_DMA_CTRL_TXRDY	(1<<GRTM_REV0_DMA_CTRL_TXRDY_BIT)
+
+/* GRTM Revision 1 */
+#define GRTM_REV1_DMA_STS_TXRDY_BIT	6
+#define GRTM_REV1_DMA_STS_TXSTAT_BIT	7
+#define GRTM_REV1_DMA_STS_TXRDY		(1<<GRTM_REV1_DMA_STS_TXRDY_BIT)
+#define GRTM_REV1_DMA_STS_TXSTAT	(1<<GRTM_REV1_DMA_STS_TXSTAT_BIT)
+
+#define GRTM_REV1_REV_SREV_BIT		0
+#define GRTM_REV1_REV_MREV_BIT		8
+#define GRTM_REV1_REV_TIRQ_BIT		16
+#define GRTM_REV1_REV_SREV		(0xff<<GRTM_REV1_REV_SREV_BIT)
+#define GRTM_REV1_REV_MREV		(0xff<<GRTM_REV1_REV_MREV_BIT)
+#define GRTM_REV1_REV_TIRQ		(1<<GRTM_REV1_REV_TIRQ_BIT)
+
+
+/* GRTM transmit descriptor (0x400 Alignment need) */
+struct grtm_bd {
+	volatile unsigned int	ctrl;
+	unsigned int		address;
+};
+
+#define GRTM_BD_EN_BIT		0
+#define GRTM_BD_WR_BIT		1
+#define GRTM_BD_IE_BIT		2
+#define GRTM_BD_FECFB_BIT	3
+#define GRTM_BD_IZB_BIT		4
+#define GRTM_BD_FHECB_BIT	5
+#define GRTM_BD_OCFB_BIT	6
+#define GRTM_BD_FSHB_BIT	7
+#define GRTM_BD_MCB_BIT		8
+#define GRTM_BD_VCE_BIT		9
+#define GRTM_BD_TS_BIT		14
+#define GRTM_BD_UE_BIT		15
+
+#define GRTM_BD_EN		(1<<GRTM_BD_EN_BIT)
+#define GRTM_BD_WR		(1<<GRTM_BD_WR_BIT)
+#define GRTM_BD_IE		(1<<GRTM_BD_IE_BIT)
+#define GRTM_BD_FECFB		(1<<GRTM_BD_FECFB_BIT)
+#define GRTM_BD_IZB		(1<<GRTM_BD_IZB_BIT)
+#define GRTM_BD_FHECB		(1<<GRTM_BD_FHECB_BIT)
+#define GRTM_BD_OCFB		(1<<GRTM_BD_OCFB_BIT)
+#define GRTM_BD_FSHB		(1<<GRTM_BD_FSHB_BIT)
+#define GRTM_BD_MCB		(1<<GRTM_BD_MCB_BIT)
+#define GRTM_BD_VCE		(1<<GRTM_BD_VCE_BIT)
+#define GRTM_BD_TS		(1<<GRTM_BD_TS_BIT)
+#define GRTM_BD_UE		(1<<GRTM_BD_UE_BIT)
+
+/* Load register */
+
+#define READ_REG(address)	(*(volatile unsigned int *)address)
+
+/* Driver functions */
+static rtems_device_driver grtm_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor, void *arg);
+static rtems_device_driver grtm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
+
+#define GRTM_DRIVER_TABLE_ENTRY { grtm_initialize, grtm_open, grtm_close, grtm_read, grtm_write, grtm_ioctl }
+
+static rtems_driver_address_table grtm_driver = GRTM_DRIVER_TABLE_ENTRY;
+
+/* Structure that connects BD with SoftWare Frame */
+struct grtm_ring {
+	struct grtm_ring	*next;
+	struct grtm_bd		*bd;
+	struct grtm_frame	*frm;
+};
+
+struct grtm_priv {
+	struct drvmgr_dev	*dev;		/* Driver manager device */
+	char			devName[32];	/* Device Name */
+	struct grtm_regs	*regs;
+	int			irq;
+	int			minor;
+	int			subrev;		/* GRTM Revision */
+
+	int			open;
+	int			running;
+
+	struct grtm_bd		*bds;
+	void			*_bds;
+
+	/* Interrupt generation */
+	int			enable_cnt_curr;/* Down counter, when 0 the interrupt bit is set for next descriptor */
+	volatile int		handling_transmission;	/* Tells ISR if user are active changing descriptors/queues */
+
+	struct grtm_ring 	*_ring;		/* Root of ring */
+	struct grtm_ring 	*ring;		/* Next ring to use for new frames to be transmitted */
+	struct grtm_ring 	*ring_end;	/* Oldest activated ring used */
+
+	/* Collections of frames Ready to sent/ Scheduled for transmission/Sent 
+	 * frames waiting for the user to reclaim 
+	 */
+	struct grtm_list	ready;		/* Frames Waiting for free BDs */
+	struct grtm_list	scheduled;	/* Frames in BDs beeing transmitted */
+	struct grtm_list	sent;		/* Sent Frames waiting for user to reclaim and reuse */
+
+	/* Number of frames in the lists */
+	int			ready_cnt;	/* Number of ready frames */
+	int			scheduled_cnt;	/* Number of scheduled frames */
+	int			sent_cnt;	/* Number of sent frames */
+
+	struct grtm_ioc_hw	hw_avail;	/* Hardware support available */
+	struct grtm_ioc_config	config;
+	struct grtm_ioc_stats	stats;
+
+	rtems_id		sem_tx;
+};
+
+/* Prototypes */
+static void *grtm_memalign(unsigned int boundary, unsigned int length, void *realbuf);
+static void grtm_hw_reset(struct grtm_priv *pDev);
+static void grtm_interrupt(void *arg);
+
+/* Common Global Variables */
+static rtems_id grtm_dev_sem;
+static int grtm_driver_io_registered = 0;
+static rtems_device_major_number grtm_driver_io_major = 0;
+
+/******************* Driver manager interface ***********************/
+
+/* Driver prototypes */
+static int grtm_register_io(rtems_device_major_number *m);
+static int grtm_device_init(struct grtm_priv *pDev);
+
+static int grtm_init2(struct drvmgr_dev *dev);
+static int grtm_init3(struct drvmgr_dev *dev);
+
+static struct drvmgr_drv_ops grtm_ops = 
+{
+	{NULL, grtm_init2, grtm_init3, NULL},
+	NULL,
+	NULL
+};
+
+static struct amba_dev_id grtm_ids[] = 
+{
+	{VENDOR_GAISLER, GAISLER_GRTM},
+	{0, 0}		/* Mark end of table */
+};
+
+static struct amba_drv_info grtm_drv_info =
+{
+	{
+		DRVMGR_OBJ_DRV,			/* Driver */
+		NULL,				/* Next driver */
+		NULL,				/* Device list */
+		DRIVER_AMBAPP_GAISLER_GRTM_ID,	/* Driver ID */
+		"GRTM_DRV",			/* Driver Name */
+		DRVMGR_BUS_TYPE_AMBAPP,		/* Bus Type */
+		&grtm_ops,
+		NULL,				/* Funcs */
+		0,				/* No devices yet */
+		0,
+	},
+	&grtm_ids[0]
+};
+
+void grtm_register_drv (void)
+{
+	DBG("Registering GRTM driver\n");
+	drvmgr_drv_register(&grtm_drv_info.general);
+}
+
+static int grtm_init2(struct drvmgr_dev *dev)
+{
+	struct grtm_priv *priv;
+
+	DBG("GRTM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+	priv = dev->priv = malloc(sizeof(struct grtm_priv));
+	if ( !priv )
+		return DRVMGR_NOMEM;
+	memset(priv, 0, sizeof(*priv));
+	priv->dev = dev;
+
+	/* This core will not find other cores, so we wait for init2() */
+
+	return DRVMGR_OK;
+}
+
+static int grtm_init3(struct drvmgr_dev *dev)
+{
+	struct grtm_priv *priv;
+	char prefix[32];
+	rtems_status_code status;
+
+	priv = dev->priv;
+
+	/* Do initialization */
+
+	if ( grtm_driver_io_registered == 0) {
+		/* Register the I/O driver only once for all cores */
+		if ( grtm_register_io(&grtm_driver_io_major) ) {
+			/* Failed to register I/O driver */
+			dev->priv = NULL;
+			return DRVMGR_FAIL;
+		}
+
+		grtm_driver_io_registered = 1;
+	}
+
+	/* I/O system registered and initialized 
+	 * Now we take care of device initialization.
+	 */
+	if ( grtm_device_init(priv) ) {
+		return DRVMGR_FAIL;
+	}
+
+	/* Get Filesystem name prefix */
+	prefix[0] = '\0';
+	if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+		/* Failed to get prefix, make sure of a unique FS name
+		 * by using the driver minor.
+		 */
+		sprintf(priv->devName, "/dev/grtm%d", dev->minor_drv);
+	} else {
+		/* Got special prefix, this means we have a bus prefix
+		 * And we should use our "bus minor"
+		 */
+		sprintf(priv->devName, "/dev/%sgrtm%d", prefix, dev->minor_bus);
+	}
+
+	/* Register Device */
+	status = rtems_io_register_name(priv->devName, grtm_driver_io_major, dev->minor_drv);
+	if (status != RTEMS_SUCCESSFUL) {
+		return DRVMGR_FAIL;
+	}
+
+	return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+static int grtm_register_io(rtems_device_major_number *m)
+{
+	rtems_status_code r;
+
+	if ((r = rtems_io_register_driver(0, &grtm_driver, m)) == RTEMS_SUCCESSFUL) {
+		DBG("GRTM driver successfully registered, major: %d\n", *m);
+	} else {
+		switch(r) {
+		case RTEMS_TOO_MANY:
+			printk("GRTM rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
+			return -1;
+		case RTEMS_INVALID_NUMBER:  
+			printk("GRTM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
+			return -1;
+		case RTEMS_RESOURCE_IN_USE:
+			printk("GRTM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
+			return -1;
+		default:
+			printk("GRTM rtems_io_register_driver failed\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int grtm_device_init(struct grtm_priv *pDev)
+{
+	struct amba_dev_info *ambadev;
+	struct ambapp_core *pnpinfo;
+	union drvmgr_key_value *value;
+
+	/* Get device information from AMBA PnP information */
+	ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+	if ( ambadev == NULL ) {
+		return -1;
+	}
+	pnpinfo = &ambadev->info;
+	pDev->irq = pnpinfo->irq;
+	pDev->regs = (struct grtm_regs *)pnpinfo->apb_slv->start;
+	pDev->minor = pDev->dev->minor_drv;
+	pDev->open = 0;
+	pDev->running = 0;
+
+	/* Create Binary RX Semaphore with count = 0 */
+	if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'M', '0' + pDev->minor),
+		0,
+		RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
+		RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, 
+		0,
+		&pDev->sem_tx) != RTEMS_SUCCESSFUL ) {
+		return -1;
+	}
+
+	/* Allocate Memory for Buffer Descriptor Table, or let user provide a custom
+	 * address.
+	 */
+	value = drvmgr_dev_key_get(pDev->dev, "bdTabAdr", KEY_TYPE_POINTER);
+	if ( value ) {
+		pDev->bds = (struct grtm_bd *)value->ptr;
+		pDev->_bds = (void *)value->ptr;	
+	} else {
+		pDev->bds = (struct grtm_bd *)grtm_memalign(0x400, 0x400, &pDev->_bds);
+	}
+	if ( !pDev->bds ) {
+		DBG("GRTM: Failed to allocate descriptor table\n");
+		return -1;
+	}
+	memset(pDev->bds, 0, 0x400);
+
+	pDev->_ring = malloc(sizeof(struct grtm_ring) * 128);
+	if ( !pDev->_ring ) {
+		return -1;
+	}
+
+	/* Reset Hardware before attaching IRQ handler */
+	grtm_hw_reset(pDev);
+
+	/* Read SUB revision number, ignore  */
+	pDev->subrev = (READ_REG(&pDev->regs->revision) & GRTM_REV1_REV_SREV)
+			>> GRTM_REV1_REV_SREV_BIT;
+
+	return 0;
+}
+
+
+static inline void grtm_list_clr(struct grtm_list *list)
+{
+	list->head = NULL;
+	list->tail = NULL;
+}
+
+static void grtm_hw_reset(struct grtm_priv *pDev)
+{
+	/* Reset Core */
+	pDev->regs->dma_ctrl = GRTM_DMA_CTRL_RST;
+}
+
+static void grtm_hw_get_implementation(struct grtm_priv *pDev, struct grtm_ioc_hw *hwcfg)
+{
+	unsigned int cfg = READ_REG(&pDev->regs->cfg);
+
+	hwcfg->cs	= (cfg & GRTM_CFG_SC)	? 1:0;
+	hwcfg->sp	= (cfg & GRTM_CFG_SP)	? 1:0;
+	hwcfg->ce	= (cfg & GRTM_CFG_CE)	? 1:0;
+	hwcfg->nrz	= (cfg & GRTM_CFG_NRZ)	? 1:0;
+	hwcfg->psr	= (cfg & GRTM_CFG_PSR)	? 1:0;
+	hwcfg->te	= (cfg & GRTM_CFG_TE)	? 1:0;
+	hwcfg->rsdep	= (cfg & GRTM_CFG_RSDEP)>>GRTM_CFG_RSDEP_BIT;
+	hwcfg->rs	= (cfg & GRTM_CFG_RS)>>GRTM_CFG_RS_BIT;
+	hwcfg->aasm	= (cfg & GRTM_CFG_AASM)	? 1:0;
+	hwcfg->fecf	= (cfg & GRTM_CFG_FECF)	? 1:0;
+	hwcfg->ocf	= (cfg & GRTM_CFG_OCF)	? 1:0;
+	hwcfg->evc	= (cfg & GRTM_CFG_EVC)	? 1:0;
+	hwcfg->idle	= (cfg & GRTM_CFG_IDLE)	? 1:0;
+	hwcfg->fsh	= (cfg & GRTM_CFG_FSH)	? 1:0;
+	hwcfg->mcg	= (cfg & GRTM_CFG_MCG)	? 1:0;
+	hwcfg->iz	= (cfg & GRTM_CFG_IZ)	? 1:0;
+	hwcfg->fhec	= (cfg & GRTM_CFG_FHEC)	? 1:0;
+	hwcfg->aos	= (cfg & GRTM_CFG_AOS)	? 1:0;
+	hwcfg->cif	= (cfg & GRTM_CFG_CIF)	? 1:0;
+	hwcfg->ocfb	= (cfg & GRTM_CFG_OCFB)	? 1:0;
+
+	cfg = READ_REG(&pDev->regs->dma_cfg);
+	hwcfg->blk_size	= (cfg & GRTM_DMA_CFG_BLKSZ) >> GRTM_DMA_CFG_BLKSZ_BIT;
+	hwcfg->fifo_size= (cfg & GRTM_DMA_CFG_FIFOSZ) >> GRTM_DMA_CFG_FIFOSZ_BIT;
+}
+
+#warning Extra: Implement proper default calculation from hardware configuration
+static void grtm_hw_get_default_modes(struct grtm_ioc_config *cfg, struct grtm_ioc_hw *hwcfg)
+{
+	cfg->mode = GRTM_MODE_TM;
+	cfg->frame_length = 223;
+	cfg->limit = 0; /* Make driver auto configure it on START, user may override with non-zero value */
+	cfg->as_marker = 0x1ACFFC1D;
+
+	/* Physical */
+	cfg->phy_subrate = 1;
+	cfg->phy_symbolrate = 1;
+	cfg->phy_opts = 0;
+
+	/* Coding Layer */
+	cfg->code_rsdep = 1;
+	cfg->code_ce_rate = 0;
+	cfg->code_csel = 0;
+	cfg->code_opts = 0;
+
+	/* All Frame Generation */
+	cfg->all_izlen = 0;
+	cfg->all_opts = GRTM_IOC_ALL_FECF;
+
+	/* Master Channel Frame Generation */
+	if ( hwcfg->mcg ) {
+		cfg->mf_opts = GRTM_IOC_MF_MC;
+	} else {
+		cfg->mf_opts = 0;
+	}
+
+	/* Idle Frame Generation */
+	cfg->idle_scid = 0;
+	cfg->idle_vcid = 0;
+	if ( hwcfg->idle ) {
+		cfg->idle_opts = GRTM_IOC_IDLE_EN;
+	} else {
+		cfg->idle_opts = 0;
+	}
+
+	/* Interrupt options */
+	cfg->blocking = 0;	/* non-blocking mode is default */
+	cfg->enable_cnt = 16;	/* generate interrupt every 16 descriptor */
+	cfg->isr_desc_proc = 1;	/* Let interrupt handler do descriptor processing */
+	cfg->timeout = RTEMS_NO_TIMEOUT;
+	
+}
+
+static void *grtm_memalign(unsigned int boundary, unsigned int length, void *realbuf)
+{
+	*(int *)realbuf = (int)malloc(length+boundary);
+	DBG("GRTM: Alloced %d (0x%x) bytes, requested: %d\n",length+boundary,length+boundary,length);
+	return (void *)(((*(unsigned int *)realbuf)+boundary) & ~(boundary-1));
+}
+
+static int grtm_hw_set_config(struct grtm_priv *pDev, struct grtm_ioc_config *cfg, struct grtm_ioc_hw *hwcfg)
+{
+	struct grtm_regs *regs = pDev->regs;
+	unsigned int tmp;
+	unsigned int limit;
+
+	if ( cfg->limit == 0 ) {
+		/* Calculate Limit */
+		if ( cfg->frame_length > hwcfg->blk_size ) {
+			limit = hwcfg->blk_size*2;
+		} else {
+			limit = cfg->frame_length;
+		}
+	} else {
+		/* Use user configured limit */
+		limit = cfg->limit;
+	}
+
+	/* Frame Length and Limit */
+	regs->dma_len =	(((limit-1) << GRTM_DMA_LEN_LIM_BIT) & GRTM_DMA_LEN_LIM)|
+			(((cfg->frame_length-1) << GRTM_DMA_LEN_LEN_BIT) & GRTM_DMA_LEN_LEN);
+
+	/* Physical layer options */
+	tmp =	(cfg->phy_opts & (GRTM_IOC_PHY_SCF|GRTM_IOC_PHY_SF)) | 
+		(((cfg->phy_symbolrate-1)<<GRTM_PHY_SYM_BIT) & GRTM_PHY_SYM) | (((cfg->phy_subrate-1)<<GRTM_PHY_SUB_BIT) & GRTM_PHY_SUB);
+	regs->phy = tmp;
+
+	/* Coding Sub-layer Options */
+	tmp =	(cfg->code_opts & GRTM_IOC_CODE_ALL) | ((cfg->code_csel<<GRTM_CODE_CSEL_BIT) & GRTM_CODE_CSEL) |
+		(((cfg->code_rsdep-1)<<GRTM_CODE_RSDEP_BIT) & GRTM_CODE_RSDEP) | ((cfg->code_ce_rate<<GRTM_CODE_CERATE_BIT) & GRTM_CODE_CERATE);
+	regs->code = tmp;
+
+	/* Attached synchronization marker register */
+	regs->asmr = cfg->as_marker;
+
+	/* All Frames Generation */
+	tmp =	((cfg->all_opts & GRTM_IOC_ALL_ALL)<<14) | 
+		((cfg->all_izlen<<GRTM_ALL_IZLEN_BIT) & GRTM_ALL_IZLEN) |
+		((cfg->mode<<GRTM_ALL_VER_BIT) & GRTM_ALL_VER);
+	regs->all_frm = tmp;
+
+	/* Master Frame Generation */
+	regs->mst_frm = cfg->mf_opts & GRTM_IOC_MF_ALL;
+
+	/* Idle frame Generation */
+	tmp =	((cfg->idle_opts & GRTM_IOC_IDLE_ALL) << 16) |
+		((cfg->idle_vcid << GRTM_IDLE_VCID_BIT) & GRTM_IDLE_VCID) |
+		((cfg->idle_scid << GRTM_IDLE_SCID_BIT) & GRTM_IDLE_SCID);
+	regs->idle_frm = tmp;
+
+	return 0;
+}
+
+static int grtm_start(struct grtm_priv *pDev)
+{
+	struct grtm_regs *regs = pDev->regs;
+	int i;
+	struct grtm_ioc_config *cfg = &pDev->config;
+	volatile unsigned int *txrdy_reg;
+	unsigned int txrdy_mask;
+
+	/* Clear Descriptors */
+	memset(pDev->bds,0,0x400);
+	
+	/* Clear stats */
+	memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats));
+	
+	/* Init Descriptor Ring */
+	memset(pDev->_ring,0,sizeof(struct grtm_ring)*128);
+	for(i=0;i<127;i++){
+		pDev->_ring[i].next = &pDev->_ring[i+1];
+		pDev->_ring[i].bd = &pDev->bds[i];
+		pDev->_ring[i].frm = NULL;
+	}
+	pDev->_ring[127].next = &pDev->_ring[0];
+	pDev->_ring[127].bd = &pDev->bds[127];
+	pDev->_ring[127].frm = NULL;
+
+	pDev->ring = &pDev->_ring[0];
+	pDev->ring_end = &pDev->_ring[0];
+
+	/* Clear Scheduled, Ready and Sent list */
+	grtm_list_clr(&pDev->ready);
+	grtm_list_clr(&pDev->scheduled);
+	grtm_list_clr(&pDev->sent);
+
+	/* Software init */
+	pDev->handling_transmission = 0;
+	
+	/* Reset the transmitter */
+	regs->dma_ctrl = GRTM_DMA_CTRL_TXRST;
+	regs->dma_ctrl = 0;	/* Leave Reset */
+
+	/* Clear old interrupts */
+	regs->dma_status = GRTM_DMA_STS_ALL;
+
+	/* Set Descriptor Pointer Base register to point to first descriptor */
+	drvmgr_translate_check(pDev->dev, CPUMEM_TO_DMA, (void *)pDev->bds,
+				(void **)&regs->dma_bd, 0x400);
+
+	/* Set hardware options as defined by config */
+	if ( grtm_hw_set_config(pDev, cfg, &pDev->hw_avail) ) {
+		return RTEMS_IO_ERROR;
+	}
+
+	/* Enable TM Transmitter */
+	regs->ctrl = GRTM_CTRL_EN;
+
+	/* Wait for TXRDY to be cleared */
+	i=1000;
+	while( i > 0 ) {
+		asm volatile ("nop"::);
+		i--;
+	}
+
+	/* Location of TXRDY Bit is different for different revisions */
+	if ( pDev->subrev == 0 ) {
+		txrdy_reg = &regs->dma_ctrl;
+		txrdy_mask = GRTM_REV0_DMA_CTRL_TXRDY;
+	} else {
+		txrdy_reg = &regs->dma_status;
+		txrdy_mask = GRTM_REV1_DMA_STS_TXRDY;
+	}
+
+	/* Check transmitter startup OK */
+	i=0;
+	while( !(READ_REG(txrdy_reg) & txrdy_mask) && (i<1000000) ){
+		i++;
+	}
+	if ( !(READ_REG(txrdy_reg) & txrdy_mask) ){
+		/* Reset Failed */
+		DBG("GRTM: start: Reseting transmitter failed (%d)\n",i);
+		return RTEMS_IO_ERROR;
+	}
+	DBG("GRTM: reset time %d\n",i);
+
+	/* Everything is configured, the TM transmitter is started
+	 * and idle frames has been sent.
+	 */
+
+	/* Mark running before enabling the DMA transmitter */
+	pDev->running = 1;
+
+	/* Enable interrupts (Error and DMA TX) */
+	regs->dma_ctrl = GRTM_DMA_CTRL_IE;
+
+	DBG("GRTM: STARTED\n");
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static void grtm_stop(struct grtm_priv *pDev)
+{
+	struct grtm_regs *regs = pDev->regs;
+
+	/* Disable the transmitter & Interrupts */
+	regs->dma_ctrl = 0;
+	
+	/* Clear any pending interrupt  */
+	regs->dma_status = GRTM_DMA_STS_ALL;
+
+	DBG("GRTM: STOPPED\n");
+
+	/* Flush semaphore in case a thread is stuck waiting for TX Interrupts */
+	rtems_semaphore_flush(pDev->sem_tx);
+}
+
+static rtems_device_driver grtm_open(
+	rtems_device_major_number major, 
+	rtems_device_minor_number minor, 
+	void *arg)
+{
+	struct grtm_priv *pDev;
+	struct drvmgr_dev *dev;
+
+	FUNCDBG();
+
+	if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) {
+		DBG("Wrong minor %d\n", minor);
+		return RTEMS_INVALID_NUMBER;
+	}
+	pDev = (struct grtm_priv *)dev->priv;
+	
+	/* Wait until we get semaphore */
+	if ( rtems_semaphore_obtain(grtm_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){
+		return RTEMS_INTERNAL_ERROR;
+	}
+
+	/* Is device in use? */
+	if ( pDev->open ){
+		rtems_semaphore_release(grtm_dev_sem);
+		return RTEMS_RESOURCE_IN_USE;
+	}
+	
+	/* Mark device taken */
+	pDev->open = 1;
+	
+	rtems_semaphore_release(grtm_dev_sem);
+	
+	DBG("grtm_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev);
+	
+	/* Set defaults */
+	pDev->config.timeout = RTEMS_NO_TIMEOUT;	/* no timeout (wait forever) */
+	pDev->config.blocking = 0;			/* polling mode */
+	
+	pDev->running = 0;				/* not in running mode yet */
+
+	memset(&pDev->config,0,sizeof(pDev->config));
+	
+	/* The core has been reset when we execute here, so it is possible
+	 * to read out what HW is implemented from core.
+	 */
+	grtm_hw_get_implementation(pDev, &pDev->hw_avail);
+
+	/* Get default modes */
+	grtm_hw_get_default_modes(&pDev->config,&pDev->hw_avail);
+	
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	struct grtm_priv *pDev;
+	struct drvmgr_dev *dev;
+
+	FUNCDBG();
+
+	if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) {
+		return RTEMS_INVALID_NUMBER;
+	}
+	pDev = (struct grtm_priv *)dev->priv;
+
+	if ( pDev->running ){
+		grtm_stop(pDev);
+		pDev->running = 0;
+	}
+	
+	/* Reset core */
+	grtm_hw_reset(pDev);
+
+	/* Clear descriptor area just for sure */
+	memset(pDev->bds, 0, 0x400);
+	
+	/* Mark not open */
+	pDev->open = 0;
+
+	return RTEMS_SUCCESSFUL;
+}
+
+static rtems_device_driver grtm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	FUNCDBG();
+	return RTEMS_NOT_IMPLEMENTED;
+}
+
+static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	FUNCDBG();
+	return RTEMS_NOT_IMPLEMENTED;
+}
+
+/* Scans the desciptor table for scheduled frames that has been sent, 
+ * and moves these frames from the head of the scheduled queue to the
+ * tail of the sent queue.
+ *
+ * Also, for all frames the status is updated.
+ *
+ * Return Value
+ * Number of frames freed.
+ */
+static int grtm_free_sent(struct grtm_priv *pDev)
+{
+	struct grtm_ring *curr;
+	struct grtm_frame *last_frm, *first_frm;
+	int freed_frame_cnt=0;
+	unsigned int ctrl;
+
+	curr = pDev->ring_end;
+
+	/* Step into TX ring to find sent frames */
+	if ( !curr->frm ){
+		/* No scheduled frames, abort */
+		return 0;
+	}
+
+	/* There has been messages scheduled ==> scheduled messages may have been
+	 * transmitted and needs to be collected.
+	 */
+
+	first_frm = curr->frm;
+
+	/* Loop until first enabled unsent frame is found. 
+	 * A unused descriptor is indicated by an unassigned frm field
+	 */
+	while ( curr->frm && !((ctrl=READ_REG(&curr->bd->ctrl)) & GRTM_BD_EN) ){
+		/* Handle one sent Frame */
+		
+		/* Remember last handled frame so that insertion/removal from
+		 * frames lists go fast.
+		 */
+		last_frm = curr->frm;
+		
+		/* 1. Set flags to indicate error(s) and other information */
+		last_frm->flags |= GRTM_FLAGS_SENT; /* Mark sent */
+		
+		/* Update Stats */
+		pDev->stats.frames_sent++;
+    
+		/* Did packet encounter link error? */
+		if ( ctrl & GRTM_BD_UE ) {
+			pDev->stats.err_underrun++;
+			last_frm->flags |= GRRM_FLAGS_ERR;
+		}
+
+		curr->frm = NULL; /* Mark unused */
+
+		/* Increment */
+		curr = curr->next;
+		freed_frame_cnt++;
+	}
+
+	/* 1. Remove all handled frames from scheduled queue
+	 * 2. Put all handled frames into sent queue
+	 */
+	if ( freed_frame_cnt > 0 ){
+
+		/* Save TX ring posistion */
+		pDev->ring_end = curr;
+
+		/* Remove all sent frames from scheduled list */
+		if ( pDev->scheduled.tail == last_frm ){
+			/* All scheduled frames sent... */
+			pDev->scheduled.head = NULL;
+			pDev->scheduled.tail = NULL;
+		}else{
+			pDev->scheduled.head = last_frm->next;
+		}
+		last_frm->next = NULL;
+
+		/* Put all sent frames into "Sent queue" for user to
+		 * collect, later on.
+		 */
+		if ( !pDev->sent.head ){
+			/* Sent queue empty */
+			pDev->sent.head = first_frm;
+			pDev->sent.tail = last_frm;
+		}else{
+			pDev->sent.tail->next = first_frm;
+			pDev->sent.tail = last_frm;
+		}
+	}
+	return freed_frame_cnt;
+}
+
+
+/* Moves as many frames in the ready queue (as there are free descriptors for)
+ * to the scheduled queue. The free descriptors are then assigned one frame
+ * each and enabled for transmission.
+ * 
+ * Return Value
+ * Returns number of frames moved from ready to scheduled queue 
+ */
+static int grtm_schedule_ready(struct grtm_priv *pDev, int ints_off)
+{
+	int cnt;
+	unsigned int ctrl, dmactrl;
+	struct grtm_ring *curr_bd;
+	struct grtm_frame *curr_frm, *last_frm;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+
+	if ( !pDev->ready.head ){
+		return 0;
+	}
+
+	cnt=0;
+	curr_frm = pDev->ready.head;
+	curr_bd = pDev->ring;
+	while( !curr_bd->frm ){
+		/* Assign frame to descriptor */
+		curr_bd->frm = curr_frm;
+
+		/* Prepare descriptor address. Three cases:
+		 *  - GRTM core on same bus as CPU ==> no translation (Address used by CPU = address used by GRTM)
+		 *  - GRTM core on remote bus, and payload address given as used by CPU ==> Translation needed
+		 *  - GRTM core on remote bus, and payload address given as used by GRTM ==> no translation  [ USER does custom translation]
+		 */
+		if ( curr_frm->flags & (GRTM_FLAGS_TRANSLATE|GRTM_FLAGS_TRANSLATE_AND_REMEMBER) ) {
+			/* Do translation */
+			drvmgr_translate(pDev->dev, CPUMEM_TO_DMA, (void *)curr_frm->payload, (void **)&curr_bd->bd->address);
+			if ( curr_frm->flags & GRTM_FLAGS_TRANSLATE_AND_REMEMBER ) {
+				if ( curr_frm->payload != curr_bd->bd->address ) {
+					/* Translation needed */
+					curr_frm->flags &= ~GRTM_FLAGS_TRANSLATE_AND_REMEMBER;
+					curr_frm->flags |= GRTM_FLAGS_TRANSLATE;
+				} else {
+					/* No Trnaslation needed */
+					curr_frm->flags &= ~(GRTM_FLAGS_TRANSLATE|GRTM_FLAGS_TRANSLATE_AND_REMEMBER);
+				}
+			}
+		} else {
+			/* Custom translation or no translation needed */
+			curr_bd->bd->address = (unsigned int)curr_frm->payload;
+		}
+
+		ctrl = GRTM_BD_EN;
+		if ( curr_bd->next == pDev->_ring ){
+			ctrl |= GRTM_BD_WR; /* Wrap around */
+		}
+		/* Apply user options/flags */
+		ctrl |= (curr_frm->flags & GRTM_FLAGS_MASK);
+
+		/* Is this Frame going to be an interrupt Frame? */
+		if ( (--pDev->enable_cnt_curr) <= 0 ){
+			if ( pDev->config.enable_cnt == 0 ){
+				pDev->enable_cnt_curr = 0x3fffffff;
+			}else{
+				pDev->enable_cnt_curr = pDev->config.enable_cnt;
+				ctrl |= GRTM_BD_IE;
+			}
+		}
+
+		/* Enable descriptor */
+		curr_bd->bd->ctrl = ctrl;
+
+		last_frm = curr_frm;
+		curr_bd = curr_bd->next;
+		cnt++;
+		
+		/* Get Next Frame from Ready Queue */
+		if ( curr_frm == pDev->ready.tail ){
+			/* Handled all in ready queue. */
+			curr_frm = NULL;
+			break;
+		}
+		curr_frm = curr_frm->next;
+	}
+	
+	/* Has frames have been scheduled? */
+	if ( cnt > 0 ){
+		/* Make last frame mark end of chain, probably pointless... */
+		last_frm->next = NULL;
+
+		/* Insert scheduled packets into scheduled queue */
+		if ( !pDev->scheduled.head ){
+			/* empty scheduled queue */
+			pDev->scheduled.head = pDev->ready.head;
+			pDev->scheduled.tail = last_frm;
+		}else{
+			pDev->scheduled.tail->next = pDev->ready.head;
+			pDev->scheduled.tail = last_frm;
+		}
+
+		/* Remove scheduled packets from ready queue */
+		pDev->ready.head = curr_frm;
+		if ( !curr_frm ){
+			pDev->ready.tail = NULL;
+		}
+
+		/* Update TX ring posistion */
+		pDev->ring = curr_bd;
+		if ( !ints_off ) {
+			IRQ_GLOBAL_DISABLE(oldLevel);
+		}
+
+		/* Make hardware aware of the newly enabled descriptors */
+		dmactrl = READ_REG(&pDev->regs->dma_ctrl);
+		dmactrl &= ~(GRTM_DMA_CTRL_TXRST | GRTM_DMA_CTRL_RST);
+		dmactrl |= GRTM_DMA_CTRL_EN;
+		pDev->regs->dma_ctrl = dmactrl;
+		
+		if ( !ints_off ) {
+			IRQ_GLOBAL_ENABLE(oldLevel);
+		}
+	}
+	return cnt;
+}
+
+
+static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+{
+	struct grtm_priv *pDev;
+	struct drvmgr_dev *dev;
+	rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
+	unsigned int *data = ioarg->buffer;
+	int status;
+	struct grtm_ioc_config *cfg;
+	struct grtm_ioc_hw_status *hwregs;
+	IRQ_GLOBAL_PREPARE(oldLevel);
+	struct grtm_list *chain;
+	struct grtm_frame *curr;
+	struct grtm_ioc_hw *hwimpl;
+	struct grtm_ioc_stats *stats;
+	int num,ret;
+
+	FUNCDBG();
+
+	if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) {
+		return RTEMS_INVALID_NUMBER;
+	}
+	pDev = (struct grtm_priv *)dev->priv;
+
+	if (!ioarg)
+		return RTEMS_INVALID_NAME;
+
+	ioarg->ioctl_return = 0;
+	switch(ioarg->command) {
+		case GRTM_IOC_START:
+		if ( pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE; /* EBUSY */
+		}
+		if ( (status=grtm_start(pDev)) != RTEMS_SUCCESSFUL ){
+			return status;
+		}
+		/* Register ISR & Enable interrupt */
+		drvmgr_interrupt_register(dev, 0, "grtm", grtm_interrupt, pDev);
+
+		/* Read and write are now open... */
+		break;
+
+		case GRTM_IOC_STOP:
+		if ( !pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE;
+		}
+
+		/* Disable interrupts */
+		drvmgr_interrupt_unregister(dev, 0, grtm_interrupt, pDev);
+		grtm_stop(pDev);
+		pDev->running = 0;
+		break;
+
+		case GRTM_IOC_ISSTARTED:
+		if ( !pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE;
+		}
+		break;
+
+		case GRTM_IOC_SET_BLOCKING_MODE:
+		if ( (unsigned int)data > GRTM_BLKMODE_BLK ) {
+			return RTEMS_INVALID_NAME;
+		}
+		DBG("GRTM: Set blocking mode: %d\n",(unsigned int)data);
+		pDev->config.blocking = (unsigned int)data;
+		break;
+
+		case GRTM_IOC_SET_TIMEOUT:
+		DBG("GRTM: Timeout: %d\n",(unsigned int)data);
+		pDev->config.timeout = (rtems_interval)data;
+		break;
+
+		case GRTM_IOC_SET_CONFIG:
+		cfg = (struct grtm_ioc_config *)data;
+		if ( !cfg ) {
+			return RTEMS_INVALID_NAME;
+		}
+		
+		if ( pDev->running ) {
+			return RTEMS_RESOURCE_IN_USE;
+		}
+
+		pDev->config = *cfg;
+		break;
+
+		case GRTM_IOC_GET_STATS:
+		stats = (struct grtm_ioc_stats *)data;
+		if ( !stats ) {
+			return RTEMS_INVALID_NAME;
+		}
+		memcpy(stats,&pDev->stats,sizeof(struct grtm_ioc_stats));
+		break;
+
+		case GRTM_IOC_CLR_STATS:
+		memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats));
+		break;
+
+		case GRTM_IOC_GET_CONFIG:
+		cfg = (struct grtm_ioc_config *)data;
+		if ( !cfg ) {
+			return RTEMS_INVALID_NAME;
+		}
+
+		*cfg = pDev->config;
+		break;
+
+		case GRTM_IOC_GET_OCFREG:
+		if ( !pDev->hw_avail.ocf ) {
+			/* Hardware does not implement the OCF register */
+			return RTEMS_NOT_DEFINED;
+		}
+		if ( !data ) {
+			return RTEMS_INVALID_NAME;
+		}
+		*(unsigned int **)data = (unsigned int *)&pDev->regs->ocf;
+		break;
+
+		case GRTM_IOC_GET_HW_IMPL:
+		hwimpl = (struct grtm_ioc_hw *)data;
+		if ( !hwimpl ) {
+			return RTEMS_INVALID_NAME;
+		}
+		*hwimpl = pDev->hw_avail;
+		break;
+
+		case GRTM_IOC_GET_HW_STATUS:
+		hwregs = (struct grtm_ioc_hw_status *)data;
+		if ( !hwregs ) {
+			return RTEMS_INVALID_NAME;
+		}
+		/* We disable interrupt in order to get a snapshot of the registers */
+		IRQ_GLOBAL_DISABLE(oldLevel);
+#warning IMPLEMENT HWREGS
+		IRQ_GLOBAL_ENABLE(oldLevel);
+		break;
+
+		/* Put a chain of frames at the back of the "Ready frames" queue. This 
+		 * triggers the driver to put frames from the Ready queue into unused 
+		 * available descriptors. (Ready -> Scheduled)
+		 */
+
+		case GRTM_IOC_SEND:
+		if ( !pDev->running ){
+			return RTEMS_RESOURCE_IN_USE;
+		}
+		num=0;
+
+		/* Get pointer to frame chain wished be sent */
+		chain = (struct grtm_list *)ioarg->buffer;
+		if ( !chain ){
+			/* No new frames to send ==> just trigger hardware
+			 * to send previously made ready frames to be sent.
+			 */
+			pDev->handling_transmission = 1;
+			goto trigger_transmission;
+		}
+		if ( !chain->tail || !chain->head ){
+			return RTEMS_INVALID_NAME;
+		}
+
+		DBG("GRTM_SEND: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail);
+
+		/* Mark ready frames unsent by clearing GRTM_FLAGS_SENT of all frames */
+
+		curr = chain->head;
+		while(curr != chain->tail){
+			curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR);
+			curr = curr->next;
+			num++;
+		}
+		curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR);
+		num++;
+
+		pDev->handling_transmission = 1;
+		/* 1. Put frames into ready queue 
+		 *    (New Frames->READY)
+		 */
+		if ( pDev->ready.head ){
+			/* Frames already on ready queue (no free descriptors previously) ==>
+			 * Put frames at end of ready queue
+			 */
+			pDev->ready.tail->next = chain->head;
+			pDev->ready.tail = chain->tail;
+			chain->tail->next = NULL;
+		}else{
+			/* All frames is put into the ready queue for later processing */
+			pDev->ready.head = chain->head;
+			pDev->ready.tail = chain->tail;
+			chain->tail->next = NULL;
+		}
+		pDev->ready_cnt += num;	/* Added 'num' frames to ready queue */
+trigger_transmission:
+		/* 2. Free used descriptors and put the sent frame into the "Sent queue"  
+		 *    (SCHEDULED->SENT)
+		 */
+		num = grtm_free_sent(pDev);
+		pDev->scheduled_cnt -= num;
+		pDev->sent_cnt += num;
+
+		/* 3. Use all available free descriptors there are frames for
+		 *    in the ready queue.
+		 *    (READY->SCHEDULED)
+		 */
+		num = grtm_schedule_ready(pDev,0);
+		pDev->ready_cnt -= num;
+		pDev->scheduled_cnt += num;
+	
+		pDev->handling_transmission = 0;
+		break;
+
+		/* Take all available sent frames from the "Sent frames" queue.
+		 * If no frames has been sent, the thread may get blocked if in blocking
+		 * mode. The blocking mode is not available if driver is not in running mode.
+		 *
+		 * Note this ioctl may return success even if the driver is not in STARTED mode.
+		 * This is because in case of a error (link error of similar) and the driver switch
+		 * from START to STOP mode we must still be able to get our frames back.
+		 * 
+		 * Note in case the driver fails to send a frame for some reason (link error),
+		 * the sent flag is set to 0 indicating a failure.
+		 *
+		 */
+		case GRTM_IOC_RECLAIM:
+		/* Get pointer to were to place reaped chain */
+		chain = (struct grtm_list *)ioarg->buffer;
+		if ( !chain ){
+			return RTEMS_INVALID_NAME;
+		}
+
+		/* Lock out interrupt handler */
+		pDev->handling_transmission = 1;
+
+		do {
+			/* Move sent frames from descriptors to Sent queue. This makes more 
+			 * descriptors (BDs) available.
+			 */
+			num = grtm_free_sent(pDev);
+			pDev->scheduled_cnt -= num;
+			pDev->sent_cnt += num;
+			
+
+			if ( pDev->running ){
+				/* Fill descriptors with as many frames from the ready list 
+				 * as possible.
+				 */
+				num = grtm_schedule_ready(pDev,0);
+				pDev->ready_cnt -= num;
+				pDev->scheduled_cnt += num;
+			}
+
+			/* Are there any frames on the sent queue waiting to be 
+			 * reclaimed?
+			 */
+
+			if ( !pDev->sent.head ){
+				/* No frames to reclaim - no frame in sent queue.
+				 * Instead we block thread until frames have been sent 
+				 * if in blocking mode.
+				 */
+				if ( pDev->running && pDev->config.blocking ){
+					ret = rtems_semaphore_obtain(pDev->sem_tx,RTEMS_WAIT,pDev->config.timeout);
+					if ( ret == RTEMS_TIMEOUT ) {
+						pDev->handling_transmission = 0;
+						return RTEMS_TIMEOUT;
+					} else if ( ret == RTEMS_SUCCESSFUL ) {
+						/* There might be frames available, go check */
+						continue;
+					} else {
+						/* any error (driver closed, internal error etc.) */
+						pDev->handling_transmission = 0;
+						return RTEMS_UNSATISFIED;
+					}
+
+				}else{
+					/* non-blocking mode, we quit */
+					chain->head = NULL;
+					chain->tail = NULL;
+					/* do not lock out interrupt handler any more */
+					pDev->handling_transmission = 0;
+					return RTEMS_TIMEOUT;
+				}
+			}else{
+				/* Take all sent framess from sent queue to userspace queue */
+				chain->head = pDev->sent.head;
+				chain->tail = pDev->sent.tail;
+				chain->tail->next = NULL; /* Just for sure */
+
+				/* Mark no Sent */
+				grtm_list_clr(&pDev->sent);
+				pDev->sent_cnt = 0;
+
+				DBG("TX_RECLAIM: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail);
+				break;
+			}
+
+		}while(1);
+		
+		/* do not lock out interrupt handler any more */
+		pDev->handling_transmission = 0;
+		break;
+
+		default:
+		return RTEMS_NOT_DEFINED;
+	}
+	return RTEMS_SUCCESSFUL;
+}
+
+static void grtm_interrupt(void *arg)
+{
+	struct grtm_priv *pDev = arg;
+	struct grtm_regs *regs = pDev->regs;
+	unsigned int status;
+	int num;
+
+	/* Clear interrupt by reading it */
+	status = READ_REG(&regs->dma_status);
+	
+	/* Spurious Interrupt? */
+	if ( !pDev->running )
+		return;
+
+	if ( status )
+		regs->dma_status = status;
+
+	if ( status & GRTM_DMA_STS_TFF ){
+		pDev->stats.err_transfer_frame++;
+	}
+
+	if ( status & GRTM_DMA_STS_TA ){
+		pDev->stats.err_ahb++;
+	}
+
+	if ( status & GRTM_DMA_STS_TE ){
+		pDev->stats.err_tx++;
+	}
+
+	if ( status & GRTM_DMA_STS_TI ){
+		
+		if ( pDev->config.isr_desc_proc && !pDev->handling_transmission ) {
+			/* Free used descriptors and put the sent frame into the "Sent queue"  
+			 *   (SCHEDULED->SENT)
+			 */
+			num = grtm_free_sent(pDev);
+			pDev->scheduled_cnt -= num;
+			pDev->sent_cnt += num;
+
+			/* Use all available free descriptors there are frames for
+			 * in the ready queue.
+			 *   (READY->SCHEDULED)
+			 */
+			num = grtm_schedule_ready(pDev,1);
+			pDev->ready_cnt -= num;
+			pDev->scheduled_cnt += num;
+
+#if 0
+			if ( (pDev->config.blocking==GRTM_BLKMODE_COMPLETE) && pDev->timeout ){
+				/* Signal to thread only if enough data is available */
+				if ( pDev->wait_for_frames > grtm_data_avail(pDev) ){
+					/* Not enough data available */
+					goto procceed_processing_interrupts;
+				}
+
+				/* Enough number of frames has been transmitted which means that
+				 * the waiting thread should be woken up.
+				 */
+				rtems_semaphore_release(pDev->sem_tx);
+			}
+#endif
+		}
+
+		if ( pDev->config.blocking == GRTM_BLKMODE_BLK ) {
+			/* Blocking mode */
+
+#if 0
+			/* Disable further Interrupts until handled by waiting task. */
+			regs->dma_ctrl = READ_REG(&regs->dma_ctrl) & ~GRTM_DMA_CTRL_IE;
+#endif
+		
+			/* Signal Semaphore to wake waiting thread in ioctl(SEND|RECLAIM) */
+			rtems_semaphore_release(pDev->sem_tx);
+		}
+
+	}
+
+procceed_processing_interrupts:
+	;
+}
+
+static rtems_device_driver grtm_initialize(
+  rtems_device_major_number major, 
+  rtems_device_minor_number unused,
+  void *arg
+  )
+{
+	/* Device Semaphore created with count = 1 */
+	if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'T', 'M'),
+		1,
+		RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
+		0,
+		&grtm_dev_sem) != RTEMS_SUCCESSFUL ) {
+		return RTEMS_INTERNAL_ERROR;
+	}
+
+	return RTEMS_SUCCESSFUL;
+}
-- 
1.7.0.4




More information about the devel mailing list