This is the mail archive of the ecos-patches@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

synthetic target framebuffer driver


This patch contributes eCosCentric's synthetic target framebuffer
device driver. It should allow people to experiment with the
framebuffer support, as well as act as a reference (albeit not
entirely typical) device driver.

Bart

Index: ChangeLog
===================================================================
RCS file: ChangeLog
diff -N ChangeLog
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ChangeLog	7 Oct 2008 21:00:17 -0000
@@ -0,0 +1,35 @@
+2008-10-06  Bart Veer  <bartv@ecoscentric.com>
+
+	* synthetic target framebuffer driver imported into anoncvs
+
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
Index: cdl/framebuf_synth.cdl
===================================================================
RCS file: cdl/framebuf_synth.cdl
diff -N cdl/framebuf_synth.cdl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ cdl/framebuf_synth.cdl	7 Oct 2008 21:00:17 -0000
@@ -0,0 +1,256 @@
+# ====================================================================
+#
+#      framebuf_synth.cdl
+#
+#      Framebuffer device driver for the synthetic target.
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+# -------------------------------------------
+# This file is part of eCos, the Embedded Configurable Operating System.
+# Copyright (C) 2008 Free Software Foundation, Inc.
+#
+# eCos is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 or (at your option) any later version.
+#
+# eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with eCos; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# As a special exception, if other files instantiate templates or use macros
+# or inline functions from this file, or you compile this file and link it
+# with other works to produce a work based on this file, this file does not
+# by itself cause the resulting work to be covered by the GNU General Public
+# License. However the source code for this file must still be made available
+# in accordance with section (3) of the GNU General Public License.
+#
+# This exception does not invalidate any other reasons why a work based on
+# this file might be covered by the GNU General Public License.
+# -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):     bartv
+# Date:          2005-10-24
+#
+#####DESCRIPTIONEND####
+#========================================================================
+
+cdl_package CYGPKG_DEVS_FRAMEBUF_SYNTH {
+    display		"Synthetic Target Framebuffer device driver"
+    parent		CYGPKG_IO_FRAMEBUF
+    active_if		CYGPKG_IO_FRAMEBUF
+    hardware
+    include_files
+
+    description "
+        This package provides a framebuffer device driver for the
+        synthetic target."
+
+    for { set _fb 0 } { $_fb < 4 } { incr _fb } {
+        cdl_component CYGPKG_DEVS_FRAMEBUF_SYNTH_FB$_fb {
+            display	"Provide framebuffer device fb$_fb"
+            description "
+                The synthetic target framebuffer driver can provide up to
+                four framebuffer devices, named fb0 to fb3. Each device's
+                width, height, depth, and colour format can be controlled.
+                This option enables device fb$_fb"
+
+            flavor		    bool
+            default_value	[expr $_fb ? 0 : 1]
+            implements		CYGINT_IO_FRAMEBUF_DEVICES
+            implements		CYGHWR_IO_FRAMEBUF_FUNCTIONALITY_DOUBLE_BUFFER
+            requires		is_substr(CYGDAT_IO_FRAMEBUF_DEVICES, \" fb[set _fb] \")
+
+            cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_WIDTH {
+                display		"fb$_fb width"
+                flavor 		data
+                default_value	320
+                legal_values	16 to 4096
+            }
+
+            cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_HEIGHT {
+                display		"fb$_fb height"
+                flavor 		data
+                default_value	240
+                legal_values	16 to 4096
+            }
+
+            cdl_option CYGDAT_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_FORMAT {
+                display		"fb$_fb format"
+                flavor		data
+                if { 0 } {
+                    legal_values	{ "1BPP_BE_PAL888"  "1BPP_LE_PAL888"
+                        "2BPP_BE_PAL888"  "2BPP_LE_PAL888"
+                        "4BPP_BE_PAL888"  "4BPP_LE_PAL888"
+                        "8BPP_PAL888"     "8BPP_TRUE_332"
+                        "16BPP_TRUE_565"  "16BPP_TRUE_555"
+                        "32BPP_TRUE_0888"
+                    }
+                } else {
+                    legal_values	{
+                        "8BPP_PAL888"     "8BPP_TRUE_332"
+                        "16BPP_TRUE_565"  "16BPP_TRUE_555"
+                        "32BPP_TRUE_0888"
+                    }
+                }
+                default_value	{ "8BPP_PAL888" }
+                if { 0 } {
+                    description "
+                        Each synthetic target framebuffer device can be configured
+                        to emulate a particular format. This consists of three fields:
+                        depth, endianness, and colour. The depth is in bits per pixel
+                        and can be 1bpp, 2bpp, 4bpp, 8bpp, 16bpp or 32bpp. The endianness
+                        is only relevant for 1bpp, 2bpp and 4bpp devices and affects how
+                        pixels are organized within each byte. Colour can be either
+                        paletted or true colour. 1bpp, 2bpp and 4bpp implies paletted, and
+                        16bpp and 32bpp implies true colour. 8bpp can be either paletted
+                        or true colour. For 1bpp the default palette is monochrome with
+                        colour 0 == black. For 2bpp the default palette is greyscale with
+                        colour 0 == black. For 4bpp the default palette is EGA. For 8bpp
+                        the default palette is VGA. The application can change these
+                        default palettes as required to match the hardware being emulated."
+                } else {
+                    description "
+                        Each synthetic target framebuffer device can be configured
+                        to emulate a particular format. This consists of two fields:
+                        depth and colour. The depth is in bits per pixel and can be
+                        8bpp, 16bpp or 32bpp. Colour can be either paletted or true colour.
+                        16bpp and 32bpp implies true colour. 8bpp can be either paletted
+                        or true colour. For 8bpp the default palette is VGA. The application
+                        can change these default palettes as required to match the hardware being emulated."
+                }
+            }
+
+            cdl_component CYGIMP_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_VIEWPORT {
+                display		    "fb$_fb provides viewport support"
+                default_value	0
+                implements	    CYGHWR_IO_FRAMEBUF_FUNCTIONALITY_VIEWPORT
+                description "
+                    Optionally framebuffer device $_fb can support a viewport.
+                    In other words only a subset of the framebuffer, the viewport,
+                    is actually visible on the display and application code can
+                    move this viewport."
+
+                cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_VIEWPORT_WIDTH {
+                    display		    "fb$_fb viewport width"
+                    flavor		    data
+                    default_value	CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_WIDTH
+                    legal_values	16 to CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_WIDTH
+                }
+
+                cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_VIEWPORT_HEIGHT {
+                    display		    "fb$_fb viewport height"
+                    flavor		    data
+                    default_value	CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_HEIGHT
+                    legal_values	16 to CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_HEIGHT
+                }
+            }
+
+            cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set _fb]_PAGE_FLIPPING {
+                display		    "fb$_fb supports page flipping"
+                flavor		    booldata
+                default_value	0
+                legal_values	2 3 4
+                description "
+                    Optionally framebuffer device $_fb can support page flipping.
+                    The device supports between two and four pages, only one
+                    of which is visible on the display. This allows code to
+                    update one page without disturbing what is currently visible."
+            }
+        }
+
+        # Eliminate any framebuffer devices that are no longer enabled.
+        requires (CYGPKG_DEVS_FRAMEBUF_SYNTH_FB$_fb || !is_substr(CYGDAT_IO_FRAMEBUF_DEVICES, \" fb[set _fb] \"))
+    }
+
+    cdl_component CYGPKG_DEVS_FRAMEBUF_SYNTH_FUNCTIONALITY {
+        display		"Functionality supported by the enabled framebuffer(s)"
+        flavor		none
+        description "
+            The generic framebuffer code needs configure-time information about
+            functionality of the enabled framebuffer or framebuffers. Usually
+            all this information is fixed by the hardware, but the synthetic
+            target framebuffer support is more flexible than real hardware. To
+            cope with this some dummy options are needed."
+
+        active_if { CYGPKG_DEVS_FRAMEBUF_SYNTH_FB0 ||
+            CYGPKG_DEVS_FRAMEBUF_SYNTH_FB1 ||
+            CYGPKG_DEVS_FRAMEBUF_SYNTH_FB2 ||
+            CYGPKG_DEVS_FRAMEBUF_SYNTH_FB3 }
+        make -priority=1 {
+            $(PREFIX)/include/cyg/io/framebufs/synth_fb.h :	\
+                $(REPOSITORY)/$(PACKAGE)/src/gen_synthfb.tcl 	\
+                $(PREFIX)/include/pkgconf/devs_framebuf_synth.h
+            sh $< $(PREFIX)
+        }
+        compile synthfb.c
+        compile -library=libextras.a synthfb_init.cxx
+
+        cdl_option CYGHWR_DEVS_FRAMEBUF_SYNTH_FUNCTIONALITY_32BPP {
+            display	"One or more of the enabled framebuffer devices has a depth of 32bpp"
+            calculated  { is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB0_FORMAT, "32BPP") ||
+                is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB1_FORMAT, "32BPP") ||
+                is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB2_FORMAT, "32BPP") ||
+                is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB3_FORMAT, "32BPP") }
+            implements	CYGHWR_IO_FRAMEBUF_FUNCTIONALITY_32BPP
+        }
+        
+        cdl_option CYGHWR_DEVS_FRAMEBUF_SYNTH_FUNCTIONALITY_PALETTED {
+            display	"One or more of the enabled framebuffer devices uses a paletted display"
+            calculated  { is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB0_FORMAT, "PAL") ||
+                is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB1_FORMAT, "PAL") ||
+                is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB2_FORMAT, "PAL") ||
+                is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB3_FORMAT, "PAL") }
+            implements CYGHWR_IO_FRAMEBUF_FUNCTIONALITY_PALETTE
+            implements CYGHWR_IO_FRAMEBUF_FUNCTIONALITY_WRITEABLE_PALETTE
+        }
+
+        cdl_option CYGHWR_DEVS_FRAMEBUF_SYNTH_TRUE_COLOUR {
+            display	"One or more of the enabled framebuffer devices uses a true colour display"
+            calculated  { is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB0_FORMAT, "TRUE") ||
+                is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB1_FORMAT, "TRUE") ||
+                is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB2_FORMAT, "TRUE") ||
+                is_substr(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB3_FORMAT, "TRUE") }
+            implements CYGHWR_IO_FRAMEBUF_FUNCTIONALITY_TRUE_COLOUR
+        }
+    }
+
+    cdl_component CYGPKG_DEVS_FRAMEBUF_SYNTH_OPTIONS {
+        display "Framebuffer build options"
+        flavor  none
+        description   "
+	    Package specific build options including control over
+	    compiler flags used only in building the synthetic
+            target framebuffer device driver."
+
+        cdl_option CYGPKG_DEVS_FRAMEBUF_SYNTH_CFLAGS_ADD {
+            display "Additional compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for building
+                the synthetic target framebuffer device driver. These flags
+                are used in addition to the set of global flags."
+        }
+
+        cdl_option CYGPKG_DEVS_FRAMEBUF_SYNTH_CFLAGS_REMOVE {
+            display "Suppressed compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for building
+                the synthetic target framebuffer device driver. These flags
+                are removed from the set of global flags if present."
+        }
+    }
+}
Index: doc/synth_framebuf.sgml
===================================================================
RCS file: doc/synth_framebuf.sgml
diff -N doc/synth_framebuf.sgml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ doc/synth_framebuf.sgml	7 Oct 2008 21:00:18 -0000
@@ -0,0 +1,239 @@
+<!-- DOCTYPE refentry  PUBLIC "-//OASIS//DTD DocBook V3.1//EN" -->
+
+<!-- =============================================================== -->
+<!--                                                                 -->
+<!--     synth_framebuf.sgml                                         -->
+<!--                                                                 -->
+<!--     Synthetic target frame buffer device                        -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- ####COPYRIGHTBEGIN####                                          -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.               -->
+<!-- This material may be distributed only subject to the terms      -->
+<!-- and conditions set forth in the Open Publication License, v1.0  -->
+<!-- or later (the latest version is presently available at          -->
+<!-- http://www.opencontent.org/openpub/)                            -->
+<!-- Distribution of the work or derivative of the work in any       -->
+<!-- standard (paper) book form is prohibited unless prior           -->
+<!-- permission obtained from the copyright holder                   -->
+<!-- =============================================================== -->
+<!--                                                                 -->      
+<!-- ####COPYRIGHTEND####                                            -->
+<!-- =============================================================== -->
+<!-- #####DESCRIPTIONBEGIN####                                       -->
+<!--                                                                 -->
+<!-- Author(s):   bartv                                              -->
+<!-- Contact(s):  bartv                                              -->
+<!-- Date:        2008/10/07                                         -->
+<!-- Version:     0.01                                               -->
+<!--                                                                 -->
+<!-- ####DESCRIPTIONEND####                                          -->
+<!-- =============================================================== -->
+
+<part id="devs-framebuf-synth-ref">
+  <title>Synthetic Target Framebuffer Device</title>
+
+<refentry id="devs-framebuf-synth">
+  <refmeta>
+    <refentrytitle>Synthetic Target Framebuffer Device</refentrytitle>
+  </refmeta>
+  <refnamediv>
+    <refname>Synthetic Target Framebuffer Device</refname>
+    <refpurpose>Emulate framebuffer hardware in the synthetic target</refpurpose> 
+  </refnamediv>
+
+  <refsect1 id="devs-framebuf-synth-overview"><title>Overview</title>
+    <para>
+This package <varname>CYGPKG_DEVS_FRAMEBUF_SYNTH</varname> provides a
+framebuffer device driver for the eCos synthetic target.
+    </para>
+    <informalfigure PgWide=1>
+      <mediaobject>
+        <imageobject>
+          <imagedata fileref="synthfb.png" Scalefit=1 Align="Center">
+        </imageobject>
+      </mediaobject>
+    </informalfigure>
+    <para>
+The driver supports up to four framebuffer devices
+<varname>fb0</varname>, <varname>fb1</varname>, <varname>fb2</varname>
+and <varname>fb3</varname>. The width, height, depth, and display
+format of each framebuffer can be controlled via configuration
+options. It is also possible to set a viewport for each device and to
+enable page flipping.
+    </para>
+    <para>
+To use the framebuffer support the eCos application must run inside an
+X session, not from the console, and it must be started with
+<parameter>--io</parameter> to enable the I/O auxiliary. The I/O
+auxiliary will start a separate instance of a host-side utility
+<application>framebuf</application> for each target-side framebuffer
+device. The <application>framebuf</application> utility can access the
+eCos framebuffer data via a shared memory region and draw it to the
+screen using X library calls. It needs the X server to run with a
+TrueColor visual and a display of depth of 24 or 32 bits per pixel.
+    </para>
+  </refsect1>
+
+  <refsect1 id="devs-framebuf-synth-install"><title>Installation</title>
+    <para>
+The synthetic target framebuffer driver depends on host-side support
+which must be built and installed. The relevant code resides in the
+<filename class="directory">host</filename> subdirectory of the
+synthetic target framebuffer package, and building it involves the
+standard <command>configure</command>, <command>make</command> and
+<command>make install</command> steps. This will build and install a
+utility program <application>framebuf</application> that does the
+actual drawing of the eCos framebuffer contents to the host-side X
+display. It will also install a Tcl script and some support files.
+<application>framebuf</application> is an X11 application so can only
+be built on Linux systems with the appropriate X11 development package
+or packages.
+    </para>
+    <para>
+There are two main ways of building the host-side software. It is
+possible to build both the generic host-side software and all
+package-specific host-side software, including the framebuffer
+support, in a single build tree. This involves using the
+<command>configure</command> script at the toplevel of the eCos
+repository. For more information on this, see the
+<filename>README.host</filename> file at the top of the repository.
+Note that if you have an existing build tree which does not include
+the synthetic target framebuffer support then it will be necessary to
+rerun the toplevel configure script: the search for appropriate
+packages happens at configure time.
+    </para>
+    <para>
+The alternative is to build just the host-side for this package.
+This requires a separate build directory, building directly in the
+source tree is disallowed. The <command>configure</command> options
+are much the same as for a build from the toplevel, and the
+<filename>README.host</filename> file can be consulted for more
+details. It is essential that the framebuffer support be configured with
+the same <option>--prefix</option> option as other eCos host-side
+software, especially the I/O auxiliary provided by the architectural
+synthetic target HAL package, otherwise the I/O auxiliary will be
+unable to locate the framebuffer support.
+    </para>
+  </refsect1>
+  
+  <refsect1 id="devs-framebuf-synth-config"><title>Configuration</title>
+    <para>
+The package is loaded automatically when creating a configuration for
+the synthetic target. However it is inactive unless the generic
+framebuffer support <varname>CYGPKG_IO_FRAMEBUF</varname> is also
+added to the configuration, for example by <computeroutput>ecosconfig
+add framebuf</computeroutput>.
+    </para>
+    <para>
+By default the package enables a single framebuffer device
+<varname>fb0</varname> with a corresponding
+<structname>cyg_fb</structname> data structure
+<varname>cyg_synth_fb0</varname>. The default settings for this device
+are 320 by 240 pixels, a depth of 8 bits per pixel, a paletted
+display, no viewport support, and no page flipping. All of these
+settings can be changed by configuration options inside the CDL
+component <varname>CYGPKG_DEVS_FRAMEBUF_SYNTH_FB0</varname>. The
+supported display formats are: 8 bpp paletted; 8bpp true colour 332;
+16bpp true 565; 16bpp true 555; and 32bpp 0888. This allows the
+synthetic target to match the actual display capabilities of the
+hardware that is being emulated. If the actual hardware has more than
+one framebuffer device then this can be emulated by enabling
+additional components
+<varname>CYGPKG_DEVS_FRAMEBUF_SYNTH_FB1</varname> &hellip;, and
+setting the appropriate options.
+    </para>
+  </refsect1>
+
+  <refsect1 id="devs-framebuf-synth-customization"><title>Customization</title>
+    <para>
+In addition to the target-side configurability it is possible to
+customize the host-side behaviour. For example, the default behaviour
+is for <varname>fb0</varname> to be drawn inside the I/O auxiliary's
+main window, if it is not too large. <varname>fb1</varname>,
+<varname>fb2</varname> and <varname>fb3</varname> will be drawn inside
+separate toplevel windows, as will <varname>fb0</varname> if that has
+been configured too large for embedding in the main window. This
+behaviour can be changed by providing a custom Tcl/Tk procedure that
+creates the containing frame for the framebuffer device.
+    </para>
+    <para>
+Customization involves adding a <structname>synth_device</structname>
+<varname>framebuf</varname> section to the <filename>.tdf</filename>
+target definition file, usually <filename>default.tdf</filename> or
+<filename>~/.ecos/synth/default.tdf</filename>.
+    </para>
+    <programlisting width=72>
+proc my_framebuf_create_frame { &hellip } {
+    &hellip;
+}
+
+synth_device framebuf {
+    fb2_magnification   2
+    create_frame_proc   my_framebuf_create_frame
+}
+    </programlisting>
+    <para>
+The pixel size on the host display may be rather smaller than on the
+final hardware, causing a serious mismatch between the application's
+appearance when using synthetic target emulation and when using real
+hardware. To reduce this problem the host-side can magnify the
+target-side framebuffer devices. In the example above each target-side
+pixel in device <varname>fb2</varname> will be drawn using 2*2 pixels
+on the host side. Valid magnifications are 1, 2, 3 and 4. With a
+magnification of 4 an eCos framebuffer device of 320*240 pixels will
+be drawn in an X window of 1280*960 pixels.
+    </para>
+    <para>
+The <parameter>create_frame_proc</parameter> entry can be used to
+specify a custom Tcl/Tk procedure that will create the containing Tk
+frames for the host-side displays. This procedure can be written for a
+specific configuration, but it is supplied with all the parameters
+associated with the framebuffer device so can be more generic. An
+example is supplied in the package's <filename
+class="directory">misc</filename> subdirectory:
+    </para>
+    <orderedlist>
+      <listitem><para>
+Create a configuration for the synthetic target with the default
+template.
+      </para></listitem>
+      <listitem><para>
+Import the <filename>example.ecm</filename> configuration fragment
+from the <filename class="directory">misc</filename> subdirectory.
+This will add the generic framebuffer support package, enable all four
+framebuffer devices, and configure each device. Build the resulting
+configuration.
+      </para></listitem>
+      <listitem><para>
+Compile the <filename>example.c</filename> program and link it against
+the eCos configuration.
+      </para></listitem>
+      <listitem><para>
+Incorporate the <filename>example.tdf</filename> fragment into the
+appropriate target definition file, typically
+<filename>default.tdf</filename> or
+<filename>~/.ecos/synth/default.tdf</filename>.
+      </para></listitem>
+      <listitem><para>
+Run the example executable. The four framebuffer devices should get
+instantiated in a separate window in a single column.
+<varname>FB0</varname> just contains a static display.
+<varname>FB1</varname> supports two pages, one with vertical stripes
+and one with horizontal stripes, and the two pages are flipped at
+regular intervals. <varname>FB2</varname> has a static display similar
+to <varname>FB0</varname>, but is drawn in a viewport of only 160x120
+pixels. However <filename>example.tdf</filename> magnifies this by 2
+so it appears the same size as the other devices. The application
+moves the viewport around the underlying framebuffer device.
+<varname>FB3</varname> is also a static display, a simple set of
+vertical stripes. However this framebuffer is paletted and the palette
+is changed at regular intervals, causing apparent movement.
+      </para></listitem>
+    </orderedlist>
+  </refsect1>
+
+</refentry>
+</part>
\ No newline at end of file
Index: doc/synthfb.png
===================================================================
RCS file: doc/synthfb.png
diff -N doc/synthfb.png
Binary files /dev/null and synthfb.png differ
Index: host/Makefile.am
===================================================================
RCS file: host/Makefile.am
diff -N host/Makefile.am
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ host/Makefile.am	7 Oct 2008 21:00:19 -0000
@@ -0,0 +1,84 @@
+## Process this file with automake to produce Makefile.in
+## =====================================================================
+##
+##     Makefile.am
+##
+##     Build support for the host-side synthetic target support,
+##     the ethernetpackage.
+##
+## =====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+# -------------------------------------------
+# This file is part of eCos, the Embedded Configurable Operating System.
+# Copyright (C) 2008 Free Software Foundation, Inc.
+#
+# eCos is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 or (at your option) any later version.
+#
+# eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with eCos; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# As a special exception, if other files instantiate templates or use macros
+# or inline functions from this file, or you compile this file and link it
+# with other works to produce a work based on this file, this file does not
+# by itself cause the resulting work to be covered by the GNU General Public
+# License. However the source code for this file must still be made available
+# in accordance with section (3) of the GNU General Public License.
+#
+# This exception does not invalidate any other reasons why a work based on
+# this file might be covered by the GNU General Public License.
+# -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+## =====================================================================
+#######DESCRIPTIONBEGIN####
+##
+## Author(s):	bartv
+## Contact(s):	bartv
+## Date:	2005/10/28
+## Version:	0.01
+##
+######DESCRIPTIONEND####
+## =====================================================================
+
+AUTOMAKE_OPTIONS = 1.10 foreign
+
+## The synthetic target support consists of a single program framebuf,
+## a Tcl script, and some additional data files. These are
+## all installed in a single directory $(libexec)/ecos/<package>_<version>/
+## Neither the framebuf executable nor any of the scripts are directly
+## executable, instead framebuf gets fork()'d/execve()'d by the Tcl
+## script so $(libexec) is appropriate. Strictly speaking the
+## Tcl scripts and data files are architecture-independent so should
+## probably be installed in an analogous directory below $(datadir),
+## but that would add more directories for little real gain. The scripts
+## are treated as data files since they should not be executed directly,
+## i.e. they should not be installed with the execute bit set.
+
+AM_CFLAGS       = @ecos_CFLAGS@ -DECOSYNTH_VERSION=\"@VERSION@\" \
+ -DECOS_REPOSITORY=\"@ECOS_REPOSITORY@\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DPKG_DIR=\"@PACKAGE_DIR@\" \
+ -DPKG_VERSION=\"@PACKAGE_VERSION@\" \
+ -DPKG_INSTALL=\"@PACKAGE_INSTALL@\"
+AM_CXXFLAGS     = @ecos_CXXFLAGS@
+INCLUDES        = @ecos_INCLUDES@
+LIBS            = @ecos_LIBS@ @ecos_LDADD@
+
+if SUPPORTED
+framebufdir 	= $(libexecdir)/ecos/@PACKAGE_INSTALL@
+framebuf_PROGRAMS	= framebuf
+framebuf_DATA		= framebuf.tcl framebuf.tdf framebuf_icon.xbm framebuf_iconmask.xbm
+framebuf_SOURCES	= framebuf.c
+framebuf_LDADD		= -L/usr/X11R6/lib -lX11
+
+## Manual dependencies
+framebuf.$(OBJEXT)	: Makefile ../src/protocol.h
+
+endif
Index: host/acinclude.m4
===================================================================
RCS file: host/acinclude.m4
diff -N host/acinclude.m4
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ host/acinclude.m4	7 Oct 2008 21:00:19 -0000
@@ -0,0 +1,45 @@
+dnl Process this file with aclocal to get an aclocal.m4 file. Then
+dnl process that with autoconf.
+dnl ====================================================================
+dnl
+dnl     acinclude.m4
+dnl
+dnl ====================================================================
+dnl####COPYRIGHTBEGIN####
+dnl                                                                         
+dnl ----------------------------------------------------------------------------
+dnl Copyright (C) 2005 Bart Veer
+dnl
+dnl This file is part of the eCos host tools.
+dnl
+dnl This program is free software; you can redistribute it and/or modify it 
+dnl under the terms of the GNU General Public License as published by the Free 
+dnl Software Foundation; either version 2 of the License, or (at your option) 
+dnl any later version.
+dnl 
+dnl This program is distributed in the hope that it will be useful, but WITHOUT 
+dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+dnl FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+dnl more details.
+dnl 
+dnl You should have received a copy of the GNU General Public License along with
+dnl this program; if not, write to the Free Software Foundation, Inc., 
+dnl 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+dnl ----------------------------------------------------------------------------
+dnl                                                                          
+dnl####COPYRIGHTEND####
+dnl ====================================================================
+dnl#####DESCRIPTIONBEGIN####
+dnl
+dnl Author(s):	bartv
+dnl Contact(s):	bartv
+dnl Date:	2005/10/28
+dnl Version:	0.01
+dnl
+dnl####DESCRIPTIONEND####
+dnl ====================================================================
+
+dnl Access shared macros.
+dnl AM_CONDITIONAL needs to be mentioned here or else aclocal does not
+dnl incorporate the macro into aclocal.m4
+sinclude(../../../../../../acsupport/acinclude.m4)
Index: host/configure.in
===================================================================
RCS file: host/configure.in
diff -N host/configure.in
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ host/configure.in	7 Oct 2008 21:00:31 -0000
@@ -0,0 +1,91 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl ====================================================================
+dnl
+dnl     configure.in
+dnl
+dnl     configure script for eCos synthetic target framebuffer
+dnl	host-side support
+dnl
+dnl ====================================================================
+dnl####ECOSGPLCOPYRIGHTBEGIN####
+dnl -------------------------------------------
+dnl This file is part of eCos, the Embedded Configurable Operating System.
+dnl Copyright (C) 2008 Free Software Foundation, Inc.
+dnl
+dnl eCos is free software; you can redistribute it and/or modify it under
+dnl the terms of the GNU General Public License as published by the Free
+dnl Software Foundation; either version 2 or (at your option) any later version.
+dnl
+dnl eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or
+dnl FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License along
+dnl with eCos; if not, write to the Free Software Foundation, Inc.,
+dnl 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+dnl
+dnl As a special exception, if other files instantiate templates or use macros
+dnl or inline functions from this file, or you compile this file and link it
+dnl with other works to produce a work based on this file, this file does not
+dnl by itself cause the resulting work to be covered by the GNU General Public
+dnl License. However the source code for this file must still be made available
+dnl in accordance with section (3) of the GNU General Public License.
+dnl
+dnl This exception does not invalidate any other reasons why a work based on
+dnl this file might be covered by the GNU General Public License.
+dnl -------------------------------------------
+dnl####ECOSGPLCOPYRIGHTEND####
+dnl ====================================================================
+dnl#####DESCRIPTIONBEGIN####
+dnl
+dnl Author(s):	bartv
+dnl Contact(s):	bartv
+dnl Date:	2005/10/28
+dnl Version:	0.01
+dnl
+dnl####DESCRIPTIONEND####
+dnl ====================================================================
+
+
+AC_INIT(framebuf.c)
+
+dnl Pick up the support files from the top-level acsupport directory.
+AC_CONFIG_AUX_DIR(../../../../../../acsupport)
+
+dnl The current version of the synthetic target is implemented only for
+dnl x86 Linux platforms, so a test is appropriate here. However
+dnl it is not a good idea for the configure script to report an error:
+dnl that would prevent any top-level configury working for other
+dnl platforms. Instead an automake conditional is used to suppress adding
+dnl targets to the build. Unfortunately it is still necessary to
+dnl perform most of the tests or you run into problems with e.g.
+dnl automake's dependency handling.
+
+ECOS_CHECK_BUILD_ne_SRC
+AC_CANONICAL_HOST
+AM_INIT_AUTOMAKE(eCos_synthetic_target_framebuf,0.1,0)
+AM_MAINTAINER_MODE
+AC_PROG_CC
+AC_PROG_CXX
+AC_OBJEXT
+AC_EXEEXT
+ECOS_PROG_MSVC
+ECOS_PROG_STANDARD_COMPILER_FLAGS
+ECOS_PACKAGE_DIRS
+
+case "${host}" in
+    i[[34567]]86-*-linux-gnu* ) SUPPORTED="yes";;
+    * ) SUPPORTED="no"
+esac
+if test "${SUPPORTED}" = "no" ; then
+    AC_MSG_WARN([Synthetic target framebuffer support is only available on x86 Linux hosts])
+fi   
+
+AM_CONDITIONAL(SUPPORTED, test "${SUPPORTED}" = "yes")
+
+dnl There is no real need for a config.h file at this time, since the code
+dnl is specific to x86 Linux. This may change in future.
+dnl AM_CONFIG_HEADER(config.h:config.h.in)
+
+AC_OUTPUT(Makefile:Makefile.in)
Index: host/framebuf.c
===================================================================
RCS file: host/framebuf.c
diff -N host/framebuf.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ host/framebuf.c	7 Oct 2008 21:00:31 -0000
@@ -0,0 +1,1484 @@
+//============================================================================
+//
+//     framebuf.c
+//
+//     A utility program to perform low-level ethernet operations
+//
+//============================================================================
+//###ECOSGPLCOPYRIGHTBEGIN####
+//-------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//============================================================================
+//#####DESCRIPTIONBEGIN####
+//
+//  Author(s):   bartv
+//  Contact(s):  bartv
+//  Date:        2005/10/28
+//  Version:     0.01
+//  Description:
+//      Implementation of a framebuffer device. This script should only ever
+//      be run from inside the ecosynth auxiliary.
+//
+// This program is fork'ed by the framebuf.tcl script running inside
+// the synthetic target auxiliary. It is responsible for performing the
+// low-level framebuffer accesses.
+//
+//####DESCRIPTIONEND####
+//============================================================================
+
+// We want to instantiate multiple conversion routines for the different
+// graphics formats, with extensive use of macros for efficiences. Multiple
+// C #include's are used for this.
+#ifndef RENDERFN
+# include <stdio.h>
+# include <stdarg.h>
+# include <stdlib.h>
+# include <string.h>
+# include <time.h>
+# include <signal.h>
+# include <limits.h>
+# include <unistd.h>
+# include <fcntl.h>
+# include <errno.h>
+# include <sys/param.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/socket.h>
+# include <sys/ioctl.h>
+# include <sys/mman.h>
+# include <X11/Xlib.h>
+
+// The protocol between host and target is defined by a private
+// target-side header.
+# include "../src/protocol.h"
+
+// ----------------------------------------------------------------------------
+// Globals
+// First the variables needed for X operations. The window is created by
+// Tcl/Tk code and its id is supplied as an argument.
+static Display*         host_display;
+static Window           host_win    = 0;
+static GC               host_gc;
+static XImage*          host_image;
+
+// R, G & B shifts for the host-side. Used for palette conversion.
+static int              host_r_shift;
+static int              host_g_shift;
+static int              host_b_shift;
+
+// The image data. Only 32bpp is supported.
+// NOTE: this is not 64-bit clean.
+static unsigned int*    img_fb;
+
+// This is used for display depths up to and including 16bpp -
+// 256K of static data is irrelevant for a Linux host-side app.
+// 32bpp will have to be handled differently.
+static unsigned int     host_palette[65536];
+
+// The current function for rendering target-side data
+static void             (*render_fn)(int, int, int, int);
+
+// And palette init and update functions.
+static void             (*palette_init_fn)(void);
+static void             (*palette_update_fn)(void);
+
+// Positions. With target-side viewports, magnification, and the
+// possibility of windows being resized, this can
+// get very messy.
+//
+// The target-side framebuffer consists of n pages, each of
+// width*height pixels, plus possibly padding at the end of each
+// scanline.
+//
+// img_fb consists of viewport_width*viewport_height pixels.
+// At magnification 1 each pixel is a 32-bit unsigned int, but
+// at higher magnification each pixel takes up mag^2 unsigned
+// ints.
+//
+// win_width and win_height determine the current window dimensions in
+// target pixel units, i.e. ignoring magnification. x_win_width
+// and x_win_height are the same dimensions in X pixels, so
+// mag*win_width. These dimensions are provided by X configure events.
+// They may be smaller, the same size, or larger than the viewport.
+//
+// A coordinate (target_x,target_y) within the current page
+// corresponds to (target_x - viewport_x, target_y - viewport_y).
+// within host_image and within the window.
+//
+// For an X expose event we get X windows coordinates.
+
+// The actually visible window dimensions. If the Tk window gets
+// resized then only part of the image data may be visible. These
+// variables change in response to X configure events.
+static int              win_width;
+static int              win_height;
+static int              x_win_width;
+static int              x_win_height;
+
+// Target-side framebuffer.
+//
+// The synth_fb_data structure at the start of the shared memory region.
+static synth_fb_data*   shared_fb_data;
+
+// The target-side framebuffer starts at shared_fb_data->framebuf[0].
+// However that is not necessarily where the visible data starts
+// because of page flipping and viewport support. This always points
+// at the top-left corner of visible data.
+static void*            target_fb;
+
+// Parameters supplied by the target.
+static int              target_id;
+static int              target_depth;
+static int              target_le;
+static int              target_width;
+static int              target_height;
+static int              target_viewport_width;
+static int              target_viewport_height;
+static int              target_stride;
+static int              target_number_pages;
+static char*            target_format;
+
+// Parameters supplied by a host-side configuration file
+static int              config_magnification;
+
+// Communication between host and target happens partially through the
+// shared memory region and partially through a fifo, the latter
+// allowing for select(). shared_fb_data already points at the shared
+// memory region.
+static char             shm_name[L_tmpnam];
+static int              shm_created;
+static int              shm_fd;
+static char             fifo_t2h_name[L_tmpnam];
+static int              fifo_t2h_created;
+static int              fifo_t2h_fd;
+static char             fifo_h2t_name[L_tmpnam];
+static int              fifo_h2t_created;
+static int              fifo_h2t_fd;
+
+// An atexit() handler for cleaning up the fifos and shared memory.
+static void
+atexit_handler(void)
+{
+    if (shm_created) {
+        unlink(shm_name);
+    }
+    if (fifo_t2h_created) {
+        unlink(fifo_t2h_name);
+    }
+    if (fifo_h2t_created) {
+        unlink(fifo_h2t_name);
+    }
+}
+
+// ----------------------------------------------------------------------------
+// Diagnostics. Warnings and errors are sent up to the I/O auxiliary for
+// display there. Debug output goes straight to stderr
+
+// Set the DEBUG_LEVEL to 0 for no debugging, 3 for maximum debugging.
+#define DEBUG_LEVEL 0
+#define DEBUG(_level_, _str_, ...)                                  \
+    if (_level_ <= DEBUG_LEVEL) {                                   \
+        fprintf(stderr, "%d: " _str_, target_id, ## __VA_ARGS__);   \
+    }
+
+#if 0
+static void
+warn(char* fmt, ...)
+{
+    char        buf[512];
+    va_list     args;
+    va_start(args, fmt);
+
+    sprintf(buf, "Warning (fb%d) : ", target_id);
+    vsnprintf(buf + strlen(buf), 512 - strlen(buf), fmt, args);
+    buf[511] = '\0';
+
+    (void) write(1, buf, strlen(buf));
+}
+#endif
+
+static void
+error(char* fmt, ...)
+{
+    char        buf[512];
+    va_list     args;
+    va_start(args, fmt);
+
+    sprintf(buf, "Error (fb%d) : ", target_id);
+    vsnprintf(buf + strlen(buf), 512 - strlen(buf), fmt, args);
+    buf[511] = '\0';
+
+    (void) write(1, buf, strlen(buf));
+    exit(1);
+}
+
+// ----------------------------------------------------------------------------
+// Host-side.
+//
+// The main redraw routines. schedule_redraw() can get called as a result of:
+//
+// 1) an X expose event.
+// 2) a message from the Tk code affecting the on/off setting of
+//    the framebuffer.
+// 3) a message from the target-side code indicating some of the
+//    target-side data has changed, or some other event such as
+//    viewport repositioning or page flipping.
+//
+// It just maintains a bounding box. do_redraw() does the real work and
+// is called from inside the main loop.
+
+static int  redraw_pending = 0;
+static int  x_redraw_x, x_redraw_y, x_redraw_width, x_redraw_height;
+
+static void
+do_redraw(void)
+{
+    while (redraw_pending) {
+        redraw_pending = 0;
+        DEBUG(3, "do_redraw: win_x %d, win_y %d, width %d, height %d\n", x_redraw_x, x_redraw_y, x_redraw_width, x_redraw_height);
+        XPutImage(host_display, host_win, host_gc, host_image, x_redraw_x, x_redraw_y, x_redraw_x, x_redraw_y, x_redraw_width, x_redraw_height);
+        XFlush(host_display);
+    }
+}
+
+static void
+schedule_redraw(int x_new_x, int x_new_y, int x_new_width, int x_new_height)
+{
+    if (! redraw_pending) {
+        redraw_pending  = 1;
+        x_redraw_x        = x_new_x;
+        x_redraw_y        = x_new_y;
+        x_redraw_width    = x_new_width;
+        x_redraw_height   = x_new_height;
+    } else {
+        if (x_redraw_x > x_new_x) {
+            x_redraw_x = x_new_x;
+        } else {
+            x_new_width += (x_new_x - x_redraw_x);
+        }
+        if (x_redraw_y > x_new_y) {
+            x_redraw_y = x_new_y;
+        } else {
+            x_new_height += (x_new_y - x_redraw_y);
+        }
+        if (x_new_width > x_redraw_width) {
+            x_redraw_width = x_new_width;
+        }
+        if (x_new_height > x_redraw_height) {
+            x_redraw_height = x_new_height;
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+// Utility for blanking the screen
+static void
+blackout(void)
+{
+    memset(img_fb, 0, target_viewport_width * target_viewport_height * sizeof(int) * config_magnification * config_magnification);
+    if (0 != host_win) {
+        schedule_redraw(0, 0, x_win_width, x_win_height);
+    }
+}
+
+// ----------------------------------------------------------------------------
+// This function gets called when the main select() indicates the
+// X server is trying to send some data.
+static void
+handle_X_event(void)
+{
+    XEvent      event;
+
+    XNextEvent(host_display, &event);
+    switch(event.type) {
+      case Expose:
+        {
+            // In theory this code should be able to do partial redraws for every
+            // expose event, but that does not seem to work reliably. Instead do a
+            // full redraw, but only for the final event in a sequence.
+            if (0 == event.xexpose.count) {
+                DEBUG(3, "X expose event, x %d, y %d, width %d, height %d\n",
+                      event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height);
+                schedule_redraw(0, 0, x_win_width, x_win_height);
+            }
+            break;
+        }
+
+      case ConfigureNotify:
+        {
+            DEBUG(2, "X configure notify event, width %d, height %d\n", event.xconfigure.width, event.xconfigure.height);
+            x_win_width     = event.xconfigure.width;
+            x_win_height    = event.xconfigure.height;
+            win_width       = (x_win_width  + config_magnification - 1) / config_magnification;
+            win_height      = (x_win_height + config_magnification - 1) / config_magnification;
+
+            if (shared_fb_data->display_on && shared_fb_data->blank_on) {
+                (*render_fn)(0 + shared_fb_data->viewport_x, 0 + shared_fb_data->viewport_y, win_width, win_height);
+            } else {
+                blackout();
+            }
+            break;
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+// Conversion routines
+
+// This dummy function is installed to handle draw requests before the
+// window is mapped - until that time the exact render function is unknown.
+static void
+dummy_render_fn(int target_x, int target_y, int width, int height)
+{
+    DEBUG(2, "rendering: target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
+    DEBUG(2, "         : window has not been mapped on to the display yet\n");
+}
+#else  // RENDERFN
+
+// These functions get instantiated N times for the N different
+// graphics formats. We need to take the target-side region defined by
+// x/y/width/height, render it into the image data, and then redraw
+// the relevant part of the image data. There is no point rendering more
+// data than is visible.
+
+static void
+RENDERFN(1, TARGET_FORMAT)(int target_x, int target_y, int width, int height)
+{
+    int             x, y;
+    int             win_x, win_y;
+    unsigned int*   img_data;
+    unsigned int    colour;
+    TARGET_DATA;
+
+    DEBUG(2, "rendering: target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
+    if ((0 == host_win) || !shared_fb_data->display_on || !shared_fb_data->blank_on) {
+        DEBUG(2, "         : no-op, host_win %d, display_on %d, blank_on %d\n", (int)host_win, shared_fb_data->display_on, shared_fb_data->blank_on);
+        return;
+    }
+    DEBUG(2, "         : current viewport x %d, y %d\n", shared_fb_data->viewport_x, shared_fb_data->viewport_y);
+
+    win_x   = target_x - shared_fb_data->viewport_x;
+    win_y   = target_y - shared_fb_data->viewport_y;
+    if (win_x < 0) {
+        width       += win_x;
+        win_x        = 0;
+    }
+    if (win_y < 0) {
+        height      += win_y;
+        win_y        = 0;
+    }
+    if ((win_x + width) > win_width) {
+        width = win_width - win_x;
+    }
+    if ((win_y + height) > win_height) {
+        height = win_height - win_y;
+    }
+    DEBUG(2, "         : after clipping, win_x %d, win_y %d, width %d, height %d\n", win_x, win_y, width, height);
+    if ((width < 0) || (height < 0)) {
+        return;
+    }
+
+    img_data    = img_fb    + (win_y * target_viewport_width) + win_x;
+    for (y = 0; y < height; y++) {
+        for (x = 0; x < width; x++) {
+            colour  = TARGET_NEXT_COLOUR();
+            *img_data++  = colour;
+        }
+        img_data += (target_viewport_width - width);
+        TARGET_NEXT_LINE();
+    }
+    schedule_redraw(win_x, win_y, width, height);
+}
+
+static void
+RENDERFN(2, TARGET_FORMAT)(int target_x, int target_y, int width, int height)
+{
+    int             x, y;
+    int             win_x, win_y;
+    unsigned int*   img_data0;
+    unsigned int*   img_data1;
+    unsigned int    colour;
+    TARGET_DATA;
+
+    DEBUG(2, "rendering: target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
+    if ((0 == host_win) || !shared_fb_data->display_on || !shared_fb_data->blank_on) {
+        DEBUG(2, "         : no-op, host_win %d, display_on %d, blank_on %d\n", (int)host_win, shared_fb_data->display_on, shared_fb_data->blank_on);
+        return;
+    }
+    DEBUG(2, "         : current viewport x %d, y %d\n", shared_fb_data->viewport_x, shared_fb_data->viewport_y);
+    win_x   = target_x - shared_fb_data->viewport_x;
+    win_y   = target_y - shared_fb_data->viewport_y;
+    if (win_x < 0) {
+        width       += win_x;
+        win_x        = 0;
+    }
+    if (win_y < 0) {
+        height      += win_y;
+        win_y        = 0;
+    }
+    if ((win_x + width) > win_width) {
+        width = win_width - win_x;
+    }
+    if ((win_y + height) > win_height) {
+        height = win_height - win_y;
+    }
+    DEBUG(2, "         : after clipping, target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
+    if ((width < 0) || (height < 0)) {
+        return;
+    }
+    
+
+    for (y = 0; y < height; y++) {
+        img_data0       = img_fb + (2 * (win_y + y) * (2 * target_viewport_width)) + (2 * win_x);
+        img_data1       = img_data0 + (2 * target_viewport_width);
+        for (x = 0; x < width; x++) {
+            colour  = TARGET_NEXT_COLOUR();
+            *img_data0++  = colour;
+            *img_data0++  = colour;
+            *img_data1++  = colour;
+            *img_data1++  = colour;
+        }
+        TARGET_NEXT_LINE();
+    }
+    schedule_redraw(2 * win_x, 2 * win_y, 2 * width, 2 * height);
+}
+
+static void
+RENDERFN(3, TARGET_FORMAT)(int target_x, int target_y, int width, int height)
+{
+    int             x, y;
+    int             win_x, win_y;
+    unsigned int*   img_data0;
+    unsigned int*   img_data1;
+    unsigned int*   img_data2;
+    unsigned int    colour;
+    TARGET_DATA;
+
+    DEBUG(2, "rendering: target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
+    if ((0 == host_win) || !shared_fb_data->display_on || !shared_fb_data->blank_on) {
+        DEBUG(2, "         : no-op, host_win %d, display_on %d, blank_on %d\n", (int)host_win, shared_fb_data->display_on, shared_fb_data->blank_on);
+        return;
+    }
+    DEBUG(2, "         : current viewport x %d, y %d\n", shared_fb_data->viewport_x, shared_fb_data->viewport_y);
+    win_x   = target_x - shared_fb_data->viewport_x;
+    win_y   = target_y - shared_fb_data->viewport_y;
+    if (win_x < 0) {
+        width       += win_x;
+        win_x        = 0;
+    }
+    if (win_y < 0) {
+        height      += win_y;
+        win_y        = 0;
+    }
+    if ((win_x + width) > win_width) {
+        width = win_width - win_x;
+    }
+    if ((win_y + height) > win_height) {
+        height = win_height - win_y;
+    }
+    DEBUG(2, "         : after clipping, target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
+    if ((width < 0) || (height < 0)) {
+        return;
+    }
+
+    for (y = 0; y < height; y++) {
+        img_data0       = img_fb + (3 * (win_y + y) * (3 * target_viewport_width)) + (3 * win_x);
+        img_data1       = img_data0 + (3 * target_viewport_width);
+        img_data2       = img_data1 + (3 * target_viewport_width);
+
+        for (x = 0; x < width; x++) {
+            colour  = TARGET_NEXT_COLOUR();
+            *img_data0++  = colour;
+            *img_data0++  = colour;
+            *img_data0++  = colour;
+            *img_data1++  = colour;
+            *img_data1++  = colour;
+            *img_data1++  = colour;
+            *img_data2++  = colour;
+            *img_data2++  = colour;
+            *img_data2++  = colour;
+        }
+        TARGET_NEXT_LINE();
+    }
+    schedule_redraw(3 * win_x, 3 * win_y, 3 * width, 3 * height);
+}
+
+static void
+RENDERFN(4, TARGET_FORMAT)(int target_x, int target_y, int width, int height)
+{
+    int             x, y;
+    int             win_x, win_y;
+    unsigned int*   img_data0;
+    unsigned int*   img_data1;
+    unsigned int*   img_data2;
+    unsigned int*   img_data3;
+    unsigned int    colour;
+    TARGET_DATA;
+
+    DEBUG(2, "rendering: target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
+    if ((0 == host_win) || !shared_fb_data->display_on || !shared_fb_data->blank_on) {
+        DEBUG(2, "         : no-op, host_win %d, display_on %d, blank_on %d\n", (int)host_win, shared_fb_data->display_on, shared_fb_data->blank_on);
+        return;
+    }
+    DEBUG(2, "         : current viewport x %d, y %d\n", shared_fb_data->viewport_x, shared_fb_data->viewport_y);
+    win_x   = target_x - shared_fb_data->viewport_x;
+    win_y   = target_y - shared_fb_data->viewport_y;
+    if (win_x < 0) {
+        width       += win_x;
+        win_x        = 0;
+    }
+    if (win_y < 0) {
+        height      += win_y;
+        win_y        = 0;
+    }
+    if ((win_x + width) > win_width) {
+        width = win_width - win_x;
+    }
+    if ((win_y + height) > win_height) {
+        height = win_height - win_y;
+    }
+    DEBUG(2, "         : after clipping, target_x %d, target_y %d, width %d, height %d\n", target_x, target_y, width, height);
+    if ((width < 0) || (height < 0)) {
+        return;
+    }
+
+    for (y = 0; y < height; y++) {
+        img_data0       = img_fb + (4 * (win_y + y) * (4 * target_viewport_width)) + (4 * win_x);
+        img_data1       = img_data0 + (4 * target_viewport_width);
+        img_data2       = img_data1 + (4 * target_viewport_width);
+        img_data3       = img_data2 + (4 * target_viewport_width);
+
+        for (x = 0; x < width; x++) {
+            colour  = TARGET_NEXT_COLOUR();
+            *img_data0++  = colour;
+            *img_data0++  = colour;
+            *img_data0++  = colour;
+            *img_data0++  = colour;
+            *img_data1++  = colour;
+            *img_data1++  = colour;
+            *img_data1++  = colour;
+            *img_data1++  = colour;
+            *img_data2++  = colour;
+            *img_data2++  = colour;
+            *img_data2++  = colour;
+            *img_data2++  = colour;
+            *img_data3++  = colour;
+            *img_data3++  = colour;
+            *img_data3++  = colour;
+            *img_data3++  = colour;
+        }
+        TARGET_NEXT_LINE();
+    }
+    schedule_redraw(4 * win_x, 4 * win_y, 4 * width, 4 * height);
+}
+
+#endif
+#ifndef RENDERFN
+
+# define RENDERFN_AUX(_magnification_, _format_) render_ ## _magnification_ ## _ ## _format_
+# define RENDERFN(_magnification_, _format_)     RENDERFN_AUX(_magnification_, _format_)
+
+// ----------------------------------------------------------------------------
+// 1bpp, BE. It is convenient to always render in byte-multiples
+# define TARGET_FORMAT   1BPP_BE
+
+# define TARGET_DATA                                                \
+    unsigned char*  target_fb_current;                              \
+    unsigned int    mask;                                           \
+    width       += target_x & 0x07;                                 \
+    target_x    &= ~0x07;                                           \
+    width        = (width + 7) & ~0x07;                             \
+    target_fb_current   = ((unsigned char*)target_fb) +             \
+        (target_y * target_stride) + (target_x >> 3);               \
+    mask         = 0x0080
+
+# define TARGET_NEXT_COLOUR()                                       \
+    ({                                                              \
+        unsigned int next_colour;                                   \
+        next_colour = host_palette[*target_fb_current & mask];      \
+        mask >>= 1;                                                 \
+        if (0 == mask) {                                            \
+            target_fb_current += 1;                                 \
+            mask               = 0x0080;                            \
+        }                                                           \
+        next_colour;                                                \
+    })
+
+# define TARGET_NEXT_LINE()                                         \
+    target_fb_current += target_stride - (width >> 3)
+
+# include "framebuf.c"
+# undef TARGET_FORMAT
+# undef TARGET_DATA
+# undef TARGET_NEXT_COLOUR
+# undef TARGET_NEXT_LINE
+
+// ----------------------------------------------------------------------------
+// 1bpp, LE
+# define TARGET_FORMAT   1BPP_LE
+
+# define TARGET_DATA                                                \
+    unsigned char*  target_fb_current;                              \
+    unsigned int    mask;                                           \
+    width       += target_x & 0x07;                                 \
+    target_x    &= ~0x07;                                           \
+    width        = (width + 7) & ~0x07;                             \
+    target_fb_current   = ((unsigned char*)target_fb) +             \
+        (target_y * target_stride) + (target_x >> 3);               \
+    mask         = 0x0001
+
+# define TARGET_NEXT_COLOUR()                                       \
+    ({                                                              \
+        unsigned int next_colour;                                   \
+        next_colour = host_palette[*target_fb_current & mask];      \
+        mask <<= 1;                                                 \
+        if (0x0100 == mask) {                                       \
+            target_fb_current += 1;                                 \
+            mask               = 0x0001;                            \
+        }                                                           \
+        next_colour;                                                \
+    })
+
+# define TARGET_NEXT_LINE()                                         \
+    target_fb_current += target_stride - (width >> 3)
+
+# include "framebuf.c"
+# undef TARGET_FORMAT
+# undef TARGET_DATA
+# undef TARGET_NEXT_COLOUR
+# undef TARGET_NEXT_LINE
+
+// ----------------------------------------------------------------------------
+// 2bpp, BE
+# define TARGET_FORMAT   2BPP_BE
+
+# define TARGET_DATA                                                \
+    unsigned char*  target_fb_current;                              \
+    unsigned int    mask;                                           \
+    width       += target_x & 0x03;                                 \
+    target_x    &= ~0x03;                                           \
+    width        = (width + 3) & ~0x03;                             \
+    target_fb_current   = ((unsigned char*)target_fb) +             \
+        (target_y * target_stride) + (target_x >> 2);               \
+    mask         = 0x00C0
+
+# define TARGET_NEXT_COLOUR()                                       \
+    ({                                                              \
+        unsigned int next_colour;                                   \
+        next_colour = host_palette[*target_fb_current & mask];      \
+        mask >>= 2;                                                 \
+        if (0x00 == mask) {                                         \
+            target_fb_current += 1;                                 \
+            mask               = 0x00C0;                            \
+        }                                                           \
+        next_colour;                                                \
+    })
+
+# define TARGET_NEXT_LINE()                                         \
+    target_fb_current += target_stride - (width >> 2)
+
+# include "framebuf.c"
+# undef TARGET_FORMAT
+# undef TARGET_DATA
+# undef TARGET_NEXT_COLOUR
+# undef TARGET_NEXT_LINE
+
+// ----------------------------------------------------------------------------
+// 2bpp, LE
+# define TARGET_FORMAT   2BPP_LE
+
+# define TARGET_DATA                                                \
+    unsigned char*  target_fb_current;                              \
+    unsigned int    mask;                                           \
+    width       += target_x & 0x03;                                 \
+    target_x    &= ~0x03;                                           \
+    width        = (width + 3) & ~0x03;                             \
+    target_fb_current   = ((unsigned char*)target_fb) +             \
+        (target_y * target_stride) + (target_x >> 2);               \
+    mask         = 0x0003
+
+# define TARGET_NEXT_COLOUR()                                       \
+    ({                                                              \
+        unsigned int next_colour;                                   \
+        next_colour = host_palette[*target_fb_current & mask];      \
+        mask <<= 2;                                                 \
+        if (0x0300 == mask) {                                       \
+            target_fb_current += 1;                                 \
+            mask               = 0x0003;                            \
+        }                                                           \
+        next_colour;                                                \
+    })
+
+# define TARGET_NEXT_LINE()                                         \
+    target_fb_current += target_stride - (width >> 2)
+
+# include "framebuf.c"
+# undef TARGET_FORMAT
+# undef TARGET_DATA
+# undef TARGET_NEXT_COLOUR
+# undef TARGET_NEXT_LINE
+
+// ----------------------------------------------------------------------------
+// 4bpp, BE
+# define TARGET_FORMAT   4BPP_BE
+
+# define TARGET_DATA                                                \
+    unsigned char*  target_fb_current;                              \
+    unsigned int    mask;                                           \
+    width       += target_x & 0x01;                                 \
+    target_x    &= ~0x01;                                           \
+    width        = (width + 1) & ~0x01;                             \
+    target_fb_current   = ((unsigned char*)target_fb) +             \
+        (target_y * target_stride) + (target_x >> 1);               \
+    mask         = 0x00F0
+
+# define TARGET_NEXT_COLOUR()                                       \
+    ({                                                              \
+        unsigned int next_colour;                                   \
+        next_colour = host_palette[*target_fb_current & mask];      \
+        mask >>= 4;                                                 \
+        if (0 == mask) {                                            \
+            target_fb_current += 1;                                 \
+            mask               = 0x00F0;                            \
+        }                                                           \
+        next_colour;                                                \
+    })
+
+# define TARGET_NEXT_LINE()                                         \
+    target_fb_current += target_stride - (width >> 1)
+
+# include "framebuf.c"
+# undef TARGET_FORMAT
+# undef TARGET_DATA
+# undef TARGET_NEXT_COLOUR
+# undef TARGET_NEXT_LINE
+
+// ----------------------------------------------------------------------------
+// 4bpp, LE
+# define TARGET_FORMAT   4BPP_LE
+
+# define TARGET_DATA                                                \
+    unsigned char*  target_fb_current;                              \
+    unsigned int    mask;                                           \
+    width       += target_x & 0x01;                                 \
+    target_x    &= ~0x01;                                           \
+    width        = (width + 1) & ~0x01;                             \
+    target_fb_current   = ((unsigned char*)target_fb) +             \
+        (target_y * target_stride) + (target_x >> 1);               \
+    mask         = 0x000F
+
+# define TARGET_NEXT_COLOUR()                                       \
+    ({                                                              \
+        unsigned int next_colour;                                   \
+        next_colour = host_palette[*target_fb_current & mask];      \
+        mask <<= 4;                                                 \
+        if (0x0F00 == mask) {                                       \
+            target_fb_current += 1;                                 \
+            mask               = 0x000F;                            \
+        }                                                           \
+        next_colour;                                                \
+    })
+
+# define TARGET_NEXT_LINE()                                         \
+    target_fb_current += target_stride - (width >> 2)
+
+# include "framebuf.c"
+# undef TARGET_FORMAT
+# undef TARGET_DATA
+# undef TARGET_NEXT_COLOUR
+# undef TARGET_NEXT_LINE
+
+// ----------------------------------------------------------------------------
+// 8bpp, paletted or true colour. In the case of a true colour display the
+// host_palette array will have been filled in appropriately for 332 so
+// conversion to 32-bit true colour again just involves indirecting through
+// the palette, rather than the more expensive bit masking and shifting.
+# define TARGET_FORMAT   8BPP
+
+# define TARGET_DATA                                                \
+    unsigned char*  target_fb_current;                              \
+    target_fb_current   = ((unsigned char*)target_fb) +             \
+        (target_y * target_stride) + target_x
+
+# define TARGET_NEXT_COLOUR() host_palette[*target_fb_current++]
+
+# define TARGET_NEXT_LINE()                                         \
+    target_fb_current += (target_stride - width)
+
+# include "framebuf.c"
+# undef TARGET_FORMAT
+# undef TARGET_DATA
+# undef TARGET_NEXT_COLOUR
+# undef TARGET_NEXT_LINE
+
+// ----------------------------------------------------------------------------
+// 16bpp. Again this is handled via the host_palette array, suitably
+// initialized for either 555 or 565
+# define TARGET_FORMAT   16BPP
+
+# define TARGET_DATA                                                \
+    unsigned short*  target_fb_current;                             \
+    target_fb_current   = ((unsigned short*)target_fb) +            \
+        (target_y * (target_stride >> 1)) + target_x
+
+# define TARGET_NEXT_COLOUR()   host_palette[*target_fb_current++]
+
+# define TARGET_NEXT_LINE()                                         \
+    target_fb_current += ((target_stride >> 1) - width)
+
+# include "framebuf.c"
+# undef TARGET_FORMAT
+# undef TARGET_DATA
+# undef TARGET_NEXT_COLOUR
+# undef TARGET_NEXT_LINE
+
+// ----------------------------------------------------------------------------
+// 32bpp, 0888, no swapping
+
+# define TARGET_FORMAT   32BPP
+
+# define TARGET_DATA                                                \
+    unsigned int*  target_fb_current;                               \
+    target_fb_current   = ((unsigned int*)target_fb) +              \
+        (target_y * (target_stride >> 2)) + target_x
+
+# define TARGET_NEXT_COLOUR() *target_fb_current++ & 0x00FFFFFF
+
+# define TARGET_NEXT_LINE()                                         \
+    target_fb_current += ((target_stride >> 2) - width)
+
+# include "framebuf.c"
+# undef TARGET_FORMAT
+# undef TARGET_DATA
+# undef TARGET_NEXT_COLOUR
+# undef TARGET_NEXT_LINE
+
+// ----------------------------------------------------------------------------
+// 32bpp, 0888, but the host uses 8880.
+# define TARGET_FORMAT   32BPP_SWAPPED
+
+# define TARGET_DATA                                                \
+    unsigned int*  target_fb_current;                               \
+    target_fb_current   = ((unsigned int*)target_fb) +              \
+        (target_y * (target_stride >> 2)) + target_x
+
+# define TARGET_NEXT_COLOUR()                                       \
+    ({                                                              \
+        unsigned int _colour_ = *target_fb_current++;               \
+        _colour_ =                                                  \
+            ((_colour_ & 0x000000FF) << 24) |                       \
+            ((_colour_ & 0x0000FF00) << 16) |                       \
+            ((_colour_ & 0x00FF0000) <<  8);                        \
+        _colour_;                                                   \
+    })
+        
+# define TARGET_NEXT_LINE()                                         \
+    target_fb_current += ((target_stride >> 2) - width)
+
+# include "framebuf.c"
+# undef TARGET_FORMAT
+# undef TARGET_DATA
+# undef TARGET_NEXT_COLOUR
+# undef TARGET_NEXT_LINE
+
+// ----------------------------------------------------------------------------
+// Palette management. 8bpp and 16bpp true colour can be initialized
+// statically. 32bpp does not involve the host_palette array at all.
+// Other formats involve dynamic palette updating.
+
+static void
+palette_initialize_8bpp_332(void)
+{
+    static const unsigned char expand2[4]  = { 0x00, 0x55, 0xAA, 0xFF };
+    static const unsigned char expand3[8]  = { 0x00, 0x20 + 4, 0x40 + 9, 0x60 + 13, 0x80 + 18, 0xA0 + 22, 0xC0 + 27, 0xE0 + 31 };
+    int i;
+    for (i = 0; i < 256; i++) {
+        int r   = (i & 0x00E0) >> 5;
+        int g   = (i & 0x001C) >> 2;
+        int b   = (i & 0x0003) >> 0;
+        host_palette[i] = (expand3[r] << host_r_shift) | (expand3[g] << host_g_shift) | (expand2[b] << host_b_shift);
+    }
+}
+
+static void
+palette_initialize_16bpp_555(void)
+{
+    static const unsigned char expand5[32] = {
+        0x00 + 0, 0x08 + 0, 0x10 + 0, 0x18 + 0, 0x20 + 1, 0x28 + 1, 0x30 + 1, 0x38 + 1,
+        0x40 + 2, 0x48 + 2, 0x50 + 2, 0x58 + 2, 0x60 + 3, 0x68 + 3, 0x70 + 3, 0x78 + 3,
+        0x80 + 4, 0x88 + 4, 0x90 + 4, 0x98 + 4, 0xA0 + 5, 0xA8 + 5, 0xB0 + 5, 0xB8 + 5,
+        0xC0 + 6, 0xC8 + 6, 0xD0 + 6, 0xD8 + 6, 0xE0 + 7, 0xE8 + 7, 0xF0 + 7, 0xF8 + 7,
+    };
+    int i;
+    for (i = 0; i < 65536; i++) {
+        int r = (i & 0x00007C00) >> 10;
+        int g = (i & 0x000003E0) >> 5;
+        int b = (i & 0x0000001F) >> 0;
+        host_palette[i] = (expand5[r] << host_r_shift) | (expand5[g] << host_g_shift) | (expand5[b] << host_b_shift);
+    }
+}
+
+static void
+palette_initialize_16bpp_565(void)
+{
+    static const unsigned char expand5[32] = {
+        0x00 + 0, 0x08 + 0, 0x10 + 0, 0x18 + 0, 0x20 + 1, 0x28 + 1, 0x30 + 1, 0x38 + 1,
+        0x40 + 2, 0x48 + 2, 0x50 + 2, 0x58 + 2, 0x60 + 3, 0x68 + 3, 0x70 + 3, 0x78 + 3,
+        0x80 + 4, 0x88 + 4, 0x90 + 4, 0x98 + 4, 0xA0 + 5, 0xA8 + 5, 0xB0 + 5, 0xB8 + 5,
+        0xC0 + 6, 0xC8 + 6, 0xD0 + 6, 0xD8 + 6, 0xE0 + 7, 0xE8 + 7, 0xF0 + 7, 0xF8 + 7,
+    };
+    static const unsigned char expand6[64] = {
+        0x00 + 0, 0x04 + 0, 0x08 + 0, 0x0C + 0, 0x10 + 0, 0x14 + 0, 0x18 + 0, 0x1C + 0,
+        0x20 + 0, 0x24 + 0, 0x28 + 0, 0x2C + 0, 0x30 + 0, 0x34 + 0, 0x38 + 0, 0x3C + 0,
+        0x40 + 1, 0x44 + 1, 0x48 + 1, 0x4C + 1, 0x50 + 1, 0x54 + 1, 0x58 + 1, 0x5C + 1,
+        0x60 + 1, 0x64 + 1, 0x68 + 1, 0x6C + 1, 0x70 + 1, 0x74 + 1, 0x78 + 1, 0x7C + 1,
+        0x80 + 2, 0x84 + 2, 0x88 + 2, 0x8C + 2, 0x90 + 2, 0x94 + 2, 0x98 + 2, 0x9C + 2,
+        0xA0 + 2, 0xA4 + 2, 0xA8 + 2, 0xAC + 2, 0xB0 + 2, 0xB4 + 2, 0xB8 + 2, 0xBC + 2,
+        0xC0 + 3, 0xC4 + 3, 0xC8 + 3, 0xCC + 3, 0xD0 + 3, 0xD4 + 3, 0xD8 + 3, 0xDC + 3,
+        0xE0 + 3, 0xE4 + 3, 0xE8 + 3, 0xEC + 3, 0xF0 + 3, 0xF4 + 3, 0xF8 + 3, 0xFC + 3,
+    };
+    int i;
+    for (i = 0; i < 65536; i++) {
+        int r = (i & 0x0000F800) >> 11;
+        int g = (i & 0x000007E0) >> 5;
+        int b = (i & 0x0000001F) >> 0;
+        host_palette[i] = (expand5[r] << host_r_shift) | (expand6[g] << host_g_shift) | (expand5[b] << host_b_shift);
+    }
+}
+
+static void
+palette_update(void)
+{
+    int             i, j;
+    unsigned char*  target_palette;
+    int             r, g, b;
+
+    target_palette  = shared_fb_data->palette;
+    for (i = 0; i < (0x01 << target_depth); i++) {
+        r = *target_palette++;
+        g = *target_palette++;
+        b = *target_palette++;
+        host_palette[i] = (r << host_r_shift) | (g << host_g_shift) | (b << host_b_shift);
+    }
+
+    // Make sure the palette is replicated throughout the first 256
+    // entries. That way when rendering <8bpp data we can just mask
+    // the target-side bytes without having to shift.
+    for (j = 0; i < 256; i++, j++) {
+        host_palette[i] = host_palette[j];
+    }
+}
+
+// ----------------------------------------------------------------------------
+// This array is used to map the various display formats etc. on to
+// render functions.
+static struct _render_details {
+    char*           rd_format;
+    unsigned int    rd_endianness_matters;
+    unsigned int    rd_le;
+    void            (*rd_palette_init)(void);
+    void            (*rd_palette_update)(void);
+    void            (*rd_render_fns[4])(int, int, int, int);
+} render_array[] = {
+    // 32BPP must come first
+    { "32BPP_TRUE_0888", 0, 0, NULL, NULL,
+      { &render_1_32BPP, &render_2_32BPP, &render_3_32BPP, &render_4_32BPP }
+    },
+    { "16BPP_TRUE_555",  0, 0, &palette_initialize_16bpp_555, NULL,
+      { &render_1_16BPP, &render_2_16BPP, &render_3_16BPP, &render_4_16BPP }
+    },
+    { "16BPP_TRUE_565",  0, 0, &palette_initialize_16bpp_565, NULL,
+      { &render_1_16BPP, &render_2_16BPP, &render_3_16BPP, &render_4_16BPP }
+    },
+    { "8BPP_TRUE_332",   0, 0, &palette_initialize_8bpp_332, NULL,
+      { &render_1_8BPP, &render_2_8BPP, &render_3_8BPP, &render_4_8BPP }
+    },
+    { "8BPP_PAL888",     0, 0, NULL, &palette_update,
+      { &render_1_8BPP, &render_2_8BPP, &render_3_8BPP, &render_4_8BPP }
+    },
+    { "4BPP_PAL888",     1, 1, NULL, &palette_update,
+      { &render_1_4BPP_LE, &render_2_4BPP_LE, &render_3_4BPP_LE, &render_4_4BPP_LE }
+    },
+    { "4BPP_PAL888",     1, 0, NULL, &palette_update,
+      { &render_1_4BPP_BE, &render_2_4BPP_BE, &render_3_4BPP_BE, &render_4_4BPP_BE }
+    },
+    { "2BPP_PAL888",     1, 1, NULL, &palette_update,
+      { &render_1_2BPP_LE, &render_2_2BPP_LE, &render_3_2BPP_LE, &render_4_2BPP_LE }
+    },
+    { "2BPP_PAL888",     1, 0, NULL, &palette_update,
+      { &render_1_2BPP_BE, &render_2_2BPP_BE, &render_3_2BPP_BE, &render_4_2BPP_BE }
+    },
+    { "1BPP_PAL888",     1, 1, NULL, &palette_update,
+      { &render_1_1BPP_LE, &render_2_1BPP_LE, &render_3_1BPP_LE, &render_4_1BPP_LE }
+    },
+    { "1BPP_PAL888",     1, 0, NULL, &palette_update,
+      { &render_1_1BPP_BE, &render_2_1BPP_BE, &render_3_1BPP_BE, &render_4_1BPP_BE }
+    },
+    { NULL }
+};
+
+
+// ----------------------------------------------------------------------------
+// Communication between host and target
+//
+// When the target wants to wake up the host it sends a single byte down
+// a fifo, typically after having filled in appropriate fields in the
+// shared memory region.
+static void
+handle_target_request(void)
+{
+    unsigned char   buf[1];
+    int             result;
+
+    result  = read(fifo_t2h_fd, buf, 1);
+    if (-1 == result) {
+        if (EINTR == errno) {
+            return;
+        }
+        error("unexpected error %d (%s) reading fifo command from target-side code", errno, strerror(errno));
+    }
+    if (0 == result) {
+        // The target-side must have exited. Do not follow suit yet. Instead
+        // exit only when the I/O auxiliary exits.
+        DEBUG(1, "eCos application has exited\n");
+        close(fifo_t2h_fd);
+        fifo_t2h_fd = -1;
+        return;
+    }
+
+    switch(buf[0]) {
+      case SYNTH_FB_OK:
+        {
+            // The target has finished initializing. This may have
+            // involved filling in the palette
+            DEBUG(1, "target request SYNTH_FB_OK, eCos application has connected.\n");
+            if (palette_update_fn) {
+                (*palette_update_fn)();
+            }
+            break;
+        }
+        
+      case SYNTH_FB_SYNC:
+        {
+            // The target has updated part of the display.
+            DEBUG(2, "target request SYNC, x0 %d, y0 %d, x1 %d, y1 %d\n",
+                  shared_fb_data->sync_x0, shared_fb_data->sync_y0, shared_fb_data->sync_x1, shared_fb_data->sync_y1);
+            (*render_fn)(shared_fb_data->sync_x0, shared_fb_data->sync_y0,
+                         (shared_fb_data->sync_x1 - shared_fb_data->sync_x0),
+                         (shared_fb_data->sync_y1 - shared_fb_data->sync_y0));
+            break;
+        }
+        
+      case SYNTH_FB_WRITE_PALETTE:
+        {
+            // The target-side palette has been updated. Adjust the
+            // host-side palette and then render the whole window with
+            // the curent colours (unless blanked).
+            DEBUG(1, "target request WRITE_PALETTE\n");
+            if (palette_update_fn) {
+                (*palette_update_fn)();
+            }
+            (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
+        }
+
+      case SYNTH_FB_BLANK:
+        {
+            DEBUG(1, "target request blank, display should be %s\n", shared_fb_data->blank_on ? "on" : "off");
+            if (shared_fb_data->blank_on) {
+                (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
+            } else {
+                blackout();
+            }
+            break;
+        }
+        
+      case SYNTH_FB_VIEWPORT:
+        {
+            // Just rerender the whole display as per the new viewport position.
+            DEBUG(1, "target request move viewport to x %d, y %d\n", shared_fb_data->viewport_x, shared_fb_data->viewport_y);
+            (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
+            break;
+        }
+
+      case SYNTH_FB_PAGE_FLIP:
+        {
+            int page_size   = target_height * target_stride;
+            DEBUG(1, "target request page flip to page %d\n", shared_fb_data->page_visible);
+            target_fb       = (void*)(((char*)&(shared_fb_data->framebuf[0])) + (page_size * shared_fb_data->page_visible));
+            (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
+            break;
+        }
+    }
+
+    // Send a single-byte response back to the target
+    DEBUG(2, "target request handled\n");
+    buf[0] = SYNTH_FB_OK;
+    do {
+        result = write(fifo_h2t_fd, buf, 1);
+    } while ((result < 0) && (errno == EINTR));
+    if (result < 0) {
+        error("unexpected error %d (%s) writing fifo status to target-side code", errno, strerror(errno));
+    }
+}
+
+// ----------------------------------------------------------------------------
+// Communication from the Tcl/Tk script
+static void
+handle_mapped(int winid)
+{
+    Status              result;
+    XWindowAttributes   attr;
+    XGCValues           gc_values;
+    Visual*             visual;
+    int                 i;
+
+    DEBUG(1, "X window %d has been mapped\n", winid);
+    if (0 != (int)host_win) {
+        error("  window has already been mapped.\n");
+    }
+    
+    host_win    = (Window)winid;
+    result      = XGetWindowAttributes(host_display, host_win, &attr);
+    if (0 == result) {
+        error("failed to get window attributes.");
+    }
+    gc_values.graphics_exposures    = False;
+    host_gc = XCreateGC(host_display, host_win, GCGraphicsExposures, &gc_values);
+    result = XSelectInput(host_display, host_win, ExposureMask | StructureNotifyMask);
+
+    // The Tcl script has already checked that we are on a 24/32 bit display.
+    // We need to know the colour shifts and possibly adjust the render array.
+    visual  = attr.visual;
+    DEBUG(1, "  red_mask 0x%08lx, green_mask 0x%08lx, blue_mask 0x%08lx\n", visual->red_mask, visual->green_mask, visual->blue_mask);
+    if ((0x00FF0000 == visual->red_mask) && (0x0000FF00 == visual->green_mask) && (0x000000FF == visual->blue_mask)) {
+        // 0888, nothing special needed
+        host_r_shift    = 16;
+        host_g_shift    =  8;
+        host_b_shift    =  0;
+    } else if ((0x0000FF00 == visual->red_mask) && (0x00FF0000 == visual->green_mask) && (0xFF000000 == visual->blue_mask)) {
+        // 8880
+        host_r_shift    =  8;
+        host_g_shift    = 16;
+        host_b_shift    = 24;
+        render_array[0].rd_render_fns[0]    = &render_1_32BPP_SWAPPED;
+        render_array[0].rd_render_fns[1]    = &render_2_32BPP_SWAPPED;
+        render_array[0].rd_render_fns[2]    = &render_3_32BPP_SWAPPED;
+        render_array[0].rd_render_fns[3]    = &render_4_32BPP_SWAPPED;
+    }
+    
+    // Time to figure out which render function etc. to use.
+    render_fn = (void (*)(int, int, int, int)) NULL;
+    for (i = 0; render_array[i].rd_format; i++) {
+        if ((0 == strcmp(render_array[i].rd_format, target_format)) &&
+            (!render_array[i].rd_endianness_matters || (render_array[i].rd_le == target_le))) {
+
+            render_fn           = render_array[i].rd_render_fns[config_magnification - 1];
+            palette_init_fn     = render_array[i].rd_palette_init;
+            palette_update_fn   = render_array[i].rd_palette_update;
+            break;
+        }
+    }
+    if (NULL == render_fn) {
+        error("Target format not supported.");
+    }
+
+    // Now it is possible to create the XImage structure, the fifos,
+    // and the shared memory region for interaction with the target.
+    // The XImage needs to be large enough for the viewport. That may
+    // be larger than the actually visible window, but the window may
+    // get resized.
+    host_image  = XCreateImage(host_display, visual,
+                               24,          // image depth. 24 bits of colour info.
+                               ZPixmap,
+                               0,           // offset
+                               NULL,        // data, filled in later
+                               target_viewport_width  * config_magnification,
+                               target_viewport_height * config_magnification,
+                               32,          // bitmap_pad
+                               0            // bytes_per_line, calculated by X
+        );
+    if (NULL == host_image) {
+        error("Failed to allocate XImage structure.");
+    }
+    host_image->data    = (void*)img_fb;
+
+    x_win_width     = attr.width;
+    x_win_height    = attr.height;
+    win_width       = (x_win_width  + config_magnification - 1) / config_magnification;
+    win_height      = (x_win_height + config_magnification - 1) / config_magnification;
+    DEBUG(1, "  mapped window, X width %d, X height %d, win width %d, win height %d, blank on %d, display on %d\n",
+          x_win_width, x_win_height, win_width, win_height, shared_fb_data->blank_on, shared_fb_data->display_on);
+
+    // The palette may get initialized locally or by the target, depending
+    // on the mode.
+    if (palette_init_fn) {
+        (*palette_init_fn)();
+    }
+    if (palette_update_fn) {
+        (*palette_update_fn)();
+    }
+    if (shared_fb_data->display_on && shared_fb_data->blank_on) {
+        (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
+    } else {
+        // Just draw the initial blank screen.
+        blackout();
+    }
+}
+
+static void
+handle_auxiliary_request(void)
+{
+    synth_fb_auxiliary_request  req;
+    int                         result;
+    
+    result = read(0, &req, sizeof(synth_fb_auxiliary_request));
+    if (result <= 0) {
+        // The I/O auxiliary has terminated, so assume the window has gone as well.
+        exit(0);
+    }
+    DEBUG(2, "handle_auxiliary request %d\n", req.command);
+    switch (req.command) {
+      case SYNTH_FB_AUX_MAPPED:
+        {
+            handle_mapped(req.arg1);
+            break;
+        }
+      case SYNTH_FB_AUX_ON:
+        {
+            // This is used when the target-side switches the display
+            // off and back on, rather than just blanking it. Treat it
+            // the same as blanking.
+            DEBUG(1, "Target has switched the display on\n");
+            shared_fb_data->display_on  = 1;
+            (*render_fn)(shared_fb_data->viewport_x, shared_fb_data->viewport_y, win_width, win_height);
+            break;
+        }
+      case SYNTH_FB_AUX_OFF:
+        {
+            DEBUG(1, "Target has switched the display off\n");
+            shared_fb_data->display_on  = 0;
+            blackout();
+            break;
+        }
+      case SYNTH_FB_AUX_REDRAW:
+        {
+            DEBUG(1, "Auxiliary has requested a redraw\n");
+            schedule_redraw(0, 0, x_win_width, x_win_height);
+        }
+    }
+    DEBUG(2, "handle_auxiliary request done\n");
+}
+
+// Report an error to ecosynth during initialization. This means a
+// single byte 0, followed by a string.
+static void
+report_init_error(char* msg)
+{
+    write(1, "0", 1);
+    write(1, msg, strlen(msg));
+    close(1);
+    exit(0);
+}
+
+// ----------------------------------------------------------------------------
+int
+main(int argc, char** argv)
+{
+    int                 size;
+    fd_set              read_fds;
+    int                 max_fd;
+
+    atexit(&atexit_handler);
+    signal(SIGPIPE, SIG_IGN);
+
+    if (12 != argc) {
+        report_init_error("Incorrect number of arguments.");
+    }
+    target_id               = (int) strtoul(argv[1], NULL, 0);
+    target_depth            = (int) strtoul(argv[2], NULL, 0);
+    target_le               = (int) strtoul(argv[3], NULL, 0);
+    target_width            = (int) strtoul(argv[4], NULL, 0);
+    target_height           = (int) strtoul(argv[5], NULL, 0);
+    target_viewport_width   = (int) strtoul(argv[6], NULL, 0);
+    target_viewport_height  = (int) strtoul(argv[7], NULL, 0);
+    target_stride           = (int) strtoul(argv[8], NULL, 0);
+    target_number_pages     = (int) strtoul(argv[9], NULL, 0);
+    target_format           = argv[10];
+    config_magnification    = (int) strtoul(argv[11], NULL, 0);
+
+    if ((target_depth != 1) && (target_depth != 2) && (target_depth != 4) && (target_depth != 8) && (target_depth != 16) && (target_depth != 32)) {
+        report_init_error("Invalid target depth.");
+    }
+    if ((target_width < 16) || (target_width > 4096)) {
+        report_init_error("Invalid target width.");
+    }
+    if ((target_height < 16) || (target_height > 4096)) {
+        report_init_error("Invalid target height.");
+    }
+    if ((target_viewport_width < 16) || (target_viewport_width > target_width)) {
+        report_init_error("Invalid target viewport width.");
+    }
+    if ((target_viewport_height < 16) || (target_viewport_height > target_height)) {
+        report_init_error("Invalid target viewport height.");
+    }
+    if ((target_number_pages < 1) || (target_number_pages > 4)) {
+        report_init_error("Invalid target number of pages.");
+    }
+    if ((config_magnification < 1) || (config_magnification > 4)) {
+        report_init_error("Invalid config magnification.");
+    }
+
+    host_display    = XOpenDisplay(NULL);
+    if (NULL == host_display) {
+        report_init_error("Failed to open X display.");
+    }
+    img_fb = (unsigned int*) malloc(target_viewport_width * target_viewport_height * sizeof(int) * config_magnification * config_magnification);
+    if (NULL == img_fb) {
+        report_init_error("Failed to allocate XImage data.");
+    }
+    blackout();
+
+    // Use of tmpnam() is generally discouraged and generates a linker
+    // warning, but only three temporary file names are needed and
+    // there are no root privileges involved so security is not a big
+    // issue. mkstemp() cannot easily be used with fifos.
+    if (NULL == tmpnam(fifo_t2h_name)) {
+        report_init_error("Failed to create unique file name for target->host fifo.");
+    }
+    if (0 != mkfifo(fifo_t2h_name, S_IRUSR | S_IWUSR)) {
+        report_init_error("Failed to create target->host fifo.");
+    }
+    // Opening O_RDONLY or O_WRONLY will result in blocking until the
+    // other end is open as well, which is not what is wanted here.
+    // Instead we use the Linux feature of opening with O_RDWR which
+    // gives non-blocking behaviour.
+    fifo_t2h_created    = 1;
+    fifo_t2h_fd         = open(fifo_t2h_name, O_RDWR);
+    if (-1 == fifo_t2h_fd) {
+        report_init_error("Failed to open target->host fifo.");
+    }
+    if (NULL == tmpnam(fifo_h2t_name)) {
+        report_init_error("Failed to create unique file name for host->target fifo.");
+    }
+    if (0 != mkfifo(fifo_h2t_name, S_IRUSR | S_IWUSR)) {
+        report_init_error("Failed to create host->target fifo.");
+    }
+    fifo_h2t_created    = 1;
+    fifo_h2t_fd         = open(fifo_h2t_name, O_RDWR);
+    if (-1 == fifo_h2t_fd) {
+        report_init_error("Failed to open target->host fifo.");
+    }
+
+    size    = sizeof(synth_fb_data) + (target_height * target_stride * target_number_pages);
+    if (NULL == tmpnam(shm_name)) {
+        report_init_error("Failed to create unique file name for shared memory.");
+    }
+    shm_fd  = open(shm_name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+    if (shm_fd < 0) {
+        report_init_error("Failed to open file for shared memory region.");
+    }
+    shm_created = 1;
+    if (ftruncate(shm_fd, size) < 0) {
+        report_init_error("Failed to set shared memory file size.");
+    }
+    
+    shared_fb_data = (synth_fb_data*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+    if (shared_fb_data == (synth_fb_data*)MAP_FAILED) {
+        report_init_error("Failed to mmap shared memory file.");
+    }
+    target_fb   = &(shared_fb_data->framebuf[0]);
+
+    shared_fb_data->connected           = 0;
+    shared_fb_data->fifo_to_framebuf    = -1;
+    shared_fb_data->fifo_from_framebuf  = -1;
+    shared_fb_data->devid               = target_id;
+    shared_fb_data->sync_x0             = 0;
+    shared_fb_data->sync_y0             = 0;
+    shared_fb_data->sync_x1             = target_viewport_width;
+    shared_fb_data->sync_y1             = target_viewport_height;
+    shared_fb_data->display_on          = 0;
+    shared_fb_data->blank_on            = 1;
+    shared_fb_data->viewport_x          = 0;
+    shared_fb_data->viewport_y          = 0;
+    shared_fb_data->page_visible        = 0;
+
+    render_fn   = &dummy_render_fn;
+    msync(shared_fb_data, size, MS_SYNC);
+
+    // Everything seems to be in order. Report back to the auxiliary.
+    {
+        char    buf[513];
+        if ((strlen(shm_name) + strlen(fifo_t2h_name) + strlen(fifo_h2t_name) + 3) > 512) {
+            report_init_error("Temporary path names too long.");
+        }
+        buf[0]  = '1';
+        strcpy(&(buf[1]), shm_name);
+        strcat(&(buf[1]), ";");
+        strcat(&(buf[1]), fifo_t2h_name);
+        strcat(&(buf[1]), ";");
+        strcat(&(buf[1]), fifo_h2t_name);
+        strcat(&(buf[1]), ";");
+        write(1, buf, 2 + strlen(&(buf[1])));
+    }
+    
+    // Now we just loop, processing events. We want to select on file descriptor
+    // 0 from the auxiliary, the X file descriptor, and the fifo t2h descriptor.
+    // The latter may go away. X should never go away, and if the auxiliary goes
+    // away we exit immediately.
+    max_fd  = MAX(ConnectionNumber(host_display), fifo_t2h_fd);
+    while ( 1 ) {
+        while (XPending(host_display) > 0) {
+            handle_X_event();
+        }
+        FD_ZERO(&read_fds);
+        FD_SET(0, &read_fds);
+        FD_SET(ConnectionNumber(host_display), &read_fds);
+        if (-1 != fifo_t2h_fd) {
+            FD_SET(fifo_t2h_fd, &read_fds);
+        }
+        DEBUG(3, "framebuf main loop: selecting on 0x%08x\n", *(int*)&read_fds);
+        do_redraw();
+        if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) >= 0) {
+            if (FD_ISSET(0, &read_fds)) {
+                DEBUG(2, "framebuf main loop: auxiliary request\n");
+                handle_auxiliary_request();
+            }
+            if ((-1 != fifo_t2h_fd) && FD_ISSET(fifo_t2h_fd, &read_fds)) {
+                DEBUG(2, "framebuf main loop: target request\n");
+                handle_target_request();
+            }
+            if (FD_ISSET(ConnectionNumber(host_display), &read_fds)) {
+                DEBUG(3, "framebuf main loop: X request\n");
+                (void)XEventsQueued(host_display, QueuedAfterReading);
+            }
+        }
+    }
+    
+    exit(EXIT_SUCCESS);
+}
+#endif // INSTANTIATE_CONVERTER
Index: host/framebuf.tcl
===================================================================
RCS file: host/framebuf.tcl
diff -N host/framebuf.tcl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ host/framebuf.tcl	7 Oct 2008 21:00:31 -0000
@@ -0,0 +1,373 @@
+# {{{  Banner                                                   
+
+# ============================================================================
+# 
+#      framebuf.tcl
+# 
+#      Framebuffer support for the eCos synthetic target I/O auxiliary
+# 
+# ============================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+# -------------------------------------------
+# This file is part of eCos, the Embedded Configurable Operating System.
+# Copyright (C) 2008 Free Software Foundation, Inc.
+#
+# eCos is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 or (at your option) any later version.
+#
+# eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with eCos; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# As a special exception, if other files instantiate templates or use macros
+# or inline functions from this file, or you compile this file and link it
+# with other works to produce a work based on this file, this file does not
+# by itself cause the resulting work to be covered by the GNU General Public
+# License. However the source code for this file must still be made available
+# in accordance with section (3) of the GNU General Public License.
+#
+# This exception does not invalidate any other reasons why a work based on
+# this file might be covered by the GNU General Public License.
+# -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ============================================================================
+# #####DESCRIPTIONBEGIN####
+# 
+#  Author(s):   bartv
+#  Contact(s):  bartv
+#  Date:        2005/10/28
+#  Version:     0.01
+#  Description:
+#      Implementation of a framebuffer device. This script should only ever
+#      be run from inside the ecosynth auxiliary.
+# 
+# ####DESCRIPTIONEND####
+# ============================================================================
+
+# }}}
+
+# Overview
+#
+# The synthetic framebuffer package supports up to four framebuffer
+# devices. The eCos framebuffers are displayed by a separate C program
+# framebuf which gets spawned by this script. framebuf operates using
+# low-level X library calls. Doing the drawing inside Tcl/Tk would be
+# far too slow, and trying to draw directly to an X display from inside
+# an eCos application would be complicated.
+#
+# When an eCos framebuffer is switched on for the first time it will
+# result in a device instantiation in this script. A suitable frame
+# is created, and once it is mapped the framebuf program is started.
+# The device data string from the target includes a protocol version
+# number, target display depth, width and height, display format, etc.
+
+namespace eval framebuf {
+
+    # Protocol between the target-side and the auxiliary, as per protocol.h
+    variable    SYNTH_FB_INIT       0x01
+    variable    SYNTH_FB_ABORT      0x02
+    variable    SYNTH_FB_ON         0x03
+    variable    SYNTH_FB_OFF        0x04
+
+    # Protocol between the auxiliary and the framebuf program
+    variable    SYNTH_FB_AUX_MAPPED 0x01
+    variable    SYNTH_FB_AUX_ON     0x02
+    variable    SYNTH_FB_AUX_OFF    0x03
+    variable    SYNTH_FB_AUX_REDRAW 0x04
+    
+    variable 	init_ok		1
+    array set	settings	[]
+
+    # Set DEBUG_LEVEL to between 0 for no debug output, 2 for maximum
+    variable    DEBUG_LEVEL 0
+    proc DEBUG { level devid msg } {
+        if { $level < $framebuf::DEBUG_LEVEL } {
+            if { [info exists framebuf::settings($devid,fbid)] } {
+                set fbid $framebuf::settings($devid,fbid)
+            } else {
+                set fbid "<unknown>"
+            }
+            puts -nonewline stderr "framebuf.tcl (fb$fbid): $msg"; flush stderr
+        }
+    }
+    
+    # One-off initialization.
+    variable install_dir	$synth::device_install_dir
+    variable framebuf_executable [file join $framebuf::install_dir "framebuf"]
+    if { ! [file exists $framebuf_executable] } {
+        synth::report_error "Framebuffer device, framebuf executable has not been installed in $framebuf::install_dir.\n"
+        set init_ok 0
+    } elseif { ! [file executable $framebuf_executable] } {
+        synth::report_error "Framebuffer device, installed program $framebuf_executable is not executable.\n"
+        set init_ok 0
+    }
+
+    if { ! [file exists [file join $framebuf::install_dir "framebuf_icon.xbm"]] ||
+         ! [file exists [file join $framebuf::install_dir "framebuf_iconmask.xbm"]] } {
+        synth::report_error "Framebuffer device, bitmap support files have not been installed.\n"
+        set init_ok =
+    }
+
+    # A default function for creating the Tk frame for an eCos
+    # framebuffer device. Framebuffer 0 is usually part of the
+    # main window, unless it would take up too much space.
+    # Unfortunately at this stage of initialization there is no
+    # easy way to work out how big . is going to be so some
+    # hard-wired numbers are used instead.
+    proc default_create_frame { fbid magnification depth little_endian width height viewport_width viewport_height stride number_pages format } {
+
+        puts "default_create_frame $fbid mag $magnification width $viewport_width height $viewport_height"
+        set viewport_width [expr $viewport_width * $magnification]
+        set viewport_height [expr $viewport_height * $magnification]
+        puts "default_create_frame $fbid mag $magnification width $viewport_width height $viewport_height"
+        
+        if { (0 == $fbid) && ($viewport_height <= 240) && ($viewport_width <= 640) } {
+            frame           .fb$fbid -container 1 -height $viewport_height -width $viewport_width
+            pack            .fb$fbid -in .main.n -expand 0 -anchor nw
+            return          .fb$fbid
+        } else {
+            toplevel        .fb$fbid
+            frame           .fb$fbid.frame -container 1 -height $viewport_height -width $viewport_width
+            pack            .fb$fbid.frame -side top -expand 0 -anchor nw
+            wm title        .fb$fbid	"Synth FB[set fbid] [set width]*[set height]*[set depth]bpp"
+            wm iconbitmap   .fb$fbid "@[file join $framebuf::install_dir framebuf_icon.xbm]"
+            wm iconmask     .fb$fbid "@[file join $framebuf::install_dir framebuf_iconmask.xbm]"
+            wm iconname     .fb$fbid "Synth FB[set fbid]"
+            wm protocol     .fb$fbid WM_DELETE_WINDOW { }
+            return .fb$fbid.frame
+        }
+    }
+
+    variable create_frame_proc	default_create_frame
+    
+    if { [synth::tdf_has_option "framebuf" "create_frame_proc"] } {
+        set framebuf::create_frame_proc [synth::tdf_get_option "framebuf" "create_frame_proc"]
+    }
+
+    # Optional magnification
+    for { set i 0 } { $i < 4 } { incr i } {
+        set framebuf::settings(fb$i,magnification) 1
+        if { [synth::tdf_has_option "framebuf" "fb[set i]_magnification"] } {
+            set magnification [synth::tdf_get_option "framebuf" "fb[set i]_magnification"]
+            if { ! [string is integer -strict $magnification] } {
+                synth::report_error [concat
+                                     "Framebuf device, invalid value in target definition file $synth::target_definition\n"
+                                     "    fb[set i]_magnification should be a simple integer, not $magnification\n"]
+                set init_ok 0
+            } elseif { ($magnification < 1) || ($magnification > 4) } {
+                synth::report_error [concat
+                                     "Framebuf device, invalid value in target definition file $synth::target_definition\n"
+                                     "    fb[set i]_magnification should be 1, 2, 3 or 4.\n"]
+                set init_ok 0
+            } else {
+                set framebuf::settings(fb$i,magnification) $magnification
+            }
+        }
+    }
+
+    proc handle_framebuf_reply { devid } {
+        DEBUG 1 $devid "reading reply from framebuf program\n"
+        if { ! $framebuf::settings($devid,got_reply) } {
+            # The first message from the framebuf program indicates success+pathnames or failure+message
+            # This will wake up a vwait in the instantiate proc
+            set framebuf::settings($devid,reply) [read $framebuf::settings($devid,fd)]
+            set framebuf::settings($devid,got_reply) 1
+        } else {
+            # The framebuf program sends back no other data, but may issue warnings or failures
+            synth::report [read $framebuf::settings($devid,fd)]
+        }
+    }
+    
+    proc send_framebuf_request { devid code arg1 arg2 } {
+        # FIXME handle endianness
+        set auxiliary_request [binary format iii $code $arg1 $arg2]
+        puts -nonewline $framebuf::settings($devid,fd) $auxiliary_request
+        flush $framebuf::settings($devid,fd)
+    }
+    
+    proc handle_ecos_request { devid reqcode arg1 arg2 reqdata reqlen reply_len } {
+        DEBUG 1 $devid "got request $reqcode from eCos application\n"
+        if { $framebuf::SYNTH_FB_INIT == $reqcode } {
+            # This request is used after instantiation to get hold of the connectivity information
+            synth::send_reply 1 [string length $framebuf::settings($devid,connectivity)] $framebuf::settings($devid,connectivity)
+        } elseif { $framebuf::SYNTH_FB_ABORT == $reqcode } {
+            # FIXME: kill off the framebuf program? Destroy the window/frame?
+            synth::report_error "framebuf: eCos application has failed to connect to host-side framebuf program"
+            synth::report_error "        : graphical display is not operational"
+        } elseif { $framebuf::SYNTH_FB_ON == $reqcode } {
+            send_framebuf_request $devid $framebuf::SYNTH_FB_AUX_ON 0 0
+        } elseif { $framebuf::SYNTH_FB_OFF == $reqcode } {
+            send_framebuf_request $devid $framebuf::SYNTH_FB_AUX_OFF 0 0
+        } else {
+            synth::report_error "framebuf: got invalid request $reqcode from eCos application"
+        }
+    }
+    
+    proc mapped { devid } {
+        DEBUG 1 $devid "frame has been mapped\n"
+        bind $framebuf::settings($devid,frame) <Map> ""
+        send_framebuf_request $devid $framebuf::SYNTH_FB_AUX_MAPPED [winfo id $framebuf::settings($devid,frame)] 0
+        # This should not be necessary, but sometimes there are problems
+        # with an initial XPutImage() not actually drawing anything.
+        after 250 framebuf::send_framebuf_request $devid $framebuf::SYNTH_FB_AUX_REDRAW 0 0
+    }
+    
+    proc instantiate { devid name data } {
+
+        DEBUG 1 $devid "instantiate devid $devid, name $name, data $data\n"
+        
+        if { ! $synth::flag_gui } {
+            # If we are not running under a windowing system we cannot
+            # show the framebuffer data. Just stuck to the default
+            # memory framebuffer.
+            return ""
+        }
+
+        if { [info exists framebuf::settings($name,id)] } {
+            synth::report_error "Framebuf device: attempt to create several $name instances\n"
+            return ""
+        }
+
+        # Check that the framebuf program can actually handle this display.
+        set depth [winfo depth .]
+        if { (24 != $depth) && (32 != $depth) } {
+            synth::report_error "Framebuf device: requires 24bpp or 32bpp X display\n"
+            return ""
+        }
+        set visual [winfo visual .]
+        if { ![string equal "truecolor" $visual] && ![string equal "directcolor" $visual] } {
+            synth::report_error "Framebuf device: requires a truecolor or directcolor X display\n"
+            return ""
+        }
+        
+        # Data is a set of comma-separated parameters, mostly numeric,
+        # describing the desired framebuffer device. The first number
+        # is a protocol number as per ../src/protocol.h
+        set junk 	""
+        set protocol 	0
+        if { ! [regexp -- {^(\d*),.*} $data junk protocol] } {
+            synth::report_error "Framebuf device: missing protocol number for device $name\n"
+            return ""
+        }
+        if { $protocol != 1 } {
+            synth::report_error "Framebuf device: protocol mismatch\n    \
+                     Target uses protocol version $protocol\n    \
+                     Host is only up to version 1\n"
+            return ""
+        }
+        set framebuf::settings($devid,name) $name
+        set result [regexp -- {^(\d*),(\d*),(\d*),(\d*),(\d*),(\d*),(\d*),(\d*),(\d*),(\d*),(.*)$} $data junk protocol \
+                        framebuf::settings($devid,fbid) \
+                        framebuf::settings($devid,depth) \
+                        framebuf::settings($devid,little_endian) \
+                        framebuf::settings($devid,width) \
+                        framebuf::settings($devid,height) \
+                        framebuf::settings($devid,viewport_width) \
+                        framebuf::settings($devid,viewport_height) \
+                        framebuf::settings($devid,stride) \
+                        framebuf::settings($devid,number_pages) \
+                        framebuf::settings($devid,format)]
+        if { ! $result } {
+            synth::report_error "Framebuf device: invalid parameter string $data\n"
+            return ""
+        }
+        set framebuf::settings($devid,magnification) $framebuf::settings(fb$framebuf::settings($devid,fbid),magnification)
+
+        # Spawn the framebuf process. Its stdin and stdout are pipes
+        # connected to ecosynth. Its stderr is redirected to the current
+        # tty for debugging/diagnostics.
+        set cmd "|$framebuf::framebuf_executable "
+        append cmd "$framebuf::settings($devid,fbid) "
+        append cmd "$framebuf::settings($devid,depth) "
+        append cmd "$framebuf::settings($devid,little_endian) "
+        append cmd "$framebuf::settings($devid,width) "
+        append cmd "$framebuf::settings($devid,height) "
+        append cmd "$framebuf::settings($devid,viewport_width) "
+        append cmd "$framebuf::settings($devid,viewport_height) "
+        append cmd "$framebuf::settings($devid,stride) "
+        append cmd "$framebuf::settings($devid,number_pages) "
+        append cmd "$framebuf::settings($devid,format) "
+        append cmd "$framebuf::settings($devid,magnification) "
+
+        DEBUG 1 $devid "spawning framebuf program : $cmd\n"
+        if { [catch { set framebuf::settings($devid,fd) [open "$cmd 2>/dev/tty" "w+"] } message] } {
+            synth::report_error "Failed to spawn framebuf process for device $name\n    $message"
+            return ""
+        }
+        set framebuf::settings($devid,reply) 0
+        set framebuf::settings($devid,got_reply) 0
+        fconfigure $framebuf::settings($devid,fd) -translation binary -blocking 0
+        fileevent $framebuf::settings($devid,fd) readable "framebuf::handle_framebuf_reply $devid"
+        
+        # Now wait for the framebuf device to initialize. It should send back a single byte,
+        # 0 for failure followed by an error string, 1 for success followed by a string with
+        # the connectivity information.
+        DEBUG 1 $devid "waiting for initial reply from framebuf program\n"
+        vwait framebuf::settings($devid,reply)
+        if { "" == $framebuf::settings($devid,reply) } {
+            synth::report_error "framebuf process for device $name exited unexpectedly.\n"
+            catch { close $framebuf::settings($devid,fd) }
+            return ""
+        }
+        set code [string index $framebuf::settings($devid,reply) 0]
+        if { "0" == $code } {
+            synth::report_error "framebuf process was unable to initialize eCos device $name\n    $message"
+            catch { close $framebuf::settings($devid,fd) }
+            return ""
+        }
+        if { "1" !=  $code } {
+            synth::report_error "Unexpected response $code from framebuf process for eCos device $name\n"
+            catch { close $framebuf::settings($devid,fd) }
+            return ""
+        }
+        set framebuf::settings($devid,connectivity) [string range $framebuf::settings($devid,reply) 1 end]
+
+        # Now the the framebuf program is up and running, create the frame.
+        # Doing this earlier could result in spurious frames appearing if
+        # the framebuf program failed, and also causes timing problems
+        # between the <Map> binding and the framebuf program being ready.
+        DEBUG 1 $devid "invoking create_frame procedure $framebuf::create_frame_proc\n"
+        set framebuf::settings($devid,frame)                  	\
+            [$framebuf::create_frame_proc                   	\
+                 $framebuf::settings($devid,fbid)           	\
+                 $framebuf::settings($devid,magnification)   	\
+                 $framebuf::settings($devid,depth)           	\
+                 $framebuf::settings($devid,little_endian)   	\
+                 $framebuf::settings($devid,width)           	\
+                 $framebuf::settings($devid,height)          	\
+                 $framebuf::settings($devid,viewport_width)  	\
+                 $framebuf::settings($devid,viewport_height) 	\
+                 $framebuf::settings($devid,stride)          	\
+                 $framebuf::settings($devid,number_pages)    	\
+                 $framebuf::settings($devid,format)          	\
+                ]
+        DEBUG 1 $devid "frame is $framebuf::settings($devid,frame)\n"
+        if { "" == $framebuf::settings($devid,frame) } {
+            return ""
+        }
+
+        # Everything appears to be up and running. When the frame becomes visible,
+        # inform the framebuf program.
+        if { [winfo ismapped $framebuf::settings($devid,frame)] } {
+            framebuf::mapped $devid
+        } else {
+            bind $framebuf::settings($devid,frame) <Map>        "framebuf::mapped $devid"
+        }
+        DEBUG 1 $devid "instantiate succeeded, connectivity $framebuf::settings($devid,connectivity)\n"
+
+        return framebuf::handle_ecos_request
+    }
+}
+
+if { $framebuf::init_ok } {
+    return framebuf::instantiate
+} else {
+    synth::report "Framebuffer cannot be instantiated, initialization failed.\n"
+    return ""
+}
Index: host/framebuf.tdf
===================================================================
RCS file: host/framebuf.tdf
diff -N host/framebuf.tdf
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ host/framebuf.tdf	7 Oct 2008 21:00:31 -0000
@@ -0,0 +1,37 @@
+# Target definition file fragment for framebuffer devices.
+#
+# The main support available is for controlled creation
+# of the Tk frames in which the eCos framebuffer data will
+# be displayed. By default the main framebuf.tcl script will
+# create the 
+
+proc my_framebuf_create_frame { id magnification depth little_endian width height viewport_width viewport_height stride number_pages format} {
+
+    toplevel 		.ecosfb$id
+    wm title 		.ecosfb$id	"eCos FB[set id]: $width*$height*\#depth"
+    wm iconbitmap	.ecosfb$id	$framebuf::image_framebuf_icon
+    wm iconmask		.ecosfb$id	$framebuf::image_framebufmask_icon
+    wm protocol		.ecosfb$id	""
+
+    frame .ecosfb$id.frame -container 1 -height [expr $magnification * $viewport_height] -width [expr $magnification * $viewport_width]
+    pack  .ecosfb$id.frame -side top -expand 0
+
+    return .ecosfb$id.frame
+}
+
+synth_device framebuf {
+
+    # Customize how the eCos framebuffer appears on the X display.
+    # The argument should be a function which takes a long list of
+    # arguments, as above, and returns a Tk frame id. Spawning the
+    # C program is still the responsibility of the main framebuf.tcl
+    # script.
+    create_frame_proc	my_framebuf_create_frame
+
+    # Optional magnification for all four permitted framebuffer
+    # devices. Magnification can be 1, 2, 3 or 4
+    # fb0_magnification 2
+    # fb1_magnification 4
+    # fb2_magnification 3
+    # fb4_magnification 1
+}
Index: host/framebuf_icon.xbm
===================================================================
RCS file: host/framebuf_icon.xbm
diff -N host/framebuf_icon.xbm
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ host/framebuf_icon.xbm	7 Oct 2008 21:00:31 -0000
@@ -0,0 +1,10 @@
+#define framebuf_icon_width 40
+#define framebuf_icon_height 16
+static unsigned char framebuf_icon_bits[] = {
+   0xfc, 0xff, 0xff, 0xff, 0x3f, 0x06, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00,
+   0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x54, 0xba, 0xe2,
+   0x86, 0x21, 0x55, 0x92, 0x22, 0x8a, 0x21, 0xd4, 0x92, 0x22, 0x8a, 0xc1,
+   0xd4, 0x92, 0xe3, 0x86, 0x01, 0x49, 0x93, 0x22, 0x8a, 0x01, 0x49, 0x93,
+   0x22, 0x8a, 0x21, 0x49, 0x92, 0x22, 0x8a, 0xc1, 0x48, 0x92, 0x22, 0x86,
+   0x01, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0xc0, 0x06, 0x00,
+   0x00, 0x00, 0x60, 0xfc, 0xff, 0xff, 0xff, 0x3f};
Index: host/framebuf_iconmask.xbm
===================================================================
RCS file: host/framebuf_iconmask.xbm
diff -N host/framebuf_iconmask.xbm
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ host/framebuf_iconmask.xbm	7 Oct 2008 21:00:31 -0000
@@ -0,0 +1,10 @@
+#define ecosiconmask_width 40
+#define ecosiconmask_height 16
+static unsigned char ecosiconmask_bits[] = {
+   0xfc, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff,
+   0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0x3f};
Index: misc/example.c
===================================================================
RCS file: misc/example.c
diff -N misc/example.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ misc/example.c	7 Oct 2008 21:00:32 -0000
@@ -0,0 +1,374 @@
+//==========================================================================
+//
+//      example.c
+//
+//      Demonstration of the synthetic target framebuffer capabilities
+//
+//==========================================================================
+//###ECOSGPLCOPYRIGHTBEGIN####
+//-------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//###DESCRIPTIONBEGIN####
+//
+// Author(s):     bartv
+// Date:          2008-10-06
+//
+//###DESCRIPTIONEND####
+//========================================================================
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/io/framebuf.h>
+#include <cyg/kernel/kapi.h>
+#include <string.h>
+#include <stdio.h>
+
+#define BLACK        colours[0x00]
+#define BLUE         colours[0x01]
+#define GREEN        colours[0x02]
+#define CYAN         colours[0x03]
+#define RED          colours[0x04]
+#define MAGENTA      colours[0x05]
+#define BROWN        colours[0x06]
+#define LIGHTGREY    colours[0x07]
+#define DARKGREY     colours[0x08]
+#define LIGHTBLUE    colours[0x09]
+#define LIGHTGREEN   colours[0x0A]
+#define LIGHTCYAN    colours[0x0B]
+#define LIGHTRED     colours[0x0C]
+#define LIGHTMAGENTA colours[0x0D]
+#define YELLOW       colours[0x0E]
+#define WHITE        colours[0x0F]
+
+// ----------------------------------------------------------------------------
+// FB0. 320x240 32bpp true 0888. Just draw a simple image as per the fb.c
+// example and return to main().
+
+static void
+fb0_thread(cyg_addrword_t arg)
+{
+#define FRAMEBUF cyg_synth_fb0    
+    static cyg_ucount32 colours[16];
+    cyg_ucount16 block_width;
+    int i;
+    
+    for (i = 0; i < 16; i++) {
+        colours[i]  = cyg_fb_make_colour(&FRAMEBUF,
+                                         cyg_fb_palette_vga[i + i + i], cyg_fb_palette_vga[i + i + i + 1],cyg_fb_palette_vga[i + i + i + 2]);
+    }
+
+    cyg_fb_on(&FRAMEBUF);
+    // A white background
+    cyg_fb_fill_block(&FRAMEBUF, 0, 0, FRAMEBUF.fb_width, FRAMEBUF.fb_height, WHITE);
+    // A black block in the middle, 25 pixels in.
+    cyg_fb_fill_block(&FRAMEBUF, 25, 25, FRAMEBUF.fb_width - 50, FRAMEBUF.fb_height - 50, BLACK);
+
+    // Four diagonal lines in the corners. Red in the top left, blue in the top right,
+    // green in the bottom left, and yellow in the bottom right.
+    for (i = 0; i < 25; i++) {
+        cyg_fb_write_pixel(&FRAMEBUF, i,                           i,                            RED);
+        cyg_fb_write_pixel(&FRAMEBUF, (FRAMEBUF.fb_width - 1) - i, i,                            BLUE);
+        cyg_fb_write_pixel(&FRAMEBUF, i,                           (FRAMEBUF.fb_height - 1) - i, GREEN);
+        cyg_fb_write_pixel(&FRAMEBUF, (FRAMEBUF.fb_width - 1) - i, (FRAMEBUF.fb_height - 1) - i, YELLOW);
+    }
+
+    // Horizontal and vertical lines. Cyan at the top, magenta on the bottom,
+    // brown on the left, lightgrey on the right.
+    cyg_fb_write_hline(&FRAMEBUF, 25, 12, FRAMEBUF.fb_width - 50, CYAN);
+    cyg_fb_write_hline(&FRAMEBUF, 25, FRAMEBUF.fb_height - 12, FRAMEBUF.fb_width - 50, MAGENTA);
+    cyg_fb_write_vline(&FRAMEBUF, 12, 25, FRAMEBUF.fb_height - 50, BROWN);
+    cyg_fb_write_vline(&FRAMEBUF, FRAMEBUF.fb_width - 12, 25, FRAMEBUF.fb_height - 50, LIGHTGREY);
+
+    // And 14 vertical stripes, from blue to yellow, in the centre of the box.
+    block_width     = (FRAMEBUF.fb_width - 100) / 14;
+    for (i = 1; i <= 14; i++) {
+        cyg_fb_fill_block(&FRAMEBUF, 50 + ((i - 1) * block_width), 50, block_width, FRAMEBUF.fb_height - 100, colours[i]);
+    }
+
+    cyg_fb_synch(&FRAMEBUF, CYG_FB_UPDATE_NOW);
+#undef FRAMEBUF    
+}
+
+// ----------------------------------------------------------------------------
+// FB1, 320x240 15bpp, true 555, two pages. Draw a set of horizontal lines
+// in one page, vertical lines in the other, and flip between them at
+// one second intervals.
+
+static void
+fb1_thread(cyg_addrword_t arg)
+{
+#define FRAMEBUF cyg_synth_fb1
+    static cyg_ucount32 colours[16];
+    struct cyg_fb_ioctl_page_flip page_flip;
+    size_t len;
+    int result;
+    int i;
+
+    cyg_fb_on(&FRAMEBUF);
+    for (i = 0; i < 16; i++) {
+        colours[i]  = cyg_fb_make_colour(&FRAMEBUF,
+                                         cyg_fb_palette_vga[i + i + i], cyg_fb_palette_vga[i + i + i + 1],cyg_fb_palette_vga[i + i + i + 2]);
+    }
+
+    // Draw the horizontal stripes on page 0.
+    page_flip.fbpf_visible_page     = 0;
+    page_flip.fbpf_drawable_page    = 1;
+    page_flip.fbpf_when             = CYG_FB_UPDATE_NOW;
+    len                             = sizeof(page_flip);
+    result = cyg_fb_ioctl(&FRAMEBUF, CYG_FB_IOCTL_PAGE_FLIPPING_SET_PAGES, &page_flip, &len);
+    if (result != 0) {
+        fprintf(stderr, "fb1_thread: initial page flip failed.\n");
+    }
+    // 16 colours, 240 rows -> 15 rows/colour
+    for (i = 0; i < 16; i++) {
+        cyg_fb_fill_block(&FRAMEBUF, 0, 15 * i, 320, 15, colours[i]);
+    }
+    
+    // Show the horizontal stripes and draw the vertical stripes on page 0.
+    page_flip.fbpf_visible_page     = 1;
+    page_flip.fbpf_drawable_page    = 0;
+    page_flip.fbpf_when             = CYG_FB_UPDATE_NOW;
+    len                             = sizeof(page_flip);
+    result = cyg_fb_ioctl(&FRAMEBUF, CYG_FB_IOCTL_PAGE_FLIPPING_SET_PAGES, &page_flip, &len);
+    if (result != 0) {
+        fprintf(stderr, "fb1_thread: second page flip failed.\n");
+    }
+    // 16 colours, 320 columns -> 20 columns/colour
+    for (i = 0; i < 16; i++) {
+        cyg_fb_fill_block(&FRAMEBUF, 20 * i, 0, 20, 240, colours[i]);
+    }
+    
+    for ( i = 0; ; i = 1 - i) {
+        page_flip.fbpf_visible_page     = i;
+        page_flip.fbpf_drawable_page    = 1 - i;
+        page_flip.fbpf_when             = CYG_FB_UPDATE_NOW;
+        len                             = sizeof(page_flip);
+        result = cyg_fb_ioctl(&FRAMEBUF, CYG_FB_IOCTL_PAGE_FLIPPING_SET_PAGES, &page_flip, &len);
+        if (result != 0) {
+            fprintf(stderr, "fb1_thread: ongoing page flip failed.\n");
+        }
+        cyg_thread_delay(100);
+    }
+#undef FRAMEBUF    
+}
+
+// ----------------------------------------------------------------------------
+// FB2, 320x240 15bpp, true 565, with a 160x120 viewport. Draw a simple image
+// as per the fbmacro.c example. Then move around within the viewport in a
+// clockwise direction at 110ms intervals.
+
+static void
+fb2_thread(cyg_addrword_t arg)
+{
+#define FRAMEBUF fb2
+#define WIDTH    320
+#define HEIGHT   240
+    
+    static cyg_ucount32 colours[16];
+    cyg_ucount16 block_width;
+    int i, j;
+    int x = 0, y = 0;
+    CYG_FB_PIXEL0_VAR(FRAMEBUF);
+    CYG_FB_PIXEL1_VAR(FRAMEBUF);
+    cyg_fb_ioctl_viewport viewport;
+    size_t len;
+
+    CYG_FB_ON(FRAMEBUF);
+    for (i = 0; i < 16; i++) {
+        colours[i]  = CYG_FB_MAKE_COLOUR(FRAMEBUF,
+                                         cyg_fb_palette_vga[i + i + i], cyg_fb_palette_vga[i + i + i + 1],cyg_fb_palette_vga[i + i + i + 2]);
+    }
+    // A white background
+    CYG_FB_FILL_BLOCK(FRAMEBUF, 0, 0, WIDTH, HEIGHT, WHITE);
+    // A black block in the middle, 25 pixels in.
+    CYG_FB_FILL_BLOCK(FRAMEBUF, 32, 32, WIDTH - 64, HEIGHT - 64, BLACK);
+
+    // Four diagonal lines in the corners. Red in the top left, blue in the top right,
+    // green in the bottom left, and yellow in the bottom right.
+    for (i = 0; i < 32; i++) {
+        CYG_FB_WRITE_PIXEL(FRAMEBUF, i,               i,                RED);
+        CYG_FB_WRITE_PIXEL(FRAMEBUF, (WIDTH - 1) - i, i,                BLUE);
+        CYG_FB_WRITE_PIXEL(FRAMEBUF, i,               (HEIGHT - 1) - i, GREEN);
+        CYG_FB_WRITE_PIXEL(FRAMEBUF, (WIDTH - 1) - i, (HEIGHT - 1) - i, YELLOW);
+    }
+
+    // Horizontal and vertical lines. Cyan at the top, magenta on the bottom,
+    // brown on the left, lightgrey on the right.
+    CYG_FB_WRITE_HLINE(FRAMEBUF, 32,         16,            WIDTH - 64, CYAN);
+    CYG_FB_WRITE_HLINE(FRAMEBUF, 32,         HEIGHT - 16,   WIDTH - 64, MAGENTA);
+    CYG_FB_WRITE_VLINE(FRAMEBUF, 16,         32,            HEIGHT - 64, BROWN);
+    CYG_FB_WRITE_VLINE(FRAMEBUF, WIDTH - 16, 32,            HEIGHT - 64, LIGHTGREY);
+
+    // Top left, diagonal lines away from 0,0 with increasing spacing horizontally
+    for (i = 0; i < 16; i++) {
+        CYG_FB_PIXEL0_SET(FRAMEBUF, i + 16, i);
+        for (j = 0; j < 16; j++) {
+            CYG_FB_PIXEL0_WRITE(FRAMEBUF, colours[i]);
+            CYG_FB_PIXEL0_ADDX(FRAMEBUF, j);
+        }
+    }
+
+    // Top right, diagonal lines away from the corner, with increasing spacing horizontally
+    for (i = 0; i < 16; i++) {
+        CYG_FB_PIXEL0_SET(FRAMEBUF, WIDTH - (i + 16), i);
+        for (j = 0; j < 16; j++) {
+            CYG_FB_PIXEL0_WRITE(FRAMEBUF, colours[i]);
+            CYG_FB_PIXEL0_ADDX(FRAMEBUF, -1 * j);
+        }
+    }
+
+    // Top left, diagonal lines away from the corner, with increasing spacing vertically
+    for (i = 0; i < 16; i++) {
+        CYG_FB_PIXEL0_SET(FRAMEBUF, i, i + 16);
+        for (j = 0; j < 16; j++) {
+            CYG_FB_PIXEL0_WRITE(FRAMEBUF, colours[i]);
+            CYG_FB_PIXEL0_ADDY(FRAMEBUF, j);
+        }
+    }
+    // Bottom left, diagonal lines away from the corner, with increasing spacing vertically
+    for (i = 0; i < 16; i++) {
+        CYG_FB_PIXEL0_SET(FRAMEBUF, i, HEIGHT - (i + 16));
+        for (j = 0; j < 16; j++) {
+            CYG_FB_PIXEL0_WRITE(FRAMEBUF, colours[i]);
+            CYG_FB_PIXEL0_ADDY(FRAMEBUF, -1 * j);
+        }
+    }
+
+    // Thin vertical bars in the top-middle of the screen, between the hline and the box.
+    // Starting in the center and moving out with increasing spacing.
+    for (j = 0; j < 8; j++) {
+        CYG_FB_PIXEL0_SET(FRAMEBUF, (WIDTH / 2) - 2, 20 + j);
+        CYG_FB_PIXEL0_GET(FRAMEBUF, x, y);
+        CYG_FB_PIXEL1_SET(FRAMEBUF, x + 3, y);
+        for (i = 0; i < 16; i++) {
+            CYG_FB_PIXEL0_ADDX(FRAMEBUF, -1 * i);
+            CYG_FB_PIXEL1_ADDX(FRAMEBUF, i);
+            CYG_FB_PIXEL0_WRITE(FRAMEBUF, colours[i]);
+            CYG_FB_PIXEL1_WRITE(FRAMEBUF, colours[i]);
+        }
+    }
+    
+    block_width     = (WIDTH - 100) / 14;
+    for (i = 1; i <= 14; i++) {
+        CYG_FB_FILL_BLOCK(FRAMEBUF, 50 + ((i - 1) * block_width), 50, block_width, HEIGHT - 100, colours[i]);
+    }
+    
+    
+    for ( ; ; ) {
+        for (x = 0; x <= 160; x += 5) {
+            viewport.fbvp_x     = x;
+            viewport.fbvp_y     = 0;
+            viewport.fbvp_when  = CYG_FB_UPDATE_NOW;
+            len                 = sizeof(viewport);
+            CYG_FB_IOCTL(FRAMEBUF, CYG_FB_IOCTL_VIEWPORT_SET_POSITION, &viewport, &len);
+            cyg_thread_delay(11);
+        }
+        for (y = 0; y < 120; y += 5) {
+            viewport.fbvp_x     = 160;
+            viewport.fbvp_y     = y;
+            viewport.fbvp_when  = CYG_FB_UPDATE_NOW;
+            len                 = sizeof(viewport);
+            CYG_FB_IOCTL(FRAMEBUF, CYG_FB_IOCTL_VIEWPORT_SET_POSITION, &viewport, &len);
+            cyg_thread_delay(11);
+        }
+        for (x = 160; x >= 0; x -= 5) {
+            viewport.fbvp_x     = x;
+            viewport.fbvp_y     = 120;
+            viewport.fbvp_when  = CYG_FB_UPDATE_NOW;
+            len                 = sizeof(viewport);
+            CYG_FB_IOCTL(FRAMEBUF, CYG_FB_IOCTL_VIEWPORT_SET_POSITION, &viewport, &len);
+            cyg_thread_delay(11);
+        }
+        for (y = 120; y >= 0; y -= 5) {
+            viewport.fbvp_x     = 0;
+            viewport.fbvp_y     = y;
+            viewport.fbvp_when  = CYG_FB_UPDATE_NOW;
+            len                 = sizeof(viewport);
+            CYG_FB_IOCTL(FRAMEBUF, CYG_FB_IOCTL_VIEWPORT_SET_POSITION, &viewport, &len);
+            cyg_thread_delay(11);
+        }
+    }
+#undef FRAMEBUF
+#undef WIDTH
+#undef HEIGHT
+}
+
+// ----------------------------------------------------------------------------
+// FB3, 320x240 8bpp, paletted 888. Draw a series of vertical stripes, 5 pixels
+// wide, and rotate through the palette at 210ms intervals.
+
+static void
+fb3_thread(cyg_addrword_t arg)
+{
+#define FRAMEBUF    fb3
+    static cyg_uint8 palette[(128 +16) * 3];
+    int i;
+
+    CYG_FB_ON(FRAMEBUF);
+
+    // Read in the first 128 palette entries, and copy the first 16
+    // entries to give a wrap-around. After 128 the palette gets less
+    // interesting.
+    CYG_FB_READ_PALETTE(FRAMEBUF, 0, 128, palette);
+    memcpy(&(palette[128 * 3]), palette, 16 * 3);
+    
+    for (i = 0; i < 32; i++) {
+        CYG_FB_FILL_BLOCK(FRAMEBUF, 10 * i, 0, 10, 240, i);
+    }
+    
+    for ( i = 0; ; i = (i + 1) % 128 ) {
+        cyg_thread_delay(21);
+        CYG_FB_WRITE_PALETTE(FRAMEBUF, 0, 64, &(palette[i * 3]), CYG_FB_UPDATE_NOW);
+    }
+#undef FRAMEBUF    
+}
+
+// ----------------------------------------------------------------------------
+// main(). Start up separate threads for FB1 and FB2, run the FB0 code since
+// it just does some drawing and finishes, then run the FB3 code.
+static cyg_thread       fb1_thread_data;
+static cyg_handle_t     fb1_thread_handle;
+static unsigned char    fb1_thread_stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];
+static cyg_thread       fb2_thread_data;
+static cyg_handle_t     fb2_thread_handle;
+static unsigned char    fb2_thread_stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];
+
+int
+main(int argc, char** argv)
+{
+    cyg_thread_create(10, &fb1_thread, 0, "fb1", fb1_thread_stack, CYGNUM_HAL_STACK_SIZE_TYPICAL, &fb1_thread_handle, &fb1_thread_data);
+    cyg_thread_create(10, &fb2_thread, 0, "fb2", fb2_thread_stack, CYGNUM_HAL_STACK_SIZE_TYPICAL, &fb2_thread_handle, &fb2_thread_data);
+    cyg_thread_resume(fb1_thread_handle);
+    cyg_thread_resume(fb2_thread_handle);
+    fb0_thread(0);
+    fb3_thread(0);
+    return 0;
+}
+
Index: misc/example.ecm
===================================================================
RCS file: misc/example.ecm
diff -N misc/example.ecm
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ misc/example.ecm	7 Oct 2008 21:00:32 -0000
@@ -0,0 +1,85 @@
+cdl_configuration eCos {
+    package CYGPKG_IO_FRAMEBUF ;
+};
+
+cdl_component CYGPKG_DEVS_FRAMEBUF_SYNTH_FB0 {
+    user_value 1
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB0_WIDTH {
+    user_value 320
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB0_HEIGHT {
+    user_value 240
+};
+
+cdl_option CYGDAT_DEVS_FRAMEBUF_SYNTH_FB0_FORMAT {
+    user_value 32BPP_TRUE_0888
+};
+
+cdl_component CYGPKG_DEVS_FRAMEBUF_SYNTH_FB1 {
+    user_value 1
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB1_WIDTH {
+    user_value 320
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB1_HEIGHT {
+    user_value 240
+};
+
+cdl_option CYGDAT_DEVS_FRAMEBUF_SYNTH_FB1_FORMAT {
+    user_value 16BPP_TRUE_555
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB1_PAGE_FLIPPING {
+    user_value 1 2
+};
+
+cdl_component CYGPKG_DEVS_FRAMEBUF_SYNTH_FB2 {
+    user_value 1
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB2_WIDTH {
+    user_value 320
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB2_HEIGHT {
+    user_value 240
+};
+
+cdl_option CYGDAT_DEVS_FRAMEBUF_SYNTH_FB2_FORMAT {
+    user_value 16BPP_TRUE_565
+};
+
+cdl_component CYGIMP_DEVS_FRAMEBUF_SYNTH_FB2_VIEWPORT {
+    user_value 1
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB2_VIEWPORT_WIDTH {
+    user_value 160
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB2_VIEWPORT_HEIGHT {
+    user_value 120
+};
+
+cdl_component CYGPKG_DEVS_FRAMEBUF_SYNTH_FB3 {
+    user_value 1
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB3_WIDTH {
+    user_value 320
+};
+
+cdl_option CYGNUM_DEVS_FRAMEBUF_SYNTH_FB3_HEIGHT {
+    user_value 240
+};
+
+cdl_option CYGDAT_DEVS_FRAMEBUF_SYNTH_FB3_FORMAT {
+    user_value 8BPP_PAL888
+};
+
+
Index: misc/example.tdf
===================================================================
RCS file: misc/example.tdf
diff -N misc/example.tdf
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ misc/example.tdf	7 Oct 2008 21:00:32 -0000
@@ -0,0 +1,42 @@
+# An example framebuffer create function. This is for use with the
+# synthetic target framebuffer example program which uses four
+# devices:
+#
+#  fb0: 320x240 32bpp true 0888
+#  fb1: 320x240 16bpp true 555 with two pages
+#  fb2: 320x240 16bpp true 565 with a viewport of 160x120
+#  fb3: 320x240 8bpp  pal  888
+#
+# These are all created in a single toplevel .synth_framebufs, one above the other,
+# with labels in between.
+proc my_framebuf_create_frame { fb_id magnification depth little_endian width height viewport_width viewport_height stride number_pages format } {
+    if { ![winfo exists .synth_framebufs] } {
+        toplevel    .synth_framebufs
+        wm title    .synth_framebufs "Synthetic target framebuffers"
+        wm protocol .synth_framebufs WM_DELETE_WINDOW {}
+        wm geometry .synth_framebufs +1000+0
+
+        label .synth_framebufs.fb0_label -text "FB0 320x240 32bpp true 0888"
+        frame .synth_framebufs.fb0 -container 1 -height 240 -width 320
+        label .synth_framebufs.fb1_label -text "FB1 320x240 16bpp true 0555 two pages"
+        frame .synth_framebufs.fb1 -container 1 -height 240 -width 320
+        label .synth_framebufs.fb2_label -text "FB2 320x240 16bpp true 0565\nviewport 160x120 magnified *2"
+        frame .synth_framebufs.fb2 -container 1 -height 240 -width 320
+        label .synth_framebufs.fb3_label -text "FB3 320x240  8bpp paletted 888"
+        frame .synth_framebufs.fb3 -container 1 -height 240 -width 320
+        pack .synth_framebufs.fb0_label -side top -expand 1 -anchor w -fill x
+        pack .synth_framebufs.fb0       -side top -expand 0 -anchor w
+        pack .synth_framebufs.fb1_label -side top -expand 1 -anchor w -fill x
+        pack .synth_framebufs.fb1       -side top -expand 0 -anchor w
+        pack .synth_framebufs.fb2_label -side top -expand 1 -anchor w -fill x
+        pack .synth_framebufs.fb2       -side top -expand 0 -anchor w
+        pack .synth_framebufs.fb3_label -side top -expand 1 -anchor w -fill x
+        pack .synth_framebufs.fb3       -side top -expand 0 -anchor w
+    }
+    return .synth_framebufs.fb$fb_id
+}
+
+synth_device framebuf {
+    fb2_magnification   2
+    create_frame_proc   my_framebuf_create_frame
+}
Index: src/gen_synthfb.tcl
===================================================================
RCS file: src/gen_synthfb.tcl
diff -N src/gen_synthfb.tcl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/gen_synthfb.tcl	7 Oct 2008 21:00:32 -0000
@@ -0,0 +1,352 @@
+#!/bin/bash
+# restart using a Tcl shell \
+    exec sh -c 'for tclshell in tclsh tclsh83 cygtclsh80 ; do \
+    ( echo | $tclshell ) 2> /dev/null && exec $tclshell "`( cygpath -w \"$0\" ) 2> /dev/null || echo $0`" "$@" ; \
+    done ; \
+    echo "gen_synthfb.tcl: cannot find Tcl shell" ; exit 1' "$0" "$@"
+
+#===============================================================================
+#
+#    gen_synthfb.tcl
+#
+#    Generate header files for all enabled synthetic target framebuffer devices.
+#
+#===============================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+# -------------------------------------------
+# This file is part of eCos, the Embedded Configurable Operating System.
+# Copyright (C) 2008 Free Software Foundation, Inc.
+#
+# eCos is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 or (at your option) any later version.
+#
+# eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with eCos; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# As a special exception, if other files instantiate templates or use macros
+# or inline functions from this file, or you compile this file and link it
+# with other works to produce a work based on this file, this file does not
+# by itself cause the resulting work to be covered by the GNU General Public
+# License. However the source code for this file must still be made available
+# in accordance with section (3) of the GNU General Public License.
+#
+# This exception does not invalidate any other reasons why a work based on
+# this file might be covered by the GNU General Public License.
+# -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+#===============================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):	bartv
+# Date:		2005-10-28
+#
+# This script is invoked via a custom make rule to generate files
+# <cyg/io/framebufs/synth_fb.h> and synth_fbs.c
+#
+#####DESCRIPTIONEND####
+#===============================================================================
+
+proc do_it { prefix } {
+    set pkgconf_file	[file join $prefix "include/pkgconf/devs_framebuf_synth.h"]
+    if { ! [file exists $pkgconf_file] } {
+        puts stderr "gen_synthfb.tcl: missing configuration header $pkgconf_file"
+        exit 1
+    }
+    set fd [open $pkgconf_file "r"]
+    set data [read $fd]
+    close $fd
+    
+    array set defines	[list]
+    foreach line [split $data "\n"] {
+        if { [regexp -- {^\#define[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]+([^[:space:]]+)$} $line junk symbol value] } {
+            set defines($symbol) $value
+        }
+    }
+
+    set data \
+        "/*
+ * File <cyg/io/framebufs/synth_fb.h>
+ *
+ * This is a generated file - do not edit!
+ * It should not be \#include'd directly. Instead use <cyg/io/framebuf.h>
+ */
+
+#include <cyg/io/framebuf.inl>
+
+"
+    
+    for { set fb 0 } { $fb < 4 } { incr fb } {
+        if { ! [info exists defines(CYGPKG_DEVS_FRAMEBUF_SYNTH_FB[set fb])] } {
+            continue
+        }
+        
+        set width	$defines(CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set fb]_WIDTH)
+        set height	$defines(CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set fb]_HEIGHT)
+        set flags0  "(CYG_FB_FLAGS0_LINEAR_FRAMEBUFFER | \\\n    CYG_FB_FLAGS0_DOUBLE_BUFFER | \\\n"
+        if { [info exists defines(CYGIMP_DEVS_FRAMEBUF_SYNTH_FB[set fb]_VIEWPORT) ] } {
+            set viewport_width	$defines(CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set fb]_VIEWPORT_WIDTH)
+            set viewport_height	$defines(CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set fb]_VIEWPORT_HEIGHT)
+            append flags0 "    CYG_FB_FLAGS0_VIEWPORT | \\\n"
+        } else {
+            set viewport_width  $width
+            set viewport_height $height
+        }
+        if { [info exists defines(CYGNUM_DEVS_FRAMEBUF_SYNTH_FB[set fb]_PAGE_FLIPPING)] } {
+            append flags0 "    CYG_FB_FLAGS0_PAGE_FLIPPING | \\\n"
+        }
+        set paletted		1
+        switch -- $defines(CYGDAT_DEVS_FRAMEBUF_SYNTH_FB[set fb]_FORMAT) {
+            1BPP_BE_PAL888 {
+                set format	    "CYG_FB_FORMAT_1BPP_PAL888"
+                set suffix	    "1BE"
+                set depth	    1
+                set stride	    [expr ($width + 7) >> 3]
+            }
+            1BPP_LE_PAL888 {
+                append flags0	"    CYG_FB_FLAGS0_LE | \\\n"
+                set format	    "CYG_FB_FORMAT_1BPP_PAL888"
+                set suffix	    "1LE"
+                set depth	    1
+                set stride	    [expr ($width + 7) >> 3]
+            }
+            2BPP_BE_PAL888 {
+                set format	    "CYG_FB_FORMAT_2BPP_PAL888"
+                set suffix	    "2BE"
+                set depth   	2
+                set stride	    [expr ($width + 3) >> 2]
+            }
+            2BPP_LE_PAL888 {
+                append flags0	"    CYG_FB_FLAGS0_LE | \\\n"
+                set format	    "CYG_FB_FORMAT_2BPP_PAL888"
+                set suffix	    "2LE"
+                set depth	    2
+                set stride	    [expr ($width + 3) >> 2]
+            }
+            4BPP_BE_PAL888 {
+                set format	    "CYG_FB_FORMAT_4BPP_PAL888"
+                set suffix	    "4BE"
+                set depth	    4
+                set stride	    [expr ($width + 1) >> 1]
+            }
+            4BPP_LE_PAL888 {
+                append flags0	"    CYG_FB_FLAGS0_LE | \\\n"
+                set format	    "CYG_FB_FORMAT_4BPP_PAL888"
+                set suffix	    "4LE"
+                set depth	    4
+                set stride	    [expr ($width + 1) >> 1]
+            }
+            8BPP_PAL888 {
+                set format	    "CYG_FB_FORMAT_8BPP_PAL888"
+                set suffix	    "8"
+                set depth	    8
+                set stride	    $width
+            }
+            8BPP_TRUE_332 {
+                set format		        "CYG_FB_FORMAT_8BPP_TRUE_332"
+                set suffix		        "8"
+                set paletted		    0
+                set make_colour_fn	    "cyg_fb_dev_make_colour_8bpp_true_332"
+                set break_colour_fn	    "cyg_fb_dev_break_colour_8bpp_true_332"
+                set make_colour_macro	"CYG_FB_MAKE_COLOUR_8BPP_TRUE_332"
+                set break_colour_macro	"CYG_FB_BREAK_COLOUR_8BPP_TRUE_332"
+                set depth		        8
+                set stride		        $width
+            }
+            16BPP_TRUE_565 {
+                set format		        "CYG_FB_FORMAT_16BPP_TRUE_565"
+                set suffix		        "16"
+                set paletted		    0
+                set make_colour_fn	    "cyg_fb_dev_make_colour_16bpp_true_565"
+                set break_colour_fn	    "cyg_fb_dev_break_colour_16bpp_true_565"
+                set make_colour_macro   "CYG_FB_MAKE_COLOUR_16BPP_TRUE_565"
+                set break_colour_macro  "CYG_FB_BREAK_COLOUR_16BPP_TRUE_565"
+                set depth		        16
+                set stride		        [expr $width * 2]
+            }
+            16BPP_TRUE_555 {
+                set format		        "CYG_FB_FORMAT_16BPP_TRUE_555"
+                set suffix		        "16"
+                set paletted		    0
+                set make_colour_fn	    "cyg_fb_dev_make_colour_16bpp_true_555"
+                set break_colour_fn	    "cyg_fb_dev_break_colour_16bpp_true_555"
+                set make_colour_macro   "CYG_FB_MAKE_COLOUR_16BPP_TRUE_555"
+                set break_colour_macro	"CYG_FB_BREAK_COLOUR_16BPP_TRUE_555"
+                set depth		        16
+                set stride		        [expr $width * 2]
+            }
+            32BPP_TRUE_0888 {
+                set format		        "CYG_FB_FORMAT_32BPP_TRUE_0888"
+                set suffix		        "32"
+                set paletted		    0
+                set make_colour_fn	    "cyg_fb_dev_make_colour_32bpp_true_0888"
+                set break_colour_fn	    "cyg_fb_dev_break_colour_32bpp_true_0888"
+                set make_colour_macro	"CYG_FB_MAKE_COLOUR_32BPP_TRUE_0888"
+                set break_colour_macro  "CYG_FB_BREAK_COLOUR_32BPP_TRUE_0888"
+                set depth		        32
+                set stride		        [expr $width * 4]
+            }
+        }
+        if { $paletted } {
+            append flags0		"    CYG_FB_FLAGS0_PALETTE | \\\n    CYG_FB_FLAGS0_WRITEABLE_PALETTE | \\\n"
+            set write_palette_fn	"cyg_synth_fb_write_palette"
+            set read_palette_fn		"cyg_synth_fb_read_palette"
+            set make_colour_fn		"cyg_fb_nop_make_colour"
+            set break_colour_fn		"cyg_fb_nop_break_colour"
+        } else {
+            append flags0 		"    CYG_FB_FLAGS0_TRUE_COLOUR | \\\n"
+            set write_palette_fn	"cyg_fb_nop_write_palette"
+            set read_palette_fn		"cyg_fb_nop_read_palette"
+        }
+        append flags0		"    CYG_FB_FLAGS0_BLANK)"
+
+        # The framebuffer parameters
+        append data \
+            "
+extern cyg_fb cyg_synth_fb[set fb];
+extern cyg_uint8* cyg_synth_fb[set fb]_base;
+#define CYG_FB_fb[set fb]_STRUCT            cyg_synth_fb[set fb]
+#define CYG_FB_fb[set fb]_DEPTH             $depth
+#define CYG_FB_fb[set fb]_FORMAT            $format
+#define CYG_FB_fb[set fb]_WIDTH             $width
+#define CYG_FB_fb[set fb]_HEIGHT            $height
+#define CYG_FB_fb[set fb]_VIEWPORT_WIDTH    $viewport_width
+#define CYG_FB_fb[set fb]_VIEWPORT_HEIGHT   $viewport_height
+#define CYG_FB_fb[set fb]_BASE              cyg_synth_fb[set fb]_base
+#define CYG_FB_fb[set fb]_STRIDE            $stride
+#define CYG_FB_fb[set fb]_FLAGS0            $flags0
+#define CYG_FB_fb[set fb]_FLAGS1            0
+#define CYG_FB_fb[set fb]_FLAGS2            0
+#define CYG_FB_fb[set fb]_FLAGS3            0
+"
+
+        # These macros are not part of the usual framebuffer set, but are
+        # useful because of the configurable nature of the synthetic target
+        append data \
+            "
+#define CYG_FB_fb[set fb]_SUFFIX            $suffix
+#define CYG_FB_fb[set fb]_READ_PALETTE_FN   $read_palette_fn
+#define CYG_FB_fb[set fb]_WRITE_PALETTE_FN  $write_palette_fn
+#define CYG_FB_fb[set fb]_MAKE_COLOUR_FN    $make_colour_fn
+#define CYG_FB_fb[set fb]_BREAK_COLOUR_FN   $break_colour_fn
+"
+        # And the macro API, all done in terms of the linear framebuffer functions.
+        append data \
+            "
+#define CYG_FB_fb[set fb]_PIXELx_VAR(  _fb_, _id_)    CYG_FB_PIXELx_VAR_[set suffix](  _fb_, _id_)
+#define CYG_FB_fb[set fb]_PIXELx_SET(  _fb_, _id_, _x_, _y_) \\
+    CYG_MACRO_START \\
+    CYG_FB_PIXELx_SET_[set suffix](  _fb_, _id_, CYG_FB_fb[set fb]_BASE, CYG_FB_fb[set fb]_STRIDE, _x_, _y_); \\
+    CYG_MACRO_END
+#define CYG_FB_fb[set fb]_PIXELx_GET(  _fb_, _id_, _x_, _y_) \\
+    CYG_MACRO_START \\
+    CYG_FB_PIXELx_GET_[set suffix](  _fb_, _id_, CYG_FB_fb[set fb]_BASE, CYG_FB_fb[set fb]_STRIDE, _x_, _y_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_PIXELx_ADDX( _fb_, _id_, _incr_) \\
+    CYG_MACRO_START \\
+    CYG_FB_PIXELx_ADDX_[set suffix]( _fb_, _id_, CYG_FB_fb[set fb]_STRIDE, _incr_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_PIXELx_ADDY( _fb_, _id_, _incr_) \\
+    CYG_MACRO_START \\
+    CYG_FB_PIXELx_ADDY_[set suffix]( _fb_, _id_, CYG_FB_fb[set fb]_STRIDE, _incr_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_PIXELx_WRITE(_fb_, _id_, _colour_) \\
+    CYG_MACRO_START \\
+    CYG_FB_PIXELx_WRITE_[set suffix](_fb_, _id_, _colour_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_PIXELx_READ( _fb_, _id_) \\
+    ({ CYG_FB_PIXELx_READ_[set suffix]( _fb_, _id_); }) 
+#define CYG_FB_fb[set fb]_PIXELx_FLUSHABS( _fb_, _id_, _x0_, _y0_, _width_, _height_) \\
+    CYG_MACRO_START \\
+    CYG_FB_PIXELx_FLUSHABS_[set suffix](_fb_, _id_, _x0_, _y0_, _width_, _height_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_PIXELx_FLUSHREL( _fb_, _id_, _x0_, _y0_, _dx_, _dy_) \\
+    CYG_MACRO_START \\
+    CYG_FB_PIXELx_FLUSHREL_[set suffix](_fb_, _id_, _x0_, _y0_, _dx_, _dy_); \\
+    CYG_MACRO_END 
+
+#define CYG_FB_fb[set fb]_WRITE_PIXEL(_x_, _y_, _colour_) \\
+    CYG_MACRO_START \\
+    cyg_fb_linear_write_pixel_[set suffix]_inl(CYG_FB_fb[set fb]_BASE, CYG_FB_fb[set fb]_STRIDE, \\
+                                    _x_, _y_, _colour_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_READ_PIXEL(_x_, _y_) \\
+    ({ cyg_fb_linear_read_pixel_[set suffix]_inl(CYG_FB_fb[set fb]_BASE, CYG_FB_fb[set fb]_STRIDE, _x_, _y_); }) 
+#define CYG_FB_fb[set fb]_WRITE_HLINE(_x_, _y_, _len_, _colour_) \\
+    CYG_MACRO_START \\
+    cyg_fb_linear_write_hline_[set suffix]_inl(CYG_FB_fb[set fb]_BASE, CYG_FB_fb[set fb]_STRIDE, \\
+                                    _x_, _y_, _len_, _colour_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_WRITE_VLINE(_x_, _y_, _len_, _colour_) \\
+    CYG_MACRO_START \\
+    cyg_fb_linear_write_vline_[set suffix]_inl(CYG_FB_fb[set fb]_BASE, CYG_FB_fb[set fb]_STRIDE, \\
+                                    _x_, _y_, _len_, _colour_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_FILL_BLOCK(_x_, _y_, _width_, _height_, _colour_) \\
+    CYG_MACRO_START \\
+    cyg_fb_linear_fill_block_[set suffix]_inl(CYG_FB_fb[set fb]_BASE, CYG_FB_fb[set fb]_STRIDE, \\
+                                   _x_, _y_, _width_, _height_, _colour_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_WRITE_BLOCK(_x_, _y_, _width_, _height_, _data_, _offset_, _data_stride_) \\
+    CYG_MACRO_START \\
+    cyg_fb_linear_write_block_[set suffix]_inl(CYG_FB_fb[set fb]_BASE, CYG_FB_fb[set fb]_STRIDE, \\
+                                    _x_, _y_, _width_, _height_, _data_, _offset_, _data_stride_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_READ_BLOCK(_x_, _y_, _width_, _height_, _data_, _offset_, _data_stride_) \\
+    CYG_MACRO_START \\
+    cyg_fb_linear_read_block_[set suffix]_inl(CYG_FB_fb[set fb]_BASE, CYG_FB_fb[set fb]_STRIDE, \\
+                                   _x_, _y_, _width_, _height_, _data_, _offset_, _data_stride_); \\
+    CYG_MACRO_END 
+#define CYG_FB_fb[set fb]_MOVE_BLOCK(_x_, _y_, _width_, _height_, _new_x_, _new_y_) \\
+    CYG_MACRO_START \\
+    cyg_fb_linear_move_block_[set suffix]_inl(CYG_FB_fb[set fb]_BASE, CYG_FB_fb[set fb]_STRIDE, \\
+                                   _x_, _y_, _width_, _height_, _new_x_, _new_y_); \\
+    CYG_MACRO_END
+"
+        if { !$paletted } {
+            append data \
+                "
+#define CYG_FB_fb[set fb]_MAKE_COLOUR(_r_, _g_, _b_)                \\
+    ({ [set make_colour_macro](_r_, _g_, _b_); })
+#define CYG_FB_fb[set fb]_BREAK_COLOUR(_colour_, _r_, _g_, _b_)     \\
+    CYG_MACRO_START                                                 \\
+    [set break_colour_macro](_colour_, _r_, _g_, _b_);              \\
+    CYG_MACRO_END
+"
+        }
+    }
+
+    set old_data ""
+    set framebuf_file [file join $prefix "include/cyg/io/framebufs/synth_fb.h"]
+    if { [file exists $framebuf_file] && [file readable $framebuf_file] } {
+        set fd [open $framebuf_file "r"]
+        set old_data [read $fd]
+        close $fd
+    }
+    if { ! [string equal $old_data $data] } {
+        if { ! [info exists [file dirname $framebuf_file]] } {
+            file mkdir [file dirname $framebuf_file]
+        }
+        set fd [open $framebuf_file "w"]
+        puts -nonewline $fd $data
+        close $fd
+    }
+}
+
+if { 0 == $::argc } {
+    puts stderr "gen_synthfb.tcl: missing argument for install directory"
+    exit 1
+}
+if { [catch { do_it [lindex $::argv 0] } msg] } {
+    puts stderr "gen_synthfb.tcl: internal error"
+    puts stderr "    $msg"
+    exit 1
+}
+exit 0
+
Index: src/protocol.h
===================================================================
RCS file: src/protocol.h
diff -N src/protocol.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/protocol.h	7 Oct 2008 21:00:32 -0000
@@ -0,0 +1,123 @@
+//==========================================================================
+//
+//      protocol.h
+//
+//      Data common to host and target.
+//
+//==========================================================================
+//###ECOSGPLCOPYRIGHTBEGIN####
+//-------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//###DESCRIPTIONBEGIN####
+//
+// Author(s):     bartv
+// Date:          2005-10-28
+//
+//###DESCRIPTIONEND####
+//========================================================================
+
+// These requests are sent by eCos to the I/O auxiliary and the
+// framebuf.tcl script.
+//
+// Protocol version number
+#define SYNTH_FB_PROTOCOL_VERSION   0x01
+
+// Initialize, getting back various file names.
+#define SYNTH_FB_INIT               0x01
+// Abort, failed to open the file names
+#define SYNTH_FB_ABORT              0x02
+// Switch a device back on.
+#define SYNTH_FB_ON                 0x03
+// Or off
+#define SYNTH_FB_OFF                0x04
+
+// These requests are sent by eCos to the host-side framebuf program
+// to indicate what has changed.
+//
+// All connected
+#define SYNTH_FB_OK                 0x01
+// A double buffer synch.
+#define SYNTH_FB_SYNC               0x02
+// Palette change, redraw the lot
+#define SYNTH_FB_WRITE_PALETTE      0x03
+// Blank or unblank the screen
+#define SYNTH_FB_BLANK              0x04
+// Move the viewport
+#define SYNTH_FB_VIEWPORT           0x05
+// Page flipping
+#define SYNTH_FB_PAGE_FLIP          0x06
+
+// These requests go from the framebuf.tcl script to the framebuf
+// program.
+typedef struct synth_fb_auxiliary_request {
+    unsigned int command;
+    unsigned int arg1;
+    unsigned int arg2;
+} synth_fb_auxiliary_request;
+
+// This is sent when the frame becomes visible. It is followed
+// by a 32-bit windows id.
+#define SYNTH_FB_AUX_MAPPED         0x01
+// ON, processed by auxiliary and then passed on to framebuf
+#define SYNTH_FB_AUX_ON             0x02
+// OFF, processed by auxiliary and then passed on to framebuf
+#define SYNTH_FB_AUX_OFF            0x03
+// Refresh, sent by the auxiliary a second after mapping.
+#define SYNTH_FB_AUX_REDRAW         0x04
+
+// This data structure is in the shared memory region.
+typedef struct synth_fb_data {
+    // Do we have a connection to a host-side framebuf program to do
+    // the drawing?
+    int             connected;
+    // Named fifo between framebuf and the synthetic target.
+    int             fifo_to_framebuf;
+    int             fifo_from_framebuf;
+    // The device id for the auxiliary
+    int             devid;
+    // The bounding box for syncs.
+    int             sync_x0;
+    int             sync_y0;
+    int             sync_x1;
+    int             sync_y1;
+    // Is the display on?
+    int             display_on;
+    // Current blank state
+    int             blank_on;
+    // Current viewport position, top left
+    int             viewport_x;
+    int             viewport_y;
+    // Current page for page flipping
+    int             page_visible;
+    int             page_drawable;
+    // The palette, if used.
+    unsigned char   palette[3 * 256];
+    // The framebuffer data follows.
+    unsigned int    framebuf[1];
+} synth_fb_data;
Index: src/synthfb.c
===================================================================
RCS file: src/synthfb.c
diff -N src/synthfb.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/synthfb.c	7 Oct 2008 21:00:34 -0000
@@ -0,0 +1,679 @@
+//==========================================================================
+//
+//      synthfb.c
+//
+//      Provide one or more framebuffer devices for the synthetic target.
+//
+//==========================================================================
+//###ECOSGPLCOPYRIGHTBEGIN####
+//-------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//###DESCRIPTIONBEGIN####
+//
+// Author(s):     bartv
+// Date:          2005-10-28
+//
+//###DESCRIPTIONEND####
+//========================================================================
+
+#include <pkgconf/devs_framebuf_synth.h>
+#include <pkgconf/io_framebuf.h>
+#include <cyg/io/framebuf.h>
+#include <errno.h>
+#include <string.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_io.h>
+#include "protocol.h"
+
+// Set the DEBUG_LEVEL to 0 for no debugging, 2 for maximum debugging.
+#define DEBUG_LEVEL 0
+#define DEBUG(_level_, _str_, ...)              \
+    CYG_MACRO_START                             \
+    if (_level_ <= DEBUG_LEVEL) {               \
+        diag_printf( _str_, ## __VA_ARGS__);    \
+    }                                           \
+    CYG_MACRO_END
+
+// Achieving high performance graphics operations in the synthetic
+// target is difficult. Theoretically it might be possible to access
+// the Linux framebuffer directly using MIT-SHM or DGA. However there
+// is no practical way to handle the relevant parts of the X prococol,
+// e.g. expose events. We also don't want to go via the
+// general-purpose xchgmsg() functionality and a Tcl script, those
+// are not appropriate for high performance.
+//
+// Instead if the I/O auxiliary is running a framebuffer device is
+// instantiated, and the framebuf.tcl script will start a program
+// framebuf. That program will create a shared memory region which
+// then gets mapped into the synthetic target's address space. The
+// shared memory region holds a synth_fb_data structure followed by
+// the framebuffer data. If there are multiple framebuffer devices
+// then there will be multiple invocations of the framebuf program.
+//
+// The framebuf program needs to respond to requests from several
+// different sources. The X server may send events like expose.
+// The synthetic target application can send synchronization requests,
+// palette updates, and so on. The X events will come via a socket,
+// and the requests from framebuf.tcl can come via a pipe. select()
+// will serve for this. Several mechanisms can be used for the
+// communication between the synthetic target application and framebuf
+// including shared memory semaphores and reliable signals. To fit in
+// neatly with the select() a named fifo is used.
+//
+// So assuming a framebuf program is running fb_op() writes a single
+// byte to the fifo, then waits for framebuf to complete the
+// operation. That wait also uses a named fifo. This keeps everything
+// synchronous, and avoids some portability problems between
+// Linux on various architectures.
+static void
+fb_op(cyg_fb* fb, int command)
+{
+    synth_fb_data*  fb_data = (synth_fb_data*) fb->fb_driver2;
+    DEBUG(2, "target synthfb: fb_op %d\n", command);
+    if (fb_data->connected) {
+        cyg_uint8   data[1];
+        int         rc;
+        
+        data[0] = (cyg_uint8)command;
+        do {
+            rc = cyg_hal_sys_write(fb_data->fifo_to_framebuf, (const void*) data, 1);
+        } while (-CYG_HAL_SYS_EINTR == rc);
+        do {
+            rc = cyg_hal_sys_read(fb_data->fifo_from_framebuf, (void*) data, 1);
+        } while (-CYG_HAL_SYS_EINTR == rc);
+        if (rc < 0) {
+            diag_printf("Internal error: unexpected result %d when receiving response from the framebuf program.\n", rc);
+            diag_printf("              : disabling framebuffer device fb%d.\n", fb->fb_driver0);
+            fb_data->connected = 0;
+        }
+    }
+    DEBUG(2, "target synthfb: fb_op %d done\n", command);
+}
+
+// Create a framebuffer device. This gets called from a C++
+// static constructor, to ensure that all the framebuffer
+// windows are created early on during initialization before
+// the host-side ecosynth support performs any cleanups.
+void
+_cyg_synth_fb_instantiate(struct cyg_fb* fb)
+{
+    synth_fb_data*  local_fb_data = (synth_fb_data*) fb->fb_driver2;
+    synth_fb_data*  shared_fb_data;
+    char            device_data[512];
+    char            fb_name[4];
+    char*           fb_format   = 0;
+    char*           ptr;
+    char*           filename;
+    int             fd;
+    int             len;
+    int             reply;
+    cyg_uint8*      fb_base;
+    DEBUG(1, "target synth_fb_instantiate\n");
+
+    if (!synth_auxiliary_running) {
+        diag_printf("cyg_synth_fb_instantiate(): no I/O auxiliary, sticking with in-memory framebuffer\n");
+        return;
+    }
+
+    diag_sprintf(fb_name, "fb%d", fb->fb_driver0);
+    switch(fb->fb_format) {
+        // Only bother with the formats used by gensynth_fb.tcl
+      case CYG_FB_FORMAT_1BPP_PAL888:
+        {
+            static const cyg_uint8  fb_1bpp_palette[2 * 3]  = {
+                0x00, 0x00, 0x00,   // colour 0 == black
+                0xFF, 0xFF, 0xFF    // colour 1 == white
+            };
+            fb_format = "1BPP_PAL888";
+            memcpy(local_fb_data->palette, fb_1bpp_palette, sizeof(fb_1bpp_palette));
+            break;
+        }
+      case CYG_FB_FORMAT_2BPP_PAL888:
+        {
+            static const cyg_uint8  fb_2bpp_palette[4 * 3]  = {
+                0x00, 0x00, 0x00,   // colour 0 == black
+                0x54, 0x54, 0x54,   // dark grey
+                0xA8, 0xA8, 0xA8,   // light grey
+                0xFF, 0xFF, 0xFF    // colour 3 == white
+            } ;
+            fb_format = "2BPP_PAL888";
+            memcpy(local_fb_data->palette, fb_2bpp_palette, sizeof(fb_2bpp_palette));
+            break;
+        }
+      case CYG_FB_FORMAT_4BPP_PAL888:
+        fb_format = "4BPP_PAL888";
+        memcpy(local_fb_data->palette, cyg_fb_palette_ega, 16 * 3);
+        break;
+      case CYG_FB_FORMAT_8BPP_PAL888:
+        fb_format = "8BPP_PAL888";
+        memcpy(local_fb_data->palette, cyg_fb_palette_vga, 256 * 3);
+        break;
+      case CYG_FB_FORMAT_8BPP_TRUE_332:
+        fb_format = "8BPP_TRUE_332";
+        break;
+      case CYG_FB_FORMAT_16BPP_TRUE_565:
+        fb_format = "16BPP_TRUE_565";
+        break;
+      case CYG_FB_FORMAT_16BPP_TRUE_555:
+        fb_format = "16BPP_TRUE_555";
+        break;
+      case CYG_FB_FORMAT_32BPP_TRUE_0888:
+        fb_format = "32BPP_TRUE_0888";
+        break;
+    }
+        
+    diag_sprintf(device_data, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s",
+                 SYNTH_FB_PROTOCOL_VERSION,
+                 fb->fb_driver0,  /* id 0-3   */
+                 fb->fb_depth,
+                 fb->fb_flags0 & CYG_FB_FLAGS0_LE,
+                 fb->fb_width, fb->fb_height,
+#ifdef CYGHWR_IO_FRAMEBUF_FUNCTIONALITY_VIEWPORT
+                 fb->fb_viewport_width, fb->fb_viewport_height,
+#else
+                 fb->fb_width, fb->fb_height,
+#endif
+                 fb->fb_stride,
+                 fb->fb_driver1,    /* number of pages */
+                 fb_format);
+
+    local_fb_data->devid = synth_auxiliary_instantiate("devs/framebuf/synth", SYNTH_MAKESTRING(CYGPKG_DEVS_FRAMEBUF_SYNTH),
+                                                       "framebuf", fb_name, device_data);
+    if (local_fb_data->devid < 0) {
+        // The I/O auxiliary should have reported a suitable error.
+        // Just stick with an in-memory device.
+        diag_printf("cyg_synth_fb_instantiate(): failed to instantiate device, sticking with in-memory framebuffer\n");
+        return;
+    } else {
+        DEBUG(1, "target synth_auxiliary_instantiate(), host-side framebuf utility running\n");
+        // At this point the framebuf.tcl script has run, the window has
+        // been created, the framebuf program has been started, it will
+        // have created the shared memory region and the two fifos, 
+        // passed the names back up to framebuf.tcl, and everything should
+        // be running. This xchgmsg() retrieves the file names from
+        // framebuf.tcl.
+        synth_auxiliary_xchgmsg(local_fb_data->devid, SYNTH_FB_INIT, 0, 0, 0, 0, &reply, (unsigned char*)device_data, &len, 512);
+        // First filename is the shared memory region.
+        filename    = device_data;
+        for (ptr = device_data; *ptr != ';'; ptr++)
+            ;
+        *ptr++  = '\0';
+        DEBUG(1, "target :  Opening shared memory region %s\n", filename);
+        fd = cyg_hal_sys_open(filename, CYG_HAL_SYS_O_RDWR, 0);
+        if (fd < 0) {
+            synth_auxiliary_xchgmsg(local_fb_data->devid, SYNTH_FB_ABORT, 0, 0, 0, 0, 0, 0, 0, 0);
+            return;
+        }
+        shared_fb_data = (synth_fb_data*)cyg_hal_sys_mmap(0,
+                                                          sizeof(synth_fb_data) + (fb->fb_height * fb->fb_stride * fb->fb_driver1),
+                                                          CYG_HAL_SYS_PROT_READ | CYG_HAL_SYS_PROT_WRITE,
+                                                          CYG_HAL_SYS_MAP_SHARED,
+                                                          fd,
+                                                          0
+            );
+        if (shared_fb_data <= 0) {
+            synth_auxiliary_xchgmsg(local_fb_data->devid, SYNTH_FB_ABORT, 0, 0, 0, 0, 0, 0, 0, 0);
+            cyg_hal_sys_close(fd);
+            return;
+        }
+        DEBUG(1, "target:  mmap()'d shared memory region -> %p\n", shared_fb_data);
+        shared_fb_data->devid       = local_fb_data->devid;
+        
+        // Next filename is the fifo to the framebuf program.
+        filename = ptr;
+        for (ptr = device_data; *ptr != ';'; ptr++)
+            ;
+        *ptr++ = '\0';
+        DEBUG(1, "target:  Opening fifo to framebuf %s\n", filename);
+        shared_fb_data->fifo_to_framebuf = cyg_hal_sys_open(filename, CYG_HAL_SYS_O_WRONLY, 0);
+        if (shared_fb_data->fifo_to_framebuf < 0) {
+            synth_auxiliary_xchgmsg(shared_fb_data->devid, SYNTH_FB_ABORT, 0, 0, 0, 0, 0, 0, 0, 0);
+            cyg_hal_sys_close(fd);
+            return;
+        }
+        // And finally the fifo from the framebuf program.
+        filename = ptr;
+        for (ptr = device_data; *ptr != ';'; ptr++)
+            ;
+        *ptr = '\0';
+        DEBUG(1, "target:  Opening fifo from framebuf %s\n", filename);
+        shared_fb_data->fifo_from_framebuf = cyg_hal_sys_open(filename, CYG_HAL_SYS_O_RDONLY, 0);
+        if (shared_fb_data->fifo_from_framebuf < 0) {
+            synth_auxiliary_xchgmsg(shared_fb_data->devid, SYNTH_FB_ABORT, 0, 0, 0, 0, 0, 0, 0, 0);
+            cyg_hal_sys_close(fd);
+            cyg_hal_sys_close(shared_fb_data->fifo_to_framebuf);
+            return;
+        }
+
+        // We have a shared memory region and the two files. Copy
+        // all existing fb_data contents (e.g. the palettes) and
+        // the framebuffer contents to the shared memory region.
+        // The MUST_BE_ON flag is not set for synthetic target
+        // framebuffers so there may already be contents.
+        fb_base  = (cyg_uint8*)fb->fb_base;
+        fb_base -= (fb->fb_height * fb->fb_stride * shared_fb_data->page_drawable);
+        memcpy(&(shared_fb_data->palette[0]), &(local_fb_data->palette[0]), 3 * 256);
+        memcpy(&(shared_fb_data->framebuf[0]), fb_base, fb->fb_height * fb->fb_stride * fb->fb_driver1);
+        shared_fb_data->connected   = 1;
+        fb->fb_driver2              = (CYG_ADDRWORD)shared_fb_data;
+            
+        fb_base     = (cyg_uint8*)&(shared_fb_data->framebuf[0]);
+        fb_base    += (fb->fb_height * fb->fb_stride * shared_fb_data->page_drawable);
+        fb->fb_base = fb_base;
+        *(cyg_uint8**)fb->fb_driver3    = fb_base;
+
+        DEBUG(1, "target:  Fully instantiated, fb_data %p, blank_on %d, display_on %d\n",
+              shared_fb_data, shared_fb_data->blank_on, shared_fb_data->display_on);
+        DEBUG(1, "target:    devid %d, t2h %d, h2t %d\n",
+                    shared_fb_data->devid, shared_fb_data->fifo_to_framebuf, shared_fb_data->fifo_from_framebuf);
+        // Finally tell the framebuf program everything is ready.
+        fb_op(fb, SYNTH_FB_OK);
+        DEBUG(1, "target: Sent SYNTH_FB_OK\n");
+    }
+}
+
+
+// Switch on a framebuffer device. This may get called multiple
+// times, e.g. when switching between different screen modes.
+// It just involves sending a message to the auxiliary.
+static int
+cyg_synth_fb_on(struct cyg_fb* fb)
+{
+    synth_fb_data*  fb_data = (synth_fb_data*) fb->fb_driver2;
+    if (fb_data->connected) {
+        synth_auxiliary_xchgmsg(fb_data->devid, SYNTH_FB_ON, 0, 0, 0, 0, 0, 0, 0, 0);
+    }
+
+    return 0;
+}
+
+static int
+cyg_synth_fb_off(struct cyg_fb* fb)
+{
+    synth_fb_data*  fb_data = (synth_fb_data*) fb->fb_driver2;
+    if (fb_data->connected) {
+        synth_auxiliary_xchgmsg(fb_data->devid, SYNTH_FB_OFF, 0, 0, 0, 0, 0, 0, 0, 0);
+    }
+    return 0;
+}
+
+static int
+cyg_synth_fb_ioctl(struct cyg_fb* fb, cyg_ucount16 key, void* data, size_t* len)
+{
+    synth_fb_data*  fb_data = (synth_fb_data*) fb->fb_driver2;
+    int             result  = ENOSYS;
+
+    switch(key) {
+      case CYG_FB_IOCTL_VIEWPORT_GET_POSITION:
+        DEBUG(1, "cyg_synth_fb_ioctl: viewport_get_position\n");
+        if (fb->fb_flags0 & CYG_FB_FLAGS0_VIEWPORT) {
+            cyg_fb_ioctl_viewport*  viewport = (cyg_fb_ioctl_viewport*)data;
+            CYG_ASSERT(*len == sizeof(cyg_fb_ioctl_viewport), "data argument should be a cyg_fb_ioctl_viewport structure");
+            viewport->fbvp_x    = fb_data->viewport_x;
+            viewport->fbvp_y    = fb_data->viewport_y;
+            result  = 0;
+            DEBUG(1, "                  : current viewport x %d, y %d\n", fb_data->viewport_x, fb_data->viewport_y);
+        } else {
+            DEBUG(1, "                  : framebuffer does not support a viewport\n");
+        }
+        break;
+      case CYG_FB_IOCTL_VIEWPORT_SET_POSITION:
+        DEBUG(1, "cyg_synth_fb_ioctl: viewport_set_position\n");
+        if (fb->fb_flags0 & CYG_FB_FLAGS0_VIEWPORT) {
+            cyg_fb_ioctl_viewport*  viewport = (cyg_fb_ioctl_viewport*)data;
+            CYG_ASSERT(*len == sizeof(cyg_fb_ioctl_viewport), "data argument should be a cyg_fb_ioctl_viewport structure");
+            CYG_ASSERT(((viewport->fbvp_x + fb->fb_viewport_width) <= fb->fb_width) &&
+                       ((viewport->fbvp_y + fb->fb_viewport_height) <= fb->fb_height),
+                       "viewport should be within framebuffer dimensions");
+            DEBUG(1, "                  : setting viewport from x %d, y %d to x %d, y %d\n",
+                  fb_data->viewport_x, fb_data->viewport_y, (int) viewport->fbvp_x, (int) viewport->fbvp_y);
+            if ((fb_data->viewport_x != (int)viewport->fbvp_x) || (fb_data->viewport_y != (int)viewport->fbvp_y)) {
+                fb_data->viewport_x = (int)viewport->fbvp_x;
+                fb_data->viewport_y = (int)viewport->fbvp_y;
+                fb_op(fb, SYNTH_FB_VIEWPORT);
+            }
+            result = 0;
+        } else {
+            DEBUG(1, "                  : framebuffer does not support a viewport\n");
+        }
+        break;
+      case CYG_FB_IOCTL_PAGE_FLIPPING_GET_PAGES:
+        DEBUG(1, "cyg_synth_fb_ioctl: page_flipping_get_pages\n");
+        if (fb->fb_flags0 & CYG_FB_FLAGS0_PAGE_FLIPPING) {
+            cyg_fb_ioctl_page_flip* page_flip = (cyg_fb_ioctl_page_flip*)data;
+            CYG_ASSERT(*len == sizeof(cyg_fb_ioctl_page_flip), "data argument should be a cyg_fb_ioctl_page_flip structure");
+            page_flip->fbpf_number_pages    = fb->fb_driver1;
+            page_flip->fbpf_visible_page    = fb_data->page_visible;
+            page_flip->fbpf_drawable_page   = fb_data->page_drawable;
+            result = 0;
+            DEBUG(1, "                  : number_pages %d, visible page %d, drawable page %d\n",
+                  fb->fb_driver1, fb_data->page_visible, fb_data->page_drawable);
+        } else {
+            DEBUG(1, "                  : framebuffer does not support page flipping\n");
+        }
+        break;
+      case CYG_FB_IOCTL_PAGE_FLIPPING_SET_PAGES:
+        DEBUG(1, "cyg_synth_fb_ioctl: page_flipping_set_pages\n");
+        if (fb->fb_flags0 & CYG_FB_FLAGS0_PAGE_FLIPPING) {
+            cyg_fb_ioctl_page_flip* page_flip = (cyg_fb_ioctl_page_flip*)data;
+            cyg_uint8*  fb_base;
+            
+            CYG_ASSERT(*len == sizeof(cyg_fb_ioctl_page_flip), "data argument should be a cyg_fb_ioctl_page_flip structure");
+            CYG_ASSERT((page_flip->fbpf_visible_page  < fb->driver1) &&
+                       (page_flip->fbpf_drawable_page < fb->driver1),
+                       "framebuffer does not have that many pages");
+            DEBUG(1, "                  : drawable page was %d, now %d, visible page was %d, now %d\n",
+                  fb_data->page_drawable, (int)page_flip->fbpf_drawable_page,
+                  fb_data->page_visible, (int)page_flip->fbpf_visible_page);
+            fb_base  = (cyg_uint8*)fb->fb_base;
+            fb_base -= (fb->fb_height * fb->fb_stride * fb_data->page_drawable);
+            fb_data->page_drawable          = page_flip->fbpf_drawable_page;
+            fb_base += (fb->fb_height * fb->fb_stride * fb_data->page_drawable);
+            fb->fb_base = fb_base;
+            *(cyg_uint8**)fb->fb_driver3 = fb_base;
+            if (fb_data->page_visible != (int)page_flip->fbpf_visible_page) {
+                fb_data->page_visible = (int)page_flip->fbpf_visible_page;
+                fb_op(fb, SYNTH_FB_PAGE_FLIP);
+            }
+            result = 0;
+        } else {
+            DEBUG(1, "                  : framebuffer does not support page flipping\n");
+        }
+        break;
+      case CYG_FB_IOCTL_BLANK_GET:
+        {
+            cyg_fb_ioctl_blank* blank = (cyg_fb_ioctl_blank*)data;
+            DEBUG(1, "cyg_synth_fb_ioctl: blank_get, current on state %d\n", fb_data->blank_on);
+            CYG_ASSERT(*len == sizeof(cyg_fb_ioctl_blank), "data argument should be a cyg_fb_ioctl_blank structure");
+            blank->fbbl_on  = fb_data->blank_on;
+            result = 0;
+        }
+        break;
+      case CYG_FB_IOCTL_BLANK_SET:
+        {
+            cyg_fb_ioctl_blank* blank = (cyg_fb_ioctl_blank*)data;
+            CYG_ASSERT(*len == sizeof(cyg_fb_ioctl_blank), "data argument should be a cyg_fb_ioctl_blank structure");
+            DEBUG(1, "cyg_synth_fb_ioctl: blank_set, on was %d, now %d\n", fb_data->blank_on, blank->fbbl_on);
+            if (blank->fbbl_on != fb_data->blank_on) {
+                fb_data->blank_on = blank->fbbl_on;
+                fb_op(fb, SYNTH_FB_BLANK);
+            }
+            result = 0;
+        }
+        break;
+      default:
+        result  = ENOSYS;
+        break;
+    }
+    return result;
+}
+
+void
+cyg_synth_fb_synch(struct cyg_fb* fb, cyg_ucount16 when)
+{
+    // FIXME: update synch_x0/y0/x1/y1 once the generic framebuffer
+    // code actually maintains a bounding box.
+    fb_op(fb, SYNTH_FB_SYNC);
+}
+
+#ifdef CYGHWR_DEVS_FRAMEBUF_SYNTH_FUNCTIONALITY_PALETTED
+// The palette is held in the synth_fb_data structure.
+static void
+cyg_synth_fb_read_palette(struct cyg_fb* fb, cyg_ucount32 first, cyg_ucount32 count, void* dest)
+{
+    synth_fb_data*  fb_data = (synth_fb_data*) fb->fb_driver2;
+    CYG_ASSERT(fb->fb_flags0 & CYG_FB_FLAGS0_PALETTE, "reading palette of non-paletted display");
+    CYG_ASSERT((first + count) <= (0x01 << fb->fb_depth), "palette size exceeded");
+
+    memcpy(dest, &(fb_data->palette[3 * first]), 3 * count);
+}
+
+static void
+cyg_synth_fb_write_palette(struct cyg_fb* fb, cyg_ucount32 first, cyg_ucount32 count, const void* source, cyg_ucount16 when)
+{
+    synth_fb_data*  fb_data = (synth_fb_data*) fb->fb_driver2;
+    CYG_ASSERT(fb->fb_flags0 & CYG_FB_FLAGS0_PALETTE, "reading palette of non-paletted display");
+    CYG_ASSERT((first + count) <= (0x01 << fb->fb_depth), "palette size exceeded");
+
+    DEBUG(1, "write_palette: fb %p, first %d, count %d, source %p\n", fb, first, count, source);
+    memcpy(&(fb_data->palette[3 * first]), source, 3 * count);
+    fb_op(fb, SYNTH_FB_WRITE_PALETTE);
+    CYG_UNUSED_PARAM(cyg_ucount16, when);
+}
+#endif
+
+#define LINEAR1(_fn_, _suffix_)  cyg_fb_linear_ ## _fn_ ## _ ## _suffix_
+#define LINEAR( _fn_, _suffix_)  LINEAR1(_fn_, _suffix_)
+
+#ifdef CYGPKG_DEVS_FRAMEBUF_SYNTH_FB0
+# ifdef CYGNUM_DEVS_FRAMEBUF_SYNTH_FB0_PAGE_FLIPPING
+#  define FB0_PAGES CYGNUM_DEVS_FRAMEBUF_SYNTH_FB0_PAGE_FLIPPING
+# else
+#  define FB0_PAGES 1
+#endif
+
+// A default area of memory for the framebuffer, if the auxiliary is not
+// running.
+static cyg_uint8            cyg_synth_fb0_default_base[CYG_FB_fb0_HEIGHT * CYG_FB_fb0_STRIDE * FB0_PAGES];
+
+// Pointer to framebuffer memory. This defaults to a statically
+// allocated memory but will switch to a shared memory region if
+// the auxiliary is running. It may also change if page flipping
+// is enabled.
+cyg_uint8*  cyg_synth_fb0_base  = cyg_synth_fb0_default_base;
+
+// Driver-specific data needed for interacting with the auxiliary.
+static synth_fb_data    cyg_synth_fb0_data;
+
+CYG_FB_FRAMEBUFFER(CYG_FB_fb0_STRUCT,
+                   CYG_FB_fb0_DEPTH,
+                   CYG_FB_fb0_FORMAT,
+                   CYG_FB_fb0_WIDTH,
+                   CYG_FB_fb0_HEIGHT,
+                   CYG_FB_fb0_VIEWPORT_WIDTH,
+                   CYG_FB_fb0_VIEWPORT_HEIGHT,
+                   cyg_synth_fb0_default_base,
+                   CYG_FB_fb0_STRIDE,
+                   CYG_FB_fb0_FLAGS0,
+                   CYG_FB_fb0_FLAGS1,
+                   CYG_FB_fb0_FLAGS2,
+                   CYG_FB_fb0_FLAGS3,
+                   (CYG_ADDRWORD) 0,  // id, 0 - 3
+                   (CYG_ADDRWORD) FB0_PAGES,
+                   (CYG_ADDRWORD) &cyg_synth_fb0_data,
+                   (CYG_ADDRWORD) &cyg_synth_fb0_base,
+                   &cyg_synth_fb_on,
+                   &cyg_synth_fb_off,
+                   &cyg_synth_fb_ioctl,
+                   &cyg_synth_fb_synch,
+                   &CYG_FB_fb0_READ_PALETTE_FN,
+                   &CYG_FB_fb0_WRITE_PALETTE_FN,
+                   &CYG_FB_fb0_MAKE_COLOUR_FN,
+                   &CYG_FB_fb0_BREAK_COLOUR_FN,
+                   LINEAR(write_pixel, CYG_FB_fb0_SUFFIX),
+                   LINEAR(read_pixel, CYG_FB_fb0_SUFFIX),
+                   LINEAR(write_hline, CYG_FB_fb0_SUFFIX),
+                   LINEAR(write_vline, CYG_FB_fb0_SUFFIX),
+                   LINEAR(fill_block, CYG_FB_fb0_SUFFIX),
+                   LINEAR(write_block, CYG_FB_fb0_SUFFIX),
+                   LINEAR(read_block, CYG_FB_fb0_SUFFIX),
+                   LINEAR(move_block, CYG_FB_fb0_SUFFIX),
+                   0, 0, 0, 0       // Spare0 -> spare3
+    );
+                   
+#endif
+
+#ifdef CYGPKG_DEVS_FRAMEBUF_SYNTH_FB1
+
+# ifdef CYGNUM_DEVS_FRAMEBUF_SYNTH_FB1_PAGE_FLIPPING
+#  define FB1_PAGES CYGNUM_DEVS_FRAMEBUF_SYNTH_FB1_PAGE_FLIPPING
+# else
+#  define FB1_PAGES 1
+#endif
+static cyg_uint8 cyg_synth_fb1_default_base[CYG_FB_fb1_HEIGHT * CYG_FB_fb1_STRIDE * FB1_PAGES];
+cyg_uint8*  cyg_synth_fb1_base  = cyg_synth_fb1_default_base;
+static synth_fb_data    cyg_synth_fb1_data;
+
+CYG_FB_FRAMEBUFFER(CYG_FB_fb1_STRUCT,
+                   CYG_FB_fb1_DEPTH,
+                   CYG_FB_fb1_FORMAT,
+                   CYG_FB_fb1_WIDTH,
+                   CYG_FB_fb1_HEIGHT,
+                   CYG_FB_fb1_VIEWPORT_WIDTH,
+                   CYG_FB_fb1_VIEWPORT_HEIGHT,
+                   cyg_synth_fb1_default_base,
+                   CYG_FB_fb1_STRIDE,
+                   CYG_FB_fb1_FLAGS0,
+                   CYG_FB_fb1_FLAGS1,
+                   CYG_FB_fb1_FLAGS2,
+                   CYG_FB_fb1_FLAGS3,
+                   (CYG_ADDRWORD) 1,  // id, 0 - 3
+                   (CYG_ADDRWORD) FB1_PAGES,
+                   (CYG_ADDRWORD) &cyg_synth_fb1_data,
+                   (CYG_ADDRWORD) &cyg_synth_fb1_base,
+                   &cyg_synth_fb_on,
+                   &cyg_synth_fb_off,
+                   &cyg_synth_fb_ioctl,
+                   &cyg_synth_fb_synch,
+                   &CYG_FB_fb1_READ_PALETTE_FN,
+                   &CYG_FB_fb1_WRITE_PALETTE_FN,
+                   &CYG_FB_fb1_MAKE_COLOUR_FN,
+                   &CYG_FB_fb1_BREAK_COLOUR_FN,
+                   LINEAR(write_pixel, CYG_FB_fb1_SUFFIX),
+                   LINEAR(read_pixel, CYG_FB_fb1_SUFFIX),
+                   LINEAR(write_hline, CYG_FB_fb1_SUFFIX),
+                   LINEAR(write_vline, CYG_FB_fb1_SUFFIX),
+                   LINEAR(fill_block, CYG_FB_fb1_SUFFIX),
+                   LINEAR(write_block, CYG_FB_fb1_SUFFIX),
+                   LINEAR(read_block, CYG_FB_fb1_SUFFIX),
+                   LINEAR(move_block, CYG_FB_fb1_SUFFIX),
+                   0, 0, 0, 0       // Spare0 -> spare3
+    );
+                   
+#endif
+
+#ifdef CYGPKG_DEVS_FRAMEBUF_SYNTH_FB2
+
+# ifdef CYGNUM_DEVS_FRAMEBUF_SYNTH_FB2_PAGE_FLIPPING
+#  define FB2_PAGES CYGNUM_DEVS_FRAMEBUF_SYNTH_FB2_PAGE_FLIPPING
+# else
+#  define FB2_PAGES 1
+#endif
+static cyg_uint8 cyg_synth_fb2_default_base[CYG_FB_fb2_HEIGHT * CYG_FB_fb2_STRIDE * FB2_PAGES];
+cyg_uint8*  cyg_synth_fb2_base  = cyg_synth_fb2_default_base;
+static synth_fb_data    cyg_synth_fb2_data;
+
+CYG_FB_FRAMEBUFFER(CYG_FB_fb2_STRUCT,
+                   CYG_FB_fb2_DEPTH,
+                   CYG_FB_fb2_FORMAT,
+                   CYG_FB_fb2_WIDTH,
+                   CYG_FB_fb2_HEIGHT,
+                   CYG_FB_fb2_VIEWPORT_WIDTH,
+                   CYG_FB_fb2_VIEWPORT_HEIGHT,
+                   cyg_synth_fb2_default_base,
+                   CYG_FB_fb2_STRIDE,
+                   CYG_FB_fb2_FLAGS0,
+                   CYG_FB_fb2_FLAGS1,
+                   CYG_FB_fb2_FLAGS2,
+                   CYG_FB_fb2_FLAGS3,
+                   (CYG_ADDRWORD) 2,  // id, 0 - 3
+                   (CYG_ADDRWORD) FB2_PAGES,
+                   (CYG_ADDRWORD) &cyg_synth_fb2_data,
+                   (CYG_ADDRWORD) &cyg_synth_fb2_base,
+                   &cyg_synth_fb_on,
+                   &cyg_synth_fb_off,
+                   &cyg_synth_fb_ioctl,
+                   &cyg_synth_fb_synch,
+                   &CYG_FB_fb2_READ_PALETTE_FN,
+                   &CYG_FB_fb2_WRITE_PALETTE_FN,
+                   &CYG_FB_fb2_MAKE_COLOUR_FN,
+                   &CYG_FB_fb2_BREAK_COLOUR_FN,
+                   LINEAR(write_pixel, CYG_FB_fb2_SUFFIX),
+                   LINEAR(read_pixel, CYG_FB_fb2_SUFFIX),
+                   LINEAR(write_hline, CYG_FB_fb2_SUFFIX),
+                   LINEAR(write_vline, CYG_FB_fb2_SUFFIX),
+                   LINEAR(fill_block, CYG_FB_fb2_SUFFIX),
+                   LINEAR(write_block, CYG_FB_fb2_SUFFIX),
+                   LINEAR(read_block, CYG_FB_fb2_SUFFIX),
+                   LINEAR(move_block, CYG_FB_fb2_SUFFIX),
+                   0, 0, 0, 0       // Spare0 -> spare3
+    );
+                   
+#endif
+
+#ifdef CYGPKG_DEVS_FRAMEBUF_SYNTH_FB3
+
+# ifdef CYGNUM_DEVS_FRAMEBUF_SYNTH_FB3_PAGE_FLIPPING
+#  define FB3_PAGES CYGNUM_DEVS_FRAMEBUF_SYNTH_FB3_PAGE_FLIPPING
+# else
+#  define FB3_PAGES 1
+#endif
+static cyg_uint8 cyg_synth_fb3_default_base[CYG_FB_fb3_HEIGHT * CYG_FB_fb3_STRIDE * FB3_PAGES];
+cyg_uint8*  cyg_synth_fb3_base  = cyg_synth_fb3_default_base;
+static synth_fb_data    cyg_synth_fb3_data;
+
+CYG_FB_FRAMEBUFFER(CYG_FB_fb3_STRUCT,
+                   CYG_FB_fb3_DEPTH,
+                   CYG_FB_fb3_FORMAT,
+                   CYG_FB_fb3_WIDTH,
+                   CYG_FB_fb3_HEIGHT,
+                   CYG_FB_fb3_VIEWPORT_WIDTH,
+                   CYG_FB_fb3_VIEWPORT_HEIGHT,
+                   cyg_synth_fb3_default_base,
+                   CYG_FB_fb3_STRIDE,
+                   CYG_FB_fb3_FLAGS0,
+                   CYG_FB_fb3_FLAGS1,
+                   CYG_FB_fb3_FLAGS2,
+                   CYG_FB_fb3_FLAGS3,
+                   (CYG_ADDRWORD) 3,  // id, 0 - 3
+                   (CYG_ADDRWORD) FB3_PAGES,
+                   (CYG_ADDRWORD) &cyg_synth_fb3_data,
+                   (CYG_ADDRWORD) &cyg_synth_fb3_base,
+                   &cyg_synth_fb_on,
+                   &cyg_synth_fb_off,
+                   &cyg_synth_fb_ioctl,
+                   &cyg_synth_fb_synch,
+                   &CYG_FB_fb3_READ_PALETTE_FN,
+                   &CYG_FB_fb3_WRITE_PALETTE_FN,
+                   &CYG_FB_fb3_MAKE_COLOUR_FN,
+                   &CYG_FB_fb3_BREAK_COLOUR_FN,
+                   LINEAR(write_pixel, CYG_FB_fb3_SUFFIX),
+                   LINEAR(read_pixel, CYG_FB_fb3_SUFFIX),
+                   LINEAR(write_hline, CYG_FB_fb3_SUFFIX),
+                   LINEAR(write_vline, CYG_FB_fb3_SUFFIX),
+                   LINEAR(fill_block, CYG_FB_fb3_SUFFIX),
+                   LINEAR(write_block, CYG_FB_fb3_SUFFIX),
+                   LINEAR(read_block, CYG_FB_fb3_SUFFIX),
+                   LINEAR(move_block, CYG_FB_fb3_SUFFIX),
+                   0, 0, 0, 0       // Spare0 -> spare3
+    );
+                   
+#endif
Index: src/synthfb_init.cxx
===================================================================
RCS file: src/synthfb_init.cxx
diff -N src/synthfb_init.cxx
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/synthfb_init.cxx	7 Oct 2008 21:00:34 -0000
@@ -0,0 +1,70 @@
+//==========================================================================
+//
+//      synthfb_init.cxx
+//
+//      Instantiate one or more framebuffer devices for the synthetic target.
+//
+//==========================================================================
+//###ECOSGPLCOPYRIGHTBEGIN####
+//-------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//###DESCRIPTIONBEGIN####
+//
+// Author(s):     bartv
+// Date:          2007-02-0
+//
+//###DESCRIPTIONEND####
+//========================================================================
+
+#include <pkgconf/devs_framebuf_synth.h>
+#include <cyg/io/framebuf.h>
+
+extern "C" void _cyg_synth_fb_instantiate(struct cyg_fb*);
+                                          
+class _synth_fb_init {
+    
+  public:
+    _synth_fb_init(void)
+    {
+#ifdef CYGPKG_DEVS_FRAMEBUF_SYNTH_FB0
+        _cyg_synth_fb_instantiate(&cyg_synth_fb0);
+#endif        
+#ifdef CYGPKG_DEVS_FRAMEBUF_SYNTH_FB1
+        _cyg_synth_fb_instantiate(&cyg_synth_fb1);
+#endif        
+#ifdef CYGPKG_DEVS_FRAMEBUF_SYNTH_FB2
+        _cyg_synth_fb_instantiate(&cyg_synth_fb2);
+#endif        
+#ifdef CYGPKG_DEVS_FRAMEBUF_SYNTH_FB3
+        _cyg_synth_fb_instantiate(&cyg_synth_fb3);
+#endif        
+    }
+};
+
+static _synth_fb_init _synth_fb_init_object CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]